From 8edcd00b87a6c0200a935b5f8b03d5d9c6cc6d9b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 11 Aug 2020 11:19:30 +0200 Subject: [PATCH] implement enum decoder --- decoder/src/lib.rs | 66 +++++++++++++++++++++++++++++++++--- firmware/qemu/src/bin/log.rs | 17 ++++++++++ src/impls.rs | 2 +- 3 files changed, 79 insertions(+), 6 deletions(-) diff --git a/decoder/src/lib.rs b/decoder/src/lib.rs index 397c6309..7e219681 100644 --- a/decoder/src/lib.rs +++ b/decoder/src/lib.rs @@ -355,12 +355,29 @@ fn parse_args<'t>( } Type::Format => { let format = get_format(format_list, bytes, table)?; - let inner_args = parse_args(bytes, format, table, format_list)?; - args.push(Arg::Format { - format, - args: inner_args, - }); + if format.contains('|') { + // enum + let enum_string = format; + let discriminant = bytes.read_u8().map_err(drop)?; + // NOTE nesting of enums, like "A|B(C|D)" is not possible; indirection is + // required: "A|B({:?})" where "{:?}" -> "C|D" + let variant = enum_string + .split('|') + .nth(usize::from(discriminant)) + .ok_or(())?; + let inner_args = parse_args(bytes, variant, table, format_list)?; + args.push(Arg::Format { + format: variant, + args: inner_args, + }); + } else { + let inner_args = parse_args(bytes, format, table, format_list)?; + args.push(Arg::Format { + format, + args: inner_args, + }); + } } Type::I16 => { let data = bytes.read_i16::().map_err(drop)?; @@ -937,4 +954,43 @@ mod tests { "0.000002 INFO Hello World 125", ); } + + #[test] + fn option() { + let mut entries = BTreeMap::new(); + entries.insert(4, "x={:?}".to_owned()); + entries.insert(3, "None|Some({:?})".to_owned()); + entries.insert(2, "{:u8}".to_owned()); + + let table = Table { + entries, + debug: 0..0, + error: 0..0, + info: 4..5, + trace: 0..0, + warn: 0..0, + }; + + let bytes = [ + 4, // string index (INFO) + 0, // timestamp + 3, // string index (enum) + 1, // Some discriminant + 2, // string index (u8) + 42, // Some.0 + ]; + + let frame = super::decode(&bytes, &table).unwrap().0; + assert_eq!(frame.display(false).to_string(), "0.000000 INFO x=Some(42)"); + + let bytes = [ + 4, // string index (INFO) + 1, // timestamp + 3, // string index (enum) + 0, // None discriminant + ]; + + let frame = super::decode(&bytes, &table).unwrap().0; + assert_eq!(frame.display(false).to_string(), "0.000001 INFO x=None"); + } } diff --git a/firmware/qemu/src/bin/log.rs b/firmware/qemu/src/bin/log.rs index 66a2bbaf..b042aa61 100644 --- a/firmware/qemu/src/bin/log.rs +++ b/firmware/qemu/src/bin/log.rs @@ -94,6 +94,23 @@ fn main() -> ! { let slices: &[&[u16]] = &[&[256, 257, 258], &[259, 260]]; binfmt::info!("{:[?]}", slices); + #[derive(Format)] + enum E { + A, + B, + } + + binfmt::info!("e1={:?}", E::A); + binfmt::info!("e2={:?}", E::B); + + binfmt::info!("e3={:?}", Some(42u8)); + binfmt::info!("e4={:?}", None::); + + binfmt::info!("e5={:?}", Ok::(42u8)); + binfmt::info!("e6={:?}", Err::(256u16)); + + binfmt::info!("e7={:?}", Some(X { y: Y { z: 42 } })); + loop { debug::exit(debug::EXIT_SUCCESS) } diff --git a/src/impls.rs b/src/impls.rs index 4a3cbe9e..40f2cd9d 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -194,7 +194,7 @@ where { fn format(&self, f: &mut Formatter) { if f.needs_tag() { - let t = internp!("None|Some({})"); + let t = internp!("None|Some({:?})"); f.u8(&t); } match self {