webauthn_rp

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

ser.rs (48197B)


      1 extern crate alloc;
      2 use super::{
      3     AllAcceptedCredentialsOptions, AuthTransports, AuthenticatorAttachment, AuthenticatorTransport,
      4     Challenge, CredentialId, CurrentUserDetailsOptions, Origin, SentChallenge,
      5 };
      6 use alloc::borrow::Cow;
      7 use core::{
      8     fmt::{self, Formatter},
      9     marker::PhantomData,
     10 };
     11 use data_encoding::BASE64URL_NOPAD;
     12 use serde::{
     13     de::{Deserialize, Deserializer, Error, IgnoredAny, MapAccess, SeqAccess, Unexpected, Visitor},
     14     ser::{Serialize, SerializeSeq as _, SerializeStruct as _, Serializer},
     15 };
     16 /// [`"ble"`](https://www.w3.org/TR/webauthn-3/#dom-authenticatortransport-ble).
     17 const BLE: &str = "ble";
     18 /// [`"hybrid"`](https://www.w3.org/TR/webauthn-3/#dom-authenticatortransport-hybrid).
     19 const HYBRID: &str = "hybrid";
     20 /// [`"internal"`](https://www.w3.org/TR/webauthn-3/#dom-authenticatortransport-internal).
     21 const INTERNAL: &str = "internal";
     22 /// [`"nfc"`](https://www.w3.org/TR/webauthn-3/#dom-authenticatortransport-nfc).
     23 const NFC: &str = "nfc";
     24 /// [`"smart-card"`](https://www.w3.org/TR/webauthn-3/#dom-authenticatortransport-smart-card).
     25 const SMART_CARD: &str = "smart-card";
     26 /// [`"usb"`](https://www.w3.org/TR/webauthn-3/#dom-authenticatortransport-usb).
     27 const USB: &str = "usb";
     28 impl Serialize for AuthenticatorTransport {
     29     /// Serializes `self` as
     30     /// [`AuthenticatorTransport`](https://www.w3.org/TR/webauthn-3/#enumdef-authenticatortransport).
     31     ///
     32     /// # Examples
     33     ///
     34     /// ```
     35     /// # use webauthn_rp::response::AuthenticatorTransport;
     36     /// assert_eq!(
     37     ///     serde_json::to_string(&AuthenticatorTransport::Usb)?,
     38     ///     r#""usb""#
     39     /// );
     40     /// # Ok::<_, serde_json::Error>(())
     41     /// ```
     42     #[inline]
     43     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     44     where
     45         S: Serializer,
     46     {
     47         serializer.serialize_str(match *self {
     48             Self::Ble => BLE,
     49             Self::Hybrid => HYBRID,
     50             Self::Internal => INTERNAL,
     51             Self::Nfc => NFC,
     52             Self::SmartCard => SMART_CARD,
     53             Self::Usb => USB,
     54         })
     55     }
     56 }
     57 impl<'de> Deserialize<'de> for AuthenticatorTransport {
     58     /// Deserializes [`prim@str`] based on
     59     /// [`AuthenticatorTransport`](https://www.w3.org/TR/webauthn-3/#enumdef-authenticatortransport).
     60     ///
     61     /// Note `"cable"` is also supported and will be interpreted as [`Self::Hybrid`].
     62     ///
     63     /// # Examples
     64     ///
     65     /// ```
     66     /// # use webauthn_rp::response::AuthenticatorTransport;
     67     /// assert!(matches!(
     68     ///     serde_json::from_str::<AuthenticatorTransport>(r#""usb""#)?,
     69     ///     AuthenticatorTransport::Usb
     70     /// ));
     71     /// // Case matters.
     72     /// assert!(serde_json::from_str::<AuthenticatorTransport>(r#""Usb""#).is_err());
     73     /// # Ok::<_, serde_json::Error>(())
     74     /// ```
     75     #[inline]
     76     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     77     where
     78         D: Deserializer<'de>,
     79     {
     80         /// `Visitor` for `AuthenticatorTransport`.
     81         struct AuthenticatorTransportVisitor;
     82         impl Visitor<'_> for AuthenticatorTransportVisitor {
     83             type Value = AuthenticatorTransport;
     84             fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
     85                 formatter.write_str("AuthenticatorTransport")
     86             }
     87             fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
     88             where
     89                 E: Error,
     90             {
     91                 /// Legacy version of [`Self::Hybrid`].
     92                 const CA_BLE: &str = "cable";
     93                 match v {
     94                     BLE => Ok(AuthenticatorTransport::Ble),
     95                     CA_BLE | 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}', '{CA_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 use super::UserHandle;
    809 impl<const USER_LEN: usize> Serialize for AllAcceptedCredentialsOptions<'_, '_, USER_LEN>
    810 where
    811     UserHandle<USER_LEN>: Serialize,
    812 {
    813     /// Serializes `self` to conform with
    814     /// [`AllAcceptedCredentialsOptions`](https://www.w3.org/TR/webauthn-3/#dictdef-allacceptedcredentialsoptions).
    815     ///
    816     /// # Examples
    817     ///
    818     /// ```
    819     /// # use core::str::FromStr;
    820     /// # #[cfg(feature = "bin")]
    821     /// # use webauthn_rp::bin::Decode;
    822     /// # use webauthn_rp::{
    823     /// #     request::{register::{UserHandle, USER_HANDLE_MIN_LEN}, AsciiDomain, RpId},
    824     /// #     response::{error::CredentialIdErr, AllAcceptedCredentialsOptions, CredentialId},
    825     /// # };
    826     /// /// Retrieves the `CredentialId`s associated with `user_id` from the database.
    827     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    828     /// fn get_credential_ids(user_id: UserHandle<USER_HANDLE_MIN_LEN>) -> Result<Vec<CredentialId<Vec<u8>>>, CredentialIdErr> {
    829     ///     // ⋮
    830     /// #     CredentialId::decode(vec![0; 16]).map(|cred_id| vec![cred_id])
    831     /// }
    832     /// /// Retrieves the `UserHandle` from a session cookie.
    833     /// # #[cfg(feature = "custom")]
    834     /// fn get_user_handle() -> UserHandle<USER_HANDLE_MIN_LEN> {
    835     ///     // ⋮
    836     /// #     [0].into()
    837     /// }
    838     /// # #[cfg(feature = "custom")]
    839     /// let user_id = get_user_handle();
    840     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    841     /// assert_eq!(
    842     ///     serde_json::to_string(&AllAcceptedCredentialsOptions {
    843     ///         rp_id: &RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?),
    844     ///         user_id: &user_id,
    845     ///         all_accepted_credential_ids: get_credential_ids(user_id)?,
    846     ///     })
    847     ///     .unwrap(),
    848     ///     r#"{"rpId":"example.com","userId":"AA","allAcceptedCredentialIds":["AAAAAAAAAAAAAAAAAAAAAA"]}"#
    849     /// );
    850     /// # Ok::<_, webauthn_rp::AggErr>(())
    851     /// ```
    852     #[inline]
    853     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    854     where
    855         S: Serializer,
    856     {
    857         serializer
    858             .serialize_struct("AllAcceptedCredentialsOptions", 3)
    859             .and_then(|mut ser| {
    860                 ser.serialize_field("rpId", self.rp_id).and_then(|()| {
    861                     ser.serialize_field("userId", &self.user_id).and_then(|()| {
    862                         ser.serialize_field(
    863                             "allAcceptedCredentialIds",
    864                             &self.all_accepted_credential_ids,
    865                         )
    866                         .and_then(|()| ser.end())
    867                     })
    868                 })
    869             })
    870     }
    871 }
    872 impl<const LEN: usize> Serialize for CurrentUserDetailsOptions<'_, '_, '_, '_, LEN>
    873 where
    874     UserHandle<LEN>: Serialize,
    875 {
    876     /// Serializes `self` to conform with
    877     /// [`CurrentUserDetailsOptions`](https://www.w3.org/TR/webauthn-3/#dictdef-currentuserdetailsoptions).
    878     ///
    879     /// # Examples
    880     ///
    881     /// ```
    882     /// # use core::str::FromStr;
    883     /// # #[cfg(feature = "bin")]
    884     /// # use webauthn_rp::bin::Decode;
    885     /// # use webauthn_rp::{
    886     /// #     request::{register::{Nickname, PublicKeyCredentialUserEntity, UserHandle, USER_HANDLE_MIN_LEN, Username}, AsciiDomain, RpId},
    887     /// #     response::CurrentUserDetailsOptions,
    888     /// #     AggErr,
    889     /// # };
    890     /// /// Retrieves the `PublicKeyCredentialUserEntity` info associated with `user_id` from the database.
    891     /// # #[cfg(feature = "bin")]
    892     /// fn get_user_info(user_id: UserHandle<USER_HANDLE_MIN_LEN>) -> Result<(Username<'static>, Option<Nickname<'static>>), AggErr> {
    893     ///     // ⋮
    894     /// #     Ok((Username::decode("foo").unwrap(), Some(Nickname::decode("foo").unwrap())))
    895     /// }
    896     /// /// Retrieves the `UserHandle` from a session cookie.
    897     /// # #[cfg(feature = "custom")]
    898     /// fn get_user_handle() -> UserHandle<USER_HANDLE_MIN_LEN> {
    899     ///     // ⋮
    900     /// #     [0].into()
    901     /// }
    902     /// # #[cfg(feature = "custom")]
    903     /// let user_handle = get_user_handle();
    904     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    905     /// let (name, display_name) = get_user_info(user_handle)?;
    906     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    907     /// assert_eq!(
    908     ///     serde_json::to_string(&CurrentUserDetailsOptions {
    909     ///         rp_id: &RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?),
    910     ///         user: PublicKeyCredentialUserEntity { name, id: &user_handle, display_name, },
    911     ///     })
    912     ///     .unwrap(),
    913     ///     r#"{"rpId":"example.com","userId":"AA","name":"foo","displayName":"foo"}"#
    914     /// );
    915     /// # Ok::<_, AggErr>(())
    916     /// ```
    917     #[inline]
    918     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    919     where
    920         S: Serializer,
    921     {
    922         serializer
    923             .serialize_struct("CurrentUserDetailsOptions", 4)
    924             .and_then(|mut ser| {
    925                 ser.serialize_field("rpId", self.rp_id).and_then(|()| {
    926                     ser.serialize_field("userId", &self.user.id).and_then(|()| {
    927                         ser.serialize_field("name", &self.user.name).and_then(|()| {
    928                             ser.serialize_field("displayName", &self.user.display_name)
    929                                 .and_then(|()| ser.end())
    930                         })
    931                     })
    932                 })
    933             })
    934     }
    935 }
    936 /// JSON `null`.
    937 struct Null;
    938 impl<'de> Deserialize<'de> for Null {
    939     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    940     where
    941         D: Deserializer<'de>,
    942     {
    943         /// `Visitor` for `Null`.
    944         struct NullVisitor;
    945         impl Visitor<'_> for NullVisitor {
    946             type Value = Null;
    947             fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    948                 formatter.write_str("null")
    949             }
    950             fn visit_none<E>(self) -> Result<Self::Value, E>
    951             where
    952                 E: Error,
    953             {
    954                 Ok(Null)
    955             }
    956         }
    957         deserializer.deserialize_option(NullVisitor)
    958     }
    959 }
    960 /// [`AuthenticationExtensionsPRFValues`](https://www.w3.org/TR/webauthn-3/#dictdef-authenticationextensionsprfvalues).
    961 pub(super) struct AuthenticationExtensionsPrfValues;
    962 /// `Visitor` for `AuthenticationExtensionsPrfValues`.
    963 ///
    964 /// Unknown fields are ignored iff `RELAXED`.`first` must always exist if `second` does.
    965 /// `first` and `second` must be `null` if they exist. `first` must exist iff `!RELAXED`.
    966 pub(super) struct AuthenticationExtensionsPrfValuesVisitor<const RELAXED: bool>;
    967 impl<'d, const R: bool> Visitor<'d> for AuthenticationExtensionsPrfValuesVisitor<R> {
    968     type Value = AuthenticationExtensionsPrfValues;
    969     fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    970         formatter.write_str("AuthenticationExtensionsPrfValues")
    971     }
    972     fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
    973     where
    974         A: MapAccess<'d>,
    975     {
    976         /// Fields.
    977         enum Field<const IGNORE_UNKNOWN: bool> {
    978             /// `first` field.
    979             First,
    980             /// `second` field.
    981             Second,
    982             /// Unknown field.
    983             Other,
    984         }
    985         impl<'e, const I: bool> Deserialize<'e> for Field<I> {
    986             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    987             where
    988                 D: Deserializer<'e>,
    989             {
    990                 /// `Visitor` for `Field`.
    991                 ///
    992                 /// Unknown fields are ignored iff `IGNORE_UNKNOWN`.
    993                 struct FieldVisitor<const IGNORE_UNKNOWN: bool>;
    994                 impl<const IG: bool> Visitor<'_> for FieldVisitor<IG> {
    995                     type Value = Field<IG>;
    996                     fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    997                         write!(formatter, "'{FIRST}' or '{SECOND}'")
    998                     }
    999                     fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
   1000                     where
   1001                         E: Error,
   1002                     {
   1003                         match v {
   1004                             FIRST => Ok(Field::First),
   1005                             SECOND => Ok(Field::Second),
   1006                             _ => {
   1007                                 if IG {
   1008                                     Ok(Field::Other)
   1009                                 } else {
   1010                                     Err(E::unknown_field(v, PRF_VALUES_FIELDS))
   1011                                 }
   1012                             }
   1013                         }
   1014                     }
   1015                 }
   1016                 deserializer.deserialize_identifier(FieldVisitor)
   1017             }
   1018         }
   1019         let mut first = None;
   1020         let mut second = None;
   1021         while let Some(key) = map.next_key::<Field<R>>()? {
   1022             match key {
   1023                 Field::First => {
   1024                     if first.is_some() {
   1025                         return Err(Error::duplicate_field(FIRST));
   1026                     }
   1027                     first = map.next_value::<Null>().map(Some)?;
   1028                 }
   1029                 Field::Second => {
   1030                     if second.is_some() {
   1031                         return Err(Error::duplicate_field(SECOND));
   1032                     }
   1033                     second = map.next_value::<Null>().map(Some)?;
   1034                 }
   1035                 Field::Other => map.next_value::<IgnoredAny>().map(|_| ())?,
   1036             }
   1037         }
   1038         if first.is_some() || (R && second.is_none()) {
   1039             Ok(AuthenticationExtensionsPrfValues)
   1040         } else {
   1041             Err(Error::missing_field(FIRST))
   1042         }
   1043     }
   1044 }
   1045 /// `"first"`
   1046 const FIRST: &str = "first";
   1047 /// `"second"`
   1048 const SECOND: &str = "second";
   1049 /// `AuthenticationExtensionsPrfValues` fields.
   1050 pub(super) const PRF_VALUES_FIELDS: &[&str; 2] = &[FIRST, SECOND];
   1051 impl<'de> Deserialize<'de> for AuthenticationExtensionsPrfValues {
   1052     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1053     where
   1054         D: Deserializer<'de>,
   1055     {
   1056         deserializer.deserialize_struct(
   1057             "AuthenticationExtensionsPrfValues",
   1058             PRF_VALUES_FIELDS,
   1059             AuthenticationExtensionsPrfValuesVisitor::<false>,
   1060         )
   1061     }
   1062 }
   1063 /// [`AuthenticationExtensionsPRFOutputs`](https://www.w3.org/TR/webauthn-3/#dictdef-authenticationextensionsprfoutputs).
   1064 ///
   1065 /// `RELAXED` iff unknown fields are ignored.
   1066 ///
   1067 /// `REGISTRATION` iff
   1068 /// [`enabled`](https://www.w3.org/TR/webauthn-3/#dom-authenticationextensionsprfoutputs-enabled)
   1069 /// is required (and must not be `null`); otherwise it's forbidden.
   1070 ///
   1071 /// The contained `Option` is `Some` iff `REGISTRATION`.
   1072 pub(super) struct AuthenticationExtensionsPrfOutputsHelper<
   1073     const RELAXED: bool,
   1074     const REGISTRATION: bool,
   1075     Prf,
   1076 >(pub Option<bool>, pub PhantomData<fn() -> Prf>);
   1077 /// `Visitor` for `AuthenticationExtensionsPrfOutputs`.
   1078 ///
   1079 /// Unknown fields are ignored iff `RELAXED`.`enabled` must exist and not be `null` iff `REGISTRATION`.
   1080 struct AuthenticationExtensionsPrfOutputsVisitor<const RELAXED: bool, const REGISTRATION: bool, Prf>(
   1081     PhantomData<fn() -> Prf>,
   1082 );
   1083 impl<'d, const REL: bool, const REG: bool, Prf> Visitor<'d>
   1084     for AuthenticationExtensionsPrfOutputsVisitor<REL, REG, Prf>
   1085 where
   1086     Prf: for<'a> Deserialize<'a>,
   1087 {
   1088     type Value = AuthenticationExtensionsPrfOutputsHelper<REL, REG, Prf>;
   1089     fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
   1090         formatter.write_str("AuthenticationExtensionsPrfOutputs")
   1091     }
   1092     fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
   1093     where
   1094         A: MapAccess<'d>,
   1095     {
   1096         /// Fields.
   1097         enum Field<const IGNORE_UNKNOWN: bool, const REGI: bool> {
   1098             /// `enabled` field.
   1099             Enabled,
   1100             /// `results` field.
   1101             Results,
   1102             /// Unknown field.
   1103             Other,
   1104         }
   1105         impl<'e, const I: bool, const R: bool> Deserialize<'e> for Field<I, R> {
   1106             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1107             where
   1108                 D: Deserializer<'e>,
   1109             {
   1110                 /// `Visitor` for `Field`.
   1111                 ///
   1112                 /// Unknown fields are ignored iff `IGNORE_UNKNOWN`.
   1113                 /// `enabled` is allowed to exist iff `REGI`.
   1114                 struct FieldVisitor<const IGNORE_UNKNOWN: bool, const REGI: bool>;
   1115                 impl<const IG: bool, const RE: bool> Visitor<'_> for FieldVisitor<IG, RE> {
   1116                     type Value = Field<IG, RE>;
   1117                     fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
   1118                         if RE {
   1119                             write!(formatter, "'{ENABLED}' or '{RESULTS}'")
   1120                         } else {
   1121                             write!(formatter, "'{RESULTS}'")
   1122                         }
   1123                     }
   1124                     fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
   1125                     where
   1126                         E: Error,
   1127                     {
   1128                         match v {
   1129                             ENABLED => {
   1130                                 if RE {
   1131                                     Ok(Field::Enabled)
   1132                                 } else {
   1133                                     Err(E::unknown_field(v, PRF_AUTH_OUTPUTS_FIELDS))
   1134                                 }
   1135                             }
   1136                             RESULTS => Ok(Field::Results),
   1137                             _ => {
   1138                                 if IG {
   1139                                     Ok(Field::Other)
   1140                                 } else if RE {
   1141                                     Err(E::unknown_field(v, PRF_REG_OUTPUTS_FIELDS))
   1142                                 } else {
   1143                                     Err(E::unknown_field(v, PRF_AUTH_OUTPUTS_FIELDS))
   1144                                 }
   1145                             }
   1146                         }
   1147                     }
   1148                 }
   1149                 deserializer.deserialize_identifier(FieldVisitor)
   1150             }
   1151         }
   1152         let mut enabled = None;
   1153         let mut results = None;
   1154         while let Some(key) = map.next_key::<Field<REL, REG>>()? {
   1155             match key {
   1156                 Field::Enabled => {
   1157                     if enabled.is_some() {
   1158                         return Err(Error::duplicate_field(ENABLED));
   1159                     }
   1160                     enabled = map.next_value().map(Some)?;
   1161                 }
   1162                 Field::Results => {
   1163                     if results.is_some() {
   1164                         return Err(Error::duplicate_field(RESULTS));
   1165                     }
   1166                     results = map.next_value::<Option<Prf>>().map(Some)?;
   1167                 }
   1168                 Field::Other => map.next_value::<IgnoredAny>().map(|_| ())?,
   1169             }
   1170         }
   1171         if REG {
   1172             enabled.ok_or_else(|| Error::missing_field(ENABLED)).and_then(|e| {
   1173                 if e || results.is_none() {
   1174                     Ok(())
   1175                 } else {
   1176                     Err(Error::custom("prf must not have 'results', including a null 'results', if 'enabled' is false"))
   1177                 }
   1178             })
   1179         } else {
   1180             Ok(())
   1181         }.map(|()| AuthenticationExtensionsPrfOutputsHelper(enabled, PhantomData))
   1182     }
   1183 }
   1184 /// `"enabled"`
   1185 const ENABLED: &str = "enabled";
   1186 /// `"results"`
   1187 const RESULTS: &str = "results";
   1188 /// `AuthenticationExtensionsPrfOutputs` field during registration.
   1189 const PRF_REG_OUTPUTS_FIELDS: &[&str; 2] = &[ENABLED, RESULTS];
   1190 /// `AuthenticationExtensionsPrfOutputs` field during authentication.
   1191 const PRF_AUTH_OUTPUTS_FIELDS: &[&str; 1] = &[RESULTS];
   1192 impl<'de, const REL: bool, const REG: bool, Prf> Deserialize<'de>
   1193     for AuthenticationExtensionsPrfOutputsHelper<REL, REG, Prf>
   1194 where
   1195     for<'a> Prf: Deserialize<'a>,
   1196 {
   1197     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1198     where
   1199         D: Deserializer<'de>,
   1200     {
   1201         deserializer.deserialize_struct(
   1202             "AuthenticationExtensionsPrfOutputs",
   1203             if REG {
   1204                 PRF_REG_OUTPUTS_FIELDS
   1205             } else {
   1206                 PRF_AUTH_OUTPUTS_FIELDS
   1207             },
   1208             AuthenticationExtensionsPrfOutputsVisitor::<REL, REG, Prf>(PhantomData),
   1209         )
   1210     }
   1211 }