Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ build --enable_platform_specific_config
build:linux --@rules_rust//:extra_rustc_flags=-Clink-arg=-fuse-ld=lld
build:linux --cxxopt=-std=c++17
build:macos --cxxopt=-std=c++17
build:windows --cxxopt=/std:c++17
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
{
"search.exclude": {
"**/target": true
},
"files.associations": {
"variant": "cpp",
"string": "cpp"
}
}
4 changes: 3 additions & 1 deletion demo/build.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
fn main() {
cxx_build::bridge("src/main.rs")
.file("src/blobstore.cc")
.flag_if_supported("-std=c++14")
.flag_if_supported("-std=c++17")
.flag_if_supported("/std:c++17")
.flag_if_supported("/Zc:__cplusplus")
.compile("cxxbridge-demo");

println!("cargo:rerun-if-changed=src/main.rs");
Expand Down
5 changes: 5 additions & 0 deletions demo/include/blobstore.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace blobstore {

struct MultiBuf;
struct BlobMetadata;
struct BlobEnum;

class BlobstoreClient {
public:
Expand All @@ -22,5 +23,9 @@ class BlobstoreClient {

std::unique_ptr<BlobstoreClient> new_blobstore_client();

BlobEnum make_enum();
void take_enum(const BlobEnum&);
void take_mut_enum(BlobEnum&);

} // namespace blobstore
} // namespace org
26 changes: 26 additions & 0 deletions demo/src/blobstore.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "demo/src/main.rs.h"
#include <algorithm>
#include <functional>
#include <iostream>
#include <set>
#include <string>
#include <unordered_map>
Expand Down Expand Up @@ -67,5 +68,30 @@ std::unique_ptr<BlobstoreClient> new_blobstore_client() {
return std::make_unique<BlobstoreClient>();
}

BlobEnum make_enum() { return BlobEnum{false}; }

std::ostream &operator<<(std::ostream &os, const BlobMetadata &md) {
os << "The size [" << md.size << "] and some tags...";
return os;
}

void take_enum(const BlobEnum &enm) {
std::cout << "The index of enum is " << enm.index() << std::endl;
rust::visit(
[](const auto &v) {
std::cout << "The value of enum is " << v << std::endl;
},
enm);
}

void take_mut_enum(BlobEnum &enm) {
take_enum(enm);
if (!::rust::holds_alternative<bool>(enm)) {
enm = false;
} else {
enm = 111;
}
}

} // namespace blobstore
} // namespace org
33 changes: 33 additions & 0 deletions demo/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@ mod ffi {
tags: Vec<String>,
}

/// A classic.
enum BlobEnum {
/// This is my doc
Bar(i32),
Baz(bool),
Bam(BlobMetadata),
}

enum BlobCLike {
Bar,
Baz,
Bam,
}

// Rust types and signatures exposed to C++.
extern "Rust" {
type MultiBuf;
Expand All @@ -23,6 +37,10 @@ mod ffi {
fn put(&self, parts: &mut MultiBuf) -> u64;
fn tag(&self, blobid: u64, tag: &str);
fn metadata(&self, blobid: u64) -> BlobMetadata;

fn make_enum() -> BlobEnum;
fn take_enum(enm: &BlobEnum);
fn take_mut_enum(enm: &mut BlobEnum);
}
}

Expand All @@ -42,6 +60,21 @@ pub fn next_chunk(buf: &mut MultiBuf) -> &[u8] {
}

