typeslice-macros 0.1.2

type-level slices
Documentation
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use syn::{parse_macro_input, LitByte, LitByteStr, LitChar, LitStr};

#[proc_macro]
pub fn from_str(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let item = parse_macro_input!(item as Option<LitStr>);
    expand_chars(item)
        .unwrap_or_else(syn::Error::into_compile_error)
        .into()
}

#[proc_macro]
pub fn from_bytes(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let item = parse_macro_input!(item as Option<LitByteStr>);
    expand_bytes(item)
        .unwrap_or_else(syn::Error::into_compile_error)
        .into()
}

#[proc_macro]
pub fn utf8(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let item = parse_macro_input!(item as Option<LitStr>);
    expand_utf8(item)
        .unwrap_or_else(syn::Error::into_compile_error)
        .into()
}

enum Chars {
    Cons(LitChar, Box<Self>),
    Nil,
}

impl ToTokens for Chars {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        tokens.extend(match self {
            Chars::Cons(c, rest) => quote!(::typeslice::types::Char<#c, #rest>),
            Chars::Nil => quote!(::typeslice::types::CharNil),
        })
    }
}

fn expand_chars(lit: Option<LitStr>) -> syn::Result<TokenStream> {
    let root = match lit {
        Some(it) => it.value().chars().rev().fold(Chars::Nil, |acc, el| {
            Chars::Cons(LitChar::new(el, it.span()), Box::new(acc))
        }),
        None => Chars::Nil,
    };
    Ok(root.into_token_stream())
}

fn expand_utf8(lit: Option<LitStr>) -> syn::Result<TokenStream> {
    let root = match lit {
        Some(it) => it.value().bytes().rev().fold(Bytes::Nil, |acc, el| {
            Bytes::Cons(LitByte::new(el, it.span()), Box::new(acc))
        }),
        None => Bytes::Nil,
    };
    Ok(root.into_token_stream())
}

enum Bytes {
    Cons(LitByte, Box<Self>),
    Nil,
}

impl ToTokens for Bytes {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        tokens.extend(match self {
            Bytes::Cons(b, rest) => quote!(::typeslice::types::U8<#b, #rest>),
            Bytes::Nil => quote!(::typeslice::types::U8Nil),
        })
    }
}

fn expand_bytes(lit: Option<LitByteStr>) -> syn::Result<TokenStream> {
    let root = match lit {
        Some(it) => it.value().into_iter().rev().fold(Bytes::Nil, |acc, el| {
            Bytes::Cons(LitByte::new(el, it.span()), Box::new(acc))
        }),
        None => Bytes::Nil,
    };
    Ok(root.into_token_stream())
}