use std::hash::{Hash, Hasher}; use crate::DocumentId; use serde::{ser, Serialize}; use serde_json::Value; use siphasher::sip::SipHasher; use super::{ConvertToString, SerializerError}; pub fn extract_document_id( identifier: &str, document: &D, ) -> Result, SerializerError> where D: serde::Serialize, { let serializer = ExtractDocumentId { identifier }; document.serialize(serializer) } pub fn value_to_string(value: &Value) -> Option { match value { Value::Null => None, Value::Bool(_) => None, Value::Number(value) => Some(value.to_string()), Value::String(value) => Some(value.to_string()), Value::Array(_) => None, Value::Object(_) => None, } } pub fn compute_document_id(t: H) -> DocumentId { let mut s = SipHasher::new(); t.hash(&mut s); let hash = s.finish(); DocumentId(hash) } struct ExtractDocumentId<'a> { identifier: &'a str, } impl<'a> ser::Serializer for ExtractDocumentId<'a> { type Ok = Option; type Error = SerializerError; type SerializeSeq = ser::Impossible; type SerializeTuple = ser::Impossible; type SerializeTupleStruct = ser::Impossible; type SerializeTupleVariant = ser::Impossible; type SerializeMap = ExtractDocumentIdMapSerializer<'a>; type SerializeStruct = ExtractDocumentIdStructSerializer<'a>; type SerializeStructVariant = ser::Impossible; forward_to_unserializable_type! { bool => serialize_bool, char => serialize_char, i8 => serialize_i8, i16 => serialize_i16, i32 => serialize_i32, i64 => serialize_i64, u8 => serialize_u8, u16 => serialize_u16, u32 => serialize_u32, u64 => serialize_u64, f32 => serialize_f32, f64 => serialize_f64, } fn serialize_str(self, _value: &str) -> Result { Err(SerializerError::UnserializableType { type_name: "str" }) } fn serialize_bytes(self, _value: &[u8]) -> Result { Err(SerializerError::UnserializableType { type_name: "&[u8]" }) } fn serialize_none(self) -> Result { Err(SerializerError::UnserializableType { type_name: "Option", }) } fn serialize_some(self, _value: &T) -> Result where T: Serialize, { Err(SerializerError::UnserializableType { type_name: "Option", }) } fn serialize_unit(self) -> Result { Err(SerializerError::UnserializableType { type_name: "()" }) } fn serialize_unit_struct(self, _name: &'static str) -> Result { Err(SerializerError::UnserializableType { type_name: "unit struct", }) } fn serialize_unit_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, ) -> Result { Err(SerializerError::UnserializableType { type_name: "unit variant", }) } fn serialize_newtype_struct( self, _name: &'static str, value: &T, ) -> Result where T: Serialize, { value.serialize(self) } fn serialize_newtype_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _value: &T, ) -> Result where T: Serialize, { Err(SerializerError::UnserializableType { type_name: "newtype variant", }) } fn serialize_seq(self, _len: Option) -> Result { Err(SerializerError::UnserializableType { type_name: "sequence", }) } fn serialize_tuple(self, _len: usize) -> Result { Err(SerializerError::UnserializableType { type_name: "tuple" }) } fn serialize_tuple_struct( self, _name: &'static str, _len: usize, ) -> Result { Err(SerializerError::UnserializableType { type_name: "tuple struct", }) } fn serialize_tuple_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { Err(SerializerError::UnserializableType { type_name: "tuple variant", }) } fn serialize_map(self, _len: Option) -> Result { let serializer = ExtractDocumentIdMapSerializer { identifier: self.identifier, document_id: None, current_key_name: None, }; Ok(serializer) } fn serialize_struct( self, _name: &'static str, _len: usize, ) -> Result { let serializer = ExtractDocumentIdStructSerializer { identifier: self.identifier, document_id: None, }; Ok(serializer) } fn serialize_struct_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { Err(SerializerError::UnserializableType { type_name: "struct variant", }) } } pub struct ExtractDocumentIdMapSerializer<'a> { identifier: &'a str, document_id: Option, current_key_name: Option, } impl<'a> ser::SerializeMap for ExtractDocumentIdMapSerializer<'a> { type Ok = Option; type Error = SerializerError; fn serialize_key(&mut self, key: &T) -> Result<(), Self::Error> where T: Serialize, { let key = key.serialize(ConvertToString)?; self.current_key_name = Some(key); Ok(()) } fn serialize_value(&mut self, value: &T) -> Result<(), Self::Error> where T: Serialize, { let key = self.current_key_name.take().unwrap(); self.serialize_entry(&key, value) } fn serialize_entry( &mut self, key: &K, value: &V, ) -> Result<(), Self::Error> where K: Serialize, V: Serialize, { let key = key.serialize(ConvertToString)?; if self.identifier == key { let value = serde_json::to_string(value).and_then(|s| serde_json::from_str(&s))?; match value_to_string(&value).map(|s| compute_document_id(&s)) { Some(document_id) => self.document_id = Some(document_id), None => return Err(SerializerError::InvalidDocumentIdType), } } Ok(()) } fn end(self) -> Result { Ok(self.document_id) } } pub struct ExtractDocumentIdStructSerializer<'a> { identifier: &'a str, document_id: Option, } impl<'a> ser::SerializeStruct for ExtractDocumentIdStructSerializer<'a> { type Ok = Option; type Error = SerializerError; fn serialize_field( &mut self, key: &'static str, value: &T, ) -> Result<(), Self::Error> where T: Serialize, { if self.identifier == key { let value = serde_json::to_string(value).and_then(|s| serde_json::from_str(&s))?; match value_to_string(&value).map(compute_document_id) { Some(document_id) => self.document_id = Some(document_id), None => return Err(SerializerError::InvalidDocumentIdType), } } Ok(()) } fn end(self) -> Result { Ok(self.document_id) } }