use hashbrown::HashSet;
use std::collections::BTreeMap;
use crate::adt::{AdtMetadata, FieldPosition};
use crate::deserializer::InputRegion;
use crate::evolution::SerializedEvolutionStep;
use crate::{BinaryDeserializer, BinaryInput, DeserializationContext, Error, Result};
pub struct AdtDeserializer<'a, 'b, 'c, const V: usize> {
metadata: &'a AdtMetadata,
context: &'b mut DeserializationContext<'c>,
last_index_per_chunk: Option<[i8; V]>,
stored_version: u8,
made_optional_at: Option<BTreeMap<FieldPosition, u8>>,
removed_fields: Option<HashSet<String>>,
inputs: Option<Vec<InputRegion>>,
}
impl<'a, 'b, 'c, const V: usize> AdtDeserializer<'a, 'b, 'c, V> {
pub fn new_v0(
metadata: &'a AdtMetadata,
context: &'b mut DeserializationContext<'c>,
) -> Result<Self> {
Ok(Self {
metadata,
context,
last_index_per_chunk: None,
stored_version: 0,
made_optional_at: None,
removed_fields: None,
inputs: None,
})
}
pub fn new(
metadata: &'a AdtMetadata,
context: &'b mut DeserializationContext<'c>,
stored_version: u8,
) -> Result<Self> {
let mut serialized_evolution_steps = Vec::with_capacity(stored_version as usize + 1);
for _ in 0..=stored_version {
let serialized_evolution_step = SerializedEvolutionStep::deserialize(context)?;
serialized_evolution_steps.push(serialized_evolution_step);
}
let mut inputs = Vec::with_capacity(serialized_evolution_steps.len());
let mut made_optional_at = BTreeMap::new();
let mut removed_fields = HashSet::new();
for (idx, serialized_evolution_step) in serialized_evolution_steps.iter().enumerate() {
match serialized_evolution_step {
SerializedEvolutionStep::FieldAddedToNewChunk { size } => {
let start = context.pos();
context.skip(*size as usize)?;
inputs.push(InputRegion::new(start, *size as usize));
}
SerializedEvolutionStep::FieldMadeOptional { position } => {
made_optional_at.insert(*position, idx as u8);
inputs.push(InputRegion::empty());
}
SerializedEvolutionStep::FieldRemoved { field_name } => {
removed_fields.insert(field_name.clone());
inputs.push(InputRegion::empty());
}
_ => {
inputs.push(InputRegion::empty());
}
}
}
Ok(Self {
metadata,
context,
last_index_per_chunk: if made_optional_at.is_empty() {
None
} else {
Some([-1i8; V])
},
stored_version,
made_optional_at: if made_optional_at.is_empty() {
None
} else {
Some(made_optional_at)
},
removed_fields: if removed_fields.is_empty() {
None
} else {
Some(removed_fields)
},
inputs: if inputs.is_empty() {
None
} else {
Some(inputs)
},
})
}
pub fn read_field<T: BinaryDeserializer>(
&mut self,
field_name: &str,
field_default: Option<T>,
) -> Result<T> {
if self
.removed_fields
.as_ref()
.map(|f| f.contains(field_name))
.unwrap_or(false)
{
Err(Error::FieldRemovedInSerializedVersion(
field_name.to_string(),
))
} else {
let chunk = *self
.metadata
.field_generations
.get(field_name)
.unwrap_or(&0);
let field_position = self.record_field_index(chunk);
if self.stored_version < chunk {
match field_default {
Some(value) => Ok(value),
None => Err(Error::FieldWithoutDefaultValueIsMissing(
field_name.to_string(),
)),
}
} else {
let mut has_inputs = false;
if let Some(inputs) = self.inputs.as_mut() {
self.context.push_region(inputs[chunk as usize]);
has_inputs = true;
}
let result = if self
.made_optional_at
.as_ref()
.map(|m| m.contains_key(&field_position))
.unwrap_or(false)
{
let is_defined = bool::deserialize(self.context)?;
if is_defined {
T::deserialize(self.context)
} else {
Err(Error::NonOptionalFieldSerializedAsNone(
field_name.to_string(),
))
}
} else {
T::deserialize(self.context)
};
if has_inputs {
self.inputs.as_mut().unwrap()[chunk as usize] = self.context.pop_region();
}
result
}
}
}
pub fn read_optional_field<T: BinaryDeserializer>(
&mut self,
field_name: &str,
field_default: Option<Option<T>>,
) -> Result<Option<T>> {
if self
.removed_fields
.as_ref()
.map(|f| f.contains(field_name))
.unwrap_or(false)
{
Ok(None)
} else {
let chunk = *self
.metadata
.field_generations
.get(field_name)
.unwrap_or(&0);
let opt_since = *self.metadata.made_optional_at.get(field_name).unwrap_or(&0);
self.record_field_index(chunk);
if self.stored_version < chunk {
match field_default {
Some(default_value) => Ok(default_value),
None => Err(Error::DeserializationFailure(format!(
"Field {field_name} is not in the stream and does not have a default value"
))),
}
} else {
let mut has_inputs = false;
if let Some(inputs) = self.inputs.as_mut() {
self.context.push_region(inputs[chunk as usize]);
has_inputs = true;
}
let result = if self.stored_version < opt_since {
Ok(Some(T::deserialize(self.context)?))
} else {
Option::<T>::deserialize(self.context)
};
if has_inputs {
self.inputs.as_mut().unwrap()[chunk as usize] = self.context.pop_region();
}
result
}
}
}
fn record_field_index(&mut self, chunk: u8) -> FieldPosition {
if let Some(last_index_per_chunk) = self.last_index_per_chunk.as_mut() {
let last_index = &mut last_index_per_chunk.as_mut()[chunk as usize];
let new_index = *last_index + 1;
let fp = FieldPosition::new(chunk, new_index as u8);
*last_index = new_index;
fp
} else {
FieldPosition::EMPTY
}
}
pub fn read_constructor_idx(&mut self) -> Result<u32> {
self.context.read_var_u32()
}
}