use core::marker::PhantomData;
use serde::Serialize;
use serde_reflection::{Format, FormatHolder, Samples, Tracer, Value};
use std::sync::LazyLock;
use crate::{
Internal, IntoKeys, Schema, SerdeError, TreeDeserialize, TreeSchema, TreeSerialize, ValueError,
};
pub fn trace_value(
tracer: &mut Tracer,
samples: &mut Samples,
keys: impl IntoKeys,
value: impl TreeSerialize,
) -> Result<(Format, Value), SerdeError<serde_reflection::Error>> {
let (mut format, sample) = value.serialize_by_key(
keys.into_keys(),
serde_reflection::Serializer::new(tracer, samples),
)?;
format.reduce();
Ok((format, sample))
}
pub fn trace_type_once<'de, T: TreeDeserialize<'de>>(
tracer: &mut Tracer,
samples: &'de Samples,
keys: impl IntoKeys,
) -> Result<Format, SerdeError<serde_reflection::Error>> {
let mut format = Format::unknown();
T::probe_by_key(
keys.into_keys(),
serde_reflection::Deserializer::new(tracer, samples, &mut format),
)?;
format.reduce();
Ok(format)
}
pub fn trace_type<'de, T: TreeDeserialize<'de>>(
tracer: &mut Tracer,
samples: &'de Samples,
keys: impl IntoKeys + Clone,
) -> Result<Format, SerdeError<serde_reflection::Error>> {
loop {
let format = trace_type_once::<T>(tracer, samples, keys.clone())?;
if let Format::TypeName(name) = &format
&& let Some(_reason) = tracer.check_incomplete_enum(name)
{
continue;
}
return Ok(format);
}
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Hash, Serialize)]
pub struct Node<D> {
pub data: D,
pub children: Vec<Node<D>>,
}
impl<D> Node<D> {
pub fn visit<T, E>(
&self,
idx: &mut [usize],
depth: usize,
func: &mut impl FnMut(&[usize], &D) -> Result<T, E>,
) -> Result<T, E> {
if depth < idx.len() {
for (i, c) in self.children.iter().enumerate() {
idx[depth] = i;
c.visit(idx, depth + 1, func)?;
}
}
(*func)(&idx[..depth], &self.data)
}
pub fn visit_mut<T, E>(
&mut self,
idx: &mut [usize],
depth: usize,
func: &mut impl FnMut(&[usize], &mut D) -> Result<T, E>,
) -> Result<T, E> {
if depth < idx.len() {
for (i, c) in self.children.iter_mut().enumerate() {
idx[depth] = i;
c.visit_mut(idx, depth + 1, func)?;
}
}
(*func)(&idx[..depth], &mut self.data)
}
}
impl<L: Default> From<&'static Schema> for Node<(&'static Schema, L)> {
fn from(value: &'static Schema) -> Self {
Self {
data: (value, L::default()),
children: value
.internal
.as_ref()
.map(|internal| match internal {
Internal::Named(n) => n.iter().map(|n| Self::from(n.schema)).collect(),
Internal::Numbered(n) => n.iter().map(|n| Self::from(n.schema)).collect(),
Internal::Homogeneous(n) => vec![Self::from(n.schema)],
})
.unwrap_or_default(),
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct Types<T> {
pub(crate) root: Node<(&'static Schema, Option<Format>)>,
_t: PhantomData<T>,
}
impl<T> Types<T> {
pub fn root(&self) -> &Node<(&'static Schema, Option<Format>)> {
&self.root
}
}
impl<T: TreeSchema> Default for Types<T> {
fn default() -> Self {
Self {
root: Node::from(T::SCHEMA),
_t: PhantomData,
}
}
}
impl<T> Types<T> {
pub fn trace_values(
&mut self,
tracer: &mut Tracer,
samples: &mut Samples,
value: &T,
) -> Result<(), serde_reflection::Error>
where
T: TreeSerialize,
{
let mut idx = vec![0; T::SCHEMA.shape().max_depth];
self.root
.visit_mut(&mut idx, 0, &mut |idx, (schema, format)| {
if schema.is_leaf() {
match trace_value(tracer, samples, idx, value) {
Ok((fmt, _value)) => {
if let Some(f) = format {
f.unify(fmt)?;
} else {
*format = Some(fmt);
}
}
Err(SerdeError::Value(ValueError::Absent | ValueError::Access(_))) => {}
Err(SerdeError::Inner(serde_reflection::Error::Custom(_))) => {}
Err(SerdeError::Inner(e) | SerdeError::Finalization(e)) => Err(e)?,
Err(SerdeError::Value(ValueError::Key(_))) => unreachable!(),
}
}
Ok(())
})
}
pub fn trace_types<'de>(
&mut self,
tracer: &mut Tracer,
samples: &'de Samples,
) -> Result<(), serde_reflection::Error>
where
T: TreeDeserialize<'de>,
{
let mut idx = vec![0; T::SCHEMA.shape().max_depth];
self.root
.visit_mut(&mut idx, 0, &mut |idx, (schema, format)| {
if schema.is_leaf() {
match trace_type::<T>(tracer, samples, idx) {
Ok(fmt) => {
*format = Some(fmt);
}
Err(SerdeError::Value(ValueError::Access(_))) => {}
Err(SerdeError::Inner(serde_reflection::Error::Custom(_))) => {}
Err(SerdeError::Inner(e) | SerdeError::Finalization(e)) => Err(e)?,
Err(SerdeError::Value(ValueError::Absent | ValueError::Key(_))) => {
unreachable!()
}
}
}
Ok(())
})
}
pub fn normalize(&mut self) -> Result<(), serde_reflection::Error>
where
T: TreeSchema,
{
let mut idx = vec![0; T::SCHEMA.shape().max_depth];
self.root
.visit_mut(&mut idx, 0, &mut |_idx, (_schema, format)| {
if let Some(format) = format.as_mut() {
format.normalize()?;
}
Ok(())
})
}
pub fn trace_types_simple<'de>(
&mut self,
tracer: &mut Tracer,
) -> Result<(), serde_reflection::Error>
where
T: TreeDeserialize<'de>,
{
static SAMPLES: LazyLock<Samples> = LazyLock::new(Samples::new);
self.trace_types(tracer, &SAMPLES)
}
}