use std::{cell::RefCell, collections::HashMap, hash::Hash, rc::Rc}; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum ValueInner { Boolean(bool), Number(i64), String(String), Table(Table), } macro_rules! impl_from { ($as: ident, $from: ty) => { impl From<$from> for ValueInner { fn from(value: $from) -> Self { Self::$as(value.into()) } } }; (try $as: ident, $from: ty) => { impl TryFrom<$from> for ValueInner { type Error = ::std::num::TryFromIntError; fn try_from(value: $from) -> Result { Ok(Self::$as(value.try_into()?)) } } }; } impl_from!(Boolean, bool); impl_from!(try Number, isize); impl_from!(try Number, usize); impl_from!(try Number, i64); impl_from!(try Number, u64); impl_from!(Number, u32); impl_from!(Number, i32); impl_from!(String, String); impl_from!(String, &str); impl_from!(Table, Table); pub type Value = Option; #[derive(Debug, Clone, Default)] struct TableInner { content: HashMap, } #[derive(Debug, Clone, Default)] pub struct Table(Rc>); impl PartialEq for Table { fn eq(&self, other: &Self) -> bool { std::ptr::eq(self.0.as_ptr(), other.0.as_ptr()) } } impl Eq for Table {} impl Hash for Table { fn hash(&self, state: &mut H) { std::ptr::hash(self.0.as_ptr(), state) } } impl Table { pub fn get(&self, key: ValueInner) -> Value { self.0.borrow().content.get(&key).cloned() } pub fn set(&self, key: ValueInner, value: Value) { let mut this = self.0.borrow_mut(); if let Some(value) = value { this.content.insert(key, value); } else { this.content.remove(&key); } } }