Skip to main content

bacnet_types/enums/
object_type.rs

1// ===========================================================================
2// ObjectType (Clause 12)
3// ===========================================================================
4
5#[cfg(all(feature = "serde", not(feature = "std")))]
6use alloc::string::String;
7
8#[cfg(feature = "serde")]
9use serde::Deserialize;
10
11bacnet_enum! {
12    /// BACnet object types (Clause 12).
13    ///
14    /// Standard types are 0-63; vendor-proprietary types are 128-1023.
15    /// The 10-bit type field allows values 0-1023.
16    pub struct ObjectType(u32);
17
18    const ANALOG_INPUT = 0;
19    const ANALOG_OUTPUT = 1;
20    const ANALOG_VALUE = 2;
21    const BINARY_INPUT = 3;
22    const BINARY_OUTPUT = 4;
23    const BINARY_VALUE = 5;
24    const CALENDAR = 6;
25    const COMMAND = 7;
26    const DEVICE = 8;
27    const EVENT_ENROLLMENT = 9;
28    const FILE = 10;
29    const GROUP = 11;
30    const LOOP = 12;
31    const MULTI_STATE_INPUT = 13;
32    const MULTI_STATE_OUTPUT = 14;
33    const NOTIFICATION_CLASS = 15;
34    const PROGRAM = 16;
35    const SCHEDULE = 17;
36    const AVERAGING = 18;
37    const MULTI_STATE_VALUE = 19;
38    const TREND_LOG = 20;
39    const LIFE_SAFETY_POINT = 21;
40    const LIFE_SAFETY_ZONE = 22;
41    const ACCUMULATOR = 23;
42    const PULSE_CONVERTER = 24;
43    const EVENT_LOG = 25;
44    const GLOBAL_GROUP = 26;
45    const TREND_LOG_MULTIPLE = 27;
46    const LOAD_CONTROL = 28;
47    const STRUCTURED_VIEW = 29;
48    const ACCESS_DOOR = 30;
49    const TIMER = 31;
50    const ACCESS_CREDENTIAL = 32;
51    const ACCESS_POINT = 33;
52    const ACCESS_RIGHTS = 34;
53    const ACCESS_USER = 35;
54    const ACCESS_ZONE = 36;
55    const CREDENTIAL_DATA_INPUT = 37;
56    /// Deprecated in 135-2020 (Clause 24 deleted).
57    const NETWORK_SECURITY = 38;
58    const BITSTRING_VALUE = 39;
59    const CHARACTERSTRING_VALUE = 40;
60    const DATEPATTERN_VALUE = 41;
61    const DATE_VALUE = 42;
62    const DATETIMEPATTERN_VALUE = 43;
63    const DATETIME_VALUE = 44;
64    const INTEGER_VALUE = 45;
65    const LARGE_ANALOG_VALUE = 46;
66    const OCTETSTRING_VALUE = 47;
67    const POSITIVE_INTEGER_VALUE = 48;
68    const TIMEPATTERN_VALUE = 49;
69    const TIME_VALUE = 50;
70    const NOTIFICATION_FORWARDER = 51;
71    const ALERT_ENROLLMENT = 52;
72    const CHANNEL = 53;
73    const LIGHTING_OUTPUT = 54;
74    const BINARY_LIGHTING_OUTPUT = 55;
75    const NETWORK_PORT = 56;
76    const ELEVATOR_GROUP = 57;
77    const ESCALATOR = 58;
78    const LIFT = 59;
79    /// New in 135-2020.
80    const STAGING = 60;
81    /// New in 135-2020.
82    const AUDIT_LOG = 61;
83    /// New in 135-2020.
84    const AUDIT_REPORTER = 62;
85    /// New in 135-2020.
86    const COLOR = 63;
87    /// New in 135-2020.
88    const COLOR_TEMPERATURE = 64;
89}
90
91#[cfg(feature = "serde")]
92impl<'de> Deserialize<'de> for ObjectType {
93    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
94    where
95        D: serde::Deserializer<'de>,
96    {
97        let string: String = Deserialize::deserialize(deserializer)?;
98        string.parse().map_err(serde::de::Error::custom)
99    }
100}
101
102#[cfg(all(test, feature = "serde"))]
103mod serde_tests {
104    use super::ObjectType;
105
106    fn parse(input: &str) -> ObjectType {
107        serde_json::from_str(&format!("\"{input}\"")).expect("deserializes")
108    }
109
110    #[test]
111    fn accepts_every_supported_case_style() {
112        for input in [
113            "analoginput",
114            "ANALOGINPUT",
115            "AnalogInput",
116            "analogInput",
117            "analog_input",
118            "ANALOG_INPUT",
119            "analog-input",
120            "ANALOG-INPUT",
121        ] {
122            assert_eq!(parse(input), ObjectType::ANALOG_INPUT, "input: {input}");
123        }
124    }
125
126    #[test]
127    fn covers_the_full_standard_range() {
128        assert_eq!(parse("device"), ObjectType::DEVICE);
129        assert_eq!(parse("color-temperature"), ObjectType::COLOR_TEMPERATURE);
130    }
131
132    /// The hand-written name table this impl replaced still mapped
133    /// `audit-reporter` to 61 and `audit-log` to 62, contradicting the
134    /// constants (and Clause 21.6). Deriving names from `ALL_NAMED` keeps the
135    /// two from drifting apart again.
136    #[test]
137    fn audit_names_agree_with_the_constants() {
138        assert_eq!(parse("audit-log"), ObjectType::AUDIT_LOG);
139        assert_eq!(parse("audit-log").to_raw(), 61);
140        assert_eq!(parse("audit-reporter"), ObjectType::AUDIT_REPORTER);
141        assert_eq!(parse("audit-reporter").to_raw(), 62);
142    }
143
144    #[test]
145    fn rejects_unknown_names() {
146        assert!(serde_json::from_str::<ObjectType>("\"not-an-object\"").is_err());
147    }
148
149    #[test]
150    fn rejects_non_string_input() {
151        assert!(serde_json::from_str::<ObjectType>("8").is_err());
152    }
153}