irox_types/
lib.rs

1// SPDX-License-Identifier: MIT
2// Copyright 2025 IROX Contributors
3//
4
5//!
6//! This module contains a rudimentary reflection/type system
7//!
8#![warn(clippy::alloc_instead_of_core)]
9#![warn(clippy::std_instead_of_alloc)]
10#![warn(clippy::std_instead_of_core)]
11#![no_std]
12#![cfg_attr(docsrs, feature(doc_cfg))]
13
14extern crate alloc;
15use alloc::string::String;
16use alloc::vec::Vec;
17
18mod num;
19mod primitive;
20mod schema;
21#[cfg(feature = "syn")]
22mod syn;
23
24use core::fmt::{Display, Formatter};
25use irox_enums_derive::{EnumIterItem, EnumName, EnumTryFromStr};
26
27pub use crate::num::*;
28pub use crate::primitive::*;
29pub use crate::schema::*;
30#[cfg(feature = "syn")]
31pub use crate::syn::*;
32
33///
34/// An enumeration to describe the type of a pseudo-primitve
35#[derive(Debug, Copy, Clone, Eq, PartialEq, EnumName)]
36pub enum PrimitiveType {
37    Primitive(Primitives),
38    Array(Primitives, usize),
39    DynamicallySized(VariableType),
40}
41
42impl PrimitiveType {
43    /// Returns the number of bytes required to encode/decode this value.  If dynamic, returns None.
44    #[must_use]
45    pub fn bytes_length(&self) -> Option<usize> {
46        match self {
47            PrimitiveType::Primitive(p) => Some(p.bytes_length()),
48            PrimitiveType::Array(p, l) => Some(p.bytes_length() * *l),
49            PrimitiveType::DynamicallySized(_) => None,
50        }
51    }
52}
53
54impl From<Primitives> for PrimitiveType {
55    fn from(value: Primitives) -> Self {
56        PrimitiveType::Primitive(value)
57    }
58}
59
60impl From<VariableType> for PrimitiveType {
61    fn from(value: VariableType) -> Self {
62        PrimitiveType::DynamicallySized(value)
63    }
64}
65
66///
67/// An enumeration to describe a variable-length type
68#[allow(non_camel_case_types)]
69#[derive(Debug, Copy, Clone, Eq, PartialEq, EnumName, EnumIterItem, EnumTryFromStr)]
70#[non_exhaustive]
71pub enum VariableType {
72    str,
73    u8_blob,
74    u16_blob,
75    u32_blob,
76    u64_blob,
77}
78
79///
80/// An enumeration to store the value of a dynamic/variable sized element
81#[allow(non_camel_case_types)]
82#[derive(Debug, Clone, Eq, PartialEq, EnumName)]
83#[non_exhaustive]
84pub enum DynamicallySizedValue {
85    /// A string
86    str(String),
87    /// A blob of u8 of max length 255 (u8)
88    u8_blob(Vec<u8>),
89    /// A blob of u8 of max length 65535 (u16)
90    u16_blob(Vec<u8>),
91    /// A blob of u8 of max length [`u32::MAX`] (u32)
92    u32_blob(Vec<u8>),
93    /// A blob of u8 of max length [`u64::MAX`] (u64)
94    u64_blob(Vec<u8>),
95}
96
97impl DynamicallySizedValue {
98    /// Returns the type of this primitive
99    #[must_use]
100    pub const fn primitive(&self) -> VariableType {
101        match self {
102            DynamicallySizedValue::str(_) => VariableType::str,
103            DynamicallySizedValue::u8_blob(_) => VariableType::u8_blob,
104            DynamicallySizedValue::u16_blob(_) => VariableType::u16_blob,
105            DynamicallySizedValue::u32_blob(_) => VariableType::u32_blob,
106            DynamicallySizedValue::u64_blob(_) => VariableType::u64_blob,
107        }
108    }
109}
110
111impl Display for DynamicallySizedValue {
112    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
113        match self {
114            DynamicallySizedValue::str(v) => write!(f, "{v}"),
115            DynamicallySizedValue::u8_blob(v)
116            | DynamicallySizedValue::u16_blob(v)
117            | DynamicallySizedValue::u32_blob(v)
118            | DynamicallySizedValue::u64_blob(v) => write!(f, "{}", String::from_utf8_lossy(v)),
119        }
120    }
121}
122
123impl From<DynamicallySizedValue> for VariableValue {
124    fn from(value: DynamicallySizedValue) -> Self {
125        VariableValue::DynamicallySized(value)
126    }
127}
128
129impl From<PrimitiveValue> for VariableValue {
130    fn from(value: PrimitiveValue) -> Self {
131        VariableValue::Primitive(value)
132    }
133}
134
135///
136/// A value type that can be either statically sized (primitive) or variably sized (dynamic)
137#[derive(Debug, Clone, PartialEq, EnumName)]
138pub enum VariableValue {
139    Primitive(PrimitiveValue),
140    DynamicallySized(DynamicallySizedValue),
141}
142
143impl Display for VariableValue {
144    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
145        match self {
146            VariableValue::Primitive(v) => write!(f, "{v}"),
147            VariableValue::DynamicallySized(v) => write!(f, "{v}"),
148        }
149    }
150}
151
152/// An element that has both a Name and a Type
153#[derive(Debug, Clone, PartialEq)]
154pub struct NamedVariable {
155    name: String,
156    ty: PrimitiveType,
157}
158
159impl NamedVariable {
160    #[must_use]
161    pub fn new(name: String, ty: PrimitiveType) -> Self {
162        Self { name, ty }
163    }
164
165    /// Returns the name of the field
166    #[must_use]
167    pub fn name(&self) -> &String {
168        &self.name
169    }
170
171    /// Returns the type of the field
172    #[must_use]
173    pub fn variable_type(&self) -> PrimitiveType {
174        self.ty
175    }
176}
177
178/// An element that has both a Name and a Type
179#[derive(Debug, Clone, PartialEq)]
180pub struct NamedVariableValue {
181    name: String,
182    value: VariableValue,
183}
184
185impl NamedVariableValue {
186    #[must_use]
187    pub fn new(name: String, value: VariableValue) -> NamedVariableValue {
188        NamedVariableValue { name, value }
189    }
190
191    /// Returns the name of this field
192    #[must_use]
193    pub fn name(&self) -> &String {
194        &self.name
195    }
196
197    /// Returns the stored value of the field
198    #[must_use]
199    pub fn value(&self) -> &VariableValue {
200        &self.value
201    }
202}
203
204impl From<NamedPrimitiveValue> for NamedVariableValue {
205    fn from(value: NamedPrimitiveValue) -> Self {
206        NamedVariableValue {
207            name: value.name,
208            value: VariableValue::Primitive(value.value),
209        }
210    }
211}