如何解决如何仅将自定义序列化用于“严格”序列化?
我最近开始使用自定义序列化/反序列化:https://stackoverflow.com/a/63846824/129805
我只想对JSON和RON使用此自定义的“字符串式”序列化(和des),而对所有二进制序列化(例如bincode)使用#[derive(Serialisation,...
。 (将两个字节的(100,200)
夸大到"100:200"
的七个或更多字节是毫无意义的。)
我需要在单个可执行文件中执行此操作,因为服务器/服务器的通信将是bincode或protobufs,而客户端/服务器的通信将是JSON。
服务器/服务器和客户端/服务器通信都将使用相同的可序列化结构。即,我希望所有通信使用单个结构集,但是它们应该对JSON / RON使用自定义序列化,但对bin / probubufs使用派生序列化。
我该怎么做?
更新:
以下是通过测试的有效代码:
use serde::{Serialize,Serializer,Deserialize,Deserializer};
use serde::de::{self,Visitor,Unexpected};
use std::fmt;
use std::str::FromStr;
use regex::Regex;
#[derive(Serialize,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,Ord)]
struct StringyIncline {
rise: 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;当序列化为二进制码时,其行为与DerivedIncline相同。
解决方法
如果您每天晚上使用并愿意打开specialization
功能,则可以编写一个函数来告诉您通用参数S
是否为serde_json::Serializer
trait IsJsonSerializer {
fn is_json_serializer() -> bool;
}
impl<T> IsJsonSerializer for T {
default fn is_json_serializer() -> bool {
false
}
}
impl<W,F> IsJsonSerializer for &mut serde_json::Serializer<W,F> {
fn is_json_serializer() -> bool {
true
}
}
然后,您可以编写if S::is_json_serializer() {...}
。使用此代码,您的序列化功能可以编写为:
#[derive(Serialize,Deserialize,PartialEq,Eq,Debug)]
struct RawIncline {
rise: u8,distance: u8,}
impl Serialize for Incline {
fn serialize<S>(&self,serializer: S) -> Result<S::Ok,S::Error>
where
S: Serializer,{
if S::is_json_serializer() {
serializer.serialize_str(&format!("{}:{}",self.rise,self.distance))
} else {
RawIncline{rise:self.rise,distance:self.distance}.serialize(serializer)
}
}
}
然后您可以对反序列化执行类似的操作。
我想不出没有specialization
功能就可以使类似的东西工作的方法,因此目前仅限于每晚-但我很想知道是否有可能。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。