fn main() {
let f = ffi::BlobEnum::Bar(1);
ffi::take_enum(&f);
let mut f = ffi::make_enum();
match f {
ffi::BlobEnum::Bar(val) => println!("The value is {val}"),
ffi::BlobEnum::Baz(val) => println!("The value is {val}"),
_ => {}
}
ffi::take_mut_enum(&mut f);
match f {
ffi::BlobEnum::Bar(val) => println!("The value is {val}"),
ffi::BlobEnum::Baz(val) => println!("The value is {val}"),
_ => {}
}

let client = ffi::new_blobstore_client();

// Upload a blob.
Expand Down
4 changes: 2 additions & 2 deletions gen/src/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub(super) fn strip(
Api::Struct(strct) => strct
.fields
.retain(|field| eval(cx, cfg_errors, cfg_evaluator, &field.cfg)),
Api::Enum(enm) => enm
Api::Enum(enm, _) | Api::EnumUnnamed(enm) => enm
.variants
.retain(|variant| eval(cx, cfg_errors, cfg_evaluator, &variant.cfg)),
_ => {}
Expand Down Expand Up @@ -113,7 +113,7 @@ impl Api {
match self {
Api::Include(include) => &include.cfg,
Api::Struct(strct) => &strct.cfg,
Api::Enum(enm) => &enm.cfg,
Api::Enum(enm, _) | Api::EnumUnnamed(enm) => &enm.cfg,
Api::CxxType(ety) | Api::RustType(ety) => &ety.cfg,
Api::CxxFunction(efn) | Api::RustFunction(efn) => &efn.cfg,
Api::TypeAlias(alias) => &alias.cfg,
Expand Down
2 changes: 1 addition & 1 deletion gen/src/namespace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ impl Api {
match self {
Api::CxxFunction(efn) | Api::RustFunction(efn) => &efn.name.namespace,
Api::CxxType(ety) | Api::RustType(ety) => &ety.name.namespace,
Api::Enum(enm) => &enm.name.namespace,
Api::Enum(enm, _) | Api::EnumUnnamed(enm) => &enm.name.namespace,
Api::Struct(strct) => &strct.name.namespace,
Api::Impl(_) | Api::Include(_) | Api::TypeAlias(_) => Default::default(),
}
Expand Down
89 changes: 72 additions & 17 deletions gen/src/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use crate::syntax::set::UnorderedSet;
use crate::syntax::symbol::{self, Symbol};
use crate::syntax::trivial::{self, TrivialReason};
use crate::syntax::{
derive, mangle, Api, Doc, Enum, EnumRepr, ExternFn, ExternType, Pair, Signature, Struct, Trait,
Type, TypeAlias, Types, Var,
derive, mangle, Api, CEnumOpts, Doc, Enum, EnumRepr, ExternFn, ExternType, Pair, Signature,
Struct, Trait, Type, TypeAlias, Types, Var,
};
use proc_macro2::Ident;

Expand All @@ -34,8 +34,8 @@ pub(super) fn gen(apis: &[Api], types: &Types, opt: &Opt, header: bool) -> Vec<u

fn write_forward_declarations(out: &mut OutFile, apis: &[Api]) {
let needs_forward_declaration = |api: &&Api| match api {
Api::Struct(_) | Api::CxxType(_) | Api::RustType(_) => true,
Api::Enum(enm) => !out.types.cxx.contains(&enm.name.rust),
Api::Struct(_) | Api::CxxType(_) | Api::RustType(_) | Api::EnumUnnamed(_) => true,
Api::Enum(enm, _) => !out.types.cxx.contains(&enm.name.rust),
_ => false,
};

Expand All @@ -46,12 +46,12 @@ fn write_forward_declarations(out: &mut OutFile, apis: &[Api]) {

fn write(out: &mut OutFile, ns_entries: &NamespaceEntries, indent: usize) {
let apis = ns_entries.direct_content();

for api in apis {
write!(out, "{:1$}", "", indent);
match api {
Api::Struct(strct) => write_struct_decl(out, &strct.name),
Api::Enum(enm) => write_enum_decl(out, enm),
Api::Enum(enm, opts) => write_enum_decl(out, enm, opts),
Api::EnumUnnamed(enm) => write_struct_decl(out, &enm.name),
Api::CxxType(ety) => write_struct_using(out, &ety.name),
Api::RustType(ety) => write_struct_decl(out, &ety.name),
_ => unreachable!(),
Expand Down Expand Up @@ -99,14 +99,18 @@ fn write_data_structures<'a>(out: &mut OutFile<'a>, apis: &'a [Api]) {
}
}
}
Api::Enum(enm) => {
Api::Enum(enm, opts) => {
out.next_section();
if !out.types.cxx.contains(&enm.name.rust) {
write_enum(out, enm);
} else if !enm.variants_from_header {
check_enum(out, enm);
write_enum(out, enm, opts);
} else if !opts.variants_from_header {
check_enum(out, enm, opts);
}
}
Api::EnumUnnamed(enm) => {
out.next_section();
write_enum_unnamed(out, enm);
}
Api::RustType(ety) => {
out.next_section();
let methods = methods_for_type
Expand Down Expand Up @@ -328,8 +332,8 @@ fn write_struct_decl(out: &mut OutFile, ident: &Pair) {
writeln!(out, "struct {};", ident.cxx);
}

fn write_enum_decl(out: &mut OutFile, enm: &Enum) {
let repr = match &enm.repr {
fn write_enum_decl(out: &mut OutFile, enm: &Enum, opts: &CEnumOpts) {
let repr = match &opts.repr {
#[cfg(feature = "experimental-enum-variants-from-header")]
EnumRepr::Foreign { .. } => return,
EnumRepr::Native { atom, .. } => *atom,
Expand All @@ -339,6 +343,56 @@ fn write_enum_decl(out: &mut OutFile, enm: &Enum) {
writeln!(out, ";");
}

fn write_enum_unnamed(out: &mut OutFile, enm: &Enum) {
write!(out, "struct {} final : public ", enm.name.cxx);

/// Writes something like `::rust::variant<type1, type2, ...>` with type1...
/// being cxx types of the enum's variants.
fn write_variants(out: &mut OutFile, enm: &Enum) {
write!(out, "::rust::variant<");
let mut iter = enm.variants.iter().peekable();
while let Some(value) = iter.next() {
match &value.ty {
None => {
write!(out, "::rust::empty");
}
Some(ty) => {
match ty {
Type::Ref(r) => {
// References are not allowed in variants, so we wrap them
// into std::reference_wrapper.
write!(out, "std::reference_wrapper<");
write_type_space(out, &r.inner);
if !r.mutable {
write!(out, "const ");
}
write!(out, ">");
}
_ => write_type(out, ty),
}
}
};
if iter.peek().is_some() {
write!(out, ", ");
}
}
write!(out, ">");
}

write_variants(out, enm);
writeln!(out, "{{");

write!(out, " using base = ");
write_variants(out, enm);
writeln!(out, ";");
writeln!(out, " {}() = delete;", enm.name.cxx);
writeln!(out, " {0}(const {0}&) = default;", enm.name.cxx);
writeln!(out, " {0}({0}&&) = delete;", enm.name.cxx);
writeln!(out, " using base::base;");
writeln!(out, " using base::operator=;");
writeln!(out, "}};");
}

fn write_struct_using(out: &mut OutFile, ident: &Pair) {
writeln!(out, "using {} = {};", ident.cxx, ident.to_fully_qualified());
}
Expand Down Expand Up @@ -388,8 +442,8 @@ fn write_opaque_type<'a>(out: &mut OutFile<'a>, ety: &'a ExternType, methods: &[
writeln!(out, "#endif // {}", guard);
}

fn write_enum<'a>(out: &mut OutFile<'a>, enm: &'a Enum) {
let repr = match &enm.repr {
fn write_enum<'a>(out: &mut OutFile<'a>, enm: &'a Enum, opts: &'a CEnumOpts) {
let repr = match &opts.repr {
#[cfg(feature = "experimental-enum-variants-from-header")]
EnumRepr::Foreign { .. } => return,
EnumRepr::Native { atom, .. } => *atom,
Expand All @@ -410,8 +464,8 @@ fn write_enum<'a>(out: &mut OutFile<'a>, enm: &'a Enum) {
writeln!(out, "#endif // {}", guard);
}

fn check_enum<'a>(out: &mut OutFile<'a>, enm: &'a Enum) {
let repr = match &enm.repr {
fn check_enum<'a>(out: &mut OutFile<'a>, enm: &'a Enum, opts: &'a CEnumOpts) {
let repr = match &opts.repr {
#[cfg(feature = "experimental-enum-variants-from-header")]
EnumRepr::Foreign { .. } => return,
EnumRepr::Native { atom, .. } => *atom,
Expand Down Expand Up @@ -838,7 +892,8 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
write!(out, "(::rust::unsafe_bitcopy, *{})", arg.name.cxx);
} else if out.types.needs_indirect_abi(&arg.ty) {
out.include.utility = true;
write!(out, "::std::move(*{})", arg.name.cxx);
// Let the compiler resolve if this is a copy or a move constructor.
write!(out, "*{}", arg.name.cxx);
} else {
write!(out, "{}", arg.name.cxx);
}
Expand Down
Loading