mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 10:18:41 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			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(())
 | 
						|
}
 |