Serbia

docs.rs badge crates.io badge Build Status

Serde big arrays. An attribute macro to make (de)serializing big arrays painless, roughly following a design proposed by David Tolnay.

Why?

I saw the idea in request-for-implementation. Then I came up with the name.

The name was too good. I had to do it. Don't judge me.

Also: Serbia has some tasty food.

But what is it for?

Serde only implements Serialize/Deserialize for arrays of length up to 32. This is due to Rust's current limitation - we can't be generic over array length, so an arbitrary upper limit was chosen and implementations were generated only up to it.

The crate provides a macro that generates all the code you need to (de)serialize arrays bigger than that.

Status

Under development, but functional. Let me know what's missing or broken!

Usage

Just slap #[serbia] on top of your type definition. Structs and enums both work!

```rust use serbia::serbia;

[serbia]

[derive(Serialize, Deserialize)]

struct S { arrbig: [u8; 300], // custom serialize/deserialize code generated here arrsmall: [u8; 8], // no custom code - this is handled by Serde fine }

[serbia]

[derive(Serialize, Deserialize)]

enum E { ArrBig([u8; 300]), ArrSmall([u8; 22]), Mixed([u8; 8], [i32; 44], String), } ```

If Serbia sees an array length given as a constant, it will generate custom serialize/deserialize code by default, without inspecting whether the constant is larger than 32 or not. This is a limitation of macros.

```rust const BUFSIZE: usize = 22;

[serbia]

[derive(Serialize, Deserialize)]

struct S { arr: [i32; BUFSIZE], // custom serialize/deserialize code generated here foo: String, } ```

Skipping fields

If for some reason you don't want Serbia to generate custom serialize/deserialize code for a field that it would normally handle, you can skip it.

```rust const BUFSIZE: usize = 24;

[serbia]

[derive(Serialize, Deserialize)]

struct S { #[serbia(skip)] arra: [u8; BUFSIZE], arrb: [u8; 42], arr_small: [u8; 8], } ```

It's possible to be more granular if needed for some reason.

```rust const BUFSIZE: usize = 24;

[serbia]

[derive(Serialize, Deserialize)]

struct S { #[serbia(skipserializing, skipdeserializing)] arra: [u8; BUFSIZE], arrb: [u8; 42], arr_small: [u8; 8], } ```

Manual array length

You can use the #[serbia(bufsize = ... )] option to set an array length for a field. This can be useful to make type aliases work. Constants work here!

```rust type BigArray = [i32; 300];

[serbia]

[derive(Serialize, Deserialize)]

struct S { #[serbia(bufsize = 300)] arr_a: BigArray, foo: String, } ```

```rust const BUFSIZE: usize = 300; type BigArray = [i32; BUFSIZE];

[serbia]

[derive(Serialize, Deserialize)]

struct S { #[serbia(bufsize = "BUFSIZE")] arr_a: BigArray, foo: String, } ```

Interaction with Serde field attributes

Serbia detects when certain Serde field attributes are used and avoids generating code that would cause a conflict, instead yielding to Serde.

rust #[serbia] #[derive(Debug, Serialize, Deserialize, PartialEq)] struct S { big_arr: [u8; 40], // serbia generates code for this #[serde(serialize_with="ser", deserialize_with="de")] bigger_arr: [u8; 42], // serbia ignores this in favor of the (de)serializers you provided }

Serbia is intended to play nice with Serde field attributes. If there are problems, please create an issue or submit a PR!

What doesn't work

Nested types.

```rust

[serbia]

[derive(Debug, Serialize, Deserialize, PartialEq)]

struct S { big_arr: Option<[u8; 300]>, // no code generated for this nested array } ```

Serbia doesn't yet pick up on Serde variant attributes, so there might be conflicts there. This can probably be worked around by using #[serbia(skip)] on each field that Serbia would try to generate custom (de)serialization code for.