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_member_resolved(
144 &mut self,
145 mut descriptor: MemberDescriptor,
146 member_type: DynamicType,
147 ) -> Result<(), DynamicError> {
148 if self.sealed.load(Ordering::Acquire) {
149 return Err(DynamicError::PreconditionNotMet(String::from(
150 "add_member after build()",
151 )));
152 }
153 if !self.descriptor.kind.is_aggregable() {
154 return Err(DynamicError::IllegalOperation(alloc::format!(
155 "add_member on non-composite kind {:?}",
156 self.descriptor.kind
157 )));
158 }
159 descriptor
160 .is_consistent()
161 .map_err(DynamicError::inconsistent)?;
162 if self
163 .members
164 .iter()
165 .any(|m| m.descriptor.name == descriptor.name)
166 {
167 return Err(DynamicError::builder(alloc::format!(
168 "duplicate member name {}",
169 descriptor.name
170 )));
171 }
172 if self
173 .members
174 .iter()
175 .any(|m| m.descriptor.id == descriptor.id)
176 {
177 return Err(DynamicError::builder(alloc::format!(
178 "duplicate member id {}",
179 descriptor.id
180 )));
181 }
182 let auto_index = u32::try_from(self.members.len()).unwrap_or(u32::MAX);
183 if descriptor.index == 0 && auto_index != 0 {
184 descriptor.index = auto_index;
185 }
186 self.members.push(DynamicTypeMember {
187 descriptor,
188 member_type,
189 });
190 Ok(())
191 }
192
193 pub fn add_struct_member(
198 &mut self,
199 name: impl Into<String>,
200 id: MemberId,
201 ty: TypeDescriptor,
202 ) -> Result<(), DynamicError> {
203 let mut d = MemberDescriptor::new(name, id, ty);
204 d.index = u32::try_from(self.members.len()).unwrap_or(u32::MAX);
205 self.add_member(d)
206 }
207
208 pub fn build(&self) -> Result<DynamicType, DynamicError> {
219 if self.sealed.swap(true, Ordering::AcqRel) {
220 return Err(DynamicError::PreconditionNotMet(String::from(
221 "build() called twice",
222 )));
223 }
224 self.descriptor
225 .is_consistent()
226 .map_err(DynamicError::inconsistent)?;
227 if let Some(b) = &self.descriptor.base_type {
229 check_inheritance_chain(&self.descriptor.name, b)?;
230 }
231 if self.descriptor.kind == TypeKind::Union {
233 if self.members.is_empty() {
234 return Err(DynamicError::builder(
235 "union without case members".to_string(),
236 ));
237 }
238 let mut seen_labels: BTreeMap<i64, &str> = BTreeMap::new();
239 let mut default_count = 0_u32;
240 for m in &self.members {
241 if m.descriptor.is_default_label {
242 default_count += 1;
243 }
244 for label in &m.descriptor.label {
245 if let Some(prev) = seen_labels.insert(*label, &m.descriptor.name) {
246 return Err(DynamicError::builder(alloc::format!(
247 "duplicate union label {label} (prev member: {prev})"
248 )));
249 }
250 }
251 }
252 if default_count > 1 {
253 return Err(DynamicError::builder(
254 "union with multiple default-label members",
255 ));
256 }
257 }
258 let inner = DynamicTypeInner {
259 descriptor: self.descriptor.clone(),
260 members: self.members.clone(),
261 };
262 Ok(DynamicType {
263 inner: Arc::new(inner),
264 })
265 }
266}
267
268fn check_inheritance_chain(self_name: &str, base: &TypeDescriptor) -> Result<(), DynamicError> {
271 let mut seen: alloc::vec::Vec<&str> = alloc::vec![self_name];
272 let mut cur = base;
273 let mut depth = 0_usize;
274 loop {
275 if depth >= 64 {
276 return Err(DynamicError::builder("inheritance chain exceeds 64 levels"));
277 }
278 if seen.iter().any(|n| *n == cur.name) {
279 return Err(DynamicError::builder(alloc::format!(
280 "inheritance cycle through '{}'",
281 cur.name
282 )));
283 }
284 seen.push(&cur.name);
285 depth += 1;
286 if let Some(b) = &cur.base_type {
287 cur = b;
288 } else {
289 return Ok(());
290 }
291 }
292}
293
294pub(super) fn descriptor_to_dynamic_type_inner(
300 desc: &TypeDescriptor,
301) -> Result<DynamicTypeInner, DynamicError> {
302 desc.is_consistent().map_err(DynamicError::inconsistent)?;
303 Ok(DynamicTypeInner {
304 descriptor: desc.clone(),
305 members: Vec::new(),
306 })
307}
308
309pub struct DynamicTypeBuilderFactory;
314
315impl DynamicTypeBuilderFactory {
316 pub fn create_type(descriptor: TypeDescriptor) -> Result<DynamicTypeBuilder, DynamicError> {
321 descriptor
322 .is_consistent()
323 .map_err(DynamicError::inconsistent)?;
324 Ok(DynamicTypeBuilder::new(descriptor))
325 }
326
327 #[must_use]
329 pub fn create_struct(name: impl Into<String>) -> DynamicTypeBuilder {
330 DynamicTypeBuilder::new(TypeDescriptor::structure(name))
331 }
332
333 pub fn create_union(
339 name: impl Into<String>,
340 discriminator: TypeDescriptor,
341 ) -> Result<DynamicTypeBuilder, DynamicError> {
342 let desc = TypeDescriptor::union(name, discriminator);
343 Self::create_type(desc)
344 }
345
346 pub fn get_primitive_type(kind: TypeKind) -> Result<DynamicType, DynamicError> {
354 if !kind.is_primitive() {
355 return Err(DynamicError::IllegalOperation(alloc::format!(
356 "get_primitive_type called with non-primitive {kind:?}"
357 )));
358 }
359 Ok(primitive_singleton(kind))
360 }
361
362 #[must_use]
364 pub fn create_string_type(bound: u32) -> DynamicType {
365 DynamicType::from_inner(DynamicTypeInner {
366 descriptor: TypeDescriptor::string8(bound),
367 members: Vec::new(),
368 })
369 }
370
371 #[must_use]
373 pub fn create_wstring_type(bound: u32) -> DynamicType {
374 DynamicType::from_inner(DynamicTypeInner {
375 descriptor: TypeDescriptor::string16(bound),
376 members: Vec::new(),
377 })
378 }
379}
380
381#[cfg(feature = "std")]
386fn primitive_singleton(kind: TypeKind) -> DynamicType {
387 use std::sync::OnceLock;
388 type Cell = OnceLock<DynamicType>;
389 macro_rules! cell {
390 () => {{
391 static C: Cell = OnceLock::new();
392 &C
393 }};
394 }
395 let cell: &Cell = match kind {
396 TypeKind::Boolean => cell!(),
397 TypeKind::Byte => cell!(),
398 TypeKind::Int8 => cell!(),
399 TypeKind::UInt8 => cell!(),
400 TypeKind::Int16 => cell!(),
401 TypeKind::UInt16 => cell!(),
402 TypeKind::Int32 => cell!(),
403 TypeKind::UInt32 => cell!(),
404 TypeKind::Int64 => cell!(),
405 TypeKind::UInt64 => cell!(),
406 TypeKind::Float32 => cell!(),
407 TypeKind::Float64 => cell!(),
408 TypeKind::Float128 => cell!(),
409 TypeKind::Char8 => cell!(),
410 TypeKind::Char16 => cell!(),
411 _ => {
415 return DynamicType::from_inner(DynamicTypeInner {
416 descriptor: TypeDescriptor::primitive(
417 kind,
418 alloc::string::String::from(primitive_name(kind)),
419 ),
420 members: Vec::new(),
421 });
422 }
423 };
424 cell.get_or_init(|| {
425 DynamicType::from_inner(DynamicTypeInner {
426 descriptor: TypeDescriptor::primitive(
427 kind,
428 alloc::string::String::from(primitive_name(kind)),
429 ),
430 members: Vec::new(),
431 })
432 })
433 .clone()
434}
435
436#[cfg(not(feature = "std"))]
437fn primitive_singleton(kind: TypeKind) -> DynamicType {
438 DynamicType::from_inner(DynamicTypeInner {
442 descriptor: TypeDescriptor::primitive(
443 kind,
444 alloc::string::String::from(primitive_name(kind)),
445 ),
446 members: Vec::new(),
447 })
448}
449
450#[cfg(test)]
451#[allow(clippy::unwrap_used)]
452mod tests {
453 use super::*;
454
455 #[test]
456 fn create_type_rejects_invalid_descriptor() {
457 let mut bad = TypeDescriptor::structure("");
458 bad.kind = TypeKind::Structure;
459 let err = DynamicTypeBuilderFactory::create_type(bad).unwrap_err();
460 assert!(matches!(err, DynamicError::Inconsistent(_)));
461 }
462
463 #[test]
464 fn add_member_rejects_duplicate_name() {
465 let mut b = DynamicTypeBuilderFactory::create_struct("::S");
466 b.add_struct_member("a", 1, TypeDescriptor::primitive(TypeKind::Int32, "int32"))
467 .unwrap();
468 let err = b
469 .add_struct_member("a", 2, TypeDescriptor::primitive(TypeKind::Int32, "int32"))
470 .unwrap_err();
471 assert!(matches!(err, DynamicError::BuilderConflict(_)));
472 }
473
474 #[test]
475 fn add_member_rejects_duplicate_id() {
476 let mut b = DynamicTypeBuilderFactory::create_struct("::S");
477 b.add_struct_member("a", 5, TypeDescriptor::primitive(TypeKind::Int32, "int32"))
478 .unwrap();
479 let err = b
480 .add_struct_member("b", 5, TypeDescriptor::primitive(TypeKind::Int32, "int32"))
481 .unwrap_err();
482 assert!(matches!(err, DynamicError::BuilderConflict(_)));
483 }
484
485 #[test]
486 fn add_member_on_primitive_is_illegal() {
487 let mut b = DynamicTypeBuilder::new(TypeDescriptor::primitive(TypeKind::Int32, "int32"));
488 let err = b
489 .add_struct_member("x", 1, TypeDescriptor::primitive(TypeKind::Int32, "int32"))
490 .unwrap_err();
491 assert!(matches!(err, DynamicError::IllegalOperation(_)));
492 }
493
494 #[test]
495 fn build_twice_rejected() {
496 let b = DynamicTypeBuilderFactory::create_struct("::S");
497 let _ = b.build().unwrap();
498 let err = b.build().unwrap_err();
499 assert!(matches!(err, DynamicError::PreconditionNotMet(_)));
500 }
501
502 #[test]
503 fn primitive_singleton_returns_same_arc() {
504 let a = DynamicTypeBuilderFactory::get_primitive_type(TypeKind::Int32).unwrap();
505 let b = DynamicTypeBuilderFactory::get_primitive_type(TypeKind::Int32).unwrap();
506 assert!(Arc::ptr_eq(&a.inner, &b.inner));
508 }
509
510 #[test]
511 fn primitive_singleton_rejects_non_primitive() {
512 assert!(matches!(
513 DynamicTypeBuilderFactory::get_primitive_type(TypeKind::Structure),
514 Err(DynamicError::IllegalOperation(_))
515 ));
516 }
517
518 #[test]
519 fn union_build_requires_at_least_one_member() {
520 let disc = TypeDescriptor::primitive(TypeKind::Int32, "int32");
521 let b = DynamicTypeBuilderFactory::create_union("::U", disc).unwrap();
522 let err = b.build().unwrap_err();
523 assert!(matches!(err, DynamicError::BuilderConflict(_)));
524 }
525
526 #[test]
527 fn union_duplicate_label_rejected() {
528 let disc = TypeDescriptor::primitive(TypeKind::Int32, "int32");
529 let mut b = DynamicTypeBuilderFactory::create_union("::U", disc).unwrap();
530 let mut a =
531 MemberDescriptor::new("a", 1, TypeDescriptor::primitive(TypeKind::Int32, "int32"));
532 a.label = alloc::vec![1, 2];
533 b.add_member(a).unwrap();
534 let mut c =
535 MemberDescriptor::new("c", 2, TypeDescriptor::primitive(TypeKind::Int32, "int32"));
536 c.label = alloc::vec![2, 3];
537 b.add_member(c).unwrap();
538 let err = b.build().unwrap_err();
539 assert!(matches!(err, DynamicError::BuilderConflict(_)));
540 }
541
542 #[test]
543 fn build_simple_struct_with_three_members() {
544 let mut b = DynamicTypeBuilderFactory::create_struct("::S");
545 b.add_struct_member("a", 1, TypeDescriptor::primitive(TypeKind::Int32, "int32"))
546 .unwrap();
547 b.add_struct_member("b", 2, TypeDescriptor::primitive(TypeKind::Int64, "int64"))
548 .unwrap();
549 b.add_struct_member("c", 3, TypeDescriptor::string8(64))
550 .unwrap();
551 let t = b.build().unwrap();
552 assert_eq!(t.member_count(), 3);
553 assert_eq!(t.member_by_name("b").unwrap().id(), 2);
554 assert_eq!(t.member_by_id(3).unwrap().name(), "c");
555 assert_eq!(t.member_by_index(0).unwrap().name(), "a");
556 }
557}