use crate::resources::handles::GeometryHandle;
use crate::resources::storage::{BorrowedStringStorage, OwnedStringStorage, StringStorage};
use std::collections::HashMap;
use std::fmt::Debug;
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub enum AttributeValue<SS: StringStorage> {
Null,
Bool(bool),
Unsigned(u64),
Integer(i64),
Float(f64),
String(SS::String),
Vec(Vec<AttributeValue<SS>>),
Map(HashMap<SS::String, AttributeValue<SS>>),
Geometry(GeometryHandle),
}
impl<SS: StringStorage> std::fmt::Display for AttributeValue<SS>
where
SS::String: std::fmt::Display,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
AttributeValue::Null => write!(f, "null"),
AttributeValue::Bool(value) => write!(f, "{value}"),
AttributeValue::Unsigned(value) => write!(f, "{value}"),
AttributeValue::Integer(value) => write!(f, "{value}"),
AttributeValue::Float(value) => write!(f, "{value}"),
AttributeValue::String(value) => write!(f, "\"{value}\""),
AttributeValue::Vec(values) => {
write!(f, "[")?;
for (i, value) in values.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{value}")?;
}
write!(f, "]")
}
AttributeValue::Map(map) => {
write!(f, "{{")?;
for (i, (key, value)) in map.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "\"{key}\": {value}")?;
}
write!(f, "}}")
}
AttributeValue::Geometry(value) => write!(f, "Geometry({value})"),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Attributes<SS: StringStorage> {
values: HashMap<SS::String, AttributeValue<SS>>,
}
impl<SS: StringStorage> Attributes<SS> {
#[must_use]
pub fn new() -> Self {
Self {
values: HashMap::new(),
}
}
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self {
values: HashMap::with_capacity(capacity),
}
}
#[must_use]
pub fn get(&self, key: &str) -> Option<&AttributeValue<SS>> {
self.values.get(key)
}
pub fn get_mut(&mut self, key: &str) -> Option<&mut AttributeValue<SS>> {
self.values.get_mut(key)
}
pub fn insert(
&mut self,
key: SS::String,
value: AttributeValue<SS>,
) -> Option<AttributeValue<SS>> {
self.values.insert(key, value)
}
pub fn remove(&mut self, key: &str) -> Option<AttributeValue<SS>> {
self.values.remove(key)
}
#[must_use]
pub fn len(&self) -> usize {
self.values.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.values.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = (&SS::String, &AttributeValue<SS>)> {
self.values.iter()
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&SS::String, &mut AttributeValue<SS>)> {
self.values.iter_mut()
}
pub fn keys(&self) -> impl Iterator<Item = &SS::String> {
self.values.keys()
}
pub fn values(&self) -> impl Iterator<Item = &AttributeValue<SS>> {
self.values.values()
}
pub fn clear(&mut self) {
self.values.clear();
}
#[must_use]
pub fn contains_key(&self, key: &str) -> bool {
self.values.contains_key(key)
}
}
impl<SS: StringStorage> Default for Attributes<SS> {
fn default() -> Self {
Self::new()
}
}
impl<SS: StringStorage> From<HashMap<SS::String, AttributeValue<SS>>> for Attributes<SS> {
fn from(values: HashMap<SS::String, AttributeValue<SS>>) -> Self {
Self { values }
}
}
impl<SS: StringStorage> std::fmt::Display for Attributes<SS>
where
SS::String: std::fmt::Display + Eq + std::hash::Hash,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{{")?;
for (i, (key, value)) in self.values.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "\"{key}\": {value}")?;
}
write!(f, "}}")
}
}
pub type OwnedAttributeValue = AttributeValue<OwnedStringStorage>;
pub type BorrowedAttributeValue<'a> = AttributeValue<BorrowedStringStorage<'a>>;
pub type OwnedAttributes = Attributes<OwnedStringStorage>;
pub type BorrowedAttributes<'a> = Attributes<BorrowedStringStorage<'a>>;