euphony_command/
lib.rs

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                    // the lossy will check that this is valid
227                    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        // TODO map generator to name
357        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}