1use alloc::collections::BTreeMap;
13use alloc::string::{String, ToString};
14use alloc::sync::Arc;
15use alloc::vec::Vec;
16use core::sync::atomic::{AtomicBool, Ordering};
17
18use super::descriptor::{MemberDescriptor, MemberId, TypeDescriptor, TypeKind};
19use super::error::DynamicError;
20use super::type_::{DynamicType, DynamicTypeInner, DynamicTypeMember, primitive_name};
21
22#[derive(Debug)]
24pub struct DynamicTypeBuilder {
25 descriptor: TypeDescriptor,
26 members: Vec<DynamicTypeMember>,
27 sealed: AtomicBool,
28}
29
30impl DynamicTypeBuilder {
31 pub(super) fn new(descriptor: TypeDescriptor) -> Self {
33 Self {
34 descriptor,
35 members: Vec::new(),
36 sealed: AtomicBool::new(false),
37 }
38 }
39
40 #[must_use]
42 pub fn descriptor(&self) -> &TypeDescriptor {
43 &self.descriptor
44 }
45
46 pub fn set_descriptor(&mut self, descriptor: TypeDescriptor) -> Result<(), DynamicError> {
52 if self.sealed.load(Ordering::Acquire) {
53 return Err(DynamicError::PreconditionNotMet(String::from(
54 "set_descriptor after build()",
55 )));
56 }
57 descriptor
58 .is_consistent()
59 .map_err(DynamicError::inconsistent)?;
60 self.descriptor = descriptor;
61 Ok(())
62 }
63
64 pub fn add_member(&mut self, mut descriptor: MemberDescriptor) -> Result<(), DynamicError> {
79 if self.sealed.load(Ordering::Acquire) {
80 return Err(DynamicError::PreconditionNotMet(String::from(
81 "add_member after build()",
82 )));
83 }
84 if !self.descriptor.kind.is_aggregable() {
85 return Err(DynamicError::IllegalOperation(alloc::format!(
86 "add_member on non-composite kind {:?}",
87 self.descriptor.kind
88 )));
89 }
90 descriptor
91 .is_consistent()
92 .map_err(DynamicError::inconsistent)?;
93
94 if self
96 .members
97 .iter()
98 .any(|m| m.descriptor.name == descriptor.name)
99 {
100 return Err(DynamicError::builder(alloc::format!(
101 "duplicate member name {}",
102 descriptor.name
103 )));
104 }
105 if self
107 .members
108 .iter()
109 .any(|m| m.descriptor.id == descriptor.id)
110 {
111 return Err(DynamicError::builder(alloc::format!(
112 "duplicate member id {}",
113 descriptor.id
114 )));
115 }
116 let auto_index = u32::try_from(self.members.len()).unwrap_or(u32::MAX);
118 if descriptor.index == 0 && auto_index != 0 {
119 descriptor.index = auto_index;
120 } else if descriptor.index == 0 {
121 descriptor.index = 0; }
123 let member_type =
125 DynamicType::from_inner(descriptor_to_dynamic_type_inner(&descriptor.member_type)?);
126 self.members.push(DynamicTypeMember {
127 descriptor,
128 member_type,
129 });
130 Ok(())
131 }
132
133 pub fn add_struct_member(
138 &mut self,
139 name: impl Into<String>,
140 id: MemberId,
141 ty: TypeDescriptor,
142 ) -> Result<(), DynamicError> {
143 let mut d = MemberDescriptor::new(name, id, ty);
144 d.index = u32::try_from(self.members.len()).unwrap_or(u32::MAX);
145 self.add_member(d)
146 }
147
148 pub fn build(&self) -> Result<DynamicType, DynamicError> {
159 if self.sealed.swap(true, Ordering::AcqRel) {
160 return Err(DynamicError::PreconditionNotMet(String::from(
161 "build() called twice",
162 )));
163 }
164 self.descriptor
165 .is_consistent()
166 .map_err(DynamicError::inconsistent)?;
167 if let Some(b) = &self.descriptor.base_type {
169 check_inheritance_chain(&self.descriptor.name, b)?;
170 }
171 if self.descriptor.kind == TypeKind::Union {
173 if self.members.is_empty() {
174 return Err(DynamicError::builder(
175 "union without case members".to_string(),
176 ));
177 }
178 let mut seen_labels: BTreeMap<i64, &str> = BTreeMap::new();
179 let mut default_count = 0_u32;
180 for m in &self.members {
181 if m.descriptor.is_default_label {
182 default_count += 1;
183 }
184 for label in &m.descriptor.label {
185 if let Some(prev) = seen_labels.insert(*label, &m.descriptor.name) {
186 return Err(DynamicError::builder(alloc::format!(
187 "duplicate union label {label} (prev member: {prev})"
188 )));
189 }
190 }
191 }
192 if default_count > 1 {
193 return Err(DynamicError::builder(
194 "union with multiple default-label members",
195 ));
196 }
197 }
198 let inner = DynamicTypeInner {
199 descriptor: self.descriptor.clone(),
200 members: self.members.clone(),
201 };
202 Ok(DynamicType {
203 inner: Arc::new(inner),
204 })
205 }
206}
207
208fn check_inheritance_chain(self_name: &str, base: &TypeDescriptor) -> Result<(), DynamicError> {
211 let mut seen: alloc::vec::Vec<&str> = alloc::vec![self_name];
212 let mut cur = base;
213 let mut depth = 0_usize;
214 loop {
215 if depth >= 64 {
216 return Err(DynamicError::builder("inheritance chain exceeds 64 levels"));
217 }
218 if seen.iter().any(|n| *n == cur.name) {
219 return Err(DynamicError::builder(alloc::format!(
220 "inheritance cycle through '{}'",
221 cur.name
222 )));
223 }
224 seen.push(&cur.name);
225 depth += 1;
226 if let Some(b) = &cur.base_type {
227 cur = b;
228 } else {
229 return Ok(());
230 }
231 }
232}
233
234pub(super) fn descriptor_to_dynamic_type_inner(
240 desc: &TypeDescriptor,
241) -> Result<DynamicTypeInner, DynamicError> {
242 desc.is_consistent().map_err(DynamicError::inconsistent)?;
243 Ok(DynamicTypeInner {
244 descriptor: desc.clone(),
245 members: Vec::new(),
246 })
247}
248
249pub struct DynamicTypeBuilderFactory;
254
255impl DynamicTypeBuilderFactory {
256 pub fn create_type(descriptor: TypeDescriptor) -> Result<DynamicTypeBuilder, DynamicError> {
261 descriptor
262 .is_consistent()
263 .map_err(DynamicError::inconsistent)?;
264 Ok(DynamicTypeBuilder::new(descriptor))
265 }
266
267 #[must_use]
269 pub fn create_struct(name: impl Into<String>) -> DynamicTypeBuilder {
270 DynamicTypeBuilder::new(TypeDescriptor::structure(name))
271 }
272
273 pub fn create_union(
279 name: impl Into<String>,
280 discriminator: TypeDescriptor,
281 ) -> Result<DynamicTypeBuilder, DynamicError> {
282 let desc = TypeDescriptor::union(name, discriminator);
283 Self::create_type(desc)
284 }
285
286 pub fn get_primitive_type(kind: TypeKind) -> Result<DynamicType, DynamicError> {
294 if !kind.is_primitive() {
295 return Err(DynamicError::IllegalOperation(alloc::format!(
296 "get_primitive_type called with non-primitive {kind:?}"
297 )));
298 }
299 Ok(primitive_singleton(kind))
300 }
301
302 #[must_use]
304 pub fn create_string_type(bound: u32) -> DynamicType {
305 DynamicType::from_inner(DynamicTypeInner {
306 descriptor: TypeDescriptor::string8(bound),
307 members: Vec::new(),
308 })
309 }
310
311 #[must_use]
313 pub fn create_wstring_type(bound: u32) -> DynamicType {
314 DynamicType::from_inner(DynamicTypeInner {
315 descriptor: TypeDescriptor::string16(bound),
316 members: Vec::new(),
317 })
318 }
319}
320
321#[cfg(feature = "std")]
326fn primitive_singleton(kind: TypeKind) -> DynamicType {
327 use std::sync::OnceLock;
328 type Cell = OnceLock<DynamicType>;
329 macro_rules! cell {
330 () => {{
331 static C: Cell = OnceLock::new();
332 &C
333 }};
334 }
335 let cell: &Cell = match kind {
336 TypeKind::Boolean => cell!(),
337 TypeKind::Byte => cell!(),
338 TypeKind::Int8 => cell!(),
339 TypeKind::UInt8 => cell!(),
340 TypeKind::Int16 => cell!(),
341 TypeKind::UInt16 => cell!(),
342 TypeKind::Int32 => cell!(),
343 TypeKind::UInt32 => cell!(),
344 TypeKind::Int64 => cell!(),
345 TypeKind::UInt64 => cell!(),
346 TypeKind::Float32 => cell!(),
347 TypeKind::Float64 => cell!(),
348 TypeKind::Float128 => cell!(),
349 TypeKind::Char8 => cell!(),
350 TypeKind::Char16 => cell!(),
351 _ => {
355 return DynamicType::from_inner(DynamicTypeInner {
356 descriptor: TypeDescriptor::primitive(
357 kind,
358 alloc::string::String::from(primitive_name(kind)),
359 ),
360 members: Vec::new(),
361 });
362 }
363 };
364 cell.get_or_init(|| {
365 DynamicType::from_inner(DynamicTypeInner {
366 descriptor: TypeDescriptor::primitive(
367 kind,
368 alloc::string::String::from(primitive_name(kind)),
369 ),
370 members: Vec::new(),
371 })
372 })
373 .clone()
374}
375
376#[cfg(not(feature = "std"))]
377fn primitive_singleton(kind: TypeKind) -> DynamicType {
378 DynamicType::from_inner(DynamicTypeInner {
382 descriptor: TypeDescriptor::primitive(
383 kind,
384 alloc::string::String::from(primitive_name(kind)),
385 ),
386 members: Vec::new(),
387 })
388}
389
390#[cfg(test)]
391#[allow(clippy::unwrap_used)]
392mod tests {
393 use super::*;
394
395 #[test]
396 fn create_type_rejects_invalid_descriptor() {
397 let mut bad = TypeDescriptor::structure("");
398 bad.kind = TypeKind::Structure;
399 let err = DynamicTypeBuilderFactory::create_type(bad).unwrap_err();
400 assert!(matches!(err, DynamicError::Inconsistent(_)));
401 }
402
403 #[test]
404 fn add_member_rejects_duplicate_name() {
405 let mut b = DynamicTypeBuilderFactory::create_struct("::S");
406 b.add_struct_member("a", 1, TypeDescriptor::primitive(TypeKind::Int32, "int32"))
407 .unwrap();
408 let err = b
409 .add_struct_member("a", 2, TypeDescriptor::primitive(TypeKind::Int32, "int32"))
410 .unwrap_err();
411 assert!(matches!(err, DynamicError::BuilderConflict(_)));
412 }
413
414 #[test]
415 fn add_member_rejects_duplicate_id() {
416 let mut b = DynamicTypeBuilderFactory::create_struct("::S");
417 b.add_struct_member("a", 5, TypeDescriptor::primitive(TypeKind::Int32, "int32"))
418 .unwrap();
419 let err = b
420 .add_struct_member("b", 5, TypeDescriptor::primitive(TypeKind::Int32, "int32"))
421 .unwrap_err();
422 assert!(matches!(err, DynamicError::BuilderConflict(_)));
423 }
424
425 #[test]
426 fn add_member_on_primitive_is_illegal() {
427 let mut b = DynamicTypeBuilder::new(TypeDescriptor::primitive(TypeKind::Int32, "int32"));
428 let err = b
429 .add_struct_member("x", 1, TypeDescriptor::primitive(TypeKind::Int32, "int32"))
430 .unwrap_err();
431 assert!(matches!(err, DynamicError::IllegalOperation(_)));
432 }
433
434 #[test]
435 fn build_twice_rejected() {
436 let b = DynamicTypeBuilderFactory::create_struct("::S");
437 let _ = b.build().unwrap();
438 let err = b.build().unwrap_err();
439 assert!(matches!(err, DynamicError::PreconditionNotMet(_)));
440 }
441
442 #[test]
443 fn primitive_singleton_returns_same_arc() {
444 let a = DynamicTypeBuilderFactory::get_primitive_type(TypeKind::Int32).unwrap();
445 let b = DynamicTypeBuilderFactory::get_primitive_type(TypeKind::Int32).unwrap();
446 assert!(Arc::ptr_eq(&a.inner, &b.inner));
448 }
449
450 #[test]
451 fn primitive_singleton_rejects_non_primitive() {
452 assert!(matches!(
453 DynamicTypeBuilderFactory::get_primitive_type(TypeKind::Structure),
454 Err(DynamicError::IllegalOperation(_))
455 ));
456 }
457
458 #[test]
459 fn union_build_requires_at_least_one_member() {
460 let disc = TypeDescriptor::primitive(TypeKind::Int32, "int32");
461 let b = DynamicTypeBuilderFactory::create_union("::U", disc).unwrap();
462 let err = b.build().unwrap_err();
463 assert!(matches!(err, DynamicError::BuilderConflict(_)));
464 }
465
466 #[test]
467 fn union_duplicate_label_rejected() {
468 let disc = TypeDescriptor::primitive(TypeKind::Int32, "int32");
469 let mut b = DynamicTypeBuilderFactory::create_union("::U", disc).unwrap();
470 let mut a =
471 MemberDescriptor::new("a", 1, TypeDescriptor::primitive(TypeKind::Int32, "int32"));
472 a.label = alloc::vec![1, 2];
473 b.add_member(a).unwrap();
474 let mut c =
475 MemberDescriptor::new("c", 2, TypeDescriptor::primitive(TypeKind::Int32, "int32"));
476 c.label = alloc::vec![2, 3];
477 b.add_member(c).unwrap();
478 let err = b.build().unwrap_err();
479 assert!(matches!(err, DynamicError::BuilderConflict(_)));
480 }
481
482 #[test]
483 fn build_simple_struct_with_three_members() {
484 let mut b = DynamicTypeBuilderFactory::create_struct("::S");
485 b.add_struct_member("a", 1, TypeDescriptor::primitive(TypeKind::Int32, "int32"))
486 .unwrap();
487 b.add_struct_member("b", 2, TypeDescriptor::primitive(TypeKind::Int64, "int64"))
488 .unwrap();
489 b.add_struct_member("c", 3, TypeDescriptor::string8(64))
490 .unwrap();
491 let t = b.build().unwrap();
492 assert_eq!(t.member_count(), 3);
493 assert_eq!(t.member_by_name("b").unwrap().id(), 2);
494 assert_eq!(t.member_by_id(3).unwrap().name(), "c");
495 assert_eq!(t.member_by_index(0).unwrap().name(), "a");
496 }
497}