| // 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 | |
| use crate::code_snippet::{ | |
| ApiSnippets, BindingsInfo, NoBindingsReason, ResolvedTypeName, Visibility, | |
| }; | |
| use crate::function_types::{FunctionId, GeneratedFunction, ImplKind}; | |
| use crate::rs_snippet::{LifetimeOptions, RsTypeKind}; | |
| use arc_anyhow::{anyhow, Result}; | |
| use crubit_abi_type::CrubitAbiType; | |
| use error_report::{ErrorReporting, ReportFatalError}; | |
| use ffi_types::Environment; | |
| use ir::{BazelLabel, CcType, Enum, Func, Record, UnqualifiedIdentifier, IR}; | |
| use proc_macro2::Ident; | |
| use std::collections::HashMap; | |
| use std::rc::Rc; | |
| #[unsafe(no_mangle)] | |
| pub fn test_again() {} | |
| #[derive(Clone)] | |
| pub struct CodegenFunctions { | |
| pub generate_enum: fn(&dyn BindingsGenerator, Rc<Enum>) -> Result<ApiSnippets>, | |
| pub generate_item: fn(&dyn BindingsGenerator, ir::Item) -> Result<ApiSnippets>, | |
| pub generate_record: fn(&dyn BindingsGenerator, Rc<Record>) -> Result<ApiSnippets>, | |
| } | |
| memoized::query_group! { | |
| pub trait BindingsGenerator<'db> { | |
| #[input] | |
| fn ir(&self) -> &'db IR; | |
| #[input] | |
| fn errors(&self) -> &'db dyn ErrorReporting; | |
| #[input] | |
| /// A collection of errors that should cause bindings generation to fail. | |
| /// | |
| /// These errors should be issued only in response to misusage of Crubit itself, such as | |
| /// incorrect use of Crubit-specific annotations. | |
| fn fatal_errors(&self) -> &'db dyn ReportFatalError; | |
| #[input] | |
| fn environment(&self) -> Environment; | |
| #[input] | |
| fn codegen_functions(&self) -> CodegenFunctions; | |
| #[break_cycles_with = false] | |
| /// Returns true if the given Rust type is an unsafe type, such as a raw pointer. | |
| /// | |
| /// Implementation: rs_bindings_from_cc/generate_bindings/lib.rs?q=function:is_rs_type_kind_unsafe | |
| fn is_rs_type_kind_unsafe(&self, rs_type_kind: RsTypeKind) -> bool; | |
| /// Returns the bindings info for the given item, or an error if the item is not supported. | |
| /// | |
| /// Implementation: rs_bindings_from_cc/generate_bindings/has_bindings.rs?q=function:has_bindings | |
| fn has_bindings(&self, item: ir::Item) -> Result<BindingsInfo, NoBindingsReason>; | |
| /// Returns the Rust type kind of the given C++ type, optionally filling in missing | |
| /// reference lifetimes with the elided lifetime (`'_`). | |
| /// | |
| /// An `Ok()` return value does not necessarily imply that the resulting `RsTypeKind` is | |
| /// usable in APIs: callers must also check the result of `db::type_visibility()` for | |
| /// the type, to see if it is usable within a specific crate. Eventually, all types will | |
| /// have a successful non-error return value, even if the type is not generally usable. | |
| /// Instead, restrictions will always be done via `type_visibility`. | |
| /// | |
| /// TODO(b/409128537): never return `Err` here, instead check `type_visibility` | |
| /// | |
| /// Implementation: rs_bindings_from_cc/generate_bindings/rs_type_kind.rs?q=function:rs_type_kind_with_lifetime_elision | |
| fn rs_type_kind_with_lifetime_elision(&self, cc_type: CcType, lifetime_options: LifetimeOptions) -> Result<RsTypeKind>; | |
| /// Returns the generated bindings for the given function. | |
| /// | |
| /// `derived_record` is a derived class type which re-exports `func` as a | |
| /// method on this record. `func` must be a method on a base class of | |
| /// `derived_record`, if present. | |
| /// | |
| /// Returns: | |
| /// | |
| /// * `Err(_)`: couldn't import the function, emit an `UnsupportedItem`. | |
| /// * `Ok(None)`: the function imported as "nothing". (For example, a defaulted | |
| /// destructor might be mapped to no `Drop` impl at all.) | |
| /// * `Ok(GeneratedFunction)`: The Rust function definition, | |
| /// thunk FFI definition, and function ID. | |
| /// | |
| /// Note that unlike other `generate_*` functions, this function may return `Ok()` but still | |
| /// fail to generate bindings (if `GeneratedFunction.status` is `Err`), and may fail | |
| /// to generate bindings even if `has_bindings` would return `Ok`. In general, one cannot | |
| /// rely on the bindings of a function being generated correctly, except for `Drop`. | |
| /// | |
| /// Implementation: rs_bindings_from_cc/generate_bindings/generate_function.rs?q=function:generate_function | |
| fn generate_function(&self, func: Rc<Func>, derived_record: Option<Rc<Record>>) -> Result<Option<GeneratedFunction>>; | |
| /// You should call is_function_ambiguous() instead. | |
| /// | |
| /// Identifies all functions having overloads that we can't import (yet). | |
| /// | |
| /// TODO(b/213280424): Implement support for overloaded functions. | |
| /// | |
| /// Implementation: rs_bindings_from_cc/generate_bindings/generate_function.rs?q=function:overload_sets | |
| fn overload_sets(&self) -> Rc<HashMap<Rc<FunctionId>, Option<ir::ItemId>>>; | |
| /// Returns whether the given record either implements or derives the Clone | |
| /// trait. | |
| /// | |
| /// Implementation: rs_bindings_from_cc/generate_bindings/generate_function.rs?q=function:is_record_clonable | |
| fn is_record_clonable(&self, record: Rc<Record>) -> bool; | |
| /// Returns the generated bindings for a function with the given name and param | |
| /// types. If none exists, returns None. | |
| /// | |
| /// Implementation: rs_bindings_from_cc/generate_bindings/generate_function.rs?q=function:get_binding | |
| fn get_binding( | |
| &self, | |
| expected_function_name: UnqualifiedIdentifier, | |
| expected_param_types: Vec<RsTypeKind>, | |
| ) -> Option<(Ident, ImplKind)>; | |
| /// Returns a collection of unqualified member functions of the given record. | |
| /// | |
| /// Implementation: rs_bindings_from_cc/generate_bindings/generate_struct_and_union.rs?q=function:collect_unqualified_member_functions | |
| fn collect_unqualified_member_functions( | |
| &self, | |
| record: Rc<Record>, | |
| ) -> Rc<[Rc<Func>]>; | |
| /// Returns the `CrubitAbiType` for the given `RsTypeKind`. | |
| /// | |
| /// Implementation: rs_bindings_from_cc/generate_bindings/lib.rs?q=function:crubit_abi_type | |
| fn crubit_abi_type(&self, rs_type_kind: RsTypeKind) -> Result<CrubitAbiType>; | |
| // You should probably use db::type_visibility instead of this function. | |
| fn type_target_restriction(&self, rs_type_kind: RsTypeKind) -> Result<Option<BazelLabel>>; | |
| /// Resolves type names to a map from name to ResolvedTypeName. | |
| /// | |
| /// This only checks the type namespace, as described here: | |
| /// https://doc.rust-lang.org/reference/names/namespaces.html. | |
| /// | |
| /// Implementation: rs_bindings_from_cc/generate_bindings/has_bindings.rs?q=function:resolve_type_names | |
| fn resolve_type_names(&self, parent: Rc<Record>) -> Result<Rc<HashMap<Rc<str>, ResolvedTypeName>>>; | |
| #[provided] | |
| /// Returns the generated bindings for the given enum. | |
| /// | |
| /// Implementation: rs_bindings_from_cc/generate_bindings/generate_enum.rs?q=function:generate_enum | |
| fn generate_enum(&self, enum_: Rc<Enum>) -> Result<ApiSnippets> { | |
| (self.codegen_functions().generate_enum)(self, enum_) | |
| } | |
| #[provided] | |
| /// Returns the generated bindings for an item, or `Err` if bindings generation | |
| /// failed in such a way as to make the generated bindings as a whole invalid. | |
| /// | |
| /// Implementation: rs_bindings_from_cc/generate_bindings/lib.rs?q=function:generate_item | |
| fn generate_item(&self, item: ir::Item) -> Result<ApiSnippets> { | |
| (self.codegen_functions().generate_item)(self, item) | |
| } | |
| #[provided] | |
| /// Returns the generated bindings for the given record, along with associated safety | |
| /// assertions. | |
| /// | |
| /// Implementation: rs_bindings_from_cc/generate_bindings/generate_struct_and_union.rs?q=function:generate_record | |
| fn generate_record(&self, record: Rc<Record>) -> Result<ApiSnippets> { | |
| (self.codegen_functions().generate_record)(self, record) | |
| } | |
| #[provided] | |
| /// Returns the Rust type kind of the given C++ type. | |
| /// | |
| /// This differs from `rs_type_kind_with_lifetime_elision` in that it replaces references | |
| /// with missing lifetimes with pointer types. | |
| fn rs_type_kind(&self, cc_type: CcType) -> Result<RsTypeKind> { | |
| self.rs_type_kind_with_lifetime_elision(cc_type, LifetimeOptions::default()) | |
| } | |
| #[provided] | |
| /// Returns true if an ItemId refers to a function that cannot receive bindings, because | |
| /// it is overloaded and ambiguous. | |
| /// | |
| /// This does not include functions that are overloaded, where all but one overload is | |
| /// deprecated. | |
| fn is_ambiguous_function(&self, function_id: &FunctionId, item_id: ir::ItemId) -> bool { | |
| match self.overload_sets().get(function_id) { | |
| None => false, | |
| Some(id) => *id != Some(item_id), | |
| } | |
| } | |
| } | |
| pub struct Database; | |
| } | |
| /// Returns the `Visibility` of the `rs_type_kind` in the given `library`. | |
| // TODO(jeanpierreda): it would be nice if this was a `#[provided]` function, | |
| // but because it calls `display`, it would need to convert to a | |
| // `dyn BindingsGenerator`, which is not reasonably possible. | |
| // | |
| // See e.g. https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=10f937bb0f13d2ea05f20f676c37439a | |
| pub fn type_visibility( | |
| db: &dyn BindingsGenerator, | |
| library: &BazelLabel, | |
| rs_type_kind: RsTypeKind, | |
| ) -> Result<Visibility> { | |
| match db.type_target_restriction(rs_type_kind.clone())? { | |
| Some(label) if &label != library => { | |
| let rs_type_kind = rs_type_kind.display(db); | |
| Err(anyhow!("{rs_type_kind} is `pub(crate)` in {label}")) | |
| } | |
| Some(_) => Ok(Visibility::PubCrate), | |
| None => { | |
| for subtype in rs_type_kind.dfs_iter() { | |
| if let RsTypeKind::Error { visibility_override, .. } = subtype { | |
| return Ok(visibility_override.unwrap_or(Visibility::PubCrate)); | |
| } | |
| } | |
| Ok(Visibility::Public) | |
| } | |
| } | |
| } |