1use anyhow::{bail, ensure, Context, Result};
6use std::sync::atomic::{AtomicU64, Ordering};
7use std::time::Duration;
8use tokio::io::{AsyncRead, AsyncReadExt};
9
10pub const MAX_MESSAGE_BYTES: usize = 4 * 1024 * 1024;
12pub const MAX_MESSAGE_WORDS: usize = MAX_MESSAGE_BYTES / 8;
13pub const MAX_SEGMENTS: usize = 64;
15pub const MAX_DEPTH: u32 = 64;
17pub const TRAVERSAL_LIMIT_WORDS: u64 = 4 * MAX_MESSAGE_WORDS as u64;
20pub const MESSAGE_TIMEOUT: Duration = Duration::from_secs(30);
22
23pub 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 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
71pub 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 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
133pub 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 data_words: u16,
159 ptr_count: u16,
160 depth: u32,
161}
162
163pub 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 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 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 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 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 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 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 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 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 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#[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 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 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 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 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 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 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 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 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 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 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}