Skip to main content

capnp/private/
layout.rs

1// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
2// Licensed under the MIT License:
3//
4// Permission is hereby granted, free of charge, to any person obtaining a copy
5// of this software and associated documentation files (the "Software"), to deal
6// in the Software without restriction, including without limitation the rights
7// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8// copies of the Software, and to permit persons to whom the Software is
9// furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20// THE SOFTWARE.
21
22use 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    // We cast *u8 to *WirePointer, so we need to make sure its alignment allows that.
141    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 // match Struct and List but not Far and Other.
153    }
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    // At one point, we had `&self` here instead of `ptr: *const Self`, but miri
167    // flagged that as running afoul of "stacked borrow" rules.
168    #[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    // At one point, we had `&mut self` here instead of `ptr: *mut Self`, but miri
182    // flagged that as running afoul of "stacked borrow" rules.
183    #[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        //# This pointer points at an empty struct. Assuming the
215        //# WirePointer itself is in-bounds, we can set the target to
216        //# point either at the WirePointer itself or immediately after
217        //# it. The latter would cause the WirePointer to be "null"
218        //# (since for an empty struct the upper 32 bits are going to
219        //# be zero). So we set an offset of -1, as if the struct were
220        //# allocated immediately before this pointer, to distinguish
221        //# it from null.
222
223        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        //# This code assumes 64-bit words.
376        (bytes + 7) / u32::try_from(BYTES_PER_WORD).unwrap()
377    }
378
379    //# The maximum object size is 4GB - 1 byte. If measured in bits,
380    //# this would overflow a 32-bit counter, so we need to accept
381    //# BitCount64. However, 32 bits is enough for the returned
382    //# ByteCounts and WordCounts.
383    #[inline]
384    pub(crate) fn round_bits_up_to_words(bits: BitCount64) -> WordCount32 {
385        //# This code assumes 64-bit words.
386        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                //# Need to allocate in a different segment. We'll need to
443                //# allocate an extra pointer worth of space to act as
444                //# the landing pad for a far pointer.
445
446                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                //# Set up the original pointer to be a far pointer to
452                //# the new segment.
453                (*reff).set_far(false, word_idx);
454                (*reff).set_far_segment_id(segment_id);
455
456                //# Initialize the landing pad to indicate that the
457                //# data immediately follows the pad.
458                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 `ref` is a far pointer, follow it. On return, `ref` will have been updated to point at
481        // a WirePointer that contains the type information about the target object, and a pointer
482        // to the object contents is returned. The caller must NOT use `ref->target()` as this may
483        // or may not actually return a valid pointer. `segment` is also updated to point at the
484        // segment which actually contains the object.
485        //
486        // If `ref` is not a far pointer, this simply returns `ref_target`. Usually, `ref_target`
487        // should be the same as `ref->target()`, but may not be in cases where `ref` is only a tag.
488
489        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                //# Landing pad is another far pointer. It is followed by a
498                //# tag describing the pointed-to object.
499                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    /// Follows a WirePointer to get a triple containing:
513    ///   - the pointed-to object
514    ///   - the resolved WirePointer, whose kind is something other than WirePointerKind::Far
515    ///   - the segment on which the pointed-to object lives
516    #[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                // Landing pad is another far pointer. It is followed by a tag describing the
542                // pointed-to object.
543
544                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        //# Zero out the pointed-to object. Use when the pointer is
566        //# about to be overwritten making the target object no longer
567        //# reachable.
568
569        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        // Zero out the pointer itself and, if it is a far pointer, zero the landing pad as well,
685        // but do not zero the object body. Used when upgrading.
686
687        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                        // Count the actual size rather than the claimed word count because
808                        // that's what we end up with if we make a copy.
809                        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    // Helper for copy_message().
849    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    // Copies from a trusted message.
875    // Returns (new_dst_ptr, new_dst, new_segment_id).
876    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        //# Make *dst point to the same object as *src. Both must
1019        //# reside in the same message, but can be in different
1020        //# segments. Not always-inline because this is rarely used.
1021        //
1022        //# Caller MUST zero out the source pointer after calling this,
1023        //# to make sure no later code mistakenly thinks the source
1024        //# location still owns the object. transferPointer() doesn't
1025        //# do this zeroing itself because many callers transfer
1026        //# several pointers in a loop then zero out the whole section.
1027
1028        assert!((*dst).is_null());
1029        // We expect the caller to ensure the target is already null so won't leak.
1030
1031        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        // Like the other transfer_pointer, but splits src into a tag and a
1056        // target. Particularly useful for OrphanBuilder.
1057
1058        if dst_segment_id == src_segment_id {
1059            // Same segment, so create a direct pointer.
1060
1061            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            // We can just copy the upper 32 bits. (Use memcpy() to comply with aliasing rules.)
1067            ptr::copy_nonoverlapping(&(*src_tag).upper32bits, &mut (*dst).upper32bits, 1);
1068        } else {
1069            // Need to create a far pointer. Try to allocate it in the same segment as the source,
1070            // so that it doesn't need to be a double-far.
1071
1072            match arena.allocate(src_segment_id, 1) {
1073                None => {
1074                    //# Darn, need a double-far.
1075                    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                    //# Simple landing pad is just a pointer.
1103                    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            //# The space allocated for this struct is too small.
1202            //# Unlike with readers, we can't just run with it and do
1203            //# bounds checks at access time, because how would we
1204            //# handle writes? Instead, we have to copy the struct to a
1205            //# new space now.
1206
1207            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            //# Don't let allocate() zero out the object just yet.
1213            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 data section.
1220            // Note: copy_nonoverlapping's third argument is an element count, not a byte count.
1221            copy_nonoverlapping_check_zero(old_ptr, ptr, old_data_size as usize * BYTES_PER_WORD);
1222
1223            //# Copy pointer section.
1224            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        //# Allocate the list, prefixed by a single WirePointer.
1312        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        //# Initialize the pointer.
1328        (*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        // We must verify that the pointer has the right size. Unlike in
1384        // get_writable_struct_list_pointer(), we never need to "upgrade" the data, because this
1385        // method is called only for non-struct lists, and there is no allowed upgrade path *to* a
1386        // non-struct list, only *from* them.
1387
1388        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            // The existing element size is InlineComposite, which means that it is at least two
1399            // words, which makes it bigger than the expected element size. Since fields can only
1400            // grow when upgraded, the existing data must have been written with a newer version of
1401            // the protocol. We therefore never need to upgrade the data in this case, but we do
1402            // need to validate that it is a valid upgrade from what we expected.
1403
1404            // Read the tag to get the actual element count.
1405            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 => {} // Anything is a valid upgrade from Void.
1420                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                    // Adjust the pointer to point at the reference segment.
1439                    ptr = ptr.offset(data_size as isize * BYTES_PER_WORD as isize);
1440                }
1441                InlineComposite => {
1442                    unreachable!()
1443                }
1444            }
1445            // OK, looks valid.
1446
1447            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        // We must verify that the pointer has the right size and potentially upgrade it if not.
1514
1515        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            // Existing list is InlineComposite, but we need to verify that the sizes match.
1526
1527            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                // Old size is at least as large as we need. Ship it.
1543                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            // The structs in this list are smaller than expected, probably written using an older
1558            // version of the protocol. We need to make a copy and expand them.
1559
1560            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            // Don't let allocate() zero out the object just yet.
1574            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 data section.
1597                copy_nonoverlapping_check_zero(src, dst, old_data_size as usize);
1598
1599                // Copy pointer section
1600                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            // Zero out the old location, making sure to include the tag word.
1617            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            // We're upgrading from a non-struct list.
1638
1639            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                // Nothing to copy, just allocate a new list.
1647                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                // Upgrade to an inline composite list.
1657
1658                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                    // Old list contains data elements, so we need at least one word of data.
1671                    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                // Don't let allocate() zero out the object just yet.
1686                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                // Zero out old location.
1725                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        //# The byte list must include a NUL terminator.
1757        let byte_size = size + 1;
1758
1759        //# Allocate the space.
1760        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        //# Initialize the pointer.
1769        (*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        // TODO make sure the string is not longer than 2 ** 29.
1786        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        // Subtract 1 from the size for the NUL terminator.
1844        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        //# Allocate the space.
1858        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        //# Initialize the pointer.
1867        (*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            // StructReaders should not have bitwidths other than 1, but let's be safe
1949            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            // Data size could be made 0 by truncation
1993            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        // TODO if ref is not null, zero object.
2032        (*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            //# List of non-structs.
2048            let (ptr, reff, segment_id) =
2049                allocate(arena, reff, segment_id, total_size, WirePointerKind::List);
2050
2051            if value.struct_pointer_count == 1 {
2052                //# List of pointers.
2053                (*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                //# List of data.
2070                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                // Be careful to avoid copying any bytes past the end of the list.
2085                // TODO(perf) Is ptr::copy_nonoverlapping faster if word-aligned?
2086                // If so, then perhaps we should only drop to the byte-index level
2087                // in the canonicalize=true case.
2088                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            //# List of structs.
2115
2116            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                        // Watch out for lists of zero-sized structs, which can claim to be
2308                        // arbitrarily large without having sent actual data.
2309                        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                        // Watch out for lists of void, which can claim to be arbitrarily large
2350                        // without having sent actual data.
2351                        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                    // Watch out for lists of zero-sized structs, which can claim to be
2557                    // arbitrarily large without having sent actual data.
2558                    amplified_read(arena, u64::from(size))?;
2559                }
2560
2561                // If a struct list was not expected, then presumably a non-struct list was upgraded
2562                // to a struct list. We need to manipulate the pointer to point at the first field
2563                // of the struct. Together with the `step` field, this will allow the struct list to
2564                // be accessed as if it were a primitive list without branching.
2565
2566                // Check whether the size is compatible.
2567                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                // This is a primitive or pointer list, but all such lists can also be interpreted
2606                // as struct lists. We need to compute the data size and pointer count for such
2607                // structs.
2608                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                    // Watch out for lists of void, which can claim to be arbitrarily large
2624                    // without having sent actual data.
2625                    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                    // Verify that the elements are at least as large as the expected type. Note that if
2637                    // we expected InlineComposite, the expected sizes here will be zero, because bounds
2638                    // checking will be performed at field access time. So this check here is for the
2639                    // case where we expected a list of some primitive or pointer type.
2640
2641                    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    // At one point, we had a `Dummy` variant here, but that ended up
2793    // making values of this type take 16 bytes of memory. Now we instead
2794    // represent a null CapTableReader with `Plain(ptr::null())`.
2795    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    // At one point, we had a `Dummy` variant here, but that ended up
2827    // making values of this type take 16 bytes of memory. Now we instead
2828    // represent a null CapTableBuilder with `Plain(ptr::null_mut())`.
2829    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            // Explicitly handle this case to avoid forming a slice to a null pointer,
3509            // which would be undefined behavior.
3510            &[]
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        // We need to check the offset because the struct may have
3521        // been created with an old version of the protocol that did
3522        // not contain the field.
3523        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        // TODO when we have read limiting: segment->unread()
3598
3599        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            // legacy non-word-size struct
3619            return Ok(false);
3620        }
3621
3622        let data_size = self.get_data_section_size() / u32::try_from(BITS_PER_WORD).unwrap();
3623
3624        // mark whether the struct is properly truncated
3625        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        //# This branch should be compiled out whenever this is
3741        //# inlined with a constant offset.
3742        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        // Determine the amount of data the builders have in common.
3783        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            // At least one of the section pointers is pointing to ourself. Verify that the other is too
3790            // (but ignore empty sections).
3791            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            // So `other` appears to be a reader for this same struct. No copying is needed.
3800            return Ok(());
3801        }
3802
3803        unsafe {
3804            if self.data_size > shared_data_size {
3805                // Since the target is larger than the source, make sure to zero out the extra bits that the
3806                // source doesn't have.
3807                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            // Copy over the shared part.
3827            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            // Zero out all pointers in the target.
3838            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            // Explicitly handle this case to avoid forming a slice to a null pointer,
3921            // which would be undefined behavior.
3922            &[]
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) }); // tag word
3980                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            // Explicitly handle this case to avoid forming a slice to a null pointer,
4187            // which would be undefined behavior.
4188            &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
4198/**
4199  An element that can be stored in a `primitive_list`.
4200*/
4201pub trait PrimitiveElement {
4202    /// Gets the element at position `index`. Bounds checking is *not* performed.
4203    fn get(list_reader: &ListReader, index: ElementCount32) -> Self;
4204
4205    /// Gets the element at position `index`. Bounds checking is *not* performed.
4206    fn get_from_builder(list_builder: &ListBuilder, index: ElementCount32) -> Self;
4207
4208    /// Sets to element at position `index` to be `value`. Bounds checking is *not* performed.
4209    fn set(list_builder: &ListBuilder, index: ElementCount32, value: Self);
4210
4211    /// Returns the size of an individual element.
4212    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}