Skip to main content

sparkplug_b/
datatype.rs

1//! Sparkplug B data types (spec §6.4.16 “Data Types”, codes 0..=34).
2//!
3//! The integer codes are shared across the metric, DataSet-column, template-
4//! parameter, and property-value sub-domains; this single [`DataType`] models
5//! all of them and exposes classifiers (`is_basic`, `is_array`, …) instead of
6//! Tahu's four parallel enums.
7
8use crate::error::{Result, SparkplugError};
9
10/// A Sparkplug B data type code.
11///
12/// Values `1..=14` are the *basic* scalar types (valid as DataSet columns,
13/// template parameters, and property values). `15..=19` add UUID/DataSet/Bytes/
14/// File/Template. `20..=21` are property-value-only (`PropertySet`/list).
15/// `22..=34` are the array types.
16#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
17#[repr(i32)]
18#[allow(missing_docs)] // variant names are self-describing; documented as a group above
19pub enum DataType {
20    Unknown = 0,
21    Int8 = 1,
22    Int16 = 2,
23    Int32 = 3,
24    Int64 = 4,
25    UInt8 = 5,
26    UInt16 = 6,
27    UInt32 = 7,
28    UInt64 = 8,
29    Float = 9,
30    Double = 10,
31    Boolean = 11,
32    String = 12,
33    DateTime = 13,
34    Text = 14,
35    Uuid = 15,
36    DataSet = 16,
37    Bytes = 17,
38    File = 18,
39    Template = 19,
40    PropertySet = 20,
41    PropertySetList = 21,
42    Int8Array = 22,
43    Int16Array = 23,
44    Int32Array = 24,
45    Int64Array = 25,
46    UInt8Array = 26,
47    UInt16Array = 27,
48    UInt32Array = 28,
49    UInt64Array = 29,
50    FloatArray = 30,
51    DoubleArray = 31,
52    BooleanArray = 32,
53    StringArray = 33,
54    DateTimeArray = 34,
55}
56
57impl DataType {
58    /// The integer code as it appears on the wire (`datatype` field, an unsigned
59    /// 32-bit integer per `tck-id-payloads-metric-datatype-value-type`).
60    #[must_use]
61    pub const fn as_u32(self) -> u32 {
62        self as i32 as u32
63    }
64
65    /// Parse a wire datatype code, rejecting unknown values
66    /// (`tck-id-payloads-metric-datatype-value`).
67    ///
68    /// # Errors
69    /// Returns [`SparkplugError::UnknownDataType`] for codes outside `0..=34`.
70    pub const fn from_u32(v: u32) -> Result<Self> {
71        let ty = match v {
72            0 => Self::Unknown,
73            1 => Self::Int8,
74            2 => Self::Int16,
75            3 => Self::Int32,
76            4 => Self::Int64,
77            5 => Self::UInt8,
78            6 => Self::UInt16,
79            7 => Self::UInt32,
80            8 => Self::UInt64,
81            9 => Self::Float,
82            10 => Self::Double,
83            11 => Self::Boolean,
84            12 => Self::String,
85            13 => Self::DateTime,
86            14 => Self::Text,
87            15 => Self::Uuid,
88            16 => Self::DataSet,
89            17 => Self::Bytes,
90            18 => Self::File,
91            19 => Self::Template,
92            20 => Self::PropertySet,
93            21 => Self::PropertySetList,
94            22 => Self::Int8Array,
95            23 => Self::Int16Array,
96            24 => Self::Int32Array,
97            25 => Self::Int64Array,
98            26 => Self::UInt8Array,
99            27 => Self::UInt16Array,
100            28 => Self::UInt32Array,
101            29 => Self::UInt64Array,
102            30 => Self::FloatArray,
103            31 => Self::DoubleArray,
104            32 => Self::BooleanArray,
105            33 => Self::StringArray,
106            34 => Self::DateTimeArray,
107            other => return Err(SparkplugError::UnknownDataType(other)),
108        };
109        Ok(ty)
110    }
111
112    /// `true` for the basic scalar types `1..=14`, the only types permitted as
113    /// DataSet columns and template parameters (`tck-id-payloads-dataset-types-value`).
114    #[must_use]
115    pub const fn is_basic(self) -> bool {
116        matches!(self as i32, 1..=14)
117    }
118
119    /// `true` for the array types `22..=34`.
120    #[must_use]
121    pub const fn is_array(self) -> bool {
122        matches!(self as i32, 22..=34)
123    }
124
125    /// For numeric/temporal array types, the fixed little-endian element width
126    /// in bytes. `BooleanArray`/`StringArray` use special framing and return
127    /// `None`, as do non-array types.
128    #[must_use]
129    pub const fn array_element_width(self) -> Option<usize> {
130        let w = match self {
131            Self::Int8Array | Self::UInt8Array => 1,
132            Self::Int16Array | Self::UInt16Array => 2,
133            Self::Int32Array | Self::UInt32Array | Self::FloatArray => 4,
134            Self::Int64Array | Self::UInt64Array | Self::DoubleArray | Self::DateTimeArray => 8,
135            _ => return None,
136        };
137        Some(w)
138    }
139}