Skip to content

Commit b319759

Browse files
committed
Make a proc macro for more easily defining VIF tables
I'm not sure this is a remotely sensible way to do this but it sure does seem to be working so let's go right ahead!
1 parent 61506ff commit b319759

File tree

5 files changed

+72
-9
lines changed

5 files changed

+72
-9
lines changed

Cargo.lock

Lines changed: 16 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
[workspace]
2+
3+
members = ["libmbus_macros"]
4+
15
[package]
26
name = "libmbus"
37
license = "EUPL-1.2"
@@ -10,3 +14,4 @@ edition = "2021"
1014
chrono = "0.4.23"
1115
encoding_rs = "0.8.32"
1216
winnow = "0.6.5"
17+
libmbus_macros = { path = "./libmbus_macros" }

libmbus_macros/Cargo.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[package]
2+
name = "libmbus_macros"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[lib]
9+
proc-macro = true
10+
11+
[dependencies]
12+
winnow = "0.6.6"

libmbus_macros/src/lib.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
use proc_macro::TokenStream;
2+
use winnow::ascii;
3+
use winnow::combinator::repeat;
4+
use winnow::error::InputError;
5+
use winnow::prelude::*;
6+
use winnow::Str;
7+
8+
#[proc_macro]
9+
pub fn vif(input: TokenStream) -> TokenStream {
10+
let raw_input = input.to_string();
11+
12+
let (_, upper_bits, _, lower_bits, ns) = (
13+
'E'.void(),
14+
ascii::digit1::<_, InputError<Str>>.map(|s| u8::from_str_radix(s, 2).unwrap()),
15+
' '.void(),
16+
ascii::digit0.map(|s| u8::from_str_radix(s, 2).unwrap()),
17+
repeat::<_, _, String, _, _>(0..=4, 'n'),
18+
)
19+
.parse(raw_input.as_str())
20+
.unwrap();
21+
22+
let base = (upper_bits << 4) | (lower_bits << ns.len());
23+
24+
let mask_inv = 0xFF << ns.len();
25+
let mask = !mask_inv;
26+
27+
let range_start = base & mask_inv;
28+
let range_end = base | mask;
29+
30+
if range_start == range_end {
31+
format!(r"{range_start}")
32+
} else {
33+
format!(r"{range_start}..={range_end}")
34+
}
35+
.parse()
36+
.unwrap()
37+
}

src/parse/application_layer/vib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use crate::parse::error::MBResult;
66
use crate::parse::types::string::parse_length_prefix_ascii;
77
use crate::parse::types::BitsInput;
8+
use libmbus_macros::vif;
89
use winnow::binary::bits;
910
use winnow::error::{AddContext, ErrMode, ErrorKind, ParserError, StrContext};
1011
use winnow::prelude::*;
@@ -135,7 +136,7 @@ impl ValueInfoBlock {
135136

136137
fn parse_table_10(value: u8) -> Option<ValueType> {
137138
Some(match value {
138-
0b0111_0100..=0b0111_0111 => {
139+
vif!(E111 01nn) => {
139140
ValueType::ActualityDuration(DurationType::decode_nn(value & DURATION_MASK))
140141
}
141142
_ => todo!("table 10 {value} {value:x} {value:b}"),

0 commit comments

Comments
 (0)