From 8b02d13daefe0fb5fedf431eaafaf5adbd45e5ac Mon Sep 17 00:00:00 2001 From: Soispha Date: Sun, 24 Mar 2024 21:06:14 +0100 Subject: [PATCH] fix(macros): Generate namespacesed types and convertible impls --- trixy-macros/src/generate/host/mod.rs | 111 ++++++++++---------- trixy-macros/src/generate/mod.rs | 140 ++++++++++++++++++++++++-- 2 files changed, 189 insertions(+), 62 deletions(-) diff --git a/trixy-macros/src/generate/host/mod.rs b/trixy-macros/src/generate/host/mod.rs index b0a182e..548c051 100644 --- a/trixy-macros/src/generate/host/mod.rs +++ b/trixy-macros/src/generate/host/mod.rs @@ -29,16 +29,23 @@ use convert_case::{Case, Casing}; use proc_macro2::TokenStream as TokenStream2; use quote::{format_ident, quote}; use trixy_parser::command_spec::{ - Attribute, CommandSpec, DocIdentifier, DocNamedType, Enumeration, Function, Identifier, - Namespace, Structure, + CommandSpec, Enumeration, Function, Identifier, Namespace, Structure, }; use crate::{ config::TrixyConfig, - generate::{identifier_to_rust, named_type_to_rust}, + generate::{ + attribute_to_rust, + c_api::{mangle_c_type_identifier, type_variant_c_path}, + convertible_derive::{ + rust_enumeration_into_impl, structure_convertable_derive, structure_into_impl, + }, + doc_identifier_to_rust, doc_named_type_to_rust, identifier_to_rust, named_type_to_rust, + type_variant_rust_path, + }, }; -use super::{c_api::type_to_c_equalivalent, function_identifier_to_rust}; +use super::{c_api::type_to_c_equivalent, function_identifier_to_rust}; thread_local! {static DEBUG: OnceCell = OnceCell::new();} @@ -66,13 +73,13 @@ thread_local! {static DEBUG: OnceCell = OnceCell::new();} /// } /// pub mod trinitrix { /// #[allow(non_camel_case_types)] -/// #[derive(Debug, Convertible)] +/// #[derive(Debug)] /// struct Callback { /// func: String, /// timeout: String, /// } /// #[allow(non_camel_case_types)] -/// #[derive(Debug, Convertible)] +/// #[derive(Debug)] /// enum CallbackPriority { /// High, /// Medium, @@ -122,9 +129,6 @@ pub fn generate(trixy: &CommandSpec, config: &TrixyConfig) -> TokenStream2 { let debug = get_debug_sate(); quote! { - #[allow(unused_imports)] - use trixy::types::traits::convert_trait::*; - #structures #enumerations #debug @@ -145,7 +149,7 @@ fn namespace_to_module(namespace: &Namespace, namespaces: &Vec<&Identifier>) -> let doc_comments: TokenStream2 = namespace .attributes .iter() - .map(attribute_to_doc_comment) + .map(|attr| attribute_to_rust(&namespace.name, attr)) .collect(); let structures: TokenStream2 = namespace.structures.iter().map(structure_to_rust).collect(); let enumerations: TokenStream2 = namespace @@ -173,9 +177,6 @@ fn namespace_to_module(namespace: &Namespace, namespaces: &Vec<&Identifier>) -> quote! { #doc_comments pub mod #ident { - #[allow(unused_imports)] - use trixy::types::traits::convert_trait::*; - #structures #enumerations #debug @@ -196,14 +197,6 @@ fn namespace_to_module_enum(namespace: &Namespace) -> TokenStream2 { } } -fn attribute_to_doc_comment(attribute: &Attribute) -> TokenStream2 { - let Attribute::doc(doc_comment) = attribute; - - quote! { - #[doc = #doc_comment] - } -} - fn get_debug_sate() -> TokenStream2 { let debug = DEBUG.with(|d| { d.get() @@ -217,11 +210,11 @@ fn function_to_rust(function: &Function, namespaces: &[&Identifier]) -> TokenStr let doc_comments: TokenStream2 = function .attributes .iter() - .map(attribute_to_doc_comment) + .map(|attr| attribute_to_rust(&function.identifier, attr)) .collect(); let function_ident = function_identifier_to_rust(&function, named_type_to_rust, move |r#type| { - let ident = type_to_c_equalivalent(r#type, namespaces); + let ident = type_to_c_equivalent(r#type); quote! { trixy::oneshot::Sender<#ident> } @@ -238,8 +231,9 @@ fn enumeration_to_rust(enumeration: &Enumeration) -> TokenStream2 { let doc_comments: TokenStream2 = enumeration .attributes .iter() - .map(attribute_to_doc_comment) + .map(|attr| attribute_to_rust(&enumeration.identifier, attr)) .collect(); + let ident = identifier_to_rust(&enumeration.identifier); let states: Vec = enumeration .states @@ -249,15 +243,31 @@ fn enumeration_to_rust(enumeration: &Enumeration) -> TokenStream2 { let debug = get_debug_sate(); + let paired_type = { + let path = type_variant_c_path(&enumeration.identifier.variant); + + let ident = mangle_c_type_identifier(&enumeration.identifier); + if path.is_empty() { + quote! { + crate :: #ident + } + } else { + quote! { + #path :: #ident + } + } + }; + + let convertible = rust_enumeration_into_impl(&enumeration, &paired_type); + quote! { #doc_comments #[allow(non_camel_case_types)] #debug - #[repr(C)] - #[derive(Convertible)] pub enum #ident { #(#states),* } + #convertible } } @@ -265,14 +275,30 @@ fn structure_to_rust(structure: &Structure) -> TokenStream2 { let doc_comments: TokenStream2 = structure .attributes .iter() - .map(attribute_to_doc_comment) + .map(|attr| attribute_to_rust(&structure.identifier, attr)) .collect(); + let ident = identifier_to_rust(&structure.identifier); + let c_ident = { + let path = type_variant_c_path(&structure.identifier.variant); + let ident = mangle_c_type_identifier(&structure.identifier); + if path.is_empty() { + quote! { + crate :: #ident + } + } else { + quote! { + #path :: #ident + } + } + }; let contents: Vec = structure .contents .iter() .map(doc_named_type_to_rust) .collect(); + let convertible = structure_convertable_derive(&structure, &c_ident); + let into_impl = structure_into_impl(&structure, &c_ident); let debug = get_debug_sate(); @@ -280,37 +306,10 @@ fn structure_to_rust(structure: &Structure) -> TokenStream2 { #doc_comments #[allow(non_camel_case_types)] #debug - #[repr(C)] - #[derive(Convertible)] pub struct #ident { #(#contents),* } - } -} - -fn doc_identifier_to_rust(doc_identifier: &DocIdentifier) -> TokenStream2 { - let doc_comments: TokenStream2 = doc_identifier - .attributes - .iter() - .map(attribute_to_doc_comment) - .collect(); - let identifier = identifier_to_rust(&doc_identifier.into()); - - quote! { - #doc_comments - #identifier - } -} - -fn doc_named_type_to_rust(doc_named_type: &DocNamedType) -> TokenStream2 { - let doc_comments: TokenStream2 = doc_named_type - .attributes - .iter() - .map(attribute_to_doc_comment) - .collect(); - let named_type = named_type_to_rust(&doc_named_type.into()); - quote! { - #doc_comments - #named_type + #convertible + #into_impl } } diff --git a/trixy-macros/src/generate/mod.rs b/trixy-macros/src/generate/mod.rs index 0db6789..2b429f6 100644 --- a/trixy-macros/src/generate/mod.rs +++ b/trixy-macros/src/generate/mod.rs @@ -19,13 +19,19 @@ * If not, see . */ +use std::ops::Deref; + use proc_macro2::TokenStream as TokenStream2; use quote::{format_ident, quote}; -use trixy_parser::command_spec::{CommandSpec, Function, Identifier, NamedType, Type}; +use trixy_parser::command_spec::{ + Attribute, CommandSpec, DocIdentifier, DocNamedType, Function, Identifier, NamedType, Type, + Variant, +}; use crate::config::TrixyConfig; pub mod c_api; +pub mod convertible_derive; pub mod host; pub fn generate(trixy: &CommandSpec, config: &TrixyConfig) -> TokenStream2 { @@ -97,20 +103,142 @@ fn named_type_to_rust(named_type: &NamedType) -> TokenStream2 { } fn type_to_rust(r#type: &Type) -> TokenStream2 { let ident = identifier_to_rust(&r#type.identifier); - if r#type.generic_args.is_empty() { - if r#type.identifier.name == "str" { + let namespaces_path = type_variant_rust_path(&r#type.identifier.variant); + + let nasp_path = if let Some(nasp_path) = type_variant_rust_path(&r#type.identifier.variant) { + if nasp_path.is_empty() { quote! { - &str + crate :: } } else { + let path = namespaces_path; quote! { - #ident + #path :: } } + } else { + quote! {} + }; + + if r#type.generic_args.is_empty() { + quote! { + #nasp_path #ident + } } else { let generics: Vec = r#type.generic_args.iter().map(type_to_rust).collect(); quote! { - #ident <#(#generics),*> + #nasp_path #ident <#(#generics),*> } } } +fn doc_identifier_to_rust(doc_identifier: &DocIdentifier) -> TokenStream2 { + let doc_comments: TokenStream2 = doc_identifier + .attributes + .iter() + .map(|attr| attribute_to_rust(&doc_identifier.into(), attr)) + .collect(); + let identifier = identifier_to_rust(&doc_identifier.into()); + + quote! { + #doc_comments + #identifier + } +} + +fn doc_named_type_to_rust(doc_named_type: &DocNamedType) -> TokenStream2 { + let doc_comments: TokenStream2 = doc_named_type + .attributes + .iter() + .map(|attr| attribute_to_rust(&&doc_named_type.name, attr)) + .collect(); + let named_type = named_type_to_rust(&doc_named_type.into()); + quote! { + #doc_comments + pub #named_type + } +} +fn attribute_to_rust(_target: &Identifier, attribute: &Attribute) -> TokenStream2 { + match attribute { + Attribute::doc(comment) => quote! { + #[doc = #comment] + }, + Attribute::error => quote! { + // We simply use thiserror here + #[derive(trixy::__private::thiserror::Error)] + }, + Attribute::msg(msg) => quote! { + #[error(#msg)] + }, + Attribute::derive(_) => unimplemented!("Derive is not used as of now"), + } +} +pub fn type_variant_rust_path(variant: &Variant) -> Option { + fn namespace_to_borrowed(vec: &Vec) -> Vec<&Identifier> { + let vec_2: Vec<&Identifier> = vec.iter().collect(); + vec_2 + } + + let main_namespace; + match variant { + Variant::Structure { namespace } => { + main_namespace = namespace_to_borrowed(namespace); + } + Variant::Enumeration { namespace } => { + main_namespace = namespace_to_borrowed(namespace); + } + _ => return None, + } + Some(namespaces_to_path(&main_namespace[..])) +} +fn namespaces_to_path>(namespaces: &[T]) -> TokenStream2 { + namespaces + .iter() + .fold(TokenStream2::default(), |acc, nasp| { + if nasp.variant == Variant::RootNamespace && nasp.name == "" { + if acc.is_empty() { + quote! { + crate + } + } else { + unreachable!("An root namespace can never come, after another namespcae") + } + } else { + let ident = format_ident!("{}", nasp.name); + if acc.is_empty() { + quote! { + crate :: #ident + } + } else { + quote! { + #acc :: #ident + } + } + } + }) +} +fn namespaces_to_path_expansive(namespaces: &[Identifier]) -> TokenStream2 { + namespaces + .iter() + .fold(TokenStream2::default(), |acc, nasp| { + if nasp.variant == Variant::RootNamespace && nasp.name == "" { + if acc.is_empty() { + quote! { + crate + } + } else { + unreachable!("An root namespace can never come, after another namespcae") + } + } else { + let ident = format_ident!("{}", nasp.name); + if acc.is_empty() { + quote! { + crate :: #ident + } + } else { + quote! { + #acc :: #ident + } + } + } + }) +}