Skip to main content

slices_hack/
lib.rs

1// Copyright (C) 2019 Boyu Yang
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! This is a internal crate used by [slices].
10//!
11//! **Notice:
12//! You should NOT use this crate directly.
13//! Please use [slices] instead of this crate.**
14//!
15//! [slices]: https://docs.rs/slices
16
17extern crate proc_macro;
18
19use proc_macro_hack::proc_macro_hack;
20use quote::quote;
21use syn::parse_macro_input;
22
23struct Bytes(Vec<u8>);
24
25impl ::std::fmt::Debug for Bytes {
26    #[inline]
27    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
28        let data = &self.0;
29        write!(f, "&[")?;
30        if data.len() != 0 {
31            write!(f, "{:#04x}u8", data[0])?;
32            for unit in data.iter().skip(1) {
33                write!(f, ", {:#04x}", unit)?;
34            }
35        }
36        write!(f, "]")
37    }
38}
39
40#[proc_macro_hack]
41pub fn u8_slice(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
42    let input = parse_macro_input!(input as syn::LitStr);
43    let expanded = {
44        let input = input.value().replace("_", "");
45        if input.len() < 2 || &input[..2] != "0x" || input.len() % 2 != 0 {
46            panic!("Input has to be a hexadecimal string with 0x-prefix.");
47        };
48        let input_str = &input[2..];
49        let buffer_len = input_str.len() / 2;
50        let buffer = if buffer_len != 0 {
51            let mut buffer = vec![0u8; buffer_len];
52            faster_hex::hex_decode(input_str.as_bytes(), &mut buffer).unwrap_or_else(|err| {
53                panic!("Failed to parse the input hexadecimal string: {}", err);
54            });
55            buffer
56        } else {
57            vec![]
58        };
59        let bytes = Bytes(buffer);
60        let eval_str = format!("{:?}", bytes);
61        let eval_ts: proc_macro2::TokenStream = eval_str.parse().unwrap_or_else(|_| {
62            panic!(
63                "Failed to parse the string \"{}\" to TokenStream.",
64                eval_str
65            );
66        });
67        quote!(#eval_ts)
68    };
69    expanded.into()
70}