//! The one macro every enum here is built with. //! //! `macro_rules!` is textually scoped, so a sibling cannot see it by being a //! sibling: it reaches them through the `pub(super) use` at the bottom of this //! file, and each sibling imports it by name. /// Generate `Display`, `FromStr`, and sqlx `Type`/`Encode`/`Decode` impls /// for a simple enum ↔ string mapping. The sqlx impls delegate to `String` /// so the enum is compatible with any text-like column (TEXT, VARCHAR, etc.). macro_rules! impl_str_enum { ($enum_name:ident { $($variant:ident => $str:literal),+ $(,)? }) => { impl std::fmt::Display for $enum_name { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let s = match self { $( Self::$variant => $str, )+ }; f.write_str(s) } } impl std::str::FromStr for $enum_name { type Err = String; fn from_str(s: &str) -> std::result::Result { match s { $( $str => Ok(Self::$variant), )+ other => Err(format!("invalid {}: {other}", stringify!($enum_name))), } } } // sqlx Type: delegate to String so it's compatible with TEXT/VARCHAR. impl sqlx::Type for $enum_name { fn type_info() -> sqlx::postgres::PgTypeInfo { >::type_info() } fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> bool { >::compatible(ty) } } // sqlx Encode: write the Display string. impl sqlx::Encode<'_, sqlx::Postgres> for $enum_name { fn encode_by_ref( &self, buf: &mut sqlx::postgres::PgArgumentBuffer, ) -> Result> { >::encode(self.to_string(), buf) } } // sqlx Decode: parse the string value via FromStr. impl sqlx::Decode<'_, sqlx::Postgres> for $enum_name { fn decode( value: sqlx::postgres::PgValueRef<'_>, ) -> std::result::Result> { let s = >::decode(value)?; Ok(s.parse::()?) } } // Allow comparison with string slices (useful in Askama templates). impl PartialEq<&str> for $enum_name { fn eq(&self, other: &&str) -> bool { let s: &str = match self { $( Self::$variant => $str, )+ }; s == *other } } impl PartialEq for $enum_name { fn eq(&self, other: &str) -> bool { let s: &str = match self { $( Self::$variant => $str, )+ }; s == other } } impl $enum_name { /// Every wire/DB string this enum maps to, the single source of /// truth for the variant set. For each enum *registered* in the /// enum-drift integration test (`tests/workflows/enum_drift.rs`), /// this set is asserted equal to the Postgres `CHECK (... IN (...))` /// list on its backing column, so a variant added here without /// widening the DB constraint (or vice versa) fails at test time /// rather than at the first read of a poisoned row. Coverage is that /// registry, not every enum automatically: add a `(enum, table, /// column)` row there when a new CHECK-constrained column lands. pub const VARIANTS: &'static [&'static str] = &[$($str),+]; } }; } pub(super) use impl_str_enum;