data_encoding_macro_internal/
lib.rs1#![warn(unused_results)]
11
12use std::collections::HashMap;
13
14use data_encoding::{BitOrder, Encoding, Specification, Translate, Wrap};
15use proc_macro::token_stream::IntoIter;
16use proc_macro::{TokenStream, TokenTree};
17
18fn 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
25fn 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
43fn 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
54fn 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
69fn 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
80fn 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
88fn 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
106fn check_present<T>(hash_map: &HashMap<String, T>, key: &str) {
107 assert!(hash_map.contains_key(key), "{} is required", key);
108}
109
110fn 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
130fn 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)]
136pub 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)]
145pub 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)]
159pub 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}