use crate::ig::strings::{BoxedString, InlineString};
use crate::ig::symbols::{Symbol, SymbolMap};
pub const NODE_MAP_SIZE: usize = std::mem::size_of::<SymbolMap<Node>>();
#[derive(Debug, PartialEq)]
pub enum Node {
Empty,
Integer(i64),
BoxedString(BoxedString),
InlineString(InlineString),
Boolean(bool),
List(Vec<Node>),
Object(SymbolMap<Node>),
Symbol(Symbol),
}
impl Node {
pub fn allocated_size(&self) -> usize {
match self {
Node::BoxedString(str) => std::mem::size_of::<usize>() + str.len(),
Node::List(list) => {
let vector_size = list.capacity() * std::mem::size_of::<Node>();
let content_size: usize = list.iter().map(|node| node.allocated_size()).sum();
vector_size + content_size
}
Node::Object(map) => {
let vector_size =
map.capacity() * (std::mem::size_of::<Symbol>() + std::mem::size_of::<Node>());
let content_size: usize = map.entries().map(|node| node.1.allocated_size()).sum();
vector_size + content_size
}
_ => 0,
}
}
}
impl Default for Node {
fn default() -> Self {
Node::Empty
}
}
impl From<&str> for Node {
fn from(value: &str) -> Self {
if value.len() <= InlineString::MAX {
Node::InlineString(InlineString::from(value))
} else {
Node::BoxedString(BoxedString::from(value))
}
}
}
#[cfg(test)]
mod tests {
use crate::ig::node::Node;
use crate::ig::strings::{BoxedString, InlineString};
#[test]
fn nodes_are_empty_by_default() {
assert_eq!(Node::default(), Node::Empty);
}
#[test]
fn from_string_works() {
assert_eq!(
Node::from("Hello"),
Node::InlineString(InlineString::from("Hello"))
);
assert_eq!(
Node::from("X".repeat(64).as_str()),
Node::BoxedString(BoxedString::from("X".repeat(64).as_str()))
);
}
#[test]
fn allocated_size_works() {
assert_eq!(Node::Integer(1).allocated_size(), 0);
assert_eq!(Node::Boolean(true).allocated_size(), 0);
assert_eq!(
Node::InlineString(InlineString::from("Hello")).allocated_size(),
0
);
assert_eq!(
Node::BoxedString(BoxedString::from("Hello")).allocated_size(),
"Hello".len() + std::mem::size_of::<usize>()
);
}
}