blob: ac6202356effd37c0781e02c86b3be6528319880 [file] [log] [blame]
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;
fn get_loc(item: &Item) -> String {
item.location()
.map(|x| x.to_string())
.unwrap_or_else(|| "unknown".to_owned())
}
pub(crate) 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 = ();
fn serialize<W: Write>(
&self,
ctx: &BindgenContext,
(): Self::Extra,
stack: &mut Vec<String>,
writer: &mut W,
) -> Result<(), CodegenError> {
match self.kind() {
ItemKind::Function(func) => {
func.serialize(ctx, self, 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;
fn serialize<W: Write>(
&self,
ctx: &BindgenContext,
item: 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!(),
};
let name = self.name();
// Function argoments stored as `(name, type_id)` tuples.
let args = {
let mut count = 0;
signature
.argument_types()
.iter()
.cloned()
.map(|(opt_name, type_id)| {
(
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_ty = signature.return_type();
// Write `ret_ty wrap_name(args) { return name(arg_names)' }`
ret_ty.serialize(ctx, (), stack, writer)?;
write!(writer, " {}(", wrap_name)?;
serialize_args(&args, ctx, writer)?;
write!(writer, ") {{ return {}(", name)?;
serialize_sep(", ", args.iter(), ctx, writer, |(name, _), _, buf| {
write!(buf, "{}", name).map_err(From::from)
})?;
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::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::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, ")")?;
write!(writer, " (")?;
serialize_sep(
", ",
signature.argument_types().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(())
}