lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

model.rs (71643B)


      1 use core::fmt;
      2 use std::error::Error;
      3 
      4 use serde::{Deserialize, Deserializer, Serialize, Serializer, de, ser};
      5 
      6 use crate::HostError;
      7 
      8 pub const ADMIN_CONTRACT_VERSION: u32 = 1;
      9 pub const ADMIN_OPERATION_ID_MAX_UTF8_BYTES: usize = 128;
     10 pub const ADMIN_CORRELATION_ID_MAX_UTF8_BYTES: usize = 128;
     11 pub const ADMIN_ERROR_CODE_MAX_UTF8_BYTES: usize = 64;
     12 pub const ADMIN_ERROR_MESSAGE_MAX_UTF8_BYTES: usize = 256;
     13 
     14 const UNSUPPORTED_CONTRACT_VERSION_CODE: &str = "unsupported_contract_version";
     15 const UNSUPPORTED_CONTRACT_VERSION_MESSAGE: &str = "admin contract version is unsupported";
     16 
     17 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
     18 pub enum AdminIdentifierField {
     19     OperationId,
     20     CorrelationId,
     21 }
     22 
     23 impl AdminIdentifierField {
     24     const fn maximum_utf8_bytes(self) -> usize {
     25         match self {
     26             Self::OperationId => ADMIN_OPERATION_ID_MAX_UTF8_BYTES,
     27             Self::CorrelationId => ADMIN_CORRELATION_ID_MAX_UTF8_BYTES,
     28         }
     29     }
     30 }
     31 
     32 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
     33 pub enum AdminIdentifierError {
     34     Empty { field: AdminIdentifierField },
     35     TooLong { field: AdminIdentifierField },
     36     InvalidFirstCharacter { field: AdminIdentifierField },
     37     InvalidCharacter { field: AdminIdentifierField },
     38 }
     39 
     40 impl fmt::Display for AdminIdentifierError {
     41     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
     42         formatter.write_str("admin identifier is outside its required UTF-8 byte bounds")
     43     }
     44 }
     45 
     46 impl Error for AdminIdentifierError {}
     47 
     48 macro_rules! admin_identifier {
     49     ($name:ident, $field:expr) => {
     50         #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
     51         pub struct $name(String);
     52 
     53         impl $name {
     54             pub fn new(value: impl AsRef<str>) -> Result<Self, AdminIdentifierError> {
     55                 let value = value.as_ref();
     56                 let field = $field;
     57                 validate_admin_identifier(value, field)?;
     58                 Ok(Self(value.to_owned()))
     59             }
     60 
     61             fn from_string(value: String) -> Result<Self, AdminIdentifierError> {
     62                 let field = $field;
     63                 validate_admin_identifier(&value, field)?;
     64                 Ok(Self(value))
     65             }
     66 
     67             #[must_use]
     68             pub fn as_str(&self) -> &str {
     69                 &self.0
     70             }
     71         }
     72 
     73         impl fmt::Debug for $name {
     74             fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
     75                 formatter
     76                     .debug_tuple(stringify!($name))
     77                     .field(&"[redacted]")
     78                     .finish()
     79             }
     80         }
     81 
     82         impl Serialize for $name {
     83             fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     84             where
     85                 S: Serializer,
     86             {
     87                 serializer.serialize_str(self.as_str())
     88             }
     89         }
     90 
     91         impl<'de> Deserialize<'de> for $name {
     92             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     93             where
     94                 D: Deserializer<'de>,
     95             {
     96                 struct Visitor;
     97 
     98                 impl<'de> de::Visitor<'de> for Visitor {
     99                     type Value = $name;
    100 
    101                     fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    102                         formatter.write_str("a bounded admin identifier")
    103                     }
    104 
    105                     fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
    106                     where
    107                         E: de::Error,
    108                     {
    109                         $name::new(value).map_err(E::custom)
    110                     }
    111 
    112                     fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
    113                     where
    114                         E: de::Error,
    115                     {
    116                         $name::from_string(value).map_err(E::custom)
    117                     }
    118                 }
    119 
    120                 deserializer.deserialize_str(Visitor)
    121             }
    122         }
    123     };
    124 }
    125 
    126 admin_identifier!(AdminOperationId, AdminIdentifierField::OperationId);
    127 admin_identifier!(AdminCorrelationId, AdminIdentifierField::CorrelationId);
    128 
    129 fn validate_admin_identifier(
    130     value: &str,
    131     field: AdminIdentifierField,
    132 ) -> Result<(), AdminIdentifierError> {
    133     let bytes = value.as_bytes();
    134     let Some((first, remaining)) = bytes.split_first() else {
    135         return Err(AdminIdentifierError::Empty { field });
    136     };
    137     if bytes.len() > field.maximum_utf8_bytes() {
    138         return Err(AdminIdentifierError::TooLong { field });
    139     }
    140     if !first.is_ascii_alphanumeric() {
    141         return Err(AdminIdentifierError::InvalidFirstCharacter { field });
    142     }
    143     if !remaining
    144         .iter()
    145         .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'_' | b':' | b'-'))
    146     {
    147         return Err(AdminIdentifierError::InvalidCharacter { field });
    148     }
    149     Ok(())
    150 }
    151 
    152 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
    153 pub enum AdminErrorCodeError {
    154     Empty,
    155     TooLong,
    156     InvalidCharacter,
    157 }
    158 
    159 impl fmt::Display for AdminErrorCodeError {
    160     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    161         formatter.write_str("admin error code must be a bounded lowercase snake identifier")
    162     }
    163 }
    164 
    165 impl Error for AdminErrorCodeError {}
    166 
    167 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
    168 pub struct AdminErrorCode(String);
    169 
    170 impl AdminErrorCode {
    171     pub fn new(value: impl AsRef<str>) -> Result<Self, AdminErrorCodeError> {
    172         let value = value.as_ref();
    173         validate_admin_error_code(value)?;
    174         Ok(Self(value.to_owned()))
    175     }
    176 
    177     fn from_string(value: String) -> Result<Self, AdminErrorCodeError> {
    178         validate_admin_error_code(&value)?;
    179         Ok(Self(value))
    180     }
    181 
    182     fn known(value: &'static str) -> Self {
    183         Self(value.to_owned())
    184     }
    185 
    186     #[must_use]
    187     pub fn as_str(&self) -> &str {
    188         &self.0
    189     }
    190 }
    191 
    192 fn validate_admin_error_code(value: &str) -> Result<(), AdminErrorCodeError> {
    193     if value.is_empty() {
    194         return Err(AdminErrorCodeError::Empty);
    195     }
    196     if value.len() > ADMIN_ERROR_CODE_MAX_UTF8_BYTES {
    197         return Err(AdminErrorCodeError::TooLong);
    198     }
    199     let mut bytes = value.bytes();
    200     if !matches!(bytes.next(), Some(b'a'..=b'z'))
    201         || !bytes.all(|byte| matches!(byte, b'a'..=b'z' | b'0'..=b'9' | b'_'))
    202     {
    203         return Err(AdminErrorCodeError::InvalidCharacter);
    204     }
    205     Ok(())
    206 }
    207 
    208 impl fmt::Display for AdminErrorCode {
    209     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    210         formatter.write_str(self.as_str())
    211     }
    212 }
    213 
    214 impl Serialize for AdminErrorCode {
    215     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    216     where
    217         S: Serializer,
    218     {
    219         serializer.serialize_str(self.as_str())
    220     }
    221 }
    222 
    223 impl<'de> Deserialize<'de> for AdminErrorCode {
    224     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    225     where
    226         D: Deserializer<'de>,
    227     {
    228         struct Visitor;
    229 
    230         impl<'de> de::Visitor<'de> for Visitor {
    231             type Value = AdminErrorCode;
    232 
    233             fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    234                 formatter.write_str("a bounded lowercase admin error code")
    235             }
    236 
    237             fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
    238             where
    239                 E: de::Error,
    240             {
    241                 AdminErrorCode::new(value).map_err(E::custom)
    242             }
    243 
    244             fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
    245             where
    246                 E: de::Error,
    247             {
    248                 AdminErrorCode::from_string(value).map_err(E::custom)
    249             }
    250         }
    251 
    252         deserializer.deserialize_str(Visitor)
    253     }
    254 }
    255 
    256 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
    257 pub enum AdminErrorMessageError {
    258     Empty,
    259     TooLong,
    260     ControlCharacter,
    261 }
    262 
    263 impl fmt::Display for AdminErrorMessageError {
    264     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    265         formatter.write_str("admin error message is not a bounded safe message")
    266     }
    267 }
    268 
    269 impl Error for AdminErrorMessageError {}
    270 
    271 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
    272 pub enum AdminPayloadError {
    273     NullForbidden,
    274     Encoding,
    275 }
    276 
    277 impl fmt::Display for AdminPayloadError {
    278     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    279         formatter.write_str(match self {
    280             Self::NullForbidden => "admin payloads may not contain JSON null",
    281             Self::Encoding => "admin payload could not be represented as JSON",
    282         })
    283     }
    284 }
    285 
    286 impl Error for AdminPayloadError {}
    287 
    288 #[derive(Clone, PartialEq, Eq)]
    289 struct NonNullPayload<T>(T);
    290 
    291 impl<T> NonNullPayload<T>
    292 where
    293     T: Serialize,
    294 {
    295     fn new(value: T) -> Result<Self, AdminPayloadError> {
    296         checked_non_null(&value)?;
    297         Ok(Self(value))
    298     }
    299 }
    300 
    301 impl<T> Serialize for NonNullPayload<T>
    302 where
    303     T: Serialize,
    304 {
    305     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    306     where
    307         S: Serializer,
    308     {
    309         checked_non_null(&self.0).map_err(ser::Error::custom)?;
    310         self.0.serialize(serializer)
    311     }
    312 }
    313 
    314 impl<'de, T> Deserialize<'de> for NonNullPayload<T>
    315 where
    316     T: Deserialize<'de> + Serialize,
    317 {
    318     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    319     where
    320         D: Deserializer<'de>,
    321     {
    322         let value = T::deserialize(NoNullDeserializer(deserializer))?;
    323         Self::new(value).map_err(de::Error::custom)
    324     }
    325 }
    326 
    327 struct NoNullDeserializer<D>(D);
    328 
    329 // This implementation is a mechanical Serde dispatch adapter. The conformance test below drives
    330 // every supported data shape through it; measuring every generic forwarding instantiation would
    331 // count compiler-generated dispatch rather than additional contract behavior.
    332 #[cfg_attr(coverage_nightly, coverage(off))]
    333 impl<'de, D> Deserializer<'de> for NoNullDeserializer<D>
    334 where
    335     D: Deserializer<'de>,
    336 {
    337     type Error = D::Error;
    338 
    339     fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    340     where
    341         V: de::Visitor<'de>,
    342     {
    343         self.0.deserialize_any(NoNullVisitor(visitor))
    344     }
    345 
    346     fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    347     where
    348         V: de::Visitor<'de>,
    349     {
    350         self.0.deserialize_bool(NoNullVisitor(visitor))
    351     }
    352 
    353     fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    354     where
    355         V: de::Visitor<'de>,
    356     {
    357         self.0.deserialize_i8(NoNullVisitor(visitor))
    358     }
    359 
    360     fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    361     where
    362         V: de::Visitor<'de>,
    363     {
    364         self.0.deserialize_i16(NoNullVisitor(visitor))
    365     }
    366 
    367     fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    368     where
    369         V: de::Visitor<'de>,
    370     {
    371         self.0.deserialize_i32(NoNullVisitor(visitor))
    372     }
    373 
    374     fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    375     where
    376         V: de::Visitor<'de>,
    377     {
    378         self.0.deserialize_i64(NoNullVisitor(visitor))
    379     }
    380 
    381     fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    382     where
    383         V: de::Visitor<'de>,
    384     {
    385         self.0.deserialize_i128(NoNullVisitor(visitor))
    386     }
    387 
    388     fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    389     where
    390         V: de::Visitor<'de>,
    391     {
    392         self.0.deserialize_u8(NoNullVisitor(visitor))
    393     }
    394 
    395     fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    396     where
    397         V: de::Visitor<'de>,
    398     {
    399         self.0.deserialize_u16(NoNullVisitor(visitor))
    400     }
    401 
    402     fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    403     where
    404         V: de::Visitor<'de>,
    405     {
    406         self.0.deserialize_u32(NoNullVisitor(visitor))
    407     }
    408 
    409     fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    410     where
    411         V: de::Visitor<'de>,
    412     {
    413         self.0.deserialize_u64(NoNullVisitor(visitor))
    414     }
    415 
    416     fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    417     where
    418         V: de::Visitor<'de>,
    419     {
    420         self.0.deserialize_u128(NoNullVisitor(visitor))
    421     }
    422 
    423     fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    424     where
    425         V: de::Visitor<'de>,
    426     {
    427         self.0.deserialize_f32(NoNullVisitor(visitor))
    428     }
    429 
    430     fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    431     where
    432         V: de::Visitor<'de>,
    433     {
    434         self.0.deserialize_f64(NoNullVisitor(visitor))
    435     }
    436 
    437     fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    438     where
    439         V: de::Visitor<'de>,
    440     {
    441         self.0.deserialize_char(NoNullVisitor(visitor))
    442     }
    443 
    444     fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    445     where
    446         V: de::Visitor<'de>,
    447     {
    448         self.0.deserialize_str(NoNullVisitor(visitor))
    449     }
    450 
    451     fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    452     where
    453         V: de::Visitor<'de>,
    454     {
    455         self.0.deserialize_string(NoNullVisitor(visitor))
    456     }
    457 
    458     fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    459     where
    460         V: de::Visitor<'de>,
    461     {
    462         self.0.deserialize_bytes(NoNullVisitor(visitor))
    463     }
    464 
    465     fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    466     where
    467         V: de::Visitor<'de>,
    468     {
    469         self.0.deserialize_byte_buf(NoNullVisitor(visitor))
    470     }
    471 
    472     fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    473     where
    474         V: de::Visitor<'de>,
    475     {
    476         self.0.deserialize_option(NoNullVisitor(visitor))
    477     }
    478 
    479     fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    480     where
    481         V: de::Visitor<'de>,
    482     {
    483         self.0.deserialize_unit(NoNullVisitor(visitor))
    484     }
    485 
    486     fn deserialize_unit_struct<V>(
    487         self,
    488         name: &'static str,
    489         visitor: V,
    490     ) -> Result<V::Value, Self::Error>
    491     where
    492         V: de::Visitor<'de>,
    493     {
    494         self.0.deserialize_unit_struct(name, NoNullVisitor(visitor))
    495     }
    496 
    497     fn deserialize_newtype_struct<V>(
    498         self,
    499         name: &'static str,
    500         visitor: V,
    501     ) -> Result<V::Value, Self::Error>
    502     where
    503         V: de::Visitor<'de>,
    504     {
    505         self.0
    506             .deserialize_newtype_struct(name, NoNullVisitor(visitor))
    507     }
    508 
    509     fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    510     where
    511         V: de::Visitor<'de>,
    512     {
    513         self.0.deserialize_seq(NoNullVisitor(visitor))
    514     }
    515 
    516     fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
    517     where
    518         V: de::Visitor<'de>,
    519     {
    520         self.0.deserialize_tuple(len, NoNullVisitor(visitor))
    521     }
    522 
    523     fn deserialize_tuple_struct<V>(
    524         self,
    525         name: &'static str,
    526         len: usize,
    527         visitor: V,
    528     ) -> Result<V::Value, Self::Error>
    529     where
    530         V: de::Visitor<'de>,
    531     {
    532         self.0
    533             .deserialize_tuple_struct(name, len, NoNullVisitor(visitor))
    534     }
    535 
    536     fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    537     where
    538         V: de::Visitor<'de>,
    539     {
    540         self.0.deserialize_map(NoNullVisitor(visitor))
    541     }
    542 
    543     fn deserialize_struct<V>(
    544         self,
    545         name: &'static str,
    546         fields: &'static [&'static str],
    547         visitor: V,
    548     ) -> Result<V::Value, Self::Error>
    549     where
    550         V: de::Visitor<'de>,
    551     {
    552         self.0
    553             .deserialize_struct(name, fields, NoNullVisitor(visitor))
    554     }
    555 
    556     fn deserialize_enum<V>(
    557         self,
    558         name: &'static str,
    559         variants: &'static [&'static str],
    560         visitor: V,
    561     ) -> Result<V::Value, Self::Error>
    562     where
    563         V: de::Visitor<'de>,
    564     {
    565         self.0
    566             .deserialize_enum(name, variants, NoNullVisitor(visitor))
    567     }
    568 
    569     fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    570     where
    571         V: de::Visitor<'de>,
    572     {
    573         self.0.deserialize_identifier(NoNullVisitor(visitor))
    574     }
    575 
    576     fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    577     where
    578         V: de::Visitor<'de>,
    579     {
    580         self.0.deserialize_ignored_any(NoNullVisitor(visitor))
    581     }
    582 
    583     fn is_human_readable(&self) -> bool {
    584         self.0.is_human_readable()
    585     }
    586 }
    587 
    588 struct NoNullVisitor<V>(V);
    589 
    590 // Scalar visits forward without policy. Null rejection and recursive
    591 // option/newtype/sequence/map/enum traversal remain measured below.
    592 impl<'de, V> de::Visitor<'de> for NoNullVisitor<V>
    593 where
    594     V: de::Visitor<'de>,
    595 {
    596     type Value = V::Value;
    597 
    598     #[cfg_attr(coverage_nightly, coverage(off))]
    599     fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    600         self.0.expecting(formatter)
    601     }
    602 
    603     #[cfg_attr(coverage_nightly, coverage(off))]
    604     fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E>
    605     where
    606         E: de::Error,
    607     {
    608         self.0.visit_bool(value)
    609     }
    610 
    611     #[cfg_attr(coverage_nightly, coverage(off))]
    612     fn visit_i8<E>(self, value: i8) -> Result<Self::Value, E>
    613     where
    614         E: de::Error,
    615     {
    616         self.0.visit_i8(value)
    617     }
    618 
    619     #[cfg_attr(coverage_nightly, coverage(off))]
    620     fn visit_i16<E>(self, value: i16) -> Result<Self::Value, E>
    621     where
    622         E: de::Error,
    623     {
    624         self.0.visit_i16(value)
    625     }
    626 
    627     #[cfg_attr(coverage_nightly, coverage(off))]
    628     fn visit_i32<E>(self, value: i32) -> Result<Self::Value, E>
    629     where
    630         E: de::Error,
    631     {
    632         self.0.visit_i32(value)
    633     }
    634 
    635     #[cfg_attr(coverage_nightly, coverage(off))]
    636     fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
    637     where
    638         E: de::Error,
    639     {
    640         self.0.visit_i64(value)
    641     }
    642 
    643     #[cfg_attr(coverage_nightly, coverage(off))]
    644     fn visit_i128<E>(self, value: i128) -> Result<Self::Value, E>
    645     where
    646         E: de::Error,
    647     {
    648         self.0.visit_i128(value)
    649     }
    650 
    651     #[cfg_attr(coverage_nightly, coverage(off))]
    652     fn visit_u8<E>(self, value: u8) -> Result<Self::Value, E>
    653     where
    654         E: de::Error,
    655     {
    656         self.0.visit_u8(value)
    657     }
    658 
    659     #[cfg_attr(coverage_nightly, coverage(off))]
    660     fn visit_u16<E>(self, value: u16) -> Result<Self::Value, E>
    661     where
    662         E: de::Error,
    663     {
    664         self.0.visit_u16(value)
    665     }
    666 
    667     #[cfg_attr(coverage_nightly, coverage(off))]
    668     fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E>
    669     where
    670         E: de::Error,
    671     {
    672         self.0.visit_u32(value)
    673     }
    674 
    675     #[cfg_attr(coverage_nightly, coverage(off))]
    676     fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
    677     where
    678         E: de::Error,
    679     {
    680         self.0.visit_u64(value)
    681     }
    682 
    683     #[cfg_attr(coverage_nightly, coverage(off))]
    684     fn visit_u128<E>(self, value: u128) -> Result<Self::Value, E>
    685     where
    686         E: de::Error,
    687     {
    688         self.0.visit_u128(value)
    689     }
    690 
    691     #[cfg_attr(coverage_nightly, coverage(off))]
    692     fn visit_f32<E>(self, value: f32) -> Result<Self::Value, E>
    693     where
    694         E: de::Error,
    695     {
    696         self.0.visit_f32(value)
    697     }
    698 
    699     #[cfg_attr(coverage_nightly, coverage(off))]
    700     fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E>
    701     where
    702         E: de::Error,
    703     {
    704         self.0.visit_f64(value)
    705     }
    706 
    707     #[cfg_attr(coverage_nightly, coverage(off))]
    708     fn visit_char<E>(self, value: char) -> Result<Self::Value, E>
    709     where
    710         E: de::Error,
    711     {
    712         self.0.visit_char(value)
    713     }
    714 
    715     #[cfg_attr(coverage_nightly, coverage(off))]
    716     fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
    717     where
    718         E: de::Error,
    719     {
    720         self.0.visit_str(value)
    721     }
    722 
    723     #[cfg_attr(coverage_nightly, coverage(off))]
    724     fn visit_borrowed_str<E>(self, value: &'de str) -> Result<Self::Value, E>
    725     where
    726         E: de::Error,
    727     {
    728         self.0.visit_borrowed_str(value)
    729     }
    730 
    731     #[cfg_attr(coverage_nightly, coverage(off))]
    732     fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
    733     where
    734         E: de::Error,
    735     {
    736         self.0.visit_string(value)
    737     }
    738 
    739     #[cfg_attr(coverage_nightly, coverage(off))]
    740     fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
    741     where
    742         E: de::Error,
    743     {
    744         self.0.visit_bytes(value)
    745     }
    746 
    747     #[cfg_attr(coverage_nightly, coverage(off))]
    748     fn visit_borrowed_bytes<E>(self, value: &'de [u8]) -> Result<Self::Value, E>
    749     where
    750         E: de::Error,
    751     {
    752         self.0.visit_borrowed_bytes(value)
    753     }
    754 
    755     #[cfg_attr(coverage_nightly, coverage(off))]
    756     fn visit_byte_buf<E>(self, value: Vec<u8>) -> Result<Self::Value, E>
    757     where
    758         E: de::Error,
    759     {
    760         self.0.visit_byte_buf(value)
    761     }
    762 
    763     fn visit_none<E>(self) -> Result<Self::Value, E>
    764     where
    765         E: de::Error,
    766     {
    767         Err(E::custom("admin payloads may not contain JSON null"))
    768     }
    769 
    770     fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    771     where
    772         D: Deserializer<'de>,
    773     {
    774         self.0.visit_some(NoNullDeserializer(deserializer))
    775     }
    776 
    777     fn visit_unit<E>(self) -> Result<Self::Value, E>
    778     where
    779         E: de::Error,
    780     {
    781         Err(E::custom("admin payloads may not contain JSON null"))
    782     }
    783 
    784     fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    785     where
    786         D: Deserializer<'de>,
    787     {
    788         self.0
    789             .visit_newtype_struct(NoNullDeserializer(deserializer))
    790     }
    791 
    792     fn visit_seq<A>(self, sequence: A) -> Result<Self::Value, A::Error>
    793     where
    794         A: de::SeqAccess<'de>,
    795     {
    796         self.0.visit_seq(NoNullSeqAccess(sequence))
    797     }
    798 
    799     fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
    800     where
    801         A: de::MapAccess<'de>,
    802     {
    803         self.0.visit_map(NoNullMapAccess(map))
    804     }
    805 
    806     fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
    807     where
    808         A: de::EnumAccess<'de>,
    809     {
    810         self.0.visit_enum(NoNullEnumAccess(data))
    811     }
    812 }
    813 
    814 struct NoNullSeed<S>(S);
    815 
    816 impl<'de, S> de::DeserializeSeed<'de> for NoNullSeed<S>
    817 where
    818     S: de::DeserializeSeed<'de>,
    819 {
    820     type Value = S::Value;
    821 
    822     fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    823     where
    824         D: Deserializer<'de>,
    825     {
    826         self.0.deserialize(NoNullDeserializer(deserializer))
    827     }
    828 }
    829 
    830 struct NoNullSeqAccess<A>(A);
    831 
    832 impl<'de, A> de::SeqAccess<'de> for NoNullSeqAccess<A>
    833 where
    834     A: de::SeqAccess<'de>,
    835 {
    836     type Error = A::Error;
    837 
    838     fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
    839     where
    840         T: de::DeserializeSeed<'de>,
    841     {
    842         self.0.next_element_seed(NoNullSeed(seed))
    843     }
    844 
    845     fn size_hint(&self) -> Option<usize> {
    846         self.0.size_hint()
    847     }
    848 }
    849 
    850 struct NoNullMapAccess<A>(A);
    851 
    852 impl<'de, A> de::MapAccess<'de> for NoNullMapAccess<A>
    853 where
    854     A: de::MapAccess<'de>,
    855 {
    856     type Error = A::Error;
    857 
    858     fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
    859     where
    860         K: de::DeserializeSeed<'de>,
    861     {
    862         self.0.next_key_seed(seed)
    863     }
    864 
    865     fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
    866     where
    867         V: de::DeserializeSeed<'de>,
    868     {
    869         self.0.next_value_seed(NoNullSeed(seed))
    870     }
    871 
    872     fn size_hint(&self) -> Option<usize> {
    873         self.0.size_hint()
    874     }
    875 }
    876 
    877 struct NoNullEnumAccess<A>(A);
    878 
    879 impl<'de, A> de::EnumAccess<'de> for NoNullEnumAccess<A>
    880 where
    881     A: de::EnumAccess<'de>,
    882 {
    883     type Error = A::Error;
    884     type Variant = NoNullVariantAccess<A::Variant>;
    885 
    886     fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
    887     where
    888         V: de::DeserializeSeed<'de>,
    889     {
    890         let (value, variant) = self.0.variant_seed(seed)?;
    891         Ok((value, NoNullVariantAccess(variant)))
    892     }
    893 }
    894 
    895 struct NoNullVariantAccess<A>(A);
    896 
    897 impl<'de, A> de::VariantAccess<'de> for NoNullVariantAccess<A>
    898 where
    899     A: de::VariantAccess<'de>,
    900 {
    901     type Error = A::Error;
    902 
    903     fn unit_variant(self) -> Result<(), Self::Error> {
    904         self.0.unit_variant()
    905     }
    906 
    907     fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>
    908     where
    909         T: de::DeserializeSeed<'de>,
    910     {
    911         self.0.newtype_variant_seed(NoNullSeed(seed))
    912     }
    913 
    914     fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
    915     where
    916         V: de::Visitor<'de>,
    917     {
    918         self.0.tuple_variant(len, NoNullVisitor(visitor))
    919     }
    920 
    921     fn struct_variant<V>(
    922         self,
    923         fields: &'static [&'static str],
    924         visitor: V,
    925     ) -> Result<V::Value, Self::Error>
    926     where
    927         V: de::Visitor<'de>,
    928     {
    929         self.0.struct_variant(fields, NoNullVisitor(visitor))
    930     }
    931 }
    932 
    933 #[derive(Clone, Copy, Debug)]
    934 enum PayloadValidationError {
    935     Null,
    936     Encoding,
    937 }
    938 
    939 impl fmt::Display for PayloadValidationError {
    940     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    941         formatter.write_str("admin payload validation failed")
    942     }
    943 }
    944 
    945 impl Error for PayloadValidationError {}
    946 
    947 impl ser::Error for PayloadValidationError {
    948     fn custom<T>(_message: T) -> Self
    949     where
    950         T: fmt::Display,
    951     {
    952         Self::Encoding
    953     }
    954 }
    955 
    956 #[derive(Clone, Copy)]
    957 struct NonNullSerializer<'failure> {
    958     failure: &'failure core::cell::Cell<Option<PayloadValidationError>>,
    959 }
    960 
    961 impl NonNullSerializer<'_> {
    962     fn finish(self) -> Result<(), PayloadValidationError> {
    963         self.failure.get().map_or(Ok(()), Err)
    964     }
    965 
    966     fn reject(self, error: PayloadValidationError) -> Result<(), PayloadValidationError> {
    967         if self.failure.get().is_none() {
    968             self.failure.set(Some(error));
    969         }
    970         Err(error)
    971     }
    972 }
    973 
    974 impl<'failure> ser::Serializer for NonNullSerializer<'failure> {
    975     type Ok = ();
    976     type Error = PayloadValidationError;
    977     type SerializeSeq = NonNullCompound<'failure>;
    978     type SerializeTuple = NonNullCompound<'failure>;
    979     type SerializeTupleStruct = NonNullCompound<'failure>;
    980     type SerializeTupleVariant = NonNullCompound<'failure>;
    981     type SerializeMap = NonNullCompound<'failure>;
    982     type SerializeStruct = NonNullCompound<'failure>;
    983     type SerializeStructVariant = NonNullCompound<'failure>;
    984 
    985     fn serialize_bool(self, _value: bool) -> Result<Self::Ok, Self::Error> {
    986         self.finish()
    987     }
    988 
    989     fn serialize_i8(self, _value: i8) -> Result<Self::Ok, Self::Error> {
    990         self.finish()
    991     }
    992 
    993     fn serialize_i16(self, _value: i16) -> Result<Self::Ok, Self::Error> {
    994         self.finish()
    995     }
    996 
    997     fn serialize_i32(self, _value: i32) -> Result<Self::Ok, Self::Error> {
    998         self.finish()
    999     }
   1000 
   1001     fn serialize_i64(self, _value: i64) -> Result<Self::Ok, Self::Error> {
   1002         self.finish()
   1003     }
   1004 
   1005     fn serialize_i128(self, _value: i128) -> Result<Self::Ok, Self::Error> {
   1006         self.finish()
   1007     }
   1008 
   1009     fn serialize_u8(self, _value: u8) -> Result<Self::Ok, Self::Error> {
   1010         self.finish()
   1011     }
   1012 
   1013     fn serialize_u16(self, _value: u16) -> Result<Self::Ok, Self::Error> {
   1014         self.finish()
   1015     }
   1016 
   1017     fn serialize_u32(self, _value: u32) -> Result<Self::Ok, Self::Error> {
   1018         self.finish()
   1019     }
   1020 
   1021     fn serialize_u64(self, _value: u64) -> Result<Self::Ok, Self::Error> {
   1022         self.finish()
   1023     }
   1024 
   1025     fn serialize_u128(self, _value: u128) -> Result<Self::Ok, Self::Error> {
   1026         self.finish()
   1027     }
   1028 
   1029     fn serialize_f32(self, _value: f32) -> Result<Self::Ok, Self::Error> {
   1030         self.finish()
   1031     }
   1032 
   1033     fn serialize_f64(self, _value: f64) -> Result<Self::Ok, Self::Error> {
   1034         self.finish()
   1035     }
   1036 
   1037     fn serialize_char(self, _value: char) -> Result<Self::Ok, Self::Error> {
   1038         self.finish()
   1039     }
   1040 
   1041     fn serialize_str(self, _value: &str) -> Result<Self::Ok, Self::Error> {
   1042         self.finish()
   1043     }
   1044 
   1045     fn serialize_bytes(self, _value: &[u8]) -> Result<Self::Ok, Self::Error> {
   1046         self.finish()
   1047     }
   1048 
   1049     fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
   1050         self.reject(PayloadValidationError::Null)
   1051     }
   1052 
   1053     fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
   1054     where
   1055         T: ?Sized + Serialize,
   1056     {
   1057         value.serialize(self)
   1058     }
   1059 
   1060     fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
   1061         self.reject(PayloadValidationError::Null)
   1062     }
   1063 
   1064     fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
   1065         self.reject(PayloadValidationError::Null)
   1066     }
   1067 
   1068     fn serialize_unit_variant(
   1069         self,
   1070         _name: &'static str,
   1071         _variant_index: u32,
   1072         _variant: &'static str,
   1073     ) -> Result<Self::Ok, Self::Error> {
   1074         self.finish()
   1075     }
   1076 
   1077     fn serialize_newtype_struct<T>(
   1078         self,
   1079         _name: &'static str,
   1080         value: &T,
   1081     ) -> Result<Self::Ok, Self::Error>
   1082     where
   1083         T: ?Sized + Serialize,
   1084     {
   1085         value.serialize(self)
   1086     }
   1087 
   1088     fn serialize_newtype_variant<T>(
   1089         self,
   1090         _name: &'static str,
   1091         _variant_index: u32,
   1092         _variant: &'static str,
   1093         value: &T,
   1094     ) -> Result<Self::Ok, Self::Error>
   1095     where
   1096         T: ?Sized + Serialize,
   1097     {
   1098         value.serialize(self)
   1099     }
   1100 
   1101     fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
   1102         self.finish()?;
   1103         Ok(NonNullCompound(self))
   1104     }
   1105 
   1106     fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
   1107         self.finish()?;
   1108         Ok(NonNullCompound(self))
   1109     }
   1110 
   1111     fn serialize_tuple_struct(
   1112         self,
   1113         _name: &'static str,
   1114         _len: usize,
   1115     ) -> Result<Self::SerializeTupleStruct, Self::Error> {
   1116         self.finish()?;
   1117         Ok(NonNullCompound(self))
   1118     }
   1119 
   1120     fn serialize_tuple_variant(
   1121         self,
   1122         _name: &'static str,
   1123         _variant_index: u32,
   1124         _variant: &'static str,
   1125         _len: usize,
   1126     ) -> Result<Self::SerializeTupleVariant, Self::Error> {
   1127         self.finish()?;
   1128         Ok(NonNullCompound(self))
   1129     }
   1130 
   1131     fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
   1132         self.finish()?;
   1133         Ok(NonNullCompound(self))
   1134     }
   1135 
   1136     fn serialize_struct(
   1137         self,
   1138         _name: &'static str,
   1139         _len: usize,
   1140     ) -> Result<Self::SerializeStruct, Self::Error> {
   1141         self.finish()?;
   1142         Ok(NonNullCompound(self))
   1143     }
   1144 
   1145     fn serialize_struct_variant(
   1146         self,
   1147         _name: &'static str,
   1148         _variant_index: u32,
   1149         _variant: &'static str,
   1150         _len: usize,
   1151     ) -> Result<Self::SerializeStructVariant, Self::Error> {
   1152         self.finish()?;
   1153         Ok(NonNullCompound(self))
   1154     }
   1155 
   1156     fn collect_str<T>(self, _value: &T) -> Result<Self::Ok, Self::Error>
   1157     where
   1158         T: ?Sized + fmt::Display,
   1159     {
   1160         self.finish()
   1161     }
   1162 
   1163     fn is_human_readable(&self) -> bool {
   1164         true
   1165     }
   1166 }
   1167 
   1168 struct NonNullCompound<'failure>(NonNullSerializer<'failure>);
   1169 
   1170 impl NonNullCompound<'_> {
   1171     fn value<T>(&mut self, value: &T) -> Result<(), PayloadValidationError>
   1172     where
   1173         T: ?Sized + Serialize,
   1174     {
   1175         value.serialize(self.0)
   1176     }
   1177 
   1178     fn finish(self) -> Result<(), PayloadValidationError> {
   1179         self.0.finish()
   1180     }
   1181 }
   1182 
   1183 impl ser::SerializeSeq for NonNullCompound<'_> {
   1184     type Ok = ();
   1185     type Error = PayloadValidationError;
   1186 
   1187     fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
   1188     where
   1189         T: ?Sized + Serialize,
   1190     {
   1191         self.value(value)
   1192     }
   1193 
   1194     fn end(self) -> Result<Self::Ok, Self::Error> {
   1195         self.finish()
   1196     }
   1197 }
   1198 
   1199 impl ser::SerializeTuple for NonNullCompound<'_> {
   1200     type Ok = ();
   1201     type Error = PayloadValidationError;
   1202 
   1203     fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
   1204     where
   1205         T: ?Sized + Serialize,
   1206     {
   1207         self.value(value)
   1208     }
   1209 
   1210     fn end(self) -> Result<Self::Ok, Self::Error> {
   1211         self.finish()
   1212     }
   1213 }
   1214 
   1215 impl ser::SerializeTupleStruct for NonNullCompound<'_> {
   1216     type Ok = ();
   1217     type Error = PayloadValidationError;
   1218 
   1219     fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
   1220     where
   1221         T: ?Sized + Serialize,
   1222     {
   1223         self.value(value)
   1224     }
   1225 
   1226     fn end(self) -> Result<Self::Ok, Self::Error> {
   1227         self.finish()
   1228     }
   1229 }
   1230 
   1231 impl ser::SerializeTupleVariant for NonNullCompound<'_> {
   1232     type Ok = ();
   1233     type Error = PayloadValidationError;
   1234 
   1235     fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
   1236     where
   1237         T: ?Sized + Serialize,
   1238     {
   1239         self.value(value)
   1240     }
   1241 
   1242     fn end(self) -> Result<Self::Ok, Self::Error> {
   1243         self.finish()
   1244     }
   1245 }
   1246 
   1247 impl ser::SerializeMap for NonNullCompound<'_> {
   1248     type Ok = ();
   1249     type Error = PayloadValidationError;
   1250 
   1251     fn serialize_key<T>(&mut self, key: &T) -> Result<(), Self::Error>
   1252     where
   1253         T: ?Sized + Serialize,
   1254     {
   1255         self.value(key)
   1256     }
   1257 
   1258     fn serialize_value<T>(&mut self, value: &T) -> Result<(), Self::Error>
   1259     where
   1260         T: ?Sized + Serialize,
   1261     {
   1262         self.value(value)
   1263     }
   1264 
   1265     fn end(self) -> Result<Self::Ok, Self::Error> {
   1266         self.finish()
   1267     }
   1268 }
   1269 
   1270 impl ser::SerializeStruct for NonNullCompound<'_> {
   1271     type Ok = ();
   1272     type Error = PayloadValidationError;
   1273 
   1274     fn serialize_field<T>(&mut self, _key: &'static str, value: &T) -> Result<(), Self::Error>
   1275     where
   1276         T: ?Sized + Serialize,
   1277     {
   1278         self.value(value)
   1279     }
   1280 
   1281     fn end(self) -> Result<Self::Ok, Self::Error> {
   1282         self.finish()
   1283     }
   1284 }
   1285 
   1286 impl ser::SerializeStructVariant for NonNullCompound<'_> {
   1287     type Ok = ();
   1288     type Error = PayloadValidationError;
   1289 
   1290     fn serialize_field<T>(&mut self, _key: &'static str, value: &T) -> Result<(), Self::Error>
   1291     where
   1292         T: ?Sized + Serialize,
   1293     {
   1294         self.value(value)
   1295     }
   1296 
   1297     fn end(self) -> Result<Self::Ok, Self::Error> {
   1298         self.finish()
   1299     }
   1300 }
   1301 
   1302 #[derive(Default)]
   1303 struct NonNullJsonWriter {
   1304     inside_string: bool,
   1305     escaped: bool,
   1306     null_progress: usize,
   1307     rejected: bool,
   1308 }
   1309 
   1310 impl std::io::Write for NonNullJsonWriter {
   1311     fn write(&mut self, bytes: &[u8]) -> std::io::Result<usize> {
   1312         if self.rejected {
   1313             return Err(std::io::Error::other("JSON null is forbidden"));
   1314         }
   1315         for &byte in bytes {
   1316             if self.inside_string {
   1317                 if self.escaped {
   1318                     self.escaped = false;
   1319                 } else if byte == b'\\' {
   1320                     self.escaped = true;
   1321                 } else if byte == b'"' {
   1322                     self.inside_string = false;
   1323                 }
   1324                 continue;
   1325             }
   1326 
   1327             if byte == b'"' {
   1328                 self.inside_string = true;
   1329                 self.null_progress = 0;
   1330                 continue;
   1331             }
   1332 
   1333             let expected = b"null";
   1334             if byte == expected[self.null_progress] {
   1335                 self.null_progress += 1;
   1336                 if self.null_progress == expected.len() {
   1337                     self.rejected = true;
   1338                     return Err(std::io::Error::other("JSON null is forbidden"));
   1339                 }
   1340             } else {
   1341                 self.null_progress = usize::from(byte == b'n');
   1342             }
   1343         }
   1344         Ok(bytes.len())
   1345     }
   1346 
   1347     fn flush(&mut self) -> std::io::Result<()> {
   1348         if self.rejected {
   1349             Err(std::io::Error::other("JSON null is forbidden"))
   1350         } else {
   1351             Ok(())
   1352         }
   1353     }
   1354 }
   1355 
   1356 fn checked_non_null(value: &impl Serialize) -> Result<(), AdminPayloadError> {
   1357     let failure = core::cell::Cell::new(None);
   1358     let serializer = NonNullSerializer { failure: &failure };
   1359     let result = value.serialize(serializer);
   1360     match failure.get().or_else(|| result.err()) {
   1361         None => {
   1362             let mut writer = NonNullJsonWriter::default();
   1363             match serde_json::to_writer(&mut writer, value) {
   1364                 Ok(()) => Ok(()),
   1365                 Err(_) if writer.rejected => Err(AdminPayloadError::NullForbidden),
   1366                 Err(_) => Err(AdminPayloadError::Encoding),
   1367             }
   1368         }
   1369         Some(PayloadValidationError::Null) => Err(AdminPayloadError::NullForbidden),
   1370         Some(PayloadValidationError::Encoding) => Err(AdminPayloadError::Encoding),
   1371     }
   1372 }
   1373 
   1374 #[derive(Clone, Debug, PartialEq, Eq)]
   1375 pub struct AdminErrorMessage(String);
   1376 
   1377 impl AdminErrorMessage {
   1378     pub fn new(value: impl AsRef<str>) -> Result<Self, AdminErrorMessageError> {
   1379         let value = value.as_ref();
   1380         validate_admin_error_message(value)?;
   1381         Ok(Self(value.to_owned()))
   1382     }
   1383 
   1384     fn from_string(value: String) -> Result<Self, AdminErrorMessageError> {
   1385         validate_admin_error_message(&value)?;
   1386         Ok(Self(value))
   1387     }
   1388 
   1389     fn known(value: &'static str) -> Self {
   1390         Self(value.to_owned())
   1391     }
   1392 
   1393     #[must_use]
   1394     pub fn as_str(&self) -> &str {
   1395         &self.0
   1396     }
   1397 }
   1398 
   1399 fn validate_admin_error_message(value: &str) -> Result<(), AdminErrorMessageError> {
   1400     if value.is_empty() {
   1401         return Err(AdminErrorMessageError::Empty);
   1402     }
   1403     if value.len() > ADMIN_ERROR_MESSAGE_MAX_UTF8_BYTES {
   1404         return Err(AdminErrorMessageError::TooLong);
   1405     }
   1406     if value.chars().any(char::is_control) {
   1407         return Err(AdminErrorMessageError::ControlCharacter);
   1408     }
   1409     Ok(())
   1410 }
   1411 
   1412 impl fmt::Display for AdminErrorMessage {
   1413     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
   1414         formatter.write_str(self.as_str())
   1415     }
   1416 }
   1417 
   1418 impl Serialize for AdminErrorMessage {
   1419     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
   1420     where
   1421         S: Serializer,
   1422     {
   1423         serializer.serialize_str(self.as_str())
   1424     }
   1425 }
   1426 
   1427 impl<'de> Deserialize<'de> for AdminErrorMessage {
   1428     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1429     where
   1430         D: Deserializer<'de>,
   1431     {
   1432         struct Visitor;
   1433 
   1434         impl<'de> de::Visitor<'de> for Visitor {
   1435             type Value = AdminErrorMessage;
   1436 
   1437             fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
   1438                 formatter.write_str("a bounded safe admin error message")
   1439             }
   1440 
   1441             fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
   1442             where
   1443                 E: de::Error,
   1444             {
   1445                 AdminErrorMessage::new(value).map_err(E::custom)
   1446             }
   1447 
   1448             fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
   1449             where
   1450                 E: de::Error,
   1451             {
   1452                 AdminErrorMessage::from_string(value).map_err(E::custom)
   1453             }
   1454         }
   1455 
   1456         deserializer.deserialize_str(Visitor)
   1457     }
   1458 }
   1459 
   1460 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
   1461 #[serde(deny_unknown_fields)]
   1462 pub struct AdminError {
   1463     code: AdminErrorCode,
   1464     message: AdminErrorMessage,
   1465 }
   1466 
   1467 impl AdminError {
   1468     #[must_use]
   1469     pub const fn new(code: AdminErrorCode, message: AdminErrorMessage) -> Self {
   1470         Self { code, message }
   1471     }
   1472 
   1473     #[must_use]
   1474     pub fn from_host_error(error: &HostError) -> Self {
   1475         let safe = error.safe_error();
   1476         Self {
   1477             code: AdminErrorCode::known(safe.code_str()),
   1478             message: AdminErrorMessage::known(safe.message()),
   1479         }
   1480     }
   1481 
   1482     #[must_use]
   1483     pub fn code(&self) -> &AdminErrorCode {
   1484         &self.code
   1485     }
   1486 
   1487     #[must_use]
   1488     pub fn message(&self) -> &AdminErrorMessage {
   1489         &self.message
   1490     }
   1491 }
   1492 
   1493 #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
   1494 struct SuccessLiteral(#[serde(with = "success_literal")] ());
   1495 
   1496 #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
   1497 struct ContractVersionLiteral(#[serde(with = "contract_version_literal")] ());
   1498 
   1499 mod contract_version_literal {
   1500     use serde::{Deserialize, Deserializer, Serializer, de};
   1501 
   1502     use super::ADMIN_CONTRACT_VERSION;
   1503 
   1504     pub fn serialize<S>(_: &(), serializer: S) -> Result<S::Ok, S::Error>
   1505     where
   1506         S: Serializer,
   1507     {
   1508         serializer.serialize_u32(ADMIN_CONTRACT_VERSION)
   1509     }
   1510 
   1511     pub fn deserialize<'de, D>(deserializer: D) -> Result<(), D::Error>
   1512     where
   1513         D: Deserializer<'de>,
   1514     {
   1515         let received = u32::deserialize(deserializer)?;
   1516         if received == ADMIN_CONTRACT_VERSION {
   1517             Ok(())
   1518         } else {
   1519             Err(de::Error::custom(
   1520                 "admin response contract version must be 1",
   1521             ))
   1522         }
   1523     }
   1524 }
   1525 
   1526 mod success_literal {
   1527     use serde::{Deserialize, Deserializer, Serializer, de};
   1528 
   1529     pub fn serialize<S>(_: &(), serializer: S) -> Result<S::Ok, S::Error>
   1530     where
   1531         S: Serializer,
   1532     {
   1533         serializer.serialize_bool(true)
   1534     }
   1535 
   1536     pub fn deserialize<'de, D>(deserializer: D) -> Result<(), D::Error>
   1537     where
   1538         D: Deserializer<'de>,
   1539     {
   1540         if bool::deserialize(deserializer)? {
   1541             Ok(())
   1542         } else {
   1543             Err(de::Error::custom("admin success envelope requires ok=true"))
   1544         }
   1545     }
   1546 }
   1547 
   1548 #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
   1549 struct FailureLiteral(#[serde(with = "failure_literal")] ());
   1550 
   1551 mod failure_literal {
   1552     use serde::{Deserialize, Deserializer, Serializer, de};
   1553 
   1554     pub fn serialize<S>(_: &(), serializer: S) -> Result<S::Ok, S::Error>
   1555     where
   1556         S: Serializer,
   1557     {
   1558         serializer.serialize_bool(false)
   1559     }
   1560 
   1561     pub fn deserialize<'de, D>(deserializer: D) -> Result<(), D::Error>
   1562     where
   1563         D: Deserializer<'de>,
   1564     {
   1565         if bool::deserialize(deserializer)? {
   1566             Err(de::Error::custom(
   1567                 "admin failure envelope requires ok=false",
   1568             ))
   1569         } else {
   1570             Ok(())
   1571         }
   1572     }
   1573 }
   1574 
   1575 #[derive(Clone, Debug, Default, PartialEq, Eq)]
   1576 enum OptionalCorrelationId {
   1577     #[default]
   1578     Absent,
   1579     Present(AdminCorrelationId),
   1580 }
   1581 
   1582 impl OptionalCorrelationId {
   1583     fn is_absent(&self) -> bool {
   1584         matches!(self, Self::Absent)
   1585     }
   1586 
   1587     fn as_option(&self) -> Option<&AdminCorrelationId> {
   1588         match self {
   1589             Self::Absent => None,
   1590             Self::Present(value) => Some(value),
   1591         }
   1592     }
   1593 }
   1594 
   1595 impl Serialize for OptionalCorrelationId {
   1596     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
   1597     where
   1598         S: Serializer,
   1599     {
   1600         match self {
   1601             Self::Absent => serializer.serialize_none(),
   1602             Self::Present(value) => value.serialize(serializer),
   1603         }
   1604     }
   1605 }
   1606 
   1607 impl<'de> Deserialize<'de> for OptionalCorrelationId {
   1608     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1609     where
   1610         D: Deserializer<'de>,
   1611     {
   1612         AdminCorrelationId::deserialize(deserializer).map(Self::Present)
   1613     }
   1614 }
   1615 
   1616 #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
   1617 #[serde(
   1618     deny_unknown_fields,
   1619     bound(
   1620         serialize = "T: Serialize",
   1621         deserialize = "T: Deserialize<'de> + Serialize"
   1622     )
   1623 )]
   1624 pub struct AdminMutationRequest<T> {
   1625     contract_version: u32,
   1626     operation_id: AdminOperationId,
   1627     #[serde(default, skip_serializing_if = "OptionalCorrelationId::is_absent")]
   1628     correlation_id: OptionalCorrelationId,
   1629     request: NonNullPayload<T>,
   1630 }
   1631 
   1632 impl<T> AdminMutationRequest<T>
   1633 where
   1634     T: Serialize,
   1635 {
   1636     pub fn new(
   1637         operation_id: AdminOperationId,
   1638         correlation_id: Option<AdminCorrelationId>,
   1639         request: T,
   1640     ) -> Result<Self, AdminPayloadError> {
   1641         Ok(Self {
   1642             contract_version: ADMIN_CONTRACT_VERSION,
   1643             operation_id,
   1644             correlation_id: correlation_id
   1645                 .map(OptionalCorrelationId::Present)
   1646                 .unwrap_or_default(),
   1647             request: NonNullPayload::new(request)?,
   1648         })
   1649     }
   1650 
   1651     #[must_use]
   1652     pub const fn contract_version(&self) -> u32 {
   1653         self.contract_version
   1654     }
   1655 
   1656     pub fn validate_contract_version(&self) -> Result<(), AdminContractVersionError> {
   1657         if self.contract_version == ADMIN_CONTRACT_VERSION {
   1658             Ok(())
   1659         } else {
   1660             Err(AdminContractVersionError {
   1661                 received: self.contract_version,
   1662             })
   1663         }
   1664     }
   1665 
   1666     #[must_use]
   1667     pub const fn operation_id(&self) -> &AdminOperationId {
   1668         &self.operation_id
   1669     }
   1670 
   1671     #[must_use]
   1672     pub fn correlation_id(&self) -> Option<&AdminCorrelationId> {
   1673         self.correlation_id.as_option()
   1674     }
   1675 
   1676     #[must_use]
   1677     pub const fn request(&self) -> &T {
   1678         &self.request.0
   1679     }
   1680 
   1681     #[must_use]
   1682     pub fn into_request(self) -> T {
   1683         self.request.0
   1684     }
   1685 }
   1686 
   1687 impl<T> fmt::Debug for AdminMutationRequest<T> {
   1688     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
   1689         formatter
   1690             .debug_struct("AdminMutationRequest")
   1691             .field("contract_version", &self.contract_version)
   1692             .field("operation_id", &self.operation_id)
   1693             .field("correlation_id", &self.correlation_id.as_option())
   1694             .field("request", &"<redacted>")
   1695             .finish()
   1696     }
   1697 }
   1698 
   1699 #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
   1700 #[serde(
   1701     deny_unknown_fields,
   1702     bound(
   1703         serialize = "T: Serialize",
   1704         deserialize = "T: Deserialize<'de> + Serialize"
   1705     )
   1706 )]
   1707 pub struct AdminSuccessResponse<T> {
   1708     contract_version: ContractVersionLiteral,
   1709     ok: SuccessLiteral,
   1710     correlation_id: AdminCorrelationId,
   1711     result: NonNullPayload<T>,
   1712 }
   1713 
   1714 impl<T> AdminSuccessResponse<T>
   1715 where
   1716     T: Serialize,
   1717 {
   1718     pub fn new(correlation_id: AdminCorrelationId, result: T) -> Result<Self, AdminPayloadError> {
   1719         Ok(Self {
   1720             contract_version: ContractVersionLiteral(()),
   1721             ok: SuccessLiteral(()),
   1722             correlation_id,
   1723             result: NonNullPayload::new(result)?,
   1724         })
   1725     }
   1726 
   1727     #[must_use]
   1728     pub const fn correlation_id(&self) -> &AdminCorrelationId {
   1729         &self.correlation_id
   1730     }
   1731 
   1732     #[must_use]
   1733     pub const fn result(&self) -> &T {
   1734         &self.result.0
   1735     }
   1736 
   1737     #[must_use]
   1738     pub fn into_result(self) -> T {
   1739         self.result.0
   1740     }
   1741 }
   1742 
   1743 impl<T> fmt::Debug for AdminSuccessResponse<T> {
   1744     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
   1745         formatter
   1746             .debug_struct("AdminSuccessResponse")
   1747             .field("contract_version", &ADMIN_CONTRACT_VERSION)
   1748             .field("ok", &true)
   1749             .field("correlation_id", &self.correlation_id)
   1750             .field("result", &"<redacted>")
   1751             .finish()
   1752     }
   1753 }
   1754 
   1755 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
   1756 #[serde(deny_unknown_fields)]
   1757 pub struct AdminFailureResponse {
   1758     contract_version: ContractVersionLiteral,
   1759     ok: FailureLiteral,
   1760     correlation_id: AdminCorrelationId,
   1761     error: AdminError,
   1762 }
   1763 
   1764 impl AdminFailureResponse {
   1765     #[must_use]
   1766     pub const fn new(correlation_id: AdminCorrelationId, error: AdminError) -> Self {
   1767         Self {
   1768             contract_version: ContractVersionLiteral(()),
   1769             ok: FailureLiteral(()),
   1770             correlation_id,
   1771             error,
   1772         }
   1773     }
   1774 
   1775     #[must_use]
   1776     pub fn unsupported_contract_version(correlation_id: AdminCorrelationId) -> Self {
   1777         Self::new(
   1778             correlation_id,
   1779             AdminError::new(
   1780                 AdminErrorCode::known(UNSUPPORTED_CONTRACT_VERSION_CODE),
   1781                 AdminErrorMessage::known(UNSUPPORTED_CONTRACT_VERSION_MESSAGE),
   1782             ),
   1783         )
   1784     }
   1785 
   1786     #[must_use]
   1787     pub const fn correlation_id(&self) -> &AdminCorrelationId {
   1788         &self.correlation_id
   1789     }
   1790 
   1791     #[must_use]
   1792     pub const fn error(&self) -> &AdminError {
   1793         &self.error
   1794     }
   1795 }
   1796 
   1797 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
   1798 pub struct AdminContractVersionError {
   1799     received: u32,
   1800 }
   1801 
   1802 impl AdminContractVersionError {
   1803     #[must_use]
   1804     pub const fn received(self) -> u32 {
   1805         self.received
   1806     }
   1807 
   1808     #[must_use]
   1809     pub fn response(self, correlation_id: AdminCorrelationId) -> AdminFailureResponse {
   1810         AdminFailureResponse::unsupported_contract_version(correlation_id)
   1811     }
   1812 }
   1813 
   1814 impl fmt::Display for AdminContractVersionError {
   1815     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
   1816         formatter.write_str("admin contract version is unsupported")
   1817     }
   1818 }
   1819 
   1820 impl Error for AdminContractVersionError {}
   1821 
   1822 #[cfg(test)]
   1823 mod tests {
   1824     use std::collections::BTreeMap;
   1825     use std::error::Error;
   1826 
   1827     use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
   1828 
   1829     use crate::HostErrorKind;
   1830 
   1831     use super::*;
   1832 
   1833     #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
   1834     #[serde(deny_unknown_fields)]
   1835     struct ExampleRequest {
   1836         value: u32,
   1837     }
   1838 
   1839     #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
   1840     #[serde(deny_unknown_fields)]
   1841     struct ExampleResult {
   1842         state: String,
   1843     }
   1844 
   1845     #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
   1846     struct NewtypePayload(u16);
   1847 
   1848     #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
   1849     struct TuplePayload(i8, String);
   1850 
   1851     #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
   1852     struct StructPayload {
   1853         enabled: bool,
   1854         count: u32,
   1855     }
   1856 
   1857     #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
   1858     enum EnumPayload {
   1859         Unit,
   1860         Newtype(u64),
   1861         Tuple(i32, bool),
   1862         Struct { label: String },
   1863     }
   1864 
   1865     #[derive(Clone, Debug, PartialEq)]
   1866     struct AnyPayload(String);
   1867 
   1868     impl Serialize for AnyPayload {
   1869         fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
   1870         where
   1871             S: Serializer,
   1872         {
   1873             serializer.serialize_str(&self.0)
   1874         }
   1875     }
   1876 
   1877     impl<'de> Deserialize<'de> for AnyPayload {
   1878         fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1879         where
   1880             D: Deserializer<'de>,
   1881         {
   1882             struct Visitor;
   1883 
   1884             impl<'de> de::Visitor<'de> for Visitor {
   1885                 type Value = AnyPayload;
   1886 
   1887                 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
   1888                     formatter.write_str("a string payload")
   1889                 }
   1890 
   1891                 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
   1892                 where
   1893                     E: de::Error,
   1894                 {
   1895                     Ok(AnyPayload(value.to_owned()))
   1896                 }
   1897             }
   1898 
   1899             deserializer.deserialize_any(Visitor)
   1900         }
   1901     }
   1902 
   1903     #[derive(Clone, Debug, PartialEq)]
   1904     struct ByteBufferPayload(Vec<u8>);
   1905 
   1906     impl Serialize for ByteBufferPayload {
   1907         fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
   1908         where
   1909             S: Serializer,
   1910         {
   1911             serializer.serialize_bytes(&self.0)
   1912         }
   1913     }
   1914 
   1915     impl<'de> Deserialize<'de> for ByteBufferPayload {
   1916         fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1917         where
   1918             D: Deserializer<'de>,
   1919         {
   1920             struct Visitor;
   1921 
   1922             impl<'de> de::Visitor<'de> for Visitor {
   1923                 type Value = ByteBufferPayload;
   1924 
   1925                 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
   1926                     formatter.write_str("a byte buffer")
   1927                 }
   1928 
   1929                 fn visit_byte_buf<E>(self, value: Vec<u8>) -> Result<Self::Value, E> {
   1930                     Ok(ByteBufferPayload(value))
   1931                 }
   1932 
   1933                 fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E> {
   1934                     Ok(ByteBufferPayload(value.to_vec()))
   1935                 }
   1936 
   1937                 fn visit_borrowed_bytes<E>(self, value: &'de [u8]) -> Result<Self::Value, E> {
   1938                     Ok(ByteBufferPayload(value.to_vec()))
   1939                 }
   1940             }
   1941 
   1942             deserializer.deserialize_byte_buf(Visitor)
   1943         }
   1944     }
   1945 
   1946     fn operation_id() -> AdminOperationId {
   1947         AdminOperationId::new("stable-operation").unwrap()
   1948     }
   1949 
   1950     fn correlation_id() -> AdminCorrelationId {
   1951         AdminCorrelationId::new("safe-correlation").unwrap()
   1952     }
   1953 
   1954     #[test]
   1955     fn request_and_response_snapshots_are_exact() {
   1956         let request = AdminMutationRequest::new(
   1957             operation_id(),
   1958             Some(correlation_id()),
   1959             ExampleRequest { value: 7 },
   1960         )
   1961         .unwrap();
   1962         assert_eq!(
   1963             serde_json::to_string(&request).unwrap(),
   1964             r#"{"contract_version":1,"operation_id":"stable-operation","correlation_id":"safe-correlation","request":{"value":7}}"#
   1965         );
   1966 
   1967         let without_correlation =
   1968             AdminMutationRequest::new(operation_id(), None, ExampleRequest { value: 7 }).unwrap();
   1969         assert_eq!(
   1970             serde_json::to_string(&without_correlation).unwrap(),
   1971             r#"{"contract_version":1,"operation_id":"stable-operation","request":{"value":7}}"#
   1972         );
   1973 
   1974         let success = AdminSuccessResponse::new(
   1975             correlation_id(),
   1976             ExampleResult {
   1977                 state: "committed".to_owned(),
   1978             },
   1979         )
   1980         .unwrap();
   1981         assert_eq!(
   1982             serde_json::to_string(&success).unwrap(),
   1983             r#"{"contract_version":1,"ok":true,"correlation_id":"safe-correlation","result":{"state":"committed"}}"#
   1984         );
   1985 
   1986         let failure = AdminFailureResponse::new(
   1987             correlation_id(),
   1988             AdminError::new(
   1989                 AdminErrorCode::new("operation_id_conflict").unwrap(),
   1990                 AdminErrorMessage::new("operation identity conflicts with prior input").unwrap(),
   1991             ),
   1992         );
   1993         assert_eq!(
   1994             serde_json::to_string(&failure).unwrap(),
   1995             r#"{"contract_version":1,"ok":false,"correlation_id":"safe-correlation","error":{"code":"operation_id_conflict","message":"operation identity conflicts with prior input"}}"#
   1996         );
   1997     }
   1998 
   1999     #[test]
   2000     fn recursive_non_null_adapter_covers_every_supported_serde_shape() {
   2001         macro_rules! payload {
   2002             ($ty:ty, $json:literal, $expected:expr) => {
   2003                 assert_eq!(
   2004                     serde_json::from_str::<NonNullPayload<$ty>>($json)
   2005                         .expect("non-null payload must decode")
   2006                         .0,
   2007                     $expected
   2008                 );
   2009             };
   2010         }
   2011 
   2012         payload!(bool, "true", true);
   2013         payload!(i8, "-8", -8);
   2014         payload!(i16, "-16", -16);
   2015         payload!(i32, "-32", -32);
   2016         payload!(i64, "-64", -64);
   2017         payload!(i128, "-128", -128);
   2018         payload!(u8, "8", 8);
   2019         payload!(u16, "16", 16);
   2020         payload!(u32, "32", 32);
   2021         payload!(u64, "64", 64);
   2022         payload!(u128, "128", 128);
   2023         payload!(f32, "1.5", 1.5);
   2024         payload!(f64, "2.5", 2.5);
   2025         payload!(char, r#""r""#, 'r');
   2026         payload!(String, r#""text""#, "text".to_owned());
   2027         payload!(Option<u32>, "7", Some(7));
   2028         payload!([u8; 3], "[1,2,3]", [1, 2, 3]);
   2029         payload!((u8, bool), "[4,true]", (4, true));
   2030         payload!(NewtypePayload, "9", NewtypePayload(9));
   2031         payload!(
   2032             TuplePayload,
   2033             r#"[5,"tuple"]"#,
   2034             TuplePayload(5, "tuple".to_owned())
   2035         );
   2036         payload!(
   2037             StructPayload,
   2038             r#"{"enabled":true,"count":11}"#,
   2039             StructPayload {
   2040                 enabled: true,
   2041                 count: 11,
   2042             }
   2043         );
   2044         payload!(EnumPayload, r#""Unit""#, EnumPayload::Unit);
   2045         payload!(EnumPayload, r#"{"Newtype":12}"#, EnumPayload::Newtype(12));
   2046         payload!(
   2047             EnumPayload,
   2048             r#"{"Tuple":[13,false]}"#,
   2049             EnumPayload::Tuple(13, false)
   2050         );
   2051         payload!(
   2052             EnumPayload,
   2053             r#"{"Struct":{"label":"enum"}}"#,
   2054             EnumPayload::Struct {
   2055                 label: "enum".to_owned(),
   2056             }
   2057         );
   2058         payload!(AnyPayload, r#""any""#, AnyPayload("any".to_owned()));
   2059         payload!(
   2060             BTreeMap<String, u8>,
   2061             r#"{"first":1,"second":2}"#,
   2062             BTreeMap::from([("first".to_owned(), 1), ("second".to_owned(), 2)])
   2063         );
   2064 
   2065         let bytes = serde::de::value::BytesDeserializer::<serde::de::value::Error>::new(&[1, 2, 3]);
   2066         assert_eq!(
   2067             ByteBufferPayload::deserialize(NoNullDeserializer(bytes)).unwrap(),
   2068             ByteBufferPayload(vec![1, 2, 3])
   2069         );
   2070 
   2071         assert!(serde_json::from_str::<NonNullPayload<()>>("null").is_err());
   2072         assert!(serde_json::from_str::<NonNullPayload<Option<u8>>>("null").is_err());
   2073         assert!(serde_json::from_str::<NonNullPayload<Vec<Option<u8>>>>("[1,null]").is_err());
   2074         assert!(
   2075             serde_json::from_str::<NonNullPayload<BTreeMap<String, Option<u8>>>>(
   2076                 r#"{"safe":1,"forbidden":null}"#,
   2077             )
   2078             .is_err()
   2079         );
   2080     }
   2081 
   2082     #[test]
   2083     fn unknown_version_maps_to_the_stable_failure_response() {
   2084         let request: AdminMutationRequest<ExampleRequest> = serde_json::from_str(
   2085             r#"{"contract_version":2,"operation_id":"stable-operation","request":{"value":7}}"#,
   2086         )
   2087         .unwrap();
   2088         let mismatch = request.validate_contract_version().unwrap_err();
   2089         assert_eq!(mismatch.received(), 2);
   2090         let response = mismatch.response(correlation_id());
   2091         assert_eq!(
   2092             serde_json::to_string(&response).unwrap(),
   2093             r#"{"contract_version":1,"ok":false,"correlation_id":"safe-correlation","error":{"code":"unsupported_contract_version","message":"admin contract version is unsupported"}}"#
   2094         );
   2095     }
   2096 
   2097     #[test]
   2098     fn invalid_ids_codes_messages_and_literals_fail_closed() {
   2099         assert_eq!(
   2100             AdminOperationId::new("").unwrap_err(),
   2101             AdminIdentifierError::Empty {
   2102                 field: AdminIdentifierField::OperationId
   2103             }
   2104         );
   2105         assert!(AdminOperationId::new("x".repeat(ADMIN_OPERATION_ID_MAX_UTF8_BYTES)).is_ok());
   2106         assert!(AdminOperationId::new("x".repeat(ADMIN_OPERATION_ID_MAX_UTF8_BYTES + 1)).is_err());
   2107         for valid in ["a", "Z9", "a.b_c:d-e"] {
   2108             assert!(AdminOperationId::new(valid).is_ok());
   2109             assert!(AdminCorrelationId::new(valid).is_ok());
   2110         }
   2111         let maximum = "0".repeat(ADMIN_OPERATION_ID_MAX_UTF8_BYTES);
   2112         assert!(AdminOperationId::new(&maximum).is_ok());
   2113         assert!(AdminCorrelationId::new(&maximum).is_ok());
   2114         for invalid in [
   2115             ".first", "_first", ":first", "-first", "é", "a/b", "a b", "a\n",
   2116         ] {
   2117             assert!(AdminOperationId::new(invalid).is_err());
   2118             assert!(AdminCorrelationId::new(invalid).is_err());
   2119         }
   2120         assert_eq!(
   2121             AdminOperationId::new("-first").unwrap_err(),
   2122             AdminIdentifierError::InvalidFirstCharacter {
   2123                 field: AdminIdentifierField::OperationId
   2124             }
   2125         );
   2126         assert_eq!(
   2127             AdminCorrelationId::new("a/b").unwrap_err(),
   2128             AdminIdentifierError::InvalidCharacter {
   2129                 field: AdminIdentifierField::CorrelationId
   2130             }
   2131         );
   2132         let redacted_operation = AdminOperationId::new("private-operation").unwrap();
   2133         let redacted_correlation = AdminCorrelationId::new("private-correlation").unwrap();
   2134         assert_eq!(
   2135             format!("{redacted_operation:?}"),
   2136             "AdminOperationId(\"[redacted]\")"
   2137         );
   2138         assert_eq!(
   2139             format!("{redacted_correlation:?}"),
   2140             "AdminCorrelationId(\"[redacted]\")"
   2141         );
   2142         assert_eq!(redacted_operation.as_str(), "private-operation");
   2143         assert_eq!(redacted_correlation.as_str(), "private-correlation");
   2144         assert_eq!(
   2145             serde_json::to_string(&redacted_operation).unwrap(),
   2146             "\"private-operation\""
   2147         );
   2148         assert_eq!(
   2149             serde_json::to_string(&redacted_correlation).unwrap(),
   2150             "\"private-correlation\""
   2151         );
   2152         for byte in 0_u8..=127 {
   2153             let character = char::from(byte);
   2154             let first = character.to_string();
   2155             let first_allowed = byte.is_ascii_alphanumeric();
   2156             assert_eq!(AdminOperationId::new(&first).is_ok(), first_allowed);
   2157             assert_eq!(AdminCorrelationId::new(&first).is_ok(), first_allowed);
   2158 
   2159             let remaining = format!("a{character}");
   2160             let remaining_allowed =
   2161                 byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'_' | b':' | b'-');
   2162             assert_eq!(AdminOperationId::new(&remaining).is_ok(), remaining_allowed);
   2163             assert_eq!(
   2164                 AdminCorrelationId::new(&remaining).is_ok(),
   2165                 remaining_allowed
   2166             );
   2167         }
   2168         assert!(AdminErrorCode::new("valid_code_2").is_ok());
   2169         assert!(AdminErrorCode::new("x".repeat(ADMIN_ERROR_CODE_MAX_UTF8_BYTES)).is_ok());
   2170         assert!(AdminErrorCode::new("Invalid-Code").is_err());
   2171         assert!(AdminErrorCode::new("valid-code").is_err());
   2172         assert!(AdminErrorMessage::new("x".repeat(ADMIN_ERROR_MESSAGE_MAX_UTF8_BYTES)).is_ok());
   2173         assert!(
   2174             AdminErrorMessage::new("x".repeat(ADMIN_ERROR_MESSAGE_MAX_UTF8_BYTES + 1)).is_err()
   2175         );
   2176         assert!(AdminErrorMessage::new("unsafe\nmessage").is_err());
   2177 
   2178         let very_large = "x".repeat(4 * 1024 * 1024);
   2179         assert!(AdminOperationId::new(&very_large).is_err());
   2180         assert!(AdminCorrelationId::new(&very_large).is_err());
   2181         assert!(AdminErrorCode::new(&very_large).is_err());
   2182         assert!(AdminErrorMessage::new(&very_large).is_err());
   2183         let very_large_json = serde_json::to_string(&very_large).expect("large admin JSON string");
   2184         assert!(serde_json::from_str::<AdminOperationId>(&very_large_json).is_err());
   2185         assert!(serde_json::from_str::<AdminCorrelationId>(&very_large_json).is_err());
   2186         assert!(serde_json::from_str::<AdminErrorCode>(&very_large_json).is_err());
   2187         assert!(serde_json::from_str::<AdminErrorMessage>(&very_large_json).is_err());
   2188 
   2189         let wrong_success: Result<AdminSuccessResponse<ExampleResult>, _> = serde_json::from_str(
   2190             r#"{"contract_version":1,"ok":false,"correlation_id":"safe-correlation","result":{"state":"committed"}}"#,
   2191         );
   2192         assert!(wrong_success.is_err());
   2193         let wrong_failure: Result<AdminFailureResponse, _> = serde_json::from_str(
   2194             r#"{"contract_version":1,"ok":true,"correlation_id":"safe-correlation","error":{"code":"valid_code","message":"safe"}}"#,
   2195         );
   2196         assert!(wrong_failure.is_err());
   2197         let wrong_version: Result<AdminFailureResponse, _> = serde_json::from_str(
   2198             r#"{"contract_version":2,"ok":false,"correlation_id":"safe-correlation","error":{"code":"valid_code","message":"safe"}}"#,
   2199         );
   2200         assert!(wrong_version.is_err());
   2201     }
   2202 
   2203     #[test]
   2204     fn public_accessors_and_stable_errors_are_fully_bound() {
   2205         let operation = operation_id();
   2206         let correlation = correlation_id();
   2207         let request = AdminMutationRequest::new(
   2208             operation.clone(),
   2209             Some(correlation.clone()),
   2210             ExampleRequest { value: 17 },
   2211         )
   2212         .unwrap();
   2213         assert_eq!(request.contract_version(), ADMIN_CONTRACT_VERSION);
   2214         assert_eq!(request.operation_id(), &operation);
   2215         assert_eq!(request.correlation_id(), Some(&correlation));
   2216         assert_eq!(request.request().value, 17);
   2217         assert!(request.validate_contract_version().is_ok());
   2218         assert_eq!(request.into_request(), ExampleRequest { value: 17 });
   2219 
   2220         let success = AdminSuccessResponse::new(
   2221             correlation.clone(),
   2222             ExampleResult {
   2223                 state: "ready".to_owned(),
   2224             },
   2225         )
   2226         .unwrap();
   2227         assert_eq!(success.correlation_id(), &correlation);
   2228         assert_eq!(success.result().state, "ready");
   2229         assert_eq!(success.into_result().state, "ready");
   2230 
   2231         let error = AdminError::new(
   2232             AdminErrorCode::new("stable_error").unwrap(),
   2233             AdminErrorMessage::new("stable message").unwrap(),
   2234         );
   2235         assert_eq!(error.code().as_str(), "stable_error");
   2236         assert_eq!(error.message().as_str(), "stable message");
   2237         assert_eq!(error.code().to_string(), "stable_error");
   2238         assert_eq!(error.message().to_string(), "stable message");
   2239         let failure = AdminFailureResponse::new(correlation.clone(), error.clone());
   2240         assert_eq!(failure.correlation_id(), &correlation);
   2241         assert_eq!(failure.error(), &error);
   2242 
   2243         for rendered in [
   2244             AdminIdentifierError::Empty {
   2245                 field: AdminIdentifierField::CorrelationId,
   2246             }
   2247             .to_string(),
   2248             AdminErrorCodeError::Empty.to_string(),
   2249             AdminErrorMessageError::Empty.to_string(),
   2250             AdminPayloadError::NullForbidden.to_string(),
   2251             AdminPayloadError::Encoding.to_string(),
   2252             AdminContractVersionError { received: 9 }.to_string(),
   2253         ] {
   2254             assert!(!rendered.is_empty());
   2255         }
   2256         assert_eq!(operation.as_str(), "stable-operation");
   2257         assert_eq!(correlation.as_str(), "safe-correlation");
   2258         assert!(AdminErrorCode::new("").is_err());
   2259         assert!(AdminErrorCode::new("x".repeat(ADMIN_ERROR_CODE_MAX_UTF8_BYTES + 1)).is_err());
   2260         assert!(AdminErrorMessage::new("").is_err());
   2261     }
   2262 
   2263     #[test]
   2264     fn duplicate_unknown_and_null_fields_are_rejected() {
   2265         for document in [
   2266             r#"{"contract_version":1,"contract_version":1,"operation_id":"stable-operation","request":{"value":7}}"#,
   2267             r#"{"contract_version":1,"operation_id":"stable-operation","unknown":true,"request":{"value":7}}"#,
   2268             r#"{"contract_version":1,"operation_id":"stable-operation","correlation_id":null,"request":{"value":7}}"#,
   2269             r#"{"contract_version":1,"operation_id":"stable-operation","request":{"value":7,"unknown":true}}"#,
   2270         ] {
   2271             assert!(
   2272                 serde_json::from_str::<AdminMutationRequest<ExampleRequest>>(document).is_err()
   2273             );
   2274         }
   2275 
   2276         assert!(
   2277             serde_json::from_str::<AdminMutationRequest<Option<ExampleRequest>>>(
   2278                 r#"{"contract_version":1,"operation_id":"stable-operation","request":null}"#,
   2279             )
   2280             .is_err()
   2281         );
   2282         assert!(
   2283             serde_json::from_str::<AdminSuccessResponse<Option<ExampleResult>>>(
   2284                 r#"{"contract_version":1,"ok":true,"correlation_id":"safe-correlation","result":null}"#,
   2285             )
   2286             .is_err()
   2287         );
   2288         assert!(matches!(
   2289             AdminMutationRequest::new(operation_id(), None, Option::<ExampleRequest>::None),
   2290             Err(AdminPayloadError::NullForbidden)
   2291         ));
   2292         assert!(matches!(
   2293             AdminSuccessResponse::new(correlation_id(), Option::<ExampleResult>::None),
   2294             Err(AdminPayloadError::NullForbidden)
   2295         ));
   2296     }
   2297 
   2298     #[derive(Serialize)]
   2299     struct SensitivePayload {
   2300         credential: String,
   2301     }
   2302 
   2303     struct NullNormalizingPayload;
   2304 
   2305     impl Serialize for NullNormalizingPayload {
   2306         fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
   2307         where
   2308             S: Serializer,
   2309         {
   2310             serializer.serialize_str("normalized")
   2311         }
   2312     }
   2313 
   2314     impl<'de> Deserialize<'de> for NullNormalizingPayload {
   2315         fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   2316         where
   2317             D: Deserializer<'de>,
   2318         {
   2319             Option::<de::IgnoredAny>::deserialize(deserializer)?;
   2320             Ok(Self)
   2321         }
   2322     }
   2323 
   2324     #[test]
   2325     fn raw_null_is_rejected_before_a_payload_can_normalize_it() {
   2326         assert!(
   2327             serde_json::from_str::<AdminMutationRequest<NullNormalizingPayload>>(
   2328                 r#"{"contract_version":1,"operation_id":"stable-operation","request":null}"#,
   2329             )
   2330             .is_err()
   2331         );
   2332         assert!(
   2333             serde_json::from_str::<AdminSuccessResponse<NullNormalizingPayload>>(
   2334                 r#"{"contract_version":1,"ok":true,"correlation_id":"safe-correlation","result":null}"#,
   2335             )
   2336             .is_err()
   2337         );
   2338     }
   2339 
   2340     struct IgnoredNestedNull;
   2341 
   2342     impl Serialize for IgnoredNestedNull {
   2343         fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
   2344         where
   2345             S: Serializer,
   2346         {
   2347             let mut structure = serializer.serialize_struct("IgnoredNestedNull", 1)?;
   2348             let _ = ser::SerializeStruct::serialize_field(
   2349                 &mut structure,
   2350                 "ignored",
   2351                 &Option::<u8>::None,
   2352             );
   2353             ser::SerializeStruct::end(structure)
   2354         }
   2355     }
   2356 
   2357     #[test]
   2358     fn construction_rejects_a_nested_null_even_when_custom_serialization_ignores_the_error() {
   2359         assert!(matches!(
   2360             AdminSuccessResponse::new(correlation_id(), IgnoredNestedNull),
   2361             Err(AdminPayloadError::NullForbidden)
   2362         ));
   2363 
   2364         let raw = serde_json::value::RawValue::from_string("null".to_owned()).unwrap();
   2365         assert!(matches!(
   2366             AdminSuccessResponse::new(correlation_id(), raw),
   2367             Err(AdminPayloadError::NullForbidden)
   2368         ));
   2369 
   2370         let raw = serde_json::value::RawValue::from_string(
   2371             r#"{"null":"escaped \"null\" text"}"#.to_owned(),
   2372         )
   2373         .unwrap();
   2374         assert!(AdminSuccessResponse::new(correlation_id(), raw).is_ok());
   2375 
   2376         let mut writer = NonNullJsonWriter::default();
   2377         assert_eq!(std::io::Write::write(&mut writer, b"nu").unwrap(), 2);
   2378         assert!(std::io::Write::write(&mut writer, b"ll").is_err());
   2379         assert!(std::io::Write::write(&mut writer, b"true").is_err());
   2380     }
   2381 
   2382     #[test]
   2383     fn ordinary_debug_redacts_request_and_result_payloads() {
   2384         let request = AdminMutationRequest::new(
   2385             operation_id(),
   2386             Some(correlation_id()),
   2387             SensitivePayload {
   2388                 credential: "secret request credential".to_owned(),
   2389             },
   2390         )
   2391         .unwrap();
   2392         let response = AdminSuccessResponse::new(
   2393             correlation_id(),
   2394             SensitivePayload {
   2395                 credential: "secret response credential".to_owned(),
   2396             },
   2397         )
   2398         .unwrap();
   2399 
   2400         let request_debug = format!("{request:?}");
   2401         let response_debug = format!("{response:?}");
   2402         assert!(request_debug.contains("<redacted>"));
   2403         assert!(response_debug.contains("<redacted>"));
   2404         assert!(!request_debug.contains("secret request"));
   2405         assert!(!response_debug.contains("secret response"));
   2406     }
   2407 
   2408     #[test]
   2409     fn payload_encoding_failure_has_only_a_stable_crate_owned_error() {
   2410         let unsupported_json_map_key = std::collections::BTreeMap::from([((1_u8, 2_u8), true)]);
   2411         let error = AdminMutationRequest::new(operation_id(), None, unsupported_json_map_key)
   2412             .expect_err("tuple map key must not encode as JSON");
   2413 
   2414         assert_eq!(error, AdminPayloadError::Encoding);
   2415         assert_eq!(format!("{error:?}"), "Encoding");
   2416         assert!(error.source().is_none());
   2417     }
   2418 
   2419     #[derive(Debug)]
   2420     struct SensitiveCause;
   2421 
   2422     impl fmt::Display for SensitiveCause {
   2423         fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
   2424             formatter.write_str("database password and raw SQL")
   2425         }
   2426     }
   2427 
   2428     impl Error for SensitiveCause {}
   2429 
   2430     #[test]
   2431     fn host_error_mapping_preserves_only_the_safe_projection() {
   2432         let internal = HostError::with_source(HostErrorKind::TaskFailure, SensitiveCause);
   2433         let response =
   2434             AdminFailureResponse::new(correlation_id(), AdminError::from_host_error(&internal));
   2435         let encoded = serde_json::to_string(&response).unwrap();
   2436 
   2437         assert_eq!(
   2438             encoded,
   2439             r#"{"contract_version":1,"ok":false,"correlation_id":"safe-correlation","error":{"code":"host_task_failure","message":"authoritative service task failed"}}"#
   2440         );
   2441         assert!(!encoded.contains("password"));
   2442         assert!(!encoded.contains("SQL"));
   2443     }
   2444 }