blob: dc28501fe6ae6fdf84953440e6b227b06070019a [file] [log] [blame] [edit]
// Part of the Crubit project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//! Generates Rust bindings for C++ enums.
use arc_anyhow::Result;
use code_gen_utils::{expect_format_cc_ident, make_rs_ident};
use database::code_snippet::{ApiSnippets, Feature, GeneratedItem};
use database::BindingsGenerator;
use ir::Enum;
use proc_macro2::Literal;
use quote::{quote, ToTokens};
use std::collections::HashMap;
use std::rc::Rc;
/// Implementation of `BindingsGenerator::generate_enum`.
pub fn generate_enum(db: &dyn BindingsGenerator, enum_: Rc<Enum>) -> Result<ApiSnippets> {
let ident = expect_format_cc_ident(&enum_.cc_name.identifier);
let namespace_qualifier = db.ir().namespace_qualifier(&enum_).format_for_cc()?;
let fully_qualified_cc_name = quote! { #namespace_qualifier #ident }.to_string();
let name = make_rs_ident(&enum_.rs_name.identifier);
let underlying_type = db.rs_type_kind(enum_.underlying_type.clone())?;
let enumerators = enum_.enumerators.iter().flatten().map(|enumerator| {
if let Some(unknown_attr) = &enumerator.unknown_attr {
let comment = format!(
"Omitting bindings for {ident}\nreason: unknown attribute(s): {unknown_attr}",
ident = &enumerator.identifier.identifier
);
return quote! {
__COMMENT__ #comment
};
}
let ident = make_rs_ident(&enumerator.identifier.identifier);
let value = if underlying_type.is_bool() {
if enumerator.value.wrapped_value == 0 {
quote! {false}
} else {
quote! {true}
}
} else {
if enumerator.value.is_negative {
Literal::i64_unsuffixed(enumerator.value.wrapped_value as i64).into_token_stream()
} else {
Literal::u64_unsuffixed(enumerator.value.wrapped_value).into_token_stream()
}
};
quote! {pub const #ident: #name = #name(#value);}
});
let underlying_type_tokens = underlying_type.to_token_stream(db);
let annotation = format!("CRUBIT_ANNOTATE: cpp_type={fully_qualified_cc_name}");
let item = quote! {
#[repr(transparent)]
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, PartialOrd, Ord)]
#[doc=#annotation]
pub struct #name(#underlying_type_tokens);
impl #name {
#(#enumerators)*
}
impl From<#underlying_type_tokens> for #name {
fn from(value: #underlying_type_tokens) -> #name {
#name(value)
}
}
impl From<#name> for #underlying_type_tokens {
fn from(value: #name) -> #underlying_type_tokens {
value.0
}
}
};
Ok(ApiSnippets {
generated_items: HashMap::from([(enum_.id, GeneratedItem::Enum(item))]),
features: Feature::register_tool.into(),
..Default::default()
})
}