1use bacnet_types::enums::{ObjectType, PropertyIdentifier};
13use bacnet_types::error::Error;
14use bacnet_types::primitives::{Date, ObjectIdentifier, PropertyValue, StatusFlags, Time};
15use std::borrow::Cow;
16
17use crate::common::{self, read_common_properties};
18use crate::traits::BACnetObject;
19
20pub struct AccessDoorObject {
29 oid: ObjectIdentifier,
30 name: String,
31 description: String,
32 present_value: u32, door_status: u32, lock_status: u32, secured_status: u32, door_alarm_state: u32, door_members: Vec<ObjectIdentifier>,
38 status_flags: StatusFlags,
39 event_state: u32,
41 out_of_service: bool,
42 reliability: u32,
43 priority_array: [Option<u32>; 16],
45 relinquish_default: u32,
46}
47
48impl AccessDoorObject {
49 pub fn new(instance: u32, name: impl Into<String>) -> Result<Self, Error> {
51 let oid = ObjectIdentifier::new(ObjectType::ACCESS_DOOR, instance)?;
52 Ok(Self {
53 oid,
54 name: name.into(),
55 description: String::new(),
56 present_value: 0, door_status: 0, lock_status: 0,
59 secured_status: 0,
60 door_alarm_state: 0,
61 door_members: Vec::new(),
62 status_flags: StatusFlags::empty(),
63 event_state: 0, out_of_service: false,
65 reliability: 0,
66 priority_array: Default::default(),
67 relinquish_default: 0, })
69 }
70}
71
72impl BACnetObject for AccessDoorObject {
73 fn object_identifier(&self) -> ObjectIdentifier {
74 self.oid
75 }
76
77 fn object_name(&self) -> &str {
78 &self.name
79 }
80
81 fn read_property(
82 &self,
83 property: PropertyIdentifier,
84 array_index: Option<u32>,
85 ) -> Result<PropertyValue, Error> {
86 if let Some(result) = read_common_properties!(self, property, array_index) {
87 return result;
88 }
89 match property {
90 p if p == PropertyIdentifier::OBJECT_TYPE => {
91 Ok(PropertyValue::Enumerated(ObjectType::ACCESS_DOOR.to_raw()))
92 }
93 p if p == PropertyIdentifier::PRESENT_VALUE => {
94 Ok(PropertyValue::Enumerated(self.present_value))
95 }
96 p if p == PropertyIdentifier::DOOR_STATUS => {
97 Ok(PropertyValue::Enumerated(self.door_status))
98 }
99 p if p == PropertyIdentifier::LOCK_STATUS => {
100 Ok(PropertyValue::Enumerated(self.lock_status))
101 }
102 p if p == PropertyIdentifier::SECURED_STATUS => {
103 Ok(PropertyValue::Enumerated(self.secured_status))
104 }
105 p if p == PropertyIdentifier::DOOR_ALARM_STATE => {
106 Ok(PropertyValue::Enumerated(self.door_alarm_state))
107 }
108 p if p == PropertyIdentifier::DOOR_MEMBERS => Ok(PropertyValue::List(
109 self.door_members
110 .iter()
111 .map(|oid| PropertyValue::ObjectIdentifier(*oid))
112 .collect(),
113 )),
114 p if p == PropertyIdentifier::EVENT_STATE => {
115 Ok(PropertyValue::Enumerated(self.event_state))
116 }
117 p if p == PropertyIdentifier::PRIORITY_ARRAY => {
118 common::read_priority_array!(self, array_index, PropertyValue::Enumerated)
119 }
120 p if p == PropertyIdentifier::RELINQUISH_DEFAULT => {
121 Ok(PropertyValue::Enumerated(self.relinquish_default))
122 }
123 _ => Err(common::unknown_property_error()),
124 }
125 }
126
127 fn write_property(
128 &mut self,
129 property: PropertyIdentifier,
130 _array_index: Option<u32>,
131 value: PropertyValue,
132 priority: Option<u8>,
133 ) -> Result<(), Error> {
134 if let Some(result) =
135 common::write_out_of_service(&mut self.out_of_service, property, &value)
136 {
137 return result;
138 }
139 if let Some(result) = common::write_description(&mut self.description, property, &value) {
140 return result;
141 }
142 match property {
143 p if p == PropertyIdentifier::PRESENT_VALUE => {
144 let slot = priority.unwrap_or(16).clamp(1, 16) as usize - 1;
145 if let PropertyValue::Null = value {
146 self.priority_array[slot] = None;
148 } else if let PropertyValue::Enumerated(v) = value {
149 self.priority_array[slot] = Some(v);
150 } else if self.out_of_service {
151 if let PropertyValue::Enumerated(v) = value {
153 self.present_value = v;
154 return Ok(());
155 }
156 return Err(common::invalid_data_type_error());
157 } else {
158 return Err(common::invalid_data_type_error());
159 }
160 self.present_value = self
162 .priority_array
163 .iter()
164 .flatten()
165 .next()
166 .copied()
167 .unwrap_or(self.relinquish_default);
168 Ok(())
169 }
170 _ => Err(common::write_access_denied_error()),
171 }
172 }
173
174 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
175 static PROPS: &[PropertyIdentifier] = &[
176 PropertyIdentifier::OBJECT_IDENTIFIER,
177 PropertyIdentifier::OBJECT_NAME,
178 PropertyIdentifier::DESCRIPTION,
179 PropertyIdentifier::OBJECT_TYPE,
180 PropertyIdentifier::PRESENT_VALUE,
181 PropertyIdentifier::DOOR_STATUS,
182 PropertyIdentifier::LOCK_STATUS,
183 PropertyIdentifier::SECURED_STATUS,
184 PropertyIdentifier::DOOR_ALARM_STATE,
185 PropertyIdentifier::DOOR_MEMBERS,
186 PropertyIdentifier::STATUS_FLAGS,
187 PropertyIdentifier::OUT_OF_SERVICE,
188 PropertyIdentifier::RELIABILITY,
189 ];
190 Cow::Borrowed(PROPS)
191 }
192
193 fn supports_cov(&self) -> bool {
194 true
195 }
196}
197
198pub struct AccessCredentialObject {
207 oid: ObjectIdentifier,
208 name: String,
209 description: String,
210 present_value: u32, credential_status: u32,
212 assigned_access_rights_count: u32,
213 authentication_factors: Vec<Vec<u8>>,
214 status_flags: StatusFlags,
215 out_of_service: bool,
216 reliability: u32,
217}
218
219impl AccessCredentialObject {
220 pub fn new(instance: u32, name: impl Into<String>) -> Result<Self, Error> {
222 let oid = ObjectIdentifier::new(ObjectType::ACCESS_CREDENTIAL, instance)?;
223 Ok(Self {
224 oid,
225 name: name.into(),
226 description: String::new(),
227 present_value: 0, credential_status: 0,
229 assigned_access_rights_count: 0,
230 authentication_factors: Vec::new(),
231 status_flags: StatusFlags::empty(),
232 out_of_service: false,
233 reliability: 0,
234 })
235 }
236}
237
238impl BACnetObject for AccessCredentialObject {
239 fn object_identifier(&self) -> ObjectIdentifier {
240 self.oid
241 }
242
243 fn object_name(&self) -> &str {
244 &self.name
245 }
246
247 fn read_property(
248 &self,
249 property: PropertyIdentifier,
250 array_index: Option<u32>,
251 ) -> Result<PropertyValue, Error> {
252 if let Some(result) = read_common_properties!(self, property, array_index) {
253 return result;
254 }
255 match property {
256 p if p == PropertyIdentifier::OBJECT_TYPE => Ok(PropertyValue::Enumerated(
257 ObjectType::ACCESS_CREDENTIAL.to_raw(),
258 )),
259 p if p == PropertyIdentifier::PRESENT_VALUE => {
260 Ok(PropertyValue::Enumerated(self.present_value))
261 }
262 p if p == PropertyIdentifier::CREDENTIAL_STATUS => {
263 Ok(PropertyValue::Enumerated(self.credential_status))
264 }
265 p if p == PropertyIdentifier::ASSIGNED_ACCESS_RIGHTS => Ok(PropertyValue::Unsigned(
266 self.assigned_access_rights_count as u64,
267 )),
268 p if p == PropertyIdentifier::AUTHENTICATION_FACTORS => Ok(PropertyValue::List(
269 self.authentication_factors
270 .iter()
271 .map(|f| PropertyValue::OctetString(f.clone()))
272 .collect(),
273 )),
274 _ => Err(common::unknown_property_error()),
275 }
276 }
277
278 fn write_property(
279 &mut self,
280 property: PropertyIdentifier,
281 _array_index: Option<u32>,
282 value: PropertyValue,
283 _priority: Option<u8>,
284 ) -> Result<(), Error> {
285 if let Some(result) =
286 common::write_out_of_service(&mut self.out_of_service, property, &value)
287 {
288 return result;
289 }
290 if let Some(result) = common::write_description(&mut self.description, property, &value) {
291 return result;
292 }
293 match property {
294 p if p == PropertyIdentifier::PRESENT_VALUE => {
295 if let PropertyValue::Enumerated(v) = value {
296 self.present_value = v;
297 Ok(())
298 } else {
299 Err(common::invalid_data_type_error())
300 }
301 }
302 p if p == PropertyIdentifier::CREDENTIAL_STATUS => {
303 if let PropertyValue::Enumerated(v) = value {
304 self.credential_status = v;
305 Ok(())
306 } else {
307 Err(common::invalid_data_type_error())
308 }
309 }
310 _ => Err(common::write_access_denied_error()),
311 }
312 }
313
314 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
315 static PROPS: &[PropertyIdentifier] = &[
316 PropertyIdentifier::OBJECT_IDENTIFIER,
317 PropertyIdentifier::OBJECT_NAME,
318 PropertyIdentifier::DESCRIPTION,
319 PropertyIdentifier::OBJECT_TYPE,
320 PropertyIdentifier::PRESENT_VALUE,
321 PropertyIdentifier::CREDENTIAL_STATUS,
322 PropertyIdentifier::ASSIGNED_ACCESS_RIGHTS,
323 PropertyIdentifier::AUTHENTICATION_FACTORS,
324 PropertyIdentifier::STATUS_FLAGS,
325 PropertyIdentifier::OUT_OF_SERVICE,
326 PropertyIdentifier::RELIABILITY,
327 ];
328 Cow::Borrowed(PROPS)
329 }
330}
331
332pub struct AccessPointObject {
341 oid: ObjectIdentifier,
342 name: String,
343 description: String,
344 present_value: u32, access_event: u32,
346 access_event_tag: u64,
347 access_event_time: ([u8; 4], [u8; 4]), access_doors: Vec<ObjectIdentifier>,
349 event_state: u32,
350 status_flags: StatusFlags,
351 out_of_service: bool,
352 reliability: u32,
353}
354
355impl AccessPointObject {
356 pub fn new(instance: u32, name: impl Into<String>) -> Result<Self, Error> {
358 let oid = ObjectIdentifier::new(ObjectType::ACCESS_POINT, instance)?;
359 Ok(Self {
360 oid,
361 name: name.into(),
362 description: String::new(),
363 present_value: 0,
364 access_event: 0,
365 access_event_tag: 0,
366 access_event_time: ([0xFF, 0xFF, 0xFF, 0xFF], [0xFF, 0xFF, 0xFF, 0xFF]),
367 access_doors: Vec::new(),
368 event_state: 0,
369 status_flags: StatusFlags::empty(),
370 out_of_service: false,
371 reliability: 0,
372 })
373 }
374}
375
376impl BACnetObject for AccessPointObject {
377 fn object_identifier(&self) -> ObjectIdentifier {
378 self.oid
379 }
380
381 fn object_name(&self) -> &str {
382 &self.name
383 }
384
385 fn read_property(
386 &self,
387 property: PropertyIdentifier,
388 array_index: Option<u32>,
389 ) -> Result<PropertyValue, Error> {
390 if let Some(result) = read_common_properties!(self, property, array_index) {
391 return result;
392 }
393 match property {
394 p if p == PropertyIdentifier::OBJECT_TYPE => {
395 Ok(PropertyValue::Enumerated(ObjectType::ACCESS_POINT.to_raw()))
396 }
397 p if p == PropertyIdentifier::PRESENT_VALUE => {
398 Ok(PropertyValue::Enumerated(self.present_value))
399 }
400 p if p == PropertyIdentifier::ACCESS_EVENT => {
401 Ok(PropertyValue::Enumerated(self.access_event))
402 }
403 p if p == PropertyIdentifier::ACCESS_EVENT_TAG => {
404 Ok(PropertyValue::Unsigned(self.access_event_tag))
405 }
406 p if p == PropertyIdentifier::ACCESS_EVENT_TIME => {
407 let (d, t) = &self.access_event_time;
408 Ok(PropertyValue::List(vec![
409 PropertyValue::Date(Date {
410 year: d[0],
411 month: d[1],
412 day: d[2],
413 day_of_week: d[3],
414 }),
415 PropertyValue::Time(Time {
416 hour: t[0],
417 minute: t[1],
418 second: t[2],
419 hundredths: t[3],
420 }),
421 ]))
422 }
423 p if p == PropertyIdentifier::ACCESS_DOORS => Ok(PropertyValue::List(
424 self.access_doors
425 .iter()
426 .map(|oid| PropertyValue::ObjectIdentifier(*oid))
427 .collect(),
428 )),
429 p if p == PropertyIdentifier::EVENT_STATE => {
430 Ok(PropertyValue::Enumerated(self.event_state))
431 }
432 _ => Err(common::unknown_property_error()),
433 }
434 }
435
436 fn write_property(
437 &mut self,
438 property: PropertyIdentifier,
439 _array_index: Option<u32>,
440 value: PropertyValue,
441 _priority: Option<u8>,
442 ) -> Result<(), Error> {
443 if let Some(result) =
444 common::write_out_of_service(&mut self.out_of_service, property, &value)
445 {
446 return result;
447 }
448 if let Some(result) = common::write_description(&mut self.description, property, &value) {
449 return result;
450 }
451 match property {
452 p if p == PropertyIdentifier::PRESENT_VALUE => {
453 if let PropertyValue::Enumerated(v) = value {
454 self.present_value = v;
455 Ok(())
456 } else {
457 Err(common::invalid_data_type_error())
458 }
459 }
460 _ => Err(common::write_access_denied_error()),
461 }
462 }
463
464 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
465 static PROPS: &[PropertyIdentifier] = &[
466 PropertyIdentifier::OBJECT_IDENTIFIER,
467 PropertyIdentifier::OBJECT_NAME,
468 PropertyIdentifier::DESCRIPTION,
469 PropertyIdentifier::OBJECT_TYPE,
470 PropertyIdentifier::PRESENT_VALUE,
471 PropertyIdentifier::ACCESS_EVENT,
472 PropertyIdentifier::ACCESS_EVENT_TAG,
473 PropertyIdentifier::ACCESS_EVENT_TIME,
474 PropertyIdentifier::ACCESS_DOORS,
475 PropertyIdentifier::EVENT_STATE,
476 PropertyIdentifier::STATUS_FLAGS,
477 PropertyIdentifier::OUT_OF_SERVICE,
478 PropertyIdentifier::RELIABILITY,
479 ];
480 Cow::Borrowed(PROPS)
481 }
482}
483
484pub struct AccessRightsObject {
493 oid: ObjectIdentifier,
494 name: String,
495 description: String,
496 global_identifier: u64,
497 positive_access_rules_count: u32,
498 negative_access_rules_count: u32,
499 status_flags: StatusFlags,
500 out_of_service: bool,
501 reliability: u32,
502}
503
504impl AccessRightsObject {
505 pub fn new(instance: u32, name: impl Into<String>) -> Result<Self, Error> {
507 let oid = ObjectIdentifier::new(ObjectType::ACCESS_RIGHTS, instance)?;
508 Ok(Self {
509 oid,
510 name: name.into(),
511 description: String::new(),
512 global_identifier: 0,
513 positive_access_rules_count: 0,
514 negative_access_rules_count: 0,
515 status_flags: StatusFlags::empty(),
516 out_of_service: false,
517 reliability: 0,
518 })
519 }
520}
521
522impl BACnetObject for AccessRightsObject {
523 fn object_identifier(&self) -> ObjectIdentifier {
524 self.oid
525 }
526
527 fn object_name(&self) -> &str {
528 &self.name
529 }
530
531 fn read_property(
532 &self,
533 property: PropertyIdentifier,
534 array_index: Option<u32>,
535 ) -> Result<PropertyValue, Error> {
536 if let Some(result) = read_common_properties!(self, property, array_index) {
537 return result;
538 }
539 match property {
540 p if p == PropertyIdentifier::OBJECT_TYPE => Ok(PropertyValue::Enumerated(
541 ObjectType::ACCESS_RIGHTS.to_raw(),
542 )),
543 p if p == PropertyIdentifier::GLOBAL_IDENTIFIER => {
544 Ok(PropertyValue::Unsigned(self.global_identifier))
545 }
546 p if p == PropertyIdentifier::POSITIVE_ACCESS_RULES => Ok(PropertyValue::Unsigned(
547 self.positive_access_rules_count as u64,
548 )),
549 p if p == PropertyIdentifier::NEGATIVE_ACCESS_RULES => Ok(PropertyValue::Unsigned(
550 self.negative_access_rules_count as u64,
551 )),
552 _ => Err(common::unknown_property_error()),
553 }
554 }
555
556 fn write_property(
557 &mut self,
558 property: PropertyIdentifier,
559 _array_index: Option<u32>,
560 value: PropertyValue,
561 _priority: Option<u8>,
562 ) -> Result<(), Error> {
563 if let Some(result) =
564 common::write_out_of_service(&mut self.out_of_service, property, &value)
565 {
566 return result;
567 }
568 if let Some(result) = common::write_description(&mut self.description, property, &value) {
569 return result;
570 }
571 match property {
572 p if p == PropertyIdentifier::GLOBAL_IDENTIFIER => {
573 if let PropertyValue::Unsigned(v) = value {
574 self.global_identifier = v;
575 Ok(())
576 } else {
577 Err(common::invalid_data_type_error())
578 }
579 }
580 _ => Err(common::write_access_denied_error()),
581 }
582 }
583
584 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
585 static PROPS: &[PropertyIdentifier] = &[
586 PropertyIdentifier::OBJECT_IDENTIFIER,
587 PropertyIdentifier::OBJECT_NAME,
588 PropertyIdentifier::DESCRIPTION,
589 PropertyIdentifier::OBJECT_TYPE,
590 PropertyIdentifier::GLOBAL_IDENTIFIER,
591 PropertyIdentifier::POSITIVE_ACCESS_RULES,
592 PropertyIdentifier::NEGATIVE_ACCESS_RULES,
593 PropertyIdentifier::STATUS_FLAGS,
594 PropertyIdentifier::OUT_OF_SERVICE,
595 PropertyIdentifier::RELIABILITY,
596 ];
597 Cow::Borrowed(PROPS)
598 }
599}
600
601pub struct AccessUserObject {
610 oid: ObjectIdentifier,
611 name: String,
612 description: String,
613 present_value: u32, user_type: u32,
615 credentials: Vec<ObjectIdentifier>,
616 assigned_access_rights_count: u32,
617 status_flags: StatusFlags,
618 out_of_service: bool,
619 reliability: u32,
620}
621
622impl AccessUserObject {
623 pub fn new(instance: u32, name: impl Into<String>) -> Result<Self, Error> {
625 let oid = ObjectIdentifier::new(ObjectType::ACCESS_USER, instance)?;
626 Ok(Self {
627 oid,
628 name: name.into(),
629 description: String::new(),
630 present_value: 0,
631 user_type: 0,
632 credentials: Vec::new(),
633 assigned_access_rights_count: 0,
634 status_flags: StatusFlags::empty(),
635 out_of_service: false,
636 reliability: 0,
637 })
638 }
639}
640
641impl BACnetObject for AccessUserObject {
642 fn object_identifier(&self) -> ObjectIdentifier {
643 self.oid
644 }
645
646 fn object_name(&self) -> &str {
647 &self.name
648 }
649
650 fn read_property(
651 &self,
652 property: PropertyIdentifier,
653 array_index: Option<u32>,
654 ) -> Result<PropertyValue, Error> {
655 if let Some(result) = read_common_properties!(self, property, array_index) {
656 return result;
657 }
658 match property {
659 p if p == PropertyIdentifier::OBJECT_TYPE => {
660 Ok(PropertyValue::Enumerated(ObjectType::ACCESS_USER.to_raw()))
661 }
662 p if p == PropertyIdentifier::PRESENT_VALUE => {
663 Ok(PropertyValue::Enumerated(self.present_value))
664 }
665 p if p == PropertyIdentifier::USER_TYPE => {
666 Ok(PropertyValue::Enumerated(self.user_type))
667 }
668 p if p == PropertyIdentifier::CREDENTIALS => Ok(PropertyValue::List(
669 self.credentials
670 .iter()
671 .map(|oid| PropertyValue::ObjectIdentifier(*oid))
672 .collect(),
673 )),
674 p if p == PropertyIdentifier::ASSIGNED_ACCESS_RIGHTS => Ok(PropertyValue::Unsigned(
675 self.assigned_access_rights_count as u64,
676 )),
677 _ => Err(common::unknown_property_error()),
678 }
679 }
680
681 fn write_property(
682 &mut self,
683 property: PropertyIdentifier,
684 _array_index: Option<u32>,
685 value: PropertyValue,
686 _priority: Option<u8>,
687 ) -> Result<(), Error> {
688 if let Some(result) =
689 common::write_out_of_service(&mut self.out_of_service, property, &value)
690 {
691 return result;
692 }
693 if let Some(result) = common::write_description(&mut self.description, property, &value) {
694 return result;
695 }
696 match property {
697 p if p == PropertyIdentifier::PRESENT_VALUE => {
698 if let PropertyValue::Enumerated(v) = value {
699 self.present_value = v;
700 Ok(())
701 } else {
702 Err(common::invalid_data_type_error())
703 }
704 }
705 p if p == PropertyIdentifier::USER_TYPE => {
706 if let PropertyValue::Enumerated(v) = value {
707 self.user_type = v;
708 Ok(())
709 } else {
710 Err(common::invalid_data_type_error())
711 }
712 }
713 _ => Err(common::write_access_denied_error()),
714 }
715 }
716
717 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
718 static PROPS: &[PropertyIdentifier] = &[
719 PropertyIdentifier::OBJECT_IDENTIFIER,
720 PropertyIdentifier::OBJECT_NAME,
721 PropertyIdentifier::DESCRIPTION,
722 PropertyIdentifier::OBJECT_TYPE,
723 PropertyIdentifier::PRESENT_VALUE,
724 PropertyIdentifier::USER_TYPE,
725 PropertyIdentifier::CREDENTIALS,
726 PropertyIdentifier::ASSIGNED_ACCESS_RIGHTS,
727 PropertyIdentifier::STATUS_FLAGS,
728 PropertyIdentifier::OUT_OF_SERVICE,
729 PropertyIdentifier::RELIABILITY,
730 ];
731 Cow::Borrowed(PROPS)
732 }
733}
734
735pub struct AccessZoneObject {
744 oid: ObjectIdentifier,
745 name: String,
746 description: String,
747 present_value: u32, global_identifier: u64,
749 occupancy_count: u64,
750 access_doors: Vec<ObjectIdentifier>,
751 entry_points: Vec<ObjectIdentifier>,
752 exit_points: Vec<ObjectIdentifier>,
753 status_flags: StatusFlags,
754 out_of_service: bool,
755 reliability: u32,
756}
757
758impl AccessZoneObject {
759 pub fn new(instance: u32, name: impl Into<String>) -> Result<Self, Error> {
761 let oid = ObjectIdentifier::new(ObjectType::ACCESS_ZONE, instance)?;
762 Ok(Self {
763 oid,
764 name: name.into(),
765 description: String::new(),
766 present_value: 0,
767 global_identifier: 0,
768 occupancy_count: 0,
769 access_doors: Vec::new(),
770 entry_points: Vec::new(),
771 exit_points: Vec::new(),
772 status_flags: StatusFlags::empty(),
773 out_of_service: false,
774 reliability: 0,
775 })
776 }
777}
778
779impl BACnetObject for AccessZoneObject {
780 fn object_identifier(&self) -> ObjectIdentifier {
781 self.oid
782 }
783
784 fn object_name(&self) -> &str {
785 &self.name
786 }
787
788 fn read_property(
789 &self,
790 property: PropertyIdentifier,
791 array_index: Option<u32>,
792 ) -> Result<PropertyValue, Error> {
793 if let Some(result) = read_common_properties!(self, property, array_index) {
794 return result;
795 }
796 match property {
797 p if p == PropertyIdentifier::OBJECT_TYPE => {
798 Ok(PropertyValue::Enumerated(ObjectType::ACCESS_ZONE.to_raw()))
799 }
800 p if p == PropertyIdentifier::PRESENT_VALUE => {
801 Ok(PropertyValue::Enumerated(self.present_value))
802 }
803 p if p == PropertyIdentifier::GLOBAL_IDENTIFIER => {
804 Ok(PropertyValue::Unsigned(self.global_identifier))
805 }
806 p if p == PropertyIdentifier::OCCUPANCY_COUNT => {
807 Ok(PropertyValue::Unsigned(self.occupancy_count))
808 }
809 p if p == PropertyIdentifier::ACCESS_DOORS => Ok(PropertyValue::List(
810 self.access_doors
811 .iter()
812 .map(|oid| PropertyValue::ObjectIdentifier(*oid))
813 .collect(),
814 )),
815 p if p == PropertyIdentifier::ENTRY_POINTS => Ok(PropertyValue::List(
816 self.entry_points
817 .iter()
818 .map(|oid| PropertyValue::ObjectIdentifier(*oid))
819 .collect(),
820 )),
821 p if p == PropertyIdentifier::EXIT_POINTS => Ok(PropertyValue::List(
822 self.exit_points
823 .iter()
824 .map(|oid| PropertyValue::ObjectIdentifier(*oid))
825 .collect(),
826 )),
827 _ => Err(common::unknown_property_error()),
828 }
829 }
830
831 fn write_property(
832 &mut self,
833 property: PropertyIdentifier,
834 _array_index: Option<u32>,
835 value: PropertyValue,
836 _priority: Option<u8>,
837 ) -> Result<(), Error> {
838 if let Some(result) =
839 common::write_out_of_service(&mut self.out_of_service, property, &value)
840 {
841 return result;
842 }
843 if let Some(result) = common::write_description(&mut self.description, property, &value) {
844 return result;
845 }
846 match property {
847 p if p == PropertyIdentifier::PRESENT_VALUE => {
848 if let PropertyValue::Enumerated(v) = value {
849 self.present_value = v;
850 Ok(())
851 } else {
852 Err(common::invalid_data_type_error())
853 }
854 }
855 p if p == PropertyIdentifier::GLOBAL_IDENTIFIER => {
856 if let PropertyValue::Unsigned(v) = value {
857 self.global_identifier = v;
858 Ok(())
859 } else {
860 Err(common::invalid_data_type_error())
861 }
862 }
863 _ => Err(common::write_access_denied_error()),
864 }
865 }
866
867 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
868 static PROPS: &[PropertyIdentifier] = &[
869 PropertyIdentifier::OBJECT_IDENTIFIER,
870 PropertyIdentifier::OBJECT_NAME,
871 PropertyIdentifier::DESCRIPTION,
872 PropertyIdentifier::OBJECT_TYPE,
873 PropertyIdentifier::PRESENT_VALUE,
874 PropertyIdentifier::GLOBAL_IDENTIFIER,
875 PropertyIdentifier::OCCUPANCY_COUNT,
876 PropertyIdentifier::ACCESS_DOORS,
877 PropertyIdentifier::ENTRY_POINTS,
878 PropertyIdentifier::EXIT_POINTS,
879 PropertyIdentifier::STATUS_FLAGS,
880 PropertyIdentifier::OUT_OF_SERVICE,
881 PropertyIdentifier::RELIABILITY,
882 ];
883 Cow::Borrowed(PROPS)
884 }
885}
886
887pub struct CredentialDataInputObject {
896 oid: ObjectIdentifier,
897 name: String,
898 description: String,
899 present_value: u32, update_time: ([u8; 4], [u8; 4]), supported_formats: Vec<u64>,
902 supported_format_classes: Vec<u64>,
903 status_flags: StatusFlags,
904 out_of_service: bool,
905 reliability: u32,
906}
907
908impl CredentialDataInputObject {
909 pub fn new(instance: u32, name: impl Into<String>) -> Result<Self, Error> {
911 let oid = ObjectIdentifier::new(ObjectType::CREDENTIAL_DATA_INPUT, instance)?;
912 Ok(Self {
913 oid,
914 name: name.into(),
915 description: String::new(),
916 present_value: 0, update_time: ([0xFF, 0xFF, 0xFF, 0xFF], [0xFF, 0xFF, 0xFF, 0xFF]),
918 supported_formats: Vec::new(),
919 supported_format_classes: Vec::new(),
920 status_flags: StatusFlags::empty(),
921 out_of_service: false,
922 reliability: 0,
923 })
924 }
925}
926
927impl BACnetObject for CredentialDataInputObject {
928 fn object_identifier(&self) -> ObjectIdentifier {
929 self.oid
930 }
931
932 fn object_name(&self) -> &str {
933 &self.name
934 }
935
936 fn read_property(
937 &self,
938 property: PropertyIdentifier,
939 array_index: Option<u32>,
940 ) -> Result<PropertyValue, Error> {
941 if let Some(result) = read_common_properties!(self, property, array_index) {
942 return result;
943 }
944 match property {
945 p if p == PropertyIdentifier::OBJECT_TYPE => Ok(PropertyValue::Enumerated(
946 ObjectType::CREDENTIAL_DATA_INPUT.to_raw(),
947 )),
948 p if p == PropertyIdentifier::PRESENT_VALUE => {
949 Ok(PropertyValue::Enumerated(self.present_value))
950 }
951 p if p == PropertyIdentifier::UPDATE_TIME => {
952 let (d, t) = &self.update_time;
953 Ok(PropertyValue::List(vec![
954 PropertyValue::Date(Date {
955 year: d[0],
956 month: d[1],
957 day: d[2],
958 day_of_week: d[3],
959 }),
960 PropertyValue::Time(Time {
961 hour: t[0],
962 minute: t[1],
963 second: t[2],
964 hundredths: t[3],
965 }),
966 ]))
967 }
968 p if p == PropertyIdentifier::SUPPORTED_FORMATS => Ok(PropertyValue::List(
969 self.supported_formats
970 .iter()
971 .map(|v| PropertyValue::Unsigned(*v))
972 .collect(),
973 )),
974 p if p == PropertyIdentifier::SUPPORTED_FORMAT_CLASSES => Ok(PropertyValue::List(
975 self.supported_format_classes
976 .iter()
977 .map(|v| PropertyValue::Unsigned(*v))
978 .collect(),
979 )),
980 _ => Err(common::unknown_property_error()),
981 }
982 }
983
984 fn write_property(
985 &mut self,
986 property: PropertyIdentifier,
987 _array_index: Option<u32>,
988 value: PropertyValue,
989 _priority: Option<u8>,
990 ) -> Result<(), Error> {
991 if let Some(result) =
992 common::write_out_of_service(&mut self.out_of_service, property, &value)
993 {
994 return result;
995 }
996 if let Some(result) = common::write_description(&mut self.description, property, &value) {
997 return result;
998 }
999 Err(common::write_access_denied_error())
1001 }
1002
1003 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
1004 static PROPS: &[PropertyIdentifier] = &[
1005 PropertyIdentifier::OBJECT_IDENTIFIER,
1006 PropertyIdentifier::OBJECT_NAME,
1007 PropertyIdentifier::DESCRIPTION,
1008 PropertyIdentifier::OBJECT_TYPE,
1009 PropertyIdentifier::PRESENT_VALUE,
1010 PropertyIdentifier::UPDATE_TIME,
1011 PropertyIdentifier::SUPPORTED_FORMATS,
1012 PropertyIdentifier::SUPPORTED_FORMAT_CLASSES,
1013 PropertyIdentifier::STATUS_FLAGS,
1014 PropertyIdentifier::OUT_OF_SERVICE,
1015 PropertyIdentifier::RELIABILITY,
1016 ];
1017 Cow::Borrowed(PROPS)
1018 }
1019}
1020
1021#[cfg(test)]
1026mod tests {
1027 use super::*;
1028
1029 #[test]
1032 fn access_door_create_and_read_defaults() {
1033 let door = AccessDoorObject::new(1, "DOOR-1").unwrap();
1034 assert_eq!(door.object_name(), "DOOR-1");
1035 assert_eq!(
1036 door.read_property(PropertyIdentifier::PRESENT_VALUE, None)
1037 .unwrap(),
1038 PropertyValue::Enumerated(0) );
1040 }
1041
1042 #[test]
1043 fn access_door_object_type() {
1044 let door = AccessDoorObject::new(1, "DOOR-1").unwrap();
1045 assert_eq!(
1046 door.read_property(PropertyIdentifier::OBJECT_TYPE, None)
1047 .unwrap(),
1048 PropertyValue::Enumerated(ObjectType::ACCESS_DOOR.to_raw())
1049 );
1050 }
1051
1052 #[test]
1053 fn access_door_property_list() {
1054 let door = AccessDoorObject::new(1, "DOOR-1").unwrap();
1055 let list = door.property_list();
1056 assert!(list.contains(&PropertyIdentifier::PRESENT_VALUE));
1057 assert!(list.contains(&PropertyIdentifier::DOOR_STATUS));
1058 assert!(list.contains(&PropertyIdentifier::LOCK_STATUS));
1059 assert!(list.contains(&PropertyIdentifier::SECURED_STATUS));
1060 assert!(list.contains(&PropertyIdentifier::DOOR_ALARM_STATE));
1061 assert!(list.contains(&PropertyIdentifier::DOOR_MEMBERS));
1062 }
1063
1064 #[test]
1065 fn access_door_read_door_members_empty() {
1066 let door = AccessDoorObject::new(1, "DOOR-1").unwrap();
1067 assert_eq!(
1068 door.read_property(PropertyIdentifier::DOOR_MEMBERS, None)
1069 .unwrap(),
1070 PropertyValue::List(vec![])
1071 );
1072 }
1073
1074 #[test]
1075 fn access_door_write_present_value() {
1076 let mut door = AccessDoorObject::new(1, "DOOR-1").unwrap();
1077 door.write_property(
1079 PropertyIdentifier::OUT_OF_SERVICE,
1080 None,
1081 PropertyValue::Boolean(true),
1082 None,
1083 )
1084 .unwrap();
1085 door.write_property(
1086 PropertyIdentifier::PRESENT_VALUE,
1087 None,
1088 PropertyValue::Enumerated(1), None,
1090 )
1091 .unwrap();
1092 assert_eq!(
1093 door.read_property(PropertyIdentifier::PRESENT_VALUE, None)
1094 .unwrap(),
1095 PropertyValue::Enumerated(1)
1096 );
1097 }
1098
1099 #[test]
1100 fn access_door_write_present_value_commandable() {
1101 let mut door = AccessDoorObject::new(1, "DOOR-1").unwrap();
1102 let result = door.write_property(
1104 PropertyIdentifier::PRESENT_VALUE,
1105 None,
1106 PropertyValue::Enumerated(1), Some(16),
1108 );
1109 assert!(result.is_ok());
1110 let pv = door
1112 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
1113 .unwrap();
1114 assert_eq!(pv, PropertyValue::Enumerated(1));
1115 let result = door.write_property(
1117 PropertyIdentifier::PRESENT_VALUE,
1118 None,
1119 PropertyValue::Null,
1120 Some(16),
1121 );
1122 assert!(result.is_ok());
1123 let pv = door
1125 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
1126 .unwrap();
1127 assert_eq!(pv, PropertyValue::Enumerated(0));
1128 }
1129
1130 #[test]
1131 fn access_door_write_present_value_wrong_type() {
1132 let mut door = AccessDoorObject::new(1, "DOOR-1").unwrap();
1133 door.write_property(
1134 PropertyIdentifier::OUT_OF_SERVICE,
1135 None,
1136 PropertyValue::Boolean(true),
1137 None,
1138 )
1139 .unwrap();
1140 let result = door.write_property(
1141 PropertyIdentifier::PRESENT_VALUE,
1142 None,
1143 PropertyValue::Real(1.0),
1144 None,
1145 );
1146 assert!(result.is_err());
1147 }
1148
1149 #[test]
1152 fn access_credential_create_and_read_defaults() {
1153 let cred = AccessCredentialObject::new(1, "CRED-1").unwrap();
1154 assert_eq!(cred.object_name(), "CRED-1");
1155 assert_eq!(
1156 cred.read_property(PropertyIdentifier::PRESENT_VALUE, None)
1157 .unwrap(),
1158 PropertyValue::Enumerated(0) );
1160 }
1161
1162 #[test]
1163 fn access_credential_object_type() {
1164 let cred = AccessCredentialObject::new(1, "CRED-1").unwrap();
1165 assert_eq!(
1166 cred.read_property(PropertyIdentifier::OBJECT_TYPE, None)
1167 .unwrap(),
1168 PropertyValue::Enumerated(ObjectType::ACCESS_CREDENTIAL.to_raw())
1169 );
1170 }
1171
1172 #[test]
1173 fn access_credential_property_list() {
1174 let cred = AccessCredentialObject::new(1, "CRED-1").unwrap();
1175 let list = cred.property_list();
1176 assert!(list.contains(&PropertyIdentifier::PRESENT_VALUE));
1177 assert!(list.contains(&PropertyIdentifier::CREDENTIAL_STATUS));
1178 assert!(list.contains(&PropertyIdentifier::ASSIGNED_ACCESS_RIGHTS));
1179 assert!(list.contains(&PropertyIdentifier::AUTHENTICATION_FACTORS));
1180 }
1181
1182 #[test]
1183 fn access_credential_read_assigned_access_rights() {
1184 let cred = AccessCredentialObject::new(1, "CRED-1").unwrap();
1185 assert_eq!(
1186 cred.read_property(PropertyIdentifier::ASSIGNED_ACCESS_RIGHTS, None)
1187 .unwrap(),
1188 PropertyValue::Unsigned(0)
1189 );
1190 }
1191
1192 #[test]
1193 fn access_credential_read_authentication_factors() {
1194 let cred = AccessCredentialObject::new(1, "CRED-1").unwrap();
1195 assert_eq!(
1196 cred.read_property(PropertyIdentifier::AUTHENTICATION_FACTORS, None)
1197 .unwrap(),
1198 PropertyValue::List(vec![])
1199 );
1200 }
1201
1202 #[test]
1205 fn access_point_create_and_read_defaults() {
1206 let point = AccessPointObject::new(1, "AP-1").unwrap();
1207 assert_eq!(point.object_name(), "AP-1");
1208 assert_eq!(
1209 point
1210 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
1211 .unwrap(),
1212 PropertyValue::Enumerated(0)
1213 );
1214 }
1215
1216 #[test]
1217 fn access_point_object_type() {
1218 let point = AccessPointObject::new(1, "AP-1").unwrap();
1219 assert_eq!(
1220 point
1221 .read_property(PropertyIdentifier::OBJECT_TYPE, None)
1222 .unwrap(),
1223 PropertyValue::Enumerated(ObjectType::ACCESS_POINT.to_raw())
1224 );
1225 }
1226
1227 #[test]
1228 fn access_point_property_list() {
1229 let point = AccessPointObject::new(1, "AP-1").unwrap();
1230 let list = point.property_list();
1231 assert!(list.contains(&PropertyIdentifier::PRESENT_VALUE));
1232 assert!(list.contains(&PropertyIdentifier::ACCESS_EVENT));
1233 assert!(list.contains(&PropertyIdentifier::ACCESS_EVENT_TAG));
1234 assert!(list.contains(&PropertyIdentifier::ACCESS_EVENT_TIME));
1235 assert!(list.contains(&PropertyIdentifier::ACCESS_DOORS));
1236 assert!(list.contains(&PropertyIdentifier::EVENT_STATE));
1237 }
1238
1239 #[test]
1240 fn access_point_read_access_event_time() {
1241 let point = AccessPointObject::new(1, "AP-1").unwrap();
1242 let val = point
1243 .read_property(PropertyIdentifier::ACCESS_EVENT_TIME, None)
1244 .unwrap();
1245 match val {
1246 PropertyValue::List(items) => {
1247 assert_eq!(items.len(), 2);
1248 }
1249 other => panic!("expected List, got {other:?}"),
1250 }
1251 }
1252
1253 #[test]
1254 fn access_point_read_access_doors_empty() {
1255 let point = AccessPointObject::new(1, "AP-1").unwrap();
1256 assert_eq!(
1257 point
1258 .read_property(PropertyIdentifier::ACCESS_DOORS, None)
1259 .unwrap(),
1260 PropertyValue::List(vec![])
1261 );
1262 }
1263
1264 #[test]
1267 fn access_rights_create_and_read_defaults() {
1268 let rights = AccessRightsObject::new(1, "AR-1").unwrap();
1269 assert_eq!(rights.object_name(), "AR-1");
1270 assert_eq!(
1271 rights
1272 .read_property(PropertyIdentifier::GLOBAL_IDENTIFIER, None)
1273 .unwrap(),
1274 PropertyValue::Unsigned(0)
1275 );
1276 }
1277
1278 #[test]
1279 fn access_rights_object_type() {
1280 let rights = AccessRightsObject::new(1, "AR-1").unwrap();
1281 assert_eq!(
1282 rights
1283 .read_property(PropertyIdentifier::OBJECT_TYPE, None)
1284 .unwrap(),
1285 PropertyValue::Enumerated(ObjectType::ACCESS_RIGHTS.to_raw())
1286 );
1287 }
1288
1289 #[test]
1290 fn access_rights_property_list() {
1291 let rights = AccessRightsObject::new(1, "AR-1").unwrap();
1292 let list = rights.property_list();
1293 assert!(list.contains(&PropertyIdentifier::GLOBAL_IDENTIFIER));
1294 assert!(list.contains(&PropertyIdentifier::POSITIVE_ACCESS_RULES));
1295 assert!(list.contains(&PropertyIdentifier::NEGATIVE_ACCESS_RULES));
1296 }
1297
1298 #[test]
1299 fn access_rights_read_rules_counts() {
1300 let rights = AccessRightsObject::new(1, "AR-1").unwrap();
1301 assert_eq!(
1302 rights
1303 .read_property(PropertyIdentifier::POSITIVE_ACCESS_RULES, None)
1304 .unwrap(),
1305 PropertyValue::Unsigned(0)
1306 );
1307 assert_eq!(
1308 rights
1309 .read_property(PropertyIdentifier::NEGATIVE_ACCESS_RULES, None)
1310 .unwrap(),
1311 PropertyValue::Unsigned(0)
1312 );
1313 }
1314
1315 #[test]
1316 fn access_rights_write_global_identifier() {
1317 let mut rights = AccessRightsObject::new(1, "AR-1").unwrap();
1318 rights
1319 .write_property(
1320 PropertyIdentifier::GLOBAL_IDENTIFIER,
1321 None,
1322 PropertyValue::Unsigned(42),
1323 None,
1324 )
1325 .unwrap();
1326 assert_eq!(
1327 rights
1328 .read_property(PropertyIdentifier::GLOBAL_IDENTIFIER, None)
1329 .unwrap(),
1330 PropertyValue::Unsigned(42)
1331 );
1332 }
1333
1334 #[test]
1337 fn access_user_create_and_read_defaults() {
1338 let user = AccessUserObject::new(1, "USER-1").unwrap();
1339 assert_eq!(user.object_name(), "USER-1");
1340 assert_eq!(
1341 user.read_property(PropertyIdentifier::PRESENT_VALUE, None)
1342 .unwrap(),
1343 PropertyValue::Enumerated(0)
1344 );
1345 }
1346
1347 #[test]
1348 fn access_user_object_type() {
1349 let user = AccessUserObject::new(1, "USER-1").unwrap();
1350 assert_eq!(
1351 user.read_property(PropertyIdentifier::OBJECT_TYPE, None)
1352 .unwrap(),
1353 PropertyValue::Enumerated(ObjectType::ACCESS_USER.to_raw())
1354 );
1355 }
1356
1357 #[test]
1358 fn access_user_property_list() {
1359 let user = AccessUserObject::new(1, "USER-1").unwrap();
1360 let list = user.property_list();
1361 assert!(list.contains(&PropertyIdentifier::PRESENT_VALUE));
1362 assert!(list.contains(&PropertyIdentifier::USER_TYPE));
1363 assert!(list.contains(&PropertyIdentifier::CREDENTIALS));
1364 assert!(list.contains(&PropertyIdentifier::ASSIGNED_ACCESS_RIGHTS));
1365 }
1366
1367 #[test]
1368 fn access_user_read_credentials_empty() {
1369 let user = AccessUserObject::new(1, "USER-1").unwrap();
1370 assert_eq!(
1371 user.read_property(PropertyIdentifier::CREDENTIALS, None)
1372 .unwrap(),
1373 PropertyValue::List(vec![])
1374 );
1375 }
1376
1377 #[test]
1378 fn access_user_write_user_type() {
1379 let mut user = AccessUserObject::new(1, "USER-1").unwrap();
1380 user.write_property(
1381 PropertyIdentifier::USER_TYPE,
1382 None,
1383 PropertyValue::Enumerated(1),
1384 None,
1385 )
1386 .unwrap();
1387 assert_eq!(
1388 user.read_property(PropertyIdentifier::USER_TYPE, None)
1389 .unwrap(),
1390 PropertyValue::Enumerated(1)
1391 );
1392 }
1393
1394 #[test]
1397 fn access_zone_create_and_read_defaults() {
1398 let zone = AccessZoneObject::new(1, "ZONE-1").unwrap();
1399 assert_eq!(zone.object_name(), "ZONE-1");
1400 assert_eq!(
1401 zone.read_property(PropertyIdentifier::PRESENT_VALUE, None)
1402 .unwrap(),
1403 PropertyValue::Enumerated(0)
1404 );
1405 }
1406
1407 #[test]
1408 fn access_zone_object_type() {
1409 let zone = AccessZoneObject::new(1, "ZONE-1").unwrap();
1410 assert_eq!(
1411 zone.read_property(PropertyIdentifier::OBJECT_TYPE, None)
1412 .unwrap(),
1413 PropertyValue::Enumerated(ObjectType::ACCESS_ZONE.to_raw())
1414 );
1415 }
1416
1417 #[test]
1418 fn access_zone_property_list() {
1419 let zone = AccessZoneObject::new(1, "ZONE-1").unwrap();
1420 let list = zone.property_list();
1421 assert!(list.contains(&PropertyIdentifier::PRESENT_VALUE));
1422 assert!(list.contains(&PropertyIdentifier::GLOBAL_IDENTIFIER));
1423 assert!(list.contains(&PropertyIdentifier::OCCUPANCY_COUNT));
1424 assert!(list.contains(&PropertyIdentifier::ACCESS_DOORS));
1425 assert!(list.contains(&PropertyIdentifier::ENTRY_POINTS));
1426 assert!(list.contains(&PropertyIdentifier::EXIT_POINTS));
1427 }
1428
1429 #[test]
1430 fn access_zone_read_lists_empty() {
1431 let zone = AccessZoneObject::new(1, "ZONE-1").unwrap();
1432 assert_eq!(
1433 zone.read_property(PropertyIdentifier::ACCESS_DOORS, None)
1434 .unwrap(),
1435 PropertyValue::List(vec![])
1436 );
1437 assert_eq!(
1438 zone.read_property(PropertyIdentifier::ENTRY_POINTS, None)
1439 .unwrap(),
1440 PropertyValue::List(vec![])
1441 );
1442 assert_eq!(
1443 zone.read_property(PropertyIdentifier::EXIT_POINTS, None)
1444 .unwrap(),
1445 PropertyValue::List(vec![])
1446 );
1447 }
1448
1449 #[test]
1450 fn access_zone_read_occupancy_count() {
1451 let zone = AccessZoneObject::new(1, "ZONE-1").unwrap();
1452 assert_eq!(
1453 zone.read_property(PropertyIdentifier::OCCUPANCY_COUNT, None)
1454 .unwrap(),
1455 PropertyValue::Unsigned(0)
1456 );
1457 }
1458
1459 #[test]
1460 fn access_zone_write_global_identifier() {
1461 let mut zone = AccessZoneObject::new(1, "ZONE-1").unwrap();
1462 zone.write_property(
1463 PropertyIdentifier::GLOBAL_IDENTIFIER,
1464 None,
1465 PropertyValue::Unsigned(99),
1466 None,
1467 )
1468 .unwrap();
1469 assert_eq!(
1470 zone.read_property(PropertyIdentifier::GLOBAL_IDENTIFIER, None)
1471 .unwrap(),
1472 PropertyValue::Unsigned(99)
1473 );
1474 }
1475
1476 #[test]
1479 fn credential_data_input_create_and_read_defaults() {
1480 let cdi = CredentialDataInputObject::new(1, "CDI-1").unwrap();
1481 assert_eq!(cdi.object_name(), "CDI-1");
1482 assert_eq!(
1483 cdi.read_property(PropertyIdentifier::PRESENT_VALUE, None)
1484 .unwrap(),
1485 PropertyValue::Enumerated(0) );
1487 }
1488
1489 #[test]
1490 fn credential_data_input_object_type() {
1491 let cdi = CredentialDataInputObject::new(1, "CDI-1").unwrap();
1492 assert_eq!(
1493 cdi.read_property(PropertyIdentifier::OBJECT_TYPE, None)
1494 .unwrap(),
1495 PropertyValue::Enumerated(ObjectType::CREDENTIAL_DATA_INPUT.to_raw())
1496 );
1497 }
1498
1499 #[test]
1500 fn credential_data_input_property_list() {
1501 let cdi = CredentialDataInputObject::new(1, "CDI-1").unwrap();
1502 let list = cdi.property_list();
1503 assert!(list.contains(&PropertyIdentifier::PRESENT_VALUE));
1504 assert!(list.contains(&PropertyIdentifier::UPDATE_TIME));
1505 assert!(list.contains(&PropertyIdentifier::SUPPORTED_FORMATS));
1506 assert!(list.contains(&PropertyIdentifier::SUPPORTED_FORMAT_CLASSES));
1507 }
1508
1509 #[test]
1510 fn credential_data_input_read_update_time() {
1511 let cdi = CredentialDataInputObject::new(1, "CDI-1").unwrap();
1512 let val = cdi
1513 .read_property(PropertyIdentifier::UPDATE_TIME, None)
1514 .unwrap();
1515 match val {
1516 PropertyValue::List(items) => {
1517 assert_eq!(items.len(), 2);
1518 }
1519 other => panic!("expected List, got {other:?}"),
1520 }
1521 }
1522
1523 #[test]
1524 fn credential_data_input_read_supported_formats_empty() {
1525 let cdi = CredentialDataInputObject::new(1, "CDI-1").unwrap();
1526 assert_eq!(
1527 cdi.read_property(PropertyIdentifier::SUPPORTED_FORMATS, None)
1528 .unwrap(),
1529 PropertyValue::List(vec![])
1530 );
1531 }
1532
1533 #[test]
1534 fn credential_data_input_write_denied() {
1535 let mut cdi = CredentialDataInputObject::new(1, "CDI-1").unwrap();
1536 let result = cdi.write_property(
1537 PropertyIdentifier::PRESENT_VALUE,
1538 None,
1539 PropertyValue::Enumerated(1),
1540 None,
1541 );
1542 assert!(result.is_err());
1543 }
1544}