bitflags-serde-legacy 0.1.1

Implement serde traits for bitflags 2.x types compatibly with 1.x.
Documentation
#![no_std]

//! This library is a generic implementation of `Serialize` and `Deserialize` that can be used by
//! any flags type generated by `bitflags!`.
//!
//! # Usage
//!
//! Add `bitflags-serde-legacy` to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies.bitflags_serde_legacy]
//! version = "0.1.1"
//! ```
//!
//! Then, replace an existing `#[derive(Serialize, Deserialize)]` on your `bitflags!`
//! generated types with the following manual implementations:
//!
//! ```
//! use bitflags::bitflags;
//!
//! bitflags! {
//!     // #[derive(Serialize, Deserialize)]
//!     struct Flags: u32 {
//!         const A = 0b00000001;
//!         const B = 0b00000010;
//!         const C = 0b00000100;
//!         const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits();
//!     }
//! }
//!
//! impl serde::Serialize for Flags {
//!     fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
//!         bitflags_serde_legacy::serialize(self, "Flags", serializer)
//!     }
//! }
//!
//! impl<'de> serde::Deserialize<'de> for Flags {
//!     fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
//!         bitflags_serde_legacy::deserialize("Flags", deserializer)
//!     }
//! }
//! ```

use core::fmt;
use serde::{
    de::{Error, MapAccess, Visitor},
    ser::SerializeStruct,
    Deserialize, Deserializer, Serialize, Serializer,
};

use bitflags::Flags;

/// Serialize a flags type equivalently to how `#[derive(Serialize)]` on a flags type
/// from `bitflags` `1.x` would.
pub fn serialize<T: Flags, S: Serializer>(
    flags: &T,
    name: &'static str,
    serializer: S,
) -> Result<S::Ok, S::Error>
where
    T::Bits: Serialize,
{
    let mut serialize_struct = serializer.serialize_struct(name, 1)?;
    serialize_struct.serialize_field("bits", &flags.bits())?;
    serialize_struct.end()
}

/// Deserialize a flags type equivalently to how `#[derive(Deserialize)]` on a flags type
/// from `bitflags` `1.x` would.
pub fn deserialize<'de, T: Flags, D: Deserializer<'de>>(
    name: &'static str,
    deserializer: D,
) -> Result<T, D::Error>
where
    T::Bits: Deserialize<'de>,
{
    struct BitsVisitor<T>(core::marker::PhantomData<T>);

    impl<'de, T: Deserialize<'de>> Visitor<'de> for BitsVisitor<T> {
        type Value = T;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a primitive bitflags value wrapped in a struct")
        }

        fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
            let mut bits = None;

            struct Field;

            impl<'de> Deserialize<'de> for Field {
                fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
                    struct FieldVisitor;

                    impl<'de> Visitor<'de> for FieldVisitor {
                        type Value = Field;

                        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                            formatter.write_str("field identifier")
                        }

                        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
                        where
                            E: Error,
                        {
                            match v {
                                "bits" => Ok(Field),
                                field => Err(E::unknown_field(field, &["bits"])),
                            }
                        }
                    }

                    deserializer.deserialize_identifier(FieldVisitor)
                }
            }

            while map.next_key::<Field>()?.is_some() {
                if bits.is_some() {
                    return Err(Error::duplicate_field("bits"));
                }

                bits = Some(map.next_value()?);
            }

            bits.ok_or_else(|| Error::missing_field("bits"))
        }
    }

    let bits = deserializer.deserialize_struct(name, &["bits"], BitsVisitor(Default::default()))?;

    Ok(T::from_bits_retain(bits))
}

#[cfg(test)]
mod tests {
    bitflags1::bitflags! {
        #[derive(serde_derive::Serialize, serde_derive::Deserialize)]
        struct Flags1: u32 {
            const A = 0b00000001;
            const B = 0b00000010;
            const C = 0b00000100;
            const ABC = Self::A.bits | Self::B.bits | Self::C.bits;
        }
    }

    bitflags::bitflags! {
        #[derive(Debug, PartialEq, Eq)]
        struct Flags2: u32 {
            const A = 0b00000001;
            const B = 0b00000010;
            const C = 0b00000100;
            const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits();
        }
    }

    impl serde::Serialize for Flags2 {
        fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
            crate::serialize(self, "Flags1", serializer)
        }
    }

    impl<'de> serde::Deserialize<'de> for Flags2 {
        fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
            crate::deserialize("Flags1", deserializer)
        }
    }

    #[test]
    fn serde_compat() {
        use serde_test::{assert_tokens, Configure as _, Token::*};

        let expected = &[
            Struct {
                name: "Flags1",
                len: 1,
            },
            Str("bits"),
            U32(0b00000010),
            StructEnd,
        ];

        assert_tokens(&(Flags1::B).readable(), expected);
        assert_tokens(&(Flags2::B).readable(), expected);

        assert_tokens(&(Flags1::B).compact(), expected);
        assert_tokens(&(Flags2::B).compact(), expected);
    }
}