From 2f60cbfa8b6d572750404d0b8c6c52d64e1f7e25 Mon Sep 17 00:00:00 2001 From: anweiss <2326106+anweiss@users.noreply.github.com> Date: Mon, 10 Apr 2023 12:20:35 -0400 Subject: [PATCH 1/2] fix #183 --- src/parser.rs | 12 +++---- src/validator/cbor.rs | 82 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 84 insertions(+), 10 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index e1f0c2d2..dadd0455 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -448,7 +448,7 @@ impl<'a> Parser<'a> { let begin_rule_col = self.lexer_position.column; let ident = match &self.cur_token { - Token::IDENT(i, s) => self.identifier_from_ident_token(*i, *s), + Token::IDENT(i, s) => self.identifier_from_ident_token(i, *s), _ => { #[cfg(feature = "ast-span")] { @@ -940,7 +940,7 @@ impl<'a> Parser<'a> { match &self.cur_token { Token::IDENT(ident, socket) => { - let param = self.identifier_from_ident_token(*ident, *socket); + let param = self.identifier_from_ident_token(ident, *socket); self.next_token()?; @@ -1397,7 +1397,7 @@ impl<'a> Parser<'a> { // optional genericarg detected if self.peek_token_is(&Token::LANGLEBRACKET) { - let ident = self.identifier_from_ident_token(*ident, *socket); + let ident = self.identifier_from_ident_token(ident, *socket); let ga = self.parse_genericargs()?; #[cfg(feature = "ast-span")] @@ -1418,7 +1418,7 @@ impl<'a> Parser<'a> { } Ok(Type2::Typename { - ident: self.identifier_from_ident_token(*ident, *socket), + ident: self.identifier_from_ident_token(ident, *socket), generic_args: None, #[cfg(feature = "ast-span")] span: ( @@ -1598,7 +1598,7 @@ impl<'a> Parser<'a> { let ident = if let Some(ident) = self.cur_token.in_standard_prelude() { Some(self.identifier_from_ident_token(ident, None)) } else if let Token::IDENT(ident, socket) = &self.cur_token { - Some(self.identifier_from_ident_token(*ident, *socket)) + Some(self.identifier_from_ident_token(ident, *socket)) } else { None }; @@ -1684,7 +1684,7 @@ impl<'a> Parser<'a> { }) } Token::IDENT(ident, socket) => { - let ident = self.identifier_from_ident_token(*ident, *socket); + let ident = self.identifier_from_ident_token(ident, *socket); if self.peek_token_is(&Token::LANGLEBRACKET) { self.next_token()?; diff --git a/src/validator/cbor.rs b/src/validator/cbor.rs index b694ab3a..2b542920 100644 --- a/src/validator/cbor.rs +++ b/src/validator/cbor.rs @@ -9,6 +9,7 @@ use crate::{ visitor::{self, *}, }; +use core::convert::TryInto; use std::{ borrow::Cow, collections::HashMap, @@ -2292,6 +2293,53 @@ where Ok(()) } + Value::Tag(tag, value) => { + match *tag { + 0 => { + if is_ident_tdate_data_type(self.cddl, ident) { + if let Value::Text(value) = value.as_ref() { + if let Err(e) = chrono::DateTime::parse_from_rfc3339(value) { + self.add_error(format!("expected tdate data type, decoding error: {}", e)); + } + } else { + self.add_error(format!("expected type {}, got {:?}", ident, self.cbor)); + } + } else { + self.add_error(format!("expected type {}, got {:?}", ident, self.cbor)); + } + } + 1 => { + if is_ident_time_data_type(self.cddl, ident) { + if let Value::Integer(value) = *value.as_ref() { + let dt = Utc.timestamp_opt(value.try_into().unwrap(), 0); + if let chrono::LocalResult::None = dt { + self.add_error(format!( + "expected time data type, invalid UNIX timestamp {:?}", + self.cbor + )); + } + } else if let Value::Float(value) = value.as_ref() { + let seconds = value.trunc() as i64; + let nanoseconds = (value.fract() * 1e9) as u32; + let dt = Utc.timestamp_opt(seconds, nanoseconds); + if let chrono::LocalResult::None = dt { + self.add_error(format!( + "expected time data type, invalid UNIX timestamp {:?}", + self.cbor + )); + } + } else { + self.add_error(format!("expected type {}, got {:?}", ident, self.cbor)); + } + } else { + self.add_error(format!("expected type {}, got {:?}", ident, self.cbor)); + } + } + _ => (), + } + + Ok(()) + } Value::Array(_) => self.validate_array_items(&ArrayItemToken::Identifier(ident)), Value::Map(m) => { match &self.occurrence { @@ -3209,10 +3257,10 @@ where { None } - Some(ControlOperator::LT) if *f < *v as f64 => None, - Some(ControlOperator::LE) if *f <= *v as f64 => None, - Some(ControlOperator::GT) if *f > *v as f64 => None, - Some(ControlOperator::GE) if *f >= *v as f64 => None, + Some(ControlOperator::LT) if *f < *v => None, + Some(ControlOperator::LE) if *f <= *v => None, + Some(ControlOperator::GT) if *f > *v => None, + Some(ControlOperator::GE) if *f >= *v => None, #[cfg(feature = "additional-controls")] Some(ControlOperator::PLUS) => { if (*f - *v).abs() < std::f64::EPSILON { @@ -3635,4 +3683,30 @@ mod tests { Ok(()) } + + #[test] + fn validate_tdate_tag() -> std::result::Result<(), Box> { + let cddl = indoc!( + r#" + root = time + "# + ); + + let cddl = cddl_from_str(cddl, true).map_err(json::Error::CDDLParsing); + if let Err(e) = &cddl { + println!("{}", e); + } + + let cbor = ciborium::value::Value::Tag( + 1, + Box::from(ciborium::value::Value::Float(1680965875.01_f64)), + ); + + let cddl = cddl.unwrap(); + + let mut cv = CBORValidator::new(&cddl, cbor, None); + cv.validate()?; + + Ok(()) + } } From 4a23f122bac4a0b7b6733818c5a37f43fb2d698d Mon Sep 17 00:00:00 2001 From: anweiss <2326106+anweiss@users.noreply.github.com> Date: Mon, 10 Apr 2023 12:20:45 -0400 Subject: [PATCH 2/2] clippy lints --- src/ast/mod.rs | 13 +------------ src/validator/control.rs | 8 ++++---- src/validator/json.rs | 12 ++++++------ 3 files changed, 11 insertions(+), 22 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 9e16b0fc..783c11f7 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -637,7 +637,7 @@ impl<'a> fmt::Display for GenericParams<'a> { /// genericarg = "<" S type1 S *("," S type1 S ) ">" /// ``` #[cfg_attr(target_arch = "wasm32", derive(Serialize))] -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Default)] pub struct GenericArgs<'a> { /// Generic arguments pub args: Vec>, @@ -646,17 +646,6 @@ pub struct GenericArgs<'a> { pub span: Span, } -impl<'a> GenericArgs<'a> { - /// Default `GenericArg` - pub fn default() -> Self { - GenericArgs { - args: Vec::new(), - #[cfg(feature = "ast-span")] - span: (0, 0, 0), - } - } -} - /// Generic argument #[cfg_attr(target_arch = "wasm32", derive(Serialize))] #[derive(Debug, Clone, PartialEq)] diff --git a/src/validator/control.rs b/src/validator/control.rs index a0c7e872..22895ca0 100644 --- a/src/validator/control.rs +++ b/src/validator/control.rs @@ -435,7 +435,7 @@ pub fn cat_operation<'a>( literals.push( ByteValue::B64( - base64::encode_config(&concat, base64::URL_SAFE) + base64::encode_config(concat, base64::URL_SAFE) .into_bytes() .into(), ) @@ -474,7 +474,7 @@ pub fn cat_operation<'a>( literals.push( ByteValue::B64( - base64::encode_config(&concat, base64::URL_SAFE) + base64::encode_config(concat, base64::URL_SAFE) .into_bytes() .into(), ) @@ -500,7 +500,7 @@ pub fn cat_operation<'a>( }; literals.push( ByteValue::B64( - base64::encode_config(&concat, base64::URL_SAFE) + base64::encode_config(concat, base64::URL_SAFE) .into_bytes() .into(), ) @@ -528,7 +528,7 @@ pub fn cat_operation<'a>( }; literals.push( ByteValue::B64( - base64::encode_config(&concat, base64::URL_SAFE) + base64::encode_config(concat, base64::URL_SAFE) .into_bytes() .into(), ) diff --git a/src/validator/json.rs b/src/validator/json.rs index 5fbf3a71..b03a9ee8 100644 --- a/src/validator/json.rs +++ b/src/validator/json.rs @@ -1040,12 +1040,12 @@ impl<'a, 'b> Visitor<'a, 'b, Error> for JSONValidator<'a> { Value::Number(n) => { if let Some(f) = n.as_f64() { if is_inclusive { - if f < *l as f64 || f > *u as f64 { + if f < *l || f > *u { self.add_error(error_str); } else { return Ok(()); } - } else if f <= *l as f64 || f >= *u as f64 { + } else if f <= *l || f >= *u { self.add_error(error_str); return Ok(()); } else { @@ -2383,10 +2383,10 @@ impl<'a, 'b> Visitor<'a, 'b, Error> for JSONValidator<'a> { { None } - Some(ControlOperator::LT) if f < *v as f64 => None, - Some(ControlOperator::LE) if f <= *v as f64 => None, - Some(ControlOperator::GT) if f > *v as f64 => None, - Some(ControlOperator::GE) if f >= *v as f64 => None, + Some(ControlOperator::LT) if f < *v => None, + Some(ControlOperator::LE) if f <= *v => None, + Some(ControlOperator::GT) if f > *v => None, + Some(ControlOperator::GE) if f >= *v => None, #[cfg(feature = "additional-controls")] Some(ControlOperator::PLUS) => { if (f - *v).abs() < std::f64::EPSILON {