diff --git a/src/database/mod.rs b/src/database/mod.rs index 4ff34709b..2830f934b 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -1,45 +1,29 @@ -use std::collections::hash_map::DefaultHasher; -use std::hash::{Hash, Hasher}; use std::error::Error; use std::ops::Deref; use std::sync::Arc; use rocksdb::rocksdb::{DB, Snapshot}; -pub use self::index::Index; -pub use self::update::{Update, UpdateBuilder}; pub use self::document_key::{DocumentKey, DocumentKeyAttr}; pub use self::database_view::{DatabaseView, DocumentIter}; +pub use self::update::{Update, UpdateBuilder}; +pub use self::serde::SerializerError; pub use self::database::Database; pub use self::schema::Schema; +pub use self::index::Index; const DATA_INDEX: &[u8] = b"data-index"; const DATA_SCHEMA: &[u8] = b"data-schema"; -macro_rules! forward_to_unserializable_type { - ($($ty:ident => $se_method:ident,)*) => { - $( - fn $se_method(self, _v: $ty) -> Result { - Err(SerializerError::UnserializableType { name: "$ty" }) - } - )* - } -} - pub mod schema; pub(crate) mod index; mod update; +mod serde; mod database; mod document_key; mod database_view; mod deserializer; -fn calculate_hash(t: &T) -> u64 { - let mut s = DefaultHasher::new(); - t.hash(&mut s); - s.finish() -} - fn retrieve_data_schema(snapshot: &Snapshot) -> Result> where D: Deref { diff --git a/src/database/schema.rs b/src/database/schema.rs index bffd0aaa5..5f622e003 100644 --- a/src/database/schema.rs +++ b/src/database/schema.rs @@ -1,5 +1,4 @@ use std::collections::{HashMap, BTreeMap}; -use crate::database::calculate_hash; use std::io::{Read, Write}; use std::error::Error; use std::{fmt, u16}; @@ -7,9 +6,11 @@ use std::ops::BitOr; use std::sync::Arc; use serde_derive::{Serialize, Deserialize}; -use serde::ser::{self, Serialize}; use linked_hash_map::LinkedHashMap; +use serde::Serialize; +use crate::database::serde::find_id::FindDocumentIdSerializer; +use crate::database::serde::SerializerError; use crate::DocumentId; pub const STORED: SchemaProps = SchemaProps { stored: true, indexed: false }; diff --git a/src/database/serde/find_id.rs b/src/database/serde/find_id.rs new file mode 100644 index 000000000..98e2e8036 --- /dev/null +++ b/src/database/serde/find_id.rs @@ -0,0 +1,243 @@ +use serde::Serialize; +use serde::ser; + +use crate::database::serde::key_to_string::KeyToStringSerializer; +use crate::database::serde::{SerializerError, calculate_hash}; +use crate::DocumentId; + +pub struct FindDocumentIdSerializer<'a> { + pub id_attribute_name: &'a str, +} + +impl<'a> ser::Serializer for FindDocumentIdSerializer<'a> { + type Ok = DocumentId; + type Error = SerializerError; + type SerializeSeq = ser::Impossible; + type SerializeTuple = ser::Impossible; + type SerializeTupleStruct = ser::Impossible; + type SerializeTupleVariant = ser::Impossible; + type SerializeMap = FindDocumentIdMapSerializer<'a>; + type SerializeStruct = FindDocumentIdStructSerializer<'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, _v: &str) -> Result { + Err(SerializerError::UnserializableType { name: "str" }) + } + + fn serialize_bytes(self, _v: &[u8]) -> Result { + Err(SerializerError::UnserializableType { name: "&[u8]" }) + } + + fn serialize_none(self) -> Result { + Err(SerializerError::UnserializableType { name: "Option" }) + } + + fn serialize_some(self, _value: &T) -> Result + where T: Serialize, + { + Err(SerializerError::UnserializableType { name: "Option" }) + } + + fn serialize_unit(self) -> Result { + Err(SerializerError::UnserializableType { name: "()" }) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result { + Err(SerializerError::UnserializableType { name: "unit struct" }) + } + + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str + ) -> Result + { + Err(SerializerError::UnserializableType { 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 { name: "newtype variant" }) + } + + fn serialize_seq(self, _len: Option) -> Result { + Err(SerializerError::UnserializableType { name: "sequence" }) + } + + fn serialize_tuple(self, _len: usize) -> Result { + Err(SerializerError::UnserializableType { name: "tuple" }) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize + ) -> Result + { + Err(SerializerError::UnserializableType { name: "tuple struct" }) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize + ) -> Result + { + Err(SerializerError::UnserializableType { name: "tuple variant" }) + } + + fn serialize_map(self, _len: Option) -> Result { + Ok(FindDocumentIdMapSerializer { + id_attribute_name: self.id_attribute_name, + document_id: None, + current_key_name: None, + }) + } + + fn serialize_struct( + self, + _name: &'static str, + _len: usize + ) -> Result + { + Ok(FindDocumentIdStructSerializer { + id_attribute_name: self.id_attribute_name, + document_id: None, + }) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize + ) -> Result + { + Err(SerializerError::UnserializableType { name: "struct variant" }) + } +} + +pub struct FindDocumentIdMapSerializer<'a> { + id_attribute_name: &'a str, + document_id: Option, + current_key_name: Option, +} + +impl<'a> ser::SerializeMap for FindDocumentIdMapSerializer<'a> { + type Ok = DocumentId; + type Error = SerializerError; + + fn serialize_key(&mut self, key: &T) -> Result<(), Self::Error> + where T: Serialize, + { + let key = key.serialize(KeyToStringSerializer)?; + 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(KeyToStringSerializer)?; + + if self.id_attribute_name == key { + // TODO is it possible to have multiple ids? + let id = bincode::serialize(value).unwrap(); + let hash = calculate_hash(&id); + self.document_id = Some(DocumentId(hash)); + } + + Ok(()) + } + + fn end(self) -> Result { + match self.document_id { + Some(document_id) => Ok(document_id), + None => Err(SerializerError::DocumentIdNotFound) + } + } +} + +pub struct FindDocumentIdStructSerializer<'a> { + id_attribute_name: &'a str, + document_id: Option, +} + +impl<'a> ser::SerializeStruct for FindDocumentIdStructSerializer<'a> { + type Ok = DocumentId; + type Error = SerializerError; + + fn serialize_field( + &mut self, + key: &'static str, + value: &T + ) -> Result<(), Self::Error> + where T: Serialize, + { + if self.id_attribute_name == key { + // TODO can it be possible to have multiple ids? + let id = bincode::serialize(value).unwrap(); + let hash = calculate_hash(&id); + self.document_id = Some(DocumentId(hash)); + } + + Ok(()) + } + + fn end(self) -> Result { + match self.document_id { + Some(document_id) => Ok(document_id), + None => Err(SerializerError::DocumentIdNotFound) + } + } +} diff --git a/src/database/serde/indexer_serializer.rs b/src/database/serde/indexer_serializer.rs new file mode 100644 index 000000000..bfb0118ed --- /dev/null +++ b/src/database/serde/indexer_serializer.rs @@ -0,0 +1,188 @@ +use crate::database::update::UnorderedPositiveBlobBuilder; +use crate::database::schema::SchemaAttr; +use crate::database::serde::SerializerError; +use crate::tokenizer::TokenizerBuilder; +use crate::tokenizer::Token; +use crate::{DocumentId, DocIndex, Attribute, WordArea}; + +use serde::Serialize; +use serde::ser; + +pub struct IndexerSerializer<'a, B> { + pub tokenizer_builder: &'a B, + pub builder: &'a mut UnorderedPositiveBlobBuilder, Vec>, + pub document_id: DocumentId, + pub attribute: SchemaAttr, +} + +impl<'a, B> ser::Serializer for IndexerSerializer<'a, B> +where B: TokenizerBuilder +{ + type Ok = (); + type Error = SerializerError; + type SerializeSeq = ser::Impossible; + type SerializeTuple = ser::Impossible; + type SerializeTupleStruct = ser::Impossible; + type SerializeTupleVariant = ser::Impossible; + type SerializeMap = ser::Impossible; + type SerializeStruct = ser::Impossible; + 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, v: &str) -> Result { + for Token { word, word_index, char_index } in self.tokenizer_builder.build(v) { + // FIXME must u32::try_from instead + let attribute = match Attribute::new(self.attribute.0, word_index as u32) { + Ok(attribute) => attribute, + Err(_) => return Ok(()), + }; + + // FIXME must u16/u32::try_from instead + let word_area = match WordArea::new(char_index as u32, word.len() as u16) { + Ok(word_area) => word_area, + Err(_) => return Ok(()), + }; + + let doc_index = DocIndex { + document_id: self.document_id, + attribute, + word_area + }; + + // insert the exact representation + let word_lower = word.to_lowercase(); + + // and the unidecoded lowercased version + let word_unidecoded = unidecode::unidecode(word).to_lowercase(); + if word_lower != word_unidecoded { + self.builder.insert(word_unidecoded, doc_index); + } + + self.builder.insert(word_lower, doc_index); + } + Ok(()) + } + + fn serialize_bytes(self, _v: &[u8]) -> Result { + Err(SerializerError::UnserializableType { name: "&[u8]" }) + } + + fn serialize_none(self) -> Result { + Err(SerializerError::UnserializableType { name: "Option" }) + } + + fn serialize_some(self, _value: &T) -> Result + where T: Serialize, + { + Err(SerializerError::UnserializableType { name: "Option" }) + } + + fn serialize_unit(self) -> Result { + Err(SerializerError::UnserializableType { name: "()" }) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result { + Err(SerializerError::UnserializableType { name: "unit struct" }) + } + + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str + ) -> Result + { + Err(SerializerError::UnserializableType { 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 { name: "newtype variant" }) + } + + fn serialize_seq(self, _len: Option) -> Result { + Err(SerializerError::UnserializableType { name: "seq" }) + } + + fn serialize_tuple(self, _len: usize) -> Result { + Err(SerializerError::UnserializableType { name: "tuple" }) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize + ) -> Result + { + Err(SerializerError::UnserializableType { name: "tuple struct" }) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize + ) -> Result + { + Err(SerializerError::UnserializableType { name: "tuple variant" }) + } + + fn serialize_map(self, _len: Option) -> Result { + Err(SerializerError::UnserializableType { name: "map" }) + } + + fn serialize_struct( + self, + _name: &'static str, + _len: usize + ) -> Result + { + Err(SerializerError::UnserializableType { name: "struct" }) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize + ) -> Result + { + Err(SerializerError::UnserializableType { name: "struct variant" }) + } +} diff --git a/src/database/serde/key_to_string.rs b/src/database/serde/key_to_string.rs new file mode 100644 index 000000000..2fe0c5a39 --- /dev/null +++ b/src/database/serde/key_to_string.rs @@ -0,0 +1,146 @@ +use serde::Serialize; +use serde::ser; + +use crate::database::serde::SerializerError; + +pub struct KeyToStringSerializer; + +impl ser::Serializer for KeyToStringSerializer { + type Ok = String; + type Error = SerializerError; + type SerializeSeq = ser::Impossible; + type SerializeTuple = ser::Impossible; + type SerializeTupleStruct = ser::Impossible; + type SerializeTupleVariant = ser::Impossible; + type SerializeMap = ser::Impossible; + type SerializeStruct = ser::Impossible; + 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 { + Ok(value.to_string()) + } + + fn serialize_bytes(self, _v: &[u8]) -> Result { + Err(SerializerError::UnserializableType { name: "&[u8]" }) + } + + fn serialize_none(self) -> Result { + Err(SerializerError::UnserializableType { name: "Option" }) + } + + fn serialize_some(self, _value: &T) -> Result + where T: Serialize, + { + Err(SerializerError::UnserializableType { name: "Option" }) + } + + fn serialize_unit(self) -> Result { + Err(SerializerError::UnserializableType { name: "()" }) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result { + Err(SerializerError::UnserializableType { name: "unit struct" }) + } + + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str + ) -> Result + { + Err(SerializerError::UnserializableType { 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 { name: "newtype variant" }) + } + + fn serialize_seq(self, _len: Option) -> Result { + Err(SerializerError::UnserializableType { name: "sequence" }) + } + + fn serialize_tuple(self, _len: usize) -> Result { + Err(SerializerError::UnserializableType { name: "tuple" }) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize + ) -> Result + { + Err(SerializerError::UnserializableType { name: "tuple struct" }) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize + ) -> Result + { + Err(SerializerError::UnserializableType { name: "tuple variant" }) + } + + fn serialize_map(self, _len: Option) -> Result { + Err(SerializerError::UnserializableType { name: "map" }) + } + + fn serialize_struct( + self, + _name: &'static str, + _len: usize + ) -> Result + { + Err(SerializerError::UnserializableType { name: "struct" }) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize + ) -> Result + { + Err(SerializerError::UnserializableType { name: "struct variant" }) + } +} diff --git a/src/database/serde/mod.rs b/src/database/serde/mod.rs new file mode 100644 index 000000000..248c5cf5f --- /dev/null +++ b/src/database/serde/mod.rs @@ -0,0 +1,57 @@ +use std::collections::hash_map::DefaultHasher; +use std::hash::{Hash, Hasher}; +use std::error::Error; +use std::fmt; + +use serde::ser; + +macro_rules! forward_to_unserializable_type { + ($($ty:ident => $se_method:ident,)*) => { + $( + fn $se_method(self, _v: $ty) -> Result { + Err(SerializerError::UnserializableType { name: "$ty" }) + } + )* + } +} + +pub mod find_id; +pub mod key_to_string; +pub mod serializer; +pub mod indexer_serializer; + +pub fn calculate_hash(t: &T) -> u64 { + let mut s = DefaultHasher::new(); + t.hash(&mut s); + s.finish() +} + +#[derive(Debug)] +pub enum SerializerError { + DocumentIdNotFound, + UnserializableType { name: &'static str }, + Custom(String), +} + +impl ser::Error for SerializerError { + fn custom(msg: T) -> Self { + SerializerError::Custom(msg.to_string()) + } +} + +impl fmt::Display for SerializerError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + SerializerError::DocumentIdNotFound => { + write!(f, "serialized document does not have an id according to the schema") + } + SerializerError::UnserializableType { name } => { + write!(f, "Only struct and map types are considered valid documents and + can be serialized, not {} types directly.", name) + }, + SerializerError::Custom(s) => f.write_str(&s), + } + } +} + +impl Error for SerializerError {} diff --git a/src/database/serde/serializer.rs b/src/database/serde/serializer.rs new file mode 100644 index 000000000..d2faed2db --- /dev/null +++ b/src/database/serde/serializer.rs @@ -0,0 +1,289 @@ +use std::collections::BTreeMap; + +use serde::Serialize; +use serde::ser; + +use crate::database::serde::indexer_serializer::IndexerSerializer; +use crate::database::serde::key_to_string::KeyToStringSerializer; +use crate::database::update::UnorderedPositiveBlobBuilder; +use crate::database::document_key::DocumentKeyAttr; +use crate::database::update::NewState; +use crate::database::Schema; +use crate::database::serde::SerializerError; +use crate::tokenizer::TokenizerBuilder; +use crate::DocumentId; + +pub struct Serializer<'a, B> { + pub schema: &'a Schema, + pub tokenizer_builder: &'a B, + pub document_id: DocumentId, + pub builder: &'a mut UnorderedPositiveBlobBuilder, Vec>, + pub new_states: &'a mut BTreeMap, +} + +impl<'a, B> ser::Serializer for Serializer<'a, B> +where B: TokenizerBuilder +{ + type Ok = (); + type Error = SerializerError; + type SerializeSeq = ser::Impossible; + type SerializeTuple = ser::Impossible; + type SerializeTupleStruct = ser::Impossible; + type SerializeTupleVariant = ser::Impossible; + type SerializeMap = MapSerializer<'a, B>; + type SerializeStruct = StructSerializer<'a, B>; + 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, _v: &str) -> Result { + Err(SerializerError::UnserializableType { name: "str" }) + } + + fn serialize_bytes(self, _v: &[u8]) -> Result { + Err(SerializerError::UnserializableType { name: "&[u8]" }) + } + + fn serialize_none(self) -> Result { + Err(SerializerError::UnserializableType { name: "Option" }) + } + + fn serialize_some(self, _value: &T) -> Result + where T: Serialize, + { + Err(SerializerError::UnserializableType { name: "Option" }) + } + + fn serialize_unit(self) -> Result { + Err(SerializerError::UnserializableType { name: "()" }) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result { + Err(SerializerError::UnserializableType { name: "unit struct" }) + } + + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str + ) -> Result + { + Err(SerializerError::UnserializableType { 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 { name: "newtype variant" }) + } + + fn serialize_seq(self, _len: Option) -> Result { + Err(SerializerError::UnserializableType { name: "sequence" }) + } + + fn serialize_tuple(self, _len: usize) -> Result { + Err(SerializerError::UnserializableType { name: "tuple" }) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize + ) -> Result + { + Err(SerializerError::UnserializableType { name: "tuple struct" }) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize + ) -> Result + { + Err(SerializerError::UnserializableType { name: "tuple variant" }) + } + + fn serialize_map(self, _len: Option) -> Result { + Ok(MapSerializer { + schema: self.schema, + tokenizer_builder: self.tokenizer_builder, + document_id: self.document_id, + current_key_name: None, + builder: self.builder, + new_states: self.new_states, + }) + } + + fn serialize_struct( + self, + _name: &'static str, + _len: usize + ) -> Result + { + Ok(StructSerializer { + schema: self.schema, + tokenizer_builder: self.tokenizer_builder, + document_id: self.document_id, + builder: self.builder, + new_states: self.new_states, + }) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize + ) -> Result + { + Err(SerializerError::UnserializableType { name: "struct variant" }) + } +} + +pub struct MapSerializer<'a, B> { + pub schema: &'a Schema, + pub tokenizer_builder: &'a B, + pub document_id: DocumentId, + pub current_key_name: Option, + pub builder: &'a mut UnorderedPositiveBlobBuilder, Vec>, + pub new_states: &'a mut BTreeMap, +} + +impl<'a, B> ser::SerializeMap for MapSerializer<'a, B> +where B: TokenizerBuilder +{ + type Ok = (); + type Error = SerializerError; + + fn serialize_key(&mut self, key: &T) -> Result<(), Self::Error> + where T: Serialize, + { + let key = key.serialize(KeyToStringSerializer)?; + 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(KeyToStringSerializer)?; + + if let Some(attr) = self.schema.attribute(key) { + let props = self.schema.props(attr); + if props.is_stored() { + let value = bincode::serialize(value).unwrap(); + let key = DocumentKeyAttr::new(self.document_id, attr); + self.new_states.insert(key, NewState::Updated { value }); + } + if props.is_indexed() { + let serializer = IndexerSerializer { + builder: self.builder, + tokenizer_builder: self.tokenizer_builder, + document_id: self.document_id, + attribute: attr, + }; + value.serialize(serializer)?; + } + } + + Ok(()) + } + + fn end(self) -> Result { + Ok(()) + } +} + +pub struct StructSerializer<'a, B> { + pub schema: &'a Schema, + pub tokenizer_builder: &'a B, + pub document_id: DocumentId, + pub builder: &'a mut UnorderedPositiveBlobBuilder, Vec>, + pub new_states: &'a mut BTreeMap, +} + +impl<'a, B> ser::SerializeStruct for StructSerializer<'a, B> +where B: TokenizerBuilder +{ + type Ok = (); + type Error = SerializerError; + + fn serialize_field( + &mut self, + key: &'static str, + value: &T + ) -> Result<(), Self::Error> + where T: Serialize, + { + if let Some(attr) = self.schema.attribute(key) { + let props = self.schema.props(attr); + if props.is_stored() { + let value = bincode::serialize(value).unwrap(); + let key = DocumentKeyAttr::new(self.document_id, attr); + self.new_states.insert(key, NewState::Updated { value }); + } + if props.is_indexed() { + let serializer = IndexerSerializer { + builder: self.builder, + tokenizer_builder: self.tokenizer_builder, + document_id: self.document_id, + attribute: attr, + }; + value.serialize(serializer)?; + } + } + + Ok(()) + } + + fn end(self) -> Result { + Ok(()) + } +}