Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support rust char binding, mapping to new cpp rust::Char #1147

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions gen/src/builtin.rs
Expand Up @@ -9,6 +9,7 @@ pub struct Builtins<'a> {
pub rust_str: bool,
pub rust_slice: bool,
pub rust_box: bool,
pub rust_char: bool,
pub rust_vec: bool,
pub rust_fn: bool,
pub rust_isize: bool,
Expand Down Expand Up @@ -179,6 +180,7 @@ pub(super) fn write(out: &mut OutFile) {
}

ifndef::write(out, builtin.rust_string, "CXXBRIDGE1_RUST_STRING");
ifndef::write(out, builtin.rust_char, "CXXBRIDGE1_RUST_CHAR");
ifndef::write(out, builtin.rust_str, "CXXBRIDGE1_RUST_STR");
ifndef::write(out, builtin.rust_slice, "CXXBRIDGE1_RUST_SLICE");
ifndef::write(out, builtin.rust_box, "CXXBRIDGE1_RUST_BOX");
Expand Down
2 changes: 2 additions & 0 deletions gen/src/write.rs
Expand Up @@ -210,6 +210,7 @@ fn pick_includes_and_builtins(out: &mut OutFile, apis: &[Api]) {
Some(Usize) => out.include.cstddef = true,
Some(Isize) => out.builtin.rust_isize = true,
Some(CxxString) => out.include.string = true,
Some(RustChar) => out.builtin.rust_char = true,
Some(RustString) => out.builtin.rust_string = true,
Some(Bool) | Some(Char) | Some(F32) | Some(F64) | None => {}
},
Expand Down Expand Up @@ -1322,6 +1323,7 @@ fn write_atom(out: &mut OutFile, atom: Atom) {
F32 => write!(out, "float"),
F64 => write!(out, "double"),
CxxString => write!(out, "::std::string"),
RustChar => write!(out, "::rust::Char"),
RustString => write!(out, "::rust::String"),
}
}
Expand Down
16 changes: 16 additions & 0 deletions include/cxx.h
Expand Up @@ -152,6 +152,22 @@ class Str final {
};
#endif // CXXBRIDGE1_RUST_STR

#ifndef CXXBRIDGE1_RUST_CHAR
#define CXXBRIDGE1_RUST_CHAR
// TODO https://cxx.rs/binding/char.html
class Char final {
public:
// Throws std::invalid_argument if not valid Unicode value
Char(char32_t);

char32_t get() const noexcept;

private:
char32_t inner;

};
#endif // CXXBRIDGE1_RUST_CHAR

