Rust 如何仅为“使用自定义序列化”;";连载?

Rust 如何仅为“使用自定义序列化”;";连载?,rust,serde,Rust,Serde,我最近已经开始处理自定义序列化/反序列化: 我只想对JSON和RON使用这种自定义的“stringy”序列化(和des),而对所有二进制序列化(如bincode)使用#[派生(序列化,)。(将两个字节的(100200)膨胀到七个或更多字节的“100:200”是毫无意义的浪费。) 我需要在单个可执行文件中执行此操作,因为服务器/服务器通信将是bincode或protobufs,而客户端/服务器通信将是JSON 服务器/服务器和客户机/服务器通信都将使用相同的可序列化结构。即,我希望所有通信都使用一

我最近已经开始处理自定义序列化/反序列化:

我只想对JSON和RON使用这种自定义的“stringy”序列化(和des),而对所有二进制序列化(如bincode)使用
#[派生(序列化,
)。(将两个字节的
(100200)
膨胀到七个或更多字节的
“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));
    }
}
使用serde::{Serialize,Serializer,Deserialize,Deserializer};
使用serde::de:{self,Visitor,Unexpected};
使用std::fmt;
使用std::str::FromStr;
使用regex::regex;
#[派生(序列化、反序列化、调试、PartialEq、Eq、PartialOrd、Ord)]
结构衍生斜坡{
上升:u8,
距离:u8,
}
impl-derivedden{
新酒吧(上升:u8,距离:u8)->衍生斜坡{
倾斜{上升,距离}
}
}
#[导出(调试、部分Q、等式、部分Ord、Ord)]
StringyCline结构{
上升:u8,
距离:u8,
}
impl StringyCline{
新酒吧(上升:u8,距离:u8)->StringyCline{
弦斜{上升,距离}
}
}
StringyCline的impl序列化{
fn序列化(&self,序列化程序:S)->结果
哪里
S:序列化程序,
{
serializer.serialize_str(&format!(“{}:{}”,self.rise,self.distance))
}
}
StringyInclineVisitor结构;
StringyInclineVisitor的impl{
类型值=StringyCline;
fn预期(&self,格式化程序:&mut fmt::formatter)->fmt::Result{
write_str(“0到255之间以冒号分隔的整数对”)
}
fn访问\u str(self,s:&str)->结果
哪里
E:de::错误,
{
让re=Regex::new(r“(\d+):(\d+)).unwrap();//性能:将其移动到惰性静态中!
如果让一些(nums)=重新捕获{
如果让Ok(上升)=u8::from_str(&nums[1]){//nums[0]是整个匹配,那么我们必须跳过它
如果让Ok(距离)=u8::from_str(&nums[2]){
正常(直线倾斜::新(上升,距离))
}否则{
Err(de::Error::无效的_值(意外的::Str和self))
}
}否则{
Err(de::Error::无效的_值(意外的::Str和self))
}
}否则{
Err(de::Error::无效的_值(意外的::Str和self))
}
}
}
StringyIncline的impl{
fn反序列化(反序列化程序:D)->结果
哪里

D:反序列化器如果您每晚都在使用,并且愿意打开
专门化
功能,您可以编写一个函数,告诉您通用参数
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
  }
}
然后可以执行类似的反序列化操作


如果没有
专门化
功能,我想不出一种方法来让这样的东西工作,所以现在它只限于夜间-但我想看看是否有可能。

你能为你可能想要使用的界面提供一些伪代码吗?谢谢你的评论。我已经更新了这个问题。我不想“接口”。我想根据数据序列化的格式使用不同的序列化或反序列化函数。理想情况下,我希望对非JSON情况进行
派生
序列化,但如果必要,我也可以编写这些函数。我的意思是
接口
,就像您可能希望最终使用的API一样。很抱歉困惑。谢谢,这是一个非常有趣的答案,但我不能使用它,直到每晚
专业化
出来。如果我没有其他好的答案,我将在下周接受。我正在考虑的其他方法是使用板条箱上的功能标志来指定序列化类型(以某种方式导入同一板条箱两次,每一面旗帜一次),或者将
倾斜
一般化为空旗帜特征,以控制使用哪种序列化。这两种方法都没有那么好。
#[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)
        }
    }
}