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

Deserialize a Box<[u8]> from an older format as a Arc<str>, but still be able to Deserialize Arc<str> in "new" files? #2506

Closed
fritschy opened this issue Jul 11, 2023 · 4 comments

Comments

@fritschy
Copy link

I have a file format that serialized strings as &[u8]. After learning more this seems cumbersome and complicates things down the line. So I would like to change the format to instead contain (effectively) String but still be able to read older files which will contain byte sequences instead of strings.

Is it possible to use a field attribute to accomplish this?

@oli-obk
Copy link
Member

oli-obk commented Jul 12, 2023

Do you mean something like

struct Foo {
   my_thing: StringOrBytes,
}
enum StringOrBytes {
    String(Arc<str>),
    Bytes(Box<[u8]>),
}

In that case, i believe you should be able to use #[serde(untagged)] on the enum.

@fritschy
Copy link
Author

This is nearly what I had in mind - but having to discriminate String of Bytes is not what I wanted.

I did however find the docs on #[serde(untagged)] - is it possible to override the default deserializer for one field and do what untagged does here? That is deserialize the following field but trying out String (Arc<str>) and if it fails Vec<u8> (that is Box<[u8]>)? I should add, if the data is a u8 sequence, this is just a String in bytes form.

@Mingun
Copy link
Contributor

Mingun commented Jul 12, 2023

I think, that you just need to write your function for use with #[serde(deserialize_with)]. Implement a visitor that will accept visit_bytes & Co. and visit_str & Co. and produce Arc<str>, something like:

impl Visitor for MyVisitor {
  type Value = Arc<str>;

  fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
  where
    E: Error
  {
    Arc::new(str::from_utf8(v)?)
  }
  fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
  where
    E: Error
  {
    Arc::new(v)
  }
}

@fritschy
Copy link
Author

@Mingun THIS was the hint I needed! Thank you for pointing me in the right direction.

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

No branches or pull requests

3 participants