niklasf/shakmaty

serde serialization and deserialization support

ngerow2025 opened this issue · 5 comments

There is no way to currently encode chess positions from this crate in an efficient way with a binary encoding and serde support would enable this without much trouble. I am willing to implement this through a feature flag with all of the public facing types in the crate.

Hi. The reason why I've been hesitant to add this, is that there's no single best way to implement these traits. For example, for efficient IPC, I'd expect Square::A1 to be serialized as 0. For a public facing JSON API, I'd find "a1" more suitable.

Types do implement common traits like TryFrom, Into, FromStr, and Display. I find serde_with useful to explicitly explicitly choose the format.
For example, serde_with::TryFromInto for round trips via integers, serde_with::DisplayFromStr for round trips via string representations.

Any tricks with which I can de/ser ArrayVec<T, CAP>? I have something like this:

#[derive(Serialize, Deserialize)]
pub struct OrderedSan {
    pub sans: ArrayVec<SanPlus, 128>,
}

arrayvec has serde support but I can't seem to make it integrate with DisplayFromStr.

edit: the following works but not the most ergonomic

#[serde_as]
#[derive(Serialize, Deserialize)]
pub struct SanPlusWrapper {
    #[serde_as(as = "DisplayFromStr")]
    pub sp: SanPlus,
}

#[derive(Serialize, Deserialize)]
pub struct OrderedSan {
    pub sans: ArrayVec<SanPlusWrapper, 128>,
}

More workarounds ... if allocating a Vec is acceptable:

#[serde_as]
#[derive(Serialize)]
struct Example {
    #[serde_as(as = "Vec<DisplayFromStr>")]
    moves: Vec<SanPlus>,
}

Or borrowing to serialize:

#[serde_as]
#[derive(Serialize)]
struct Example<'a> {
    #[serde_as(as = "&[DisplayFromStr]")]
    moves: &'a [SanPlus],
}

I currently have the Vec implementation, was trying to move to arrayvec to see if I could get some perf gains :)

It's because arrayvec does not implement SerialiseAs and DeserialiseAs. I implemented them: bluss/arrayvec@master...kraktus:arrayvec:serde_with
and will try to merge it upstream under the serde or new serde_with feature, but I expect the patch to be rejected. I'll then try to add it as a arrayvec07 feature to serde_with where I've more hope it'll be accepted.

Side note. The SerialiseAs/DeserialiseAs is a type hell and I didn't really understand how it worked but tests pass so should be good.

Working version with the patch. For a binary, using a git dep is fine.

// in Cargo.toml
// arrayvec = { git = "https://github.com/kraktus/arrayvec", branch = "serde_with", features = ["serde"] }
#[serde_as]
#[derive(Serialize, Deserialize)]
pub struct Native {
    #[serde_as(as = "ArrayVec<DisplayFromStr,128>")]
    pub sans: ArrayVec<SanPlus, 128>,
}