1use crate::pool::BufPool;
4use alloc::vec::Vec;
5use crate::envelope::{self, HEADER_LEN};
6use crate::{Bit, Error, Le};
7use bytes::{Buf, Bytes, BytesMut};
8
9pub struct Builder<'p> {
27 pool: &'p dyn BufPool,
28 buf: Option<BytesMut>,
29 stash: Vec<BytesMut>,
31 chunk: usize,
32 sealed: usize,
34 msg_start: Option<usize>,
36 prefix: usize,
38}
39
40const FRAME_PREFIX: usize = 4;
41
42#[inline]
45fn begin_msg(main: &mut BytesMut, sealed: usize, chunk: usize, prefix: usize) -> usize {
46 main.truncate(sealed);
47 if sealed == 0 && main.capacity() < chunk / 4 {
51 main.reserve(chunk);
52 }
53 main.extend_from_slice(&[0; FRAME_PREFIX]);
56 if prefix != FRAME_PREFIX {
57 widen_slot(main);
58 }
59 sealed + prefix
60}
61
62#[cold]
63#[inline(never)]
64fn widen_slot(main: &mut BytesMut) {
65 main.extend_from_slice(&[0; HEADER_LEN - FRAME_PREFIX]);
66}
67
68#[cold]
69#[inline(never)]
70#[track_caller]
71fn mode_mismatch() -> ! {
72 panic!("builder mode mismatch")
73}
74
75impl<'p> Builder<'p> {
76 #[inline]
77 pub fn new(pool: &'p dyn BufPool) -> Self {
78 Self::with_prefix(pool, FRAME_PREFIX)
79 }
80
81 #[inline]
85 pub fn new_enveloped(pool: &'p dyn BufPool) -> Self {
86 Self::with_prefix(pool, HEADER_LEN)
87 }
88
89 #[inline]
90 fn with_prefix(pool: &'p dyn BufPool, prefix: usize) -> Self {
91 Builder {
92 pool,
93 buf: Some(pool.take()),
94 stash: Vec::new(),
95 chunk: pool.chunk_size(),
96 sealed: 0,
97 msg_start: None,
98 prefix,
99 }
100 }
101
102 #[inline]
104 pub fn root(&mut self, fixed_len: u16) -> TableW<'_> {
105 let main = self.buf.as_mut().expect("builder already finished");
106 let ms = begin_msg(main, self.sealed, self.chunk, self.prefix);
107 self.msg_start = Some(ms);
108 let start = alloc_table(main, fixed_len);
109 TableW { main, aux: None, start, pool: self.pool, stash: &mut self.stash }
110 }
111
112 #[inline]
114 pub fn root_fixed<const N: usize>(&mut self) -> FixedW<'_, N> {
115 let main = self.buf.as_mut().expect("builder already finished");
116 let ms = begin_msg(main, self.sealed, self.chunk, self.prefix);
117 self.msg_start = Some(ms);
118 let start = alloc_table(main, N as u16);
119 FixedW::new(&mut main[start..start + N])
120 }
121
122 #[inline]
123 fn current(&self) -> &[u8] {
124 let buf = self.buf.as_ref().expect("builder already finished");
125 match self.msg_start {
126 Some(ms) => &buf[ms..],
127 None => &[],
128 }
129 }
130
131 #[inline]
135 pub fn finished(&self) -> Result<&[u8], Error> {
136 let m = self.current();
137 if m.len() > i32::MAX as usize {
138 return Err(Error::TooLarge);
139 }
140 Ok(m)
141 }
142
143 #[inline]
146 pub fn seal(&mut self) -> Result<(), Error> {
147 if self.prefix != FRAME_PREFIX {
148 mode_mismatch();
149 }
150 let Some(ms) = self.msg_start.take() else { return Ok(()) };
151 let buf = self.buf.as_mut().expect("builder already finished");
152 let len = buf.len() - ms;
153 if len > i32::MAX as usize {
154 buf.truncate(self.sealed);
155 return Err(Error::TooLarge);
156 }
157 buf[ms - 4..ms].copy_from_slice(&(len as u32).to_le_bytes());
158 self.sealed = buf.len();
159 Ok(())
160 }
161
162 #[inline]
164 pub fn sealed_len(&self) -> usize {
165 self.sealed
166 }
167
168 #[inline]
172 pub fn take_frames(&mut self) -> Bytes {
173 let buf = self.buf.as_mut().expect("builder already finished");
174 buf.truncate(self.sealed);
175 self.sealed = 0;
176 self.msg_start = None;
177 buf.split().freeze()
178 }
179
180 #[inline]
184 pub fn flush(&mut self) -> Result<Bytes, Error> {
185 assert!(self.sealed == 0, "flush: sealed frames pending; call take_frames first");
186 let buf = self.buf.as_mut().expect("builder already finished");
187 let Some(ms) = self.msg_start.take() else {
188 buf.clear();
189 return Ok(Bytes::new());
190 };
191 if buf.len() - ms > i32::MAX as usize {
192 buf.clear();
193 return Err(Error::TooLarge);
194 }
195 let mut msg = buf.split().freeze();
196 msg.advance(ms); Ok(msg)
198 }
199
200 #[inline]
203 fn close_envelope(buf: &mut BytesMut, ms: usize, schema_id: u64) {
204 let len = buf.len() - ms;
205 buf[ms - HEADER_LEN..ms].copy_from_slice(&envelope::header(schema_id, len as u32));
206 let crc = crate::crc32c(&buf[ms - HEADER_LEN..]);
207 buf.extend_from_slice(&crc.to_le_bytes());
208 }
209
210 #[inline]
215 pub fn seal_envelope(&mut self, schema_id: u64) -> Result<(), Error> {
216 if self.prefix != HEADER_LEN {
217 mode_mismatch();
218 }
219 let Some(ms) = self.msg_start.take() else { return Ok(()) };
220 let buf = self.buf.as_mut().expect("builder already finished");
221 if buf.len() - ms > i32::MAX as usize {
222 buf.truncate(self.sealed);
223 return Err(Error::TooLarge);
224 }
225 Self::close_envelope(buf, ms, schema_id);
226 self.sealed = buf.len();
227 Ok(())
228 }
229
230 #[inline]
236 pub fn flush_envelope(&mut self, schema_id: u64) -> Result<Bytes, Error> {
237 if self.prefix != HEADER_LEN {
238 mode_mismatch();
239 }
240 assert!(self.sealed == 0, "flush_envelope: sealed frames pending; call take_frames first");
241 let buf = self.buf.as_mut().expect("builder already finished");
242 let Some(ms) = self.msg_start.take() else {
243 buf.clear();
244 return Ok(Bytes::new());
245 };
246 if buf.len() - ms > i32::MAX as usize {
247 buf.clear();
248 return Err(Error::TooLarge);
249 }
250 Self::close_envelope(buf, ms, schema_id);
251 let mut env = buf.split().freeze();
252 env.advance(ms - HEADER_LEN); Ok(env)
254 }
255
256 #[inline]
258 pub fn finish(mut self) -> Result<Bytes, Error> {
259 self.flush()
260 }
261}
262
263impl Drop for Builder<'_> {
264 fn drop(&mut self) {
265 if let Some(b) = self.buf.take() {
266 self.pool.give(b);
267 }
268 for b in self.stash.drain(..) {
269 self.pool.give(b);
270 }
271 }
272}
273
274#[inline]
276fn alloc_table(main: &mut BytesMut, fixed_len: u16) -> usize {
277 let pos = main.len();
278 main.resize(pos + 2 + fixed_len as usize, 0);
279 main[pos..pos + 2].copy_from_slice(&fixed_len.to_le_bytes());
280 pos + 2
281}
282
283#[inline]
286fn list_size(n: u32, efl: u64) -> usize {
287 let size = n as u64 * efl;
288 assert!(size <= i32::MAX as u64, "list too large: {n} × {efl} bytes exceeds i32::MAX");
289 size as usize
290}
291
292#[inline]
295fn list_end(first: usize, size: usize) -> usize {
296 first.checked_add(size).unwrap_or_else(|| panic!("list too large: buffer offset {first} + {size} bytes overflows usize"))
297}
298
299#[inline]
300fn put<T: Le>(main: &mut BytesMut, v: T) {
301 let mut a = [0u8; 16];
302 v.write_le(&mut a[..T::SIZE]);
303 main.extend_from_slice(&a[..T::SIZE]);
304}
305
306pub struct FixedW<'a, const N: usize> {
310 fixed: &'a mut [u8; N],
311}
312
313impl<'a, const N: usize> FixedW<'a, N> {
314 #[inline(always)]
315 fn new(s: &'a mut [u8]) -> Self {
316 FixedW { fixed: s.try_into().expect("FixedW: element size mismatch (writer bug)") }
317 }
318
319 #[inline(always)]
320 pub fn set<T: Le>(&mut self, off: u16, presence: Bit, v: T) {
321 let i = off as usize;
322 v.write_le(&mut self.fixed[i..i + T::SIZE]);
323 self.fixed[presence.byte as usize] |= 1 << presence.shift;
324 }
325
326 #[inline(always)]
327 pub fn set_bool(&mut self, presence: Bit, v: bool) {
328 let b = &mut self.fixed[presence.byte as usize];
329 *b |= 1 << presence.shift;
330 if v {
331 *b |= 1 << (presence.shift + 1);
332 } else {
333 *b &= !(1 << (presence.shift + 1));
334 }
335 }
336}
337
338pub struct TableW<'b> {
348 main: &'b mut BytesMut,
349 aux: Option<&'b mut BytesMut>,
350 start: usize,
351 pool: &'b dyn BufPool,
352 stash: &'b mut Vec<BytesMut>,
353}
354
355impl<'b> TableW<'b> {
356 #[inline]
357 fn fixed_buf(&mut self) -> &mut BytesMut {
358 match self.aux.as_deref_mut() {
359 Some(a) => a,
360 None => self.main,
361 }
362 }
363
364 #[inline]
365 fn set_bit(&mut self, b: Bit) {
366 let i = self.start + b.byte as usize;
367 self.fixed_buf()[i] |= 1 << b.shift;
368 }
369
370 #[inline]
371 fn clear_bit(&mut self, b: Bit) {
372 let i = self.start + b.byte as usize;
373 self.fixed_buf()[i] &= !(1 << b.shift);
374 }
375
376 #[inline]
380 fn patch(&mut self, off: u16, target: usize) {
381 let slot = self.start + off as usize;
382 let v = if self.aux.is_some() { (target as i64 + 1) as i32 } else { (target as i64 - slot as i64) as i32 };
383 v.write_le(&mut self.fixed_buf()[slot..slot + 4]);
384 }
385
386 #[inline]
387 pub fn set<T: Le>(&mut self, off: u16, presence: Bit, v: T) {
388 let i = self.start + off as usize;
389 v.write_le(&mut self.fixed_buf()[i..i + T::SIZE]);
390 self.set_bit(presence);
391 }
392
393 #[inline]
394 pub fn set_bool(&mut self, presence: Bit, v: bool) {
395 self.set_bit(presence);
396 let value = Bit { byte: presence.byte, shift: presence.shift + 1 };
397 if v { self.set_bit(value) } else { self.clear_bit(value) }
398 }
399
400 #[inline]
401 pub fn set_bytes(&mut self, off: u16, b: &[u8]) {
402 let pos = self.main.len();
403 self.main.reserve(4 + b.len());
404 put(self.main, b.len() as u32);
405 self.main.extend_from_slice(b);
406 self.patch(off, pos);
407 }
408
409 #[inline]
410 pub fn set_str(&mut self, off: u16, s: &str) {
411 self.set_bytes(off, s.as_bytes());
412 }
413
414 pub fn set_scalars<T: Le>(&mut self, off: u16, v: &[T]) {
415 let pos = self.main.len();
416 let n = 4 + v.len() * T::SIZE;
417 self.main.resize(pos + n, 0);
418 (v.len() as u32).write_le(&mut self.main[pos..pos + 4]);
419 for (chunk, x) in self.main[pos + 4..pos + n].chunks_exact_mut(T::SIZE).zip(v) {
420 x.write_le(chunk);
421 }
422 self.patch(off, pos);
423 }
424
425 pub fn set_strs<'s>(&mut self, off: u16, v: impl ExactSizeIterator<Item = &'s str>) {
427 self.set_bytes_list(off, v.map(str::as_bytes));
428 }
429
430 pub fn set_bytes_list<'s>(&mut self, off: u16, v: impl ExactSizeIterator<Item = &'s [u8]>) {
432 let pos = self.main.len();
433 let n = v.len();
434 self.main.resize(pos + 4 + 4 * n, 0);
435 (n as u32).write_le(&mut self.main[pos..pos + 4]);
436 for (i, b) in v.enumerate() {
437 let slot = pos + 4 + 4 * i;
438 let target = self.main.len();
439 put(self.main, b.len() as u32);
440 self.main.extend_from_slice(b);
441 ((target - slot) as i32).write_le(&mut self.main[slot..slot + 4]);
442 }
443 self.patch(off, pos);
444 }
445
446 pub fn table(&mut self, off: u16, fixed_len: u16) -> TableW<'_> {
448 let pos = self.main.len();
449 let start = alloc_table(self.main, fixed_len);
450 self.patch(off, pos);
451 TableW { main: &mut *self.main, aux: None, start, pool: self.pool, stash: &mut *self.stash }
452 }
453
454 pub fn union(&mut self, off: u16, tag: u16, fixed_len: u16) -> TableW<'_> {
456 let i = self.start + off as usize;
457 tag.write_le(&mut self.fixed_buf()[i..i + 2]);
458 self.table(off + 2, fixed_len)
459 }
460
461 #[inline]
464 pub fn table_fixed<const N: usize>(&mut self, off: u16) -> FixedW<'_, N> {
465 let pos = self.main.len();
466 let start = alloc_table(self.main, N as u16);
467 self.patch(off, pos);
468 FixedW::new(&mut self.main[start..start + N])
469 }
470
471 #[inline]
474 pub fn union_fixed<const N: usize>(&mut self, off: u16, tag: u16) -> FixedW<'_, N> {
475 let i = self.start + off as usize;
476 tag.write_le(&mut self.fixed_buf()[i..i + 2]);
477 self.table_fixed(off + 2)
478 }
479
480 pub fn tables(&mut self, off: u16, n: u32, elem_fixed_len: u16) -> TableListW<'_> {
482 let size = list_size(n, elem_fixed_len as u64);
483 let pos = self.main.len();
484 let first = pos + 6;
485 self.main.resize(list_end(first, size), 0);
486 elem_fixed_len.write_le(&mut self.main[pos + 4..pos + 6]);
487 self.patch(off, pos);
488 TableListW {
489 main: &mut *self.main,
490 pool: self.pool,
491 stash: &mut *self.stash,
492 pos,
493 first,
494 efl: elem_fixed_len,
495 cap: n,
496 count: 0,
497 }
498 }
499
500 #[inline]
504 pub fn tables_fixed<const N: usize>(&mut self, off: u16, n: u32) -> FixedListW<'_, N> {
505 let size = list_size(n, N as u64);
506 let pos = self.main.len();
507 let first = pos + 6;
508 let end = list_end(first, size);
509 self.main.resize(end, 0);
510 (N as u16).write_le(&mut self.main[pos + 4..pos + 6]);
511 self.patch(off, pos);
512 let (head, region) = self.main[pos..end].split_at_mut(6);
513 let (chunks, _) = region.as_chunks_mut::<N>();
514 FixedListW { count_slot: (&mut head[..4]).try_into().unwrap(), elems: chunks.iter_mut(), count: 0 }
515 }
516
517 pub fn tables_streaming(&mut self, off: u16, elem_fixed_len: u16, ptr_slots: &'static [u16]) -> StreamListW<'_, 'b> {
521 let aux = match self.stash.pop() {
522 Some(a) => a,
523 None => self.pool.take(),
524 };
525 StreamListW { parent: self, off, aux, efl: elem_fixed_len, ptr_slots, count: 0, closed: false }
526 }
527
528 pub fn scalars_streaming<T: Le>(&mut self, off: u16) -> ScalarListW<'_, T> {
530 let pos = self.main.len();
531 self.main.resize(pos + 4, 0);
532 self.patch(off, pos);
533 ScalarListW { main: &mut *self.main, pos, count: 0, _t: core::marker::PhantomData }
534 }
535}
536
537pub struct TableListW<'a> {
539 main: &'a mut BytesMut,
540 pool: &'a dyn BufPool,
541 stash: &'a mut Vec<BytesMut>,
542 pos: usize,
543 first: usize,
544 efl: u16,
545 cap: u32,
546 count: u32,
547}
548
549impl TableListW<'_> {
550 #[inline]
552 pub fn push(&mut self) -> TableW<'_> {
553 assert!(self.count < self.cap, "TableListW: pushed more elements than reserved");
554 let start = self.first + self.count as usize * self.efl as usize;
555 self.count += 1;
556 TableW { main: &mut *self.main, aux: None, start, pool: self.pool, stash: &mut *self.stash }
557 }
558}
559
560impl TableListW<'_> {
561 #[inline]
563 pub fn push_fixed<const N: usize>(&mut self) -> FixedW<'_, N> {
564 assert!(self.count < self.cap, "TableListW: pushed more elements than reserved");
565 let start = self.first + self.count as usize * self.efl as usize;
566 self.count += 1;
567 FixedW::new(&mut self.main[start..start + N])
568 }
569}
570
571impl Drop for TableListW<'_> {
572 #[inline]
573 fn drop(&mut self) {
574 let p = self.pos;
575 self.count.write_le(&mut self.main[p..p + 4]);
576 }
577}
578
579pub struct FixedListW<'a, const N: usize> {
582 count_slot: &'a mut [u8; 4],
583 elems: core::slice::IterMut<'a, [u8; N]>,
584 count: u32,
585}
586
587impl<const N: usize> FixedListW<'_, N> {
588 #[inline(always)]
590 pub fn push(&mut self) -> FixedW<'_, N> {
591 let fixed = self.elems.next().expect("FixedListW: pushed more elements than reserved");
592 self.count += 1;
593 FixedW { fixed }
594 }
595}
596
597impl<const N: usize> Drop for FixedListW<'_, N> {
598 #[inline]
599 fn drop(&mut self) {
600 *self.count_slot = self.count.to_le_bytes();
601 }
602}
603
604pub struct StreamListW<'a, 'b> {
606 parent: &'a mut TableW<'b>,
607 off: u16,
608 aux: BytesMut,
609 efl: u16,
610 ptr_slots: &'static [u16],
611 count: u32,
612 closed: bool,
613}
614
615impl<'b> StreamListW<'_, 'b> {
616 #[inline]
617 pub fn push(&mut self) -> TableW<'_> {
618 let start = self.aux.len();
619 self.aux.resize(start + self.efl as usize, 0);
620 self.count += 1;
621 TableW {
622 main: &mut *self.parent.main,
623 aux: Some(&mut self.aux),
624 start,
625 pool: self.parent.pool,
626 stash: &mut *self.parent.stash,
627 }
628 }
629
630 #[inline]
632 pub fn push_fixed<const N: usize>(&mut self) -> FixedW<'_, N> {
633 let start = self.aux.len();
634 self.aux.resize(start + self.efl as usize, 0);
635 self.count += 1;
636 FixedW::new(&mut self.aux[start..start + N])
637 }
638
639 pub fn close(mut self) {
640 self.finalize();
641 }
642
643 fn finalize(&mut self) {
644 if self.closed {
645 return;
646 }
647 self.closed = true;
648 let main = &mut *self.parent.main;
649 let header = main.len();
650 put(main, self.count);
651 put(main, self.efl);
652 let base = main.len();
653 main.extend_from_slice(&self.aux);
654 let efl = self.efl as usize;
655 for i in 0..self.count as usize {
656 for &slot in self.ptr_slots {
657 let p = base + i * efl + slot as usize;
658 let stored = i32::read_le(&main[p..p + 4]);
659 if stored != 0 {
660 let rel = (stored as i64 - 1) - p as i64;
661 (rel as i32).write_le(&mut main[p..p + 4]);
662 }
663 }
664 }
665 self.parent.patch(self.off, header);
666 let mut aux = core::mem::take(&mut self.aux);
667 aux.clear();
668 self.parent.stash.push(aux);
669 }
670}
671
672impl Drop for StreamListW<'_, '_> {
673 fn drop(&mut self) {
674 self.finalize();
675 }
676}
677
678pub struct ScalarListW<'a, T: Le> {
680 main: &'a mut BytesMut,
681 pos: usize,
682 count: u32,
683 _t: core::marker::PhantomData<T>,
684}
685
686impl<T: Le> ScalarListW<'_, T> {
687 #[inline]
688 pub fn push(&mut self, v: T) {
689 put(self.main, v);
690 self.count += 1;
691 }
692}
693
694impl<T: Le> Drop for ScalarListW<'_, T> {
695 #[inline]
696 fn drop(&mut self) {
697 let p = self.pos;
698 self.count.write_le(&mut self.main[p..p + 4]);
699 }
700}
701
702#[cfg(all(test, feature = "std"))]
703mod tests {
704 use super::*;
705 use crate::pool::{BufPool, SimplePool};
706 use crate::{Bit, TableRef};
707 use bytes::BytesMut;
708 use core::cell::Cell;
709
710 const B0: Bit = Bit { byte: 0, shift: 0 };
711 const B1: Bit = Bit { byte: 0, shift: 1 };
712 const BB: Bit = Bit { byte: 0, shift: 2 }; const FL: u16 = 29;
716
717 #[test]
718 fn roundtrip_scalars_bool_str_bytes() {
719 let pool = SimplePool::new(64);
720 let mut b = Builder::new(&pool);
721 {
722 let mut t = b.root(FL);
723 t.set::<u64>(1, B0, 0xDEAD_BEEF_0000_0001);
724 t.set::<i16>(9, B1, -7);
725 t.set_bool(BB, true);
726 t.set_str(11, "olá");
727 t.set_bytes(15, &[1, 2, 3]);
728 }
729 let msg = b.finish().unwrap();
730 let t = TableRef::at(&msg, 0).unwrap();
731 assert_eq!(t.fixed_len(), FL);
732 assert_eq!(t.scalar::<u64>(1, B0).unwrap(), Some(0xDEAD_BEEF_0000_0001));
733 assert_eq!(t.scalar::<i16>(9, B1).unwrap(), Some(-7));
734 assert_eq!(t.bool(BB), Some(true));
735 assert_eq!(t.str(11).unwrap(), Some("olá"));
736 assert_eq!(t.bytes(15).unwrap(), Some(&[1u8, 2, 3][..]));
737 assert!(t.table(19).unwrap().is_none());
738 assert!(t.union(23).unwrap().is_none());
739 }
740
741 #[test]
742 fn bool_false_is_present() {
743 let pool = SimplePool::new(64);
744 let mut b = Builder::new(&pool);
745 b.root(FL).set_bool(BB, false);
746 let msg = b.finish().unwrap();
747 assert_eq!(TableRef::at(&msg, 0).unwrap().bool(BB), Some(false));
748 }
749
750 #[test]
751 fn nested_table_and_union_roundtrip() {
752 let pool = SimplePool::new(64);
753 let mut b = Builder::new(&pool);
754 {
755 let mut t = b.root(FL);
756 {
757 let mut c = t.table(19, 5);
758 c.set::<u32>(1, B0, 77);
759 }
760 t.set::<u64>(1, B0, 5);
761 let mut u = t.union(23, 3, 5);
762 u.set::<u32>(1, B0, 99);
763 }
764 let msg = b.finish().unwrap();
765 let t = TableRef::at(&msg, 0).unwrap();
766 assert_eq!(t.scalar::<u64>(1, B0).unwrap(), Some(5));
767 let c = t.table(19).unwrap().unwrap();
768 assert_eq!(c.fixed_len(), 5);
769 assert_eq!(c.scalar::<u32>(1, B0).unwrap(), Some(77));
770 let (tag, u) = t.union(23).unwrap().unwrap();
771 assert_eq!(tag, 3);
772 assert_eq!(u.scalar::<u32>(1, B0).unwrap(), Some(99));
773 }
774
775 #[test]
776 fn empty_string_present_vs_absent() {
777 let pool = SimplePool::new(64);
778 let mut b = Builder::new(&pool);
779 {
780 let mut t = b.root(FL);
781 t.set_str(11, "");
782 t.set_scalars::<u32>(19, &[]);
783 }
784 let msg = b.finish().unwrap();
785 let t = TableRef::at(&msg, 0).unwrap();
786 assert_eq!(t.str(11).unwrap(), Some(""));
787 assert_eq!(t.bytes(15).unwrap(), None);
788 assert_eq!(t.scalars::<u32>(19).unwrap().unwrap().len(), 0);
789 }
790
791 #[test]
792 fn scalars_and_strs_roundtrip() {
793 let pool = SimplePool::new(64);
794 let mut b = Builder::new(&pool);
795 {
796 let mut t = b.root(FL);
797 t.set_scalars::<u16>(11, &[1, 2, 3]);
798 t.set_strs(15, ["a", "", "ccc"].into_iter());
799 }
800 let msg = b.finish().unwrap();
801 let t = TableRef::at(&msg, 0).unwrap();
802 let s = t.scalars::<u16>(11).unwrap().unwrap();
803 assert_eq!(s.iter().collect::<Vec<_>>(), [1, 2, 3]);
804 let l = t.strs(15).unwrap().unwrap();
805 assert_eq!((l.get(0), l.get(1), l.get(2)), (Ok("a"), Ok(""), Ok("ccc")));
806 }
807
808 #[test]
809 fn old_bytes_survive_pool_reuse() {
810 let pool = SimplePool::new(64);
811 let mut b = Builder::new(&pool);
812 b.root(FL).set_str(11, "first");
813 let m1 = b.finish().unwrap();
814 let snapshot = m1.to_vec();
815 let mut b = Builder::new(&pool);
816 b.root(FL).set_str(11, "SECOND-LONGER-MESSAGE");
817 let m2 = b.finish().unwrap();
818 assert_eq!(&m1[..], &snapshot[..]);
819 assert_eq!(TableRef::at(&m1, 0).unwrap().str(11).unwrap(), Some("first"));
820 assert_eq!(TableRef::at(&m2, 0).unwrap().str(11).unwrap(), Some("SECOND-LONGER-MESSAGE"));
821 }
822
823 pub(crate) struct CountingPool {
824 pub takes: Cell<usize>,
825 pub gives: Cell<usize>,
826 }
827 impl CountingPool {
828 pub fn new() -> Self {
829 CountingPool { takes: Cell::new(0), gives: Cell::new(0) }
830 }
831 }
832 impl BufPool for CountingPool {
833 fn take(&self) -> BytesMut {
834 self.takes.set(self.takes.get() + 1);
835 BytesMut::with_capacity(64)
836 }
837 fn give(&self, _b: BytesMut) {
838 self.gives.set(self.gives.get() + 1);
839 }
840 }
841
842 #[test]
843 fn dropped_builder_returns_buffer() {
844 let pool = CountingPool::new();
845 {
846 let mut b = Builder::new(&pool);
847 b.root(FL).set::<u64>(1, B0, 1);
848 }
849 assert_eq!(pool.takes.get(), 1);
850 assert_eq!(pool.gives.get(), 1);
851 let b = Builder::new(&pool);
852 let _ = b.finish();
853 assert_eq!(pool.gives.get(), 2);
854 }
855
856 const EFL: u16 = 23;
859 const EPTRS: &[u16] = &[5, 9, 15, 19];
860
861 fn read_elem(e: TableRef<'_>) -> (u32, Option<String>) {
862 (e.scalar::<u32>(1, B0).unwrap().unwrap(), e.str(5).unwrap().map(String::from))
863 }
864
865 #[test]
866 fn known_count_list_roundtrip() {
867 let pool = SimplePool::new(64);
868 let mut b = Builder::new(&pool);
869 {
870 let mut t = b.root(FL);
871 let mut l = t.tables(11, 3, EFL);
872 for i in 0..3u32 {
873 let mut e = l.push();
874 e.set::<u32>(1, B0, i);
875 e.set_str(5, &format!("m{i}"));
876 }
877 }
878 let msg = b.finish().unwrap();
879 let l = TableRef::at(&msg, 0).unwrap().tables(11).unwrap().unwrap();
880 let got: Vec<_> = l.iter().map(|e| read_elem(e.unwrap())).collect();
881 assert_eq!(got, [(0, Some("m0".into())), (1, Some("m1".into())), (2, Some("m2".into()))]);
882 }
883
884 #[test]
885 fn known_count_closed_short_fixes_count() {
886 let pool = SimplePool::new(64);
887 let mut b = Builder::new(&pool);
888 {
889 let mut t = b.root(FL);
890 let mut l = t.tables(11, 5, EFL);
891 l.push().set::<u32>(1, B0, 1);
892 l.push().set::<u32>(1, B0, 2);
893 }
894 let msg = b.finish().unwrap();
895 let l = TableRef::at(&msg, 0).unwrap().tables(11).unwrap().unwrap();
896 assert_eq!(l.len(), 2);
897 assert_eq!(read_elem(l.get(1).unwrap()).0, 2);
898 }
899
900 #[test]
901 fn streaming_list_with_strings_offsets_fixed() {
902 let pool = SimplePool::new(64);
903 let mut b = Builder::new(&pool);
904 {
905 let mut t = b.root(FL);
906 t.set::<u64>(1, B0, 42);
907 let mut l = t.tables_streaming(11, EFL, EPTRS);
908 for i in 0..10u32 {
909 let mut e = l.push();
910 e.set::<u32>(1, B0, i * 10);
911 if i % 3 != 0 {
912 e.set_str(5, &format!("memo-{i}"));
913 }
914 }
915 l.close();
916 t.set_str(15, "later");
917 }
918 let msg = b.finish().unwrap();
919 let t = TableRef::at(&msg, 0).unwrap();
920 assert_eq!(t.str(15).unwrap(), Some("later"));
921 let l = t.tables(11).unwrap().unwrap();
922 assert_eq!(l.len(), 10);
923 for (i, e) in l.iter().enumerate() {
924 let (v, memo) = read_elem(e.unwrap());
925 assert_eq!(v, i as u32 * 10);
926 let want = if i % 3 != 0 { Some(format!("memo-{i}")) } else { None };
927 assert_eq!(memo, want);
928 }
929 }
930
931 #[test]
932 fn streaming_elem_with_nested_table_and_union() {
933 let pool = SimplePool::new(64);
934 let mut b = Builder::new(&pool);
935 {
936 let mut t = b.root(FL);
937 let mut l = t.tables_streaming(11, EFL, EPTRS);
938 for i in 0..4u32 {
939 let mut e = l.push();
940 e.set_str(5, "m");
941 e.table(9, 5).set::<u32>(1, B0, 100 + i);
942 e.union(13, 2, 5).set::<u32>(1, B0, 200 + i);
943 }
944 }
945 let msg = b.finish().unwrap();
946 let l = TableRef::at(&msg, 0).unwrap().tables(11).unwrap().unwrap();
947 for (i, e) in l.iter().enumerate() {
948 let e = e.unwrap();
949 assert_eq!(e.str(5).unwrap(), Some("m"));
950 assert_eq!(e.table(9).unwrap().unwrap().scalar::<u32>(1, B0).unwrap(), Some(100 + i as u32));
951 let (tag, u) = e.union(13).unwrap().unwrap();
952 assert_eq!(tag, 2);
953 assert_eq!(u.scalar::<u32>(1, B0).unwrap(), Some(200 + i as u32));
954 }
955 }
956
957 #[test]
958 fn streaming_inside_streaming() {
959 let pool = SimplePool::new(64);
960 let mut b = Builder::new(&pool);
961 {
962 let mut t = b.root(FL);
963 let mut outer = t.tables_streaming(11, EFL, EPTRS);
964 for i in 0..3u32 {
965 let mut e = outer.push();
966 e.set::<u32>(1, B0, i);
967 let mut inner = e.tables_streaming(19, EFL, EPTRS);
968 for j in 0..=i {
969 let mut ie = inner.push();
970 ie.set::<u32>(1, B0, i * 10 + j);
971 ie.set_str(5, &format!("{i}.{j}"));
972 }
973 inner.close();
974 e.set_str(5, &format!("o{i}"));
975 }
976 }
977 let msg = b.finish().unwrap();
978 let outer = TableRef::at(&msg, 0).unwrap().tables(11).unwrap().unwrap();
979 assert_eq!(outer.len(), 3);
980 for (i, e) in outer.iter().enumerate() {
981 let e = e.unwrap();
982 assert_eq!(read_elem(e), (i as u32, Some(format!("o{i}"))));
983 let inner = e.tables(19).unwrap().unwrap();
984 assert_eq!(inner.len(), i + 1);
985 for (j, ie) in inner.iter().enumerate() {
986 assert_eq!(read_elem(ie.unwrap()), ((i * 10 + j) as u32, Some(format!("{i}.{j}"))));
987 }
988 }
989 }
990
991 #[test]
992 fn streaming_list_dropped_without_close() {
993 fn fill(t: &mut TableW<'_>) -> Result<(), ()> {
994 let mut l = t.tables_streaming(11, EFL, EPTRS);
995 for i in 0..5u32 {
996 let mut e = l.push();
997 e.set::<u32>(1, B0, i);
998 e.set_str(5, "x");
999 if i == 2 {
1000 return Err(());
1001 }
1002 }
1003 Ok(())
1004 }
1005 let pool = CountingPool::new();
1006 let mut b = Builder::new(&pool);
1007 {
1008 let mut t = b.root(FL);
1009 assert!(fill(&mut t).is_err());
1010 }
1011 let msg = b.finish().unwrap();
1012 assert_eq!(pool.takes.get(), 2);
1013 assert_eq!(pool.gives.get(), 2);
1014 let l = TableRef::at(&msg, 0).unwrap().tables(11).unwrap().unwrap();
1015 assert_eq!(l.len(), 3);
1016 assert_eq!(read_elem(l.get(2).unwrap()), (2, Some("x".into())));
1017 }
1018
1019 #[test]
1020 fn streaming_scalars_roundtrip() {
1021 let pool = SimplePool::new(64);
1022 let mut b = Builder::new(&pool);
1023 {
1024 let mut t = b.root(FL);
1025 let mut l = t.scalars_streaming::<u64>(11);
1026 for i in 0..7 {
1027 l.push(i * i);
1028 }
1029 drop(l);
1030 t.set_str(15, "fim");
1031 }
1032 let msg = b.finish().unwrap();
1033 let t = TableRef::at(&msg, 0).unwrap();
1034 let l = t.scalars::<u64>(11).unwrap().unwrap();
1035 assert_eq!(l.iter().collect::<Vec<_>>(), [0, 1, 4, 9, 16, 25, 36]);
1036 assert_eq!(t.str(15).unwrap(), Some("fim"));
1037 }
1038
1039 #[test]
1040 fn empty_streaming_list_is_present() {
1041 let pool = SimplePool::new(64);
1042 let mut b = Builder::new(&pool);
1043 b.root(FL).tables_streaming(11, EFL, EPTRS).close();
1044 let msg = b.finish().unwrap();
1045 assert_eq!(TableRef::at(&msg, 0).unwrap().tables(11).unwrap().unwrap().len(), 0);
1046 }
1047
1048 #[test]
1050 fn fixed_writer_in_known_list_and_root() {
1051 let pool = SimplePool::new(64);
1052 let mut b = Builder::new(&pool);
1053 {
1054 let mut t = b.root(FL);
1055 let mut l = t.tables(11, 2, 5);
1056 for i in 0..2u32 {
1057 let mut e = l.push_fixed::<5>();
1058 e.set::<u32>(1, B0, 10 + i);
1059 }
1060 }
1061 let msg = b.finish().unwrap();
1062 let l = TableRef::at(&msg, 0).unwrap().tables(11).unwrap().unwrap();
1063 assert_eq!(l.get(1).unwrap().scalar::<u32>(1, B0).unwrap(), Some(11));
1064
1065 let mut b = Builder::new(&pool);
1066 {
1067 let mut r = b.root_fixed::<9>();
1068 r.set::<u64>(1, B0, 7);
1069 r.set_bool(B1, true);
1070 }
1071 let msg = b.finish().unwrap();
1072 let t = TableRef::at(&msg, 0).unwrap();
1073 assert_eq!(t.fixed_len(), 9);
1074 assert_eq!(t.scalar::<u64>(1, B0).unwrap(), Some(7));
1075 assert_eq!(t.bool(B1), Some(true));
1076 }
1077
1078 #[test]
1079 fn fixed_writer_in_streaming_list() {
1080 let pool = SimplePool::new(64);
1081 let mut b = Builder::new(&pool);
1082 {
1083 let mut t = b.root(FL);
1084 let mut l = t.tables_streaming(11, 5, &[]);
1085 for i in 0..3u32 {
1086 l.push_fixed::<5>().set::<u32>(1, B0, i);
1087 }
1088 }
1089 let msg = b.finish().unwrap();
1090 let l = TableRef::at(&msg, 0).unwrap().tables(11).unwrap().unwrap();
1091 assert_eq!(l.len(), 3);
1092 assert_eq!(l.get(2).unwrap().scalar::<u32>(1, B0).unwrap(), Some(2));
1093 }
1094
1095 #[test]
1097 fn finished_borrows_current_message_and_next_root_resets() {
1098 let pool = SimplePool::new(64);
1099 let mut b = Builder::new(&pool);
1100 b.root(FL).set::<u64>(1, B0, 1);
1101 let first = b.finished().unwrap().to_vec();
1102 assert_eq!(TableRef::at(&first, 0).unwrap().scalar::<u64>(1, B0).unwrap(), Some(1));
1103 b.root(FL).set::<u64>(1, B0, 2);
1104 let second = b.finished().unwrap();
1105 assert_eq!(second.len(), first.len());
1106 assert_eq!(TableRef::at(second, 0).unwrap().scalar::<u64>(1, B0).unwrap(), Some(2));
1107 }
1108
1109 #[test]
1110 fn fixed_list_roundtrip_and_short_count() {
1111 let pool = SimplePool::new(64);
1112 let mut b = Builder::new(&pool);
1113 {
1114 let mut t = b.root(FL);
1115 let mut l = t.tables_fixed::<5>(11, 4);
1116 for i in 0..3u32 {
1117 l.push().set::<u32>(1, B0, 100 + i);
1118 }
1119 }
1120 let msg = b.finish().unwrap();
1121 let l = TableRef::at(&msg, 0).unwrap().tables(11).unwrap().unwrap();
1122 assert_eq!((l.len(), l.elem_fixed_len()), (3, 5));
1123 assert_eq!(l.get(2).unwrap().scalar::<u32>(1, B0).unwrap(), Some(102));
1124 }
1125
1126 #[test]
1127 #[should_panic(expected = "list too large")]
1128 fn list_end_overflow_panics() {
1129 let _ = list_end(usize::MAX - 3, 8);
1131 }
1132
1133 #[test]
1134 fn list_end_in_range() {
1135 assert_eq!(list_end(6, 10), 16);
1136 }
1137
1138 #[test]
1139 #[should_panic(expected = "more elements than reserved")]
1140 fn fixed_list_overflow_panics() {
1141 let pool = SimplePool::new(64);
1142 let mut b = Builder::new(&pool);
1143 let mut t = b.root(FL);
1144 let mut l = t.tables_fixed::<5>(11, 1);
1145 l.push();
1146 l.push();
1147 }
1148
1149 #[test]
1151 fn sealed_frames_roundtrip_in_one_bytes() {
1152 let pool = SimplePool::new(256);
1153 let mut b = Builder::new(&pool);
1154 for i in 0..3u64 {
1155 let mut t = b.root(FL);
1156 t.set::<u64>(1, B0, i);
1157 t.set_str(11, &"x".repeat(i as usize));
1158 b.seal().unwrap();
1159 }
1160 let total: usize = (0..3).map(|i| 4 + 2 + FL as usize + 4 + i).sum();
1161 assert_eq!(b.sealed_len(), total);
1162 let batch = b.take_frames();
1163 assert_eq!(b.sealed_len(), 0);
1164 let msgs: Vec<&[u8]> = crate::frames(&batch).map(|f| f.unwrap()).collect();
1165 assert_eq!(msgs.len(), 3);
1166 for (i, m) in msgs.iter().enumerate() {
1167 let t = TableRef::at(m, 0).unwrap();
1168 assert_eq!(t.scalar::<u64>(1, B0).unwrap(), Some(i as u64));
1169 assert_eq!(t.str(11).unwrap().unwrap().len(), i);
1170 }
1171 b.root(FL).set::<u64>(1, B0, 9);
1173 b.seal().unwrap();
1174 let next = b.take_frames();
1175 assert_eq!(crate::frames(&next).count(), 1);
1176 assert_eq!(crate::frames(&batch).count(), 3, "earlier batch intact");
1177 }
1178
1179 #[test]
1180 fn unsealed_message_is_discarded_by_next_root() {
1181 let pool = SimplePool::new(256);
1182 let mut b = Builder::new(&pool);
1183 b.root(FL).set::<u64>(1, B0, 1);
1184 b.seal().unwrap();
1185 b.root(FL).set::<u64>(1, B0, 2); b.root(FL).set::<u64>(1, B0, 3);
1187 b.seal().unwrap();
1188 let batch = b.take_frames();
1189 let vals: Vec<_> = crate::frames(&batch)
1190 .map(|f| TableRef::at(f.unwrap(), 0).unwrap().scalar::<u64>(1, B0).unwrap().unwrap())
1191 .collect();
1192 assert_eq!(vals, [1, 3]);
1193 }
1194
1195 #[test]
1196 fn take_frames_excludes_unsealed_tail() {
1197 let pool = SimplePool::new(256);
1198 let mut b = Builder::new(&pool);
1199 b.root(FL).set::<u64>(1, B0, 1);
1200 b.seal().unwrap();
1201 b.root(FL).set::<u64>(1, B0, 2); let batch = b.take_frames();
1203 assert_eq!(crate::frames(&batch).count(), 1);
1204 }
1205
1206 #[test]
1207 fn frames_iterator_rejects_truncated_input() {
1208 let mut v = 10u32.to_le_bytes().to_vec();
1209 v.extend_from_slice(&[0; 4]);
1210 let r: Vec<_> = crate::frames(&v).collect();
1211 assert_eq!(r, [Err(Error::OutOfBounds)]);
1212 assert_eq!(crate::frames(&[1, 0]).collect::<Vec<_>>(), [Err(Error::OutOfBounds)]);
1213 assert_eq!(crate::frames(&[]).count(), 0);
1214 }
1215
1216 #[test]
1217 #[should_panic(expected = "sealed frames pending")]
1218 fn flush_with_pending_frames_panics() {
1219 let pool = SimplePool::new(256);
1220 let mut b = Builder::new(&pool);
1221 b.root(FL);
1222 b.seal().unwrap();
1223 b.root(FL);
1224 let _ = b.flush();
1225 }
1226}