autocxx-engine 0.5.2

Safe autogenerated interop between Rust and C++
Documentation
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

mod analysis;
mod api;
mod codegen_cpp;
mod codegen_rs;
#[cfg(test)]
mod conversion_tests;
mod convert_error;
mod parse;
mod utilities;

use analysis::fun::FnAnalyzer;
use autocxx_parser::TypeConfig;
pub(crate) use codegen_cpp::type_to_cpp::type_to_cpp;
pub(crate) use codegen_cpp::CppCodeGenerator;
pub(crate) use codegen_cpp::CppCodegenResults;
pub(crate) use convert_error::ConvertError;
use syn::{Item, ItemMod};

use crate::UnsafePolicy;

use self::{
    analysis::{
        gc::filter_apis_by_following_edges_from_allowlist, pod::analyze_pod_apis,
        remove_ignored::filter_apis_by_ignored_dependents,
    },
    codegen_rs::RsCodeGenerator,
    parse::ParseBindgen,
};

/// Converts the bindings generated by bindgen into a form suitable
/// for use with `cxx`.
/// In fact, most of the actual operation happens within an
/// individual `BridgeConversion`.
///
/// # Flexibility in handling bindgen output
///
/// autocxx is inevitably tied to the details of the bindgen output;
/// e.g. the creation of a 'root' mod when namespaces are enabled.
/// At the moment this crate takes the view that it's OK to panic
/// if the bindgen output is not as expected. It may be in future that
/// we need to be a bit more graceful, but for now, that's OK.
pub(crate) struct BridgeConverter<'a> {
    include_list: &'a [String],
    type_config: &'a TypeConfig,
}

/// C++ and Rust code generation output.
pub(crate) struct CodegenResults {
    pub(crate) rs: Vec<Item>,
    pub(crate) cpp: Option<CppCodegenResults>,
}

impl<'a> BridgeConverter<'a> {
    pub fn new(include_list: &'a [String], type_config: &'a TypeConfig) -> Self {
        Self {
            include_list,
            type_config,
        }
    }

    /// Convert a TokenStream of bindgen-generated bindings to a form
    /// suitable for cxx.
    ///
    /// This is really the heart of autocxx. It parses the output of `bindgen`
    /// (although really by "parse" we mean to interpret the structures already built
    /// up by the `syn` crate).
    pub(crate) fn convert(
        &self,
        mut bindgen_mod: ItemMod,
        exclude_utilities: bool,
        unsafe_policy: UnsafePolicy,
        inclusions: String,
    ) -> Result<CodegenResults, ConvertError> {
        match &mut bindgen_mod.content {
            None => Err(ConvertError::NoContent),
            Some((_, items)) => {
                // Parse the bindgen mod.
                let items_to_process = items.drain(..).collect();
                let parser = ParseBindgen::new(&self.type_config);
                let parse_results = parser.parse_items(items_to_process, exclude_utilities)?;
                // Inside parse_results, we now have a list of APIs and a few other things
                // e.g. type relationships. The latter are stored in here...
                let mut type_converter = parse_results.type_converter;
                // The code above will have contributed lots of `Api`s to self.apis.
                // Now analyze which of them can be POD (i.e. trivial, movable, pass-by-value
                // versus which need to be opaque).
                // Specifically, let's confirm that the items requested by the user to be
                // POD really are POD, and duly mark any dependent types.
                // This returns a new list of `Api`s, which will be parameterized with
                // the analysis results. It also returns an object which can be used
                // by subsequent phases to work out which objects are POD.
                let analyzed_apis =
                    analyze_pod_apis(parse_results.apis, &self.type_config, &mut type_converter)?;
                // Next, figure out how we materialize different functions.
                // Some will be simple entries in the cxx::bridge module; others will
                // require C++ wrapper functions. This is probably the most complex
                // part of `autocxx`. Again, this returns a new set of `Api`s, but
                // parameterized by a richer set of metadata.
                let analyzed_apis = FnAnalyzer::analyze_functions(
                    analyzed_apis,
                    unsafe_policy,
                    &mut type_converter,
                    self.type_config,
                )?;
                // During parsing or subsequent processing we might have encountered
                // items which we couldn't process due to as-yet-unsupported features.
                // There might be other items depending on such things. Let's remove them
                // too.
                let analyzed_apis = filter_apis_by_ignored_dependents(analyzed_apis);
                // We now garbage collect the ones we don't need...
                let mut analyzed_apis =
                    filter_apis_by_following_edges_from_allowlist(analyzed_apis, &self.type_config);
                // Determine what variably-sized C types (e.g. int) we need to include
                analysis::ctypes::append_ctype_information(&mut analyzed_apis);
                // And finally pass them to the code gen phases, which outputs
                // code suitable for cxx to consume.
                let cpp = CppCodeGenerator::generate_cpp_code(inclusions, &analyzed_apis)?;
                let rs = RsCodeGenerator::generate_rs_code(
                    analyzed_apis,
                    self.include_list,
                    bindgen_mod,
                );
                Ok(CodegenResults { rs, cpp })
            }
        }
    }
}