essence 0.7.0

Essential models and database logic for the Adapt chat platform.
Documentation
#[macro_export]
macro_rules! serde_for_bitflags {
    (@bincode for $t:ty) => {
        #[cfg(feature = "db")]
        impl bincode::Encode for $t {
            fn encode<E: bincode::enc::Encoder>(
                &self,
                encoder: &mut E,
            ) -> Result<(), bincode::error::EncodeError> {
                bincode::Encode::encode(&self.bits(), encoder)
            }
        }

        #[cfg(feature = "db")]
        impl bincode::Decode<()> for $t {
            fn decode<D: bincode::de::Decoder>(
                decoder: &mut D,
            ) -> Result<Self, bincode::error::DecodeError> {
                Self::from_bits(bincode::Decode::decode(decoder)?).ok_or_else(|| {
                    bincode::error::DecodeError::OtherString(
                        "representation contains bits that do not correspond to a flag".to_string(),
                    )
                })
            }
        }
    };
    (@openapi for $t:ty => $format:ident) => {
        #[cfg(feature = "utoipa")]
        impl utoipa::ToSchema<'static> for $t {
            fn schema() -> (&'static str, utoipa::openapi::RefOr<utoipa::openapi::Schema>) {
                (
                    stringify!($t),
                    utoipa::openapi::RefOr::T(
                        utoipa::openapi::ObjectBuilder::new()
                            .schema_type(utoipa::openapi::SchemaType::Integer)
                            .format(Some(utoipa::openapi::SchemaFormat::KnownFormat(
                                utoipa::openapi::KnownFormat::$format,
                            )))
                            .build()
                            .into(),
                    )
                )
            }
        }
    };
    (@serde($repr:ty) $tgt:ty => $openapi_format:ident; $minmax:expr) => {
        impl serde::Serialize for $tgt {
            fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
            where
                S: serde::Serializer,
            {
                self.bits().serialize(serializer)
            }
        }

        impl<'de> serde::Deserialize<'de> for $tgt {
            fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
            where
                D: serde::Deserializer<'de>,
            {
                let raw = <$repr as serde::Deserialize<'de>>::deserialize(deserializer)?;
                let (min, max) = $minmax;

                Self::from_bits(raw).ok_or(serde::de::Error::custom(format!(
                    "invalid bitflags value for {}: {} (expected an integer between {} and {})",
                    stringify!($tgt),
                    raw,
                    min,
                    max,
                )))
            }
        }

        serde_for_bitflags!(@openapi for $tgt => $openapi_format);
        serde_for_bitflags!(@bincode for $tgt);
    };
    (@serde_signed($repr:ty) $tgt:ty => $openapi_format:ident) => {
        serde_for_bitflags!(
            @serde($repr) $tgt => $openapi_format;
            {
                const MAX: $repr = <$tgt>::all().bits();
                if MAX > 0 { (0, MAX) } else { (<$repr>::MIN, <$repr>::MAX) }
            }
        );
    };
    (@serde_unsigned($repr:ty) $tgt:ty => $openapi_format:ident) => {
        serde_for_bitflags!(
            @serde($repr) $tgt => $openapi_format;
            (0, <$tgt>::all().bits())
        );
    };

    (u32: $t:ty) => { serde_for_bitflags!(@serde_unsigned(u32) $t => Int32); };
    (i32: $t:ty) => { serde_for_bitflags!(@serde_signed(i32) $t => Int32); };
    (i16: $t:ty) => { serde_for_bitflags!(@serde_signed(i16) $t => Int32); };
    (i64: $t:ty) => { serde_for_bitflags!(@serde_signed(i64) $t => Int64); };
}