webauthn_rp

WebAuthn Level 3 RP library.
git clone https://git.philomathiclife.com/repos/webauthn_rp
Log | Files | Refs | README

ser.rs (48010B)


      1 #![expect(
      2     clippy::question_mark_used,
      3     reason = "noisy, opinionated, and likely doesn't prevent bugs or improve APIs"
      4 )]
      5 extern crate alloc;
      6 use super::{
      7     AllAcceptedCredentialsOptions, AuthTransports, AuthenticatorAttachment, AuthenticatorTransport,
      8     Challenge, CredentialId, CurrentUserDetailsOptions, Origin, SentChallenge,
      9 };
     10 use alloc::borrow::Cow;
     11 use core::{
     12     fmt::{self, Formatter},
     13     marker::PhantomData,
     14 };
     15 use data_encoding::BASE64URL_NOPAD;
     16 use serde::{
     17     de::{Deserialize, Deserializer, Error, IgnoredAny, MapAccess, SeqAccess, Unexpected, Visitor},
     18     ser::{Serialize, SerializeSeq as _, SerializeStruct as _, Serializer},
     19 };
     20 /// [`"ble"`](https://www.w3.org/TR/webauthn-3/#dom-authenticatortransport-ble).
     21 const BLE: &str = "ble";
     22 /// [`"hybrid"`](https://www.w3.org/TR/webauthn-3/#dom-authenticatortransport-hybrid).
     23 const HYBRID: &str = "hybrid";
     24 /// [`"internal"`](https://www.w3.org/TR/webauthn-3/#dom-authenticatortransport-internal).
     25 const INTERNAL: &str = "internal";
     26 /// [`"nfc"`](https://www.w3.org/TR/webauthn-3/#dom-authenticatortransport-nfc).
     27 const NFC: &str = "nfc";
     28 /// [`"smart-card"`](https://www.w3.org/TR/webauthn-3/#dom-authenticatortransport-smart-card).
     29 const SMART_CARD: &str = "smart-card";
     30 /// [`"usb"`](https://www.w3.org/TR/webauthn-3/#dom-authenticatortransport-usb).
     31 const USB: &str = "usb";
     32 impl Serialize for AuthenticatorTransport {
     33     /// Serializes `self` as
     34     /// [`AuthenticatorTransport`](https://www.w3.org/TR/webauthn-3/#enumdef-authenticatortransport).
     35     ///
     36     /// # Examples
     37     ///
     38     /// ```
     39     /// # use webauthn_rp::response::AuthenticatorTransport;
     40     /// assert_eq!(
     41     ///     serde_json::to_string(&AuthenticatorTransport::Usb)?,
     42     ///     r#""usb""#
     43     /// );
     44     /// # Ok::<_, serde_json::Error>(())
     45     /// ```
     46     #[inline]
     47     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     48     where
     49         S: Serializer,
     50     {
     51         serializer.serialize_str(match *self {
     52             Self::Ble => BLE,
     53             Self::Hybrid => HYBRID,
     54             Self::Internal => INTERNAL,
     55             Self::Nfc => NFC,
     56             Self::SmartCard => SMART_CARD,
     57             Self::Usb => USB,
     58         })
     59     }
     60 }
     61 impl<'de> Deserialize<'de> for AuthenticatorTransport {
     62     /// Deserializes [`prim@str`] based on
     63     /// [`AuthenticatorTransport`](https://www.w3.org/TR/webauthn-3/#enumdef-authenticatortransport).
     64     ///
     65     /// # Examples
     66     ///
     67     /// ```
     68     /// # use webauthn_rp::response::AuthenticatorTransport;
     69     /// assert!(matches!(
     70     ///     serde_json::from_str::<AuthenticatorTransport>(r#""usb""#)?,
     71     ///     AuthenticatorTransport::Usb
     72     /// ));
     73     /// // Case matters.
     74     /// assert!(serde_json::from_str::<AuthenticatorTransport>(r#""Usb""#).is_err());
     75     /// # Ok::<_, serde_json::Error>(())
     76     /// ```
     77     #[inline]
     78     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     79     where
     80         D: Deserializer<'de>,
     81     {
     82         /// `Visitor` for `AuthenticatorTransport`.
     83         struct AuthenticatorTransportVisitor;
     84         impl Visitor<'_> for AuthenticatorTransportVisitor {
     85             type Value = AuthenticatorTransport;
     86             fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
     87                 formatter.write_str("AuthenticatorTransport")
     88             }
     89             fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
     90             where
     91                 E: Error,
     92             {
     93                 match v {
     94                     BLE => Ok(AuthenticatorTransport::Ble),
     95                     HYBRID => Ok(AuthenticatorTransport::Hybrid),
     96                     INTERNAL => Ok(AuthenticatorTransport::Internal),
     97                     NFC => Ok(AuthenticatorTransport::Nfc),
     98                     SMART_CARD => Ok(AuthenticatorTransport::SmartCard),
     99                     USB => Ok(AuthenticatorTransport::Usb),
    100                     _ => Err(E::invalid_value(
    101                         Unexpected::Str(v),
    102                         &format!(
    103                             "'{BLE}', '{HYBRID}', '{INTERNAL}', '{NFC}', '{SMART_CARD}', or '{USB}'"
    104                         )
    105                         .as_str(),
    106                     )),
    107                 }
    108             }
    109         }
    110         deserializer.deserialize_str(AuthenticatorTransportVisitor)
    111     }
    112 }
    113 impl Serialize for AuthTransports {
    114     /// Serializes `self` based on
    115     /// [`transports`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialdescriptor-transports).
    116     ///
    117     /// # Examples
    118     ///
    119     /// ```
    120     /// # use webauthn_rp::response::{AuthTransports, AuthenticatorTransport};
    121     /// # #[cfg(feature = "custom")]
    122     /// assert_eq!(
    123     ///     serde_json::to_string(&AuthTransports::ALL)?,
    124     ///     r#"["ble","hybrid","internal","nfc","smart-card","usb"]"#
    125     /// );
    126     /// # Ok::<_, serde_json::Error>(())
    127     /// ```
    128     #[expect(clippy::unreachable, reason = "there is a bug, so we want to crash")]
    129     #[inline]
    130     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    131     where
    132         S: Serializer,
    133     {
    134         let count = usize::try_from(self.count())
    135             .unwrap_or_else(|_e| unreachable!("there is a bug in AuthenticatorTransports::count"));
    136         serializer.serialize_seq(Some(count)).and_then(|mut ser| {
    137             if self.contains(AuthenticatorTransport::Ble) {
    138                 ser.serialize_element(&AuthenticatorTransport::Ble)
    139             } else {
    140                 Ok(())
    141             }
    142             .and_then(|()| {
    143                 if self.contains(AuthenticatorTransport::Hybrid) {
    144                     ser.serialize_element(&AuthenticatorTransport::Hybrid)
    145                 } else {
    146                     Ok(())
    147                 }
    148                 .and_then(|()| {
    149                     if self.contains(AuthenticatorTransport::Internal) {
    150                         ser.serialize_element(&AuthenticatorTransport::Internal)
    151                     } else {
    152                         Ok(())
    153                     }
    154                     .and_then(|()| {
    155                         if self.contains(AuthenticatorTransport::Nfc) {
    156                             ser.serialize_element(&AuthenticatorTransport::Nfc)
    157                         } else {
    158                             Ok(())
    159                         }
    160                         .and_then(|()| {
    161                             if self.contains(AuthenticatorTransport::SmartCard) {
    162                                 ser.serialize_element(&AuthenticatorTransport::SmartCard)
    163                             } else {
    164                                 Ok(())
    165                             }
    166                             .and_then(|()| {
    167                                 if self.contains(AuthenticatorTransport::Usb) {
    168                                     ser.serialize_element(&AuthenticatorTransport::Usb)
    169                                 } else {
    170                                     Ok(())
    171                                 }
    172                                 .and_then(|()| ser.end())
    173                             })
    174                         })
    175                     })
    176                 })
    177             })
    178         })
    179     }
    180 }
    181 impl<'de> Deserialize<'de> for AuthTransports {
    182     /// Deserializes a sequence based on
    183     /// [`transports`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialdescriptor-transports).
    184     ///
    185     /// # Examples
    186     ///
    187     /// ```
    188     /// # use webauthn_rp::response::{AuthTransports, AuthenticatorTransport};
    189     /// # #[cfg(feature = "custom")]
    190     /// assert_eq!(
    191     ///     serde_json::from_str::<AuthTransports>(
    192     ///         r#"["ble","hybrid","internal","nfc","smart-card","usb"]"#
    193     ///     )
    194     ///     ?.count(),
    195     ///     6
    196     /// );
    197     /// // Errors since `"foo"` is not valid.
    198     /// assert!(serde_json::from_str::<AuthTransports>(r#"["foo"]"#).is_err());
    199     /// # Ok::<_, serde_json::Error>(())
    200     /// ```
    201     #[inline]
    202     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    203     where
    204         D: Deserializer<'de>,
    205     {
    206         /// `Visitor` for `AuthTransports`.
    207         struct AuthTransportsVisitor;
    208         impl<'d> Visitor<'d> for AuthTransportsVisitor {
    209             type Value = AuthTransports;
    210             fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    211                 formatter.write_str("AuthTransports")
    212             }
    213             fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
    214             where
    215                 A: SeqAccess<'d>,
    216             {
    217                 let mut transports = AuthTransports::new();
    218                 while let Some(val) = seq.next_element::<AuthenticatorTransport>()? {
    219                     transports = transports.add_transport(val);
    220                 }
    221                 Ok(transports)
    222             }
    223         }
    224         deserializer.deserialize_seq(AuthTransportsVisitor)
    225     }
    226 }
    227 impl<T: AsRef<[u8]>> Serialize for CredentialId<T> {
    228     /// Serializes `self` into a [`prim@str`] based on
    229     /// [`id`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialdescriptorjson-id).
    230     ///
    231     /// # Examples
    232     ///
    233     /// ```
    234     /// # use webauthn_rp::response::CredentialId;
    235     /// // `CredentialId::try_from` only exists when `custom` is enabled; and even then, it is
    236     /// // likely never needed since the `CredentialId` was originally sent from the client and is likely
    237     /// // stored in a database which would be fetched by `UserHandle` or `Authentication::raw_id`.
    238     /// # #[cfg(feature = "custom")]
    239     /// assert_eq!(
    240     ///     serde_json::to_string(&CredentialId::try_from(vec![0; 16])?).unwrap(),
    241     ///     r#""AAAAAAAAAAAAAAAAAAAAAA""#
    242     /// );
    243     /// # Ok::<_, webauthn_rp::AggErr>(())
    244     ///```
    245     #[inline]
    246     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    247     where
    248         S: Serializer,
    249     {
    250         serializer.serialize_str(BASE64URL_NOPAD.encode(self.0.as_ref()).as_str())
    251     }
    252 }
    253 impl<'de> Deserialize<'de> for CredentialId<Vec<u8>> {
    254     /// Deserializes [`prim@str`] based on
    255     /// [`id`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialdescriptorjson-id).
    256     ///
    257     /// # Examples
    258     ///
    259     /// ```
    260     /// # use webauthn_rp::response::CredentialId;
    261     /// # #[cfg(feature = "custom")]
    262     /// assert_eq!(
    263     ///     serde_json::from_str::<CredentialId<_>>(r#""AAAAAAAAAAAAAAAAAAAAAA""#).unwrap(),
    264     ///     CredentialId::try_from(vec![0; 16])?
    265     /// );
    266     /// # Ok::<_, webauthn_rp::AggErr>(())
    267     ///```
    268     #[inline]
    269     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    270     where
    271         D: Deserializer<'de>,
    272     {
    273         /// `Visitor` for `CredentialId`.
    274         struct CredentialIdVisitor;
    275         impl Visitor<'_> for CredentialIdVisitor {
    276             type Value = CredentialId<Vec<u8>>;
    277             fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    278                 formatter.write_str("CredentialId")
    279             }
    280             #[expect(clippy::unreachable, reason = "we want to crash when there is a bug")]
    281             fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    282             where
    283                 E: Error,
    284             {
    285                 // Any value between `super::CRED_ID_MIN_LEN` and `super::CRED_ID_MIN_LEN` can be base64url encoded
    286                 // without fear since that range is just 16 to 1023, and
    287                 // 4/3 of 1023 is less than `usize::MAX`.
    288                 if (crate::base64url_nopad_len(super::CRED_ID_MIN_LEN).unwrap_or_else(|| {
    289                     unreachable!("there is a bug in webauthn_rp::base64url_nopad_len")
    290                 })
    291                     ..=crate::base64url_nopad_len(super::CRED_ID_MAX_LEN).unwrap_or_else(|| {
    292                         unreachable!("there is a bug in webauthn_rp::base64url_nopad_len")
    293                     }))
    294                     .contains(&v.len())
    295                 {
    296                     BASE64URL_NOPAD
    297                         .decode(v.as_bytes())
    298                         .map_err(E::custom)
    299                         .map(CredentialId)
    300                 } else {
    301                     Err(E::invalid_value(
    302                         Unexpected::Str(v),
    303                         &"16 to 1023 bytes encoded in base64url without padding",
    304                     ))
    305                 }
    306             }
    307         }
    308         deserializer.deserialize_str(CredentialIdVisitor)
    309     }
    310 }
    311 impl<'de> Deserialize<'de> for AuthenticatorAttachment {
    312     /// Deserializes [`prim@str`] based on
    313     /// [`AuthenticatorAttachment`](https://www.w3.org/TR/webauthn-3/#enumdef-authenticatorattachment).
    314     ///
    315     /// # Examples
    316     ///
    317     /// ```
    318     /// # use webauthn_rp::response::AuthenticatorAttachment;
    319     /// assert!(matches!(
    320     ///     serde_json::from_str::<AuthenticatorAttachment>(r#""cross-platform""#)?,
    321     ///     AuthenticatorAttachment::CrossPlatform)
    322     /// );
    323     /// assert!(matches!(
    324     ///     serde_json::from_str::<AuthenticatorAttachment>(r#""platform""#)?,
    325     ///     AuthenticatorAttachment::Platform)
    326     /// );
    327     /// // Case matters.
    328     /// assert!(serde_json::from_str::<AuthenticatorAttachment>(r#""Platform""#).is_err());
    329     /// // `AuthenticatorAttachment::None` is not deserializable.
    330     /// assert!(serde_json::from_str::<AuthenticatorAttachment>(r#""""#).is_err());
    331     /// assert!(serde_json::from_str::<AuthenticatorAttachment>("null").is_err());
    332     /// assert!(serde_json::from_str::<AuthenticatorAttachment>(r#""none""#).is_err());
    333     /// assert!(serde_json::from_str::<AuthenticatorAttachment>(r#""None""#).is_err());
    334     /// # Ok::<_, serde_json::Error>(())
    335     ///```
    336     #[inline]
    337     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    338     where
    339         D: Deserializer<'de>,
    340     {
    341         /// `Visitor` for `AuthenticatorAttachment`.
    342         struct AuthenticatorAttachmentVisitor;
    343         impl Visitor<'_> for AuthenticatorAttachmentVisitor {
    344             type Value = AuthenticatorAttachment;
    345             fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    346                 formatter.write_str("AuthenticatorAttachment")
    347             }
    348             fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    349             where
    350                 E: Error,
    351             {
    352                 /// `"platform"`
    353                 const PLATFORM: &str = "platform";
    354                 /// `"cross-platform"`
    355                 const CROSS_PLATFORM: &str = "cross-platform";
    356                 match v {
    357                     PLATFORM => Ok(AuthenticatorAttachment::Platform),
    358                     CROSS_PLATFORM => Ok(AuthenticatorAttachment::CrossPlatform),
    359                     _ => Err(E::invalid_value(
    360                         Unexpected::Str(v),
    361                         &format!("'{PLATFORM}' or '{CROSS_PLATFORM}'").as_str(),
    362                     )),
    363                 }
    364             }
    365         }
    366         deserializer.deserialize_str(AuthenticatorAttachmentVisitor)
    367     }
    368 }
    369 /// Container of data that was encoded in base64url.
    370 pub(super) struct Base64DecodedVal(pub Vec<u8>);
    371 impl<'de> Deserialize<'de> for Base64DecodedVal {
    372     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    373     where
    374         D: Deserializer<'de>,
    375     {
    376         /// `Visitor` for `Base64DecodedVal`.
    377         struct Base64DecodedValVisitor;
    378         impl Visitor<'_> for Base64DecodedValVisitor {
    379             type Value = Base64DecodedVal;
    380             fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    381                 formatter.write_str("base64url-encoded data")
    382             }
    383             fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    384             where
    385                 E: Error,
    386             {
    387                 BASE64URL_NOPAD
    388                     .decode(v.as_bytes())
    389                     .map_err(E::custom)
    390                     .map(Base64DecodedVal)
    391             }
    392         }
    393         deserializer.deserialize_str(Base64DecodedValVisitor)
    394     }
    395 }
    396 impl<'de> Deserialize<'de> for SentChallenge {
    397     /// Deserializes `[u8]` or [`prim@str`] based on
    398     /// [`challenge`](https://www.w3.org/TR/webauthn-3/#dom-collectedclientdata-challenge).
    399     ///
    400     /// Specifically a `[u8]` or `str` is base64url-decoded and interpreted as a little-endian
    401     /// `u128`.
    402     ///
    403     /// # Examples
    404     ///
    405     /// ```
    406     /// # use webauthn_rp::response::SentChallenge;
    407     /// assert_eq!(
    408     ///     serde_json::from_slice::<SentChallenge>(br#""AAAAAAAAAAAAAAAAAAAAAA""#)?,
    409     ///     SentChallenge(0)
    410     /// );
    411     /// # Ok::<_, serde_json::Error>(())
    412     ///```
    413     #[inline]
    414     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    415     where
    416         D: Deserializer<'de>,
    417     {
    418         /// `Visitor` for `SentChallenge`.
    419         struct ChallengeVisitor;
    420         impl Visitor<'_> for ChallengeVisitor {
    421             type Value = SentChallenge;
    422             fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    423                 formatter.write_str(
    424                     "base64 encoding of the 16-byte challenge in a URL safe way without padding",
    425                 )
    426             }
    427             #[expect(
    428                 clippy::panic_in_result_fn,
    429                 reason = "we want to crash when there is a bug"
    430             )]
    431             #[expect(
    432                 clippy::little_endian_bytes,
    433                 reason = "SentChallenge::deserialize and Challenge::serialize need to be consistent across architectures"
    434             )]
    435             fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
    436             where
    437                 E: Error,
    438             {
    439                 if v.len() == Challenge::BASE64_LEN {
    440                     let mut data = [0; 16];
    441                     BASE64URL_NOPAD
    442                         .decode_mut(v, data.as_mut_slice())
    443                         .map_err(|err| E::custom(err.error))
    444                         .map(|len| {
    445                             assert_eq!(len, 16, "there is a bug in BASE64URL_NOPAD::decode_mut");
    446                             SentChallenge(u128::from_le_bytes(data))
    447                         })
    448                 } else {
    449                     Err(E::invalid_value(
    450                         Unexpected::Bytes(v),
    451                         &"22 bytes encoded in base64url without padding",
    452                     ))
    453                 }
    454             }
    455             fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    456             where
    457                 E: Error,
    458             {
    459                 self.visit_bytes(v.as_bytes())
    460             }
    461         }
    462         deserializer.deserialize_bytes(ChallengeVisitor)
    463     }
    464 }
    465 impl<'de: 'a, 'a> Deserialize<'de> for Origin<'a> {
    466     /// Deserializes [`prim@str`] by borrowing the data when possible.
    467     ///
    468     /// # Examples
    469     ///
    470     /// ```
    471     /// # extern crate alloc;
    472     /// # use alloc::borrow::Cow;
    473     /// # use webauthn_rp::response::Origin;
    474     /// let origin_borrowed = "https://example.com";
    475     /// let origin_owned = "\\\\https://example.com";
    476     /// assert!(
    477     ///     matches!(serde_json::from_str::<Origin<'_>>(format!("\"{origin_borrowed}\"").as_str())?.0, Cow::Borrowed(val) if val == origin_borrowed)
    478     /// );
    479     /// assert!(
    480     ///     matches!(serde_json::from_str::<Origin<'_>>(format!("\"{origin_owned}\"").as_str())?.0, Cow::Owned(val) if *val.as_bytes() == origin_owned.as_bytes()[1..])
    481     /// );
    482     /// # Ok::<_, serde_json::Error>(())
    483     ///```
    484     #[inline]
    485     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    486     where
    487         D: Deserializer<'de>,
    488     {
    489         /// `Visitor` for `Origin`.
    490         struct OriginVisitor<'b>(PhantomData<fn() -> &'b ()>);
    491         impl<'d: 'b, 'b> Visitor<'d> for OriginVisitor<'b> {
    492             type Value = Origin<'b>;
    493             fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    494                 formatter.write_str("Origin")
    495             }
    496             fn visit_borrowed_str<E>(self, v: &'d str) -> Result<Self::Value, E>
    497             where
    498                 E: Error,
    499             {
    500                 Ok(Origin(Cow::Borrowed(v)))
    501             }
    502             fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
    503             where
    504                 E: Error,
    505             {
    506                 Ok(Origin(Cow::Owned(v)))
    507             }
    508             fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    509             where
    510                 E: Error,
    511             {
    512                 self.visit_string(v.to_owned())
    513             }
    514         }
    515         deserializer.deserialize_str(OriginVisitor(PhantomData))
    516     }
    517 }
    518 /// `trait` that returns an empty instance of `Self`.
    519 pub(super) trait ClientExtensions: Sized {
    520     /// Returns an empty instance of `Self`.
    521     fn empty() -> Self;
    522 }
    523 /// Response for both registration and authentication ceremonies.
    524 ///
    525 /// [`Self::raw_id`] is always `Some` when `!RELAXED` or `!REG`.
    526 ///
    527 /// `RELAXED` and `REG` are used purely for deserialization purposes.
    528 pub(super) struct PublicKeyCredential<const RELAXED: bool, const REG: bool, AuthResp, Ext> {
    529     /// [`rawId`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredential-rawid).
    530     pub id: Option<CredentialId<Vec<u8>>>,
    531     /// [`response`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredential-response).
    532     pub response: AuthResp,
    533     /// [`authenticatorAttachment`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredential-authenticatorattachment).
    534     pub authenticator_attachment: AuthenticatorAttachment,
    535     /// [`getClientExtensionResults`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredential-getclientextensionresults).
    536     pub client_extension_results: Ext,
    537 }
    538 /// Deserializes the value for type.
    539 pub(super) struct Type;
    540 impl<'e> Deserialize<'e> for Type {
    541     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    542     where
    543         D: Deserializer<'e>,
    544     {
    545         /// `Visitor` for `Type`.
    546         struct TypeVisitor;
    547         impl Visitor<'_> for TypeVisitor {
    548             type Value = Type;
    549             fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    550                 formatter.write_str(PUBLIC_KEY)
    551             }
    552             fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    553             where
    554                 E: Error,
    555             {
    556                 if v == PUBLIC_KEY {
    557                     Ok(Type)
    558                 } else {
    559                     Err(E::invalid_value(Unexpected::Str(v), &PUBLIC_KEY))
    560                 }
    561             }
    562         }
    563         deserializer.deserialize_str(TypeVisitor)
    564     }
    565 }
    566 /// `Visitor` for `PublicKeyCredential`.
    567 ///
    568 /// When `!RELAXED`, `REG` is ignored and all fields must exist and unknown fields are not allowed.
    569 /// When `RELAXED`, unknown fields are ignored.
    570 /// When `RELAXED` and `REG`, only `response` is required.
    571 /// When `RELAXED` and `!REG`, only `id` and `response` are required.
    572 struct PublicKeyCredentialVisitor<const RELAXED: bool, const REG: bool, R, E>(
    573     pub PhantomData<fn() -> (R, E)>,
    574 );
    575 impl<'d, const REL: bool, const REGI: bool, R, E> Visitor<'d>
    576     for PublicKeyCredentialVisitor<REL, REGI, R, E>
    577 where
    578     R: Deserialize<'d>,
    579     E: for<'a> Deserialize<'a> + ClientExtensions,
    580 {
    581     type Value = PublicKeyCredential<REL, REGI, R, E>;
    582     fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    583         formatter.write_str("PublicKeyCredential")
    584     }
    585     #[expect(
    586         clippy::too_many_lines,
    587         reason = "rather hide all the internal logic instead instead of moving into an outer scope"
    588     )]
    589     fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
    590     where
    591         A: MapAccess<'d>,
    592     {
    593         /// `PublicKeyCredentialJSON` fields.
    594         enum Field<const IGNORE_UNKNOWN: bool> {
    595             /// `id`.
    596             Id,
    597             /// `type`.
    598             Type,
    599             /// `rawId`.
    600             RawId,
    601             /// `response`.
    602             Response,
    603             /// `authenticatorAttachment`.
    604             AuthenticatorAttachment,
    605             /// `clientExtensionResults`.
    606             ClientExtensionResults,
    607             /// Unknown field.
    608             Other,
    609         }
    610         impl<'e, const IGNORE: bool> Deserialize<'e> for Field<IGNORE> {
    611             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    612             where
    613                 D: Deserializer<'e>,
    614             {
    615                 /// `Visitor` for `Field`.
    616                 struct FieldVisitor<const IGNORE_UNKNOWN: bool>;
    617                 impl<const IGN: bool> Visitor<'_> for FieldVisitor<IGN> {
    618                     type Value = Field<IGN>;
    619                     fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    620                         write!(
    621                             formatter,
    622                             "'{ID}', '{TYPE}', '{RAW_ID}', '{RESPONSE}', '{AUTHENTICATOR_ATTACHMENT}', or '{CLIENT_EXTENSION_RESULTS}'"
    623                         )
    624                     }
    625                     fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    626                     where
    627                         E: Error,
    628                     {
    629                         match v {
    630                             ID => Ok(Field::Id),
    631                             TYPE => Ok(Field::Type),
    632                             RAW_ID => Ok(Field::RawId),
    633                             RESPONSE => Ok(Field::Response),
    634                             AUTHENTICATOR_ATTACHMENT => Ok(Field::AuthenticatorAttachment),
    635                             CLIENT_EXTENSION_RESULTS => Ok(Field::ClientExtensionResults),
    636                             _ => {
    637                                 if IGN {
    638                                     Ok(Field::Other)
    639                                 } else {
    640                                     Err(E::unknown_field(v, REG_FIELDS))
    641                                 }
    642                             }
    643                         }
    644                     }
    645                 }
    646                 deserializer.deserialize_identifier(FieldVisitor::<IGNORE>)
    647             }
    648         }
    649         let mut opt_id = None;
    650         let mut typ = false;
    651         let mut raw = None;
    652         let mut resp = None;
    653         let mut attach = None;
    654         let mut ext = None;
    655         while let Some(key) = map.next_key::<Field<REL>>()? {
    656             match key {
    657                 Field::Id => {
    658                     if opt_id.is_some() {
    659                         return Err(Error::duplicate_field(ID));
    660                     }
    661                     opt_id = map.next_value::<CredentialId<_>>().map(Some)?;
    662                 }
    663                 Field::Type => {
    664                     if typ {
    665                         return Err(Error::duplicate_field(TYPE));
    666                     }
    667                     typ = map.next_value::<Type>().map(|_| true)?;
    668                 }
    669                 Field::RawId => {
    670                     if raw.is_some() {
    671                         return Err(Error::duplicate_field(RAW_ID));
    672                     }
    673                     raw = map.next_value::<CredentialId<_>>().map(Some)?;
    674                 }
    675                 Field::Response => {
    676                     if resp.is_some() {
    677                         return Err(Error::duplicate_field(RESPONSE));
    678                     }
    679                     resp = map.next_value::<R>().map(Some)?;
    680                 }
    681                 Field::AuthenticatorAttachment => {
    682                     if attach.is_some() {
    683                         return Err(Error::duplicate_field(AUTHENTICATOR_ATTACHMENT));
    684                     }
    685                     attach = map.next_value().map(Some)?;
    686                 }
    687                 Field::ClientExtensionResults => {
    688                     if ext.is_some() {
    689                         return Err(Error::duplicate_field(CLIENT_EXTENSION_RESULTS));
    690                     }
    691                     ext = map.next_value::<Option<E>>().map(Some)?;
    692                 }
    693                 Field::Other => map.next_value::<IgnoredAny>().map(|_| ())?,
    694             }
    695         }
    696         resp.ok_or_else(|| Error::missing_field(RESPONSE))
    697             .and_then(|response| {
    698                 opt_id.map_or_else(
    699                     || {
    700                         if REL && REGI {
    701                             Ok(None)
    702                         } else {
    703                             Err(Error::missing_field(ID))
    704                         }
    705                     },
    706                     |id| Ok(Some(id)),
    707                 )
    708                 .and_then(|id| {
    709                     raw.map_or_else(
    710                         || {
    711                             if REL {
    712                                 Ok(())
    713                             } else {
    714                                 Err(Error::missing_field(RAW_ID))
    715                             }
    716                         },
    717                         |raw_id| {
    718                             id.as_ref().map_or_else(
    719                                 || Ok(()),
    720                                 |i| {
    721                                     if raw_id == i {
    722                                         Ok(())
    723                                     } else {
    724                                         Err(Error::invalid_value(
    725                                             Unexpected::Bytes(raw_id.as_ref()),
    726                                             &format!("{ID} and {RAW_ID} to match: {i:?}").as_str(),
    727                                         ))
    728                                     }
    729                                 },
    730                             )
    731                         }
    732                     )
    733                     .and_then(|()| {
    734                         ext.ok_or(false).and_then(|opt_ext| opt_ext.ok_or(true)).map_or_else(
    735                             |flag| {
    736                                 if REL {
    737                                     Ok(E::empty())
    738                                 } else if flag {
    739                                     Err(Error::invalid_type(Unexpected::Other("null"), &format!("{CLIENT_EXTENSION_RESULTS} to be a map of allowed client extensions").as_str()))
    740                                 } else {
    741                                     Err(Error::missing_field(CLIENT_EXTENSION_RESULTS))
    742                                 }
    743                             },
    744                             Ok
    745                         )
    746                         .and_then(|client_extension_results| {
    747                             if typ || REL {
    748                                 Ok(PublicKeyCredential {
    749                                     id,
    750                                     response,
    751                                     authenticator_attachment: attach.flatten().unwrap_or(AuthenticatorAttachment::None),
    752                                     client_extension_results,
    753                                 })
    754                             } else {
    755                                 Err(Error::missing_field(TYPE))
    756                             }
    757                         })
    758                     })
    759                 })
    760             })
    761     }
    762 }
    763 /// `"id"`.
    764 const ID: &str = "id";
    765 /// `"type"`.
    766 const TYPE: &str = "type";
    767 /// `"rawId"`.
    768 const RAW_ID: &str = "rawId";
    769 /// `"response"`.
    770 const RESPONSE: &str = "response";
    771 /// `"authenticatorAttachment"`.
    772 const AUTHENTICATOR_ATTACHMENT: &str = "authenticatorAttachment";
    773 /// `"clientExtensionResults"`.
    774 const CLIENT_EXTENSION_RESULTS: &str = "clientExtensionResults";
    775 /// `"public-key"`.
    776 const PUBLIC_KEY: &str = "public-key";
    777 /// Fields for `PublicKeyCredentialJSON`.
    778 const REG_FIELDS: &[&str; 6] = &[
    779     ID,
    780     TYPE,
    781     RAW_ID,
    782     RESPONSE,
    783     AUTHENTICATOR_ATTACHMENT,
    784     CLIENT_EXTENSION_RESULTS,
    785 ];
    786 impl<'de, const REL: bool, const REGI: bool, R, E> Deserialize<'de>
    787     for PublicKeyCredential<REL, REGI, R, E>
    788 where
    789     R: Deserialize<'de>,
    790     E: for<'a> Deserialize<'a> + ClientExtensions,
    791 {
    792     /// Deserializes a `struct` based on
    793     /// [`PublicKeyCredentialJSON`](https://www.w3.org/TR/webauthn-3/#typedefdef-publickeycredentialjson).
    794     ///
    795     /// `REL` iff unknown fields should be ignored and not cause an error.
    796     /// `REGI` iff `Self` is from a registration ceremony.
    797     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    798     where
    799         D: Deserializer<'de>,
    800     {
    801         deserializer.deserialize_struct(
    802             "PublicKeyCredential",
    803             REG_FIELDS,
    804             PublicKeyCredentialVisitor::<REL, REGI, _, _>(PhantomData),
    805         )
    806     }
    807 }
    808 impl Serialize for AllAcceptedCredentialsOptions<'_, '_> {
    809     /// Serializes `self` to conform with
    810     /// [`AllAcceptedCredentialsOptions`](https://www.w3.org/TR/webauthn-3/#dictdef-allacceptedcredentialsoptions).
    811     ///
    812     /// # Examples
    813     ///
    814     /// ```
    815     /// # use core::str::FromStr;
    816     /// # #[cfg(feature = "bin")]
    817     /// # use webauthn_rp::bin::Decode;
    818     /// # use webauthn_rp::{
    819     /// #     request::{register::{UserHandle, USER_HANDLE_MIN_LEN}, AsciiDomain, RpId},
    820     /// #     response::{error::CredentialIdErr, AllAcceptedCredentialsOptions, CredentialId},
    821     /// # };
    822     /// /// Retrieves the `CredentialId`s associated with `user_id` from the database.
    823     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    824     /// fn get_credential_ids(user_id: UserHandle<&[u8]>) -> Result<Vec<CredentialId<Vec<u8>>>, CredentialIdErr> {
    825     ///     // ⋮
    826     /// #     CredentialId::decode(vec![0; 16]).map(|cred_id| vec![cred_id])
    827     /// }
    828     /// /// Retrieves the `UserHandle` from a session cookie.
    829     /// # #[cfg(feature = "custom")]
    830     /// fn get_user_handle() -> UserHandle<[u8; USER_HANDLE_MIN_LEN]> {
    831     ///     // ⋮
    832     /// #     [0].into()
    833     /// }
    834     /// # #[cfg(feature = "custom")]
    835     /// let user_id = get_user_handle();
    836     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    837     /// assert_eq!(
    838     ///     serde_json::to_string(&AllAcceptedCredentialsOptions {
    839     ///         rp_id: &RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?),
    840     ///         user_id: (&user_id).into(),
    841     ///         all_accepted_credential_ids: get_credential_ids((&user_id).into())?,
    842     ///     })
    843     ///     .unwrap(),
    844     ///     r#"{"rpId":"example.com","userId":"AA","allAcceptedCredentialIds":["AAAAAAAAAAAAAAAAAAAAAA"]}"#
    845     /// );
    846     /// # Ok::<_, webauthn_rp::AggErr>(())
    847     /// ```
    848     #[inline]
    849     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    850     where
    851         S: Serializer,
    852     {
    853         serializer
    854             .serialize_struct("AllAcceptedCredentialsOptions", 3)
    855             .and_then(|mut ser| {
    856                 ser.serialize_field("rpId", self.rp_id).and_then(|()| {
    857                     ser.serialize_field("userId", &self.user_id).and_then(|()| {
    858                         ser.serialize_field(
    859                             "allAcceptedCredentialIds",
    860                             &self.all_accepted_credential_ids,
    861                         )
    862                         .and_then(|()| ser.end())
    863                     })
    864                 })
    865             })
    866     }
    867 }
    868 impl Serialize for CurrentUserDetailsOptions<'_, '_, '_, '_> {
    869     /// Serializes `self` to conform with
    870     /// [`CurrentUserDetailsOptions`](https://www.w3.org/TR/webauthn-3/#dictdef-currentuserdetailsoptions).
    871     ///
    872     /// # Examples
    873     ///
    874     /// ```
    875     /// # use core::str::FromStr;
    876     /// # #[cfg(feature = "bin")]
    877     /// # use webauthn_rp::bin::Decode;
    878     /// # use webauthn_rp::{
    879     /// #     request::{register::{Nickname, PublicKeyCredentialUserEntity, UserHandle, USER_HANDLE_MIN_LEN, Username}, AsciiDomain, RpId},
    880     /// #     response::CurrentUserDetailsOptions,
    881     /// #     AggErr,
    882     /// # };
    883     /// /// Retrieves the `PublicKeyCredentialUserEntity` info associated with `user_id` from the database.
    884     /// # #[cfg(feature = "bin")]
    885     /// fn get_user_info(user_id: UserHandle<&[u8]>) -> Result<(Username, Option<Nickname>), AggErr> {
    886     ///     // ⋮
    887     /// #     Ok((Username::decode("foo").unwrap(), Some(Nickname::decode("foo").unwrap())))
    888     /// }
    889     /// /// Retrieves the `UserHandle` from a session cookie.
    890     /// # #[cfg(feature = "custom")]
    891     /// fn get_user_handle() -> UserHandle<[u8; USER_HANDLE_MIN_LEN]> {
    892     ///     // ⋮
    893     /// #     [0].into()
    894     /// }
    895     /// # #[cfg(feature = "custom")]
    896     /// let user_handle = get_user_handle();
    897     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    898     /// let id = (&user_handle).into();
    899     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    900     /// let (name, display_name) = get_user_info(id)?;
    901     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    902     /// assert_eq!(
    903     ///     serde_json::to_string(&CurrentUserDetailsOptions {
    904     ///         rp_id: &RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?),
    905     ///         user: PublicKeyCredentialUserEntity { name, id, display_name, },
    906     ///     })
    907     ///     .unwrap(),
    908     ///     r#"{"rpId":"example.com","userId":"AA","name":"foo","displayName":"foo"}"#
    909     /// );
    910     /// # Ok::<_, AggErr>(())
    911     /// ```
    912     #[inline]
    913     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    914     where
    915         S: Serializer,
    916     {
    917         serializer
    918             .serialize_struct("CurrentUserDetailsOptions", 4)
    919             .and_then(|mut ser| {
    920                 ser.serialize_field("rpId", self.rp_id).and_then(|()| {
    921                     ser.serialize_field("userId", &self.user.id).and_then(|()| {
    922                         ser.serialize_field("name", &self.user.name).and_then(|()| {
    923                             ser.serialize_field("displayName", &self.user.display_name)
    924                                 .and_then(|()| ser.end())
    925                         })
    926                     })
    927                 })
    928             })
    929     }
    930 }
    931 /// JSON `null`.
    932 struct Null;
    933 impl<'de> Deserialize<'de> for Null {
    934     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    935     where
    936         D: Deserializer<'de>,
    937     {
    938         /// `Visitor` for `Null`.
    939         struct NullVisitor;
    940         impl Visitor<'_> for NullVisitor {
    941             type Value = Null;
    942             fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    943                 formatter.write_str("null")
    944             }
    945             fn visit_none<E>(self) -> Result<Self::Value, E>
    946             where
    947                 E: Error,
    948             {
    949                 Ok(Null)
    950             }
    951         }
    952         deserializer.deserialize_option(NullVisitor)
    953     }
    954 }
    955 /// [`AuthenticationExtensionsPRFValues`](https://www.w3.org/TR/webauthn-3/#dictdef-authenticationextensionsprfvalues).
    956 pub(super) struct AuthenticationExtensionsPrfValues;
    957 /// `Visitor` for `AuthenticationExtensionsPrfValues`.
    958 ///
    959 /// Unknown fields are ignored iff `RELAXED`.`first` must always exist if `second` does.
    960 /// `first` and `second` must be `null` if they exist. `first` must exist iff `!RELAXED`.
    961 pub(super) struct AuthenticationExtensionsPrfValuesVisitor<const RELAXED: bool>;
    962 impl<'d, const R: bool> Visitor<'d> for AuthenticationExtensionsPrfValuesVisitor<R> {
    963     type Value = AuthenticationExtensionsPrfValues;
    964     fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    965         formatter.write_str("AuthenticationExtensionsPrfValues")
    966     }
    967     fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
    968     where
    969         A: MapAccess<'d>,
    970     {
    971         /// Fields.
    972         enum Field<const IGNORE_UNKNOWN: bool> {
    973             /// `first` field.
    974             First,
    975             /// `second` field.
    976             Second,
    977             /// Unknown field.
    978             Other,
    979         }
    980         impl<'e, const I: bool> Deserialize<'e> for Field<I> {
    981             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    982             where
    983                 D: Deserializer<'e>,
    984             {
    985                 /// `Visitor` for `Field`.
    986                 ///
    987                 /// Unknown fields are ignored iff `IGNORE_UNKNOWN`.
    988                 struct FieldVisitor<const IGNORE_UNKNOWN: bool>;
    989                 impl<const IG: bool> Visitor<'_> for FieldVisitor<IG> {
    990                     type Value = Field<IG>;
    991                     fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    992                         write!(formatter, "'{FIRST}' or '{SECOND}'")
    993                     }
    994                     fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    995                     where
    996                         E: Error,
    997                     {
    998                         match v {
    999                             FIRST => Ok(Field::First),
   1000                             SECOND => Ok(Field::Second),
   1001                             _ => {
   1002                                 if IG {
   1003                                     Ok(Field::Other)
   1004                                 } else {
   1005                                     Err(E::unknown_field(v, PRF_VALUES_FIELDS))
   1006                                 }
   1007                             }
   1008                         }
   1009                     }
   1010                 }
   1011                 deserializer.deserialize_identifier(FieldVisitor)
   1012             }
   1013         }
   1014         let mut first = None;
   1015         let mut second = None;
   1016         while let Some(key) = map.next_key::<Field<R>>()? {
   1017             match key {
   1018                 Field::First => {
   1019                     if first.is_some() {
   1020                         return Err(Error::duplicate_field(FIRST));
   1021                     }
   1022                     first = map.next_value::<Null>().map(Some)?;
   1023                 }
   1024                 Field::Second => {
   1025                     if second.is_some() {
   1026                         return Err(Error::duplicate_field(SECOND));
   1027                     }
   1028                     second = map.next_value::<Null>().map(Some)?;
   1029                 }
   1030                 Field::Other => map.next_value::<IgnoredAny>().map(|_| ())?,
   1031             }
   1032         }
   1033         if first.is_some() || (R && second.is_none()) {
   1034             Ok(AuthenticationExtensionsPrfValues)
   1035         } else {
   1036             Err(Error::missing_field(FIRST))
   1037         }
   1038     }
   1039 }
   1040 /// `"first"`
   1041 const FIRST: &str = "first";
   1042 /// `"second"`
   1043 const SECOND: &str = "second";
   1044 /// `AuthenticationExtensionsPrfValues` fields.
   1045 pub(super) const PRF_VALUES_FIELDS: &[&str; 2] = &[FIRST, SECOND];
   1046 impl<'de> Deserialize<'de> for AuthenticationExtensionsPrfValues {
   1047     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1048     where
   1049         D: Deserializer<'de>,
   1050     {
   1051         deserializer.deserialize_struct(
   1052             "AuthenticationExtensionsPrfValues",
   1053             PRF_VALUES_FIELDS,
   1054             AuthenticationExtensionsPrfValuesVisitor::<false>,
   1055         )
   1056     }
   1057 }
   1058 /// [`AuthenticationExtensionsPRFOutputs`](https://www.w3.org/TR/webauthn-3/#dictdef-authenticationextensionsprfoutputs).
   1059 ///
   1060 /// `RELAXED` iff unknown fields are ignored.
   1061 ///
   1062 /// `REGISTRATION` iff
   1063 /// [`enabled`](https://www.w3.org/TR/webauthn-3/#dom-authenticationextensionsprfoutputs-enabled)
   1064 /// is required (and must not be `null`); otherwise it's forbidden.
   1065 ///
   1066 /// The contained `Option` is `Some` iff `REGISTRATION`.
   1067 pub(super) struct AuthenticationExtensionsPrfOutputsHelper<
   1068     const RELAXED: bool,
   1069     const REGISTRATION: bool,
   1070     Prf,
   1071 >(pub Option<bool>, pub PhantomData<fn() -> Prf>);
   1072 /// `Visitor` for `AuthenticationExtensionsPrfOutputs`.
   1073 ///
   1074 /// Unknown fields are ignored iff `RELAXED`.`enabled` must exist and not be `null` iff `REGISTRATION`.
   1075 struct AuthenticationExtensionsPrfOutputsVisitor<const RELAXED: bool, const REGISTRATION: bool, Prf>(
   1076     PhantomData<fn() -> Prf>,
   1077 );
   1078 impl<'d, const REL: bool, const REG: bool, Prf> Visitor<'d>
   1079     for AuthenticationExtensionsPrfOutputsVisitor<REL, REG, Prf>
   1080 where
   1081     Prf: for<'a> Deserialize<'a>,
   1082 {
   1083     type Value = AuthenticationExtensionsPrfOutputsHelper<REL, REG, Prf>;
   1084     fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
   1085         formatter.write_str("AuthenticationExtensionsPrfOutputs")
   1086     }
   1087     fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
   1088     where
   1089         A: MapAccess<'d>,
   1090     {
   1091         /// Fields.
   1092         enum Field<const IGNORE_UNKNOWN: bool, const REGI: bool> {
   1093             /// `enabled` field.
   1094             Enabled,
   1095             /// `results` field.
   1096             Results,
   1097             /// Unknown field.
   1098             Other,
   1099         }
   1100         impl<'e, const I: bool, const R: bool> Deserialize<'e> for Field<I, R> {
   1101             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1102             where
   1103                 D: Deserializer<'e>,
   1104             {
   1105                 /// `Visitor` for `Field`.
   1106                 ///
   1107                 /// Unknown fields are ignored iff `IGNORE_UNKNOWN`.
   1108                 /// `enabled` is allowed to exist iff `REGI`.
   1109                 struct FieldVisitor<const IGNORE_UNKNOWN: bool, const REGI: bool>;
   1110                 impl<const IG: bool, const RE: bool> Visitor<'_> for FieldVisitor<IG, RE> {
   1111                     type Value = Field<IG, RE>;
   1112                     fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
   1113                         if RE {
   1114                             write!(formatter, "'{ENABLED}' or '{RESULTS}'")
   1115                         } else {
   1116                             write!(formatter, "'{RESULTS}'")
   1117                         }
   1118                     }
   1119                     fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
   1120                     where
   1121                         E: Error,
   1122                     {
   1123                         match v {
   1124                             ENABLED => {
   1125                                 if RE {
   1126                                     Ok(Field::Enabled)
   1127                                 } else {
   1128                                     Err(E::unknown_field(v, PRF_AUTH_OUTPUTS_FIELDS))
   1129                                 }
   1130                             }
   1131                             RESULTS => Ok(Field::Results),
   1132                             _ => {
   1133                                 if IG {
   1134                                     Ok(Field::Other)
   1135                                 } else if RE {
   1136                                     Err(E::unknown_field(v, PRF_REG_OUTPUTS_FIELDS))
   1137                                 } else {
   1138                                     Err(E::unknown_field(v, PRF_AUTH_OUTPUTS_FIELDS))
   1139                                 }
   1140                             }
   1141                         }
   1142                     }
   1143                 }
   1144                 deserializer.deserialize_identifier(FieldVisitor)
   1145             }
   1146         }
   1147         let mut enabled = None;
   1148         let mut results = None;
   1149         while let Some(key) = map.next_key::<Field<REL, REG>>()? {
   1150             match key {
   1151                 Field::Enabled => {
   1152                     if enabled.is_some() {
   1153                         return Err(Error::duplicate_field(ENABLED));
   1154                     }
   1155                     enabled = map.next_value().map(Some)?;
   1156                 }
   1157                 Field::Results => {
   1158                     if results.is_some() {
   1159                         return Err(Error::duplicate_field(RESULTS));
   1160                     }
   1161                     results = map.next_value::<Option<Prf>>().map(Some)?;
   1162                 }
   1163                 Field::Other => map.next_value::<IgnoredAny>().map(|_| ())?,
   1164             }
   1165         }
   1166         if REG {
   1167             enabled.ok_or_else(|| Error::missing_field(ENABLED)).and_then(|e| {
   1168                 if e || results.is_none() {
   1169                     Ok(())
   1170                 } else {
   1171                     Err(Error::custom("prf must not have 'results', including a null 'results', if 'enabled' is false"))
   1172                 }
   1173             })
   1174         } else {
   1175             Ok(())
   1176         }.map(|()| AuthenticationExtensionsPrfOutputsHelper(enabled, PhantomData))
   1177     }
   1178 }
   1179 /// `"enabled"`
   1180 const ENABLED: &str = "enabled";
   1181 /// `"results"`
   1182 const RESULTS: &str = "results";
   1183 /// `AuthenticationExtensionsPrfOutputs` field during registration.
   1184 const PRF_REG_OUTPUTS_FIELDS: &[&str; 2] = &[ENABLED, RESULTS];
   1185 /// `AuthenticationExtensionsPrfOutputs` field during authentication.
   1186 const PRF_AUTH_OUTPUTS_FIELDS: &[&str; 1] = &[RESULTS];
   1187 impl<'de, const REL: bool, const REG: bool, Prf> Deserialize<'de>
   1188     for AuthenticationExtensionsPrfOutputsHelper<REL, REG, Prf>
   1189 where
   1190     for<'a> Prf: Deserialize<'a>,
   1191 {
   1192     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1193     where
   1194         D: Deserializer<'de>,
   1195     {
   1196         deserializer.deserialize_struct(
   1197             "AuthenticationExtensionsPrfOutputs",
   1198             if REG {
   1199                 PRF_REG_OUTPUTS_FIELDS
   1200             } else {
   1201                 PRF_AUTH_OUTPUTS_FIELDS
   1202             },
   1203             AuthenticationExtensionsPrfOutputsVisitor::<REL, REG, Prf>(PhantomData),
   1204         )
   1205     }
   1206 }