diff --git a/gen/src/write.rs b/gen/src/write.rs index 6ef982502..23e038781 100644 --- a/gen/src/write.rs +++ b/gen/src/write.rs @@ -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::{CxxVectorPayloadImplKey, ImplKey, NamedImplKey, PtrMutability}; use crate::syntax::map::UnorderedMap as Map; use crate::syntax::set::UnorderedSet; use crate::syntax::symbol::{self, Symbol}; @@ -1352,6 +1352,7 @@ fn write_space_after_type(out: &mut OutFile, ty: &Type) { enum UniquePtr<'a> { Ident(&'a Ident), CxxVector(&'a Ident), + CxxVectorPtr(PtrMutability, &'a Ident), } trait ToTypename { @@ -1371,6 +1372,17 @@ impl<'a> ToTypename for UniquePtr<'a> { UniquePtr::CxxVector(element) => { format!("::std::vector<{}>", element.to_typename(types)) } + UniquePtr::CxxVectorPtr(mutability, element) => { + let const_prefix = match mutability { + PtrMutability::Const => "const ", + PtrMutability::Mut => "", + }; + format!( + "::std::vector<{}{}*>", + const_prefix, + element.to_typename(types) + ) + } } } } @@ -1392,6 +1404,13 @@ impl<'a> ToMangled for UniquePtr<'a> { UniquePtr::CxxVector(element) => { symbol::join(&[&"std", &"vector", &element.to_mangled(types)]) } + UniquePtr::CxxVectorPtr(mutability, element) => { + let prefix = match mutability { + PtrMutability::Const => "ptrc", + PtrMutability::Mut => "ptrm", + }; + symbol::join(&[&"std", &"vector", &prefix, &element.to_mangled(types)]) + } } } } @@ -1412,7 +1431,7 @@ fn write_generic_instantiations(out: &mut OutFile) { ImplKey::UniquePtr(ident) => write_unique_ptr(out, ident), ImplKey::SharedPtr(ident) => write_shared_ptr(out, ident), ImplKey::WeakPtr(ident) => write_weak_ptr(out, ident), - ImplKey::CxxVector(ident) => write_cxx_vector(out, ident), + ImplKey::CxxVector(payload) => write_cxx_vector(out, payload), } } out.end_block(Block::ExternC); @@ -1639,21 +1658,21 @@ fn write_unique_ptr_common(out: &mut OutFile, ty: UniquePtr) { // bindings for a "new" method anyway. But the Rust code can't be called // for Opaque types because the 'new' method is not implemented. UniquePtr::Ident(ident) => out.types.is_maybe_trivial(ident), - UniquePtr::CxxVector(_) => false, + UniquePtr::CxxVector(_) | UniquePtr::CxxVectorPtr(..) => false, }; let conditional_delete = match ty { UniquePtr::Ident(ident) => { !out.types.structs.contains_key(ident) && !out.types.enums.contains_key(ident) } - UniquePtr::CxxVector(_) => false, + UniquePtr::CxxVector(_) | UniquePtr::CxxVectorPtr(..) => false, }; if conditional_delete { out.builtin.is_complete = true; let definition = match ty { UniquePtr::Ident(ty) => &out.types.resolve(ty).name.cxx, - UniquePtr::CxxVector(_) => unreachable!(), + UniquePtr::CxxVector(_) | UniquePtr::CxxVectorPtr(..) => unreachable!(), }; writeln!( out, @@ -1895,7 +1914,17 @@ fn write_weak_ptr(out: &mut OutFile, key: NamedImplKey) { writeln!(out, "}}"); } -fn write_cxx_vector(out: &mut OutFile, key: NamedImplKey) { +fn write_cxx_vector(out: &mut OutFile, payload: CxxVectorPayloadImplKey) { + let (key, ptr_prefix, unique_ptr_payload) = match payload { + CxxVectorPayloadImplKey::Named(id) => (id, "", UniquePtr::CxxVector(id.rust)), + CxxVectorPayloadImplKey::Ptr(id, mutability) => { + let prefix = match mutability { + PtrMutability::Const => "ptrc$", + PtrMutability::Mut => "ptrm$", + }; + (id, prefix, UniquePtr::CxxVectorPtr(mutability, id.rust)) + } + }; let element = key.rust; let inner = element.to_typename(out.types); let instance = element.to_mangled(out.types); @@ -1907,8 +1936,8 @@ fn write_cxx_vector(out: &mut OutFile, key: NamedImplKey) { begin_function_definition(out); writeln!( out, - "::std::vector<{}> *cxxbridge1$std$vector${}$new() noexcept {{", - inner, instance, + "::std::vector<{}> *cxxbridge1$std$vector${}{}$new() noexcept {{", + inner, ptr_prefix, instance, ); writeln!(out, " return new ::std::vector<{}>();", inner); writeln!(out, "}}"); @@ -1916,8 +1945,8 @@ fn write_cxx_vector(out: &mut OutFile, key: NamedImplKey) { begin_function_definition(out); writeln!( out, - "::std::size_t cxxbridge1$std$vector${}$size(::std::vector<{}> const &s) noexcept {{", - instance, inner, + "::std::size_t cxxbridge1$std$vector${}{}$size(const ::std::vector<{}> &s) noexcept {{", + ptr_prefix, instance, inner, ); writeln!(out, " return s.size();"); writeln!(out, "}}"); @@ -1925,8 +1954,8 @@ fn write_cxx_vector(out: &mut OutFile, key: NamedImplKey) { begin_function_definition(out); writeln!( out, - "{} *cxxbridge1$std$vector${}$get_unchecked(::std::vector<{}> *s, ::std::size_t pos) noexcept {{", - inner, instance, inner, + "{} *cxxbridge1$std$vector${}{}$get_unchecked(::std::vector<{}> *s, ::std::size_t pos) noexcept {{", + inner, ptr_prefix, instance, inner, ); writeln!(out, " return &(*s)[pos];"); writeln!(out, "}}"); @@ -1935,8 +1964,8 @@ fn write_cxx_vector(out: &mut OutFile, key: NamedImplKey) { begin_function_definition(out); writeln!( out, - "void cxxbridge1$std$vector${}$push_back(::std::vector<{}> *v, {} *value) noexcept {{", - instance, inner, inner, + "void cxxbridge1$std$vector${}{}$push_back(::std::vector<{}> *v, {} *value) noexcept {{", + ptr_prefix, instance, inner, inner, ); writeln!(out, " v->push_back(::std::move(*value));"); writeln!(out, " ::rust::destroy(value);"); @@ -1945,8 +1974,8 @@ fn write_cxx_vector(out: &mut OutFile, key: NamedImplKey) { begin_function_definition(out); writeln!( out, - "void cxxbridge1$std$vector${}$pop_back(::std::vector<{}> *v, {} *out) noexcept {{", - instance, inner, inner, + "void cxxbridge1$std$vector${}{}$pop_back(::std::vector<{}> *v, {} *out) noexcept {{", + ptr_prefix, instance, inner, inner, ); writeln!(out, " ::new (out) {}(::std::move(v->back()));", inner); writeln!(out, " v->pop_back();"); @@ -1954,5 +1983,5 @@ fn write_cxx_vector(out: &mut OutFile, key: NamedImplKey) { } out.include.memory = true; - write_unique_ptr_common(out, UniquePtr::CxxVector(element)); + write_unique_ptr_common(out, unique_ptr_payload); } diff --git a/macro/src/expand.rs b/macro/src/expand.rs index c98b2a55e..32cfd6c2a 100644 --- a/macro/src/expand.rs +++ b/macro/src/expand.rs @@ -2,7 +2,7 @@ use crate::syntax::atom::Atom::*; use crate::syntax::attrs::{self, OtherAttrs}; use crate::syntax::cfg::CfgExpr; use crate::syntax::file::Module; -use crate::syntax::instantiate::{ImplKey, NamedImplKey}; +use crate::syntax::instantiate::{CxxVectorPayloadImplKey, ImplKey, NamedImplKey, PtrMutability}; use crate::syntax::qualified::QualifiedName; use crate::syntax::report::Errors; use crate::syntax::symbol::Symbol; @@ -108,8 +108,8 @@ fn expand(ffi: Module, doc: Doc, attrs: OtherAttrs, apis: &[Api], types: &Types) ImplKey::WeakPtr(ident) => { expanded.extend(expand_weak_ptr(ident, types, explicit_impl)); } - ImplKey::CxxVector(ident) => { - expanded.extend(expand_cxx_vector(ident, explicit_impl, types)); + ImplKey::CxxVector(payload) => { + expanded.extend(expand_cxx_vector(payload, explicit_impl, types)); } } } @@ -1670,21 +1670,31 @@ fn expand_weak_ptr(key: NamedImplKey, types: &Types, explicit_impl: Option<&Impl } fn expand_cxx_vector( - key: NamedImplKey, + payload: CxxVectorPayloadImplKey, explicit_impl: Option<&Impl>, types: &Types, ) -> TokenStream { + let (ptr_prefix, key, ty_prefix, elem_trait) = match payload { + CxxVectorPayloadImplKey::Named(id) => ("", id, quote! {}, quote!{ ::cxx::private::VectorElement }), + CxxVectorPayloadImplKey::Ptr(id, PtrMutability::Const) => ("ptrc$", id, quote! { *const }, quote!{ ::cxx::private::ConstPtrVectorElement }), + CxxVectorPayloadImplKey::Ptr(id, PtrMutability::Mut) => ("ptrm$", id, quote! { *mut }, quote!{ ::cxx::private::MutPtrVectorElement }), + }; let elem = key.rust; let name = elem.to_string(); let resolve = types.resolve(elem); - let prefix = format!("cxxbridge1$std$vector${}$", resolve.name.to_symbol()); + let prefix = format!( + "cxxbridge1$std$vector${}{}$", + ptr_prefix, + resolve.name.to_symbol() + ); let link_new = format!("{}new", prefix); let link_size = format!("{}size", prefix); let link_get_unchecked = format!("{}get_unchecked", prefix); let link_push_back = format!("{}push_back", prefix); let link_pop_back = format!("{}pop_back", prefix); let unique_ptr_prefix = format!( - "cxxbridge1$unique_ptr$std$vector${}$", + "cxxbridge1$unique_ptr$std$vector${}{}$", + ptr_prefix, resolve.name.to_symbol(), ); let link_unique_ptr_null = format!("{}null", unique_ptr_prefix); @@ -1694,6 +1704,7 @@ fn expand_cxx_vector( let link_unique_ptr_drop = format!("{}drop", unique_ptr_prefix); let (impl_generics, ty_generics) = generics::split_for_impl(key, explicit_impl, resolve); + let impl_target = quote! { #ty_prefix #elem #ty_generics }; let begin_span = explicit_impl.map_or(key.begin_span, |explicit| explicit.impl_token.span); let end_span = explicit_impl.map_or(key.end_span, |explicit| explicit.brace_token.span.join()); @@ -1702,75 +1713,76 @@ fn expand_cxx_vector( let can_pass_element_by_value = types.is_maybe_trivial(elem); let by_value_methods = if can_pass_element_by_value { Some(quote_spanned! {end_span=> - unsafe fn __push_back( - this: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector>, - value: &mut ::cxx::core::mem::ManuallyDrop, - ) { - extern "C" { - #[link_name = #link_push_back] - fn __push_back #impl_generics( - this: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<#elem #ty_generics>>, - value: *mut ::cxx::core::ffi::c_void, - ); - } - unsafe { - __push_back( - this, - value as *mut ::cxx::core::mem::ManuallyDrop as *mut ::cxx::core::ffi::c_void, - ); - } - } - unsafe fn __pop_back( - this: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector>, - out: &mut ::cxx::core::mem::MaybeUninit, - ) { - extern "C" { - #[link_name = #link_pop_back] - fn __pop_back #impl_generics( - this: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<#elem #ty_generics>>, - out: *mut ::cxx::core::ffi::c_void, - ); + unsafe fn __push_back( + this: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<#ty_prefix Self>>, + value: &mut ::cxx::core::mem::ManuallyDrop<#ty_prefix Self>, + ) { + extern "C" { + #[link_name = #link_push_back] + fn __push_back #impl_generics( + this: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<#impl_target>>, + value: *mut ::cxx::core::ffi::c_void, + ); + } + unsafe { + __push_back( + this, + value as *mut ::cxx::core::mem::ManuallyDrop<#ty_prefix Self> as *mut ::cxx::core::ffi::c_void, + ); + } } - unsafe { - __pop_back( - this, - out as *mut ::cxx::core::mem::MaybeUninit as *mut ::cxx::core::ffi::c_void, - ); + unsafe fn __pop_back( + this: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<#ty_prefix Self>>, + out: &mut ::cxx::core::mem::MaybeUninit<#ty_prefix Self>, + ) { + extern "C" { + #[link_name = #link_pop_back] + fn __pop_back #impl_generics( + this: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<#impl_target>>, + out: *mut ::cxx::core::ffi::c_void, + ); + } + unsafe { + __pop_back( + this, + out as *mut ::cxx::core::mem::MaybeUninit<#ty_prefix Self> as *mut ::cxx::core::ffi::c_void, + ); + } } - } - }) + }) } else { None }; quote_spanned! {end_span=> - #unsafe_token impl #impl_generics ::cxx::private::VectorElement for #elem #ty_generics { + #unsafe_token impl #impl_generics #elem_trait for #elem #ty_generics { + #[doc(hidden)] fn __typename(f: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result { f.write_str(#name) } - fn __vector_new() -> *mut ::cxx::CxxVector { + fn __vector_new() -> *mut ::cxx::CxxVector<#ty_prefix Self> { extern "C" { #[link_name = #link_new] - fn __vector_new #impl_generics() -> *mut ::cxx::CxxVector<#elem #ty_generics>; + fn __vector_new #impl_generics() -> *mut ::cxx::CxxVector<#impl_target>; } unsafe { __vector_new() } } - fn __vector_size(v: &::cxx::CxxVector) -> usize { + fn __vector_size(v: &::cxx::CxxVector<#ty_prefix Self>) -> usize { extern "C" { #[link_name = #link_size] - fn __vector_size #impl_generics(_: &::cxx::CxxVector<#elem #ty_generics>) -> usize; + fn __vector_size #impl_generics(_: &::cxx::CxxVector<#impl_target>) -> usize; } unsafe { __vector_size(v) } } - unsafe fn __get_unchecked(v: *mut ::cxx::CxxVector, pos: usize) -> *mut Self { + unsafe fn __get_unchecked(v: *mut ::cxx::CxxVector<#ty_prefix Self>, pos: usize) -> *mut #ty_prefix Self { extern "C" { #[link_name = #link_get_unchecked] fn __get_unchecked #impl_generics( - v: *mut ::cxx::CxxVector<#elem #ty_generics>, + v: *mut ::cxx::CxxVector<#impl_target>, pos: usize, ) -> *mut ::cxx::core::ffi::c_void; } - unsafe { __get_unchecked(v, pos) as *mut Self } + unsafe { __get_unchecked(v, pos) as *mut #ty_prefix Self } } #by_value_methods fn __unique_ptr_null() -> ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void> { @@ -1784,10 +1796,10 @@ fn expand_cxx_vector( } repr } - unsafe fn __unique_ptr_raw(raw: *mut ::cxx::CxxVector) -> ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void> { + unsafe fn __unique_ptr_raw(raw: *mut ::cxx::CxxVector<#ty_prefix Self>) -> ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void> { extern "C" { #[link_name = #link_unique_ptr_raw] - fn __unique_ptr_raw #impl_generics(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>, raw: *mut ::cxx::CxxVector<#elem #ty_generics>); + fn __unique_ptr_raw #impl_generics(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>, raw: *mut ::cxx::CxxVector<#impl_target>); } let mut repr = ::cxx::core::mem::MaybeUninit::uninit(); unsafe { @@ -1795,17 +1807,17 @@ fn expand_cxx_vector( } repr } - unsafe fn __unique_ptr_get(repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *const ::cxx::CxxVector { + unsafe fn __unique_ptr_get(repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *const ::cxx::CxxVector<#ty_prefix Self> { extern "C" { #[link_name = #link_unique_ptr_get] - fn __unique_ptr_get #impl_generics(this: *const ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *const ::cxx::CxxVector<#elem #ty_generics>; + fn __unique_ptr_get #impl_generics(this: *const ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *const ::cxx::CxxVector<#impl_target>; } unsafe { __unique_ptr_get(&repr) } } - unsafe fn __unique_ptr_release(mut repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *mut ::cxx::CxxVector { + unsafe fn __unique_ptr_release(mut repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *mut ::cxx::CxxVector<#ty_prefix Self> { extern "C" { #[link_name = #link_unique_ptr_release] - fn __unique_ptr_release #impl_generics(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *mut ::cxx::CxxVector<#elem #ty_generics>; + fn __unique_ptr_release #impl_generics(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *mut ::cxx::CxxVector<#impl_target>; } unsafe { __unique_ptr_release(&mut repr) } } diff --git a/src/cxx.cc b/src/cxx.cc index 0e8523103..007ba0185 100644 --- a/src/cxx.cc +++ b/src/cxx.cc @@ -633,6 +633,42 @@ static_assert(sizeof(std::string) <= kMaxExpectedWordsInString * sizeof(void *), ptr->~unique_ptr(); \ } +#define STD_VECTOR_OPS_PTR(PTR_PREFIX, RUST_TYPE, CXX_TYPE) \ + std::vector *cxxbridge1$std$vector$##PTR_PREFIX##$##RUST_TYPE##$new() noexcept { \ + return new std::vector(); \ + } \ + std::size_t cxxbridge1$std$vector$##PTR_PREFIX##$##RUST_TYPE##$size( \ + const std::vector &s) noexcept { \ + return s.size(); \ + } \ + CXX_TYPE *cxxbridge1$std$vector$##PTR_PREFIX##$##RUST_TYPE##$get_unchecked( \ + std::vector *s, std::size_t pos) noexcept { \ + return &(*s)[pos]; \ + } \ + void cxxbridge1$unique_ptr$std$vector$##PTR_PREFIX##$##RUST_TYPE##$null( \ + std::unique_ptr> *ptr) noexcept { \ + new (ptr) std::unique_ptr>(); \ + } \ + void cxxbridge1$unique_ptr$std$vector$##PTR_PREFIX##$##RUST_TYPE##$raw( \ + std::unique_ptr> *ptr, \ + std::vector *raw) noexcept { \ + new (ptr) std::unique_ptr>(raw); \ + } \ + const std::vector \ + *cxxbridge1$unique_ptr$std$vector$##PTR_PREFIX##$##RUST_TYPE##$get( \ + const std::unique_ptr> &ptr) noexcept { \ + return ptr.get(); \ + } \ + std::vector \ + *cxxbridge1$unique_ptr$std$vector$##PTR_PREFIX##$##RUST_TYPE##$release( \ + std::unique_ptr> &ptr) noexcept { \ + return ptr.release(); \ + } \ + void cxxbridge1$unique_ptr$std$vector$##PTR_PREFIX##$##RUST_TYPE##$drop( \ + std::unique_ptr> *ptr) noexcept { \ + ptr->~unique_ptr(); \ + } + #define STD_VECTOR_TRIVIAL_OPS(RUST_TYPE, CXX_TYPE) \ void cxxbridge1$std$vector$##RUST_TYPE##$push_back( \ std::vector *v, CXX_TYPE *value) noexcept { \ @@ -645,6 +681,18 @@ static_assert(sizeof(std::string) <= kMaxExpectedWordsInString * sizeof(void *), v->pop_back(); \ } +#define STD_VECTOR_TRIVIAL_OPS_PTR(PTR_PREFIX, RUST_TYPE, CXX_TYPE) \ + void cxxbridge1$std$vector$##PTR_PREFIX##$##RUST_TYPE##$push_back( \ + std::vector *v, CXX_TYPE *value) noexcept { \ + v->push_back(std::move(*value)); \ + destroy(value); \ + } \ + void cxxbridge1$std$vector$##PTR_PREFIX##$##RUST_TYPE##$pop_back(std::vector *v, \ + CXX_TYPE *out) noexcept { \ + new (out) CXX_TYPE(std::move(v->back())); \ + v->pop_back(); \ + } + #define RUST_VEC_EXTERNS(RUST_TYPE, CXX_TYPE) \ void cxxbridge1$rust_vec$##RUST_TYPE##$new( \ rust::Vec *ptr) noexcept; \ @@ -763,15 +811,49 @@ static_assert(sizeof(std::string) <= kMaxExpectedWordsInString * sizeof(void *), MACRO(f32, float) \ MACRO(f64, double) +#define FOR_EACH_NUMERIC_WITH_PTR_PREFIX(MACRO) \ + MACRO(ptrc, u8, std::uint8_t) \ + MACRO(ptrc, u16, std::uint16_t) \ + MACRO(ptrc, u32, std::uint32_t) \ + MACRO(ptrc, u64, std::uint64_t) \ + MACRO(ptrc, i8, std::int8_t) \ + MACRO(ptrc, i16, std::int16_t) \ + MACRO(ptrc, i32, std::int32_t) \ + MACRO(ptrc, i64, std::int64_t) \ + MACRO(ptrc, f32, float) \ + MACRO(ptrc, f64, double) \ + MACRO(ptrm, u8, std::uint8_t) \ + MACRO(ptrm, u16, std::uint16_t) \ + MACRO(ptrm, u32, std::uint32_t) \ + MACRO(ptrm, u64, std::uint64_t) \ + MACRO(ptrm, i8, std::int8_t) \ + MACRO(ptrm, i16, std::int16_t) \ + MACRO(ptrm, i32, std::int32_t) \ + MACRO(ptrm, i64, std::int64_t) \ + MACRO(ptrm, f32, float) \ + MACRO(ptrm, f64, double) + #define FOR_EACH_TRIVIAL_STD_VECTOR(MACRO) \ FOR_EACH_NUMERIC(MACRO) \ MACRO(usize, std::size_t) \ MACRO(isize, rust::isize) +#define FOR_EACH_TRIVIAL_STD_VECTOR_PTR(MACRO) \ + FOR_EACH_NUMERIC_WITH_PTR_PREFIX(MACRO) \ + MACRO(ptrc, usize, std::size_t) \ + MACRO(ptrc, isize, rust::isize) \ + MACRO(ptrm, usize, std::size_t) \ + MACRO(ptrm, isize, rust::isize) + #define FOR_EACH_STD_VECTOR(MACRO) \ FOR_EACH_TRIVIAL_STD_VECTOR(MACRO) \ MACRO(string, std::string) +#define FOR_EACH_STD_VECTOR_PTR(MACRO) \ + FOR_EACH_TRIVIAL_STD_VECTOR_PTR(MACRO) \ + MACRO(ptrc, string, std::string) \ + MACRO(ptrm, string, std::string) + #define FOR_EACH_RUST_VEC(MACRO) \ FOR_EACH_NUMERIC(MACRO) \ MACRO(bool, bool) \ @@ -791,6 +873,8 @@ static_assert(sizeof(std::string) <= kMaxExpectedWordsInString * sizeof(void *), extern "C" { FOR_EACH_STD_VECTOR(STD_VECTOR_OPS) FOR_EACH_TRIVIAL_STD_VECTOR(STD_VECTOR_TRIVIAL_OPS) +FOR_EACH_STD_VECTOR_PTR(STD_VECTOR_OPS_PTR) +FOR_EACH_TRIVIAL_STD_VECTOR_PTR(STD_VECTOR_TRIVIAL_OPS_PTR) FOR_EACH_RUST_VEC(RUST_VEC_EXTERNS) FOR_EACH_SHARED_PTR(SHARED_PTR_OPS) } // extern "C" diff --git a/src/cxx_vector.rs b/src/cxx_vector.rs index 5dcbe1c53..00b09a7b6 100644 --- a/src/cxx_vector.rs +++ b/src/cxx_vector.rs @@ -12,7 +12,6 @@ use core::marker::{PhantomData, PhantomPinned}; use core::mem::{self, ManuallyDrop, MaybeUninit}; use core::pin::Pin; use core::slice; - /// Binding to C++ `std::vector>`. /// /// # Invariants @@ -379,6 +378,175 @@ pub unsafe trait VectorElement: Sized { unsafe fn __unique_ptr_drop(repr: MaybeUninit<*mut c_void>); } +/// Trait bound for types which may be used as the `T` inside of a +/// `CxxVector<*const T>` in generic code. +pub unsafe trait ConstPtrVectorElement: Sized { + #[doc(hidden)] + fn __typename(f: &mut fmt::Formatter) -> fmt::Result; + #[doc(hidden)] + fn __vector_new() -> *mut CxxVector<*const Self>; + #[doc(hidden)] + fn __vector_size(v: &CxxVector<*const Self>) -> usize; + #[doc(hidden)] + unsafe fn __get_unchecked(v: *mut CxxVector<*const Self>, pos: usize) -> *mut *const Self; + #[doc(hidden)] + unsafe fn __push_back(v: Pin<&mut CxxVector<*const Self>>, value: &mut ManuallyDrop<*const Self>) { + // Opaque C type vector elements do not get this method because they can + // never exist by value on the Rust side of the bridge. + let _ = v; + let _ = value; + unreachable!() + } + #[doc(hidden)] + unsafe fn __pop_back(v: Pin<&mut CxxVector<*const Self>>, out: &mut MaybeUninit<*const Self>) { + // Opaque C type vector elements do not get this method because they can + // never exist by value on the Rust side of the bridge. + let _ = v; + let _ = out; + unreachable!() + } + #[doc(hidden)] + fn __unique_ptr_null() -> MaybeUninit<*mut c_void>; + #[doc(hidden)] + unsafe fn __unique_ptr_raw(raw: *mut CxxVector<*const Self>) -> MaybeUninit<*mut c_void>; + #[doc(hidden)] + unsafe fn __unique_ptr_get(repr: MaybeUninit<*mut c_void>) -> *const CxxVector<*const Self>; + #[doc(hidden)] + unsafe fn __unique_ptr_release(repr: MaybeUninit<*mut c_void>) -> *mut CxxVector<*const Self>; + #[doc(hidden)] + unsafe fn __unique_ptr_drop(repr: MaybeUninit<*mut c_void>); +} + +/// Trait bound for types which may be used as the `T` inside of a +/// `CxxVector<*mut T>` in generic code. +pub unsafe trait MutPtrVectorElement: Sized { + #[doc(hidden)] + fn __typename(f: &mut fmt::Formatter) -> fmt::Result; + #[doc(hidden)] + fn __vector_new() -> *mut CxxVector<*mut Self>; + #[doc(hidden)] + fn __vector_size(v: &CxxVector<*mut Self>) -> usize; + #[doc(hidden)] + unsafe fn __get_unchecked(v: *mut CxxVector<*mut Self>, pos: usize) -> *mut *mut Self; + #[doc(hidden)] + unsafe fn __push_back(v: Pin<&mut CxxVector<*mut Self>>, value: &mut ManuallyDrop<*mut Self>) { + // Opaque C type vector elements do not get this method because they can + // never exist by value on the Rust side of the bridge. + let _ = v; + let _ = value; + unreachable!() + } + #[doc(hidden)] + unsafe fn __pop_back(v: Pin<&mut CxxVector<*mut Self>>, out: &mut MaybeUninit<*mut Self>) { + // Opaque C type vector elements do not get this method because they can + // never exist by value on the Rust side of the bridge. + let _ = v; + let _ = out; + unreachable!() + } + #[doc(hidden)] + fn __unique_ptr_null() -> MaybeUninit<*mut c_void>; + #[doc(hidden)] + unsafe fn __unique_ptr_raw(raw: *mut CxxVector<*mut Self>) -> MaybeUninit<*mut c_void>; + #[doc(hidden)] + unsafe fn __unique_ptr_get(repr: MaybeUninit<*mut c_void>) -> *const CxxVector<*mut Self>; + #[doc(hidden)] + unsafe fn __unique_ptr_release(repr: MaybeUninit<*mut c_void>) -> *mut CxxVector<*mut Self>; + #[doc(hidden)] + unsafe fn __unique_ptr_drop(repr: MaybeUninit<*mut c_void>); +} + +unsafe impl VectorElement for *const T { + fn __typename(f: &mut fmt::Formatter) -> fmt::Result { + T::__typename(f) + } + + fn __vector_new() -> *mut CxxVector { + T::__vector_new() + } + + fn __vector_size(v: &CxxVector) -> usize { + T::__vector_size(v) + } + + unsafe fn __get_unchecked(v: *mut CxxVector, pos: usize) -> *mut Self { + unsafe { T::__get_unchecked(v, pos) } + } + + unsafe fn __pop_back(v: Pin<&mut CxxVector>, out: &mut MaybeUninit) { + unsafe { T::__pop_back(v, out) } + } + + unsafe fn __push_back(v: Pin<&mut CxxVector>, value: &mut ManuallyDrop) { + unsafe { T::__push_back(v, value) } + } + + fn __unique_ptr_null() -> MaybeUninit<*mut c_void> { + T::__unique_ptr_null() + } + + unsafe fn __unique_ptr_raw(raw: *mut CxxVector) -> MaybeUninit<*mut c_void> { + unsafe { T::__unique_ptr_raw(raw) } + } + + unsafe fn __unique_ptr_get(repr: MaybeUninit<*mut c_void>) -> *const CxxVector { + unsafe { T::__unique_ptr_get(repr) } + } + + unsafe fn __unique_ptr_release(repr: MaybeUninit<*mut c_void>) -> *mut CxxVector { + unsafe { T::__unique_ptr_release(repr) } + } + + unsafe fn __unique_ptr_drop(repr: MaybeUninit<*mut c_void>) { + unsafe { T::__unique_ptr_drop(repr) } + } +} + +unsafe impl VectorElement for *mut T { + fn __typename(f: &mut fmt::Formatter) -> fmt::Result { + T::__typename(f) + } + + fn __vector_new() -> *mut CxxVector { + T::__vector_new() + } + + fn __vector_size(v: &CxxVector) -> usize { + T::__vector_size(v) + } + + unsafe fn __get_unchecked(v: *mut CxxVector, pos: usize) -> *mut Self { + unsafe { T::__get_unchecked(v, pos) } + } + + unsafe fn __pop_back(v: Pin<&mut CxxVector>, out: &mut MaybeUninit) { + unsafe { T::__pop_back(v, out) } + } + + unsafe fn __push_back(v: Pin<&mut CxxVector>, value: &mut ManuallyDrop) { + unsafe { T::__push_back(v, value) } + } + fn __unique_ptr_null() -> MaybeUninit<*mut c_void> { + T::__unique_ptr_null() + } + + unsafe fn __unique_ptr_raw(raw: *mut CxxVector) -> MaybeUninit<*mut c_void> { + unsafe { T::__unique_ptr_raw(raw) } + } + + unsafe fn __unique_ptr_get(repr: MaybeUninit<*mut c_void>) -> *const CxxVector { + unsafe { T::__unique_ptr_get(repr) } + } + + unsafe fn __unique_ptr_release(repr: MaybeUninit<*mut c_void>) -> *mut CxxVector { + unsafe { T::__unique_ptr_release(repr) } + } + + unsafe fn __unique_ptr_drop(repr: MaybeUninit<*mut c_void>) { + unsafe { T::__unique_ptr_drop(repr) } + } +} + macro_rules! vector_element_by_value_methods { (opaque, $segment:expr, $ty:ty) => {}; (trivial, $segment:expr, $ty:ty) => { @@ -479,6 +647,183 @@ macro_rules! impl_vector_element_for_primitive { }; } +macro_rules! ptr_vector_element_by_value_methods { + (opaque, $segment:expr, $iden:expr, $ty:ty) => {}; + (trivial, $segment:expr, $iden:expr, $ty:ty) => { + unsafe fn __push_back(v: Pin<&mut CxxVector<$ty>>, value: &mut ManuallyDrop<$ty>) { + extern "C" { + #[link_name = concat!("cxxbridge1$std$vector$", $iden, "$", $segment, "$push_back")] + fn __push_back(_: Pin<&mut CxxVector<$ty>>, _: &mut ManuallyDrop<$ty>); + } + unsafe { __push_back(v, value) } + } + unsafe fn __pop_back(v: Pin<&mut CxxVector<$ty>>, out: &mut MaybeUninit<$ty>) { + extern "C" { + #[link_name = concat!("cxxbridge1$std$vector$", $iden, "$", $segment, "$pop_back")] + fn __pop_back(_: Pin<&mut CxxVector<$ty>>, _: &mut MaybeUninit<$ty>); + } + unsafe { __pop_back(v, out) } + } + }; +} + +macro_rules! impl_const_ptr_vector_element { + ($kind:ident, $segment:expr, $name:expr, $ty:ty) => { + const_assert_eq!(0, mem::size_of::>()); + const_assert_eq!(1, mem::align_of::>()); + + unsafe impl ConstPtrVectorElement for $ty { + fn __typename(f: &mut fmt::Formatter) -> fmt::Result { + f.write_str($name) + } + fn __vector_new() -> *mut CxxVector<*const Self> { + extern "C" { + #[link_name = concat!("cxxbridge1$std$vector$ptrc$", $segment, "$new")] + fn __vector_new() -> *mut CxxVector<*const $ty>; + } + unsafe { __vector_new() } + } + fn __vector_size(v: &CxxVector<*const $ty>) -> usize { + extern "C" { + #[link_name = concat!("cxxbridge1$std$vector$ptrc$", $segment, "$size")] + fn __vector_size(_: &CxxVector<*const $ty>) -> usize; + } + unsafe { __vector_size(v) } + } + unsafe fn __get_unchecked(v: *mut CxxVector<*const $ty>, pos: usize) -> *mut *const $ty { + extern "C" { + #[link_name = concat!("cxxbridge1$std$vector$ptrc$", $segment, "$get_unchecked")] + fn __get_unchecked(_: *mut CxxVector<*const $ty>, _: usize) -> *mut *const $ty; + } + unsafe { __get_unchecked(v, pos) } + } + ptr_vector_element_by_value_methods!($kind, $segment, "ptrc", *const $ty); + fn __unique_ptr_null() -> MaybeUninit<*mut c_void> { + extern "C" { + #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$ptrc$", $segment, "$null")] + fn __unique_ptr_null(this: *mut MaybeUninit<*mut c_void>); + } + let mut repr = MaybeUninit::uninit(); + unsafe { __unique_ptr_null(&mut repr) } + repr + } + unsafe fn __unique_ptr_raw(raw: *mut CxxVector<*const Self>) -> MaybeUninit<*mut c_void> { + extern "C" { + #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$ptrc$", $segment, "$raw")] + fn __unique_ptr_raw(this: *mut MaybeUninit<*mut c_void>, raw: *mut CxxVector<*const $ty>); + } + let mut repr = MaybeUninit::uninit(); + unsafe { __unique_ptr_raw(&mut repr, raw) } + repr + } + unsafe fn __unique_ptr_get(repr: MaybeUninit<*mut c_void>) -> *const CxxVector<*const Self> { + extern "C" { + #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$ptrc$", $segment, "$get")] + fn __unique_ptr_get(this: *const MaybeUninit<*mut c_void>) -> *const CxxVector<*const $ty>; + } + unsafe { __unique_ptr_get(&repr) } + } + unsafe fn __unique_ptr_release(mut repr: MaybeUninit<*mut c_void>) -> *mut CxxVector<*const Self> { + extern "C" { + #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$ptrc$", $segment, "$release")] + fn __unique_ptr_release(this: *mut MaybeUninit<*mut c_void>) -> *mut CxxVector<*const $ty>; + } + unsafe { __unique_ptr_release(&mut repr) } + } + unsafe fn __unique_ptr_drop(mut repr: MaybeUninit<*mut c_void>) { + extern "C" { + #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$ptrc$", $segment, "$drop")] + fn __unique_ptr_drop(this: *mut MaybeUninit<*mut c_void>); + } + unsafe { __unique_ptr_drop(&mut repr) } + } + } + }; +} + +macro_rules! impl_mut_ptr_vector_element { + ($kind:ident, $segment:expr, $name:expr, $ty:ty) => { + const_assert_eq!(0, mem::size_of::>()); + const_assert_eq!(1, mem::align_of::>()); + + unsafe impl MutPtrVectorElement for $ty { + fn __typename(f: &mut fmt::Formatter) -> fmt::Result { + f.write_str($name) + } + fn __vector_new() -> *mut CxxVector<*mut Self> { + extern "C" { + #[link_name = concat!("cxxbridge1$std$vector$ptrm$", $segment, "$new")] + fn __vector_new() -> *mut CxxVector<*mut $ty>; + } + unsafe { __vector_new() } + } + fn __vector_size(v: &CxxVector<*mut $ty>) -> usize { + extern "C" { + #[link_name = concat!("cxxbridge1$std$vector$ptrm$", $segment, "$size")] + fn __vector_size(_: &CxxVector<*mut $ty>) -> usize; + } + unsafe { __vector_size(v) } + } + unsafe fn __get_unchecked(v: *mut CxxVector<*mut $ty>, pos: usize) -> *mut *mut $ty { + extern "C" { + #[link_name = concat!("cxxbridge1$std$vector$ptrm$", $segment, "$get_unchecked")] + fn __get_unchecked(_: *mut CxxVector<*mut $ty>, _: usize) -> *mut *mut $ty; + } + unsafe { __get_unchecked(v, pos) } + } + ptr_vector_element_by_value_methods!($kind, $segment, "ptrm", *mut $ty); + fn __unique_ptr_null() -> MaybeUninit<*mut c_void> { + extern "C" { + #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$ptrm$", $segment, "$null")] + fn __unique_ptr_null(this: *mut MaybeUninit<*mut c_void>); + } + let mut repr = MaybeUninit::uninit(); + unsafe { __unique_ptr_null(&mut repr) } + repr + } + unsafe fn __unique_ptr_raw(raw: *mut CxxVector<*mut Self>) -> MaybeUninit<*mut c_void> { + extern "C" { + #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$ptrm$", $segment, "$raw")] + fn __unique_ptr_raw(this: *mut MaybeUninit<*mut c_void>, raw: *mut CxxVector<*mut $ty>); + } + let mut repr = MaybeUninit::uninit(); + unsafe { __unique_ptr_raw(&mut repr, raw) } + repr + } + unsafe fn __unique_ptr_get(repr: MaybeUninit<*mut c_void>) -> *const CxxVector<*mut Self> { + extern "C" { + #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$ptrm$", $segment, "$get")] + fn __unique_ptr_get(this: *const MaybeUninit<*mut c_void>) -> *const CxxVector<*mut $ty>; + } + unsafe { __unique_ptr_get(&repr) } + } + unsafe fn __unique_ptr_release(mut repr: MaybeUninit<*mut c_void>) -> *mut CxxVector<*mut Self> { + extern "C" { + #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$ptrm$", $segment, "$release")] + fn __unique_ptr_release(this: *mut MaybeUninit<*mut c_void>) -> *mut CxxVector<*mut $ty>; + } + unsafe { __unique_ptr_release(&mut repr) } + } + unsafe fn __unique_ptr_drop(mut repr: MaybeUninit<*mut c_void>) { + extern "C" { + #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$ptrm$", $segment, "$drop")] + fn __unique_ptr_drop(this: *mut MaybeUninit<*mut c_void>); + } + unsafe { __unique_ptr_drop(&mut repr) } + } + } + }; +} + +macro_rules! impl_ptr_vector_element_for_primitive { + (ptrc, $ty:ident) => { + impl_const_ptr_vector_element!(trivial, stringify!($ty), stringify!($ty), $ty); + }; + (ptrm, $ty:ident) => { + impl_mut_ptr_vector_element!(trivial, stringify!($ty), stringify!($ty), $ty); + }; +} + impl_vector_element_for_primitive!(u8); impl_vector_element_for_primitive!(u16); impl_vector_element_for_primitive!(u32); @@ -493,3 +838,32 @@ impl_vector_element_for_primitive!(f32); impl_vector_element_for_primitive!(f64); impl_vector_element!(opaque, "string", "CxxString", CxxString); + +impl_ptr_vector_element_for_primitive!(ptrc, u8); +impl_ptr_vector_element_for_primitive!(ptrc, u16); +impl_ptr_vector_element_for_primitive!(ptrc, u32); +impl_ptr_vector_element_for_primitive!(ptrc, u64); +impl_ptr_vector_element_for_primitive!(ptrc, usize); +impl_ptr_vector_element_for_primitive!(ptrc, i8); +impl_ptr_vector_element_for_primitive!(ptrc, i16); +impl_ptr_vector_element_for_primitive!(ptrc, i32); +impl_ptr_vector_element_for_primitive!(ptrc, i64); +impl_ptr_vector_element_for_primitive!(ptrc, isize); +impl_ptr_vector_element_for_primitive!(ptrc, f32); +impl_ptr_vector_element_for_primitive!(ptrc, f64); + +impl_ptr_vector_element_for_primitive!(ptrm, u8); +impl_ptr_vector_element_for_primitive!(ptrm, u16); +impl_ptr_vector_element_for_primitive!(ptrm, u32); +impl_ptr_vector_element_for_primitive!(ptrm, u64); +impl_ptr_vector_element_for_primitive!(ptrm, usize); +impl_ptr_vector_element_for_primitive!(ptrm, i8); +impl_ptr_vector_element_for_primitive!(ptrm, i16); +impl_ptr_vector_element_for_primitive!(ptrm, i32); +impl_ptr_vector_element_for_primitive!(ptrm, i64); +impl_ptr_vector_element_for_primitive!(ptrm, isize); +impl_ptr_vector_element_for_primitive!(ptrm, f32); +impl_ptr_vector_element_for_primitive!(ptrm, f64); + +impl_const_ptr_vector_element!(opaque, "string", "CxxString", CxxString); +impl_mut_ptr_vector_element!(opaque, "string", "CxxString", CxxString); diff --git a/src/lib.rs b/src/lib.rs index d133df69c..69c0fc3a7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -503,6 +503,8 @@ pub type Vector = CxxVector; // Not public API. #[doc(hidden)] pub mod private { + pub use crate::cxx_vector::ConstPtrVectorElement; + pub use crate::cxx_vector::MutPtrVectorElement; pub use crate::cxx_vector::VectorElement; pub use crate::extern_type::{verify_extern_kind, verify_extern_type}; pub use crate::function::FatFunction; diff --git a/syntax/check.rs b/syntax/check.rs index 39ee0b0a4..bdf7cea52 100644 --- a/syntax/check.rs +++ b/syntax/check.rs @@ -203,26 +203,29 @@ fn check_type_weak_ptr(cx: &mut Check, ptr: &Ty1) { } fn check_type_cxx_vector(cx: &mut Check, ptr: &Ty1) { - if let Type::Ident(ident) = &ptr.inner { - if cx.types.rust.contains(&ident.rust) { - cx.error( - ptr, - "C++ vector containing a Rust type is not supported yet", - ); - return; - } + match &ptr.inner { + Type::Ident(ident) => { + if cx.types.rust.contains(&ident.rust) { + cx.error( + ptr, + "C++ vector containing a Rust type is not supported yet", + ); + return; + } - match Atom::from(&ident.rust) { - None - | Some( - U8 | U16 | U32 | U64 | Usize | I8 | I16 | I32 | I64 | Isize | F32 | F64 | CxxString, - ) => return, - Some(Char) => { /* todo */ } - Some(Bool | RustString) => {} + match Atom::from(&ident.rust) { + None | 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) => { /* todo */ } + Some(Bool) | Some(RustString) => {} + } + } + Type::Ptr(ptr) => check_type_ptr(cx, ptr), // TODO - confirm whether we need to recurse here + _ => { + cx.error(ptr, "unsupported vector element type"); } } - - cx.error(ptr, "unsupported vector element type"); } fn check_type_ref(cx: &mut Check, ty: &Ref) { diff --git a/syntax/instantiate.rs b/syntax/instantiate.rs index dda306982..2d2333e48 100644 --- a/syntax/instantiate.rs +++ b/syntax/instantiate.rs @@ -10,7 +10,19 @@ pub(crate) enum ImplKey<'a> { UniquePtr(NamedImplKey<'a>), SharedPtr(NamedImplKey<'a>), WeakPtr(NamedImplKey<'a>), - CxxVector(NamedImplKey<'a>), + CxxVector(CxxVectorPayloadImplKey<'a>), +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub enum PtrMutability { + Const, + Mut, +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub(crate) enum CxxVectorPayloadImplKey<'a> { + Named(NamedImplKey<'a>), + Ptr(NamedImplKey<'a>, PtrMutability), } #[derive(Copy, Clone)] @@ -50,7 +62,22 @@ impl Type { } } else if let Type::CxxVector(ty) = self { if let Type::Ident(ident) = &ty.inner { - return Some(ImplKey::CxxVector(NamedImplKey::new(ty, ident))); + return Some(ImplKey::CxxVector(CxxVectorPayloadImplKey::Named( + NamedImplKey::new(ty, ident), + ))); + } + if let Type::Ptr(ptr) = &ty.inner { + if let Type::Ident(ident) = &ptr.inner { + let mutability = if ptr.constness.is_some() { + PtrMutability::Const + } else { + PtrMutability::Mut + }; + return Some(ImplKey::CxxVector(CxxVectorPayloadImplKey::Ptr( + NamedImplKey::new(ty, ident), + mutability, + ))); + } } } None diff --git a/syntax/types.rs b/syntax/types.rs index bc11eb00c..953747139 100644 --- a/syntax/types.rs +++ b/syntax/types.rs @@ -1,5 +1,5 @@ use crate::syntax::improper::ImproperCtype; -use crate::syntax::instantiate::ImplKey; +use crate::syntax::instantiate::{CxxVectorPayloadImplKey, ImplKey}; use crate::syntax::map::{OrderedMap, UnorderedMap}; use crate::syntax::report::Errors; use crate::syntax::resolve::Resolution; @@ -180,7 +180,8 @@ impl<'a> Types<'a> { | ImplKey::UniquePtr(ident) | ImplKey::SharedPtr(ident) | ImplKey::WeakPtr(ident) - | ImplKey::CxxVector(ident) => { + | ImplKey::CxxVector(CxxVectorPayloadImplKey::Named(ident)) + | ImplKey::CxxVector(CxxVectorPayloadImplKey::Ptr(ident, _)) => { Atom::from(ident.rust).is_none() && !aliases.contains_key(ident.rust) } }; diff --git a/tests/ffi/lib.rs b/tests/ffi/lib.rs index f3a8310f1..361a8b577 100644 --- a/tests/ffi/lib.rs +++ b/tests/ffi/lib.rs @@ -131,6 +131,8 @@ pub mod ffi { fn c_return_nested_ns_enum(n: u16) -> ABEnum; fn c_return_const_ptr(n: usize) -> *const C; fn c_return_mut_ptr(n: usize) -> *mut C; + fn c_return_unique_ptr_vector_const_ptr(n: usize) -> UniquePtr>; + fn c_return_unique_ptr_vector_mut_ptr(n: usize) -> UniquePtr>; fn c_take_primitive(n: usize); fn c_take_shared(shared: Shared); @@ -179,6 +181,8 @@ pub mod ffi { fn c_take_rust_vec_nested_ns_shared(v: Vec); unsafe fn c_take_const_ptr(c: *const C) -> usize; unsafe fn c_take_mut_ptr(c: *mut C) -> usize; + unsafe fn c_take_unique_ptr_vector_const_ptr(c: UniquePtr>) -> usize; + unsafe fn c_take_unique_ptr_vector_mut_ptr(c: UniquePtr>) -> usize; fn c_try_return_void() -> Result<()>; fn c_try_return_primitive() -> Result; diff --git a/tests/ffi/tests.cc b/tests/ffi/tests.cc index ca71276f8..9f55e4ac0 100644 --- a/tests/ffi/tests.cc +++ b/tests/ffi/tests.cc @@ -219,6 +219,22 @@ const C *c_return_const_ptr(size_t c) { return new C(c); } C *c_return_mut_ptr(size_t c) { return new C(c); } +std::unique_ptr> c_return_unique_ptr_vector_const_ptr(size_t n) { + auto v = std::unique_ptr>(new std::vector()); + for (auto i = 0; i<2; i++) { + v->push_back(new C(n)); + } + return v; +} + +std::unique_ptr> c_return_unique_ptr_vector_mut_ptr(size_t n) { + auto v = std::unique_ptr>(new std::vector()); + for (auto i = 0; i<2; i++) { + v->push_back(new C(n)); + } + return v; +} + Borrow::Borrow(const std::string &s) : s(s) {} void Borrow::const_member() const {} @@ -555,6 +571,23 @@ size_t c_take_mut_ptr(C *c) { return result; } +size_t c_take_unique_ptr_vector_const_ptr(std::unique_ptr> c) { + size_t accumulator = 0; + for (auto& item: *c) { + accumulator += item->get(); + } + return accumulator; +} + +size_t c_take_unique_ptr_vector_mut_ptr(std::unique_ptr> c) { + size_t accumulator = 0; + for (auto& item: *c) { + accumulator += item->get(); + delete item; + } + return accumulator; +} + void c_try_return_void() {} size_t c_try_return_primitive() { return 2020; } diff --git a/tests/ffi/tests.h b/tests/ffi/tests.h index dc02e4ff8..3198c7ed0 100644 --- a/tests/ffi/tests.h +++ b/tests/ffi/tests.h @@ -124,6 +124,8 @@ ::A::B::ABEnum c_return_nested_ns_enum(uint16_t n); std::unique_ptr c_return_borrow(const std::string &s); const C *c_return_const_ptr(size_t n); C *c_return_mut_ptr(size_t n); +std::unique_ptr> c_return_unique_ptr_vector_const_ptr(size_t n); +std::unique_ptr> c_return_unique_ptr_vector_mut_ptr(size_t n); void c_take_primitive(size_t n); void c_take_shared(Shared shared); @@ -173,6 +175,8 @@ void c_take_ns_enum(::A::AEnum e); void c_take_nested_ns_enum(::A::B::ABEnum e); size_t c_take_const_ptr(const C *c); size_t c_take_mut_ptr(C *c); +size_t c_take_unique_ptr_vector_const_ptr(std::unique_ptr> c); +size_t c_take_unique_ptr_vector_mut_ptr(std::unique_ptr> c); void c_try_return_void(); size_t c_try_return_primitive(); diff --git a/tests/test.rs b/tests/test.rs index ac396589c..b4f5f8de6 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -382,6 +382,19 @@ fn test_raw_ptr() { assert_eq!(2025, unsafe { ffi::c_take_mut_ptr(c3 as *mut ffi::C) }); // deletes c3 } +#[test] +fn test_unique_ptr_vector_raw_ptr() { + let m = ffi::c_return_unique_ptr_vector_mut_ptr(2024); + let c = ffi::c_return_unique_ptr_vector_const_ptr(2024); + assert_eq!(4048, unsafe { ffi::c_take_unique_ptr_vector_const_ptr(c) }); + assert_eq!(4048, unsafe { ffi::c_take_unique_ptr_vector_mut_ptr(m) }); // deletes elements + + let m2 = ffi::c_return_unique_ptr_vector_mut_ptr(2025); + let c2 = ffi::c_return_unique_ptr_vector_const_ptr(2025); + assert_eq!(4050, unsafe { ffi::c_take_unique_ptr_vector_mut_ptr(m2) }); + assert_eq!(4050, unsafe { ffi::c_take_unique_ptr_vector_const_ptr(c2) }); +} + #[test] #[allow(clippy::items_after_statements, clippy::no_effect_underscore_binding)] fn test_unwind_safe() { diff --git a/tests/ui/ptr_unsupported.rs b/tests/ui/ptr_unsupported.rs index 9d59c0330..1784892f3 100644 --- a/tests/ui/ptr_unsupported.rs +++ b/tests/ui/ptr_unsupported.rs @@ -5,7 +5,6 @@ mod ffi { fn get_ptr_to_reference() -> *mut &C; fn get_uniqueptr_to_ptr() -> UniquePtr<*mut C>; - fn get_vector_of_ptr() -> UniquePtr>; } } diff --git a/tests/ui/ptr_unsupported.stderr b/tests/ui/ptr_unsupported.stderr index ea1dafd86..247f80063 100644 --- a/tests/ui/ptr_unsupported.stderr +++ b/tests/ui/ptr_unsupported.stderr @@ -9,9 +9,3 @@ error: unsupported unique_ptr target type | 7 | fn get_uniqueptr_to_ptr() -> UniquePtr<*mut C>; | ^^^^^^^^^^^^^^^^^ - -error: unsupported vector element type - --> tests/ui/ptr_unsupported.rs:8:45 - | -8 | fn get_vector_of_ptr() -> UniquePtr>; - | ^^^^^^^^^^^^^^^^^