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

Adding &[u8] support. #117

Merged
merged 2 commits into from
Apr 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 299,7 @@ returns of functions.
<tr><th>name in Rust</th><th>name in C </th><th>restrictions</th></tr>
<tr><td>String</td><td>rust::String</td><td></td></tr>
<tr><td>&amp;str</td><td>rust::Str</td><td></td></tr>
<tr><td>&amp;[u8]</td><td>rust::Slice&lt;uint8_t&gt;</td><td>(no other slice types currently supported)</td></tr>
<tr><td><a href="https://docs.rs/cxx/0.2/cxx/struct.CxxString.html">CxxString</a></td><td>std::string</td><td><sup><i>cannot be passed by value</i></sup></td></tr>
<tr><td>Box&lt;T&gt;</td><td>rust::Box&lt;T&gt;</td><td><sup><i>cannot hold opaque C type</i></sup></td></tr>
<tr><td><a href="https://docs.rs/cxx/0.2/cxx/struct.UniquePtr.html">UniquePtr&lt;T&gt;</a></td><td>std::unique_ptr&lt;T&gt;</td><td><sup><i>cannot hold opaque Rust type</i></sup></td></tr>
Expand All @@ -316,7 317,6 @@ matter of designing a nice API for each in its non-native language.

<table>
<tr><th>name in Rust</th><th>name in C </th></tr>
<tr><td>&amp;[T]</td><td><sup><i>tbd</i></sup></td></tr>
<tr><td>Vec&lt;T&gt;</td><td><sup><i>tbd</i></sup></td></tr>
<tr><td>BTreeMap&lt;K, V&gt;</td><td><sup><i>tbd</i></sup></td></tr>
<tr><td>HashMap&lt;K, V&gt;</td><td><sup><i>tbd</i></sup></td></tr>
Expand Down
22 changes: 17 additions & 5 deletions gen/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 365,7 @@ fn write_cxx_function_shim(out: &mut OutFile, efn: &ExternFn, types: &Types) {
match &efn.ret {
Some(Type::Ref(_)) => write!(out, "&"),
Some(Type::Str(_)) if !indirect_return => write!(out, "::rust::Str::Repr("),
Some(Type::SliceRefU8(_)) if !indirect_return => write!(out, "::rust::Slice<uint8_t>::Repr("),
_ => {}
}
write!(out, "{}$(", efn.ident);
Expand Down Expand Up @@ -395,7 396,7 @@ fn write_cxx_function_shim(out: &mut OutFile, efn: &ExternFn, types: &Types) {
match &efn.ret {
Some(Type::RustBox(_)) => write!(out, ".into_raw()"),
Some(Type::UniquePtr(_)) => write!(out, ".release()"),
Some(Type::Str(_)) if !indirect_return => write!(out, ")"),
Some(Type::Str(_)) | Some(Type::SliceRefU8(_)) if !indirect_return => write!(out, ")"),
_ => {}
}
if indirect_return {
Expand Down Expand Up @@ -566,14 567,15 @@ fn write_rust_function_shim_impl(
}
match &arg.ty {
Type::Str(_) => write!(out, "::rust::Str::Repr("),
Type::SliceRefU8(_) => write!(out, "::rust::Slice<uint8_t>::Repr("),
ty if types.needs_indirect_abi(ty) => write!(out, "&"),
_ => {}
}
write!(out, "{}", arg.ident);
match &arg.ty {
Type::RustBox(_) => write!(out, ".into_raw()"),
Type::UniquePtr(_) => write!(out, ".release()"),
Type::Str(_) => write!(out, ")"),
Type::Str(_) | Type::SliceRefU8(_) => write!(out, ")"),
ty if ty != RustString && types.needs_indirect_abi(ty) => write!(out, "$.value"),
_ => {}
}
Expand Down Expand Up @@ -637,6 639,7 @@ fn write_indirect_return_type(out: &mut OutFile, ty: &Type) {
write!(out, " *");
}
Type::Str(_) => write!(out, "::rust::Str::Repr"),
Type::SliceRefU8(_) => write!(out, "::rust::Slice<uint8_t>::Repr"),
_ => write_type(out, ty),
}
}
Expand All @@ -645,7 648,7 @@ fn write_indirect_return_type_space(out: &mut OutFile, ty: &Type) {
write_indirect_return_type(out, ty);
match ty {
Type::RustBox(_) | Type::UniquePtr(_) | Type::Ref(_) => {}
Type::Str(_) => write!(out, " "),
Type::Str(_) | Type::SliceRefU8(_) => write!(out, " "),
_ => write_space_after_type(out, ty),
}
}
Expand All @@ -664,6 667,7 @@ fn write_extern_return_type_space(out: &mut OutFile, ty: &Option<Type>, types: &
write!(out, " *");
}
Some(Type::Str(_)) => write!(out, "::rust::Str::Repr "),
Some(Type::SliceRefU8(_)) => write!(out, "::rust::Slice<uint8_t>::Repr "),
Some(ty) if types.needs_indirect_abi(ty) => write!(out, "void "),
_ => write_return_type(out, ty),
}
Expand All @@ -676,6 680,7 @@ fn write_extern_arg(out: &mut OutFile, arg: &Var, types: &Types) {
write!(out, "*");
}
Type::Str(_) => write!(out, "::rust::Str::Repr "),
Type::SliceRefU8(_) => write!(out, "::rust::Slice<uint8_t>::Repr "),
_ => write_type_space(out, &arg.ty),
}
if types.needs_indirect_abi(&arg.ty) {
Expand Down Expand Up @@ -721,9 726,16 @@ fn write_type(out: &mut OutFile, ty: &Type) {
write_type(out, &r.inner);
write!(out, " &");
}
Type::Slice(_) => {
// For now, only U8 slices are supported, which are covered separately below
unreachable!()
}
Type::Str(_) => {
write!(out, "::rust::Str");
}
Type::SliceRefU8(_) => {
write!(out, "::rust::Slice<uint8_t>");
}
Type::Fn(f) => {
write!(out, "::rust::{}<", if f.throws { "TryFn" } else { "Fn" });
match &f.ret {
Expand All @@ -750,11 762,11 @@ fn write_type_space(out: &mut OutFile, ty: &Type) {

fn write_space_after_type(out: &mut OutFile, ty: &Type) {
match ty {
Type::Ident(_) | Type::RustBox(_) | Type::UniquePtr(_) | Type::Str(_) | Type::Fn(_) => {
Type::Ident(_) | Type::RustBox(_) | Type::UniquePtr(_) | Type::Str(_) | Type::SliceRefU8(_) | Type::Fn(_) => {
write!(out, " ")
}
Type::Ref(_) => {}
Type::Void(_) => unreachable!(),
Type::Void(_) | Type::Slice(_) => unreachable!(),
}
}

Expand Down
37 changes: 37 additions & 0 deletions include/cxx.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 16,43 @@ inline namespace cxxbridge02 {

struct unsafe_bitcopy_t;

#ifndef CXXBRIDGE02_RUST_SLICE
#define CXXBRIDGE02_RUST_SLICE
template<typename T>
class Slice final {
public:
Slice() noexcept : repr(Repr{reinterpret_cast<const T *>(this), 0}) {}
Slice(const Slice<T> &) noexcept = default;

Slice(const T* s, size_t size) : repr(Repr{s, size}) {}

Slice &operator=(Slice<T> other) noexcept {
this->repr = other.repr;
return *this;
}

const T *data() const noexcept { return this->repr.ptr; }
size_t size() const noexcept { return this->repr.len; }
size_t length() const noexcept { return this->repr.len; }

// Repr is PRIVATE; must not be used other than by our generated code.
//
// At present this class is only used for &[u8] slices.
// Not necessarily ABI compatible with &[u8]. Codegen will translate to
// cxx::rust_slice_u8::RustSlice which matches this layout.
struct Repr {
const T *ptr;
size_t len;
};
Slice(Repr repr_) noexcept : repr(repr_) {}
explicit operator Repr() noexcept { return this->repr; }

private:
Repr repr;
};

#endif // CXXBRIDGE02_RUST_SLICE

#ifndef CXXBRIDGE02_RUST_STRING
#define CXXBRIDGE02_RUST_STRING
class String final {
Expand Down
6 changes: 6 additions & 0 deletions macro/src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 184,7 @@ fn expand_cxx_function_shim(namespace: &Namespace, efn: &ExternFn, types: &Types
_ => quote!(#var),
},
Type::Str(_) => quote!(::cxx::private::RustStr::from(#var)),
Type::SliceRefU8(_) => quote!(::cxx::private::RustSliceU8::from(#var)),
ty if types.needs_indirect_abi(ty) => quote!(#var.as_mut_ptr()),
_ => quote!(#var),
}
Expand Down Expand Up @@ -255,6 256,7 @@ fn expand_cxx_function_shim(namespace: &Namespace, efn: &ExternFn, types: &Types
_ => None,
},
Type::Str(_) => Some(quote!(#call.map(|r| r.as_str()))),
Type::SliceRefU8(_) => Some(quote!(#call.map(|r| r.as_slice()))),
_ => None,
})
} else {
Expand All @@ -267,6 269,7 @@ fn expand_cxx_function_shim(namespace: &Namespace, efn: &ExternFn, types: &Types
_ => None,
},
Type::Str(_) => Some(quote!(#call.as_str())),
Type::SliceRefU8(_) => Some(quote!(#call.as_slice())),
_ => None,
})
}
Expand Down Expand Up @@ -375,6 378,7 @@ fn expand_rust_function_shim_impl(
_ => quote!(#ident),
},
Type::Str(_) => quote!(#ident.as_str()),
Type::SliceRefU8(_) => quote!(#ident.as_slice()),
ty if types.needs_indirect_abi(ty) => quote!(::std::ptr::read(#ident)),
_ => quote!(#ident),
}
Expand Down Expand Up @@ -402,6 406,7 @@ fn expand_rust_function_shim_impl(
_ => None,
},
Type::Str(_) => Some(quote!(::cxx::private::RustStr::from(#call))),
Type::SliceRefU8(_) => Some(quote!(::cxx::private::RustSliceU8::from(#call))),
_ => None,
})
.unwrap_or(call);
Expand Down Expand Up @@ -572,6 577,7 @@ fn expand_extern_type(ty: &Type) -> TokenStream {
_ => quote!(#ty),
},
Type::Str(_) => quote!(::cxx::private::RustStr),
Type::SliceRefU8(_) => quote!(::cxx::private::RustSliceU8),
_ => quote!(#ty),
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 367,7 @@ mod gen;
mod opaque;
mod paths;
mod result;
mod rust_sliceu8;
mod rust_str;
mod rust_string;
mod syntax;
Expand All @@ -384,6 385,7 @@ pub mod private {
pub use crate::function::FatFunction;
pub use crate::opaque::Opaque;
pub use crate::result::{r#try, Result};
pub use crate::rust_sliceu8::RustSliceU8;
pub use crate::rust_str::RustStr;
pub use crate::rust_string::RustString;
pub use crate::unique_ptr::UniquePtrTarget;
Expand Down
26 changes: 26 additions & 0 deletions src/rust_sliceu8.rs
Original file line number Diff line number Diff line change
@@ -0,0 1,26 @@
use std::mem;
use std::slice;
use std::ptr::NonNull;

// Not necessarily ABI compatible with &[u8]. Codegen performs the translation.
#[repr(C)]
#[derive(Copy, Clone)]
pub struct RustSliceU8 {
pub(crate) ptr: NonNull<u8>,
pub(crate) len: usize,
}

impl RustSliceU8 {
pub fn from(s: &[u8]) -> Self {
RustSliceU8 {
ptr: NonNull::from(s).cast::<u8>(),
len: s.len(),
}
}

pub unsafe fn as_slice<'a>(self) -> &'a [u8] {
slice::from_raw_parts(self.ptr.as_ptr(), self.len)
}
}

const_assert!(mem::size_of::<Option<RustSliceU8>>() == mem::size_of::<RustSliceU8>());
2 changes: 2 additions & 0 deletions syntax/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 245,8 @@ fn describe(cx: &mut Check, ty: &Type) -> String {
Type::UniquePtr(_) => "unique_ptr".to_owned(),
Type::Ref(_) => "reference".to_owned(),
Type::Str(_) => "&str".to_owned(),
Type::Slice(_) => "slice".to_owned(),
Type::SliceRefU8(_) => "&[u8]".to_owned(),
Type::Fn(_) => "function pointer".to_owned(),
Type::Void(_) => "()".to_owned(),
}
Expand Down
32 changes: 31 additions & 1 deletion syntax/impls.rs
Original file line number Diff line number Diff line change
@@ -1,4 1,4 @@
use crate::syntax::{ExternFn, Receiver, Ref, Signature, Ty1, Type};
use crate::syntax::{ExternFn, Receiver, Ref, Signature, Slice, Ty1, Type};
use std::hash::{Hash, Hasher};
use std::mem;
use std::ops::Deref;
Expand All @@ -21,6 21,8 @@ impl Hash for Type {
Type::Ref(t) => t.hash(state),
Type::Str(t) => t.hash(state),
Type::Fn(t) => t.hash(state),
Type::Slice(t) => t.hash(state),
Type::SliceRefU8(t) => t.hash(state),
Type::Void(_) => {}
}
}
Expand All @@ -37,6 39,8 @@ impl PartialEq for Type {
(Type::Ref(lhs), Type::Ref(rhs)) => lhs == rhs,
(Type::Str(lhs), Type::Str(rhs)) => lhs == rhs,
(Type::Fn(lhs), Type::Fn(rhs)) => lhs == rhs,
(Type::Slice(lhs), Type::Slice(rhs)) => lhs == rhs,
(Type::SliceRefU8(lhs), Type::SliceRefU8(rhs)) => lhs == rhs,
(Type::Void(_), Type::Void(_)) => true,
(_, _) => false,
}
Expand Down Expand Up @@ -106,6 110,32 @@ impl Hash for Ref {
}
}

impl Eq for Slice {}

impl PartialEq for Slice {
fn eq(&self, other: &Slice) -> bool {
let Slice {
bracket: _,
inner,
} = self;
let Slice {
bracket: _,
inner: inner2,
} = other;
inner == inner2
}
}

impl Hash for Slice {
fn hash<H: Hasher>(&self, state: &mut H) {
let Slice {
bracket: _,
inner,
} = self;
inner.hash(state);
}
}

impl Eq for Signature {}

impl PartialEq for Signature {
Expand Down
9 changes: 8 additions & 1 deletion syntax/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 15,7 @@ pub mod types;
use self::parse::kw;
use proc_macro2::{Ident, Span};
use syn::punctuated::Punctuated;
use syn::token::{Brace, Paren};
use syn::token::{Brace, Bracket, Paren};
use syn::{LitStr, Token};

pub use self::atom::Atom;
Expand Down Expand Up @@ -84,6 84,8 @@ pub enum Type {
Str(Box<Ref>),
Fn(Box<Signature>),
Void(Span),
Slice(Box<Slice>),
SliceRefU8(Box<Ref>),
}

pub struct Ty1 {
Expand All @@ -99,6 101,11 @@ pub struct Ref {
pub inner: Type,
}

pub struct Slice {
pub bracket: Bracket,
pub inner: Type,
}

#[derive(Copy, Clone, PartialEq)]
pub enum Lang {
Cxx,
Expand Down
Loading