| 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<W: Write>( | |
| &self, | |
| ctx: &BindgenContext, | |
| extra: Self::Extra, | |
| stack: &mut Vec<String>, | |
| writer: &mut W, | |
| ) -> Result<(), CodegenError>; | |
| } | |
| impl<'a> CSerialize<'a> for Item { | |
| type Extra = &'a Option<WrapAsVariadic>; | |
| fn serialize<W: Write>( | |
| &self, | |
| ctx: &BindgenContext, | |
| extra: Self::Extra, | |
| stack: &mut Vec<String>, | |
| 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<WrapAsVariadic>); | |
| fn serialize<W: Write>( | |
| &self, | |
| ctx: &BindgenContext, | |
| (item, wrap_as_variadic): Self::Extra, | |
| stack: &mut Vec<String>, | |
| 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::<Vec<_>>() | |
| }; | |
| // 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<W: Write>( | |
| &self, | |
| ctx: &BindgenContext, | |
| (): Self::Extra, | |
| stack: &mut Vec<String>, | |
| 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<W: Write>( | |
| &self, | |
| ctx: &BindgenContext, | |
| item: Self::Extra, | |
| stack: &mut Vec<String>, | |
| 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<W: Write>( | |
| 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(()) | |
| } |