1use std::collections::HashMap;
2use std::process::{abort};
3use askama::Template;
4use logos::{Lexer, Logos, Span};
5use regex::Regex;
6use stringcase::Caser;
7
8
9fn integer_bit_size(bit_size: &u8) -> u8 {
12 match bit_size {
13 0..=8 => 8,
14 9..=16 => 16,
15 17..=32 => 32,
16 _ => 64
17 }
18}
19#[derive(Debug, Clone )]
21#[allow(unused)]
22pub struct AttributeEx {
23 base: Attribute,
24 rust_type_str: String,
25 base_type_str: String,
27 is_py_wrapped: bool, is_msg: bool, is_enum: bool, is_oo: bool, add_val: bool,
28}
29#[derive(Debug, Clone )]
30pub struct MessageR {
31 pub name: String,
32 pub comment: Option<String>,
34 pub parent: Option<String>,
35 pub attributes: Vec<AttributeEx>,
36}
37#[derive(Debug, Clone )]
38pub struct OneOfInfoR {
39 name: String,
40 dyn_bits: u8,
41 attributes: Vec<AttributeEx>,
42}
43fn to_rust_attribute(attribute: &Attribute, msg_names: &Vec<String>) -> AttributeEx {
44 let (rtype, base_type, is_py_wrapped, is_msg, is_enum, is_oo, add_val) = {
45 let mut is_py_wrapped = false;
46 let mut is_enum = false;
47 let mut is_msg = false;
48 let mut is_oo = false;
49 let mut add_val = false;
50
51 let (rtype, base_type) = match &attribute.specific_details {
52 AttributeDetails::AttributeSimple(a) => {
53 match a {
54 SimpleType::NoTypeSetYet => {
55 println!("Unexpected unspecified attribute type");
56 abort()
57 },
58 SimpleType::Bool => { ("bool".to_string(), "bool".to_string()) }
59 SimpleType::UIntFixed(b) => {
60 add_val = true;
61 let base = format!("u{}", integer_bit_size(&b));
62 (format!("VarWithGivenBitSize<{}, {}>", base.clone(), b), base) }
63 SimpleType::IntFixed(b) => {
64 add_val = true;
65 let base = format!("{}", integer_bit_size(&b));
66 (format!("VarWithGivenBitSize<{}, {}>", base.clone(), b), base) }
67 SimpleType::UIntDyn(b) => {
68 add_val = true;
69 let base = format!("u{}", integer_bit_size(&b.0));
70 (format!("DynInteger<{}, {}>", base.clone(), b.1), base) }
71 SimpleType::IntDyn(b) => {
72 add_val = true;
73 let base = format!("i{}", integer_bit_size(&b.0));
74 (format!("DynInteger<{}, {}>", base.clone(), b.1), base) }
75 SimpleType::Float => {
76 add_val = true;
77 let base = "f32".to_string();
78 (base.clone(), base)
79 }
80 SimpleType::Double => {
81 let base = "f64".to_string();
82 (base.clone(), base) }
83 SimpleType::FixedPrecision(fpp) => {
84 add_val = true;
85 (format!("FixPrecisionMinMax<{}, {}, {}>", fpp.bits, fpp.min_val, fpp.max_val), "f64".to_string())
86 }
87 SimpleType::Binary(b) => {
88 add_val = true;
89 (format!("Binary<{}>", b), "Vec<u8>".to_string()) }
90 }
91 }
92 AttributeDetails::AttributeEnumOrMsg(em) => {
93 is_py_wrapped = true;
94 is_msg = msg_names.contains(&em);
95 is_enum = !is_msg.clone();
96 (em.clone(), em.clone()) }
97 AttributeDetails::AttributeOneOf(ooi) => {
98 is_py_wrapped=true; is_oo = true;
99 (ooi.name.clone(), ooi.name.clone()) }
100 };
101 (rtype, base_type, is_py_wrapped, is_msg, is_enum, is_oo, add_val)
102 };
103 AttributeEx{base: attribute.clone(), rust_type_str: rtype, base_type_str: base_type,
104 is_py_wrapped, is_msg, is_enum, is_oo, add_val }
105}
106
107pub fn to_rust_messages(msgs: &Vec<Message>) -> Vec<MessageR> {
108 let msgs_names: Vec<_> = msgs.iter().map(|m| {m.name.clone()}).collect();
109
110 msgs.iter().map(|msg| {
111 let attrs_rust: Vec<_> = msg.attributes.iter().map(|attribute| {
112 to_rust_attribute(attribute, &msgs_names) }).collect();
113 MessageR{name: msg.name.clone(), comment: msg.comment.clone(), parent: msg.parent.clone(),
114 attributes: attrs_rust}
115 }).collect()
116}
117pub fn to_rust_oneofs(oos: &Vec<OneOfInfo>, msgs: &Vec<Message>) -> HashMap<String, OneOfInfoR> {
118 let msgs_names: Vec<_> = msgs.iter().map(|m| {m.name.clone()}).collect();
119
120 oos.iter().map(|oo| {
121 let attrs_rust: Vec<_> = oo.attributes.iter().map(|attribute| {
122 to_rust_attribute(attribute, &msgs_names) }).collect();
123 (oo.name.clone(), OneOfInfoR{name: oo.name.clone(), dyn_bits: oo.dyn_bits, attributes: attrs_rust})
124 }).collect()
125}
126
127#[derive(Clone, Debug)]
128pub struct JinjaData {
129 pub enums: Vec<Enum>,
130 pub msgs: Vec<MessageR>,
131 pub oos: HashMap<String, OneOfInfoR>,
132}
133
134#[derive(Template, Clone, Debug)]
135#[template(path = "data_objects.rs.jinja")]
136pub struct RustDataObjects {
137 pub d: JinjaData
138}
139#[derive(Template, Clone, Debug)]
140#[template(path = "pyclasses.py.rs.jinja")]
141pub struct RustPyDataObjects {
142 pub d: JinjaData
143}
144#[derive(Template, Clone, Debug)]
145#[template(path = "pylib.py.rs.jinja")]
146pub struct RustPyLib {
147 pub d: JinjaData,
148 pub lib_name: String
149}
150#[derive(Template, Clone, Debug)]
151#[template(path = "py_type_hints.pyi.jinja")]
152pub struct PyTypeHints {
153 pub d: JinjaData
154}
155
156
157mod filters {
158 #[allow(dead_code)]
159 pub fn snake_case<T: std::fmt::Display>(s: T) -> ::askama::Result<String> {
160 Ok(stringcase::snake_case(s.to_string().as_str()))
161 }
162 #[allow(dead_code)]
163 pub fn camel_case<T: std::fmt::Display>(s: T) -> ::askama::Result<String> {
164 Ok(stringcase::camel_case(s.to_string().as_str()))
165 }
166 #[allow(dead_code)]
167 pub fn pascal_case<T: std::fmt::Display>(s: T) -> ::askama::Result<String> {
168 Ok(stringcase::pascal_case(s.to_string().as_str()))
169 }
170 #[allow(dead_code)]
171 pub fn to_py_type<T: std::fmt::Display>(s: T) -> ::askama::Result<String> {
172 if ["u8", "u16", "u32", "u64", "i8", "i16", "i32", "i64"].contains(&s.to_string().as_str()) {
173 Ok("int".to_string()) }
174 else if ["f32", "f64"].contains(&s.to_string().as_str()) {
175 Ok("float".to_string())
176 }
177 else { Ok(s.to_string()) }
178 }
179}
180
181type Error = (String, Span);
183
184type Result<T> = std::result::Result<T, Error>;
185
186#[derive(Debug, Clone)]
187pub enum DynOrFixedType {
188 Dyn(u8),
189 Fixed(u8)
190}
191#[derive(Debug, PartialEq, Eq, Clone, Copy)]
192pub struct FixedPrecisionProperties {
193 bits: u8, min_val: i64, max_val: i64
194}
195#[derive(Debug, PartialEq, Eq, Clone, Copy)]
196pub enum SimpleType {
197 NoTypeSetYet,
198 Bool,
199 UIntFixed(u8), IntFixed(u8),
200 UIntDyn((u8,u8)), IntDyn((u8,u8)),
201 Float, Double,
202 FixedPrecision(FixedPrecisionProperties),
203 Binary(u8)
204}
205#[derive(Debug, Clone )]
237pub struct OneOfInfo {
238 name: String,
239 dyn_bits: u8,
240 attributes: Vec<Attribute>,
241}
242#[derive(Debug, Clone )]
243pub enum AttributeDetails {
244 AttributeSimple(SimpleType),
245 AttributeEnumOrMsg(String),
246 AttributeOneOf(OneOfInfo),
247}
248#[derive(Debug, Clone )]
249pub struct Attribute {
250 name: String,
251 comment: Option<String>,
252 is_repeated_and_size: Option<DynOrFixedType>,
253 is_optional: bool,
254 specific_details: AttributeDetails
255}
256#[derive(Debug, Clone)]
262pub struct Message {
263 pub name: String,
264 pub comment: Option<String>,
266 pub parent: Option<String>,
267 pub attributes: Vec<Attribute>,
268}
269
270#[derive(Debug, Clone)]
272pub struct Enum {
273 pub name: String,
274 pub comment: Option<String>,
276 pub bit_size: u8,
277 pub values: Vec<String>,
278}
279
280pub fn get_suffix_number(lex: &mut Lexer<Token>) -> Option<u8> {
281 let slice = lex.slice();
282 let re = Regex::new(r".*_d?([0-9]+)$").unwrap();
283 let num_str = re.captures(slice)?.get(1)?;
284 num_str.as_str().parse().ok()
285}
286pub fn get_d_suffix_numbers(lex: &mut Lexer<Token>) -> Option<(u8,u8)> {
287 let slice = lex.slice();
288 let re = Regex::new(r".*_([0-9]+)d([0-9]+)$").unwrap();
289 let first_num_str = re.captures(slice)?.get(1)?.as_str().parse().ok()?;
290 let second_num_str = re.captures(slice)?.get(2)?.as_str().parse().ok()?;
291 Some((first_num_str, second_num_str))
292}
293pub fn get_fp_properties_number(lex: &mut Lexer<Token>) -> Option<FixedPrecisionProperties> {
294 let slice = lex.slice();
295 let re = Regex::new(r".?fp_([0-9]+)\[ *(-?[0-9]+) *, *(-?[0-9]+) *]").unwrap();
296 let bits = re.captures(slice)?.get(1)?.as_str().parse::<u8>().ok()?;
297 let min_val = re.captures(slice)?.get(2)?.as_str().parse::<i64>().ok()?;
298 let max_val = re.captures(slice)?.get(3)?.as_str().parse::<i64>().ok()?;
299 Some(FixedPrecisionProperties {bits, min_val, max_val})
300}
301pub fn get_enum_bit_size(lex: &mut Lexer<Token>) -> Option<u8> {
314 let slice = lex.slice();
315 let re = Regex::new(r"\( *([0-9]+) *\)").unwrap();
316 let bits = re.captures(slice)?.get(1)?.as_str().parse::<u8>().ok()?;
317 Some(bits)
318}
319pub fn get_version(lex: &mut Lexer<Token>) -> Option<u16> {
320 let slice = lex.slice();
321 let re = Regex::new(r"\[.* +(v[0-9]+) *]").unwrap();
322 let ver_str = re.captures(slice)?.get(1)?.as_str();
323 Some(ver_str.parse::<u16>().ok()?)
324}
325
326#[derive(Debug, Logos)]
327#[logos(skip r"[ \t\r\n\f]+")]
328#[logos(extras = u16)]
329#[allow(dead_code)]
330pub enum Token{
331 #[regex(r"//[^\n]*\n?", priority=40)] Comment,
332 #[regex(r"//\|[^\n]*\n?", |lex| lex.slice()[3..].to_owned(), priority=41)] SpecificComment(String),
333 #[token("msg", priority=20)] Msg,
334 #[token("enum", priority=20)] Enum,
335 #[token("oneof", priority=20)] OneOf,
336 #[token("{")] CBraceOpen,
337 #[token("}")] CBraceClose,
338 #[token("(")] BraceOpen,
339 #[token(")")] BraceClose,
340 #[token(":")] Colon,
341 #[token(";")] SemiColon,
342 #[token(",")] Comma,
343 #[regex(r"\[ *base +use +starting +with +v[0-9]+ *\]", get_version, priority=35)] MsgBaseInfoToken(u16),
346 #[regex(r"\[ *version +v[0-9]+ *\]", get_version, priority=35)] MsgVersionToken(u16),
347 #[regex("[0-9]+", |lex| lex.slice().parse::<isize>().unwrap(), priority=1)] IntegerVal(isize),
349 #[regex(r"-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?",
350 |lex| lex.slice().parse::<f64>().unwrap(), priority=2)] Number(f64),
351 #[token("bool", priority=30)] Bool,
352 #[regex(r"uint_[0-9]+", get_suffix_number, priority=30)] UIntFixed(u8),
353 #[regex(r"int_[0-9]+", get_suffix_number, priority=30)] IntFixed(u8),
354 #[regex(r"uint_[0-9]+d[0-9]+", get_d_suffix_numbers, priority=31)] UIntDyn((u8,u8)),
355 #[regex(r"int_[0-9]+d[0-9]+", get_d_suffix_numbers, priority=31)] IntDyn((u8,u8)),
356 #[token("float", priority=30)] Float,
357 #[token("double", priority=30)] Double,
358 #[regex(r"fp_[0-9]+\[ *-?[0-9]+ *, *-?[0-9]+ *]", get_fp_properties_number, priority=30)] FixedPoint(FixedPrecisionProperties),
359 #[regex(r"ufp_[0-9]+\[ *-?[0-9]+ *, *-?[0-9]+ *]", get_fp_properties_number, priority=30)] UFixedPoint(FixedPrecisionProperties),
360 #[token("binary_d[0-9]+", get_suffix_number, priority=30)] Binary(u8),
362 #[regex(r"repeated_dyn_[0-9]+", get_suffix_number, priority=30)] RepeatedDyn(u8),
363 #[regex(r"repeated_fixed_[0-9]+", get_suffix_number, priority=30)] RepeatedFixed(u8),
364 #[token("optional", priority=30)] Optional,
365 #[regex(r"[A-Za-z][A-Za-z0-9_-]+", |lex| lex.slice().to_owned(), priority=11)] StringVal(String),
366 #[token("false", |_| false, priority=20)]
367 #[token("true", |_| true, priority=20)]
368 BoolVal(bool),
369 #[regex(r"\( *([0-9]+) *\)", get_enum_bit_size, priority=40)] EnumDynSize(u8),
370}
371
372#[derive(Debug, Clone)]
373pub enum Value {
374 Message(Message),
376 Enum(Enum)
378}
379
380macro_rules! parse_one_token {
381 ($token_enum: path, $lexer: expr, $error_msg_or_empty: expr) => {
382 loop {
383 let rv = $lexer.next();
384 if let Some(token) = rv {
385 match token {
386 Ok($token_enum) => {
387 break Ok(Ok(()));
388 },
389 Ok(Token::Comment) => (),
390 _ => {
391 if let Some(err_str) = $error_msg_or_empty {
392 break Err((format!("{err_str}\nToken: {token:?}").to_owned(), $lexer.span()));
393 }
394 else {
395 break Ok(Err($lexer.span()));
396 }
397 }
398 }
399 }
400 else {
401 break Err((format!("Unexpected end or text {rv:?}").to_owned(), $lexer.span()));
402 }
403 }
404 }
405}
406macro_rules! parse_one_token_with_arg {
407 ($token_enum: path, $lexer: expr, $error_msg_or_empty: expr) => {
408 loop {
409 let rv = $lexer.next();
410 if let Some(token) = rv {
411 match token {
412 Ok($token_enum(s)) => {
413 break Ok(Ok(s));
414 },
415 Ok(Token::Comment) => (),
416 _ => {
417 if let Some(err_str) = $error_msg_or_empty {
418 break Err((format!("{}\nFound token: {:?}.",
419 err_str, token).to_owned(), $lexer.span()));
420 }
421 else {
422 break Ok(Err($lexer.span()));
423 }
424 }
425 }
426 }
427 else {
428 break Err((format!("Unexpected end or text {rv:?}").to_owned(), $lexer.span()));
429 }
430 }
431 }
432}
433
434
435pub fn parse_root(lexer: &mut Lexer<'_, Token>) -> Result<Vec<Value>> {
436 let mut list: Vec<Value> = Vec::new();
437 let mut specific_comment: Option<String> = None;
438 loop {
439 if let Some(token) = lexer.next() {
440 let rv = match token {
441 Ok(Token::Msg) => Some(parse_msg(lexer, specific_comment.clone())),
442 Ok(Token::Enum) => Some(parse_enum(lexer, specific_comment.clone())),
443 Ok(Token::Comment) => None,
444 Ok(Token::SpecificComment(s)) => {
445 specific_comment = Some(s); None },
446 _ => Some(Err((format!("Unexpected token {:?}", token).to_owned(), lexer.span()))),
447 };
448 match rv {
449 None => (),
450 Some(Ok(value)) => { list.push(value); specific_comment = None; },
451 Some(Err(err)) => return Err(err)
452 }
453 }
454 else { break; }
455 }
456 Ok(list)
457}
458
459pub fn parse_msg(lexer: &mut Lexer<'_, Token>, comment_for_msg: Option<String>) -> Result<Value> {
460 let mut attributes = Vec::new();
461
462 let name = match parse_one_token_with_arg!(Token::StringVal, lexer, Some("Expected msg name but received:"))? {
463 Ok(s) => s,
464 Err(s) => { return Err(("Code should not be reached".into(), s)); }
465 };
466
467 let parent = {
481 let has_parent; let p;
482 if let Some(token) = lexer.next() {
483 match token {
484 Ok(Token::Colon) => has_parent = true,
485 Ok(Token::CBraceOpen) => has_parent = false,
486 _ => { return Err((format!("Unexpected text for msg '{name}'.").into(), lexer.span())) },
487 }
488 if has_parent {
489 match parse_one_token_with_arg!(Token::StringVal, lexer, Some("Expected msg name."))? {
490 Ok(s) => p = Some(s),
491 Err(s) => { return Err((format!("For msg '{name} colon found but no parent name").into(), s)); }
492 };
493 parse_one_token!(Token::CBraceOpen, lexer, Some(format!("Expected curly bracket open for msg '{name}'")))?.unwrap();
494 }
495 else {
496 p = None
497 }
498 }
499 else { return Err(("Unexpected end of file".into(), lexer.span())); }
500 p
501 };
502
503 loop {
504 if let Some(token) = lexer.next() {
505 match token {
506 Ok(Token::CBraceClose) => break,
507 Ok(Token::Comment) => (),
508 Ok(ctoken) => match parse_attribute(ctoken, lexer, name.clone(), false) {
509 Ok(a) => { attributes.push(a); },
510 Err(e) => { return Err(e); }
511 },
512 _ => { return Err((format!("Error: Unexpected text found for msg '{name}'.").into(), lexer.span())) },
513 };
514 }
515 else { return Err(("Unexpected end of file".into(), lexer.span())); }
516 }
517
518 Ok(Value::Message(Message{name, comment: comment_for_msg, parent, attributes}))
519}
520
521pub fn parse_attribute(last_token: Token, lexer: &mut Lexer<'_, Token>,
522 parent_name: String, attributes_for_oneof: bool) -> Result<Attribute> {
523 let mut is_optional = false;
524 let mut is_repeated_and_size: Option<DynOrFixedType> = None;
525 let mut attr_type = SimpleType::NoTypeSetYet;
526 let mut ctoken = last_token;
527 let mut enum_or_msg_str = None;
528 let mut oneof_infos = None;
529 let lexer_span_start = lexer.span();
530 let mut specific_comment: Option<String> = None;
531
532 loop {
533 match ctoken {
534 Token::SpecificComment(s) => {
535 specific_comment = Some(s); () },
536 Token::Optional if is_repeated_and_size.is_some() =>
537 return Err(("Error: Optional and repeated not allowed together".to_owned(), lexer.span())),
538 Token::RepeatedFixed(_) | Token::RepeatedDyn(_) if is_optional =>
539 return Err(("Error: Optional and repeated are not allowed together".to_owned(), lexer.span())),
540
541 Token::Optional | Token::RepeatedDyn(_) | Token::RepeatedFixed(_) if attributes_for_oneof =>
542 return Err(("Error: Optional and repeated are not allowed in oneof".to_owned(), lexer.span())),
543
544 Token::Optional => is_optional = true,
545 Token::RepeatedDyn(b) => is_repeated_and_size = Some(DynOrFixedType::Dyn(b)),
546 Token::RepeatedFixed(b) => is_repeated_and_size = Some(DynOrFixedType::Fixed(b)),
547
548 Token::Bool => { attr_type = SimpleType::Bool; break; },
549 Token::UIntFixed(s) => { attr_type = SimpleType::UIntFixed(s); break; },
550 Token::UIntDyn((m,s)) => { attr_type = SimpleType::UIntDyn((m, s)); break; },
551 Token::IntFixed(s) => { attr_type = SimpleType::IntFixed(s); break; },
552 Token::IntDyn((m,s)) => { attr_type = SimpleType::IntDyn((m,s)); break; },
553 Token::Float => { attr_type = SimpleType::Float; break; },
555 Token::Double => { attr_type = SimpleType::Double; break; },
556 Token::FixedPoint(s) => { attr_type = SimpleType::FixedPrecision(s); break; },
557 Token::Binary(b) => { attr_type = SimpleType::Binary(b); break; },
558 Token::StringVal(s) => { enum_or_msg_str = Some(s); break; }
559 Token::OneOf => {
560 oneof_infos = match parse_oneof(lexer, parent_name.clone(), specific_comment.clone(),
561 is_repeated_and_size.clone(), is_optional.clone()) {
562 Ok(oo) => Some(oo),
563 Err(s) => { return Err(s); }
564 };
565 break;
566 }
567 _ => { return Err((format!("Error: Expected attribute type or modifier (got {ctoken:?}) when parsing msg or oneof '{parent_name}'")
568 .to_owned(), lexer.span())); }
569 }
570 if let Some(token) = lexer.next() {
571 match token {
572 Ok(t) => ctoken = t,
573 Err(_) => { return Err((format!("Error: Unexpected text found for msg '{parent_name}'.").to_owned(), lexer.span())); }
574 }
575 } else {
576 return Err(("Unexpected end of file".to_string(), lexer.span()));
577 }
578 }
579
580 let mut name= "".to_owned();
581 if oneof_infos.is_none() {
582 name = parse_one_token_with_arg!(
583 Token::StringVal, lexer, Some(format!("Error: Expected attribute name for msg '{parent_name}' (type: {attr_type:?}/{enum_or_msg_str:?})")))?.unwrap();
584
585 parse_one_token!(Token::SemiColon, lexer, Some(format!(
586 "Error: Expected semicolon to end line of attribute '{name}' of msg or oneof '{parent_name}'")))?.unwrap();
587 }
588 let num_of_set_types_or_opts = vec![(attr_type != SimpleType::NoTypeSetYet), enum_or_msg_str.is_some(), oneof_infos.is_some()]
589 .iter().map(|&x| if x { 1_u8 } else { 0_u8 }).sum::<u8>();
590 if num_of_set_types_or_opts > 1 {
591 let mut span = lexer_span_start.clone();
592 span.end = lexer.span().end;
593 return Err(("Error: Attribute contains inconsistent optional, simple types and messages or Enums".to_string(), span));
594 }
595
596 if let Some(oo) = oneof_infos {
597 Ok(oo)
598 }
599 else if let Some(t) = enum_or_msg_str {
600 Ok(Attribute{name, comment: specific_comment, is_repeated_and_size, is_optional,
601 specific_details: AttributeDetails::AttributeEnumOrMsg(t)})
602 }
603 else {
604 Ok(Attribute{name, comment: specific_comment, is_repeated_and_size, is_optional,
605 specific_details: AttributeDetails::AttributeSimple(attr_type)})
606 }
607}
608
609pub fn parse_oneof(lexer: &mut Lexer<'_, Token>, parent_name: String, comment: Option<String>,
610 is_repeated_and_size: Option<DynOrFixedType>, is_optional: bool) -> Result<Attribute> {
611 let oo_name = parse_one_token_with_arg!(
612 Token::StringVal, lexer, Some(format!("Error: Expected name for oneof in parent '{parent_name}'")))?.unwrap();
613
614 let bit_size = match parse_one_token_with_arg!(Token::EnumDynSize, lexer, Some("Expected oneof properties for dyn size, e.g. (4)."))? {
615 Ok(s) => s, Err(s) => { return Err(("Code should not be reached".into(), s)); }
616 };
617
618 parse_one_token!(Token::CBraceOpen, lexer, Some("Error: Expected open curly bracket to enclose oneof elements"))?.unwrap();
619
620 let mut oo_attribs = Vec::new();
621 loop {
622 if let Some(token) = lexer.next() {
623 match token {
624 Ok(Token::CBraceClose) => break,
625 Ok(last_token) => {
626 match parse_attribute(last_token, lexer, oo_name.clone(), true) {
627 Ok(o) => oo_attribs.push(o),
628 Err(s) => return Err(s),
629 }
630 }
631 Err(_) => { return Err((format!("Error: Unexpected text when decoding oneof ({token:?})").to_owned(), lexer.span())); },
632 }
633 }
634 }
635 Ok(Attribute{name: oo_name.clone(), comment, is_repeated_and_size, is_optional,
636 specific_details: AttributeDetails::AttributeOneOf(OneOfInfo{
637 name: format!("OO_{}_{}", parent_name.to_pascal_case(), oo_name.to_pascal_case()),
638 dyn_bits: bit_size, attributes: oo_attribs})})
639}
640
641pub fn parse_enum(lexer: &mut Lexer<'_, Token>, comment: Option<String>) -> Result<Value> {
642 let name = match parse_one_token_with_arg!(Token::StringVal, lexer, Some("Expected msg name but received."))? {
643 Ok(s) => s, Err(s) => { return Err(("Code should not be reached".into(), s)); }
644 };
645
646 let bit_size = match parse_one_token_with_arg!(Token::EnumDynSize, lexer, Some("Expected enum properties for dyn size, e.g. (4)."))? {
647 Ok(s) => s, Err(s) => { return Err(("Code should not be reached".into(), s)); }
648 };
649
650 parse_one_token!(Token::CBraceOpen, lexer, Some(format!("Expected open curly bracket for enum '{name}'")))?.unwrap();
664
665 let mut values = Vec::new();
666 loop {
667 if let Some(token) = lexer.next() {
668 match token {
669 Ok(Token::CBraceClose) => break,
670 Ok(Token::StringVal(s)) => values.push(s),
671 Ok(Token::Comma) | Ok(Token::Comment)=> (),
672 _ => { return Err((format!("Error: Unexpected text found for enum '{name}'.").into(), lexer.span())) },
673 }
674 } else { return Err(("Unexpected end of file".into(), lexer.span())); }
675 }
676
677 Ok(Value::Enum(Enum{name, comment, bit_size, values}))
678}
679
680
681#[derive(Debug, Clone)]
760pub struct BitisProcessed {
761 pub max_version_number: u16,
762 pub msgs: Vec<Message>,
763 pub enums: Vec<Enum>,
764 pub oo_enums: Vec<OneOfInfo>,
765}
766
767pub fn process_and_validate_bitis(parsed_bitis: &Vec<Value>) -> BitisProcessed {
769 let msgs: Vec<_> = parsed_bitis.iter().filter_map(|v| {
894 match v { Value::Message(msg) => Some(msg.clone()), _ => None }
895 }).collect();
896 let enums: Vec<_> = parsed_bitis.iter().filter_map(|v| {
897 match v { Value::Enum(enm) => Some(enm.clone()), _ => None }
898 }).collect();
899
900 fn get_oneofs(attrs: &Vec<Attribute>) -> Option<Vec<OneOfInfo>> {
901 let direct_oos = attrs.iter().filter_map(|attr| {
902 match &attr.specific_details {
903 AttributeDetails::AttributeOneOf(oo) => Some(vec![oo.clone()]),
904 _ => None
905 }
906 }).collect::<Vec<Vec<OneOfInfo>>>().concat();
907
908 let inner_oos = direct_oos.iter().filter_map(|doo| {
909 get_oneofs(&doo.attributes)
910 }).collect::<Vec<Vec<_>>>().concat();
911
912 let all_oos = vec![direct_oos, inner_oos].concat();
913 if all_oos.len() == 0 { None }
914 else { Some(all_oos) }
915 }
916 let oo_enums: Vec<_> = msgs.iter().filter_map(|msg| {
917 get_oneofs(&msg.attributes)
918 }).collect::<Vec<_>>().concat();
919
920 { let msg_names = msgs.iter().map(|msg| &msg.name).collect::<Vec<_>>();
924 msg_names.iter().for_each(|name| {
925 if msg_names.iter().filter(|cname| **cname == *name).count() > 1 {
927 println!("Error: Multiple instances of msg '{}' found.", name);
928 abort()
929 }
930 });
931 let enum_names = enums.iter().map(|enm| &enm.name).collect::<Vec<_>>();
932 enum_names.iter().for_each(|name| {
933 if enum_names.iter().filter(|cname| **cname == *name).count() > 1 {
934 println!("Error: Multiple instances of enum '{}' found.", name); abort()
935 }
936 });
937
938 }
941
942 BitisProcessed { max_version_number: 0, msgs, enums, oo_enums}
943}
944
945
946#[cfg(test)]
949mod bitis_semantic {
950 use rstest::rstest;
951 use super::*;
952
953 #[rstest]
954 fn msg_empty_msg() {
955 let test_empty_msg = "msg Lala { }";
956
957 let mut lexer = Token::lexer(test_empty_msg);
958 lexer.extras = 0;
959
960 let parsed_bitis = parse_root(&mut lexer);
961 if let Err(s) = parsed_bitis.clone() {
962 panic!("Error: {} ('{}' ,span: {:?})", s.0, &test_empty_msg[s.1.clone()], s.1);
963 }
964 assert_eq!(parsed_bitis.is_ok(), true);
965
966 let parsed_bitis = parsed_bitis.unwrap();
967 assert_eq!(parsed_bitis.len(), 1);
968
969 assert!(if let Value::Message(_) = parsed_bitis[0].clone() { true } else { false });
970
971 if let Value::Message(msg) = parsed_bitis[0].clone() {
972 assert_eq!(msg.name, "Lala".to_string());
973 }
974
975 let process_result = process_and_validate_bitis(&parsed_bitis);
979 println!("process_result {:?}", process_result);
980
981 assert_eq!(process_result.msgs.len(), 1);
982 assert_eq!(process_result.enums.len(), 0);
983 }
984
985 #[rstest]
986 fn msg_simple_msg() {
987 let test_empty_msg = "msg Lala { uint_7 a1; }";
988
989 let mut lexer = Token::lexer(test_empty_msg);
990 lexer.extras = 0;
991
992 let parsed_bitis = parse_root(&mut lexer);
993 if let Err(s) = parsed_bitis.clone() {
994 panic!("Error: {} ('{}' ,span: {:?})", s.0, &test_empty_msg[s.1.clone()], s.1);
995 }
996 assert_eq!(parsed_bitis.is_ok(), true);
997
998 let parsed_bitis = parsed_bitis.unwrap();
999 assert_eq!(parsed_bitis.len(), 1);
1000
1001 if let Value::Message(msg) = parsed_bitis[0].clone() {
1002 assert_eq!(msg.attributes.len(), 1);
1003 assert_eq!(msg.attributes[0].name, "a1".to_string());
1004 if let AttributeDetails::AttributeSimple(s) = msg.attributes[0].specific_details.clone() {
1005 assert_eq!(s, SimpleType::UIntFixed(7));
1006 }
1007 else { assert!(false, "Attribute type must be AttributeSimple."); }
1008 }
1009 else { assert!(false, "Value must be a message."); }
1010 }
1011
1012 #[rstest]
1013 fn msg_simple_enum() {
1014 let test_empty_msg = "enum Lala(4) { one, two }";
1015
1016 let mut lexer = Token::lexer(test_empty_msg);
1017 lexer.extras = 0;
1018
1019 let parsed_bitis = parse_root(&mut lexer);
1020 if let Err(s) = parsed_bitis.clone() {
1021 panic!("Error: {} ('{}' ,span: {:?})", s.0, &test_empty_msg[s.1.clone()], s.1);
1022 }
1023 assert_eq!(parsed_bitis.is_ok(), true);
1024
1025 let parsed_bitis = parsed_bitis.unwrap();
1026 assert_eq!(parsed_bitis.len(), 1);
1027
1028 if let Value::Enum(enm) = parsed_bitis[0].clone() {
1029 assert_eq!(enm.values.len(), 2);
1030 assert_eq!(enm.values[0], "one".to_string());
1031 assert_eq!(enm.values[1], "two".to_string());
1032 }
1033 else { assert!(false, "Value must be a message."); }
1034 }
1035
1036
1037 }
1074
1075#[cfg(test)]
1076mod bitis_generate_rust {
1077 use rstest::rstest;
1078 use super::*;
1079
1080 const HEADER: &str = "use bitis_lib::*;\n\n";
1081 const ENUMS_HEADER: &str = "// Enums\n";
1082 const OO_HEADER: &str = "// Enums for oneof\n";
1083 const MSG_HEADER: &str = "// Messages\n";
1084 const PER_ENUM_HEADER: &str = "#[derive(BiserdiEnum, Debug, Clone, PartialEq)]\n#[biserdi_enum_id_dynbits(3)]\n#[allow(nonstandard_style)]\n";
1085 const PER_OO_HEADER: &str = "#[derive(BiserdiOneOf, Debug, Clone, PartialEq)]\n#[biserdi_enum_id_dynbits(3)]\n#[allow(nonstandard_style)]\n";
1086 const PER_MSG_HEADER: &str = "#[derive(BiserdiMsg, Debug, Clone, PartialEq)]\n#[allow(nonstandard_style)]\n";
1087
1088 #[rstest]
1089 fn msg_empty_msg() {
1090 let test_empty_msg = "msg Lala { }";
1091
1092 let mut lexer = Token::lexer(test_empty_msg);
1093 lexer.extras = 0;
1094
1095 let parsed_bitis = parse_root(&mut lexer);
1096 if let Err(s) = parsed_bitis.clone() {
1097 panic!("Error: {} ('{}' ,span: {:?})", s.0, &test_empty_msg[s.1.clone()], s.1);
1098 }
1099 assert_eq!(parsed_bitis.is_ok(), true);
1100
1101 let parsed_bitis = parsed_bitis.unwrap();
1102 assert_eq!(parsed_bitis.len(), 1);
1103
1104 let processed_bitis = process_and_validate_bitis(&parsed_bitis);
1105 let rdo = RustDataObjects{ d: JinjaData{
1106 enums: processed_bitis.enums,
1107 msgs: to_rust_messages(&processed_bitis.msgs),
1108 oos: to_rust_oneofs(&processed_bitis.oo_enums, &processed_bitis.msgs) } };
1109
1110 let rendered = rdo.render().unwrap();
1111 let lala_empty = "pub struct Lala {\n}\n";
1112 assert_eq!(rendered, (HEADER.to_owned() + ENUMS_HEADER + "\n\n" + OO_HEADER + "\n\n" +
1113 MSG_HEADER + PER_MSG_HEADER +lala_empty).to_string());
1114 }
1115
1116 #[rstest]
1117 fn msg_simple_msg() {
1118 let test_empty_msg = "//| comment for Lala\nmsg Lala { uint_5 a1; repeated_fixed_4 bool bool_array; }";
1119 println!("Input code:\n{}", test_empty_msg);
1120
1121 let mut lexer = Token::lexer(test_empty_msg);
1122 lexer.extras = 0;
1123
1124 let parsed_bitis = parse_root(&mut lexer);
1125 if let Err(s) = parsed_bitis.clone() {
1126 panic!("Error: {} ('{}' ,span: {:?})", s.0, &test_empty_msg[s.1.clone()], s.1);
1127 }
1128 assert_eq!(parsed_bitis.is_ok(), true);
1129
1130 let parsed_bitis = parsed_bitis.unwrap();
1131 assert_eq!(parsed_bitis.len(), 1);
1132
1133 let processed_bitis = process_and_validate_bitis(&parsed_bitis);
1134 let rdo = RustDataObjects{ d: JinjaData{
1135 enums: processed_bitis.enums, msgs: to_rust_messages(&processed_bitis.msgs),
1136 oos: to_rust_oneofs(&processed_bitis.oo_enums, &processed_bitis.msgs) } };
1137
1138 let rendered = rdo.render().unwrap();
1139 let lala_commment = "/// comment for Lala\n";
1140 let lala_empty = "pub struct Lala {\n pub a1: VarWithGivenBitSize<u8, 5>,\n pub bool_array: FixedArray<bool,4>,\n}\n";
1141 println!("rendered:\n{}",rendered);
1142 assert_eq!(rendered, (HEADER.to_owned() + ENUMS_HEADER + "\n\n" + OO_HEADER + "\n\n" +
1143 MSG_HEADER + lala_commment + PER_MSG_HEADER +lala_empty).to_string());
1144 }
1145
1146 #[rstest]
1147 fn msg_simple_enum() {
1148 let test_enum_msg = "//| comment for Numbers\nenum Numbers(3) {\n // Comment for One\n One,\n Two,\n Three\n}";
1149 println!("Input code:\n{}", test_enum_msg);
1150
1151 let mut lexer = Token::lexer(test_enum_msg);
1152 lexer.extras = 0;
1153
1154 let parsed_bitis = parse_root(&mut lexer);
1155 if let Err(s) = parsed_bitis.clone() {
1156 panic!("Error: {} ('{}' ,span: {:?})", s.0, &test_enum_msg[s.1.clone()], s.1);
1157 }
1158 assert_eq!(parsed_bitis.is_ok(), true);
1159
1160 let parsed_bitis = parsed_bitis.unwrap();
1161 assert_eq!(parsed_bitis.len(), 1);
1162
1163 let processed_bitis = process_and_validate_bitis(&parsed_bitis);
1164 let rdo = RustDataObjects{ d: JinjaData{ enums: processed_bitis.enums,
1165 msgs: to_rust_messages(&processed_bitis.msgs),
1166 oos: to_rust_oneofs(&processed_bitis.oo_enums, &processed_bitis.msgs) } };
1167
1168 let rendered = rdo.render().unwrap();
1169 let lala_commment = "/// comment for Numbers\n";
1170 let lala_enum = "pub enum Numbers {\n One,\n Two,\n Three,\n}\n\n";
1171 println!("*rendered:\n{}",rendered);
1172 assert_eq!(rendered, (HEADER.to_owned() + ENUMS_HEADER + lala_commment + PER_ENUM_HEADER + lala_enum + OO_HEADER +
1173 "\n\n" + MSG_HEADER ).to_string());
1174 }
1175
1176 #[rstest]
1177 fn msg_simple_oneof() {
1178 let test_enum_msg = "//| comment for Oneof\nmsg TestOO {\n oneof oo_li(3) { uint_3 test1; float test2; }\n bool b1;\n}";
1179 println!("Input code:\n{}", test_enum_msg);
1180
1181 let mut lexer = Token::lexer(test_enum_msg);
1182 lexer.extras = 0;
1183
1184 let parsed_bitis = parse_root(&mut lexer);
1185 if let Err(s) = parsed_bitis.clone() {
1186 panic!("Error: {} ('{}' ,span: {:?})", s.0, &test_enum_msg[s.1.clone()], s.1);
1187 }
1188 assert_eq!(parsed_bitis.is_ok(), true);
1189
1190 let parsed_bitis = parsed_bitis.unwrap();
1191 assert_eq!(parsed_bitis.len(), 1);
1192
1193 let processed_bitis = process_and_validate_bitis(&parsed_bitis);
1194 let rdo = RustDataObjects{ d: JinjaData{ enums: processed_bitis.enums,
1195 msgs: to_rust_messages(&processed_bitis.msgs),
1196 oos: to_rust_oneofs(&processed_bitis.oo_enums, &processed_bitis.msgs) } };
1197
1198 let rendered = rdo.render().unwrap();
1199 let testoo_commment = "/// comment for Oneof\n";
1200 let testoo_enum = "pub enum OO_TestOo_OoLi {\n Test1(VarWithGivenBitSize<u8, 3>),\n Test2(f32),\n}\n\n";
1201 let testoo_msg = "pub struct TestOo {\n pub oo_li: OO_TestOo_OoLi,\n pub b1: bool,\n}\n";
1202 println!("*rendered:\n{}",rendered);
1203 assert_eq!(rendered, (HEADER.to_owned() + ENUMS_HEADER + "\n\n" + OO_HEADER + PER_OO_HEADER
1204 + testoo_enum + MSG_HEADER + testoo_commment + PER_MSG_HEADER + testoo_msg).to_string());
1205 }
1206}
1207
1208#[cfg(test)]
1209mod bitis_compile {
1210 use std::fs;
1211 use std::path::Path;
1212 use rstest::rstest;
1213 use super::*;
1214
1215 fn compile(content: &str) -> BitisProcessed {
1216 let mut lexer = Token::lexer(content);
1217 lexer.extras = 0;
1218 println!("*** content:\n{}", content);
1219 let bitis_parsed = match parse_root(&mut lexer) {
1220 Ok(v) => v,
1221 Err(e) => {
1222 let (err_str, err_span) = e.clone();
1223 let content_err = &content[err_span];
1224 println!("Error: {}\n -> Source: '{}'", err_str, content_err);
1225 abort()
1226 }
1227 };
1228 println!("** content:\n{:?}", bitis_parsed);
1229 process_and_validate_bitis(&bitis_parsed)
1230 }
1231 fn render(d: JinjaData) {
1232 let rdo = RustDataObjects{ d: d.clone() };
1233 let rendered_rust = rdo.render().unwrap();
1234 println!("*** rendered DO:\n{}", rendered_rust);
1235 fs::write(Path::new("./test_data/test_py/bitis/src/messages_test.rs"), rendered_rust).expect("Unable to write file");
1236
1237 let rdo = RustPyDataObjects{ d: d.clone() };
1238 let rendered_rust = rdo.render().unwrap();
1239 println!("*** rendered PyDO:\n{}", rendered_rust);
1240 fs::write(Path::new("./test_data/test_py/bitis/src/pyrust_test.rs"), rendered_rust).expect("Unable to write file");
1241
1242 let rdo = RustPyLib{ d: d.clone(), lib_name: "bitis_msgs".into() };
1243 let rendered_rust = rdo.render().unwrap();
1244 println!("*** rendered pyLib:\n{}", rendered_rust);
1245 fs::write(Path::new("./test_data/test_py/bitis/src/lib_test.rs"), rendered_rust).expect("Unable to write file");
1246
1247 let rdo = PyTypeHints{ d };
1248 let rendered_rust = rdo.render().unwrap();
1249 println!("*** rendered py_type_hints:\n{}", rendered_rust);
1250 fs::write(Path::new("./test_data/test_py/bitis/bitis_msgs/bitis_msgs.pyi"), rendered_rust).expect("Unable to write file");
1251 }
1252
1253 #[rstest]
1254 #[ignore]
1255 fn simple_rust_py() {
1256 let bitis_str = "msg ParamTestSimple { uint_4 param_1; bool param_2; }";
1257
1258 let bitis_processed_org = compile(bitis_str);
1259
1260 let bitis_processed = bitis_processed_org.clone();
1261 let d = JinjaData{
1262 enums: bitis_processed.enums,
1263 msgs: to_rust_messages(&bitis_processed.msgs),
1264 oos: to_rust_oneofs(&bitis_processed.oo_enums, &bitis_processed.msgs)
1265 };
1266 render(d);
1267 }
1268
1269 #[rstest]
1270 #[ignore]
1271 fn nested_rust_py() {
1272 let bitis_str = "msg Inner { uint_2 val; }\nmsg ParamTestWithInner { uint_4 param_1; bool param_2; Inner inner; }";
1273
1274 let bitis_processed_org = compile(bitis_str);
1275
1276 let bitis_processed = bitis_processed_org.clone();
1277
1278 let d = JinjaData{
1279 enums: bitis_processed.enums,
1280 msgs: to_rust_messages(&bitis_processed.msgs),
1281 oos: to_rust_oneofs(&bitis_processed.oo_enums, &bitis_processed.msgs)
1282 };
1283 render(d);
1284 }
1285 #[test]
1286 #[ignore]
1287 fn nested_and_enum_rust_py() {
1288 let bitis_str = [
1289 "enum Numbers(4) { one, two, three, four }\n/// Test comment for Inner\nmsg Inner { uint_3 val; Numbers num; }\n",
1290 "msg ParamTestWithInner { uint_4 param_1; bool param_2; Inner inner; } }"
1291 ].join("");
1292
1293 let bitis_processed_org = compile(bitis_str.as_str());
1294
1295 let bitis_processed = bitis_processed_org.clone();
1296
1297 let d = JinjaData{
1298 enums: bitis_processed.enums,
1299 msgs: to_rust_messages(&bitis_processed.msgs),
1300 oos: to_rust_oneofs(&bitis_processed.oo_enums, &bitis_processed.msgs)
1301 };
1302 render(d);
1303 }
1304 #[test]
1305 fn oneof_nested_and_enum_rust_py() {
1306 let bitis_str = [
1307 "//| Test comment for Enum\nenum Numbers(4) { one, two, three, four }\n\n//| Test comment for Inner\nmsg Inner { uint_3 val; Numbers num; }\n",
1308 "msg ParamTestWithInner { uint_4 param_1; bool param_2; oneof action(4) { Inner inner; uint_3 val; } }"
1309 ].join("");
1310
1311 let bitis_processed_org = compile(bitis_str.as_str());
1312
1313 let bitis_processed = bitis_processed_org.clone();
1314
1315 let d = JinjaData{
1316 enums: bitis_processed.enums,
1317 msgs: to_rust_messages(&bitis_processed.msgs),
1318 oos: to_rust_oneofs(&bitis_processed.oo_enums, &bitis_processed.msgs)
1319 };
1320 render(d);
1321 }
1322}
1323
1324#[cfg(test)]
1325mod bitis_serialization {
1326 use rstest::rstest;
1328 use super::*;
1329
1330 #[rstest]
1332 fn msg_simple_msg_compile() {
1333 let test_empty_msg = "msg Lala { repeated_fixed_10 bool data_bool; uint_4 data1_uint; uint_12 data2_uint; }";
1334
1335 let mut lexer = Token::lexer(test_empty_msg);
1336 lexer.extras = 0;
1337
1338 let parsed_bitis = parse_root(&mut lexer);
1339 assert_eq!(parsed_bitis.is_ok(), true);
1340
1341 let _parsed_bitis = parsed_bitis.unwrap();
1342
1343 }
1368}
1369
1370#[cfg(test)]
1371mod bitis_processing {
1372 use rstest::rstest;
1373 use crate::AttributeDetails::{AttributeEnumOrMsg, AttributeSimple};
1374 use super::*;
1375
1376 #[rstest]
1377 #[ignore]
1378 fn msg_base_and_v2() {
1379 let bitis_values = vec![
1380 Value::Message(Message{
1381 name: "TestMsg".to_string(),
1382 comment: Some("This is a test".to_string()),
1384 parent: None,
1385 attributes: vec![Attribute{name: "a1".to_string(), comment: None,
1386 is_repeated_and_size: None, is_optional: false,
1387 specific_details: AttributeSimple(SimpleType::UIntFixed(4)),
1388 }],
1389 }),
1390 Value::Message(Message{
1391 name: "TestMsg".to_string(),
1392 comment: Some("This is a test".to_string()),
1394 parent: None,
1395 attributes: vec![Attribute{name: "a2".to_string(), comment: None,
1396 is_repeated_and_size: None, is_optional: false,
1397 specific_details: AttributeSimple(SimpleType::UIntFixed(4)),
1398 }],
1399 })
1400 ];
1401 let pb = process_and_validate_bitis(&bitis_values);
1402
1403 assert_eq!(pb.max_version_number, 2);
1404 assert_eq!(pb.msgs.len(), 3);
1405
1406 assert_eq!(pb.msgs[0].name, "TestMsg_Base".to_string());
1407 assert_eq!(pb.msgs[1].name, "TestMsg_V1".to_string());
1408 assert_eq!(pb.msgs[2].name, "TestMsg_V2".to_string());
1409
1410 assert_eq!(pb.msgs[0].attributes.len(), 1);
1411 assert_eq!(pb.msgs[0].attributes.get(0).unwrap().name, "a1".to_string());
1412 assert_eq!(pb.msgs[1].attributes.len(), 0);
1413 assert_eq!(pb.msgs[2].attributes.len(), 1);
1414 assert_eq!(pb.msgs[2].attributes.get(0).unwrap().name, "a2".to_string());
1415 }
1416
1417 #[rstest]
1418 #[ignore]
1419 fn msg_base_and_v2_and_add_msg() {
1420 let bitis_values = vec![
1421 Value::Message(Message{
1422 name: "TestMsgInner".to_string(),
1423 comment: Some("This is a test2".to_string()),
1425 parent: None,
1426 attributes: vec![Attribute{name: "lala".to_string(), comment: None,
1427 is_repeated_and_size: None, is_optional: false,
1428 specific_details: AttributeSimple(SimpleType::UIntFixed(4)),
1429 }],
1430 }),
1431 Value::Message(Message{
1432 name: "TestMsgInner".to_string(),
1433 comment: Some("This is a test2".to_string()),
1435 parent: None,
1436 attributes: vec![
1437 Attribute{name: "lala".to_string(), comment: None, is_repeated_and_size: None, is_optional: false,
1438 specific_details: AttributeSimple(SimpleType::UIntFixed(4)),},
1439 Attribute{name: "lala2".to_string(), comment: None, is_repeated_and_size: None, is_optional: false,
1440 specific_details: AttributeSimple(SimpleType::UIntFixed(3)),},
1441 ],
1442 }),
1443 Value::Message(Message{
1444 name: "TestMsg".to_string(),
1445 comment: Some("This is a test".to_string()),
1447 parent: None,
1448 attributes: vec![
1449 Attribute{ name: "a1".to_string(), comment: None, is_repeated_and_size: None, is_optional: false,
1450 specific_details: AttributeSimple(SimpleType::UIntFixed(4)) },
1451 Attribute{ name: "lala_use".to_string(), comment: None, is_repeated_and_size: None, is_optional: false,
1452 specific_details: AttributeEnumOrMsg("TestMsgInner".to_string()) },
1453 ],
1454 }),
1455 Value::Message(Message{
1456 name: "TestMsg".to_string(),
1457 comment: Some("This isa test".to_string()),
1459 parent: None,
1460 attributes: vec![Attribute{name: "a2".to_string(), comment: None,
1461 is_repeated_and_size: None, is_optional: false,
1462 specific_details: AttributeSimple(SimpleType::UIntFixed(4)),
1463 }],
1464 }),
1465 ];
1466 let pb = process_and_validate_bitis(&bitis_values);
1467
1468 assert_eq!(pb.max_version_number, 2);
1469 assert_eq!(pb.msgs.len(), 4);
1470
1471}
1486}
1487