0

I have the following struct:


#[derive(Serialize, Deserialize)]
pub(crate) struct Item {
    pub id: u32,
    pub path: Vec<u8>
}

impl Item {
    pub fn path_as_str(&self) -> String {
        return GBK.decode(self.path.as_slice(), DecoderTrap::Strict).unwrap();
    }
}

I have to read some binary files and parse them into this struct, I'm using bincode2 for it, and it works great, the problem is that once I have these items, I need to save them in a json format in another file, the problem is that path is a UTF-16 String stored as raw bytes in the binary file, an I need it as a String in the json file, I've managed to do it by implementing the path_as_str method and generating the json manually, but it's not ideal since I need to do this for multiple data structures and this operation needs to be done in a reverse order as well, Binary -> Json and Json -> Binary, I've tried to play around with custom Serializers, but I can't find a way make it work. For instance, how do I know from the serialize method that I'm serializing from a json file and not from the binary? Is it even possibile? I've read this answer but it doesn't seem to work as of now.

I'm new to rust, and as of now, I'm just looking for the right tool that suits better my needs for this project, I've done it in javascript, but I don't exactly trust javascript for the job since I'll need to deal with very low level bitwise operations.

Here is an example of the custom WString type that I was trying to implement:

use std::{fmt};

use encoding::{all::GBK, Encoding, DecoderTrap, EncoderTrap};
use serde::{Deserialize, Serialize, Serializer, de::{self, Visitor}, Deserializer};

#[derive(Debug)]
pub struct WString(Vec<u8>);

impl Serialize for WString {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
    S: Serializer,
    {
      // From here HOW can I know if I'am serializing to a json or to a binary file

      let gbkValue = GBK.encode(self.0, EncoderTrap::Strict).unwrap();
      return serializer.serialize_str(gbkValue);
    }
}


impl<'de> Deserialize<'de> for WString {
  fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
      where
          D: Deserializer<'de>
  {
    // From here HOW can I know if I'm deserializing from a string or from the binary file?
    deserializer.deserialize_string(WStringVisitor)
  }
}

struct WStringVisitor;

impl<'de> Visitor<'de> for WStringVisitor {
    type Value = WString;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("Expected a string")
    }

    fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
        where
            E: de::Error,
        {
          let gbkValue = GBK.decode(value.as_bytes(), DecoderTrap::Strict).unwrap();
          Ok(WString(gbkValue))
        }
}
Leo Letto
  • 1,774
  • 1
  • 12
  • 17
  • See also https://serde.rs/field-attrs.html#with – E_net4 Apr 13 '23 at 10:01
  • Store the path as `String` in your code, then implement a (De-)Serializer for your custom format, it's not `bincode2` because that would store strings as utf-8 so you can't use it. You're trying to use bincode2 for something that it wasn't designed for (reading non bincode encoded data). – cafce25 Apr 13 '23 at 10:04
  • That binary files are legacy files that I have to deal with, the point is that I need to tell "If I'm deserializing from the binary file that I'll read it as a vector and convert it to a string, but if I'm reading from the json, I just need to read the string" – Leo Letto Apr 13 '23 at 10:06
  • The other way around is "If I'm serializing to a json file, then I need to keep it as string, instead if I'm serializing to a binary file, that I need to convert it to a vector" – Leo Letto Apr 13 '23 at 10:07
  • Yes, so as I told you, you have to write a custom (De-)Serializer for your custom legacy format. Or do you need file type detection with it? That's not really what serde does. – cafce25 Apr 13 '23 at 10:08
  • I have tried a custom de/serializer, but from within the custom serialize method, how can I determinate the source/target of my serialization? On the question that I linked someone had a similar problem – Leo Letto Apr 13 '23 at 10:11
  • The custom [`Serializer`](https://docs.rs/serde/1.0.160/serde/trait.Serializer.html) (with r at the end) only serializes your custom format. Are you mixing it up with a custom [`Serialize`](https://docs.rs/serde/1.0.160/serde/trait.Serialize.html) (note missing r) implementation? – cafce25 Apr 13 '23 at 10:13
  • I've added the custom serialization for a WString type that I was trying to implement – Leo Letto Apr 13 '23 at 10:21
  • `Serialize` is the wrong place to care for format differences. – cafce25 Apr 13 '23 at 10:24
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/253128/discussion-between-leo-letto-and-cafce25). – Leo Letto Apr 13 '23 at 10:27

0 Answers0