1#[cfg(feature = "std")]
7use std::{
8 collections::HashMap,
9 sync::{Arc, RwLock},
10 time::Instant,
11};
12
13#[cfg(not(feature = "std"))]
14use alloc::{boxed::Box, collections::BTreeMap as HashMap, string::String, sync::Arc, vec::Vec};
15
16use super::{
17 BacnetObject, Device, ObjectError, ObjectIdentifier, ObjectType, PropertyIdentifier,
18 PropertyValue, Result,
19};
20
21#[cfg(feature = "std")]
23pub struct ObjectDatabase {
24 objects: Arc<RwLock<HashMap<ObjectIdentifier, Box<dyn BacnetObject>>>>,
26 type_index: Arc<RwLock<HashMap<ObjectType, Vec<ObjectIdentifier>>>>,
28 name_index: Arc<RwLock<HashMap<String, ObjectIdentifier>>>,
30 revision: Arc<RwLock<u32>>,
32 last_modified: Arc<RwLock<Instant>>,
34 device_id: ObjectIdentifier,
36}
37
38#[cfg(feature = "std")]
39impl ObjectDatabase {
40 pub fn new(device: Device) -> Self {
42 let device_id = device.identifier();
43 let mut objects = HashMap::new();
44 let mut type_index = HashMap::new();
45 let mut name_index = HashMap::new();
46
47 type_index
49 .entry(ObjectType::Device)
50 .or_insert_with(Vec::new)
51 .push(device_id);
52 name_index.insert(device.object_name.clone(), device_id);
53
54 objects.insert(device_id, Box::new(device) as Box<dyn BacnetObject>);
56
57 Self {
58 objects: Arc::new(RwLock::new(objects)),
59 type_index: Arc::new(RwLock::new(type_index)),
60 name_index: Arc::new(RwLock::new(name_index)),
61 revision: Arc::new(RwLock::new(1)),
62 last_modified: Arc::new(RwLock::new(Instant::now())),
63 device_id,
64 }
65 }
66
67 pub fn add_object(&self, object: Box<dyn BacnetObject>) -> Result<()> {
69 let identifier = object.identifier();
70
71 {
73 let objects = self.objects.read().unwrap();
74 if objects.contains_key(&identifier) {
75 return Err(ObjectError::InvalidConfiguration(format!(
76 "Object {} already exists",
77 identifier.instance
78 )));
79 }
80 }
81
82 let object_name = match object.get_property(PropertyIdentifier::ObjectName)? {
84 PropertyValue::CharacterString(name) => name,
85 _ => return Err(ObjectError::InvalidPropertyType),
86 };
87
88 {
90 let mut objects = self.objects.write().unwrap();
91 let mut type_index = self.type_index.write().unwrap();
92 let mut name_index = self.name_index.write().unwrap();
93
94 type_index
96 .entry(identifier.object_type)
97 .or_default()
98 .push(identifier);
99
100 name_index.insert(object_name, identifier);
102
103 objects.insert(identifier, object);
105
106 self.increment_revision();
108 }
109
110 Ok(())
111 }
112
113 pub fn remove_object(&self, identifier: ObjectIdentifier) -> Result<()> {
115 if identifier == self.device_id {
117 return Err(ObjectError::WriteAccessDenied);
118 }
119
120 let object_name = {
122 let objects = self.objects.read().unwrap();
123 match objects.get(&identifier) {
124 Some(obj) => match obj.get_property(PropertyIdentifier::ObjectName)? {
125 PropertyValue::CharacterString(name) => name,
126 _ => return Err(ObjectError::InvalidPropertyType),
127 },
128 None => return Err(ObjectError::NotFound),
129 }
130 };
131
132 {
134 let mut objects = self.objects.write().unwrap();
135 let mut type_index = self.type_index.write().unwrap();
136 let mut name_index = self.name_index.write().unwrap();
137
138 objects.remove(&identifier);
140
141 if let Some(type_list) = type_index.get_mut(&identifier.object_type) {
143 type_list.retain(|&id| id != identifier);
144 }
145
146 name_index.remove(&object_name);
148
149 self.increment_revision();
151 }
152
153 Ok(())
154 }
155
156 pub fn get_property(
158 &self,
159 identifier: ObjectIdentifier,
160 property: PropertyIdentifier,
161 ) -> Result<PropertyValue> {
162 let objects = self.objects.read().unwrap();
163 match objects.get(&identifier) {
164 Some(obj) => obj.get_property(property),
165 None => Err(ObjectError::NotFound),
166 }
167 }
168
169 pub fn set_property(
171 &self,
172 identifier: ObjectIdentifier,
173 property: PropertyIdentifier,
174 value: PropertyValue,
175 ) -> Result<()> {
176 let mut objects = self.objects.write().unwrap();
177 match objects.get_mut(&identifier) {
178 Some(obj) => {
179 let result = obj.set_property(property, value);
180 if result.is_ok() {
181 self.increment_revision();
182 }
183 result
184 }
185 None => Err(ObjectError::NotFound),
186 }
187 }
188
189 pub fn get_object_by_name(&self, name: &str) -> Result<ObjectIdentifier> {
191 let name_index = self.name_index.read().unwrap();
192 match name_index.get(name) {
193 Some(&identifier) => Ok(identifier),
194 None => Err(ObjectError::NotFound),
195 }
196 }
197
198 pub fn get_objects_by_type(&self, object_type: ObjectType) -> Vec<ObjectIdentifier> {
200 let type_index = self.type_index.read().unwrap();
201 type_index.get(&object_type).cloned().unwrap_or_default()
202 }
203
204 pub fn get_all_objects(&self) -> Vec<ObjectIdentifier> {
206 let objects = self.objects.read().unwrap();
207 objects.keys().cloned().collect()
208 }
209
210 pub fn object_count(&self) -> usize {
212 let objects = self.objects.read().unwrap();
213 objects.len()
214 }
215
216 pub fn object_count_by_type(&self, object_type: ObjectType) -> usize {
218 let type_index = self.type_index.read().unwrap();
219 type_index
220 .get(&object_type)
221 .map(|list| list.len())
222 .unwrap_or(0)
223 }
224
225 pub fn get_device_id(&self) -> ObjectIdentifier {
227 self.device_id
228 }
229
230 pub fn revision(&self) -> u32 {
232 *self.revision.read().unwrap()
233 }
234
235 pub fn last_modified(&self) -> Instant {
237 *self.last_modified.read().unwrap()
238 }
239
240 pub fn contains(&self, identifier: ObjectIdentifier) -> bool {
242 let objects = self.objects.read().unwrap();
243 objects.contains_key(&identifier)
244 }
245
246 pub fn contains_name(&self, name: &str) -> bool {
248 let name_index = self.name_index.read().unwrap();
249 name_index.contains_key(name)
250 }
251
252 pub fn next_instance(&self, object_type: ObjectType) -> u32 {
254 let type_index = self.type_index.read().unwrap();
255 if let Some(objects) = type_index.get(&object_type) {
256 let max_instance = objects.iter().map(|id| id.instance).max().unwrap_or(0);
257 max_instance.saturating_add(1)
258 } else {
259 0
260 }
261 }
262
263 pub fn search_by_property(
265 &self,
266 property: PropertyIdentifier,
267 value: &PropertyValue,
268 ) -> Vec<ObjectIdentifier> {
269 let objects = self.objects.read().unwrap();
270 let mut results = Vec::new();
271
272 for (&id, obj) in objects.iter() {
273 if let Ok(prop_value) = obj.get_property(property) {
274 if Self::property_values_equal(&prop_value, value) {
275 results.push(id);
276 }
277 }
278 }
279
280 results
281 }
282
283 fn property_values_equal(a: &PropertyValue, b: &PropertyValue) -> bool {
285 match (a, b) {
286 (PropertyValue::Null, PropertyValue::Null) => true,
287 (PropertyValue::Boolean(a), PropertyValue::Boolean(b)) => a == b,
288 (PropertyValue::UnsignedInteger(a), PropertyValue::UnsignedInteger(b)) => a == b,
289 (PropertyValue::SignedInt(a), PropertyValue::SignedInt(b)) => a == b,
290 (PropertyValue::Real(a), PropertyValue::Real(b)) => (a - b).abs() < f32::EPSILON,
291 (PropertyValue::Double(a), PropertyValue::Double(b)) => (a - b).abs() < f64::EPSILON,
292 (PropertyValue::CharacterString(a), PropertyValue::CharacterString(b)) => a == b,
293 (PropertyValue::Enumerated(a), PropertyValue::Enumerated(b)) => a == b,
294 (PropertyValue::ObjectIdentifier(a), PropertyValue::ObjectIdentifier(b)) => a == b,
295 _ => false,
296 }
297 }
298
299 fn increment_revision(&self) {
301 let mut revision = self.revision.write().unwrap();
302 *revision = revision.wrapping_add(1);
303
304 let mut last_modified = self.last_modified.write().unwrap();
305 *last_modified = Instant::now();
306 }
307
308 pub fn statistics(&self) -> DatabaseStatistics {
310 let objects = self.objects.read().unwrap();
311 let type_index = self.type_index.read().unwrap();
312
313 let mut type_counts = HashMap::new();
314 for (object_type, identifiers) in type_index.iter() {
315 type_counts.insert(*object_type, identifiers.len());
316 }
317
318 DatabaseStatistics {
319 total_objects: objects.len(),
320 object_types: type_index.len(),
321 type_counts,
322 revision: self.revision(),
323 last_modified: self.last_modified(),
324 }
325 }
326}
327
328#[cfg(feature = "std")]
330#[derive(Debug, Clone)]
331pub struct DatabaseStatistics {
332 pub total_objects: usize,
333 pub object_types: usize,
334 pub type_counts: HashMap<ObjectType, usize>,
335 pub revision: u32,
336 pub last_modified: Instant,
337}
338
339#[cfg(feature = "std")]
341#[derive(Default)]
342pub struct DatabaseBuilder {
343 device: Option<Device>,
344 objects: Vec<Box<dyn BacnetObject>>,
345}
346
347#[cfg(feature = "std")]
348impl DatabaseBuilder {
349 pub fn new() -> Self {
351 Self::default()
352 }
353
354 pub fn with_device(mut self, device: Device) -> Self {
356 self.device = Some(device);
357 self
358 }
359
360 pub fn add_object(mut self, object: Box<dyn BacnetObject>) -> Self {
362 self.objects.push(object);
363 self
364 }
365
366 pub fn build(self) -> Result<ObjectDatabase> {
368 let device = self.device.ok_or_else(|| {
369 ObjectError::InvalidConfiguration("Device object is required".to_string())
370 })?;
371
372 let database = ObjectDatabase::new(device);
373
374 for object in self.objects {
376 database.add_object(object)?;
377 }
378
379 Ok(database)
380 }
381}
382
383#[cfg(test)]
384mod tests {
385 use super::*;
386 use crate::object::{
387 analog::{AnalogInput, AnalogValue},
388 binary::BinaryInput,
389 };
390
391 #[test]
392 fn test_database_creation() {
393 let device = Device::new(1234, "Test Device".to_string());
394 let db = ObjectDatabase::new(device);
395
396 assert_eq!(db.object_count(), 1);
397 assert_eq!(db.revision(), 1);
398 assert!(db.contains(ObjectIdentifier::new(ObjectType::Device, 1234)));
399 }
400
401 #[test]
402 fn test_add_remove_objects() {
403 let device = Device::new(1234, "Test Device".to_string());
404 let db = ObjectDatabase::new(device);
405
406 let ai = AnalogInput::new(1, "Temperature".to_string());
408 db.add_object(Box::new(ai)).unwrap();
409
410 assert_eq!(db.object_count(), 2);
411 assert_eq!(db.object_count_by_type(ObjectType::AnalogInput), 1);
412
413 let bi = BinaryInput::new(1, "Door Sensor".to_string());
415 db.add_object(Box::new(bi)).unwrap();
416
417 assert_eq!(db.object_count(), 3);
418
419 let ai_id = ObjectIdentifier::new(ObjectType::AnalogInput, 1);
421 db.remove_object(ai_id).unwrap();
422
423 assert_eq!(db.object_count(), 2);
424 assert_eq!(db.object_count_by_type(ObjectType::AnalogInput), 0);
425 }
426
427 #[test]
428 fn test_object_lookup() {
429 let device = Device::new(1234, "Test Device".to_string());
430 let db = ObjectDatabase::new(device);
431
432 let av = AnalogValue::new(100, "Setpoint".to_string());
433 db.add_object(Box::new(av)).unwrap();
434
435 let av_id = ObjectIdentifier::new(ObjectType::AnalogValue, 100);
437 assert!(db.contains(av_id));
438
439 let found_id = db.get_object_by_name("Setpoint").unwrap();
441 assert_eq!(found_id, av_id);
442
443 let objects = db.get_objects_by_type(ObjectType::AnalogValue);
445 assert_eq!(objects.len(), 1);
446 assert_eq!(objects[0], av_id);
447 }
448
449 #[test]
450 fn test_property_search() {
451 let device = Device::new(1234, "Test Device".to_string());
452 let db = ObjectDatabase::new(device);
453
454 for i in 0..5 {
456 let mut av = AnalogValue::new(i, format!("AV{}", i));
457 av.present_value = 20.0 + i as f32;
458 db.add_object(Box::new(av)).unwrap();
459 }
460
461 let results =
463 db.search_by_property(PropertyIdentifier::PresentValue, &PropertyValue::Real(22.0));
464
465 assert_eq!(results.len(), 1);
466 assert_eq!(results[0].instance, 2);
467 }
468
469 #[test]
470 fn test_database_builder() {
471 let db = DatabaseBuilder::new()
472 .with_device(Device::new(5000, "Built Device".to_string()))
473 .add_object(Box::new(AnalogInput::new(1, "AI1".to_string())))
474 .add_object(Box::new(AnalogInput::new(2, "AI2".to_string())))
475 .add_object(Box::new(BinaryInput::new(1, "BI1".to_string())))
476 .build()
477 .unwrap();
478
479 assert_eq!(db.object_count(), 4); assert_eq!(db.object_count_by_type(ObjectType::AnalogInput), 2);
481 assert_eq!(db.object_count_by_type(ObjectType::BinaryInput), 1);
482 }
483
484 #[test]
485 fn test_next_instance() {
486 let device = Device::new(1234, "Test Device".to_string());
487 let db = ObjectDatabase::new(device);
488
489 assert_eq!(db.next_instance(ObjectType::AnalogInput), 0);
491
492 db.add_object(Box::new(AnalogInput::new(5, "AI5".to_string())))
494 .unwrap();
495 db.add_object(Box::new(AnalogInput::new(10, "AI10".to_string())))
496 .unwrap();
497 db.add_object(Box::new(AnalogInput::new(3, "AI3".to_string())))
498 .unwrap();
499
500 assert_eq!(db.next_instance(ObjectType::AnalogInput), 11);
502 }
503}