Skip to content
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

Make Serialize* traits public #102

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

oscartbeaumont
Copy link

I am working on a library that I would like the library to remain format-agnostic. To do this I am using erased-serde to "inject" the format at runtime as a &mut dyn Serializer.

In my library the user defines a schema which looks something like this and the resolve function would be implemented by them:

pub struct Schema {
   types: Vec<Type>
}

pub struct Type {
   name: Cow<'static, str>,
   resolve: Box<dyn Fn(Serializer)> // `Serializer` is shown in the next code snippet
}

As discussed in #39 erased-serde isn't something that should be in the public API so I am wrapping all of its types. This also has the added side-effect that I can require self instead of &mut self for extra type safety.

An example of what I am doing is below.

pub struct Serializer<'a>(&'a mut dyn erased_serde::Serializer);

impl<'a> Serializer<'a> {
    pub fn serialize_bool(self, value: bool) {
        self.0.erased_serialize_bool(value)
    }
    
    // ...
}

However, right now I can only deal with primitive types as SerializeMap and similar types are private. This PR makes them public so the following code would compile.

pub struct SerializeMap<'a>(&'a mut dyn erased_serde::SerializeMap);

Copy link
Owner

@dtolnay dtolnay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR.

One thing that would need to be figured out before exposing these traits is how errors from the underlying serializer are returned. For example if serialize_map or serialize_entry fails. Thoughts?

@greenboxal
Copy link

greenboxal commented Sep 8, 2024

fwiw, I had to do the following so I could delegate the serialization to a dynamic vtable:

impl<'a> serde::Serialize for Object<'a> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer
    {
        let mut erased = erased_serde::SerializerImpl::new(serializer);

        match (self.0.vtable.serialize)(self, &mut erased) {
            Ok(()) => {}
            Err(err) => {
                let err: erased_serde::ErrorImpl = err.into();

                match err {
                    erased_serde::ErrorImpl::Custom(msg) => return Err(serde::ser::Error::custom(msg)),
                    erased_serde::ErrorImpl::ShortCircuit => {}
                }
            }
        }

        match erased {
            erased_serde::SerializerImpl::Complete(ok) => Ok(ok),
            erased_serde::SerializerImpl::Error(err) => Err(err),
            _ => unreachable!(),
        }
    }
}

This meant I had to copy the serialize fn, and needed a few more types to be public. I can push a PR but I'm also not sure this is the best because of the error handling

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants