byte_strings_proc_macros/
mod.rs

1//! Crate not intended for direct use.
2//! Use https:://docs.rs/byte-strings instead.
3// Templated by `cargo-generate` using https://github.com/danielhenrymantilla/proc-macro-template
4#![allow(nonstandard_style, unused_imports)]
5
6use ::core::{
7    mem,
8    ops::Not as _,
9};
10use ::proc_macro::{
11    TokenStream,
12};
13use ::proc_macro2::{
14    Span,
15    TokenStream as TokenStream2,
16    TokenTree as TT,
17};
18use ::quote::{
19    format_ident,
20    quote,
21    quote_spanned,
22    ToTokens,
23};
24use ::syn::{*,
25    parse::{Parse, Parser, ParseStream},
26    punctuated::Punctuated,
27    Result, // Explicitly shadow it
28    spanned::Spanned,
29};
30
31use input_bytes::Input;
32mod input_bytes;
33
34#[proc_macro] pub
35fn concat_bytes (
36    input: TokenStream,
37) -> TokenStream
38{
39    concat_bytes_impl(input.into())
40    //  .map(|ret| { println!("{}", ret); ret })
41        .unwrap_or_else(|err| {
42            let mut errors =
43                err .into_iter()
44                    .map(|err| Error::new(
45                        err.span(),
46                        format_args!("`#[byte_strings::concat_bytes]`: {}", err),
47                    ))
48            ;
49            let mut err = errors.next().unwrap();
50            errors.for_each(|cur| err.combine(cur));
51            err.to_compile_error()
52        })
53        .into()
54}
55
56fn concat_bytes_impl (
57    input: TokenStream2,
58) -> Result<TokenStream2>
59{
60    let Input(_, ref mut bytes) = parse2(input)?;
61    let byte_string_literal = LitByteStr::new(bytes, Span::call_site());
62    Ok(byte_string_literal.into_token_stream())
63}
64
65#[proc_macro] pub
66fn c_str (
67    input: TokenStream,
68) -> TokenStream
69{
70    c_str_impl(input.into())
71    //  .map(|ret| { println!("{}", ret); ret })
72        .unwrap_or_else(|err| {
73            let mut errors =
74                err .into_iter()
75                    .map(|err| Error::new(
76                        err.span(),
77                        format_args!("`#[byte_strings::c_str]`: {}", err),
78                    ))
79            ;
80            let mut err = errors.next().unwrap();
81            errors.for_each(|cur| err.combine(cur));
82            err.to_compile_error()
83        })
84        .into()
85}
86
87fn c_str_impl (
88    input: TokenStream2,
89) -> Result<TokenStream2>
90{
91    let Input(ref crate_, ref mut bytes) = parse2(input)?;
92    match bytes.iter().position(|&b| b == b'\0') {
93        | Some(i) if i < bytes.len() - 1 => {
94            // Not the last byte: error!
95            return Err(Error::new(
96                Span::call_site(),
97                format!("Inner null byte at index {}", i),
98            ));
99        },
100        | None => {
101            // No terminating null byte: add it!
102            bytes.reserve_exact(1);
103            bytes.push(b'\0');
104        },
105        | Some(_last_byte) => {
106            // Terminating null byte already present: nothing to do.
107        },
108    }
109    let byte_string_literal = LitByteStr::new(bytes, Span::call_site());
110    Ok(quote!(
111        {
112            #[allow(unused_unsafe)] {
113                unsafe {
114                    #crate_::__::core::ffi::CStr::from_bytes_with_nul_unchecked(
115                        #byte_string_literal
116                    )
117                }
118            }
119        }
120    ))
121}