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.
This commit is contained in:
parent
4b7cd3a0b7
commit
a669f399a8
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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::<Vec<String>>()
|
||||
.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::<Vec<String>>()
|
||||
.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 {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,12 +20,14 @@
|
|||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<Type>)) -> bool,
|
||||
) -> Vec<(Identifier, Vec<Type>)> {
|
||||
fn filter_type(ty: &Type) -> Vec<(Identifier, Vec<Type>)> {
|
||||
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<Type> {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Box<Type>>) -> 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<Self, trixy::types::error::TypeConversionError> {
|
||||
unreachable!("This should probably not be called?");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fn to_c_typical(identifier: &Identifier, generic_args: &Vec<Type>) -> 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: <Result<TrainedDog, TrainingMistake> as Convertible>::Ptr,
|
||||
<Result<#ident_ok, #ident_err> as Convertible>::Ptr
|
||||
#nasp_path #ident
|
||||
}
|
||||
}
|
||||
"Option" => {
|
||||
|
|
|
@ -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[..])
|
||||
}
|
||||
|
|
|
@ -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<T, E> {{
|
||||
value: Result<T, E>,
|
||||
}}
|
||||
|
||||
impl<T, E> From<Result<T, E>> for OurResult<T, E> {{
|
||||
fn from(value: Result<T, E>) -> 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:
|
||||
|
|
|
@ -36,9 +36,14 @@ pub enum Variant {
|
|||
Enumeration {
|
||||
namespace: Vec<Identifier>,
|
||||
},
|
||||
Result {
|
||||
namespace: Vec<Identifier>,
|
||||
},
|
||||
|
||||
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<Namespace> for CommandSpec {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
|
||||
pub struct Structure {
|
||||
pub identifier: Identifier,
|
||||
pub contents: Vec<DocNamedType>,
|
||||
pub attributes: Vec<Attribute>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
|
||||
pub struct Enumeration {
|
||||
pub identifier: Identifier,
|
||||
pub states: Vec<DocIdentifier>,
|
||||
pub attributes: Vec<Attribute>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
|
||||
pub struct Function {
|
||||
pub identifier: Identifier,
|
||||
pub inputs: Vec<NamedType>,
|
||||
|
@ -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,
|
||||
|
|
|
@ -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<Identifier>,
|
||||
) -> Result<Function, ParsingError> {
|
||||
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<Identifier>,
|
||||
) -> Result<NamedType, ParsingError> {
|
||||
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<Identifier>,
|
||||
) -> Result<DocNamedType, ParsingError> {
|
||||
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<Type, ParsingError> {
|
||||
fn process_type(
|
||||
&mut self,
|
||||
r#type: UncheckedType,
|
||||
parent_namespaces: &Vec<Identifier>,
|
||||
) -> Result<Type, ParsingError> {
|
||||
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<UncheckedType>,
|
||||
parent_namespaces: &Vec<Identifier>,
|
||||
) -> Result<Type, ParsingError> {
|
||||
fn match_to_vector_struct(matches: Vec<&UncheckedStructure>) -> Vec<Identifier> {
|
||||
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<checked::Type> = 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<UncheckedNamedType>,
|
||||
output: Option<Box<UncheckedType>>,
|
||||
parent_namespaces: &Vec<Identifier>,
|
||||
) -> Result<Type, ParsingError> {
|
||||
let inputs = inputs
|
||||
.into_iter()
|
||||
.map(|input| self.process_named_type(input))
|
||||
.map(|input| self.process_named_type(input, parent_namespaces))
|
||||
.collect::<Result<Vec<NamedType>, 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 {
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (C) 2023 - 2024:
|
||||
* The Trinitrix Project <soispha@vhack.eu, antifallobst@systemausfall.org>
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
|
@ -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
|
||||
|
|
|
@ -129,121 +129,93 @@ pub extern "C" fn string_free(ptr: *const c_char) {
|
|||
CString::drop_ptr(ptr);
|
||||
}
|
||||
|
||||
impl<T: Convertible> Convertible for Option<T> {
|
||||
type Ptr = *const <T as Convertible>::Ptr;
|
||||
// impl<T: Convertible> Convertible for Option<T> {
|
||||
// type Ptr = *const <T as Convertible>::Ptr;
|
||||
//
|
||||
// fn into_ptr(self) -> Self::Ptr {
|
||||
// if let Some(inner) = self {
|
||||
// &inner.into_ptr()
|
||||
// } else {
|
||||
// ptr::null()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fn from_ptr(_: Self::Ptr) -> Result<Self, error::TypeConversionError> {
|
||||
// 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<T>`)
|
||||
// "
|
||||
// );
|
||||
// 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<Self, error::TypeConversionError> {
|
||||
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<T>`)
|
||||
"
|
||||
);
|
||||
Ok(Option::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Convertible, E: Error> Convertible for Result<T, E> {
|
||||
type Ptr = *const <T as Convertible>::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<Self, error::TypeConversionError> {
|
||||
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<T>`)
|
||||
"
|
||||
);
|
||||
todo!()
|
||||
// Ok(Result::Ok(T::default()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Convertible> Convertible for Vec<T> {
|
||||
type Ptr = crate::types::Vec<<T as Convertible>::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<Self, error::TypeConversionError> {
|
||||
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 <T as Convertible>::Ptr,
|
||||
ptr.length,
|
||||
ptr.capacity,
|
||||
)
|
||||
};
|
||||
|
||||
let vec: Vec<_> = base_vec
|
||||
.into_iter()
|
||||
.map(|val| <T as Convertible>::from_ptr(val))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
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<T: Convertible> Convertible for Vec<T> {
|
||||
// type Ptr = crate::types::Vec<<T as Convertible>::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<Self, error::TypeConversionError> {
|
||||
// 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 <T as Convertible>::Ptr,
|
||||
// ptr.length,
|
||||
// ptr.capacity,
|
||||
// )
|
||||
// };
|
||||
//
|
||||
// let vec: Vec<_> = base_vec
|
||||
// .into_iter()
|
||||
// .map(|val| <T as Convertible>::from_ptr(val))
|
||||
// .collect::<Result<Vec<_>, _>>()?;
|
||||
// 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);
|
||||
|
|
|
@ -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<T> {
|
||||
/// 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<T> {
|
||||
// /// 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;
|
||||
|
|
Reference in New Issue