spatialos-codegen 0.2.1

Codegen tool used with spatialos-macro and spatialos-sdk
Documentation
use quote::__private::TokenStream;

use crate::ast::{Component, Enum, Member, Type, Variant};

impl Generator for Component {
    fn generate_one(&self) -> TokenStream {
        let enums = <Enum as Generator>::generate_multiple(&self.enums);
        let types = <Type as Generator>::generate_multiple(&self.types);
        let members = <Member as Generator>::generate_multiple(&self.members);
        let comments = &self.comments;
        let id = &self.id;
        let name = format_ident!("{}", &self.name);
        quote! {
            #enums

            #types

            #[allow(dead_code)]
            #(#[doc = #comments])*
            #[derive(SpatialComponent)]
            #[id(#id)]
            pub struct #name {
                #members
            }
        }
    }

    fn generate_multiple(data: &[Self]) -> TokenStream {
        let ones: Vec<_> = data.iter().map(Self::generate_one).collect();
        quote! {
            #(#ones)*
        }
    }
}

impl Generator for Enum {
    fn generate_one(&self) -> TokenStream {
        let comments = &self.comments;
        let name = format_ident!("{}", &self.name);
        let variants = <Variant as Generator>::generate_multiple(&self.variants);
        quote! {
            #(#[doc = #comments])*
            #[derive(SpatialEnum)]
            pub enum #name {
                #variants
            }

        }
    }

    fn generate_multiple(data: &[Self]) -> TokenStream {
        let ones: Vec<_> = data.iter().map(Self::generate_one).collect();
        quote! {
            #(#ones)*
        }
    }
}

impl Generator for Member {
    fn generate_one(&self) -> TokenStream {
        let docs = &self.comments;
        let id = self.id;
        let spatial_type = self.m_type.spatial_type();
        let rust_type =
            syn::parse_str::<syn::Type>(&self.m_type.rust_type()).expect("Can't parse type");
        let name = format_ident!("{}", &self.name);
        quote! {
            #(#[doc = #docs])*
            #[field_id(#id)]
            #[spatial_type(#spatial_type)]
            #name: #rust_type
        }
    }
}

pub(crate) trait Generator: Sized {
    fn generate_one(&self) -> TokenStream;
    fn generate_multiple(data: &[Self]) -> TokenStream {
        let ones: Vec<_> = data.iter().map(Self::generate_one).collect();
        quote! {
            #(#ones),*
        }
    }
}

impl Generator for Type {
    fn generate_one(&self) -> TokenStream {
        let enums = <Enum as Generator>::generate_multiple(&self.enums);
        let types = <Type as Generator>::generate_multiple(&self.types);
        let members = <Member as Generator>::generate_multiple(&self.members);
        let comments = &self.comments;
        let name = format_ident!("{}", &self.name);
        quote! {
            #enums

            #types

            #[allow(dead_code)]
            #(#[doc = #comments])*
            #[derive(SpatialType)]
            pub struct #name {
                #members
            }

        }
    }

    fn generate_multiple(data: &[Self]) -> TokenStream {
        let ones: Vec<_> = data.iter().map(Self::generate_one).collect();
        quote! {
            #(#ones)*
        }
    }
}

fn capitalize(s: &str) -> String {
    let mut chars = s.chars();
    format!(
        "{}{}",
        chars.next().unwrap().to_uppercase().collect::<String>(),
        chars.collect::<String>()
    )
}

fn to_upper_camel_case<S: AsRef<str>>(s: S) -> String {
    s.as_ref()
        .to_lowercase()
        .split("_")
        .map(capitalize)
        .fold(String::new(), |acc, val| acc + &val)
}

impl Generator for Variant {
    fn generate_one(&self) -> TokenStream {
        let comments = &self.comments;
        let id = &self.id;
        let name = format_ident!("{}", to_upper_camel_case(&self.name));
        quote! {
            #(#[doc = #comments])*
            #[value(#id)]
            #name
        }
    }
}