hpl-toolkit-derive-to-schema 0.0.6

HPL attribute derive for defining a schema
Documentation
use quote::quote;

pub fn type_to_ident(ident: &String, ty: &syn::Type) -> Result<proc_macro2::TokenStream, String> {
    match ty {
        // A fixed size array type: `[T; n]`.
        syn::Type::Array(ty) => type_to_ident(ident, ty.elem.as_ref()),

        // A bare function type: `fn(usize) -> bool`.
        syn::Type::BareFn(_ty) => Err(format!("Unhandled type ImplTrait for {}", ident)),

        // A type contained within invisible delimiters.
        syn::Type::Group(ty) => type_to_ident(ident, ty.elem.as_ref()),

        // An `impl Bound1 + Bound2 + Bound3` type where `Bound` is a trait or
        // a lifetime.
        syn::Type::ImplTrait(_ty) => Err(format!("Unhandled type ImplTrait for {}", ident)),

        // Indication that a type should be inferred by the compiler: `_`.
        syn::Type::Infer(_ty) => Err(format!("Unhandled type Infer for {}", ident)),

        // A macro in the type position.
        syn::Type::Macro(_ty) => Err(format!("Unhandled type Macro for {}", ident)),

        // The never type: `!`.
        syn::Type::Never(_ty) => Err(format!("Unhandled type Never for {}", ident)),

        // A parenthesized type equivalent to the inner type.
        syn::Type::Paren(ty) => type_to_ident(ident, ty.elem.as_ref()),

        // A path like `std::slice::Iter`, optionally qualified with a
        // self-type as in `<Vec<T> as SomeTrait>::Associated`.
        syn::Type::Path(ty) => {
            let ident = ty.path.segments[0].ident.to_owned();
            let stream = ty.path.segments[0].arguments.to_owned();
            if let syn::PathArguments::None = stream {
                return Ok(quote!(#ident));
            }
            Ok(quote!(#ident ::#stream))
        }

        // A raw pointer type: `*const T` or `*mut T`.
        syn::Type::Ptr(_ty) => Err(format!("Unhandled type Ptr for {}", ident)),

        // A reference type: `&'a T` or `&'a mut T`.
        syn::Type::Reference(_ty) => Err(format!("Unhandled type Reference for {}", ident)),

        // A dynamically sized slice type: `[T]`.
        syn::Type::Slice(_ty) => Err(format!("Unhandled type Slice for {}", ident)),

        // A trait object type `dyn Bound1 + Bound2 + Bound3` where `Bound` is a
        // trait or a lifetime.
        syn::Type::TraitObject(_ty) => Err(format!("Unhandled type TraitObject for {}", ident)),

        // A tuple type: `(A, B, C, String)`.
        syn::Type::Tuple(_ty) => Err(format!("Unhandled type Tuple for {}", ident)),

        // Tokens in type position not interpreted by Syn.
        syn::Type::Verbatim(_ty) => Err(format!("Unhandled type Verbatim for {}", ident)),

        _ => Err(format!("Unknown Type for {}", ident)),
    }
}

pub fn type_to_ident_unnamed(
    index: usize,
    ty: &syn::Type,
) -> Result<proc_macro2::TokenStream, String> {
    match ty {
        // A fixed size array type: `[T; n]`.
        syn::Type::Array(ty) => type_to_ident_unnamed(index, ty.elem.as_ref()),

        // A bare function type: `fn(usize) -> bool`.
        syn::Type::BareFn(_ty) => Err(format!("Unhandled type ImplTrait for {}", index)),

        // A type contained within invisible delimiters.
        syn::Type::Group(ty) => type_to_ident_unnamed(index, ty.elem.as_ref()),

        // An `impl Bound1 + Bound2 + Bound3` type where `Bound` is a trait or
        // a lifetime.
        syn::Type::ImplTrait(_ty) => Err(format!("Unhandled type ImplTrait for {}", index)),

        // Indication that a type should be inferred by the compiler: `_`.
        syn::Type::Infer(_ty) => Err(format!("Unhandled type Infer for {}", index)),

        // A macro in the type position.
        syn::Type::Macro(_ty) => Err(format!("Unhandled type Macro for {}", index)),

        // The never type: `!`.
        syn::Type::Never(_ty) => Err(format!("Unhandled type Never for {}", index)),

        // A parenthesized type equivalent to the inner type.
        syn::Type::Paren(ty) => type_to_ident_unnamed(index, ty.elem.as_ref()),

        // A path like `std::slice::Iter`, optionally qualified with a
        // self-type as in `<Vec<T> as SomeTrait>::Associated`.
        syn::Type::Path(ty) => {
            let ident = ty.path.segments[0].ident.to_owned();
            let stream = ty.path.segments[0].arguments.to_owned();
            if let syn::PathArguments::None = stream {
                return Ok(quote!(#ident));
            }
            Ok(quote!(#ident ::#stream))
        }

        // A raw pointer type: `*const T` or `*mut T`.
        syn::Type::Ptr(_ty) => Err(format!("Unhandled type Ptr for {}", index)),

        // A reference type: `&'a T` or `&'a mut T`.
        syn::Type::Reference(_ty) => Err(format!("Unhandled type Reference for {}", index)),

        // A dynamically sized slice type: `[T]`.
        syn::Type::Slice(_ty) => Err(format!("Unhandled type Slice for {}", index)),

        // A trait object type `dyn Bound1 + Bound2 + Bound3` where `Bound` is a
        // trait or a lifetime.
        syn::Type::TraitObject(_ty) => Err(format!("Unhandled type TraitObject for {}", index)),

        // A tuple type: `(A, B, C, String)`.
        syn::Type::Tuple(_ty) => Err(format!("Unhandled type Tuple for {}", index)),

        // Tokens in type position not interpreted by Syn.
        syn::Type::Verbatim(_ty) => Err(format!("Unhandled type Verbatim for {}", index)),

        _ => Err(format!("Unknown Type for {}", index)),
    }
}