asn1_rs_impl/
lib.rs

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    // "fn answer() -> u32 { 42 }".parse().unwrap()
38    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
55// encode int as base128
56fn 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    // let token_stream = input.to_string();
83    // let items: Result<Vec<_>, _> = token_stream
84    //     .split('.')
85    //     .map(|x| x.trim().parse::<u64>())
86    //     .collect();
87    // let err = Error::new(Span::call_site().into(), "invalid OID");
88    // if let Ok(items) = items {
89    //     let mut v = Vec::new();
90    //     if items.len() < 2 || items[0] > 2 || items[1] > 39 {
91    //         return err.to_compile_error().into();
92    //     }
93    //     let first_byte = (items[0] * 40 + items[1]) as u8;
94    //     v.push(first_byte);
95    //     for &int in &items[2..] {
96    //         let enc = encode_base128(int);
97    //         v.extend_from_slice(&enc);
98    //     }
99    //     // "fn answer() -> u32 { 42 }".parse().unwrap()
100    //     let mut s = String::with_capacity(2 + 6 * v.len());
101    //     s.push('[');
102    //     for byte in v.iter() {
103    //         s.insert_str(s.len(), &format!("0x{:02x}, ", byte));
104    //     }
105    //     s.push(']');
106    //     s.parse().unwrap()
107    // } else {
108    //     eprintln!("could not parse OID '{}'", token_stream);
109    //     err.to_compile_error().into()
110    // }
111}
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}