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