Skip to content

Commit f677f0a

Browse files
authored
Merge pull request #117 from adetaylor/sliceu8
Adding &[u8] support.
2 parents 850ca90 + ec9430e commit f677f0a

File tree

16 files changed

+200
-14
lines changed

16 files changed

+200
-14
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,7 @@ returns of functions.
299299
<tr><th>name in Rust</th><th>name in C++</th><th>restrictions</th></tr>
300300
<tr><td>String</td><td>rust::String</td><td></td></tr>
301301
<tr><td>&amp;str</td><td>rust::Str</td><td></td></tr>
302+
<tr><td>&amp;[u8]</td><td>rust::Slice&lt;uint8_t&gt;</td><td>(no other slice types currently supported)</td></tr>
302303
<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>
303304
<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>
304305
<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>
@@ -316,7 +317,6 @@ matter of designing a nice API for each in its non-native language.
316317

317318
<table>
318319
<tr><th>name in Rust</th><th>name in C++</th></tr>
319-
<tr><td>&amp;[T]</td><td><sup><i>tbd</i></sup></td></tr>
320320
<tr><td>Vec&lt;T&gt;</td><td><sup><i>tbd</i></sup></td></tr>
321321
<tr><td>BTreeMap&lt;K, V&gt;</td><td><sup><i>tbd</i></sup></td></tr>
322322
<tr><td>HashMap&lt;K, V&gt;</td><td><sup><i>tbd</i></sup></td></tr>

