1extern crate alloc;
19use alloc::boxed::Box;
20use alloc::string::String;
21use alloc::vec::Vec;
22
23use crate::type_code::TypeCode;
24
25use crate::buffer::{BufferReader, BufferWriter, XCDR2_MAX_ALIGNMENT};
26use crate::encode::{CdrDecode, CdrEncode};
27use crate::endianness::Endianness;
28use crate::error::{DecodeError, EncodeError};
29
30#[inline]
46fn needs_collection_dheader(writer_max_alignment: usize, elem_is_primitive: bool) -> bool {
47 !elem_is_primitive && writer_max_alignment == XCDR2_MAX_ALIGNMENT
48}
49
50fn write_with_dheader<F>(writer: &mut BufferWriter, body: F) -> Result<(), EncodeError>
55where
56 F: FnOnce(&mut BufferWriter) -> Result<(), EncodeError>,
57{
58 let mut sub = BufferWriter::new(writer.endianness()).with_max_alignment(writer.max_alignment());
59 body(&mut sub)?;
60 let bytes = sub.into_bytes();
61 let dheader = u32::try_from(bytes.len()).map_err(|_| EncodeError::ValueOutOfRange {
62 message: "collection DHEADER exceeds u32::MAX",
63 })?;
64 writer.write_u32(dheader)?;
65 writer.write_bytes(&bytes)
66}
67
68impl CdrEncode for str {
73 fn encode(&self, writer: &mut BufferWriter) -> Result<(), EncodeError> {
74 let bytes = self.as_bytes();
75 let len_with_nul = bytes
77 .len()
78 .checked_add(1)
79 .and_then(|n| u32::try_from(n).ok())
80 .ok_or(EncodeError::ValueOutOfRange {
81 message: "string length exceeds u32::MAX",
82 })?;
83 writer.write_u32(len_with_nul)?;
84 writer.write_bytes(bytes)?;
85 writer.write_u8(0)?;
86 Ok(())
87 }
88}
89
90impl CdrEncode for String {
91 fn encode(&self, writer: &mut BufferWriter) -> Result<(), EncodeError> {
92 self.as_str().encode(writer)
93 }
94}
95
96impl CdrDecode for String {
97 fn decode(reader: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
98 let len_with_nul = reader.read_u32()? as usize;
99 if len_with_nul == 0 {
100 return Err(DecodeError::LengthExceeded {
101 announced: 0,
102 remaining: reader.remaining(),
103 offset: reader.position(),
104 });
105 }
106 if len_with_nul > reader.remaining() {
107 return Err(DecodeError::LengthExceeded {
108 announced: len_with_nul,
109 remaining: reader.remaining(),
110 offset: reader.position(),
111 });
112 }
113 let payload_len = len_with_nul - 1;
115 let offset = reader.position();
116 let bytes = reader.read_bytes(payload_len)?;
117 let s = core::str::from_utf8(bytes).map_err(|_| DecodeError::InvalidUtf8 { offset })?;
118 let owned = String::from(s);
119 let nul = reader.read_u8()?;
121 if nul != 0 {
122 return Err(DecodeError::InvalidUtf8 { offset });
123 }
124 Ok(owned)
125 }
126}
127
128#[derive(Debug, Clone, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
140pub struct WString(pub String);
141
142impl WString {
143 #[must_use]
145 pub fn as_str(&self) -> &str {
146 &self.0
147 }
148
149 pub fn encode_with_bom(
158 &self,
159 writer: &mut BufferWriter,
160 with_bom: bool,
161 ) -> Result<(), EncodeError> {
162 let units = self.0.encode_utf16().count();
163 if units == 0 {
164 writer.write_u32(0)?;
165 return Ok(());
166 }
167 let total_units = if with_bom {
168 units.saturating_add(1)
169 } else {
170 units
171 };
172 let octets = u32::try_from(total_units.saturating_mul(2)).map_err(|_| {
173 EncodeError::ValueOutOfRange {
174 message: "CDR wstring length exceeds u32::MAX",
175 }
176 })?;
177 writer.write_u32(octets)?;
178 if with_bom {
181 writer.write_u16(UTF16_BOM)?;
182 }
183 for unit in self.0.encode_utf16() {
184 writer.write_u16(unit)?;
185 }
186 Ok(())
187 }
188}
189
190impl From<&str> for WString {
191 fn from(s: &str) -> Self {
192 Self(String::from(s))
193 }
194}
195
196impl From<String> for WString {
197 fn from(s: String) -> Self {
198 Self(s)
199 }
200}
201
202const UTF16_BOM: u16 = 0xFEFF;
205
206static CORBA_WSTRING_BOM: core::sync::atomic::AtomicBool =
218 core::sync::atomic::AtomicBool::new(true);
219
220pub fn set_corba_wstring_bom(with_bom: bool) {
224 CORBA_WSTRING_BOM.store(with_bom, core::sync::atomic::Ordering::Relaxed);
225}
226
227#[must_use]
229pub fn corba_wstring_bom() -> bool {
230 CORBA_WSTRING_BOM.load(core::sync::atomic::Ordering::Relaxed)
231}
232
233impl CdrEncode for WString {
234 fn encode(&self, writer: &mut BufferWriter) -> Result<(), EncodeError> {
235 self.encode_with_bom(writer, corba_wstring_bom())
241 }
242}
243
244impl CdrDecode for WString {
245 fn decode(reader: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
246 let octets = reader.read_u32()? as usize;
247 if octets % 2 != 0 || octets > reader.remaining() {
248 return Err(DecodeError::LengthExceeded {
249 announced: octets,
250 remaining: reader.remaining(),
251 offset: reader.position(),
252 });
253 }
254 if octets == 0 {
255 return Ok(Self(String::new()));
256 }
257 let offset = reader.position();
258 let msg_big_endian = matches!(reader.endianness(), Endianness::Big);
264 let bytes = reader.read_bytes(octets)?;
265 let (start, big_endian) = match (bytes[0], bytes[1]) {
266 (0xFE, 0xFF) => (2, true), (0xFF, 0xFE) => (2, false), _ => (0, msg_big_endian), };
270 let mut units = Vec::with_capacity((octets - start) / 2);
271 let mut idx = start;
272 while idx + 1 < octets {
273 let pair = [bytes[idx], bytes[idx + 1]];
274 units.push(if big_endian {
275 u16::from_be_bytes(pair)
276 } else {
277 u16::from_le_bytes(pair)
278 });
279 idx += 2;
280 }
281 let s = String::from_utf16(&units).map_err(|_| DecodeError::InvalidUtf8 { offset })?;
282 Ok(Self(s))
283 }
284}
285
286#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
309pub struct WChar(pub char);
310
311impl WChar {
312 #[must_use]
314 pub fn as_char(&self) -> char {
315 self.0
316 }
317}
318
319impl From<char> for WChar {
320 fn from(c: char) -> Self {
321 Self(c)
322 }
323}
324
325impl CdrEncode for WChar {
326 fn encode(&self, writer: &mut BufferWriter) -> Result<(), EncodeError> {
327 let mut buf = [0u16; 2];
332 let units = self.0.encode_utf16(&mut buf);
333 let octets = units.len().saturating_mul(2);
334 let octets = u8::try_from(octets).map_err(|_| EncodeError::ValueOutOfRange {
335 message: "CDR wchar octet length exceeds u8::MAX",
336 })?;
337 writer.write_u8(octets)?;
338 for unit in units {
339 writer.write_bytes(&unit.to_be_bytes())?;
340 }
341 Ok(())
342 }
343}
344
345impl CdrDecode for WChar {
346 fn decode(reader: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
347 let offset = reader.position();
348 let octets = reader.read_u8()? as usize;
349 if octets == 0 || octets % 2 != 0 || octets > 4 || octets > reader.remaining() {
350 return Err(DecodeError::LengthExceeded {
351 announced: octets,
352 remaining: reader.remaining(),
353 offset,
354 });
355 }
356 let bytes = reader.read_bytes(octets)?;
357 let mut units = [0u16; 2];
358 let mut count = 0usize;
359 let mut idx = 0usize;
360 while idx + 1 < octets {
361 units[count] = u16::from_be_bytes([bytes[idx], bytes[idx + 1]]);
362 count += 1;
363 idx += 2;
364 }
365 let mut iter = char::decode_utf16(units[..count].iter().copied());
368 let c = iter
369 .next()
370 .and_then(Result::ok)
371 .filter(|_| iter.next().is_none())
372 .ok_or(DecodeError::InvalidUtf8 { offset })?;
373 Ok(Self(c))
374 }
375}
376
377#[derive(Debug, Clone, PartialEq, Default)]
387pub enum AnyValue {
388 #[default]
390 Null,
391 Boolean(bool),
393 Octet(u8),
395 Char(u8),
397 Short(i16),
399 UShort(u16),
401 Long(i32),
403 ULong(u32),
405 LongLong(i64),
407 ULongLong(u64),
409 Float(f32),
411 Double(f64),
413 WChar(u16),
415 Str(String),
417 WStr(WString),
419 Seq {
421 element: TypeCode,
423 items: Vec<AnyValue>,
425 },
426 Struct {
428 repo_id: String,
430 name: String,
432 members: Vec<(String, AnyValue)>,
434 },
435 Enum {
437 repo_id: String,
439 name: String,
441 value: u32,
443 members: Vec<String>,
445 },
446 Any(Box<CorbaAny>),
448}
449
450impl AnyValue {
451 #[must_use]
453 pub fn type_code(&self) -> TypeCode {
454 match self {
455 Self::Null => TypeCode::Null,
456 Self::Boolean(_) => TypeCode::Boolean,
457 Self::Octet(_) => TypeCode::Octet,
458 Self::Char(_) => TypeCode::Char,
459 Self::Short(_) => TypeCode::Short,
460 Self::UShort(_) => TypeCode::UShort,
461 Self::Long(_) => TypeCode::Long,
462 Self::ULong(_) => TypeCode::ULong,
463 Self::LongLong(_) => TypeCode::LongLong,
464 Self::ULongLong(_) => TypeCode::ULongLong,
465 Self::Float(_) => TypeCode::Float,
466 Self::Double(_) => TypeCode::Double,
467 Self::WChar(_) => TypeCode::WChar,
468 Self::Str(_) => TypeCode::String(0),
469 Self::WStr(_) => TypeCode::WString(0),
470 Self::Seq { element, .. } => TypeCode::Sequence {
471 element: Box::new(element.clone()),
472 bound: 0,
473 },
474 Self::Struct {
475 repo_id,
476 name,
477 members,
478 } => TypeCode::Struct {
479 repo_id: repo_id.clone(),
480 name: name.clone(),
481 members: members
482 .iter()
483 .map(|(n, v)| (n.clone(), v.type_code()))
484 .collect(),
485 is_except: false,
486 },
487 Self::Enum {
488 repo_id,
489 name,
490 members,
491 ..
492 } => TypeCode::Enum {
493 repo_id: repo_id.clone(),
494 name: name.clone(),
495 members: members.clone(),
496 },
497 Self::Any(_) => TypeCode::Any,
498 }
499 }
500
501 fn encode_value(&self, w: &mut BufferWriter) -> Result<(), EncodeError> {
503 match self {
504 Self::Null => Ok(()),
505 Self::Boolean(v) => v.encode(w),
506 Self::Octet(v) => v.encode(w),
507 Self::Char(v) => v.encode(w),
508 Self::Short(v) => v.encode(w),
509 Self::UShort(v) => v.encode(w),
510 Self::Long(v) => v.encode(w),
511 Self::ULong(v) => v.encode(w),
512 Self::LongLong(v) => v.encode(w),
513 Self::ULongLong(v) => v.encode(w),
514 Self::Float(v) => v.encode(w),
515 Self::Double(v) => v.encode(w),
516 Self::WChar(v) => v.encode(w),
517 Self::Str(s) => s.encode(w),
518 Self::WStr(s) => s.encode(w),
519 Self::Seq { items, .. } => {
520 let len = u32::try_from(items.len()).map_err(|_| EncodeError::ValueOutOfRange {
521 message: "any sequence length exceeds u32",
522 })?;
523 w.write_u32(len)?;
524 for it in items {
525 it.encode_value(w)?;
526 }
527 Ok(())
528 }
529 Self::Struct { members, .. } => {
530 for (_, v) in members {
531 v.encode_value(w)?;
532 }
533 Ok(())
534 }
535 Self::Enum { value, .. } => w.write_u32(*value),
536 Self::Any(inner) => inner.encode(w),
537 }
538 }
539
540 fn decode_value(tc: &TypeCode, r: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
542 match tc {
543 TypeCode::Null | TypeCode::Void => Ok(Self::Null),
544 TypeCode::Boolean => Ok(Self::Boolean(bool::decode(r)?)),
545 TypeCode::Octet => Ok(Self::Octet(u8::decode(r)?)),
546 TypeCode::Char => Ok(Self::Char(u8::decode(r)?)),
547 TypeCode::Short => Ok(Self::Short(i16::decode(r)?)),
548 TypeCode::UShort => Ok(Self::UShort(u16::decode(r)?)),
549 TypeCode::Long => Ok(Self::Long(i32::decode(r)?)),
550 TypeCode::ULong => Ok(Self::ULong(u32::decode(r)?)),
551 TypeCode::LongLong => Ok(Self::LongLong(i64::decode(r)?)),
552 TypeCode::ULongLong => Ok(Self::ULongLong(u64::decode(r)?)),
553 TypeCode::Float => Ok(Self::Float(f32::decode(r)?)),
554 TypeCode::Double => Ok(Self::Double(f64::decode(r)?)),
555 TypeCode::WChar => Ok(Self::WChar(u16::decode(r)?)),
556 TypeCode::String(_) => Ok(Self::Str(String::decode(r)?)),
557 TypeCode::WString(_) => Ok(Self::WStr(WString::decode(r)?)),
558 TypeCode::Sequence { element, .. } => {
559 let count = r.read_u32()? as usize;
560 let mut items = Vec::with_capacity(count.min(4096));
561 for _ in 0..count {
562 items.push(Self::decode_value(element, r)?);
563 }
564 Ok(Self::Seq {
565 element: (**element).clone(),
566 items,
567 })
568 }
569 TypeCode::Struct {
570 repo_id,
571 name,
572 members,
573 ..
574 } => {
575 let mut out = Vec::with_capacity(members.len());
576 for (mn, mt) in members {
577 out.push((mn.clone(), Self::decode_value(mt, r)?));
578 }
579 Ok(Self::Struct {
580 repo_id: repo_id.clone(),
581 name: name.clone(),
582 members: out,
583 })
584 }
585 TypeCode::Enum {
586 repo_id,
587 name,
588 members,
589 } => Ok(Self::Enum {
590 repo_id: repo_id.clone(),
591 name: name.clone(),
592 value: r.read_u32()?,
593 members: members.clone(),
594 }),
595 TypeCode::Alias { content, .. } => Self::decode_value(content, r),
597 TypeCode::Any => Ok(Self::Any(Box::new(CorbaAny::decode(r)?))),
598 TypeCode::ObjRef { .. } | TypeCode::TypeCodeTc => Err(DecodeError::InvalidEnum {
600 kind: "any value (objref/TypeCode value unsupported)",
601 value: tc.tckind(),
602 }),
603 TypeCode::Recursive { .. } => Err(DecodeError::InvalidEnum {
606 kind: "any value against recursive TypeCode marker unsupported",
607 value: tc.tckind(),
608 }),
609 }
610 }
611}
612
613#[derive(Debug, Clone, PartialEq, Default)]
618pub struct CorbaAny(pub AnyValue);
619
620impl CdrEncode for CorbaAny {
621 fn encode(&self, w: &mut BufferWriter) -> Result<(), EncodeError> {
622 self.0.type_code().encode(w)?;
623 self.0.encode_value(w)
624 }
625}
626
627impl CdrDecode for CorbaAny {
628 fn decode(r: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
629 let tc = TypeCode::decode(r)?;
630 Ok(Self(AnyValue::decode_value(&tc, r)?))
631 }
632}
633
634impl<T: CdrEncode> CdrEncode for Vec<T> {
639 fn encode(&self, writer: &mut BufferWriter) -> Result<(), EncodeError> {
640 let len = u32::try_from(self.len()).map_err(|_| EncodeError::ValueOutOfRange {
641 message: "sequence length exceeds u32::MAX",
642 })?;
643 if needs_collection_dheader(writer.max_alignment(), T::IS_PRIMITIVE) {
644 write_with_dheader(writer, |sub| {
646 sub.write_u32(len)?;
647 for item in self {
648 item.encode(sub)?;
649 }
650 Ok(())
651 })
652 } else {
653 writer.write_u32(len)?;
654 for item in self {
655 item.encode(writer)?;
656 }
657 Ok(())
658 }
659 }
660}
661
662impl<T: CdrDecode> CdrDecode for Vec<T> {
663 fn decode(reader: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
664 if needs_collection_dheader(reader.max_alignment(), T::IS_PRIMITIVE) {
665 let _dheader = reader.read_u32()?;
667 }
668 let len = reader.read_u32()? as usize;
669 if len > reader.remaining() {
672 return Err(DecodeError::LengthExceeded {
673 announced: len,
674 remaining: reader.remaining(),
675 offset: reader.position(),
676 });
677 }
678 let mut out = Vec::with_capacity(len);
679 for _ in 0..len {
680 out.push(T::decode(reader)?);
681 }
682 Ok(out)
683 }
684}
685
686impl<T: CdrEncode, const N: usize> CdrEncode for [T; N] {
691 const IS_PRIMITIVE: bool = T::IS_PRIMITIVE;
697
698 fn encode(&self, writer: &mut BufferWriter) -> Result<(), EncodeError> {
699 if needs_collection_dheader(writer.max_alignment(), T::IS_PRIMITIVE) {
700 write_with_dheader(writer, |sub| {
702 for item in self {
703 item.encode(sub)?;
704 }
705 Ok(())
706 })
707 } else {
708 for item in self {
709 item.encode(writer)?;
710 }
711 Ok(())
712 }
713 }
714}
715
716impl<T: CdrDecode + Default + Copy, const N: usize> CdrDecode for [T; N] {
717 const IS_PRIMITIVE: bool = T::IS_PRIMITIVE;
725
726 fn decode(reader: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
727 if needs_collection_dheader(reader.max_alignment(), T::IS_PRIMITIVE) {
728 let _dheader = reader.read_u32()?;
730 }
731 let mut out = [T::default(); N];
732 for slot in &mut out {
733 *slot = T::decode(reader)?;
734 }
735 Ok(out)
736 }
737}
738
739impl<T: CdrEncode> CdrEncode for Option<T> {
744 fn encode(&self, writer: &mut BufferWriter) -> Result<(), EncodeError> {
745 match self {
746 None => writer.write_u8(0),
747 Some(value) => {
748 writer.write_u8(1)?;
749 value.encode(writer)
750 }
751 }
752 }
753}
754
755impl<T: CdrDecode> CdrDecode for Option<T> {
756 fn decode(reader: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
757 let offset = reader.position();
758 let flag = reader.read_u8()?;
759 match flag {
760 0 => Ok(None),
761 1 => Ok(Some(T::decode(reader)?)),
762 other => Err(DecodeError::InvalidBool {
765 value: other,
766 offset,
767 }),
768 }
769 }
770}
771
772use alloc::collections::BTreeMap;
781
782impl<K, V> CdrEncode for BTreeMap<K, V>
783where
784 K: CdrEncode + Ord,
785 V: CdrEncode,
786{
787 fn encode(&self, w: &mut BufferWriter) -> Result<(), EncodeError> {
788 let len = u32::try_from(self.len()).map_err(|_| EncodeError::ValueOutOfRange {
789 message: "map: entry-count > u32::MAX",
790 })?;
791 if needs_collection_dheader(w.max_alignment(), K::IS_PRIMITIVE && V::IS_PRIMITIVE) {
798 write_with_dheader(w, |sub| {
799 sub.write_u32(len)?;
800 for (k, v) in self {
801 k.encode(sub)?;
802 v.encode(sub)?;
803 }
804 Ok(())
805 })
806 } else {
807 w.write_u32(len)?;
808 for (k, v) in self {
809 k.encode(w)?;
810 v.encode(w)?;
811 }
812 Ok(())
813 }
814 }
815}
816
817impl<K, V> CdrDecode for BTreeMap<K, V>
818where
819 K: CdrDecode + Ord,
820 V: CdrDecode,
821{
822 fn decode(r: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
823 if needs_collection_dheader(r.max_alignment(), K::IS_PRIMITIVE && V::IS_PRIMITIVE) {
825 let _dheader = r.read_u32()?;
826 }
827 let len = r.read_u32()? as usize;
828 let mut map = BTreeMap::new();
829 for _ in 0..len {
830 let k = K::decode(r)?;
831 let v = V::decode(r)?;
832 map.insert(k, v);
833 }
834 Ok(map)
835 }
836}
837
838#[cfg(test)]
839mod tests {
840 #![allow(clippy::expect_used, clippy::panic, clippy::unwrap_used)]
841 use super::*;
842 use crate::Endianness;
843 use alloc::string::ToString;
844 use alloc::vec;
845
846 #[test]
847 fn map_primitive_pair_omits_dheader_xcdr2() {
848 let mut m = BTreeMap::new();
853 m.insert(7i32, 42i32);
854 let mut w = BufferWriter::new(Endianness::Little).with_max_alignment(XCDR2_MAX_ALIGNMENT);
855 m.encode(&mut w).unwrap();
856 assert_eq!(
857 w.into_bytes(),
858 vec![1, 0, 0, 0, 7, 0, 0, 0, 42, 0, 0, 0],
859 "primitive map must be count+key+value with NO leading DHEADER"
860 );
861 let bytes = vec![1u8, 0, 0, 0, 7, 0, 0, 0, 42, 0, 0, 0];
863 let mut r =
864 BufferReader::new(&bytes, Endianness::Little).with_max_alignment(XCDR2_MAX_ALIGNMENT);
865 let back: BTreeMap<i32, i32> = BTreeMap::decode(&mut r).unwrap();
866 assert_eq!(back.get(&7), Some(&42));
867 }
868
869 #[test]
870 fn map_non_primitive_value_keeps_dheader_xcdr2() {
871 let mut m = BTreeMap::new();
876 m.insert(1i32, "x".to_string());
877 let mut w = BufferWriter::new(Endianness::Little).with_max_alignment(XCDR2_MAX_ALIGNMENT);
878 m.encode(&mut w).unwrap();
879 let b = w.into_bytes();
880 assert_ne!(
881 &b[0..4],
882 &[1, 0, 0, 0],
883 "non-primitive map must lead with a DHEADER"
884 );
885 let mut r =
886 BufferReader::new(&b, Endianness::Little).with_max_alignment(XCDR2_MAX_ALIGNMENT);
887 let back: BTreeMap<i32, alloc::string::String> = BTreeMap::decode(&mut r).unwrap();
888 assert_eq!(back.get(&1).map(|s| s.as_str()), Some("x"));
889 }
890
891 #[test]
892 fn wstring_giop12_wire_format_and_roundtrip() {
893 let ws = WString::from("Aü€");
895 let mut w = BufferWriter::new(Endianness::Big);
896 ws.encode(&mut w).unwrap();
897 let bytes = w.into_bytes();
898 assert_eq!(
900 &bytes[0..4],
901 &[0, 0, 0, 8],
902 "length in octets incl. BOM, not characters"
903 );
904 assert_eq!(
905 &bytes[4..],
906 &[0xFE, 0xFF, 0x00, 0x41, 0x00, 0xFC, 0x20, 0xAC]
907 );
908 assert_eq!(bytes.len(), 12, "no null terminator");
909
910 let mut r = BufferReader::new(&bytes, Endianness::Big);
911 assert_eq!(WString::decode(&mut r).unwrap(), ws);
912 }
913
914 #[test]
915 fn wstring_decodes_foreign_byte_order_via_bom() {
916 let mut bytes = vec![0, 0, 0, 8]; bytes.extend_from_slice(&[0xFF, 0xFE]); bytes.extend_from_slice(&[0x41, 0x00, 0xFC, 0x00, 0xAC, 0x20]); let mut r = BufferReader::new(&bytes, Endianness::Big);
924 assert_eq!(WString::decode(&mut r).unwrap(), WString::from("Aü€"));
925 }
926
927 #[test]
928 fn wstring_decodes_jacorb_style_no_bom_big_endian() {
929 let mut bytes = vec![0, 0, 0, 6];
932 bytes.extend_from_slice(&[0x00, 0x41, 0x00, 0xFC, 0x20, 0xAC]); let mut r = BufferReader::new(&bytes, Endianness::Big);
934 assert_eq!(WString::decode(&mut r).unwrap(), WString::from("Aü€"));
935 }
936
937 #[test]
938 fn wstring_little_endian_roundtrips() {
939 let ws = WString::from("hello wörld 🌍");
940 let mut w = BufferWriter::new(Endianness::Little);
941 ws.encode(&mut w).unwrap();
942 let bytes = w.into_bytes();
943 let mut r = BufferReader::new(&bytes, Endianness::Little);
944 assert_eq!(WString::decode(&mut r).unwrap(), ws);
945 }
946
947 #[test]
948 fn corba_any_simple_types_roundtrip() {
949 for (label, v) in [
950 ("long", AnyValue::Long(-123456)),
951 ("ulong", AnyValue::ULong(4_000_000_000)),
952 ("double", AnyValue::Double(2.5)),
953 ("boolean", AnyValue::Boolean(true)),
954 ("octet", AnyValue::Octet(0xAB)),
955 ("longlong", AnyValue::LongLong(-1_000_000_000_000)),
956 ("short", AnyValue::Short(-7)),
957 ("char", AnyValue::Char(b'Q')),
958 ] {
959 for e in [Endianness::Big, Endianness::Little] {
960 let any = CorbaAny(v.clone());
961 let mut w = BufferWriter::new(e);
962 any.encode(&mut w).unwrap();
963 let bytes = w.into_bytes();
964 let mut r = BufferReader::new(&bytes, e);
965 assert_eq!(CorbaAny::decode(&mut r).unwrap(), any, "{label}/{e:?}");
966 }
967 }
968 }
969
970 #[test]
971 fn corba_any_long_wire_format() {
972 let any = CorbaAny(AnyValue::Long(42));
974 let mut w = BufferWriter::new(Endianness::Big);
975 any.encode(&mut w).unwrap();
976 assert_eq!(w.into_bytes(), vec![0, 0, 0, 3, 0, 0, 0, 42]);
977 }
978
979 #[test]
980 fn corba_any_string_roundtrip() {
981 let any = CorbaAny(AnyValue::Str("héllo".to_string()));
982 let mut w = BufferWriter::new(Endianness::Little);
983 any.encode(&mut w).unwrap();
984 let bytes = w.into_bytes();
985 assert_eq!(&bytes[0..8], &[18, 0, 0, 0, 0, 0, 0, 0]);
987 let mut r = BufferReader::new(&bytes, Endianness::Little);
988 assert_eq!(CorbaAny::decode(&mut r).unwrap(), any);
989 }
990
991 fn any_rt(v: AnyValue) {
992 for e in [Endianness::Big, Endianness::Little] {
993 let any = CorbaAny(v.clone());
994 let mut w = BufferWriter::new(e);
995 any.encode(&mut w).unwrap();
996 let bytes = w.into_bytes();
997 let mut r = BufferReader::new(&bytes, e);
998 assert_eq!(CorbaAny::decode(&mut r).unwrap(), any, "{v:?} / {e:?}");
999 }
1000 }
1001
1002 #[test]
1003 fn corba_any_sequence_of_long() {
1004 any_rt(AnyValue::Seq {
1005 element: TypeCode::Long,
1006 items: vec![AnyValue::Long(1), AnyValue::Long(-2), AnyValue::Long(3)],
1007 });
1008 any_rt(AnyValue::Seq {
1010 element: TypeCode::Double,
1011 items: vec![],
1012 });
1013 }
1014
1015 #[test]
1016 fn corba_any_struct_mixed_members() {
1017 any_rt(AnyValue::Struct {
1018 repo_id: "IDL:Point:1.0".to_string(),
1019 name: "Point".to_string(),
1020 members: vec![
1021 ("x".to_string(), AnyValue::Long(10)),
1022 ("y".to_string(), AnyValue::Long(-20)),
1023 ("label".to_string(), AnyValue::Str("p1".to_string())),
1024 ("active".to_string(), AnyValue::Boolean(true)),
1025 ],
1026 });
1027 }
1028
1029 #[test]
1030 fn corba_any_enum_and_nested_any_and_seq_of_struct() {
1031 any_rt(AnyValue::Enum {
1032 repo_id: "IDL:Color:1.0".to_string(),
1033 name: "Color".to_string(),
1034 value: 2,
1035 members: vec!["RED".to_string(), "GREEN".to_string(), "BLUE".to_string()],
1036 });
1037 any_rt(AnyValue::Any(Box::new(CorbaAny(AnyValue::Double(2.5)))));
1039 let mk = |x: i32| AnyValue::Struct {
1041 repo_id: "IDL:Pair:1.0".to_string(),
1042 name: "Pair".to_string(),
1043 members: vec![
1044 ("k".to_string(), AnyValue::Long(x)),
1045 ("v".to_string(), AnyValue::Str(alloc::format!("v{x}"))),
1046 ],
1047 };
1048 any_rt(AnyValue::Seq {
1049 element: mk(0).type_code(),
1050 items: vec![mk(1), mk(2)],
1051 });
1052 }
1053
1054 #[test]
1055 fn corba_any_wstring_roundtrip() {
1056 let any = CorbaAny(AnyValue::WStr(WString::from("wíde€")));
1057 let mut w = BufferWriter::new(Endianness::Big);
1058 any.encode(&mut w).unwrap();
1059 let bytes = w.into_bytes();
1060 let mut r = BufferReader::new(&bytes, Endianness::Big);
1061 assert_eq!(CorbaAny::decode(&mut r).unwrap(), any);
1062 }
1063
1064 #[test]
1065 fn wchar_giop12_wire_format_pinned_bytes() {
1066 let wc = WChar('A');
1069 let mut w = BufferWriter::new(Endianness::Big);
1070 wc.encode(&mut w).unwrap();
1071 assert_eq!(w.into_bytes(), vec![0x02, 0x00, 0x41]);
1072 }
1073
1074 #[test]
1075 fn wchar_units_are_big_endian_even_in_le_message() {
1076 let wc = WChar('A');
1079 let mut w = BufferWriter::new(Endianness::Little);
1080 wc.encode(&mut w).unwrap();
1081 assert_eq!(w.into_bytes(), vec![0x02, 0x00, 0x41]);
1082 }
1083
1084 #[test]
1085 fn wchar_non_ascii_bmp() {
1086 for (c, want) in [('ü', vec![0x02, 0x00, 0xFC]), ('€', vec![0x02, 0x20, 0xAC])] {
1088 let mut w = BufferWriter::new(Endianness::Big);
1089 WChar(c).encode(&mut w).unwrap();
1090 assert_eq!(w.into_bytes(), want, "wchar {c:?}");
1091 }
1092 }
1093
1094 #[test]
1095 fn wchar_roundtrip_both_orders() {
1096 for c in ['A', 'ü', '€', '\u{4E2D}'] {
1097 for e in [Endianness::Big, Endianness::Little] {
1098 let wc = WChar(c);
1099 let mut w = BufferWriter::new(e);
1100 wc.encode(&mut w).unwrap();
1101 let bytes = w.into_bytes();
1102 let mut r = BufferReader::new(&bytes, e);
1103 assert_eq!(WChar::decode(&mut r).unwrap(), wc, "{c:?}/{e:?}");
1104 assert_eq!(r.remaining(), 0);
1105 }
1106 }
1107 }
1108
1109 #[test]
1110 fn wchar_astral_surrogate_pair_length_4() {
1111 let wc = WChar('\u{1F310}');
1116 let mut w = BufferWriter::new(Endianness::Big);
1117 wc.encode(&mut w).unwrap();
1118 let bytes = w.into_bytes();
1119 assert_eq!(bytes[0], 0x04, "length octet = 4 (two units)");
1120 assert_eq!(&bytes[1..], &[0xD8, 0x3C, 0xDF, 0x10]); let mut r = BufferReader::new(&bytes, Endianness::Big);
1122 assert_eq!(WChar::decode(&mut r).unwrap(), wc);
1123 }
1124
1125 #[test]
1126 fn wchar_decode_rejects_odd_or_oversized_length() {
1127 let mut r = BufferReader::new(&[0x01, 0x00], Endianness::Big);
1129 assert!(matches!(
1130 WChar::decode(&mut r),
1131 Err(DecodeError::LengthExceeded { .. })
1132 ));
1133 let mut r = BufferReader::new(&[0x00], Endianness::Big);
1135 assert!(matches!(
1136 WChar::decode(&mut r),
1137 Err(DecodeError::LengthExceeded { .. })
1138 ));
1139 let mut r = BufferReader::new(&[0x02, 0xD8, 0x3C], Endianness::Big);
1141 assert!(matches!(
1142 WChar::decode(&mut r),
1143 Err(DecodeError::InvalidUtf8 { .. })
1144 ));
1145 }
1146
1147 #[test]
1148 fn wstring_empty() {
1149 let ws = WString::from("");
1150 let mut w = BufferWriter::new(Endianness::Big);
1151 ws.encode(&mut w).unwrap();
1152 let bytes = w.into_bytes();
1153 assert_eq!(
1154 bytes,
1155 vec![0, 0, 0, 0],
1156 "empty wstring = length 0, no bytes"
1157 );
1158 let mut r = BufferReader::new(&bytes, Endianness::Big);
1159 assert_eq!(WString::decode(&mut r).unwrap(), ws);
1160 }
1161
1162 #[test]
1163 fn wstring_bom_policy_default_is_omniorb_form() {
1164 assert!(corba_wstring_bom(), "default GIOP wstring policy is BOM-on");
1167 }
1168
1169 #[test]
1170 fn wstring_encode_with_bom_omniorb_form() {
1171 let ws = WString::from("AB");
1174 let mut w = BufferWriter::new(Endianness::Little);
1175 ws.encode_with_bom(&mut w, true).unwrap();
1176 let bytes = w.into_bytes();
1177 assert_eq!(&bytes[0..4], &[6, 0, 0, 0]);
1179 assert_eq!(&bytes[4..6], &[0xFF, 0xFE]); assert_eq!(bytes.len(), 4 + 6);
1181 let mut r = BufferReader::new(&bytes, Endianness::Little);
1183 assert_eq!(WString::decode(&mut r).unwrap(), ws);
1184 }
1185
1186 #[test]
1187 fn wstring_encode_with_bom_jacorb_form() {
1188 let ws = WString::from("AB");
1190 let mut w = BufferWriter::new(Endianness::Little);
1191 ws.encode_with_bom(&mut w, false).unwrap();
1192 let bytes = w.into_bytes();
1193 assert_eq!(&bytes[0..4], &[4, 0, 0, 0]); assert_eq!(&bytes[4..8], &[0x41, 0x00, 0x42, 0x00]); assert_eq!(bytes.len(), 4 + 4);
1196 let mut r = BufferReader::new(&bytes, Endianness::Little);
1197 assert_eq!(WString::decode(&mut r).unwrap(), ws);
1198 }
1199
1200 #[test]
1201 fn wstring_empty_both_bom_policies_are_length_zero() {
1202 let ws = WString::from("");
1203 for with_bom in [true, false] {
1204 let mut w = BufferWriter::new(Endianness::Little);
1205 ws.encode_with_bom(&mut w, with_bom).unwrap();
1206 assert_eq!(w.into_bytes(), vec![0, 0, 0, 0]);
1207 }
1208 }
1209
1210 fn rt_le<T>(value: T)
1211 where
1212 T: CdrEncode + CdrDecode + PartialEq + core::fmt::Debug,
1213 {
1214 let mut w = BufferWriter::new(Endianness::Little);
1215 value.encode(&mut w).expect("encode");
1216 let bytes = w.into_bytes();
1217 let mut r = BufferReader::new(&bytes, Endianness::Little);
1218 let decoded = T::decode(&mut r).expect("decode");
1219 assert_eq!(decoded, value);
1220 assert_eq!(r.remaining(), 0);
1221 }
1222
1223 #[test]
1226 fn string_roundtrip_ascii() {
1227 rt_le(String::from("hello"));
1228 }
1229
1230 #[test]
1231 fn string_roundtrip_unicode() {
1232 rt_le(String::from("Hällo, 🌍 Welt"));
1233 }
1234
1235 #[test]
1236 fn string_roundtrip_empty() {
1237 rt_le(String::new());
1238 }
1239
1240 #[test]
1241 fn string_wire_format_includes_null_terminator() {
1242 let mut w = BufferWriter::new(Endianness::Little);
1243 "ab".encode(&mut w).unwrap();
1244 let bytes = w.into_bytes();
1245 assert_eq!(bytes, vec![3, 0, 0, 0, b'a', b'b', 0]);
1247 }
1248
1249 #[test]
1250 fn string_decode_rejects_zero_length() {
1251 let bytes = [0u8, 0, 0, 0]; let mut r = BufferReader::new(&bytes, Endianness::Little);
1253 let res = String::decode(&mut r);
1254 assert!(matches!(res, Err(DecodeError::LengthExceeded { .. })));
1255 }
1256
1257 #[test]
1258 fn string_decode_rejects_announced_overrun() {
1259 let bytes = [100u8, 0, 0, 0, b'x'];
1260 let mut r = BufferReader::new(&bytes, Endianness::Little);
1261 let res = String::decode(&mut r);
1262 assert!(matches!(res, Err(DecodeError::LengthExceeded { .. })));
1263 }
1264
1265 #[test]
1266 fn string_decode_rejects_missing_null_terminator() {
1267 let bytes = [3u8, 0, 0, 0, b'a', b'b', b'x'];
1269 let mut r = BufferReader::new(&bytes, Endianness::Little);
1270 let res = String::decode(&mut r);
1271 assert!(matches!(res, Err(DecodeError::InvalidUtf8 { .. })));
1272 }
1273
1274 #[test]
1277 fn sequence_u8_roundtrip() {
1278 rt_le::<Vec<u8>>(vec![1, 2, 3, 4, 5]);
1279 }
1280
1281 #[test]
1282 fn sequence_u32_roundtrip() {
1283 rt_le::<Vec<u32>>(vec![0xDEAD, 0xBEEF, 0x1234]);
1284 }
1285
1286 #[test]
1287 fn sequence_empty_roundtrip() {
1288 rt_le::<Vec<u32>>(vec![]);
1289 }
1290
1291 #[test]
1292 fn sequence_string_roundtrip() {
1293 rt_le::<Vec<String>>(vec!["alpha".to_string(), "beta".to_string()]);
1294 }
1295
1296 #[test]
1297 fn sequence_decode_rejects_overrun_length() {
1298 let bytes = [0xE7u8, 0x03, 0, 0, b'x']; let mut r = BufferReader::new(&bytes, Endianness::Little);
1301 let res = Vec::<u8>::decode(&mut r);
1302 assert!(matches!(res, Err(DecodeError::LengthExceeded { .. })));
1303 }
1304
1305 #[test]
1306 fn sequence_alignment_4_byte_prefix() {
1307 let mut w = BufferWriter::new(Endianness::Little);
1309 1u8.encode(&mut w).unwrap();
1310 vec![10u8, 20, 30].encode(&mut w).unwrap();
1311 let bytes = w.into_bytes();
1312 assert_eq!(bytes[0], 1); assert_eq!(&bytes[1..4], &[0, 0, 0]); assert_eq!(&bytes[4..8], &[3, 0, 0, 0]); assert_eq!(&bytes[8..11], &[10, 20, 30]); }
1317
1318 #[test]
1321 fn array_u8_roundtrip() {
1322 rt_le::<[u8; 4]>([1, 2, 3, 4]);
1323 }
1324
1325 #[test]
1326 fn array_u32_roundtrip() {
1327 rt_le::<[u32; 3]>([100, 200, 300]);
1328 }
1329
1330 #[test]
1331 fn array_no_length_prefix() {
1332 let mut w = BufferWriter::new(Endianness::Little);
1333 [1u8, 2, 3].encode(&mut w).unwrap();
1334 assert_eq!(w.into_bytes(), vec![1, 2, 3]);
1336 }
1337
1338 #[test]
1339 fn array_zero_size() {
1340 let arr: [u32; 0] = [];
1341 let mut w = BufferWriter::new(Endianness::Little);
1342 arr.encode(&mut w).unwrap();
1343 assert!(w.into_bytes().is_empty());
1344 }
1345
1346 #[test]
1349 fn optional_none_roundtrip() {
1350 rt_le::<Option<u32>>(None);
1351 }
1352
1353 #[test]
1354 fn optional_some_roundtrip() {
1355 rt_le::<Option<u32>>(Some(42));
1356 }
1357
1358 #[test]
1359 fn optional_some_string_roundtrip() {
1360 rt_le::<Option<String>>(Some("hi".to_string()));
1361 }
1362
1363 #[test]
1364 fn optional_wire_format_none_is_zero_byte() {
1365 let mut w = BufferWriter::new(Endianness::Little);
1366 Option::<u32>::None.encode(&mut w).unwrap();
1367 assert_eq!(w.into_bytes(), vec![0]);
1368 }
1369
1370 #[test]
1371 fn optional_wire_format_some_is_one_then_value() {
1372 let mut w = BufferWriter::new(Endianness::Little);
1373 Some(0xABCDu32).encode(&mut w).unwrap();
1374 let bytes = w.into_bytes();
1375 assert_eq!(bytes[0], 1); assert_eq!(&bytes[1..4], &[0, 0, 0]);
1378 assert_eq!(&bytes[4..8], &[0xCD, 0xAB, 0, 0]);
1379 }
1380
1381 #[test]
1382 fn optional_decode_rejects_invalid_flag() {
1383 let bytes = [0xFFu8];
1384 let mut r = BufferReader::new(&bytes, Endianness::Little);
1385 let res = Option::<u32>::decode(&mut r);
1386 assert!(matches!(res, Err(DecodeError::InvalidBool { .. })));
1387 }
1388
1389 #[test]
1392 fn nested_optional_sequence_string() {
1393 let value: Option<Vec<String>> = Some(vec!["a".to_string(), "bb".to_string()]);
1394 rt_le(value);
1395 }
1396
1397 #[test]
1398 fn nested_array_of_optionals() {
1399 let value: [Option<u32>; 3] = [Some(1), None, Some(3)];
1400 rt_le(value);
1401 }
1402}