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