Skip to main content

ember_plus/glow/
element.rs

1//! Glow element types.
2
3use crate::error::{GlowError, Result};
4use crate::ber::{Tag, BerReader, BerWriter};
5use super::tags;
6
7/// Parameter type enumeration.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
9#[repr(i32)]
10pub enum ParameterType {
11    /// Null/unknown type
12    #[default]
13    Null = 0,
14    /// Integer parameter
15    Integer = 1,
16    /// Real (floating point) parameter
17    Real = 2,
18    /// String parameter
19    String = 3,
20    /// Boolean parameter
21    Boolean = 4,
22    /// Trigger (action) parameter
23    Trigger = 5,
24    /// Enumerated parameter
25    Enum = 6,
26    /// Octet string (binary data)
27    Octets = 7,
28}
29
30impl TryFrom<i64> for ParameterType {
31    type Error = GlowError;
32
33    fn try_from(value: i64) -> std::result::Result<Self, Self::Error> {
34        match value {
35            0 => Ok(ParameterType::Null),
36            1 => Ok(ParameterType::Integer),
37            2 => Ok(ParameterType::Real),
38            3 => Ok(ParameterType::String),
39            4 => Ok(ParameterType::Boolean),
40            5 => Ok(ParameterType::Trigger),
41            6 => Ok(ParameterType::Enum),
42            7 => Ok(ParameterType::Octets),
43            _ => Err(GlowError::InvalidField {
44                field: "ParameterType".to_string(),
45                details: format!("unknown type value: {}", value),
46            }),
47        }
48    }
49}
50
51/// Parameter access mode.
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
53#[repr(i32)]
54pub enum ParameterAccess {
55    /// No access
56    None = 0,
57    /// Read-only access
58    #[default]
59    Read = 1,
60    /// Write-only access
61    Write = 2,
62    /// Read-write access
63    ReadWrite = 3,
64}
65
66impl TryFrom<i64> for ParameterAccess {
67    type Error = GlowError;
68
69    fn try_from(value: i64) -> std::result::Result<Self, Self::Error> {
70        match value {
71            0 => Ok(ParameterAccess::None),
72            1 => Ok(ParameterAccess::Read),
73            2 => Ok(ParameterAccess::Write),
74            3 => Ok(ParameterAccess::ReadWrite),
75            _ => Err(GlowError::InvalidField {
76                field: "ParameterAccess".to_string(),
77                details: format!("unknown access value: {}", value),
78            }),
79        }
80    }
81}
82
83/// Matrix type.
84#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
85#[repr(i32)]
86pub enum MatrixType {
87    /// One-to-N matrix (one source to multiple targets)
88    #[default]
89    OneToN = 0,
90    /// One-to-one matrix
91    OneToOne = 1,
92    /// N-to-N matrix (any source to any target)
93    NToN = 2,
94}
95
96impl TryFrom<i64> for MatrixType {
97    type Error = GlowError;
98
99    fn try_from(value: i64) -> std::result::Result<Self, Self::Error> {
100        match value {
101            0 => Ok(MatrixType::OneToN),
102            1 => Ok(MatrixType::OneToOne),
103            2 => Ok(MatrixType::NToN),
104            _ => Err(GlowError::InvalidField {
105                field: "MatrixType".to_string(),
106                details: format!("unknown type value: {}", value),
107            }),
108        }
109    }
110}
111
112/// Matrix addressing mode.
113#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
114#[repr(i32)]
115pub enum MatrixAddressingMode {
116    /// Linear addressing (0 to count-1)
117    #[default]
118    Linear = 0,
119    /// Non-linear addressing (sparse)
120    NonLinear = 1,
121}
122
123impl TryFrom<i64> for MatrixAddressingMode {
124    type Error = GlowError;
125
126    fn try_from(value: i64) -> std::result::Result<Self, Self::Error> {
127        match value {
128            0 => Ok(MatrixAddressingMode::Linear),
129            1 => Ok(MatrixAddressingMode::NonLinear),
130            _ => Err(GlowError::InvalidField {
131                field: "MatrixAddressingMode".to_string(),
132                details: format!("unknown mode value: {}", value),
133            }),
134        }
135    }
136}
137
138/// Connection operation.
139#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
140#[repr(i32)]
141pub enum ConnectionOperation {
142    /// Absolute connection (replace)
143    #[default]
144    Absolute = 0,
145    /// Connect (add)
146    Connect = 1,
147    /// Disconnect (remove)
148    Disconnect = 2,
149}
150
151impl TryFrom<i64> for ConnectionOperation {
152    type Error = GlowError;
153
154    fn try_from(value: i64) -> std::result::Result<Self, Self::Error> {
155        match value {
156            0 => Ok(ConnectionOperation::Absolute),
157            1 => Ok(ConnectionOperation::Connect),
158            2 => Ok(ConnectionOperation::Disconnect),
159            _ => Err(GlowError::InvalidField {
160                field: "ConnectionOperation".to_string(),
161                details: format!("unknown operation value: {}", value),
162            }),
163        }
164    }
165}
166
167/// Connection disposition.
168#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
169#[repr(i32)]
170pub enum ConnectionDisposition {
171    /// Tally (feedback)
172    #[default]
173    Tally = 0,
174    /// Modified (needs update)
175    Modified = 1,
176    /// Pending (operation in progress)
177    Pending = 2,
178    /// Locked (cannot modify)
179    Locked = 3,
180}
181
182impl TryFrom<i64> for ConnectionDisposition {
183    type Error = GlowError;
184
185    fn try_from(value: i64) -> std::result::Result<Self, Self::Error> {
186        match value {
187            0 => Ok(ConnectionDisposition::Tally),
188            1 => Ok(ConnectionDisposition::Modified),
189            2 => Ok(ConnectionDisposition::Pending),
190            3 => Ok(ConnectionDisposition::Locked),
191            _ => Err(GlowError::InvalidField {
192                field: "ConnectionDisposition".to_string(),
193                details: format!("unknown disposition value: {}", value),
194            }),
195        }
196    }
197}
198
199/// A value that can be held by a parameter.
200#[derive(Debug, Clone, PartialEq)]
201pub enum EmberValue {
202    /// Integer value
203    Integer(i64),
204    /// Real (floating point) value
205    Real(f64),
206    /// String value
207    String(String),
208    /// Boolean value
209    Boolean(bool),
210    /// Octet string (binary data)
211    Octets(Vec<u8>),
212    /// Null/empty value
213    Null,
214}
215
216impl EmberValue {
217    /// Get as integer if possible.
218    pub fn as_integer(&self) -> Option<i64> {
219        match self {
220            EmberValue::Integer(v) => Some(*v),
221            EmberValue::Real(v) => Some(*v as i64),
222            EmberValue::Boolean(v) => Some(if *v { 1 } else { 0 }),
223            _ => None,
224        }
225    }
226
227    /// Get as real if possible.
228    pub fn as_real(&self) -> Option<f64> {
229        match self {
230            EmberValue::Integer(v) => Some(*v as f64),
231            EmberValue::Real(v) => Some(*v),
232            _ => None,
233        }
234    }
235
236    /// Get as string if possible.
237    pub fn as_string(&self) -> Option<&str> {
238        match self {
239            EmberValue::String(v) => Some(v),
240            _ => None,
241        }
242    }
243
244    /// Get as boolean if possible.
245    pub fn as_boolean(&self) -> Option<bool> {
246        match self {
247            EmberValue::Boolean(v) => Some(*v),
248            EmberValue::Integer(v) => Some(*v != 0),
249            _ => None,
250        }
251    }
252
253    /// Check if this value is null.
254    pub fn is_null(&self) -> bool {
255        matches!(self, EmberValue::Null)
256    }
257
258    /// Get the parameter type for this value.
259    pub fn parameter_type(&self) -> ParameterType {
260        match self {
261            EmberValue::Integer(_) => ParameterType::Integer,
262            EmberValue::Real(_) => ParameterType::Real,
263            EmberValue::String(_) => ParameterType::String,
264            EmberValue::Boolean(_) => ParameterType::Boolean,
265            EmberValue::Octets(_) => ParameterType::Octets,
266            EmberValue::Null => ParameterType::Null,
267        }
268    }
269}
270
271impl Default for EmberValue {
272    fn default() -> Self {
273        EmberValue::Null
274    }
275}
276
277impl From<i64> for EmberValue {
278    fn from(v: i64) -> Self {
279        EmberValue::Integer(v)
280    }
281}
282
283impl From<i32> for EmberValue {
284    fn from(v: i32) -> Self {
285        EmberValue::Integer(v as i64)
286    }
287}
288
289impl From<f64> for EmberValue {
290    fn from(v: f64) -> Self {
291        EmberValue::Real(v)
292    }
293}
294
295impl From<String> for EmberValue {
296    fn from(v: String) -> Self {
297        EmberValue::String(v)
298    }
299}
300
301impl From<&str> for EmberValue {
302    fn from(v: &str) -> Self {
303        EmberValue::String(v.to_string())
304    }
305}
306
307impl From<bool> for EmberValue {
308    fn from(v: bool) -> Self {
309        EmberValue::Boolean(v)
310    }
311}
312
313impl From<Vec<u8>> for EmberValue {
314    fn from(v: Vec<u8>) -> Self {
315        EmberValue::Octets(v)
316    }
317}
318
319impl std::fmt::Display for EmberValue {
320    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
321        match self {
322            EmberValue::Integer(v) => write!(f, "{}", v),
323            EmberValue::Real(v) => write!(f, "{}", v),
324            EmberValue::String(v) => write!(f, "{}", v),
325            EmberValue::Boolean(v) => write!(f, "{}", v),
326            EmberValue::Octets(v) => write!(f, "{:?}", v),
327            EmberValue::Null => write!(f, "null"),
328        }
329    }
330}
331
332/// Tuple item description (for function arguments/results).
333#[derive(Debug, Clone, PartialEq, Eq)]
334pub struct TupleItemDescription {
335    /// Item type
336    pub item_type: ParameterType,
337    /// Item name
338    pub name: Option<String>,
339}
340
341impl TupleItemDescription {
342    /// Create a new tuple item description.
343    pub fn new(item_type: ParameterType, name: Option<String>) -> Self {
344        TupleItemDescription { item_type, name }
345    }
346}
347
348/// Stream descriptor for streamed parameters.
349#[derive(Debug, Clone, PartialEq, Eq)]
350pub struct StreamDescriptor {
351    /// Stream format
352    pub format: StreamFormat,
353    /// Offset in stream
354    pub offset: i32,
355}
356
357/// Stream format.
358#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
359#[repr(i32)]
360pub enum StreamFormat {
361    /// Unsigned 8-bit integer
362    #[default]
363    UInt8 = 0,
364    /// Unsigned 16-bit integer (big-endian)
365    UInt16BigEndian = 2,
366    /// Unsigned 16-bit integer (little-endian)
367    UInt16LittleEndian = 3,
368    /// Unsigned 32-bit integer (big-endian)
369    UInt32BigEndian = 4,
370    /// Unsigned 32-bit integer (little-endian)
371    UInt32LittleEndian = 5,
372    /// Unsigned 64-bit integer (big-endian)
373    UInt64BigEndian = 6,
374    /// Unsigned 64-bit integer (little-endian)
375    UInt64LittleEndian = 7,
376    /// Signed 8-bit integer
377    Int8 = 8,
378    /// Signed 16-bit integer (big-endian)
379    Int16BigEndian = 10,
380    /// Signed 16-bit integer (little-endian)
381    Int16LittleEndian = 11,
382    /// Signed 32-bit integer (big-endian)
383    Int32BigEndian = 12,
384    /// Signed 32-bit integer (little-endian)
385    Int32LittleEndian = 13,
386    /// Signed 64-bit integer (big-endian)
387    Int64BigEndian = 14,
388    /// Signed 64-bit integer (little-endian)
389    Int64LittleEndian = 15,
390    /// 32-bit float (big-endian)
391    Float32BigEndian = 20,
392    /// 32-bit float (little-endian)
393    Float32LittleEndian = 21,
394    /// 64-bit float (big-endian)
395    Float64BigEndian = 22,
396    /// 64-bit float (little-endian)
397    Float64LittleEndian = 23,
398}
399
400impl TryFrom<i64> for StreamFormat {
401    type Error = GlowError;
402
403    fn try_from(value: i64) -> std::result::Result<Self, Self::Error> {
404        match value {
405            0 => Ok(StreamFormat::UInt8),
406            2 => Ok(StreamFormat::UInt16BigEndian),
407            3 => Ok(StreamFormat::UInt16LittleEndian),
408            4 => Ok(StreamFormat::UInt32BigEndian),
409            5 => Ok(StreamFormat::UInt32LittleEndian),
410            6 => Ok(StreamFormat::UInt64BigEndian),
411            7 => Ok(StreamFormat::UInt64LittleEndian),
412            8 => Ok(StreamFormat::Int8),
413            10 => Ok(StreamFormat::Int16BigEndian),
414            11 => Ok(StreamFormat::Int16LittleEndian),
415            12 => Ok(StreamFormat::Int32BigEndian),
416            13 => Ok(StreamFormat::Int32LittleEndian),
417            14 => Ok(StreamFormat::Int64BigEndian),
418            15 => Ok(StreamFormat::Int64LittleEndian),
419            20 => Ok(StreamFormat::Float32BigEndian),
420            21 => Ok(StreamFormat::Float32LittleEndian),
421            22 => Ok(StreamFormat::Float64BigEndian),
422            23 => Ok(StreamFormat::Float64LittleEndian),
423            _ => Err(GlowError::InvalidField {
424                field: "StreamFormat".to_string(),
425                details: format!("unknown format value: {}", value),
426            }),
427        }
428    }
429}
430
431/// String-integer entry for enumeration maps.
432#[derive(Debug, Clone, PartialEq, Eq)]
433pub struct StringIntegerPair {
434    /// String key
435    pub key: String,
436    /// Integer value
437    pub value: i64,
438}
439
440impl StringIntegerPair {
441    /// Create a new pair.
442    pub fn new(key: String, value: i64) -> Self {
443        StringIntegerPair { key, value }
444    }
445}
446
447/// Matrix label.
448#[derive(Debug, Clone, PartialEq, Eq)]
449pub struct Label {
450    /// Base path (relative OID)
451    pub base_path: Vec<u32>,
452    /// Description string
453    pub description: String,
454}
455
456impl Label {
457    /// Create a new label.
458    pub fn new(base_path: Vec<u32>, description: String) -> Self {
459        Label { base_path, description }
460    }
461}