mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-11-28 00:06:09 +03:00
298 lines
10 KiB
Rust
298 lines
10 KiB
Rust
|
// Copyright 2021 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 std::pin::Pin;
|
||
|
|
||
|
use crate::rs_glue;
|
||
|
|
||
|
/// A reference to a C++ `base::Value` of type `base::Value::Type::DICTIONARY`.
|
||
|
/// Such a value is currently either held directly in a populated
|
||
|
/// [`ValueSlotRef`] or in a child `base::Value` thereof.
|
||
|
pub struct DictValueRef<'a>(Pin<&'a mut rs_glue::ffi::Value>);
|
||
|
|
||
|
impl<'a> DictValueRef<'a> {
|
||
|
/// Get a reference to the base::Value.
|
||
|
fn raw_mut(&mut self) -> Pin<&mut rs_glue::ffi::Value> {
|
||
|
self.0.as_mut()
|
||
|
}
|
||
|
|
||
|
/// Sets the value at this dictionary key to be a value of type
|
||
|
/// `base::Value::Type::NONE`.
|
||
|
pub fn set_none_key(&mut self, key: &str) {
|
||
|
rs_glue::ffi::ValueSetNoneKey(self.raw_mut(), key);
|
||
|
}
|
||
|
|
||
|
/// Sets the value at this dictionary key to a Boolean.
|
||
|
pub fn set_bool_key(&mut self, key: &str, val: bool) {
|
||
|
rs_glue::ffi::ValueSetBoolKey(self.raw_mut(), key, val);
|
||
|
}
|
||
|
|
||
|
/// Sets the value at this dictionary key to an integer.
|
||
|
pub fn set_integer_key(&mut self, key: &str, val: i32) {
|
||
|
rs_glue::ffi::ValueSetIntegerKey(self.raw_mut(), key, val);
|
||
|
}
|
||
|
|
||
|
/// Sets the value at this dictionary key to a double.
|
||
|
pub fn set_double_key(&mut self, key: &str, val: f64) {
|
||
|
rs_glue::ffi::ValueSetDoubleKey(self.raw_mut(), key, val);
|
||
|
}
|
||
|
|
||
|
/// Sets the value at this dictionary key to a string.
|
||
|
pub fn set_string_key(&mut self, key: &str, val: &str) {
|
||
|
rs_glue::ffi::ValueSetStringKey(self.raw_mut(), key, val);
|
||
|
}
|
||
|
|
||
|
/// Sets the value at this dictionary key to a new dictionary, and returns
|
||
|
/// a reference to it.
|
||
|
pub fn set_dict_key(&mut self, key: &str) -> DictValueRef {
|
||
|
rs_glue::ffi::ValueSetDictKey(self.raw_mut(), key).into()
|
||
|
}
|
||
|
|
||
|
/// Sets the value at this dictionary key to a new list, and returns a
|
||
|
/// reference to it.
|
||
|
pub fn set_list_key(&mut self, key: &str) -> ListValueRef {
|
||
|
rs_glue::ffi::ValueSetListKey(self.raw_mut(), key).into()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<'a> From<Pin<&'a mut rs_glue::ffi::Value>> for DictValueRef<'a> {
|
||
|
/// Wrap a reference to a C++ `base::Value` in a newtype wrapper to
|
||
|
/// indicate that it's of type DICTIONARY. This is not actually unsafe,
|
||
|
/// since any mistakes here will result in a deliberate crash due to
|
||
|
/// assertions on the C++ side, rather than memory safety errors.
|
||
|
fn from(value: Pin<&'a mut rs_glue::ffi::Value>) -> Self {
|
||
|
Self(value)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// A reference to a C++ `base::Value` of type `base::Value::Type::LIST`.
|
||
|
/// Such a value is currently either held directly in a populated
|
||
|
/// [`ValueSlotRef`] or in a child `base::Value` thereof.
|
||
|
pub struct ListValueRef<'a>(Pin<&'a mut rs_glue::ffi::Value>);
|
||
|
|
||
|
impl<'a> ListValueRef<'a> {
|
||
|
/// Get a reference to the underlying base::Value.
|
||
|
fn raw_mut(&mut self) -> Pin<&mut rs_glue::ffi::Value> {
|
||
|
self.0.as_mut()
|
||
|
}
|
||
|
|
||
|
/// Appends a value of type `base::Value::Type::NONE`. Grows
|
||
|
/// the list as necessary.
|
||
|
pub fn append_none(&mut self) {
|
||
|
rs_glue::ffi::ValueAppendNone(self.raw_mut());
|
||
|
}
|
||
|
|
||
|
/// Appends a Boolean. Grows the list as necessary.
|
||
|
pub fn append_bool(&mut self, val: bool) {
|
||
|
self.raw_mut().ValueAppendBool(val)
|
||
|
}
|
||
|
|
||
|
/// Appends an integer. Grows the list as necessary.
|
||
|
pub fn append_integer(&mut self, val: i32) {
|
||
|
self.raw_mut().ValueAppendInteger(val)
|
||
|
}
|
||
|
|
||
|
/// Appends a double. Grows the list as necessary.
|
||
|
pub fn append_double(&mut self, val: f64) {
|
||
|
self.raw_mut().ValueAppendDouble(val)
|
||
|
}
|
||
|
|
||
|
/// Appends a string. Grows the list as necessary.
|
||
|
pub fn append_string(&mut self, val: &str) {
|
||
|
rs_glue::ffi::ValueAppendString(self.raw_mut(), val);
|
||
|
}
|
||
|
|
||
|
/// Appends a new dictionary, and returns a reference to it.
|
||
|
/// Grows the list as necessary.
|
||
|
pub fn append_dict(&mut self) -> DictValueRef {
|
||
|
rs_glue::ffi::ValueAppendDict(self.raw_mut()).into()
|
||
|
}
|
||
|
|
||
|
/// Appends a new list, and returns a reference to it. Grows
|
||
|
/// the list as necessary.
|
||
|
pub fn append_list(&mut self) -> ListValueRef {
|
||
|
rs_glue::ffi::ValueAppendList(self.raw_mut()).into()
|
||
|
}
|
||
|
|
||
|
/// Reserves space for a given number of elements within a list. This is
|
||
|
/// optional - lists will grow as necessary to accommodate the items you
|
||
|
/// add, so this just reduces the allocations necessary.
|
||
|
pub fn reserve_size(&mut self, len: usize) {
|
||
|
rs_glue::ffi::ValueReserveSize(self.raw_mut(), len);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<'a> From<Pin<&'a mut rs_glue::ffi::Value>> for ListValueRef<'a> {
|
||
|
/// Wrap a reference to a C++ `base::Value` in a newtype wrapper to
|
||
|
/// indicate that it's of type LIST. This is not actually unsafe, since
|
||
|
/// any mistakes here will result in a deliberate crash due to assertions
|
||
|
/// on the C++ side, rather than memory safety errors.
|
||
|
fn from(value: Pin<&'a mut rs_glue::ffi::Value>) -> Self {
|
||
|
Self(value)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// A reference to a slot in which a `base::Value` can be constructed.
|
||
|
/// Such a slot can only be created within C++ and passed to Rust; Rust
|
||
|
/// can then create a `base::Value` therein.
|
||
|
pub struct ValueSlotRef<'a>(Pin<&'a mut rs_glue::ffi::ValueSlot>);
|
||
|
|
||
|
impl<'a> From<Pin<&'a mut rs_glue::ffi::ValueSlot>> for ValueSlotRef<'a> {
|
||
|
fn from(value: Pin<&'a mut rs_glue::ffi::ValueSlot>) -> Self {
|
||
|
Self(value)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<'a> From<&'a mut cxx::UniquePtr<rs_glue::ffi::ValueSlot>> for ValueSlotRef<'a> {
|
||
|
fn from(value: &'a mut cxx::UniquePtr<rs_glue::ffi::ValueSlot>) -> Self {
|
||
|
Self(value.pin_mut())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<'a> ValueSlotRef<'a> {
|
||
|
/// Return a mutable reference to the underlying raw value.
|
||
|
fn raw_mut(&mut self) -> Pin<&mut rs_glue::ffi::ValueSlot> {
|
||
|
self.0.as_mut()
|
||
|
}
|
||
|
|
||
|
/// Return a reference to the underlying raw value.
|
||
|
fn raw(&self) -> &rs_glue::ffi::ValueSlot {
|
||
|
&self.0
|
||
|
}
|
||
|
|
||
|
/// Creates a new `base::Value::Type::NONE` `base::Value` in this slot.
|
||
|
pub fn construct_none(&mut self) {
|
||
|
rs_glue::ffi::ConstructNoneValue(self.raw_mut());
|
||
|
}
|
||
|
|
||
|
/// Creates a new Boolean `base::Value` in this slot.
|
||
|
pub fn construct_bool(&mut self, val: bool) {
|
||
|
rs_glue::ffi::ConstructBoolValue(self.raw_mut(), val);
|
||
|
}
|
||
|
|
||
|
/// Creates a new integer `base::Value` in this slot.
|
||
|
pub fn construct_integer(&mut self, val: i32) {
|
||
|
rs_glue::ffi::ConstructIntegerValue(self.raw_mut(), val);
|
||
|
}
|
||
|
|
||
|
/// Creates a new double `base::Value` in this slot.
|
||
|
pub fn construct_double(&mut self, val: f64) {
|
||
|
rs_glue::ffi::ConstructDoubleValue(self.raw_mut(), val);
|
||
|
}
|
||
|
|
||
|
/// Creates a new string `base::Value` in this slot.
|
||
|
pub fn construct_string(&mut self, val: &str) {
|
||
|
rs_glue::ffi::ConstructStringValue(self.raw_mut(), val);
|
||
|
}
|
||
|
|
||
|
/// Creates a new dictionary `base::Value` in this slot.
|
||
|
pub fn construct_dict(&mut self) -> DictValueRef {
|
||
|
rs_glue::ffi::ConstructDictValue(self.raw_mut()).into()
|
||
|
}
|
||
|
|
||
|
/// Creates a new list `base::Value` in this slot.
|
||
|
pub fn construct_list(&mut self) -> ListValueRef {
|
||
|
rs_glue::ffi::ConstructListValue(self.raw_mut()).into()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Asks C++ code to dump this base::Value back to JSON.
|
||
|
/// Primarily for testing the round-trip.
|
||
|
impl<'a> std::fmt::Debug for ValueSlotRef<'a> {
|
||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||
|
f.write_str(&rs_glue::ffi::DumpValueSlot(self.raw()))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[cfg(test)]
|
||
|
mod tests {
|
||
|
|
||
|
use crate::{rs_glue, values::ValueSlotRef};
|
||
|
|
||
|
#[test]
|
||
|
fn test_alloc_dealloc() {
|
||
|
rs_glue::ffi::NewValueSlot();
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn test_starts_none() {
|
||
|
let mut v = rs_glue::ffi::NewValueSlot();
|
||
|
let v = ValueSlotRef::from(v.pin_mut());
|
||
|
assert_eq!(format!("{:?}", v), "(empty)");
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn test_set_dict() {
|
||
|
let mut v = rs_glue::ffi::NewValueSlot();
|
||
|
let mut v = ValueSlotRef::from(&mut v);
|
||
|
let mut d = v.construct_dict();
|
||
|
d.set_string_key("fish", "skate");
|
||
|
d.set_none_key("antlers");
|
||
|
d.set_bool_key("has_lungs", false);
|
||
|
d.set_integer_key("fins", 2);
|
||
|
d.set_double_key("bouyancy", 1.0);
|
||
|
let mut nested_list = d.set_list_key("scales");
|
||
|
nested_list.append_string("sea major");
|
||
|
let mut nested_dict = d.set_dict_key("taxonomy");
|
||
|
nested_dict.set_string_key("kingdom", "animalia");
|
||
|
nested_dict.set_string_key("phylum", "chordata");
|
||
|
// TODO(crbug.com/1282310): Use indoc to make this neater.
|
||
|
assert_eq!(
|
||
|
format!("{:?}", v),
|
||
|
"{\n \"antlers\": null,\n \"bouyancy\": 1.0,\n \"fins\": 2,\n \"fish\": \"skate\",\n \"has_lungs\": false,\n \"scales\": [ \"sea major\" ],\n \"taxonomy\": {\n \"kingdom\": \"animalia\",\n \"phylum\": \"chordata\"\n }\n}\n"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn test_set_list() {
|
||
|
let mut v = rs_glue::ffi::NewValueSlot();
|
||
|
let mut v = ValueSlotRef::from(&mut v);
|
||
|
let mut l = v.construct_list();
|
||
|
l.reserve_size(5);
|
||
|
l.append_bool(false);
|
||
|
l.append_none();
|
||
|
l.append_double(2.0);
|
||
|
l.append_integer(4);
|
||
|
let mut nested_list = l.append_list();
|
||
|
nested_list.append_none();
|
||
|
let mut nested_dict = l.append_dict();
|
||
|
nested_dict.set_string_key("a", "b");
|
||
|
l.append_string("hello");
|
||
|
assert_eq!(
|
||
|
format!("{:?}", v),
|
||
|
"[ false, null, 2.0, 4, [ null ], {\n \"a\": \"b\"\n}, \"hello\" ]\n"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
fn assert_simple_value_matches<F>(f: F, expected: &str)
|
||
|
where
|
||
|
F: FnOnce(&mut ValueSlotRef),
|
||
|
{
|
||
|
let mut v = rs_glue::ffi::NewValueSlot();
|
||
|
let mut v = ValueSlotRef::from(&mut v);
|
||
|
f(&mut v);
|
||
|
assert_eq!(format!("{:?}", v).trim_end(), expected);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn test_set_simple_optional_values() {
|
||
|
assert_simple_value_matches(|v| v.construct_none(), "null");
|
||
|
assert_simple_value_matches(|v| v.construct_bool(true), "true");
|
||
|
assert_simple_value_matches(|v| v.construct_integer(3), "3");
|
||
|
assert_simple_value_matches(|v| v.construct_double(3.1), "3.1");
|
||
|
assert_simple_value_matches(|v| v.construct_string("a"), "\"a\"");
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn test_reuse_slot() {
|
||
|
let mut v = rs_glue::ffi::NewValueSlot();
|
||
|
let mut v = ValueSlotRef::from(&mut v);
|
||
|
v.construct_none();
|
||
|
let mut d = v.construct_dict();
|
||
|
d.set_integer_key("a", 3);
|
||
|
v.construct_integer(7);
|
||
|
assert_eq!(format!("{:?}", v).trim_end(), "7");
|
||
|
}
|
||
|
}
|