1extern crate proc_macro;
2use proc_macro::{Span, TokenStream};
3use syn::{parse_macro_input, Error, LitInt};
4
5#[proc_macro]
6pub fn encode_oid(input: TokenStream) -> TokenStream {
7 let token_stream = input.to_string();
8 let (s, relative) = if token_stream.starts_with("rel ") {
9 (&token_stream[4..], true)
10 } else {
11 (token_stream.as_ref(), false)
12 };
13 let items: Result<Vec<_>, _> = s.split('.').map(|x| x.trim().parse::<u128>()).collect();
14 let mut items: &[_] = match items.as_ref() {
15 Ok(v) => v.as_ref(),
16 Err(_) => return create_error("Could not parse OID"),
17 };
18 let mut v = Vec::new();
19 if !relative {
20 if items.len() < 2 {
21 if items.len() == 1 && items[0] == 0 {
22 return "[0]".parse().unwrap();
23 }
24 return create_error("Need at least two components for non-relative oid");
25 }
26 if items[0] > 2 || items[1] > 39 {
27 return create_error("First components are too big");
28 }
29 let first_byte = (items[0] * 40 + items[1]) as u8;
30 v.push(first_byte);
31 items = &items[2..];
32 }
33 for &int in items {
34 let enc = encode_base128(int);
35 v.extend_from_slice(&enc);
36 }
37 let mut s = String::with_capacity(2 + 6 * v.len());
39 s.push('[');
40 for byte in v.iter() {
41 s.insert_str(s.len(), &format!("0x{:02x}, ", byte));
42 }
43 s.push(']');
44 s.parse().unwrap()
45}
46
47#[inline]
48fn create_error(msg: &str) -> TokenStream {
49 let s = format!("Invalid OID({})", msg);
50 Error::new(Span::call_site().into(), &s)
51 .to_compile_error()
52 .into()
53}
54
55fn encode_base128(int: u128) -> Vec<u8> {
57 let mut val = int;
58 let mut base128 = Vec::new();
59 let lo = val & 0x7f;
60 base128.push(lo as u8);
61 val >>= 7;
62 loop {
63 if val == 0 {
64 base128.reverse();
65 return base128;
66 }
67 let lo = val & 0x7f;
68 base128.push(lo as u8 | 0x80);
69 val >>= 7;
70 }
71}
72
73#[proc_macro]
74pub fn encode_int(input: TokenStream) -> TokenStream {
75 let lit = parse_macro_input!(input as LitInt);
76
77 match impl_encode_int(lit) {
78 Ok(ts) => ts,
79 Err(e) => e.to_compile_error().into(),
80 }
81
82 }
112
113fn impl_encode_int(lit: LitInt) -> Result<TokenStream, Error> {
114 let value = lit.base10_parse::<u64>()?;
115
116 let bytes = value.to_be_bytes();
117 let v: Vec<_> = bytes.iter().skip_while(|&c| *c == 0).collect();
118
119 let mut s = String::with_capacity(2 + 6 * v.len());
120 s.push('[');
121 for byte in v.iter() {
122 s.insert_str(s.len(), &format!("0x{:02x}, ", byte));
123 }
124 s.push(']');
125 Ok(s.parse().unwrap())
126}