dsdl_parser/
lib.rs

1//! A parser for the DSDL (Data structure description language) used in [uavcan](http://uavcan.org)
2//!
3//! For full description have a look at the [specification](http://uavcan.org/Specification/3._Data_structure_description_language/)
4//!
5//! ## Examples
6//! ### Parse DSDL directory
7//!
8//! ```
9//! use dsdl_parser::DSDL;
10//!
11//! assert!(DSDL::read("tests/dsdl/").is_ok());
12//!
13//! ```
14//!
15//! ### Parse single file
16//!
17//! ```
18//! use dsdl_parser::DSDL;
19//! 
20//! assert!(DSDL::read("tests/dsdl/uavcan/protocol/341.NodeStatus.uavcan").is_ok());
21//! 
22//! ```
23//!
24//! ### Display a file
25//!
26//! ```
27//! use dsdl_parser::DSDL;
28//!
29//! let dsdl = DSDL::read("./tests/dsdl/").unwrap();
30//!
31//! println!("{}", dsdl.get_file("uavcan.protocol.GetNodeInfo").unwrap());
32//! 
33//! ```
34//!
35//! ### Calculate data type signature
36//!
37//! ```
38//! use dsdl_parser::DSDL;
39//!
40//! let dsdl = DSDL::read("./tests/dsdl/").unwrap();
41//!
42//! assert_eq!(dsdl.data_type_signature("uavcan.protocol.GetNodeInfo").unwrap(), 0xee468a8121c46a9e);
43//! ```
44
45
46
47#[macro_use]
48extern crate nom;
49
50#[macro_use]
51extern crate log;
52
53use std::io::Read;
54
55use std::fs;
56
57use std::path::Path;
58
59use std::str;
60use std::str::FromStr;
61
62use std::collections::HashMap;
63
64use nom::IResult;
65
66mod parse;
67mod display;
68mod normalize;
69mod crc;
70
71use crc::CRC64WE as CRC;
72
73pub use normalize::NormalizedFile;
74
75/// The `DSDL` struct contains a number of data type definition
76#[derive(Debug, PartialEq, Eq)]
77pub struct DSDL {
78    files: HashMap<String, File>,
79}
80
81impl DSDL {
82    /// Reads `DSDL` definition recursively if path is a directory. Reads one `DSDL` definition if path is a definition.
83    ///
84    /// ## Example
85    /// ```
86    /// use dsdl_parser::DSDL;
87    ///
88    /// assert!(DSDL::read("tests/dsdl/").is_ok());
89    ///
90    /// ```
91    pub fn read<P: AsRef<Path>>(path: P) -> std::io::Result<DSDL> {
92        let mut dsdl = DSDL{files: HashMap::new()};
93
94        if path.as_ref().is_dir() {
95            for entry in fs::read_dir(path)? {
96                let current_path = entry?.path();
97                DSDL::read_uavcan_files(current_path.as_ref(), String::new(), &mut dsdl.files)?;
98            }
99        } else {
100            DSDL::read_uavcan_files(path.as_ref(), String::new(), &mut dsdl.files)?;
101        }
102
103        Ok(dsdl)
104    }
105
106    fn read_uavcan_files(path: &Path, namespace: String, files: &mut HashMap<String, File>) -> std::io::Result<()> {
107        let uavcan_path = if namespace.as_str() == "" {
108            String::from(path.file_name().unwrap().to_str().unwrap())
109        } else {
110            namespace.clone() + "." + path.file_name().unwrap().to_str().unwrap()
111        };
112        if path.is_dir() {
113            for entry in fs::read_dir(path)? {
114                let current_path = entry?.path();
115                DSDL::read_uavcan_files(&current_path, uavcan_path.clone(), files)?;
116            }
117        } else if let IResult::Done(_i, file_name) = parse::file_name(uavcan_path.as_bytes()) {
118            let mut file = fs::File::open(path)?;
119            let mut bytes = Vec::new();
120            file.read_to_end(&mut bytes)?;
121            let bytes_slice = bytes.into_boxed_slice();
122            let (remaining, definition) = parse::type_definition(&bytes_slice).unwrap();
123            
124            assert!(remaining == &b""[..], "Parsing failed at file: {}, with the following data remaining: {}", uavcan_path, str::from_utf8(remaining).unwrap());
125                                
126            let qualified_name = if file_name.namespace.as_str() == "" {
127                file_name.name.clone()
128            } else {
129                file_name.namespace.clone() + "." + file_name.name.as_str()
130            };
131            files.insert(qualified_name, File{name: file_name, definition: definition});
132        } else {
133            warn!("The file, {}, was not recognized as a DSDL file. DSDL files need to have the .uavcan extension", uavcan_path);
134        }
135        
136        Ok(())
137    }
138
139    /// Return a file if there exists one, returns `None` otherwise
140    ///
141    /// ## Example
142    /// ```
143    /// use dsdl_parser::DSDL;
144    ///
145    /// let dsdl = DSDL::read("tests/dsdl/").unwrap();
146    ///
147    /// assert!(dsdl.get_file("uavcan.protocol.NodeStatus").is_some());
148    ///
149    /// ```
150    pub fn get_file<T: AsRef<str>>(&self, name: T) -> Option<&File> {
151        self.files.get(name.as_ref())
152    }
153
154    /// Returns a vector containing references to all files
155    ///
156    /// ## Example
157    /// ```
158    /// use dsdl_parser::DSDL;
159    ///
160    /// let dsdl = DSDL::read("tests/dsdl/").unwrap();
161    ///
162    /// assert!(dsdl.files().len() >= 1);
163    ///
164    /// ```
165    pub fn files(&self) -> Vec<&File> {
166        self.files.values().collect()
167    }
168
169    /// Returns the data type signature of a data type
170    ///
171    /// ## Example
172    /// ```
173    /// use dsdl_parser::DSDL;
174    ///
175    /// let dsdl = DSDL::read("tests/dsdl/").unwrap();
176    ///
177    /// assert_eq!(dsdl.data_type_signature("uavcan.protocol.GetNodeInfo").unwrap(), 0xee468a8121c46a9e);
178    ///
179    /// ```
180    pub fn data_type_signature<T: AsRef<str>>(&self, name: T) -> Option<u64> {
181        let normalized_file = match self.get_file(name) {
182            Some(file) => file.clone().normalize(),
183            None => return None,
184        };
185        let current_namespace = normalized_file.as_file().clone().name.namespace;
186        let mut crc = CRC::from_value(normalized_file.dsdl_signature());
187
188        let lines = match normalized_file.as_file().definition {
189            TypeDefinition::Message(MessageDefinition(ref lines)) => lines.clone(),
190            TypeDefinition::Service(ServiceDefinition{request: MessageDefinition(ref request), response: MessageDefinition(ref response)}) => {let mut lines = request.clone(); lines.append(&mut response.clone()); lines},
191        };
192
193        for line in lines {
194            match line {
195                Line::Definition(
196                    AttributeDefinition::Field(
197                        FieldDefinition{field_type: Ty::Composite(
198                            CompositeType{namespace: None, ref name}), ..}), _)
199                    => crc.extend(self.data_type_signature((String::from(current_namespace.clone()) + "." + name.as_ref()).as_str()).unwrap()),
200                Line::Definition(
201                    AttributeDefinition::Field(
202                        FieldDefinition{field_type: Ty::Composite(
203                            CompositeType{namespace: Some(ref namespace), ref name}), .. }), _)
204                    => crc.extend(self.data_type_signature(String::from(namespace.clone()) + "." + name.as_ref()).unwrap()),
205                _ => (),
206            }
207
208        }
209        Some(crc.value())
210        
211    }
212        
213}
214
215/// Uniquely defines a DSDL file
216#[derive(Clone, Debug, PartialEq, Eq)]
217pub struct FileName {
218    pub id: Option<String>,
219    pub namespace: String,
220    pub name: String,
221    pub version: Option<Version>,
222}
223
224impl FileName {
225    /// Split a namespace into parts
226    ///
227    /// # Examples
228    /// ```
229    /// use dsdl_parser::FileName;
230    ///
231    /// let name = FileName {
232    ///                     id: Some(String::from("341")),
233    ///                     namespace: String::from("uavcan.protocol"),
234    ///                     name: String::from("NodeStatus"),
235    ///                     version: None,
236    /// };
237    ///
238    /// assert_eq!(name.split_namespace(), vec!["uavcan", "protocol"]);
239    ///
240    /// ```
241    pub fn split_namespace(&self) -> Vec<String> {
242        if self.namespace == String::new() {
243            Vec::new()
244        } else {
245            self.namespace.split('.').map(|x| String::from(x)).collect()
246        }
247    }
248    
249    /// Split a namespace into parts
250    ///
251    /// # Examples
252    /// ```
253    /// use dsdl_parser::FileName;
254    ///
255    /// let name = FileName {
256    ///                     id: Some(String::from("341")),
257    ///                     namespace: String::from("uavcan.protocol"),
258    ///                     name: String::from("NodeStatus"),
259    ///                     version: None,
260    /// };
261    ///
262    /// assert_eq!(name.rsplit_namespace(), vec!["protocol", "uavcan"]);
263    ///
264    /// ```
265    pub fn rsplit_namespace(&self) -> Vec<String> {
266        if self.namespace == String::new() {
267            Vec::new()
268        } else {
269            self.namespace.rsplit('.').map(|x| String::from(x)).collect()
270        }
271    }
272
273}
274
275
276#[derive(Clone, Debug, PartialEq, Eq)]
277pub enum ParseFileNameError {
278    Extension,
279    Format,
280    VersionFormat,
281}
282
283impl FromStr for FileName {
284    type Err = ParseFileNameError;
285
286    fn from_str(s: &str) -> Result<FileName, Self::Err> {
287        let mut split = s.rsplit('.').peekable();
288        
289        if let Some("uavcan") = split.next() {
290        } else {
291            return Err(ParseFileNameError::Extension);
292        }
293
294        let version = match u32::from_str(split.peek().ok_or(ParseFileNameError::Format)?) {
295            Ok(minor_version) => {
296                split.next().unwrap(); // remove minor version
297                let major_version = u32::from_str(split.next().ok_or(ParseFileNameError::Format)?).map_err(|_| ParseFileNameError::VersionFormat)?;
298                Some(Version{major: major_version, minor: minor_version})
299            },
300            Err(_) => None,
301        };
302
303        let name = String::from(split.next().unwrap());
304
305        let id = if let IResult::Done(_i, o) = parse::id(split.peek().unwrap_or(&"").as_bytes()) {
306            split.next().unwrap();
307            Some(o)
308        } else {
309            None
310        };
311
312        let mut namespace = String::from(split.next().unwrap_or(""));
313        while let Some(namespace_part) = split.next() {
314            namespace = String::from(namespace_part) + "." + namespace.as_str();
315        }
316
317        Ok(FileName{id: id, namespace: namespace, name: name, version: version})
318    }
319}
320
321
322/// A dsdl file version
323#[derive(Clone, Debug, PartialEq, Eq)]
324pub struct Version {
325    pub major: u32,
326    pub minor: u32,
327}
328
329/// A DSDL file
330#[derive(Clone, Debug, PartialEq, Eq)]
331pub struct File {
332    pub name: FileName,
333    pub definition: TypeDefinition,
334}
335
336/// A DSDL type definition.
337///
338/// Each DSDL definition specifies exactly one data structure that can be used for message broadcasting
339/// or a pair of structures that can be used for service invocation data exchange.
340#[derive(Clone, Debug, PartialEq, Eq)]
341pub enum TypeDefinition {
342    Message(MessageDefinition),
343    Service(ServiceDefinition),
344}
345
346impl From<MessageDefinition> for TypeDefinition {
347    fn from(d: MessageDefinition) -> Self {
348        TypeDefinition::Message(d)
349    }
350}
351
352impl From<ServiceDefinition> for TypeDefinition {
353    fn from(d: ServiceDefinition) -> Self {
354        TypeDefinition::Service(d)
355    }
356}
357
358
359
360/// An Uavcan message definition
361#[derive(Clone, Debug, PartialEq, Eq)]
362pub struct MessageDefinition(pub Vec<Line>);
363
364/// An Uavcan service definition
365///
366/// Since a service invocation consists of two network exchange operations,
367/// the DSDL definition for a service must define two structures:
368///
369/// - Request part - for request transfer (client to server).
370/// - Response part - for response transfer (server to client).
371#[derive(Clone, Debug, PartialEq, Eq)]
372pub struct ServiceDefinition{
373    /// The request part - for request transfer (client to server)
374    pub request: MessageDefinition,
375    /// The response part - for response transfer (server to client)
376    pub response: MessageDefinition,
377}
378
379/// A `Line` in a DSDL `File`
380///
381/// A data structure definition consists of attributes and directives.
382/// Any line of the definition file may contain at most one attribute definition or at most one directive.
383/// The same line cannot contain an attribute definition and a directive at the same time.
384#[derive(Clone, Debug, PartialEq, Eq)]
385pub enum Line {
386    Empty,
387    Comment(Comment),
388    Definition(AttributeDefinition, Option<Comment>),
389    Directive(Directive, Option<Comment>),
390}
391
392impl Line {
393    /// returns true if the `Line` is empty
394    pub fn is_empty(&self) -> bool {
395        match *self {
396            Line::Empty => true,
397            _ => false,
398        }
399    }
400
401    /// returns true if the `Line` contains a directive
402    pub fn is_directive(&self) -> bool {
403        match *self {
404            Line::Directive(_,_) => true,
405            _ => false,
406        }
407    }
408
409    /// returns true if the `Line` contains a definiition
410    pub fn is_definition(&self) -> bool {
411        match *self {
412            Line::Definition(_,_) => true,
413            _ => false,
414        }
415    }
416
417    /// returns true if the `Line` is nothing but a comment
418    pub fn is_comment(&self) -> bool {
419        match *self {
420            Line::Comment(_) => true,
421            _ => false,
422        }
423    }
424
425    /// returns true if the `Line` contains a comment
426    pub fn has_comment(&self) -> bool {
427        match *self {
428            Line::Comment(_) => true,
429            Line::Directive(_,Some(_)) => true,
430            Line::Definition(_,Some(_)) => true,
431            _ => false,
432        }
433    }
434        
435}
436
437/// A CompositeType is what the uavcan specification refers to as "Nested data structures"
438///
439/// In short if it's not a primitive data type (or arrays of primitive data types) it's a `CompositeType`
440#[derive(Clone, Debug, PartialEq, Eq)]
441pub struct CompositeType {
442    pub namespace: Option<Ident>,
443    pub name: Ident,
444}
445
446impl FromStr for CompositeType {
447    type Err = ();
448    
449    fn from_str(s: &str) -> Result<CompositeType, Self::Err> {
450        if s.contains('.') {
451            let mut split = s.rsplitn(2, '.');
452            let name = Ident(String::from(split.next().unwrap()));
453            let namespace = match split.next() {
454                Some(x) => Some(Ident(String::from(x))),
455                None => None,
456            };
457            Ok(CompositeType {
458                namespace: namespace,
459                name: name,
460            })
461        } else {
462            Ok(CompositeType {
463                namespace: None,
464                name: Ident(String::from(s))
465            })
466        }
467    }
468}
469
470/// A comment
471#[derive(Clone, Debug, PartialEq, Eq)]
472pub struct Comment(String);
473
474impl<'a> From<&'a str> for Comment {
475    fn from(s: &'a str) -> Comment {
476        Comment(String::from(s))
477    }
478}
479
480impl FromStr for Comment {
481    type Err = ();
482    
483    fn from_str(s: &str) -> Result<Comment, Self::Err> {
484        Ok(Comment::from(s))
485    }
486}
487
488impl AsRef<str> for Comment {
489    fn as_ref(&self) -> &str {
490        self.0.as_ref()
491    }
492}
493
494/// An Uavcan Directive
495///
496/// A directive is a single case-sensitive word starting with an “at sign” (@),
497/// possibly followed by space-separated arguments.
498#[derive(Clone, Copy, Debug, PartialEq, Eq)]
499pub enum Directive {
500    /// This directive instructs the DSDL compiler that the current message or the current part of a service data type (request or response) is a tagged union.
501    /// A tagged union is a data structure that may encode either of its fields at a time.
502    /// Such a data structure contains one implicit field, a union tag that indicates what particular field the data structure is holding at the moment.
503    /// Unions are required to have at least two fields.
504    Union,
505}
506
507#[derive(Clone, Debug, PartialEq, Eq)]
508pub enum ParseDirectiveError {
509    NotDirective(String),
510}
511
512impl FromStr for Directive {
513    type Err = ParseDirectiveError;
514    
515    fn from_str(s: &str) -> Result<Directive, Self::Err> {
516        match s {
517            "@union" => Ok(Directive::Union),
518            "union" => Ok(Directive::Union),
519            _ => Err(ParseDirectiveError::NotDirective(String::from(s))),
520        }
521    }
522}
523
524#[derive(Clone, Debug, PartialEq, Eq)]
525struct ServiceResponseMarker {}
526
527/// An Identifier (name)
528#[derive(Clone, Debug, PartialEq, Eq)]
529pub struct Ident(String);
530
531impl<'a> From<&'a str> for Ident {
532    fn from(s: &'a str) -> Ident {
533        Ident(String::from(s))
534    }
535}
536
537impl FromStr for Ident {
538    type Err = ();
539    
540    fn from_str(s: &str) -> Result<Ident, Self::Err> {
541        Ok(Ident(String::from(s)))
542    }
543}
544
545impl AsRef<str> for Ident {
546    fn as_ref(&self) -> &str {
547        self.0.as_ref()
548    }
549}
550
551impl From<Ident> for String {
552    fn from(i: Ident) -> String {
553        i.0
554    }
555}
556
557impl From<String> for Ident {
558    fn from(s: String) -> Ident {
559        Ident(s)
560    }
561}
562
563/// Used to determin size of e.g. DynamicArray or a StaticArray
564#[derive(Clone, Copy, Debug, PartialEq, Eq)]
565pub struct Size(u64);
566
567impl FromStr for Size {
568    type Err = std::num::ParseIntError;
569    
570    fn from_str(s: &str) -> Result<Self, Self::Err> {
571        Ok(Size(u64::from_str(s)?))
572    }
573}
574
575impl From<Size> for u64 {
576    fn from(i: Size) -> u64 {
577        i.0
578    }
579}
580
581impl From<u8> for Size {
582    fn from(i: u8) -> Size {
583        Size(u64::from(i))
584    }
585}
586
587impl From<u16> for Size {
588    fn from(i: u16) -> Size {
589        Size(u64::from(i))
590    }
591}
592
593impl From<u32> for Size {
594    fn from(i: u32) -> Size {
595        Size(u64::from(i))
596    }
597}
598
599impl From<u64> for Size {
600    fn from(i: u64) -> Size {
601        Size(i)
602    }
603}
604
605/// A constant must be a primitive scalar type (i.e., arrays and nested data structures are not allowed as constant types).
606#[derive(Clone, Debug, PartialEq, Eq)]
607pub enum Const {
608
609    /// Integer zero (0) or Integer literal in base 10, starting with a non-zero character. E.g., 123, -12.
610    Dec(String),
611    
612    /// Integer literal in base 16 prefixed with 0x. E.g., 0x123, -0x12, +0x123.
613    Hex(String),
614
615    /// Integer literal in base 8 prefixed with 0o. E.g., 0o123, -0o777, +0o777.
616    Oct(String),
617    
618    /// Integer literal in base 2 prefixed with 0b. E.g., 0b1101, -0b101101, +0b101101.
619    Bin(String),
620    
621    /// Boolean true or false.
622    Bool(bool),
623    
624    /// Single ASCII character, ASCII escape sequence, or ASCII hex literal in single quotes. E.g., 'a', '\x61', '\n'.
625    Char(String),
626    
627    /// Floating point literal. Fractional part with an optional exponent part, e.g., 15.75, 1.575E1, 1575e-2, -2.5e-3, +25E-4. Not-a-number (NaN), positive infinity, and negative infinity are intentionally not supported in order to maximize cross-platform compatibility.
628    Float(String),
629}
630
631/// Cast mode defines the rules of conversion from the native value of a certain programming language to the serialized field value.
632///
633/// Cast mode may be left undefined, in which case the default will be used.
634#[derive(Clone, Copy, Debug, PartialEq, Eq)]
635pub enum CastMode {
636    /// This is the default cast mode, which will be used if the attribute definition does not specify the cast mode explicitly.
637    ///
638    /// For integers, it prevents an integer overflow - for example, attempting to write 0x44 to a 4-bit field will result in a bitfield value of 0x0F.
639    /// For floating point values, it prevents overflow when casting to a lower precision floating point representation -
640    /// for example, 65536.0 will be converted to a float16 as 65504.0; infinity will be preserved.
641    Saturated,
642
643    ///  For integers, it discards the excess most significant bits - for example, attempting to write 0x44 to a 4-bit field will produce 0x04.
644    /// For floating point values, overflow during downcasting will produce an infinity.
645    Truncated,
646}
647
648#[derive(Clone, Debug, PartialEq, Eq)]
649pub enum ParseCastModeError {
650    NotCastMode(String),
651}
652
653impl FromStr for CastMode {
654    type Err = ParseCastModeError;
655    
656    fn from_str(s: &str) -> Result<Self, Self::Err> {
657        match s {
658            "saturated" => Ok(CastMode::Saturated),
659            "truncated" => Ok(CastMode::Truncated),
660            _ => Err(ParseCastModeError::NotCastMode(String::from(s))),
661        }
662    }
663}
664
665/// Uavcan array information
666#[derive(Clone, Debug, PartialEq, Eq)]
667pub enum ArrayInfo {
668    /// Not an array (i.e. `uint2`)
669    Single,
670    /// Dynamic array on the less than form (i.e. `uint2[<5]`)
671    DynamicLess(Size),
672    /// Dynamic array on the less or equal form (i.e. `uint2[<=5]`)
673    DynamicLeq(Size),
674    /// Static array on the less or equal form (i.e. `uint2[5]`)
675    Static(Size),
676}
677
678
679/// A Field definition
680///
681/// Field definition patterns
682/// - `cast_mode field_type field_name`
683/// - `cast_mode field_type[X] field_name`
684/// - `cast_mode field_type[<X] field_name`
685/// - `cast_mode field_type[<=X] field_name`
686/// - `void_type`
687#[derive(Clone, Debug, PartialEq, Eq)]
688pub struct FieldDefinition {
689    pub cast_mode: Option<CastMode>,
690    pub field_type: Ty,
691    pub array: ArrayInfo,
692    pub name: Option<Ident>,
693}
694
695/// A constant definition
696///
697/// Constant definition patterns
698/// - `cast_mode constant_type constant_name = constant_initializer`
699#[derive(Clone, Debug, PartialEq, Eq)]
700pub struct ConstDefinition {
701    pub cast_mode: Option<CastMode>,
702    pub field_type: Ty,
703    pub name: Ident,
704    pub constant: Const,
705}
706
707/// An attribute definition is either a `FieldDefintion` or a `ConstDefinition`
708#[derive(Clone, Debug, PartialEq, Eq)]
709pub enum AttributeDefinition {
710    Field(FieldDefinition),
711    Const(ConstDefinition),
712}
713
714impl From<FieldDefinition> for AttributeDefinition {
715    fn from(d: FieldDefinition) -> Self {
716        AttributeDefinition::Field(d)
717    }
718}
719
720impl From<ConstDefinition> for AttributeDefinition {
721    fn from(d: ConstDefinition) -> Self {
722        AttributeDefinition::Const(d)
723    }
724}
725
726/// An Uavcan data type
727#[derive(Clone, Debug, PartialEq, Eq)]
728pub enum Ty{
729    Primitive(PrimitiveType),
730    Composite(CompositeType),
731}
732
733impl Ty {
734    pub fn is_void(&self) -> bool {
735        match *self{
736            Ty::Primitive(ref x) => x.is_void(),
737            Ty::Composite(_) => false,
738        }
739    }
740}
741
742impl From<PrimitiveType> for Ty {
743    fn from(t: PrimitiveType) -> Ty {
744        Ty::Primitive(t)
745    }
746}
747
748impl From<CompositeType> for Ty {
749    fn from(t: CompositeType) -> Ty {
750        Ty::Composite(t)
751    }
752}
753
754/// An Uavcan `PrimitiveDataType`
755///
756/// These types are assumed to be built-in. They can be directly referenced from any data type of any namespace.
757/// The DSDL compiler should implement these types using the native types of the target programming language.
758#[derive(Clone, Copy, Debug, PartialEq, Eq)]
759pub enum PrimitiveType {
760    Bool,
761    
762            Uint2,  Uint3,  Uint4,  Uint5,  Uint6,  Uint7,  Uint8,
763    Uint9,  Uint10, Uint11, Uint12, Uint13, Uint14, Uint15, Uint16,
764    Uint17, Uint18, Uint19, Uint20, Uint21, Uint22, Uint23, Uint24,
765    Uint25, Uint26, Uint27, Uint28, Uint29, Uint30, Uint31, Uint32,
766    Uint33, Uint34, Uint35, Uint36, Uint37, Uint38, Uint39, Uint40,
767    Uint41, Uint42, Uint43, Uint44, Uint45, Uint46, Uint47, Uint48,
768    Uint49, Uint50, Uint51, Uint52, Uint53, Uint54, Uint55, Uint56,
769    Uint57, Uint58, Uint59, Uint60, Uint61, Uint62, Uint63, Uint64,
770
771           Int2,  Int3,  Int4,  Int5,  Int6,  Int7,  Int8,
772    Int9,  Int10, Int11, Int12, Int13, Int14, Int15, Int16,
773    Int17, Int18, Int19, Int20, Int21, Int22, Int23, Int24,
774    Int25, Int26, Int27, Int28, Int29, Int30, Int31, Int32,
775    Int33, Int34, Int35, Int36, Int37, Int38, Int39, Int40,
776    Int41, Int42, Int43, Int44, Int45, Int46, Int47, Int48,
777    Int49, Int50, Int51, Int52, Int53, Int54, Int55, Int56,
778    Int57, Int58, Int59, Int60, Int61, Int62, Int63, Int64,
779
780    Float16, Float32, Float64,
781    
782    Void1,  Void2,  Void3,  Void4,  Void5,  Void6,  Void7,  Void8,
783    Void9,  Void10, Void11, Void12, Void13, Void14, Void15, Void16,
784    Void17, Void18, Void19, Void20, Void21, Void22, Void23, Void24,
785    Void25, Void26, Void27, Void28, Void29, Void30, Void31, Void32,
786    Void33, Void34, Void35, Void36, Void37, Void38, Void39, Void40,
787    Void41, Void42, Void43, Void44, Void45, Void46, Void47, Void48,
788    Void49, Void50, Void51, Void52, Void53, Void54, Void55, Void56,
789    Void57, Void58, Void59, Void60, Void61, Void62, Void63, Void64,
790}
791
792#[derive(Clone, Debug, PartialEq, Eq)]
793pub enum ParsePrimitiveTypeError {
794    NotPrimitiveType(String),
795}
796
797impl FromStr for PrimitiveType {
798    type Err = ParsePrimitiveTypeError;
799    
800    fn from_str(s: &str) -> Result<PrimitiveType, Self::Err> {    
801        match s {
802            "bool" => Ok(PrimitiveType::Bool),
803            
804            "uint2" => Ok(PrimitiveType::Uint2),
805            "uint3" => Ok(PrimitiveType::Uint3),
806            "uint4" => Ok(PrimitiveType::Uint4),
807            "uint5" => Ok(PrimitiveType::Uint5),
808            "uint6" => Ok(PrimitiveType::Uint6),
809            "uint7" => Ok(PrimitiveType::Uint7),
810            "uint8" => Ok(PrimitiveType::Uint8),
811            "uint9" => Ok(PrimitiveType::Uint9),            
812            "uint10" => Ok(PrimitiveType::Uint10),
813            "uint11" => Ok(PrimitiveType::Uint11),
814            "uint12" => Ok(PrimitiveType::Uint12),
815            "uint13" => Ok(PrimitiveType::Uint13),
816            "uint14" => Ok(PrimitiveType::Uint14),
817            "uint15" => Ok(PrimitiveType::Uint15),
818            "uint16" => Ok(PrimitiveType::Uint16),
819            "uint17" => Ok(PrimitiveType::Uint17),
820            "uint18" => Ok(PrimitiveType::Uint18),
821            "uint19" => Ok(PrimitiveType::Uint19),
822            "uint20" => Ok(PrimitiveType::Uint20),
823            "uint21" => Ok(PrimitiveType::Uint21),
824            "uint22" => Ok(PrimitiveType::Uint22),
825            "uint23" => Ok(PrimitiveType::Uint23),
826            "uint24" => Ok(PrimitiveType::Uint24),
827            "uint25" => Ok(PrimitiveType::Uint25),
828            "uint26" => Ok(PrimitiveType::Uint26),
829            "uint27" => Ok(PrimitiveType::Uint27),
830            "uint28" => Ok(PrimitiveType::Uint28),
831            "uint29" => Ok(PrimitiveType::Uint29),
832            "uint30" => Ok(PrimitiveType::Uint30),
833            "uint31" => Ok(PrimitiveType::Uint31),
834            "uint32" => Ok(PrimitiveType::Uint32),
835            
836            "uint33" => Ok(PrimitiveType::Uint33),
837            "uint34" => Ok(PrimitiveType::Uint34),
838            "uint35" => Ok(PrimitiveType::Uint35),
839            "uint36" => Ok(PrimitiveType::Uint36),
840            "uint37" => Ok(PrimitiveType::Uint37),
841            "uint38" => Ok(PrimitiveType::Uint38),
842            "uint39" => Ok(PrimitiveType::Uint39),
843            "uint40" => Ok(PrimitiveType::Uint40),
844            "uint41" => Ok(PrimitiveType::Uint41),
845            "uint42" => Ok(PrimitiveType::Uint42),
846            "uint43" => Ok(PrimitiveType::Uint43),
847            "uint44" => Ok(PrimitiveType::Uint44),
848            "uint45" => Ok(PrimitiveType::Uint45),
849            "uint46" => Ok(PrimitiveType::Uint46),
850            "uint47" => Ok(PrimitiveType::Uint47),
851            "uint48" => Ok(PrimitiveType::Uint48),
852            "uint49" => Ok(PrimitiveType::Uint49),
853            "uint50" => Ok(PrimitiveType::Uint50),
854            "uint51" => Ok(PrimitiveType::Uint51),
855            "uint52" => Ok(PrimitiveType::Uint52),
856            "uint53" => Ok(PrimitiveType::Uint53),
857            "uint54" => Ok(PrimitiveType::Uint54),
858            "uint55" => Ok(PrimitiveType::Uint55),
859            "uint56" => Ok(PrimitiveType::Uint56),
860            "uint57" => Ok(PrimitiveType::Uint57),
861            "uint58" => Ok(PrimitiveType::Uint58),
862            "uint59" => Ok(PrimitiveType::Uint59),
863            "uint60" => Ok(PrimitiveType::Uint60),
864            "uint61" => Ok(PrimitiveType::Uint61),
865            "uint62" => Ok(PrimitiveType::Uint62),
866            "uint63" => Ok(PrimitiveType::Uint63),
867            "uint64" => Ok(PrimitiveType::Uint64),
868
869            "int2" => Ok(PrimitiveType::Int2),
870            "int3" => Ok(PrimitiveType::Int3),
871            "int4" => Ok(PrimitiveType::Int4),
872            "int5" => Ok(PrimitiveType::Int5),
873            "int6" => Ok(PrimitiveType::Int6),
874            "int7" => Ok(PrimitiveType::Int7),
875            "int8" => Ok(PrimitiveType::Int8),
876            "int9" => Ok(PrimitiveType::Int9),            
877            "int10" => Ok(PrimitiveType::Int10),
878            "int11" => Ok(PrimitiveType::Int11),
879            "int12" => Ok(PrimitiveType::Int12),
880            "int13" => Ok(PrimitiveType::Int13),
881            "int14" => Ok(PrimitiveType::Int14),
882            "int15" => Ok(PrimitiveType::Int15),
883            "int16" => Ok(PrimitiveType::Int16),
884            "int17" => Ok(PrimitiveType::Int17),
885            "int18" => Ok(PrimitiveType::Int18),
886            "int19" => Ok(PrimitiveType::Int19),
887            "int20" => Ok(PrimitiveType::Int20),
888            "int21" => Ok(PrimitiveType::Int21),
889            "int22" => Ok(PrimitiveType::Int22),
890            "int23" => Ok(PrimitiveType::Int23),
891            "int24" => Ok(PrimitiveType::Int24),
892            "int25" => Ok(PrimitiveType::Int25),
893            "int26" => Ok(PrimitiveType::Int26),
894            "int27" => Ok(PrimitiveType::Int27),
895            "int28" => Ok(PrimitiveType::Int28),
896            "int29" => Ok(PrimitiveType::Int29),
897            "int30" => Ok(PrimitiveType::Int30),
898            "int31" => Ok(PrimitiveType::Int31),
899            "int32" => Ok(PrimitiveType::Int32),
900            
901            "int33" => Ok(PrimitiveType::Int33),
902            "int34" => Ok(PrimitiveType::Int34),
903            "int35" => Ok(PrimitiveType::Int35),
904            "int36" => Ok(PrimitiveType::Int36),
905            "int37" => Ok(PrimitiveType::Int37),
906            "int38" => Ok(PrimitiveType::Int38),
907            "int39" => Ok(PrimitiveType::Int39),
908            "int40" => Ok(PrimitiveType::Int40),
909            "int41" => Ok(PrimitiveType::Int41),
910            "int42" => Ok(PrimitiveType::Int42),
911            "int43" => Ok(PrimitiveType::Int43),
912            "int44" => Ok(PrimitiveType::Int44),
913            "int45" => Ok(PrimitiveType::Int45),
914            "int46" => Ok(PrimitiveType::Int46),
915            "int47" => Ok(PrimitiveType::Int47),
916            "int48" => Ok(PrimitiveType::Int48),
917            "int49" => Ok(PrimitiveType::Int49),
918            "int50" => Ok(PrimitiveType::Int50),
919            "int51" => Ok(PrimitiveType::Int51),
920            "int52" => Ok(PrimitiveType::Int52),
921            "int53" => Ok(PrimitiveType::Int53),
922            "int54" => Ok(PrimitiveType::Int54),
923            "int55" => Ok(PrimitiveType::Int55),
924            "int56" => Ok(PrimitiveType::Int56),
925            "int57" => Ok(PrimitiveType::Int57),
926            "int58" => Ok(PrimitiveType::Int58),
927            "int59" => Ok(PrimitiveType::Int59),
928            "int60" => Ok(PrimitiveType::Int60),
929            "int61" => Ok(PrimitiveType::Int61),
930            "int62" => Ok(PrimitiveType::Int62),
931            "int63" => Ok(PrimitiveType::Int63),
932            "int64" => Ok(PrimitiveType::Int64),
933
934            "void1" => Ok(PrimitiveType::Void1),
935            "void2" => Ok(PrimitiveType::Void2),
936            "void3" => Ok(PrimitiveType::Void3),
937            "void4" => Ok(PrimitiveType::Void4),
938            "void5" => Ok(PrimitiveType::Void5),
939            "void6" => Ok(PrimitiveType::Void6),
940            "void7" => Ok(PrimitiveType::Void7),
941            "void8" => Ok(PrimitiveType::Void8),
942            "void9" => Ok(PrimitiveType::Void9),            
943            "void10" => Ok(PrimitiveType::Void10),
944            "void11" => Ok(PrimitiveType::Void11),
945            "void12" => Ok(PrimitiveType::Void12),
946            "void13" => Ok(PrimitiveType::Void13),
947            "void14" => Ok(PrimitiveType::Void14),
948            "void15" => Ok(PrimitiveType::Void15),
949            "void16" => Ok(PrimitiveType::Void16),
950            "void17" => Ok(PrimitiveType::Void17),
951            "void18" => Ok(PrimitiveType::Void18),
952            "void19" => Ok(PrimitiveType::Void19),
953            "void20" => Ok(PrimitiveType::Void20),
954            "void21" => Ok(PrimitiveType::Void21),
955            "void22" => Ok(PrimitiveType::Void22),
956            "void23" => Ok(PrimitiveType::Void23),
957            "void24" => Ok(PrimitiveType::Void24),
958            "void25" => Ok(PrimitiveType::Void25),
959            "void26" => Ok(PrimitiveType::Void26),
960            "void27" => Ok(PrimitiveType::Void27),
961            "void28" => Ok(PrimitiveType::Void28),
962            "void29" => Ok(PrimitiveType::Void29),
963            "void30" => Ok(PrimitiveType::Void30),
964            "void31" => Ok(PrimitiveType::Void31),
965            "void32" => Ok(PrimitiveType::Void32),
966            
967            "void33" => Ok(PrimitiveType::Void33),
968            "void34" => Ok(PrimitiveType::Void34),
969            "void35" => Ok(PrimitiveType::Void35),
970            "void36" => Ok(PrimitiveType::Void36),
971            "void37" => Ok(PrimitiveType::Void37),
972            "void38" => Ok(PrimitiveType::Void38),
973            "void39" => Ok(PrimitiveType::Void39),
974            "void40" => Ok(PrimitiveType::Void40),
975            "void41" => Ok(PrimitiveType::Void41),
976            "void42" => Ok(PrimitiveType::Void42),
977            "void43" => Ok(PrimitiveType::Void43),
978            "void44" => Ok(PrimitiveType::Void44),
979            "void45" => Ok(PrimitiveType::Void45),
980            "void46" => Ok(PrimitiveType::Void46),
981            "void47" => Ok(PrimitiveType::Void47),
982            "void48" => Ok(PrimitiveType::Void48),
983            "void49" => Ok(PrimitiveType::Void49),
984            "void50" => Ok(PrimitiveType::Void50),
985            "void51" => Ok(PrimitiveType::Void51),
986            "void52" => Ok(PrimitiveType::Void52),
987            "void53" => Ok(PrimitiveType::Void53),
988            "void54" => Ok(PrimitiveType::Void54),
989            "void55" => Ok(PrimitiveType::Void55),
990            "void56" => Ok(PrimitiveType::Void56),
991            "void57" => Ok(PrimitiveType::Void57),
992            "void58" => Ok(PrimitiveType::Void58),
993            "void59" => Ok(PrimitiveType::Void59),
994            "void60" => Ok(PrimitiveType::Void60),
995            "void61" => Ok(PrimitiveType::Void61),
996            "void62" => Ok(PrimitiveType::Void62),
997            "void63" => Ok(PrimitiveType::Void63),
998            "void64" => Ok(PrimitiveType::Void64),
999            
1000            "float16" => Ok(PrimitiveType::Float16),
1001            "float32" => Ok(PrimitiveType::Float32),
1002            "float64" => Ok(PrimitiveType::Float64),
1003            _ => Err(ParsePrimitiveTypeError::NotPrimitiveType(String::from(s))),
1004        }
1005    }
1006}
1007
1008impl PrimitiveType {
1009    pub fn is_void(&self) -> bool {
1010        match *self {
1011            PrimitiveType::Void1 => true,
1012            PrimitiveType::Void2 => true,
1013            PrimitiveType::Void3 => true,
1014            PrimitiveType::Void4 => true,
1015            PrimitiveType::Void5 => true,
1016            PrimitiveType::Void6 => true,
1017            PrimitiveType::Void7 => true,
1018            PrimitiveType::Void8 => true,
1019            PrimitiveType::Void9 => true,
1020            PrimitiveType::Void10 => true,
1021            PrimitiveType::Void11 => true,
1022            PrimitiveType::Void12 => true,
1023            PrimitiveType::Void13 => true,
1024            PrimitiveType::Void14 => true,
1025            PrimitiveType::Void15 => true,
1026            PrimitiveType::Void16 => true,
1027            PrimitiveType::Void17 => true,
1028            PrimitiveType::Void18 => true,
1029            PrimitiveType::Void19 => true,
1030            PrimitiveType::Void20 => true,
1031            PrimitiveType::Void21 => true,
1032            PrimitiveType::Void22 => true,
1033            PrimitiveType::Void23 => true,
1034            PrimitiveType::Void24 => true,
1035            PrimitiveType::Void25 => true,
1036            PrimitiveType::Void26 => true,
1037            PrimitiveType::Void27 => true,
1038            PrimitiveType::Void28 => true,
1039            PrimitiveType::Void29 => true,
1040            PrimitiveType::Void30 => true,
1041            PrimitiveType::Void31 => true,
1042            PrimitiveType::Void32 => true,
1043            PrimitiveType::Void33 => true,
1044            PrimitiveType::Void34 => true,
1045            PrimitiveType::Void35 => true,
1046            PrimitiveType::Void36 => true,
1047            PrimitiveType::Void37 => true,
1048            PrimitiveType::Void38 => true,
1049            PrimitiveType::Void39 => true,
1050            PrimitiveType::Void40 => true,
1051            PrimitiveType::Void41 => true,
1052            PrimitiveType::Void42 => true,
1053            PrimitiveType::Void43 => true,
1054            PrimitiveType::Void44 => true,
1055            PrimitiveType::Void45 => true,
1056            PrimitiveType::Void46 => true,
1057            PrimitiveType::Void47 => true,
1058            PrimitiveType::Void48 => true,
1059            PrimitiveType::Void49 => true,
1060            PrimitiveType::Void50 => true,
1061            PrimitiveType::Void51 => true,
1062            PrimitiveType::Void52 => true,
1063            PrimitiveType::Void53 => true,
1064            PrimitiveType::Void54 => true,
1065            PrimitiveType::Void55 => true,
1066            PrimitiveType::Void56 => true,
1067            PrimitiveType::Void57 => true,
1068            PrimitiveType::Void58 => true,
1069            PrimitiveType::Void59 => true,
1070            PrimitiveType::Void60 => true,
1071            PrimitiveType::Void61 => true,
1072            PrimitiveType::Void62 => true,
1073            PrimitiveType::Void63 => true,
1074            PrimitiveType::Void64 => true,
1075            _ => false,
1076        }
1077    }
1078}
1079
1080
1081#[cfg(test)]
1082mod tests {
1083    use super::*;
1084    
1085    #[test]
1086    fn read_node_status() {
1087        let dsdl = DSDL::read("tests/dsdl/uavcan/protocol/341.NodeStatus.uavcan").unwrap();
1088        
1089        assert_eq!(dsdl.files.get(&String::from("NodeStatus")).unwrap(),
1090                   &File {
1091                       name: FileName {
1092                           id: Some(String::from("341")),
1093                           namespace: String::from(""),
1094                           name: String::from("NodeStatus"),
1095                           version: None,
1096                       },
1097                       definition: TypeDefinition::Message(MessageDefinition(vec!(
1098                           Line::Comment(Comment(String::new())),
1099                           Line::Comment(Comment(String::from(" Abstract node status information."))),
1100                           Line::Comment(Comment(String::new())),
1101                           Line::Comment(Comment(String::from(" Any UAVCAN node is required to publish this message periodically."))),
1102                           Line::Comment(Comment(String::new())),
1103                           Line::Empty,
1104                           Line::Comment(Comment(String::from(""))),
1105                           Line::Comment(Comment(String::from(" Publication period may vary within these limits."))),
1106                           Line::Comment(Comment(String::from(" It is NOT recommended to change it at run time."))),
1107                           Line::Comment(Comment(String::new())),
1108                           Line::Definition(AttributeDefinition::Const(ConstDefinition { cast_mode: None, field_type: Ty::Primitive(PrimitiveType::Uint16), name: Ident(String::from("MAX_BROADCASTING_PERIOD_MS")), constant: Const::Dec(String::from("1000")) }), None),
1109                           Line::Definition(AttributeDefinition::Const(ConstDefinition { cast_mode: None, field_type: Ty::Primitive(PrimitiveType::Uint16), name: Ident(String::from("MIN_BROADCASTING_PERIOD_MS")), constant: Const::Dec(String::from("2")) }), None),
1110                           Line::Empty,
1111                           Line::Comment(Comment(String::new())),
1112                           Line::Comment(Comment(String::from(" If a node fails to publish this message in this amount of time, it should be considered offline."))),
1113                           Line::Comment(Comment(String::new())),
1114                           Line::Definition(AttributeDefinition::Const(ConstDefinition { cast_mode: None, field_type: Ty::Primitive(PrimitiveType::Uint16), name: Ident(String::from("OFFLINE_TIMEOUT_MS")), constant: Const::Dec(String::from("3000")) }), None),
1115                           Line::Empty,
1116                           Line::Comment(Comment(String::new())),
1117                           Line::Comment(Comment(String::from(" Uptime counter should never overflow."))),
1118                           Line::Comment(Comment(String::from(" Other nodes may detect that a remote node has restarted when this value goes backwards."))),
1119                           Line::Comment(Comment(String::new())),
1120                           Line::Definition(AttributeDefinition::Field(FieldDefinition { cast_mode: None, field_type: Ty::Primitive(PrimitiveType::Uint32), array: ArrayInfo::Single, name: Some(Ident(String::from("uptime_sec"))) }), None),
1121                           Line::Empty,
1122                           Line::Comment(Comment(String::new())),
1123                           Line::Comment(Comment(String::from(" Abstract node health."))),
1124                           Line::Comment(Comment(String::from(""))),
1125                           Line::Definition(AttributeDefinition::Const(ConstDefinition { cast_mode: None, field_type: Ty::Primitive(PrimitiveType::Uint2), name: Ident(String::from("HEALTH_OK")), constant: Const::Dec(String::from("0")) }), Some(Comment(String::from(" The node is functioning properly.")))),
1126                           Line::Definition(AttributeDefinition::Const(ConstDefinition { cast_mode: None, field_type: Ty::Primitive(PrimitiveType::Uint2), name: Ident(String::from("HEALTH_WARNING")), constant: Const::Dec(String::from("1")) }), Some(Comment(String::from(" A critical parameter went out of range or the node encountered a minor failure.")))),
1127                           Line::Definition(AttributeDefinition::Const(ConstDefinition { cast_mode: None, field_type: Ty::Primitive(PrimitiveType::Uint2), name: Ident(String::from("HEALTH_ERROR")), constant: Const::Dec(String::from("2")) }), Some(Comment(String::from(" The node encountered a major failure.")))),
1128                           Line::Definition(AttributeDefinition::Const(ConstDefinition { cast_mode: None, field_type: Ty::Primitive(PrimitiveType::Uint2), name: Ident(String::from("HEALTH_CRITICAL")), constant: Const::Dec(String::from("3")) }), Some(Comment(String::from(" The node suffered a fatal malfunction.")))),
1129                           Line::Definition(AttributeDefinition::Field(FieldDefinition { cast_mode: None, field_type: Ty::Primitive(PrimitiveType::Uint2), array: ArrayInfo::Single, name: Some(Ident(String::from("health"))) }), None),
1130                           Line::Empty,
1131                           Line::Comment(Comment(String::from(""))),
1132                           Line::Comment(Comment(String::from(" Current mode."))),
1133                           Line::Comment(Comment(String::new())),
1134                           Line::Comment(Comment(String::from(" Mode OFFLINE can be actually reported by the node to explicitly inform other network"))),
1135                           Line::Comment(Comment(String::from(" participants that the sending node is about to shutdown. In this case other nodes will not"))),
1136                           Line::Comment(Comment(String::from(" have to wait OFFLINE_TIMEOUT_MS before they detect that the node is no longer available."))),
1137                           Line::Comment(Comment(String::new())),
1138                           Line::Comment(Comment(String::from(" Reserved values can be used in future revisions of the specification."))),
1139                           Line::Comment(Comment(String::new())),
1140                           Line::Definition(AttributeDefinition::Const(ConstDefinition { cast_mode: None, field_type: Ty::Primitive(PrimitiveType::Uint3), name: Ident(String::from("MODE_OPERATIONAL")), constant: Const::Dec(String::from("0")) }), Some(Comment(String::from(" Normal operating mode.")))),
1141                           Line::Definition(AttributeDefinition::Const(ConstDefinition { cast_mode: None, field_type: Ty::Primitive(PrimitiveType::Uint3), name: Ident(String::from("MODE_INITIALIZATION")), constant: Const::Dec(String::from("1")) }), Some(Comment(String::from(" Initialization is in progress; this mode is entered immediately after startup.")))),
1142                           Line::Definition(AttributeDefinition::Const(ConstDefinition { cast_mode: None, field_type: Ty::Primitive(PrimitiveType::Uint3), name: Ident(String::from("MODE_MAINTENANCE")), constant: Const::Dec(String::from("2")) }), Some(Comment(String::from(" E.g. calibration, the bootloader is running, etc.")))),
1143                           Line::Definition(AttributeDefinition::Const(ConstDefinition { cast_mode: None, field_type: Ty::Primitive(PrimitiveType::Uint3), name: Ident(String::from("MODE_SOFTWARE_UPDATE")), constant: Const::Dec(String::from("3")) }), Some(Comment(String::from(" New software/firmware is being loaded.")))),
1144                           Line::Definition(AttributeDefinition::Const(ConstDefinition { cast_mode: None, field_type: Ty::Primitive(PrimitiveType::Uint3), name: Ident(String::from("MODE_OFFLINE")), constant: Const::Dec(String::from("7")) }), Some(Comment(String::from(" The node is no longer available.")))),
1145                           Line::Definition(AttributeDefinition::Field(FieldDefinition { cast_mode: None, field_type: Ty::Primitive(PrimitiveType::Uint3), array: ArrayInfo::Single, name: Some(Ident(String::from("mode"))) }), None),
1146                           Line::Empty,
1147                           Line::Comment(Comment(String::new())),
1148                           Line::Comment(Comment(String::from(" Not used currently, keep zero when publishing, ignore when receiving."))),
1149                           Line::Comment(Comment(String::new())),
1150                           Line::Definition(AttributeDefinition::Field(FieldDefinition { cast_mode: None, field_type: Ty::Primitive(PrimitiveType::Uint3), array: ArrayInfo::Single, name: Some(Ident(String::from("sub_mode"))) }), None),
1151                           Line::Empty,
1152                           Line::Comment(Comment(String::new())),
1153                           Line::Comment(Comment(String::from(" Optional, vendor-specific node status code, e.g. a fault code or a status bitmask."))),
1154                           Line::Comment(Comment(String::new())),
1155                           Line::Definition(AttributeDefinition::Field(FieldDefinition { cast_mode: None, field_type: Ty::Primitive(PrimitiveType::Uint16), array: ArrayInfo::Single, name: Some(Ident(String::from("vendor_specific_status_code"))) }), None),
1156                       ))),}
1157        );        
1158    }
1159}
1160