flatbuffers icon indicating copy to clipboard operation
flatbuffers copied to clipboard

[Rust] Map key encode as human-readable, but decoded as raw

Open koxu1996 opened this issue 1 year ago • 5 comments

Reproducible example

use std::collections::HashMap;

use serde::{Serialize, Deserialize, Serializer, Deserializer};
use flexbuffers::{self, FlexbufferSerializer, Reader};

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
struct User(String);

impl User {
  fn to_bytes(&self) -> Vec<u8> {
    self.0.clone().into_bytes()
  }

  fn from_bytes(bytes: &[u8]) -> Self {
    User(String::from_utf8_lossy(bytes).into_owned())
  }
}

impl Serialize for User {
  fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
    if serializer.is_human_readable() {
      println!("Serializing as human readable string");
      serializer.serialize_str(&hex::encode(self.to_bytes()))
    } else {
      println!("Serializing as raw bytes");
      serializer.serialize_bytes(&self.to_bytes())
    }
  }
}

impl<'de> Deserialize<'de> for User {
  fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
    if deserializer.is_human_readable() && false {
      println!("Deserializing as human readable string");
      let hex_string = String::deserialize(deserializer)?;
      let bytes = hex::decode(&hex_string).map_err(serde::de::Error::custom)?;
      Ok(User::from_bytes(&bytes))
    } else {
      println!("Deserializing as raw bytes");
      let bytes = <Vec<u8>>::deserialize(deserializer)?;
      Ok(User::from_bytes(&bytes))
    }
  }
}

#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
struct TestStruct {
  map: HashMap<User, u32>,
}

fn main() {
  // Prepare test data.
  let mut map = HashMap::new();
  map.insert(User("john".to_string()), 100);
  let test_struct = TestStruct { map };

  // Serialize using flexbuffers.
  let mut serializer = FlexbufferSerializer::new();
  test_struct.serialize(&mut serializer).unwrap();
  let serialized_data = serializer.take_buffer();

  // Deserialize back.
  let reader = Reader::get_root(serialized_data.as_slice()).unwrap();
  let deserialized_struct = TestStruct::deserialize(reader).expect("Deserialization should not fail");
}

Output

Serializing as human readable string
Deserializing as raw bytes
thread 'main' panicked at src/main.rs:64:61:
Deserialization should not fail: Serde("invalid type: string \"6a6f686e\", expected a sequence")
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

koxu1996 avatar Nov 07 '24 19:11 koxu1996

Key always must be string, so deserializer should use human readble format too (instead of relying on false that is set globally).

koxu1996 avatar Nov 07 '24 19:11 koxu1996

This issue is stale because it has been open 6 months with no activity. Please comment or label not-stale, or this will be closed in 14 days.

github-actions[bot] avatar May 08 '25 20:05 github-actions[bot]

not-stale

koxu1996 avatar May 09 '25 15:05 koxu1996

This issue is stale because it has been open 6 months with no activity. Please comment or label not-stale, or this will be closed in 14 days.

github-actions[bot] avatar Nov 08 '25 20:11 github-actions[bot]

Not stale!

koxu1996 avatar Nov 12 '25 14:11 koxu1996

@fawdlstty or @Muon if either of you want to take a stab at this one, feel free :D

jtdavis777 avatar Dec 14 '25 00:12 jtdavis777

if deserializer.is_human_readable() && false {

This means that the condition is always false.

fawdlstty avatar Dec 14 '25 04:12 fawdlstty