#ifndef CXXBRIDGE1_RUST_SLICE
namespace detail {
template <bool>
Expand Down
15 changes: 15 additions & 0 deletions src/cxx.cc
Expand Up @@ -388,6 +388,21 @@ std::size_t sliceLen(const void *self) noexcept {
return cxxbridge1$slice$len(self);
}

// copied from rust code source: char::from_u32
inline bool is_invalid_unicode(char32_t c) {
return c >= 0x110000 || (c >= 0xD800 && c < 0xE000);
}

// Throws std::invalid_argument if not valid Unicode value
Char::Char(char32_t c): inner(c) {
if (is_invalid_unicode(c)) {
panic<std::invalid_argument>("data for rust::Char is not unicode value");
}
}

char32_t Char::get() const noexcept { return this->inner; }


// Rust specifies that usize is ABI compatible with C's uintptr_t.
// https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#isize-and-usize
// However there is no direct Rust equivalent for size_t. C does not guarantee
Expand Down
5 changes: 4 additions & 1 deletion syntax/atom.rs
Expand Up @@ -5,7 +5,7 @@ use std::fmt::{self, Display};
#[derive(Copy, Clone, PartialEq)]
pub enum Atom {
Bool,
Char, // C char, not Rust char
Char, // C char, not Rust char, see `RustChar`
U8,
U16,
U32,
Expand All @@ -19,6 +19,7 @@ pub enum Atom {
F32,
F64,
CxxString,
RustChar,
RustString,
}

Expand All @@ -31,6 +32,7 @@ impl Atom {
use self::Atom::*;
match s {
"bool" => Some(Bool),
"char" => Some(RustChar),
"c_char" => Some(Char),
"u8" => Some(U8),
"u16" => Some(U16),
Expand Down Expand Up @@ -76,6 +78,7 @@ impl AsRef<str> for Atom {
F32 => "f32",
F64 => "f64",
CxxString => "CxxString",
RustChar => "char",
RustString => "String",
}
}
Expand Down
8 changes: 4 additions & 4 deletions syntax/check.rs
Expand Up @@ -125,7 +125,7 @@ fn check_type_rust_vec(cx: &mut Check, ty: &Ty1) {
match Atom::from(&ident.rust) {
None | Some(Bool) | Some(Char) | Some(U8) | Some(U16) | Some(U32) | Some(U64)
| Some(Usize) | Some(I8) | Some(I16) | Some(I32) | Some(I64) | Some(Isize)
| Some(F32) | Some(F64) | Some(RustString) => return,
| Some(F32) | Some(F64) | Some(RustChar) | Some(RustString) => return,
Some(CxxString) => {}
}
}
Expand Down Expand Up @@ -165,7 +165,7 @@ fn check_type_shared_ptr(cx: &mut Check, ptr: &Ty1) {
None | Some(Bool) | Some(U8) | Some(U16) | Some(U32) | Some(U64) | Some(Usize)
| Some(I8) | Some(I16) | Some(I32) | Some(I64) | Some(Isize) | Some(F32)
| Some(F64) | Some(CxxString) => return,
Some(Char) | Some(RustString) => {}
Some(Char) | Some(RustChar) | Some(RustString) => {}
}
} else if let Type::CxxVector(_) = &ptr.inner {
cx.error(ptr, "std::shared_ptr<std::vector> is not supported yet");
Expand All @@ -185,7 +185,7 @@ fn check_type_weak_ptr(cx: &mut Check, ptr: &Ty1) {
match Atom::from(&ident.rust) {
None | Some(Bool) | Some(U8) | Some(U16) | Some(U32) | Some(U64) | Some(Usize)
| Some(I8) | Some(I16) | Some(I32) | Some(I64) | Some(Isize) | Some(F32)
| Some(F64) | Some(CxxString) => return,
| Some(F64) | Some(CxxString) | Some(RustChar) => return,
Some(Char) | Some(RustString) => {}
}
} else if let Type::CxxVector(_) = &ptr.inner {
Expand All @@ -211,7 +211,7 @@ fn check_type_cxx_vector(cx: &mut Check, ptr: &Ty1) {
| Some(I16) | Some(I32) | Some(I64) | Some(Isize) | Some(F32) | Some(F64)
| Some(CxxString) => return,
Some(Char) => { /* todo */ }
Some(Bool) | Some(RustString) => {}
Some(Bool) | Some(RustChar) | Some(RustString) => {}
}
}

Expand Down
2 changes: 1 addition & 1 deletion syntax/pod.rs
Expand Up @@ -10,7 +10,7 @@ impl<'a> Types<'a> {
match atom {
Bool | Char | U8 | U16 | U32 | U64 | Usize | I8 | I16 | I32 | I64
| Isize | F32 | F64 => true,
CxxString | RustString => false,
RustChar | CxxString | RustString => false,
}
} else if let Some(strct) = self.structs.get(ident) {
derive::contains(&strct.derives, Trait::Copy)
Expand Down
12 changes: 12 additions & 0 deletions tests/ffi/lib.rs
Expand Up @@ -103,6 +103,7 @@ pub mod ffi {
fn c_return_str(shared: &Shared) -> &str;
fn c_return_slice_char(shared: &Shared) -> &[c_char];
fn c_return_mutsliceu8(slice: &mut [u8]) -> &mut [u8];
fn c_return_rust_char() -> char;
fn c_return_rust_string() -> String;
fn c_return_rust_string_lossy() -> String;
fn c_return_unique_ptr_string() -> UniquePtr<CxxString>;
Expand All @@ -129,6 +130,7 @@ pub mod ffi {
fn c_return_mut_ptr(n: usize) -> *mut C;

fn c_take_primitive(n: usize);
fn c_take_rust_char(c: char);
fn c_take_shared(shared: Shared);
fn c_take_box(r: Box<R>);
fn c_take_ref_r(r: &R);
Expand Down Expand Up @@ -258,6 +260,7 @@ pub mod ffi {
type R;

fn r_return_primitive() -> usize;
fn r_return_rust_char() -> char;
fn r_return_shared() -> Shared;
fn r_return_box() -> Box<R>;
fn r_return_unique_ptr() -> UniquePtr<C>;
Expand All @@ -279,6 +282,7 @@ pub mod ffi {
fn r_return_enum(n: u32) -> Enum;

fn r_take_primitive(n: usize);
fn r_take_rust_char(c: char);
fn r_take_shared(shared: Shared);
fn r_take_box(r: Box<R>);
fn r_take_unique_ptr(c: UniquePtr<C>);
Expand Down Expand Up @@ -442,6 +446,10 @@ fn r_return_primitive() -> usize {
2020
}

fn r_return_rust_char() -> char {
'🙃'
}

fn r_return_shared() -> ffi::Shared {
ffi::Shared { z: 2020 }
}
Expand Down Expand Up @@ -519,6 +527,10 @@ fn r_return_ref_rust_vec(shared: &ffi::Shared) -> &Vec<u8> {
unimplemented!()
}

fn r_take_rust_char(c: char) {
assert_eq!('🙃', c);
}

fn r_return_mut_rust_vec(shared: &mut ffi::Shared) -> &mut Vec<u8> {
let _ = shared;
unimplemented!()
Expand Down
10 changes: 10 additions & 0 deletions tests/ffi/tests.cc
Expand Up @@ -54,6 +54,8 @@ std::vector<uint8_t> &C::get_v() { return this->v; }

size_t c_return_primitive() { return 2020; }

rust::Char c_return_rust_char() { return rust::Char{U'\U0001f643'}; }

Shared c_return_shared() { return Shared{2020}; }

::A::AShared c_return_ns_shared() { return ::A::AShared{2020}; }
Expand Down Expand Up @@ -223,6 +225,12 @@ void Borrow::const_member() const {}

void Borrow::nonconst_member() {}

void c_take_rust_char(rust::Char c) {
if (c.get() == U'\U0001f643') {
cxx_test_suite_set_correct();
}
}

std::unique_ptr<Borrow> c_return_borrow(const std::string &s) {
return std::unique_ptr<Borrow>(new Borrow(s));
}
Expand Down Expand Up @@ -770,6 +778,7 @@ extern "C" const char *cxx_run_test() noexcept {
ASSERT(rust::size_of<size_t>() == sizeof(size_t));
ASSERT(rust::align_of<size_t>() == alignof(size_t));

ASSERT(r_return_rust_char().get() == U'\U0001f643');
ASSERT(r_return_primitive() == 2020);
ASSERT(r_return_shared().z == 2020);
ASSERT(cxx_test_suite_r_is_correct(&*r_return_box()));
Expand All @@ -786,6 +795,7 @@ extern "C" const char *cxx_run_test() noexcept {
ASSERT(r_return_enum(2021) == Enum::CVal);

r_take_primitive(2020);
r_take_rust_char(rust::Char(U'\U0001f643'));
r_take_shared(Shared{2020});
r_take_unique_ptr(std::unique_ptr<C>(new C{2020}));
r_take_shared_ptr(std::shared_ptr<C>(new C{2020}));
Expand Down
2 changes: 2 additions & 0 deletions tests/ffi/tests.h
Expand Up @@ -87,6 +87,7 @@ struct Borrow {
typedef char Buffer[12];

size_t c_return_primitive();
rust::Char c_return_rust_char();
Shared c_return_shared();
::A::AShared c_return_ns_shared();
::A::B::ABShared c_return_nested_ns_shared();
Expand Down Expand Up @@ -125,6 +126,7 @@ std::unique_ptr<Borrow> c_return_borrow(const std::string &s);
const C *c_return_const_ptr(size_t n);
C *c_return_mut_ptr(size_t n);

void c_take_rust_char(rust::Char c);
void c_take_primitive(size_t n);
void c_take_shared(Shared shared);
void c_take_ns_shared(::A::AShared shared);
Expand Down
1 change: 1 addition & 0 deletions tests/test.rs
Expand Up @@ -118,6 +118,7 @@ fn test_c_take() {
let unique_ptr = ffi::c_return_unique_ptr();
let unique_ptr_ns = ffi2::c_return_ns_unique_ptr();

check!(ffi::c_take_rust_char('🙃'));
check!(ffi::c_take_primitive(2020));
check!(ffi::c_take_shared(ffi::Shared { z: 2020 }));
check!(ffi::c_take_ns_shared(ffi::AShared { z: 2020 }));
Expand Down