1use core::cell::Cell;
23use core::mem;
24use core::ptr;
25
26use crate::data;
27use crate::private::arena::{BuilderArena, NullArena, ReaderArena, SegmentId};
28#[cfg(feature = "alloc")]
29use crate::private::capability::ClientHook;
30use crate::private::mask::Mask;
31use crate::private::primitive::{Primitive, WireValue};
32use crate::private::units::*;
33use crate::private::zero;
34use crate::text;
35use crate::{Error, ErrorKind, MessageSize, Result};
36
37pub use self::ElementSize::{
38 Bit, Byte, EightBytes, FourBytes, InlineComposite, Pointer, TwoBytes, Void,
39};
40
41#[repr(u8)]
42#[derive(Clone, Copy, Debug, PartialEq)]
43pub enum ElementSize {
44 Void = 0,
45 Bit = 1,
46 Byte = 2,
47 TwoBytes = 3,
48 FourBytes = 4,
49 EightBytes = 5,
50 Pointer = 6,
51 InlineComposite = 7,
52}
53
54impl ElementSize {
55 fn from(val: u8) -> Self {
56 match val {
57 0 => Self::Void,
58 1 => Self::Bit,
59 2 => Self::Byte,
60 3 => Self::TwoBytes,
61 4 => Self::FourBytes,
62 5 => Self::EightBytes,
63 6 => Self::Pointer,
64 7 => Self::InlineComposite,
65 _ => panic!("illegal element size: {val}"),
66 }
67 }
68}
69
70pub fn data_bits_per_element(size: ElementSize) -> BitCount32 {
71 match size {
72 Void => 0,
73 Bit => 1,
74 Byte => 8,
75 TwoBytes => 16,
76 FourBytes => 32,
77 EightBytes => 64,
78 Pointer => 0,
79 InlineComposite => 0,
80 }
81}
82
83pub fn pointers_per_element(size: ElementSize) -> WirePointerCount32 {
84 match size {
85 Pointer => 1,
86 _ => 0,
87 }
88}
89
90#[derive(Clone, Copy, Debug)]
91pub struct StructSize {
92 pub data: WordCount16,
93 pub pointers: WirePointerCount16,
94}
95
96impl StructSize {
97 pub fn total(&self) -> WordCount32 {
98 u32::from(self.data)
99 + u32::from(self.pointers) * WordCount32::try_from(WORDS_PER_POINTER).unwrap()
100 }
101}
102
103#[repr(u8)]
104#[derive(Clone, Copy, PartialEq)]
105pub enum WirePointerKind {
106 Struct = 0,
107 List = 1,
108 Far = 2,
109 Other = 3,
110}
111
112pub enum PointerType {
113 Null,
114 Struct,
115 List,
116 Capability,
117}
118
119impl WirePointerKind {
120 fn from(val: u8) -> Self {
121 match val {
122 0 => Self::Struct,
123 1 => Self::List,
124 2 => Self::Far,
125 3 => Self::Other,
126 _ => panic!("illegal element size: {val}"),
127 }
128 }
129}
130
131#[repr(C)]
132pub struct WirePointer {
133 offset_and_kind: WireValue<u32>,
140
141 upper32bits: WireValue<u32>,
147}
148
149#[test]
150#[cfg(feature = "unaligned")]
151fn wire_pointer_align() {
152 assert_eq!(core::mem::align_of::<WirePointer>(), 1);
154}
155
156impl WirePointer {
157 #[inline]
158 pub fn kind(&self) -> WirePointerKind {
159 WirePointerKind::from((self.offset_and_kind.get() & 3) as u8)
160 }
161
162 #[inline]
163 pub fn is_positional(&self) -> bool {
164 (self.offset_and_kind.get() & 2) == 0 }
166
167 #[inline]
168 pub fn is_capability(&self) -> bool {
169 self.offset_and_kind.get() == WirePointerKind::Other as u32
170 }
171
172 #[inline]
173 #[allow(clippy::cast_possible_wrap)]
174 fn offset_in_words(&self) -> i32 {
175 1 + ((self.offset_and_kind.get() as i32) >> 2)
177 }
178
179 #[inline]
180 pub unsafe fn target(ptr: *const Self) -> *const u8 {
181 let this_addr: *const u8 = ptr as *const _;
182 unsafe { this_addr.offset(8 * (*ptr).offset_in_words() as isize) }
183 }
184
185 #[inline]
188 fn target_from_segment(
189 ptr: *const Self,
190 arena: &dyn ReaderArena,
191 segment_id: u32,
192 ) -> Result<*const u8> {
193 let this_addr: *const u8 = ptr as *const _;
194 unsafe { arena.check_offset(segment_id, this_addr, (*ptr).offset_in_words()) }
195 }
196
197 #[inline]
200 fn mut_target(ptr: *mut Self) -> *mut u8 {
201 let this_addr: *mut u8 = ptr as *mut _;
202 unsafe {
203 this_addr.wrapping_offset(
204 isize::try_from(BYTES_PER_WORD).unwrap() * (*ptr).offset_in_words() as isize,
205 )
206 }
207 }
208
209 #[inline]
210 pub fn set_kind_and_target(&mut self, kind: WirePointerKind, target: *mut u8) {
211 let this_addr: isize = self as *const _ as isize;
212 let target_addr: isize = target as *const _ as isize;
213 self.offset_and_kind.set(
214 ((i32::try_from((target_addr - this_addr) / isize::try_from(BYTES_PER_WORD).unwrap())
215 .unwrap()
216 - 1)
217 << 2) as u32
218 | (kind as u32),
219 )
220 }
221
222 #[inline]
223 pub fn set_kind_with_zero_offset(&mut self, kind: WirePointerKind) {
224 self.offset_and_kind.set(kind as u32)
225 }
226
227 #[inline]
228 pub fn set_kind_and_target_for_empty_struct(&mut self) {
229 self.offset_and_kind.set(0xfffffffc);
239 }
240
241 #[inline]
242 pub fn inline_composite_list_element_count(&self) -> ElementCount32 {
243 self.offset_and_kind.get() >> 2
244 }
245
246 #[inline]
247 pub fn set_kind_and_inline_composite_list_element_count(
248 &mut self,
249 kind: WirePointerKind,
250 element_count: ElementCount32,
251 ) {
252 self.offset_and_kind
253 .set((element_count << 2) | (kind as u32))
254 }
255
256 #[inline]
257 pub fn far_position_in_segment(&self) -> WordCount32 {
258 self.offset_and_kind.get() >> 3
259 }
260
261 #[inline]
262 pub fn is_double_far(&self) -> bool {
263 ((self.offset_and_kind.get() >> 2) & 1) != 0
264 }
265
266 #[inline]
267 pub fn set_far(&mut self, is_double_far: bool, pos: WordCount32) {
268 self.offset_and_kind
269 .set((pos << 3) | (u32::from(is_double_far) << 2) | WirePointerKind::Far as u32);
270 }
271
272 #[inline]
273 pub fn set_cap(&mut self, index: u32) {
274 self.offset_and_kind.set(WirePointerKind::Other as u32);
275 self.upper32bits.set(index);
276 }
277
278 #[inline]
279 pub fn struct_data_size(&self) -> WordCount16 {
280 (self.upper32bits.get() & 0xFFFF) as WordCount16
281 }
282
283 #[inline]
284 pub fn struct_ptr_count(&self) -> WordCount16 {
285 (self.upper32bits.get() >> 16) as WordCount16
286 }
287
288 #[inline]
289 pub fn struct_word_size(&self) -> WordCount32 {
290 u32::from(self.struct_data_size())
291 + u32::from(self.struct_ptr_count()) * u32::try_from(WORDS_PER_POINTER).unwrap()
292 }
293
294 #[inline]
295 pub fn set_struct_size(&mut self, size: StructSize) {
296 self.upper32bits
297 .set(u32::from(size.data) | (u32::from(size.pointers) << 16))
298 }
299
300 #[inline]
301 pub fn set_struct_size_from_pieces(&mut self, ds: WordCount16, rc: WirePointerCount16) {
302 self.set_struct_size(StructSize {
303 data: ds,
304 pointers: rc,
305 })
306 }
307
308 #[inline]
309 pub fn list_element_size(&self) -> ElementSize {
310 ElementSize::from((self.upper32bits.get() & 7) as u8)
311 }
312
313 #[inline]
314 pub fn list_element_count(&self) -> ElementCount32 {
315 self.upper32bits.get() >> 3
316 }
317
318 #[inline]
319 pub fn list_inline_composite_word_count(&self) -> WordCount32 {
320 self.list_element_count()
321 }
322
323 #[inline]
324 pub fn set_list_size_and_count(&mut self, es: ElementSize, ec: ElementCount32) {
325 assert!(ec < (1 << 29), "Lists are limited to 2**29 elements");
326 self.upper32bits.set((ec << 3) | (es as u32));
327 }
328
329 #[inline]
330 pub fn set_list_inline_composite(&mut self, wc: WordCount32) {
331 assert!(
332 wc < (1 << 29),
333 "Inline composite lists are limited to 2**29 words"
334 );
335 self.upper32bits.set((wc << 3) | (InlineComposite as u32));
336 }
337
338 #[inline]
339 pub fn far_segment_id(&self) -> SegmentId {
340 self.upper32bits.get() as SegmentId
341 }
342
343 #[inline]
344 pub fn set_far_segment_id(&mut self, si: SegmentId) {
345 self.upper32bits.set(si)
346 }
347
348 #[inline]
349 pub fn cap_index(&self) -> u32 {
350 self.upper32bits.get()
351 }
352
353 #[inline]
354 pub fn set_cap_index(&mut self, index: u32) {
355 self.upper32bits.set(index)
356 }
357
358 #[inline]
359 pub fn is_null(&self) -> bool {
360 self.offset_and_kind.get() == 0 && self.upper32bits.get() == 0
361 }
362}
363
364mod wire_helpers {
365 use core::{ptr, slice};
366
367 use crate::data;
368 use crate::private::arena::*;
369 #[cfg(feature = "alloc")]
370 use crate::private::capability::ClientHook;
371 use crate::private::layout::ElementSize::*;
372 use crate::private::layout::{data_bits_per_element, pointers_per_element};
373 use crate::private::layout::{CapTableBuilder, CapTableReader};
374 use crate::private::layout::{
375 ElementSize, ListBuilder, ListReader, PointerReader, StructBuilder, StructReader,
376 StructSize, WirePointer, WirePointerKind,
377 };
378 use crate::private::units::*;
379 use crate::text;
380 use crate::{Error, ErrorKind, MessageSize, Result};
381
382 pub(crate) struct SegmentAnd<T> {
383 #[allow(dead_code)]
384 segment_id: u32,
385 pub value: T,
386 }
387
388 #[inline]
389 pub(crate) fn round_bytes_up_to_words(bytes: ByteCount32) -> WordCount32 {
390 (bytes + 7) / u32::try_from(BYTES_PER_WORD).unwrap()
392 }
393
394 #[inline]
399 pub(crate) fn round_bits_up_to_words(bits: BitCount64) -> WordCount32 {
400 WordCount32::try_from((bits + 63) / (BITS_PER_WORD as u64)).unwrap()
402 }
403
404 #[allow(dead_code)]
405 #[inline]
406 pub(crate) fn round_bits_up_to_bytes(bits: BitCount64) -> ByteCount32 {
407 ByteCount32::try_from((bits + 7) / (BITS_PER_BYTE as u64)).unwrap()
408 }
409
410 #[inline]
411 pub(crate) fn bounds_check(
412 arena: &dyn ReaderArena,
413 segment_id: u32,
414 start: *const u8,
415 size_in_words: usize,
416 _kind: WirePointerKind,
417 ) -> Result<()> {
418 arena.contains_interval(segment_id, start, size_in_words)
419 }
420
421 #[inline]
422 pub(crate) fn amplified_read(arena: &dyn ReaderArena, virtual_amount: u64) -> Result<()> {
423 arena.amplified_read(virtual_amount)
424 }
425
426 #[inline]
427 pub(crate) unsafe fn copy_nonoverlapping_check_zero<T>(
428 src: *const T,
429 dst: *mut T,
430 count: usize,
431 ) {
432 if count > 0 {
433 ptr::copy_nonoverlapping(src, dst, count);
434 }
435 }
436
437 #[inline]
438 pub(crate) unsafe fn allocate(
439 arena: &mut dyn BuilderArena,
440 reff: *mut WirePointer,
441 segment_id: u32,
442 amount: WordCount32,
443 kind: WirePointerKind,
444 ) -> (*mut u8, *mut WirePointer, u32) {
445 let is_null = (*reff).is_null();
446 if !is_null {
447 zero_object(arena, segment_id, reff)
448 }
449
450 if amount == 0 && kind == WirePointerKind::Struct {
451 (*reff).set_kind_and_target_for_empty_struct();
452 return (reff as *mut _, reff, segment_id);
453 }
454
455 match arena.allocate(segment_id, amount) {
456 None => {
457 let amount_plus_ref = amount + u32::try_from(POINTER_SIZE_IN_WORDS).unwrap();
462 let (segment_id, word_idx) = arena.allocate_anywhere(amount_plus_ref);
463 let (seg_start, _seg_len) = arena.get_segment_mut(segment_id);
464 let ptr = seg_start.add(word_idx as usize * BYTES_PER_WORD);
465
466 (*reff).set_far(false, word_idx);
469 (*reff).set_far_segment_id(segment_id);
470
471 let reff = ptr as *mut WirePointer;
474
475 let ptr1 = ptr.add(BYTES_PER_WORD);
476 (*reff).set_kind_and_target(kind, ptr1);
477 (ptr1, reff, segment_id)
478 }
479 Some(idx) => {
480 let (seg_start, _seg_len) = arena.get_segment_mut(segment_id);
481 let ptr = seg_start.add(idx as usize * BYTES_PER_WORD);
482 (*reff).set_kind_and_target(kind, ptr);
483 (ptr, reff, segment_id)
484 }
485 }
486 }
487
488 #[inline]
489 pub(crate) unsafe fn follow_builder_fars(
490 arena: &mut dyn BuilderArena,
491 reff: *mut WirePointer,
492 ref_target: *mut u8,
493 segment_id: u32,
494 ) -> Result<(*mut u8, *mut WirePointer, u32)> {
495 if (*reff).kind() == WirePointerKind::Far {
505 let segment_id = (*reff).far_segment_id();
506 let (seg_start, _seg_len) = arena.get_segment_mut(segment_id);
507 let pad: *mut WirePointer =
508 (seg_start as *mut WirePointer).add((*reff).far_position_in_segment() as usize);
509 if !(*reff).is_double_far() {
510 Ok((WirePointer::mut_target(pad), pad, segment_id))
511 } else {
512 let reff = pad.add(1);
515
516 let segment_id = (*pad).far_segment_id();
517 let (segment_start, _segment_len) = arena.get_segment_mut(segment_id);
518 let ptr =
519 segment_start.add((*pad).far_position_in_segment() as usize * BYTES_PER_WORD);
520 Ok((ptr, reff, segment_id))
521 }
522 } else {
523 Ok((ref_target, reff, segment_id))
524 }
525 }
526
527 #[inline]
532 pub(crate) unsafe fn follow_fars(
533 arena: &dyn ReaderArena,
534 reff: *const WirePointer,
535 segment_id: u32,
536 ) -> Result<(*const u8, *const WirePointer, u32)> {
537 if (*reff).kind() == WirePointerKind::Far {
538 let far_segment_id = (*reff).far_segment_id();
539
540 let (seg_start, _seg_len) = arena.get_segment(far_segment_id)?;
541 let ptr =
545 seg_start.wrapping_add((*reff).far_position_in_segment() as usize * BYTES_PER_WORD);
546
547 let pad_words: usize = if (*reff).is_double_far() { 2 } else { 1 };
548 bounds_check(arena, far_segment_id, ptr, pad_words, WirePointerKind::Far)?;
549
550 let pad: *const WirePointer = ptr as *const _;
551
552 if !(*reff).is_double_far() {
553 Ok((
554 WirePointer::target_from_segment(pad, arena, far_segment_id)?,
555 pad,
556 far_segment_id,
557 ))
558 } else {
559 let tag = pad.add(1);
563 let double_far_segment_id = (*pad).far_segment_id();
564 let (segment_start, _segment_len) = arena.get_segment(double_far_segment_id)?;
565 let ptr = segment_start
569 .wrapping_add((*pad).far_position_in_segment() as usize * BYTES_PER_WORD);
570 Ok((ptr, tag, double_far_segment_id))
571 }
572 } else {
573 Ok((
574 WirePointer::target_from_segment(reff, arena, segment_id)?,
575 reff,
576 segment_id,
577 ))
578 }
579 }
580
581 pub(crate) unsafe fn zero_object(
582 arena: &mut dyn BuilderArena,
583 segment_id: u32,
584 reff: *mut WirePointer,
585 ) {
586 match (*reff).kind() {
591 WirePointerKind::Struct | WirePointerKind::List | WirePointerKind::Other => {
592 zero_object_helper(arena, segment_id, reff, WirePointer::mut_target(reff))
593 }
594 WirePointerKind::Far => {
595 let segment_id = (*reff).far_segment_id();
596 let (seg_start, _seg_len) = arena.get_segment_mut(segment_id);
597 let pad: *mut WirePointer =
598 (seg_start as *mut WirePointer).add((*reff).far_position_in_segment() as usize);
599
600 if (*reff).is_double_far() {
601 let segment_id = (*pad).far_segment_id();
602
603 let (seg_start, _seg_len) = arena.get_segment_mut(segment_id);
604 let ptr =
605 seg_start.add((*pad).far_position_in_segment() as usize * BYTES_PER_WORD);
606 zero_object_helper(arena, segment_id, pad.add(1), ptr);
607
608 ptr::write_bytes(pad, 0u8, 2);
609 } else {
610 zero_object(arena, segment_id, pad);
611 ptr::write_bytes(pad, 0u8, 1);
612 }
613 }
614 }
615 }
616
617 pub(crate) unsafe fn zero_object_helper(
618 arena: &mut dyn BuilderArena,
619 segment_id: u32,
620 tag: *mut WirePointer,
621 ptr: *mut u8,
622 ) {
623 match (*tag).kind() {
624 WirePointerKind::Other => {
625 panic!("Don't know how to handle OTHER")
626 }
627 WirePointerKind::Struct => {
628 let pointer_section: *mut WirePointer =
629 ptr.add((*tag).struct_data_size() as usize * BYTES_PER_WORD) as *mut _;
630
631 let count = (*tag).struct_ptr_count();
632 for i in 0..count {
633 zero_object(arena, segment_id, pointer_section.add(i as usize));
634 }
635 ptr::write_bytes(
636 ptr,
637 0u8,
638 (*tag).struct_word_size() as usize * BYTES_PER_WORD,
639 );
640 }
641 WirePointerKind::List => match (*tag).list_element_size() {
642 Void => {}
643 Bit | Byte | TwoBytes | FourBytes | EightBytes => ptr::write_bytes(
644 ptr,
645 0u8,
646 BYTES_PER_WORD
647 * round_bits_up_to_words(
648 u64::from((*tag).list_element_count())
649 * u64::from(data_bits_per_element((*tag).list_element_size())),
650 ) as usize,
651 ),
652 Pointer => {
653 let count = (*tag).list_element_count() as usize;
654 for i in 0..count {
655 zero_object(arena, segment_id, ptr.add(i * BYTES_PER_WORD) as *mut _);
656 }
657 ptr::write_bytes(ptr, 0u8, count * BYTES_PER_WORD);
658 }
659 InlineComposite => {
660 let element_tag: *mut WirePointer = ptr as *mut _;
661
662 assert!(
663 (*element_tag).kind() == WirePointerKind::Struct,
664 "Don't know how to handle non-STRUCT inline composite"
665 );
666
667 let data_size = (*element_tag).struct_data_size();
668 let pointer_count = (*element_tag).struct_ptr_count();
669 let mut pos = ptr.add(BYTES_PER_WORD);
670 let count = (*element_tag).inline_composite_list_element_count();
671 if pointer_count > 0 {
672 for _ in 0..count {
673 pos = pos.add(data_size as usize * BYTES_PER_WORD);
674 for _ in 0..pointer_count {
675 zero_object(arena, segment_id, pos as *mut WirePointer);
676 pos = pos.add(BYTES_PER_WORD);
677 }
678 }
679 }
680 ptr::write_bytes(
681 ptr,
682 0u8,
683 BYTES_PER_WORD * ((*element_tag).struct_word_size() * count + 1) as usize,
684 );
685 }
686 },
687 WirePointerKind::Far => {
688 panic!("Unexpected FAR pointer")
689 }
690 }
691 }
692
693 #[inline]
694 pub(crate) unsafe fn zero_pointer_and_fars(
695 arena: &mut dyn BuilderArena,
696 _segment_id: u32,
697 reff: *mut WirePointer,
698 ) -> Result<()> {
699 if (*reff).kind() == WirePointerKind::Far {
703 let far_segment_id = (*reff).far_segment_id();
704 let (seg_start, _seg_len) = arena.get_segment_mut(far_segment_id);
705 let pad = seg_start.add((*reff).far_position_in_segment() as usize * BYTES_PER_WORD);
706 let num_elements = if (*reff).is_double_far() { 2 } else { 1 };
707 ptr::write_bytes(pad, 0, num_elements * BYTES_PER_WORD);
708 }
709 ptr::write_bytes(reff, 0, 1);
710 Ok(())
711 }
712
713 pub(crate) unsafe fn total_size(
714 arena: &dyn ReaderArena,
715 segment_id: u32,
716 reff: *const WirePointer,
717 mut nesting_limit: i32,
718 ) -> Result<MessageSize> {
719 let mut result = MessageSize {
720 word_count: 0,
721 cap_count: 0,
722 };
723
724 if (*reff).is_null() {
725 return Ok(result);
726 };
727
728 if nesting_limit <= 0 {
729 return Err(Error::from_kind(ErrorKind::MessageIsTooDeeplyNested));
730 }
731
732 nesting_limit -= 1;
733
734 let (ptr, reff, segment_id) = follow_fars(arena, reff, segment_id)?;
735
736 match (*reff).kind() {
737 WirePointerKind::Struct => {
738 bounds_check(
739 arena,
740 segment_id,
741 ptr,
742 (*reff).struct_word_size() as usize,
743 WirePointerKind::Struct,
744 )?;
745 result.word_count += u64::from((*reff).struct_word_size());
746
747 let pointer_section: *const WirePointer =
748 ptr.add((*reff).struct_data_size() as usize * BYTES_PER_WORD) as *const _;
749 let count: usize = (*reff).struct_ptr_count() as usize;
750 for i in 0..count {
751 result += total_size(arena, segment_id, pointer_section.add(i), nesting_limit)?;
752 }
753 }
754 WirePointerKind::List => {
755 match (*reff).list_element_size() {
756 Void => {}
757 Bit | Byte | TwoBytes | FourBytes | EightBytes => {
758 let total_words = round_bits_up_to_words(
759 u64::from((*reff).list_element_count())
760 * u64::from(data_bits_per_element((*reff).list_element_size())),
761 );
762 bounds_check(
763 arena,
764 segment_id,
765 ptr,
766 total_words as usize,
767 WirePointerKind::List,
768 )?;
769 result.word_count += u64::from(total_words);
770 }
771 Pointer => {
772 let count = (*reff).list_element_count();
773 bounds_check(
774 arena,
775 segment_id,
776 ptr,
777 count as usize * WORDS_PER_POINTER,
778 WirePointerKind::List,
779 )?;
780
781 result.word_count += u64::from(count) * WORDS_PER_POINTER as u64;
782
783 for i in 0..count as usize {
784 result += total_size(
785 arena,
786 segment_id,
787 (ptr as *const WirePointer).add(i),
788 nesting_limit,
789 )?;
790 }
791 }
792 InlineComposite => {
793 let word_count = (*reff).list_inline_composite_word_count();
794 bounds_check(
795 arena,
796 segment_id,
797 ptr,
798 word_count as usize + POINTER_SIZE_IN_WORDS,
799 WirePointerKind::List,
800 )?;
801
802 let element_tag: *const WirePointer = ptr as *const _;
803 let count = (*element_tag).inline_composite_list_element_count();
804
805 if (*element_tag).kind() != WirePointerKind::Struct {
806 return Err(Error::from_kind(
807 ErrorKind::CantHandleNonStructInlineComposite,
808 ));
809 }
810
811 let actual_size =
812 u64::from((*element_tag).struct_word_size()) * u64::from(count);
813 if actual_size > u64::from(word_count) {
814 return Err(Error::from_kind(
815 ErrorKind::InlineCompositeListsElementsOverrunItsWordCount,
816 ));
817 }
818
819 result.word_count += actual_size + POINTER_SIZE_IN_WORDS as u64;
822
823 let data_size = (*element_tag).struct_data_size();
824 let pointer_count = (*element_tag).struct_ptr_count();
825
826 if pointer_count > 0 {
827 let mut pos = ptr.add(BYTES_PER_WORD);
828 for _ in 0..count {
829 pos = pos.add(data_size as usize * BYTES_PER_WORD);
830
831 for _ in 0..pointer_count {
832 result += total_size(
833 arena,
834 segment_id,
835 pos as *const WirePointer,
836 nesting_limit,
837 )?;
838 pos = pos.add(BYTES_PER_WORD);
839 }
840 }
841 }
842 }
843 }
844 }
845 WirePointerKind::Far => {
846 return Err(Error::from_kind(ErrorKind::MalformedDoubleFarPointer));
847 }
848 WirePointerKind::Other => {
849 if (*reff).is_capability() {
850 result.cap_count += 1;
851 } else {
852 return Err(Error::from_kind(ErrorKind::UnknownPointerType));
853 }
854 }
855 }
856
857 Ok(result)
858 }
859
860 unsafe fn copy_struct(
862 arena: &mut dyn BuilderArena,
863 segment_id: u32,
864 cap_table: CapTableBuilder,
865 dst: *mut u8,
866 src: *const u8,
867 data_size: usize,
868 pointer_count: usize,
869 ) {
870 copy_nonoverlapping_check_zero(src, dst, data_size * BYTES_PER_WORD);
871
872 let src_refs: *const WirePointer = (src as *const WirePointer).add(data_size);
873 let dst_refs: *mut WirePointer = (dst as *mut WirePointer).add(data_size);
874
875 for ii in 0..pointer_count {
876 copy_message(
877 arena,
878 segment_id,
879 cap_table,
880 dst_refs.add(ii),
881 src_refs.add(ii),
882 );
883 }
884 }
885
886 pub(crate) unsafe fn copy_message(
889 arena: &mut dyn BuilderArena,
890 segment_id: u32,
891 cap_table: CapTableBuilder,
892 dst: *mut WirePointer,
893 src: *const WirePointer,
894 ) -> (*mut u8, *mut WirePointer, u32) {
895 match (*src).kind() {
896 WirePointerKind::Struct => {
897 if (*src).is_null() {
898 ptr::write_bytes(dst, 0, 1);
899 (ptr::null_mut(), dst, segment_id)
900 } else {
901 let src_ptr = WirePointer::target(src);
902 let (dst_ptr, dst, segment_id) = allocate(
903 arena,
904 dst,
905 segment_id,
906 (*src).struct_word_size(),
907 WirePointerKind::Struct,
908 );
909 copy_struct(
910 arena,
911 segment_id,
912 cap_table,
913 dst_ptr,
914 src_ptr,
915 (*src).struct_data_size() as usize,
916 (*src).struct_ptr_count() as usize,
917 );
918 (*dst).set_struct_size_from_pieces(
919 (*src).struct_data_size(),
920 (*src).struct_ptr_count(),
921 );
922 (dst_ptr, dst, segment_id)
923 }
924 }
925 WirePointerKind::List => match (*src).list_element_size() {
926 ElementSize::Void
927 | ElementSize::Bit
928 | ElementSize::Byte
929 | ElementSize::TwoBytes
930 | ElementSize::FourBytes
931 | ElementSize::EightBytes => {
932 let word_count = round_bits_up_to_words(
933 u64::from((*src).list_element_count())
934 * u64::from(data_bits_per_element((*src).list_element_size())),
935 );
936 let src_ptr = WirePointer::target(src);
937 let (dst_ptr, dst, segment_id) =
938 allocate(arena, dst, segment_id, word_count, WirePointerKind::List);
939 copy_nonoverlapping_check_zero(
940 src_ptr,
941 dst_ptr,
942 word_count as usize * BYTES_PER_WORD,
943 );
944 (*dst).set_list_size_and_count(
945 (*src).list_element_size(),
946 (*src).list_element_count(),
947 );
948 (dst_ptr, dst, segment_id)
949 }
950
951 ElementSize::Pointer => {
952 let src_refs: *const WirePointer = WirePointer::target(src) as _;
953 let (dst_refs, dst, segment_id) = allocate(
954 arena,
955 dst,
956 segment_id,
957 (*src).list_element_count(),
958 WirePointerKind::List,
959 );
960 for ii in 0..((*src).list_element_count() as usize) {
961 copy_message(
962 arena,
963 segment_id,
964 cap_table,
965 dst_refs.add(ii * BYTES_PER_WORD) as *mut WirePointer,
966 src_refs.add(ii),
967 );
968 }
969 (*dst)
970 .set_list_size_and_count(ElementSize::Pointer, (*src).list_element_count());
971 (dst_refs, dst, segment_id)
972 }
973 ElementSize::InlineComposite => {
974 let src_ptr = WirePointer::target(src);
975 let (dst_ptr, dst, segment_id) = allocate(
976 arena,
977 dst,
978 segment_id,
979 (*src).list_inline_composite_word_count() + 1,
980 WirePointerKind::List,
981 );
982
983 (*dst).set_list_inline_composite((*src).list_inline_composite_word_count());
984
985 let src_tag: *const WirePointer = src_ptr as _;
986 ptr::copy_nonoverlapping(src_tag, dst_ptr as *mut WirePointer, 1);
987
988 let mut src_element = src_ptr.add(BYTES_PER_WORD);
989 let mut dst_element = dst_ptr.add(BYTES_PER_WORD);
990
991 if (*src_tag).kind() != WirePointerKind::Struct {
992 panic!("unsupported INLINE_COMPOSITE list");
993 }
994 for _ in 0..(*src_tag).inline_composite_list_element_count() {
995 copy_struct(
996 arena,
997 segment_id,
998 cap_table,
999 dst_element,
1000 src_element,
1001 (*src_tag).struct_data_size() as usize,
1002 (*src_tag).struct_ptr_count() as usize,
1003 );
1004 src_element = src_element
1005 .add(BYTES_PER_WORD * (*src_tag).struct_word_size() as usize);
1006 dst_element = dst_element
1007 .add(BYTES_PER_WORD * (*src_tag).struct_word_size() as usize);
1008 }
1009 (dst_ptr, dst, segment_id)
1010 }
1011 },
1012 WirePointerKind::Other => {
1013 panic!("Unchecked message contained an OTHER pointer.")
1014 }
1015 WirePointerKind::Far => {
1016 panic!("Unchecked message contained a far pointer.")
1017 }
1018 }
1019 }
1020
1021 pub(crate) unsafe fn transfer_pointer(
1022 arena: &mut dyn BuilderArena,
1023 dst_segment_id: u32,
1024 dst: *mut WirePointer,
1025 src_segment_id: u32,
1026 src: *mut WirePointer,
1027 ) {
1028 assert!((*dst).is_null());
1039 if (*src).is_null() {
1042 ptr::write_bytes(dst, 0, 1);
1043 } else if (*src).is_positional() {
1044 transfer_pointer_split(
1045 arena,
1046 dst_segment_id,
1047 dst,
1048 src_segment_id,
1049 src,
1050 WirePointer::mut_target(src),
1051 );
1052 } else {
1053 ptr::copy_nonoverlapping(src, dst, 1);
1054 }
1055 }
1056
1057 pub(crate) unsafe fn transfer_pointer_split(
1058 arena: &mut dyn BuilderArena,
1059 dst_segment_id: u32,
1060 dst: *mut WirePointer,
1061 src_segment_id: u32,
1062 src_tag: *mut WirePointer,
1063 src_ptr: *mut u8,
1064 ) {
1065 if dst_segment_id == src_segment_id {
1069 if (*src_tag).kind() == WirePointerKind::Struct && (*src_tag).struct_word_size() == 0 {
1072 (*dst).set_kind_and_target_for_empty_struct();
1073 } else {
1074 (*dst).set_kind_and_target((*src_tag).kind(), src_ptr);
1075 }
1076 ptr::copy_nonoverlapping(&(*src_tag).upper32bits, &mut (*dst).upper32bits, 1);
1078 } else {
1079 match arena.allocate(src_segment_id, 1) {
1083 None => {
1084 let (far_segment_id, word_idx) = arena.allocate_anywhere(2);
1086 let (seg_start, _seg_len) = arena.get_segment_mut(far_segment_id);
1087 let landing_pad: *mut WirePointer =
1088 (seg_start as *mut WirePointer).add(word_idx as usize);
1089
1090 let (src_seg_start, _seg_len) = arena.get_segment_mut(src_segment_id);
1091
1092 (*landing_pad).set_far(
1093 false,
1094 u32::try_from((src_ptr as usize - src_seg_start as usize) / BYTES_PER_WORD)
1095 .unwrap(),
1096 );
1097 (*landing_pad).set_far_segment_id(src_segment_id);
1098
1099 let landing_pad1 = landing_pad.add(1);
1100 (*landing_pad1).set_kind_with_zero_offset((*src_tag).kind());
1101
1102 ptr::copy_nonoverlapping(
1103 &(*src_tag).upper32bits,
1104 &mut (*landing_pad1).upper32bits,
1105 1,
1106 );
1107
1108 (*dst).set_far(true, word_idx);
1109 (*dst).set_far_segment_id(far_segment_id);
1110 }
1111 Some(landing_pad_word) => {
1112 let (seg_start, seg_len) = arena.get_segment_mut(src_segment_id);
1114 assert!(landing_pad_word < seg_len);
1115 let landing_pad: *mut WirePointer =
1116 (seg_start as *mut WirePointer).add(landing_pad_word as usize);
1117 (*landing_pad).set_kind_and_target((*src_tag).kind(), src_ptr);
1118 ptr::copy_nonoverlapping(
1119 &(*src_tag).upper32bits,
1120 &mut (*landing_pad).upper32bits,
1121 1,
1122 );
1123
1124 (*dst).set_far(false, landing_pad_word);
1125 (*dst).set_far_segment_id(src_segment_id);
1126 }
1127 }
1128 }
1129 }
1130
1131 #[inline]
1132 pub(crate) unsafe fn init_struct_pointer(
1133 arena: &mut dyn BuilderArena,
1134 reff: *mut WirePointer,
1135 segment_id: u32,
1136 cap_table: CapTableBuilder,
1137 size: StructSize,
1138 ) -> StructBuilder<'_> {
1139 let (ptr, reff, segment_id) = allocate(
1140 arena,
1141 reff,
1142 segment_id,
1143 size.total(),
1144 WirePointerKind::Struct,
1145 );
1146 (*reff).set_struct_size(size);
1147
1148 StructBuilder {
1149 arena,
1150 segment_id,
1151 cap_table,
1152 data: ptr as *mut _,
1153 pointers: ptr.add(size.data as usize * BYTES_PER_WORD) as *mut _,
1154 data_size: u32::from(size.data) * BitCount32::try_from(BITS_PER_WORD).unwrap(),
1155 pointer_count: size.pointers,
1156 }
1157 }
1158
1159 #[inline]
1160 pub(crate) unsafe fn get_writable_struct_pointer<'a>(
1161 arena: &'a mut dyn BuilderArena,
1162 mut reff: *mut WirePointer,
1163 mut segment_id: u32,
1164 cap_table: CapTableBuilder,
1165 size: StructSize,
1166 default: Option<&'a [crate::Word]>,
1167 ) -> Result<StructBuilder<'a>> {
1168 let mut ref_target = WirePointer::mut_target(reff);
1169
1170 if (*reff).is_null() {
1171 match default {
1172 None => {
1173 return Ok(init_struct_pointer(
1174 arena, reff, segment_id, cap_table, size,
1175 ))
1176 }
1177 Some(d) if (*(d.as_ptr() as *const WirePointer)).is_null() => {
1178 return Ok(init_struct_pointer(
1179 arena, reff, segment_id, cap_table, size,
1180 ))
1181 }
1182 Some(d) => {
1183 let (new_ref_target, new_reff, new_segment_id) = copy_message(
1184 arena,
1185 segment_id,
1186 cap_table,
1187 reff,
1188 d.as_ptr() as *const WirePointer,
1189 );
1190 reff = new_reff;
1191 segment_id = new_segment_id;
1192 ref_target = new_ref_target;
1193 }
1194 }
1195 }
1196
1197 let (old_ptr, old_ref, old_segment_id) =
1198 follow_builder_fars(arena, reff, ref_target, segment_id)?;
1199 if (*old_ref).kind() != WirePointerKind::Struct {
1200 return Err(Error::from_kind(
1201 ErrorKind::MessageContainsNonStructPointerWhereStructPointerWasExpected,
1202 ));
1203 }
1204
1205 let old_data_size = (*old_ref).struct_data_size();
1206 let old_pointer_count = (*old_ref).struct_ptr_count();
1207 let old_pointer_section: *mut WirePointer =
1208 old_ptr.add(old_data_size as usize * BYTES_PER_WORD) as *mut _;
1209
1210 if old_data_size < size.data || old_pointer_count < size.pointers {
1211 let new_data_size = ::core::cmp::max(old_data_size, size.data);
1218 let new_pointer_count = ::core::cmp::max(old_pointer_count, size.pointers);
1219 let total_size = u32::from(new_data_size)
1220 + u32::from(new_pointer_count) * u32::try_from(WORDS_PER_POINTER).unwrap();
1221
1222 zero_pointer_and_fars(arena, segment_id, reff)?;
1224
1225 let (ptr, reff, segment_id) =
1226 allocate(arena, reff, segment_id, total_size, WirePointerKind::Struct);
1227 (*reff).set_struct_size_from_pieces(new_data_size, new_pointer_count);
1228
1229 copy_nonoverlapping_check_zero(old_ptr, ptr, old_data_size as usize * BYTES_PER_WORD);
1232
1233 let new_pointer_section: *mut WirePointer =
1235 ptr.add(new_data_size as usize * BYTES_PER_WORD) as *mut _;
1236 for i in 0..old_pointer_count as usize {
1237 transfer_pointer(
1238 arena,
1239 segment_id,
1240 new_pointer_section.add(i),
1241 old_segment_id,
1242 old_pointer_section.add(i),
1243 );
1244 }
1245
1246 ptr::write_bytes(
1247 old_ptr,
1248 0,
1249 (old_data_size as usize + old_pointer_count as usize) * BYTES_PER_WORD,
1250 );
1251
1252 Ok(StructBuilder {
1253 arena,
1254 segment_id,
1255 cap_table,
1256 data: ptr as *mut _,
1257 pointers: new_pointer_section,
1258 data_size: u32::from(new_data_size) * u32::try_from(BITS_PER_WORD).unwrap(),
1259 pointer_count: new_pointer_count,
1260 })
1261 } else {
1262 Ok(StructBuilder {
1263 arena,
1264 segment_id: old_segment_id,
1265 cap_table,
1266 data: old_ptr,
1267 pointers: old_pointer_section,
1268 data_size: u32::from(old_data_size) * u32::try_from(BITS_PER_WORD).unwrap(),
1269 pointer_count: old_pointer_count,
1270 })
1271 }
1272 }
1273
1274 #[inline]
1275 pub(crate) unsafe fn init_list_pointer(
1276 arena: &mut dyn BuilderArena,
1277 reff: *mut WirePointer,
1278 segment_id: u32,
1279 cap_table: CapTableBuilder,
1280 element_count: ElementCount32,
1281 element_size: ElementSize,
1282 ) -> ListBuilder<'_> {
1283 assert!(
1284 element_size != InlineComposite,
1285 "Should have called initStructListPointer() instead"
1286 );
1287
1288 let data_size = data_bits_per_element(element_size);
1289 let pointer_count = pointers_per_element(element_size);
1290 let step = data_size + pointer_count * u32::try_from(BITS_PER_POINTER).unwrap();
1291 let word_count = round_bits_up_to_words(u64::from(element_count) * u64::from(step));
1292 let (ptr, reff, segment_id) =
1293 allocate(arena, reff, segment_id, word_count, WirePointerKind::List);
1294
1295 (*reff).set_list_size_and_count(element_size, element_count);
1296
1297 ListBuilder {
1298 arena,
1299 segment_id,
1300 cap_table,
1301 ptr,
1302 step,
1303 element_count,
1304 element_size,
1305 struct_data_size: data_size,
1306 struct_pointer_count: u16::try_from(pointer_count).unwrap(),
1307 }
1308 }
1309
1310 #[inline]
1311 pub(crate) unsafe fn init_struct_list_pointer(
1312 arena: &mut dyn BuilderArena,
1313 reff: *mut WirePointer,
1314 segment_id: u32,
1315 cap_table: CapTableBuilder,
1316 element_count: ElementCount32,
1317 element_size: StructSize,
1318 ) -> ListBuilder<'_> {
1319 let words_per_element = element_size.total();
1320
1321 let word_count_u64 = u64::from(element_count) * u64::from(words_per_element);
1323 assert!(
1324 word_count_u64 < (1 << 29),
1325 "Inline composite lists are limited to 2**29 words"
1326 );
1327 let word_count: WordCount32 = WordCount32::try_from(word_count_u64).unwrap();
1328 let (ptr, reff, segment_id) = allocate(
1329 arena,
1330 reff,
1331 segment_id,
1332 u32::try_from(POINTER_SIZE_IN_WORDS).unwrap() + word_count,
1333 WirePointerKind::List,
1334 );
1335 let ptr = ptr as *mut WirePointer;
1336
1337 (*reff).set_list_inline_composite(word_count);
1339 (*ptr).set_kind_and_inline_composite_list_element_count(
1340 WirePointerKind::Struct,
1341 element_count,
1342 );
1343 (*ptr).set_struct_size(element_size);
1344
1345 let ptr1 = ptr.add(POINTER_SIZE_IN_WORDS);
1346
1347 ListBuilder {
1348 arena,
1349 segment_id,
1350 cap_table,
1351 ptr: ptr1 as *mut _,
1352 step: words_per_element * u32::try_from(BITS_PER_WORD).unwrap(),
1353 element_count,
1354 element_size: ElementSize::InlineComposite,
1355 struct_data_size: u32::from(element_size.data)
1356 * (u32::try_from(BITS_PER_WORD).unwrap()),
1357 struct_pointer_count: element_size.pointers,
1358 }
1359 }
1360
1361 #[inline]
1362 pub(crate) unsafe fn get_writable_list_pointer(
1363 arena: &mut dyn BuilderArena,
1364 mut orig_ref: *mut WirePointer,
1365 mut orig_segment_id: u32,
1366 cap_table: CapTableBuilder,
1367 element_size: ElementSize,
1368 default_value: *const u8,
1369 ) -> Result<ListBuilder<'_>> {
1370 assert!(
1371 element_size != InlineComposite,
1372 "Use get_writable_struct_list_pointer() for struct lists"
1373 );
1374
1375 let mut orig_ref_target = WirePointer::mut_target(orig_ref);
1376
1377 if (*orig_ref).is_null() {
1378 if default_value.is_null() || (*(default_value as *const WirePointer)).is_null() {
1379 return Ok(ListBuilder::new_default(arena));
1380 }
1381 let (new_orig_ref_target, new_orig_ref, new_orig_segment_id) = copy_message(
1382 arena,
1383 orig_segment_id,
1384 cap_table,
1385 orig_ref,
1386 default_value as *const WirePointer,
1387 );
1388 orig_ref_target = new_orig_ref_target;
1389 orig_ref = new_orig_ref;
1390 orig_segment_id = new_orig_segment_id;
1391 }
1392
1393 let (mut ptr, reff, segment_id) =
1399 follow_builder_fars(arena, orig_ref, orig_ref_target, orig_segment_id)?;
1400
1401 if (*reff).kind() != WirePointerKind::List {
1402 return Err(Error::from_kind(ErrorKind::ExistingPointerIsNotAList));
1403 }
1404
1405 let old_size = (*reff).list_element_size();
1406
1407 if old_size == InlineComposite {
1408 let tag: *const WirePointer = ptr as *const _;
1416
1417 if (*tag).kind() != WirePointerKind::Struct {
1418 return Err(Error::from_kind(
1419 ErrorKind::InlineCompositeListWithNonStructElementsNotSupported,
1420 ));
1421 }
1422
1423 ptr = ptr.add(BYTES_PER_WORD);
1424
1425 let data_size = (*tag).struct_data_size();
1426 let pointer_count = (*tag).struct_ptr_count();
1427
1428 match element_size {
1429 Void => {} Bit => {
1431 return Err(Error::from_kind(
1432 ErrorKind::FoundStructListWhereBitListWasExpected,
1433 ));
1434 }
1435 Byte | TwoBytes | FourBytes | EightBytes => {
1436 if data_size < 1 {
1437 return Err(Error::from_kind(
1438 ErrorKind::ExistingListValueIsIncompatibleWithExpectedType,
1439 ));
1440 }
1441 }
1442 Pointer => {
1443 if pointer_count < 1 {
1444 return Err(Error::from_kind(
1445 ErrorKind::ExistingListValueIsIncompatibleWithExpectedType,
1446 ));
1447 }
1448 ptr = ptr.add(data_size as usize * BYTES_PER_WORD);
1450 }
1451 InlineComposite => {
1452 unreachable!()
1453 }
1454 }
1455 Ok(ListBuilder {
1458 arena,
1459 segment_id,
1460 cap_table,
1461 ptr: ptr as *mut _,
1462 element_count: (*tag).inline_composite_list_element_count(),
1463 element_size: ElementSize::InlineComposite,
1464 step: (*tag).struct_word_size() * u32::try_from(BITS_PER_WORD).unwrap(),
1465 struct_data_size: u32::from(data_size) * u32::try_from(BITS_PER_WORD).unwrap(),
1466 struct_pointer_count: pointer_count,
1467 })
1468 } else {
1469 let data_size = data_bits_per_element(old_size);
1470 let pointer_count = pointers_per_element(old_size);
1471
1472 if data_size < data_bits_per_element(element_size)
1473 || pointer_count < pointers_per_element(element_size)
1474 {
1475 return Err(Error::from_kind(
1476 ErrorKind::ExistingListValueIsIncompatibleWithExpectedType,
1477 ));
1478 }
1479
1480 let step = data_size + pointer_count * u32::try_from(BITS_PER_POINTER).unwrap();
1481
1482 Ok(ListBuilder {
1483 arena,
1484 segment_id,
1485 cap_table,
1486 ptr: ptr as *mut _,
1487 step,
1488 element_count: (*reff).list_element_count(),
1489 element_size: old_size,
1490 struct_data_size: data_size,
1491 struct_pointer_count: u16::try_from(pointer_count).unwrap(),
1492 })
1493 }
1494 }
1495
1496 #[inline]
1497 pub(crate) unsafe fn get_writable_struct_list_pointer(
1498 arena: &mut dyn BuilderArena,
1499 mut orig_ref: *mut WirePointer,
1500 mut orig_segment_id: u32,
1501 cap_table: CapTableBuilder,
1502 element_size: StructSize,
1503 default_value: *const u8,
1504 ) -> Result<ListBuilder<'_>> {
1505 let mut orig_ref_target = WirePointer::mut_target(orig_ref);
1506
1507 if (*orig_ref).is_null() {
1508 if default_value.is_null() || (*(default_value as *const WirePointer)).is_null() {
1509 return Ok(ListBuilder::new_default(arena));
1510 }
1511 let (new_orig_ref_target, new_orig_ref, new_orig_segment_id) = copy_message(
1512 arena,
1513 orig_segment_id,
1514 cap_table,
1515 orig_ref,
1516 default_value as *const WirePointer,
1517 );
1518 orig_ref_target = new_orig_ref_target;
1519 orig_ref = new_orig_ref;
1520 orig_segment_id = new_orig_segment_id;
1521 }
1522
1523 let (mut old_ptr, old_ref, old_segment_id) =
1526 follow_builder_fars(arena, orig_ref, orig_ref_target, orig_segment_id)?;
1527
1528 if (*old_ref).kind() != WirePointerKind::List {
1529 return Err(Error::from_kind(ErrorKind::ExistingPointerIsNotAList));
1530 }
1531
1532 let old_size = (*old_ref).list_element_size();
1533
1534 if old_size == InlineComposite {
1535 let old_tag: *const WirePointer = old_ptr as *const _;
1538 old_ptr = old_ptr.add(BYTES_PER_WORD);
1539 if (*old_tag).kind() != WirePointerKind::Struct {
1540 return Err(Error::from_kind(
1541 ErrorKind::InlineCompositeListWithNonStructElementsNotSupported,
1542 ));
1543 }
1544
1545 let old_data_size = (*old_tag).struct_data_size();
1546 let old_pointer_count = (*old_tag).struct_ptr_count();
1547 let old_step = u32::from(old_data_size)
1548 + u32::from(old_pointer_count) * u32::try_from(WORDS_PER_POINTER).unwrap();
1549 let element_count = (*old_tag).inline_composite_list_element_count();
1550
1551 if old_data_size >= element_size.data && old_pointer_count >= element_size.pointers {
1552 return Ok(ListBuilder {
1554 arena,
1555 segment_id: old_segment_id,
1556 cap_table,
1557 ptr: old_ptr as *mut _,
1558 element_count,
1559 element_size: ElementSize::InlineComposite,
1560 step: old_step * u32::try_from(BITS_PER_WORD).unwrap(),
1561 struct_data_size: u32::from(old_data_size)
1562 * u32::try_from(BITS_PER_WORD).unwrap(),
1563 struct_pointer_count: old_pointer_count,
1564 });
1565 }
1566
1567 let new_data_size = ::core::cmp::max(old_data_size, element_size.data);
1571 let new_pointer_count = ::core::cmp::max(old_pointer_count, element_size.pointers);
1572 let new_step = u32::from(new_data_size)
1573 + u32::from(new_pointer_count) * u32::try_from(WORDS_PER_POINTER).unwrap();
1574
1575 let total_size_u64 = u64::from(new_step) * u64::from(element_count);
1576 if total_size_u64 >= (1 << 29) {
1577 return Err(Error::from_kind(ErrorKind::MessageTooLarge(
1578 usize::try_from(total_size_u64).unwrap_or(usize::MAX),
1579 )));
1580 }
1581 let total_size = u32::try_from(total_size_u64).unwrap();
1582
1583 zero_pointer_and_fars(arena, orig_segment_id, orig_ref)?;
1585
1586 let (mut new_ptr, new_ref, new_segment_id) = allocate(
1587 arena,
1588 orig_ref,
1589 orig_segment_id,
1590 total_size + u32::try_from(POINTER_SIZE_IN_WORDS).unwrap(),
1591 WirePointerKind::List,
1592 );
1593 (*new_ref).set_list_inline_composite(total_size);
1594
1595 let new_tag: *mut WirePointer = new_ptr as *mut _;
1596 (*new_tag).set_kind_and_inline_composite_list_element_count(
1597 WirePointerKind::Struct,
1598 element_count,
1599 );
1600 (*new_tag).set_struct_size_from_pieces(new_data_size, new_pointer_count);
1601 new_ptr = new_ptr.add(BYTES_PER_WORD);
1602
1603 let mut src = old_ptr as *mut WirePointer;
1604 let mut dst = new_ptr as *mut WirePointer;
1605 for _ in 0..element_count {
1606 copy_nonoverlapping_check_zero(src, dst, old_data_size as usize);
1608
1609 let new_pointer_section = dst.add(new_data_size as usize);
1611 let old_pointer_section = src.add(old_data_size as usize);
1612 for jj in 0..(old_pointer_count as usize) {
1613 transfer_pointer(
1614 arena,
1615 new_segment_id,
1616 new_pointer_section.add(jj),
1617 old_segment_id,
1618 old_pointer_section.add(jj),
1619 );
1620 }
1621
1622 dst = dst.add(new_step as usize);
1623 src = src.add(old_step as usize);
1624 }
1625
1626 ptr::write_bytes(
1628 old_ptr.sub(BYTES_PER_WORD),
1629 0,
1630 usize::try_from(u64::from(old_step) * u64::from(element_count)).unwrap()
1631 * BYTES_PER_WORD
1632 + POINTER_SIZE_IN_WORDS,
1633 );
1634
1635 Ok(ListBuilder {
1636 arena,
1637 segment_id: new_segment_id,
1638 cap_table,
1639 ptr: new_ptr,
1640 element_count,
1641 element_size: ElementSize::InlineComposite,
1642 step: new_step * u32::try_from(BITS_PER_WORD).unwrap(),
1643 struct_data_size: u32::from(new_data_size) * u32::try_from(BITS_PER_WORD).unwrap(),
1644 struct_pointer_count: new_pointer_count,
1645 })
1646 } else {
1647 let old_data_size = data_bits_per_element(old_size);
1650 let old_pointer_count = pointers_per_element(old_size);
1651 let old_step =
1652 old_data_size + old_pointer_count * u32::try_from(BITS_PER_POINTER).unwrap();
1653 let element_count = (*old_ref).list_element_count();
1654
1655 if old_size == ElementSize::Void {
1656 Ok(init_struct_list_pointer(
1658 arena,
1659 orig_ref,
1660 orig_segment_id,
1661 cap_table,
1662 element_count,
1663 element_size,
1664 ))
1665 } else {
1666 if old_size == ElementSize::Bit {
1669 return Err(Error::from_kind(
1670 ErrorKind::FoundBitListWhereStructListWasExpected,
1671 ));
1672 }
1673
1674 let mut new_data_size = element_size.data;
1675 let mut new_pointer_count = element_size.pointers;
1676
1677 if old_size == ElementSize::Pointer {
1678 new_pointer_count = ::core::cmp::max(new_pointer_count, 1);
1679 } else {
1680 new_data_size = ::core::cmp::max(new_data_size, 1);
1682 }
1683
1684 let new_step = u32::from(new_data_size)
1685 + u32::from(new_pointer_count) * u32::try_from(WORDS_PER_POINTER).unwrap();
1686
1687 let total_words_u64 = u64::from(new_step) * u64::from(element_count);
1688 if total_words_u64 >= (1 << 29) {
1689 return Err(Error::from_kind(ErrorKind::MessageTooLarge(
1690 usize::try_from(total_words_u64).unwrap_or(usize::MAX),
1691 )));
1692 }
1693 let total_words = u32::try_from(total_words_u64).unwrap();
1694
1695 zero_pointer_and_fars(arena, orig_segment_id, orig_ref)?;
1697
1698 let (mut new_ptr, new_ref, new_segment_id) = allocate(
1699 arena,
1700 orig_ref,
1701 orig_segment_id,
1702 total_words + u32::try_from(POINTER_SIZE_IN_WORDS).unwrap(),
1703 WirePointerKind::List,
1704 );
1705 (*new_ref).set_list_inline_composite(total_words);
1706
1707 let tag: *mut WirePointer = new_ptr as *mut _;
1708 (*tag).set_kind_and_inline_composite_list_element_count(
1709 WirePointerKind::Struct,
1710 element_count,
1711 );
1712 (*tag).set_struct_size_from_pieces(new_data_size, new_pointer_count);
1713 new_ptr = new_ptr.add(BYTES_PER_WORD);
1714
1715 if old_size == ElementSize::Pointer {
1716 let mut dst = new_ptr.add(new_data_size as usize * BYTES_PER_WORD);
1717 let mut src: *mut WirePointer = old_ptr as *mut _;
1718 for _ in 0..element_count {
1719 transfer_pointer(arena, new_segment_id, dst as *mut _, old_segment_id, src);
1720 dst = dst.add(new_step as usize * BYTES_PER_WORD);
1721 src = src.add(1);
1722 }
1723 } else {
1724 let mut dst = new_ptr;
1725 let mut src: *mut u8 = old_ptr;
1726 let old_byte_step = old_data_size / u32::try_from(BITS_PER_BYTE).unwrap();
1727 for _ in 0..element_count {
1728 copy_nonoverlapping_check_zero(src, dst, old_byte_step as usize);
1729 src = src.add(old_byte_step as usize);
1730 dst = dst.add(new_step as usize * BYTES_PER_WORD);
1731 }
1732 }
1733
1734 ptr::write_bytes(
1736 old_ptr,
1737 0,
1738 round_bits_up_to_bytes(u64::from(old_step) * u64::from(element_count)) as usize,
1739 );
1740
1741 Ok(ListBuilder {
1742 arena,
1743 segment_id: new_segment_id,
1744 cap_table,
1745 ptr: new_ptr,
1746 element_count,
1747 element_size: ElementSize::InlineComposite,
1748 step: new_step * u32::try_from(BITS_PER_WORD).unwrap(),
1749 struct_data_size: u32::from(new_data_size)
1750 * u32::try_from(BITS_PER_WORD).unwrap(),
1751 struct_pointer_count: new_pointer_count,
1752 })
1753 }
1754 }
1755 }
1756
1757 #[inline]
1758 pub(crate) unsafe fn init_text_pointer(
1759 arena: &mut dyn BuilderArena,
1760 reff: *mut WirePointer,
1761 segment_id: u32,
1762 size: ByteCount32,
1763 ) -> SegmentAnd<text::Builder<'_>> {
1764 assert!(size < (1 << 29), "text size too large");
1765
1766 let byte_size = size + 1;
1768
1769 let (ptr, reff, segment_id) = allocate(
1771 arena,
1772 reff,
1773 segment_id,
1774 round_bytes_up_to_words(byte_size),
1775 WirePointerKind::List,
1776 );
1777
1778 (*reff).set_list_size_and_count(Byte, byte_size);
1780
1781 SegmentAnd {
1782 segment_id,
1783 value: text::Builder::new(slice::from_raw_parts_mut(ptr, size as usize)),
1784 }
1785 }
1786
1787 #[inline]
1788 pub(crate) unsafe fn set_text_pointer<'a>(
1789 arena: &'a mut dyn BuilderArena,
1790 reff: *mut WirePointer,
1791 segment_id: u32,
1792 value: crate::text::Reader<'_>,
1793 ) -> SegmentAnd<text::Builder<'a>> {
1794 let value_bytes = value.as_bytes();
1795 let mut allocation = init_text_pointer(
1797 arena,
1798 reff,
1799 segment_id,
1800 u32::try_from(value_bytes.len()).expect("Text len does not fit in u32"),
1801 );
1802 allocation
1803 .value
1804 .reborrow()
1805 .as_bytes_mut()
1806 .copy_from_slice(value_bytes);
1807 allocation
1808 }
1809
1810 #[inline]
1811 pub(crate) unsafe fn get_writable_text_pointer<'a>(
1812 arena: &'a mut dyn BuilderArena,
1813 mut reff: *mut WirePointer,
1814 mut segment_id: u32,
1815 default: Option<&'a [crate::Word]>,
1816 ) -> Result<text::Builder<'a>> {
1817 let ref_target = if (*reff).is_null() {
1818 match default {
1819 None => return Ok(text::Builder::new(&mut [])),
1820 Some(d) => {
1821 let (new_ref_target, new_reff, new_segment_id) = copy_message(
1822 arena,
1823 segment_id,
1824 Default::default(),
1825 reff,
1826 d.as_ptr() as *const _,
1827 );
1828 reff = new_reff;
1829 segment_id = new_segment_id;
1830 new_ref_target
1831 }
1832 }
1833 } else {
1834 WirePointer::mut_target(reff)
1835 };
1836
1837 let (ptr, reff, _segment_id) = follow_builder_fars(arena, reff, ref_target, segment_id)?;
1838
1839 if (*reff).kind() != WirePointerKind::List {
1840 return Err(Error::from_kind(ErrorKind::ExistingPointerIsNotAList));
1841 }
1842 if (*reff).list_element_size() != Byte {
1843 return Err(Error::from_kind(
1844 ErrorKind::ExistingListPointerIsNotByteSized,
1845 ));
1846 }
1847
1848 let count = (*reff).list_element_count();
1849 if count == 0 || *ptr.add((count - 1) as usize) != 0 {
1850 return Err(Error::from_kind(ErrorKind::TextBlobMissingNULTerminator));
1851 }
1852
1853 Ok(text::Builder::with_pos(
1855 slice::from_raw_parts_mut(ptr, (count - 1) as usize),
1856 (count - 1) as usize,
1857 ))
1858 }
1859
1860 #[inline]
1861 pub(crate) unsafe fn init_data_pointer(
1862 arena: &mut dyn BuilderArena,
1863 reff: *mut WirePointer,
1864 segment_id: u32,
1865 size: ByteCount32,
1866 ) -> SegmentAnd<data::Builder<'_>> {
1867 let (ptr, reff, segment_id) = allocate(
1869 arena,
1870 reff,
1871 segment_id,
1872 round_bytes_up_to_words(size),
1873 WirePointerKind::List,
1874 );
1875
1876 (*reff).set_list_size_and_count(Byte, size);
1878
1879 SegmentAnd {
1880 segment_id,
1881 value: data::builder_from_raw_parts(ptr, size),
1882 }
1883 }
1884
1885 #[inline]
1886 pub(crate) unsafe fn set_data_pointer<'a>(
1887 arena: &'a mut dyn BuilderArena,
1888 reff: *mut WirePointer,
1889 segment_id: u32,
1890 value: &[u8],
1891 ) -> SegmentAnd<data::Builder<'a>> {
1892 let allocation = init_data_pointer(
1893 arena,
1894 reff,
1895 segment_id,
1896 value.len().try_into().expect("data too large"),
1897 );
1898 allocation.value.copy_from_slice(value);
1899 allocation
1900 }
1901
1902 #[inline]
1903 pub(crate) unsafe fn get_writable_data_pointer<'a>(
1904 arena: &'a mut dyn BuilderArena,
1905 mut reff: *mut WirePointer,
1906 mut segment_id: u32,
1907 default: Option<&'a [crate::Word]>,
1908 ) -> Result<data::Builder<'a>> {
1909 let ref_target = if (*reff).is_null() {
1910 match default {
1911 None => return Ok(&mut []),
1912 Some(d) => {
1913 let (new_ref_target, new_reff, new_segment_id) = copy_message(
1914 arena,
1915 segment_id,
1916 Default::default(),
1917 reff,
1918 d.as_ptr() as *const _,
1919 );
1920 reff = new_reff;
1921 segment_id = new_segment_id;
1922 new_ref_target
1923 }
1924 }
1925 } else {
1926 WirePointer::mut_target(reff)
1927 };
1928
1929 let (ptr, reff, _segment_id) = follow_builder_fars(arena, reff, ref_target, segment_id)?;
1930
1931 if (*reff).kind() != WirePointerKind::List {
1932 return Err(Error::from_kind(ErrorKind::ExistingPointerIsNotAList));
1933 }
1934 if (*reff).list_element_size() != Byte {
1935 return Err(Error::from_kind(
1936 ErrorKind::ExistingListPointerIsNotByteSized,
1937 ));
1938 }
1939
1940 Ok(data::builder_from_raw_parts(
1941 ptr,
1942 (*reff).list_element_count(),
1943 ))
1944 }
1945
1946 pub(crate) unsafe fn set_struct_pointer(
1947 arena: &mut dyn BuilderArena,
1948 segment_id: u32,
1949 cap_table: CapTableBuilder,
1950 reff: *mut WirePointer,
1951 value: StructReader,
1952 canonicalize: bool,
1953 ) -> Result<SegmentAnd<*mut u8>> {
1954 let mut data_size: ByteCount32 = round_bits_up_to_bytes(u64::from(value.data_size));
1955 let mut ptr_count = value.pointer_count;
1956
1957 if canonicalize {
1958 if !(value.data_size == 1
1960 || value.data_size % u32::try_from(BITS_PER_BYTE).unwrap() == 0)
1961 {
1962 return Err(Error::from_kind(
1963 ErrorKind::StructReaderHadBitwidthOtherThan1,
1964 ));
1965 }
1966
1967 if value.data_size == 1 {
1968 if !value.get_bool_field(0) {
1969 data_size = 0;
1970 }
1971 } else {
1972 'chop: while data_size != 0 {
1973 let end = data_size;
1974 let mut window = data_size % u32::try_from(BYTES_PER_WORD).unwrap();
1975 if window == 0 {
1976 window = u32::try_from(BYTES_PER_WORD).unwrap();
1977 }
1978 let start = end - window;
1979 let last_word = &value.get_data_section_as_blob()[start as usize..end as usize];
1980 if last_word == [0; 8] {
1981 data_size -= window;
1982 } else {
1983 break 'chop;
1984 }
1985 }
1986 }
1987
1988 while ptr_count != 0 && value.get_pointer_field(ptr_count as usize - 1).is_null() {
1989 ptr_count -= 1;
1990 }
1991 }
1992
1993 let data_words = round_bytes_up_to_words(data_size);
1994 let total_size: WordCount32 =
1995 data_words + u32::from(ptr_count) * u32::try_from(WORDS_PER_POINTER).unwrap();
1996
1997 let (ptr, reff, segment_id) =
1998 allocate(arena, reff, segment_id, total_size, WirePointerKind::Struct);
1999 (*reff).set_struct_size_from_pieces(u16::try_from(data_words).unwrap(), ptr_count);
2000
2001 if value.data_size == 1 {
2002 if data_size != 0 {
2004 *ptr = u8::from(value.get_bool_field(0))
2005 }
2006 } else {
2007 copy_nonoverlapping_check_zero::<u8>(value.data, ptr, data_size as usize);
2008 }
2009
2010 let pointer_section: *mut WirePointer =
2011 ptr.add(data_words as usize * BYTES_PER_WORD) as *mut _;
2012 for i in 0..ptr_count as usize {
2013 deep_copy_pointee(
2014 arena,
2015 segment_id,
2016 cap_table,
2017 pointer_section.add(i),
2018 value.get_pointer_field(i),
2019 canonicalize,
2020 )?;
2021 }
2022
2023 Ok(SegmentAnd {
2024 segment_id,
2025 value: ptr,
2026 })
2027 }
2028
2029 #[cfg(feature = "alloc")]
2030 pub(crate) unsafe fn set_capability_pointer(
2031 _arena: &mut dyn BuilderArena,
2032 _segment_id: u32,
2033 mut cap_table: CapTableBuilder,
2034 reff: *mut WirePointer,
2035 cap: alloc::boxed::Box<dyn ClientHook>,
2036 ) {
2037 (*reff).set_cap(u32::try_from(cap_table.inject_cap(cap)).unwrap());
2039 }
2040
2041 pub(crate) unsafe fn set_list_pointer(
2042 arena: &mut dyn BuilderArena,
2043 segment_id: u32,
2044 cap_table: CapTableBuilder,
2045 reff: *mut WirePointer,
2046 value: ListReader,
2047 canonicalize: bool,
2048 ) -> Result<SegmentAnd<*mut u8>> {
2049 let total_size =
2050 round_bits_up_to_words(u64::from(value.element_count) * u64::from(value.step));
2051
2052 if value.element_size != ElementSize::InlineComposite {
2053 let (ptr, reff, segment_id) =
2055 allocate(arena, reff, segment_id, total_size, WirePointerKind::List);
2056
2057 if value.struct_pointer_count == 1 {
2058 (*reff).set_list_size_and_count(Pointer, value.element_count);
2060 for i in 0..value.element_count {
2061 deep_copy_pointee(
2062 arena,
2063 segment_id,
2064 cap_table,
2065 (ptr as *mut WirePointer).add(i as usize),
2066 value.get_pointer_element(i),
2067 canonicalize,
2068 )?;
2069 }
2070 } else {
2071 let element_size = match value.step {
2073 0 => Void,
2074 1 => Bit,
2075 8 => Byte,
2076 16 => TwoBytes,
2077 32 => FourBytes,
2078 64 => EightBytes,
2079 _ => {
2080 panic!("invalid list step size: {}", value.step)
2081 }
2082 };
2083
2084 (*reff).set_list_size_and_count(element_size, value.element_count);
2085
2086 let whole_byte_size =
2091 u64::from(value.element_count) * u64::from(value.step) / BITS_PER_BYTE as u64;
2092 copy_nonoverlapping_check_zero(
2093 value.ptr,
2094 ptr,
2095 usize::try_from(whole_byte_size).unwrap(),
2096 );
2097
2098 let leftover_bits = u8::try_from(
2099 u64::from(value.element_count) * u64::from(value.step)
2100 % u64::try_from(BITS_PER_BYTE).unwrap(),
2101 )
2102 .unwrap();
2103 if leftover_bits > 0 {
2104 let mask: u8 = (1 << leftover_bits) - 1;
2105
2106 *ptr.add(usize::try_from(whole_byte_size).unwrap()) =
2107 mask & (*value.ptr.add(usize::try_from(whole_byte_size).unwrap()))
2108 }
2109 }
2110
2111 Ok(SegmentAnd {
2112 segment_id,
2113 value: ptr,
2114 })
2115 } else {
2116 let decl_data_size = value.struct_data_size / u32::try_from(BITS_PER_WORD).unwrap();
2119 let decl_pointer_count = value.struct_pointer_count;
2120
2121 let mut data_size = 0;
2122 let mut ptr_count = 0;
2123 let mut total_size = total_size;
2124
2125 if canonicalize {
2126 for ec in 0..value.element_count {
2127 let se = value.get_struct_element(ec);
2128 let mut local_data_size = decl_data_size;
2129 'data_chop: while local_data_size != 0 {
2130 let end = local_data_size * u32::try_from(BYTES_PER_WORD).unwrap();
2131 let window = u32::try_from(BYTES_PER_WORD).unwrap();
2132 let start = end - window;
2133 let last_word =
2134 &se.get_data_section_as_blob()[start as usize..end as usize];
2135 if last_word != [0; 8] {
2136 break 'data_chop;
2137 } else {
2138 local_data_size -= 1;
2139 }
2140 }
2141 if local_data_size > data_size {
2142 data_size = local_data_size;
2143 }
2144 let mut local_ptr_count = decl_pointer_count;
2145 while local_ptr_count != 0
2146 && se.get_pointer_field(local_ptr_count as usize - 1).is_null()
2147 {
2148 local_ptr_count -= 1;
2149 }
2150 if local_ptr_count > ptr_count {
2151 ptr_count = local_ptr_count;
2152 }
2153 }
2154 total_size = (data_size + u32::from(ptr_count)) * value.element_count;
2155 } else {
2156 data_size = decl_data_size;
2157 ptr_count = decl_pointer_count;
2158 }
2159
2160 let (ptr, reff, segment_id) = allocate(
2161 arena,
2162 reff,
2163 segment_id,
2164 total_size + u32::try_from(POINTER_SIZE_IN_WORDS).unwrap(),
2165 WirePointerKind::List,
2166 );
2167 (*reff).set_list_inline_composite(total_size);
2168
2169 let tag: *mut WirePointer = ptr as *mut _;
2170 (*tag).set_kind_and_inline_composite_list_element_count(
2171 WirePointerKind::Struct,
2172 value.element_count,
2173 );
2174 (*tag).set_struct_size_from_pieces(u16::try_from(data_size).unwrap(), ptr_count);
2175 let mut dst = ptr.add(BYTES_PER_WORD);
2176
2177 let mut src: *const u8 = value.ptr;
2178 for _ in 0..value.element_count {
2179 copy_nonoverlapping_check_zero(src, dst, data_size as usize * BYTES_PER_WORD);
2180 dst = dst.add(data_size as usize * BYTES_PER_WORD);
2181 src = src.add(decl_data_size as usize * BYTES_PER_WORD);
2182
2183 for _ in 0..ptr_count {
2184 let src_pr = PointerReader {
2185 arena: value.arena,
2186 segment_id: value.segment_id,
2187 cap_table: value.cap_table,
2188 pointer: src as *const WirePointer,
2189 nesting_limit: value.nesting_limit,
2190 };
2191 deep_copy_pointee(
2192 arena,
2193 segment_id,
2194 cap_table,
2195 dst as *mut _,
2196 src_pr,
2197 canonicalize,
2198 )?;
2199 dst = dst.add(BYTES_PER_WORD);
2200 src = src.add(BYTES_PER_WORD);
2201 }
2202
2203 src = src.add(
2204 decl_pointer_count.checked_sub(ptr_count).unwrap() as usize * BYTES_PER_WORD,
2205 );
2206 }
2207 Ok(SegmentAnd {
2208 segment_id,
2209 value: ptr,
2210 })
2211 }
2212 }
2213
2214 pub(crate) unsafe fn deep_copy_pointee(
2215 dst_arena: &mut dyn BuilderArena,
2216 dst_segment_id: u32,
2217 dst_cap_table: CapTableBuilder,
2218 dst: *mut WirePointer,
2219 src: PointerReader,
2220 canonicalize: bool,
2221 ) -> Result<SegmentAnd<*mut u8>> {
2222 if (*src.pointer).is_null() {
2223 ptr::write_bytes(dst, 0, 1);
2224 return Ok(SegmentAnd {
2225 segment_id: dst_segment_id,
2226 value: ptr::null_mut(),
2227 });
2228 }
2229
2230 let (mut ptr, src_ptr, src_segment_id) =
2231 follow_fars(src.arena, src.pointer, src.segment_id)?;
2232
2233 match (*src_ptr).kind() {
2234 WirePointerKind::Struct => {
2235 if src.nesting_limit <= 0 {
2236 return Err(Error::from_kind(
2237 ErrorKind::MessageIsTooDeeplyNestedOrContainsCycles,
2238 ));
2239 }
2240
2241 bounds_check(
2242 src.arena,
2243 src_segment_id,
2244 ptr,
2245 (*src_ptr).struct_word_size() as usize,
2246 WirePointerKind::Struct,
2247 )?;
2248
2249 set_struct_pointer(
2250 dst_arena,
2251 dst_segment_id,
2252 dst_cap_table,
2253 dst,
2254 StructReader {
2255 arena: src.arena,
2256 segment_id: src_segment_id,
2257 cap_table: src.cap_table,
2258 data: ptr,
2259 pointers: ptr.add((*src_ptr).struct_data_size() as usize * BYTES_PER_WORD)
2260 as *const _,
2261 data_size: u32::from((*src_ptr).struct_data_size())
2262 * u32::try_from(BITS_PER_WORD).unwrap(),
2263 pointer_count: (*src_ptr).struct_ptr_count(),
2264 nesting_limit: src.nesting_limit - 1,
2265 },
2266 canonicalize,
2267 )
2268 }
2269 WirePointerKind::List => {
2270 let element_size = (*src_ptr).list_element_size();
2271 if src.nesting_limit <= 0 {
2272 return Err(Error::from_kind(
2273 ErrorKind::MessageIsTooDeeplyNestedOrContainsCycles,
2274 ));
2275 }
2276
2277 if element_size == InlineComposite {
2278 let word_count = (*src_ptr).list_inline_composite_word_count();
2279
2280 bounds_check(
2285 src.arena,
2286 src_segment_id,
2287 ptr,
2288 word_count as usize + 1,
2289 WirePointerKind::List,
2290 )?;
2291
2292 let tag: *const WirePointer = ptr as *const _;
2293 ptr = ptr.add(BYTES_PER_WORD);
2294
2295 if (*tag).kind() != WirePointerKind::Struct {
2296 return Err(Error::from_kind(
2297 ErrorKind::InlineCompositeListsOfNonStructTypeAreNotSupported,
2298 ));
2299 }
2300
2301 let element_count = (*tag).inline_composite_list_element_count();
2302 let words_per_element = (*tag).struct_word_size();
2303
2304 if u64::from(words_per_element) * u64::from(element_count)
2305 > u64::from(word_count)
2306 {
2307 return Err(Error::from_kind(
2308 ErrorKind::InlineCompositeListsElementsOverrunItsWordCount,
2309 ));
2310 }
2311
2312 if words_per_element == 0 {
2313 amplified_read(src.arena, u64::from(element_count))?;
2316 }
2317
2318 set_list_pointer(
2319 dst_arena,
2320 dst_segment_id,
2321 dst_cap_table,
2322 dst,
2323 ListReader {
2324 arena: src.arena,
2325 segment_id: src_segment_id,
2326 cap_table: src.cap_table,
2327 ptr: ptr as *const _,
2328 element_count,
2329 element_size,
2330 step: words_per_element * u32::try_from(BITS_PER_WORD).unwrap(),
2331 struct_data_size: u32::from((*tag).struct_data_size())
2332 * u32::try_from(BITS_PER_WORD).unwrap(),
2333 struct_pointer_count: (*tag).struct_ptr_count(),
2334 nesting_limit: src.nesting_limit - 1,
2335 },
2336 canonicalize,
2337 )
2338 } else {
2339 let data_size = data_bits_per_element(element_size);
2340 let pointer_count = pointers_per_element(element_size);
2341 let step = data_size + pointer_count * u32::try_from(BITS_PER_POINTER).unwrap();
2342 let element_count = (*src_ptr).list_element_count();
2343 let word_count =
2344 round_bits_up_to_words(u64::from(element_count) * u64::from(step));
2345
2346 bounds_check(
2347 src.arena,
2348 src_segment_id,
2349 ptr,
2350 word_count as usize,
2351 WirePointerKind::List,
2352 )?;
2353
2354 if element_size == Void {
2355 amplified_read(src.arena, u64::from(element_count))?;
2358 }
2359
2360 set_list_pointer(
2361 dst_arena,
2362 dst_segment_id,
2363 dst_cap_table,
2364 dst,
2365 ListReader {
2366 arena: src.arena,
2367 segment_id: src_segment_id,
2368 cap_table: src.cap_table,
2369 ptr: ptr as *const _,
2370 element_count,
2371 element_size,
2372 step,
2373 struct_data_size: data_size,
2374 struct_pointer_count: u16::try_from(pointer_count).unwrap(),
2375 nesting_limit: src.nesting_limit - 1,
2376 },
2377 canonicalize,
2378 )
2379 }
2380 }
2381 WirePointerKind::Far => Err(Error::from_kind(ErrorKind::MalformedDoubleFarPointer)),
2382 WirePointerKind::Other => {
2383 if !(*src_ptr).is_capability() {
2384 return Err(Error::from_kind(ErrorKind::UnknownPointerType));
2385 }
2386 if canonicalize {
2387 return Err(Error::from_kind(
2388 ErrorKind::CannotCreateACanonicalMessageWithACapability,
2389 ));
2390 }
2391 #[cfg(feature = "alloc")]
2392 match src.cap_table.extract_cap((*src_ptr).cap_index() as usize) {
2393 Some(cap) => {
2394 set_capability_pointer(dst_arena, dst_segment_id, dst_cap_table, dst, cap);
2395 Ok(SegmentAnd {
2396 segment_id: dst_segment_id,
2397 value: ptr::null_mut(),
2398 })
2399 }
2400 None => Err(Error::from_kind(
2401 ErrorKind::MessageContainsInvalidCapabilityPointer,
2402 )),
2403 }
2404 #[cfg(not(feature = "alloc"))]
2405 return Err(Error::from_kind(ErrorKind::UnknownPointerType));
2406 }
2407 }
2408 }
2409
2410 #[inline]
2411 pub(crate) unsafe fn read_struct_pointer<'a>(
2412 mut arena: &'a dyn ReaderArena,
2413 mut segment_id: u32,
2414 cap_table: CapTableReader,
2415 mut reff: *const WirePointer,
2416 default: Option<&'a [crate::Word]>,
2417 nesting_limit: i32,
2418 ) -> Result<StructReader<'a>> {
2419 if (*reff).is_null() {
2420 match default {
2421 None => return Ok(StructReader::new_default()),
2422 Some(d) if (*(d.as_ptr() as *const WirePointer)).is_null() => {
2423 return Ok(StructReader::new_default())
2424 }
2425 Some(d) => {
2426 reff = d.as_ptr() as *const _;
2427 arena = &super::NULL_ARENA;
2428 segment_id = 0;
2429 }
2430 }
2431 }
2432
2433 if nesting_limit <= 0 {
2434 return Err(Error::from_kind(
2435 ErrorKind::MessageIsTooDeeplyNestedOrContainsCycles,
2436 ));
2437 }
2438
2439 let (ptr, reff, segment_id) = follow_fars(arena, reff, segment_id)?;
2440
2441 let data_size_words = (*reff).struct_data_size();
2442
2443 if (*reff).kind() != WirePointerKind::Struct {
2444 return Err(Error::from_kind(
2445 ErrorKind::MessageContainsNonStructPointerWhereStructPointerWasExpected,
2446 ));
2447 }
2448
2449 bounds_check(
2450 arena,
2451 segment_id,
2452 ptr,
2453 (*reff).struct_word_size() as usize,
2454 WirePointerKind::Struct,
2455 )?;
2456
2457 Ok(StructReader {
2458 arena,
2459 segment_id,
2460 cap_table,
2461 data: ptr,
2462 pointers: ptr.add(data_size_words as usize * BYTES_PER_WORD) as *const _,
2463 data_size: u32::from(data_size_words) * u32::try_from(BITS_PER_WORD).unwrap(),
2464 pointer_count: (*reff).struct_ptr_count(),
2465 nesting_limit: nesting_limit - 1,
2466 })
2467 }
2468
2469 #[inline]
2470 #[cfg(feature = "alloc")]
2471 pub(crate) unsafe fn read_capability_pointer(
2472 _arena: &dyn ReaderArena,
2473 _segment_id: u32,
2474 cap_table: CapTableReader,
2475 reff: *const WirePointer,
2476 _nesting_limit: i32,
2477 ) -> Result<alloc::boxed::Box<dyn ClientHook>> {
2478 if (*reff).is_null() {
2479 Err(Error::from_kind(
2480 ErrorKind::MessageContainsNullCapabilityPointer,
2481 ))
2482 } else if !(*reff).is_capability() {
2483 Err(Error::from_kind(
2484 ErrorKind::MessageContainsNonCapabilityPointerWhereCapabilityPointerWasExpected,
2485 ))
2486 } else {
2487 let n = (*reff).cap_index() as usize;
2488 match cap_table.extract_cap(n) {
2489 Some(client_hook) => Ok(client_hook),
2490 None => Err(Error::from_kind(
2491 ErrorKind::MessageContainsInvalidCapabilityPointer,
2492 )),
2493 }
2494 }
2495 }
2496
2497 #[inline]
2498 pub(crate) unsafe fn read_list_pointer(
2499 mut arena: &dyn ReaderArena,
2500 mut segment_id: u32,
2501 cap_table: CapTableReader,
2502 mut reff: *const WirePointer,
2503 default_value: *const u8,
2504 expected_element_size: Option<ElementSize>,
2505 nesting_limit: i32,
2506 ) -> Result<ListReader<'_>> {
2507 if (*reff).is_null() {
2508 if default_value.is_null() || (*(default_value as *const WirePointer)).is_null() {
2509 return Ok(ListReader::new_default());
2510 }
2511 reff = default_value as *const _;
2512 arena = &super::NULL_ARENA;
2513 segment_id = 0;
2514 }
2515
2516 if nesting_limit <= 0 {
2517 return Err(Error::from_kind(ErrorKind::NestingLimitExceeded));
2518 }
2519 let (mut ptr, reff, segment_id) = follow_fars(arena, reff, segment_id)?;
2520
2521 if (*reff).kind() != WirePointerKind::List {
2522 return Err(Error::from_kind(
2523 ErrorKind::MessageContainsNonListPointerWhereListPointerWasExpected,
2524 ));
2525 }
2526
2527 let element_size = (*reff).list_element_size();
2528 match element_size {
2529 InlineComposite => {
2530 let word_count = (*reff).list_inline_composite_word_count();
2531
2532 bounds_check(
2538 arena,
2539 segment_id,
2540 ptr,
2541 word_count as usize + 1,
2542 WirePointerKind::List,
2543 )?;
2544
2545 let tag: *const WirePointer = ptr as *const WirePointer;
2546
2547 ptr = ptr.add(BYTES_PER_WORD);
2548
2549 if (*tag).kind() != WirePointerKind::Struct {
2550 return Err(Error::from_kind(
2551 ErrorKind::InlineCompositeListsOfNonStructTypeAreNotSupported,
2552 ));
2553 }
2554
2555 let size = (*tag).inline_composite_list_element_count();
2556 let data_size = (*tag).struct_data_size();
2557 let ptr_count = (*tag).struct_ptr_count();
2558 let words_per_element = (*tag).struct_word_size();
2559
2560 if u64::from(size) * u64::from(words_per_element) > u64::from(word_count) {
2561 return Err(Error::from_kind(
2562 ErrorKind::InlineCompositeListsElementsOverrunItsWordCount,
2563 ));
2564 }
2565
2566 if words_per_element == 0 {
2567 amplified_read(arena, u64::from(size))?;
2570 }
2571
2572 match expected_element_size {
2579 None | Some(Void | InlineComposite) => (),
2580 Some(Bit) => {
2581 return Err(Error::from_kind(
2582 ErrorKind::FoundStructListWhereBitListWasExpected,
2583 ));
2584 }
2585 Some(Byte | TwoBytes | FourBytes | EightBytes) => {
2586 if data_size == 0 {
2587 return Err(Error::from_kind(
2588 ErrorKind::ExpectedAPrimitiveListButGotAListOfPointerOnlyStructs,
2589 ));
2590 }
2591 }
2592 Some(Pointer) => {
2593 if ptr_count == 0 {
2594 return Err(Error::from_kind(
2595 ErrorKind::ExpectedAPointerListButGotAListOfDataOnlyStructs,
2596 ));
2597 }
2598 }
2599 }
2600
2601 Ok(ListReader {
2602 arena,
2603 segment_id,
2604 cap_table,
2605 ptr: ptr as *const _,
2606 element_count: size,
2607 element_size,
2608 step: words_per_element * u32::try_from(BITS_PER_WORD).unwrap(),
2609 struct_data_size: u32::from(data_size)
2610 * (u32::try_from(BITS_PER_WORD).unwrap()),
2611 struct_pointer_count: ptr_count,
2612 nesting_limit: nesting_limit - 1,
2613 })
2614 }
2615 _ => {
2616 let data_size = data_bits_per_element((*reff).list_element_size());
2620 let pointer_count = pointers_per_element((*reff).list_element_size());
2621 let element_count = (*reff).list_element_count();
2622 let step = data_size + pointer_count * u32::try_from(BITS_PER_POINTER).unwrap();
2623
2624 let word_count = round_bits_up_to_words(u64::from(element_count) * u64::from(step));
2625 bounds_check(
2626 arena,
2627 segment_id,
2628 ptr,
2629 word_count as usize,
2630 WirePointerKind::List,
2631 )?;
2632
2633 if element_size == Void {
2634 amplified_read(arena, u64::from(element_count))?;
2637 }
2638
2639 if let Some(expected_element_size) = expected_element_size {
2640 if element_size == ElementSize::Bit && expected_element_size != ElementSize::Bit
2641 {
2642 return Err(Error::from_kind(
2643 ErrorKind::FoundBitListWhereStructListWasExpected,
2644 ));
2645 }
2646
2647 let expected_data_bits_per_element =
2653 data_bits_per_element(expected_element_size);
2654 let expected_pointers_per_element = pointers_per_element(expected_element_size);
2655
2656 if expected_data_bits_per_element > data_size
2657 || expected_pointers_per_element > pointer_count
2658 {
2659 return Err(Error::from_kind(
2660 ErrorKind::MessageContainsListWithIncompatibleElementType,
2661 ));
2662 }
2663 }
2664
2665 Ok(ListReader {
2666 arena,
2667 segment_id,
2668 cap_table,
2669 ptr: ptr as *const _,
2670 element_count,
2671 element_size,
2672 step,
2673 struct_data_size: data_size,
2674 struct_pointer_count: u16::try_from(pointer_count).unwrap(),
2675 nesting_limit: nesting_limit - 1,
2676 })
2677 }
2678 }
2679 }
2680
2681 #[inline]
2682 pub(crate) unsafe fn read_text_pointer<'a>(
2683 mut arena: &'a dyn ReaderArena,
2684 mut segment_id: u32,
2685 mut reff: *const WirePointer,
2686 default: Option<&[crate::Word]>,
2687 ) -> Result<text::Reader<'a>> {
2688 if (*reff).is_null() {
2689 match default {
2690 None => return Ok("".into()),
2691 Some(d) => {
2692 reff = d.as_ptr() as *const WirePointer;
2693 arena = &super::NULL_ARENA;
2694 segment_id = 0;
2695 }
2696 }
2697 }
2698
2699 let (ptr, reff, segment_id) = follow_fars(arena, reff, segment_id)?;
2700 let size = (*reff).list_element_count();
2701
2702 if (*reff).kind() != WirePointerKind::List {
2703 return Err(Error::from_kind(
2704 ErrorKind::MessageContainsNonListPointerWhereTextWasExpected,
2705 ));
2706 }
2707
2708 if (*reff).list_element_size() != Byte {
2709 return Err(Error::from_kind(
2710 ErrorKind::MessageContainsListPointerOfNonBytesWhereTextWasExpected,
2711 ));
2712 }
2713
2714 bounds_check(
2715 arena,
2716 segment_id,
2717 ptr,
2718 round_bytes_up_to_words(size) as usize,
2719 WirePointerKind::List,
2720 )?;
2721
2722 if size == 0 {
2723 return Err(Error::from_kind(
2724 ErrorKind::MessageContainsTextThatIsNotNULTerminated,
2725 ));
2726 }
2727
2728 let str_ptr = ptr;
2729
2730 if (*str_ptr.add((size - 1) as usize)) != 0u8 {
2731 return Err(Error::from_kind(
2732 ErrorKind::MessageContainsTextThatIsNotNULTerminated,
2733 ));
2734 }
2735
2736 Ok(text::Reader(slice::from_raw_parts(
2737 str_ptr,
2738 size as usize - 1,
2739 )))
2740 }
2741
2742 #[inline]
2743 pub(crate) unsafe fn read_data_pointer<'a>(
2744 mut arena: &'a dyn ReaderArena,
2745 mut segment_id: u32,
2746 mut reff: *const WirePointer,
2747 default: Option<&'a [crate::Word]>,
2748 ) -> Result<data::Reader<'a>> {
2749 if (*reff).is_null() {
2750 match default {
2751 None => return Ok(&[]),
2752 Some(d) => {
2753 reff = d.as_ptr() as *const WirePointer;
2754 arena = &super::NULL_ARENA;
2755 segment_id = 0;
2756 }
2757 }
2758 }
2759
2760 let (ptr, reff, segment_id) = follow_fars(arena, reff, segment_id)?;
2761
2762 let size: u32 = (*reff).list_element_count();
2763
2764 if (*reff).kind() != WirePointerKind::List {
2765 return Err(Error::from_kind(
2766 ErrorKind::MessageContainsNonListPointerWhereDataWasExpected,
2767 ));
2768 }
2769
2770 if (*reff).list_element_size() != Byte {
2771 return Err(Error::from_kind(
2772 ErrorKind::MessageContainsListPointerOfNonBytesWhereDataWasExpected,
2773 ));
2774 }
2775
2776 bounds_check(
2777 arena,
2778 segment_id,
2779 ptr,
2780 round_bytes_up_to_words(size) as usize,
2781 WirePointerKind::List,
2782 )?;
2783
2784 Ok(data::reader_from_raw_parts(ptr as *const _, size))
2785 }
2786}
2787
2788static ZERO: u64 = 0;
2789fn zero_pointer() -> *const WirePointer {
2790 &ZERO as *const _ as *const _
2791}
2792
2793static NULL_ARENA: NullArena = NullArena;
2794
2795#[cfg(feature = "alloc")]
2796pub type CapTable = alloc::vec::Vec<Option<alloc::boxed::Box<dyn ClientHook>>>;
2797
2798#[cfg(not(feature = "alloc"))]
2799pub struct CapTable;
2800
2801#[derive(Copy, Clone)]
2802pub enum CapTableReader {
2803 Plain(*const CapTable),
2807}
2808
2809impl Default for CapTableReader {
2810 fn default() -> Self {
2811 CapTableReader::Plain(ptr::null())
2812 }
2813}
2814
2815#[cfg(feature = "alloc")]
2816impl CapTableReader {
2817 pub fn extract_cap(&self, index: usize) -> Option<alloc::boxed::Box<dyn ClientHook>> {
2818 match *self {
2819 Self::Plain(hooks) => {
2820 if hooks.is_null() {
2821 return None;
2822 }
2823 let hooks: &alloc::vec::Vec<Option<alloc::boxed::Box<dyn ClientHook>>> =
2824 unsafe { &*hooks };
2825 if index >= hooks.len() {
2826 None
2827 } else {
2828 hooks[index].as_ref().map(|hook| hook.add_ref())
2829 }
2830 }
2831 }
2832 }
2833}
2834
2835#[derive(Copy, Clone)]
2836pub enum CapTableBuilder {
2837 Plain(*mut CapTable),
2841}
2842
2843impl Default for CapTableBuilder {
2844 fn default() -> Self {
2845 CapTableBuilder::Plain(ptr::null_mut())
2846 }
2847}
2848
2849impl CapTableBuilder {
2850 pub fn into_reader(self) -> CapTableReader {
2851 match self {
2852 Self::Plain(hooks) => CapTableReader::Plain(hooks),
2853 }
2854 }
2855
2856 #[cfg(feature = "alloc")]
2857 pub fn extract_cap(&self, index: usize) -> Option<alloc::boxed::Box<dyn ClientHook>> {
2858 match *self {
2859 Self::Plain(hooks) => {
2860 if hooks.is_null() {
2861 return None;
2862 }
2863 let hooks: &alloc::vec::Vec<Option<alloc::boxed::Box<dyn ClientHook>>> =
2864 unsafe { &*hooks };
2865 if index >= hooks.len() {
2866 None
2867 } else {
2868 hooks[index].as_ref().map(|hook| hook.add_ref())
2869 }
2870 }
2871 }
2872 }
2873
2874 #[cfg(feature = "alloc")]
2875 pub fn inject_cap(&mut self, cap: alloc::boxed::Box<dyn ClientHook>) -> usize {
2876 match *self {
2877 Self::Plain(hooks) => {
2878 if hooks.is_null() {
2879 panic!(
2880 "Called inject_cap() on a null capability table. You need \
2881 to call imbue_mut() on this message before adding capabilities."
2882 );
2883 }
2884 let hooks: &mut alloc::vec::Vec<Option<alloc::boxed::Box<dyn ClientHook>>> =
2885 unsafe { &mut *hooks };
2886 hooks.push(Some(cap));
2887 hooks.len() - 1
2888 }
2889 }
2890 }
2891
2892 #[cfg(feature = "alloc")]
2893 pub fn drop_cap(&mut self, index: usize) {
2894 match *self {
2895 Self::Plain(hooks) => {
2896 if hooks.is_null() {
2897 panic!(
2898 "Called drop_cap() on a null capability table. You need \
2899 to call imbue_mut() on this message before adding capabilities."
2900 );
2901 }
2902 let hooks: &mut alloc::vec::Vec<Option<alloc::boxed::Box<dyn ClientHook>>> =
2903 unsafe { &mut *hooks };
2904 if index < hooks.len() {
2905 hooks[index] = None;
2906 }
2907 }
2908 }
2909 }
2910}
2911
2912#[derive(Clone, Copy)]
2913pub struct PointerReader<'a> {
2914 arena: &'a dyn ReaderArena,
2915 cap_table: CapTableReader,
2916 pointer: *const WirePointer,
2917 segment_id: u32,
2918 nesting_limit: i32,
2919}
2920
2921impl<'a> PointerReader<'a> {
2922 pub fn new_default<'b>() -> PointerReader<'b> {
2923 PointerReader {
2924 arena: &NULL_ARENA,
2925 segment_id: 0,
2926 cap_table: Default::default(),
2927 pointer: ptr::null(),
2928 nesting_limit: 0x7fffffff,
2929 }
2930 }
2931
2932 pub unsafe fn get_root(
2933 arena: &'a dyn ReaderArena,
2934 segment_id: u32,
2935 location: *const u8,
2936 nesting_limit: i32,
2937 ) -> Result<Self> {
2938 wire_helpers::bounds_check(
2939 arena,
2940 segment_id,
2941 location as *const _,
2942 POINTER_SIZE_IN_WORDS,
2943 WirePointerKind::Struct,
2944 )?;
2945
2946 Ok(PointerReader {
2947 arena,
2948 segment_id,
2949 cap_table: Default::default(),
2950 pointer: location as *const _,
2951 nesting_limit,
2952 })
2953 }
2954
2955 pub fn reborrow(&self) -> PointerReader<'_> {
2956 PointerReader {
2957 arena: self.arena,
2958 ..*self
2959 }
2960 }
2961
2962 pub unsafe fn get_root_unchecked<'b>(location: *const u8) -> PointerReader<'b> {
2963 PointerReader {
2964 arena: &NULL_ARENA,
2965 segment_id: 0,
2966 cap_table: Default::default(),
2967 pointer: location as *const _,
2968 nesting_limit: 0x7fffffff,
2969 }
2970 }
2971
2972 pub fn get_root_from_arena(arena: &'a dyn ReaderArena) -> Result<Self> {
2973 let (segment_start, _seg_len) = arena.get_segment(0)?;
2974
2975 wire_helpers::bounds_check(
2976 arena,
2977 0,
2978 segment_start as *const _,
2979 POINTER_SIZE_IN_WORDS,
2980 WirePointerKind::Struct,
2981 )?;
2982
2983 Ok(PointerReader {
2984 arena,
2985 segment_id: 0,
2986 cap_table: Default::default(),
2987 pointer: segment_start as *const _,
2988 nesting_limit: arena.nesting_limit(),
2989 })
2990 }
2991
2992 pub fn imbue(&mut self, cap_table: CapTableReader) {
2993 self.cap_table = cap_table;
2994 }
2995
2996 #[inline]
2997 pub fn is_null(&self) -> bool {
2998 self.pointer.is_null() || unsafe { (*self.pointer).is_null() }
2999 }
3000
3001 pub fn total_size(&self) -> Result<MessageSize> {
3002 if self.pointer.is_null() {
3003 Ok(MessageSize {
3004 word_count: 0,
3005 cap_count: 0,
3006 })
3007 } else {
3008 unsafe {
3009 wire_helpers::total_size(
3010 self.arena,
3011 self.segment_id,
3012 self.pointer,
3013 self.nesting_limit,
3014 )
3015 }
3016 }
3017 }
3018
3019 pub fn get_struct(self, default: Option<&'a [crate::Word]>) -> Result<StructReader<'a>> {
3020 let reff: *const WirePointer = if self.pointer.is_null() {
3021 zero_pointer()
3022 } else {
3023 self.pointer
3024 };
3025 unsafe {
3026 wire_helpers::read_struct_pointer(
3027 self.arena,
3028 self.segment_id,
3029 self.cap_table,
3030 reff,
3031 default,
3032 self.nesting_limit,
3033 )
3034 }
3035 }
3036
3037 pub fn get_list(
3038 self,
3039 expected_element_size: ElementSize,
3040 default: Option<&'a [crate::Word]>,
3041 ) -> Result<ListReader<'a>> {
3042 let default_value: *const u8 = match default {
3043 None => core::ptr::null(),
3044 Some(d) => d.as_ptr() as *const u8,
3045 };
3046 let reff = if self.pointer.is_null() {
3047 zero_pointer()
3048 } else {
3049 self.pointer
3050 };
3051 unsafe {
3052 wire_helpers::read_list_pointer(
3053 self.arena,
3054 self.segment_id,
3055 self.cap_table,
3056 reff,
3057 default_value,
3058 Some(expected_element_size),
3059 self.nesting_limit,
3060 )
3061 }
3062 }
3063
3064 fn get_list_any_size(self, default_value: *const u8) -> Result<ListReader<'a>> {
3065 let reff = if self.pointer.is_null() {
3066 zero_pointer()
3067 } else {
3068 self.pointer
3069 };
3070 unsafe {
3071 wire_helpers::read_list_pointer(
3072 self.arena,
3073 self.segment_id,
3074 self.cap_table,
3075 reff,
3076 default_value,
3077 None,
3078 self.nesting_limit,
3079 )
3080 }
3081 }
3082
3083 pub fn get_text(self, default: Option<&[crate::Word]>) -> Result<text::Reader<'a>> {
3084 let reff = if self.pointer.is_null() {
3085 zero_pointer()
3086 } else {
3087 self.pointer
3088 };
3089 unsafe { wire_helpers::read_text_pointer(self.arena, self.segment_id, reff, default) }
3090 }
3091
3092 pub fn get_data(&self, default: Option<&'a [crate::Word]>) -> Result<data::Reader<'a>> {
3093 let reff = if self.pointer.is_null() {
3094 zero_pointer()
3095 } else {
3096 self.pointer
3097 };
3098 unsafe { wire_helpers::read_data_pointer(self.arena, self.segment_id, reff, default) }
3099 }
3100
3101 #[cfg(feature = "alloc")]
3102 pub fn get_capability(&self) -> Result<alloc::boxed::Box<dyn ClientHook>> {
3103 let reff: *const WirePointer = if self.pointer.is_null() {
3104 zero_pointer()
3105 } else {
3106 self.pointer
3107 };
3108 unsafe {
3109 wire_helpers::read_capability_pointer(
3110 self.arena,
3111 self.segment_id,
3112 self.cap_table,
3113 reff,
3114 self.nesting_limit,
3115 )
3116 }
3117 }
3118
3119 pub fn get_pointer_type(&self) -> Result<PointerType> {
3120 if self.is_null() {
3121 Ok(PointerType::Null)
3122 } else {
3123 let (_, reff, _) =
3124 unsafe { wire_helpers::follow_fars(self.arena, self.pointer, self.segment_id)? };
3125
3126 match unsafe { (*reff).kind() } {
3127 WirePointerKind::Far => Err(Error::from_kind(ErrorKind::UnexpectedFarPointer)),
3128 WirePointerKind::Struct => Ok(PointerType::Struct),
3129 WirePointerKind::List => Ok(PointerType::List),
3130 WirePointerKind::Other => {
3131 if unsafe { (*reff).is_capability() } {
3132 Ok(PointerType::Capability)
3133 } else {
3134 Err(Error::from_kind(ErrorKind::UnknownPointerType))
3135 }
3136 }
3137 }
3138 }
3139 }
3140
3141 pub fn is_canonical(&self, read_head: &Cell<*const u8>) -> Result<bool> {
3142 if self.pointer.is_null() || unsafe { !(*self.pointer).is_positional() } {
3143 return Ok(false);
3144 }
3145
3146 match self.get_pointer_type()? {
3147 PointerType::Null => Ok(true),
3148 PointerType::Struct => {
3149 let mut data_trunc = false;
3150 let mut ptr_trunc = false;
3151 let st = self.get_struct(None)?;
3152 if st.get_data_section_size() == 0 && st.get_pointer_section_size() == 0 {
3153 Ok(self.pointer as *const _ == st.get_location())
3154 } else {
3155 let result =
3156 st.is_canonical(read_head, read_head, &mut data_trunc, &mut ptr_trunc)?;
3157 Ok(result && data_trunc && ptr_trunc)
3158 }
3159 }
3160 PointerType::List => unsafe {
3161 self.get_list_any_size(ptr::null())?
3162 .is_canonical(read_head, self.pointer)
3163 },
3164 PointerType::Capability => Ok(false),
3165 }
3166 }
3167}
3168
3169pub struct PointerBuilder<'a> {
3170 arena: &'a mut dyn BuilderArena,
3171 segment_id: u32,
3172 cap_table: CapTableBuilder,
3173 pointer: *mut WirePointer,
3174}
3175
3176impl<'a> PointerBuilder<'a> {
3177 #[inline]
3178 pub fn get_root(arena: &'a mut dyn BuilderArena, segment_id: u32, location: *mut u8) -> Self {
3179 PointerBuilder {
3180 arena,
3181 cap_table: Default::default(),
3182 segment_id,
3183 pointer: location as *mut _,
3184 }
3185 }
3186
3187 #[inline]
3188 pub fn reborrow(&mut self) -> PointerBuilder<'_> {
3189 PointerBuilder {
3190 arena: self.arena,
3191 ..*self
3192 }
3193 }
3194
3195 pub fn imbue(&mut self, cap_table: CapTableBuilder) {
3196 self.cap_table = cap_table;
3197 }
3198
3199 #[inline]
3200 pub fn is_null(&self) -> bool {
3201 unsafe { (*self.pointer).is_null() }
3202 }
3203
3204 pub fn get_struct(
3205 self,
3206 size: StructSize,
3207 default: Option<&'a [crate::Word]>,
3208 ) -> Result<StructBuilder<'a>> {
3209 unsafe {
3210 wire_helpers::get_writable_struct_pointer(
3211 self.arena,
3212 self.pointer,
3213 self.segment_id,
3214 self.cap_table,
3215 size,
3216 default,
3217 )
3218 }
3219 }
3220
3221 pub fn get_list(
3222 self,
3223 element_size: ElementSize,
3224 default: Option<&'a [crate::Word]>,
3225 ) -> Result<ListBuilder<'a>> {
3226 let default_value: *const u8 = match default {
3227 None => core::ptr::null(),
3228 Some(d) => d.as_ptr() as *const u8,
3229 };
3230 unsafe {
3231 wire_helpers::get_writable_list_pointer(
3232 self.arena,
3233 self.pointer,
3234 self.segment_id,
3235 self.cap_table,
3236 element_size,
3237 default_value,
3238 )
3239 }
3240 }
3241
3242 pub fn get_struct_list(
3243 self,
3244 element_size: StructSize,
3245 default: Option<&'a [crate::Word]>,
3246 ) -> Result<ListBuilder<'a>> {
3247 let default_value: *const u8 = match default {
3248 None => core::ptr::null(),
3249 Some(d) => d.as_ptr() as *const u8,
3250 };
3251 unsafe {
3252 wire_helpers::get_writable_struct_list_pointer(
3253 self.arena,
3254 self.pointer,
3255 self.segment_id,
3256 self.cap_table,
3257 element_size,
3258 default_value,
3259 )
3260 }
3261 }
3262
3263 pub fn get_text(self, default: Option<&'a [crate::Word]>) -> Result<text::Builder<'a>> {
3264 unsafe {
3265 wire_helpers::get_writable_text_pointer(
3266 self.arena,
3267 self.pointer,
3268 self.segment_id,
3269 default,
3270 )
3271 }
3272 }
3273
3274 pub fn get_data(self, default: Option<&'a [crate::Word]>) -> Result<data::Builder<'a>> {
3275 unsafe {
3276 wire_helpers::get_writable_data_pointer(
3277 self.arena,
3278 self.pointer,
3279 self.segment_id,
3280 default,
3281 )
3282 }
3283 }
3284
3285 #[cfg(feature = "alloc")]
3286 pub fn get_capability(&self) -> Result<alloc::boxed::Box<dyn ClientHook>> {
3287 unsafe {
3288 wire_helpers::read_capability_pointer(
3289 self.arena.as_reader(),
3290 self.segment_id,
3291 self.cap_table.into_reader(),
3292 self.pointer,
3293 i32::MAX,
3294 )
3295 }
3296 }
3297
3298 pub fn init_struct(self, size: StructSize) -> StructBuilder<'a> {
3299 unsafe {
3300 wire_helpers::init_struct_pointer(
3301 self.arena,
3302 self.pointer,
3303 self.segment_id,
3304 self.cap_table,
3305 size,
3306 )
3307 }
3308 }
3309
3310 pub fn init_list(
3311 self,
3312 element_size: ElementSize,
3313 element_count: ElementCount32,
3314 ) -> ListBuilder<'a> {
3315 unsafe {
3316 wire_helpers::init_list_pointer(
3317 self.arena,
3318 self.pointer,
3319 self.segment_id,
3320 self.cap_table,
3321 element_count,
3322 element_size,
3323 )
3324 }
3325 }
3326
3327 pub fn init_struct_list(
3328 self,
3329 element_count: ElementCount32,
3330 element_size: StructSize,
3331 ) -> ListBuilder<'a> {
3332 unsafe {
3333 wire_helpers::init_struct_list_pointer(
3334 self.arena,
3335 self.pointer,
3336 self.segment_id,
3337 self.cap_table,
3338 element_count,
3339 element_size,
3340 )
3341 }
3342 }
3343
3344 pub fn init_text(self, size: ByteCount32) -> text::Builder<'a> {
3345 unsafe {
3346 wire_helpers::init_text_pointer(self.arena, self.pointer, self.segment_id, size).value
3347 }
3348 }
3349
3350 pub fn init_data(self, size: ByteCount32) -> data::Builder<'a> {
3351 unsafe {
3352 wire_helpers::init_data_pointer(self.arena, self.pointer, self.segment_id, size).value
3353 }
3354 }
3355
3356 pub fn set_struct(&mut self, value: &StructReader, canonicalize: bool) -> Result<()> {
3357 unsafe {
3358 wire_helpers::set_struct_pointer(
3359 self.arena,
3360 self.segment_id,
3361 self.cap_table,
3362 self.pointer,
3363 *value,
3364 canonicalize,
3365 )?;
3366 Ok(())
3367 }
3368 }
3369
3370 pub fn set_list(&mut self, value: &ListReader, canonicalize: bool) -> Result<()> {
3371 unsafe {
3372 wire_helpers::set_list_pointer(
3373 self.arena,
3374 self.segment_id,
3375 self.cap_table,
3376 self.pointer,
3377 *value,
3378 canonicalize,
3379 )?;
3380 Ok(())
3381 }
3382 }
3383
3384 pub fn set_text(&mut self, value: crate::text::Reader<'_>) {
3385 unsafe {
3386 wire_helpers::set_text_pointer(self.arena, self.pointer, self.segment_id, value);
3387 }
3388 }
3389
3390 pub fn set_data(&mut self, value: &[u8]) {
3391 unsafe {
3392 wire_helpers::set_data_pointer(self.arena, self.pointer, self.segment_id, value);
3393 }
3394 }
3395
3396 #[cfg(feature = "alloc")]
3397 pub fn set_capability(&mut self, cap: alloc::boxed::Box<dyn ClientHook>) {
3398 unsafe {
3399 wire_helpers::set_capability_pointer(
3400 self.arena,
3401 self.segment_id,
3402 self.cap_table,
3403 self.pointer,
3404 cap,
3405 );
3406 }
3407 }
3408
3409 pub fn copy_from(&mut self, other: PointerReader, canonicalize: bool) -> Result<()> {
3410 if other.pointer.is_null() {
3411 if !self.pointer.is_null() {
3412 unsafe {
3413 wire_helpers::zero_object(self.arena, self.segment_id, self.pointer);
3414 *self.pointer = mem::zeroed();
3415 }
3416 }
3417 } else {
3418 unsafe {
3419 wire_helpers::deep_copy_pointee(
3420 self.arena,
3421 self.segment_id,
3422 self.cap_table,
3423 self.pointer,
3424 other,
3425 canonicalize,
3426 )?;
3427 }
3428 }
3429 Ok(())
3430 }
3431
3432 pub fn clear(&mut self) {
3433 unsafe {
3434 wire_helpers::zero_object(self.arena, self.segment_id, self.pointer);
3435 ptr::write_bytes(self.pointer, 0, 1);
3436 }
3437 }
3438
3439 pub fn as_reader(&self) -> PointerReader<'_> {
3440 PointerReader {
3441 arena: self.arena.as_reader(),
3442 segment_id: self.segment_id,
3443 cap_table: self.cap_table.into_reader(),
3444 pointer: self.pointer,
3445 nesting_limit: 0x7fffffff,
3446 }
3447 }
3448
3449 pub fn into_reader(self) -> PointerReader<'a> {
3450 PointerReader {
3451 arena: self.arena.as_reader(),
3452 segment_id: self.segment_id,
3453 cap_table: self.cap_table.into_reader(),
3454 pointer: self.pointer,
3455 nesting_limit: 0x7fffffff,
3456 }
3457 }
3458}
3459
3460#[derive(Clone, Copy)]
3461pub struct StructReader<'a> {
3462 arena: &'a dyn ReaderArena,
3463 cap_table: CapTableReader,
3464 data: *const u8,
3465 pointers: *const WirePointer,
3466 segment_id: u32,
3467 data_size: BitCount32,
3468 pointer_count: WirePointerCount16,
3469 nesting_limit: i32,
3470}
3471
3472impl<'a> StructReader<'a> {
3473 pub fn new_default<'b>() -> StructReader<'b> {
3474 StructReader {
3475 arena: &NULL_ARENA,
3476 segment_id: 0,
3477 cap_table: Default::default(),
3478 data: ptr::null(),
3479 pointers: ptr::null(),
3480 data_size: 0,
3481 pointer_count: 0,
3482 nesting_limit: 0x7fffffff,
3483 }
3484 }
3485
3486 pub fn imbue(&mut self, cap_table: CapTableReader) {
3487 self.cap_table = cap_table
3488 }
3489
3490 pub fn get_data_section_size(&self) -> BitCount32 {
3491 self.data_size
3492 }
3493
3494 pub fn get_pointer_section_size(&self) -> WirePointerCount16 {
3495 self.pointer_count
3496 }
3497
3498 pub fn get_pointer_section_as_list(&self) -> ListReader<'a> {
3499 ListReader {
3500 arena: self.arena,
3501 segment_id: self.segment_id,
3502 cap_table: self.cap_table,
3503 ptr: self.pointers as *const _,
3504 element_count: u32::from(self.pointer_count),
3505 element_size: ElementSize::Pointer,
3506 step: BitCount32::try_from(BITS_PER_WORD).unwrap(),
3507 struct_data_size: 0,
3508 struct_pointer_count: 0,
3509 nesting_limit: self.nesting_limit,
3510 }
3511 }
3512
3513 pub fn get_data_section_as_blob(&self) -> &'a [u8] {
3514 if self.data_size == 0 {
3515 &[]
3518 } else {
3519 unsafe {
3520 ::core::slice::from_raw_parts(self.data, self.data_size as usize / BITS_PER_BYTE)
3521 }
3522 }
3523 }
3524
3525 #[inline]
3526 pub fn get_data_field<T: Primitive + zero::Zero>(&self, offset: ElementCount) -> T {
3527 if (offset + 1) * bits_per_element::<T>() <= self.data_size as usize {
3531 let dwv: *const <T as Primitive>::Raw = self.data as *const _;
3532 unsafe { <T as Primitive>::get(&*dwv.add(offset)) }
3533 } else {
3534 T::zero()
3535 }
3536 }
3537
3538 #[inline]
3539 pub fn get_bool_field(&self, offset: ElementCount) -> bool {
3540 let boffset: BitCount32 = BitCount32::try_from(offset).unwrap();
3541 if boffset < self.data_size {
3542 unsafe {
3543 let b: *const u8 = self.data.add(offset / BITS_PER_BYTE);
3544 ((*b) & (1u8 << (boffset % u32::try_from(BITS_PER_BYTE).unwrap()) as usize)) != 0
3545 }
3546 } else {
3547 false
3548 }
3549 }
3550
3551 #[inline]
3552 pub fn get_data_field_mask<T: Primitive + zero::Zero + Mask>(
3553 &self,
3554 offset: ElementCount,
3555 mask: <T as Mask>::T,
3556 ) -> T {
3557 Mask::mask(self.get_data_field(offset), mask)
3558 }
3559
3560 #[inline]
3561 pub fn get_bool_field_mask(&self, offset: ElementCount, mask: bool) -> bool {
3562 self.get_bool_field(offset) ^ mask
3563 }
3564
3565 #[inline]
3566 pub fn get_pointer_field(&self, ptr_index: WirePointerCount) -> PointerReader<'a> {
3567 if ptr_index < self.pointer_count as WirePointerCount {
3568 PointerReader {
3569 arena: self.arena,
3570 segment_id: self.segment_id,
3571 cap_table: self.cap_table,
3572 pointer: unsafe { self.pointers.add(ptr_index) },
3573 nesting_limit: self.nesting_limit,
3574 }
3575 } else {
3576 PointerReader::new_default()
3577 }
3578 }
3579
3580 #[inline]
3581 pub fn is_pointer_field_null(&self, ptr_index: WirePointerCount) -> bool {
3582 self.get_pointer_field(ptr_index).is_null()
3583 }
3584
3585 pub fn total_size(&self) -> Result<MessageSize> {
3586 let mut result = MessageSize {
3587 word_count: u64::from(wire_helpers::round_bits_up_to_words(u64::from(
3588 self.data_size,
3589 ))) + u64::from(self.pointer_count) * WORDS_PER_POINTER as u64,
3590 cap_count: 0,
3591 };
3592
3593 for i in 0..self.pointer_count as usize {
3594 unsafe {
3595 result += wire_helpers::total_size(
3596 self.arena,
3597 self.segment_id,
3598 self.pointers.add(i),
3599 self.nesting_limit,
3600 )?;
3601 }
3602 }
3603
3604 Ok(result)
3607 }
3608
3609 fn get_location(&self) -> *const u8 {
3610 self.data
3611 }
3612
3613 pub fn is_canonical(
3614 &self,
3615 read_head: &Cell<*const u8>,
3616 ptr_head: &Cell<*const u8>,
3617 data_trunc: &mut bool,
3618 ptr_trunc: &mut bool,
3619 ) -> Result<bool> {
3620 if self.get_location() != read_head.get() {
3621 return Ok(false);
3622 }
3623
3624 if self.get_data_section_size() % u32::try_from(BITS_PER_WORD).unwrap() != 0 {
3625 return Ok(false);
3627 }
3628
3629 let data_size = self.get_data_section_size() / u32::try_from(BITS_PER_WORD).unwrap();
3630
3631 if data_size != 0 {
3633 *data_trunc = self.get_data_field::<u64>((data_size - 1) as usize) != 0;
3634 } else {
3635 *data_trunc = true;
3636 }
3637
3638 if self.pointer_count != 0 {
3639 *ptr_trunc = !self
3640 .get_pointer_field(self.pointer_count as usize - 1)
3641 .is_null();
3642 } else {
3643 *ptr_trunc = true;
3644 }
3645
3646 read_head.set(unsafe {
3647 read_head
3648 .get()
3649 .add((data_size as usize + self.pointer_count as usize) * BYTES_PER_WORD)
3650 });
3651
3652 for ptr_idx in 0..self.pointer_count {
3653 if !self
3654 .get_pointer_field(ptr_idx as usize)
3655 .is_canonical(ptr_head)?
3656 {
3657 return Ok(false);
3658 }
3659 }
3660
3661 Ok(true)
3662 }
3663}
3664
3665pub struct StructBuilder<'a> {
3666 arena: &'a mut dyn BuilderArena,
3667 cap_table: CapTableBuilder,
3668 data: *mut u8,
3669 pointers: *mut WirePointer,
3670 segment_id: u32,
3671 data_size: BitCount32,
3672 pointer_count: WirePointerCount16,
3673}
3674
3675impl<'a> StructBuilder<'a> {
3676 #[inline]
3677 pub fn reborrow(&mut self) -> StructBuilder<'_> {
3678 StructBuilder {
3679 arena: self.arena,
3680 ..*self
3681 }
3682 }
3683
3684 pub fn as_reader(&self) -> StructReader<'_> {
3685 StructReader {
3686 arena: self.arena.as_reader(),
3687 cap_table: self.cap_table.into_reader(),
3688 data: self.data,
3689 pointers: self.pointers,
3690 pointer_count: self.pointer_count,
3691 segment_id: self.segment_id,
3692 data_size: self.data_size,
3693 nesting_limit: 0x7fffffff,
3694 }
3695 }
3696
3697 pub fn into_reader(self) -> StructReader<'a> {
3698 StructReader {
3699 arena: self.arena.as_reader(),
3700 cap_table: self.cap_table.into_reader(),
3701 data: self.data,
3702 pointers: self.pointers,
3703 pointer_count: self.pointer_count,
3704 segment_id: self.segment_id,
3705 data_size: self.data_size,
3706 nesting_limit: 0x7fffffff,
3707 }
3708 }
3709
3710 pub fn imbue(&mut self, cap_table: CapTableBuilder) {
3711 self.cap_table = cap_table
3712 }
3713
3714 #[inline]
3715 pub fn set_data_field<T: Primitive>(&self, offset: ElementCount, value: T) {
3716 let ptr: *mut <T as Primitive>::Raw = self.data as *mut _;
3717 unsafe { <T as Primitive>::set(&mut *ptr.add(offset), value) }
3718 }
3719
3720 #[inline]
3721 pub fn set_data_field_mask<T: Primitive + Mask>(
3722 &self,
3723 offset: ElementCount,
3724 value: T,
3725 mask: <T as Mask>::T,
3726 ) {
3727 self.set_data_field(offset, Mask::mask(value, mask));
3728 }
3729
3730 #[inline]
3731 pub fn get_data_field<T: Primitive>(&self, offset: ElementCount) -> T {
3732 let ptr: *const <T as Primitive>::Raw = self.data as *const _;
3733 unsafe { <T as Primitive>::get(&*ptr.add(offset)) }
3734 }
3735
3736 #[inline]
3737 pub fn get_data_field_mask<T: Primitive + Mask>(
3738 &self,
3739 offset: ElementCount,
3740 mask: <T as Mask>::T,
3741 ) -> T {
3742 Mask::mask(self.get_data_field(offset), mask)
3743 }
3744
3745 #[inline]
3746 pub fn set_bool_field(&self, offset: ElementCount, value: bool) {
3747 let boffset: BitCount0 = offset;
3750 let b = unsafe { self.data.add(boffset / BITS_PER_BYTE) };
3751 let bitnum = boffset % BITS_PER_BYTE;
3752 unsafe { (*b) = ((*b) & !(1 << bitnum)) | (u8::from(value) << bitnum) }
3753 }
3754
3755 #[inline]
3756 pub fn set_bool_field_mask(&self, offset: ElementCount, value: bool, mask: bool) {
3757 self.set_bool_field(offset, value ^ mask);
3758 }
3759
3760 #[inline]
3761 pub fn get_bool_field(&self, offset: ElementCount) -> bool {
3762 let boffset: BitCount0 = offset;
3763 let b = unsafe { self.data.add(boffset / BITS_PER_BYTE) };
3764 unsafe { ((*b) & (1 << (boffset % BITS_PER_BYTE))) != 0 }
3765 }
3766
3767 #[inline]
3768 pub fn get_bool_field_mask(&self, offset: ElementCount, mask: bool) -> bool {
3769 self.get_bool_field(offset) ^ mask
3770 }
3771
3772 #[inline]
3773 pub fn get_pointer_field(self, ptr_index: WirePointerCount) -> PointerBuilder<'a> {
3774 PointerBuilder {
3775 arena: self.arena,
3776 segment_id: self.segment_id,
3777 cap_table: self.cap_table,
3778 pointer: unsafe { self.pointers.add(ptr_index) },
3779 }
3780 }
3781
3782 #[inline]
3783 pub fn is_pointer_field_null(&self, ptr_index: WirePointerCount) -> bool {
3784 unsafe { (*self.pointers.add(ptr_index)).is_null() }
3785 }
3786
3787 pub fn copy_content_from(&mut self, other: &StructReader) -> Result<()> {
3788 use core::cmp::min;
3789 let shared_data_size = min(self.data_size, other.data_size);
3791 let shared_pointer_count = min(self.pointer_count, other.pointer_count);
3792
3793 if (shared_data_size > 0 && other.data == self.data)
3794 || (shared_pointer_count > 0 && other.pointers == self.pointers)
3795 {
3796 if (shared_data_size == 0 || other.data == self.data)
3799 && (shared_pointer_count == 0 || other.pointers == self.pointers)
3800 {
3801 return Err(Error::from_kind(
3802 ErrorKind::OnlyOneOfTheSectionPointersIsPointingToOurself,
3803 ));
3804 }
3805
3806 return Ok(());
3808 }
3809
3810 unsafe {
3811 if self.data_size > shared_data_size {
3812 if self.data_size == 1 {
3815 self.set_bool_field(0, false);
3816 } else {
3817 let unshared = self.data.add(
3818 usize::try_from(shared_data_size / u32::try_from(BITS_PER_BYTE).unwrap())
3819 .unwrap(),
3820 );
3821 ptr::write_bytes(
3822 unshared,
3823 0,
3824 usize::try_from(
3825 (self.data_size - shared_data_size)
3826 / u32::try_from(BITS_PER_BYTE).unwrap(),
3827 )
3828 .unwrap(),
3829 );
3830 }
3831 }
3832
3833 if shared_data_size == 1 {
3835 self.set_bool_field(0, other.get_bool_field(0));
3836 } else {
3837 wire_helpers::copy_nonoverlapping_check_zero(
3838 other.data,
3839 self.data,
3840 (shared_data_size / u32::try_from(BITS_PER_BYTE).unwrap()) as usize,
3841 );
3842 }
3843
3844 for i in 0..self.pointer_count as usize {
3846 wire_helpers::zero_object(
3847 self.arena,
3848 self.segment_id,
3849 self.pointers.add(i) as *mut _,
3850 );
3851 }
3852 ptr::write_bytes(self.pointers, 0u8, self.pointer_count as usize);
3853
3854 for i in 0..shared_pointer_count as usize {
3855 wire_helpers::deep_copy_pointee(
3856 self.arena,
3857 self.segment_id,
3858 self.cap_table,
3859 self.pointers.add(i),
3860 other.get_pointer_field(i),
3861 false,
3862 )?;
3863 }
3864 }
3865
3866 Ok(())
3867 }
3868}
3869
3870#[derive(Clone, Copy)]
3871pub struct ListReader<'a> {
3872 arena: &'a dyn ReaderArena,
3873 cap_table: CapTableReader,
3874 ptr: *const u8,
3875 segment_id: u32,
3876 element_count: ElementCount32,
3877 step: BitCount32,
3878 struct_data_size: BitCount32,
3879 nesting_limit: i32,
3880 struct_pointer_count: WirePointerCount16,
3881 element_size: ElementSize,
3882}
3883
3884impl<'a> ListReader<'a> {
3885 pub fn new_default<'b>() -> ListReader<'b> {
3886 ListReader {
3887 arena: &NULL_ARENA,
3888 segment_id: 0,
3889 cap_table: Default::default(),
3890 ptr: ptr::null(),
3891 element_count: 0,
3892 element_size: ElementSize::Void,
3893 step: 0,
3894 struct_data_size: 0,
3895 struct_pointer_count: 0,
3896 nesting_limit: 0x7fffffff,
3897 }
3898 }
3899
3900 pub fn imbue(&mut self, cap_table: CapTableReader) {
3901 self.cap_table = cap_table
3902 }
3903
3904 #[inline]
3905 pub fn len(&self) -> ElementCount32 {
3906 self.element_count
3907 }
3908
3909 pub fn is_empty(&self) -> bool {
3910 self.len() == 0
3911 }
3912
3913 pub(crate) fn get_step_size_in_bits(&self) -> u32 {
3914 self.step
3915 }
3916
3917 pub(crate) fn get_element_size(&self) -> ElementSize {
3918 self.element_size
3919 }
3920
3921 pub(crate) fn into_raw_bytes(self) -> &'a [u8] {
3922 if self.element_count == 0 {
3923 &[]
3926 } else {
3927 let num_bytes = wire_helpers::round_bits_up_to_bytes(
3928 u64::from(self.step) * u64::from(self.element_count),
3929 ) as usize;
3930 unsafe { ::core::slice::from_raw_parts(self.ptr, num_bytes) }
3931 }
3932 }
3933
3934 #[inline]
3935 pub fn get_struct_element(&self, index: ElementCount32) -> StructReader<'a> {
3936 assert!(index < self.element_count);
3937 let index_byte =
3938 usize::try_from((u64::from(index) * u64::from(self.step)) / BITS_PER_BYTE as u64)
3939 .unwrap();
3940
3941 let struct_data: *const u8 = unsafe { self.ptr.add(index_byte) };
3942
3943 let struct_pointers: *const WirePointer =
3944 unsafe { struct_data.add(self.struct_data_size as usize / BITS_PER_BYTE) as *const _ };
3945
3946 StructReader {
3947 arena: self.arena,
3948 segment_id: self.segment_id,
3949 cap_table: self.cap_table,
3950 data: struct_data,
3951 pointers: struct_pointers,
3952 data_size: self.struct_data_size,
3953 pointer_count: self.struct_pointer_count,
3954 nesting_limit: self.nesting_limit - 1,
3955 }
3956 }
3957
3958 #[inline]
3959 pub fn get_pointer_element(self, index: ElementCount32) -> PointerReader<'a> {
3960 assert!(index < self.element_count);
3961 let offset = usize::try_from(
3962 self.struct_data_size as u64 / BITS_PER_BYTE as u64
3963 + u64::from(index) * u64::from(self.step) / BITS_PER_BYTE as u64,
3964 )
3965 .unwrap();
3966 PointerReader {
3967 arena: self.arena,
3968 segment_id: self.segment_id,
3969 cap_table: self.cap_table,
3970 pointer: unsafe { self.ptr.add(offset) } as *const _,
3971 nesting_limit: self.nesting_limit,
3972 }
3973 }
3974
3975 pub unsafe fn is_canonical(
3976 &self,
3977 read_head: &Cell<*const u8>,
3978 reff: *const WirePointer,
3979 ) -> Result<bool> {
3980 match self.element_size {
3981 ElementSize::InlineComposite => {
3982 read_head.set(unsafe { read_head.get().add(BYTES_PER_WORD) }); if !core::ptr::eq(self.ptr, read_head.get()) {
3984 return Ok(false);
3985 }
3986 if self.struct_data_size % u32::try_from(BITS_PER_WORD).unwrap() != 0 {
3987 return Ok(false);
3988 }
3989 let struct_size = (self.struct_data_size / u32::try_from(BITS_PER_WORD).unwrap())
3990 + u32::from(self.struct_pointer_count);
3991 let word_count = unsafe { (*reff).list_inline_composite_word_count() };
3992 if struct_size * self.element_count != word_count {
3993 return Ok(false);
3994 }
3995 if struct_size == 0 {
3996 return Ok(true);
3997 }
3998 let list_end = unsafe {
3999 read_head
4000 .get()
4001 .add((self.element_count * struct_size) as usize * BYTES_PER_WORD)
4002 };
4003 let pointer_head = Cell::new(list_end);
4004 let mut list_data_trunc = false;
4005 let mut list_ptr_trunc = false;
4006 for idx in 0..self.element_count {
4007 let mut data_trunc = false;
4008 let mut ptr_trunc = false;
4009 if !self.get_struct_element(idx).is_canonical(
4010 read_head,
4011 &pointer_head,
4012 &mut data_trunc,
4013 &mut ptr_trunc,
4014 )? {
4015 return Ok(false);
4016 }
4017 list_data_trunc |= data_trunc;
4018 list_ptr_trunc |= ptr_trunc;
4019 }
4020 assert_eq!(read_head.get(), list_end);
4021 read_head.set(pointer_head.get());
4022 Ok(list_data_trunc && list_ptr_trunc)
4023 }
4024 ElementSize::Pointer => {
4025 if !core::ptr::eq(self.ptr, read_head.get()) {
4026 return Ok(false);
4027 }
4028 read_head.set(unsafe {
4029 read_head
4030 .get()
4031 .add(self.element_count as usize * BYTES_PER_WORD)
4032 });
4033 for idx in 0..self.element_count {
4034 if !self.get_pointer_element(idx).is_canonical(read_head)? {
4035 return Ok(false);
4036 }
4037 }
4038 Ok(true)
4039 }
4040 element_size => {
4041 if !core::ptr::eq(self.ptr, read_head.get()) {
4042 return Ok(false);
4043 }
4044 let bit_size =
4045 u64::from(self.element_count) * u64::from(data_bits_per_element(element_size));
4046 let mut word_size = bit_size / BITS_PER_WORD as u64;
4047 if bit_size % BITS_PER_WORD as u64 != 0 {
4048 word_size += 1
4049 }
4050
4051 let byte_size = bit_size / BITS_PER_BYTE as u64;
4052 let mut byte_read_head: *const u8 = read_head.get();
4053 byte_read_head = unsafe { byte_read_head.add(usize::try_from(byte_size).unwrap()) };
4054 let read_head_end = unsafe {
4055 read_head
4056 .get()
4057 .add(usize::try_from(word_size).unwrap() * BYTES_PER_WORD)
4058 };
4059
4060 let leftover_bits = u8::try_from(bit_size % BITS_PER_BYTE as u64).unwrap();
4061 if leftover_bits > 0 {
4062 let mask: u8 = !((1 << leftover_bits) - 1);
4063 let partial_byte = unsafe { *byte_read_head };
4064
4065 if partial_byte & mask != 0 {
4066 return Ok(false);
4067 }
4068 byte_read_head = unsafe { byte_read_head.add(1) };
4069 }
4070
4071 while byte_read_head != read_head_end {
4072 if unsafe { *byte_read_head } != 0 {
4073 return Ok(false);
4074 }
4075 byte_read_head = unsafe { byte_read_head.add(1) };
4076 }
4077
4078 read_head.set(read_head_end);
4079 Ok(true)
4080 }
4081 }
4082 }
4083}
4084
4085pub struct ListBuilder<'a> {
4086 arena: &'a mut dyn BuilderArena,
4087 cap_table: CapTableBuilder,
4088 ptr: *mut u8,
4089 segment_id: u32,
4090 element_count: ElementCount32,
4091 step: BitCount32,
4092 struct_data_size: BitCount32,
4093 struct_pointer_count: WirePointerCount16,
4094 element_size: ElementSize,
4095}
4096
4097impl<'a> ListBuilder<'a> {
4098 #[inline]
4099 pub fn new_default(arena: &mut dyn BuilderArena) -> ListBuilder<'_> {
4100 ListBuilder {
4101 arena,
4102 segment_id: 0,
4103 cap_table: Default::default(),
4104 ptr: ptr::null_mut(),
4105 element_count: 0,
4106 element_size: ElementSize::Void,
4107 step: 0,
4108 struct_data_size: 0,
4109 struct_pointer_count: 0,
4110 }
4111 }
4112
4113 pub fn into_reader(self) -> ListReader<'a> {
4114 ListReader {
4115 arena: self.arena.as_reader(),
4116 segment_id: self.segment_id,
4117 cap_table: self.cap_table.into_reader(),
4118 ptr: self.ptr as *const _,
4119 element_count: self.element_count,
4120 element_size: self.element_size,
4121 step: self.step,
4122 struct_data_size: self.struct_data_size,
4123 struct_pointer_count: self.struct_pointer_count,
4124 nesting_limit: 0x7fffffff,
4125 }
4126 }
4127
4128 #[inline]
4129 pub fn reborrow(&mut self) -> ListBuilder<'_> {
4130 ListBuilder {
4131 arena: self.arena,
4132 ..*self
4133 }
4134 }
4135
4136 pub fn imbue(&mut self, cap_table: CapTableBuilder) {
4137 self.cap_table = cap_table
4138 }
4139
4140 #[inline]
4141 pub fn len(&self) -> ElementCount32 {
4142 self.element_count
4143 }
4144
4145 pub fn is_empty(&self) -> bool {
4146 self.len() == 0
4147 }
4148
4149 #[inline]
4150 pub fn get_struct_element(self, index: ElementCount32) -> StructBuilder<'a> {
4151 assert!(index < self.element_count);
4152 let index_byte =
4153 usize::try_from((u64::from(index) * u64::from(self.step)) / BITS_PER_BYTE as u64)
4154 .unwrap();
4155 let struct_data = unsafe { self.ptr.add(index_byte) };
4156 let struct_pointers =
4157 unsafe { struct_data.add((self.struct_data_size as usize) / BITS_PER_BYTE) as *mut _ };
4158 StructBuilder {
4159 arena: self.arena,
4160 segment_id: self.segment_id,
4161 cap_table: self.cap_table,
4162 data: struct_data,
4163 pointers: struct_pointers,
4164 data_size: self.struct_data_size,
4165 pointer_count: self.struct_pointer_count,
4166 }
4167 }
4168
4169 pub(crate) fn get_element_size(&self) -> ElementSize {
4170 self.element_size
4171 }
4172
4173 #[inline]
4174 pub fn get_pointer_element(self, index: ElementCount32) -> PointerBuilder<'a> {
4175 assert!(index < self.element_count);
4176 let offset =
4177 usize::try_from(u64::from(index) * u64::from(self.step) / BITS_PER_BYTE as u64)
4178 .unwrap();
4179 PointerBuilder {
4180 arena: self.arena,
4181 segment_id: self.segment_id,
4182 cap_table: self.cap_table,
4183 pointer: unsafe { self.ptr.add(offset) } as *mut _,
4184 }
4185 }
4186
4187 pub(crate) fn as_raw_bytes(&self) -> &'a mut [u8] {
4188 if self.element_count == 0 {
4189 &mut []
4192 } else {
4193 let num_bytes = wire_helpers::round_bits_up_to_bytes(
4194 u64::from(self.step) * u64::from(self.element_count),
4195 ) as usize;
4196 unsafe { ::core::slice::from_raw_parts_mut(self.ptr, num_bytes) }
4197 }
4198 }
4199}
4200
4201pub trait PrimitiveElement {
4205 fn get(list_reader: &ListReader, index: ElementCount32) -> Self;
4207
4208 fn get_from_builder(list_builder: &ListBuilder, index: ElementCount32) -> Self;
4210
4211 fn set(list_builder: &ListBuilder, index: ElementCount32, value: Self);
4213
4214 fn element_size() -> ElementSize;
4216}
4217
4218impl<T: Primitive> PrimitiveElement for T {
4219 #[inline]
4220 fn get(list_reader: &ListReader, index: ElementCount32) -> Self {
4221 assert!(index < list_reader.len());
4222 let offset =
4223 usize::try_from(u64::from(index) * u64::from(list_reader.step) / BITS_PER_BYTE as u64)
4224 .unwrap();
4225 unsafe {
4226 let ptr: *const u8 = list_reader.ptr.add(offset);
4227 <Self as Primitive>::get(&*(ptr as *const <Self as Primitive>::Raw))
4228 }
4229 }
4230
4231 #[inline]
4232 fn get_from_builder(list_builder: &ListBuilder, index: ElementCount32) -> Self {
4233 assert!(index < list_builder.element_count);
4234 let offset =
4235 usize::try_from(u64::from(index) * u64::from(list_builder.step) / BITS_PER_BYTE as u64)
4236 .unwrap();
4237 unsafe {
4238 let ptr: *mut <Self as Primitive>::Raw = list_builder.ptr.add(offset) as *mut _;
4239 <Self as Primitive>::get(&*ptr)
4240 }
4241 }
4242
4243 #[inline]
4244 fn set(list_builder: &ListBuilder, index: ElementCount32, value: Self) {
4245 assert!(index < list_builder.element_count);
4246 let offset =
4247 usize::try_from(u64::from(index) * u64::from(list_builder.step) / BITS_PER_BYTE as u64)
4248 .unwrap();
4249 unsafe {
4250 let ptr: *mut <Self as Primitive>::Raw = list_builder.ptr.add(offset) as *mut _;
4251 <Self as Primitive>::set(&mut *ptr, value);
4252 }
4253 }
4254
4255 fn element_size() -> ElementSize {
4256 match mem::size_of::<Self>() {
4257 0 => Void,
4258 1 => Byte,
4259 2 => TwoBytes,
4260 4 => FourBytes,
4261 8 => EightBytes,
4262 _ => unreachable!(),
4263 }
4264 }
4265}
4266
4267impl PrimitiveElement for bool {
4268 #[inline]
4269 fn get(list: &ListReader, index: ElementCount32) -> Self {
4270 let bindex = u64::from(index) * u64::from(list.step);
4271 unsafe {
4272 let b: *const u8 = list
4273 .ptr
4274 .add(usize::try_from(bindex / BITS_PER_BYTE as u64).unwrap());
4275 ((*b) & (1 << (bindex % BITS_PER_BYTE as u64))) != 0
4276 }
4277 }
4278 #[inline]
4279 fn get_from_builder(list: &ListBuilder, index: ElementCount32) -> Self {
4280 let bindex = u64::from(index) * u64::from(list.step);
4281 let b = unsafe {
4282 list.ptr
4283 .add(usize::try_from(bindex / BITS_PER_BYTE as u64).unwrap())
4284 };
4285 unsafe { ((*b) & (1 << (bindex % BITS_PER_BYTE as u64))) != 0 }
4286 }
4287 #[inline]
4288 fn set(list: &ListBuilder, index: ElementCount32, value: Self) {
4289 let bindex = u64::from(index) * u64::from(list.step);
4290 let b = unsafe {
4291 list.ptr
4292 .add(usize::try_from(bindex / BITS_PER_BYTE as u64).unwrap())
4293 };
4294
4295 let bitnum = bindex % BITS_PER_BYTE as u64;
4296 unsafe { (*b) = ((*b) & !(1 << bitnum)) | (u8::from(value) << bitnum) }
4297 }
4298 fn element_size() -> ElementSize {
4299 Bit
4300 }
4301}
4302
4303impl PrimitiveElement for () {
4304 #[inline]
4305 fn get(_list: &ListReader, _index: ElementCount32) {}
4306
4307 #[inline]
4308 fn get_from_builder(_list: &ListBuilder, _index: ElementCount32) {}
4309
4310 #[inline]
4311 fn set(_list: &ListBuilder, _index: ElementCount32, _value: ()) {}
4312
4313 fn element_size() -> ElementSize {
4314 Void
4315 }
4316}