forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			444 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			444 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| 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(())
 | |
| }
 | 
