typeslice_macros/
lib.rs

1use proc_macro2::TokenStream;
2use quote::{quote, ToTokens};
3use syn::{parse_macro_input, LitByte, LitByteStr, LitChar, LitStr};
4
5#[proc_macro]
6pub fn from_str(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
7    let item = parse_macro_input!(item as Option<LitStr>);
8    expand_chars(item)
9        .unwrap_or_else(syn::Error::into_compile_error)
10        .into()
11}
12
13#[proc_macro]
14pub fn from_bytes(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
15    let item = parse_macro_input!(item as Option<LitByteStr>);
16    expand_bytes(item)
17        .unwrap_or_else(syn::Error::into_compile_error)
18        .into()
19}
20
21#[proc_macro]
22pub fn utf8(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
23    let item = parse_macro_input!(item as Option<LitStr>);
24    expand_utf8(item)
25        .unwrap_or_else(syn::Error::into_compile_error)
26        .into()
27}
28
29enum Chars {
30    Cons(LitChar, Box<Self>),
31    Nil,
32}
33
34impl ToTokens for Chars {
35    fn to_tokens(&self, tokens: &mut TokenStream) {
36        tokens.extend(match self {
37            Chars::Cons(c, rest) => quote!(::typeslice::types::Char<#c, #rest>),
38            Chars::Nil => quote!(::typeslice::types::CharNil),
39        })
40    }
41}
42
43fn expand_chars(lit: Option<LitStr>) -> syn::Result<TokenStream> {
44    let root = match lit {
45        Some(it) => it.value().chars().rev().fold(Chars::Nil, |acc, el| {
46            Chars::Cons(LitChar::new(el, it.span()), Box::new(acc))
47        }),
48        None => Chars::Nil,
49    };
50    Ok(root.into_token_stream())
51}
52
53fn expand_utf8(lit: Option<LitStr>) -> syn::Result<TokenStream> {
54    let root = match lit {
55        Some(it) => it.value().bytes().rev().fold(Bytes::Nil, |acc, el| {
56            Bytes::Cons(LitByte::new(el, it.span()), Box::new(acc))
57        }),
58        None => Bytes::Nil,
59    };
60    Ok(root.into_token_stream())
61}
62
63enum Bytes {
64    Cons(LitByte, Box<Self>),
65    Nil,
66}
67
68impl ToTokens for Bytes {
69    fn to_tokens(&self, tokens: &mut TokenStream) {
70        tokens.extend(match self {
71            Bytes::Cons(b, rest) => quote!(::typeslice::types::U8<#b, #rest>),
72            Bytes::Nil => quote!(::typeslice::types::U8Nil),
73        })
74    }
75}
76
77fn expand_bytes(lit: Option<LitByteStr>) -> syn::Result<TokenStream> {
78    let root = match lit {
79        Some(it) => it.value().into_iter().rev().fold(Bytes::Nil, |acc, el| {
80            Bytes::Cons(LitByte::new(el, it.span()), Box::new(acc))
81        }),
82        None => Bytes::Nil,
83    };
84    Ok(root.into_token_stream())
85}