1use core::{fmt, ops::ControlFlow};
2use std::io;
3
4pub mod api;
5
6#[cfg(test)]
7use bolero::generator::*;
8
9pub trait Handler {
10 fn advance_time(&mut self, msg: AdvanceTime) -> io::Result<()>;
11 fn set_nanos_per_tick(&mut self, msg: SetNanosPerTick) -> io::Result<()>;
12 fn create_group(&mut self, msg: CreateGroup) -> io::Result<()>;
13 fn spawn_node(&mut self, msg: SpawnNode) -> io::Result<()>;
14 fn set_parameter(&mut self, msg: SetParameter) -> io::Result<()>;
15 fn pipe_parameter(&mut self, msg: PipeParameter) -> io::Result<()>;
16 fn finish_node(&mut self, msg: FinishNode) -> io::Result<()>;
17 fn init_buffer(&mut self, msg: InitBuffer) -> io::Result<()>;
18 fn load_buffer(&mut self, msg: LoadBuffer) -> io::Result<()>;
19 fn set_buffer(&mut self, msg: SetBuffer) -> io::Result<()>;
20}
21
22fn push_msg<T: fmt::Display>(output: &mut String, v: T) -> io::Result<()> {
23 use std::fmt::Write;
24 let _ = writeln!(output, "{}", v);
25 Ok(())
26}
27
28impl Handler for String {
29 fn advance_time(&mut self, msg: AdvanceTime) -> io::Result<()> {
30 push_msg(self, msg)
31 }
32
33 fn set_nanos_per_tick(&mut self, msg: SetNanosPerTick) -> io::Result<()> {
34 push_msg(self, msg)
35 }
36
37 fn create_group(&mut self, msg: CreateGroup) -> io::Result<()> {
38 push_msg(self, msg)
39 }
40
41 fn spawn_node(&mut self, msg: SpawnNode) -> io::Result<()> {
42 push_msg(self, msg)
43 }
44
45 fn set_parameter(&mut self, msg: SetParameter) -> io::Result<()> {
46 push_msg(self, msg)
47 }
48
49 fn pipe_parameter(&mut self, msg: PipeParameter) -> io::Result<()> {
50 push_msg(self, msg)
51 }
52
53 fn finish_node(&mut self, msg: FinishNode) -> io::Result<()> {
54 push_msg(self, msg)
55 }
56
57 fn init_buffer(&mut self, msg: InitBuffer) -> io::Result<()> {
58 push_msg(self, msg)
59 }
60
61 fn load_buffer(&mut self, msg: LoadBuffer) -> io::Result<()> {
62 push_msg(self, msg)
63 }
64
65 fn set_buffer(&mut self, msg: SetBuffer) -> io::Result<()> {
66 push_msg(self, msg)
67 }
68}
69
70pub fn decode<R: io::Read, H: Handler>(input: &mut R, handler: &mut H) -> io::Result<()> {
71 while decode_one(input, handler)?.is_continue() {}
72 Ok(())
73}
74
75#[deny(unreachable_patterns)]
76pub fn decode_one<R: io::Read, H: Handler>(
77 input: &mut R,
78 handler: &mut H,
79) -> io::Result<ControlFlow<()>> {
80 let tag = match input.read_u8() {
81 Ok(tag) => tag,
82 Err(err) if err.kind() == io::ErrorKind::UnexpectedEof => {
83 return Ok(ControlFlow::Break(()));
84 }
85 Err(err) => return Err(err),
86 };
87
88 match tag {
89 AdvanceTime::TAG => {
90 let msg = AdvanceTime::decode(tag, input)?;
91 handler.advance_time(msg)?;
92 }
93 SetNanosPerTick::TAG => {
94 let msg = SetNanosPerTick::decode(tag, input)?;
95 handler.set_nanos_per_tick(msg)?;
96 }
97 CreateGroup::TAG => {
98 let msg = CreateGroup::decode(tag, input)?;
99 handler.create_group(msg)?;
100 }
101 SpawnNode::TAG_NO_GROUP | SpawnNode::TAG_WITH_GROUP => {
102 let msg = SpawnNode::decode(tag, input)?;
103 handler.spawn_node(msg)?;
104 }
105 SetParameter::TAG_PARAM | SetParameter::TAG_NONE => {
106 let msg = SetParameter::decode(tag, input)?;
107 handler.set_parameter(msg)?;
108 }
109 PipeParameter::TAG_PARAM | PipeParameter::TAG_NONE => {
110 let msg = PipeParameter::decode(tag, input)?;
111 handler.pipe_parameter(msg)?;
112 }
113 FinishNode::TAG => {
114 let msg = FinishNode::decode(tag, input)?;
115 handler.finish_node(msg)?;
116 }
117 InitBuffer::TAG => {
118 let msg = InitBuffer::decode(tag, input)?;
119 handler.init_buffer(msg)?;
120 }
121 LoadBuffer::TAG => {
122 let msg = LoadBuffer::decode(tag, input)?;
123 handler.load_buffer(msg)?;
124 }
125 SetBuffer::TAG => {
126 let msg = SetBuffer::decode(tag, input)?;
127 handler.set_buffer(msg)?;
128 }
129 _ => {
130 return Err(io::Error::new(
131 io::ErrorKind::InvalidData,
132 format!("invalid tag: 0x{:x}", tag),
133 ))
134 }
135 }
136
137 Ok(ControlFlow::Continue(()))
138}
139
140pub trait Codec: Sized {
141 fn encode<W: io::Write>(&self, output: &mut W) -> io::Result<()>;
142 fn decode<R: io::Read>(tag: u8, input: &mut R) -> io::Result<Self>;
143}
144
145trait WriteExt {
146 fn write_u8(&mut self, value: u8) -> io::Result<()>;
147 fn write_u16(&mut self, value: u16) -> io::Result<()>;
148 fn write_u32(&mut self, value: u32) -> io::Result<()>;
149 fn write_u64(&mut self, value: u64) -> io::Result<()>;
150}
151
152impl<W: io::Write> WriteExt for W {
153 #[inline]
154 fn write_u8(&mut self, value: u8) -> io::Result<()> {
155 self.write_all(&[value])?;
156 Ok(())
157 }
158
159 #[inline]
160 fn write_u16(&mut self, value: u16) -> io::Result<()> {
161 self.write_all(&value.to_le_bytes())?;
162 Ok(())
163 }
164
165 #[inline]
166 fn write_u32(&mut self, value: u32) -> io::Result<()> {
167 self.write_all(&value.to_le_bytes())?;
168 Ok(())
169 }
170
171 #[inline]
172 fn write_u64(&mut self, value: u64) -> io::Result<()> {
173 self.write_all(&value.to_le_bytes())?;
174 Ok(())
175 }
176}
177
178trait ReadExt {
179 fn read_u8(&mut self) -> io::Result<u8>;
180 fn read_u16(&mut self) -> io::Result<u16>;
181 fn read_u32(&mut self) -> io::Result<u32>;
182 fn read_u64(&mut self) -> io::Result<u64>;
183 fn read_string(&mut self, len: usize) -> io::Result<String>;
184}
185
186impl<R: io::Read> ReadExt for R {
187 #[inline]
188 fn read_u8(&mut self) -> io::Result<u8> {
189 let mut value = [0u8; 1];
190 self.read_exact(&mut value)?;
191 Ok(value[0])
192 }
193
194 #[inline]
195 fn read_u16(&mut self) -> io::Result<u16> {
196 let mut value = [0u8; 2];
197 self.read_exact(&mut value)?;
198 let value = u16::from_le_bytes(value);
199 Ok(value)
200 }
201
202 #[inline]
203 fn read_u32(&mut self) -> io::Result<u32> {
204 let mut value = [0u8; 4];
205 self.read_exact(&mut value)?;
206 let value = u32::from_le_bytes(value);
207 Ok(value)
208 }
209
210 #[inline]
211 fn read_u64(&mut self) -> io::Result<u64> {
212 let mut value = [0u8; 8];
213 self.read_exact(&mut value)?;
214 let value = u64::from_le_bytes(value);
215 Ok(value)
216 }
217
218 #[inline]
219 fn read_string(&mut self, len: usize) -> io::Result<String> {
220 Ok(if len > 0 {
221 let mut name = vec![0; len as usize];
222 self.read_exact(&mut name)?;
223 match String::from_utf8_lossy(&name) {
224 std::borrow::Cow::Owned(v) => v,
225 std::borrow::Cow::Borrowed(_) => unsafe {
226 String::from_utf8_unchecked(name)
228 },
229 }
230 } else {
231 String::new()
232 })
233 }
234}
235
236#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
237#[cfg_attr(test, derive(TypeGenerator))]
238pub struct AdvanceTime {
239 pub ticks: u64,
240}
241
242impl AdvanceTime {
243 const TAG: u8 = b't';
244}
245
246impl fmt::Display for AdvanceTime {
247 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248 write!(f, "ADVANCE ticks = {:?}", self.ticks)
249 }
250}
251
252impl Codec for AdvanceTime {
253 #[inline]
254 fn encode<W: io::Write>(&self, output: &mut W) -> io::Result<()> {
255 output.write_u8(Self::TAG)?;
256 output.write_u64(self.ticks)?;
257 Ok(())
258 }
259
260 #[inline]
261 fn decode<R: io::Read>(tag: u8, input: &mut R) -> io::Result<Self> {
262 debug_assert_eq!(Self::TAG, tag);
263 let ticks = input.read_u64()?;
264 Ok(Self { ticks })
265 }
266}
267
268#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
269#[cfg_attr(test, derive(TypeGenerator))]
270pub struct SetNanosPerTick {
271 pub nanos: u64,
272}
273
274impl SetNanosPerTick {
275 const TAG: u8 = b'T';
276}
277
278impl fmt::Display for SetNanosPerTick {
279 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
280 write!(f, " NANOS_PER_TICK nanos = {}", self.nanos)
281 }
282}
283
284impl Codec for SetNanosPerTick {
285 #[inline]
286 fn encode<W: io::Write>(&self, output: &mut W) -> io::Result<()> {
287 output.write_u8(Self::TAG)?;
288 output.write_u64(self.nanos)?;
289 Ok(())
290 }
291
292 #[inline]
293 fn decode<R: io::Read>(tag: u8, input: &mut R) -> io::Result<Self> {
294 debug_assert_eq!(Self::TAG, tag);
295 let nanos = input.read_u64()?;
296 Ok(Self { nanos })
297 }
298}
299
300#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
301#[cfg_attr(test, derive(TypeGenerator))]
302pub struct CreateGroup {
303 pub id: u64,
304 #[cfg_attr(test, generator(gen::<String>().with().len(0usize..64)))]
305 pub name: String,
306}
307
308impl CreateGroup {
309 const TAG: u8 = b'g';
310}
311
312impl fmt::Display for CreateGroup {
313 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
314 write!(f, " GROUP id = {}, name = {:?}", self.id, self.name)
315 }
316}
317
318impl Codec for CreateGroup {
319 #[inline]
320 fn encode<W: io::Write>(&self, output: &mut W) -> io::Result<()> {
321 output.write_u8(Self::TAG)?;
322 output.write_u64(self.id)?;
323 let len = self.name.len().min(255);
324 output.write_u8(len as u8)?;
325 if len > 0 {
326 output.write_all(&self.name.as_bytes()[..len])?;
327 }
328 Ok(())
329 }
330
331 #[inline]
332 fn decode<R: io::Read>(tag: u8, input: &mut R) -> io::Result<Self> {
333 debug_assert_eq!(Self::TAG, tag);
334 let id = input.read_u64()?;
335 let len = input.read_u8()?;
336 let name = input.read_string(len as usize)?;
337 Ok(Self { id, name })
338 }
339}
340
341#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
342#[cfg_attr(test, derive(TypeGenerator))]
343pub struct SpawnNode {
344 pub id: u64,
345 pub processor: u64,
346 pub group: Option<u64>,
347}
348
349impl SpawnNode {
350 const TAG_NO_GROUP: u8 = b'n';
351 const TAG_WITH_GROUP: u8 = b'N';
352}
353
354impl fmt::Display for SpawnNode {
355 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
356 write!(
358 f,
359 " SPAWN id = {}, processor = {}",
360 self.id, self.processor
361 )?;
362 Ok(())
363 }
364}
365
366impl Codec for SpawnNode {
367 #[inline]
368 fn encode<W: io::Write>(&self, output: &mut W) -> io::Result<()> {
369 if self.group.is_some() {
370 output.write_u8(Self::TAG_WITH_GROUP)?;
371 } else {
372 output.write_u8(Self::TAG_NO_GROUP)?;
373 }
374 output.write_u64(self.id)?;
375 output.write_u64(self.processor)?;
376 if let Some(group) = self.group {
377 output.write_u64(group)?;
378 }
379 Ok(())
380 }
381
382 #[inline]
383 fn decode<R: io::Read>(tag: u8, input: &mut R) -> io::Result<Self> {
384 let id = input.read_u64()?;
385 let generator = input.read_u64()?;
386 let group = if tag == Self::TAG_WITH_GROUP {
387 Some(input.read_u64()?)
388 } else {
389 None
390 };
391 Ok(Self {
392 id,
393 processor: generator,
394 group,
395 })
396 }
397}
398
399#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
400#[cfg_attr(test, derive(TypeGenerator))]
401pub struct SetParameter {
402 pub target_node: u64,
403 pub target_parameter: u64,
404 pub value: u64,
405}
406
407impl SetParameter {
408 const TAG_PARAM: u8 = b'S';
409 const TAG_NONE: u8 = b's';
410}
411
412impl fmt::Display for SetParameter {
413 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
414 write!(
415 f,
416 " SET node = {}, param = {}, value = {}",
417 self.target_node,
418 self.target_parameter,
419 f64::from_bits(self.value)
420 )
421 }
422}
423
424impl Codec for SetParameter {
425 #[inline]
426 fn encode<W: io::Write>(&self, output: &mut W) -> io::Result<()> {
427 match self.target_parameter {
428 0 => {
429 output.write_u8(Self::TAG_NONE)?;
430 output.write_u64(self.target_node)?;
431 output.write_u64(self.value)?;
432 }
433 param => {
434 output.write_u8(Self::TAG_PARAM)?;
435 output.write_u64(self.target_node)?;
436 output.write_u64(param)?;
437 output.write_u64(self.value)?;
438 }
439 }
440 Ok(())
441 }
442
443 #[inline]
444 fn decode<R: io::Read>(tag: u8, input: &mut R) -> io::Result<Self> {
445 let target_node = input.read_u64()?;
446 let target_parameter = if tag == Self::TAG_PARAM {
447 input.read_u64()?
448 } else {
449 0
450 };
451 let value = input.read_u64()?;
452 Ok(Self {
453 target_node,
454 target_parameter,
455 value,
456 })
457 }
458}
459
460#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
461#[cfg_attr(test, derive(TypeGenerator))]
462pub struct PipeParameter {
463 pub target_node: u64,
464 pub target_parameter: u64,
465 pub source_node: u64,
466}
467
468impl PipeParameter {
469 const TAG_PARAM: u8 = b'P';
470 const TAG_NONE: u8 = b'p';
471}
472
473impl fmt::Display for PipeParameter {
474 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
475 write!(
476 f,
477 " PIPE node = {}, param = {}, source = {}",
478 self.target_node, self.target_parameter, self.source_node
479 )
480 }
481}
482
483impl Codec for PipeParameter {
484 #[inline]
485 fn encode<W: io::Write>(&self, output: &mut W) -> io::Result<()> {
486 match self.target_parameter {
487 0 => {
488 output.write_u8(Self::TAG_NONE)?;
489 output.write_u64(self.target_node)?;
490 output.write_u64(self.source_node)?;
491 }
492 param => {
493 output.write_u8(Self::TAG_PARAM)?;
494 output.write_u64(self.target_node)?;
495 output.write_u64(self.source_node)?;
496 output.write_u64(param)?;
497 }
498 }
499 Ok(())
500 }
501
502 #[inline]
503 fn decode<R: io::Read>(tag: u8, input: &mut R) -> io::Result<Self> {
504 let target_node = input.read_u64()?;
505 let source_node = input.read_u64()?;
506 let mut v = Self {
507 target_node,
508 target_parameter: 0,
509 source_node,
510 };
511 match tag {
512 Self::TAG_NONE => {}
513 Self::TAG_PARAM => {
514 v.target_parameter = input.read_u64()?;
515 }
516 _ => unreachable!(),
517 }
518 Ok(v)
519 }
520}
521
522#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
523#[cfg_attr(test, derive(TypeGenerator))]
524pub struct FinishNode {
525 pub node: u64,
526}
527
528impl FinishNode {
529 const TAG: u8 = b'f';
530}
531
532impl fmt::Display for FinishNode {
533 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
534 write!(f, " FIN node = {}", self.node)
535 }
536}
537
538impl Codec for FinishNode {
539 #[inline]
540 fn encode<W: io::Write>(&self, output: &mut W) -> io::Result<()> {
541 output.write_u8(Self::TAG)?;
542 output.write_u64(self.node)?;
543 Ok(())
544 }
545
546 #[inline]
547 fn decode<R: io::Read>(tag: u8, input: &mut R) -> io::Result<Self> {
548 debug_assert_eq!(Self::TAG, tag);
549 let node = input.read_u64()?;
550 Ok(Self { node })
551 }
552}
553
554#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
555#[cfg_attr(test, derive(TypeGenerator))]
556pub struct InitBuffer {
557 #[cfg_attr(test, generator(gen::<String>().with().len(0usize..64)))]
558 pub source: String,
559 #[cfg_attr(test, generator(gen::<String>().with().len(0usize..64)))]
560 pub meta: String,
561}
562
563impl InitBuffer {
564 const TAG: u8 = b'I';
565}
566
567impl fmt::Display for InitBuffer {
568 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
569 write!(f, " INIT_BUF path = {:?}", self.source)
570 }
571}
572
573impl Codec for InitBuffer {
574 #[inline]
575 fn encode<W: io::Write>(&self, output: &mut W) -> io::Result<()> {
576 output.write_u8(Self::TAG)?;
577 output.write_u32(self.source.len() as _)?;
578 output.write_all(self.source.as_bytes())?;
579 output.write_u32(self.meta.len() as _)?;
580 output.write_all(self.meta.as_bytes())?;
581 Ok(())
582 }
583
584 #[inline]
585 fn decode<R: io::Read>(tag: u8, input: &mut R) -> io::Result<Self> {
586 debug_assert_eq!(Self::TAG, tag);
587 let len = input.read_u32()?;
588 let source = input.read_string(len as usize)?;
589 let len = input.read_u32()?;
590 let meta = input.read_string(len as usize)?;
591 Ok(Self { source, meta })
592 }
593}
594
595#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
596#[cfg_attr(test, derive(TypeGenerator))]
597pub struct LoadBuffer {
598 pub id: u64,
599 #[cfg_attr(test, generator(gen::<String>().with().len(0usize..64)))]
600 pub path: String,
601 #[cfg_attr(test, generator(gen::<String>().with().len(0usize..64)))]
602 pub ext: String,
603}
604
605impl LoadBuffer {
606 const TAG: u8 = b'B';
607}
608
609impl fmt::Display for LoadBuffer {
610 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
611 write!(
612 f,
613 " LOAD_BUF id = {}, path = {:?}, ext = {:?}",
614 self.id, self.path, self.ext
615 )
616 }
617}
618
619impl Codec for LoadBuffer {
620 #[inline]
621 fn encode<W: io::Write>(&self, output: &mut W) -> io::Result<()> {
622 output.write_u8(Self::TAG)?;
623 output.write_u64(self.id)?;
624 output.write_u32(self.path.len() as _)?;
625 output.write_all(self.path.as_bytes())?;
626 if !self.ext.is_empty() {
627 output.write_u8(self.ext.len() as _)?;
628 output.write_all(self.ext.as_bytes())?;
629 } else {
630 output.write_u8(0)?;
631 }
632 Ok(())
633 }
634
635 #[inline]
636 fn decode<R: io::Read>(tag: u8, input: &mut R) -> io::Result<Self> {
637 debug_assert_eq!(Self::TAG, tag);
638 let id = input.read_u64()?;
639 let len = input.read_u32()?;
640 let path = input.read_string(len as usize)?;
641 let ext_len = input.read_u8()?;
642 let ext = if ext_len > 0 {
643 input.read_string(ext_len as _)?
644 } else {
645 String::new()
646 };
647 Ok(Self { id, path, ext })
648 }
649}
650
651#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
652#[cfg_attr(test, derive(TypeGenerator))]
653pub struct SetBuffer {
654 pub target_node: u64,
655 pub target_parameter: u64,
656 pub buffer: u64,
657 pub buffer_channel: u64,
658}
659
660impl SetBuffer {
661 const TAG: u8 = b'u';
662}
663
664impl fmt::Display for SetBuffer {
665 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
666 write!(
667 f,
668 " SET_BUFFER node = {}, param = {}, buffer = {}, channel = {}",
669 self.target_node, self.target_parameter, self.buffer, self.buffer_channel
670 )
671 }
672}
673
674impl Codec for SetBuffer {
675 #[inline]
676 fn encode<W: io::Write>(&self, output: &mut W) -> io::Result<()> {
677 output.write_u8(Self::TAG)?;
678 output.write_u64(self.target_node)?;
679 output.write_u64(self.target_parameter)?;
680 output.write_u64(self.buffer)?;
681 output.write_u64(self.buffer_channel)?;
682 Ok(())
683 }
684
685 #[inline]
686 fn decode<R: io::Read>(_tag: u8, input: &mut R) -> io::Result<Self> {
687 let target_node = input.read_u64()?;
688 let target_parameter = input.read_u64()?;
689 let buffer = input.read_u64()?;
690 let buffer_channel = input.read_u64()?;
691 Ok(Self {
692 target_node,
693 target_parameter,
694 buffer,
695 buffer_channel,
696 })
697 }
698}
699
700#[cfg(test)]
701mod tests {
702 use super::*;
703 use bolero::check;
704 use std::io::Cursor;
705
706 fn round_trip<T: Codec + fmt::Debug + PartialEq>(v: &T) {
707 let mut buf = Cursor::new(vec![]);
708 v.encode(&mut buf).unwrap();
709 buf.set_position(0);
710 let tag = buf.read_u8().unwrap();
711 let actual = T::decode(tag, &mut buf).unwrap();
712 assert_eq!(&actual, v);
713 }
714
715 #[test]
716 fn advance_time() {
717 check!().with_type::<AdvanceTime>().for_each(round_trip);
718 }
719
720 #[test]
721 fn set_nanos_per_tick() {
722 check!().with_type::<SetNanosPerTick>().for_each(round_trip);
723 }
724
725 #[test]
726 fn create_group() {
727 check!().with_type::<CreateGroup>().for_each(round_trip);
728 }
729
730 #[test]
731 fn spawn_node() {
732 check!().with_type::<SpawnNode>().for_each(round_trip);
733 }
734
735 #[test]
736 fn set_parameter() {
737 check!().with_type::<SetParameter>().for_each(round_trip);
738 }
739
740 #[test]
741 fn pipe_parameter() {
742 check!().with_type::<PipeParameter>().for_each(round_trip);
743 }
744
745 #[test]
746 fn finish_node() {
747 check!().with_type::<FinishNode>().for_each(round_trip);
748 }
749
750 #[test]
751 fn load_buffer() {
752 check!().with_type::<LoadBuffer>().for_each(round_trip);
753 }
754
755 #[test]
756 fn set_buffer() {
757 check!().with_type::<SetBuffer>().for_each(round_trip);
758 }
759}