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)) } } 
10
  • See also serde.rs/field-attrs.html#with Commented Apr 13, 2023 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). Commented Apr 13, 2023 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" Commented Apr 13, 2023 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" Commented Apr 13, 2023 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. Commented Apr 13, 2023 at 10:08

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.