use std::borrow::Cow;
use crate::{error::SeaboredSerError, ser::CborSerialize};
use parsio::Write;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct RawValue<'a>(Cow<'a, [u8]>);
impl<'a> RawValue<'a> {
#[cfg(feature = "serde")]
pub(crate) const TYP_NAME: &'static str = "seabored::types::RawValue";
#[inline(always)]
pub fn from_bytes_unchecked(bytes: Vec<u8>) -> Self {
Self(Cow::Owned(bytes))
}
#[inline(always)]
pub fn from_slice_unchecked(bytes: &'a [u8]) -> Self {
Self(Cow::Borrowed(bytes))
}
#[cfg(feature = "serde")]
#[inline]
pub fn from_serialize<T: ::serde_core::Serialize>(value: &T) -> Result<Self, SeaboredSerError> {
crate::serde::to_vec(value).map(Self::from_bytes_unchecked)
}
#[inline(always)]
pub fn as_bytes(&self) -> &[u8] {
&self.0
}
#[inline(always)]
pub fn into_inner(self) -> Cow<'a, [u8]> {
self.0
}
#[cfg(feature = "serde")]
#[inline]
pub fn parse<'de, T: ::serde_core::Deserialize<'a>>(
&'de self,
) -> Result<T, crate::error::SeaboredDeError>
where
'de: 'a,
{
crate::serde::from_slice(&self.0)
}
}
impl CborSerialize for RawValue<'_> {
#[inline(always)]
fn cbor_serialize_to<W: Write>(&self, writer: &mut W) -> Result<usize, SeaboredSerError> {
writer.write(&self.0).map_err(Into::into)
}
}
impl AsRef<[u8]> for RawValue<'_> {
#[inline(always)]
fn as_ref(&self) -> &[u8] {
&self.0
}
}
#[cfg(feature = "serde")]
impl ::serde_core::Serialize for RawValue<'_> {
#[inline(always)]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ::serde_core::Serializer,
{
serializer.serialize_newtype_struct(Self::TYP_NAME, self)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{Value, types::RawValue};
use pretty_assertions::assert_eq;
use std::collections::HashMap;
#[test]
fn raw_value_hashmap_roundtrip() {
let mut map: HashMap<&'static str, RawValue> = HashMap::new();
map.insert("int_key", RawValue::from_serialize(&42u64).unwrap());
map.insert("neg_key", RawValue::from_serialize(&-7i64).unwrap());
map.insert("bool_key", RawValue::from_serialize(&true).unwrap());
map.insert("str_key", RawValue::from_serialize(&"hello CBOR").unwrap());
map.insert(
"bytes_key",
RawValue::from_serialize(&serde_bytes::ByteBuf::from(vec![0xDE, 0xAD, 0xBE, 0xEF]))
.unwrap(),
);
map.insert(
"null_key",
RawValue::from_serialize(&Option::<u8>::None).unwrap(),
);
map.insert("arr_key", RawValue::from_serialize(&[1u32, 2, 3]).unwrap());
let bytes = crate::serde::to_vec(&map).unwrap();
let decoded: Value<'_> = crate::serde::from_slice(&bytes).unwrap();
let Value::Map(seq) = decoded else {
panic!("Expected map");
};
let seq = seq.to_vec();
let map: HashMap<_, _> = seq
.into_iter()
.map(|(k, v)| match k {
Value::String(k) => (k.into_owned(), v),
_ => panic!("Expected string keys got {k:?}"),
})
.collect();
assert_eq!(map["int_key"], Value::Integer(42u64.into()),);
assert_eq!(map["neg_key"], Value::Integer((-7i64).into()),);
assert_eq!(map["bool_key"], Value::Bool(true));
assert_eq!(map["str_key"], Value::String("hello CBOR".into()),);
assert_eq!(
map["bytes_key"],
Value::Bytes(vec![0xDE, 0xAD, 0xBE, 0xEF].into()),
);
assert_eq!(map["null_key"], Value::Null);
let expected_arr = Value::Sequence(
vec![
Value::Integer(1u8.into()),
Value::Integer(2u8.into()),
Value::Integer(3u8.into()),
]
.into(),
);
assert_eq!(map["arr_key"], expected_arr);
}
#[test]
fn raw_value_ref_from_serialize_roundtrip() {
let raw = RawValue::from_serialize(&99u64).unwrap();
let parsed: u64 = raw.parse().unwrap();
assert_eq!(parsed, 99u64);
let out = raw.cbor_serialize().unwrap();
assert_eq!(out, raw.as_bytes());
}
#[test]
fn raw_value_unchecked_passthrough() {
let raw = RawValue::from_bytes_unchecked(vec![0x01]);
assert_eq!(raw.cbor_serialize().unwrap(), &[0x01]);
let bytes = [0x01u8];
let raw_ref = RawValue::from_slice_unchecked(&bytes);
assert_eq!(raw_ref.cbor_serialize().unwrap(), &[0x01]);
}
}