#silkroad #serde #serde-derive #serialization #deserialize #macro #skrillax-serde

skrillax-serde-derive

为结构体自动实现序列化和反序列化宏

2 个版本

0.1.1 2024年4月28日
0.1.0 2024年4月21日

#9 in #silkroad


3 个crate中使用(通过skrillax-serde

MIT 许可证

41KB
862

skrillax-serde-derive

这是一个实现来自skrillax-serdeSerializeDeserializeByteSize的宏,用于给定的类型。有关示例和文档,请查看模块文档。您还可以查看宏测试目录中的测试。


lib.rs:

通常,只需在代码中添加#[derive](或您需要的任何特质)即可。就像更通用的serdecrate一样,这会处理大多数常见情况,包括不同类型的字段,以及其他结构的引用。但是,有一些需要注意的事项。Silkroad Online数据包不是自描述的,因此我们通常需要提供一些帮助来序列化和反序列化某些类型的数据。通常,您可以通过添加#[silkroad]标签来提供额外的选项。以下章节将解释哪些选项适用于哪些元素。

枚举

枚举通常被序列化为一个字节的区分符,其后是该变体的内容,不包含其他细节。目前,我们不会自动将枚举变体的索引映射到区分符。因此,您需要手动定义一个值。这可以通过使用以下代码来完成:#[silkroad(value = 1)]来设置变体的字节值为1

#[derive(Serialize, Deserialize)]
enum Hello {
    #[silkroad(value = 1)]
    ClientHello(String),
    #[silkroad(value = 2)]
    ServerHello(String)
}

在某些情况下,可能需要区分符为两个字节宽,您可以通过在枚举本身上使用#[silkroad(size = 2)]来指定。

#[derive(Serialize, Deserialize)]
#[silkroad(size = 2)]
enum Hello {
    #[silkroad(value = 0x400D)]
    ClientHello(String)
}

结构体

结构体始终通过序列化和反序列化其字段来进行序列化和反序列化。因此,单元结构体的长度为零。目前还没有选项可以改变结构体的行为,只能改变其字段的行为。

#[derive(Serialize, Deserialize)]
struct Hello(String);

字段

字段之间的序列化和反序列化在结构体和枚举中是相同的。每个字段依次序列化,没有分隔符。因此,需要与消耗的字节数完全匹配。字段按定义的顺序进行序列化和反序列化。

#[derive(Serialize, Deserialize)]
struct Hello {
    one_byte: u8,
    two_bytes: u16
}

集合

集合(例如向量)使用一个字节的长度来编码,然后是集合的元素,没有分隔符。如果大小较大,则需要使用#[silkroad(size = 2)]属性来表示。

#[derive(Serialize, Deserialize)]
struct Hello {
    #[silkroad(size = 2)]
    greetings: Vec<String>
}

默认大小为1,支持的最大大小为4。此外,您可以使用list_type属性更改集合的编码类型。该属性接受三种选项之一:length(默认),breakhas-morebreakhas-more指定每个元素之前是否还有其他元素,使用不同的值。其中break使用1表示'有更多值',而2表示完成,而has-more使用1表示还有更多元素,而0表示完成。

#[derive(Serialize, Deserialize)]
struct Hello {
    #[silkroad(list_type = "break")]
    greetings: Vec<String>
}

字符串

通常使用两个字节长度来编码字符串,然后是字符串的UTF-8表示。然而,在某些情况下,Silkroad使用两个字节的宽字符(UTF-16)在字符串中。这可以通过使用大小为2的size来配置。

#[derive(Serialize, Deserialize)]
struct Hello {
    #[silkroad(size = 2)]
    greeting: String
}

可选

可选值将使用一个字节表示存在(1)或不存在(0),如果存在,则跟在基本值后面。在某些情况下,由于先前的知识,可选值可能仅出现(或缺失)而不使用存在指示符。这使得它们无法反序列化(目前),但遗憾的是这是必要的。为了实现这一点,您可以将字段的大小设置为0。

#[derive(Serialize)]
struct Hello {
    #[silkroad(size = 0)]
    greeting: Option<String>
}

如果数据中表明值是否存在,则可以使用 when 属性来指定条件。在这种情况下,存在字节将被省略,但使得反序列化成为可能。这不会进行任何序列化检查,并且始终附加一个存在的值,忽略条件。在 when 中的条件应表示一个返回布尔值的表达式,表示值是否存在于数据包中。可以访问任何先前的值,但目前限于没有导入的表达式。

#[derive(Deserialize, Serialize)]
struct Hello {
    condition: u8
    #[silkroad(when = "condition == 1")]
    greeting: Option<String>
}

依赖关系

~0.7–1.1MB
~25K SLoC