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}