diff --git a/src/lib.rs b/src/lib.rs index f7fd982f6..c2995fe88 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ pub mod der; pub mod did; pub mod error; pub mod jwk; +pub(crate) mod one_or_many; pub mod vc; extern crate pest; diff --git a/src/one_or_many.rs b/src/one_or_many.rs new file mode 100644 index 000000000..347bb00c1 --- /dev/null +++ b/src/one_or_many.rs @@ -0,0 +1,79 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(untagged)] +pub enum OneOrMany { + One(T), + Many(Vec), +} + +impl OneOrMany { + pub fn len(&self) -> usize { + match self { + Self::One(_) => 1, + Self::Many(values) => values.len(), + } + } + + pub fn contains(&self, x: &T) -> bool + where + T: PartialEq, + { + match self { + Self::One(value) => x == value, + Self::Many(values) => values.contains(x), + } + } + + pub fn first(&self) -> Option<&T> { + match self { + Self::One(value) => Some(&value), + Self::Many(values) => { + if values.len() > 0 { + Some(&values[0]) + } else { + None + } + } + } + } + + pub fn to_single(&self) -> Option<&T> { + match self { + Self::One(value) => Some(&value), + Self::Many(values) => { + if values.len() == 1 { + Some(&values[0]) + } else { + None + } + } + } + } +} + +// consuming iterator +impl IntoIterator for OneOrMany { + type Item = T; + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + match self { + Self::One(value) => vec![value].into_iter(), + Self::Many(values) => values.into_iter(), + } + } +} + +// non-consuming iterator +impl<'a, T> IntoIterator for &'a OneOrMany { + type Item = &'a T; + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + match self { + OneOrMany::One(value) => vec![value].into_iter(), + OneOrMany::Many(values) => values.into_iter().collect::>().into_iter(), + } + } +} diff --git a/src/vc.rs b/src/vc.rs index 7a6f81516..d574fa86b 100644 --- a/src/vc.rs +++ b/src/vc.rs @@ -3,6 +3,7 @@ use std::convert::TryFrom; use crate::error::Error; use crate::jwk::{JWTKeys, Params}; +use crate::one_or_many::OneOrMany; use chrono::prelude::*; use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey, Header, Validation}; @@ -63,13 +64,6 @@ pub struct Credential { pub refresh_service: Option>, } -#[derive(Debug, Serialize, Deserialize, Clone)] -#[serde(untagged)] -pub enum OneOrMany { - One(T), - Many(Vec), -} - #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(untagged)] #[serde(try_from = "OneOrMany")] @@ -231,61 +225,6 @@ pub struct JWTClaims { pub verifiable_presentation: Option, } -impl OneOrMany { - pub fn any(&self, f: F) -> bool - where - F: Fn(&T) -> bool, - { - match self { - Self::One(value) => f(value), - Self::Many(values) => values.iter().any(f), - } - } - - pub fn len(&self) -> usize { - match self { - Self::One(_) => 1, - Self::Many(values) => values.len(), - } - } - - pub fn contains(&self, x: &T) -> bool - where - T: PartialEq, - { - match self { - Self::One(value) => x == value, - Self::Many(values) => values.contains(x), - } - } - - pub fn first(&self) -> Option<&T> { - match self { - Self::One(value) => Some(&value), - Self::Many(values) => { - if values.len() > 0 { - Some(&values[0]) - } else { - None - } - } - } - } - - pub fn to_single(&self) -> Option<&T> { - match self { - Self::One(value) => Some(&value), - Self::Many(values) => { - if values.len() == 1 { - Some(&values[0]) - } else { - None - } - } - } - } -} - impl TryFrom> for Contexts { type Error = Error; fn try_from(context: OneOrMany) -> Result {