1use alloc::string::String;
8use alloc::vec::Vec;
9
10use zerodds_cdr::{BufferReader, BufferWriter, DecodeError, EncodeError};
11
12use crate::type_identifier::TypeIdentifier;
13
14use super::flags::{StructMemberFlag, UnionMemberFlag};
15
16pub type MemberId = u32;
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
26pub struct NameHash(pub [u8; 4]);
27
28impl NameHash {
29 #[must_use]
34 pub fn from_name(name: &str) -> Self {
35 let digest = zerodds_foundation::md5(name.as_bytes());
36 let out: [u8; 4] = [digest[0], digest[1], digest[2], digest[3]];
37 Self(out)
38 }
39
40 pub fn encode_into(&self, w: &mut BufferWriter) -> Result<(), EncodeError> {
45 w.write_bytes(&self.0)
46 }
47
48 pub fn decode_from(r: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
53 let bytes = r.read_bytes(4)?;
54 let Ok(out): Result<[u8; 4], _> = bytes.try_into() else {
57 return Err(DecodeError::UnexpectedEof {
58 needed: 4,
59 offset: 0,
60 });
61 };
62 Ok(Self(out))
63 }
64}
65
66#[derive(Debug, Clone, PartialEq, Eq)]
68pub struct CommonStructMember {
69 pub member_id: MemberId,
71 pub member_flags: StructMemberFlag,
73 pub member_type_id: TypeIdentifier,
75}
76
77impl CommonStructMember {
78 pub fn encode_into(&self, w: &mut BufferWriter) -> Result<(), EncodeError> {
83 w.write_u32(self.member_id)?;
84 w.write_u16(self.member_flags.0)?;
85 self.member_type_id.encode_into(w)
86 }
87
88 pub fn decode_from(r: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
93 let member_id = r.read_u32()?;
94 let member_flags = StructMemberFlag(r.read_u16()?);
95 let member_type_id = TypeIdentifier::decode_from(r)?;
96 Ok(Self {
97 member_id,
98 member_flags,
99 member_type_id,
100 })
101 }
102}
103
104#[derive(Debug, Clone, PartialEq, Eq)]
106pub struct CommonUnionMember {
107 pub member_id: MemberId,
109 pub member_flags: UnionMemberFlag,
111 pub type_id: TypeIdentifier,
113 pub label_seq: alloc::vec::Vec<i32>,
115}
116
117impl CommonUnionMember {
118 pub fn encode_into(&self, w: &mut BufferWriter) -> Result<(), EncodeError> {
123 w.write_u32(self.member_id)?;
124 w.write_u16(self.member_flags.0)?;
125 self.type_id.encode_into(w)?;
126 let len =
128 u32::try_from(self.label_seq.len()).map_err(|_| EncodeError::ValueOutOfRange {
129 message: "union label sequence length exceeds u32::MAX",
130 })?;
131 w.write_u32(len)?;
132 for l in &self.label_seq {
133 w.write_u32(*l as u32)?;
134 }
135 Ok(())
136 }
137
138 pub fn decode_from(r: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
143 let member_id = r.read_u32()?;
144 let member_flags = UnionMemberFlag(r.read_u16()?);
145 let type_id = TypeIdentifier::decode_from(r)?;
146 let len = r.read_u32()? as usize;
147 let cap = safe_capacity(len, 4, r.remaining());
148 let mut label_seq = alloc::vec::Vec::with_capacity(cap);
149 for _ in 0..len {
150 label_seq.push(r.read_u32()? as i32);
151 }
152 Ok(Self {
153 member_id,
154 member_flags,
155 type_id,
156 label_seq,
157 })
158 }
159}
160
161pub type QualifiedTypeName = String;
168
169#[derive(Debug, Clone, PartialEq, Eq)]
171pub enum VerbatimPlacement {
172 Before,
174 After,
176 BeginFile,
178 EndFile,
180 Other(String),
182}
183
184#[derive(Debug, Clone, PartialEq, Eq)]
186pub struct AppliedVerbatimAnnotation {
187 pub placement: VerbatimPlacement,
189 pub language: String,
191 pub text: String,
193}
194
195impl AppliedVerbatimAnnotation {
196 fn encode_into(&self, w: &mut BufferWriter) -> Result<(), EncodeError> {
197 let placement_str = match &self.placement {
198 VerbatimPlacement::Before => "BEFORE_DECLARATION",
199 VerbatimPlacement::After => "AFTER_DECLARATION",
200 VerbatimPlacement::BeginFile => "BEGIN_FILE",
201 VerbatimPlacement::EndFile => "END_FILE",
202 VerbatimPlacement::Other(s) => s.as_str(),
203 };
204 w.write_string(placement_str)?;
205 w.write_string(&self.language)?;
206 w.write_string(&self.text)
207 }
208
209 fn decode_from(r: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
210 let placement_str = r.read_string()?;
211 let placement = match placement_str.as_str() {
212 "BEFORE_DECLARATION" => VerbatimPlacement::Before,
213 "AFTER_DECLARATION" => VerbatimPlacement::After,
214 "BEGIN_FILE" => VerbatimPlacement::BeginFile,
215 "END_FILE" => VerbatimPlacement::EndFile,
216 _ => VerbatimPlacement::Other(placement_str),
217 };
218 let language = r.read_string()?;
219 let text = r.read_string()?;
220 Ok(Self {
221 placement,
222 language,
223 text,
224 })
225 }
226}
227
228#[derive(Debug, Clone, Default, PartialEq, Eq)]
234pub struct AppliedBuiltinTypeAnnotations {
235 pub verbatim: Option<AppliedVerbatimAnnotation>,
237}
238
239impl AppliedBuiltinTypeAnnotations {
240 pub fn encode_into(&self, w: &mut BufferWriter) -> Result<(), EncodeError> {
245 match &self.verbatim {
246 None => w.write_u32(0),
247 Some(v) => {
248 w.write_u32(1)?;
249 v.encode_into(w)
250 }
251 }
252 }
253
254 pub fn decode_from(r: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
259 let len = r.read_u32()?;
260 let verbatim = if len == 0 {
261 None
262 } else {
263 Some(AppliedVerbatimAnnotation::decode_from(r)?)
264 };
265 for _ in 1..len {
268 let _ = AppliedVerbatimAnnotation::decode_from(r)?;
269 }
270 Ok(Self { verbatim })
271 }
272}
273
274#[derive(Debug, Clone, PartialEq, Eq)]
278pub struct AppliedAnnotationParameter {
279 pub paramname_hash: NameHash,
281 pub value: Vec<u8>,
283}
284
285impl AppliedAnnotationParameter {
286 fn encode_into(&self, w: &mut BufferWriter) -> Result<(), EncodeError> {
287 self.paramname_hash.encode_into(w)?;
288 let len = u32::try_from(self.value.len()).map_err(|_| EncodeError::ValueOutOfRange {
289 message: "annotation parameter value exceeds u32::MAX bytes",
290 })?;
291 w.write_u32(len)?;
292 w.write_bytes(&self.value)
293 }
294
295 fn decode_from(r: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
296 let paramname_hash = NameHash::decode_from(r)?;
297 let len = r.read_u32()? as usize;
298 let value = r.read_bytes(len)?.to_vec();
299 Ok(Self {
300 paramname_hash,
301 value,
302 })
303 }
304}
305
306#[derive(Debug, Clone, PartialEq, Eq)]
308pub struct AppliedAnnotation {
309 pub annotation_typeid: TypeIdentifier,
311 pub param_seq: Vec<AppliedAnnotationParameter>,
313}
314
315impl AppliedAnnotation {
316 pub fn encode_into(&self, w: &mut BufferWriter) -> Result<(), EncodeError> {
321 self.annotation_typeid.encode_into(w)?;
322 encode_seq(w, &self.param_seq, |w, p| p.encode_into(w))
323 }
324
325 pub fn decode_from(r: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
330 let annotation_typeid = TypeIdentifier::decode_from(r)?;
331 let param_seq = decode_seq(r, AppliedAnnotationParameter::decode_from)?;
332 Ok(Self {
333 annotation_typeid,
334 param_seq,
335 })
336 }
337}
338
339#[derive(Debug, Clone, Default, PartialEq, Eq)]
341pub struct OptionalAppliedAnnotationSeq(pub Option<Vec<AppliedAnnotation>>);
342
343impl OptionalAppliedAnnotationSeq {
344 pub fn encode_into(&self, w: &mut BufferWriter) -> Result<(), EncodeError> {
349 match &self.0 {
350 None => w.write_u32(0),
351 Some(seq) => {
352 w.write_u32(1)?;
353 encode_seq(w, seq, |w, a| a.encode_into(w))
354 }
355 }
356 }
357
358 pub fn decode_from(r: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
363 let len = r.read_u32()?;
364 if len == 0 {
365 return Ok(Self(None));
366 }
367 let seq = decode_seq(r, AppliedAnnotation::decode_from)?;
368 for _ in 1..len {
369 let _ = decode_seq(r, AppliedAnnotation::decode_from)?;
371 }
372 Ok(Self(Some(seq)))
373 }
374}
375
376#[derive(Debug, Clone, PartialEq, Eq)]
378pub struct CompleteTypeDetail {
379 pub ann_builtin: AppliedBuiltinTypeAnnotations,
381 pub ann_custom: OptionalAppliedAnnotationSeq,
383 pub type_name: QualifiedTypeName,
385}
386
387impl CompleteTypeDetail {
388 pub fn encode_into(&self, w: &mut BufferWriter) -> Result<(), EncodeError> {
393 self.ann_builtin.encode_into(w)?;
394 self.ann_custom.encode_into(w)?;
395 w.write_string(&self.type_name)
396 }
397
398 pub fn decode_from(r: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
403 let ann_builtin = AppliedBuiltinTypeAnnotations::decode_from(r)?;
404 let ann_custom = OptionalAppliedAnnotationSeq::decode_from(r)?;
405 let type_name = r.read_string()?;
406 Ok(Self {
407 ann_builtin,
408 ann_custom,
409 type_name,
410 })
411 }
412}
413
414#[derive(Debug, Clone, Default, PartialEq, Eq)]
417pub struct AppliedBuiltinMemberAnnotations {
418 pub unit: Option<String>,
420 pub min: Option<Vec<u8>>,
422 pub max: Option<Vec<u8>>,
424 pub hash_id: Option<String>,
426 pub default_value: Option<String>,
433}
434
435impl AppliedBuiltinMemberAnnotations {
436 fn write_opt_string(w: &mut BufferWriter, s: &Option<String>) -> Result<(), EncodeError> {
437 match s {
438 None => w.write_u32(0),
439 Some(v) => {
440 w.write_u32(1)?;
441 w.write_string(v)
442 }
443 }
444 }
445
446 fn read_opt_string(r: &mut BufferReader<'_>) -> Result<Option<String>, DecodeError> {
447 let len = r.read_u32()?;
448 if len == 0 {
449 return Ok(None);
450 }
451 if len != 1 {
457 return Err(DecodeError::LengthExceeded {
458 announced: len as usize,
459 remaining: 1,
460 offset: 0,
461 });
462 }
463 let out = r.read_string()?;
464 Ok(Some(out))
465 }
466
467 fn write_opt_bytes(w: &mut BufferWriter, b: &Option<Vec<u8>>) -> Result<(), EncodeError> {
468 match b {
469 None => w.write_u32(0),
470 Some(v) => {
471 w.write_u32(1)?;
472 let len = u32::try_from(v.len()).map_err(|_| EncodeError::ValueOutOfRange {
473 message: "annotation value exceeds u32::MAX",
474 })?;
475 w.write_u32(len)?;
476 w.write_bytes(v)
477 }
478 }
479 }
480
481 fn read_opt_bytes(r: &mut BufferReader<'_>) -> Result<Option<Vec<u8>>, DecodeError> {
482 let len = r.read_u32()?;
483 if len == 0 {
484 return Ok(None);
485 }
486 if len != 1 {
489 return Err(DecodeError::LengthExceeded {
490 announced: len as usize,
491 remaining: 1,
492 offset: 0,
493 });
494 }
495 let inner_len = r.read_u32()? as usize;
496 let out = r.read_bytes(inner_len)?.to_vec();
497 Ok(Some(out))
498 }
499
500 pub fn encode_into(&self, w: &mut BufferWriter) -> Result<(), EncodeError> {
505 Self::write_opt_string(w, &self.unit)?;
506 Self::write_opt_bytes(w, &self.min)?;
507 Self::write_opt_bytes(w, &self.max)?;
508 Self::write_opt_string(w, &self.hash_id)?;
509 Self::write_opt_string(w, &self.default_value)
510 }
511
512 pub fn decode_from(r: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
517 let unit = Self::read_opt_string(r)?;
518 let min = Self::read_opt_bytes(r)?;
519 let max = Self::read_opt_bytes(r)?;
520 let hash_id = Self::read_opt_string(r)?;
521 let default_value = if r.remaining() >= 4 {
525 Self::read_opt_string(r).ok().flatten()
526 } else {
527 None
528 };
529 Ok(Self {
530 unit,
531 min,
532 max,
533 hash_id,
534 default_value,
535 })
536 }
537}
538
539#[derive(Debug, Clone, PartialEq, Eq)]
541pub struct CompleteMemberDetail {
542 pub name: String,
544 pub ann_builtin: AppliedBuiltinMemberAnnotations,
546 pub ann_custom: OptionalAppliedAnnotationSeq,
548}
549
550impl CompleteMemberDetail {
551 pub fn encode_into(&self, w: &mut BufferWriter) -> Result<(), EncodeError> {
556 w.write_string(&self.name)?;
557 self.ann_builtin.encode_into(w)?;
558 self.ann_custom.encode_into(w)
559 }
560
561 pub fn decode_from(r: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
566 let name = r.read_string()?;
567 let ann_builtin = AppliedBuiltinMemberAnnotations::decode_from(r)?;
568 let ann_custom = OptionalAppliedAnnotationSeq::decode_from(r)?;
569 Ok(Self {
570 name,
571 ann_builtin,
572 ann_custom,
573 })
574 }
575}
576
577pub(crate) fn encode_seq<T, F>(
579 w: &mut BufferWriter,
580 items: &[T],
581 mut f: F,
582) -> Result<(), EncodeError>
583where
584 F: FnMut(&mut BufferWriter, &T) -> Result<(), EncodeError>,
585{
586 let len = u32::try_from(items.len()).map_err(|_| EncodeError::ValueOutOfRange {
587 message: "sequence length exceeds u32::MAX",
588 })?;
589 w.write_u32(len)?;
590 for it in items {
591 f(w, it)?;
592 }
593 Ok(())
594}
595
596pub const DECODE_PREALLOC_CAP: usize = 4096;
605
606#[must_use]
609pub(crate) fn safe_capacity(len: usize, min_elem_size: usize, remaining_bytes: usize) -> usize {
610 let by_bytes = if min_elem_size == 0 {
611 DECODE_PREALLOC_CAP
612 } else {
613 remaining_bytes.saturating_div(min_elem_size)
614 };
615 len.min(by_bytes).min(DECODE_PREALLOC_CAP)
616}
617
618pub(crate) fn decode_seq<T, F>(
626 r: &mut BufferReader<'_>,
627 mut f: F,
628) -> Result<alloc::vec::Vec<T>, DecodeError>
629where
630 F: FnMut(&mut BufferReader<'_>) -> Result<T, DecodeError>,
631{
632 let len = r.read_u32()? as usize;
633 let cap = safe_capacity(len, 1, r.remaining());
634 let mut out = alloc::vec::Vec::with_capacity(cap);
635 for _ in 0..len {
636 out.push(f(r)?);
637 }
638 Ok(out)
639}
640
641#[cfg(test)]
642#[allow(clippy::unwrap_used)]
643mod safe_capacity_tests {
644 use super::*;
645
646 #[test]
647 fn safe_capacity_clamps_by_remaining_bytes() {
648 assert_eq!(safe_capacity(1_000_000_000, 4, 100), 25);
649 }
650
651 #[test]
652 fn safe_capacity_caps_at_prealloc_cap() {
653 let cap = safe_capacity(usize::MAX, 1, usize::MAX);
654 assert_eq!(cap, DECODE_PREALLOC_CAP);
655 }
656
657 #[test]
658 fn safe_capacity_returns_len_when_small() {
659 assert_eq!(safe_capacity(10, 4, 1000), 10);
660 }
661
662 #[test]
663 fn safe_capacity_handles_zero_elem_size() {
664 assert_eq!(safe_capacity(usize::MAX, 0, 100), DECODE_PREALLOC_CAP);
665 }
666
667 #[test]
668 fn decode_seq_truncates_preallocation_for_large_lengths() {
669 let mut bytes = alloc::vec::Vec::new();
670 bytes.extend_from_slice(&u32::MAX.to_le_bytes());
671 let mut r = BufferReader::new(&bytes, zerodds_cdr::Endianness::Little);
672 let res: Result<alloc::vec::Vec<u8>, _> = decode_seq(&mut r, |rr| rr.read_u8());
673 assert!(res.is_err());
674 }
675
676 fn roundtrip_verbatim(placement: VerbatimPlacement) {
677 let a = AppliedVerbatimAnnotation {
678 placement: placement.clone(),
679 language: alloc::string::String::from("c++"),
680 text: alloc::string::String::from("// example"),
681 };
682 let mut w = BufferWriter::new(zerodds_cdr::Endianness::Little);
683 a.encode_into(&mut w).unwrap();
684 let bytes = w.into_bytes();
685 let mut r = BufferReader::new(&bytes, zerodds_cdr::Endianness::Little);
686 let decoded = AppliedVerbatimAnnotation::decode_from(&mut r).unwrap();
687 assert_eq!(decoded, a);
688 }
689
690 #[test]
691 fn verbatim_placement_roundtrip_before() {
692 roundtrip_verbatim(VerbatimPlacement::Before);
693 }
694
695 #[test]
696 fn verbatim_placement_roundtrip_after() {
697 roundtrip_verbatim(VerbatimPlacement::After);
698 }
699
700 #[test]
701 fn verbatim_placement_roundtrip_begin_file() {
702 roundtrip_verbatim(VerbatimPlacement::BeginFile);
703 }
704
705 #[test]
706 fn verbatim_placement_roundtrip_end_file() {
707 roundtrip_verbatim(VerbatimPlacement::EndFile);
708 }
709
710 #[test]
711 fn verbatim_placement_roundtrip_other_forward_compat() {
712 roundtrip_verbatim(VerbatimPlacement::Other(alloc::string::String::from(
713 "CUSTOM_PLACEMENT",
714 )));
715 }
716}