Skip to main content

cityjson_types/backend/default/
attributes.rs

1//! # Attributes
2//!
3//! Attribute storage for `CityJSON` objects.
4//!
5//! ## Architecture: Array of Structures (`AoS`)
6//!
7//! Each object owns its attributes directly as a key-value map, rather than
8//! referencing a global pool. This avoids the ownership issues that arise when
9//! attributes are pervasive across the data model (unlike geometries, which are
10//! scoped and pool-managed).
11//!
12//! ```rust
13//! use cityjson_types::v2_0::{OwnedAttributeValue, OwnedAttributes};
14//!
15//! let mut attrs = OwnedAttributes::new();
16//! attrs.insert("name".to_string(), OwnedAttributeValue::String("Building A".to_string()));
17//! attrs.insert("height".to_string(), OwnedAttributeValue::Float(25.5));
18//! ```
19
20use crate::resources::handles::GeometryHandle;
21use crate::resources::storage::{BorrowedStringStorage, OwnedStringStorage, StringStorage};
22use std::collections::HashMap;
23use std::fmt::Debug;
24
25/// Attribute value types for `CityJSON` objects.
26#[derive(Clone, Debug, PartialEq)]
27#[non_exhaustive]
28pub enum AttributeValue<SS: StringStorage> {
29    Null,
30    Bool(bool),
31    Unsigned(u64),
32    Integer(i64),
33    Float(f64),
34    String(SS::String),
35    Vec(Vec<AttributeValue<SS>>),
36    Map(HashMap<SS::String, AttributeValue<SS>>),
37    /// Geometry reference. Used for `address.location`, which must be a `MultiPoint`.
38    Geometry(GeometryHandle),
39}
40
41impl<SS: StringStorage> std::fmt::Display for AttributeValue<SS>
42where
43    SS::String: std::fmt::Display,
44{
45    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46        match self {
47            AttributeValue::Null => write!(f, "null"),
48            AttributeValue::Bool(value) => write!(f, "{value}"),
49            AttributeValue::Unsigned(value) => write!(f, "{value}"),
50            AttributeValue::Integer(value) => write!(f, "{value}"),
51            AttributeValue::Float(value) => write!(f, "{value}"),
52            AttributeValue::String(value) => write!(f, "\"{value}\""),
53            AttributeValue::Vec(values) => {
54                write!(f, "[")?;
55                for (i, value) in values.iter().enumerate() {
56                    if i > 0 {
57                        write!(f, ", ")?;
58                    }
59                    write!(f, "{value}")?;
60                }
61                write!(f, "]")
62            }
63            AttributeValue::Map(map) => {
64                write!(f, "{{")?;
65                for (i, (key, value)) in map.iter().enumerate() {
66                    if i > 0 {
67                        write!(f, ", ")?;
68                    }
69                    write!(f, "\"{key}\": {value}")?;
70                }
71                write!(f, "}}")
72            }
73            AttributeValue::Geometry(value) => write!(f, "Geometry({value})"),
74        }
75    }
76}
77
78/// Container for attributes using a specific storage strategy.
79///
80/// `Attributes` is a key-value store where keys are strings and values are
81/// `AttributeValue` instances. Each object owns its attributes directly.
82#[derive(Clone, Debug, PartialEq)]
83pub struct Attributes<SS: StringStorage> {
84    values: HashMap<SS::String, AttributeValue<SS>>,
85}
86
87impl<SS: StringStorage> Attributes<SS> {
88    /// Creates a new, empty attributes container.
89    #[must_use]
90    pub fn new() -> Self {
91        Self {
92            values: HashMap::new(),
93        }
94    }
95
96    /// Creates a new attributes container with space for at least `capacity` entries.
97    #[must_use]
98    pub fn with_capacity(capacity: usize) -> Self {
99        Self {
100            values: HashMap::with_capacity(capacity),
101        }
102    }
103
104    /// Retrieves a reference to the attribute value associated with the given key.
105    #[must_use]
106    pub fn get(&self, key: &str) -> Option<&AttributeValue<SS>> {
107        self.values.get(key)
108    }
109
110    /// Retrieves a mutable reference to the attribute value associated with the given key.
111    pub fn get_mut(&mut self, key: &str) -> Option<&mut AttributeValue<SS>> {
112        self.values.get_mut(key)
113    }
114
115    /// Inserts an attribute value with the specified key.
116    ///
117    /// If the key already existed, returns the previous value.
118    pub fn insert(
119        &mut self,
120        key: SS::String,
121        value: AttributeValue<SS>,
122    ) -> Option<AttributeValue<SS>> {
123        self.values.insert(key, value)
124    }
125
126    /// Removes an attribute with the specified key.
127    pub fn remove(&mut self, key: &str) -> Option<AttributeValue<SS>> {
128        self.values.remove(key)
129    }
130
131    /// Returns the number of attributes in the container.
132    #[must_use]
133    pub fn len(&self) -> usize {
134        self.values.len()
135    }
136
137    /// Checks if the attributes container is empty.
138    #[must_use]
139    pub fn is_empty(&self) -> bool {
140        self.values.is_empty()
141    }
142
143    /// Returns an iterator over the attributes' keys and values.
144    pub fn iter(&self) -> impl Iterator<Item = (&SS::String, &AttributeValue<SS>)> {
145        self.values.iter()
146    }
147
148    /// Returns a mutable iterator over the attributes' keys and values.
149    pub fn iter_mut(&mut self) -> impl Iterator<Item = (&SS::String, &mut AttributeValue<SS>)> {
150        self.values.iter_mut()
151    }
152
153    /// Returns an iterator over the attribute keys.
154    pub fn keys(&self) -> impl Iterator<Item = &SS::String> {
155        self.values.keys()
156    }
157
158    /// Returns an iterator over the attribute values.
159    pub fn values(&self) -> impl Iterator<Item = &AttributeValue<SS>> {
160        self.values.values()
161    }
162
163    /// Clears the attributes container.
164    pub fn clear(&mut self) {
165        self.values.clear();
166    }
167
168    /// Checks if the attributes container contains a key.
169    #[must_use]
170    pub fn contains_key(&self, key: &str) -> bool {
171        self.values.contains_key(key)
172    }
173}
174
175impl<SS: StringStorage> Default for Attributes<SS> {
176    fn default() -> Self {
177        Self::new()
178    }
179}
180
181impl<SS: StringStorage> From<HashMap<SS::String, AttributeValue<SS>>> for Attributes<SS> {
182    fn from(values: HashMap<SS::String, AttributeValue<SS>>) -> Self {
183        Self { values }
184    }
185}
186
187impl<SS: StringStorage> std::fmt::Display for Attributes<SS>
188where
189    SS::String: std::fmt::Display + Eq + std::hash::Hash,
190{
191    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
192        write!(f, "{{")?;
193        for (i, (key, value)) in self.values.iter().enumerate() {
194            if i > 0 {
195                write!(f, ", ")?;
196            }
197            write!(f, "\"{key}\": {value}")?;
198        }
199        write!(f, "}}")
200    }
201}
202
203/// Type alias for attribute values with owned strings.
204pub type OwnedAttributeValue = AttributeValue<OwnedStringStorage>;
205
206/// Type alias for attribute values with borrowed strings.
207pub type BorrowedAttributeValue<'a> = AttributeValue<BorrowedStringStorage<'a>>;
208
209/// Type alias for attributes container with owned strings.
210pub type OwnedAttributes = Attributes<OwnedStringStorage>;
211
212/// Type alias for attributes container with borrowed strings.
213pub type BorrowedAttributes<'a> = Attributes<BorrowedStringStorage<'a>>;