diff --git a/trixy-macros/src/generate/c_api/header/mod.rs b/trixy-macros/src/generate/c_api/header/mod.rs index 5c1786a..b047bed 100644 --- a/trixy-macros/src/generate/c_api/header/mod.rs +++ b/trixy-macros/src/generate/c_api/header/mod.rs @@ -36,21 +36,21 @@ mod pure_header; mod structs_init; mod typedef; -const BEGIN_HEADER_GUARD: &'static str = r"#ifndef TRIXY_MAIN_HEADER +const BEGIN_HEADER_GUARD: &'static str = r"#if !defined TRIXY_MAIN_HEADER #define TRIXY_MAIN_HEADER"; -const END_HEADER_GUARD: &'static str = r"#endif // ifndef TRIXY_MAIN_HEADER"; +const END_HEADER_GUARD: &'static str = r"#endif // if !defined TRIXY_MAIN_HEADER"; -/// This function acts as the core transformative aspect, turning this trixy code into the +/// This function acts as the core transformative aspect, turning this Trixy code into the /// following c header: /// /// *Trixy:* /// ```text /// fn fn_alone(); -/// nasp one { +/// mod one { /// fn fn_one(); -/// nasp two { +/// mod two { /// fn fn_two(); -/// nasp three { +/// mod three { /// fn fn_three(); /// } /// } @@ -58,7 +58,7 @@ const END_HEADER_GUARD: &'static str = r"#endif // ifndef TRIXY_MAIN_HEADER"; /// ``` /// *C header:* /// ```text -/// #ifndef TRIXY_MAIN_HEADER +/// #if !defined TRIXY_MAIN_HEADER /// #define TRIXY_MAIN_HEADER /// /// extern int fn_alone(); @@ -66,30 +66,30 @@ const END_HEADER_GUARD: &'static str = r"#endif // ifndef TRIXY_MAIN_HEADER"; /// extern int one_two_fn_two(); /// extern int one_two_three_fn_three(); /// -/// typedef struct { +/// struct three { /// void (*fn_three)(void); -/// } three_t; -/// typedef struct { +/// }; +/// struct two { /// void (*fn_two)(void); /// three_t three; -/// } two_t; -/// typedef struct { +/// }; +/// struct one { /// void (*fn_one)(void); /// two_t two; -/// } one_t; +/// } ; /// -/// const three_t three = { +/// const struct three three = { /// .fn_three = one_two_three_fn_three, /// }; -/// const two_t two = { +/// const struct two two = { /// .fn_two = one_two_fn_two, /// .three = three, /// }; -/// const one_t one = { +/// const struct one one = { /// .fn_one = one_fn_one, /// .two = two, /// }; -/// #endif // ifndef TRIXY_MAIN_HEADER +/// #endif // if !defined TRIXY_MAIN_HEADER /// ``` pub fn generate(trixy: &CommandSpec, _config: &TrixyConfig) -> String { let pure_header = pure_header::generate(&trixy); diff --git a/trixy-macros/src/generate/c_api/header/pure_header.rs b/trixy-macros/src/generate/c_api/header/pure_header.rs index 9219f4e..a768471 100644 --- a/trixy-macros/src/generate/c_api/header/pure_header.rs +++ b/trixy-macros/src/generate/c_api/header/pure_header.rs @@ -54,10 +54,10 @@ fn structure_to_header(structure: &Structure) -> String { format!( " {} - typedef struct {{ + struct {} {{ {} - }} {};", - doc_comments, contents, ident + }};", + doc_comments, ident, contents ) } fn doc_named_type_to_header(doc_named_type: &DocNamedType) -> String { @@ -94,10 +94,10 @@ fn enumeration_to_header(enumeration: &Enumeration) -> String { format!( " {} - typedef enum {{ + enum {} {{ {} - }} {};", - doc_comments, states, ident + }};", + doc_comments, ident, states ) } fn doc_identifier_to_header(doc_identifier: &DocIdentifier) -> String { diff --git a/trixy-macros/src/generate/c_api/header/typedef.rs b/trixy-macros/src/generate/c_api/header/typedef.rs index 611c534..99e24d8 100644 --- a/trixy-macros/src/generate/c_api/header/typedef.rs +++ b/trixy-macros/src/generate/c_api/header/typedef.rs @@ -51,15 +51,15 @@ fn function_to_typedef(function: &Function) -> TokenStream2 { fn namespace_to_typedef(namespace: &Namespace) -> TokenStream2 { let ident = identifier_to_rust(&namespace.name); - let type_ident = format_ident!("{}_t", ident.to_string()); + let type_ident = format_ident!("{}", ident.to_string()); quote! { - #type_ident #ident ; + struct #type_ident #ident; } } fn namespace_to_full_typedef(nasp: &Namespace) -> String { - let ident = format_ident!("{}_t", nasp.name.name); + let ident = format_ident!("{}", nasp.name.name); let doc_comments = nasp .attributes .iter() @@ -84,10 +84,10 @@ fn namespace_to_full_typedef(nasp: &Namespace) -> String { .join("\n"); let namespace = quote! { - typedef struct { + struct #ident { #functions #namespaces - } #ident; + }; }; format! {"{}\n{}{}\n", next_namespace, doc_comments, namespace} } diff --git a/trixy-macros/src/generate/c_api/host.rs b/trixy-macros/src/generate/c_api/host.rs index 8f9df40..65c5873 100644 --- a/trixy-macros/src/generate/c_api/host.rs +++ b/trixy-macros/src/generate/c_api/host.rs @@ -27,7 +27,7 @@ use crate::{ config::TrixyConfig, generate::{ c_api::{mangle_c_function_ident, namespaces_to_path, type_to_c_equalivalent}, - function_identifier_to_rust, identifier_to_rust, named_type_to_rust, + function_identifier_to_rust, identifier_to_rust, }, }; diff --git a/trixy-types/Cargo.toml b/trixy-types/Cargo.toml index 379ee6d..9d2e2f5 100644 --- a/trixy-types/Cargo.toml +++ b/trixy-types/Cargo.toml @@ -30,4 +30,3 @@ proc-macro2 = "1.0.70" quote = "1.0.33" syn = { version = "2.0.41", features = ["extra-traits", "full", "parsing"] } thiserror = "1.0.51" -trixy-types-derive = { path = "./trixy-types-derive" } diff --git a/trixy-types/src/error/mod.rs b/trixy-types/src/error/mod.rs index 884b320..c6ae1a2 100644 --- a/trixy-types/src/error/mod.rs +++ b/trixy-types/src/error/mod.rs @@ -32,4 +32,10 @@ pub enum TypeConversionError { #[error("You passed a untyped (type_id == Unknown) value to the conversion function!")] UntypedInput, + + #[error("You passed an unaligned pointer to a function expecting a pointer aligned to it's required value!")] + NotAligned, + + #[error("The returned Result was an error: {original_message}")] + ResultWasErr { original_message: String }, } diff --git a/trixy-types/src/lib.rs b/trixy-types/src/lib.rs index 694eff4..41f0507 100644 --- a/trixy-types/src/lib.rs +++ b/trixy-types/src/lib.rs @@ -18,7 +18,7 @@ * If not, see . */ -//! Trixy contains the types used by the [trixy-macros] crate to provide ffi safe types +//! Trixy contains the types used by the [`trixy-macros`] crate to provide ffi safe types pub mod error; pub mod traits; pub mod types_list; @@ -33,28 +33,32 @@ macro_rules! header { /// These are the "primitive" types used in Trixy, you can use any of them to create new structures /// The str is the name, the index represents the expected generic arguments -pub const BASE_TYPES: [(&'static std::primitive::str, usize); 5] = [ - ("str", 0), +/// +// NOTE: Every type here must have the [`Convertible`] implemented on it (@soispha) +pub const BASE_TYPES: [(&'static std::primitive::str, usize); 14] = [ + // Unsigned + ("u8", 0), + ("u16", 0), + ("u32", 0), + ("u64", 0), + // Signed + ("i8", 0), + ("i16", 0), + ("i32", 0), + ("i64", 0), + // Float + ("f32", 0), + ("f64", 0), + // Other ("String", 0), - ("Result", 2), ("Option", 1), ("Vec", 1), + ("Result", 2), ]; /// The first value is the file name, the second it's contents -pub const C_TYPE_HEADER: [(&'static std::primitive::str, &'static std::primitive::str); 9] = [ - header!("errno.h"), - // These must be *before* "type_id.h" - header!("type_id_dec.h"), - header!("result_dec.h"), - header!("option.h"), - header!("string.h"), - header!("vec_dec.h"), - - header!("type_id.h"), - header!("result.h"), - header!("vec.h"), -]; +pub const C_TYPE_HEADER: [(&'static std::primitive::str, &'static std::primitive::str); 3] = + [header!("errno.h"), header!("string.h"), header!("vec.h")]; pub fn header_names() -> std::string::String { C_TYPE_HEADER diff --git a/trixy-types/src/traits/convert_trait.rs b/trixy-types/src/traits/convert_trait.rs index 0934416..13b761e 100644 --- a/trixy-types/src/traits/convert_trait.rs +++ b/trixy-types/src/traits/convert_trait.rs @@ -1,108 +1,166 @@ +use crate::error::{self, TypeConversionError}; use std::{ - any::Any, - ffi::{CStr, CString}, - os::raw::c_void, + error::Error, + ffi::{c_char, CString}, + mem::ManuallyDrop, + ptr, }; -/// Convert a value +use super::errno; + +/// Convert a value into a data structure that we can send directly to c. pub trait Convertible { - /// Turn the value into a c void pointer. - /// It should try its best to return a value which c can understand. - /// If this however is not possible, it should still return the underlying raw data - fn into_void(self) -> *const c_void; + type Ptr; + /// Turn the value into a c void pointer or a data structure that c can understand. + fn into_ptr(self) -> Self::Ptr; + + /// If the data returned by [`into_ptr`] needs to be dropped this function should do it. + fn drop_ptr(ptr: Self::Ptr) -> Result<(), error::TypeConversionError>; } -impl Convertible for crate::String { - fn into_void(self) -> *const c_void { - self.0 as *const _ as *const c_void +macro_rules! primitive_convert { + [$name:ty] => { + impl Convertible for $name { + type Ptr = $name; + + fn into_ptr(self) -> Self::Ptr { + self + } + + fn drop_ptr(_: Self::Ptr) -> Result<(), error::TypeConversionError> { + unreachable!("Theres is no need to drop a {}", stringify!($name)) + } + } } } -impl Convertible for crate::str { - fn into_void(self) -> *const c_void { - self.0 as *const _ as *const c_void - } -} +// Unsigned +primitive_convert!(u8); +primitive_convert!(u16); +primitive_convert!(u32); +primitive_convert!(u64); -impl Convertible for crate::Option { - fn into_void(mut self) -> *const c_void { - &mut self as *const _ as *const c_void - } -} +// Signed +primitive_convert!(i8); +primitive_convert!(i16); +primitive_convert!(i32); +primitive_convert!(i64); -impl Convertible for crate::Vec { - fn into_void(mut self) -> *const c_void { - &mut self as *const _ as *const c_void - } -} - -impl Convertible for crate::Result { - fn into_void(mut self) -> *const c_void { - &mut self as *const _ as *const c_void - } -} - -impl Convertible - for Result -{ - fn into_void(self) -> *const c_void { - Into::::into(self).into_void() - } -} - -impl Convertible for &CStr { - fn into_void(self) -> *const c_void { - Into::::into(self).into_void() - } -} +// Float +primitive_convert!(f32); +primitive_convert!(f64); impl Convertible for CString { - fn into_void(self) -> *const c_void { - Into::::into(self).into_void() + type Ptr = *const *const c_char; + + fn into_ptr(self) -> Self::Ptr { + self.into_raw() as *const *const c_char + } + + fn drop_ptr(ptr: Self::Ptr) -> Result<(), error::TypeConversionError> { + unsafe { + if ptr.is_null() { + return Err(TypeConversionError::NullPointer); + } + // TODO(@soispha): Add this, when this feature is stable <2024-02-17> + // if !ptr.is_aligned() { + // return Err(TypeConversionError::NotAligned); + // } + + // SAFETY: + // Checked that the ptr is not null and that it is aligned (to c_char). + // This should hopefully be enough to avoid constructing a CString from a pointer not + // constructed by a us earlier in the [`into_ptr`] function. + // However: + // This still builds on the hope that c passes the pointer with the length unchanged. + let string = CString::from_raw(ptr as *mut i8); + drop(string); + } + Ok(()) } } -impl Convertible for () { - fn into_void(self) -> *const c_void { - std::ptr::null() +impl Convertible for Option { + type Ptr = *const T; + + fn into_ptr(self) -> Self::Ptr { + if let Some(inner) = self { + let mut_ref = &mut inner.into_ptr(); + mut_ref as *mut _ as *const T + } else { + ptr::null() + } + } + + fn drop_ptr(_: Self::Ptr) -> Result<(), error::TypeConversionError> { + unreachable!( + " + This should never be called, as this option type resolves + to a null pointer or to a pointer to the real value + (e. g. a `crate::Vec`) + " + ); } } -extern crate trixy_types_derive; -pub use trixy_types_derive::{Convertible, TypeInfo}; +impl Convertible for Result { + type Ptr = *const T; -/// Similar to [`std::any::type_name`] but only really works for *some* types. -/// If the type is unknown it will just return [`TypeId::Unknown`] -pub trait TypeInfo { - fn type_of(&self) -> crate::TypeId; + fn into_ptr(self) -> Self::Ptr { + match self { + Ok(ok) => { + let mut_ref = &mut ok.into_ptr(); + mut_ref as *mut _ as *const T + } + Err(err) => { + errno::set(TypeConversionError::ResultWasErr { + original_message: err.to_string(), + }); + ptr::null() + } + } + } + + fn drop_ptr(_: Self::Ptr) -> Result<(), error::TypeConversionError> { + unreachable!( + " + This should never be called, as this result type resolves + to a null pointer (and a set error) or to a pointer to + the real value (e. g. a `crate::Vec`) + " + ); + } } -macro_rules! type_info { - ($name:tt<_>, $output:ident) => { - impl TypeInfo for $name { - fn type_of(&self) -> crate::TypeId { - crate::TypeId::$output - } +impl Convertible for Vec { + type Ptr = crate::Vec; + + fn into_ptr(self) -> Self::Ptr { + let mut me = ManuallyDrop::new(self); + Self::Ptr { + data: me.as_mut_ptr() as *const T, + length: me.len(), + capacity: me.capacity(), } - }; - ($name:tt<_,_>, $output:ident) => { - impl TypeInfo for $name { - fn type_of(&self) -> crate::TypeId { - crate::TypeId::$output + } + + fn drop_ptr(ptr: Self::Ptr) -> Result<(), error::TypeConversionError> { + let vec = unsafe { + if ptr.data.is_null() { + return Err(TypeConversionError::NullPointer); } - } - }; - ($name:ty, $output:ident) => { - impl TypeInfo for $name { - fn type_of(&self) -> crate::TypeId { - crate::TypeId::$output - } - } - }; + + // TODO(@soispha): Add this, when this feature is stable <2024-02-17> + // if !ptr.data.is_aligned() { + // return Err(TypeConversionError::NotAligned); + // } + + // SAFETY: + // We simply hope that c treated our vector as read-only and didn't modify it. + // See the SAFETY section of the String implementation for more detail. + Vec::from_raw_parts(ptr.data as *mut T, ptr.length, ptr.capacity) + }; + drop(vec); + Ok(()) + } } -type_info!((), void); -type_info!(&CStr, str_t); -type_info!(CString, string_t); -type_info!(Result<_, _>, result_t); -type_info!(Vec<_>, vec_t); -type_info!(Option<_>, option_t); diff --git a/trixy-types/src/traits/mod.rs b/trixy-types/src/traits/mod.rs index ac32f2d..62ad4b8 100644 --- a/trixy-types/src/traits/mod.rs +++ b/trixy-types/src/traits/mod.rs @@ -18,212 +18,5 @@ * If not, see . */ -use std::{ - alloc::Layout, - ffi::{c_char, CStr, CString}, - mem::ManuallyDrop, - ptr, -}; - -use crate::error::TypeConversionError; - -use self::convert_trait::{Convertible, TypeInfo}; - pub mod convert_trait; pub mod errno; - -impl<'a> TryFrom<&'a crate::str> for &'a str { - type Error = crate::error::TypeConversionError; - - fn try_from(value: &'a crate::str) -> Result { - let ptr = value.0; - if ptr.is_null() { - Err(TypeConversionError::NullPointer) - } else { - // SAFETY: We checked for null, which is a huge upside other things that we simply hope - // for: - // - null terminated - // - actually be a valid pointer (`(void*) 2` is *valid* c but not a *valid* pointer) - // - be contained in a single allocated object - // - the memory must obviously not be mutated, while this &str exists - // - the null terminator must be within `isize::MAX` from the start position - let str = unsafe { CStr::from_ptr(*ptr as *const c_char) }; - str.to_str() - .map_err(|_err| crate::error::TypeConversionError::String { - got: value.0 as *const c_char, - }) - } - } -} -impl TryFrom for String { - type Error = crate::error::TypeConversionError; - - fn try_from(value: crate::String) -> Result { - let ptr = value.0; - if ptr.is_null() { - Err(TypeConversionError::NullPointer) - } else { - // SAFETY: (exactly the same as above applies) - let string = unsafe { CStr::from_ptr(ptr) }.to_owned(); - Ok(string - .into_string() - .map_err(|err| TypeConversionError::String { - got: err.into_cstring().into_raw(), - })?) - } - } -} - -impl TryFrom for Vec { - type Error = crate::error::TypeConversionError; - - fn try_from(value: crate::Vec) -> Result { - match value.type_id { - crate::TypeId::Unknown => Err(Self::Error::UntypedInput), - crate::TypeId::void => Ok(vec![]), - crate::TypeId::str_t => { - let mut output: Vec = Vec::with_capacity(value.capacity); - for i in 0..value.size { - // output.push(value.data.add()) - } - Ok(output) - }, - crate::TypeId::string_t => todo!(), - crate::TypeId::result_t => todo!(), - crate::TypeId::vec_t => todo!(), - crate::TypeId::option_t => todo!(), - } - } -} - -impl crate::Vec { - pub fn pop(&mut self) -> Result { - match self.type_id { - crate::TypeId::Unknown => Err(TypeConversionError::UntypedInput), - crate::TypeId::void => Ok(() as T), - crate::TypeId::str_t => todo!(), - crate::TypeId::string_t => todo!(), - crate::TypeId::result_t => todo!(), - crate::TypeId::vec_t => todo!(), - crate::TypeId::option_t => todo!(), - } - } -} - -impl From for crate::String { - fn from(value: CString) -> Self { - let layout = Layout::array::(value.as_bytes_with_nul().len()).expect( - "We don't handle n > isize::MAX, in the other types. \ - Thus, this convertion will fail", - ); - // SAFETY: - // - The layout should never have zero size (at least 1) - // - The memory blocks are copied from the string, thus initialization is irrelevant - let ptr = unsafe { std::alloc::alloc(layout) }; - if ptr.is_null() { - // TODO(@soispha): How do we handle this? <2023-12-27> - panic!("While preparing a string for c failed to allocate memory, the pointer is null"); - } - - // SAFETY: - // - Both are valid for reads of `count * size_of::()` bytes because we checked - // their length - // - They are properly aligned for types of [`c_char`] - unsafe { - ptr::copy( - value.as_ptr(), - ptr as *mut i8, - value.as_bytes_with_nul().len(), - ) - }; - - Self(ptr as *const c_char) - } -} - -impl<'a> From<&'a CStr> for crate::str { - fn from(value: &'a CStr) -> Self { - crate::str(value.as_ptr() as *const u8) - } -} - -impl From> for crate::Vec -where - T: Convertible + TypeInfo, -{ - fn from(value: Vec) -> Self { - if value.is_empty() { - Self { - type_id: crate::TypeId::Unknown, - data: ptr::null(), - size: 0, - capacity: 0, - } - } else { - let value_type = value.first().expect("We checked the length").type_of(); - let value: Vec<_> = value.into_iter().map(|val| val.into_void()).collect(); - - // We simply tell rust, that c should drop the value - let vec = ManuallyDrop::new(value); - Self { - type_id: value_type, - data: *vec.first().expect("This exists"), - size: vec.len(), - capacity: vec.capacity(), - } - } - } -} - -impl From> for crate::Option -where - T: Convertible + TypeInfo, -{ - fn from(value: Option) -> Self { - match value { - Some(value) => Self { - type_id: value.type_of(), - value: value.into_void(), - some: true, - }, - None => Self { - type_id: crate::TypeId::Unknown, - value: ptr::null(), - some: false, - }, - } - } -} - -// impl<'a> From<&'a str> for crate::str { -// fn from(value: &'a str) -> Self { -// let ptr = value.as_ptr(); -// // This is taken from std's CStr -// -// // SAFETY: We do not handle any strings larger than `isize::MAX` thus this call works. -// // -// // The cast from c_char to i8 is ok because a c_char is always one byte. -// unsafe { CStr::from_ptr(ptr as *const i8) }.into() -// } -// } - -impl From> for crate::Result -where - T: Convertible + TypeInfo, - E: Convertible + TypeInfo, -{ - fn from(value: Result) -> Self { - match value { - Ok(ok) => Self { - type_id: ok.type_of(), - tag: crate::ResultTag::Ok, - value: ok.into_void(), - }, - Err(err) => Self { - type_id: err.type_of(), - tag: crate::ResultTag::Err, - value: err.into_void(), - }, - } - } -} diff --git a/trixy-types/src/types_list.rs b/trixy-types/src/types_list.rs index b28ead7..f20fda9 100644 --- a/trixy-types/src/types_list.rs +++ b/trixy-types/src/types_list.rs @@ -1,70 +1,12 @@ // NOTE(@soispha): All types specified here *MUST* be include in the BASE_TYPES constant, otherwise // they are not usable from Trixy code <2023-12-25> -use std::ffi::{c_char, c_void}; - #[derive(Debug)] #[repr(C)] -pub struct String(pub(crate) *const c_char); - -#[derive(Debug)] -#[repr(C)] -#[allow(non_camel_case_types)] -pub struct str(pub(crate) *const u8); - -#[derive(Debug)] -#[repr(C)] -pub enum TypeId { - /// We simply don't know which type this is - Unknown, - - #[allow(non_camel_case_types)] - void, - - #[allow(non_camel_case_types)] - str_t, - - #[allow(non_camel_case_types)] - string_t, - - #[allow(non_camel_case_types)] - result_t, - - #[allow(non_camel_case_types)] - vec_t, - - #[allow(non_camel_case_types)] - option_t, -} - -#[derive(Debug)] -#[repr(C)] -pub enum ResultTag { - Ok, - Err, -} - -#[derive(Debug)] -#[repr(C)] -pub struct Result { - pub(crate) type_id: TypeId, - pub(crate) tag: ResultTag, - pub(crate) value: *const c_void, -} - -#[derive(Debug)] -#[repr(C)] -pub struct Vec { - pub(crate) type_id: TypeId, - pub(crate) data: *const c_void, - pub(crate) size: usize, +pub struct Vec { + /// You should cast this value to it's supposed type (readable from the Trixy api definition + /// file) + pub(crate) data: *const T, + pub(crate) length: usize, pub(crate) capacity: usize, } - -#[derive(Debug)] -#[repr(C)] -pub struct Option { - pub(crate) type_id: TypeId, - pub(crate) value: *const c_void, - pub(crate) some: bool, -} diff --git a/trixy-types/trixy-types-derive/.gitignore b/trixy-types/trixy-types-derive/.gitignore deleted file mode 100644 index 20c0ba9..0000000 --- a/trixy-types/trixy-types-derive/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -# build -/target -/result - -# This crate is a library -Cargo.lock diff --git a/trixy-types/trixy-types-derive/Cargo.toml b/trixy-types/trixy-types-derive/Cargo.toml deleted file mode 100644 index af0be22..0000000 --- a/trixy-types/trixy-types-derive/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[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" - -[lib] -proc-macro = true diff --git a/trixy-types/trixy-types-derive/src/lib.rs b/trixy-types/trixy-types-derive/src/lib.rs deleted file mode 100644 index 800bf32..0000000 --- a/trixy-types/trixy-types-derive/src/lib.rs +++ /dev/null @@ -1,38 +0,0 @@ -use proc_macro::TokenStream; -use quote::quote; - -#[proc_macro_derive(Convertible)] -pub fn convertible_derive(input: TokenStream) -> TokenStream { - // Construct a representation of Rust code as a syntax tree - // that we can manipulate - let ast: syn::DeriveInput = syn::parse(input).unwrap(); - - // Build the trait implementation - let name = &ast.ident; - let gen = quote! { - impl trixy::types::traits::convert_trait::Convertible for #name { - fn into_void(mut self) -> *const core::ffi::c_void { - &mut self as *const _ as *const core::ffi::c_void - } - } - }; - gen.into() -} - -#[proc_macro_derive(TypeInfo)] -pub fn type_info_derive(input: TokenStream) -> TokenStream { - // Construct a representation of Rust code as a syntax tree - // that we can manipulate - let ast: syn::DeriveInput = syn::parse(input).unwrap(); - - // Build the trait implementation - let name = &ast.ident; - let gen = quote! { - impl trixy::types::traits::convert_trait::TypeInfo for #name { - fn type_of(&self) -> trixy::types::TypeId { - trixy::types::TypeId::Unknown - } - } - }; - gen.into() -}