| 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(()) |
| } |