Source code

Revision control

Copy as Markdown

Other Tools

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