zerodds_types/dynamic/
type_.rs1use alloc::string::String;
11use alloc::sync::Arc;
12use alloc::vec::Vec;
13
14use super::descriptor::{MemberDescriptor, MemberId, TypeDescriptor, TypeKind};
15use super::error::DynamicError;
16
17#[derive(Debug, Clone, PartialEq, Eq)]
22pub struct DynamicTypeMember {
23 pub(super) descriptor: MemberDescriptor,
24 pub(super) member_type: DynamicType,
25}
26
27impl DynamicTypeMember {
28 #[must_use]
30 pub fn descriptor(&self) -> &MemberDescriptor {
31 &self.descriptor
32 }
33
34 #[must_use]
36 pub fn name(&self) -> &str {
37 &self.descriptor.name
38 }
39
40 #[must_use]
42 pub fn id(&self) -> MemberId {
43 self.descriptor.id
44 }
45
46 #[must_use]
48 pub fn index(&self) -> u32 {
49 self.descriptor.index
50 }
51
52 #[must_use]
54 pub fn dynamic_type(&self) -> &DynamicType {
55 &self.member_type
56 }
57
58 #[must_use]
60 pub fn equals(&self, other: &Self) -> bool {
61 self.descriptor == other.descriptor && self.member_type.equals(&other.member_type)
62 }
63}
64
65#[derive(Debug)]
69pub(super) struct DynamicTypeInner {
70 pub(super) descriptor: TypeDescriptor,
71 pub(super) members: Vec<DynamicTypeMember>,
72}
73
74impl PartialEq for DynamicTypeInner {
75 fn eq(&self, other: &Self) -> bool {
76 self.descriptor == other.descriptor && self.members == other.members
77 }
78}
79
80impl Eq for DynamicTypeInner {}
81
82#[derive(Debug, Clone)]
88pub struct DynamicType {
89 pub(super) inner: Arc<DynamicTypeInner>,
90}
91
92impl PartialEq for DynamicType {
93 fn eq(&self, other: &Self) -> bool {
94 Arc::ptr_eq(&self.inner, &other.inner) || *self.inner == *other.inner
97 }
98}
99
100impl Eq for DynamicType {}
101
102impl DynamicType {
103 pub(super) fn from_inner(inner: DynamicTypeInner) -> Self {
104 Self {
105 inner: Arc::new(inner),
106 }
107 }
108
109 #[must_use]
111 pub fn name(&self) -> &str {
112 &self.inner.descriptor.name
113 }
114
115 #[must_use]
117 pub fn kind(&self) -> TypeKind {
118 self.inner.descriptor.kind
119 }
120
121 #[must_use]
123 pub fn descriptor(&self) -> &TypeDescriptor {
124 &self.inner.descriptor
125 }
126
127 #[must_use]
129 pub fn member_count(&self) -> u32 {
130 u32::try_from(self.inner.members.len()).unwrap_or(u32::MAX)
131 }
132
133 #[must_use]
135 pub fn member_by_index(&self, index: u32) -> Option<&DynamicTypeMember> {
136 self.inner.members.get(index as usize)
137 }
138
139 #[must_use]
141 pub fn member_by_id(&self, id: MemberId) -> Option<&DynamicTypeMember> {
142 self.inner.members.iter().find(|m| m.descriptor.id == id)
143 }
144
145 #[must_use]
147 pub fn member_by_name(&self, name: &str) -> Option<&DynamicTypeMember> {
148 self.inner
149 .members
150 .iter()
151 .find(|m| m.descriptor.name == name)
152 }
153
154 pub fn members(&self) -> impl Iterator<Item = &DynamicTypeMember> {
156 self.inner.members.iter()
157 }
158
159 #[must_use]
161 pub fn equals(&self, other: &Self) -> bool {
162 if Arc::ptr_eq(&self.inner, &other.inner) {
163 return true;
164 }
165 if self.inner.descriptor != other.inner.descriptor
166 || self.inner.members.len() != other.inner.members.len()
167 {
168 return false;
169 }
170 self.inner
171 .members
172 .iter()
173 .zip(other.inner.members.iter())
174 .all(|(a, b)| a.equals(b))
175 }
176
177 #[must_use]
179 pub fn is_aggregable(&self) -> bool {
180 self.kind().is_aggregable()
181 }
182
183 pub fn is_consistent(&self) -> Result<(), DynamicError> {
189 self.inner
190 .descriptor
191 .is_consistent()
192 .map_err(DynamicError::inconsistent)?;
193 for m in &self.inner.members {
194 m.descriptor
195 .is_consistent()
196 .map_err(DynamicError::inconsistent)?;
197 }
198 Ok(())
199 }
200
201 #[must_use]
207 pub fn new_primitive(kind: TypeKind) -> Self {
208 let name = primitive_name(kind);
209 Self::from_inner(DynamicTypeInner {
210 descriptor: TypeDescriptor::primitive(kind, String::from(name)),
211 members: Vec::new(),
212 })
213 }
214}
215
216pub(super) const fn primitive_name(kind: TypeKind) -> &'static str {
218 match kind {
219 TypeKind::Boolean => "boolean",
220 TypeKind::Byte => "octet",
221 TypeKind::Int8 => "int8",
222 TypeKind::UInt8 => "uint8",
223 TypeKind::Int16 => "int16",
224 TypeKind::UInt16 => "uint16",
225 TypeKind::Int32 => "int32",
226 TypeKind::UInt32 => "uint32",
227 TypeKind::Int64 => "int64",
228 TypeKind::UInt64 => "uint64",
229 TypeKind::Float32 => "float",
230 TypeKind::Float64 => "double",
231 TypeKind::Float128 => "long double",
232 TypeKind::Char8 => "char",
233 TypeKind::Char16 => "wchar",
234 _ => "<non-primitive>",
235 }
236}
237
238#[cfg(test)]
239#[allow(clippy::unwrap_used)]
240mod tests {
241 use super::*;
242
243 #[test]
244 fn primitive_dynamic_type_has_correct_kind_and_name() {
245 let t = DynamicType::new_primitive(TypeKind::Int32);
246 assert_eq!(t.kind(), TypeKind::Int32);
247 assert_eq!(t.name(), "int32");
248 assert_eq!(t.member_count(), 0);
249 }
250
251 #[test]
252 fn equals_is_reflexive_and_value_based() {
253 let a = DynamicType::new_primitive(TypeKind::Int32);
254 let b = DynamicType::new_primitive(TypeKind::Int32);
255 assert!(a.equals(&a));
256 assert!(a.equals(&b));
258 assert_eq!(a, b);
259 }
260
261 #[test]
262 fn equals_distinguishes_different_kinds() {
263 let a = DynamicType::new_primitive(TypeKind::Int32);
264 let b = DynamicType::new_primitive(TypeKind::Int64);
265 assert!(!a.equals(&b));
266 }
267}