From 9f6e5d18d1dc5317e8c43d984084ae323948a6b6 Mon Sep 17 00:00:00 2001 From: David Ramos Date: Sat, 7 Sep 2019 19:42:09 -0700 Subject: [PATCH] Have LocalizedClaim::get take Option<&LanguageTag> instead of &Option --- src/macros.rs | 4 +- src/types.rs | 98 +++++++++++++++++++++++++++++++-------------- src/verification.rs | 2 +- 3 files changed, 70 insertions(+), 34 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index 9409656c..6dccc869 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -468,7 +468,7 @@ macro_rules! deserialize_fields { $field = Some(new); $field.as_mut().unwrap() }; - if localized_claim.contains_key(&$language_tag_opt) { + if localized_claim.contains_key($language_tag_opt.as_ref()) { return Err(serde::de::Error::custom(format!("duplicate field `{}`", $key))); } @@ -591,7 +591,7 @@ macro_rules! serialize_fields { (@case $self:ident $map:ident LanguageTag($field:ident)) => { if let Some(ref field_map) = $self.$field { use itertools::sorted; - let sorted_field_map = sorted(field_map.clone()); + let sorted_field_map = sorted(field_map.iter()); for (language_tag_opt, $field) in sorted_field_map.iter() { if let Some(ref language_tag) = *language_tag_opt { $map.serialize_entry( diff --git a/src/types.rs b/src/types.rs index ce4e3768..1f359f75 100644 --- a/src/types.rs +++ b/src/types.rs @@ -35,7 +35,7 @@ use super::{ /// claims values. /// #[derive(Clone, Debug, PartialEq)] -pub struct LocalizedClaim(HashMap, T>); +pub struct LocalizedClaim(HashMap, Option); impl LocalizedClaim { /// /// Initialize an empty claim. @@ -47,22 +47,33 @@ impl LocalizedClaim { /// /// Returns true if the claim contains a value for the specified locale. /// - pub fn contains_key(&self, locale: &Option) -> bool { - self.0.contains_key(locale) + pub fn contains_key(&self, locale: Option<&LanguageTag>) -> bool { + if let Some(l) = locale { + self.0.contains_key(l) + } else { + self.1.is_some() + } } /// /// Returns the entry for the specified locale or `None` if there is no such entry. /// - pub fn get(&self, locale: &Option) -> Option<&T> { - self.0.get(locale) + pub fn get(&self, locale: Option<&LanguageTag>) -> Option<&T> { + if let Some(l) = locale { + self.0.get(l) + } else { + self.1.as_ref() + } } /// /// Returns an iterator over the locales and claim value entries. /// - pub fn iter(&self) -> std::collections::hash_map::Iter, T> { - self.0.iter() + pub fn iter(&self) -> impl Iterator, &T)> { + self.1 + .iter() + .map(|value| (None, value)) + .chain(self.0.iter().map(|(locale, value)| (Some(locale), value))) } /// @@ -72,7 +83,11 @@ impl LocalizedClaim { /// such entry. /// pub fn insert(&mut self, locale: Option, value: T) -> Option { - self.0.insert(locale, value) + if let Some(l) = locale { + self.0.insert(l, value) + } else { + self.1.replace(value) + } } /// @@ -81,45 +96,66 @@ impl LocalizedClaim { /// Returns the current value associated with the given locale, or `None` if there is no /// such entry. /// - pub fn remove(&mut self, locale: &Option) -> Option { - self.0.remove(locale) + pub fn remove(&mut self, locale: Option<&LanguageTag>) -> Option { + if let Some(l) = locale { + self.0.remove(l) + } else { + self.1.take() + } } } impl Default for LocalizedClaim { fn default() -> Self { - Self(HashMap::new()) - } -} -impl From, T>> for LocalizedClaim { - fn from(inner: HashMap, T>) -> Self { - Self(inner) + Self(HashMap::new(), None) } } impl From for LocalizedClaim { - fn from(inner: T) -> Self { - Self(vec![(None, inner)].into_iter().collect()) + fn from(default: T) -> Self { + Self(HashMap::new(), Some(default)) } } impl FromIterator<(Option, T)> for LocalizedClaim { fn from_iter, T)>>(iter: I) -> Self { - let inner: HashMap, T> = iter.into_iter().collect(); - Self(inner) + let mut temp: HashMap, T> = iter.into_iter().collect(); + let default = temp.remove(&None); + Self( + temp.into_iter() + .filter_map(|(locale, value)| locale.map(|l| (l, value))) + .collect(), + default, + ) } } -impl<'a, T> IntoIterator for &'a LocalizedClaim { - type Item = (&'a Option, &'a T); - type IntoIter = std::collections::hash_map::Iter<'a, Option, T>; - - fn into_iter(self) -> std::collections::hash_map::Iter<'a, Option, T> { - self.0.iter() +impl IntoIterator for LocalizedClaim +where + T: 'static, +{ + type Item = as Iterator>::Item; + type IntoIter = LocalizedClaimIterator; + + fn into_iter(self) -> Self::IntoIter { + LocalizedClaimIterator { + inner: Box::new( + self.1.into_iter().map(|value| (None, value)).chain( + self.0 + .into_iter() + .map(|(locale, value)| (Some(locale), value)), + ), + ), + } } } -impl IntoIterator for LocalizedClaim { - type Item = (Option, T); - type IntoIter = std::collections::hash_map::IntoIter, T>; - fn into_iter(self) -> std::collections::hash_map::IntoIter, T> { - self.0.into_iter() +/// +/// Owned iterator over a LocalizedClaim. +/// +pub struct LocalizedClaimIterator { + inner: Box, T)>>, +} +impl Iterator for LocalizedClaimIterator { + type Item = (Option, T); + fn next(&mut self) -> Option { + self.inner.next() } } diff --git a/src/verification.rs b/src/verification.rs index 9766e422..7109f822 100644 --- a/src/verification.rs +++ b/src/verification.rs @@ -1805,7 +1805,7 @@ mod tests { .unwrap() .iter() .collect::>(), - vec![(&None, &EndUserName::new("Jane Doe".to_string()))], + vec![(None, &EndUserName::new("Jane Doe".to_string()))], ); // Invalid subject