diff --git a/simd-json-derive-int/src/args.rs b/simd-json-derive-int/src/args.rs index 9cebce4..79cead4 100644 --- a/simd-json-derive-int/src/args.rs +++ b/simd-json-derive-int/src/args.rs @@ -38,7 +38,7 @@ impl Parse for FieldAttrs { other => { return Err(syn::Error::new( attr.span(), - format!("unexpected attribute `{}`", other), + format!("unexpected attribute `{other}`"), )) } } @@ -114,7 +114,7 @@ impl Parse for StructAttrs { other => { return Err(syn::Error::new( attr.span(), - format!("unexpected rename_all type `{}`", other), + format!("unexpected rename_all type `{other}`"), )) } } @@ -125,7 +125,7 @@ impl Parse for StructAttrs { other => { return Err(syn::Error::new( attr.span(), - format!("unexpected field attribute `{}`", other), + format!("unexpected field attribute `{other}`",), )) } } diff --git a/simd-json-derive-int/src/serialize/enum.rs b/simd-json-derive-int/src/serialize/enum.rs index 979480c..70ea8e9 100644 --- a/simd-json-derive-int/src/serialize/enum.rs +++ b/simd-json-derive-int/src/serialize/enum.rs @@ -89,7 +89,7 @@ pub(crate) fn derive( ( &v.ident, (0..v.fields.len()) - .map(|i| Ident::new(&format!("v{}", i), Span::call_site())) + .map(|i| Ident::new(&format!("v{i}"), Span::call_site())) .collect::>(), ), format!( diff --git a/simd-json-derive-int/src/serialize/struct/named.rs b/simd-json-derive-int/src/serialize/struct/named.rs index ef3cb1c..0a250c1 100644 --- a/simd-json-derive-int/src/serialize/struct/named.rs +++ b/simd-json-derive-int/src/serialize/struct/named.rs @@ -25,9 +25,9 @@ pub(crate) fn derive( } let expanded = if skip_if.iter().all(Option::is_none) { if let Some((first, rest)) = keys.split_first_mut() { - *first = format!("{{{}", first); + *first = format!("{{{first}"); for r in rest { - *r = format!(",{}", r); + *r = format!(",{r}"); } }; diff --git a/src/de.rs b/src/de.rs index 768963d..215921e 100644 --- a/src/de.rs +++ b/src/de.rs @@ -31,23 +31,33 @@ pub enum Error { expected(possible_field_names) )] UnknownField { + /// Unknown field that was encountered unknown_field: String, + /// Possible fields that are expected possible_field_names: &'static [&'static str], }, + /// unnamed enum field is not an array #[error("unnamed enum field `{0}` is not an array")] FieldNotAnArray(&'static str), + /// unknwon enum variant #[error("unknwon enum variant `{0}`")] UnknownEnumVariant(String), + /// invalid enum representation, needs to be either a string or an object #[error("invalid enum representation, needs to be either a string or an object")] InvalidEnumRepresentation, + /// invalid struct representation, needs to be an object #[error("invalid struct representation, needs to be an object")] InvalidStructRepresentation, + /// Unexpected e,nd of input #[error("Unexpected e,nd of input")] EOF, + /// Invalid integer number #[error("Invalid integer number")] InvalidNumber(#[from] TryFromIntError), + /// Custom error #[error("Custom error: {0}")] Custom(String), + /// The universe is broken #[error("The universe is broken: {0}")] BrokenUniverse(#[from] std::convert::Infallible), } @@ -58,43 +68,58 @@ impl Error { Error::Custom(msg.to_string()) } /// Expected String error + #[must_use] pub const fn expected_string() -> Self { Error::Json(simd_json::ErrorType::ExpectedString) } /// Expected Map error + #[must_use] pub const fn expected_map() -> Self { Error::Json(simd_json::ErrorType::ExpectedMap) } /// Expected Array error + #[must_use] pub const fn expected_array() -> Self { Error::Json(simd_json::ErrorType::ExpectedArray) } /// Expected Float error + #[must_use] pub const fn expected_float() -> Self { Error::Json(simd_json::ErrorType::ExpectedFloat) } /// Expected Null error + #[must_use] pub fn expected_null() -> Self { Error::Json(simd_json::ErrorType::ExpectedNull) } /// Expected Integer error + #[must_use] pub fn expected_integer() -> Self { Error::Json(simd_json::ErrorType::ExpectedInteger) } /// Expected Boolean error + #[must_use] pub fn expected_boolean() -> Self { Error::Json(simd_json::ErrorType::ExpectedBoolean) } } // Deserialisation result +/// Deserializer result pub type Result = std::result::Result; +/// Deserialisation trait for simd-json pub trait Deserialize<'input> { + /// Deserializes from a tape + /// # Errors + /// if deserialisation fails fn from_tape(tape: &mut Tape<'input>) -> Result where Self: Sized + 'input; + /// Deserializes from a u8 slice + /// # Errors + /// if deserialisation fails #[inline] fn from_slice(json: &'input mut [u8]) -> Result where @@ -105,6 +130,9 @@ pub trait Deserialize<'input> { Self::from_tape(&mut itr) } + /// Deserializes from a u8 slice using pre-allocated buffers + /// # Errors + /// if deserialisation fails #[inline] fn from_slice_with_buffers(json: &'input mut [u8], buffers: &mut Buffers) -> Result where @@ -116,6 +144,8 @@ pub trait Deserialize<'input> { } #[inline] + /// # Errors + /// if deserialisation fails /// # Safety /// /// user must not use the string afterwards diff --git a/src/impls.rs b/src/impls.rs index 0f62e86..fab7791 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -7,7 +7,7 @@ mod primitives; mod simdjson; mod string; mod tpl; -use crate::{de, *}; +use crate::{de, io, Deserialize, DummyGenerator, Serialize, Tape, Write}; use value_trait::generator::BaseGenerator; impl Serialize for Option diff --git a/src/impls/array.rs b/src/impls/array.rs index 83de232..7f16917 100644 --- a/src/impls/array.rs +++ b/src/impls/array.rs @@ -1,4 +1,4 @@ -use crate::*; +use crate::{de, io, Deserialize, Node, Serialize, Tape, Write}; use std::mem::MaybeUninit; use std::ptr; @@ -27,8 +27,10 @@ impl Drop for Guard<'_, T, N> { // SAFETY: this slice will contain only initialized objects. unsafe { - let slice = - ptr::slice_from_raw_parts_mut(self.array.as_mut_ptr() as *mut T, self.initialized); + let slice = ptr::slice_from_raw_parts_mut( + self.array.as_mut_ptr().cast::(), + self.initialized, + ); ptr::drop_in_place(slice); } } @@ -52,6 +54,7 @@ where if N == 0 { // Safety: N is 0, and so *const [T; N] is *const [T; 0] + #[allow(clippy::ref_as_ptr)] return Ok(unsafe { ptr::read((&[]) as *const [T; N]) }); } @@ -116,10 +119,10 @@ mod test { #[test] fn arr() { let s: [u8; 0] = []; - assert_eq!(s.json_string().unwrap(), "[]"); - assert_eq!([1].json_string().unwrap(), "[1]"); - assert_eq!([1, 2].json_string().unwrap(), "[1,2]"); - assert_eq!([1, 2, 3].json_string().unwrap(), "[1,2,3]"); + assert_eq!(s.json_string().expect("invalid "), "[]"); + assert_eq!([1].json_string().expect("invalid "), "[1]"); + assert_eq!([1, 2].json_string().expect("invalid "), "[1,2]"); + assert_eq!([1, 2, 3].json_string().expect("invalid "), "[1,2,3]"); } #[test] fn arr2() { @@ -143,9 +146,9 @@ mod test { #[test] fn slice() { let s: [u8; 0] = []; - assert_eq!(s.json_string().unwrap(), "[]"); - assert_eq!([1].json_string().unwrap(), "[1]"); - assert_eq!([1, 2].json_string().unwrap(), "[1,2]"); - assert_eq!([1, 2, 3].json_string().unwrap(), "[1,2,3]"); + assert_eq!(s.json_string().expect("invalid data"), "[]"); + assert_eq!([1].json_string().expect("invalid data"), "[1]"); + assert_eq!([1, 2].json_string().expect("invalid data"), "[1,2]"); + assert_eq!([1, 2, 3].json_string().expect("invalid data"), "[1,2,3]"); } } diff --git a/src/impls/chrono.rs b/src/impls/chrono.rs index d4a368b..6f639cf 100644 --- a/src/impls/chrono.rs +++ b/src/impls/chrono.rs @@ -1,5 +1,5 @@ use super::{BaseGenerator, DummyGenerator}; -use crate::*; +use crate::{de, Deserialize, Serialize, Tape, Write}; use chrono::{DateTime, FixedOffset, TimeZone}; use std::{fmt, io}; diff --git a/src/impls/collections.rs b/src/impls/collections.rs index fb6acc2..e12d802 100644 --- a/src/impls/collections.rs +++ b/src/impls/collections.rs @@ -74,7 +74,7 @@ where if let Some(simd_json::Node::Array { len, .. }) = tape.next() { let mut v = collections::VecDeque::new(); for _ in 0..len { - v.push_back(T::from_tape(tape)?) + v.push_back(T::from_tape(tape)?); } Ok(v) } else { @@ -95,7 +95,7 @@ where if let Some(simd_json::Node::Array { len, .. }) = tape.next() { let mut v = collections::BinaryHeap::new(); for _ in 0..len { - v.push(T::from_tape(tape)?) + v.push(T::from_tape(tape)?); } Ok(v) } else { @@ -349,33 +349,33 @@ mod test { #[test] fn vec() { let mut v: Vec = Vec::new(); - assert_eq!(v.json_string().unwrap(), "[]"); + assert_eq!(v.json_string().expect("invalid data"), "[]"); v.push(1); - let mut s = v.json_string().unwrap(); + let mut s = v.json_string().expect("invalid data"); assert_eq!(s, "[1]"); - let s: Vec = unsafe { Vec::from_str(s.as_mut_str()) }.unwrap(); + let s: Vec = unsafe { Vec::from_str(s.as_mut_str()) }.expect("invalid data"); assert_eq!(s, v); v.push(2); - let mut s = v.json_string().unwrap(); + let mut s = v.json_string().expect("invalid test data"); assert_eq!(s, "[1,2]"); - let s: Vec = unsafe { Vec::from_str(s.as_mut_str()) }.unwrap(); + let s: Vec = unsafe { Vec::from_str(s.as_mut_str()) }.expect("invalid test data"); assert_eq!(s, v); v.push(3); - let mut s = v.json_string().unwrap(); + let mut s = v.json_string().expect("invalid test data"); assert_eq!(s, "[1,2,3]"); - let s: Vec = unsafe { Vec::from_str(s.as_mut_str()) }.unwrap(); + let s: Vec = unsafe { Vec::from_str(s.as_mut_str()) }.expect("invalid test data"); assert_eq!(s, v); } #[test] fn range() { let r = 1..42; - let mut v = r.json_vec().unwrap(); + let mut v = r.json_vec().expect("invalid test data"); assert_eq!(br#"{"start":1,"end":42}"#, v.as_slice()); - let r1 = Range::from_slice(v.as_mut_slice()).unwrap(); + let r1 = Range::from_slice(v.as_mut_slice()).expect("invalid test data"); assert_eq!(r, r1); } } diff --git a/src/impls/primitives.rs b/src/impls/primitives.rs index 0b83b0d..c4710a6 100644 --- a/src/impls/primitives.rs +++ b/src/impls/primitives.rs @@ -4,9 +4,10 @@ use std::convert::TryFrom; impl Serialize for bool { #[inline] fn json_write(&self, writer: &mut W) -> Result { - match *self { - true => writer.write_all(b"true"), - false => writer.write_all(b"false"), + if *self { + writer.write_all(b"true") + } else { + writer.write_all(b"false") } } } @@ -96,6 +97,7 @@ ryu!(f32); impl<'input> Deserialize<'input> for f64 { #[inline] + #[allow(clippy::cast_precision_loss)] fn from_tape(tape: &mut Tape<'input>) -> de::Result where Self: Sized + 'input, @@ -115,6 +117,7 @@ impl<'input> Deserialize<'input> for f64 { impl<'input> Deserialize<'input> for f32 { #[inline] + #[allow(clippy::cast_precision_loss, clippy::cast_possible_truncation)] fn from_tape(tape: &mut Tape<'input>) -> de::Result where Self: Sized + 'input, diff --git a/src/impls/simdjson.rs b/src/impls/simdjson.rs index 69b939c..cb0c879 100644 --- a/src/impls/simdjson.rs +++ b/src/impls/simdjson.rs @@ -22,7 +22,6 @@ impl Serialize for BorrowedValue<'_> { struct OwnedDeser<'input, 'tape>(&'tape mut crate::Tape<'input>); impl OwnedDeser<'_, '_> { - #[inline(always)] fn parse(&mut self) -> OwnedValue { match self.0.next() { Some(Node::Static(s)) => OwnedValue::Static(s), @@ -32,19 +31,17 @@ impl OwnedDeser<'_, '_> { None => unreachable!("We have validated the tape in the second stage of parsing, this should never happen"), } } - #[inline(always)] fn parse_array(&mut self, len: usize) -> OwnedValue { let mut res: Vec = Vec::with_capacity(len); // Rust doesn't optimize the normal loop away here // so we write our own avoiding the length // checks during push for _ in 0..len { - res.push(self.parse()) + res.push(self.parse()); } OwnedValue::Array(Box::new(res)) } - #[inline(always)] fn parse_map(&mut self, len: usize) -> OwnedValue { let mut res = OwnedValue::object_with_capacity(len); @@ -76,7 +73,6 @@ impl<'input> Deserialize<'input> for OwnedValue { struct BorrowedDeser<'input, 'tape>(&'tape mut crate::Tape<'input>); impl<'input> BorrowedDeser<'input, '_> { - #[inline(always)] fn parse(&mut self) -> BorrowedValue<'input> { match self.0.next() { Some(Node::Static(s)) => BorrowedValue::Static(s), @@ -86,7 +82,6 @@ impl<'input> BorrowedDeser<'input, '_> { None => unreachable!("We have validated the tape in the second stage of parsing, this should never happen"), } } - #[inline(always)] fn parse_array(&mut self, len: usize) -> BorrowedValue<'input> { let mut res: Vec> = Vec::with_capacity(len); for _ in 0..len { @@ -95,7 +90,6 @@ impl<'input> BorrowedDeser<'input, '_> { BorrowedValue::Array(Box::new(res)) } - #[inline(always)] fn parse_map(&mut self, len: usize) -> BorrowedValue<'input> { let mut res = BorrowedValue::object_with_capacity(len); diff --git a/src/impls/tpl.rs b/src/impls/tpl.rs index 6bd4b02..946e581 100644 --- a/src/impls/tpl.rs +++ b/src/impls/tpl.rs @@ -95,8 +95,11 @@ mod test { #[test] fn tpl() { - assert_eq!((1).json_string().unwrap(), "1"); - assert_eq!((1, 2).json_string().unwrap(), "[1,2]"); - assert_eq!((1, 2, 3).json_string().unwrap(), "[1,2,3]"); + assert_eq!((1).json_string().expect("invalid test data"), "1"); + assert_eq!((1, 2).json_string().expect("invalid test data"), "[1,2]"); + assert_eq!( + (1, 2, 3).json_string().expect("invalid test data"), + "[1,2,3]" + ); } } diff --git a/src/lib.rs b/src/lib.rs index 4fcb8ea..205adba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,11 @@ +//! Derive for simd-json deserialisation +#![deny( + warnings, + clippy::unwrap_used, + clippy::unnecessary_unwrap, + clippy::pedantic, + missing_docs +)] use simd_json::Node; pub use simd_json_derive_int::*; use std::io::{self, Write}; @@ -5,25 +13,22 @@ use std::iter::Peekable; use std::vec::IntoIter; use value_trait::generator::BaseGenerator; mod impls; +/// Generic derive result pub type Result = io::Result<()>; +/// Tape to deserialize pub type Tape<'input> = Peekable>>; +/// Deserializer trait pub mod de; pub use de::Deserialize; +/// Skip method, skips n elements works with nested structures pub fn __skip(n: usize, tape: &mut Tape) { for _ in 0..n { match tape.next() { - Some(Node::Array { count, .. }) => { - for _ in 0..count { - if tape.next().is_none() { - return; - } - } - } - Some(Node::Object { count, .. }) => { + Some(Node::Object { count, .. } | Node::Array { count, .. }) => { for _ in 0..count { if tape.next().is_none() { return; @@ -35,26 +40,44 @@ pub fn __skip(n: usize, tape: &mut Tape) { } } } - +/// Serialisation logic for simd-json derive pub trait Serialize { + /// Writes the json to a writer + /// + /// # Errors + /// If the serialisation failed fn json_write(&self, writer: &mut W) -> Result where W: Write; #[inline] + /// Writes the json to a `Vec` + /// + /// # Errors + /// If the serialisation failed fn json_vec(&self) -> io::Result> { let mut v = Vec::with_capacity(512); self.json_write(&mut v)?; Ok(v) } + #[inline] + /// Writes the json to a `String` + /// + /// # Errors + /// If the serialisation failed fn json_string(&self) -> io::Result { self.json_vec() .map(|v| unsafe { String::from_utf8_unchecked(v) }) } } +/// Helper traint to serialize keys of json struct pub trait SerializeAsKey { + /// Writes the json to a writer + /// + /// # Errors + /// If the serialisation failed fn json_write(&self, writer: &mut W) -> Result where W: Write; diff --git a/tests/deser.rs b/tests/deser.rs index 81b4c65..d76b83e 100644 --- a/tests/deser.rs +++ b/tests/deser.rs @@ -37,7 +37,7 @@ fn deser() { f3: SnotBadger::Snot, }; let mut s = b.json_string().unwrap(); - println!("{}", s); + println!("{s}"); assert_eq!(r#"{"f1":1,"f2":"snot","f3":"Snot"}"#, s); let b1 = unsafe { Bla::from_str(s.as_mut_str()) }.unwrap(); assert_eq!(b, b1); diff --git a/tests/simdjson.rs b/tests/simdjson.rs index cfcd7fe..b724e87 100644 --- a/tests/simdjson.rs +++ b/tests/simdjson.rs @@ -11,6 +11,6 @@ fn owned_value() { assert_eq!(input, serialized); let deserialized = unsafe { simd_json::owned::Value::from_str(serialized.as_mut_str()) } .expect("Expected serialized input to be deserialized ok"); - println!("{}", deserialized); + println!("{deserialized}"); assert_eq!(value, deserialized); } diff --git a/tests/struct.rs b/tests/struct.rs index 4522ac1..53c119a 100644 --- a/tests/struct.rs +++ b/tests/struct.rs @@ -31,7 +31,7 @@ fn named() { f2: "snot".into(), }; let mut s = b.json_string().unwrap(); - println!("{}", s); + println!("{s}",); assert_eq!(r#"{"f1":1,"f2":"snot"}"#, s); let b1 = unsafe { Bla::from_str(s.as_mut_str()) }.unwrap(); assert_eq!(b, b1);