abi_stable_derive/
concat_and_ranges.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
use syn::{
    parse::{Parse, ParseStream},
    punctuated::Punctuated,
    Error, Ident, Token,
};

use proc_macro2::TokenStream as TokenStream2;

use quote::quote;

///////////////////////////////////////////////////////////////////////////////

#[derive(Debug, Clone)]
struct StringAndVariable {
    variable: Ident,
    string: String,
}

#[derive(Debug, Clone)]
struct ConcatenatedStrings {
    concatenated: Ident,
    strings: Punctuated<StringAndVariable, Token![,]>,
}

impl Parse for StringAndVariable {
    fn parse(input: ParseStream) -> Result<Self, Error> {
        let variable = input.parse()?;
        let _: Token![=] = input.parse()?;
        let string = input.parse::<syn::LitStr>()?.value();

        Ok(Self { variable, string })
    }
}

impl Parse for ConcatenatedStrings {
    fn parse(input: ParseStream) -> Result<Self, Error> {
        let concatenated = input.parse::<Ident>()?;

        let paren_tokens;
        let _ = syn::parenthesized!(paren_tokens in input);

        let strings = paren_tokens.parse_terminated(Parse::parse)?;

        Ok(Self {
            concatenated,
            strings,
        })
    }
}

pub fn macro_impl(input: TokenStream2) -> Result<TokenStream2, syn::Error> {
    let ConcatenatedStrings {
        concatenated: conc_ident,
        strings,
    } = syn::parse2::<ConcatenatedStrings>(input)?;

    let capacity = strings.iter().map(|sav| sav.string.len() + 1).sum();

    let mut concatenated = String::with_capacity(capacity);
    let mut starts = Vec::<u16>::with_capacity(strings.len());
    let mut lengths = Vec::<u16>::with_capacity(strings.len());

    for sav in &strings {
        let start = concatenated.len() as u16;
        starts.push(start);
        concatenated.push_str(&sav.string);
        lengths.push(concatenated.len() as u16 - start);
        concatenated.push(';');
    }

    let concat_len = concatenated.len();
    let variable = strings.iter().map(|x| &x.variable);

    Ok(quote!(
        use abi_stable::{
            std_types::RStr,
            type_layout::StartLen,
        };
        pub const #conc_ident:RStr<'static>=unsafe{
            RStr::from_raw_parts( #concatenated.as_ptr() ,#concat_len )
        };

        #(
            pub const #variable:StartLen= StartLen::new(#starts,#lengths);
        )*
    ))
}