Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add alternate hint ('#') #503

Merged
merged 7 commits into from
Jun 11, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions book/src/hints.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ The first 4 display hints resemble what's supported in `core::fmt`. Examples bel

``` rust
# extern crate defmt;
defmt::info!("{=u8:x}", 42); // -> INFO 0x2a
defmt::info!("{=u8:X}", 42); // -> INFO 0x2A
defmt::info!("{=u8:b}", 42); // -> INFO 0b101010
defmt::info!("{=u8:x}", 42); // -> INFO 2a
defmt::info!("{=u8:X}", 42); // -> INFO 2A
defmt::info!("{=u8:#x}", 42); // -> INFO 0x2a
defmt::info!("{=u8:b}", 42); // -> INFO 101010

defmt::info!("{=str}", "hello\tworld"); // -> INFO hello world
defmt::info!("{=str:?}", "hello\tworld"); // -> INFO "hello\tworld"
Expand All @@ -30,7 +31,7 @@ Leading zeros are supported, for example
``` rust
# extern crate defmt;
defmt::info!("{=u8:03}", 42); // -> INFO 042
defmt::info!("{=u8:08X}", 42); // -> INFO 0x0000002A
defmt::info!("{=u8:08X}", 42); // -> INFO 0000002A
Urhengulas marked this conversation as resolved.
Show resolved Hide resolved
```

No further customization like padding is supported (at the moment).
Expand Down Expand Up @@ -58,11 +59,11 @@ let x = S { x: 42 };
defmt::info!("{}", x);
// -> INFO S { x: 42 }

defmt::info!("{:x}", x);
defmt::info!("{:#x}", x);
// -> INFO S { x: 0x2a }
```

``` rust
```rust
richard-uk1 marked this conversation as resolved.
Show resolved Hide resolved
# extern crate defmt;
struct S { x: u8, y: u8 }

