Skip to content

Commit

Permalink
Have LocalizedClaim::get take Option<&LanguageTag> instead of &Option…
Browse files Browse the repository at this point in the history
…<LanguageTag>
  • Loading branch information
David Ramos committed Sep 8, 2019
1 parent 45df547 commit 9f6e5d1
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 34 deletions.
4 changes: 2 additions & 2 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
}

Expand Down Expand Up @@ -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(
Expand Down
98 changes: 67 additions & 31 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use super::{
/// claims values.
///
#[derive(Clone, Debug, PartialEq)]
pub struct LocalizedClaim<T>(HashMap<Option<LanguageTag>, T>);
pub struct LocalizedClaim<T>(HashMap<LanguageTag, T>, Option<T>);
impl<T> LocalizedClaim<T> {
///
/// Initialize an empty claim.
Expand All @@ -47,22 +47,33 @@ impl<T> LocalizedClaim<T> {
///
/// Returns true if the claim contains a value for the specified locale.
///
pub fn contains_key(&self, locale: &Option<LanguageTag>) -> 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<LanguageTag>) -> 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<Option<LanguageTag>, T> {
self.0.iter()
pub fn iter(&self) -> impl Iterator<Item = (Option<&LanguageTag>, &T)> {
self.1
.iter()
.map(|value| (None, value))
.chain(self.0.iter().map(|(locale, value)| (Some(locale), value)))
}

///
Expand All @@ -72,7 +83,11 @@ impl<T> LocalizedClaim<T> {
/// such entry.
///
pub fn insert(&mut self, locale: Option<LanguageTag>, value: T) -> Option<T> {
self.0.insert(locale, value)
if let Some(l) = locale {
self.0.insert(l, value)
} else {
self.1.replace(value)
}
}

///
Expand All @@ -81,45 +96,66 @@ impl<T> LocalizedClaim<T> {
/// Returns the current value associated with the given locale, or `None` if there is no
/// such entry.
///
pub fn remove(&mut self, locale: &Option<LanguageTag>) -> Option<T> {
self.0.remove(locale)
pub fn remove(&mut self, locale: Option<&LanguageTag>) -> Option<T> {
if let Some(l) = locale {
self.0.remove(l)
} else {
self.1.take()
}
}
}
impl<T> Default for LocalizedClaim<T> {
fn default() -> Self {
Self(HashMap::new())
}
}
impl<T> From<HashMap<Option<LanguageTag>, T>> for LocalizedClaim<T> {
fn from(inner: HashMap<Option<LanguageTag>, T>) -> Self {
Self(inner)
Self(HashMap::new(), None)
}
}
impl<T> From<T> for LocalizedClaim<T> {
fn from(inner: T) -> Self {
Self(vec![(None, inner)].into_iter().collect())
fn from(default: T) -> Self {
Self(HashMap::new(), Some(default))
}
}
impl<T> FromIterator<(Option<LanguageTag>, T)> for LocalizedClaim<T> {
fn from_iter<I: IntoIterator<Item = (Option<LanguageTag>, T)>>(iter: I) -> Self {
let inner: HashMap<Option<LanguageTag>, T> = iter.into_iter().collect();
Self(inner)
let mut temp: HashMap<Option<LanguageTag>, 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<T> {
type Item = (&'a Option<LanguageTag>, &'a T);
type IntoIter = std::collections::hash_map::Iter<'a, Option<LanguageTag>, T>;

fn into_iter(self) -> std::collections::hash_map::Iter<'a, Option<LanguageTag>, T> {
self.0.iter()
impl<T> IntoIterator for LocalizedClaim<T>
where
T: 'static,
{
type Item = <LocalizedClaimIterator<T> as Iterator>::Item;
type IntoIter = LocalizedClaimIterator<T>;

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<T> IntoIterator for LocalizedClaim<T> {
type Item = (Option<LanguageTag>, T);
type IntoIter = std::collections::hash_map::IntoIter<Option<LanguageTag>, T>;

fn into_iter(self) -> std::collections::hash_map::IntoIter<Option<LanguageTag>, T> {
self.0.into_iter()
///
/// Owned iterator over a LocalizedClaim.
///
pub struct LocalizedClaimIterator<T> {
inner: Box<dyn Iterator<Item = (Option<LanguageTag>, T)>>,
}
impl<T> Iterator for LocalizedClaimIterator<T> {
type Item = (Option<LanguageTag>, T);
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1805,7 +1805,7 @@ mod tests {
.unwrap()
.iter()
.collect::<Vec<_>>(),
vec![(&None, &EndUserName::new("Jane Doe".to_string()))],
vec![(None, &EndUserName::new("Jane Doe".to_string()))],
);

// Invalid subject
Expand Down

0 comments on commit 9f6e5d1

Please sign in to comment.