Skip to main content

netget/server/capnp_rpc/
layout.rs

1//! Cap'n Proto's encoding: the segment framing, a bounded pointer-following reader and a
2//! single-segment builder. Hand-written so every read is checked where it happens: a pointer
3//! must land inside its segment, every struct and list visited is charged to a traversal budget,
4//! and nesting stops at `MAX_DEPTH`.
5use anyhow::{bail, ensure, Context, Result};
6use std::sync::atomic::{AtomicU64, Ordering};
7use std::time::Duration;
8use tokio::io::{AsyncRead, AsyncReadExt};
9
10/// Largest message, framing included.
11pub const MAX_MESSAGE_BYTES: usize = 4 * 1024 * 1024;
12pub const MAX_MESSAGE_WORDS: usize = MAX_MESSAGE_BYTES / 8;
13/// Most segments in one message.
14pub const MAX_SEGMENTS: usize = 64;
15/// Deepest nesting of structs and lists the reader follows.
16pub const MAX_DEPTH: u32 = 64;
17/// Words the reader may visit in one message, counting every struct and list it resolves,
18/// so a message that points at the same bytes many times cannot amplify.
19pub const TRAVERSAL_LIMIT_WORDS: u64 = 4 * MAX_MESSAGE_WORDS as u64;
20/// A message must complete within this long of its first byte.
21pub const MESSAGE_TIMEOUT: Duration = Duration::from_secs(30);
22
23/// Read one framed message. `Ok(None)` is a clean end of stream before its first byte.
24pub async fn read_message<R: AsyncRead + Unpin>(
25    reader: &mut R,
26    idle: Duration,
27) -> Result<Option<Vec<Vec<u64>>>> {
28    let mut first = [0u8; 4];
29    match tokio::time::timeout(idle, reader.read(&mut first[..1])).await {
30        Err(_) => bail!("connection idle past its deadline"),
31        Ok(Ok(0)) => return Ok(None),
32        Ok(Ok(_)) => {}
33        Ok(Err(e)) => return Err(e.into()),
34    }
35    tokio::time::timeout(MESSAGE_TIMEOUT, async {
36        reader.read_exact(&mut first[1..]).await?;
37        let count = u32::from_le_bytes(first) as usize + 1;
38        ensure!(
39            count <= MAX_SEGMENTS,
40            "message has {count} segments, more than {MAX_SEGMENTS}"
41        );
42        // Sizes, then padding to a word boundary.
43        let table_words = (count + 1).div_ceil(2) * 2 - 1;
44        let mut table = vec![0u8; table_words * 4];
45        reader.read_exact(&mut table).await?;
46        let sizes: Vec<usize> = (0..count)
47            .map(|i| u32::from_le_bytes(table[i * 4..i * 4 + 4].try_into().unwrap()) as usize)
48            .collect();
49        let total: usize = sizes.iter().sum();
50        ensure!(
51            total + table_words.div_ceil(2) < MAX_MESSAGE_WORDS,
52            "message exceeds {MAX_MESSAGE_BYTES} bytes"
53        );
54        let mut segments = Vec::with_capacity(count);
55        for size in sizes {
56            let mut bytes = vec![0u8; size * 8];
57            reader.read_exact(&mut bytes).await?;
58            segments.push(
59                bytes
60                    .chunks_exact(8)
61                    .map(|c| u64::from_le_bytes(c.try_into().unwrap()))
62                    .collect(),
63            );
64        }
65        Ok(Some(segments))
66    })
67    .await
68    .context("message not completed within its deadline")?
69}
70
71/// Frame a single-segment message.
72pub fn frame(words: &[u64]) -> Vec<u8> {
73    let mut out = Vec::with_capacity(8 + words.len() * 8);
74    out.extend_from_slice(&0u32.to_le_bytes());
75    out.extend_from_slice(&(words.len() as u32).to_le_bytes());
76    for w in words {
77        out.extend_from_slice(&w.to_le_bytes());
78    }
79    out
80}
81
82#[derive(Clone, Copy, Debug, PartialEq, Eq)]
83pub enum ElementSize {
84    Void,
85    Bit,
86    Byte,
87    TwoBytes,
88    FourBytes,
89    EightBytes,
90    Pointer,
91    Composite,
92}
93
94impl ElementSize {
95    fn from_bits(b: u64) -> Self {
96        match b {
97            0 => Self::Void,
98            1 => Self::Bit,
99            2 => Self::Byte,
100            3 => Self::TwoBytes,
101            4 => Self::FourBytes,
102            5 => Self::EightBytes,
103            6 => Self::Pointer,
104            _ => Self::Composite,
105        }
106    }
107    fn bits(self) -> u64 {
108        match self {
109            Self::Void => 0,
110            Self::Bit => 1,
111            Self::Byte => 2,
112            Self::TwoBytes => 3,
113            Self::FourBytes => 4,
114            Self::EightBytes => 5,
115            Self::Pointer => 6,
116            Self::Composite => 7,
117        }
118    }
119    /// Bits per element for the non-composite sizes.
120    pub fn width(self) -> u64 {
121        match self {
122            Self::Void => 0,
123            Self::Bit => 1,
124            Self::Byte => 8,
125            Self::TwoBytes => 16,
126            Self::FourBytes => 32,
127            Self::EightBytes | Self::Pointer => 64,
128            Self::Composite => 0,
129        }
130    }
131}
132
133/// A message being read, with its traversal budget.
134pub struct Message {
135    segments: Vec<Vec<u64>>,
136    budget: AtomicU64,
137}
138
139#[derive(Clone, Copy, Debug)]
140pub struct StructReader<'a> {
141    msg: &'a Message,
142    seg: usize,
143    data: usize,
144    data_words: u16,
145    ptrs: usize,
146    ptr_count: u16,
147    pub depth: u32,
148}
149
150#[derive(Clone, Copy, Debug)]
151pub struct ListReader<'a> {
152    msg: &'a Message,
153    seg: usize,
154    start: usize,
155    pub len: u32,
156    pub size: ElementSize,
157    /// For composite lists: the per-element layout.
158    data_words: u16,
159    ptr_count: u16,
160    depth: u32,
161}
162
163/// What a pointer points at.
164pub enum Target<'a> {
165    Null,
166    Struct(StructReader<'a>),
167    List(ListReader<'a>),
168    Capability(u32),
169}
170
171impl std::fmt::Debug for Message {
172    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
173        write!(f, "Message({} segments)", self.segments.len())
174    }
175}
176
177impl Message {
178    pub fn new(segments: Vec<Vec<u64>>) -> Self {
179        Self {
180            segments,
181            budget: AtomicU64::new(TRAVERSAL_LIMIT_WORDS),
182        }
183    }
184
185    fn charge(&self, words: u64) -> Result<()> {
186        let left = self.budget.load(Ordering::Relaxed);
187        ensure!(words.max(1) <= left, "message traversal limit exceeded");
188        self.budget.store(left - words.max(1), Ordering::Relaxed);
189        Ok(())
190    }
191
192    fn word(&self, seg: usize, at: usize) -> Result<u64> {
193        self.segments
194            .get(seg)
195            .and_then(|s| s.get(at))
196            .copied()
197            .context("pointer outside its segment")
198    }
199
200    fn check_range(&self, seg: usize, start: usize, words: u64) -> Result<()> {
201        let len = self.segments.get(seg).context("no such segment")?.len() as u64;
202        ensure!(
203            start as u64 + words <= len,
204            "pointer target outside its segment"
205        );
206        Ok(())
207    }
208
209    /// The root pointer.
210    pub fn root(&self) -> Result<Target<'_>> {
211        ensure!(
212            self.segments.first().is_some_and(|s| !s.is_empty()),
213            "empty message"
214        );
215        self.follow(0, 0, 0)
216    }
217
218    pub fn root_struct(&self) -> Result<StructReader<'_>> {
219        match self.root()? {
220            Target::Struct(s) => Ok(s),
221            _ => bail!("the root is not a struct"),
222        }
223    }
224
225    /// Resolve the pointer stored at `(seg, at)`, following far pointers.
226    fn follow(&self, seg: usize, at: usize, depth: u32) -> Result<Target<'_>> {
227        ensure!(depth <= MAX_DEPTH, "nesting deeper than {MAX_DEPTH}");
228        let mut word = self.word(seg, at)?;
229        if word == 0 {
230            return Ok(Target::Null);
231        }
232        let (mut seg, mut origin) = (seg, at as i64 + 1);
233        let mut tag_override = None;
234        if word & 3 == 2 {
235            let double = word & 4 != 0;
236            let pad = ((word >> 3) & 0x1fff_ffff) as usize;
237            let target_seg = (word >> 32) as usize;
238            if !double {
239                word = self.word(target_seg, pad)?;
240                ensure!(word & 3 != 2, "far pointer to a far pointer");
241                seg = target_seg;
242                origin = pad as i64 + 1;
243            } else {
244                let landing = self.word(target_seg, pad)?;
245                let tag = self.word(target_seg, pad + 1)?;
246                ensure!(
247                    landing & 7 == 2,
248                    "double-far landing pad is not a single far pointer"
249                );
250                seg = (landing >> 32) as usize;
251                origin = ((landing >> 3) & 0x1fff_ffff) as i64;
252                ensure!(tag & 3 != 2, "double-far tag is a far pointer");
253                tag_override = Some(tag);
254                word = tag;
255            }
256        }
257        let offset = |w: u64| -> i64 {
258            if tag_override.is_some() {
259                0
260            } else {
261                ((w as u32 as i32) >> 2) as i64
262            }
263        };
264        match word & 3 {
265            0 => {
266                let data_words = (word >> 32) as u16;
267                let ptr_count = (word >> 48) as u16;
268                let start = origin + offset(word);
269                ensure!(start >= 0, "pointer before its segment");
270                let size = u64::from(data_words) + u64::from(ptr_count);
271                self.check_range(seg, start as usize, size)?;
272                self.charge(size)?;
273                Ok(Target::Struct(StructReader {
274                    msg: self,
275                    seg,
276                    data: start as usize,
277                    data_words,
278                    ptrs: start as usize + data_words as usize,
279                    ptr_count,
280                    depth: depth + 1,
281                }))
282            }
283            1 => {
284                let size = ElementSize::from_bits((word >> 32) & 7);
285                let count = (word >> 35) as u32;
286                let start = origin + offset(word);
287                ensure!(start >= 0, "pointer before its segment");
288                let start = start as usize;
289                if size == ElementSize::Composite {
290                    let words = u64::from(count);
291                    self.check_range(seg, start, words + 1)?;
292                    let tag = self.word(seg, start)?;
293                    ensure!(tag & 3 == 0, "composite list tag is not a struct");
294                    let len = ((tag as u32) >> 2) as u64;
295                    let data_words = (tag >> 32) as u16;
296                    let ptr_count = (tag >> 48) as u16;
297                    let per = u64::from(data_words) + u64::from(ptr_count);
298                    ensure!(
299                        len * per <= words,
300                        "composite list elements overrun its word count"
301                    );
302                    // A list of zero-sized structs still costs a word an element.
303                    self.charge(words.max(len))?;
304                    Ok(Target::List(ListReader {
305                        msg: self,
306                        seg,
307                        start: start + 1,
308                        len: len as u32,
309                        size,
310                        data_words,
311                        ptr_count,
312                        depth: depth + 1,
313                    }))
314                } else {
315                    let bits = u64::from(count) * size.width();
316                    self.check_range(seg, start, bits.div_ceil(64))?;
317                    self.charge(if size == ElementSize::Void {
318                        u64::from(count)
319                    } else {
320                        bits.div_ceil(64)
321                    })?;
322                    Ok(Target::List(ListReader {
323                        msg: self,
324                        seg,
325                        start,
326                        len: count,
327                        size,
328                        data_words: 0,
329                        ptr_count: 0,
330                        depth: depth + 1,
331                    }))
332                }
333            }
334            3 => {
335                ensure!((word as u32) >> 2 == 0, "unknown 'other' pointer");
336                Ok(Target::Capability((word >> 32) as u32))
337            }
338            _ => bail!("far pointer where content was expected"),
339        }
340    }
341}
342
343impl<'a> StructReader<'a> {
344    /// `bits` wide, at bit `offset` of the data section; zero beyond it.
345    pub fn bits(&self, offset: u64, bits: u64) -> u64 {
346        let word = (offset / 64) as usize;
347        if word >= self.data_words as usize {
348            return 0;
349        }
350        let w = self.msg.segments[self.seg][self.data + word];
351        let shift = offset % 64;
352        let v = w >> shift;
353        if bits == 64 {
354            v
355        } else {
356            v & ((1u64 << bits) - 1)
357        }
358    }
359    pub fn u16(&self, index: u64) -> u16 {
360        self.bits(index * 16, 16) as u16
361    }
362    pub fn u32(&self, index: u64) -> u32 {
363        self.bits(index * 32, 32) as u32
364    }
365    pub fn u64(&self, index: u64) -> u64 {
366        self.bits(index * 64, 64)
367    }
368    pub fn bool(&self, bit: u64) -> bool {
369        self.bits(bit, 1) != 0
370    }
371    pub fn pointer(&self, index: u16) -> Result<Target<'a>> {
372        if index >= self.ptr_count {
373            return Ok(Target::Null);
374        }
375        self.msg
376            .follow(self.seg, self.ptrs + index as usize, self.depth)
377    }
378    pub fn struct_field(&self, index: u16) -> Result<Option<StructReader<'a>>> {
379        match self.pointer(index)? {
380            Target::Null => Ok(None),
381            Target::Struct(s) => Ok(Some(s)),
382            _ => bail!("pointer {index} is not a struct"),
383        }
384    }
385    pub fn list_field(&self, index: u16) -> Result<Option<ListReader<'a>>> {
386        match self.pointer(index)? {
387            Target::Null => Ok(None),
388            Target::List(l) => Ok(Some(l)),
389            _ => bail!("pointer {index} is not a list"),
390        }
391    }
392    pub fn text(&self, index: u16) -> Result<Option<String>> {
393        self.list_field(index)?.map(|l| l.text()).transpose()
394    }
395    pub fn data(&self, index: u16) -> Result<Option<Vec<u8>>> {
396        self.list_field(index)?.map(|l| l.bytes()).transpose()
397    }
398}
399
400impl<'a> ListReader<'a> {
401    fn word(&self, i: usize) -> u64 {
402        self.msg.segments[self.seg][self.start + i]
403    }
404    /// The bytes of a byte list.
405    pub fn bytes(&self) -> Result<Vec<u8>> {
406        ensure!(self.size == ElementSize::Byte, "not a byte list");
407        let mut out = Vec::with_capacity(self.len as usize);
408        for i in 0..self.len as usize {
409            out.push((self.word(i / 8) >> ((i % 8) * 8)) as u8);
410        }
411        Ok(out)
412    }
413    /// Text: a NUL-terminated byte list.
414    pub fn text(&self) -> Result<String> {
415        let mut bytes = self.bytes()?;
416        ensure!(bytes.pop() == Some(0), "text is not NUL-terminated");
417        String::from_utf8(bytes).context("text is not UTF-8")
418    }
419    /// Element `i` of a primitive list, as raw bits.
420    pub fn primitive(&self, i: u32) -> Result<u64> {
421        ensure!(i < self.len, "index past the list");
422        let width = match self.size {
423            ElementSize::Composite => bail!("composite list read as primitive"),
424            ElementSize::Pointer => bail!("pointer list read as primitive"),
425            s => s.width(),
426        };
427        if width == 0 {
428            return Ok(0);
429        }
430        let bit = u64::from(i) * width;
431        let w = self.word((bit / 64) as usize) >> (bit % 64);
432        Ok(if width == 64 {
433            w
434        } else {
435            w & ((1 << width) - 1)
436        })
437    }
438    /// Element `i` of a struct list. A primitive list read as structs reads each element as a
439    /// one-field struct, as the encoding allows.
440    pub fn struct_at(&self, i: u32) -> Result<StructReader<'a>> {
441        ensure!(i < self.len, "index past the list");
442        ensure!(
443            self.size == ElementSize::Composite,
444            "expected a list of structs"
445        );
446        let per = self.data_words as usize + self.ptr_count as usize;
447        let at = self.start + per * i as usize;
448        Ok(StructReader {
449            msg: self.msg,
450            seg: self.seg,
451            data: at,
452            data_words: self.data_words,
453            ptrs: at + self.data_words as usize,
454            ptr_count: self.ptr_count,
455            depth: self.depth,
456        })
457    }
458    /// Element `i` of a pointer list.
459    pub fn pointer_at(&self, i: u32) -> Result<Target<'a>> {
460        ensure!(i < self.len, "index past the list");
461        ensure!(self.size == ElementSize::Pointer, "expected a pointer list");
462        self.msg
463            .follow(self.seg, self.start + i as usize, self.depth)
464    }
465}
466
467/// A single-segment message under construction.
468#[derive(Default)]
469pub struct Builder {
470    pub words: Vec<u64>,
471}
472
473#[derive(Clone, Copy, Debug)]
474pub struct StructBuilder {
475    pub data: usize,
476    pub data_words: u16,
477    pub ptrs: usize,
478    pub ptr_count: u16,
479}
480
481impl Builder {
482    /// A message whose root is a new struct of the given size.
483    pub fn with_root(data_words: u16, ptr_count: u16) -> (Self, StructBuilder) {
484        let mut b = Self { words: vec![0] };
485        let s = b.alloc_struct(data_words, ptr_count);
486        b.point_struct(0, s);
487        (b, s)
488    }
489
490    fn alloc(&mut self, words: usize) -> Result<usize> {
491        let at = self.words.len();
492        ensure!(
493            at + words < MAX_MESSAGE_WORDS,
494            "message exceeds {MAX_MESSAGE_BYTES} bytes"
495        );
496        self.words.resize(at + words, 0);
497        Ok(at)
498    }
499
500    fn alloc_struct(&mut self, data_words: u16, ptr_count: u16) -> StructBuilder {
501        let at = self
502            .alloc(data_words as usize + ptr_count as usize)
503            .unwrap_or(0);
504        StructBuilder {
505            data: at,
506            data_words,
507            ptrs: at + data_words as usize,
508            ptr_count,
509        }
510    }
511
512    fn offset(at: usize, target: usize) -> u64 {
513        (((target as i64 - at as i64 - 1) as i32 as u32) << 2) as u64
514    }
515
516    fn point_struct(&mut self, at: usize, s: StructBuilder) {
517        self.words[at] = Self::offset(at, s.data)
518            | (u64::from(s.data_words) << 32)
519            | (u64::from(s.ptr_count) << 48);
520    }
521
522    /// Store `bits` wide at bit `offset` of the data section.
523    pub fn set_bits(&mut self, s: StructBuilder, offset: u64, bits: u64, value: u64) {
524        let word = (offset / 64) as usize;
525        if word >= s.data_words as usize {
526            return;
527        }
528        let shift = offset % 64;
529        let mask = if bits == 64 {
530            u64::MAX
531        } else {
532            ((1u64 << bits) - 1) << shift
533        };
534        let w = &mut self.words[s.data + word];
535        *w = (*w & !mask) | ((value << shift) & mask);
536    }
537    pub fn set_u16(&mut self, s: StructBuilder, index: u64, v: u16) {
538        self.set_bits(s, index * 16, 16, u64::from(v));
539    }
540    pub fn set_u32(&mut self, s: StructBuilder, index: u64, v: u32) {
541        self.set_bits(s, index * 32, 32, u64::from(v));
542    }
543    pub fn set_u64(&mut self, s: StructBuilder, index: u64, v: u64) {
544        self.set_bits(s, index * 64, 64, v);
545    }
546    pub fn set_bool(&mut self, s: StructBuilder, bit: u64, v: bool) {
547        self.set_bits(s, bit, 1, u64::from(v));
548    }
549
550    fn pointer_slot(s: StructBuilder, index: u16) -> Result<usize> {
551        ensure!(index < s.ptr_count, "pointer {index} outside the struct");
552        Ok(s.ptrs + index as usize)
553    }
554
555    /// A new struct stored in pointer `index` of `s`.
556    pub fn init_struct(
557        &mut self,
558        s: StructBuilder,
559        index: u16,
560        data_words: u16,
561        ptr_count: u16,
562    ) -> Result<StructBuilder> {
563        let slot = Self::pointer_slot(s, index)?;
564        self.struct_at_slot(slot, data_words, ptr_count)
565    }
566
567    fn struct_at_slot(
568        &mut self,
569        slot: usize,
570        data_words: u16,
571        ptr_count: u16,
572    ) -> Result<StructBuilder> {
573        let at = self.alloc(data_words as usize + ptr_count as usize)?;
574        let child = StructBuilder {
575            data: at,
576            data_words,
577            ptrs: at + data_words as usize,
578            ptr_count,
579        };
580        self.point_struct(slot, child);
581        Ok(child)
582    }
583
584    /// A primitive list of `len` elements stored in `slot`; returns its first word.
585    fn list_at_slot(&mut self, slot: usize, size: ElementSize, len: u32) -> Result<usize> {
586        ensure!(len < 1 << 29, "list too long");
587        let words = (u64::from(len) * size.width()).div_ceil(64) as usize;
588        let at = self.alloc(words)?;
589        self.words[slot] =
590            Self::offset(slot, at) | 1 | (size.bits() << 32) | (u64::from(len) << 35);
591        Ok(at)
592    }
593
594    pub fn set_bytes(&mut self, s: StructBuilder, index: u16, bytes: &[u8]) -> Result<()> {
595        let slot = Self::pointer_slot(s, index)?;
596        self.bytes_at_slot(slot, bytes)
597    }
598
599    fn bytes_at_slot(&mut self, slot: usize, bytes: &[u8]) -> Result<()> {
600        let at = self.list_at_slot(slot, ElementSize::Byte, bytes.len() as u32)?;
601        for (i, b) in bytes.iter().enumerate() {
602            self.words[at + i / 8] |= u64::from(*b) << ((i % 8) * 8);
603        }
604        Ok(())
605    }
606
607    pub fn set_text(&mut self, s: StructBuilder, index: u16, text: &str) -> Result<()> {
608        let mut bytes = text.as_bytes().to_vec();
609        bytes.push(0);
610        self.set_bytes(s, index, &bytes)
611    }
612
613    /// A capability pointer naming entry `cap` of the payload's cap table.
614    pub fn set_capability(&mut self, s: StructBuilder, index: u16, cap: u32) -> Result<()> {
615        let slot = Self::pointer_slot(s, index)?;
616        self.words[slot] = 3 | (u64::from(cap) << 32);
617        Ok(())
618    }
619
620    /// A primitive list in pointer `index` of `s`, from raw element bits.
621    pub fn set_primitive_list(
622        &mut self,
623        s: StructBuilder,
624        index: u16,
625        size: ElementSize,
626        values: &[u64],
627    ) -> Result<()> {
628        let slot = Self::pointer_slot(s, index)?;
629        self.primitive_list_at_slot(slot, size, values)
630    }
631
632    fn primitive_list_at_slot(
633        &mut self,
634        slot: usize,
635        size: ElementSize,
636        values: &[u64],
637    ) -> Result<()> {
638        let at = self.list_at_slot(slot, size, values.len() as u32)?;
639        let width = size.width();
640        if width == 0 {
641            return Ok(());
642        }
643        for (i, v) in values.iter().enumerate() {
644            let bit = i as u64 * width;
645            let masked = if width == 64 {
646                *v
647            } else {
648                v & ((1 << width) - 1)
649            };
650            self.words[at + (bit / 64) as usize] |= masked << (bit % 64);
651        }
652        Ok(())
653    }
654
655    /// A composite list of `len` structs in pointer `index` of `s`.
656    pub fn init_struct_list(
657        &mut self,
658        s: StructBuilder,
659        index: u16,
660        len: u32,
661        data_words: u16,
662        ptr_count: u16,
663    ) -> Result<Vec<StructBuilder>> {
664        let slot = Self::pointer_slot(s, index)?;
665        self.struct_list_at_slot(slot, len, data_words, ptr_count)
666    }
667
668    fn struct_list_at_slot(
669        &mut self,
670        slot: usize,
671        len: u32,
672        data_words: u16,
673        ptr_count: u16,
674    ) -> Result<Vec<StructBuilder>> {
675        let per = data_words as usize + ptr_count as usize;
676        let words = per * len as usize;
677        ensure!(words < 1 << 29, "list too long");
678        let tag = self.alloc(1 + words)?;
679        self.words[slot] = Self::offset(slot, tag) | 1 | (7 << 32) | ((words as u64) << 35);
680        self.words[tag] =
681            (u64::from(len) << 2) | (u64::from(data_words) << 32) | (u64::from(ptr_count) << 48);
682        Ok((0..len as usize)
683            .map(|i| {
684                let at = tag + 1 + per * i;
685                StructBuilder {
686                    data: at,
687                    data_words,
688                    ptrs: at + data_words as usize,
689                    ptr_count,
690                }
691            })
692            .collect())
693    }
694
695    /// A pointer list of `len` null pointers in pointer `index` of `s`; returns the slots.
696    pub fn init_pointer_list(
697        &mut self,
698        s: StructBuilder,
699        index: u16,
700        len: u32,
701    ) -> Result<Vec<usize>> {
702        let slot = Self::pointer_slot(s, index)?;
703        self.pointer_list_at_slot(slot, len)
704    }
705
706    fn pointer_list_at_slot(&mut self, slot: usize, len: u32) -> Result<Vec<usize>> {
707        let at = self.list_at_slot(slot, ElementSize::Pointer, len)?;
708        Ok((at..at + len as usize).collect())
709    }
710
711    /// Writers addressed by raw slot, for elements of a pointer list.
712    pub fn slot_struct(
713        &mut self,
714        slot: usize,
715        data_words: u16,
716        ptr_count: u16,
717    ) -> Result<StructBuilder> {
718        self.struct_at_slot(slot, data_words, ptr_count)
719    }
720    pub fn slot_bytes(&mut self, slot: usize, bytes: &[u8]) -> Result<()> {
721        self.bytes_at_slot(slot, bytes)
722    }
723    pub fn slot_primitive_list(
724        &mut self,
725        slot: usize,
726        size: ElementSize,
727        values: &[u64],
728    ) -> Result<()> {
729        self.primitive_list_at_slot(slot, size, values)
730    }
731    pub fn slot_struct_list(
732        &mut self,
733        slot: usize,
734        len: u32,
735        data_words: u16,
736        ptr_count: u16,
737    ) -> Result<Vec<StructBuilder>> {
738        self.struct_list_at_slot(slot, len, data_words, ptr_count)
739    }
740    pub fn slot_pointer_list(&mut self, slot: usize, len: u32) -> Result<Vec<usize>> {
741        self.pointer_list_at_slot(slot, len)
742    }
743    pub fn pointer_slot_of(s: StructBuilder, index: u16) -> Result<usize> {
744        Self::pointer_slot(s, index)
745    }
746
747    /// Deep-copy what `from` points at into `slot`, capabilities kept as indexes.
748    pub fn copy_into(&mut self, slot: usize, from: Target<'_>) -> Result<()> {
749        match from {
750            Target::Null => Ok(()),
751            Target::Capability(c) => {
752                self.words[slot] = 3 | (u64::from(c) << 32);
753                Ok(())
754            }
755            Target::Struct(s) => {
756                let to = self.struct_at_slot(slot, s.data_words, s.ptr_count)?;
757                for i in 0..s.data_words as usize {
758                    self.words[to.data + i] = s.msg.segments[s.seg][s.data + i];
759                }
760                for i in 0..s.ptr_count {
761                    self.copy_into(to.ptrs + i as usize, s.pointer(i)?)?;
762                }
763                Ok(())
764            }
765            Target::List(l) => match l.size {
766                ElementSize::Composite => {
767                    let items = self.struct_list_at_slot(slot, l.len, l.data_words, l.ptr_count)?;
768                    for (i, to) in items.into_iter().enumerate() {
769                        let s = l.struct_at(i as u32)?;
770                        for w in 0..s.data_words as usize {
771                            self.words[to.data + w] = s.msg.segments[s.seg][s.data + w];
772                        }
773                        for p in 0..s.ptr_count {
774                            self.copy_into(to.ptrs + p as usize, s.pointer(p)?)?;
775                        }
776                    }
777                    Ok(())
778                }
779                ElementSize::Pointer => {
780                    let slots = self.pointer_list_at_slot(slot, l.len)?;
781                    for (i, to) in slots.into_iter().enumerate() {
782                        self.copy_into(to, l.pointer_at(i as u32)?)?;
783                    }
784                    Ok(())
785                }
786                size => {
787                    let values = (0..l.len)
788                        .map(|i| l.primitive(i))
789                        .collect::<Result<Vec<_>>>()?;
790                    self.primitive_list_at_slot(slot, size, &values)
791                }
792            },
793        }
794    }
795}