• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ia0 / data-encoding / #1030

28 Jun 2025 04:09PM UTC coverage: 52.853%. Remained the same
#1030

push

web-flow
Fix lint in xtask (#144)

491 of 929 relevant lines covered (52.85%)

2.19 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
lib/macro/internal/src/lib.rs
1
//! Internal library for data-encoding-macro
2
//!
3
//! Do **not** use this library. Use [data-encoding-macro] instead.
4
//!
5
//! This library is for internal use by data-encoding-macro because procedural
6
//! macros require a separate crate.
7
//!
8
//! [data-encoding-macro]: https://crates.io/crates/data-encoding-macro
9

10
#![warn(unused_results)]
11

12
use std::collections::HashMap;
13

14
use data_encoding::{BitOrder, Encoding, Specification, Translate, Wrap};
15
use proc_macro::token_stream::IntoIter;
16
use proc_macro::{TokenStream, TokenTree};
17

18
fn parse_op(tokens: &mut IntoIter, op: char, key: &str) {
19
    match tokens.next() {
20
        Some(TokenTree::Punct(ref x)) if x.as_char() == op => (),
21
        _ => panic!("expected {:?} after {}", op, key),
22
    }
23
}
24

25
fn parse_map(mut tokens: IntoIter) -> HashMap<String, TokenTree> {
26
    let mut map = HashMap::new();
27
    while let Some(key) = tokens.next() {
28
        let key = match key {
29
            TokenTree::Ident(ident) => format!("{}", ident),
30
            _ => panic!("expected key got {}", key),
31
        };
32
        parse_op(&mut tokens, ':', &key);
33
        let value = match tokens.next() {
34
            None => panic!("expected value for {}", key),
35
            Some(value) => value,
36
        };
37
        parse_op(&mut tokens, ',', &key);
38
        let _ = map.insert(key, value);
39
    }
40
    map
41
}
42

43
fn get_string(map: &mut HashMap<String, TokenTree>, key: &str) -> String {
44
    let node = match map.remove(key) {
45
        None => return String::new(),
46
        Some(node) => node,
47
    };
48
    match syn::parse::<syn::LitStr>(node.into()) {
49
        Ok(result) => result.value(),
50
        _ => panic!("expected string for {}", key),
51
    }
52
}
53

54
fn get_usize(map: &mut HashMap<String, TokenTree>, key: &str) -> usize {
55
    let node = match map.remove(key) {
56
        None => return 0,
57
        Some(node) => node,
58
    };
59
    let literal = match node {
60
        TokenTree::Literal(literal) => literal,
61
        _ => panic!("expected literal for {}", key),
62
    };
63
    match literal.to_string().parse() {
64
        Ok(result) => result,
65
        Err(error) => panic!("expected usize for {}: {}", key, error),
66
    }
67
}
68

69
fn get_padding(map: &mut HashMap<String, TokenTree>) -> Option<char> {
70
    let node = map.remove("padding")?;
71
    if let Ok(result) = syn::parse::<syn::LitChar>(node.clone().into()) {
72
        return Some(result.value());
73
    }
74
    match syn::parse::<syn::Ident>(node.into()) {
75
        Ok(ref result) if result == "None" => None,
76
        _ => panic!("expected None or char for padding"),
77
    }
78
}
79

80
fn get_bool(map: &mut HashMap<String, TokenTree>, key: &str) -> Option<bool> {
81
    let node = map.remove(key)?;
82
    match syn::parse::<syn::LitBool>(node.into()) {
83
        Ok(result) => Some(result.value),
84
        _ => panic!("expected bool for {}", key),
85
    }
86
}
87

88
fn get_bit_order(map: &mut HashMap<String, TokenTree>) -> BitOrder {
89
    let node = match map.remove("bit_order") {
90
        None => return BitOrder::MostSignificantFirst,
91
        Some(node) => node,
92
    };
93
    let msb = "MostSignificantFirst";
94
    let lsb = "LeastSignificantFirst";
95
    match node {
96
        TokenTree::Ident(ref ident) if format!("{}", ident) == msb => {
97
            BitOrder::MostSignificantFirst
98
        }
99
        TokenTree::Ident(ref ident) if format!("{}", ident) == lsb => {
100
            BitOrder::LeastSignificantFirst
101
        }
102
        _ => panic!("expected {} or {} for bit_order", msb, lsb),
103
    }
104
}
105

106
fn check_present<T>(hash_map: &HashMap<String, T>, key: &str) {
×
107
    assert!(hash_map.contains_key(key), "{} is required", key);
×
108
}
109

110
fn get_encoding(hash_map: &mut HashMap<String, TokenTree>) -> Encoding {
111
    check_present(hash_map, "symbols");
112
    let spec = Specification {
113
        symbols: get_string(hash_map, "symbols"),
114
        bit_order: get_bit_order(hash_map),
115
        check_trailing_bits: get_bool(hash_map, "check_trailing_bits").unwrap_or(true),
116
        padding: get_padding(hash_map),
117
        ignore: get_string(hash_map, "ignore"),
118
        wrap: Wrap {
119
            width: get_usize(hash_map, "wrap_width"),
120
            separator: get_string(hash_map, "wrap_separator"),
121
        },
122
        translate: Translate {
123
            from: get_string(hash_map, "translate_from"),
124
            to: get_string(hash_map, "translate_to"),
125
        },
126
    };
127
    spec.encoding().unwrap()
128
}
129

130
fn check_empty<T>(hash_map: HashMap<String, T>) {
×
131
    assert!(hash_map.is_empty(), "Unexpected keys {:?}", hash_map.keys());
×
132
}
133

134
#[proc_macro]
135
#[doc(hidden)]
136
pub fn internal_new_encoding(input: TokenStream) -> TokenStream {
137
    let mut hash_map = parse_map(input.into_iter());
138
    let encoding = get_encoding(&mut hash_map);
139
    check_empty(hash_map);
140
    format!("{:?}", encoding.internal_implementation()).parse().unwrap()
141
}
142

143
#[proc_macro]
144
#[doc(hidden)]
145
pub fn internal_decode_array(input: TokenStream) -> TokenStream {
146
    let mut hash_map = parse_map(input.into_iter());
147
    let encoding = get_encoding(&mut hash_map);
148
    check_present(&hash_map, "name");
149
    let name = get_string(&mut hash_map, "name");
150
    check_present(&hash_map, "input");
151
    let input = get_string(&mut hash_map, "input");
152
    check_empty(hash_map);
153
    let output = encoding.decode(input.as_bytes()).unwrap();
154
    format!("{}: [u8; {}] = {:?};", name, output.len(), output).parse().unwrap()
155
}
156

157
#[proc_macro]
158
#[doc(hidden)]
159
pub fn internal_decode_slice(input: TokenStream) -> TokenStream {
160
    let mut hash_map = parse_map(input.into_iter());
161
    let encoding = get_encoding(&mut hash_map);
162
    check_present(&hash_map, "input");
163
    let input = get_string(&mut hash_map, "input");
164
    check_empty(hash_map);
165
    format!("{:?}", encoding.decode(input.as_bytes()).unwrap()).parse().unwrap()
166
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc