Skip to content

Commit

Permalink
Add bindings for Rust std::option::Option
Browse files Browse the repository at this point in the history
  • Loading branch information
kuecks committed Oct 18, 2023
1 parent a6ca025 commit 451be69
Show file tree
Hide file tree
Showing 37 changed files with 1,424 additions and 25 deletions.
1 change: 1 addition & 0 deletions gen/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub(crate) struct Builtins<'a> {
pub rust_slice: bool,
pub rust_box: bool,
pub rust_vec: bool,
pub rust_option: bool,
pub rust_fn: bool,
pub rust_isize: bool,
pub opaque: bool,
Expand Down
125 changes: 124 additions & 1 deletion gen/src/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::gen::nested::NamespaceEntries;
use crate::gen::out::OutFile;
use crate::gen::{builtin, include, Opt};
use crate::syntax::atom::Atom::{self, *};
use crate::syntax::instantiate::{ImplKey, NamedImplKey};
use crate::syntax::instantiate::{ImplKey, NamedImplKey, OptionInner};
use crate::syntax::map::UnorderedMap as Map;
use crate::syntax::set::UnorderedSet;
use crate::syntax::symbol::{self, Symbol};
Expand Down Expand Up @@ -214,6 +214,7 @@ fn pick_includes_and_builtins(out: &mut OutFile, apis: &[Api]) {
},
Type::RustBox(_) => out.builtin.rust_box = true,
Type::RustVec(_) => out.builtin.rust_vec = true,
Type::RustOption(_) => out.builtin.rust_option = true,
Type::UniquePtr(_) => out.include.memory = true,
Type::SharedPtr(_) | Type::WeakPtr(_) => out.include.memory = true,
Type::Str(_) => out.builtin.rust_str = true,
Expand Down Expand Up @@ -836,6 +837,8 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
out.builtin.unsafe_bitcopy = true;
write_type(out, &arg.ty);
write!(out, "(::rust::unsafe_bitcopy, *{})", arg.name.cxx);
} else if let Type::RustOption(_) = arg.ty {
write!(out, "std::move(* {})", arg.name.cxx);
} else if out.types.needs_indirect_abi(&arg.ty) {
out.include.utility = true;
write!(out, "::std::move(*{})", arg.name.cxx);
Expand Down Expand Up @@ -1235,6 +1238,21 @@ fn write_type(out: &mut OutFile, ty: &Type) {
write_type(out, &ty.inner);
write!(out, ">");
}
Type::RustOption(ty) => {
write!(out, "::rust::Option<");
match &ty.inner {
Type::RustBox(_) => write_type(out, &ty.inner),
Type::Ref(r) => {
write_type_space(out, &r.inner);
if !r.mutable {
write!(out, "const ");
}
write!(out, " *");
}
_ => unreachable!(),
}
write!(out, ">");
}
Type::UniquePtr(ptr) => {
write!(out, "::std::unique_ptr<");
write_type(out, &ptr.inner);
Expand Down Expand Up @@ -1340,6 +1358,7 @@ fn write_space_after_type(out: &mut OutFile, ty: &Type) {
| Type::Str(_)
| Type::CxxVector(_)
| Type::RustVec(_)
| Type::RustOption(_)
| Type::SliceRef(_)
| Type::Fn(_)
| Type::Array(_) => write!(out, " "),
Expand All @@ -1354,6 +1373,12 @@ enum UniquePtr<'a> {
CxxVector(&'a Ident),
}

enum RustOption<'a> {
RustBox(&'a Ident),
Ref(&'a Ident),
MutRef(&'a Ident),
}

trait ToTypename {
fn to_typename(&self, types: &Types) -> String;
}
Expand All @@ -1375,6 +1400,18 @@ impl<'a> ToTypename for UniquePtr<'a> {
}
}

impl<'a> ToTypename for RustOption<'a> {
fn to_typename(&self, types: &Types) -> String {
match self {
RustOption::RustBox(inner) => {
format!("::rust::cxxbridge1::Box<{}>", inner.to_typename(types))
}
RustOption::Ref(inner) => format!("const {}*", inner.to_typename(types)),
RustOption::MutRef(inner) => format!("{}*", inner.to_typename(types)),
}
}
}

trait ToMangled {
fn to_mangled(&self, types: &Types) -> Symbol;
}
Expand All @@ -1396,6 +1433,22 @@ impl<'a> ToMangled for UniquePtr<'a> {
}
}

impl<'a> ToMangled for RustOption<'a> {
fn to_mangled(&self, types: &Types) -> Symbol {
match self {
RustOption::RustBox(inner) => symbol::join(&[&"Box", &inner.to_mangled(types)]),
RustOption::Ref(inner) => {
let symbol = symbol::join(&[&"const", &inner.to_mangled(types)]);
symbol
}
RustOption::MutRef(inner) => {
let symbol = symbol::join(&[&inner.to_mangled(types)]);
symbol
}
}
}
}

fn write_generic_instantiations(out: &mut OutFile) {
if out.header {
return;
Expand All @@ -1409,6 +1462,7 @@ fn write_generic_instantiations(out: &mut OutFile) {
match *impl_key {
ImplKey::RustBox(ident) => write_rust_box_extern(out, ident),
ImplKey::RustVec(ident) => write_rust_vec_extern(out, ident),
ImplKey::RustOption(ident) => write_rust_option_extern(out, ident),
ImplKey::UniquePtr(ident) => write_unique_ptr(out, ident),
ImplKey::SharedPtr(ident) => write_shared_ptr(out, ident),
ImplKey::WeakPtr(ident) => write_weak_ptr(out, ident),
Expand All @@ -1423,6 +1477,7 @@ fn write_generic_instantiations(out: &mut OutFile) {
match *impl_key {
ImplKey::RustBox(ident) => write_rust_box_impl(out, ident),
ImplKey::RustVec(ident) => write_rust_vec_impl(out, ident),
ImplKey::RustOption(ident) => write_rust_option_impl(out, ident),
_ => {}
}
}
Expand Down Expand Up @@ -1501,6 +1556,38 @@ fn write_rust_vec_extern(out: &mut OutFile, key: NamedImplKey) {
);
}

fn write_rust_option_extern(out: &mut OutFile, inner: OptionInner) {
out.include.cstddef = true;
let element = match inner {
OptionInner::RustBox(key) => RustOption::RustBox(key.rust),
OptionInner::Ref(key) => {
if out.types.try_resolve(key.rust).is_none() {
return;
}
RustOption::Ref(key.rust)
}
OptionInner::MutRef(key) => {
if out.types.try_resolve(key.rust).is_none() {
return;
}
RustOption::MutRef(key.rust)
}
};
let inner = element.to_typename(out.types);
let instance = element.to_mangled(out.types);

writeln!(
out,
"void cxxbridge1$rust_option${}$new(const ::rust::Option<{}> *ptr) noexcept;",
instance, inner,
);
writeln!(
out,
"void cxxbridge1$rust_option${}$drop(::rust::Option<{}> *ptr) noexcept;",
instance, inner,
);
}

fn write_rust_box_impl(out: &mut OutFile, key: NamedImplKey) {
let resolve = out.types.resolve(&key);
let inner = resolve.name.to_fully_qualified();
Expand Down Expand Up @@ -1621,6 +1708,42 @@ fn write_rust_vec_impl(out: &mut OutFile, key: NamedImplKey) {
writeln!(out, "}}");
}

fn write_rust_option_impl(out: &mut OutFile, inner: OptionInner) {
let element = match inner {
OptionInner::RustBox(key) => RustOption::RustBox(key.rust),
OptionInner::Ref(key) => {
if out.types.try_resolve(key.rust).is_none() {
return;
}
RustOption::Ref(key.rust)
}
OptionInner::MutRef(key) => {
if out.types.try_resolve(key.rust).is_none() {
return;
}
RustOption::MutRef(key.rust)
}
};
let inner = element.to_typename(out.types);
let instance = element.to_mangled(out.types);

writeln!(out, "template <>");
begin_function_definition(out);
writeln!(out, "Option<{}>::Option() noexcept {{", inner);
writeln!(out, " cxxbridge1$rust_option${}$new(this);", instance);
writeln!(out, "}}");

writeln!(out, "template <>");
begin_function_definition(out);
writeln!(out, "void Option<{}>::drop() noexcept {{", inner);
writeln!(
out,
" return cxxbridge1$rust_option${}$drop(this);",
instance
);
writeln!(out, "}}");
}

fn write_unique_ptr(out: &mut OutFile, key: NamedImplKey) {
let ty = UniquePtr::Ident(key.rust);
write_unique_ptr_common(out, ty);
Expand Down
81 changes: 81 additions & 0 deletions include/cxx.h
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,87 @@ template <typename T>
Box<T>::Box(uninit) noexcept {}
#endif // CXXBRIDGE1_RUST_BOX

#ifndef CXXBRIDGE1_RUST_OPTION
template <typename T>
class Option final {
public:
Option() noexcept;
Option(Option&&) noexcept;
Option(T&&) noexcept;
~Option() noexcept;
void drop() noexcept;

const T *operator->() const;
const T &operator*() const;
T *operator->();
T &operator*();

bool has_value() const noexcept;
const T& value() const;

union OptionContents {
T value;
size_t empty;

OptionContents() {
empty = 0;
}
// Destruction handled in Option since it knows if type was created
~OptionContents() {}
};
OptionContents inner; // Avoid initialization
};
#endif // CXXBRIDGE1_RUST_OPTION

#ifndef CXXBRIDGE1_RUST_OPTION
#define CXXBRIDGE1_RUST_OPTION
template <typename T>
Option<T>::Option() noexcept {}

template <typename T>
Option<T>::Option(Option&& other) noexcept {
if (other.inner.empty != 0) {
inner.value = std::move(other.inner.value);
}
other.inner.empty = 0;
}

template <typename T>
Option<T>::~Option() noexcept {
this->drop();
}

template <typename T>
const T *Option<T>::operator->() const {
return &inner.value;
}

template <typename T>
const T &Option<T>::operator*() const {
return inner.value;
}

template <typename T>
T *Option<T>::operator->() {
return &inner.value;
}

template <typename T>
T &Option<T>::operator*() {
return inner.value;
}

template <typename T>
bool Option<T>::has_value() const noexcept {
return inner.empty != 0;
}

template <typename T>
const T& Option<T>::value() const {
return inner.value;
}
#endif // CXXBRIDGE1_RUST_OPTION

#ifndef CXXBRIDGE1_RUST_VEC
#define CXXBRIDGE1_RUST_VEC
template <typename T>
Expand Down
Loading

0 comments on commit 451be69

Please sign in to comment.