From a669f399a8db6e341f4bbc8102cd09c4b702cd89 Mon Sep 17 00:00:00 2001 From: Benedikt Peetz Date: Mon, 20 May 2024 15:19:11 +0200 Subject: [PATCH] feat(src): Add real and working support for results Every `Result` is now -- on demand -- instantiated (i.e. the generic types are replaced with the concretely specified ones). And can thus simply be exported to c. --- .../convert/auxiliary/c/enumeration/mod.rs | 2 +- .../convert/auxiliary/c/identifier/mod.rs | 21 +- .../convert/auxiliary/c/namespace/mod.rs | 10 +- .../convert/auxiliary/c/structure/mod.rs | 2 +- .../generate/convert/auxiliary/c/type/mod.rs | 21 +- .../generate/convert/host/c/namespace/mod.rs | 90 +++++++- .../generate/convert/host/c/type/mod.rs | 104 ++++++++- .../generate/convert/host/c/variant/mod.rs | 9 +- src/macros/generate/host/c/mod.rs | 13 ++ src/parser/command_spec/checked.rs | 15 +- src/parser/parsing/checked/mod.rs | 41 ++-- src/types/c_headers/result.h | 44 ++++ src/types/mod.rs | 12 +- src/types/traits/convert_trait.rs | 200 ++++++++---------- src/types/types_list.rs | 22 +- 15 files changed, 436 insertions(+), 170 deletions(-) create mode 100644 src/types/c_headers/result.h diff --git a/src/macros/generate/convert/auxiliary/c/enumeration/mod.rs b/src/macros/generate/convert/auxiliary/c/enumeration/mod.rs index 855429a..799cece 100644 --- a/src/macros/generate/convert/auxiliary/c/enumeration/mod.rs +++ b/src/macros/generate/convert/auxiliary/c/enumeration/mod.rs @@ -25,7 +25,7 @@ use crate::parser::command_spec::{Attribute, DocIdentifier, Enumeration}; impl Enumeration { pub fn to_auxiliary_c(&self) -> String { let doc_comments: String = Attribute::to_auxiliary_c_merged(&self.attributes); - let ident = &self.identifier.to_auxiliary_c(); + let ident = &self.identifier.to_auxiliary_c(&[]); let states = self .states .iter() diff --git a/src/macros/generate/convert/auxiliary/c/identifier/mod.rs b/src/macros/generate/convert/auxiliary/c/identifier/mod.rs index a48de27..ec129db 100644 --- a/src/macros/generate/convert/auxiliary/c/identifier/mod.rs +++ b/src/macros/generate/convert/auxiliary/c/identifier/mod.rs @@ -24,15 +24,12 @@ use convert_case::{Case, Casing}; use proc_macro2::TokenStream as TokenStream2; use quote::quote; -use crate::parser::command_spec::{Identifier, Variant}; +use crate::parser::command_spec::{Identifier, Type, Variant}; mod doc_identifier; -// -// pub use doc_identifier::*; - impl Identifier { - pub fn to_auxiliary_c(&self) -> TokenStream2 { + pub fn to_auxiliary_c(&self, generic_args: &[Type]) -> TokenStream2 { let ident = self.to_rust_pascalized(); match &self.variant { Variant::Structure { .. } => { @@ -46,10 +43,17 @@ impl Identifier { enum #ident } } + Variant::Result { .. } => { + let ident = Type::mangle_result_name(generic_args); + quote! { + struct #ident + } + } + Variant::Primitive => match self.name.to_case(Case::Snake).as_str() { "string" => { quote! { - const char* + const char * } } // Unsigned @@ -65,14 +69,15 @@ impl Identifier { // Float "f_32" => quote! { float }, "f_64" => quote! { double }, - // Other (not yet imlemented) + + // Others (not yet imlemented) // ("Option", 1), // ("Vec", 1), - // ("Result", 2), other => { todo!("'{}' is not yet supported", other) } }, + other => { unimplemented!("{:#?}", other) } diff --git a/src/macros/generate/convert/auxiliary/c/namespace/mod.rs b/src/macros/generate/convert/auxiliary/c/namespace/mod.rs index 4e0a7d3..b360e27 100644 --- a/src/macros/generate/convert/auxiliary/c/namespace/mod.rs +++ b/src/macros/generate/convert/auxiliary/c/namespace/mod.rs @@ -24,7 +24,7 @@ use proc_macro2::TokenStream as TokenStream2; use quote::{format_ident, quote}; use crate::parser::command_spec::{ - Attribute, Enumeration, Function, Identifier, Namespace, Structure, + Attribute, Enumeration, Function, Identifier, Namespace, Structure, Type, }; impl Namespace { @@ -44,6 +44,12 @@ impl Namespace { .map(Enumeration::to_auxiliary_c) .collect::>() .join("\n"); + let results: String = self + .select_types_pred(|(ident, _generics)| ident.name.as_str() == "Result") + .iter() + .map(|(_, generics)| Type::to_auxilary_c_result(generics).to_string()) + .collect::>() + .join("\n"); let functions: String = self .functions .iter() @@ -56,7 +62,7 @@ impl Namespace { .map(|nasp| nasp.to_auxiliary_c(&nasps)) .collect(); - format! {"{}\n{}\n{}\n{}", enumerations, structures, functions, namespaces} + format! {"{}\n{}\n{}\n{}\n{}", enumerations, structures, results, functions, namespaces} } pub fn to_auxiliary_c_full_struct_init(&self, namespaces: &Vec<&Identifier>) -> TokenStream2 { diff --git a/src/macros/generate/convert/auxiliary/c/structure/mod.rs b/src/macros/generate/convert/auxiliary/c/structure/mod.rs index 47fbd65..4e2a336 100644 --- a/src/macros/generate/convert/auxiliary/c/structure/mod.rs +++ b/src/macros/generate/convert/auxiliary/c/structure/mod.rs @@ -25,7 +25,7 @@ use crate::parser::command_spec::{Attribute, DocNamedType, Structure}; impl Structure { pub fn to_auxiliary_c(&self) -> String { let doc_comments: String = Attribute::to_auxiliary_c_merged(&self.attributes); - let ident = self.identifier.to_auxiliary_c(); + let ident = self.identifier.to_auxiliary_c(&[]); let contents = self .contents .iter() diff --git a/src/macros/generate/convert/auxiliary/c/type/mod.rs b/src/macros/generate/convert/auxiliary/c/type/mod.rs index ecae9e3..737e7c0 100644 --- a/src/macros/generate/convert/auxiliary/c/type/mod.rs +++ b/src/macros/generate/convert/auxiliary/c/type/mod.rs @@ -36,9 +36,9 @@ impl Type { match self { Type::Typical { identifier, - generic_args: _, + generic_args, } => { - let ident = identifier.to_auxiliary_c(); + let ident = identifier.to_auxiliary_c(generic_args); let output = if is_output { quote! { * @@ -78,4 +78,21 @@ impl Type { } } } + + pub fn to_auxilary_c_result(generic_args: &[Type]) -> TokenStream2 { + let ident = Type::mangle_result_name(&generic_args); + + let generic_one = generic_args[0].to_auxiliary_c(false, None); + let generic_two = generic_args[1].to_auxiliary_c(false, None); + + quote! { + struct #ident { + enum ResultTag tag; + union { + #generic_one ok; + #generic_two err; + } value; + }; + } + } } diff --git a/src/macros/generate/convert/host/c/namespace/mod.rs b/src/macros/generate/convert/host/c/namespace/mod.rs index 0413d0e..409d1bb 100644 --- a/src/macros/generate/convert/host/c/namespace/mod.rs +++ b/src/macros/generate/convert/host/c/namespace/mod.rs @@ -20,12 +20,14 @@ * If not, see . */ +use std::iter; + use proc_macro2::TokenStream as TokenStream2; use quote::{format_ident, quote}; use crate::{ macros::config::trixy::TrixyConfig, - parser::command_spec::{Enumeration, Identifier, Namespace, Structure}, + parser::command_spec::{Enumeration, Identifier, Namespace, Structure, Type}, }; impl Namespace { @@ -48,11 +50,20 @@ impl Namespace { let enumerations: TokenStream2 = self.enumerations.iter().map(Enumeration::to_c).collect(); let callback_function = format_ident!("{}", config.callback_function); + + let all_results_types: TokenStream2 = self + .select_types_pred(|(identifier, _generic_args)| identifier.name.as_str() == "Result") + .iter() + .map(|(_, generics)| Type::to_c_result(&generics)) + .collect(); + quote! { pub mod #ident { #[allow(unused_imports)] use crate :: #callback_function; + #all_results_types + #enumerations #structures #additional_functions @@ -60,4 +71,81 @@ impl Namespace { #functions } } + + /// Get all the types used in this namespaces that conform to the predicate. + /// The predicate get's the identifier of a type and the generic arguments passed. + pub fn select_types_pred( + &self, + pred: fn(&(Identifier, Vec)) -> bool, + ) -> Vec<(Identifier, Vec)> { + fn filter_type(ty: &Type) -> Vec<(Identifier, Vec)> { + match ty { + Type::Typical { + identifier, + generic_args, + } => { + let mut output = vec![]; + output.extend(generic_args.iter().map(|ga| filter_type(ga)).flatten()); + output.push((identifier.to_owned(), generic_args.to_owned())); + // Stop recursion and return + output + } + Type::Function { inputs, output } => { + let mut full_output = vec![]; + full_output.extend( + inputs + .iter() + .map(|na| &na.r#type) + .map(|ty| filter_type(&ty)) + .flatten(), + ); + + if let Some(out) = output { + full_output.extend(filter_type(out)) + } + + full_output + } + } + } + + let all_types = self.collect_types(); + + let all_result_types: Vec<_> = all_types + .iter() + .map(|r#type| filter_type(r#type)) + .flatten() + .filter(pred) + .collect(); + + all_result_types + } + + /// Collect a vector of all types used in this namespace + pub fn collect_types(&self) -> Vec { + let structures_types = self + .structures + .iter() + .map(|st| st.contents.iter().map(|dc| dc.r#type.clone())) + .flatten(); + + self.functions + .iter() + .map(|r#fn| { + r#fn.inputs + .iter() + .map(|nt| Some(nt.r#type.clone())) + .chain({ + if let Some(output) = &r#fn.output { + iter::once(Some(output.clone())) + } else { + iter::once(None) + } + }) + .filter_map(|x| x) + }) + .flatten() + .chain(structures_types) + .collect() + } } diff --git a/src/macros/generate/convert/host/c/type/mod.rs b/src/macros/generate/convert/host/c/type/mod.rs index 13c74eb..0b5912a 100644 --- a/src/macros/generate/convert/host/c/type/mod.rs +++ b/src/macros/generate/convert/host/c/type/mod.rs @@ -21,7 +21,8 @@ */ use proc_macro2::TokenStream as TokenStream2; -use quote::quote; +use quote::{format_ident, quote}; +use syn::Ident; use crate::parser::command_spec::{Identifier, NamedType, Type}; @@ -39,10 +40,84 @@ impl Type { } } + pub fn mangle_result_name(generic_args: &[Type]) -> Ident { + assert_eq!(generic_args.len(), 2); + + format_ident!( + "result_{}_{}", + generic_args[0].to_string(), + generic_args[1].to_string() + ) + } + pub fn to_c_function(inputs: &[NamedType], output: &Option>) -> TokenStream2 { Type::to_rust_function(&inputs, &output) } + pub fn to_c_result(generic_args: &[Type]) -> TokenStream2 { + assert_eq!(generic_args.len(), 2); + let first_generic = generic_args[0].to_c(); + let second_generic = generic_args[1].to_c(); + + let ident = Type::mangle_result_name(&generic_args); + let value_ident = format_ident!("{}_value", ident); + + quote! { + #[allow(non_camel_case_types)] + #[repr(C)] + pub union #value_ident { + ok: std::mem::ManuallyDrop<#first_generic>, + err: std::mem::ManuallyDrop<#second_generic>, + } + + #[allow(non_camel_case_types)] + #[repr(C)] + pub struct #ident { + tag: trixy::types::ResultTag, + value: #value_ident, + } + + impl std::fmt::Debug for #ident { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.tag { + trixy::types::ResultTag::Ok => write!(f, "{:?}", unsafe { &self.value.ok }), + trixy::types::ResultTag::Err => write!(f, "{:?}", unsafe { &self.value.err }), + } + } + } + + + impl trixy::types::traits::convert_trait::Convertible + for crate::OurResult<#first_generic, #second_generic> + { + type Ptr = #ident; + + fn into_ptr(self) -> Self::Ptr { + if self.value.is_ok() { + Self::Ptr { + tag: trixy::types::ResultTag::Ok, + value: #value_ident { + ok: std::mem::ManuallyDrop::new(self.value.expect("Is ok")), + }, + } + } else { + Self::Ptr { + tag: trixy::types::ResultTag::Err, + value: #value_ident { + err: std::mem::ManuallyDrop::new(self.value.expect_err("Is err")), + }, + } + } + } + + fn from_ptr(_ptr: Self::Ptr) -> Result { + unreachable!("This should probably not be called?"); + } + } + + } + } + fn to_c_typical(identifier: &Identifier, generic_args: &Vec) -> TokenStream2 { let trixy_build_in_types: Vec<&str> = crate::types::BASE_TYPES .iter() @@ -75,7 +150,7 @@ impl Type { #nasp_path #ident } } else { - debug_assert_eq!(trixy_build_in_types.len(), 1); + assert_eq!(trixy_build_in_types.len(), 1); let type_name = trixy_build_in_types .first() @@ -83,11 +158,28 @@ impl Type { match *type_name { "Result" => { - let ident_ok = &generic_args.first().expect("This is a result").to_c(); - let ident_err = &generic_args.last().expect("This is a result").to_c(); + assert_eq!(generic_args.len(), 2); + + let namespaces_path = &identifier.variant.to_c_path(); + let nasp_path = if namespaces_path.is_empty() { + quote! { + crate :: + } + } else { + let path = namespaces_path; + quote! { + #path :: + } + }; + + let ident = format_ident!( + "result_{}_{}", + generic_args[0].to_string(), + generic_args[1].to_string() + ); + quote! { - // eg: as Convertible>::Ptr, - as Convertible>::Ptr + #nasp_path #ident } } "Option" => { diff --git a/src/macros/generate/convert/host/c/variant/mod.rs b/src/macros/generate/convert/host/c/variant/mod.rs index 4ff7a5e..e50c77b 100644 --- a/src/macros/generate/convert/host/c/variant/mod.rs +++ b/src/macros/generate/convert/host/c/variant/mod.rs @@ -45,13 +45,12 @@ impl Variant { let main_namespace; match self { - Variant::Structure { namespace } => { + Variant::Structure { namespace } + | Variant::Enumeration { namespace } + | Variant::Result { namespace } => { main_namespace = mangle_namespace_name(namespace); } - Variant::Enumeration { namespace } => { - main_namespace = mangle_namespace_name(namespace); - } - _ => unreachable!("This should never be called"), + other => unreachable!("This should never be called on '{:#?}'", other), } Namespace::to_rust_path_owned(&main_namespace[..]) } diff --git a/src/macros/generate/host/c/mod.rs b/src/macros/generate/host/c/mod.rs index d5d252d..5314d19 100644 --- a/src/macros/generate/host/c/mod.rs +++ b/src/macros/generate/host/c/mod.rs @@ -36,10 +36,23 @@ pub fn generate(trixy: &CommandSpec, config: &TrixyConfig) -> String { format!( "\ /* C API */\n\ +// Workaround rust rules when implementing a foreign trait on a foreign type +#[derive(Debug)] +pub struct OurResult {{ + value: Result, +}} + +impl From> for OurResult {{ + fn from(value: Result) -> Self {{ + Self {{ value }} + }} +}} +/* The real C API */\n\ {}", rust_code ) } + /// This function generates the main c API provided by Trixy. /// This works for example like this: /// Turning this: diff --git a/src/parser/command_spec/checked.rs b/src/parser/command_spec/checked.rs index 221fdf6..1ed2ec2 100644 --- a/src/parser/command_spec/checked.rs +++ b/src/parser/command_spec/checked.rs @@ -36,9 +36,14 @@ pub enum Variant { Enumeration { namespace: Vec, }, + Result { + namespace: Vec, + }, + Namespace, /// The first (implicit) namespace, containing everything RootNamespace, + Function, Primitive, NamedType, @@ -59,7 +64,7 @@ impl Variant { } } -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] pub struct Namespace { pub name: Identifier, @@ -89,21 +94,21 @@ impl From for CommandSpec { } } -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] pub struct Structure { pub identifier: Identifier, pub contents: Vec, pub attributes: Vec, } -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] pub struct Enumeration { pub identifier: Identifier, pub states: Vec, pub attributes: Vec, } -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] pub struct Function { pub identifier: Identifier, pub inputs: Vec, @@ -206,7 +211,7 @@ pub struct NamedType { pub r#type: Type, } -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] pub struct DocNamedType { pub name: Identifier, pub r#type: Type, diff --git a/src/parser/parsing/checked/mod.rs b/src/parser/parsing/checked/mod.rs index 04ca1a7..5a8c47d 100644 --- a/src/parser/parsing/checked/mod.rs +++ b/src/parser/parsing/checked/mod.rs @@ -159,7 +159,7 @@ impl Parser { let mut functions = vec![]; for function in namespace.functions { - functions.push(self.process_function(function)?); + functions.push(self.process_function(function, &previous_namespaces)?); } let mut namespaces = vec![]; for namespace in namespace.namespaces { @@ -187,14 +187,15 @@ impl Parser { fn process_function( &mut self, mut function: UncheckedFunction, + parent_namespaces: &Vec, ) -> Result { let identifier = mem::take(&mut function.identifier.kind).to_identifier(Variant::Function); let mut inputs = vec![]; for input in function.inputs { - inputs.push(self.process_named_type(input)?); + inputs.push(self.process_named_type(input, parent_namespaces)?); } let output = if let Some(r#type) = function.output { - Some(self.process_type(r#type)?) + Some(self.process_type(r#type, parent_namespaces)?) } else { None }; @@ -269,7 +270,7 @@ impl Parser { }); let mut contents = vec![]; for named_type in structure.contents { - contents.push(self.process_doc_named_type(named_type)?); + contents.push(self.process_doc_named_type(named_type, parent_namespaces)?); } Ok(Structure { @@ -282,19 +283,21 @@ impl Parser { fn process_named_type( &mut self, mut named_type: UncheckedNamedType, + parent_namespaces: &Vec, ) -> Result { let name: Identifier = mem::take(&mut named_type.name.kind).to_identifier(Variant::NamedType); - let r#type: Type = self.process_type(named_type.r#type)?; + let r#type: Type = self.process_type(named_type.r#type, parent_namespaces)?; Ok(NamedType { name, r#type }) } fn process_doc_named_type( &mut self, mut doc_named_type: UncheckedDocNamedType, + parent_namespaces: &Vec, ) -> Result { let name: Identifier = mem::take(&mut doc_named_type.name.kind).to_identifier(Variant::DocNamedType); - let r#type: Type = self.process_type(doc_named_type.r#type)?; + let r#type: Type = self.process_type(doc_named_type.r#type, parent_namespaces)?; Ok(DocNamedType { name, r#type, @@ -302,14 +305,18 @@ impl Parser { }) } - fn process_type(&mut self, r#type: UncheckedType) -> Result { + fn process_type( + &mut self, + r#type: UncheckedType, + parent_namespaces: &Vec, + ) -> Result { match r#type { UncheckedType::Typical { identifier, generic_args, - } => self.process_typical_type(identifier, generic_args), + } => self.process_typical_type(identifier, generic_args, parent_namespaces), UncheckedType::Function { inputs, output } => { - self.process_function_type(inputs, output) + self.process_function_type(inputs, output, parent_namespaces) } } } @@ -318,6 +325,7 @@ impl Parser { &mut self, mut type_identifier: Token, generic_args: Vec, + parent_namespaces: &Vec, ) -> Result { fn match_to_vector_struct(matches: Vec<&UncheckedStructure>) -> Vec { matches @@ -401,7 +409,13 @@ impl Parser { .iter() .any(|(ident, _)| ident == &identifier.name) { - variant = Variant::Primitive; + if &identifier.name == "Result" { + variant = Variant::Result { + namespace: parent_namespaces.clone(), + }; + } else { + variant = Variant::Primitive; + } } else { return Err(ParsingError::TypeNotDeclared { r#type: identifier, @@ -461,7 +475,7 @@ impl Parser { let mut new_generic_args: Vec = vec![]; for generic_arg in generic_args { - new_generic_args.push(self.process_type(generic_arg)?); + new_generic_args.push(self.process_type(generic_arg, parent_namespaces)?); } Ok(Type::Typical { @@ -473,15 +487,16 @@ impl Parser { &mut self, inputs: Vec, output: Option>, + parent_namespaces: &Vec, ) -> Result { let inputs = inputs .into_iter() - .map(|input| self.process_named_type(input)) + .map(|input| self.process_named_type(input, parent_namespaces)) .collect::, ParsingError>>()?; let mut new_output = None; if let Some(output) = output { - new_output = Some(Box::new(self.process_type(*output)?)); + new_output = Some(Box::new(self.process_type(*output, parent_namespaces)?)); } Ok(Type::Function { diff --git a/src/types/c_headers/result.h b/src/types/c_headers/result.h new file mode 100644 index 0000000..f734e0d --- /dev/null +++ b/src/types/c_headers/result.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2023 - 2024: + * The Trinitrix Project + * SPDX-License-Identifier: LGPL-3.0-or-later + * + * 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 . + */ + +#ifndef TRIXY_RESULT_H +#define TRIXY_RESULT_H + +/** + * @brief A rust-like result type + * + * @detail + * This macro effectively generates a type name from the two generic + * parameters. The generated type name is always globally unique. + */ +#define Result(ok, err) struct result_##ok##_##err + +/** + * @brief The possibly states of a Result. + */ +enum ResultTag +{ + OK, + ERR, +}; + +#endif // TRIXY_RESULT_H diff --git a/src/types/mod.rs b/src/types/mod.rs index 2fe0b90..3e9b1fc 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -40,7 +40,7 @@ macro_rules! header { // NOTE: Every type here must have the [`Convertible`] implemented on it (@soispha) // And be added to the `convert/c/auxiliary/idendentifier/mod.rs` file // And add it to the types list (`./types_list.rs`) -pub const BASE_TYPES: [(&'static std::primitive::str, usize); 11] = [ +pub const BASE_TYPES: [(&'static std::primitive::str, usize); 12] = [ // Unsigned ("u8", 0), ("u16", 0), @@ -56,15 +56,19 @@ pub const BASE_TYPES: [(&'static std::primitive::str, usize); 11] = [ ("f64", 0), // Other ("String", 0), + ("Result", 2), // FIXME(@soispha): These work, but the generated code is not really ideal <2024-03-26> // ("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); 3] = - [header!("errno.h"), header!("string.h"), header!("vec.h")]; +pub const C_TYPE_HEADER: [(&'static std::primitive::str, &'static std::primitive::str); 4] = [ + header!("errno.h"), + header!("string.h"), + header!("vec.h"), + header!("result.h"), +]; pub fn header_names() -> std::string::String { C_TYPE_HEADER diff --git a/src/types/traits/convert_trait.rs b/src/types/traits/convert_trait.rs index 653f53b..8eb64ac 100644 --- a/src/types/traits/convert_trait.rs +++ b/src/types/traits/convert_trait.rs @@ -129,121 +129,93 @@ pub extern "C" fn string_free(ptr: *const c_char) { CString::drop_ptr(ptr); } -impl Convertible for Option { - type Ptr = *const ::Ptr; +// impl Convertible for Option { +// type Ptr = *const ::Ptr; +// +// fn into_ptr(self) -> Self::Ptr { +// if let Some(inner) = self { +// &inner.into_ptr() +// } else { +// ptr::null() +// } +// } +// +// fn from_ptr(_: Self::Ptr) -> Result { +// warn!( +// " +// 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`) +// " +// ); +// Ok(Option::default()) +// } +// } - fn into_ptr(self) -> Self::Ptr { - if let Some(inner) = self { - &inner.into_ptr() - } else { - ptr::null() - } - } - - fn from_ptr(_: Self::Ptr) -> Result { - warn!( - " - 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`) - " - ); - Ok(Option::default()) - } -} - -impl Convertible for Result { - type Ptr = *const ::Ptr; - - fn into_ptr(self) -> Self::Ptr { - match self { - Ok(ok) => &ok.into_ptr(), - Err(err) => { - errno::set(TypeConversionError::ResultWasErr { - original_message: err.to_string(), - }); - ptr::null() - } - } - } - - fn from_ptr(_: Self::Ptr) -> Result { - warn!( - " - 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`) - " - ); - todo!() - // Ok(Result::Ok(T::default())) - } -} - -impl Convertible for Vec { - type Ptr = crate::types::Vec<::Ptr>; - - fn into_ptr(self) -> Self::Ptr { - let data_vec: Vec<_> = self.into_iter().map(|val| val.into_ptr()).collect(); - let data_vec = ManuallyDrop::new(data_vec); - Self::Ptr { - data: data_vec.as_ptr(), - length: data_vec.len(), - capacity: data_vec.capacity(), - } - } - - fn from_ptr(ptr: Self::Ptr) -> Result { - if ptr.data.is_null() { - return Err(TypeConversionError::NullPointer); - } - // TODO(@soispha): Add this, when this feature is stable <2024-02-17> - // if !ptr.data.is_aligned() { - // return Err(TypeConversionError::NotAligned); - // } - let base_vec = unsafe { - // 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 ::Ptr, - ptr.length, - ptr.capacity, - ) - }; - - let vec: Vec<_> = base_vec - .into_iter() - .map(|val| ::from_ptr(val)) - .collect::, _>>()?; - Ok(vec) - } -} - -macro_rules! make_vec_free { - ($value:ident, $name:ident) => { - #[no_mangle] - pub extern "C" fn $name(ptr: crate::types::Vec<<$value as Convertible>::Ptr>) { - Vec::<$value>::drop_ptr(ptr); - } - }; -} - -// Unsigned -make_vec_free!(u8, vec_free_u8); -make_vec_free!(u16, vec_free_u16); -make_vec_free!(u32, vec_free_u32); -make_vec_free!(u64, vec_free_u64); -// Signed -make_vec_free!(i8, vec_free_i8); -make_vec_free!(i16, vec_free_i16); -make_vec_free!(i32, vec_free_i32); -make_vec_free!(i64, vec_free_i64); -// Float -make_vec_free!(f32, vec_free_f32); -make_vec_free!(f64, vec_free_f64); -// Other -make_vec_free!(String, vec_free_String); +// impl Convertible for Vec { +// type Ptr = crate::types::Vec<::Ptr>; +// +// fn into_ptr(self) -> Self::Ptr { +// let data_vec: Vec<_> = self.into_iter().map(|val| val.into_ptr()).collect(); +// let data_vec = ManuallyDrop::new(data_vec); +// Self::Ptr { +// data: data_vec.as_ptr(), +// length: data_vec.len(), +// capacity: data_vec.capacity(), +// } +// } +// +// fn from_ptr(ptr: Self::Ptr) -> Result { +// if ptr.data.is_null() { +// return Err(TypeConversionError::NullPointer); +// } +// // TODO(@soispha): Add this, when this feature is stable <2024-02-17> +// // if !ptr.data.is_aligned() { +// // return Err(TypeConversionError::NotAligned); +// // } +// let base_vec = unsafe { +// // 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 ::Ptr, +// ptr.length, +// ptr.capacity, +// ) +// }; +// +// let vec: Vec<_> = base_vec +// .into_iter() +// .map(|val| ::from_ptr(val)) +// .collect::, _>>()?; +// Ok(vec) +// } +// } +// +// macro_rules! make_vec_free { +// ($value:ident, $name:ident) => { +// #[no_mangle] +// pub extern "C" fn $name(ptr: crate::types::Vec<<$value as Convertible>::Ptr>) { +// Vec::<$value>::drop_ptr(ptr); +// } +// }; +// } +// +// // Unsigned +// make_vec_free!(u8, vec_free_u8); +// make_vec_free!(u16, vec_free_u16); +// make_vec_free!(u32, vec_free_u32); +// make_vec_free!(u64, vec_free_u64); +// // Signed +// make_vec_free!(i8, vec_free_i8); +// make_vec_free!(i16, vec_free_i16); +// make_vec_free!(i32, vec_free_i32); +// make_vec_free!(i64, vec_free_i64); +// // Float +// make_vec_free!(f32, vec_free_f32); +// make_vec_free!(f64, vec_free_f64); +// // Other +// make_vec_free!(String, vec_free_String); // FIXME(@soispha): Find a way to support these <2024-02-27> // make_vec_free!(Option, vec_free_Option); diff --git a/src/types/types_list.rs b/src/types/types_list.rs index e7aa3b7..f600ed8 100644 --- a/src/types/types_list.rs +++ b/src/types/types_list.rs @@ -23,24 +23,30 @@ // 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> -// NOTE(@soispha): All types added here must also have an added free impl for the vector type (./traits/convert_trait.rs) <2024-02-27> - use std::ffi::c_char; #[derive(Debug, Clone)] #[repr(C)] pub struct String(pub(crate) *const c_char); +/// The tag used to tag the c result Enumerations #[derive(Debug)] #[repr(C)] -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, +pub enum ResultTag { + Ok, + Err, } +// #[derive(Debug)] +// #[repr(C)] +// 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, +// } + // Unsigned pub use std::primitive::u16; pub use std::primitive::u32;