mod cmp;
mod from;
mod serialize;
use crate::value::{ValueTrait, ValueType};
use crate::{stry, unlikely, Deserializer, ErrorType, Result};
use halfbrown::HashMap;
use std::borrow::Cow;
use std::fmt;
use std::ops::Index;
#[deprecated(since = "0.1.21", note = "Please use Object instead")]
pub type Map<'v> = Object<'v>;
pub type Object<'v> = HashMap<Cow<'v, str>, Value<'v>>;
pub fn to_value<'v>(s: &'v mut [u8]) -> Result<Value<'v>> {
let de = stry!(Deserializer::from_slice(s));
BorrowDeserializer::from_deserializer(de).parse()
}
#[derive(Debug, Clone)]
pub enum Value<'v> {
Null,
Bool(bool),
F64(f64),
I64(i64),
String(Cow<'v, str>),
Array(Vec<Value<'v>>),
Object(Object<'v>),
}
impl<'v> Value<'v> {
pub fn into_static(self) -> Value<'static> {
unsafe {
use std::mem::transmute;
transmute(match self {
Self::String(Cow::Borrowed(s)) => Self::String(Cow::Owned(s.to_owned())),
Self::Array(arr) => Self::Array(arr.into_iter().map(Value::into_static).collect()),
Self::Object(obj) => Self::Object(
obj.into_iter()
.map(|(k, v)| (Cow::Owned(k.into_owned()), v.into_static()))
.collect(),
),
_ => self,
})
}
}
pub fn clone_static(&self) -> Value<'static> {
unsafe {
use std::mem::transmute;
transmute(match self {
Self::String(s) => Self::String(Cow::Owned(s.to_string())),
Self::Array(arr) => Self::Array(arr.iter().map(Value::clone_static).collect()),
Self::Object(obj) => Self::Object(
obj.iter()
.map(|(k, v)| (Cow::Owned(k.to_string()), v.clone_static()))
.collect(),
),
Self::Null => Self::Null,
Self::F64(v) => Self::F64(*v),
Self::I64(v) => Self::I64(*v),
Self::Bool(v) => Self::Bool(*v),
})
}
}
}
impl<'v> ValueTrait for Value<'v> {
type Key = Cow<'v, str>;
fn value_type(&self) -> ValueType {
match self {
Value::Null => ValueType::Null,
Value::Bool(_) => ValueType::Bool,
Value::F64(_) => ValueType::F64,
Value::I64(_) => ValueType::I64,
Value::String(_) => ValueType::String,
Value::Array(_) => ValueType::Array,
Value::Object(_) => ValueType::Object,
}
}
fn is_null(&self) -> bool {
match self {
Value::Null => true,
_ => false,
}
}
fn as_bool(&self) -> Option<bool> {
match self {
Value::Bool(b) => Some(*b),
_ => None,
}
}
fn as_i64(&self) -> Option<i64> {
match self {
Value::I64(i) => Some(*i),
_ => None,
}
}
fn as_u64(&self) -> Option<u64> {
#[allow(clippy::cast_sign_loss)]
match self {
Value::I64(i) if *i >= 0 => Some(*i as u64),
_ => None,
}
}
fn as_f64(&self) -> Option<f64> {
match self {
Value::F64(i) => Some(*i),
_ => None,
}
}
fn cast_f64(&self) -> Option<f64> {
#[allow(clippy::cast_precision_loss)]
match self {
Value::F64(i) => Some(*i),
Value::I64(i) => Some(*i as f64),
_ => None,
}
}
fn as_string(&self) -> Option<String> {
match self {
Value::String(s) => Some(s.to_string()),
_ => None,
}
}
fn as_str(&self) -> Option<&str> {
use std::borrow::Borrow;
match self {
Value::String(s) => Some(s.borrow()),
_ => None,
}
}
fn as_array(&self) -> Option<&Vec<Value<'v>>> {
match self {
Value::Array(a) => Some(a),
_ => None,
}
}
fn as_array_mut(&mut self) -> Option<&mut Vec<Value<'v>>> {
match self {
Value::Array(a) => Some(a),
_ => None,
}
}
fn as_object(&self) -> Option<&HashMap<Self::Key, Self>> {
match self {
Value::Object(m) => Some(m),
_ => None,
}
}
fn as_object_mut(&mut self) -> Option<&mut HashMap<Self::Key, Self>> {
match self {
Value::Object(m) => Some(m),
_ => None,
}
}
}
impl<'v> fmt::Display for Value<'v> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Value::Null => write!(f, "null"),
Value::Bool(b) => write!(f, "{}", b),
Value::I64(n) => write!(f, "{}", n),
Value::F64(n) => write!(f, "{}", n),
Value::String(s) => write!(f, "{}", s),
Value::Array(a) => write!(f, "{:?}", a),
Value::Object(o) => write!(f, "{:?}", o),
}
}
}
impl<'v> Index<&str> for Value<'v> {
type Output = Value<'v>;
fn index(&self, index: &str) -> &Value<'v> {
static NULL: Value = Value::Null;
self.get(index).unwrap_or(&NULL)
}
}
impl<'v> Default for Value<'v> {
fn default() -> Self {
Value::Null
}
}
struct BorrowDeserializer<'de> {
de: Deserializer<'de>,
}
impl<'de> BorrowDeserializer<'de> {
pub fn from_deserializer(de: Deserializer<'de>) -> Self {
Self { de }
}
#[cfg_attr(not(feature = "no-inline"), inline(always))]
pub fn parse(&mut self) -> Result<Value<'de>> {
match self.de.next_() {
b'"' => self.de.parse_str_().map(Value::from),
b'-' => self.de.parse_number_root(true).map(Value::from),
b'0'..=b'9' => self.de.parse_number_root(false).map(Value::from),
b'n' => Ok(Value::Null),
b't' => Ok(Value::Bool(true)),
b'f' => Ok(Value::Bool(false)),
b'[' => self.parse_array(),
b'{' => self.parse_map(),
_c => Err(self.de.error(ErrorType::UnexpectedCharacter)),
}
}
#[cfg_attr(not(feature = "no-inline"), inline(always))]
fn parse_value(&mut self) -> Result<Value<'de>> {
match self.de.next_() {
b'"' => self.de.parse_str_().map(Value::from),
b'-' => self.de.parse_number_(true).map(Value::from),
b'0'..=b'9' => self.de.parse_number_(false).map(Value::from),
b'n' => Ok(Value::Null),
b't' => Ok(Value::Bool(true)),
b'f' => Ok(Value::Bool(false)),
b'[' => self.parse_array(),
b'{' => self.parse_map(),
_c => Err(self.de.error(ErrorType::UnexpectedCharacter)),
}
}
#[cfg_attr(not(feature = "no-inline"), inline(always))]
fn parse_array(&mut self) -> Result<Value<'de>> {
let es = self.de.count_elements();
if unlikely!(es == 0) {
self.de.skip();
return Ok(Value::Array(Vec::new()));
}
let mut res = Vec::with_capacity(es);
for _i in 0..es {
res.push(stry!(self.parse_value()));
self.de.skip();
}
Ok(Value::Array(res))
}
#[cfg_attr(not(feature = "no-inline"), inline(always))]
fn parse_map(&mut self) -> Result<Value<'de>> {
let es = self.de.count_elements();
if unlikely!(es == 0) {
self.de.skip();
return Ok(Value::Object(Object::new()));
}
let mut res = Object::with_capacity(es);
for _ in 0..es {
self.de.skip();
let key = stry!(self.de.parse_str_());
self.de.skip();
res.insert_nocheck(key.into(), stry!(self.parse_value()));
self.de.skip();
}
Ok(Value::Object(res))
}
}
#[cfg(test)]
mod test {
#![allow(clippy::cognitive_complexity)]
use super::*;
#[test]
fn conversions_i64() {
let v = Value::from(i64::max_value());
assert!(v.is_i128());
assert!(v.is_u128());
assert!(v.is_i64());
assert!(v.is_u64());
assert!(!v.is_i32());
assert!(!v.is_u32());
assert!(!v.is_i16());
assert!(!v.is_u16());
assert!(!v.is_i8());
assert!(!v.is_u8());
assert!(!v.is_f64());
assert!(!v.is_f32());
assert!(v.is_f64_castable());
let v = Value::from(i64::min_value());
assert!(v.is_i128());
assert!(!v.is_u128());
assert!(v.is_i64());
assert!(!v.is_u64());
assert!(!v.is_i32());
assert!(!v.is_u32());
assert!(!v.is_i16());
assert!(!v.is_u16());
assert!(!v.is_i8());
assert!(!v.is_u8());
assert!(!v.is_f64());
assert!(!v.is_f32());
assert!(v.is_f64_castable());
}
#[test]
fn conversions_i32() {
let v = Value::from(i32::max_value());
assert!(v.is_i128());
assert!(v.is_u128());
assert!(v.is_i64());
assert!(v.is_u64());
assert!(v.is_i32());
assert!(v.is_u32());
assert!(!v.is_i16());
assert!(!v.is_u16());
assert!(!v.is_i8());
assert!(!v.is_u8());
assert!(!v.is_f64());
assert!(!v.is_f32());
assert!(v.is_f64_castable());
let v = Value::from(i32::min_value());
assert!(v.is_i128());
assert!(!v.is_u128());
assert!(v.is_i64());
assert!(!v.is_u64());
assert!(v.is_i32());
assert!(!v.is_u32());
assert!(!v.is_i16());
assert!(!v.is_u16());
assert!(!v.is_i8());
assert!(!v.is_u8());
assert!(!v.is_f64());
assert!(!v.is_f32());
assert!(v.is_f64_castable());
}
#[test]
fn conversions_i16() {
let v = Value::from(i16::max_value());
assert!(v.is_i128());
assert!(v.is_u128());
assert!(v.is_i64());
assert!(v.is_u64());
assert!(v.is_i32());
assert!(v.is_u32());
assert!(v.is_i16());
assert!(v.is_u16());
assert!(!v.is_i8());
assert!(!v.is_u8());
assert!(!v.is_f64());
assert!(!v.is_f32());
assert!(v.is_f64_castable());
let v = Value::from(i16::min_value());
assert!(v.is_i128());
assert!(!v.is_u128());
assert!(v.is_i64());
assert!(!v.is_u64());
assert!(v.is_i32());
assert!(!v.is_u32());
assert!(v.is_i16());
assert!(!v.is_u16());
assert!(!v.is_i8());
assert!(!v.is_u8());
assert!(!v.is_f64());
assert!(!v.is_f32());
assert!(v.is_f64_castable());
assert!(v.is_f64_castable());
}
#[test]
fn conversions_i8() {
let v = Value::from(i8::max_value());
assert!(v.is_i128());
assert!(v.is_u128());
assert!(v.is_i64());
assert!(v.is_u64());
assert!(v.is_i32());
assert!(v.is_u32());
assert!(v.is_i16());
assert!(v.is_u16());
assert!(v.is_i8());
assert!(v.is_u8());
assert!(!v.is_f64());
assert!(!v.is_f32());
assert!(v.is_f64_castable());
let v = Value::from(i8::min_value());
assert!(v.is_i128());
assert!(!v.is_u128());
assert!(v.is_i64());
assert!(!v.is_u64());
assert!(v.is_i32());
assert!(!v.is_u32());
assert!(v.is_i16());
assert!(!v.is_u16());
assert!(v.is_i8());
assert!(!v.is_u8());
assert!(!v.is_f64());
assert!(!v.is_f32());
assert!(v.is_f64_castable());
}
#[test]
fn conversions_usize() {
let v = Value::from(usize::min_value() as u64);
assert!(v.is_i128());
assert!(v.is_u128());
assert!(v.is_i64());
assert!(v.is_u64());
assert!(v.is_usize());
assert!(v.is_i32());
assert!(v.is_u32());
assert!(v.is_i16());
assert!(v.is_u16());
assert!(v.is_i8());
assert!(v.is_u8());
assert!(!v.is_f64());
assert!(!v.is_f32());
assert!(!v.is_f64());
assert!(!v.is_f32());
assert!(v.is_f64_castable());
}
#[test]
fn conversions_u64() {
let v = Value::from(u64::min_value());
assert!(v.is_i128());
assert!(v.is_u128());
assert!(v.is_i64());
assert!(v.is_u64());
assert!(v.is_i32());
assert!(v.is_u32());
assert!(v.is_i16());
assert!(v.is_u16());
assert!(v.is_i8());
assert!(v.is_u8());
assert!(!v.is_f64());
assert!(!v.is_f32());
assert!(v.is_f64_castable());
}
#[test]
fn conversions_u32() {
let v = Value::from(u32::max_value());
assert!(v.is_i128());
assert!(v.is_u128());
assert!(v.is_i64());
assert!(v.is_u64());
assert!(!v.is_i32());
assert!(v.is_u32());
assert!(!v.is_i16());
assert!(!v.is_u16());
assert!(!v.is_i8());
assert!(!v.is_u8());
assert!(!v.is_f64());
assert!(!v.is_f32());
assert!(v.is_f64_castable());
}
#[test]
fn conversions_u16() {
let v = Value::from(u16::max_value());
assert!(v.is_i128());
assert!(v.is_u128());
assert!(v.is_i64());
assert!(v.is_u64());
assert!(v.is_i32());
assert!(v.is_u32());
assert!(!v.is_i16());
assert!(v.is_u16());
assert!(!v.is_i8());
assert!(!v.is_u8());
assert!(!v.is_f64());
assert!(!v.is_f32());
assert!(v.is_f64_castable());
}
#[test]
fn conversions_u8() {
let v = Value::from(u8::max_value());
assert!(v.is_i128());
assert!(v.is_u128());
assert!(v.is_i64());
assert!(v.is_u64());
assert!(v.is_i32());
assert!(v.is_u32());
assert!(v.is_i16());
assert!(v.is_u16());
assert!(!v.is_i8());
assert!(v.is_u8());
assert!(!v.is_f64());
assert!(!v.is_f32());
assert!(v.is_f64_castable());
}
#[test]
fn conversions_f64() {
let v = Value::from(std::f64::MAX);
assert!(!v.is_i64());
assert!(!v.is_u64());
assert!(v.is_f64());
assert!(!v.is_f32());
assert!(v.is_f64_castable());
let v = Value::from(std::f64::MIN);
assert!(!v.is_i64());
assert!(!v.is_u64());
assert!(v.is_f64());
assert!(!v.is_f32());
assert!(v.is_f64_castable());
}
#[test]
fn conversions_f32() {
let v = Value::from(std::f32::MAX);
assert!(!v.is_i64());
assert!(!v.is_u64());
assert!(v.is_f64());
assert!(v.is_f32());
assert!(v.is_f64_castable());
let v = Value::from(std::f32::MIN);
assert!(!v.is_i64());
assert!(!v.is_u64());
assert!(v.is_f64());
assert!(v.is_f32());
assert!(v.is_f64_castable());
}
#[test]
fn conversions_array() {
let v = Value::from(vec![true]);
assert!(v.is_array());
assert_eq!(v.value_type(), ValueType::Array);
}
#[test]
fn conversions_bool() {
let v = Value::from(true);
assert!(v.is_bool());
assert_eq!(v.value_type(), ValueType::Bool);
}
#[test]
fn conversions_float() {
let v = Value::from(42.0);
assert!(v.is_f64());
assert_eq!(v.value_type(), ValueType::F64);
}
#[test]
fn conversions_int() {
let v = Value::from(42);
assert!(v.is_i64());
assert_eq!(v.value_type(), ValueType::I64);
}
#[test]
fn conversions_null() {
let v = Value::from(());
assert!(v.is_null());
assert_eq!(v.value_type(), ValueType::Null);
}
#[test]
fn conversions_object() {
let v = Value::Object(Object::new());
assert!(v.is_object());
assert_eq!(v.value_type(), ValueType::Object);
}
#[test]
fn conversions_str() {
let v = Value::from("bla");
assert!(v.is_str());
assert_eq!(v.value_type(), ValueType::String);
}
use proptest::prelude::*;
fn arb_value() -> BoxedStrategy<Value<'static>> {
let leaf = prop_oneof![
Just(Value::Null),
any::<bool>().prop_map(Value::Bool),
any::<i64>().prop_map(Value::I64),
any::<f64>().prop_map(Value::F64),
".*".prop_map(Value::from),
];
leaf.prop_recursive(
8,
256,
10,
|inner| {
prop_oneof![
prop::collection::vec(inner.clone(), 0..10).prop_map(Value::Array),
prop::collection::hash_map(".*".prop_map(Cow::Owned), inner, 0..10)
.prop_map(|m| Value::Object(m.into_iter().collect())),
]
},
)
.boxed()
}
proptest! {
#![proptest_config(ProptestConfig {
.. ProptestConfig::default()
})]
#[test]
fn prop_to_owned(borrowed in arb_value()) {
use crate::OwnedValue;
let owned: OwnedValue = borrowed.clone().into();
prop_assert_eq!(borrowed, owned);
}
#[test]
fn prop_into_static(borrowed in arb_value()) {
let static_borrowed = borrowed.clone().into_static();
assert_eq!(borrowed, static_borrowed);
}
#[test]
fn prop_clone_static(borrowed in arb_value()) {
let static_borrowed = borrowed.clone_static();
assert_eq!(borrowed, static_borrowed);
}
#[test]
fn prop_serialize_deserialize(borrowed in arb_value()) {
let mut string = borrowed.encode();
let mut bytes = unsafe{ string.as_bytes_mut()};
let decoded = to_value(&mut bytes).expect("Failed to decode");
prop_assert_eq!(borrowed, decoded)
}
#[test]
fn prop_f64_cmp(f in proptest::num::f64::NORMAL) {
#[allow(clippy::float_cmp)]
let v: Value = f.into();
prop_assert_eq!(v, f)
}
#[test]
fn prop_f32_cmp(f in proptest::num::f32::NORMAL) {
#[allow(clippy::float_cmp)]
let v: Value = f.into();
prop_assert_eq!(v, f)
}
#[test]
fn prop_i64_cmp(f in proptest::num::i64::ANY) {
let v: Value = f.into();
prop_assert_eq!(v, f)
}
#[test]
fn prop_i32_cmp(f in proptest::num::i32::ANY) {
let v: Value = f.into();
prop_assert_eq!(v, f)
}
#[test]
fn prop_i16_cmp(f in proptest::num::i16::ANY) {
let v: Value = f.into();
prop_assert_eq!(v, f)
}
#[test]
fn prop_i8_cmp(f in proptest::num::i8::ANY) {
let v: Value = f.into();
prop_assert_eq!(v, f)
}
#[test]
fn prop_u64_cmp(f in (0_u64..=(i64::max_value() as u64))) {
let v: Value = f.into();
prop_assert_eq!(v, f)
}
#[allow(clippy::cast_possible_truncation)]
#[test]
fn prop_usize_cmp(f in (0_usize..=(i64::max_value() as usize))) {
let v: Value = f.into();
prop_assert_eq!(v, f)
}
#[test]
fn prop_u32_cmp(f in proptest::num::u32::ANY) {
let v: Value = f.into();
prop_assert_eq!(v, f)
}
#[test]
fn prop_u16_cmp(f in proptest::num::u16::ANY) {
let v: Value = f.into();
prop_assert_eq!(v, f)
}
#[test]
fn prop_u8_cmp(f in proptest::num::u8::ANY) {
let v: Value = f.into();
assert_eq!(v, &f);
prop_assert_eq!(v, f)
}
#[test]
fn prop_string_cmp(f in ".*") {
let v: Value = f.clone().into();
prop_assert_eq!(v.clone(), f.as_str());
prop_assert_eq!(v, f);
}
}
#[test]
fn test_union_cmp() {
let v: Value = ().into();
assert_eq!(v, ())
}
#[test]
fn test_bool_cmp() {
let v: Value = true.into();
assert_eq!(v, true);
let v: Value = false.into();
assert_eq!(v, false);
}
}