gen/write.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ fn write_cxx_function_shim(out: &mut OutFile, efn: &ExternFn, types: &Types) {
365365
match &efn.ret {
366366
Some(Type::Ref(_)) => write!(out, "&"),
367367
Some(Type::Str(_)) if !indirect_return => write!(out, "::rust::Str::Repr("),
368+
Some(Type::SliceRefU8(_)) if !indirect_return => write!(out, "::rust::Slice<uint8_t>::Repr("),
368369
_ => {}
369370
}
370371
write!(out, "{}$(", efn.ident);
@@ -395,7 +396,7 @@ fn write_cxx_function_shim(out: &mut OutFile, efn: &ExternFn, types: &Types) {
395396
match &efn.ret {
396397
Some(Type::RustBox(_)) => write!(out, ".into_raw()"),
397398
Some(Type::UniquePtr(_)) => write!(out, ".release()"),
398-
Some(Type::Str(_)) if !indirect_return => write!(out, ")"),
399+
Some(Type::Str(_)) | Some(Type::SliceRefU8(_)) if !indirect_return => write!(out, ")"),
399400
_ => {}
400401
}
401402
if indirect_return {
@@ -566,14 +567,15 @@ fn write_rust_function_shim_impl(
566567
}
567568
match &arg.ty {
568569
Type::Str(_) => write!(out, "::rust::Str::Repr("),
570+
Type::SliceRefU8(_) => write!(out, "::rust::Slice<uint8_t>::Repr("),
569571
ty if types.needs_indirect_abi(ty) => write!(out, "&"),
570572
_ => {}
571573
}
572574
write!(out, "{}", arg.ident);
573575
match &arg.ty {
574576
Type::RustBox(_) => write!(out, ".into_raw()"),
575577
Type::UniquePtr(_) => write!(out, ".release()"),
576-
Type::Str(_) => write!(out, ")"),
578+
Type::Str(_) | Type::SliceRefU8(_) => write!(out, ")"),
577579
ty if ty != RustString && types.needs_indirect_abi(ty) => write!(out, "$.value"),
578580
_ => {}
579581
}
@@ -637,6 +639,7 @@ fn write_indirect_return_type(out: &mut OutFile, ty: &Type) {
637639
write!(out, " *");
638640
}
639641
Type::Str(_) => write!(out, "::rust::Str::Repr"),
642+
Type::SliceRefU8(_) => write!(out, "::rust::Slice<uint8_t>::Repr"),
640643
_ => write_type(out, ty),
641644
}
642645
}
@@ -645,7 +648,7 @@ fn write_indirect_return_type_space(out: &mut OutFile, ty: &Type) {
645648
write_indirect_return_type(out, ty);
646649
match ty {
647650
Type::RustBox(_) | Type::UniquePtr(_) | Type::Ref(_) => {}
648-
Type::Str(_) => write!(out, " "),
651+
Type::Str(_) | Type::SliceRefU8(_) => write!(out, " "),
649652
_ => write_space_after_type(out, ty),
650653
}
651654
}
@@ -664,6 +667,7 @@ fn write_extern_return_type_space(out: &mut OutFile, ty: &Option<Type>, types: &
664667
write!(out, " *");
665668
}
666669
Some(Type::Str(_)) => write!(out, "::rust::Str::Repr "),
670+
Some(Type::SliceRefU8(_)) => write!(out, "::rust::Slice<uint8_t>::Repr "),
667671
Some(ty) if types.needs_indirect_abi(ty) => write!(out, "void "),
668672
_ => write_return_type(out, ty),
669673
}
@@ -676,6 +680,7 @@ fn write_extern_arg(out: &mut OutFile, arg: &Var, types: &Types) {
676680
write!(out, "*");
677681
}
678682
Type::Str(_) => write!(out, "::rust::Str::Repr "),
683+
Type::SliceRefU8(_) => write!(out, "::rust::Slice<uint8_t>::Repr "),
679684
_ => write_type_space(out, &arg.ty),
680685
}
681686
if types.needs_indirect_abi(&arg.ty) {
@@ -721,9 +726,16 @@ fn write_type(out: &mut OutFile, ty: &Type) {
721726
write_type(out, &r.inner);
722727
write!(out, " &");
723728
}
729+
Type::Slice(_) => {
730+
// For now, only U8 slices are supported, which are covered separately below
731+
unreachable!()
732+
}
724733
Type::Str(_) => {
725734
write!(out, "::rust::Str");
726735
}
736+
Type::SliceRefU8(_) => {
737+
write!(out, "::rust::Slice<uint8_t>");
738+
}
727739
Type::Fn(f) => {
728740
write!(out, "::rust::{}<", if f.throws { "TryFn" } else { "Fn" });
729741
match &f.ret {
@@ -750,11 +762,11 @@ fn write_type_space(out: &mut OutFile, ty: &Type) {
750762

751763
fn write_space_after_type(out: &mut OutFile, ty: &Type) {
752764
match ty {
753-
Type::Ident(_) | Type::RustBox(_) | Type::UniquePtr(_) | Type::Str(_) | Type::Fn(_) => {
765+
Type::Ident(_) | Type::RustBox(_) | Type::UniquePtr(_) | Type::Str(_) | Type::SliceRefU8(_) | Type::Fn(_) => {
754766
write!(out, " ")
755767
}
756768
Type::Ref(_) => {}
757-
Type::Void(_) => unreachable!(),
769+
Type::Void(_) | Type::Slice(_) => unreachable!(),
758770
}
759771
}
760772

include/cxx.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,43 @@ inline namespace cxxbridge02 {
1616

1717
struct unsafe_bitcopy_t;
1818

19+
#ifndef CXXBRIDGE02_RUST_SLICE
20+
#define CXXBRIDGE02_RUST_SLICE
21+
template<typename T>
22+
class Slice final {
23+
public:
24+
Slice() noexcept : repr(Repr{reinterpret_cast<const T *>(this), 0}) {}
25+
Slice(const Slice<T> &) noexcept = default;
26+
27+
Slice(const T* s, size_t size) : repr(Repr{s, size}) {}
28+
29+
Slice &operator=(Slice<T> other) noexcept {
30+
this->repr = other.repr;
31+
return *this;
32+
}
33+
34+
const T *data() const noexcept { return this->repr.ptr; }
35+
size_t size() const noexcept { return this->repr.len; }
36+
size_t length() const noexcept { return this->repr.len; }
37+
38+
// Repr is PRIVATE; must not be used other than by our generated code.
39+
//
40+
// At present this class is only used for &[u8] slices.
41+
// Not necessarily ABI compatible with &[u8]. Codegen will translate to
42+
// cxx::rust_slice_u8::RustSlice which matches this layout.
43+
struct Repr {
44+
const T *ptr;
45+
size_t len;
46+
};
47+
Slice(Repr repr_) noexcept : repr(repr_) {}
48+
explicit operator Repr() noexcept { return this->repr; }
49+
50+
private:
51+
Repr repr;
52+
};
53+
54+
#endif // CXXBRIDGE02_RUST_SLICE
55+
1956
#ifndef CXXBRIDGE02_RUST_STRING
2057
#define CXXBRIDGE02_RUST_STRING
2158
class String final {

macro/src/expand.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ fn expand_cxx_function_shim(namespace: &Namespace, efn: &ExternFn, types: &Types
184184
_ => quote!(#var),
185185
},
186186
Type::Str(_) => quote!(::cxx::private::RustStr::from(#var)),
187+
Type::SliceRefU8(_) => quote!(::cxx::private::RustSliceU8::from(#var)),
187188
ty if types.needs_indirect_abi(ty) => quote!(#var.as_mut_ptr()),
188189
_ => quote!(#var),
189190
}
@@ -255,6 +256,7 @@ fn expand_cxx_function_shim(namespace: &Namespace, efn: &ExternFn, types: &Types
255256
_ => None,
256257
},
257258
Type::Str(_) => Some(quote!(#call.map(|r| r.as_str()))),
259+
Type::SliceRefU8(_) => Some(quote!(#call.map(|r| r.as_slice()))),
258260
_ => None,
259261
})
260262
} else {
@@ -267,6 +269,7 @@ fn expand_cxx_function_shim(namespace: &Namespace, efn: &ExternFn, types: &Types
267269
_ => None,
268270
},
269271
Type::Str(_) => Some(quote!(#call.as_str())),
272+
Type::SliceRefU8(_) => Some(quote!(#call.as_slice())),
270273
_ => None,
271274
})
272275
}
@@ -375,6 +378,7 @@ fn expand_rust_function_shim_impl(
375378
_ => quote!(#ident),
376379
},
377380
Type::Str(_) => quote!(#ident.as_str()),
381+
Type::SliceRefU8(_) => quote!(#ident.as_slice()),
378382
ty if types.needs_indirect_abi(ty) => quote!(::std::ptr::read(#ident)),
379383
_ => quote!(#ident),
380384
}
@@ -402,6 +406,7 @@ fn expand_rust_function_shim_impl(
402406
_ => None,
403407
},
404408
Type::Str(_) => Some(quote!(::cxx::private::RustStr::from(#call))),
409+
Type::SliceRefU8(_) => Some(quote!(::cxx::private::RustSliceU8::from(#call))),
405410
_ => None,
406411
})
407412
.unwrap_or(call);
@@ -572,6 +577,7 @@ fn expand_extern_type(ty: &Type) -> TokenStream {
572577
_ => quote!(#ty),
573578
},
574579
Type::Str(_) => quote!(::cxx::private::RustStr),
580+
Type::SliceRefU8(_) => quote!(::cxx::private::RustSliceU8),
575581
_ => quote!(#ty),
576582
}
577583
}

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,7 @@ mod gen;
367367
mod opaque;
368368
mod paths;
369369
mod result;
370+
mod rust_sliceu8;
370371
mod rust_str;
371372
mod rust_string;
372373
mod syntax;
@@ -384,6 +385,7 @@ pub mod private {
384385
pub use crate::function::FatFunction;
385386
pub use crate::opaque::Opaque;
386387
pub use crate::result::{r#try, Result};
388+
pub use crate::rust_sliceu8::RustSliceU8;
387389
pub use crate::rust_str::RustStr;
388390
pub use crate::rust_string::RustString;
389391
pub use crate::unique_ptr::UniquePtrTarget;

src/rust_sliceu8.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use std::mem;
2+
use std::slice;
3+
use std::ptr::NonNull;
4+
5+
// Not necessarily ABI compatible with &[u8]. Codegen performs the translation.
6+
#[repr(C)]
7+
#[derive(Copy, Clone)]
8+
pub struct RustSliceU8 {
9+
pub(crate) ptr: NonNull<u8>,
10+
pub(crate) len: usize,
11+
}
12+
13+
impl RustSliceU8 {
14+
pub fn from(s: &[u8]) -> Self {
15+
RustSliceU8 {
16+
ptr: NonNull::from(s).cast::<u8>(),
17+
len: s.len(),
18+
}
19+
}
20+
21+
pub unsafe fn as_slice<'a>(self) -> &'a [u8] {
22+
slice::from_raw_parts(self.ptr.as_ptr(), self.len)
23+
}
24+
}
25+
26+
const_assert!(mem::size_of::<Option<RustSliceU8>>() == mem::size_of::<RustSliceU8>());

syntax/check.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,8 @@ fn describe(cx: &mut Check, ty: &Type) -> String {
245245
Type::UniquePtr(_) => "unique_ptr".to_owned(),
246246
Type::Ref(_) => "reference".to_owned(),
247247
Type::Str(_) => "&str".to_owned(),
248+
Type::Slice(_) => "slice".to_owned(),
249+
Type::SliceRefU8(_) => "&[u8]".to_owned(),
248250
Type::Fn(_) => "function pointer".to_owned(),
249251
Type::Void(_) => "()".to_owned(),
250252
}

syntax/impls.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::syntax::{ExternFn, Receiver, Ref, Signature, Ty1, Type};
1+
use crate::syntax::{ExternFn, Receiver, Ref, Signature, Slice, Ty1, Type};
22
use std::hash::{Hash, Hasher};
33
use std::mem;
44
use std::ops::Deref;
@@ -21,6 +21,8 @@ impl Hash for Type {
2121
Type::Ref(t) => t.hash(state),
2222
Type::Str(t) => t.hash(state),
2323
Type::Fn(t) => t.hash(state),
24+
Type::Slice(t) => t.hash(state),
25+
Type::SliceRefU8(t) => t.hash(state),
2426
Type::Void(_) => {}
2527
}
2628
}
@@ -37,6 +39,8 @@ impl PartialEq for Type {
3739
(Type::Ref(lhs), Type::Ref(rhs)) => lhs == rhs,
3840
(Type::Str(lhs), Type::Str(rhs)) => lhs == rhs,
3941
(Type::Fn(lhs), Type::Fn(rhs)) => lhs == rhs,
42+
(Type::Slice(lhs), Type::Slice(rhs)) => lhs == rhs,
43+
(Type::SliceRefU8(lhs), Type::SliceRefU8(rhs)) => lhs == rhs,
4044
(Type::Void(_), Type::Void(_)) => true,
4145
(_, _) => false,
4246
}
@@ -106,6 +110,32 @@ impl Hash for Ref {
106110
}
107111
}
108112

113+
impl Eq for Slice {}
114+
115+
impl PartialEq for Slice {
116+
fn eq(&self, other: &Slice) -> bool {
117+
let Slice {
118+
bracket: _,
119+
inner,
120+
} = self;
121+
let Slice {
122+
bracket: _,
123+
inner: inner2,
124+
} = other;
125+
inner == inner2
126+
}
127+
}
128+
129+
impl Hash for Slice {
130+
fn hash<H: Hasher>(&self, state: &mut H) {
131+
let Slice {
132+
bracket: _,
133+
inner,
134+
} = self;
135+
inner.hash(state);
136+
}
137+
}
138+
109139
impl Eq for Signature {}
110140

111141
impl PartialEq for Signature {

syntax/mod.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub mod types;
1515
use self::parse::kw;
1616
use proc_macro2::{Ident, Span};
1717
use syn::punctuated::Punctuated;
18-
use syn::token::{Brace, Paren};
18+
use syn::token::{Brace, Bracket, Paren};
1919
use syn::{LitStr, Token};
2020

2121
pub use self::atom::Atom;
@@ -84,6 +84,8 @@ pub enum Type {
8484
Str(Box<Ref>),
8585
Fn(Box<Signature>),
8686
Void(Span),
87+
Slice(Box<Slice>),
88+
SliceRefU8(Box<Ref>),
8789
}
8890

8991
pub struct Ty1 {
@@ -99,6 +101,11 @@ pub struct Ref {
99101
pub inner: Type,
100102
}
101103

104+
pub struct Slice {
105+
pub bracket: Bracket,
106+
pub inner: Type,
107+
}
108+
102109
#[derive(Copy, Clone, PartialEq)]
103110
pub enum Lang {
104111
Cxx,

0 commit comments

Comments
 (0)