#![allow(
clippy::indexing_slicing,
clippy::shadow_unrelated,
clippy::option_if_let_else,
clippy::semicolon_if_nothing_returned,
clippy::pattern_type_mismatch,
clippy::unused_trait_names,
clippy::as_conversions
)]
mod array;
mod object;
mod set;
#[cfg(feature = "std")]
mod interning;
#[cfg(test)]
mod tests;
#[allow(unused_imports)] pub use array::{Array, ArrayCursor, ArrayIntoIter, ArrayIter, ArrayIterMut};
pub use object::{IntoIter, Iter, IterMut, Object};
#[allow(unused_imports)] pub use set::Set;
#[cfg(feature = "rvm")]
#[allow(unused_imports)] pub use object::ObjectCursor;
#[allow(unused_imports)] pub use set::SetCursor;
use crate::number::Number;
use alloc::collections::{BTreeMap, BTreeSet};
use alloc::vec::Vec;
#[cfg(all(feature = "allocator-memory-limits", not(miri)))]
use core::cell::Cell;
use core::fmt;
#[cfg(all(feature = "allocator-memory-limits", not(miri)))]
use core::marker::PhantomData;
use core::ops;
use core::convert::AsRef;
use core::str::FromStr;
use anyhow::{anyhow, bail, Result};
use serde::de::{self, Deserializer, Error as DeError, MapAccess, SeqAccess, Visitor};
use serde::ser::Serializer;
use serde::{Deserialize, Serialize};
use crate::*;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Value {
Null,
Bool(bool),
Number(Number),
String(Rc<str>),
Array(Rc<Array>),
Set(Rc<Set>),
Object(Rc<Object>),
Undefined,
}
#[inline]
fn enforce_limit_anyhow() -> Result<()> {
crate::utils::limits::check_memory_limit_if_needed().map_err(|err| anyhow!(err))
}
#[inline]
fn enforce_limit_for<E: DeError>() -> core::result::Result<(), E> {
crate::utils::limits::check_memory_limit_if_needed().map_err(|err| {
#[cfg(all(feature = "allocator-memory-limits", not(miri)))]
record_resume_deserialization_limit_error(err);
E::custom(err.to_string())
})
}
#[cfg(all(feature = "allocator-memory-limits", not(miri)))]
#[derive(Clone, Copy)]
struct ResumeDeserializationLimitErrorCaptureState {
active: bool,
error: Option<crate::utils::limits::LimitError>,
}
#[cfg(all(feature = "allocator-memory-limits", not(miri)))]
std::thread_local! {
static RESUME_DESERIALIZATION_LIMIT_ERROR_CAPTURE: Cell<ResumeDeserializationLimitErrorCaptureState> =
const {
Cell::new(ResumeDeserializationLimitErrorCaptureState {
active: false,
error: None,
})
};
}
#[cfg(all(feature = "allocator-memory-limits", not(miri)))]
struct ResumeDeserializationLimitErrorCapture {
previous: ResumeDeserializationLimitErrorCaptureState,
_thread_bound: PhantomData<alloc::rc::Rc<()>>,
}
#[cfg(all(feature = "allocator-memory-limits", not(miri)))]
impl ResumeDeserializationLimitErrorCapture {
fn new() -> Self {
let previous = RESUME_DESERIALIZATION_LIMIT_ERROR_CAPTURE.with(|capture| {
let previous = capture.get();
capture.set(ResumeDeserializationLimitErrorCaptureState {
active: true,
error: None,
});
previous
});
Self {
previous,
_thread_bound: PhantomData,
}
}
fn take(_capture: &Self) -> Option<crate::utils::limits::LimitError> {
RESUME_DESERIALIZATION_LIMIT_ERROR_CAPTURE.with(|capture| {
let mut state = capture.get();
let error = state.error.take();
capture.set(state);
error
})
}
}
#[cfg(all(feature = "allocator-memory-limits", not(miri)))]
impl Drop for ResumeDeserializationLimitErrorCapture {
fn drop(&mut self) {
RESUME_DESERIALIZATION_LIMIT_ERROR_CAPTURE.with(|capture| capture.set(self.previous));
}
}
#[cfg(all(feature = "allocator-memory-limits", not(miri)))]
fn record_resume_deserialization_limit_error(error: crate::utils::limits::LimitError) {
RESUME_DESERIALIZATION_LIMIT_ERROR_CAPTURE.with(|capture| {
let mut state = capture.get();
if state.active && state.error.is_none() {
state.error = Some(error);
capture.set(state);
}
});
}
#[doc(hidden)]
impl Serialize for Value {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
Value::Null => serializer.serialize_unit(),
Value::Bool(b) => serializer.serialize_bool(*b),
Value::String(s) => serializer.serialize_str(s.as_ref()),
Value::Number(n) => n.serialize(serializer),
Value::Array(a) => a.serialize(serializer),
Value::Object(fields) => fields.serialize(serializer),
Value::Set(s) => s.serialize(serializer),
Value::Undefined => serializer.serialize_str("<undefined>"),
}
}
}
struct ValueVisitor;
impl<'de> Visitor<'de> for ValueVisitor {
type Value = Value;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a value")
}
fn visit_unit<E>(self) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Value::Null)
}
fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Value::Bool(v))
}
fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Value::Null)
}
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
Value::deserialize(deserializer)
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Value::from(v))
}
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Value::from(v))
}
fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Value::from(v))
}
fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Value::from(v))
}
fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
where
E: de::Error,
{
if !v.is_finite() {
return Err(de::Error::custom(format!(
"invalid non-finite number in input: {v}"
)));
}
Ok(Value::from(Number::from(v)))
}
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Value::String(s.to_string().into()))
}
fn visit_string<E>(self, s: String) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Value::String(s.into()))
}
fn visit_seq<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
let mut arr = vec![];
while let Some(v) = visitor.next_element()? {
arr.push(v);
enforce_limit_for::<V::Error>()?;
}
Ok(Value::from(arr))
}
fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
where
V: MapAccess<'de>,
{
if let Some((key, value)) = visitor.next_entry()? {
if let (Value::String(k), Value::String(v)) = (&key, &value) {
if k.as_ref() == "$serde_json::private::Number" {
match Number::from_str(v) {
Ok(n) => return Ok(Value::from(n)),
_ => return Err(de::Error::custom("failed to read big number")),
}
}
}
let mut map = BTreeMap::new();
map.insert(intern_object_key(key), value);
enforce_limit_for::<V::Error>()?;
while let Some((key, value)) = visitor.next_entry()? {
map.insert(intern_object_key(key), value);
enforce_limit_for::<V::Error>()?;
}
let value = Value::from(map);
enforce_limit_for::<V::Error>()?;
Ok(value)
} else {
Ok(Value::new_object())
}
}
}
#[cfg(feature = "std")]
fn intern_object_key(key: Value) -> Value {
match key {
Value::String(rc) => Value::String(interning::intern_key(rc)),
other => other,
}
}
#[cfg(not(feature = "std"))]
const fn intern_object_key(key: Value) -> Value {
key
}
#[doc(hidden)]
impl<'de> Deserialize<'de> for Value {
fn deserialize<D>(deserializer: D) -> Result<Value, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_any(ValueVisitor)
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match serde_json::to_string(self) {
Ok(s) => write!(f, "{s}"),
Err(_e) => Err(fmt::Error),
}
}
}
impl Value {
pub fn new_array() -> Value {
Value::from(vec![])
}
pub fn new_object() -> Value {
Value::from(BTreeMap::new())
}
pub fn new_set() -> Value {
Value::from(BTreeSet::new())
}
}
pub(crate) enum ResumeJsonError {
Malformed(anyhow::Error),
Other(anyhow::Error),
}
impl ResumeJsonError {
fn into_anyhow(self) -> anyhow::Error {
match self {
Self::Malformed(error) | Self::Other(error) => error,
}
}
}
impl Value {
pub fn from_json_str(json: &str) -> Result<Value> {
Self::parse_json_str(json, false).map_err(ResumeJsonError::into_anyhow)
}
#[cfg(all(feature = "rvm", feature = "allocator-memory-limits", not(miri)))]
pub(crate) fn from_json_str_for_resume(
json: &str,
) -> core::result::Result<Value, ResumeJsonError> {
Self::parse_json_str(json, true)
}
fn parse_json_str(
json: &str,
keep_malformed_retryable: bool,
) -> core::result::Result<Value, ResumeJsonError> {
#[cfg(feature = "std")]
let _guard = interning::InternGuard::install();
#[cfg(all(feature = "allocator-memory-limits", not(miri)))]
let limit_error_capture =
keep_malformed_retryable.then(ResumeDeserializationLimitErrorCapture::new);
match serde_json::from_str::<Value>(json) {
Ok(value) => Ok(value),
Err(err) => {
if keep_malformed_retryable
&& matches!(
err.classify(),
serde_json::error::Category::Syntax | serde_json::error::Category::Eof
)
{
return Err(ResumeJsonError::Malformed(anyhow!(err)));
}
#[cfg(all(feature = "allocator-memory-limits", not(miri)))]
if let Some(limit_error) = limit_error_capture
.as_ref()
.and_then(ResumeDeserializationLimitErrorCapture::take)
{
return Err(ResumeJsonError::Other(anyhow!(limit_error)));
}
#[cfg(all(feature = "allocator-memory-limits", not(miri)))]
{
match crate::utils::limits::check_global_memory_limit() {
Err(limit_err) => Err(ResumeJsonError::Other(anyhow!(limit_err))),
Ok(_) => Err(ResumeJsonError::Other(anyhow!(err))),
}
}
#[cfg(any(miri, not(feature = "allocator-memory-limits")))]
{
Err(ResumeJsonError::Other(anyhow!(err)))
}
}
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub fn from_json_file<P: AsRef<std::path::Path>>(path: P) -> Result<Value> {
match std::fs::read_to_string(&path) {
Ok(c) => Self::from_json_str(c.as_str()),
Err(e) => bail!("Failed to read {}. {e}", path.as_ref().display()),
}
}
pub fn to_json_str(&self) -> Result<String> {
serde_json::to_string_pretty(self).map_err(anyhow::Error::msg)
}
#[cfg(feature = "yaml")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub fn from_yaml_str(yaml: &str) -> Result<Value> {
let value = yaml_serde::from_str(yaml)
.map_err(|err| anyhow::anyhow!("Failed to parse YAML: {}", err))?;
Ok(value)
}
#[cfg(feature = "std")]
#[cfg(feature = "yaml")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "yaml")))]
pub fn from_yaml_file(path: &String) -> Result<Value> {
match std::fs::read_to_string(path) {
Ok(c) => Self::from_yaml_str(c.as_str()),
Err(e) => bail!("Failed to read {path}. {e}"),
}
}
}
impl From<bool> for Value {
fn from(b: bool) -> Self {
Value::Bool(b)
}
}
impl From<String> for Value {
fn from(s: String) -> Self {
Value::String(s.into())
}
}
impl From<&str> for Value {
fn from(s: &str) -> Self {
Value::String(s.into())
}
}
impl From<u128> for Value {
fn from(n: u128) -> Self {
Value::Number(Number::from(n))
}
}
impl From<i128> for Value {
fn from(n: i128) -> Self {
Value::Number(Number::from(n))
}
}
impl From<u64> for Value {
fn from(n: u64) -> Self {
Value::Number(Number::from(n))
}
}
impl From<i64> for Value {
fn from(n: i64) -> Self {
Value::Number(Number::from(n))
}
}
impl From<u32> for Value {
fn from(n: u32) -> Self {
Value::Number(Number::from(n as u64))
}
}
impl From<i32> for Value {
fn from(n: i32) -> Self {
Value::Number(Number::from(n as i64))
}
}
impl From<f64> for Value {
fn from(n: f64) -> Self {
if !n.is_finite() {
return Value::Null;
}
Value::Number(Number::from(n))
}
}
impl From<serde_json::Value> for Value {
fn from(v: serde_json::Value) -> Self {
match serde_json::from_value(v) {
Ok(v) => v,
_ => Value::Undefined,
}
}
}
#[cfg(feature = "yaml")]
#[cfg_attr(docsrs, doc(cfg(feature = "yaml")))]
impl From<yaml_serde::Value> for Value {
fn from(v: yaml_serde::Value) -> Self {
match yaml_serde::from_value(v) {
Ok(v) => v,
_ => Value::Undefined,
}
}
}
impl Value {
pub fn from_numeric_string(s: &str) -> Result<Value> {
Ok(Value::Number(
Number::from_str(s).map_err(|_| anyhow!("not a valid numeric string"))?,
))
}
}
impl From<usize> for Value {
fn from(n: usize) -> Self {
Value::Number(Number::from(n))
}
}
#[doc(hidden)]
impl From<Number> for Value {
fn from(n: Number) -> Self {
Value::Number(n)
}
}
impl From<Vec<Value>> for Value {
fn from(a: Vec<Value>) -> Self {
Value::Array(Rc::new(Array::from(a)))
}
}
impl From<BTreeSet<Value>> for Value {
fn from(s: BTreeSet<Value>) -> Self {
Value::Set(Rc::new(Set::from(s)))
}
}
impl From<BTreeMap<Value, Value>> for Value {
fn from(s: BTreeMap<Value, Value>) -> Self {
Object::from(s).into_value()
}
}
impl Value {
pub(crate) fn from_array(a: Vec<Value>) -> Value {
Value::from(a)
}
pub(crate) fn from_set(s: BTreeSet<Value>) -> Value {
Value::from(s)
}
pub(crate) fn from_map(m: BTreeMap<Value, Value>) -> Value {
Value::from(m)
}
pub(crate) fn is_empty_object(&self) -> bool {
self == &Value::new_object()
}
}
impl Value {
pub fn as_bool(&self) -> Result<&bool> {
match self {
Value::Bool(b) => Ok(b),
_ => Err(anyhow!("not a bool")),
}
}
pub fn as_bool_mut(&mut self) -> Result<&mut bool> {
match self {
Value::Bool(b) => Ok(b),
_ => Err(anyhow!("not a bool")),
}
}
pub fn as_u128(&self) -> Result<u128> {
match self {
Value::Number(b) => {
if let Some(n) = b.as_u128() {
return Ok(n);
}
bail!("not a u128");
}
_ => Err(anyhow!("not a u128")),
}
}
pub fn as_i128(&self) -> Result<i128> {
match self {
Value::Number(b) => {
if let Some(n) = b.as_i128() {
return Ok(n);
}
bail!("not a i128");
}
_ => Err(anyhow!("not a i128")),
}
}
pub fn as_u64(&self) -> Result<u64> {
match self {
Value::Number(b) => {
if let Some(n) = b.as_u64() {
return Ok(n);
}
bail!("not a u64");
}
_ => Err(anyhow!("not a u64")),
}
}
pub fn as_i64(&self) -> Result<i64> {
match self {
Value::Number(b) => {
if let Some(n) = b.as_i64() {
return Ok(n);
}
bail!("not an i64");
}
_ => Err(anyhow!("not an i64")),
}
}
pub fn as_u32(&self) -> Result<u32> {
match self {
Value::Number(b) => {
if let Some(n) = b.as_u64() {
if let Ok(v) = u32::try_from(n) {
return Ok(v);
}
}
bail!("not a u32");
}
_ => Err(anyhow!("not a u32")),
}
}
pub fn as_i32(&self) -> Result<i32> {
match self {
Value::Number(b) => {
if let Some(n) = b.as_i64() {
if let Ok(v) = i32::try_from(n) {
return Ok(v);
}
}
bail!("not an i32");
}
_ => Err(anyhow!("not an i32")),
}
}
pub fn as_u16(&self) -> Result<u16> {
match self {
Value::Number(b) => {
if let Some(n) = b.as_u64() {
if let Ok(v) = u16::try_from(n) {
return Ok(v);
}
}
bail!("not a u16");
}
_ => Err(anyhow!("not a u16")),
}
}
pub fn as_i16(&self) -> Result<i16> {
match self {
Value::Number(b) => {
if let Some(n) = b.as_i64() {
if let Ok(v) = i16::try_from(n) {
return Ok(v);
}
}
bail!("not an i16");
}
_ => Err(anyhow!("not an i16")),
}
}
pub fn as_u8(&self) -> Result<u8> {
match self {
Value::Number(b) => {
if let Some(n) = b.as_u64() {
if let Ok(v) = u8::try_from(n) {
return Ok(v);
}
}
bail!("not a u8");
}
_ => Err(anyhow!("not a u8")),
}
}
pub fn as_i8(&self) -> Result<i8> {
match self {
Value::Number(b) => {
if let Some(n) = b.as_i64() {
if let Ok(v) = i8::try_from(n) {
return Ok(v);
}
}
bail!("not an i8");
}
_ => Err(anyhow!("not an i8")),
}
}
pub fn as_f64(&self) -> Result<f64> {
match self {
Value::Number(b) => {
if let Some(n) = b.as_f64() {
return Ok(n);
}
bail!("not a f64");
}
_ => Err(anyhow!("not a f64")),
}
}
pub fn as_string(&self) -> Result<&Rc<str>> {
match self {
Value::String(s) => Ok(s),
_ => Err(anyhow!("not a string")),
}
}
pub fn as_string_mut(&mut self) -> Result<&mut Rc<str>> {
match self {
Value::String(s) => Ok(s),
_ => Err(anyhow!("not a string")),
}
}
#[doc(hidden)]
pub fn as_number(&self) -> Result<&Number> {
match self {
Value::Number(n) => Ok(n),
_ => Err(anyhow!("not a number")),
}
}
#[doc(hidden)]
pub fn as_number_mut(&mut self) -> Result<&mut Number> {
match self {
Value::Number(n) => Ok(n),
_ => Err(anyhow!("not a number")),
}
}
pub fn as_array(&self) -> Result<&Array> {
match self {
Value::Array(a) => Ok(a),
_ => Err(anyhow!("not an array")),
}
}
pub fn as_array_mut(&mut self) -> Result<&mut Array> {
match self {
Value::Array(a) => Ok(Rc::make_mut(a)),
_ => Err(anyhow!("not an array")),
}
}
pub fn as_set(&self) -> Result<&Set> {
match self {
Value::Set(s) => Ok(s),
_ => Err(anyhow!("not a set")),
}
}
pub fn as_set_mut(&mut self) -> Result<&mut Set> {
match self {
Value::Set(s) => Ok(Rc::make_mut(s)),
_ => Err(anyhow!("not a set")),
}
}
pub fn as_object(&self) -> Result<&Object> {
match self {
Value::Object(m) => Ok(m),
_ => Err(anyhow!("not an object")),
}
}
pub fn as_object_mut(&mut self) -> Result<&mut Object> {
match self {
Value::Object(m) => Ok(Rc::make_mut(m)),
_ => Err(anyhow!("not an object")),
}
}
}
const MAX_MERGE_DEPTH: usize = 128;
impl Value {
pub(crate) fn make_or_get_value_mut<'a>(&'a mut self, paths: &[&str]) -> Result<&'a mut Value> {
if paths.is_empty() {
return Ok(self);
}
let key = Value::String(paths[0].into());
if self == &Value::Undefined {
*self = Value::new_object();
}
if let Value::Object(map) = self {
if map.get(&key).is_none() {
Rc::make_mut(map).insert(key.clone(), Value::Undefined);
enforce_limit_anyhow()?;
}
}
match self {
Value::Object(map) => match Rc::make_mut(map).get_mut(&key) {
Some(v) if paths.len() == 1 => Ok(v),
Some(v) => Self::make_or_get_value_mut(v, &paths[1..]),
_ => bail!("internal error: unexpected"),
},
Value::Undefined if paths.len() > 1 => {
*self = Value::new_object();
Self::make_or_get_value_mut(self, paths)
}
Value::Undefined => Ok(self),
_ => bail!("internal error: make: not an selfect {self:?}"),
}
}
pub(crate) fn merge(&mut self, mut new: Value) -> Result<()> {
if self == &new {
return Ok(());
}
match (self, &mut new) {
(v @ Value::Undefined, _) => *v = new,
(Value::Set(ref mut set), Value::Set(new)) => {
let dst = Rc::make_mut(set);
match Rc::try_unwrap(core::mem::take(new)) {
Ok(owned) => dst.extend(owned),
Err(shared) => dst.extend(shared.iter().cloned()),
}
enforce_limit_anyhow()?;
}
(Value::Object(map), Value::Object(new)) => {
for (k, v) in new.iter() {
match map.get(k) {
Some(pv) if *pv != *v => bail!(
"value for key `{}` generated multiple times: `{}` and `{}`",
serde_json::to_string_pretty(&k).map_err(anyhow::Error::msg)?,
serde_json::to_string_pretty(&pv).map_err(anyhow::Error::msg)?,
serde_json::to_string_pretty(&v).map_err(anyhow::Error::msg)?,
),
_ => {
Rc::make_mut(map).insert(k.clone(), v.clone());
enforce_limit_anyhow()?;
}
};
}
}
_ => bail!("error: could not merge value"),
};
Ok(())
}
pub(crate) fn deep_merge(&mut self, new: Value) -> Result<()> {
self.deep_merge_at(new, 0)
}
fn deep_merge_at(&mut self, mut new: Value, depth: usize) -> Result<()> {
if depth >= MAX_MERGE_DEPTH {
bail!("data merge exceeds maximum nesting depth of {MAX_MERGE_DEPTH}");
}
if self == &new {
return Ok(());
}
match (self, &mut new) {
(v @ Value::Undefined, _) => *v = new,
(Value::Set(ref mut set), Value::Set(new)) => {
let dst = Rc::make_mut(set);
match Rc::try_unwrap(core::mem::take(new)) {
Ok(owned) => dst.extend(owned),
Err(shared) => dst.extend(shared.iter().cloned()),
}
enforce_limit_anyhow()?;
}
(Value::Object(map), Value::Object(new)) => {
enum Step {
Skip,
Insert,
Recurse,
Conflict,
}
for (k, v) in new.iter() {
let step = match map.get(k) {
None => Step::Insert,
Some(existing) if existing == v => Step::Skip,
Some(existing)
if matches!(
(existing, v),
(Value::Object(_), Value::Object(_))
| (Value::Set(_), Value::Set(_))
) =>
{
Step::Recurse
}
Some(_) => Step::Conflict,
};
match step {
Step::Skip => {}
Step::Insert => {
Rc::make_mut(map).insert(k.clone(), v.clone());
enforce_limit_anyhow()?;
}
Step::Recurse => {
let existing = Rc::make_mut(map).get_mut(k).ok_or_else(|| {
anyhow!("internal error: key vanished during merge")
})?;
existing.deep_merge_at(v.clone(), depth.saturating_add(1))?;
}
Step::Conflict => {
let existing = map.get(k).ok_or_else(|| {
anyhow!("internal error: key vanished during merge")
})?;
bail!(
"value for key `{}` generated multiple times: `{}` and `{}`",
serde_json::to_string_pretty(&k).map_err(anyhow::Error::msg)?,
serde_json::to_string_pretty(&existing)
.map_err(anyhow::Error::msg)?,
serde_json::to_string_pretty(&v).map_err(anyhow::Error::msg)?,
)
}
}
}
}
_ => bail!("error: could not merge value"),
};
Ok(())
}
#[cfg(not(feature = "allocator-memory-limits"))]
pub(crate) fn check_mergeable(&self, other: &Value) -> Result<()> {
self.check_mergeable_at(other, 0)
}
#[cfg(not(feature = "allocator-memory-limits"))]
fn check_mergeable_at(&self, other: &Value, depth: usize) -> Result<()> {
if depth >= MAX_MERGE_DEPTH {
bail!("data merge exceeds maximum nesting depth of {MAX_MERGE_DEPTH}");
}
if self == other {
return Ok(());
}
match (self, other) {
(Value::Undefined, _) => Ok(()),
(Value::Set(_), Value::Set(_)) => Ok(()),
(Value::Object(dst), Value::Object(src)) => {
for (k, sv) in src.iter() {
if let Some(dv) = dst.get(k) {
let both_mergeable = matches!(
(dv, sv),
(Value::Object(_), Value::Object(_)) | (Value::Set(_), Value::Set(_))
);
if both_mergeable {
dv.check_mergeable_at(sv, depth.saturating_add(1))?;
} else if dv != sv {
bail!(
"value for key `{}` generated multiple times: `{}` and `{}`",
serde_json::to_string_pretty(&k).map_err(anyhow::Error::msg)?,
serde_json::to_string_pretty(&dv).map_err(anyhow::Error::msg)?,
serde_json::to_string_pretty(&sv).map_err(anyhow::Error::msg)?,
)
}
}
}
Ok(())
}
_ => bail!("error: could not merge value"),
}
}
}
impl ops::Index<&Value> for Value {
type Output = Value;
fn index(&self, key: &Value) -> &Self::Output {
match (self, key) {
(Value::Object(o), _) => match &o.get(key) {
Some(v) => v,
_ => &Value::Undefined,
},
(Value::Set(s), _) => match s.get(key) {
Some(v) => v,
_ => &Value::Undefined,
},
(Value::Array(a), Value::Number(n)) => match n.as_u64() {
Some(index) => a.get(index as usize).unwrap_or(&Value::Undefined),
_ => &Value::Undefined,
},
_ => &Value::Undefined,
}
}
}
impl<T> ops::Index<T> for Value
where
Value: From<T>,
{
type Output = Value;
fn index(&self, key: T) -> &Self::Output {
&self[&Value::from(key)]
}
}