use alloc::borrow::Cow;
use indexmap::IndexMap;
use super::hasher::DefaultHashBuilder;
pub(crate) type Key<'text> = Cow<'text, str>;
#[derive(Clone, Debug, PartialEq)]
pub enum Value<'text> {
Str(Cow<'text, str>),
Obj(Obj<'text>),
I32(i32),
U64(u64),
Float(f32),
Pointer(u32),
Color([u8; 4]),
}
impl<'text> Value<'text> {
pub fn is_str(&self) -> bool {
matches!(self, Value::Str(_))
}
pub fn is_obj(&self) -> bool {
matches!(self, Value::Obj(_))
}
pub fn is_i32(&self) -> bool {
matches!(self, Value::I32(_))
}
pub fn is_u64(&self) -> bool {
matches!(self, Value::U64(_))
}
pub fn is_float(&self) -> bool {
matches!(self, Value::Float(_))
}
pub fn is_pointer(&self) -> bool {
matches!(self, Value::Pointer(_))
}
pub fn is_color(&self) -> bool {
matches!(self, Value::Color(_))
}
pub fn as_str(&self) -> Option<&str> {
match self {
Value::Str(s) => Some(s.as_ref()),
_ => None,
}
}
pub fn as_obj(&self) -> Option<&Obj<'text>> {
match self {
Value::Obj(obj) => Some(obj),
_ => None,
}
}
pub fn as_obj_mut(&mut self) -> Option<&mut Obj<'text>> {
match self {
Value::Obj(obj) => Some(obj),
_ => None,
}
}
pub fn as_i32(&self) -> Option<i32> {
match self {
Value::I32(n) => Some(*n),
_ => None,
}
}
pub fn as_u64(&self) -> Option<u64> {
match self {
Value::U64(n) => Some(*n),
_ => None,
}
}
pub fn as_float(&self) -> Option<f32> {
match self {
Value::Float(n) => Some(*n),
_ => None,
}
}
pub fn as_pointer(&self) -> Option<u32> {
match self {
Value::Pointer(n) => Some(*n),
_ => None,
}
}
pub fn as_color(&self) -> Option<[u8; 4]> {
match self {
Value::Color(c) => Some(*c),
_ => None,
}
}
pub fn get(&self, key: &str) -> Option<&Value<'text>> {
self.as_obj()?.get(key)
}
pub fn get_path(&self, path: &[&str]) -> Option<&Value<'text>> {
let mut current = self;
for key in path {
current = current.get(key)?;
}
Some(current)
}
pub fn get_str(&self, path: &[&str]) -> Option<&str> {
self.get_path(path)?.as_str()
}
pub fn get_obj(&self, path: &[&str]) -> Option<&Obj<'text>> {
self.get_path(path)?.as_obj()
}
pub fn get_i32(&self, path: &[&str]) -> Option<i32> {
self.get_path(path)?.as_i32()
}
pub fn get_u64(&self, path: &[&str]) -> Option<u64> {
self.get_path(path)?.as_u64()
}
pub fn get_float(&self, path: &[&str]) -> Option<f32> {
self.get_path(path)?.as_float()
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Obj<'text> {
pub(crate) inner: IndexMap<Key<'text>, Value<'text>, DefaultHashBuilder>,
}
impl<'text> Obj<'text> {
pub fn new() -> Self {
Self {
inner: IndexMap::with_hasher(DefaultHashBuilder::default()),
}
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn get(&self, key: &str) -> Option<&Value<'text>> {
self.inner.get(key)
}
pub fn iter(&self) -> impl Iterator<Item = (&Key<'text>, &Value<'text>)> {
self.inner.iter()
}
pub fn keys(&self) -> impl Iterator<Item = &str> {
self.inner.keys().map(|k| k.as_ref())
}
pub fn values(&self) -> impl Iterator<Item = &Value<'text>> {
self.inner.values()
}
pub fn contains_key(&self, key: &str) -> bool {
self.inner.contains_key(key)
}
pub fn get_mut(&mut self, key: &str) -> Option<&mut Value<'text>> {
self.inner.get_mut(key)
}
pub fn insert(
&mut self,
key: impl Into<Key<'text>>,
value: Value<'text>,
) -> Option<Value<'text>> {
self.inner.insert(key.into(), value)
}
pub fn remove(&mut self, key: &str) -> Option<Value<'text>> {
self.inner.shift_remove(key)
}
pub fn swap_remove(&mut self, key: &str) -> Option<Value<'text>> {
self.inner.swap_remove(key)
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Vdf<'text> {
key: Key<'text>,
value: Value<'text>,
}
impl<'text> Vdf<'text> {
pub fn new(key: impl Into<Key<'text>>, value: Value<'text>) -> Self {
Self {
key: key.into(),
value,
}
}
pub fn key(&self) -> &str {
&self.key
}
pub fn value(&self) -> &Value<'text> {
&self.value
}
pub fn value_mut(&mut self) -> &mut Value<'text> {
&mut self.value
}
pub fn into_parts(self) -> (Cow<'text, str>, Value<'text>) {
(self.key, self.value)
}
pub fn is_obj(&self) -> bool {
self.value.is_obj()
}
pub fn as_obj(&self) -> Option<&Obj<'text>> {
self.value.as_obj()
}
pub fn get(&self, key: &str) -> Option<&Value<'text>> {
self.value.get(key)
}
pub fn get_path(&self, path: &[&str]) -> Option<&Value<'text>> {
self.value.get_path(path)
}
pub fn get_str(&self, path: &[&str]) -> Option<&str> {
self.value.get_str(path)
}
pub fn get_obj(&self, path: &[&str]) -> Option<&Obj<'text>> {
self.value.get_obj(path)
}
pub fn get_i32(&self, path: &[&str]) -> Option<i32> {
self.value.get_i32(path)
}
pub fn get_u64(&self, path: &[&str]) -> Option<u64> {
self.value.get_u64(path)
}
pub fn get_float(&self, path: &[&str]) -> Option<f32> {
self.value.get_float(path)
}
}