diff --git a/src/macros.rs b/src/macros.rs index c0b34fc1..572fefbf 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1262,7 +1262,7 @@ macro_rules! static_cast_i8 { #[macro_export] macro_rules! static_cast_i32 { ($v:expr) => { - std::mem::transmute::($v) + ::std::mem::transmute::($v) }; } diff --git a/src/numberparse/approx.rs b/src/numberparse/approx.rs index 802f72e1..a47804ef 100644 --- a/src/numberparse/approx.rs +++ b/src/numberparse/approx.rs @@ -433,8 +433,6 @@ impl<'de> Deserializer<'de> { #[cfg(feature = "swar-number-parsing")] { - // FIXME - // can we omit this: buf.len() - byte_count >= 8 let chars: [u8; 8] = unsafe { *(buf .get_kinda_unchecked(byte_count..byte_count + 8) @@ -528,7 +526,6 @@ impl<'de> Deserializer<'de> { StaticNode::F64(0.0) } else { if !(-323..=308).contains(&exponent) { - //FIXME Parse it as a expensive float perhaps return Self::parse_float(idx, buf, negative); } diff --git a/src/value/lazy.rs b/src/value/lazy.rs index 7b1f6ecc..64d5c34f 100644 --- a/src/value/lazy.rs +++ b/src/value/lazy.rs @@ -1,4 +1,26 @@ -use crate::prelude::*; +//! Lazy value, this gets initialized with a tape and as long as only non mutating operations are performed +//! it will stay a tape. If it is mutated it is upgtaded to a borrowed value. +//! This allows for a very cheap parsin and data access while still maintaining mutability. +//! +//! # Example +//! +//! ```rust +//! use simd_json::{prelude::*, value::lazy::Value}; +//! +//! let mut json = br#"{"key": "value", "snot": 42}"#.to_vec(); +//! let tape = simd_json::to_tape( json.as_mut_slice()).unwrap(); +//! let value = tape.as_value(); +//! let mut lazy = Value::from_tape(value); +//! +//! assert_eq!(lazy.get("key").unwrap(), "value"); +//! +//! assert!(lazy.is_tape()); +//! lazy.insert("new", 42); +//! assert!(lazy.is_value()); +//! assert_eq!(lazy.get("key").unwrap(), "value"); +//! assert_eq!(lazy.get("new").unwrap(), 42); +//! ``` + use crate::{borrowed, tape}; use std::borrow::Cow; use std::fmt; @@ -7,6 +29,7 @@ mod array; mod cmp; mod from; mod object; +mod trait_impls; pub use array::Array; pub use object::Object; @@ -15,7 +38,10 @@ pub use object::Object; /// performed it will stay a tape. If a mutating operation is performed it will upgrade to a borrowed /// value. #[derive(Clone, Debug, PartialEq)] -pub enum Value<'tape, 'input> { +pub enum Value<'tape, 'input> +where + 'input: 'tape, +{ /// tape variant Tape(tape::Value<'tape, 'input>), /// borrowed variant @@ -30,6 +56,20 @@ impl Default for Value<'static, '_> { } impl<'tape, 'input> Value<'tape, 'input> { + /// returns true when the current representation is a tape + #[must_use] + pub fn is_tape(&self) -> bool { + match self { + Value::Tape(_) => true, + Value::Value(_) => false, + } + } + /// returns true when the current representation is a borrowed value + /// this is the opposite of `is_tape` + #[must_use] + pub fn is_value(&self) -> bool { + !self.is_tape() + } /// Creates a new lazy Value from a tape #[must_use] pub fn from_tape(tape: tape::Value<'tape, 'input>) -> Self { @@ -55,13 +95,6 @@ impl<'tape, 'input> Value<'tape, 'input> { *self = Value::Value(Cow::Owned(value)); } - fn is_tape(&self) -> bool { - match &self { - Value::Tape(_) => true, - Value::Value(_) => false, - } - } - fn as_mut(&mut self) -> &mut borrowed::Value<'input> { if self.is_tape() { self.upgrade(); @@ -75,205 +108,6 @@ impl<'tape, 'input> Value<'tape, 'input> { } } -impl<'value> ValueBuilder<'value> for Value<'static, 'value> { - #[cfg_attr(not(feature = "no-inline"), inline)] - #[must_use] - fn null() -> Self { - Value::Value(Cow::Owned(borrowed::Value::null())) - } - #[cfg_attr(not(feature = "no-inline"), inline)] - #[must_use] - fn array_with_capacity(capacity: usize) -> Self { - Value::Value(Cow::Owned(borrowed::Value::array_with_capacity(capacity))) - } - #[cfg_attr(not(feature = "no-inline"), inline)] - #[must_use] - fn object_with_capacity(capacity: usize) -> Self { - Value::Value(Cow::Owned(borrowed::Value::object_with_capacity(capacity))) - } -} - -impl<'tape, 'value> ValueAsMutContainer for Value<'tape, 'value> { - type Array = Vec>; - type Object = super::borrowed::Object<'value>; - #[cfg_attr(not(feature = "no-inline"), inline)] - #[must_use] - fn as_array_mut(&mut self) -> Option<&mut Vec>> { - self.as_mut().as_array_mut() - } - #[cfg_attr(not(feature = "no-inline"), inline)] - #[must_use] - fn as_object_mut(&mut self) -> Option<&mut super::borrowed::Object<'value>> { - self.as_mut().as_object_mut() - } -} - -impl<'tape, 'value> TypedValue for Value<'tape, 'value> { - #[cfg_attr(not(feature = "no-inline"), inline)] - #[must_use] - fn value_type(&self) -> ValueType { - match &self { - Value::Tape(tape) => tape.value_type(), - Value::Value(value) => value.value_type(), - } - } -} - -impl<'tape, 'value> ValueAsScalar for Value<'tape, 'value> { - #[cfg_attr(not(feature = "no-inline"), inline)] - #[must_use] - fn as_null(&self) -> Option<()> { - match &self { - Value::Tape(tape) => tape.as_null(), - Value::Value(value) => value.as_null(), - } - } - - #[cfg_attr(not(feature = "no-inline"), inline)] - #[must_use] - fn as_bool(&self) -> Option { - match &self { - Value::Tape(tape) => tape.as_bool(), - Value::Value(value) => value.as_bool(), - } - } - - #[cfg_attr(not(feature = "no-inline"), inline)] - #[must_use] - fn as_i64(&self) -> Option { - match &self { - Value::Tape(tape) => tape.as_i64(), - Value::Value(value) => value.as_i64(), - } - } - - #[cfg_attr(not(feature = "no-inline"), inline)] - #[must_use] - fn as_i128(&self) -> Option { - match &self { - Value::Tape(tape) => tape.as_i128(), - Value::Value(value) => value.as_i128(), - } - } - - #[cfg_attr(not(feature = "no-inline"), inline)] - #[must_use] - fn as_u64(&self) -> Option { - match &self { - Value::Tape(tape) => tape.as_u64(), - Value::Value(value) => value.as_u64(), - } - } - - #[cfg_attr(not(feature = "no-inline"), inline)] - #[must_use] - fn as_u128(&self) -> Option { - match &self { - Value::Tape(tape) => tape.as_u128(), - Value::Value(value) => value.as_u128(), - } - } - - #[cfg_attr(not(feature = "no-inline"), inline)] - #[must_use] - fn as_f64(&self) -> Option { - match &self { - Value::Tape(tape) => tape.as_f64(), - Value::Value(value) => value.as_f64(), - } - } - - #[cfg_attr(not(feature = "no-inline"), inline)] - #[must_use] - fn cast_f64(&self) -> Option { - match &self { - Value::Tape(tape) => tape.cast_f64(), - Value::Value(value) => value.cast_f64(), - } - } - - #[cfg_attr(not(feature = "no-inline"), inline)] - #[must_use] - fn as_str(&self) -> Option<&str> { - match &self { - Value::Tape(tape) => tape.as_str(), - Value::Value(value) => value.as_str(), - } - } -} - -// impl<'tape, 'value> ValueAsContainer for Value<'tape, 'value> { -impl<'tape, 'value> Value<'tape, 'value> { - // type Array = array::Array<'tape, 'value>; - // type Object = Object<'tape, 'value>; - - /// Tries to represent the value as an array and returns a reference to it - #[cfg_attr(not(feature = "no-inline"), inline)] - #[must_use] - pub fn as_array(&self) -> Option> { - match self { - Value::Tape(tape) => tape.as_array().map(Array::Tape), - Value::Value(value) => value.as_array().map(array::Array::Value), - } - } - - /// Tries to represent the value as an array and returns a reference to it - #[cfg_attr(not(feature = "no-inline"), inline)] - #[must_use] - pub fn as_object(&self) -> Option { - match self { - Value::Tape(tape) => tape.as_object().map(Object::Tape), - Value::Value(value) => value.as_object().map(Object::Value), - } - } -} - -impl<'tape, 'value> ValueIntoString for Value<'tape, 'value> { - type String = Cow<'value, str>; - - fn into_string(self) -> Option<::String> { - match self { - Value::Tape(tape) => tape.into_string().map(Cow::Borrowed), - // This is a bit complex but it allows us to avoid cloning - Value::Value(value) => match value { - Cow::Borrowed(value) => match value { - #[cfg(feature = "beef")] - borrowed::Value::String(s) => Some(s.clone().into()), - #[cfg(not(feature = "beef"))] - borrowed::Value::String(s) => Some(s.clone()), - _ => None, - }, - Cow::Owned(value) => match value { - #[cfg(feature = "beef")] - borrowed::Value::String(s) => Some(s.into()), - #[cfg(not(feature = "beef"))] - borrowed::Value::String(s) => Some(s), - _ => None, - }, - }, - } - } -} - -// impl<'value> ValueIntoContainer for Value<'value> { -// type Array = Vec; -// type Object = Object<'value>; - -// fn into_array(self) -> Option<::Array> { -// match self { -// Self::Array(a) => Some(a), -// _ => None, -// } -// } - -// fn into_object(self) -> Option<::Object> { -// match self { -// Self::Object(a) => Some(*a), -// _ => None, -// } -// } -// } - #[cfg(not(tarpaulin_include))] impl<'tape, 'value> fmt::Display for Value<'tape, 'value> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -321,8 +155,9 @@ impl<'tape, 'value> fmt::Display for Value<'tape, 'value> { #[cfg(test)] mod test { #![allow(clippy::cognitive_complexity)] + use value_trait::prelude::*; + use super::Value; - use super::*; #[test] #[should_panic = "Not supported"] diff --git a/src/value/lazy/array.rs b/src/value/lazy/array.rs index 5ef3c9b7..3c985b3b 100644 --- a/src/value/lazy/array.rs +++ b/src/value/lazy/array.rs @@ -5,11 +5,11 @@ use crate::{borrowed, tape}; #[derive(Clone)] /// Wrapper around the tape that allows interacting with it via a `Array`-like API. -pub enum Array<'tape, 'value> { +pub enum Array<'tape, 'input> { /// Tape variant - Tape(tape::Array<'tape, 'value>), + Tape(tape::Array<'tape, 'input>), /// Value variant - Value(&'tape borrowed::Array<'value>), + Value(&'tape borrowed::Array<'input>), } pub enum ArrayIter<'tape, 'input> { @@ -29,20 +29,18 @@ impl<'tape, 'input> Iterator for ArrayIter<'tape, 'input> { } // value_trait::Array for -impl<'tape, 'input> Array<'tape, 'input> -where - 'input: 'tape, -{ - /// FIXME: docs - +impl<'tape, 'input> Array<'tape, 'input> { + /// Gets a ref to a value based on n index, returns `None` if the + /// current Value isn't an Array or doesn't contain the index + /// it was asked for. #[must_use] - pub fn get(&self, idx: usize) -> Option> { + pub fn get<'a>(&'a self, idx: usize) -> Option> { match self { Array::Tape(t) => t.get(idx).map(Value::Tape), Array::Value(v) => v.get(idx).map(Cow::Borrowed).map(Value::Value), } } - /// FIXME: docs + /// Iterates over the values paris #[allow(clippy::pedantic)] // we want into_iter_without_iter but that lint doesn't exist in older clippy #[must_use] pub fn iter<'i>(&'i self) -> ArrayIter<'i, 'input> { @@ -52,9 +50,7 @@ where } } - /// FIXME: docs - /// # Panics - /// if the tape is not an array + /// Number of key/value pairs #[must_use] pub fn len(&self) -> usize { match self { @@ -62,7 +58,7 @@ where Array::Value(v) => v.len(), } } - /// FIXME: docs + /// Returns if the array is empty #[must_use] pub fn is_empty(&self) -> bool { self.len() == 0 diff --git a/src/value/lazy/object.rs b/src/value/lazy/object.rs index 79b05606..282281ac 100644 --- a/src/value/lazy/object.rs +++ b/src/value/lazy/object.rs @@ -8,11 +8,11 @@ use crate::{borrowed, tape}; /// Wrapper around the tape that allows interacting with it via a `Object`-like API. -pub enum Object<'tape, 'value> { +pub enum Object<'tape, 'input> { /// Tape variant - Tape(tape::Object<'tape, 'value>), + Tape(tape::Object<'tape, 'input>), /// Value variant - Value(&'tape borrowed::Object<'value>), + Value(&'tape borrowed::Object<'input>), } pub enum Iter<'tape, 'input> { /// Tape variant @@ -35,13 +35,14 @@ pub enum Values<'tape, 'input> { //value_trait::Object for impl<'tape, 'input> Object<'tape, 'input> { - /// FIXME: docs - + /// Gets a ref to a value based on a key, returns `None` if the + /// current Value isn't an Object or doesn't contain the key + /// it was asked for. #[must_use] - pub fn get(&self, k: &Q) -> Option> + pub fn get<'a, Q>(&'a self, k: &Q) -> Option> where str: Borrow, - crate::cow::Cow<'input, str>: Borrow, + for<'b> crate::cow::Cow<'b, str>: Borrow, Q: ?Sized + Hash + Eq + Ord, { match self { @@ -49,7 +50,8 @@ impl<'tape, 'input> Object<'tape, 'input> { Object::Value(v) => v.get(k).map(Cow::Borrowed).map(Value::Value), } } - /// FIXME: docs + + /// Iterates over the key value paris #[allow(clippy::pedantic)] // we want into_iter_without_iter but that lint doesn't exist in older clippy #[must_use] pub fn iter<'i>(&'i self) -> Iter<'i, 'input> { @@ -58,7 +60,8 @@ impl<'tape, 'input> Object<'tape, 'input> { Object::Value(v) => Iter::Value(v.iter()), } } - /// FIXME: docs + + /// Iterates over the keys #[must_use] pub fn keys<'i>(&'i self) -> Keys<'i, 'input> { match self { @@ -66,7 +69,8 @@ impl<'tape, 'input> Object<'tape, 'input> { Object::Value(v) => Keys::Value(v.keys()), } } - /// FIXME: docs + + /// Iterates over the values #[must_use] pub fn values<'i>(&'i self) -> Values<'i, 'input> { match self { @@ -74,7 +78,8 @@ impl<'tape, 'input> Object<'tape, 'input> { Object::Value(v) => Values::Value(v.values()), } } - /// FIXME: docs + + /// Number of key/value pairs #[must_use] pub fn len(&self) -> usize { match self { @@ -82,7 +87,8 @@ impl<'tape, 'input> Object<'tape, 'input> { Object::Value(v) => v.len(), } } - /// FIXME: docs + + /// Returns if the object is empty #[must_use] pub fn is_empty(&self) -> bool { self.len() == 0 diff --git a/src/value/lazy/trait_impls.rs b/src/value/lazy/trait_impls.rs new file mode 100644 index 00000000..f20c0dba --- /dev/null +++ b/src/value/lazy/trait_impls.rs @@ -0,0 +1,859 @@ +use std::{ + borrow::{Borrow, Cow}, + hash::Hash, + io::{self, Write}, +}; + +use value_trait::{ + base::{ + TypedValue, ValueAsContainer, ValueAsMutContainer, ValueAsScalar, ValueIntoString, Writable, + }, + derived::{ + ValueArrayTryAccess, ValueObjectAccessAsContainer, ValueObjectAccessAsScalar, + ValueObjectAccessTryAsContainer, ValueObjectAccessTryAsScalar, ValueObjectTryAccess, + ValueTryAsScalar, + }, + TryTypeError, ValueBuilder, ValueType, +}; + +use crate::borrowed; + +use super::{Array, Object, Value}; + +impl<'value> ValueBuilder<'value> for Value<'static, 'value> { + #[cfg_attr(not(feature = "no-inline"), inline)] + #[must_use] + fn null() -> Self { + Value::Value(Cow::Owned(borrowed::Value::null())) + } + #[cfg_attr(not(feature = "no-inline"), inline)] + #[must_use] + fn array_with_capacity(capacity: usize) -> Self { + Value::Value(Cow::Owned(borrowed::Value::array_with_capacity(capacity))) + } + #[cfg_attr(not(feature = "no-inline"), inline)] + #[must_use] + fn object_with_capacity(capacity: usize) -> Self { + Value::Value(Cow::Owned(borrowed::Value::object_with_capacity(capacity))) + } +} + +// TypedContainerValue +impl<'tape, 'input> Value<'tape, 'input> +where + 'input: 'tape, +{ + /// returns true if the current value can be represented as an array + #[must_use] + pub fn is_array(&self) -> bool { + self.as_array().is_some() + } + + /// returns true if the current value can be represented as an object + #[must_use] + pub fn is_object(&self) -> bool { + self.as_object().is_some() + } +} + +impl<'tape, 'value> ValueAsScalar for Value<'tape, 'value> { + #[cfg_attr(not(feature = "no-inline"), inline)] + #[must_use] + fn as_null(&self) -> Option<()> { + match &self { + Value::Tape(tape) => tape.as_null(), + Value::Value(value) => value.as_null(), + } + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + #[must_use] + fn as_bool(&self) -> Option { + match &self { + Value::Tape(tape) => tape.as_bool(), + Value::Value(value) => value.as_bool(), + } + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + #[must_use] + fn as_i64(&self) -> Option { + match &self { + Value::Tape(tape) => tape.as_i64(), + Value::Value(value) => value.as_i64(), + } + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + #[must_use] + fn as_i128(&self) -> Option { + match &self { + Value::Tape(tape) => tape.as_i128(), + Value::Value(value) => value.as_i128(), + } + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + #[must_use] + fn as_u64(&self) -> Option { + match &self { + Value::Tape(tape) => tape.as_u64(), + Value::Value(value) => value.as_u64(), + } + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + #[must_use] + fn as_u128(&self) -> Option { + match &self { + Value::Tape(tape) => tape.as_u128(), + Value::Value(value) => value.as_u128(), + } + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + #[must_use] + fn as_f64(&self) -> Option { + match &self { + Value::Tape(tape) => tape.as_f64(), + Value::Value(value) => value.as_f64(), + } + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + #[must_use] + fn cast_f64(&self) -> Option { + match &self { + Value::Tape(tape) => tape.cast_f64(), + Value::Value(value) => value.cast_f64(), + } + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + #[must_use] + fn as_str(&self) -> Option<&str> { + match &self { + Value::Tape(tape) => tape.as_str(), + Value::Value(value) => value.as_str(), + } + } +} + +impl<'tape, 'value> ValueIntoString for Value<'tape, 'value> { + type String = Cow<'value, str>; + + fn into_string(self) -> Option<::String> { + match self { + Value::Tape(tape) => tape.into_string().map(Cow::Borrowed), + // This is a bit complex but it allows us to avoid cloning + Value::Value(value) => match value { + Cow::Borrowed(value) => match value { + #[cfg(feature = "beef")] + borrowed::Value::String(s) => Some(s.clone().into()), + #[cfg(not(feature = "beef"))] + borrowed::Value::String(s) => Some(s.clone()), + _ => None, + }, + Cow::Owned(value) => match value { + #[cfg(feature = "beef")] + borrowed::Value::String(s) => Some(s.into()), + #[cfg(not(feature = "beef"))] + borrowed::Value::String(s) => Some(s), + _ => None, + }, + }, + } + } +} + +// impl<'tape, 'input> ValueIntoContainer for Value<'tape, 'input> { +// type Array = array::Array<'tape, 'input>; +// type Object = Object<'tape, 'input>; +// #[must_use] +// fn into_array(self) -> Option { +// if let Some(Node::Array { count, .. }) = self.0.first() { +// // we add one element as we want to keep the array header +// let count = *count + 1; +// Some(Array(&self.0[..count])) +// } else { +// None +// } +// } + +// #[must_use] +// fn into_object(self) -> Option { +// if let Some(Node::Object { count, .. }) = self.0.first() { +// // we add one element as we want to keep the object header +// let count = *count + 1; +// Some(Object(&self.0[..count])) +// } else { +// None +// } +// } +// } + +impl<'tape, 'input> TypedValue for Value<'tape, 'input> { + #[cfg_attr(not(feature = "no-inline"), inline)] + #[must_use] + fn value_type(&self) -> ValueType { + match &self { + Value::Tape(tape) => tape.value_type(), + Value::Value(value) => value.value_type(), + } + } +} + +// TryValueObjectAccess +impl<'tape, 'input> Value<'tape, 'input> { + // type Key = &str; + // type Target = Value<'tape, 'input>; + + /// Tries to get a value based on a key, returns a `TryTypeError` if the + /// current Value isn't an Object, returns `None` if the key isn't in the object + /// # Errors + /// if the value is not an object + pub fn try_get(&self, k: &Q) -> Result>, TryTypeError> + where + str: Borrow + Hash + Eq, + for<'b> crate::cow::Cow<'b, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + match self { + Value::Tape(tape) => Ok(tape.try_get(k)?.map(Value::Tape)), + Value::Value(value) => Ok(value.try_get(k)?.map(Cow::Borrowed).map(Value::Value)), + } + } +} + +//TryValueArrayAccess +impl<'tape, 'input> Value<'tape, 'input> +where + 'input: 'tape, +{ + /// Tries to get a value based on n index, returns a type error if the + /// current value isn't an Array, returns `None` if the index is out of bounds + /// # Errors + /// if the requested type doesn't match the actual type or the value is not an object + pub fn try_get_idx(&self, i: usize) -> Result>, TryTypeError> { + match self { + Value::Tape(tape) => Ok(tape.try_get_idx(i)?.map(Value::Tape)), + Value::Value(value) => Ok(value.try_get_idx(i)?.map(Cow::Borrowed).map(Value::Value)), + } + } +} + +// impl<'tape, 'value> ValueAsContainer for Value<'tape, 'value> { +impl<'tape, 'input> Value<'tape, 'input> +where + 'input: 'tape, +{ + // type Array = array::Array<'tape, 'value>; + // type Object = Object<'tape, 'value>; + + /// Tries to represent the value as an array and returns a reference to it + #[cfg_attr(not(feature = "no-inline"), inline)] + #[must_use] + pub fn as_array(&self) -> Option> { + match self { + Value::Tape(tape) => tape.as_array().map(Array::Tape), + Value::Value(value) => value.as_array().map(Array::Value), + } + } + + /// Tries to represent the value as an array and returns a reference to it + #[cfg_attr(not(feature = "no-inline"), inline)] + #[must_use] + pub fn as_object(&self) -> Option> { + match self { + Value::Tape(tape) => tape.as_object().map(Object::Tape), + Value::Value(value) => value.as_object().map(Object::Value), + } + } +} + +impl<'tape, 'input> ValueAsMutContainer for Value<'tape, 'input> { + type Array = Vec>; + type Object = super::borrowed::Object<'input>; + #[cfg_attr(not(feature = "no-inline"), inline)] + #[must_use] + fn as_array_mut(&mut self) -> Option<&mut Vec>> { + self.as_mut().as_array_mut() + } + #[cfg_attr(not(feature = "no-inline"), inline)] + #[must_use] + fn as_object_mut(&mut self) -> Option<&mut super::borrowed::Object<'input>> { + self.as_mut().as_object_mut() + } +} + +// ContainerValueTryAs (needed as we don't have ValueAsContainer) +impl<'tape, 'input> Value<'tape, 'input> { + /// Tries to represent the value as an array and returns a reference to it + /// # Errors + /// if the requested type doesn't match the actual type + pub fn try_as_array(&self) -> Result, TryTypeError> { + self.as_array().ok_or(TryTypeError { + expected: ValueType::Array, + got: self.value_type(), + }) + } + + /// Tries to represent the value as an object and returns a reference to it + /// # Errors + /// if the requested type doesn't match the actual type + pub fn try_as_object(&self) -> Result, TryTypeError> { + self.as_object().ok_or(TryTypeError { + expected: ValueType::Object, + got: self.value_type(), + }) + } +} +// ValueObjectAccess (needed as we don't have ValueAsContainer ) and can't return references +impl<'tape, 'input> Value<'tape, 'input> { + /// Gets a ref to a value based on a key, returns `None` if the + /// current Value isn't an Object or doesn't contain the key + /// it was asked for. + #[must_use] + pub fn get(&self, k: &Q) -> Option> + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + match self { + Value::Tape(tape) => tape.get(k).map(Value::Tape), + Value::Value(value) => value + .as_object()? + .get(k) + .map(Cow::Borrowed) + .map(Value::Value), + } + } + + /// Checks if a Value contains a given key. This will return + /// flase if Value isn't an object + #[must_use] + pub fn contains_key(&self, k: &Q) -> bool + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + let Some(o) = self.as_object() else { + return false; + }; + let v = o.get(k).is_some(); + v + } +} + +// ValueArrayAccess (needed as we don't have ValueAsContainer) +impl<'tape, 'input> Value<'tape, 'input> { + /// Gets a ref to a value based on n index, returns `None` if the + /// current Value isn't an Array or doesn't contain the index + /// it was asked for. + #[must_use] + pub fn get_idx(&self, i: usize) -> Option> { + match self { + Value::Tape(tape) => tape.get_idx(i).map(Value::Tape), + Value::Value(value) => value + .as_array()? + .get(i) + .map(Cow::Borrowed) + .map(Value::Value), + } + } +} + +// impl<'tape, 'input> ValueObjectAccessAsScalar for Value<'tape, 'input> +impl<'tape, 'input> Value<'tape, 'input> +where + 'input: 'tape, +{ + /// Tries to get an element of an object as a bool + pub fn get_bool(&self, k: &Q) -> Option + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.get(k)?.as_bool() + } + + /// Tries to get an element of an object as a i128 + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn get_i128(&self, k: &Q) -> Option + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.get(k)?.as_i128() + } + + /// Tries to get an element of an object as a i64 + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn get_i64(&self, k: &Q) -> Option + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.get(k)?.as_i64() + } + + /// Tries to get an element of an object as a i32 + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn get_i32(&self, k: &Q) -> Option + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.get(k)?.as_i32() + } + + /// Tries to get an element of an object as a i16 + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn get_i16(&self, k: &Q) -> Option + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.get(k)?.as_i16() + } + + /// Tries to get an element of an object as a i8 + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn get_i8(&self, k: &Q) -> Option + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.get(k)?.as_i8() + } + + /// Tries to get an element of an object as a u128 + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn get_u128(&self, k: &Q) -> Option + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.get(k)?.as_u128() + } + + /// Tries to get an element of an object as a u64 + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn get_u64(&self, k: &Q) -> Option + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.get(k).and_then(|v| v.as_u64()) + } + + /// Tries to get an element of an object as a usize + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn get_usize(&self, k: &Q) -> Option + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.get(k).and_then(|v| v.as_usize()) + } + + /// Tries to get an element of an object as a u32 + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn get_u32(&self, k: &Q) -> Option + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.get(k).and_then(|v| v.as_u32()) + } + + /// Tries to get an element of an object as a u16 + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn get_u16(&self, k: &Q) -> Option + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.get(k).and_then(|v| v.as_u16()) + } + + /// Tries to get an element of an object as a u8 + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn get_u8(&self, k: &Q) -> Option + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.get(k).and_then(|v| v.as_u8()) + } + + /// Tries to get an element of an object as a f64 + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn get_f64(&self, k: &Q) -> Option + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.get(k).and_then(|v| v.as_f64()) + } + + /// Tries to get an element of an object as a f32 + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn get_f32(&self, k: &Q) -> Option + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.get(k).and_then(|v| v.as_f32()) + } + /// Tries to get an element of an object as a str + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn get_str(&self, k: &Q) -> Option<&str> + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + match self { + Value::Tape(tape) => tape.get_str(k), + Value::Value(value) => value.get_str(k), + } + } +} + +// ValueObjectContainerAccess +impl<'tape, 'input> Value<'tape, 'input> { + /// Tries to get an element of an object as a array + #[must_use] + pub fn get_array(&self, k: &Q) -> Option> + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + match self { + Value::Tape(tape) => tape.get_array(k).map(Array::Tape), + Value::Value(value) => value.get_array(k).map(Array::Value), + } + } + + /// Tries to get an element of an object as a object + #[must_use] + pub fn get_object(&self, k: &Q) -> Option> + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + match self { + Value::Tape(tape) => tape.get_object(k).map(Object::Tape), + Value::Value(value) => value.get_object(k).map(Object::Value), + } + } +} +// TryValueObjectContainerAccess +impl<'tape, 'input> Value<'tape, 'input> { + /// Tries to get an element of an object as an array, returns + /// an error if it isn't a array + /// # Errors + /// if the requested type doesn't match the actual type or the value is not an object + pub fn try_get_array(&self, k: &Q) -> Result>, TryTypeError> + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + match self { + Value::Tape(tape) => Ok(tape.try_get_array(k)?.map(Array::Tape)), + Value::Value(value) => Ok(value.try_get_array(k)?.map(Array::Value)), + } + } + + /// Tries to get an element of an object as an object, returns + /// an error if it isn't an object + /// + /// # Errors + /// if the requested type doesn't match the actual type or the value is not an object + pub fn try_get_object(&self, k: &Q) -> Result>, TryTypeError> + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + match self { + Value::Tape(tape) => Ok(tape.try_get_object(k)?.map(Object::Tape)), + Value::Value(value) => Ok(value.try_get_object(k)?.map(Object::Value)), + } + } +} + +// impl<'tape, 'input> ValueObjectAccessTryAsScalar for Value<'tape, 'input> { +impl<'tape, 'input> Value<'tape, 'input> { + /// Tries to get an element of an object as a bool, returns + /// an error if it isn't bool + /// # Errors + /// if the requested type doesn't match the actual type or the value is not an object + pub fn try_get_bool(&self, k: &Q) -> Result, TryTypeError> + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.try_get(k)?.map(|v| v.try_as_bool()).transpose() + } + + /// Tries to get an element of an object as a i128, returns + /// an error if it isn't i128 + /// # Errors + /// if the requested type doesn't match the actual type or the value is not an object + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn try_get_i128(&self, k: &Q) -> Result, TryTypeError> + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.try_get(k)?.map(|v| v.try_as_i128()).transpose() + } + + /// Tries to get an element of an object as a i64, returns + /// an error if it isn't a i64 + /// # Errors + /// if the requested type doesn't match the actual type or the value is not an object + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn try_get_i64(&self, k: &Q) -> Result, TryTypeError> + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.try_get(k)?.map(|v| v.try_as_i64()).transpose() + } + + /// Tries to get an element of an object as a i32, returns + /// an error if it isn't a i32 + /// # Errors + /// if the requested type doesn't match the actual type or the value is not an object + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn try_get_i32(&self, k: &Q) -> Result, TryTypeError> + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.try_get(k)?.map(|v| v.try_as_i32()).transpose() + } + + /// Tries to get an element of an object as a i16, returns + /// an error if it isn't a i16 + /// # Errors + /// if the requested type doesn't match the actual type or the value is not an object + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn try_get_i16(&self, k: &Q) -> Result, TryTypeError> + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.try_get(k)?.map(|v| v.try_as_i16()).transpose() + } + + /// Tries to get an element of an object as a u128, returns + /// an error if it isn't a u128 + /// # Errors + /// if the requested type doesn't match the actual type or the value is not an object + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn try_get_i8(&self, k: &Q) -> Result, TryTypeError> + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.try_get(k)?.map(|v| v.try_as_i8()).transpose() + } + + /// Tries to get an element of an object as a u64, returns + /// an error if it isn't a u64 + /// # Errors + /// if the requested type doesn't match the actual type or the value is not an object + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn try_get_u128(&self, k: &Q) -> Result, TryTypeError> + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.try_get(k)?.map(|v| v.try_as_u128()).transpose() + } + + /// Tries to get an element of an object as a usize, returns + /// an error if it isn't a usize + /// # Errors + /// if the requested type doesn't match the actual type or the value is not an object + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn try_get_u64(&self, k: &Q) -> Result, TryTypeError> + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.try_get(k)?.map(|v| v.try_as_u64()).transpose() + } + + /// Tries to get an element of an object as a u32, returns + /// an error if it isn't a u32 + /// # Errors + /// if the requested type doesn't match the actual type or the value is not an object + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn try_get_usize(&self, k: &Q) -> Result, TryTypeError> + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.try_get(k)?.map(|v| v.try_as_usize()).transpose() + } + + /// Tries to get an element of an object as a u16, returns + /// an error if it isn't a u16 + /// # Errors + /// if the requested type doesn't match the actual type or the value is not an object + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn try_get_u32(&self, k: &Q) -> Result, TryTypeError> + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.try_get(k)?.map(|v| v.try_as_u32()).transpose() + } + + /// Tries to get an element of an object as a u8, returns + /// an error if it isn't a u8 + /// # Errors + /// if the requested type doesn't match the actual type or the value is not an object + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn try_get_u16(&self, k: &Q) -> Result, TryTypeError> + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.try_get(k)?.map(|v| v.try_as_u16()).transpose() + } + + /// Tries to get an element of an object as a u8, returns + /// an error if it isn't a u8 + /// # Errors + /// if the requested type doesn't match the actual type or the value is not an object + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn try_get_u8(&self, k: &Q) -> Result, TryTypeError> + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.try_get(k)?.map(|v| v.try_as_u8()).transpose() + } + + /// Tries to get an element of an object as a f64, returns + /// an error if it isn't a f64 + /// # Errors + /// if the requested type doesn't match the actual type or the value is not an object + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn try_get_f64(&self, k: &Q) -> Result, TryTypeError> + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.try_get(k)?.map(|v| v.try_as_f64()).transpose() + } + + /// Tries to get an element of an object as a f32, returns + /// an error if it isn't a f32 + /// # Errors + /// if the requested type doesn't match the actual type or the value is not an object + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn try_get_f32(&self, k: &Q) -> Result, TryTypeError> + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + self.try_get(k)?.map(|v| v.try_as_f32()).transpose() + } + + /// Tries to get an element of an object as a str, returns + /// an error if it isn't a str + /// # Errors + /// if the requested type doesn't match the actual type or the value is not an object + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn try_get_str(&self, k: &Q) -> Result, TryTypeError> + where + str: Borrow, + for<'a> crate::cow::Cow<'a, str>: Borrow, + Q: ?Sized + Hash + Eq + Ord, + { + match self { + Value::Tape(tape) => tape.try_get_str(k), + Value::Value(value) => value.try_get_str(k), + } + } +} + +impl<'tape, 'input> Writable for Value<'tape, 'input> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn encode(&self) -> String { + match self { + Value::Tape(tape) => tape.encode(), + Value::Value(value) => value.encode(), + } + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn encode_pp(&self) -> String { + match self { + Value::Tape(tape) => tape.encode_pp(), + Value::Value(value) => value.encode_pp(), + } + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn write<'writer, W>(&self, w: &mut W) -> io::Result<()> + where + W: 'writer + Write, + { + match self { + Value::Tape(tape) => tape.write(w), + Value::Value(value) => value.write(w), + } + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn write_pp<'writer, W>(&self, w: &mut W) -> io::Result<()> + where + W: 'writer + Write, + { + match self { + Value::Tape(tape) => tape.write_pp(w), + Value::Value(value) => value.write_pp(w), + } + } +} diff --git a/src/value/tape.rs b/src/value/tape.rs index f6ab7468..1f9f6af7 100644 --- a/src/value/tape.rs +++ b/src/value/tape.rs @@ -12,7 +12,7 @@ pub struct Tape<'input>(pub Vec>); pub use array::Array; pub use object::Object; impl<'input> Tape<'input> { - /// FIXME: add docs + /// Turns the tape into a `Value` that can be used like a `value_trait::Value` #[must_use] pub fn as_value(&self) -> Value<'_, 'input> { // Skip initial zero diff --git a/src/value/tape/array.rs b/src/value/tape/array.rs index 46b18424..795e2523 100644 --- a/src/value/tape/array.rs +++ b/src/value/tape/array.rs @@ -22,8 +22,9 @@ impl<'tape, 'input> Array<'tape, 'input> where 'input: 'tape, { - /// FIXME: docs - + /// Gets a ref to a value based on n index, returns `None` if the + /// current Value isn't an Array or doesn't contain the index + /// it was asked for. #[must_use] pub fn get(&self, mut idx: usize) -> Option> { let mut offset = 1; @@ -34,13 +35,14 @@ where let count = self.0.get(offset)?.count(); Some(Value(&self.0[offset..offset + count])) } - /// FIXME: docs + + /// Iterates over the values paris #[must_use] pub fn iter<'i>(&'i self) -> Iter<'tape, 'input> { Iter(&self.0[1..]) } - /// FIXME: docs + /// Number of key/value pairs /// # Panics /// if the tape is not an array #[must_use] @@ -51,7 +53,7 @@ where panic!("invalid tape array") } } - /// FIXME: docs + /// Returns if the array is empty #[must_use] pub fn is_empty(&self) -> bool { self.len() == 0 diff --git a/src/value/tape/object.rs b/src/value/tape/object.rs index 83d9989c..a78d7de6 100644 --- a/src/value/tape/object.rs +++ b/src/value/tape/object.rs @@ -13,8 +13,9 @@ pub struct Values<'tape, 'input>(&'tape [Node<'input>]); //value_trait::Object for impl<'tape, 'input> Object<'tape, 'input> { - /// FIXME: docs - + /// Gets a ref to a value based on a key, returns `None` if the + /// current Value isn't an Object or doesn't contain the key + /// it was asked for. #[must_use] pub fn get(&self, k: &Q) -> Option> where @@ -38,22 +39,26 @@ impl<'tape, 'input> Object<'tape, 'input> { } None } - /// FIXME: docs + + /// Iterates over the key value paris #[must_use] pub fn iter<'i>(&'i self) -> Iter<'tape, 'input> { Iter(&self.0[1..]) } - /// FIXME: docs + + /// Iterates over the keys #[must_use] pub fn keys<'i>(&'i self) -> Keys<'tape, 'input> { Keys(&self.0[1..]) } - /// FIXME: docs + + /// Iterates over the values #[must_use] pub fn values<'i>(&'i self) -> Values<'tape, 'input> { Values(&self.0[1..]) } - /// FIXME: docs + + /// Number of key/value pairs #[must_use] pub fn len(&self) -> usize { let Some(Node::Object { len, .. }) = self.0.first() else { @@ -61,7 +66,8 @@ impl<'tape, 'input> Object<'tape, 'input> { }; *len } - /// FIXME: docs + + /// Returns if the object is empty #[must_use] pub fn is_empty(&self) -> bool { self.len() == 0 diff --git a/src/value/tape/trait_impls.rs b/src/value/tape/trait_impls.rs index d58bab3a..02b69593 100644 --- a/src/value/tape/trait_impls.rs +++ b/src/value/tape/trait_impls.rs @@ -643,7 +643,7 @@ impl<'tape, 'input> ValueObjectAccessTryAsScalar for Value<'tape, 'input> { } #[cfg_attr(not(feature = "no-inline"), inline)] - fn try_get_str(&self, k: &Q) -> Result, TryTypeError> + fn try_get_str(&self, k: &Q) -> Result, TryTypeError> where str: Borrow + Hash + Eq, Q: ?Sized + Hash + Eq + Ord,