refactor(macros/convertible_derive): Generate the `Convertible` Trait impl

Previously this was derived in the `trixy-types-derive` create, but this
is just making debugging harder and has thus been refactored.
This commit is contained in:
Benedikt Peetz 2024-03-24 18:04:23 +01:00
parent 938e038075
commit 18034e28de
Signed by: bpeetz
GPG Key ID: A5E94010C3A642AD
6 changed files with 148 additions and 130 deletions

View File

@ -0,0 +1,148 @@
/*
* Copyright (C) 2023 - 2024:
* The Trinitrix Project <soispha@vhack.eu, antifallobst@systemausfall.org>
*
* This file is part of the Trixy crate for Trinitrix.
*
* Trixy is free software: you can redistribute it and/or modify
* it under the terms of the Lesser GNU General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* and the Lesser GNU General Public License along with this program.
* If not, see <https://www.gnu.org/licenses/>.
*/
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use trixy_parser::command_spec::{Enumeration, Structure};
use crate::generate::{c_api::mangle_c_type_identifier, identifier_to_rust};
/// This function generates the `Convertible` implementation for a structure
pub fn structure_convertable_derive(
structure: &Structure,
paired_type: &TokenStream,
) -> TokenStream {
let ident = identifier_to_rust(&structure.identifier);
let into_fields: TokenStream = structure
.contents
.iter()
.map(|con| {
let ident = identifier_to_rust(&con.name);
quote! {
#ident: self.#ident.into(),
}
})
.collect();
quote! {
impl trixy::types::traits::convert_trait::Convertible for #ident {
type Ptr = #paired_type;
fn into_ptr(self) -> Self::Ptr {
Self::Ptr {
#into_fields
}
}
fn from_ptr(ptr: Self::Ptr) -> Result<Self, trixy::types::error::TypeConversionError> {
todo!()
}
}
}
}
/// This function generates the `TryFrom<paired_type>` trait implementation for a given structure
pub fn structure_into_impl(structure: &Structure, paired_type: &TokenStream) -> TokenStream {
let ident = identifier_to_rust(&structure.identifier);
let try_into_fields: TokenStream = structure
.contents
.iter()
.map(|con| {
let ident = identifier_to_rust(&con.name);
quote! {
#ident: value.#ident.try_into()?,
}
})
.collect();
quote! {
impl TryFrom<#paired_type> for #ident {
type Error = trixy::types::error::TypeConversionError;
fn try_from(value: #paired_type) -> Result<Self, Self::Error> {
Ok(Self {
#try_into_fields
})
}
}
}
}
/// This function generates the `From<paired_type>` trait implementation for a given c enumeration
pub fn c_enumeration_into_impl(
enumeration: &Enumeration,
paired_type: &TokenStream,
) -> TokenStream {
let c_ident = mangle_c_type_identifier(&enumeration.identifier);
let ident = identifier_to_rust(&enumeration.identifier);
enumeration_into_impl(
enumeration,
&c_ident.into_token_stream(),
&ident,
&paired_type,
)
}
/// This function generates the `From<paired_type>` trait implementation for a given rust enumeration
pub fn rust_enumeration_into_impl(
enumeration: &Enumeration,
paired_type: &TokenStream,
) -> TokenStream {
let c_ident = mangle_c_type_identifier(&enumeration.identifier);
let ident = identifier_to_rust(&enumeration.identifier);
enumeration_into_impl(
enumeration,
&ident,
&c_ident.into_token_stream(),
&paired_type,
)
}
fn enumeration_into_impl(
enumeration: &Enumeration,
ident_main: &TokenStream,
ident_client: &TokenStream,
paired_type: &TokenStream,
) -> TokenStream {
let match_lines: TokenStream = enumeration
.states
.iter()
.map(|state| {
let name = identifier_to_rust(&(state.into()));
quote! {
#ident_client :: #name => Self :: #name,
}
})
.collect();
quote! {
impl From<#paired_type> for #ident_main {
fn from(value: #paired_type) -> Self {
match value {
#match_lines
}
}
}
}
}

View File

@ -30,4 +30,3 @@ proc-macro2 = "1.0.70"
quote = "1.0.33" quote = "1.0.33"
syn = { version = "2.0.41", features = ["extra-traits", "full", "parsing"] } syn = { version = "2.0.41", features = ["extra-traits", "full", "parsing"] }
thiserror = "1.0.51" thiserror = "1.0.51"
trixy-types-derive = {path = "./trixy-types-derive"}

View File

@ -30,8 +30,6 @@ use std::{
use super::errno; use super::errno;
pub use trixy_types_derive::Convertible;
/// Convert a value into a data structure that we can send directly to c. /// Convert a value into a data structure that we can send directly to c.
pub trait Convertible pub trait Convertible
where where

View File

@ -1,6 +0,0 @@
# build
/target
/result
# This crate is a library
Cargo.lock

View File

@ -1,33 +0,0 @@
# Copyright (C) 2023 - 2024:
# The Trinitrix Project <soispha@vhack.eu, antifallobst@systemausfall.org>
#
# This file is part of the Trixy crate for Trinitrix.
#
# Trixy is free software: you can redistribute it and/or modify
# it under the terms of the Lesser GNU General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# and the Lesser GNU General Public License along with this program.
# If not, see <https://www.gnu.org/licenses/>.
[package]
name = "trixy-types-derive"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
syn = "1.0"
quote = "1.0"
proc-macro2 = "1.0.78"
[lib]
proc-macro = true

View File

@ -1,88 +0,0 @@
/*
* Copyright (C) 2023 - 2024:
* The Trinitrix Project <soispha@vhack.eu, antifallobst@systemausfall.org>
*
* This file is part of the Trixy crate for Trinitrix.
*
* Trixy is free software: you can redistribute it and/or modify
* it under the terms of the Lesser GNU General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* and the Lesser GNU General Public License along with this program.
* If not, see <https://www.gnu.org/licenses/>.
*/
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use syn::{Fields, FieldsNamed};
#[proc_macro_derive(Convertible)]
pub fn convertible_derive(input: TokenStream) -> TokenStream {
let ast: syn::DeriveInput = syn::parse(input).unwrap();
let name = &ast.ident;
let drop_impl = match ast.data {
syn::Data::Struct(stru) => {
let field_drop = if let Fields::Named(FieldsNamed {
brace_token: _,
named,
}) = stru.fields
{
named
.iter()
.map(|field| field.ident.as_ref().expect("All are under NamedFields"))
.map(|name| {
quote! {
self.#name.drop_ptr()?;
}
})
.collect::<TokenStream2>()
} else {
unimplemented!()
};
quote! {
impl trixy::types::traits::convert_trait::Convertible for #name {
type Ptr = #name;
fn into_ptr(self) -> Self::Ptr {
self
}
fn from_ptr(ptr: Self::Ptr) -> Result<Self, trixy::types::error::TypeConversionError> {
// #field_drop
// Ok(())
Err(trixy::types::error::TypeConversionError::NotAdmissable)
}
}
}
}
syn::Data::Enum(_) => {
quote! {
impl trixy::types::traits::convert_trait::Convertible for #name {
type Ptr = #name ;
fn into_ptr(self) -> Self::Ptr {
self
}
fn from_ptr(ptr: Self::Ptr) -> Result<Self, trixy::types::error::TypeConversionError> {
// log::warn!("Drop does nothing on enums! (Called for {})", stringify!(#name));
Err(trixy::types::error::TypeConversionError::NotAdmissable)
}
}
}
}
syn::Data::Union(_) => panic!("This derive macro does nothing for unions"),
};
drop_impl.into()
}