use std::io::{Read, Write};
use borsh::{BorshDeserialize, BorshSerialize};
use serde::{Deserialize, Serialize};
use serde_json::{Map, Number, Value};
const MAX_RECURSION_DEPTH: usize = 128;
const MAX_COLLECTION_SIZE: u32 = 100_000;
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
pub struct ValueWrapper(pub Value);
impl BorshSerialize for ValueWrapper {
#[inline]
fn serialize<W: Write>(&self, writer: &mut W) -> std::io::Result<()> {
match &self.0 {
Value::Bool(data) => {
BorshSerialize::serialize(&0u8, writer)?;
BorshSerialize::serialize(&data, writer)
}
Value::Number(data) => {
BorshSerialize::serialize(&1u8, writer)?;
'data: {
if data.is_f64() {
let Some(data) = data.as_f64() else {
break 'data;
};
BorshSerialize::serialize(&0u8, writer)?;
return BorshSerialize::serialize(&data, writer);
}
else if data.is_i64() {
let Some(data) = data.as_i64() else {
break 'data;
};
BorshSerialize::serialize(&1u8, writer)?;
return BorshSerialize::serialize(&data, writer);
}
else if data.is_u64() {
let Some(data) = data.as_u64() else {
break 'data;
};
BorshSerialize::serialize(&2u8, writer)?;
return BorshSerialize::serialize(&data, writer);
}
}
Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"Invalid number type",
))
}
Value::String(data) => {
BorshSerialize::serialize(&2u8, writer)?;
BorshSerialize::serialize(&data, writer)
}
Value::Array(data) => {
BorshSerialize::serialize(&3u8, writer)?;
let len = u32::try_from(data.len()).map_err(|_| {
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!(
"Array too large to serialize: {} elements exceeds u32::MAX",
data.len()
),
)
})?;
BorshSerialize::serialize(&len, writer)?;
for element in data {
let element = ValueWrapper(element.to_owned());
BorshSerialize::serialize(&element, writer)?;
}
Ok(())
}
Value::Object(data) => {
BorshSerialize::serialize(&4u8, writer)?;
let len = u32::try_from(data.len()).map_err(|_| {
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!(
"Object too large to serialize: {} keys exceeds u32::MAX",
data.len()
),
)
})?;
BorshSerialize::serialize(&len, writer)?;
for (key, value) in data {
BorshSerialize::serialize(&key, writer)?;
let value = ValueWrapper(value.to_owned());
BorshSerialize::serialize(&value, writer)?;
}
Ok(())
}
Value::Null => BorshSerialize::serialize(&5u8, writer),
}
}
}
impl ValueWrapper {
fn deserialize_reader_with_depth<R: Read>(
reader: &mut R,
depth: usize,
) -> std::io::Result<Self> {
if depth > MAX_RECURSION_DEPTH {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!(
"Recursion depth limit exceeded: maximum depth is {}",
MAX_RECURSION_DEPTH
),
));
}
let order: u8 = BorshDeserialize::deserialize_reader(reader)?;
match order {
0 => {
let data: bool = BorshDeserialize::deserialize_reader(reader)?;
Ok(ValueWrapper(Value::Bool(data)))
}
1 => {
let internal_order: u8 =
BorshDeserialize::deserialize_reader(reader)?;
match internal_order {
0 => {
let data: f64 =
BorshDeserialize::deserialize_reader(reader)?;
let Some(data_f64) = Number::from_f64(data) else {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!("Invalid f64 Number: {}", data),
));
};
Ok(ValueWrapper(Value::Number(data_f64)))
}
1 => {
let data: i64 =
BorshDeserialize::deserialize_reader(reader)?;
Ok(ValueWrapper(Value::Number(Number::from(data))))
}
2 => {
let data: u64 =
BorshDeserialize::deserialize_reader(reader)?;
Ok(ValueWrapper(Value::Number(Number::from(data))))
}
_ => Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!(
"Invalid Number representation: {}",
internal_order
),
)),
}
}
2 => {
let data: String =
BorshDeserialize::deserialize_reader(reader)?;
Ok(ValueWrapper(Value::String(data)))
}
3 => {
let len = u32::deserialize_reader(reader)?;
if len > MAX_COLLECTION_SIZE {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!(
"Array size too large: {} exceeds maximum of {}",
len, MAX_COLLECTION_SIZE
),
));
}
if len == 0 {
Ok(ValueWrapper(Value::Array(Vec::new())))
} else {
let mut result = Vec::with_capacity(len as usize);
let next_depth = depth.checked_add(1).ok_or_else(|| {
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"Recursion depth counter overflow",
)
})?;
for _ in 0..len {
result.push(
ValueWrapper::deserialize_reader_with_depth(
reader,
next_depth,
)?
.0,
);
}
Ok(ValueWrapper(Value::Array(result)))
}
}
4 => {
let len = u32::deserialize_reader(reader)?;
if len > MAX_COLLECTION_SIZE {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!(
"Object size too large: {} exceeds maximum of {}",
len, MAX_COLLECTION_SIZE
),
));
}
let mut result = Map::new();
let next_depth = depth.checked_add(1).ok_or_else(|| {
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"Recursion depth counter overflow",
)
})?;
for _ in 0..len {
let key = String::deserialize_reader(reader)?;
let value =
ValueWrapper::deserialize_reader_with_depth(reader, next_depth)?;
result.insert(key, value.0);
}
Ok(ValueWrapper(Value::Object(result)))
}
5 => Ok(ValueWrapper(Value::Null)),
_ => Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!("Invalid Value representation: {}", order),
)),
}
}
}
impl BorshDeserialize for ValueWrapper {
#[inline]
fn deserialize_reader<R: Read>(reader: &mut R) -> std::io::Result<Self> {
ValueWrapper::deserialize_reader_with_depth(reader, 0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_value_wrapper_string() {
let value = ValueWrapper(Value::String("test".to_owned()));
let vec = borsh::to_vec(&value).unwrap();
let value2: ValueWrapper = BorshDeserialize::try_from_slice(&vec).unwrap();
assert_eq!(value, value2);
}
#[test]
fn test_value_wrapper_bool() {
let value = ValueWrapper(Value::Bool(true));
let vec = borsh::to_vec(&value).unwrap();
let value2: ValueWrapper = BorshDeserialize::try_from_slice(&vec).unwrap();
assert_eq!(value, value2);
let value_false = ValueWrapper(Value::Bool(false));
let vec_false = borsh::to_vec(&value_false).unwrap();
let value2_false: ValueWrapper = BorshDeserialize::try_from_slice(&vec_false).unwrap();
assert_eq!(value_false, value2_false);
}
#[test]
fn test_value_wrapper_number_f64() {
let value = ValueWrapper(Value::Number(Number::from_f64(3.14).unwrap()));
let vec = borsh::to_vec(&value).unwrap();
let value2: ValueWrapper = BorshDeserialize::try_from_slice(&vec).unwrap();
assert_eq!(value, value2);
}
#[test]
fn test_value_wrapper_number_i64() {
let value = ValueWrapper(Value::Number(Number::from(-42i64)));
let vec = borsh::to_vec(&value).unwrap();
let value2: ValueWrapper = BorshDeserialize::try_from_slice(&vec).unwrap();
assert_eq!(value, value2);
}
#[test]
fn test_value_wrapper_number_u64() {
let value = ValueWrapper(Value::Number(Number::from(12345u64)));
let vec = borsh::to_vec(&value).unwrap();
let value2: ValueWrapper = BorshDeserialize::try_from_slice(&vec).unwrap();
assert_eq!(value, value2);
}
#[test]
fn test_value_wrapper_null() {
let value = ValueWrapper(Value::Null);
let vec = borsh::to_vec(&value).unwrap();
let value2: ValueWrapper = BorshDeserialize::try_from_slice(&vec).unwrap();
assert_eq!(value, value2);
}
#[test]
fn test_value_wrapper_array() {
let value = ValueWrapper(Value::Array(vec![
Value::Bool(true),
Value::String("test".to_owned()),
Value::Number(Number::from(42)),
Value::Null,
]));
let vec = borsh::to_vec(&value).unwrap();
let value2: ValueWrapper = BorshDeserialize::try_from_slice(&vec).unwrap();
assert_eq!(value, value2);
}
#[test]
fn test_value_wrapper_empty_array() {
let value = ValueWrapper(Value::Array(vec![]));
let vec = borsh::to_vec(&value).unwrap();
let value2: ValueWrapper = BorshDeserialize::try_from_slice(&vec).unwrap();
assert_eq!(value, value2);
}
#[test]
fn test_value_wrapper_object() {
let mut map = Map::new();
map.insert("name".to_string(), Value::String("Alice".to_owned()));
map.insert("age".to_string(), Value::Number(Number::from(30)));
map.insert("active".to_string(), Value::Bool(true));
let value = ValueWrapper(Value::Object(map));
let vec = borsh::to_vec(&value).unwrap();
let value2: ValueWrapper = BorshDeserialize::try_from_slice(&vec).unwrap();
assert_eq!(value, value2);
}
#[test]
fn test_value_wrapper_empty_object() {
let value = ValueWrapper(Value::Object(Map::new()));
let vec = borsh::to_vec(&value).unwrap();
let value2: ValueWrapper = BorshDeserialize::try_from_slice(&vec).unwrap();
assert_eq!(value, value2);
}
#[test]
fn test_value_wrapper_nested_structure() {
let mut inner_map = Map::new();
inner_map.insert("x".to_string(), Value::Number(Number::from(1)));
inner_map.insert("y".to_string(), Value::Number(Number::from(2)));
let mut outer_map = Map::new();
outer_map.insert("point".to_string(), Value::Object(inner_map));
outer_map.insert("values".to_string(), Value::Array(vec![
Value::Number(Number::from(1)),
Value::Number(Number::from(2)),
Value::Number(Number::from(3)),
]));
let value = ValueWrapper(Value::Object(outer_map));
let vec = borsh::to_vec(&value).unwrap();
let value2: ValueWrapper = BorshDeserialize::try_from_slice(&vec).unwrap();
assert_eq!(value, value2);
}
#[test]
fn test_value_wrapper_max_recursion_depth() {
let mut value = Value::Null;
for _ in 0..MAX_RECURSION_DEPTH {
value = Value::Array(vec![value]);
}
let wrapper = ValueWrapper(value);
let vec = borsh::to_vec(&wrapper).unwrap();
let result: Result<ValueWrapper, _> = BorshDeserialize::try_from_slice(&vec);
assert!(result.is_ok());
}
#[test]
fn test_value_wrapper_exceeds_recursion_depth() {
let mut value = Value::Null;
for _ in 0..=MAX_RECURSION_DEPTH {
value = Value::Array(vec![value]);
}
let wrapper = ValueWrapper(value);
let vec = borsh::to_vec(&wrapper).unwrap();
let result: Result<ValueWrapper, _> = BorshDeserialize::try_from_slice(&vec);
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("Recursion depth limit exceeded"));
}
#[test]
fn test_value_wrapper_large_array() {
let large_array = vec![Value::Null; MAX_COLLECTION_SIZE as usize];
let value = ValueWrapper(Value::Array(large_array));
let vec = borsh::to_vec(&value).unwrap();
let value2: ValueWrapper = BorshDeserialize::try_from_slice(&vec).unwrap();
assert_eq!(value, value2);
}
#[test]
fn test_value_wrapper_array_size_overflow() {
let mut bytes = vec![3u8]; let oversized_len = MAX_COLLECTION_SIZE + 1;
bytes.extend_from_slice(&oversized_len.to_le_bytes());
let result: Result<ValueWrapper, _> = BorshDeserialize::try_from_slice(&bytes);
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("Array size too large"));
}
#[test]
fn test_value_wrapper_object_size_overflow() {
let mut bytes = vec![4u8]; let oversized_len = MAX_COLLECTION_SIZE + 1;
bytes.extend_from_slice(&oversized_len.to_le_bytes());
let result: Result<ValueWrapper, _> = BorshDeserialize::try_from_slice(&bytes);
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("Object size too large"));
}
#[test]
fn test_value_wrapper_invalid_type_tag() {
let bytes = vec![6u8];
let result: Result<ValueWrapper, _> = BorshDeserialize::try_from_slice(&bytes);
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("Invalid Value representation"));
}
#[test]
fn test_value_wrapper_invalid_number_type() {
let bytes = vec![1u8, 3u8];
let result: Result<ValueWrapper, _> = BorshDeserialize::try_from_slice(&bytes);
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("Invalid Number representation"));
}
#[test]
fn test_value_wrapper_unicode_strings() {
let value = ValueWrapper(Value::String("Hello δΈη π".to_owned()));
let vec = borsh::to_vec(&value).unwrap();
let value2: ValueWrapper = BorshDeserialize::try_from_slice(&vec).unwrap();
assert_eq!(value, value2);
}
#[test]
fn test_value_wrapper_empty_string() {
let value = ValueWrapper(Value::String(String::new()));
let vec = borsh::to_vec(&value).unwrap();
let value2: ValueWrapper = BorshDeserialize::try_from_slice(&vec).unwrap();
assert_eq!(value, value2);
}
#[test]
fn test_value_wrapper_special_floats() {
let value = ValueWrapper(Value::Number(Number::from_f64(0.0).unwrap()));
let vec = borsh::to_vec(&value).unwrap();
let value2: ValueWrapper = BorshDeserialize::try_from_slice(&vec).unwrap();
assert_eq!(value, value2);
let value = ValueWrapper(Value::Number(Number::from_f64(-0.0).unwrap()));
let vec = borsh::to_vec(&value).unwrap();
let value2: ValueWrapper = BorshDeserialize::try_from_slice(&vec).unwrap();
assert_eq!(value, value2);
}
#[test]
fn test_value_wrapper_clone() {
let value = ValueWrapper(Value::String("test".to_owned()));
let cloned = value.clone();
assert_eq!(value, cloned);
}
#[test]
fn test_value_wrapper_debug() {
let value = ValueWrapper(Value::String("test".to_owned()));
let debug_str = format!("{:?}", value);
assert!(debug_str.contains("test"));
}
}