【发布时间】:2020-09-12 05:25:33
【问题描述】:
我最近开始处理自定义序列化/反序列化:https://stackoverflow.com/a/63846824/129805
我想将此自定义“字符串”序列化(和 des。)仅用于 JSON 和 RON,而将 #[derive(Serialisation, ... 用于所有二进制序列化,例如 bincode。 (将两个字节的(100, 200) 膨胀到七个或更多字节的"100:200" 是毫无意义的浪费。)
我需要在单个可执行文件中执行此操作,因为服务器/服务器通信将是 bincode 或 protobufs,而客户端/服务器通信将是 JSON。
服务器/服务器和客户端/服务器通信都将使用相同的可序列化结构。即,我希望所有通信都使用一组结构,但它们应该对 JSON/RON 使用自定义序列化,但对 bin/protobufs 使用派生序列化。
我该怎么做?
更新:
这是测试通过的工作代码:
use serde::{Serialize, Serializer, Deserialize, Deserializer};
use serde::de::{self, Visitor, Unexpected};
use std::fmt;
use std::str::FromStr;
use regex::Regex;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord)]
struct DerivedIncline {
rise: u8,
distance: u8,
}
impl DerivedIncline {
pub fn new(rise: u8, distance: u8) -> DerivedIncline {
DerivedIncline {rise, distance}
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
struct StringyIncline {
rise: u8,
distance: u8,
}
impl StringyIncline {
pub fn new(rise: u8, distance: u8) -> StringyIncline {
StringyIncline {rise, distance}
}
}
impl Serialize for StringyIncline {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&format!("{}:{}", self.rise, self.distance))
}
}
struct StringyInclineVisitor;
impl<'de> Visitor<'de> for StringyInclineVisitor {
type Value = StringyIncline;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a colon-separated pair of integers between 0 and 255")
}
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
let re = Regex::new(r"(\d+):(\d+)").unwrap(); // PERF: move this into a lazy_static!
if let Some(nums) = re.captures_iter(s).next() {
if let Ok(rise) = u8::from_str(&nums[1]) { // nums[0] is the whole match, so we must skip that
if let Ok(distance) = u8::from_str(&nums[2]) {
Ok(StringyIncline::new(rise, distance))
} else {
Err(de::Error::invalid_value(Unexpected::Str(s), &self))
}
} else {
Err(de::Error::invalid_value(Unexpected::Str(s), &self))
}
} else {
Err(de::Error::invalid_value(Unexpected::Str(s), &self))
}
}
}
impl<'de> Deserialize<'de> for StringyIncline {
fn deserialize<D>(deserializer: D) -> Result<StringyIncline, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_string(StringyInclineVisitor)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn serialisation() {
let stringy_incline = StringyIncline::new(4, 3);
let derived_incline = DerivedIncline::new(4, 3);
let json = serde_json::to_string(&stringy_incline).unwrap();
assert_eq!(json, "\"4:3\"");
let bin = bincode::serialize(&derived_incline).unwrap();
assert_eq!(bin, [4u8, 3u8]);
}
#[test]
fn deserialisation() {
let json = "\"4:3\"";
let bin = [4u8, 3u8];
let deserialised_json: StringyIncline = serde_json::from_str(&json).unwrap();
let deserialised_bin: DerivedIncline = bincode::deserialize(&bin).unwrap();
assert_eq!(deserialised_json, StringyIncline::new(4, 3));
assert_eq!(deserialised_bin, DerivedIncline::new(4, 3));
}
}
我想要一个 Incline 结构,当序列化为 JSON 时,它的行为类似于 StringlyIncline,或者当序列化为 bincode 时,它的行为类似于 DerivedIncline。
【问题讨论】:
-
您能否提供一些您可能想要使用的接口的伪代码?
-
感谢您的评论。我已经更新了这个问题。我不想要一个“界面”。我想根据数据被序列化的格式使用不同的序列化或反序列化函数。理想情况下,我想
derive序列化非 JSON 情况,但如有必要,我也可以编写这些函数。 -
我的意思是
interface,就像您可能希望最终使用的 API 一样。很抱歉造成混乱。