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 {
249 None => w.write_u8(0),
250 Some(v) => {
251 w.write_u8(1)?;
252 v.encode_into(w)
253 }
254 }
255 }
256
257 pub fn decode_from(r: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
262 let present = r.read_u8()?;
263 let verbatim = if present == 0 {
264 None
265 } else {
266 Some(AppliedVerbatimAnnotation::decode_from(r)?)
267 };
268 Ok(Self { verbatim })
269 }
270}
271
272#[derive(Debug, Clone, PartialEq, Eq)]
276pub struct AppliedAnnotationParameter {
277 pub paramname_hash: NameHash,
279 pub value: Vec<u8>,
281}
282
283impl AppliedAnnotationParameter {
284 fn encode_into(&self, w: &mut BufferWriter) -> Result<(), EncodeError> {
285 self.paramname_hash.encode_into(w)?;
286 let len = u32::try_from(self.value.len()).map_err(|_| EncodeError::ValueOutOfRange {
287 message: "annotation parameter value exceeds u32::MAX bytes",
288 })?;
289 w.write_u32(len)?;
290 w.write_bytes(&self.value)
291 }
292
293 fn decode_from(r: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
294 let paramname_hash = NameHash::decode_from(r)?;
295 let len = r.read_u32()? as usize;
296 let value = r.read_bytes(len)?.to_vec();
297 Ok(Self {
298 paramname_hash,
299 value,
300 })
301 }
302}
303
304#[derive(Debug, Clone, PartialEq, Eq)]
306pub struct AppliedAnnotation {
307 pub annotation_typeid: TypeIdentifier,
309 pub param_seq: Vec<AppliedAnnotationParameter>,
311}
312
313impl AppliedAnnotation {
314 pub fn encode_into(&self, w: &mut BufferWriter) -> Result<(), EncodeError> {
319 self.annotation_typeid.encode_into(w)?;
320 encode_seq(w, &self.param_seq, |w, p| p.encode_into(w))
321 }
322
323 pub fn decode_from(r: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
328 let annotation_typeid = TypeIdentifier::decode_from(r)?;
329 let param_seq = decode_seq(r, AppliedAnnotationParameter::decode_from)?;
330 Ok(Self {
331 annotation_typeid,
332 param_seq,
333 })
334 }
335}
336
337#[derive(Debug, Clone, Default, PartialEq, Eq)]
339pub struct OptionalAppliedAnnotationSeq(pub Option<Vec<AppliedAnnotation>>);
340
341impl OptionalAppliedAnnotationSeq {
342 pub fn encode_into(&self, w: &mut BufferWriter) -> Result<(), EncodeError> {
347 match &self.0 {
352 None => w.write_u8(0),
353 Some(seq) => {
354 w.write_u8(1)?;
355 encode_seq(w, seq, |w, a| a.encode_into(w))
356 }
357 }
358 }
359
360 pub fn decode_from(r: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
365 let present = r.read_u8()?;
366 if present == 0 {
367 return Ok(Self(None));
368 }
369 let seq = decode_seq(r, AppliedAnnotation::decode_from)?;
370 Ok(Self(Some(seq)))
371 }
372}
373
374#[derive(Debug, Clone, PartialEq, Eq)]
376pub struct CompleteTypeDetail {
377 pub ann_builtin: AppliedBuiltinTypeAnnotations,
379 pub ann_custom: OptionalAppliedAnnotationSeq,
381 pub type_name: QualifiedTypeName,
383}
384
385impl CompleteTypeDetail {
386 pub fn encode_into(&self, w: &mut BufferWriter) -> Result<(), EncodeError> {
391 self.ann_builtin.encode_into(w)?;
392 self.ann_custom.encode_into(w)?;
393 w.write_string(&self.type_name)
394 }
395
396 pub fn decode_from(r: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
401 let ann_builtin = AppliedBuiltinTypeAnnotations::decode_from(r)?;
402 let ann_custom = OptionalAppliedAnnotationSeq::decode_from(r)?;
403 let type_name = r.read_string()?;
404 Ok(Self {
405 ann_builtin,
406 ann_custom,
407 type_name,
408 })
409 }
410}
411
412#[derive(Debug, Clone, Default, PartialEq, Eq)]
415pub struct AppliedBuiltinMemberAnnotations {
416 pub unit: Option<String>,
418 pub min: Option<Vec<u8>>,
420 pub max: Option<Vec<u8>>,
422 pub hash_id: Option<String>,
424 pub default_value: Option<String>,
431}
432
433impl AppliedBuiltinMemberAnnotations {
434 fn write_opt_string(w: &mut BufferWriter, s: &Option<String>) -> Result<(), EncodeError> {
435 match s {
438 None => w.write_u8(0),
439 Some(v) => {
440 w.write_u8(1)?;
441 w.write_string(v)
442 }
443 }
444 }
445
446 fn read_opt_string(r: &mut BufferReader<'_>) -> Result<Option<String>, DecodeError> {
447 let present = r.read_u8()?;
448 if present == 0 {
449 return Ok(None);
450 }
451 let out = r.read_string()?;
452 Ok(Some(out))
453 }
454
455 fn write_opt_bytes(w: &mut BufferWriter, b: &Option<Vec<u8>>) -> Result<(), EncodeError> {
456 match b {
459 None => w.write_u8(0),
460 Some(v) => {
461 w.write_u8(1)?;
462 let len = u32::try_from(v.len()).map_err(|_| EncodeError::ValueOutOfRange {
463 message: "annotation value exceeds u32::MAX",
464 })?;
465 w.write_u32(len)?;
466 w.write_bytes(v)
467 }
468 }
469 }
470
471 fn read_opt_bytes(r: &mut BufferReader<'_>) -> Result<Option<Vec<u8>>, DecodeError> {
472 let present = r.read_u8()?;
473 if present == 0 {
474 return Ok(None);
475 }
476 let inner_len = r.read_u32()? as usize;
477 let out = r.read_bytes(inner_len)?.to_vec();
478 Ok(Some(out))
479 }
480
481 #[must_use]
484 pub fn is_empty(&self) -> bool {
485 self.unit.is_none()
486 && self.min.is_none()
487 && self.max.is_none()
488 && self.hash_id.is_none()
489 && self.default_value.is_none()
490 }
491
492 pub fn encode_into(&self, w: &mut BufferWriter) -> Result<(), EncodeError> {
497 Self::write_opt_string(w, &self.unit)?;
498 Self::write_opt_bytes(w, &self.min)?;
499 Self::write_opt_bytes(w, &self.max)?;
500 Self::write_opt_string(w, &self.hash_id)?;
501 Self::write_opt_string(w, &self.default_value)
502 }
503
504 pub fn decode_from(r: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
509 let unit = Self::read_opt_string(r)?;
510 let min = Self::read_opt_bytes(r)?;
511 let max = Self::read_opt_bytes(r)?;
512 let hash_id = Self::read_opt_string(r)?;
513 let default_value = if r.remaining() >= 4 {
517 Self::read_opt_string(r).ok().flatten()
518 } else {
519 None
520 };
521 Ok(Self {
522 unit,
523 min,
524 max,
525 hash_id,
526 default_value,
527 })
528 }
529}
530
531#[derive(Debug, Clone, PartialEq, Eq)]
533pub struct CompleteMemberDetail {
534 pub name: String,
536 pub ann_builtin: AppliedBuiltinMemberAnnotations,
538 pub ann_custom: OptionalAppliedAnnotationSeq,
540}
541
542impl CompleteMemberDetail {
543 pub fn encode_into(&self, w: &mut BufferWriter) -> Result<(), EncodeError> {
548 w.write_string(&self.name)?;
549 if self.ann_builtin.is_empty() {
553 w.write_u8(0)?;
554 } else {
555 w.write_u8(1)?;
556 self.ann_builtin.encode_into(w)?;
557 }
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 present = r.read_u8()?;
568 let ann_builtin = if present == 0 {
569 AppliedBuiltinMemberAnnotations::default()
570 } else {
571 AppliedBuiltinMemberAnnotations::decode_from(r)?
572 };
573 let ann_custom = OptionalAppliedAnnotationSeq::decode_from(r)?;
574 Ok(Self {
575 name,
576 ann_builtin,
577 ann_custom,
578 })
579 }
580}
581
582pub(crate) fn encode_seq<T, F>(
584 w: &mut BufferWriter,
585 items: &[T],
586 mut f: F,
587) -> Result<(), EncodeError>
588where
589 F: FnMut(&mut BufferWriter, &T) -> Result<(), EncodeError>,
590{
591 let len = u32::try_from(items.len()).map_err(|_| EncodeError::ValueOutOfRange {
592 message: "sequence length exceeds u32::MAX",
593 })?;
594 w.write_u32(len)?;
595 for it in items {
596 f(w, it)?;
597 }
598 Ok(())
599}
600
601pub const DECODE_PREALLOC_CAP: usize = 4096;
610
611#[must_use]
614pub(crate) fn safe_capacity(len: usize, min_elem_size: usize, remaining_bytes: usize) -> usize {
615 let by_bytes = if min_elem_size == 0 {
616 DECODE_PREALLOC_CAP
617 } else {
618 remaining_bytes.saturating_div(min_elem_size)
619 };
620 len.min(by_bytes).min(DECODE_PREALLOC_CAP)
621}
622
623pub(crate) fn decode_seq<T, F>(
631 r: &mut BufferReader<'_>,
632 mut f: F,
633) -> Result<alloc::vec::Vec<T>, DecodeError>
634where
635 F: FnMut(&mut BufferReader<'_>) -> Result<T, DecodeError>,
636{
637 let len = r.read_u32()? as usize;
638 let cap = safe_capacity(len, 1, r.remaining());
639 let mut out = alloc::vec::Vec::with_capacity(cap);
640 for _ in 0..len {
641 out.push(f(r)?);
642 }
643 Ok(out)
644}
645
646pub(crate) fn encode_seq_appendable<T, F>(
652 w: &mut BufferWriter,
653 items: &[T],
654 f: F,
655) -> Result<(), EncodeError>
656where
657 F: FnMut(&mut BufferWriter, &T) -> Result<(), EncodeError>,
658{
659 zerodds_cdr::struct_enc::encode_appendable(w, move |w| encode_seq(w, items, f))
660}
661
662pub(crate) fn decode_seq_appendable<T, F>(
665 r: &mut BufferReader<'_>,
666 f: F,
667) -> Result<alloc::vec::Vec<T>, DecodeError>
668where
669 F: FnMut(&mut BufferReader<'_>) -> Result<T, DecodeError>,
670{
671 zerodds_cdr::struct_enc::decode_appendable(r, move |r| decode_seq(r, f))
672}
673
674#[cfg(test)]
675#[allow(clippy::unwrap_used)]
676mod safe_capacity_tests {
677 use super::*;
678
679 #[test]
680 fn safe_capacity_clamps_by_remaining_bytes() {
681 assert_eq!(safe_capacity(1_000_000_000, 4, 100), 25);
682 }
683
684 #[test]
685 fn safe_capacity_caps_at_prealloc_cap() {
686 let cap = safe_capacity(usize::MAX, 1, usize::MAX);
687 assert_eq!(cap, DECODE_PREALLOC_CAP);
688 }
689
690 #[test]
691 fn safe_capacity_returns_len_when_small() {
692 assert_eq!(safe_capacity(10, 4, 1000), 10);
693 }
694
695 #[test]
696 fn safe_capacity_handles_zero_elem_size() {
697 assert_eq!(safe_capacity(usize::MAX, 0, 100), DECODE_PREALLOC_CAP);
698 }
699
700 #[test]
701 fn decode_seq_truncates_preallocation_for_large_lengths() {
702 let mut bytes = alloc::vec::Vec::new();
703 bytes.extend_from_slice(&u32::MAX.to_le_bytes());
704 let mut r = BufferReader::new(&bytes, zerodds_cdr::Endianness::Little);
705 let res: Result<alloc::vec::Vec<u8>, _> = decode_seq(&mut r, |rr| rr.read_u8());
706 assert!(res.is_err());
707 }
708
709 fn roundtrip_verbatim(placement: VerbatimPlacement) {
710 let a = AppliedVerbatimAnnotation {
711 placement: placement.clone(),
712 language: alloc::string::String::from("c++"),
713 text: alloc::string::String::from("// example"),
714 };
715 let mut w = BufferWriter::new(zerodds_cdr::Endianness::Little);
716 a.encode_into(&mut w).unwrap();
717 let bytes = w.into_bytes();
718 let mut r = BufferReader::new(&bytes, zerodds_cdr::Endianness::Little);
719 let decoded = AppliedVerbatimAnnotation::decode_from(&mut r).unwrap();
720 assert_eq!(decoded, a);
721 }
722
723 #[test]
724 fn verbatim_placement_roundtrip_before() {
725 roundtrip_verbatim(VerbatimPlacement::Before);
726 }
727
728 #[test]
729 fn verbatim_placement_roundtrip_after() {
730 roundtrip_verbatim(VerbatimPlacement::After);
731 }
732
733 #[test]
734 fn verbatim_placement_roundtrip_begin_file() {
735 roundtrip_verbatim(VerbatimPlacement::BeginFile);
736 }
737
738 #[test]
739 fn verbatim_placement_roundtrip_end_file() {
740 roundtrip_verbatim(VerbatimPlacement::EndFile);
741 }
742
743 #[test]
744 fn verbatim_placement_roundtrip_other_forward_compat() {
745 roundtrip_verbatim(VerbatimPlacement::Other(alloc::string::String::from(
746 "CUSTOM_PLACEMENT",
747 )));
748 }
749}