Skip to main content

capnp/private/
layout.rs

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