Skip to content

Comments

Make Serialize* traits public#102

Open
oscartbeaumont wants to merge 1 commit intodtolnay:masterfrom
gurafi:master
Open

Make Serialize* traits public#102
oscartbeaumont wants to merge 1 commit intodtolnay:masterfrom
gurafi:master

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