Skip to content

Make Serializer and Deserializer pub and expose incomplete_enum mechanism #73

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 8 additions & 9 deletions serde-reflection/src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,15 @@ use std::collections::btree_map::{BTreeMap, Entry};
/// `&'a mut` references used to return tracing results.
/// * The lifetime 'de is fixed and the `&'de` reference meant to let us
/// borrow values from previous serialization runs.
pub(crate) struct Deserializer<'de, 'a> {
pub struct Deserializer<'de, 'a> {
tracer: &'a mut Tracer,
samples: &'de Samples,
format: &'a mut Format,
}

impl<'de, 'a> Deserializer<'de, 'a> {
pub(crate) fn new(
tracer: &'a mut Tracer,
samples: &'de Samples,
format: &'a mut Format,
) -> Self {
/// Create a new Deserializer
pub fn new(tracer: &'a mut Tracer, samples: &'de Samples, format: &'a mut Format) -> Self {
Deserializer {
tracer,
samples,
Expand Down Expand Up @@ -422,9 +419,11 @@ impl<'de, 'a> de::Deserializer<'de> for Deserializer<'de, 'a> {
_ => unreachable!(),
};

// If the enum is already marked as incomplete, visit the first index, hoping
// to avoid recursion.
if self.tracer.incomplete_enums.contains_key(enum_name) {
// If the enum is already marked as incomplete and not pending, visit the first index,
// hoping to avoid recursion.
if let Some(EnumProgress::IndexedVariantsRemaining | EnumProgress::NamedVariantsRemaining) =
self.tracer.incomplete_enums.get(enum_name)
{
return visitor.visit_enum(EnumDeserializer::new(
self.tracer,
self.samples,
Expand Down
4 changes: 3 additions & 1 deletion serde-reflection/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,9 @@ mod ser;
mod trace;
mod value;

pub use de::Deserializer;
pub use error::{Error, Result};
pub use format::{ContainerFormat, Format, FormatHolder, Named, Variable, VariantFormat};
pub use trace::{Registry, Samples, Tracer, TracerConfig};
pub use ser::Serializer;
pub use trace::{EnumProgress, Registry, Samples, Tracer, TracerConfig};
pub use value::Value;
5 changes: 3 additions & 2 deletions serde-reflection/src/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ use serde::{ser, Serialize};
/// Serialize a single value.
/// The lifetime 'a is set by the serialization call site and the `&'a mut`
/// references used to return tracing results and serialization samples.
pub(crate) struct Serializer<'a> {
pub struct Serializer<'a> {
tracer: &'a mut Tracer,
samples: &'a mut Samples,
}

impl<'a> Serializer<'a> {
pub(crate) fn new(tracer: &'a mut Tracer, samples: &'a mut Samples) -> Self {
/// Create a new Serializer
pub fn new(tracer: &'a mut Tracer, samples: &'a mut Samples) -> Self {
Self { tracer, samples }
}
}
Expand Down
37 changes: 32 additions & 5 deletions serde-reflection/src/trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,15 @@ pub struct Tracer {
pub(crate) discriminants: BTreeMap<(TypeId, VariantId<'static>), Discriminant>,
}

/// Type of untraced enum variants
#[derive(Copy, Clone, Debug)]
pub(crate) enum EnumProgress {
pub enum EnumProgress {
/// There are variant names that have not yet been traced.
NamedVariantsRemaining,
/// There are variant numbers that have not yet been traced.
IndexedVariantsRemaining,
/// Tracing of further variants is pending.
Pending,
}

#[derive(Eq, PartialEq, Ord, PartialOrd, Debug)]
Expand Down Expand Up @@ -243,6 +246,24 @@ impl Tracer {
Ok((format, value))
}

/// Enable tracing of further variants of a incomplete enum.
///
/// Marks an enum name as pending in the map of incomplete enums
/// and returns which type of variant tracing still needs to be performed.
///
/// Call this in order to (simultaneously):
///
/// * determine whether all variants of an enum have been traced,
/// * determine which type of variant tracing ([`EnumProgress`]) still needs to be
/// performed, and
/// * allow `Deserializer`/`trace_type_once` to make progress on a top level enum by
/// enabling tracing the next variant.
pub fn pend_enum(&mut self, name: &str) -> Option<EnumProgress> {
self.incomplete_enums
.get_mut(name)
.map(|p| std::mem::replace(p, EnumProgress::Pending))
}

/// Same as `trace_type_once` but if `T` is an enum, we repeat the process
/// until all variants of `T` are covered.
/// We accumulate and return all the sampled values at the end.
Expand All @@ -255,9 +276,12 @@ impl Tracer {
let (format, value) = self.trace_type_once::<T>(samples)?;
values.push(value);
if let Format::TypeName(name) = &format {
if let Some(&progress) = self.incomplete_enums.get(name) {
if let Some(progress) = self.pend_enum(name) {
debug_assert!(
!matches!(progress, EnumProgress::Pending),
"failed to make progress tracing enum {name}"
);
// Restart the analysis to find more variants of T.
self.incomplete_enums.remove(name);
if let EnumProgress::NamedVariantsRemaining = progress {
values.pop().unwrap();
}
Expand Down Expand Up @@ -294,9 +318,12 @@ impl Tracer {
let (format, value) = self.trace_type_once_with_seed(samples, seed.clone())?;
values.push(value);
if let Format::TypeName(name) = &format {
if let Some(&progress) = self.incomplete_enums.get(name) {
if let Some(progress) = self.pend_enum(name) {
debug_assert!(
!matches!(progress, EnumProgress::Pending),
"failed to make progress tracing enum {name}"
);
// Restart the analysis to find more variants of T.
self.incomplete_enums.remove(name);
if let EnumProgress::NamedVariantsRemaining = progress {
values.pop().unwrap();
}
Expand Down
Loading