abi_stable_derive/
concat_and_ranges.rs

1use syn::{
2    parse::{Parse, ParseStream},
3    punctuated::Punctuated,
4    Error, Ident, Token,
5};
6
7use proc_macro2::TokenStream as TokenStream2;
8
9use quote::quote;
10
11///////////////////////////////////////////////////////////////////////////////
12
13#[derive(Debug, Clone)]
14struct StringAndVariable {
15    variable: Ident,
16    string: String,
17}
18
19#[derive(Debug, Clone)]
20struct ConcatenatedStrings {
21    concatenated: Ident,
22    strings: Punctuated<StringAndVariable, Token![,]>,
23}
24
25impl Parse for StringAndVariable {
26    fn parse(input: ParseStream) -> Result<Self, Error> {
27        let variable = input.parse()?;
28        let _: Token![=] = input.parse()?;
29        let string = input.parse::<syn::LitStr>()?.value();
30
31        Ok(Self { variable, string })
32    }
33}
34
35impl Parse for ConcatenatedStrings {
36    fn parse(input: ParseStream) -> Result<Self, Error> {
37        let concatenated = input.parse::<Ident>()?;
38
39        let paren_tokens;
40        let _ = syn::parenthesized!(paren_tokens in input);
41
42        let strings = paren_tokens.parse_terminated(Parse::parse)?;
43
44        Ok(Self {
45            concatenated,
46            strings,
47        })
48    }
49}
50
51pub fn macro_impl(input: TokenStream2) -> Result<TokenStream2, syn::Error> {
52    let ConcatenatedStrings {
53        concatenated: conc_ident,
54        strings,
55    } = syn::parse2::<ConcatenatedStrings>(input)?;
56
57    let capacity = strings.iter().map(|sav| sav.string.len() + 1).sum();
58
59    let mut concatenated = String::with_capacity(capacity);
60    let mut starts = Vec::<u16>::with_capacity(strings.len());
61    let mut lengths = Vec::<u16>::with_capacity(strings.len());
62
63    for sav in &strings {
64        let start = concatenated.len() as u16;
65        starts.push(start);
66        concatenated.push_str(&sav.string);
67        lengths.push(concatenated.len() as u16 - start);
68        concatenated.push(';');
69    }
70
71    let concat_len = concatenated.len();
72    let variable = strings.iter().map(|x| &x.variable);
73
74    Ok(quote!(
75        use abi_stable::{
76            std_types::RStr,
77            type_layout::StartLen,
78        };
79        pub const #conc_ident:RStr<'static>=unsafe{
80            RStr::from_raw_parts( #concatenated.as_ptr() ,#concat_len )
81        };
82
83        #(
84            pub const #variable:StartLen= StartLen::new(#starts,#lengths);
85        )*
86    ))
87}