use std::io::Write; use crate::callbacks::IntKind; use crate::ir::comp::CompKind; use crate::ir::context::{BindgenContext, TypeId}; use crate::ir::function::{Function, FunctionKind}; use crate::ir::item::Item; use crate::ir::item::ItemCanonicalName; use crate::ir::item_kind::ItemKind; use crate::ir::ty::{FloatKind, Type, TypeKind}; use super::{CodegenError, WrapAsVariadic}; fn get_loc(item: &Item) -> String { item.location() .map(|x| x.to_string()) .unwrap_or_else(|| "unknown".to_owned()) } pub(super) trait CSerialize<'a> { type Extra; fn serialize( &self, ctx: &BindgenContext, extra: Self::Extra, stack: &mut Vec, writer: &mut W, ) -> Result<(), CodegenError>; } impl<'a> CSerialize<'a> for Item { type Extra = &'a Option; fn serialize( &self, ctx: &BindgenContext, extra: Self::Extra, stack: &mut Vec, writer: &mut W, ) -> Result<(), CodegenError> { match self.kind() { ItemKind::Function(func) => { func.serialize(ctx, (self, extra), stack, writer) } kind => Err(CodegenError::Serialize { msg: format!("Cannot serialize item kind {:?}", kind), loc: get_loc(self), }), } } } impl<'a> CSerialize<'a> for Function { type Extra = (&'a Item, &'a Option); fn serialize( &self, ctx: &BindgenContext, (item, wrap_as_variadic): Self::Extra, stack: &mut Vec, writer: &mut W, ) -> Result<(), CodegenError> { if self.kind() != FunctionKind::Function { return Err(CodegenError::Serialize { msg: format!( "Cannot serialize function kind {:?}", self.kind(), ), loc: get_loc(item), }); } let signature = match ctx.resolve_type(self.signature()).kind() { TypeKind::Function(signature) => signature, _ => unreachable!(), }; assert!(!signature.is_variadic()); let name = self.name(); // Function argoments stored as `(name, type_id)` tuples. let args = { let mut count = 0; let idx_to_prune = wrap_as_variadic.as_ref().map( |WrapAsVariadic { idx_of_va_list_arg, .. }| *idx_of_va_list_arg, ); signature .argument_types() .iter() .cloned() .enumerate() .filter_map(|(idx, (opt_name, type_id))| { if Some(idx) == idx_to_prune { None } else { Some(( opt_name.unwrap_or_else(|| { let name = format!("arg_{}", count); count += 1; name }), type_id, )) } }) .collect::>() }; // The name used for the wrapper self. let wrap_name = format!("{}{}", name, ctx.wrap_static_fns_suffix()); // The function's return type let (ret_item, ret_ty) = { let type_id = signature.return_type(); let ret_item = ctx.resolve_item(type_id); let ret_ty = ret_item.expect_type(); // Write `ret_ty`. ret_ty.serialize(ctx, ret_item, stack, writer)?; (ret_item, ret_ty) }; const INDENT: &str = " "; // Write `wrap_name(args`. write!(writer, " {}(", wrap_name)?; serialize_args(&args, ctx, writer)?; if wrap_as_variadic.is_none() { // Write `) { name(` if the function returns void and `) { return name(` if it does not. if ret_ty.is_void() { write!(writer, ") {{ {}(", name)?; } else { write!(writer, ") {{ return {}(", name)?; } } else { // Write `, ...) {` writeln!(writer, ", ...) {{")?; // Declare the return type `RET_TY ret;` if their is a need to do so if !ret_ty.is_void() { write!(writer, "{INDENT}")?; ret_ty.serialize(ctx, ret_item, stack, writer)?; writeln!(writer, " ret;")?; } // Setup va_list writeln!(writer, "{INDENT}va_list ap;\n")?; writeln!( writer, "{INDENT}va_start(ap, {});", args.last().unwrap().0 )?; write!(writer, "{INDENT}")?; // Write `ret = name(` or `name(` depending if the function returns something if !ret_ty.is_void() { write!(writer, "ret = ")?; } write!(writer, "{}(", name)?; } // Get the arguments names and insert at the right place if necessary `ap` let mut args: Vec<_> = args.into_iter().map(|(name, _)| name).collect(); if let Some(WrapAsVariadic { idx_of_va_list_arg, .. }) = wrap_as_variadic { args.insert(*idx_of_va_list_arg, "ap".to_owned()); } // Write `arg_names);`. serialize_sep(", ", args.iter(), ctx, writer, |name, _, buf| { write!(buf, "{}", name).map_err(From::from) })?; #[rustfmt::skip] write!(writer, ");{}", if wrap_as_variadic.is_none() { " " } else { "\n" })?; if wrap_as_variadic.is_some() { // End va_list and return the result if their is one writeln!(writer, "{INDENT}va_end(ap);")?; if !ret_ty.is_void() { writeln!(writer, "{INDENT}return ret;")?; } } writeln!(writer, "}}")?; Ok(()) } } impl<'a> CSerialize<'a> for TypeId { type Extra = (); fn serialize( &self, ctx: &BindgenContext, (): Self::Extra, stack: &mut Vec, writer: &mut W, ) -> Result<(), CodegenError> { let item = ctx.resolve_item(*self); item.expect_type().serialize(ctx, item, stack, writer) } } impl<'a> CSerialize<'a> for Type { type Extra = &'a Item; fn serialize( &self, ctx: &BindgenContext, item: Self::Extra, stack: &mut Vec, writer: &mut W, ) -> Result<(), CodegenError> { match self.kind() { TypeKind::Void => { if self.is_const() { write!(writer, "const ")?; } write!(writer, "void")? } TypeKind::NullPtr => { if self.is_const() { write!(writer, "const ")?; } write!(writer, "nullptr_t")? } TypeKind::Int(int_kind) => { if self.is_const() { write!(writer, "const ")?; } match int_kind { IntKind::Bool => write!(writer, "bool")?, IntKind::SChar => write!(writer, "signed char")?, IntKind::UChar => write!(writer, "unsigned char")?, IntKind::WChar => write!(writer, "wchar_t")?, IntKind::Short => write!(writer, "short")?, IntKind::UShort => write!(writer, "unsigned short")?, IntKind::Int => write!(writer, "int")?, IntKind::UInt => write!(writer, "unsigned int")?, IntKind::Long => write!(writer, "long")?, IntKind::ULong => write!(writer, "unsigned long")?, IntKind::LongLong => write!(writer, "long long")?, IntKind::ULongLong => write!(writer, "unsigned long long")?, IntKind::Char { .. } => write!(writer, "char")?, int_kind => { return Err(CodegenError::Serialize { msg: format!( "Cannot serialize integer kind {:?}", int_kind ), loc: get_loc(item), }) } } } TypeKind::Float(float_kind) => { if self.is_const() { write!(writer, "const ")?; } match float_kind { FloatKind::Float16 => write!(writer, "_Float16")?, FloatKind::Float => write!(writer, "float")?, FloatKind::Double => write!(writer, "double")?, FloatKind::LongDouble => write!(writer, "long double")?, FloatKind::Float128 => write!(writer, "__float128")?, } } TypeKind::Complex(float_kind) => { if self.is_const() { write!(writer, "const ")?; } match float_kind { FloatKind::Float16 => write!(writer, "_Float16 complex")?, FloatKind::Float => write!(writer, "float complex")?, FloatKind::Double => write!(writer, "double complex")?, FloatKind::LongDouble => { write!(writer, "long double complex")? } FloatKind::Float128 => write!(writer, "__complex128")?, } } TypeKind::Alias(type_id) => { if let Some(name) = self.name() { if self.is_const() { write!(writer, "const {}", name)?; } else { write!(writer, "{}", name)?; } } else { type_id.serialize(ctx, (), stack, writer)?; } } TypeKind::Array(type_id, length) => { type_id.serialize(ctx, (), stack, writer)?; write!(writer, " [{}]", length)? } TypeKind::Function(signature) => { if self.is_const() { stack.push("const ".to_string()); } signature.return_type().serialize( ctx, (), &mut vec![], writer, )?; write!(writer, " (")?; while let Some(item) = stack.pop() { write!(writer, "{}", item)?; } write!(writer, ")")?; let args = signature.argument_types(); if args.is_empty() { write!(writer, " (void)")?; } else { write!(writer, " (")?; serialize_sep( ", ", args.iter(), ctx, writer, |(name, type_id), ctx, buf| { let mut stack = vec![]; if let Some(name) = name { stack.push(name.clone()); } type_id.serialize(ctx, (), &mut stack, buf) }, )?; write!(writer, ")")? } } TypeKind::ResolvedTypeRef(type_id) => { if self.is_const() { write!(writer, "const ")?; } type_id.serialize(ctx, (), stack, writer)? } TypeKind::Pointer(type_id) => { if self.is_const() { stack.push("*const ".to_owned()); } else { stack.push("*".to_owned()); } type_id.serialize(ctx, (), stack, writer)? } TypeKind::Comp(comp_info) => { if self.is_const() { write!(writer, "const ")?; } let name = item.canonical_name(ctx); match comp_info.kind() { CompKind::Struct => write!(writer, "struct {}", name)?, CompKind::Union => write!(writer, "union {}", name)?, }; } TypeKind::Enum(_enum_ty) => { if self.is_const() { write!(writer, "const ")?; } let name = item.canonical_name(ctx); write!(writer, "enum {}", name)?; } ty => { return Err(CodegenError::Serialize { msg: format!("Cannot serialize type kind {:?}", ty), loc: get_loc(item), }) } }; if !stack.is_empty() { write!(writer, " ")?; while let Some(item) = stack.pop() { write!(writer, "{}", item)?; } } Ok(()) } } fn serialize_args( args: &[(String, TypeId)], ctx: &BindgenContext, writer: &mut W, ) -> Result<(), CodegenError> { if args.is_empty() { write!(writer, "void")?; } else { serialize_sep( ", ", args.iter(), ctx, writer, |(name, type_id), ctx, buf| { type_id.serialize(ctx, (), &mut vec![name.clone()], buf) }, )?; } Ok(()) } fn serialize_sep< W: Write, F: FnMut(I::Item, &BindgenContext, &mut W) -> Result<(), CodegenError>, I: Iterator, >( sep: &str, mut iter: I, ctx: &BindgenContext, buf: &mut W, mut f: F, ) -> Result<(), CodegenError> { if let Some(item) = iter.next() { f(item, ctx, buf)?; let sep = sep.as_bytes(); for item in iter { buf.write_all(sep)?; f(item, ctx, buf)?; } } Ok(()) }