diff --git a/deny.toml b/deny.toml index a7044ee..ed224ae 100644 --- a/deny.toml +++ b/deny.toml @@ -108,7 +108,7 @@ allow = [ "Apache-2.0", "ISC", "OpenSSL", - "Unicode-DFS-2016", + "Unicode-3.0", #"Apache-2.0 WITH LLVM-exception", # Considered Copyleft, but permitted in this project "MPL-2.0", diff --git a/src/base64.rs b/src/base64.rs index a8f035a..45db55d 100644 --- a/src/base64.rs +++ b/src/base64.rs @@ -79,7 +79,7 @@ impl<'de> Deserialize<'de> for Bytes { struct BytesVisitor; -impl<'de> Visitor<'de> for BytesVisitor { +impl Visitor<'_> for BytesVisitor { type Value = Bytes; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { diff --git a/src/ear.rs b/src/ear.rs index ccff68b..8d71cd4 100644 --- a/src/ear.rs +++ b/src/ear.rs @@ -609,6 +609,7 @@ fn alg_to_cose(alg: &Algorithm) -> Result { mod test { use super::*; use crate::extension::*; + use crate::raw::{RawValue, RawValueKind}; use ciborium::{de::from_reader, ser::into_writer}; const EAR_STRING: &str = r#" @@ -805,20 +806,20 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgPp4XZRnRHSMhGg0t fn serde_extensions() { let mut profile = Profile::new("tag:github.com,2023:veraison/ear"); profile - .register_ear_extension("ext1", -1, ExtensionKind::String) + .register_ear_extension("ext1", -1, RawValueKind::String) .unwrap(); profile - .register_ear_extension("ext2", -2, ExtensionKind::Integer) + .register_ear_extension("ext2", -2, RawValueKind::Integer) .unwrap(); profile - .register_appraisal_extension("ext3", -1, ExtensionKind::Bytes) + .register_appraisal_extension("ext3", -1, RawValueKind::Bytes) .unwrap(); register_profile(&profile).unwrap(); let ear = serde_json::from_str::(EAR_WITH_EXTENSIONS_STRING).unwrap(); let v1 = ear.extensions.get_by_name("ext1").unwrap(); - assert_eq!(v1, ExtensionValue::String("foo".to_string())); + assert_eq!(v1, RawValue::String("foo".to_string())); let text = serde_json::to_string(&ear).unwrap(); assert_eq!( diff --git a/src/error.rs b/src/error.rs index db954e4..e6ab4a0 100644 --- a/src/error.rs +++ b/src/error.rs @@ -38,4 +38,7 @@ pub enum Error { // error while registering or accessing profiles #[error("profile error: {0}")] ProfileError(String), + // error during value conversion + #[error("value error: {0}")] + ValueError(String), } diff --git a/src/extension.rs b/src/extension.rs index f819688..fdd5658 100644 --- a/src/extension.rs +++ b/src/extension.rs @@ -1,222 +1,27 @@ // SPDX-License-Identifier: Apache-2.0 use std::collections::{BTreeMap, HashSet}; -use std::fmt; use std::sync::{Arc, Mutex, RwLock}; use lazy_static::lazy_static; -use serde::de::{Error as _, MapAccess, SeqAccess, Visitor}; +use serde::de::Error as _; use crate::appraisal::Appraisal; -use crate::base64::Bytes; use crate::ear::Ear; use crate::error::Error; - -/// specifies the type of an ExtensionValue (without requiring a concrete value) -#[derive(Clone, Debug, PartialEq)] -pub enum ExtensionKind { - Unset, - Bool, - String, - Bytes, - Integer, - Float, - Array, - Map, -} - -/// contains the value of an extension -#[derive(Clone, Debug, PartialEq, PartialOrd)] -pub enum ExtensionValue { - Unset, - Bool(bool), - String(String), - Bytes(Bytes), - Integer(i64), - Float(f64), - Array(Vec), - Map(Vec<(ExtensionValue, ExtensionValue)>), -} - -impl ExtensionValue { - pub fn kind(&self) -> ExtensionKind { - match self { - ExtensionValue::Unset => ExtensionKind::Unset, - ExtensionValue::Bool(_) => ExtensionKind::Bool, - ExtensionValue::String(_) => ExtensionKind::String, - ExtensionValue::Bytes(_) => ExtensionKind::Bytes, - ExtensionValue::Integer(_) => ExtensionKind::Integer, - ExtensionValue::Float(_) => ExtensionKind::Float, - ExtensionValue::Array(_) => ExtensionKind::Array, - ExtensionValue::Map(_) => ExtensionKind::Map, - } - } - - pub fn is(&self, kind: &ExtensionKind) -> bool { - self.kind() == *kind - } - - pub fn can_convert(&self, kind: &ExtensionKind) -> bool { - matches!( - (self.kind(), kind), - (ExtensionKind::String, ExtensionKind::Bytes) - | (ExtensionKind::Bytes, ExtensionKind::String) - ) - } - - pub fn convert(&self, kind: &ExtensionKind) -> Result { - match kind { - ExtensionKind::Bytes => match self { - ExtensionValue::String(s) => Ok(ExtensionValue::Bytes(Bytes::try_from(s as &str)?)), - other => Err(Error::ExtensionError(format!( - "cannot convert into {kind:?} from {other:?}", - ))), - }, - _ => Err(Error::ExtensionError(format!( - "cannot convert into {kind:?} from any other variant", - ))), - } - } -} - -impl serde::Serialize for ExtensionValue { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - match self { - ExtensionValue::Unset => serializer.serialize_none(), - ExtensionValue::Bool(v) => serializer.serialize_bool(*v), - ExtensionValue::String(v) => serializer.serialize_str(v), - ExtensionValue::Bytes(v) => v.serialize(serializer), - ExtensionValue::Integer(v) => serializer.serialize_i64(*v), - ExtensionValue::Float(v) => serializer.serialize_f64(*v), - ExtensionValue::Array(v) => v.serialize(serializer), - ExtensionValue::Map(v) => v.serialize(serializer), - } - } -} - -impl<'de> serde::Deserialize<'de> for ExtensionValue { - #[inline] - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - struct ValueVisitor; - - impl<'de> Visitor<'de> for ValueVisitor { - type Value = ExtensionValue; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("any valid JSON or CBOR value") - } - - #[inline] - fn visit_bool(self, value: bool) -> Result { - Ok(ExtensionValue::Bool(value)) - } - - #[inline] - fn visit_i64(self, value: i64) -> Result { - Ok(ExtensionValue::Integer(value)) - } - - #[inline] - fn visit_u64(self, value: u64) -> Result - where - E: serde::de::Error, - { - let v = i64::try_from(value).map_err(E::custom)?; - Ok(ExtensionValue::Integer(v)) - } - - #[inline] - fn visit_f64(self, value: f64) -> Result { - Ok(ExtensionValue::Float(value)) - } - - #[inline] - fn visit_str(self, value: &str) -> Result - where - E: serde::de::Error, - { - self.visit_string(String::from(value)) - } - - #[inline] - fn visit_string(self, value: String) -> Result { - Ok(ExtensionValue::String(value)) - } - - #[inline] - fn visit_bytes(self, v: &[u8]) -> Result { - Ok(ExtensionValue::Bytes(Bytes::from(v))) - } - - #[inline] - fn visit_none(self) -> Result { - Ok(ExtensionValue::Unset) - } - - #[inline] - fn visit_some(self, deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - serde::de::Deserialize::deserialize(deserializer) - } - - #[inline] - fn visit_unit(self) -> Result { - Ok(ExtensionValue::Unset) - } - - #[inline] - fn visit_seq(self, mut visitor: V) -> Result - where - V: SeqAccess<'de>, - { - let mut vec = Vec::new(); - - while let Some(elem) = visitor.next_element()? { - vec.push(elem); - } - - Ok(ExtensionValue::Array(vec)) - } - - fn visit_map(self, mut visitor: V) -> Result - where - V: MapAccess<'de>, - { - let mut ret = Vec::new(); - - while let Some((key, val)) = - visitor.next_entry::()? - { - ret.push((key, val)); - } - - Ok(ExtensionValue::Map(ret)) - } - } - - deserializer.deserialize_any(ValueVisitor) - } -} +use crate::raw::{RawValue, RawValueKind}; #[derive(Debug, Clone)] struct ExtensionEntry { - pub kind: ExtensionKind, - pub value: ExtensionValue, + pub kind: RawValueKind, + pub value: RawValue, } impl ExtensionEntry { - pub fn new(kind: ExtensionKind) -> ExtensionEntry { + pub fn new(kind: RawValueKind) -> ExtensionEntry { ExtensionEntry { kind, - value: ExtensionValue::Unset, + value: RawValue::Null, } } } @@ -231,7 +36,7 @@ enum CollectedKey { pub struct Extensions { by_key: BTreeMap>>, by_name: BTreeMap>>, - collected: BTreeMap, + collected: BTreeMap, } impl Default for Extensions { @@ -249,7 +54,7 @@ impl<'de> Extensions { } } - pub fn register(&mut self, name: &str, key: i32, kind: ExtensionKind) -> Result<(), Error> { + pub fn register(&mut self, name: &str, key: i32, kind: RawValueKind) -> Result<(), Error> { if self.by_name.contains_key(name) { return Err(Error::ExtensionError( format!("name {name} already registered").to_string(), @@ -314,33 +119,33 @@ impl<'de> Extensions { self.by_name.contains_key(name) } - pub fn get_by_key(&self, key: &i32) -> Option { + pub fn get_by_key(&self, key: &i32) -> Option { self.by_key .get(key) .map(|entry| entry.read().unwrap().value.clone()) } - pub fn get_by_name(&self, name: &str) -> Option { + pub fn get_by_name(&self, name: &str) -> Option { self.by_name .get(name) .map(|entry| entry.read().unwrap().value.clone()) } - pub fn get_kind_by_key(&self, key: &i32) -> ExtensionKind { + pub fn get_kind_by_key(&self, key: &i32) -> RawValueKind { match self.by_key.get(key) { Some(entry) => entry.read().unwrap().kind.clone(), - None => ExtensionKind::Unset, + None => RawValueKind::Null, } } - pub fn get_kind_by_name(&self, name: &str) -> ExtensionKind { + pub fn get_kind_by_name(&self, name: &str) -> RawValueKind { match self.by_name.get(name) { Some(entry) => entry.read().unwrap().kind.clone(), - None => ExtensionKind::Unset, + None => RawValueKind::Null, } } - pub fn set_by_key(&mut self, key: i32, value: ExtensionValue) -> Result<(), Error> { + pub fn set_by_key(&mut self, key: i32, value: RawValue) -> Result<(), Error> { let entry = self.by_key.get(&key).ok_or(Error::ExtensionError( format!("{key} not registered").to_string(), ))?; @@ -358,7 +163,7 @@ impl<'de> Extensions { Ok(()) } - pub fn set_by_name(&mut self, name: &str, value: ExtensionValue) -> Result<(), Error> { + pub fn set_by_name(&mut self, name: &str, value: RawValue) -> Result<(), Error> { let entry = self.by_name.get_mut(name).ok_or(Error::ExtensionError( format!("{name} not registered").to_string(), ))?; @@ -387,25 +192,12 @@ impl<'de> Extensions { if !self.have_name(name) { self.collected.insert( CollectedKey::Name(name.to_string()), - map.next_value::()?, + map.next_value::()?, ); return Ok(()); } - let value = match self.get_kind_by_name(name) { - ExtensionKind::Unset => Err(A::Error::custom("invalid extension".to_string())), - ExtensionKind::Bool => Ok(ExtensionValue::Bool(map.next_value::()?)), - ExtensionKind::String => Ok(ExtensionValue::String(map.next_value::()?)), - ExtensionKind::Bytes => Ok(ExtensionValue::Bytes(map.next_value::()?)), - ExtensionKind::Integer => Ok(ExtensionValue::Integer(map.next_value::()?)), - ExtensionKind::Float => Ok(ExtensionValue::Float(map.next_value::()?)), - ExtensionKind::Array => Ok(ExtensionValue::Array( - map.next_value::>()?, - )), - ExtensionKind::Map => Ok(ExtensionValue::Map( - map.next_value::>()?, - )), - }?; + let value = map.next_value::()?; self.set_by_name(name, value).map_err(A::Error::custom)?; @@ -418,24 +210,11 @@ impl<'de> Extensions { { if !self.have_key(&key) { self.collected - .insert(CollectedKey::Key(key), map.next_value::()?); + .insert(CollectedKey::Key(key), map.next_value::()?); return Ok(()); } - let value = match self.get_kind_by_key(&key) { - ExtensionKind::Unset => Err(A::Error::custom("invalid extension".to_string())), - ExtensionKind::Bool => Ok(ExtensionValue::Bool(map.next_value::()?)), - ExtensionKind::String => Ok(ExtensionValue::String(map.next_value::()?)), - ExtensionKind::Bytes => Ok(ExtensionValue::Bytes(map.next_value::()?)), - ExtensionKind::Integer => Ok(ExtensionValue::Integer(map.next_value::()?)), - ExtensionKind::Float => Ok(ExtensionValue::Float(map.next_value::()?)), - ExtensionKind::Array => Ok(ExtensionValue::Array( - map.next_value::>()?, - )), - ExtensionKind::Map => Ok(ExtensionValue::Map( - map.next_value::>()?, - )), - }?; + let value = map.next_value::()?; self.set_by_key(key, value).map_err(A::Error::custom)?; @@ -447,7 +226,7 @@ impl<'de> Extensions { M: serde::ser::SerializeMap, { for (name, val) in &self.by_name { - if val.read().unwrap().value.is(&ExtensionKind::Unset) { + if val.read().unwrap().value.is(&RawValueKind::Null) { continue; } @@ -462,7 +241,7 @@ impl<'de> Extensions { M: serde::ser::SerializeMap, { for (key, val) in &self.by_key { - if val.read().unwrap().value.is(&ExtensionKind::Unset) { + if val.read().unwrap().value.is(&RawValueKind::Null) { continue; } @@ -505,7 +284,7 @@ impl PartialEq for Extensions { struct RegisterEntry { pub name: String, pub key: i32, - pub kind: ExtensionKind, + pub kind: RawValueKind, } #[derive(Debug, Clone)] @@ -524,7 +303,7 @@ impl Register { } } - pub fn register(&mut self, name: &str, key: i32, kind: ExtensionKind) -> Result<(), Error> { + pub fn register(&mut self, name: &str, key: i32, kind: RawValueKind) -> Result<(), Error> { match self.names.get(name) { Some(_) => Err(Error::ExtensionError( format!("name {name} already registered").to_string(), @@ -578,7 +357,7 @@ impl Profile { &mut self, name: &str, key: i32, - kind: ExtensionKind, + kind: RawValueKind, ) -> Result<(), Error> { self.ear.register(name, key, kind) } @@ -587,7 +366,7 @@ impl Profile { &mut self, name: &str, key: i32, - kind: ExtensionKind, + kind: RawValueKind, ) -> Result<(), Error> { self.appraisal.register(name, key, kind) } @@ -657,6 +436,7 @@ pub fn get_profile(id: &str) -> Option { #[cfg(test)] mod test { use super::*; + use crate::base64::Bytes; use crate::error::Error; use std::str; @@ -668,49 +448,49 @@ mod test { #[test] fn crud() { let mut exts = Extensions::new(); - exts.register("foo", 1, ExtensionKind::String).unwrap(); + exts.register("foo", 1, RawValueKind::String).unwrap(); - let res = exts.register("foo", 2, ExtensionKind::String); + let res = exts.register("foo", 2, RawValueKind::String); assert!(matches!(res, Err(Error::ExtensionError(t)) if t == "name foo already registered")); - let res = exts.register("bad", 1, ExtensionKind::String); + let res = exts.register("bad", 1, RawValueKind::String); assert!(matches!(res, Err(Error::ExtensionError(t)) if t == "key 1 already registered")); - assert_eq!(exts.get_kind_by_key(&1), ExtensionKind::String); - assert_eq!(exts.get_kind_by_name("foo"), ExtensionKind::String); + assert_eq!(exts.get_kind_by_key(&1), RawValueKind::String); + assert_eq!(exts.get_kind_by_name("foo"), RawValueKind::String); assert!(exts.have_name("foo")); assert!(exts.have_key(&1)); assert!(!exts.have_name("bad")); assert!(!exts.have_key(&-1)); - exts.set_by_key(1, ExtensionValue::String("bar".to_string())) + exts.set_by_key(1, RawValue::String("bar".to_string())) .unwrap(); match exts.get_by_name("foo").unwrap() { - ExtensionValue::String(s) => assert_eq!(s, "bar"), + RawValue::String(s) => assert_eq!(s, "bar"), v => panic!("unexpected value: {v:?}"), } - exts.set_by_name("foo", ExtensionValue::String("buzz".to_string())) + exts.set_by_name("foo", RawValue::String("buzz".to_string())) .unwrap(); match exts.get_by_key(&1).unwrap() { - ExtensionValue::String(s) => assert_eq!(s, "buzz"), + RawValue::String(s) => assert_eq!(s, "buzz"), v => panic!("unexpected value: {v:?}"), } - let res = exts.set_by_name("bad", ExtensionValue::String("bar".to_string())); + let res = exts.set_by_name("bad", RawValue::String("bar".to_string())); assert!(matches!(res, Err(Error::ExtensionError(t)) if t == "bad not registered")); - let res = exts.set_by_key(-1, ExtensionValue::String("bar".to_string())); + let res = exts.set_by_key(-1, RawValue::String("bar".to_string())); assert!(matches!(res, Err(Error::ExtensionError(t)) if t == "-1 not registered")); - let res = exts.set_by_name("foo", ExtensionValue::Integer(42)); + let res = exts.set_by_name("foo", RawValue::Integer(42)); assert!(matches!(res, Err(Error::ExtensionError(t)) if t == "kind mismatch: value is Integer, but want String")); - let res = exts.set_by_key(1, ExtensionValue::Bool(true)); + let res = exts.set_by_key(1, RawValue::Bool(true)); assert!(matches!(res, Err(Error::ExtensionError(t)) if t == "kind mismatch: value is Bool, but want String")); } @@ -718,8 +498,8 @@ mod test { #[test] fn serde() { let mut exts = Extensions::new(); - exts.register("foo", 1, ExtensionKind::String).unwrap(); - exts.set_by_name("foo", ExtensionValue::String("bar".to_string())) + exts.register("foo", 1, RawValueKind::String).unwrap(); + exts.set_by_name("foo", RawValue::String("bar".to_string())) .unwrap(); let mut v = Vec::new(); @@ -736,10 +516,10 @@ mod test { #[test] fn value_convert() { - let v = ExtensionValue::String("3q2-7w".to_string()); - let res = v.convert(&ExtensionKind::Bytes).unwrap(); + let v = RawValue::String("3q2-7w".to_string()); + let res = v.convert(&RawValueKind::Bytes).unwrap(); - if let ExtensionValue::Bytes(bs) = res { + if let RawValue::Bytes(bs) = res { let expected: [u8; 4] = [0xde, 0xad, 0xbe, 0xef]; assert_eq!(bs, Bytes::from(&expected[..])); } else { @@ -750,13 +530,13 @@ mod test { #[test] fn test_send() { let mut exts = Extensions::new(); - exts.register("foo", 1, ExtensionKind::String).unwrap(); - exts.set_by_name("foo", ExtensionValue::String("test".to_string())) + exts.register("foo", 1, RawValueKind::String).unwrap(); + exts.set_by_name("foo", RawValue::String("test".to_string())) .unwrap(); let handle = thread::spawn(move || { let val = match exts.get_by_name("foo").unwrap() { - ExtensionValue::String(v) => v, + RawValue::String(v) => v, _ => panic!(), }; diff --git a/src/lib.rs b/src/lib.rs index 67a813c..9389a90 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,7 +75,7 @@ //! [`Appraisal`]s. An extension is an additional field definition. Extensions can be defined by //! registering them with the `extensions` field of the corresponding struct. When registering an //! extension, you must provide a string name (used in JSON), an integer key (used in CBOR), and an -//! [`ExtensionKind`] indicating which [`ExtensionValue`]s are valid. +//! [`RawValueKind`] indicating which [`RawValue`]s are valid. //! //! ## Registering individual extensions //! @@ -83,36 +83,36 @@ //! they have been registered, their values can be set and queried //! //! ``` -//! use ear::{Ear, Appraisal, ExtensionKind, ExtensionValue}; +//! use ear::{Ear, Appraisal, RawValueKind, RawValue}; //! //! let mut ear = Ear::new(); -//! ear.extensions.register("ext.company-name", -65537, ExtensionKind::String).unwrap(); +//! ear.extensions.register("ext.company-name", -65537, RawValueKind::String).unwrap(); //! //! let mut appraisal = Appraisal::new(); //! // extensions for Ear's and Appraisal's have their own namespaces, so it is //! // to use the same key in both. -//! appraisal.extensions.register("ext.timestamp", -65537, ExtensionKind::Integer).unwrap(); +//! appraisal.extensions.register("ext.timestamp", -65537, RawValueKind::Integer).unwrap(); //! //! ear.extensions.set_by_name( //! "ext.company-name", -//! ExtensionValue::String("Acme Inc.".to_string()), +//! RawValue::String("Acme Inc.".to_string()), //! ).unwrap(); //! //! appraisal.extensions.set_by_key( //! -65537, -//! ExtensionValue::Integer(1723534859), +//! RawValue::Integer(1723534859), //! ).unwrap(); //! //! ear.submods.insert("road-runner-trap".to_string(), appraisal); //! //! assert_eq!( //! ear.extensions.get_by_key(&-65537).unwrap(), -//! ExtensionValue::String("Acme Inc.".to_string()), +//! RawValue::String("Acme Inc.".to_string()), //! ); //! //! assert_eq!( //! ear.submods["road-runner-trap"].extensions.get_by_name("ext.timestamp").unwrap(), -//! ExtensionValue::Integer(1723534859), +//! RawValue::Integer(1723534859), //! ); //! ``` //! @@ -126,15 +126,15 @@ //! registered, and can then be retrieved by its `id` when creating a new [`Ear`] or [`Appraisal`] //! //! ``` -//! use ear::{Ear, Appraisal, ExtensionKind, ExtensionValue, Profile, register_profile}; +//! use ear::{Ear, Appraisal, RawValueKind, RawValue, Profile, register_profile}; //! //! fn init_profile() { //! let mut profile = Profile::new("tag:github.com,2023:veraison/ear#acme-profile"); //! //! profile.register_ear_extension( -//! "ext.company-name", -65537, ExtensionKind::String).unwrap(); +//! "ext.company-name", -65537, RawValueKind::String).unwrap(); //! profile.register_appraisal_extension( -//! "ext.timestamp", -65537, ExtensionKind::Integer).unwrap(); +//! "ext.timestamp", -65537, RawValueKind::Integer).unwrap(); //! //! register_profile(&profile); //! } @@ -150,25 +150,25 @@ //! //! ear.extensions.set_by_name( //! "ext.company-name", -//! ExtensionValue::String("Acme Inc.".to_string()), +//! RawValue::String("Acme Inc.".to_string()), //! ).unwrap(); //! //! appraisal.extensions.set_by_key( //! -65537, -//! ExtensionValue::Integer(1723534859), +//! RawValue::Integer(1723534859), //! ).unwrap(); //! //! ear.submods.insert("road-runner-trap".to_string(), appraisal); //! //! assert_eq!( //! ear.extensions.get_by_key(&-65537).unwrap(), -//! ExtensionValue::String("Acme Inc.".to_string()), +//! RawValue::String("Acme Inc.".to_string()), //! ); //! //! assert_eq!( //! ear.submods["road-runner-trap"] //! .extensions.get_by_name("ext.timestamp").unwrap(), -//! ExtensionValue::Integer(1723534859), +//! RawValue::Integer(1723534859), //! ); //! } //! @@ -188,7 +188,7 @@ //! inside an EAR. //! //! ``` -//! use ear::{Ear, Algorithm, Appraisal, ExtensionKind, ExtensionValue}; +//! use ear::{Ear, Algorithm, Appraisal, RawValueKind, RawValue}; //! use std::time::{SystemTime, Duration, UNIX_EPOCH}; //! //! const VERIF_KEY: &str = r#" @@ -212,13 +212,13 @@ //! ear.vid.build = "vsts 0.0.1".to_string(); //! ear.vid.developer = "https://veraison-project.org".to_string(); //! ear.submods.insert("road-runner-trap".to_string(), Appraisal::new()); -//! ear.extensions.register("exp", 4, ExtensionKind::Integer).unwrap(); +//! ear.extensions.register("exp", 4, RawValueKind::Integer).unwrap(); //! //! // expire 10 days from now //! let exp = SystemTime::now().checked_add(Duration::from_secs(60*60*24*10)).unwrap() //! .duration_since(UNIX_EPOCH).unwrap().as_secs() as i64; //! -//! ear.extensions.set_by_name("exp", ExtensionValue::Integer(exp)).unwrap(); +//! ear.extensions.set_by_name("exp", RawValue::Integer(exp)).unwrap(); //! //! //! let signed = ear @@ -228,11 +228,11 @@ //! let mut ear2 = //! Ear::from_jwt_jwk(signed.as_str(), Algorithm::ES256, VERIF_KEY.as_bytes()).unwrap(); //! -//! ear2.extensions.register("exp", 4, ExtensionKind::Integer).unwrap(); +//! ear2.extensions.register("exp", 4, RawValueKind::Integer).unwrap(); //! //! // Verify the token has not expired. //! let exp2 = match ear2.extensions.get_by_name("exp").unwrap() { -//! ExtensionValue::Integer(v) => Duration::from_secs(v as u64), +//! RawValue::Integer(v) => Duration::from_secs(v as u64), //! _ => panic!(), //! }; //! assert!(SystemTime::now().duration_since(UNIX_EPOCH).unwrap() < exp2); @@ -322,14 +322,13 @@ pub use self::ear::Ear; pub use self::error::Error; pub use self::extension::get_profile; pub use self::extension::register_profile; -pub use self::extension::ExtensionKind; -pub use self::extension::ExtensionValue; pub use self::extension::Extensions; pub use self::extension::Profile; pub use self::id::VerifierID; pub use self::key::KeyAttestation; pub use self::nonce::Nonce; pub use self::raw::RawValue; +pub use self::raw::RawValueKind; pub use self::trust::claim::TrustClaim; pub use self::trust::tier::TrustTier; pub use self::trust::vector::TrustVector; diff --git a/src/nonce.rs b/src/nonce.rs index f48fca4..b7787ed 100644 --- a/src/nonce.rs +++ b/src/nonce.rs @@ -123,7 +123,7 @@ impl<'de> Deserialize<'de> for OneNonce { struct OneNonceVisitor; -impl<'de> Visitor<'de> for OneNonceVisitor { +impl Visitor<'_> for OneNonceVisitor { type Value = OneNonce; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { diff --git a/src/raw.rs b/src/raw.rs index c55b5f9..bc9ea41 100644 --- a/src/raw.rs +++ b/src/raw.rs @@ -10,21 +10,78 @@ use serde::ser::{Serialize, Serializer}; use serde::ser::{SerializeMap as _, SerializeSeq as _, SerializeTupleVariant as _}; use crate::base64::Bytes; +use crate::error::Error; /// deserialized raw JSON object or CBOR map -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Clone)] pub enum RawValue { Null, Integer(i64), Bytes(Bytes), Float(f64), - Text(String), + String(String), Bool(bool), Array(Vec), Map(Vec<(RawValue, RawValue)>), Tagged(u64, Box), } +/// specifies the type of a RawValue (without requiring a concrete value) +#[derive(Clone, Debug, PartialEq)] +pub enum RawValueKind { + Null, + Bool, + String, + Bytes, + Integer, + Float, + Array, + Map, + Tagged, +} + +impl RawValue { + pub fn kind(&self) -> RawValueKind { + match self { + RawValue::Null => RawValueKind::Null, + RawValue::Bool(_) => RawValueKind::Bool, + RawValue::String(_) => RawValueKind::String, + RawValue::Bytes(_) => RawValueKind::Bytes, + RawValue::Integer(_) => RawValueKind::Integer, + RawValue::Float(_) => RawValueKind::Float, + RawValue::Array(_) => RawValueKind::Array, + RawValue::Map(_) => RawValueKind::Map, + RawValue::Tagged(_, _) => RawValueKind::Tagged, + } + } + + pub fn is(&self, kind: &RawValueKind) -> bool { + self.kind() == *kind + } + + pub fn can_convert(&self, kind: &RawValueKind) -> bool { + matches!( + (self.kind(), kind), + (RawValueKind::String, RawValueKind::Bytes) + | (RawValueKind::Bytes, RawValueKind::String) + ) + } + + pub fn convert(&self, kind: &RawValueKind) -> Result { + match kind { + RawValueKind::Bytes => match self { + RawValue::String(s) => Ok(RawValue::Bytes(Bytes::try_from(s as &str)?)), + other => Err(Error::ValueError(format!( + "cannot convert into {kind:?} from {other:?}", + ))), + }, + _ => Err(Error::ValueError(format!( + "cannot convert into {kind:?} from any other variant", + ))), + } + } +} + impl Serialize for RawValue { fn serialize(&self, serializer: S) -> Result where @@ -35,7 +92,7 @@ impl Serialize for RawValue { Self::Integer(i) => serializer.serialize_i64(*i), Self::Bytes(b) => b.serialize(serializer), Self::Float(f) => serializer.serialize_f64(*f), - Self::Text(s) => serializer.serialize_str(s), + Self::String(s) => serializer.serialize_str(s), Self::Bool(b) => serializer.serialize_bool(*b), Self::Array(vs) => { let mut seq = serializer.serialize_seq(Some(vs.len()))?; @@ -136,7 +193,7 @@ impl<'de> Visitor<'de> for RawValueVisitor { } fn visit_str(self, v: &str) -> Result { - Ok(RawValue::Text(v.to_string())) + Ok(RawValue::String(v.to_string())) } fn visit_bytes(self, v: &[u8]) -> Result { @@ -222,7 +279,7 @@ mod test { assert_eq!(r#""3q2-7w""#, val); let rv2: RawValue = serde_json::from_str(&val).unwrap(); - assert_eq!(rv2, RawValue::Text("3q2-7w".to_string())); + assert_eq!(rv2, RawValue::String("3q2-7w".to_string())); let mut buf: Vec = Vec::new(); into_writer(&rv, &mut buf).unwrap(); @@ -239,11 +296,11 @@ mod test { let rv = RawValue::Map(vec![ ( - RawValue::Text("field one".to_string()), + RawValue::String("field one".to_string()), RawValue::Float(7.0), ), ( - RawValue::Text("field two".to_string()), + RawValue::String("field two".to_string()), RawValue::Bool(true), ), ]); @@ -274,7 +331,7 @@ mod test { assert_eq!(rv2, rv); let rv = RawValue::Array(vec![ - RawValue::Text("foo".to_string()), + RawValue::String("foo".to_string()), RawValue::Integer(-1337), ]); @@ -299,13 +356,13 @@ mod test { let rv2: RawValue = from_reader(buf.as_slice()).unwrap(); assert_eq!(rv2, rv); - let rv = RawValue::Tagged(1, Box::new(RawValue::Text("foo".to_string()))); + let rv = RawValue::Tagged(1, Box::new(RawValue::String("foo".to_string()))); let val = serde_json::to_string(&rv).unwrap(); assert_eq!(r#""foo""#, val); let rv2: RawValue = serde_json::from_str(&val).unwrap(); - assert_eq!(rv2, RawValue::Text("foo".to_string())); // tag stripped + assert_eq!(rv2, RawValue::String("foo".to_string())); // tag stripped let mut buf: Vec = Vec::new(); into_writer(&rv, &mut buf).unwrap(); diff --git a/src/trust/tier.rs b/src/trust/tier.rs index 5f32f1b..9e9698c 100644 --- a/src/trust/tier.rs +++ b/src/trust/tier.rs @@ -53,7 +53,7 @@ impl<'de> Deserialize<'de> for TrustTier { struct TrustTierVisitor; -impl<'de> Visitor<'de> for TrustTierVisitor { +impl Visitor<'_> for TrustTierVisitor { type Value = TrustTier; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {