use crate::ir::comp::SpecialMemberKind;
use crate::ir::function::Visibility;
use crate::ir::layout::Layout;
use crate::{ir::context::BindgenContext, BindgenOptions};
use proc_macro2::{Ident, Span, TokenStream};
use quote::TokenStreamExt;
pub mod attributes {
use proc_macro2::{Ident, Span, TokenStream};
use std::str::FromStr;
pub fn repr(which: &str) -> TokenStream {
let which = Ident::new(which, Span::call_site());
quote! {
#[repr( #which )]
}
}
pub fn repr_list(which_ones: &[&str]) -> TokenStream {
let which_ones = which_ones
.iter()
.cloned()
.map(|one| TokenStream::from_str(one).expect("repr to be valid"));
quote! {
#[repr( #( #which_ones ),* )]
}
}
pub fn derives(which_ones: &[&str]) -> TokenStream {
let which_ones = which_ones
.iter()
.cloned()
.map(|one| TokenStream::from_str(one).expect("derive to be valid"));
quote! {
#[derive( #( #which_ones ),* )]
}
}
pub fn inline() -> TokenStream {
quote! {
#[inline]
}
}
pub fn must_use() -> TokenStream {
quote! {
#[must_use]
}
}
pub fn non_exhaustive() -> TokenStream {
quote! {
#[non_exhaustive]
}
}
pub fn doc(comment: String) -> TokenStream {
TokenStream::from_str(&comment).unwrap()
}
pub fn link_name(name: &str) -> TokenStream {
let name = format!("\u{1}{}", name);
quote! {
#[link_name = #name]
}
}
}
pub trait CppSemanticAttributeCreator {
fn do_add(&mut self, ts: TokenStream);
fn is_enabled(&self) -> bool;
fn add(&mut self, tokens: TokenStream) {
if self.is_enabled() {
self.do_add(quote! {
#[cpp_semantics(#tokens)]
})
}
}
fn add_ident(&mut self, desc: &str) {
if self.is_enabled() {
let id = Ident::new(desc, Span::call_site());
self.add(quote! { #id })
}
}
fn special_member(&mut self, kind: SpecialMemberKind) {
let kind_str = match kind {
SpecialMemberKind::DefaultConstructor => "default_ctor",
SpecialMemberKind::CopyConstructor => "copy_ctor",
SpecialMemberKind::MoveConstructor => "move_ctor",
SpecialMemberKind::Destructor => "dtor",
SpecialMemberKind::AssignmentOperator => "assignment_operator",
};
self.add(quote! {
special_member(#kind_str)
})
}
fn original_name(&mut self, name: &str) {
self.add(quote! {
original_name(#name)
})
}
fn ret_type_reference(&mut self) {
self.add_ident("ret_type_reference")
}
fn ret_type_rvalue_reference(&mut self) {
self.add_ident("ret_type_rvalue_reference")
}
fn arg_type_reference(&mut self, arg_name: &Ident) {
self.add(quote! {
arg_type_reference(#arg_name)
})
}
fn field_type_reference(&mut self) {
self.add_ident("reference")
}
fn field_type_rvalue_reference(&mut self) {
self.add_ident("rvalue_reference")
}
fn is_virtual(&mut self) {
self.add_ident("bindgen_virtual")
}
fn arg_type_rvalue_reference(&mut self, arg_name: &Ident) {
self.add(quote! {
arg_type_rvalue_reference(#arg_name)
})
}
fn is_pure_virtual(&mut self) {
self.add_ident("pure_virtual")
}
fn visibility(&mut self, visibility: Visibility) {
match visibility {
Visibility::Protected => self.add_ident("visibility_protected"),
Visibility::Private => self.add_ident("visibility_private"),
_ => {}
}
}
fn incomprehensible_param_in_arg_or_return(&mut self) {
self.add_ident("incomprehensible_param_in_arg_or_return")
}
fn discards_template_param(&mut self) {
self.add_ident("unused_template_param")
}
fn deleted_fn(&mut self) {
self.add_ident("deleted")
}
fn defaulted_fn(&mut self) {
self.add_ident("defaulted")
}
fn layout(&mut self, layout: &Layout) {
let sz = ast_ty::int_expr(layout.size as i64);
let align = ast_ty::int_expr(layout.align as i64);
let packed = if layout.packed {
quote! { true }
} else {
quote! { false }
};
self.add(quote! {
layout(#sz, #align, #packed)
})
}
}
pub struct CppSemanticAttributeAdder<'a> {
enabled: bool,
attrs: &'a mut Vec<TokenStream>,
}
impl<'a> CppSemanticAttributeAdder<'a> {
pub(crate) fn new(
opts: &BindgenOptions,
attrs: &'a mut Vec<TokenStream>,
) -> Self {
Self {
enabled: opts.cpp_semantic_attributes,
attrs,
}
}
}
impl<'a> CppSemanticAttributeCreator for CppSemanticAttributeAdder<'a> {
fn do_add(&mut self, ts: TokenStream) {
self.attrs.push(ts)
}
fn is_enabled(&self) -> bool {
self.enabled
}
}
pub struct CppSemanticAttributeSingle {
enabled: bool,
attr: TokenStream,
}
impl CppSemanticAttributeSingle {
pub(crate) fn new(opts: &BindgenOptions) -> Self {
Self {
enabled: opts.cpp_semantic_attributes,
attr: quote! {},
}
}
pub(crate) fn result(self) -> TokenStream {
self.attr
}
}
impl CppSemanticAttributeCreator for CppSemanticAttributeSingle {
fn do_add(&mut self, ts: TokenStream) {
self.attr = ts;
}
fn is_enabled(&self) -> bool {
self.enabled
}
}
pub fn blob(ctx: &BindgenContext, layout: Layout) -> TokenStream {
let opaque = layout.opaque();
let ty_name = match opaque.known_rust_type_for_array(ctx) {
Some(ty) => ty,
None => {
warn!("Found unknown alignment on code generation!");
"u8"
}
};
let ty_name = Ident::new(ty_name, Span::call_site());
let data_len = opaque.array_size(ctx).unwrap_or(layout.size);
if data_len == 1 {
quote! {
#ty_name
}
} else {
quote! {
[ #ty_name ; #data_len ]
}
}
}
pub fn integer_type(
ctx: &BindgenContext,
layout: Layout,
) -> Option<TokenStream> {
let name = Layout::known_type_for_size(ctx, layout.size)?;
let name = Ident::new(name, Span::call_site());
Some(quote! { #name })
}
pub fn bitfield_unit(ctx: &BindgenContext, layout: Layout) -> TokenStream {
let mut tokens = quote! {};
if ctx.options().enable_cxx_namespaces {
tokens.append_all(quote! { root:: });
}
let size = layout.size;
tokens.append_all(quote! {
__BindgenBitfieldUnit<[u8; #size]>
});
tokens
}
pub mod ast_ty {
use crate::ir::context::BindgenContext;
use crate::ir::function::FunctionSig;
use crate::ir::layout::Layout;
use crate::ir::ty::FloatKind;
use proc_macro2::{self, TokenStream};
use std::str::FromStr;
pub fn c_void(ctx: &BindgenContext) -> TokenStream {
match ctx.options().ctypes_prefix {
Some(ref prefix) => {
let prefix = TokenStream::from_str(prefix.as_str()).unwrap();
quote! {
#prefix::c_void
}
}
None => {
if ctx.options().use_core &&
ctx.options().rust_features.core_ffi_c_void
{
quote! { ::core::ffi::c_void }
} else {
quote! { ::std::os::raw::c_void }
}
}
}
}
pub fn raw_type(ctx: &BindgenContext, name: &str) -> TokenStream {
let ident = ctx.rust_ident_raw(name);
match ctx.options().ctypes_prefix {
Some(ref prefix) => {
let prefix = TokenStream::from_str(prefix.as_str()).unwrap();
quote! {
#prefix::#ident
}
}
None => {
if ctx.options().use_core &&
ctx.options().rust_features().core_ffi_c
{
quote! {
::core::ffi::#ident
}
} else {
quote! {
::std::os::raw::#ident
}
}
}
}
}
pub fn float_kind_rust_type(
ctx: &BindgenContext,
fk: FloatKind,
layout: Option<Layout>,
) -> TokenStream {
match (fk, ctx.options().convert_floats) {
(FloatKind::Float, true) => quote! { f32 },
(FloatKind::Double, true) => quote! { f64 },
(FloatKind::Float, false) => raw_type(ctx, "c_float"),
(FloatKind::Double, false) => raw_type(ctx, "c_double"),
(FloatKind::LongDouble, _) => {
match layout {
Some(layout) => {
match layout.size {
4 => quote! { f32 },
8 => quote! { f64 },
_ => super::integer_type(ctx, layout)
.unwrap_or(quote! { f64 }),
}
}
None => {
debug_assert!(
false,
"How didn't we know the layout for a primitive type?"
);
quote! { f64 }
}
}
}
(FloatKind::Float128, _) => {
if ctx.options().rust_features.i128_and_u128 {
quote! { u128 }
} else {
quote! { [u64; 2] }
}
}
}
}
pub fn int_expr(val: i64) -> TokenStream {
let val = proc_macro2::Literal::i64_unsuffixed(val);
quote!(#val)
}
pub fn uint_expr(val: u64) -> TokenStream {
let val = proc_macro2::Literal::u64_unsuffixed(val);
quote!(#val)
}
pub fn byte_array_expr(bytes: &[u8]) -> TokenStream {
let mut bytes: Vec<_> = bytes.to_vec();
bytes.push(0);
quote! { [ #(#bytes),* ] }
}
pub fn cstr_expr(mut string: String) -> TokenStream {
string.push('\0');
let b = proc_macro2::Literal::byte_string(string.as_bytes());
quote! {
#b
}
}
pub fn float_expr(ctx: &BindgenContext, f: f64) -> Result<TokenStream, ()> {
if f.is_finite() {
let val = proc_macro2::Literal::f64_unsuffixed(f);
return Ok(quote!(#val));
}
let prefix = ctx.trait_prefix();
if f.is_nan() {
return Ok(quote! {
::#prefix::f64::NAN
});
}
if f.is_infinite() {
return Ok(if f.is_sign_positive() {
quote! {
::#prefix::f64::INFINITY
}
} else {
quote! {
::#prefix::f64::NEG_INFINITY
}
});
}
warn!("Unknown non-finite float number: {:?}", f);
Err(())
}
pub fn arguments_from_signature(
signature: &FunctionSig,
ctx: &BindgenContext,
) -> Vec<TokenStream> {
let mut unnamed_arguments = 0;
signature
.argument_types()
.iter()
.map(|&(ref name, _ty)| match *name {
Some(ref name) => {
let name = ctx.rust_ident(name);
quote! { #name }
}
None => {
unnamed_arguments += 1;
let name =
ctx.rust_ident(format!("arg{}", unnamed_arguments));
quote! { #name }
}
})
.collect()
}
}