cmri/node_configuration/sic/
mod.rs

1//! Details for USICs and SUSICs.
2
3pub mod node_cards;
4
5use node_cards::{NodeCards, NodeCard, Error as NodeCardsError};
6
7macro_rules! common_implementation {
8    ($name:ident, $ndp:expr, $bpc:expr) => {
9        paste::paste! {
10            common_implementation!($name, $ndp, $bpc, [<$name:camel Configuration>], [<$name:upper>]);
11        }
12    };
13    ($name:ident, $ndp:expr, $bpc:expr, $serde_name:ident, $human_name:ident) => {
14        paste::paste! {
15            common_implementation!($name, $ndp, $bpc, stringify!($serde_name), stringify!($human_name));
16        }
17    };
18    ($name:ident, $ndp:expr, $bpc:expr, $serde_name:expr, $human_name:expr) => {
19        mod $name {
20            use log::trace;
21            use crate::node_configuration::NodeConfiguration;
22            use crate::packet::{Data as PacketData, Error as PacketError};
23            use super::{NodeCards, NodeCard, NodeCardsError};
24            #[allow(unused_imports)]
25            use super::super::{NDP_USIC, NDP_SUSIC};
26
27            #[doc = concat!("Configuration for a (S)USIC node with ", $bpc, " bit cards.")]
28            #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
29            pub struct Configuration {
30                pub(in super::super) transmit_delay: u16,
31                pub(in super::super) cards: NodeCards
32            }
33
34            impl Configuration {
35                /// Bytes per card.
36                const BPC: u8 = $bpc / 8;
37
38                #[doc = concat!("Create a new `", stringify!($name), "`.")]
39                #[doc = ""]
40                #[doc = "# Errors"]
41                #[doc = ""]
42                #[doc = "* [`NodeCardsError::CardAfterNone`] if there's an Input or Output card after a None card."]
43                #[doc = "* [`NodeCardsError::TooManyCards`] if there's more than 64 input/output cards."]
44                pub fn try_new(transmit_delay: u16, cards: &[NodeCard]) -> Result<Self, NodeCardsError> {
45                    let cards = NodeCards::try_new(cards)?;
46                    Ok(Self { transmit_delay, cards })
47                }
48
49                /// The cards connected to the node, including the Nones at the end.
50                #[must_use]
51                pub fn cards(&self) -> &[NodeCard] {
52                    self.cards.as_slice()
53                }
54
55                #[doc = concat!("Create a new `", stringify!($name), "` from raw bytes.")]
56                #[doc = ""]
57                #[doc = "# Errors"]
58                #[doc = ""]
59                #[doc = concat!("* [`PacketError::InvalidNodeType`] if the NDP byte isn't valid for a ", stringify!($name), " node.")]
60                #[doc = "* [`PacketError::InvalidConfiguration`]:"]
61                #[doc = "  * [`NodeCardsError::InvalidCardType`] if there's an invalid card type in the card types sequence."]
62                #[doc = "  * [`NodeCardsError::CardAfterNone`] if there's an Input or Output card after the first None card."]
63                #[doc = "  * [`NodeCardsError::TooManyCards`] if there's more than 64 input/output cards."]
64                pub(in super::super) fn decode(raw: &[u8]) -> Result<Self, PacketError> {
65                    trace!(concat!(stringify!($name), "::decode({:?})"), raw);
66                    if raw[0] != $ndp {
67                        return Err(PacketError::InvalidNodeType(raw[0]))
68                    }
69
70                    let mut cards = [NodeCard::None; 64];
71                    for (index, &byte) in raw.iter().skip(4).enumerate() {
72                        for i in 0..4 {
73                            match (byte >> (2 * i)) & 0b11 {
74                                0b00 => (),
75                                0b01 => cards[(index * 4) + i] = NodeCard::Input,
76                                0b10 => cards[(index * 4) + i] = NodeCard::Output,
77                                _ => return Err(NodeCardsError::InvalidCardType.into())
78                            }
79                        }
80                    }
81
82                    Ok(Self::try_new(
83                        u16::from_be_bytes([raw[1], raw[2]]),
84                        &cards
85                    )?)
86                }
87
88                pub(in super::super) fn encode(&self) -> PacketData {
89                    trace!(concat!(stringify!($name), ".encode({:?})"), self);
90                    let mut raw = PacketData::default();
91
92                    raw.push($ndp).expect("Always pushes less than the maximum.");
93
94                    let transmit_delay = self.transmit_delay.to_be_bytes();
95                    raw.push(transmit_delay[0]).expect("Always pushes less than the maximum.");
96                    raw.push(transmit_delay[1]).expect("Always pushes less than the maximum.");
97
98                    // Set initial count of sets of 4 cards
99                    let count_index = raw.len();
100                    raw.push(0).expect("Always pushes less than the maximum.");
101
102                    for chunk in self.cards.as_slice().chunks(4) {
103                        let mut byte = 0;
104                        for (i, &card) in chunk.iter().enumerate() {
105                            byte |= (card as u8) << u8::try_from(2 * i).expect("Upto 64 cards * 2 = Upto 128, which is less than 255.");
106                        }
107                        if byte == 0 { break } // There are no cards at all in this set of 4
108                        raw[count_index] += 1;
109                        raw.push(byte).expect("Always pushes less than the maximum.");
110                        if byte & 0b1100_0000 == 0 { break } // This is the last set of 4 cards
111                    }
112
113                    raw
114                }
115            }
116
117            impl NodeConfiguration for Configuration {
118                fn transmit_delay(&self) -> u16 { self.transmit_delay }
119                fn input_bytes(&self) -> u16 { u16::from(self.cards.input_cards()) * u16::from(Self::BPC) }
120                fn output_bytes(&self) -> u16 { u16::from(self.cards.output_cards()) * u16::from(Self::BPC) }
121            }
122
123            #[cfg(feature = "serde")]
124            #[cfg_attr(any(docsrs, toolchain = "nightly"), doc(cfg(feature = "serde")))]
125            #[cfg_attr(not(toolchain = "nightly"), doc = "**Available on crate feature serde only.**\n\n")]
126            impl ::serde::Serialize for Configuration {
127                fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
128                    use serde::ser::SerializeStruct;
129                    let mut ser = serializer.serialize_struct($serde_name, 4)?;
130                    ser.serialize_field("transmit_delay", &self.transmit_delay)?;
131                    ser.serialize_field("cards", &self.cards)?;
132                    ser.serialize_field("input_bytes", &self.input_bytes())?;
133                    ser.serialize_field("output_bytes", &self.output_bytes())?;
134                    ser.end()
135                }
136            }
137
138            #[cfg(feature = "serde")]
139            impl<'de> serde::de::Deserialize<'de> for Configuration {
140                fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> {
141                    struct Visitor;
142                    impl<'de> serde::de::Visitor<'de> for Visitor {
143                        type Value = Configuration;
144
145                        fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
146                            write!(formatter, concat!("a ", $serde_name))
147                        }
148
149                        fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error> where A: serde::de::MapAccess<'de> {
150                            let mut transmit_delay = None;
151                            let mut cards: Option<NodeCards> = None;
152
153                            while let Some(key) = map.next_key()? {
154                                match key {
155                                    "transmit_delay" => {
156                                        if transmit_delay.is_some() {
157                                            return Err(serde::de::Error::duplicate_field("transmit_delay"));
158                                        }
159                                        transmit_delay = Some(map.next_value()?);
160                                    },
161                                    "cards" => {
162                                        if cards.is_some() {
163                                            return Err(serde::de::Error::duplicate_field("cards"));
164                                        }
165                                        cards = Some(map.next_value()?);
166                                    },
167                                    "input_bytes" | "output_bytes" =>  {
168                                        // Ignored as calculated from cards
169                                        let _:u8 = map.next_value()?;
170                                    },
171                                    _ => {
172                                        return Err(serde::de::Error::unknown_field(key, &["transmit_delay, cards"]));
173                                    }
174                                }
175                            }
176
177                            let transmit_delay = transmit_delay.unwrap_or_default();
178                            let cards = cards.ok_or_else(|| serde::de::Error::missing_field("cards"))?;
179                            Configuration::try_new(transmit_delay, cards.as_slice()).map_err(serde::de::Error::custom)
180                        }
181                    }
182
183                    deserializer.deserialize_struct($serde_name, &["transmit_delay", "cards"], Visitor)
184                }
185            }
186        }
187    }
188}
189
190
191common_implementation!(usic, NDP_USIC, 24);
192pub use usic::Configuration as UsicConfiguration;
193common_implementation!(susic, NDP_SUSIC, 32);
194pub use susic::Configuration as SusicConfiguration;
195
196
197#[allow(clippy::missing_panics_doc, reason = "tests")]
198#[cfg(test)]
199mod tests {
200    use super::{UsicConfiguration, SusicConfiguration, NodeCards, NodeCard, NodeCardsError};
201    use crate::{packet::Error as PacketError, node_configuration::NodeConfiguration};
202
203    mod usic {
204        use super::*;
205
206        mod try_new {
207            use super::*;
208
209            #[test]
210            fn creates() {
211                let mut cards = [NodeCard::None; 64];
212                cards[0] = NodeCard::Input;
213                cards[1] = NodeCard::Output;
214                cards[2] = NodeCard::Output;
215
216                assert_eq!(
217                    UsicConfiguration::try_new(10, &cards),
218                    Ok(
219                        UsicConfiguration {
220                            transmit_delay: 10,
221                            cards: NodeCards::try_new(&cards).unwrap()
222                        }
223                    )
224                );
225            }
226
227            #[test]
228            fn too_many_cards() {
229                let cards = [NodeCard::None; 65];
230                assert_eq!(
231                    SusicConfiguration::try_new(0, &cards),
232                    Err(NodeCardsError::TooManyCards)
233                );
234            }
235
236            #[test]
237            fn card_after_first_none() {
238                assert_eq!(
239                    UsicConfiguration::try_new(0, &[NodeCard::None, NodeCard::Input]),
240                    Err(NodeCardsError::CardAfterNone)
241                );
242            }
243        }
244
245        mod decode {
246            use super::*;
247
248            #[test]
249            fn nocards() {
250                let raw = [b'N', 0x01, 0xF4, 0];
251                assert_eq!(
252                    UsicConfiguration::decode(&raw),
253                    Ok(
254                        UsicConfiguration {
255                            transmit_delay: 500,
256                            cards: NodeCards::default()
257                        }
258                    )
259                );
260            }
261
262            #[test]
263            fn cards_ioox() {
264                let raw = [b'N', 0, 0, 1, 0b0010_1001];
265                let mut cards = [NodeCard::None; 64];
266                cards[0] = NodeCard::Input;
267                cards[1] = NodeCard::Output;
268                cards[2] = NodeCard::Output;
269
270                assert_eq!(
271                    UsicConfiguration::decode(&raw),
272                    Ok(
273                        UsicConfiguration {
274                            transmit_delay: 0,
275                            cards: NodeCards::try_new(&cards).unwrap()
276                        }
277                    )
278                );
279            }
280
281            #[test]
282            fn card_after_first_none() {
283                let raw = [b'N', 0, 0, 1, 0b1000_0000];
284                assert_eq!(
285                    UsicConfiguration::decode(&raw),
286                    Err(PacketError::InvalidConfiguration { source: NodeCardsError::CardAfterNone.into() })
287                );
288            }
289
290            #[test]
291            fn invalid_card_type() {
292                let raw = [b'N', 0, 0, 1, 0b0000_0011];
293                assert_eq!(
294                    UsicConfiguration::decode(&raw),
295                    Err(PacketError::InvalidConfiguration { source: NodeCardsError::InvalidCardType.into() })
296                );
297            }
298
299            #[test]
300            fn invalid_ndp() {
301                let raw = [b'Z', 0x01, 0x2C, 0];
302                let configuration = UsicConfiguration::decode(&raw);
303                assert_eq!(
304                    configuration,
305                    Err(PacketError::InvalidNodeType(90))
306                );
307            }
308        }
309
310        mod encode {
311            use super::*;
312
313            #[test]
314            fn nocards() {
315                let configuration = UsicConfiguration {
316                    transmit_delay: 500,
317                    cards: NodeCards::default()
318                };
319                assert_eq!(
320                    configuration.encode(),
321                    [b'N', 0x01, 0xF4, 0]
322                );
323            }
324
325            #[test]
326            fn cards_ioox() {
327                let mut cards = [NodeCard::None; 64];
328                cards[0] = NodeCard::Input;
329                cards[1] = NodeCard::Output;
330                cards[2] = NodeCard::Output;
331
332                let configuration = UsicConfiguration {
333                    transmit_delay: 0,
334                    cards: NodeCards::try_new(&cards).unwrap()
335                };
336
337                assert_eq!(
338                    configuration.encode(),
339                    [b'N', 0, 0, 1, 0b0010_1001]
340                );
341            }
342        }
343
344        #[test]
345        fn node_configuration() {
346            let configuration = UsicConfiguration::try_new(
347                200,
348                &[NodeCard::Input, NodeCard::Output, NodeCard::Output],
349            ).unwrap();
350
351            assert_eq!(configuration.transmit_delay(), 200);
352            assert_eq!(configuration.input_bytes(), 3);
353            assert_eq!(configuration.output_bytes(), 6);
354        }
355
356        #[test]
357        fn cards() {
358            let cards = NodeCards::try_new(&[NodeCard::Input]).unwrap();
359            let configuration = UsicConfiguration::try_new(0, cards.as_slice()).unwrap();
360            assert_eq!(configuration.cards(), cards.as_slice());
361        }
362
363        #[cfg(feature = "serde")]
364        mod serde {
365            use super::*;
366            use serde_test::{assert_tokens, assert_de_tokens, assert_de_tokens_error, Token};
367
368            #[test]
369            fn valid() {
370                let configuration = UsicConfiguration::try_new(
371                    1,
372                    &[NodeCard::Output, NodeCard::Output, NodeCard::Input]
373                ).unwrap();
374
375                assert_tokens(
376                    &configuration,
377                    &[
378                        Token::Struct { name: "UsicConfiguration", len: 4 },
379                            Token::BorrowedStr("transmit_delay"),
380                            Token::U16(1),
381                            Token::BorrowedStr("cards"),
382                            Token::Seq { len: None },
383                                Token::UnitVariant { name: "NodeCard", variant: "Output" },
384                                Token::UnitVariant { name: "NodeCard", variant: "Output" },
385                                Token::UnitVariant { name: "NodeCard", variant: "Input" },
386                            Token::SeqEnd,
387                            Token::BorrowedStr("input_bytes"),
388                            Token::U16(3),
389                            Token::BorrowedStr("output_bytes"),
390                            Token::U16(6),
391                        Token::StructEnd
392                    ]
393                );
394            }
395
396            #[test]
397            fn ignored_fields_for_deserialize() {
398                // Values of input_bytes and output_bytes are calculated from cards.
399                let configuration = UsicConfiguration::try_new(
400                    1,
401                    &[NodeCard::Output, NodeCard::Output, NodeCard::Input]
402                ).unwrap();
403
404                assert_de_tokens(
405                    &configuration,
406                    &[
407                        Token::Struct { name: "UsicConfiguration", len: 4 },
408                            Token::BorrowedStr("transmit_delay"),
409                            Token::U16(1),
410                            Token::BorrowedStr("cards"),
411                            Token::Seq { len: None },
412                                Token::UnitVariant { name: "NodeCard", variant: "Output" },
413                                Token::UnitVariant { name: "NodeCard", variant: "Output" },
414                                Token::UnitVariant { name: "NodeCard", variant: "Input" },
415                            Token::SeqEnd,
416                            Token::BorrowedStr("input_bytes"),
417                            Token::U16(0),
418                            Token::BorrowedStr("output_bytes"),
419                            Token::U16(0),
420                        Token::StructEnd
421                    ]
422                );
423            }
424
425            mod optional_fields_for_deserialize {
426                use super::*;
427
428                #[test]
429                fn transmit_delay() { // Defaults to 0
430                    let configuration = UsicConfiguration::try_new(
431                        0,
432                        &[]
433                    ).unwrap();
434
435                    assert_de_tokens(
436                        &configuration,
437                        &[
438                            Token::Struct { name: "UsicConfiguration", len: 4 },
439                                Token::BorrowedStr("cards"),
440                                Token::Seq { len: None },
441                                Token::SeqEnd,
442                            Token::StructEnd
443                        ]
444                    );
445                }
446            }
447
448            #[test]
449            fn too_many_cards() {
450                assert_de_tokens_error::<UsicConfiguration>(
451                    &[
452                        Token::Struct { name: "UsicConfiguration", len: 1 },
453                        Token::BorrowedStr("cards"),
454                        Token::Seq { len: None },
455                            // 65 cards is 1 too many.
456                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
457                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
458                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
459                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
460                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
461                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
462                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
463                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
464                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
465                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
466                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
467                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
468                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
469                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
470                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
471                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
472                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
473                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
474                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
475                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
476                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
477                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
478                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
479                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
480                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
481                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
482                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
483                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
484                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
485                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
486                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
487                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
488                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
489                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
490                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
491                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
492                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
493                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
494                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
495                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
496                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
497                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
498                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
499                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
500                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
501                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
502                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
503                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
504                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
505                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
506                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
507                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
508                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
509                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
510                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
511                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
512                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
513                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
514                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
515                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
516                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
517                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
518                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
519                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
520                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
521                        Token::SeqEnd
522                    ],
523                    "invalid length 65, expected no more than 64 cards"
524                );
525
526                assert_de_tokens_error::<UsicConfiguration>(
527                    &[
528                        Token::Struct { name: "UsicConfiguration", len: 1 },
529                        Token::BorrowedStr("cards"),
530                        Token::Seq { len: Some(65) },
531                    ],
532                    "invalid length 65, expected no more than 64 cards"
533                );
534            }
535
536            #[test]
537            fn card_after_first_none() {
538                assert_de_tokens_error::<UsicConfiguration>(
539                    &[
540                        Token::Struct { name: "UsicConfiguration", len: 1 },
541                            Token::BorrowedStr("cards"),
542                            Token::Seq { len: None },
543                                Token::UnitVariant { name: "NodeCard", variant: "None" },
544                                Token::UnitVariant { name: "NodeCard", variant: "Output" },
545                            Token::SeqEnd
546                    ],
547                    "expected no cards after the first none"
548                );
549            }
550        }
551    }
552
553    mod susic {
554        use super::*;
555
556        mod try_new {
557            use super::*;
558
559            #[test]
560            fn creates() {
561                let mut cards = [NodeCard::None; 64];
562                cards[0] = NodeCard::Input;
563                cards[1] = NodeCard::Input;
564                cards[2] = NodeCard::Output;
565
566                assert_eq!(
567                    SusicConfiguration::try_new(10, &cards),
568                    Ok(
569                        SusicConfiguration {
570                            transmit_delay: 10,
571                            cards: NodeCards::try_new(&cards).unwrap()
572                        }
573                    )
574                );
575            }
576
577            #[test]
578            fn too_many_cards() {
579                let cards = [NodeCard::None; 65];
580                assert_eq!(
581                    SusicConfiguration::try_new(0, &cards),
582                    Err(NodeCardsError::TooManyCards)
583                );
584            }
585
586            #[test]
587            fn card_after_first_none() {
588                assert_eq!(
589                    SusicConfiguration::try_new(0, &[NodeCard::None, NodeCard::Input]),
590                    Err(NodeCardsError::CardAfterNone)
591                );
592            }
593        }
594
595        mod decode {
596            use super::*;
597
598            #[test]
599            fn nocards() {
600                let raw = [b'X', 0x01, 0xF4, 0];
601                assert_eq!(
602                    SusicConfiguration::decode(&raw),
603                    Ok(
604                        SusicConfiguration {
605                            transmit_delay: 500,
606                            cards: NodeCards::default()
607                        }
608                    )
609                );
610            }
611
612            #[test]
613            fn cards_ioox() {
614                let raw = [b'X', 0, 0, 1, 0b0010_1001];
615                let mut cards = [NodeCard::None; 64];
616                cards[0] = NodeCard::Input;
617                cards[1] = NodeCard::Output;
618                cards[2] = NodeCard::Output;
619
620                assert_eq!(
621                    SusicConfiguration::decode(&raw),
622                    Ok(
623                        SusicConfiguration {
624                            transmit_delay: 0,
625                            cards: NodeCards::try_new(&cards).unwrap()
626                        }
627                    )
628                );
629            }
630
631            #[test]
632            fn card_after_first_none() {
633                let raw = [b'X', 0, 0, 1, 0b1000_0000];
634                assert_eq!(
635                    SusicConfiguration::decode(&raw),
636                    Err(PacketError::InvalidConfiguration { source: NodeCardsError::CardAfterNone.into() })
637                );
638            }
639
640            #[test]
641            fn invalid_card_type() {
642                let raw = [b'X', 0, 0, 1, 0b0000_0011];
643                assert_eq!(
644                    SusicConfiguration::decode(&raw),
645                    Err(PacketError::InvalidConfiguration { source: NodeCardsError::InvalidCardType.into() })
646                );
647            }
648
649
650            #[test]
651            fn invalid_ndp() {
652                let raw = [b'Z', 0x01, 0x2C, 0];
653                let configuration = SusicConfiguration::decode(&raw);
654                assert_eq!(
655                    configuration,
656                    Err(PacketError::InvalidNodeType(90))
657                );
658            }
659        }
660
661        mod encode {
662            use super::*;
663
664            #[test]
665            fn nocards() {
666                let configuration = SusicConfiguration {
667                    transmit_delay: 500,
668                    cards: NodeCards::default()
669                };
670                assert_eq!(
671                    configuration.encode(),
672                    [b'X', 0x01, 0xF4, 0]
673                );
674            }
675
676            #[test]
677            fn cards_ioox() {
678                let mut cards = [NodeCard::None; 64];
679                cards[0] = NodeCard::Input;
680                cards[1] = NodeCard::Output;
681                cards[2] = NodeCard::Output;
682
683                let configuration = SusicConfiguration {
684                    transmit_delay: 0,
685                    cards: NodeCards::try_new(&cards).unwrap()
686                };
687
688                assert_eq!(
689                    configuration.encode(),
690                    [b'X', 0, 0, 1, 0b0010_1001]
691                );
692            }
693        }
694
695        #[test]
696        fn node_configuration() {
697            let configuration = SusicConfiguration::try_new(
698                200,
699                &[NodeCard::Input, NodeCard::Output, NodeCard::Output]
700            ).unwrap();
701
702            assert_eq!(configuration.transmit_delay(), 200);
703            assert_eq!(configuration.input_bytes(), 4);
704            assert_eq!(configuration.output_bytes(), 8);
705        }
706
707        #[test]
708        fn cards() {
709            let cards = NodeCards::try_new(&[NodeCard::Output]).unwrap();
710            let configuration = UsicConfiguration::try_new(0, cards.as_slice()).unwrap();
711            assert_eq!(configuration.cards(), cards.as_slice());
712        }
713
714        #[cfg(feature = "serde")]
715        mod serde {
716            use super::*;
717            use serde_test::{assert_tokens, assert_de_tokens, assert_de_tokens_error, Token};
718
719            #[test]
720            fn valid() {
721                let configuration = SusicConfiguration::try_new(
722                    1,
723                    &[NodeCard::Output, NodeCard::Output, NodeCard::Input]
724                ).unwrap();
725
726                assert_tokens(
727                    &configuration,
728                    &[
729                        Token::Struct { name: "SusicConfiguration", len: 4 },
730                            Token::BorrowedStr("transmit_delay"),
731                            Token::U16(1),
732                            Token::BorrowedStr("cards"),
733                            Token::Seq { len: None },
734                                Token::UnitVariant { name: "NodeCard", variant: "Output" },
735                                Token::UnitVariant { name: "NodeCard", variant: "Output" },
736                                Token::UnitVariant { name: "NodeCard", variant: "Input" },
737                            Token::SeqEnd,
738                            Token::BorrowedStr("input_bytes"),
739                            Token::U16(4),
740                            Token::BorrowedStr("output_bytes"),
741                            Token::U16(8),
742                        Token::StructEnd
743                    ]
744                );
745            }
746
747            #[test]
748            fn ignored_fields_for_deserialize() {
749                // Values of input_bytes and output_bytes are calculated form cards.
750                let configuration = SusicConfiguration::try_new(
751                    1,
752                    &[NodeCard::Output, NodeCard::Output, NodeCard::Input]
753                ).unwrap();
754
755                assert_de_tokens(
756                    &configuration,
757                    &[
758                        Token::Struct { name: "SusicConfiguration", len: 4 },
759                            Token::BorrowedStr("transmit_delay"),
760                            Token::U16(1),
761                            Token::BorrowedStr("cards"),
762                            Token::Seq { len: None },
763                                Token::UnitVariant { name: "NodeCard", variant: "Output" },
764                                Token::UnitVariant { name: "NodeCard", variant: "Output" },
765                                Token::UnitVariant { name: "NodeCard", variant: "Input" },
766                            Token::SeqEnd,
767                            Token::BorrowedStr("input_bytes"),
768                            Token::U16(0),
769                            Token::BorrowedStr("output_bytes"),
770                            Token::U16(0),
771                        Token::StructEnd
772                    ]
773                );
774            }
775
776            mod optional_fields_for_deserialize {
777                use super::*;
778
779                #[test]
780                fn transmit_delay() { // Defaults to 0
781                    let configuration = UsicConfiguration::try_new(
782                        0,
783                        &[]
784                    ).unwrap();
785
786                    assert_de_tokens(
787                        &configuration,
788                        &[
789                            Token::Struct { name: "UsicConfiguration", len: 4 },
790                                Token::BorrowedStr("cards"),
791                                Token::Seq { len: None },
792                                Token::SeqEnd,
793                            Token::StructEnd
794                        ]
795                    );
796                }
797            }
798
799            #[test]
800            fn too_many_cards() {
801                assert_de_tokens_error::<SusicConfiguration>(
802                    &[
803                        Token::Struct { name: "SusicConfiguration", len: 1 },
804                        Token::BorrowedStr("cards"),
805                        Token::Seq { len: None },
806                            // 65 cards is 1 too many.
807                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
808                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
809                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
810                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
811                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
812                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
813                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
814                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
815                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
816                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
817                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
818                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
819                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
820                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
821                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
822                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
823                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
824                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
825                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
826                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
827                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
828                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
829                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
830                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
831                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
832                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
833                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
834                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
835                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
836                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
837                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
838                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
839                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
840                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
841                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
842                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
843                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
844                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
845                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
846                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
847                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
848                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
849                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
850                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
851                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
852                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
853                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
854                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
855                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
856                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
857                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
858                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
859                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
860                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
861                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
862                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
863                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
864                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
865                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
866                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
867                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
868                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
869                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
870                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
871                            Token::UnitVariant { name: "NodeCard", variant: "Output" },
872                        Token::SeqEnd
873                    ],
874                    "invalid length 65, expected no more than 64 cards"
875                );
876
877                assert_de_tokens_error::<SusicConfiguration>(
878                    &[
879                        Token::Struct { name: "SusicConfiguration", len: 1 },
880                        Token::BorrowedStr("cards"),
881                        Token::Seq { len: Some(65) },
882                    ],
883                    "invalid length 65, expected no more than 64 cards"
884                );
885            }
886
887            #[test]
888            fn card_after_first_none() {
889                assert_de_tokens_error::<SusicConfiguration>(
890                    &[
891                        Token::Struct { name: "SusicConfiguration", len: 1 },
892                            Token::BorrowedStr("cards"),
893                            Token::Seq { len: None },
894                                Token::UnitVariant { name: "NodeCard", variant: "None" },
895                                Token::UnitVariant { name: "NodeCard", variant: "Output" },
896                            Token::SeqEnd
897                    ],
898                    "expected no cards after the first none"
899                );
900            }
901        }
902    }
903}