1use crate::errors::*;
2use ariadne::{sources, Color, Label, Report, ReportKind};
3use chumsky::prelude::*;
4use std::{collections::HashMap, fmt, fs, path::Path};
5
6type Result<T> = std::result::Result<T, DbcError>;
8
9#[derive(Clone, Debug, PartialEq, Default)]
11pub struct Dbc {
12 pub version: String,
14
15 pub speed: BusSpeed,
17
18 pub symbols: Vec<String>,
20
21 pub nodes: Vec<String>,
23
24 pub value_tables: Vec<ValueTable>,
26
27 pub frames: Vec<Frame>,
29
30 pub signal_values: Vec<ValueDescription>,
32}
33
34#[derive(Debug, Default, Clone, PartialEq)]
36pub struct Frame {
37 pub name: String,
39
40 pub transmitter: String,
42
43 pub id: u32,
45
46 pub length: u32,
48
49 pub signals: Vec<Signal>,
51}
52
53#[derive(Debug, Default, Clone, PartialEq)]
55pub struct Signal {
56 pub name: String,
58
59 pub multiplexer: Option<String>,
61
62 pub start: u32,
64
65 pub length: u32,
67
68 pub little_endian: bool,
70
71 pub signed: bool,
73
74 pub scale: f32,
76
77 pub offset: f32,
79
80 pub min: f32,
82
83 pub max: f32,
85
86 pub unit: String,
88
89 pub receiver: Vec<String>,
91}
92
93#[derive(Debug, Default, Clone, PartialEq)]
95pub struct ValueTable {
96 pub name: String,
98
99 pub values: HashMap<u32, String>,
101}
102
103#[derive(Debug, Default, Clone, PartialEq)]
104pub struct ValueDescription {
105 pub id: u32,
107
108 pub name: String,
110
111 pub values: HashMap<u32, String>,
113}
114
115#[derive(Debug, Default, Clone, PartialEq)]
117struct Value {
118 value: u32,
120
121 description: String,
123}
124
125#[derive(Debug, Default, Clone, PartialEq)]
126pub struct BusSpeed {
127 baud: u32,
129
130 btr1: u32,
132
133 btr2: u32,
135}
136
137pub fn parse_dbc(path: &'static str) -> Result<Dbc> {
141 let path = Path::new(path);
142 let fname = path
143 .file_name()
144 .unwrap_or_default()
145 .to_string_lossy()
146 .to_string();
147
148 let contents = match fs::read_to_string(path) {
149 Ok(val) => val,
150 Err(_) => return Err(DbcError::Read(fname)),
151 };
152
153 let result = dbc_parser()
154 .parse(&contents)
155 .into_result()
156 .unwrap_or_else(|errs| parse_failure(&errs[0], fname, &contents));
157
158 Ok(result)
159}
160
161fn dbc_parser<'src>() -> impl Parser<'src, &'src str, Dbc, extra::Err<Rich<'src, char>>> {
163 version_parser()
164 .then(symbol_parser())
165 .then(baud_parser())
166 .then(node_parser())
167 .then(value_table_parser().repeated().collect::<Vec<_>>())
168 .then(frame_parser().repeated().collect::<Vec<_>>())
169 .then(value_description_parser().repeated().collect::<Vec<_>>())
170 .then_ignore(end())
171 .map(
172 |((((((version, symbols), speed), nodes), value_tables), frames), signal_values)| Dbc {
173 version,
174 symbols,
175 speed,
176 nodes,
177 value_tables,
178 frames,
179 signal_values,
180 },
181 )
182 .labelled("DBC")
183}
184
185fn frame_parser<'src>() -> impl Parser<'src, &'src str, Frame, extra::Err<Rich<'src, char>>> {
187 let ident = text::ascii::ident().padded();
188
189 just("BO_")
190 .padded()
191 .ignore_then(int_parser())
192 .then(ident)
193 .then_ignore(just(":"))
194 .padded()
195 .then(int_parser())
196 .then(ident)
197 .padded()
198 .then(signal_parser().repeated().collect::<Vec<_>>())
199 .map(|((((id, name), length), node), signals)| Frame {
200 name: name.to_owned(),
201 id: id.try_into().unwrap(),
202 length: length.try_into().unwrap(),
203 transmitter: node.to_owned(),
204 signals,
205 })
206 .labelled("frame")
207}
208
209fn signal_parser<'src>() -> impl Parser<'src, &'src str, Signal, extra::Err<Rich<'src, char>>> {
211 let ident = text::ascii::ident().and_is(just("SG_").or(just("BO_")).or(just("VAL_")).not()).padded();
212 let scale_offset = just("(")
214 .ignore_then(float_parser())
215 .then_ignore(just(","))
216 .then(float_parser())
217 .then_ignore(just(")"))
218 .padded()
219 .labelled("scale/offset");
220 let min_max = just("[")
222 .ignore_then(float_parser())
223 .then_ignore(just("|"))
224 .then(float_parser())
225 .then_ignore(just("]"))
226 .padded()
227 .labelled("min/max");
228
229 just("SG_")
230 .padded()
231 .ignore_then(ident)
232 .padded()
233 .then(ident.map(|val: &str| val.to_string()).padded().or_not())
234 .then_ignore(just(":"))
235 .padded()
236 .then(int_parser())
237 .then_ignore(just("|"))
238 .then(int_parser())
239 .then_ignore(just("@"))
240 .then(int_parser())
241 .then(just("+").or(just("-")))
242 .padded()
243 .then(scale_offset)
244 .then(min_max)
245 .padded()
246 .then(str_parser())
247 .padded()
248 .then(ident.then_ignore(just(",").or_not()).map(|val| val.to_string()).repeated().collect::<Vec<_>>())
249 .padded()
250 .map(
251 |(
252 ((((((((name, multiplexer), start), length), endianness), signed), scale_offset), min_max), unit),
253 receivers,
254 )| {
255 Signal {
256 name: name.to_string(),
257 multiplexer,
258 start: start.try_into().unwrap(),
259 length: length.try_into().unwrap(),
260 little_endian: endianness == 1,
261 signed: signed == "-",
262 scale: scale_offset.0,
263 offset: scale_offset.1,
264 min: min_max.0,
265 max: min_max.1,
266 unit: unit.to_string(),
267 receiver: receivers,
268 }
269 },
270 )
271 .labelled("signal")
272}
273
274fn version_parser<'src>() -> impl Parser<'src, &'src str, String, extra::Err<Rich<'src, char>>> {
276 just("VERSION")
277 .padded()
278 .ignore_then(str_parser())
279 .padded()
280 .map(|ver| ver)
281 .labelled("version")
282}
283
284fn baud_parser<'src>() -> impl Parser<'src, &'src str, BusSpeed, extra::Err<Rich<'src, char>>> {
286 let speed = int_parser()
287 .then_ignore(just(":"))
288 .padded()
289 .then(int_parser())
290 .then_ignore(just(","))
291 .padded()
292 .then(int_parser())
293 .padded()
294 .then_ignore(just(";"))
295 .map(|((baud, btr1), btr2)| BusSpeed {
297 baud: baud.try_into().unwrap(),
298 btr1: btr1.try_into().unwrap(),
299 btr2: btr2.try_into().unwrap(),
300 });
301
302 just("BS_")
303 .padded()
304 .ignore_then(just(":"))
305 .padded()
306 .ignore_then(speed.or_not())
307 .padded()
308 .map(|result| result.unwrap_or_default())
309 .labelled("bus speed")
310}
311
312fn symbol_parser<'src>() -> impl Parser<'src, &'src str, Vec<String>, extra::Err<Rich<'src, char>>>
314{
315 let ident = text::ascii::ident()
316 .and_is(just("BS_").not())
317 .padded()
318 .map(|val: &str| val.to_owned());
319 let nodes = ident.repeated().collect::<Vec<_>>();
320
321 just("NS_")
322 .padded()
323 .ignore_then(just(":"))
324 .padded()
325 .ignore_then(nodes)
326 .labelled("symbols")
327}
328
329fn node_parser<'src>() -> impl Parser<'src, &'src str, Vec<String>, extra::Err<Rich<'src, char>>> {
331 let ident = text::ascii::ident()
332 .and_is(just("VAL_TABLE_").not())
333 .padded()
334 .map(|val: &str| val.to_owned());
335 let nodes = ident.repeated().collect::<Vec<_>>();
336
337 just("BU_")
338 .padded()
339 .ignore_then(just(":"))
340 .padded()
341 .ignore_then(nodes)
342 .padded()
343 .labelled("nodes")
344}
345
346fn value_table_parser<'src>(
348) -> impl Parser<'src, &'src str, ValueTable, extra::Err<Rich<'src, char>>> {
349 let ident = text::ascii::ident().padded();
350 let value = int_parser()
351 .padded()
352 .then(str_parser())
353 .map(|(value, description)| Value {
354 description,
355 value: value.try_into().unwrap(),
356 });
357
358 just("VAL_TABLE_")
359 .padded()
360 .ignore_then(ident)
361 .padded()
362 .then(value.repeated().collect::<Vec<_>>())
363 .then_ignore(just(";"))
364 .padded()
365 .map(|(name, values)| ValueTable {
366 name: name.to_owned(),
367 values: {
368 let vals = values.iter().map(|expr| expr.value.clone());
369 let descs = values.iter().map(|expr| expr.description.clone());
370
371 vals.zip(descs).collect()
372 },
373 })
374 .labelled("global value table")
375}
376
377fn value_description_parser<'src>(
379) -> impl Parser<'src, &'src str, ValueDescription, extra::Err<Rich<'src, char>>> {
380 let ident = text::ascii::ident().padded();
381 let value = int_parser()
382 .padded()
383 .then(str_parser())
384 .map(|(value, description)| Value {
385 description,
386 value: value.try_into().unwrap(),
387 });
388
389 just("VAL_")
390 .padded()
391 .ignore_then(int_parser())
392 .then(ident)
393 .padded()
394 .then(value.repeated().collect::<Vec<_>>())
395 .then_ignore(just(";"))
396 .padded()
397 .map(|((id, name), values)| ValueDescription {
398 id: id.try_into().unwrap(),
399 name: name.to_owned(),
400 values: {
401 let vals = values.iter().map(|expr| expr.value.clone());
402 let descs = values.iter().map(|expr| expr.description.clone());
403
404 vals.zip(descs).collect()
405 },
406 })
407 .labelled("signal value description")
408}
409
410fn int_parser<'src>() -> impl Parser<'src, &'src str, i32, extra::Err<Rich<'src, char>>> {
412 let sign = just("-").or_not();
413
414 sign.then(text::int(10))
415 .padded()
416 .map(|(s, i)| {
417 let s = s.unwrap_or_default().to_owned() + i;
418
419 s.parse::<i32>().unwrap()
420 })
421 .labelled("integer")
422}
423
424fn float_parser<'src>() -> impl Parser<'src, &'src str, f32, extra::Err<Rich<'src, char>>> {
426 let digits = text::digits::<_, extra::Err<Rich<'src, char>>>(10).to_slice();
427
428 let fraction = just(".")
429 .ignore_then(digits)
430 .or_not()
431 .map(|val| val.unwrap_or_default())
432 .labelled("denominator");
433
434 let exponent = just("E")
435 .then(just("-").or(just("+")).or_not())
436 .then(digits)
437 .or_not()
438 .map(|e| {
439 let ((e, sign), int) = e.unwrap_or_default();
440
441 e.to_owned() + sign.unwrap_or_default() + int
442 })
443 .labelled("exponent");
444
445 int_parser()
446 .then(fraction)
447 .then(exponent)
448 .padded()
449 .map(|((int, frac), exp)| {
450 let val = int.to_string() + "." + &frac + &exp;
451 val.parse::<f32>().unwrap()
452 })
453 .labelled("float")
454}
455
456fn str_parser<'src>() -> impl Parser<'src, &'src str, String, extra::Err<Rich<'src, char>>> {
458 just('"')
459 .ignore_then(none_of('"').repeated().to_slice())
460 .then_ignore(just('"'))
461 .padded()
462 .map(|val: &str| val.to_owned())
463 .labelled("string")
464}
465
466fn parse_failure(err: &Rich<impl fmt::Display>, fname: String, src: &str) -> ! {
470 failure(
471 err.reason().to_string(),
472 fname,
473 (
474 err.found()
475 .map(|c| c.to_string())
476 .unwrap_or_else(|| "end of input".to_string()),
477 *err.span(),
478 ),
479 err.contexts()
480 .map(|(l, s)| (format!("while parsing this {l}"), *s)),
481 src,
482 )
483}
484
485fn failure(
489 msg: String,
490 fname: String,
491 label: (String, SimpleSpan),
492 extra_labels: impl IntoIterator<Item = (String, SimpleSpan)>,
493 src: &str,
494) -> ! {
495 Report::build(ReportKind::Error, (fname.clone(), label.1.into_range()))
496 .with_config(ariadne::Config::new().with_index_type(ariadne::IndexType::Byte))
497 .with_message(&msg)
498 .with_label(
499 Label::new((fname.clone(), label.1.into_range()))
500 .with_message(label.0)
501 .with_color(Color::Red),
502 )
503 .with_labels(extra_labels.into_iter().map(|label2| {
504 Label::new((fname.clone(), label2.1.into_range()))
505 .with_message(label2.0)
506 .with_color(Color::Yellow)
507 }))
508 .finish()
509 .print(sources([(fname, src)]))
510 .unwrap();
511 std::process::exit(1)
512}
513
514#[cfg(test)]
515mod top_level_parsing {
516 use super::*;
517
518 #[test]
520 fn does_run() {
521 let result = parse_dbc("./dbcs/simple.dbc");
522 assert!(result.is_ok());
523 }
524}
525
526#[cfg(test)]
527mod frame_parser {
528 use super::*;
529
530 #[test]
532 fn parse_frame() {
533 let result = frame_parser()
534 .parse("BO_ 780 DriverSeat: 8 XXX\n SG_ occupancyStatus : 16|3@1+ (1,0) [0|7] \"unit\" XXX\n")
535 .into_result();
536 assert!(result.is_ok());
537 let result = result.unwrap();
538 assert_eq!(result.name, "DriverSeat");
539 assert_eq!(result.id, 780);
540 assert_eq!(result.length, 8);
541 assert_eq!(result.transmitter, "XXX");
542 assert_eq!(result.signals[0].name, "occupancyStatus");
543 }
544}
545
546#[cfg(test)]
547mod signal_parser {
548 use super::*;
549
550 #[test]
552 fn parse_signal_int() {
553 let result = signal_parser()
554 .parse("SG_ test1 : 0|4@1+ (1,0) [0|7] \"units\" XXX\n")
555 .into_result();
556 assert!(result.is_ok());
557 let result = result.unwrap();
558 assert_eq!(result.name, "test1");
559 assert_eq!(result.multiplexer, None);
560 assert_eq!(result.start, 0);
561 assert_eq!(result.length, 4);
562 assert_eq!(result.little_endian, true);
563 assert_eq!(result.signed, false);
564 assert_eq!(result.scale, 1.);
565 assert_eq!(result.offset, 0.);
566 assert_eq!(result.min, 0.);
567 assert_eq!(result.max, 7.);
568 assert_eq!(result.unit, "units");
569 assert_eq!(result.receiver[0], "XXX");
570 }
571
572 #[test]
574 fn parse_signal_float() {
575 let result = signal_parser()
576 .parse("SG_ test2 : 16|3@0- (1.0,16.3) [0.7|32.9] \"units\" XXX\n")
577 .into_result();
578 assert!(result.is_ok());
579 let result = result.unwrap();
580 assert_eq!(result.name, "test2");
581 assert_eq!(result.multiplexer, None);
582 assert_eq!(result.start, 16);
583 assert_eq!(result.length, 3);
584 assert_eq!(result.little_endian, false);
585 assert_eq!(result.signed, true);
586 assert_eq!(result.scale, 1.);
587 assert_eq!(result.offset, 16.3);
588 assert_eq!(result.min, 0.7);
589 assert_eq!(result.max, 32.9);
590 assert_eq!(result.unit, "units");
591 assert_eq!(result.receiver[0], "XXX");
592 }
593
594 #[test]
595 fn parse_signal_float_extended() {
596 let result = signal_parser()
597 .parse("SG_ DAS_jerkMin : 18|9@1+ (0.03,-15.232) [-15.232|0.098] \"m/s^3\" NEO\n")
598 .into_result();
599 assert!(result.is_ok());
600 let result = result.unwrap();
601 assert_eq!(result.name, "DAS_jerkMin");
602 assert_eq!(result.multiplexer, None);
603 assert_eq!(result.start, 18);
604 assert_eq!(result.length, 9);
605 assert_eq!(result.little_endian, true);
606 assert_eq!(result.signed, false);
607 assert_eq!(result.scale, 0.03);
608 assert_eq!(result.offset, -15.232);
609 assert_eq!(result.min, -15.232);
610 assert_eq!(result.max, 0.098);
611 assert_eq!(result.unit, "m/s^3");
612 assert_eq!(result.receiver[0], "NEO");
613 }
614
615 #[test]
616 fn parse_signal_float_exponent() {
617 let result = signal_parser()
618 .parse("SG_ DAS_virtualLaneC2 : 32|8@1+ (2E-05,-0.0025) [-0.0025|0.0025] \"m-1\" NEO")
619 .into_result();
620 assert!(result.is_ok());
621 let result = result.unwrap();
622 assert_eq!(result.name, "DAS_virtualLaneC2");
623 assert_eq!(result.multiplexer, None);
624 assert_eq!(result.start, 32);
625 assert_eq!(result.length, 8);
626 assert_eq!(result.little_endian, true);
627 assert_eq!(result.signed, false);
628 assert_eq!(result.scale, 2E-05);
629 assert_eq!(result.offset, -0.0025);
630 assert_eq!(result.min, -0.0025);
631 assert_eq!(result.max, 0.0025);
632 assert_eq!(result.unit, "m-1");
633 assert_eq!(result.receiver[0], "NEO");
634 }
635
636 #[test]
637 fn parse_signal_multi_modes() {
638 let result = signal_parser()
639 .parse("SG_ ESP_BChecksum : 39|8@0+ (1,0) [0|255] \"\" NEO,EPAS")
640 .into_result();
641 assert!(result.is_ok());
642 let result = result.unwrap();
643 assert_eq!(result.name, "ESP_BChecksum");
644 assert_eq!(result.multiplexer, None);
645 assert_eq!(result.start, 39);
646 assert_eq!(result.length, 8);
647 assert_eq!(result.little_endian, false);
648 assert_eq!(result.signed, false);
649 assert_eq!(result.scale, 1.);
650 assert_eq!(result.offset, 0.);
651 assert_eq!(result.min, 0.);
652 assert_eq!(result.max, 255.);
653 assert_eq!(result.unit, "");
654 assert_eq!(result.receiver[0], "NEO");
655 assert_eq!(result.receiver[1], "EPAS");
656 }
657
658 #[test]
659 fn parse_signal_multiplexed() {
660 let result: std::result::Result<Signal, Vec<Rich<'_, char>>> = signal_parser()
661 .parse("SG_ UI_autopilotControlIndex M : 0|3@1+ (1,0) [0|7] \"\" APP,APS")
662 .into_result();
663 assert!(result.is_ok());
664 let result = result.unwrap();
665 assert_eq!(result.name, "UI_autopilotControlIndex");
666 assert_eq!(result.multiplexer, Some("M".to_string()));
667 assert_eq!(result.start, 0);
668 assert_eq!(result.length, 3);
669 assert_eq!(result.little_endian, true);
670 assert_eq!(result.signed, false);
671 assert_eq!(result.scale, 1.);
672 assert_eq!(result.offset, 0.);
673 assert_eq!(result.min, 0.);
674 assert_eq!(result.max, 7.);
675 assert_eq!(result.unit, "");
676 assert_eq!(result.receiver[0], "APP");
677 assert_eq!(result.receiver[1], "APS");
678 }
679}
680
681#[cfg(test)]
682mod value_table_parser {
683 use super::*;
684
685 #[test]
687 fn parse_value_table_simple() {
688 let result = value_table_parser()
689 .parse("VAL_TABLE_ StW_AnglHP_Spd 16383 \"SNA\" ;\n")
690 .into_result();
691 assert!(result.is_ok());
692 let result = result.unwrap();
693 assert_eq!(result.name, "StW_AnglHP_Spd");
694 let values = result.values;
695 assert_eq!(values[&16383], "SNA");
696 }
697
698 #[test]
700 fn parse_value_table() {
701 let result = value_table_parser()
702 .parse("VAL_TABLE_ DI_velocityEstimatorState 4 \"VE_STATE_BACKUP_MOTOR\" 3 \"VE_STATE_BACKUP_WHEELS_B\" 2 \"VE_STATE_BACKUP_WHEELS_A\" 1 \"VE_STATE_WHEELS_NORMAL\" 0 \"VE_STATE_NOT_INITIALIZED\" ;\n")
703 .into_result();
704 assert!(result.is_ok());
705 let result = result.unwrap();
706 assert_eq!(result.name, "DI_velocityEstimatorState");
707 let values = result.values;
708 assert_eq!(values[&0], "VE_STATE_NOT_INITIALIZED");
709 assert_eq!(values[&4], "VE_STATE_BACKUP_MOTOR");
710 }
711}
712
713#[cfg(test)]
714mod misc_parsers {
715 use super::*;
716
717 #[test]
719 fn parse_version() {
720 let result = version_parser()
721 .parse("VERSION \"SIMPLE-DBC\"\n")
722 .into_result();
723 assert!(result.is_ok());
724 let result = result.unwrap();
725 assert_eq!(result, "SIMPLE-DBC");
726 }
727
728 #[test]
730 fn parse_baud_empty() {
731 let result = baud_parser().parse("BS_:\n").into_result();
732 assert!(result.is_ok());
733 }
734
735 #[test]
737 fn parse_baud() {
738 let result = baud_parser()
739 .parse("BS_: 500000 : 32 , 16 ;\n")
740 .into_result();
741 assert!(result.is_ok());
742 let result = result.unwrap();
743 assert_eq!(result.baud, 500000);
744 assert_eq!(result.btr1, 32);
745 assert_eq!(result.btr2, 16);
746 }
747
748 #[test]
750 fn parse_symbols() {
751 let result = symbol_parser()
752 .parse("NS_ : \n\tNS_DESC_\n\tCM_\n\tBA_DEF_\n\tBA_\n\tVAL_\n\tCAT_DEF_\n\tCAT_\n\tFILTER\n\tBA_DEF_DEF_\n\tEV_DATA_\n\tENVVAR_DATA_\n\tSGTYPE_\n\tSGTYPE_VAL_\n\tBA_DEF_SGTYPE_\n\tBA_SGTYPE_\n\tSIG_TYPE_REF_\n\tVAL_TABLE_\n\tSIG_GROUP_\n\tSIG_VALTYPE_\n\tSIGTYPE_VALTYPE_\n\tBO_TX_BU_\n\tBA_DEF_REL_\n\tBA_REL_\n\tBA_DEF_DEF_REL_\n\tBU_SG_REL_\n\tBU_EV_REL_\n\tBU_BO_REL_\n\tSG_MUL_VAL_\n")
753 .into_result();
754 assert!(result.is_ok());
755 let result = result.unwrap();
756 assert_eq!(result[0], "NS_DESC_");
757 assert_eq!(result[27], "SG_MUL_VAL_");
758 }
759
760 #[test]
762 fn parse_nodes() {
763 let result = node_parser()
764 .parse("BU_:\n\tNEO\n\tMCU\n\tGTW\n\tEPAS\n\tDI\n\tESP\n\tSBW\n\tSTW\n\tAPP\n\tDAS\n\tXXX\n")
765 .into_result();
766 assert!(result.is_ok());
767 let result = result.unwrap();
768 assert_eq!(result[0], "NEO");
769 assert_eq!(result[10], "XXX");
770 }
771
772 #[test]
774 fn parse_signal_descriptions() {
775 let result = value_description_parser()
776 .parse("VAL_ 1001 DAS_turnIndicatorRequestReason 6 \"DAS_ACTIVE_COMMANDED_LANE_CHANGE\" 5 \"DAS_CANCEL_FORK\" 4 \"DAS_CANCEL_LANE_CHANGE\" 3 \"DAS_ACTIVE_FORK\" 2 \"DAS_ACTIVE_SPEED_LANE_CHANGE\" 1 \"DAS_ACTIVE_NAV_LANE_CHANGE\" 0 \"DAS_NONE\" ;\n")
777 .into_result();
778 assert!(result.is_ok());
779 let result = result.unwrap();
780 assert_eq!(result.id, 1001);
781 assert_eq!(result.name, "DAS_turnIndicatorRequestReason");
782 let values = result.values;
783 assert_eq!(values[&0], "DAS_NONE");
784 assert_eq!(values[&6], "DAS_ACTIVE_COMMANDED_LANE_CHANGE");
785 }
786}
787
788#[cfg(test)]
789mod int_parsing {
790 use super::*;
791
792 #[test]
794 fn parse_int_unsigned() {
795 let result = int_parser().parse("16").into_result();
796 assert!(result.is_ok());
797 let result = result.unwrap();
798 assert_eq!(result, 16);
799 }
800
801 #[test]
803 fn parse_int_signed() {
804 let result = int_parser().parse("-32").into_result();
805 assert!(result.is_ok());
806 let result = result.unwrap();
807 assert_eq!(result, -32);
808 }
809}
810
811#[cfg(test)]
812mod float_parsing {
813 use super::*;
814
815 #[test]
817 fn parse_float_unsigned() {
818 let result = float_parser().parse("1.5").into_result().unwrap();
819 assert_eq!(result, 1.5);
820 }
821
822 #[test]
824 fn parse_float_signed() {
825 let result = float_parser().parse("-1.5").into_result().unwrap();
826 assert_eq!(result, -1.5);
827 }
828
829 #[test]
831 fn parse_float_simple() {
832 let result = float_parser().parse("10").into_result().unwrap();
833 assert_eq!(result, 10.);
834 }
835}