| // Copyright 2022 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| use crate::values::{DictValueRef, ListValueRef, ValueSlotRef}; |
| use serde::de::{DeserializeSeed, Deserializer, Error, MapAccess, SeqAccess, Visitor}; |
| use std::convert::TryFrom; |
| use std::fmt; |
| |
| /// Struct to check we're not recursing too deeply. |
| #[derive(Clone)] |
| struct RecursionDepthCheck(usize); |
| |
| impl RecursionDepthCheck { |
| /// Recurse a level and return an error if we've recursed too far. |
| fn recurse<E: Error>(&self) -> Result<RecursionDepthCheck, E> { |
| match self.0.checked_sub(1) { |
| Some(recursion_limit) => Ok(RecursionDepthCheck(recursion_limit)), |
| None => Err(Error::custom("recursion limit exceeded")), |
| } |
| } |
| } |
| |
| /// What type of `base::Value` container we're deserializing into. |
| enum DeserializationTarget<'elem, 'container> { |
| /// Deserialize into a brand new root `base::Value`. |
| NewValue { slot: ValueSlotRef<'container> }, |
| /// Deserialize by appending to a list. |
| List { list: &'elem mut ListValueRef<'container> }, |
| /// Deserialize by setting a dictionary key. |
| Dict { dict: &'elem mut DictValueRef<'container>, key: String }, |
| } |
| |
| /// serde deserializer for for `base::Value`. |
| /// |
| /// serde is the "standard" framework for serializing and deserializing |
| /// data formats in Rust. https://serde.rs/ |
| /// |
| /// This implements both the Visitor and Deserialize roles described |
| /// here: https://serde.rs/impl-deserialize.html |
| /// |
| /// One note, though. Normally serde instantiates a new object. The design |
| /// of `base::Value` is that each sub-value (e.g. a list like this) |
| /// needs to be deserialized into the parent value, which is pre-existing. |
| /// To achieve this we use a feature of serde called 'stateful deserialization' |
| /// (see https://docs.serde.rs/serde/de/trait.DeserializeSeed.html) |
| /// |
| /// This struct stores that state. |
| /// |
| /// Handily, this also enables us to store the desired recursion limit. |
| /// |
| /// We use runtime dispatch (matching on an enum) to deserialize into a |
| /// dictionary, list, etc. This may be slower than having three different |
| /// `Visitor` implementations, where everything would be monomorphized |
| /// and would probably disappear with inlining, but for now this is much |
| /// less code. |
| pub struct ValueVisitor<'elem, 'container> { |
| container: DeserializationTarget<'elem, 'container>, |
| recursion_depth_check: RecursionDepthCheck, |
| } |
| |
| impl<'elem, 'container> ValueVisitor<'elem, 'container> { |
| /// Constructor - pass in an existing slot that can store a new |
| /// `base::Value`, then this visitor can be passed to serde deserialization |
| /// libraries to populate it with a tree of contents. |
| /// Any existing `base::Value` in the slot will be replaced. |
| pub fn new(slot: ValueSlotRef<'container>, mut max_depth: usize) -> Self { |
| max_depth += 1; // we will increment this counter when deserializing |
| // the initial `base::Value`. To match C++ behavior, we should |
| // only start counting for subsequent layers, hence decrement |
| // now. |
| Self { |
| container: DeserializationTarget::NewValue { slot }, |
| recursion_depth_check: RecursionDepthCheck(max_depth), |
| } |
| } |
| } |
| |
| impl<'de, 'elem, 'container> Visitor<'de> for ValueVisitor<'elem, 'container> { |
| // Because we are deserializing into a pre-existing object. |
| type Value = (); |
| |
| fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
| formatter.write_str("any valid JSON") |
| } |
| |
| fn visit_i32<E: serde::de::Error>(self, value: i32) -> Result<Self::Value, E> { |
| match self.container { |
| DeserializationTarget::NewValue { mut slot } => slot.construct_integer(value), |
| DeserializationTarget::List { list } => list.append_integer(value), |
| DeserializationTarget::Dict { dict, key } => dict.set_integer_key(&key, value), |
| }; |
| Ok(()) |
| } |
| |
| fn visit_i8<E: serde::de::Error>(self, value: i8) -> Result<Self::Value, E> { |
| self.visit_i32(value as i32) |
| } |
| |
| fn visit_bool<E: serde::de::Error>(self, value: bool) -> Result<Self::Value, E> { |
| match self.container { |
| DeserializationTarget::NewValue { mut slot } => slot.construct_bool(value), |
| DeserializationTarget::List { list } => list.append_bool(value), |
| DeserializationTarget::Dict { dict, key } => dict.set_bool_key(&key, value), |
| }; |
| Ok(()) |
| } |
| |
| fn visit_i64<E: serde::de::Error>(self, value: i64) -> Result<Self::Value, E> { |
| // Here we match the behavior of the Chromium C++ JSON parser, |
| // which will attempt to create an integer base::Value but will |
| // overflow into a double if needs be. |
| // (See JSONParser::ConsumeNumber in json_parser.cc for equivalent, |
| // and json_reader_unittest.cc LargerIntIsLossy for a related test). |
| match i32::try_from(value) { |
| Ok(value) => self.visit_i32(value), |
| Err(_) => self.visit_f64(value as f64), |
| } |
| } |
| |
| fn visit_u64<E: serde::de::Error>(self, value: u64) -> Result<Self::Value, E> { |
| // See visit_i64 comment. |
| match i32::try_from(value) { |
| Ok(value) => self.visit_i32(value), |
| Err(_) => self.visit_f64(value as f64), |
| } |
| } |
| |
| fn visit_f64<E: serde::de::Error>(self, value: f64) -> Result<Self::Value, E> { |
| match self.container { |
| DeserializationTarget::NewValue { mut slot } => slot.construct_double(value), |
| DeserializationTarget::List { list } => list.append_double(value), |
| DeserializationTarget::Dict { dict, key } => dict.set_double_key(&key, value), |
| }; |
| Ok(()) |
| } |
| |
| fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Self::Value, E> { |
| match self.container { |
| DeserializationTarget::NewValue { mut slot } => slot.construct_string(value), |
| DeserializationTarget::List { list } => list.append_string(value), |
| DeserializationTarget::Dict { dict, key } => dict.set_string_key(&key, value), |
| }; |
| Ok(()) |
| } |
| |
| fn visit_borrowed_str<E: serde::de::Error>(self, value: &'de str) -> Result<Self::Value, E> { |
| match self.container { |
| DeserializationTarget::NewValue { mut slot } => slot.construct_string(value), |
| DeserializationTarget::List { list } => list.append_string(value), |
| DeserializationTarget::Dict { dict, key } => dict.set_string_key(&key, value), |
| }; |
| Ok(()) |
| } |
| |
| fn visit_string<E: serde::de::Error>(self, value: String) -> Result<Self::Value, E> { |
| self.visit_str(&value) |
| } |
| |
| fn visit_none<E: serde::de::Error>(self) -> Result<Self::Value, E> { |
| match self.container { |
| DeserializationTarget::NewValue { mut slot } => slot.construct_none(), |
| DeserializationTarget::List { list } => list.append_none(), |
| DeserializationTarget::Dict { dict, key } => dict.set_none_key(&key), |
| }; |
| Ok(()) |
| } |
| |
| fn visit_unit<E: serde::de::Error>(self) -> Result<Self::Value, E> { |
| self.visit_none() |
| } |
| |
| fn visit_map<M>(mut self, mut access: M) -> Result<Self::Value, M::Error> |
| where |
| M: MapAccess<'de>, |
| { |
| let mut value = match self.container { |
| DeserializationTarget::NewValue { ref mut slot } => slot.construct_dict(), |
| DeserializationTarget::List { list } => list.append_dict(), |
| DeserializationTarget::Dict { dict, key } => dict.set_dict_key(&key), |
| }; |
| // If it were exposed by values.h, we could use access.size_hint() |
| // to give a clue to the C++ about the size of the desired map. |
| while let Some(key) = access.next_key::<String>()? { |
| access.next_value_seed(ValueVisitor { |
| container: DeserializationTarget::Dict { dict: &mut value, key }, |
| recursion_depth_check: self.recursion_depth_check.recurse()?, |
| })?; |
| } |
| Ok(()) |
| } |
| |
| fn visit_seq<S>(mut self, mut access: S) -> Result<Self::Value, S::Error> |
| where |
| S: SeqAccess<'de>, |
| { |
| let mut value = match self.container { |
| DeserializationTarget::NewValue { ref mut slot } => slot.construct_list(), |
| DeserializationTarget::List { list } => list.append_list(), |
| DeserializationTarget::Dict { dict, key } => dict.set_list_key(&key), |
| }; |
| if let Some(size_hint) = access.size_hint() { |
| value.reserve_size(size_hint); |
| } |
| while let Some(_) = access.next_element_seed(ValueVisitor { |
| container: DeserializationTarget::List { list: &mut value }, |
| recursion_depth_check: self.recursion_depth_check.recurse()?, |
| })? {} |
| Ok(()) |
| } |
| } |
| |
| impl<'de, 'elem, 'container> DeserializeSeed<'de> for ValueVisitor<'elem, 'container> { |
| // Because we are deserializing into a pre-existing object. |
| type Value = (); |
| |
| fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> |
| where |
| D: Deserializer<'de>, |
| { |
| deserializer.deserialize_any(self) |
| } |
| } |