use std::{borrow::Cow, collections::BTreeMap};
use crate::{
Array, ByteString, DateTime, EpochTime, Float, Map, SimpleValue, TextString, Value,
codec::{Head, Major},
view::{Payload, ValueView},
};
#[derive(Debug)]
pub struct ValueKey<'a>(Inner<'a>);
#[derive(Debug)]
enum Inner<'a> {
Array(&'a [Value<'a>]),
Map(&'a BTreeMap<Value<'a>, Value<'a>>),
Other(Cow<'a, Value<'a>>),
}
impl ValueKey<'_> {
pub(crate) fn to_usize(&self) -> Option<usize> {
if let Inner::Other(value) = &self.0 {
value.to_usize().ok()
} else {
None
}
}
}
impl<'a> From<Value<'a>> for ValueKey<'a> {
fn from(value: Value<'a>) -> Self {
Self(Inner::Other(Cow::Owned(value)))
}
}
impl<'a> From<&'a Value<'a>> for ValueKey<'a> {
fn from(value: &'a Value<'a>) -> Self {
Self(Inner::Other(Cow::Borrowed(value)))
}
}
impl<'a> From<&'a [Value<'a>]> for ValueKey<'a> {
fn from(value: &'a [Value<'a>]) -> Self {
Self(Inner::Array(value))
}
}
impl<'a> From<&'a Array<'a>> for ValueKey<'a> {
fn from(value: &'a Array<'a>) -> Self {
Self(Inner::Array(&value.0))
}
}
impl<'a> From<&'a Map<'a>> for ValueKey<'a> {
fn from(value: &'a Map<'a>) -> Self {
Self(Inner::Map(&value.0))
}
}
impl<'a> From<&'a BTreeMap<Value<'a>, Value<'a>>> for ValueKey<'a> {
fn from(value: &'a BTreeMap<Value<'a>, Value<'a>>) -> Self {
Self(Inner::Map(value))
}
}
impl<'a, T> From<&'a Vec<T>> for ValueKey<'a>
where
ValueKey<'a>: From<&'a [T]>,
{
fn from(value: &'a Vec<T>) -> Self {
value.as_slice().into()
}
}
impl<'a, T, const N: usize> From<&'a [T; N]> for ValueKey<'a>
where
ValueKey<'a>: From<&'a [T]>,
{
fn from(value: &'a [T; N]) -> Self {
value.as_slice().into()
}
}
impl<'a, const N: usize> From<[u8; N]> for ValueKey<'a> {
fn from(value: [u8; N]) -> Self {
Self(Inner::Other(Cow::Owned(Value::from(value))))
}
}
impl<'a, const N: usize> From<[Value<'a>; N]> for ValueKey<'a> {
fn from(value: [Value<'a>; N]) -> Self {
Self(Inner::Other(Cow::Owned(Value::from(value))))
}
}
macro_rules! impl_from {
($($type:ty),* $(,)?) => { $(
impl<'a> From<$type> for ValueKey<'a> {
fn from(value: $type) -> Self {
Self(Inner::Other(Cow::Owned(Value::from(value))))
}
}
)* }
}
impl_from!(bool, SimpleValue, (), char);
impl_from!(u8, u16, u32, u64, u128, usize);
impl_from!(i8, i16, i32, i64, i128, isize);
impl_from!(f32, f64, Float);
impl_from!(DateTime, &'a DateTime, EpochTime);
impl_from!(TextString<'a>, &'a TextString<'a>, ByteString<'a>, &'a ByteString<'a>);
impl_from!(&'a str, &'a String, String, Box<str>, Cow<'a, str>);
impl_from!(&'a [u8], Vec<u8>, Box<[u8]>, Cow<'a, [u8]>);
impl_from!(Array<'a>, Map<'a>);
impl_from!(Vec<Value<'a>>, Box<[Value<'a>]>, BTreeMap<Value<'a>, Value<'a>>);
impl ValueView for ValueKey<'_> {
fn head(&self) -> Head {
match &self.0 {
Inner::Array(arr) => Head::from_usize(Major::Array, arr.len()),
Inner::Map(map) => Head::from_usize(Major::Map, map.len()),
Inner::Other(value) => value.head(),
}
}
fn payload(&self) -> Payload<'_> {
match &self.0 {
Inner::Array(arr) => Payload::Array(arr),
Inner::Map(map) => Payload::Map(map),
Inner::Other(value) => value.payload(),
}
}
}