Expand All @@ -75,8 +76,8 @@ impl defmt::Format for S {

let x = S { x: 42, y: 42 };
defmt::info!("{}", x);
// -> INFO S { x: 42, y: 0x2a }
// -> INFO S { x: 42, y: 2a }

defmt::info!("{:x}", x);
// -> INFO S { x: 0b101010, y: 0x2a }
defmt::info!("{:b}", x);
// -> INFO S { x: 101010, y: 2a }
```
38 changes: 28 additions & 10 deletions decoder/src/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,14 +137,23 @@ fn format_args_real(
buf: &mut String,
) -> Result<(), fmt::Error> {
match hint {
Some(DisplayHint::NoHint { zero_pad }) => write!(buf, "{:#01$}", x, zero_pad)?,
Some(DisplayHint::Binary { zero_pad }) => write!(buf, "{:#01$b}", x, zero_pad)?,
Some(DisplayHint::NoHint { zero_pad }) => write!(buf, "{:01$}", x, zero_pad)?,
Some(DisplayHint::Binary {
alternate,
zero_pad,
}) => match alternate {
true => write!(buf, "{:#01$b}", x, zero_pad)?,
false => write!(buf, "{:01$b}", x, zero_pad)?,
},
Some(DisplayHint::Hexadecimal {
uppercase,
alternate,
zero_pad,
}) => match uppercase {
false => write!(buf, "{:#01$x}", x, zero_pad)?,
true => write!(buf, "{:#01$X}", x, zero_pad)?,
}) => match (alternate, uppercase) {
(false, false) => write!(buf, "{:01$x}", x, zero_pad)?,
(false, true) => write!(buf, "{:01$X}", x, zero_pad)?,
(true, false) => write!(buf, "{:#01$x}", x, zero_pad)?,
(true, true) => write!(buf, "{:#01$X}", x, zero_pad)?,
},
Some(DisplayHint::Microseconds) => {
let seconds = x / 1_000_000;
Expand All @@ -162,14 +171,23 @@ fn format_args_real(
buf: &mut String,
) -> Result<(), fmt::Error> {
match hint {
Some(DisplayHint::NoHint { zero_pad }) => write!(buf, "{:#01$}", x, zero_pad)?,
Some(DisplayHint::Binary { zero_pad }) => write!(buf, "{:#01$b}", x, zero_pad)?,
Some(DisplayHint::NoHint { zero_pad }) => write!(buf, "{:01$}", x, zero_pad)?,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to future: The body of fn format_u128 and fn format_i128 is pretty much the same. Refactor!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did play around with doing this, but you would need something that is generic over u128/i128, or you could refactor it into a macro (since the actual language tokens are the same but the types are different).

Some(DisplayHint::Binary {
alternate,
zero_pad,
}) => match alternate {
true => write!(buf, "{:#01$b}", x, zero_pad)?,
false => write!(buf, "{:01$b}", x, zero_pad)?,
},
Some(DisplayHint::Hexadecimal {
uppercase,
alternate,
zero_pad,
}) => match uppercase {
false => write!(buf, "{:#01$x}", x, zero_pad)?,
true => write!(buf, "{:#01$X}", x, zero_pad)?,
}) => match (alternate, uppercase) {
(false, false) => write!(buf, "{:01$x}", x, zero_pad)?,
(false, true) => write!(buf, "{:01$X}", x, zero_pad)?,
(true, false) => write!(buf, "{:#01$x}", x, zero_pad)?,
(true, true) => write!(buf, "{:#01$X}", x, zero_pad)?,
},
_ => write!(buf, "{}", x)?,
}
Expand Down
30 changes: 15 additions & 15 deletions decoder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -751,23 +751,23 @@ mod tests {
0b1110_0101, // u8
];
decode_and_expect(
"x: {0=0..4:b}, y: {0=3..8:b}",
"x: {0=0..4:b}, y: {0=3..8:#b}",
&bytes,
"0.000002 INFO x: 0b101, y: 0b11100",
"0.000002 INFO x: 101, y: 0b11100",
);
}

#[test]
fn bitfields_reverse_order() {
let bytes = [
0, // index
2, // timestamp
0b1101_0010, // u8
Urhengulas marked this conversation as resolved.
Show resolved Hide resolved
0, // index
2, // timestamp
1101_0010, // u8
];
decode_and_expect(
"x: {0=0..7:b}, y: {0=3..5:b}",
&bytes,
"0.000002 INFO x: 0b1010010, y: 0b10",
"0.000002 INFO x: 1010010, y: 10",
);
}

Expand All @@ -782,7 +782,7 @@ mod tests {
decode_and_expect(
"#0: {0=0..5:b}, #1: {1=3..8:b}",
&bytes,
"0.000002 INFO #0: 0b10000, #1: 0b11100",
"0.000002 INFO #0: 10000, #1: 11100",
);
}

Expand All @@ -794,7 +794,7 @@ mod tests {
0b1111_0000,
0b1110_0101, // u16
];
decode_and_expect("x: {0=7..12:b}", &bytes, "0.000002 INFO x: 0b1011");
decode_and_expect("x: {0=7..12:b}", &bytes, "0.000002 INFO x: 1011");
}

#[test]
Expand All @@ -809,7 +809,7 @@ mod tests {
decode_and_expect(
"#0: {0=7..12:b}, #1: {1=0..5:b}",
&bytes,
"0.000002 INFO #0: 0b1011, #1: 0b10001",
"0.000002 INFO #0: 1011, #1: 10001",
);
}

Expand All @@ -826,7 +826,7 @@ mod tests {
decode_and_expect(
"#0: {0=7..12:b}, #1: {1=u8}, #2: {2=0..5:b}",
&bytes,
"0.000002 INFO #0: 0b1011, #1: 42, #2: 0b10001",
"0.000002 INFO #0: 1011, #1: 42, #2: 10001",
);
}

Expand All @@ -841,7 +841,7 @@ mod tests {
decode_and_expect(
"bitfields {0=0..7:b} {0=9..14:b}",
&bytes,
"0.000002 INFO bitfields 0b1010010 0b10001",
"0.000002 INFO bitfields 1010010 10001",
);
}

Expand All @@ -857,7 +857,7 @@ mod tests {
decode_and_expect(
"bitfields {0=0..7:b} {0=9..14:b} {1=8..10:b}",
&bytes,
"0.000002 INFO bitfields 0b1010010 0b10001 0b11",
"0.000002 INFO bitfields 1010010 10001 11",
);
}

Expand All @@ -871,7 +871,7 @@ mod tests {
decode_and_expect(
"bitfields {0=9..14:b}",
&bytes,
"0.000002 INFO bitfields 0b10001",
"0.000002 INFO bitfields 10001",
);
}

Expand All @@ -888,7 +888,7 @@ mod tests {
decode_and_expect(
"bitfields {0=0..2:b} {0=28..31:b}",
&bytes,
"0.000002 INFO bitfields 0b11 0b100",
"0.000002 INFO bitfields 11 100",
);
}

Expand All @@ -914,7 +914,7 @@ mod tests {
0b0000_0000, // 8..15
0b0000_0000, // 0..7
];
decode_and_expect("x: {0=119..124:b}", &bytes, "0.000002 INFO x: 0b1011");
decode_and_expect("x: {0=119..124:b}", &bytes, "0.000002 INFO x: 1011");
}

#[test]
Expand Down
73 changes: 69 additions & 4 deletions parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@ pub enum DisplayHint {
/// `:x` OR `:X`
Hexadecimal {
uppercase: bool,
alternate: bool,
richard-uk1 marked this conversation as resolved.
Show resolved Hide resolved
zero_pad: usize,
},
/// `:b`
Binary {
alternate: bool,
zero_pad: usize,
},
/// `:a`
Expand All @@ -52,25 +54,41 @@ pub enum DisplayHint {
Unknown(String),
}

/// Parses the display hint (e.g. the `#x` in `{=u8:#x}`)
fn parse_display_hint(mut s: &str) -> Option<DisplayHint> {
// The `#` comes before any padding hints (I think this matches core::fmt).
// It is ignored for types that don't have an alternate representation.
let alternate = if matches!(s.chars().next(), Some('#')) {
s = &s[1..]; // '#' is always 1 byte
true
} else {
false
};

let zero_pad = if let Some(rest) = s.strip_prefix("0") {
let (rest, columns) = parse_integer::<usize>(rest)?;
s = rest;
columns
} else {
0 // default behavior is the same as zero padding.
0 // default behavior is the same as no zero-padding.
};

Some(match s {
"" => DisplayHint::NoHint { zero_pad },
"µs" => DisplayHint::Microseconds,
"a" => DisplayHint::Ascii,
"b" => DisplayHint::Binary { zero_pad },
"b" => DisplayHint::Binary {
zero_pad,
alternate,
},
"x" => DisplayHint::Hexadecimal {
uppercase: false,
alternate,
zero_pad,
},
"X" => DisplayHint::Hexadecimal {
uppercase: true,
alternate,
zero_pad,
},
"?" => DisplayHint::Debug,
Expand Down Expand Up @@ -518,6 +536,7 @@ mod tests {
ty: Type::U8,
hint: Some(DisplayHint::Hexadecimal {
uppercase: false,
alternate: false,
zero_pad: 0
}),
})
Expand Down Expand Up @@ -547,7 +566,10 @@ mod tests {
Ok(Param {
index: Some(1),
ty: Type::U8,
hint: Some(DisplayHint::Binary { zero_pad: 0 }),
hint: Some(DisplayHint::Binary {
zero_pad: 0,
alternate: false
}),
})
);
}
Expand All @@ -568,7 +590,22 @@ mod tests {
Ok(Param {
index: None,
ty: Type::Format,
hint: Some(DisplayHint::Binary { zero_pad: 0 }),
hint: Some(DisplayHint::Binary {
zero_pad: 0,
alternate: false
}),
})
);

assert_eq!(
parse_param(":#b", ParserMode::Strict),
Ok(Param {
index: None,
ty: Type::Format,
hint: Some(DisplayHint::Binary {
zero_pad: 0,
alternate: true
}),
})
);

Expand All @@ -579,6 +616,20 @@ mod tests {
ty: Type::Format,
hint: Some(DisplayHint::Hexadecimal {
uppercase: false,
alternate: false,
zero_pad: 0
}),
})
);

assert_eq!(
parse_param(":#x", ParserMode::Strict),
Ok(Param {
index: None,
ty: Type::Format,
hint: Some(DisplayHint::Hexadecimal {
uppercase: false,
alternate: true,
zero_pad: 0
}),
})
Expand All @@ -591,6 +642,20 @@ mod tests {
ty: Type::Format,
hint: Some(DisplayHint::Hexadecimal {
uppercase: true,
alternate: false,
zero_pad: 0
}),
})
);

assert_eq!(
parse_param(":#X", ParserMode::Strict),
Ok(Param {
index: None,
ty: Type::Format,
hint: Some(DisplayHint::Hexadecimal {
uppercase: true,
alternate: true,
zero_pad: 0
}),
})
Expand Down