From e4aeb28a7a76468005c5d2a70790159dc583cd88 Mon Sep 17 00:00:00 2001 From: Eric Mark Martin Date: Tue, 30 Mar 2021 17:53:46 -0700 Subject: [PATCH 1/5] Implement `de::from_slice_count` Add a function that deserializes first valid cbor value out of a slice of bytes and returns the number of consumed bytes. --- src/de.rs | 31 +++++++++++++++++++++++++++++++ src/error.rs | 4 ++++ 2 files changed, 35 insertions(+) diff --git a/src/de.rs b/src/de.rs index 170e0593..d79b861a 100644 --- a/src/de.rs +++ b/src/de.rs @@ -54,6 +54,37 @@ where Ok(value) } +/// Decodes a value from the first piece of valid CBOR data in a slice. +/// +/// # Examples +/// +/// Deserialize a `String` +/// +/// ``` +/// # use serde_cbor::de; +/// let v: Vec = vec![0x66, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72, +/// 0xde, 0xad, 0xbe, 0xef]; // nonsense trailing data +/// let (value, len): (String, _) = de::from_slice_count(&v[..]).unwrap(); +/// assert_eq!(value, "foobar"); +/// assert_eq!(len, 7); +/// ``` +#[cfg(any(feature = "std", feature = "alloc"))] +pub fn from_slice_count<'a, T>(slice: &'a [u8]) -> Result<(T, usize)> +where T: de::Deserialize<'a> +{ + from_slice::(slice) + .map(|v| (v, slice.len())) + .or_else(|e| { + if matches!(e.code(), ErrorCode::TrailingData) { + // if format!("{}", e).starts_with("trailing data") { + let end = (e.offset() - 1) as usize; + from_slice::(&slice[..end]).map(|v| (v, end)) + } else { + Err(e) + } + }) +} + // When the "std" feature is enabled there should be little to no need to ever use this function, // as `from_slice` covers all use cases (at the expense of being less efficient). /// Decode a value from CBOR data in a mutable slice. diff --git a/src/error.rs b/src/error.rs index b1a6a459..ef0cbdf4 100644 --- a/src/error.rs +++ b/src/error.rs @@ -34,6 +34,10 @@ impl Error { self.0.offset } + pub(crate) fn code(&self) -> &ErrorCode { + &self.0.code + } + pub(crate) fn syntax(code: ErrorCode, offset: u64) -> Error { Error(ErrorImpl { code, offset }) } From 319ffb3f1e40894987a5381d6c764259aa780de6 Mon Sep 17 00:00:00 2001 From: Eric Mark Martin Date: Tue, 30 Mar 2021 18:16:57 -0700 Subject: [PATCH 2/5] format with rustfmt --- src/de.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/de.rs b/src/de.rs index d79b861a..9707a31a 100644 --- a/src/de.rs +++ b/src/de.rs @@ -70,13 +70,14 @@ where /// ``` #[cfg(any(feature = "std", feature = "alloc"))] pub fn from_slice_count<'a, T>(slice: &'a [u8]) -> Result<(T, usize)> -where T: de::Deserialize<'a> +where + T: de::Deserialize<'a>, { from_slice::(slice) .map(|v| (v, slice.len())) .or_else(|e| { if matches!(e.code(), ErrorCode::TrailingData) { - // if format!("{}", e).starts_with("trailing data") { + // if format!("{}", e).starts_with("trailing data") { let end = (e.offset() - 1) as usize; from_slice::(&slice[..end]).map(|v| (v, end)) } else { From c3f58e7502c805f3454946f8e14c27042e308bdb Mon Sep 17 00:00:00 2001 From: Eric Mark Martin Date: Tue, 30 Mar 2021 18:23:41 -0700 Subject: [PATCH 3/5] refactor to not use `matches!` --- src/de.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/de.rs b/src/de.rs index 9707a31a..73a2f213 100644 --- a/src/de.rs +++ b/src/de.rs @@ -76,8 +76,7 @@ where from_slice::(slice) .map(|v| (v, slice.len())) .or_else(|e| { - if matches!(e.code(), ErrorCode::TrailingData) { - // if format!("{}", e).starts_with("trailing data") { + if let ErrorCode::TrailingData = e.code() { let end = (e.offset() - 1) as usize; from_slice::(&slice[..end]).map(|v| (v, end)) } else { From 593d2b5c041de57764b3a9afffcf155780c8a562 Mon Sep 17 00:00:00 2001 From: Eric Mark Martin Date: Tue, 30 Mar 2021 18:52:35 -0700 Subject: [PATCH 4/5] simplify --- src/de.rs | 24 ++++++++++++++---------- src/error.rs | 4 ---- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/de.rs b/src/de.rs index 73a2f213..c27cdd3c 100644 --- a/src/de.rs +++ b/src/de.rs @@ -68,21 +68,25 @@ where /// assert_eq!(value, "foobar"); /// assert_eq!(len, 7); /// ``` +/// +/// Deserialize two consecutive `String`s +/// +/// ``` +/// # use serde_cbor::de; +/// let v: Vec = vec![0x63, 0x66, 0x6F, 0x6F, 0x63, 0x62, 0x61, 0x72]; +/// let (value_1, off): (String, _) = de::from_slice_count(&v[..]).unwrap(); +/// let (value_2, _): (String, _) = de::from_slice_count(&v[off..]).unwrap(); +/// assert_eq!(value_1, "foo"); +/// assert_eq!(value_2, "bar"); +/// ``` #[cfg(any(feature = "std", feature = "alloc"))] pub fn from_slice_count<'a, T>(slice: &'a [u8]) -> Result<(T, usize)> where T: de::Deserialize<'a>, { - from_slice::(slice) - .map(|v| (v, slice.len())) - .or_else(|e| { - if let ErrorCode::TrailingData = e.code() { - let end = (e.offset() - 1) as usize; - from_slice::(&slice[..end]).map(|v| (v, end)) - } else { - Err(e) - } - }) + let mut deserializer = Deserializer::from_slice(slice); + let value = de::Deserialize::deserialize(&mut deserializer)?; + Ok((value, deserializer.byte_offset())) } // When the "std" feature is enabled there should be little to no need to ever use this function, diff --git a/src/error.rs b/src/error.rs index ef0cbdf4..b1a6a459 100644 --- a/src/error.rs +++ b/src/error.rs @@ -34,10 +34,6 @@ impl Error { self.0.offset } - pub(crate) fn code(&self) -> &ErrorCode { - &self.0.code - } - pub(crate) fn syntax(code: ErrorCode, offset: u64) -> Error { Error(ErrorImpl { code, offset }) } From 5d4ab0400635ade3956a24da0750f8b8527b2d63 Mon Sep 17 00:00:00 2001 From: Eric Mark Martin Date: Tue, 30 Mar 2021 19:05:51 -0700 Subject: [PATCH 5/5] clarify documentation --- src/de.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/de.rs b/src/de.rs index c27cdd3c..33a6e713 100644 --- a/src/de.rs +++ b/src/de.rs @@ -54,7 +54,8 @@ where Ok(value) } -/// Decodes a value from the first piece of valid CBOR data in a slice. +/// Decodes a value from the first piece of valid CBOR data in a slice, +/// returning the number of bytes read to produce the value. /// /// # Examples ///