diff --git a/book/src/binding/option.md b/book/src/binding/option.md index c9996df01..f90161a01 100644 --- a/book/src/binding/option.md +++ b/book/src/binding/option.md @@ -9,24 +9,76 @@ ...namespace rust { template -class Option final { +class Option final {}; + +template +class Option { public: Option() noexcept; Option(Option&&) noexcept; - Option(T&&) noexcept; + Option(T&) noexcept; ~Option() noexcept; - const T *operator->() const; - const T &operator*() const; - T *operator->(); - T &operator*(); - - Option& operator=(Option&&) noexcept; + Option& operator=(Option&&) noexcept; + const T& operator*() const noexcept; + const T* operator->() const noexcept; + T& operator*() noexcept; + T* operator->() noexcept; bool has_value() const noexcept; + const T& value() const noexcept; T& value() noexcept; void reset(); - void set(T&&) noexcept; + void set(T&) noexcept; + static Option from_raw(T*) noexcept; + T* into_raw() noexcept; +}; + +template +class Option { +public: + Option() noexcept; + Option(const Option&) noexcept; + Option(Option&&) noexcept; + Option(const T&) noexcept; + ~Option() noexcept; + + Option& operator=(Option&&) noexcept; + const T& operator*() const noexcept; + const T* operator->() const noexcept; + + bool has_value() const noexcept; + const T& value() const noexcept; + void reset(); + void set(const T&) noexcept; + static Option from_raw(const T*) noexcept; + const T* into_raw() const noexcept; +}; + +template +class Option> { +public: + Option() noexcept; + Option(Option&&) noexcept; + Option(Box&&) noexcept; + ~Option() noexcept; + + Option>& operator=(Option&&) noexcept; + const Box& operator*() const noexcept; + const Box* operator->() const noexcept; + Box& operator*() noexcept; + Box* operator->() noexcept; + + bool has_value() const noexcept; + const Box& value() const noexcept; + Box& value() noexcept; + void reset(); + void set(Box) noexcept; + + // Important: requires that `raw` came from an into_raw call. Do not pass a + // pointer from `new` or any other source. + static Option> from_raw(T*) noexcept; + T* into_raw() noexcept; }; ...} // namespace rust ``` @@ -34,11 +86,8 @@ public: ### Restrictions: Option only supports pointer-sized references and Box-es; that is, no -fat pointers like &str (though &String is supported) or Box<[u8]>. On the -C++ side, Option<&T> becomes rust::Option (and similar for -mutable references), but the pointer is guaranteed to be non-null if the -Option has a value. Also, you can only pass Options themselves by value. -&Option is not allowed. +fat pointers like &str (though &String is supported) or Box<[u8]>. Also, +you can only pass Options themselves by value. &Option is not allowed. ## Example @@ -72,7 +121,7 @@ fn main() { #include "example/src/main.rs.h" #include "rust/cxx.h" -void f(rust::Option); +void f(rust::Option); ``` ```cpp @@ -80,10 +129,10 @@ void f(rust::Option); #include "example/include/example.h" -void f(rust::Option o) { +void f(rust::Option o) { if (o.has_value()) { // Pointer is guaranteed to be non-null - std::cout << shared.value()->v << std::endl; + std::cout << shared.value().v << std::endl; } } ``` diff --git a/gen/src/write.rs b/gen/src/write.rs index aedb2d2a1..f272a62e8 100644 --- a/gen/src/write.rs +++ b/gen/src/write.rs @@ -709,7 +709,7 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) { out.builtin.ptr_len = true; write!(out, "::rust::repr::PtrLen "); } else { - write_extern_return_type_space(out, &efn.ret); + write_extern_return_type_space(out, efn.ret.as_ref()); } let mangled = mangle::extern_fn(efn, out.types); write!(out, "{}(", mangled); @@ -748,7 +748,7 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) { } writeln!(out, ") noexcept {{"); write!(out, " "); - write_return_type(out, &efn.ret); + write_return_type(out, efn.ret.as_ref()); match &efn.receiver { None => write!(out, "(*{}$)(", efn.name.rust), Some(receiver) => write!( @@ -820,7 +820,7 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) { if i > 0 { write!(out, ", "); } - if let Type::RustBox(_) = &arg.ty { + if let Type::RustBox(_) | Type::RustOption(_) = &arg.ty { write_type(out, &arg.ty); write!(out, "::from_raw({})", arg.name.cxx); } else if let Type::UniquePtr(_) = &arg.ty { @@ -837,8 +837,6 @@ 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); @@ -848,7 +846,7 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) { } write!(out, ")"); match &efn.ret { - Some(Type::RustBox(_)) => write!(out, ".into_raw()"), + Some(Type::RustBox(_)) | Some(Type::RustOption(_)) => write!(out, ".into_raw()"), Some(Type::UniquePtr(_)) => write!(out, ".release()"), Some(Type::Str(_) | Type::SliceRef(_)) if !indirect_return => write!(out, ")"), _ => {} @@ -904,7 +902,7 @@ fn write_rust_function_decl_impl( out.builtin.ptr_len = true; write!(out, "::rust::repr::PtrLen "); } else { - write_extern_return_type_space(out, &sig.ret); + write_extern_return_type_space(out, sig.ret.as_ref()); } write!(out, "{}(", link_name); let mut needs_comma = false; @@ -976,7 +974,7 @@ fn write_rust_function_shim_decl( indirect_call: bool, ) { begin_function_definition(out); - write_return_type(out, &sig.ret); + write_return_type(out, sig.ret.as_ref()); write!(out, "{}(", local_name); for (i, arg) in sig.args.iter().enumerate() { if i > 0 { @@ -1053,7 +1051,7 @@ fn write_rust_function_shim_impl( } else if let Some(ret) = &sig.ret { write!(out, "return "); match ret { - Type::RustBox(_) => { + Type::RustBox(_) | Type::RustOption(_) => { write_type(out, ret); write!(out, "::from_raw("); } @@ -1094,7 +1092,7 @@ fn write_rust_function_shim_impl( } write!(out, "{}", arg.name.cxx); match &arg.ty { - Type::RustBox(_) => write!(out, ".into_raw()"), + Type::RustBox(_) | Type::RustOption(_) => write!(out, ".into_raw()"), Type::UniquePtr(_) => write!(out, ".release()"), ty if ty != RustString && out.types.needs_indirect_abi(ty) => write!(out, "$.value"), _ => {} @@ -1117,7 +1115,12 @@ fn write_rust_function_shim_impl( write!(out, ")"); if !indirect_return { if let Some(ret) = &sig.ret { - if let Type::RustBox(_) | Type::UniquePtr(_) | Type::Str(_) | Type::SliceRef(_) = ret { + if let Type::RustBox(_) + | Type::UniquePtr(_) + | Type::Str(_) + | Type::SliceRef(_) + | Type::RustOption(_) = ret + { write!(out, ")"); } } @@ -1143,7 +1146,7 @@ fn write_rust_function_shim_impl( writeln!(out, "}}"); } -fn write_return_type(out: &mut OutFile, ty: &Option) { +fn write_return_type(out: &mut OutFile, ty: Option<&Type>) { match ty { None => write!(out, "void "), Some(ty) => write_type_space(out, ty), @@ -1169,6 +1172,7 @@ fn write_indirect_return_type(out: &mut OutFile, ty: &Type) { } write!(out, "*"); } + Type::RustOption(ty) => write_indirect_return_type(out, &ty.inner), _ => write_type(out, ty), } } @@ -1176,18 +1180,29 @@ fn write_indirect_return_type(out: &mut OutFile, ty: &Type) { 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::RustBox(_) | Type::UniquePtr(_) | Type::Ref(_) | Type::RustOption(_) => {} Type::Str(_) | Type::SliceRef(_) => write!(out, " "), _ => write_space_after_type(out, ty), } } -fn write_extern_return_type_space(out: &mut OutFile, ty: &Option) { +fn write_extern_return_type_space(out: &mut OutFile, ty: Option<&Type>) { match ty { Some(Type::RustBox(ty) | Type::UniquePtr(ty)) => { write_type_space(out, &ty.inner); write!(out, "*"); } + Some(Type::RustOption(ty)) => match &ty.inner { + Type::RustBox(_) => write_extern_return_type_space(out, Some(&ty.inner)), + Type::Ref(r) => { + write_type_space(out, &r.inner); + if !r.mutable { + write!(out, "const "); + } + write!(out, "*"); + } + _ => unreachable!(), + }, Some(Type::Ref(ty)) => { write_type_space(out, &ty.inner); if !ty.mutable { @@ -1210,6 +1225,20 @@ fn write_extern_arg(out: &mut OutFile, arg: &Var) { write_type_space(out, &ty.inner); write!(out, "*"); } + Type::RustOption(ty) => match &ty.inner { + Type::RustBox(b) => { + write_type_space(out, &b.inner); + write!(out, "*"); + } + Type::Ref(r) => { + write_type_space(out, &r.inner); + if !r.mutable { + write!(out, "const "); + } + write!(out, "*"); + } + _ => unreachable!(), + }, _ => write_type_space(out, &arg.ty), } if out.types.needs_indirect_abi(&arg.ty) { @@ -1240,17 +1269,7 @@ fn write_type(out: &mut OutFile, ty: &Type) { } 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_type(out, &ty.inner); write!(out, ">"); } Type::UniquePtr(ptr) => { @@ -1408,14 +1427,14 @@ impl<'a> ToTypename for RustOption<'a> { 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)), + RustOption::Ref(inner) => format!("const {}&", inner.to_typename(types)), + RustOption::MutRef(inner) => format!("{}&", inner.to_typename(types)), RustOption::RefVec(inner) => format!( - "const ::rust::cxxbridge1::Vec<{}>*", + "const ::rust::cxxbridge1::Vec<{}>&", inner.to_typename(types) ), RustOption::MutRefVec(inner) => { - format!("::rust::cxxbridge1::Vec<{}>*", inner.to_typename(types)) + format!("::rust::cxxbridge1::Vec<{}>&", inner.to_typename(types)) } } } @@ -1565,31 +1584,49 @@ 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), + let (element, is_const, value_type) = match inner { + OptionInner::RustBox(key) => { + let element = RustOption::RustBox(key.rust); + let value_type = element.to_typename(out.types) ; + (element, false, value_type) + } OptionInner::Ref(key) => { if out.types.try_resolve(key.rust).is_none() { return; } - RustOption::Ref(key.rust) + let resolve = out.types.resolve(&key); + let value_type = resolve.name.to_fully_qualified(); + (RustOption::Ref(key.rust), true, value_type) } OptionInner::MutRef(key) => { if out.types.try_resolve(key.rust).is_none() { return; } - RustOption::MutRef(key.rust) + let resolve = out.types.resolve(&key); + let value_type = resolve.name.to_fully_qualified(); + (RustOption::MutRef(key.rust), false, value_type) } OptionInner::RefVec(key) => { if out.types.try_resolve(key.rust).is_none() { return; } - RustOption::RefVec(key.rust) + let resolve = out.types.resolve(&key); + let value_type = format!( + "::rust::cxxbridge1::Vec<{}>", + resolve.name.to_fully_qualified() + ); + (RustOption::RefVec(key.rust), true, value_type) } OptionInner::MutRefVec(key) => { if out.types.try_resolve(key.rust).is_none() { return; } - RustOption::MutRefVec(key.rust) + let resolve = out.types.resolve(&key); + let value_type = format!( + "::rust::cxxbridge1::Vec<{}>", + resolve.name.to_fully_qualified() + ); + (RustOption::MutRefVec(key.rust), false, value_type) } }; let inner = element.to_typename(out.types); @@ -1610,16 +1647,34 @@ fn write_rust_option_extern(out: &mut OutFile, inner: OptionInner) { "bool cxxbridge1$rust_option${}$has_value(::rust::Option<{}> const *ptr) noexcept;", instance, inner ); - writeln!( - out, - "{}* cxxbridge1$rust_option${}$value_ptr(::rust::Option<{0}> *ptr) noexcept;", - inner, instance - ); - writeln!( - out, - "void cxxbridge1$rust_option${}$set(::rust::Option<{1}> *ptr, {1}&& value) noexcept;", - instance, inner - ); + if is_const { + writeln!( + out, + "{} const * cxxbridge1$rust_option${}$value(::rust::Option<{}> const *ptr) noexcept;", + value_type, instance, inner + ); + writeln!( + out, + "void cxxbridge1$rust_option${}$set(::rust::Option<{}> *ptr, {} const *value) noexcept;", + instance, inner, value_type + ); + } else { + writeln!( + out, + "{} const * cxxbridge1$rust_option${}$value_const(::rust::Option<{}> const *ptr) noexcept;", + value_type, instance, inner + ); + writeln!( + out, + "{}* cxxbridge1$rust_option${}$value(::rust::Option<{}> *ptr) noexcept;", + value_type, instance, inner + ); + writeln!( + out, + "void cxxbridge1$rust_option${}$set(::rust::Option<{}> *ptr, {} *value) noexcept;", + instance, inner, value_type + ); + } } fn write_rust_box_impl(out: &mut OutFile, key: NamedImplKey) { @@ -1743,31 +1798,33 @@ fn write_rust_vec_impl(out: &mut OutFile, key: NamedImplKey) { } fn write_rust_option_impl(out: &mut OutFile, inner: OptionInner) { - let element = match inner { - OptionInner::RustBox(key) => RustOption::RustBox(key.rust), + let (element, is_const, value_needs_ref) = match inner { + OptionInner::RustBox(key) => { + (RustOption::RustBox(key.rust), false, true) + } OptionInner::Ref(key) => { if out.types.try_resolve(key.rust).is_none() { return; } - RustOption::Ref(key.rust) + (RustOption::Ref(key.rust), true, false) } OptionInner::MutRef(key) => { if out.types.try_resolve(key.rust).is_none() { return; } - RustOption::MutRef(key.rust) + (RustOption::MutRef(key.rust), false, false) } OptionInner::RefVec(key) => { if out.types.try_resolve(key.rust).is_none() { return; } - RustOption::RefVec(key.rust) + (RustOption::RefVec(key.rust), true, false) } OptionInner::MutRefVec(key) => { if out.types.try_resolve(key.rust).is_none() { return; } - RustOption::MutRefVec(key.rust) + (RustOption::MutRefVec(key.rust), false, false) } }; let inner = element.to_typename(out.types); @@ -1801,20 +1858,42 @@ fn write_rust_option_impl(out: &mut OutFile, inner: OptionInner) { writeln!(out, "template <>"); begin_function_definition(out); - writeln!(out, "{0}* Option<{0}>::value_ptr() noexcept {{", inner); + if value_needs_ref { + writeln!(out, "{0}& Option<{0}>::value() noexcept {{", inner); + } else if is_const { + writeln!(out, "{0} Option<{0}>::value() const noexcept {{", inner); + } else { + writeln!(out, "{0} Option<{0}>::value() noexcept {{", inner); + } writeln!( out, - " return cxxbridge1$rust_option${}$value_ptr(this);", + " return *cxxbridge1$rust_option${}$value(this);", instance ); writeln!(out, "}}"); + if !is_const { + writeln!(out, "template <>"); + begin_function_definition(out); + if value_needs_ref { + writeln!(out, "const {0}& Option<{0}>::value() const noexcept {{", inner); + } else { + writeln!(out, "const {0} Option<{0}>::value() const noexcept {{", inner); + } + writeln!( + out, + " return *cxxbridge1$rust_option${}$value_const(this);", + instance + ); + writeln!(out, "}}"); + } + writeln!(out, "template <>"); begin_function_definition(out); - writeln!(out, "void Option<{0}>::set({0}&& value) noexcept {{", inner); + writeln!(out, "void Option<{0}>::set({0} value) noexcept {{", inner); writeln!( out, - " return cxxbridge1$rust_option${}$set(this, ::std::move(value));", + " return cxxbridge1$rust_option${}$set(this, &value);", instance ); writeln!(out, "}}"); diff --git a/include/cxx.h b/include/cxx.h index 2b0bff87e..9c417a6a3 100644 --- a/include/cxx.h +++ b/include/cxx.h @@ -297,6 +297,94 @@ class Box final { }; #endif // CXXBRIDGE1_RUST_BOX +#ifndef CXXBRIDGE1_RUST_OPTION +template +class Option final {}; + +template +class Option { +public: + Option() noexcept; + Option(Option&&) noexcept; + Option(T&) noexcept; + ~Option() noexcept; + + Option& operator=(Option&&) noexcept; + const T& operator*() const noexcept; + const T* operator->() const noexcept; + T& operator*() noexcept; + T* operator->() noexcept; + + bool has_value() const noexcept; + const T& value() const noexcept; + T& value() noexcept; + void reset(); + void set(T&) noexcept; + static Option from_raw(T*) noexcept; + T* into_raw() noexcept; +private: + void* repr; + + void drop() noexcept; +}; + +template +class Option { +public: + Option() noexcept; + Option(const Option&) noexcept; + Option(Option&&) noexcept; + Option(const T&) noexcept; + ~Option() noexcept; + + Option& operator=(const Option&) noexcept; + Option& operator=(Option&&) noexcept; + const T& operator*() const noexcept; + const T* operator->() const noexcept; + + bool has_value() const noexcept; + const T& value() const noexcept; + void reset(); + void set(const T&) noexcept; + static Option from_raw(const T*) noexcept; + const T* into_raw() const noexcept; +private: + void* repr; + + void drop() noexcept; +}; + +template +class Option> { +public: + Option() noexcept; + Option(Option&&) noexcept; + Option(Box&&) noexcept; + ~Option() noexcept; + + Option>& operator=(Option&&) noexcept; + const Box& operator*() const noexcept; + const Box* operator->() const noexcept; + Box& operator*() noexcept; + Box* operator->() noexcept; + + bool has_value() const noexcept; + const Box& value() const noexcept; + Box& value() noexcept; + void reset(); + void set(Box) noexcept; + + // Important: requires that `raw` came from an into_raw call. Do not pass a + // pointer from `new` or any other source. + static Option> from_raw(T*) noexcept; + T* into_raw() noexcept; +private: + void* repr; + + void drop() noexcept; +}; +#endif // CXXBRIDGE1_RUST_OPTION + #ifndef CXXBRIDGE1_RUST_VEC // https://cxx.rs/binding/vec.html template @@ -826,91 +914,228 @@ template Box::Box(uninit) noexcept {} #endif // CXXBRIDGE1_RUST_BOX + #ifndef CXXBRIDGE1_RUST_OPTION +#define CXXBRIDGE1_RUST_OPTION template -class Option final { -public: - Option() noexcept; - Option(Option&&) noexcept; - Option(T&&) noexcept; - ~Option() noexcept; +Option::Option(Option&& other) noexcept { + new (this) Option(); + if (other.has_value()) { + set(other.value()); + } + new (&other) Option(); +} - const T *operator->() const; - const T &operator*() const; - T *operator->(); - T &operator*(); +template +Option::Option(T& value) noexcept { + new (this) Option(); + set(value); +} - Option& operator=(Option&&) noexcept; +template +Option::~Option() noexcept { + this->drop(); +} - bool has_value() const noexcept; - T& value() noexcept; - void reset(); - void set(T&&) noexcept; -private: - void* empty_; +template +Option& Option::operator=(Option&& other) noexcept { + this->reset(); + if (other.has_value()) { + set(other.value()); + } + new (&other) Option(); + return *this; +} - T* value_ptr() noexcept; - void drop() noexcept; -}; -#endif // CXXBRIDGE1_RUST_OPTION +template +const T& Option::operator*() const noexcept { + return value(); +} -#ifndef CXXBRIDGE1_RUST_OPTION -#define CXXBRIDGE1_RUST_OPTION template -Option::Option(Option&& other) noexcept { +const T* Option::operator->() const noexcept { + return &value(); +} + +template +T& Option::operator*() noexcept { + return value(); +} + +template +T* Option::operator->() noexcept { + return &value(); +} + +template +void Option::reset() { + this->drop(); + new (this) Option(); +} + +template +Option Option::from_raw(T* ptr) noexcept { + Option opt{*ptr}; + return opt; +} + +template +T* Option::into_raw() noexcept { + if (has_value()) { + return &value(); + } else { + return nullptr; + } +} +//////// Option //////// +template +Option::Option(const Option& other) noexcept { new (this) Option(); if (other.has_value()) { - set(std::move(other.value())); + set(other.value()); + } +} + +template +Option::Option(Option&& other) noexcept { + new (this) Option(); + if (other.has_value()) { + set(other.value()); } new (&other) Option(); } template -Option::~Option() noexcept { +Option::Option(const T& value) noexcept { + new (this) Option(); + set(value); +} + +template +Option::~Option() noexcept { this->drop(); } template -Option& Option::operator=(Option&& other) noexcept { +Option& Option::operator=(const Option& other) noexcept { this->reset(); if (other.has_value()) { - set(std::move(other.value())); + set(other.value()); + } + return *this; +} + +template +Option& Option::operator=(Option&& other) noexcept { + this->reset(); + if (other.has_value()) { + set(other.value()); } new (&other) Option(); return *this; } template -const T *Option::operator->() const { +const T& Option::operator*() const noexcept { + return value(); +} + +template +const T* Option::operator->() const noexcept { return &value(); } template -const T &Option::operator*() const { +void Option::reset() { + this->drop(); + new (this) Option(); +} + +template +Option Option::from_raw(const T* ptr) noexcept { + Option opt{*ptr}; + return opt; +} + +template +const T* Option::into_raw() const noexcept { + if (has_value()) { + return &value(); + } else { + return nullptr; + } +} +//////// Option> //////////// +template +Option>::Option(Option&& other) noexcept { + new (this) Option(); + if (other.has_value()) { + set(std::move(other.value())); + } + new (&other) Option(); +} + +template +Option>::Option(Box&& value) noexcept { + new (this) Option(); + set(std::move(value)); +} + +template +Option>::~Option() noexcept { + this->drop(); +} + +template +Option>& Option>::operator=(Option&& other) noexcept { + this->reset(); + if (other.has_value()) { + set(std::move(other.value())); + } + new (&other) Option(); + return *this; +} + +template +const Box& Option>::operator*() const noexcept { return value(); } template -T *Option::operator->() { +const Box* Option>::operator->() const noexcept { return &value(); } template -T &Option::operator*() { +Box& Option>::operator*() noexcept { return value(); } template -T &Option::value() noexcept { - return *value_ptr(); +Box* Option>::operator->() noexcept { + return &value(); } template -void Option::reset() { +void Option>::reset() { this->drop(); new (this) Option(); } +template +Option> Option>::from_raw(T* ptr) noexcept { + Option> opt{Box::from_raw(ptr)}; + return opt; +} + +template +T* Option>::into_raw() noexcept { + if (has_value()) { + return value().into_raw(); + } else { + return nullptr; + } +} #endif // CXXBRIDGE1_RUST_OPTION #ifndef CXXBRIDGE1_RUST_VEC diff --git a/macro/src/expand.rs b/macro/src/expand.rs index fecdf4b5a..5eb2448d8 100644 --- a/macro/src/expand.rs +++ b/macro/src/expand.rs @@ -468,8 +468,6 @@ fn expand_cxx_function_decl(efn: &ExternFn, types: &Types) -> TokenStream { quote!(#var #colon *const #ty) } else if let Type::RustVec(_) = arg.ty { quote!(#var #colon *const #ty) - } else if let Type::RustOption(_) = arg.ty { - quote!(#var #colon *const #ty) } else if let Type::Fn(_) = arg.ty { quote!(#var #colon ::cxx::private::FatFunction) } else if types.needs_indirect_abi(&arg.ty) { @@ -553,56 +551,45 @@ fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream { } Type::RustVec(_) => quote_spanned!(span=> #var.as_mut_ptr() as *const ::cxx::private::RustVec<_>), Type::RustOption(ty) => { - match &ty.inner { - Type::RustBox(ty) => if types.is_considered_improper_ctype(&ty.inner) { - quote_spanned!(span=> &::cxx::RustOption::from_option_box_improper(#var.assume_init()) as _) - } else { - quote_spanned!(span=> &::cxx::RustOption::from_option_box(#var.assume_init()) as _) - }, - Type::Ref(r) => { - // NOTE: We do not handle Option> or Option>, but Pin<&mut Vec> and - // Pin<&mut String> actually aren't even supported in general either (and have no real reason to ever - // be used) - match &r.inner { - Type::Ident(ident) if ident.rust == RustString => match r.mutable { - false => return quote_spanned!(span=> &::cxx::private::RustOption::from_option_string_ref(#var.assume_init()) as _), - true => return quote_spanned!(span=> &::cxx::private::RustOption::from_option_string_mut(#var.assume_init()) as _), - }, - Type::RustVec(vec) if vec.inner == RustString => match r.mutable { - false => return quote_spanned!(span=> &::cxx::private::RustOption::from_option_vec_string_ref(#var.assume_init()) as _), - true => return quote_spanned!(span=> &::cxx::private::RustOption::from_option_vec_string_mut(#var.assume_init()) as _), - }, - Type::RustVec(_) => match r.mutable { - false => return quote_spanned!(span=> &::cxx::private::RustOption::from_option_vec_ref(#var.assume_init()) as _), - true => return quote_spanned!(span=> &::cxx::private::RustOption::from_option_vec_mut(#var.assume_init()) as _), - }, - _ => {}, - } - if types.is_considered_improper_ctype(&ty.inner) { - if r.mutable { - if r.pinned { - quote_spanned!(span=> &::cxx::RustOption::from_option_mut_improper_pinned(#var.assume_init()) as _) - } else { - quote_spanned!(span=> &::cxx::RustOption::from_option_mut_improper(#var.assume_init()) as _) - } - } else if r.pinned { - quote_spanned!(span=> &::cxx::RustOption::from_option_ref_improper_pinned(#var.assume_init()) as _) - } else { - quote_spanned!(span=> &::cxx::RustOption::from_option_ref_improper(#var.assume_init()) as _) + let improper; + let call = match &ty.inner { + Type::RustBox(ty) => { + improper = types.is_considered_improper_ctype(&ty.inner); + quote_spanned!(span=> ::cxx::private::RustOption::from(#var)) + } + Type::Ref(ty) => match &ty.inner { + Type::Ident(ident) if ident.rust == RustString => { + improper = false; + match ty.mutable { + false => quote_spanned!(span=> ::cxx::private::RustOption::from_option_string_ref(#var)), + true => quote_spanned!(span=> ::cxx::private::RustOption::from_option_string_mut(#var)), } - } else if r.mutable { - if r.pinned { - quote_spanned!(span=> &::cxx::RustOption::from_option_mut_pinned(#var.assume_init()) as _) - } else { - quote_spanned!(span=> &::cxx::RustOption::from_option_mut(#var.assume_init()) as _) + }, + Type::RustVec(vec) if vec.inner == RustString => { + improper = false; + match ty.mutable { + false => quote_spanned!(span=> ::cxx::private::RustOption::from_option_vec_string_ref(#var)), + true => quote_spanned!(span=> ::cxx::private::RustOption::from_option_vec_string_mut(#var)), } - } else if r.pinned { - quote_spanned!(span=> &::cxx::RustOption::from_option_ref_pinned(#var.assume_init()) as _) - } else { - quote_spanned!(span=> &::cxx::RustOption::from_option_ref(#var.assume_init()) as _) + }, + Type::RustVec(_) => { + improper = false; + match ty.mutable { + false => quote_spanned!(span=> ::cxx::private::RustOption::from_option_vec_ref(#var)), + true => quote_spanned!(span=> ::cxx::private::RustOption::from_option_vec_mut(#var)), + } + }, + _ => { + improper = types.is_considered_improper_ctype(&ty.inner); + quote!(::cxx::private::RustOption::from(#var)) } - } + }, _ => unreachable!(), + }; + if improper { + quote_spanned!(span=> #call.into_raw_improper()) + } else { + quote_spanned!(span=> #call.into_raw()) } } Type::Ref(ty) => match &ty.inner { @@ -668,16 +655,10 @@ fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream { .map(|arg| { let var = &arg.name.rust; let span = var.span(); - if let Type::RustOption(_) = arg.ty { - quote_spanned! {span=> - let #var = ::cxx::core::mem::MaybeUninit::new(#var); - } - } else { - // These are arguments for which C++ has taken ownership of the data - // behind the mut reference it received. - quote_spanned! {span=> - let mut #var = ::cxx::core::mem::MaybeUninit::new(#var); - } + // These are arguments for which C++ has taken ownership of the data + // behind the mut reference it received. + quote_spanned! {span=> + let mut #var = ::cxx::core::mem::MaybeUninit::new(#var); } }) .collect::(); @@ -731,55 +712,6 @@ fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream { quote_spanned!(span=> #call.into_vec()) } } - Type::RustOption(ty) => match &ty.inner { - Type::RustBox(ty) => { - if types.is_considered_improper_ctype(&ty.inner) { - quote_spanned!(span=> #call.into_option_box_improper()) - } else { - quote_spanned!(span=> #call.into_option_box()) - } - } - Type::Ref(r) => match &r.inner { - Type::Ident(ident) if ident.rust == RustString => match r.mutable { - false => quote_spanned!(span=> #call.into_option_string_ref()), - true => quote_spanned!(span=> #call.into_option_string_mut()), - }, - Type::RustVec(vec) if vec.inner == RustString => match r.mutable { - false => quote_spanned!(span=> #call.into_option_vec_string_ref()), - true => quote_spanned!(span=> #call.into_option_vec_string_mut()), - }, - Type::RustVec(_) => match r.mutable { - false => quote_spanned!(span=> #call.into_option_vec_ref()), - true => quote_spanned!(span=> #call.into_option_vec_mut()), - }, - _ => { - if types.is_considered_improper_ctype(&ty.inner) { - if r.mutable { - if r.pinned { - quote_spanned!(span=> #call.into_option_mut_improper_pinned()) - } else { - quote_spanned!(span=> #call.into_option_mut_improper()) - } - } else if r.pinned { - quote_spanned!(span=> #call.into_option_ref_improper_pinned()) - } else { - quote_spanned!(span=> #call.into_option_ref_improper()) - } - } else if r.mutable { - if r.pinned { - quote_spanned!(span=> #call.into_option_mut_pinned()) - } else { - quote_spanned!(span=> #call.into_option_mut()) - } - } else if r.pinned { - quote_spanned!(span=> #call.into_option_ref_pinned()) - } else { - quote_spanned!(span=> #call.into_option_ref()) - } - } - }, - _ => unreachable!(), - }, Type::UniquePtr(ty) => { if types.is_considered_improper_ctype(&ty.inner) { quote_spanned!(span=> ::cxx::UniquePtr::from_raw(#call.cast())) @@ -787,6 +719,43 @@ fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream { quote_spanned!(span=> ::cxx::UniquePtr::from_raw(#call)) } } + Type::RustOption(ty) => { + let inner = &ty.inner; + match &ty.inner { + Type::Ref(r) => match &r.inner { + Type::Ident(ident) if ident.rust == RustString => match r.mutable { + false => { + quote_spanned!(span=> ::cxx::private::RustOption::<&_>::from_raw(#call).into_option_string_ref()) + } + true => { + quote_spanned!(span=> ::cxx::private::RustOption::<&mut _>::from_raw(#call).into_option_string_mut()) + } + }, + Type::RustVec(vec) if vec.inner == RustString => match r.mutable { + false => { + quote_spanned!(span=> ::cxx::private::RustOption::<&_>::from_raw(#call).into_option_vec_string_ref()) + } + true => { + quote_spanned!(span=> ::cxx::private::RustOption::<&mut _>::from_raw(#call).into_option_vec_string_mut()) + } + }, + Type::RustVec(_) => match r.mutable { + false => { + quote_spanned!(span=> ::cxx::private::RustOption::<&_>::from_raw(#call).into_option_vec_ref()) + } + true => { + quote_spanned!(span=> ::cxx::private::RustOption::<&mut _>::from_raw(#call).into_option_vec_mut()) + } + }, + _ => { + quote_spanned!(span=> ::cxx::private::RustOption::<#inner>::from_raw(#call).into_option()) + } + }, + _ => { + quote_spanned!(span=> ::cxx::private::RustOption::<#inner>::from_raw(#call).into_option()) + } + } + } Type::Ref(ty) => match &ty.inner { Type::Ident(ident) if ident.rust == RustString => match ty.mutable { false => quote_spanned!(span=> #call.as_string()), @@ -1121,34 +1090,26 @@ fn expand_rust_function_shim_impl( } Type::RustOption(ty) => { requires_unsafe = true; + let inner = &ty.inner; match &ty.inner { - Type::RustBox(_) => quote_spanned!(span=> ::cxx::core::mem::take((*#var).as_mut_option_box())), Type::Ref(r) => match &r.inner { Type::Ident(i) if i.rust == RustString => match r.mutable { - true => quote_spanned!(span=> ::cxx::core::mem::take((*#var).as_option_string_mut())), - false => quote_spanned!(span=> ::cxx::core::mem::take((*#var).as_option_string_ref())), + true => quote_spanned!(span=> ::cxx::private::RustOption::<&mut _>::from_raw(#var).into_option_string_mut()), + false => quote_spanned!(span=> ::cxx::private::RustOption::<&_>::from_raw(#var).into_option_string_ref()), }, Type::RustVec(vec) if vec.inner == RustString => match r.mutable { - true => quote_spanned!(span=> ::cxx::core::mem::take((*#var).as_option_vec_string_mut())), - false => quote_spanned!(span=> ::cxx::core::mem::take((*#var).as_option_vec_string_ref())), + true => quote_spanned!(span=> ::cxx::private::RustOption::<&mut _>::from_raw(#var).into_option_vec_string_mut()), + false => quote_spanned!(span=> ::cxx::private::RustOption::<&_>::from_raw(#var).into_option_vec_string_ref()), }, - Type::RustVec(_) => match r.mutable { - true => quote_spanned!(span=> ::cxx::core::mem::take((*#var).as_option_vec_mut())), - false => quote_spanned!(span=> ::cxx::core::mem::take((*#var).as_option_vec_ref())), - }, - _ => if r.mutable { - if r.pinned { - quote_spanned!(span=> ::cxx::core::mem::take((*#var).as_mut_option_mut_pinned())) - } else { - quote_spanned!(span=> ::cxx::core::mem::take((*#var).as_mut_option_mut())) + Type::RustVec(_) => { + match r.mutable { + true => quote_spanned!(span=> ::cxx::private::RustOption::<&mut _>::from_raw(#var).into_option_vec_mut()), + false => quote_spanned!(span=> ::cxx::private::RustOption::<&_>::from_raw(#var).into_option_vec_ref()), } - } else if r.pinned { - quote_spanned!(span=> ::cxx::core::mem::take((*#var).as_mut_option_ref_pinned())) - } else { - quote_spanned!(span=> ::cxx::core::mem::take((*#var).as_mut_option_ref())) - } + }, + _ => quote_spanned!(span=> ::cxx::private::RustOption::<#inner>::from_raw(#var).into_option()), } - _ => unreachable!() + _ => quote_spanned!(span=> ::cxx::private::RustOption::<#inner>::from_raw(#var).into_option()), } } Type::UniquePtr(_) => { @@ -1209,6 +1170,7 @@ fn expand_rust_function_shim_impl( call.extend(quote! { (#(#vars),*) }); let span = body_span; + let mut process_converted = None; let conversion = sig.ret.as_ref().and_then(|ret| match ret { Type::Ident(ident) if ident.rust == RustString => { Some(quote_spanned!(span=> ::cxx::private::RustString::from)) @@ -1221,51 +1183,32 @@ fn expand_rust_function_shim_impl( Some(quote_spanned!(span=> ::cxx::private::RustVec::from)) } } - Type::RustOption(ty) => match &ty.inner { - Type::RustBox(_) => { - Some(quote_spanned!(span=> ::cxx::private::RustOption::from_option_box)) - } - Type::Ref(r) => { - match &r.inner { - Type::Ident(ident) if ident.rust == RustString => match r.mutable { - false => return Some(quote_spanned!(span=> ::cxx::private::RustOption::from_option_string_ref)), - true => return Some(quote_spanned!(span=> ::cxx::private::RustOption::from_option_string_mut)), - }, - Type::RustVec(vec) if vec.inner == RustString => match r.mutable { - false => return Some(quote_spanned!(span=> ::cxx::private::RustOption::from_option_vec_string_ref)), - true => return Some(quote_spanned!(span=> ::cxx::private::RustOption::from_option_vec_string_mut)), - }, - Type::RustVec(_) => match r.mutable { - false => return Some(quote_spanned!(span=> ::cxx::private::RustOption::from_option_vec_ref)), - true => return Some(quote_spanned!(span=> ::cxx::private::RustOption::from_option_vec_mut)), - }, - _ => {}, + Type::RustOption(ty) => { + process_converted = Some(quote_spanned!(span=> into_raw)); + match &ty.inner { + Type::RustBox(_) => { + Some(quote_spanned!(span=> ::cxx::private::RustOption::from)) } - if types.is_considered_improper_ctype(&ty.inner) { - if r.mutable { - if r.pinned { - Some(quote_spanned!(span=> ::cxx::private::RustOption::from_option_mut_pinned)) - } else { - Some(quote_spanned!(span=> ::cxx::private::RustOption::from_option_mut)) - } - } else if r.pinned { - Some(quote_spanned!(span=> ::cxx::private::RustOption::from_option_ref_pinned)) - } else { - Some(quote_spanned!(span=> ::cxx::private::RustOption::from_option_ref)) - } - } else if r.mutable { - if r.pinned { - Some(quote_spanned!(span=> ::cxx::private::RustOption::from_option_mut_pinned)) - } else { - Some(quote_spanned!(span=> ::cxx::private::RustOption::from_option_mut)) + Type::Ref(r) => { + match &r.inner { + Type::Ident(ident) if ident.rust == RustString => match r.mutable { + false => return Some(quote_spanned!(span=> ::cxx::private::RustOption::from_option_string_ref)), + true => return Some(quote_spanned!(span=> ::cxx::private::RustOption::from_option_string_mut)), + }, + Type::RustVec(vec) if vec.inner == RustString => match r.mutable { + false => return Some(quote_spanned!(span=> ::cxx::private::RustOption::from_option_vec_string_ref)), + true => return Some(quote_spanned!(span=> ::cxx::private::RustOption::from_option_vec_string_mut)), + }, + Type::RustVec(_) => match r.mutable { + false => return Some(quote_spanned!(span=> ::cxx::private::RustOption::from_option_vec_ref)), + true => return Some(quote_spanned!(span=> ::cxx::private::RustOption::from_option_vec_mut)), + }, + _ => {}, } - } else if r.pinned { - Some(quote_spanned!(span=> ::cxx::private::RustOption::from_option_ref_pinned)) - } else { - Some(quote_spanned!(span=> ::cxx::private::RustOption::from_option_ref)) + Some(quote_spanned!(span=> ::cxx::private::RustOption::from)) } + _ => unreachable!(), } - _ => unreachable!(), }, Type::UniquePtr(_) => Some(quote_spanned!(span=> ::cxx::UniquePtr::into_raw)), Type::Ref(ty) => match &ty.inner { @@ -1295,11 +1238,19 @@ fn expand_rust_function_shim_impl( None => call, Some(conversion) if !sig.throws => { requires_closure = true; - quote_spanned!(span=> #conversion(#call)) + if let Some(process_converted) = process_converted { + quote_spanned!(span=> #conversion(#call).#process_converted()) + } else { + quote_spanned!(span=> #conversion(#call)) + } } Some(conversion) => { requires_closure = true; - quote_spanned!(span=> ::cxx::core::result::Result::map(#call, #conversion)) + if let Some(process_converted) = process_converted { + quote_spanned!(span=> ::cxx::core::result::Result::map(#call, |v| #conversion(v).#process_converted())) + } else { + quote_spanned!(span=> ::cxx::core::result::Result::map(#call, #conversion)) + } } }; @@ -1670,13 +1621,15 @@ fn expand_rust_option( let link_new = format!("{}new", link_prefix); let link_drop = format!("{}drop", link_prefix); let link_has_value = format!("{}has_value", link_prefix); - let link_value_ptr = format!("{}value_ptr", link_prefix); + let link_value_const = format!("{}value_const", link_prefix); + let link_value = format!("{}value", link_prefix); let link_set = format!("{}set", link_prefix); let local_new = format_ident!("{}new", local_prefix); let local_drop = format_ident!("{}drop", local_prefix); let local_has_value = format_ident!("{}has_value", local_prefix); - let local_value_ptr = format_ident!("{}value_ptr", local_prefix); + let local_value_const = format_ident!("{}value_const", local_prefix); + let local_value = format_ident!("{}value", local_prefix); let local_set = format_ident!("{}set", local_prefix); let begin_span = explicit_impl.map_or(key.begin_span, |explicit| explicit.impl_token.span); @@ -1685,23 +1638,26 @@ fn expand_rust_option( let ident = key.rust; let (impl_generics, ty_generics) = generics::split_for_impl(*key, explicit_impl, resolve); - let (ty, trait_impl_ty, ty_ptr, prevent_unwind_drop_label) = match inner { + let (ty, trait_impl_ty, ty_ptr, const_ty_ptr, prevent_unwind_drop_label) = match inner { OptionInner::RustBox(_) => ( quote! { ::cxx::alloc::boxed::Box<#elem #ty_generics> }, quote! { ::cxx::alloc::boxed::Box<#elem #ty_generics> }, - quote! { ::cxx::alloc::boxed::Box<#elem #ty_generics> }, + quote! { *mut #elem #ty_generics }, + quote! { *const #elem #ty_generics }, format!("::alloc::boxed::Box<::{}> as Drop>::drop", ident), ), OptionInner::Ref(_) => ( quote! { &#elem #ty_generics }, quote! { &#elem #ty_generics }, quote! { *const #elem #ty_generics }, + quote! { *const #elem #ty_generics }, format!("&::{}> as Drop>::drop", ident), ), OptionInner::MutRef(_) => ( quote! { &mut #elem #ty_generics }, quote! { &mut #elem #ty_generics }, quote! { *mut #elem #ty_generics }, + quote! { *const #elem #ty_generics }, format!("&mut ::{}> as Drop>::drop", ident), ), OptionInner::RefVec(_) => ( @@ -1712,19 +1668,21 @@ fn expand_rust_option( // for a direct (mut) ref above (e.g. it could have been a const bool generic) // but using the actual `Vec` here at least gives some idea of what's going on // if this shows up in an error message. - quote! { &::cxx::alloc::vec::Vec<#elem #ty_generics> }, + quote! { &::cxx::private::RustVec<#elem #ty_generics> }, quote! { &#elem #ty_generics }, - quote! { *const ::cxx::alloc::vec::Vec<#elem #ty_generics> }, + quote! { *const ::cxx::private::RustVec<#elem #ty_generics> }, + quote! { *const ::cxx::private::RustVec<#elem #ty_generics> }, format!("&::alloc::vec::Vec<::{}> as Drop>::drop", ident), ), OptionInner::MutRefVec(_) => ( - quote! { &mut ::cxx::alloc::vec::Vec<#elem #ty_generics> }, + quote! { &mut ::cxx::private::RustVec<#elem #ty_generics> }, quote! { &mut #elem #ty_generics }, - quote! { *mut ::cxx::alloc::vec::Vec<#elem #ty_generics> }, + quote! { *mut ::cxx::private::RustVec<#elem #ty_generics> }, + quote! { *const ::cxx::private::RustVec<#elem #ty_generics> }, format!("&mut ::alloc::vec::Vec<::{}> as Drop>::drop", ident), ), }; - let set_impl = match inner { + let set_value_impl = match inner { OptionInner::RustBox(_) => quote! { #[doc(hidden)] #[export_name = #link_set] @@ -1732,12 +1690,61 @@ fn expand_rust_option( let value = core::mem::replace(value.as_mut().unwrap(), ::core::mem::MaybeUninit::zeroed()); this.as_mut().unwrap().set(unsafe { value.assume_init() }); } + #[doc(hidden)] + #[export_name = #link_value_const] + unsafe extern "C" fn #local_value_const #impl_generics(this: *const ::cxx::private::RustOption<#ty>) -> *const #ty { + let this = unsafe { this.as_ref().unwrap() }; + ::cxx::core::debug_assert!(this.has_value()); + let v: &#ty = unsafe { this.as_option().as_ref().unwrap() }; + v as _ + } + #[doc(hidden)] + #[export_name = #link_value] + unsafe extern "C" fn #local_value #impl_generics(this: *mut ::cxx::private::RustOption<#ty>) -> *mut #ty { + let this: &mut ::cxx::private::RustOption<#ty> = unsafe { this.as_mut().unwrap() }; + ::cxx::core::debug_assert!(this.has_value()); + this.as_mut_option().as_mut().unwrap() as _ + } }, - _ => quote! { + OptionInner::Ref(_) | OptionInner::RefVec(_) => quote! { + // no value_const, value already is value_const #[doc(hidden)] #[export_name = #link_set] - unsafe extern "C" fn #local_set #impl_generics(this: *mut ::cxx::private::RustOption<#ty_ptr>, value: *mut #ty_ptr) { - unsafe { this.as_mut().unwrap().set(*value) }; + unsafe extern "C" fn #local_set #impl_generics(this: *mut ::cxx::private::RustOption<#ty>, value: #ty_ptr) { + unsafe { this.as_mut().unwrap().set(&*value) }; + } + #[doc(hidden)] + #[export_name = #link_value] + unsafe extern "C" fn #local_value #impl_generics(this: *const ::cxx::private::RustOption<#ty>) -> #ty_ptr { + let this: &::cxx::private::RustOption<#ty> = unsafe { this.as_ref().unwrap() }; + ::cxx::core::debug_assert!(this.has_value()); + let option: &::core::option::Option<#ty> = this.as_option(); + let option: ::core::option::Option<&#ty> = option.as_ref(); + option.copied().unwrap() as _ + } + }, + OptionInner::MutRef(_) | OptionInner::MutRefVec(_) => quote! { + #[doc(hidden)] + #[export_name = #link_set] + unsafe extern "C" fn #local_set #impl_generics(this: *mut ::cxx::private::RustOption<#ty>, value: #ty_ptr) { + unsafe { this.as_mut().unwrap().set(&mut *value) }; + } + #[doc(hidden)] + #[export_name = #link_value_const] + unsafe extern "C" fn #local_value_const #impl_generics(this: *const ::cxx::private::RustOption<#ty>) -> #const_ty_ptr { + let this = unsafe { this.as_ref().unwrap() }; + ::cxx::core::debug_assert!(this.has_value()); + let v: &#ty = unsafe { this.as_option().as_ref().unwrap() }; + &**v as _ + } + #[doc(hidden)] + #[export_name = #link_value] + unsafe extern "C" fn #local_value #impl_generics(this: *mut ::cxx::private::RustOption<#ty>) -> #ty_ptr { + let this: &mut ::cxx::private::RustOption<#ty> = unsafe { this.as_mut().unwrap() }; + ::cxx::core::debug_assert!(this.has_value()); + let option: &mut ::core::option::Option<#ty> = this.as_mut_option(); + let option: ::core::option::Option<&mut #ty> = option.as_mut(); + *option.unwrap() as _ } }, }; @@ -1757,17 +1764,10 @@ fn expand_rust_option( } #[doc(hidden)] #[export_name = #link_has_value] - unsafe extern "C" fn #local_has_value #impl_generics(this: *mut ::cxx::private::RustOption<#ty>) -> bool { + unsafe extern "C" fn #local_has_value #impl_generics(this: *const ::cxx::private::RustOption<#ty>) -> bool { unsafe { this.as_ref().unwrap().value().is_some() } } - #[doc(hidden)] - #[export_name = #link_value_ptr] - unsafe extern "C" fn #local_value_ptr #impl_generics(this: *mut ::cxx::private::RustOption<#ty_ptr>) -> *mut #ty_ptr { - let this = unsafe { this.as_mut().unwrap() }; - ::cxx::core::debug_assert!(this.has_value()); - unsafe { this.as_ref_mut_inner_unchecked() as _ } - } - #set_impl + #set_value_impl } } @@ -2208,13 +2208,51 @@ fn expand_extern_type(ty: &Type, types: &Types, proper: bool) -> TokenStream { let rangle = ty.rangle; quote_spanned!(span=> ::cxx::private::RustVec #langle #elem #rangle) } - Type::RustOption(ty) => { - let span = ty.name.span(); - let langle = ty.langle; - let elem = expand_extern_type(&ty.inner, types, proper); - let rangle = ty.rangle; - quote_spanned!(span=> ::cxx::private::RustOption #langle #elem #rangle) - } + Type::RustOption(ty) => match &ty.inner { + Type::Ref(r) => { + let ampersand = r.ampersand; + let star = Token![*](ampersand.span); + match &r.inner { + Type::Ident(ident) if ident.rust == RustString => { + let span = ident.rust.span(); + match r.mutable { + false => quote_spanned!(span=> #star const ::cxx::private::RustString), + true => quote_spanned!(span=> #star mut ::cxx::private::RustString), + } + } + Type::RustVec(ty) => { + let span = ty.name.span(); + let langle = ty.langle; + let inner = expand_extern_type(&ty.inner, types, proper); + let rangle = ty.rangle; + match r.mutable { + false => { + quote_spanned!(span=> #star const ::cxx::private::RustVec #langle #inner #rangle) + } + true => { + quote_spanned!(span=> #star mut ::cxx::private::RustVec #langle #inner #rangle) + } + } + } + inner if proper && types.is_considered_improper_ctype(inner) => { + let star = Token![*](ampersand.span); + match r.mutable { + false => quote!(#star const ::cxx::core::ffi::c_void), + true => quote!(#star mut ::cxx::core::ffi::c_void), + } + } + inner => { + let star = Token![*](ampersand.span); + match r.mutable { + false => quote!(#star const #inner), + true => quote!(#star mut #inner), + } + } + } + } + Type::RustBox(_) => expand_extern_type(&ty.inner, types, proper), + _ => unreachable!(), + }, Type::Ref(ty) => { let ampersand = ty.ampersand; let lifetime = &ty.lifetime; @@ -2231,13 +2269,6 @@ fn expand_extern_type(ty: &Type, types: &Types, proper: bool) -> TokenStream { let rangle = ty.rangle; quote_spanned!(span=> #ampersand #lifetime #mutability ::cxx::private::RustVec #langle #inner #rangle) } - Type::RustOption(ty) => { - let span = ty.name.span(); - let langle = ty.langle; - let inner = expand_extern_type(&ty.inner, types, proper); - let rangle = ty.rangle; - quote_spanned!(span=> #ampersand #lifetime #mutability ::cxx::private::RustOption #langle #inner #rangle) - } inner if proper && types.is_considered_improper_ctype(inner) => { let star = Token![*](ampersand.span); match ty.mutable { diff --git a/src/cxx.cc b/src/cxx.cc index 993752ced..08f61e45a 100644 --- a/src/cxx.cc +++ b/src/cxx.cc @@ -785,136 +785,150 @@ static_assert(sizeof(std::string) <= kMaxExpectedWordsInString * sizeof(void *), MACRO(string, std::string) #define RUST_OPTION_EXTERNS(RUST_TYPE, CXX_TYPE) \ - void cxxbridge1$rust_option$const$##RUST_TYPE##$new( \ - rust::Option *ptr) noexcept; \ - void cxxbridge1$rust_option$const$##RUST_TYPE##$drop( \ - rust::Option *ptr) noexcept; \ - bool cxxbridge1$rust_option$const$##RUST_TYPE##$has_value( \ - const rust::Option *ptr) noexcept; \ - CXX_TYPE const ** cxxbridge1$rust_option$const$##RUST_TYPE##$value_ptr( \ - rust::Option *ptr) noexcept; \ - void cxxbridge1$rust_option$const$##RUST_TYPE##$set( \ - rust::Option *ptr, CXX_TYPE const *&& value) noexcept; \ - void cxxbridge1$rust_option$##RUST_TYPE##$new( \ - rust::Option *ptr) noexcept; \ - void cxxbridge1$rust_option$##RUST_TYPE##$drop( \ - rust::Option *ptr) noexcept; \ - bool cxxbridge1$rust_option$##RUST_TYPE##$has_value( \ - const rust::Option *ptr) noexcept; \ - CXX_TYPE** cxxbridge1$rust_option$##RUST_TYPE##$value_ptr( \ - rust::Option *ptr) noexcept; \ - void cxxbridge1$rust_option$##RUST_TYPE##$set( \ - rust::Option *ptr, CXX_TYPE *&& value) noexcept; \ - /* Vec implementation */ \ - void cxxbridge1$rust_option$const$rust_vec$##RUST_TYPE##$new( \ - rust::Option const *> *ptr) noexcept; \ - void cxxbridge1$rust_option$const$rust_vec$##RUST_TYPE##$drop( \ - rust::Option const *> *ptr) noexcept; \ - bool cxxbridge1$rust_option$const$rust_vec$##RUST_TYPE##$has_value( \ - const rust::Option const *> *ptr) noexcept; \ - rust::Vec const ** cxxbridge1$rust_option$const$rust_vec$##RUST_TYPE##$value_ptr( \ - rust::Option const *> *ptr) noexcept; \ - void cxxbridge1$rust_option$const$rust_vec$##RUST_TYPE##$set( \ - rust::Option const *> *ptr, rust::Vec const *&& value) noexcept; \ - void cxxbridge1$rust_option$rust_vec$##RUST_TYPE##$new( \ - rust::Option *> *ptr) noexcept; \ - void cxxbridge1$rust_option$rust_vec$##RUST_TYPE##$drop( \ - rust::Option *> *ptr) noexcept; \ - bool cxxbridge1$rust_option$rust_vec$##RUST_TYPE##$has_value( \ - const rust::Option *> *ptr) noexcept; \ - rust::Vec** cxxbridge1$rust_option$rust_vec$##RUST_TYPE##$value_ptr( \ - rust::Option *> *ptr) noexcept; \ - void cxxbridge1$rust_option$rust_vec$##RUST_TYPE##$set( \ - rust::Option *> *ptr, rust::Vec *&& value) noexcept; - - -#define RUST_OPTION_OPS(RUST_TYPE, CXX_TYPE) \ - template <> \ - Option::Option() noexcept { \ - cxxbridge1$rust_option$const$##RUST_TYPE##$new(this); \ - } \ - template <> \ - void Option::drop() noexcept { \ - cxxbridge1$rust_option$const$##RUST_TYPE##$drop(this); \ - } \ - template <> \ - bool Option::has_value() const noexcept { \ - return cxxbridge1$rust_option$const$##RUST_TYPE##$has_value(this); \ - } \ - template <> \ - CXX_TYPE const ** Option::value_ptr() noexcept { \ - return cxxbridge1$rust_option$const$##RUST_TYPE##$value_ptr(this); \ - } \ - template <> \ - void Option::set(CXX_TYPE const *&& value) noexcept { \ - return cxxbridge1$rust_option$const$##RUST_TYPE##$set( \ - this, std::move(value)); \ - } \ - template <> \ - Option::Option() noexcept { \ - cxxbridge1$rust_option$##RUST_TYPE##$new(this); \ - } \ - template <> \ - void Option::drop() noexcept { \ - cxxbridge1$rust_option$##RUST_TYPE##$drop(this); \ - } \ - template <> \ - bool Option::has_value() const noexcept { \ - return cxxbridge1$rust_option$##RUST_TYPE##$has_value(this); \ - } \ - template <> \ - CXX_TYPE** Option::value_ptr() noexcept { \ - return cxxbridge1$rust_option$##RUST_TYPE##$value_ptr(this); \ - } \ - template <> \ - void Option::set(CXX_TYPE *&& value) noexcept { \ - return cxxbridge1$rust_option$##RUST_TYPE##$set(this, std::move(value)); \ - } \ - /* Vec impl */ \ - template <> \ - Option const *>::Option() noexcept { \ - cxxbridge1$rust_option$const$rust_vec$##RUST_TYPE##$new(this); \ - } \ - template <> \ - void Option const *>::drop() noexcept { \ - cxxbridge1$rust_option$const$rust_vec$##RUST_TYPE##$drop(this); \ - } \ - template <> \ - bool Option const *>::has_value() const noexcept { \ - return cxxbridge1$rust_option$const$rust_vec$##RUST_TYPE##$has_value(this); \ - } \ - template <> \ - rust::Vec const ** Option const *>::value_ptr() noexcept { \ - return cxxbridge1$rust_option$const$rust_vec$##RUST_TYPE##$value_ptr(this); \ - } \ - template <> \ - void Option const *>::set(rust::Vec const *&& value) noexcept { \ - return cxxbridge1$rust_option$const$rust_vec$##RUST_TYPE##$set( \ - this, std::move(value)); \ - } \ - template <> \ - Option *>::Option() noexcept { \ - cxxbridge1$rust_option$rust_vec$##RUST_TYPE##$new(this); \ - } \ - template <> \ - void Option *>::drop() noexcept { \ - cxxbridge1$rust_option$rust_vec$##RUST_TYPE##$drop(this); \ - } \ - template <> \ - bool Option *>::has_value() const noexcept { \ - return cxxbridge1$rust_option$rust_vec$##RUST_TYPE##$has_value(this); \ - } \ - template <> \ - rust::Vec** Option *>::value_ptr() noexcept { \ - return cxxbridge1$rust_option$rust_vec$##RUST_TYPE##$value_ptr(this); \ - } \ - template <> \ - void Option *>::set(rust::Vec *&& value) noexcept { \ - return cxxbridge1$rust_option$rust_vec$##RUST_TYPE##$set(this, std::move(value)); \ + void cxxbridge1$rust_option$const$##RUST_TYPE##$new( \ + rust::Option *ptr) noexcept; \ + void cxxbridge1$rust_option$const$##RUST_TYPE##$drop( \ + rust::Option *ptr) noexcept; \ + bool cxxbridge1$rust_option$const$##RUST_TYPE##$has_value( \ + const rust::Option *ptr) noexcept; \ + CXX_TYPE const * cxxbridge1$rust_option$const$##RUST_TYPE##$value( \ + rust::Option const *ptr) noexcept; \ + void cxxbridge1$rust_option$const$##RUST_TYPE##$set( \ + rust::Option *ptr, CXX_TYPE const * value) noexcept; \ + void cxxbridge1$rust_option$##RUST_TYPE##$new( \ + rust::Option *ptr) noexcept; \ + void cxxbridge1$rust_option$##RUST_TYPE##$drop( \ + rust::Option *ptr) noexcept; \ + bool cxxbridge1$rust_option$##RUST_TYPE##$has_value( \ + const rust::Option *ptr) noexcept; \ + CXX_TYPE* cxxbridge1$rust_option$##RUST_TYPE##$value_const( \ + rust::Option const *ptr) noexcept; \ + CXX_TYPE* cxxbridge1$rust_option$##RUST_TYPE##$value( \ + rust::Option *ptr) noexcept; \ + void cxxbridge1$rust_option$##RUST_TYPE##$set( \ + rust::Option *ptr, CXX_TYPE * value) noexcept; \ + /* Vec implementation */ \ + void cxxbridge1$rust_option$const$rust_vec$##RUST_TYPE##$new( \ + rust::Option const &> *ptr) noexcept; \ + void cxxbridge1$rust_option$const$rust_vec$##RUST_TYPE##$drop( \ + rust::Option const &> *ptr) noexcept; \ + bool cxxbridge1$rust_option$const$rust_vec$##RUST_TYPE##$has_value( \ + const rust::Option const &> *ptr) noexcept; \ + rust::Vec const * cxxbridge1$rust_option$const$rust_vec$##RUST_TYPE##$value( \ + rust::Option const &> const *ptr) noexcept; \ + void cxxbridge1$rust_option$const$rust_vec$##RUST_TYPE##$set( \ + rust::Option const &> *ptr, rust::Vec const * value) noexcept; \ + void cxxbridge1$rust_option$rust_vec$##RUST_TYPE##$new( \ + rust::Option &> *ptr) noexcept; \ + void cxxbridge1$rust_option$rust_vec$##RUST_TYPE##$drop( \ + rust::Option &> *ptr) noexcept; \ + bool cxxbridge1$rust_option$rust_vec$##RUST_TYPE##$has_value( \ + const rust::Option &> *ptr) noexcept; \ + rust::Vec* cxxbridge1$rust_option$rust_vec$##RUST_TYPE##$value_const( \ + rust::Option &> const *ptr) noexcept; \ + rust::Vec* cxxbridge1$rust_option$rust_vec$##RUST_TYPE##$value( \ + rust::Option &> *ptr) noexcept; \ + void cxxbridge1$rust_option$rust_vec$##RUST_TYPE##$set( \ + rust::Option &> *ptr, rust::Vec * value) noexcept; + + +#define RUST_OPTION_OPS(RUST_TYPE, CXX_TYPE) \ + template <> \ + Option::Option() noexcept { \ + cxxbridge1$rust_option$const$##RUST_TYPE##$new(this); \ + } \ + template <> \ + void Option::drop() noexcept { \ + cxxbridge1$rust_option$const$##RUST_TYPE##$drop(this); \ + } \ + template <> \ + bool Option::has_value() const noexcept { \ + return cxxbridge1$rust_option$const$##RUST_TYPE##$has_value(this); \ + } \ + template <> \ + CXX_TYPE const & Option::value() const noexcept { \ + return *cxxbridge1$rust_option$const$##RUST_TYPE##$value(this); \ + } \ + template <> \ + void Option::set(CXX_TYPE const & value) noexcept { \ + return cxxbridge1$rust_option$const$##RUST_TYPE##$set( \ + this, &value); \ + } \ + template <> \ + Option::Option() noexcept { \ + cxxbridge1$rust_option$##RUST_TYPE##$new(this); \ + } \ + template <> \ + void Option::drop() noexcept { \ + cxxbridge1$rust_option$##RUST_TYPE##$drop(this); \ + } \ + template <> \ + bool Option::has_value() const noexcept { \ + return cxxbridge1$rust_option$##RUST_TYPE##$has_value(this); \ + } \ + template <> \ + const CXX_TYPE& Option::value() const noexcept { \ + return *cxxbridge1$rust_option$##RUST_TYPE##$value_const(this); \ + } \ + template <> \ + CXX_TYPE& Option::value() noexcept { \ + return *cxxbridge1$rust_option$##RUST_TYPE##$value(this); \ + } \ + template <> \ + void Option::set(CXX_TYPE & value) noexcept { \ + return cxxbridge1$rust_option$##RUST_TYPE##$set(this, &value); \ + } \ + /* Vec impl */ \ + template <> \ + Option const &>::Option() noexcept { \ + cxxbridge1$rust_option$const$rust_vec$##RUST_TYPE##$new(this); \ + } \ + template <> \ + void Option const &>::drop() noexcept { \ + cxxbridge1$rust_option$const$rust_vec$##RUST_TYPE##$drop(this); \ + } \ + template <> \ + bool Option const &>::has_value() const noexcept { \ + return cxxbridge1$rust_option$const$rust_vec$##RUST_TYPE##$has_value(this); \ + } \ + template <> \ + rust::Vec const & Option const &>::value() const noexcept { \ + return *cxxbridge1$rust_option$const$rust_vec$##RUST_TYPE##$value(this); \ + } \ + template <> \ + void Option const &>::set(rust::Vec const & value) noexcept { \ + return cxxbridge1$rust_option$const$rust_vec$##RUST_TYPE##$set( \ + this, &value); \ + } \ + template <> \ + Option &>::Option() noexcept { \ + cxxbridge1$rust_option$rust_vec$##RUST_TYPE##$new(this); \ + } \ + template <> \ + void Option &>::drop() noexcept { \ + cxxbridge1$rust_option$rust_vec$##RUST_TYPE##$drop(this); \ + } \ + template <> \ + bool Option &>::has_value() const noexcept { \ + return cxxbridge1$rust_option$rust_vec$##RUST_TYPE##$has_value(this); \ + } \ + template <> \ + const rust::Vec& Option &>::value() const noexcept { \ + return *cxxbridge1$rust_option$rust_vec$##RUST_TYPE##$value_const(this); \ + } \ + template <> \ + rust::Vec& Option &>::value() noexcept { \ + return *cxxbridge1$rust_option$rust_vec$##RUST_TYPE##$value(this); \ + } \ + template <> \ + void Option &>::set(rust::Vec & value) noexcept { \ + return cxxbridge1$rust_option$rust_vec$##RUST_TYPE##$set(this, &value); \ } #define FOR_EACH_RUST_OPTION(MACRO) \ FOR_EACH_NUMERIC(MACRO) \ + MACRO(bool, bool) \ + MACRO(char, char) \ MACRO(string, rust::String) extern "C" { diff --git a/src/lib.rs b/src/lib.rs index b4f9032a9..be45111f4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -512,8 +512,8 @@ pub mod private { pub use crate::opaque::Opaque; #[cfg(feature = "alloc")] pub use crate::result::{r#try, Result}; - pub use crate::rust_option::assert_option_safe; pub use crate::rust_option::RustOption; + pub use crate::rust_option::assert_option_safe; pub use crate::rust_slice::RustSlice; pub use crate::rust_str::RustStr; #[cfg(feature = "alloc")] diff --git a/src/rust_option.rs b/src/rust_option.rs index 29febaba1..7234b3963 100644 --- a/src/rust_option.rs +++ b/src/rust_option.rs @@ -1,6 +1,8 @@ #![allow(missing_docs)] #![allow(clippy::let_unit_value)] +use core::mem; + #[cfg(feature = "alloc")] use crate::private::RustString; #[cfg(feature = "alloc")] @@ -11,9 +13,6 @@ use alloc::boxed::Box; use alloc::string::String; #[cfg(feature = "alloc")] use alloc::vec::Vec; -use core::mem::ManuallyDrop; -use core::ops::Deref; -use core::ops::DerefMut; use core::pin::Pin; mod private { @@ -30,463 +29,332 @@ impl OptionTarget for &mut T {} impl private::Sealed for Pin<&mut T> {} impl OptionTarget for Pin<&mut T> {} -impl private::Sealed for *const T {} -impl OptionTarget for *const T {} - -impl private::Sealed for *mut T {} -impl OptionTarget for *mut T {} - #[cfg(feature = "alloc")] impl private::Sealed for Box {} #[cfg(feature = "alloc")] impl OptionTarget for Box {} -#[repr(C)] -union OptionInner { - value: ManuallyDrop, - empty: usize, -} - -impl OptionInner { - fn none() -> Self { - Self { empty: 0 } - } - - #[cfg(feature = "alloc")] - fn new(t: T) -> Self { - Self { - value: ManuallyDrop::new(t), - } - } - - fn has_value(&self) -> bool { - let _: () = assert_option_safe::<&T>(); - unsafe { self.empty != 0 } - } - - fn into_inner_unchecked(mut self) -> T { - let value = unsafe { ManuallyDrop::take(&mut self.value) }; - unsafe { core::ptr::write(&mut self as _, OptionInner::none()) }; - value - } -} - -impl Drop for OptionInner { - fn drop(&mut self) { - if self.has_value() { - unsafe { ManuallyDrop::drop(&mut self.value) }; - } - } -} +type Repr = [mem::MaybeUninit; mem::size_of::>() / core::mem::size_of::()]; // ABI compatible with C++ rust::Option (not necessarily core::option::Option). #[repr(C)] pub struct RustOption { - inner: OptionInner, + repr: Repr, + marker: core::marker::PhantomData, } pub const fn assert_option_safe() { struct __SizeCheck(core::marker::PhantomData); impl __SizeCheck { + const _IS_OPTION_SIZE: () = + assert!(mem::size_of::>() == mem::size_of::()); + const _IS_USIZE: () = + assert!(mem::size_of::() == mem::size_of::()); const _IS_NICHE: () = - assert!(core::mem::size_of::>() == core::mem::size_of::()); - const _IS_USIZE_SIZE: () = - assert!(core::mem::size_of::>() == core::mem::size_of::()); + assert!(mem::size_of::>() == mem::size_of::()); + const _IS_USIZE_ALIGN: () = + assert!(mem::align_of::() == mem::align_of::()); + const _IS_OPTION_ALIGN: () = + assert!(mem::align_of::>() == mem::align_of::()); } // Force the constants to resolve (at compile time) + let _: () = __SizeCheck::::_IS_OPTION_SIZE; + let _: () = __SizeCheck::::_IS_USIZE; let _: () = __SizeCheck::::_IS_NICHE; - let _: () = __SizeCheck::::_IS_USIZE_SIZE; + let _: () = __SizeCheck::::_IS_USIZE_ALIGN; + let _: () = __SizeCheck::::_IS_OPTION_ALIGN; } impl RustOption { pub fn new() -> Self { - let _: () = assert_option_safe::<&mut T>(); - RustOption { - inner: OptionInner::none(), - } + let _: () = assert_option_safe::(); + Self::from(None) } - pub fn value(&self) -> Option<&T> { - if self.has_value() { - unsafe { Some(self.inner.value.deref()) } - } else { - None - } + pub fn into_option(mut self) -> Option { + let _: () = assert_option_safe::(); + self.as_mut_option().take() } - pub fn into_value(self) -> Option { - if self.has_value() { - unsafe { Some(self.into_inner_unchecked()) } - } else { - None - } + pub fn as_option(&self) -> &Option { + let _: () = assert_option_safe::(); + unsafe { &*(self as *const RustOption as *const Option) } } - pub fn has_value(&self) -> bool { - self.inner.has_value() + pub fn as_mut_option(&mut self) -> &mut Option { + let _: () = assert_option_safe::(); + unsafe { &mut *(self as *mut RustOption as *mut Option) } } - pub fn set(&mut self, value: T) { - self.inner = OptionInner { - value: ManuallyDrop::new(value), - } + pub fn from(o: Option) -> Self { + let _: () = assert_option_safe::(); + let v = unsafe { core::mem::transmute_copy(&o) }; + core::mem::forget(o); + v } - pub unsafe fn into_inner_unchecked(self) -> T { - self.inner.into_inner_unchecked() + pub fn from_ref(o: &Option) -> &Self { + let _: () = assert_option_safe::(); + unsafe { &*(o as *const Option as *const RustOption) } } - pub unsafe fn as_ref_inner_unchecked(&self) -> &T { - unsafe { self.inner.value.deref() } + pub fn from_mut(o: &mut Option) -> &mut Self { + let _: () = assert_option_safe::(); + unsafe { &mut *(o as *mut Option as *mut RustOption) } } - pub unsafe fn as_ref_mut_inner_unchecked(&mut self) -> &mut T { - unsafe { self.inner.value.deref_mut() } - } -} - -impl<'a, T> RustOption<&'a T> -where - &'a T: OptionTarget, -{ - pub fn from_option_ref(other: Option<&'a T>) -> Self { - let _: () = assert_option_safe::<&T>(); - unsafe { core::mem::transmute::, RustOption<&'a T>>(other) } - } - - pub fn into_option_ref(self) -> Option<&'a T> { - let _: () = assert_option_safe::<&T>(); - unsafe { core::mem::transmute::, Option<&'a T>>(self) } - } - - pub fn as_mut_option_ref(&mut self) -> &mut Option<&'a T> { - let _: () = assert_option_safe::<&T>(); - unsafe { &mut *(self as *mut RustOption<&'a T> as *mut Option<&'a T>) } - } -} - -impl<'a, T> RustOption<&'a mut T> -where - &'a mut T: OptionTarget, -{ - pub fn from_option_mut(other: Option<&'a mut T>) -> Self { - let _: () = assert_option_safe::<&mut T>(); - unsafe { core::mem::transmute::, RustOption<&'a mut T>>(other) } + pub fn value(&self) -> Option<&T> { + self.as_option().as_ref() } - pub fn into_option_mut(self) -> Option<&'a mut T> { - let _: () = assert_option_safe::<&mut T>(); - unsafe { core::mem::transmute::, Option<&'a mut T>>(self) } + pub fn has_value(&self) -> bool { + self.as_option().is_some() } - pub fn as_mut_option_mut(&mut self) -> &mut Option<&'a mut T> { - let _: () = assert_option_safe::<&mut T>(); - unsafe { &mut *(self as *mut RustOption<&'a mut T> as *mut Option<&'a mut T>) } + pub fn set(&mut self, value: T) { + self.as_mut_option().replace(value); } - pub fn as_mut_option_mut_improper(&mut self) -> &mut Option<&'a mut T> { - let _: () = assert_option_safe::<&mut T>(); - unsafe { &mut *(self as *mut RustOption<&'a mut T> as *mut Option<&'a mut T>) } + pub unsafe fn as_ref_mut_inner_unchecked(&mut self) -> &mut T { + unsafe { self.as_mut_option().as_mut().unwrap_unchecked() } } } -impl<'a, T> RustOption> -where - Pin<&'a mut T>: OptionTarget, -{ - pub fn from_option_mut_pinned(other: Option>) -> Self { - let _: () = assert_option_safe::>(); - unsafe { core::mem::transmute::>, RustOption>>(other) } +impl<'a, T> RustOption<&'a T> { + pub fn into_raw(self) -> *const T { + self.into_option() + .map_or(core::ptr::null(), |v| v as *const T) } - pub fn into_option_mut_pinned(self) -> Option> { - let _: () = assert_option_safe::>(); - unsafe { core::mem::transmute::>, Option>>(self) } + pub fn into_raw_improper(self) -> *const core::ffi::c_void { + self.into_option().map_or(core::ptr::null(), |v| { + v as *const T as *const core::ffi::c_void + }) } - pub fn as_mut_option_mut_pinned(&mut self) -> &mut Option> { - let _: () = assert_option_safe::>(); - unsafe { &mut *(self as *mut RustOption> as *mut Option>) } - } - - pub fn into_option_mut_improper_pinned(self) -> Option> { - let _: () = assert_option_safe::>(); - unsafe { core::mem::transmute::>, Option>>(self) } + /// SAFETY: ptr must be valid for 'a + pub unsafe fn from_raw(ptr: *const T) -> Self { + let mut this = RustOption::new(); + if let Some(r) = unsafe { ptr.as_ref() } { + this.set(r); + } + this } - pub fn as_mut_option_mut_improper_pinned(&mut self) -> &mut Option> { - let _: () = assert_option_safe::>(); - unsafe { &mut *(self as *mut RustOption> as *mut Option>) } + /// SAFETY: ptr must be valid for 'a, and castable to *const T + pub unsafe fn from_raw_improper(ptr: *const core::ffi::c_void) -> Self { + let mut this = RustOption::new(); + let ptr = ptr as *const T; + if let Some(r) = unsafe { ptr.as_ref() } { + this.set(r); + } + this } } -impl RustOption<*const T> -where - *const T: OptionTarget, -{ - /// SAFETY: self must have been constructed as `Option>` - #[cfg(feature = "alloc")] - pub unsafe fn into_option_box(self) -> Option> { - let _: () = assert_option_safe::>(); - unsafe { core::mem::transmute::, Option>>(self) } +impl<'a, T> RustOption<&'a mut T> { + pub fn into_raw(self) -> *mut T { + self.into_option() + .map_or(core::ptr::null_mut(), |v| v as *mut T) } - /// SAFETY: self must have been constructed as `Option>` - #[cfg(feature = "alloc")] - pub unsafe fn as_mut_option_box(&mut self) -> &mut Option> { - let _: () = assert_option_safe::>(); - unsafe { &mut *(self as *mut RustOption<*const T> as *mut Option>) } + pub fn into_raw_improper(self) -> *mut core::ffi::c_void { + self.into_option().map_or(core::ptr::null_mut(), |v| { + v as *mut T as *mut core::ffi::c_void + }) } - pub fn into_option_ref<'a>(self) -> Option<&'a T> { - let _: () = assert_option_safe::<&T>(); - unsafe { core::mem::transmute::, Option<&'a T>>(self) } + /// SAFETY: ptr must be valid for 'a + pub unsafe fn from_raw(ptr: *mut T) -> Self { + let mut this = RustOption::new(); + if let Some(r) = unsafe { ptr.as_mut() } { + this.set(r); + } + this } - pub fn as_mut_option_ref<'a>(&mut self) -> &mut Option<&'a T> { - let _: () = assert_option_safe::<&T>(); - unsafe { &mut *(self as *mut RustOption<*const T> as *mut Option<&'a T>) } + /// SAFETY: ptr must be valid for 'a, and castable to *mut T + pub unsafe fn from_raw_improper(ptr: *mut core::ffi::c_void) -> Self { + let mut this = RustOption::new(); + let ptr = ptr as *mut T; + if let Some(r) = unsafe { ptr.as_mut() } { + this.set(r); + } + this } } -impl RustOption<*mut T> -where - *mut T: OptionTarget, -{ - #[cfg(feature = "alloc")] - pub fn from_option_box(other: Option>) -> Self { - let _: () = assert_option_safe::>(); - unsafe { core::mem::transmute::>, RustOption<*mut T>>(other) } +impl<'a, T> RustOption> { + pub fn into_raw(self) -> *mut T { + self.into_option() + .map_or(core::ptr::null_mut(), |v| unsafe { + v.get_unchecked_mut() as *mut T + }) } - /// SAFETY: self must have been constructed as `Option>` - #[cfg(feature = "alloc")] - pub unsafe fn into_option_box(self) -> Option> { - let _: () = assert_option_safe::>(); - unsafe { core::mem::transmute::, Option>>(self) } + pub fn into_raw_improper(self) -> *mut core::ffi::c_void { + self.into_option() + .map_or(core::ptr::null_mut(), |v| unsafe { + v.get_unchecked_mut() as *mut T as *mut core::ffi::c_void + }) } - /// SAFETY: self must have been constructed as `Option>` - #[cfg(feature = "alloc")] - pub unsafe fn as_mut_option_box(&mut self) -> &mut Option> { - let _: () = assert_option_safe::>(); - unsafe { &mut *(self as *mut RustOption<*mut T> as *mut Option>) } - } - - /// SAFETY: Pointer must not be aliased and must have been constructed as an `Option<&mut T>` - pub unsafe fn into_option_mut<'a>(self) -> Option<&'a mut T> { - let _: () = assert_option_safe::<&mut T>(); - unsafe { core::mem::transmute::, Option<&'a mut T>>(self) } - } - - /// SAFETY: Pointer must not be aliased and must have been constructed as an `Option<&mut T>` - pub unsafe fn as_mut_option_mut<'a>(&mut self) -> &mut Option<&'a mut T> { - let _: () = assert_option_safe::<&mut T>(); - unsafe { &mut *(self as *mut RustOption<*mut T> as *mut Option<&'a mut T>) } - } -} - -impl RustOption<*const core::ffi::c_void> { - pub fn from_option_ref_improper<'a, T>(other: Option<&'a T>) -> Self { - let _: () = assert_option_safe::<&T>(); - unsafe { - core::mem::transmute::, RustOption<*const core::ffi::c_void>>(other) + /// SAFETY: ptr must be valid for 'a + pub unsafe fn from_raw(ptr: *mut T) -> Self { + let mut this = RustOption::new(); + if let Some(r) = unsafe { ptr.as_mut() } { + this.set(unsafe { Pin::new_unchecked(r) }); } + this } - pub fn from_option_ref_improper_pinned<'a, T>(other: Option>) -> Self { - let _: () = assert_option_safe::>(); - unsafe { - core::mem::transmute::>, RustOption<*const core::ffi::c_void>>(other) + /// SAFETY: ptr must be valid for 'a, and castable to *mut T + pub unsafe fn from_raw_improper(ptr: *mut core::ffi::c_void) -> Self { + let mut this = RustOption::new(); + let ptr = ptr as *mut T; + if let Some(r) = unsafe { ptr.as_mut() } { + this.set(unsafe { Pin::new_unchecked(r) }); } - } - - /// SAFETY: self must have been constructed as `Option>` - #[cfg(feature = "alloc")] - pub unsafe fn into_option_box_improper(self) -> Option> { - let _: () = assert_option_safe::>(); - unsafe { - core::mem::transmute::, Option>>(self) - } - } - - /// SAFETY: self must have been constructed as `Option>` - #[cfg(feature = "alloc")] - pub unsafe fn as_mut_option_box_improper(&mut self) -> &mut Option> { - let _: () = assert_option_safe::>(); - unsafe { &mut *(self as *mut RustOption<*const core::ffi::c_void> as *mut Option>) } - } - - pub fn into_option_ref_improper<'a, T>(self) -> Option<&'a T> { - let _: () = assert_option_safe::<&T>(); - unsafe { core::mem::transmute::, Option<&'a T>>(self) } - } - - pub fn as_mut_option_ref_improper<'a, T>(&mut self) -> &mut Option<&'a T> { - let _: () = assert_option_safe::<&T>(); - unsafe { &mut *(self as *mut RustOption<*const core::ffi::c_void> as *mut Option<&'a T>) } + this } } -impl RustOption<*mut core::ffi::c_void> { - #[cfg(feature = "alloc")] - pub fn from_option_box_improper(other: Option>) -> Self { - let _: () = assert_option_safe::>(); - unsafe { core::mem::transmute::>, RustOption<*mut core::ffi::c_void>>(other) } +#[cfg(feature = "alloc")] +impl RustOption> { + pub fn into_raw(self) -> *mut T { + self.into_option() + .map_or(core::ptr::null_mut(), |v| Box::into_raw(v)) } - pub fn from_option_mut_improper<'a, T>(other: Option<&'a mut T>) -> Self { - let _: () = assert_option_safe::<&mut T>(); - unsafe { - core::mem::transmute::, RustOption<*mut core::ffi::c_void>>(other) - } + pub fn into_raw_improper(self) -> *mut core::ffi::c_void { + self.into_option().map_or(core::ptr::null_mut(), |v| { + Box::into_raw(v) as *mut core::ffi::c_void + }) } - pub fn from_option_mut_improper_pinned<'a, T>(other: Option>) -> Self { - let _: () = assert_option_safe::>(); - unsafe { - core::mem::transmute::>, RustOption<*mut core::ffi::c_void>>( - other, - ) + /// SAFETY: ptr must have originated from a `Option>` + pub unsafe fn from_raw(ptr: *mut T) -> Self { + let mut this = RustOption::new(); + if !ptr.is_null() { + this.set(unsafe { Box::from_raw(ptr) }); } + this } - /// SAFETY: self must have been constructed as `Option>` - #[cfg(feature = "alloc")] - pub unsafe fn into_option_box_improper(self) -> Option> { - let _: () = assert_option_safe::>(); - unsafe { core::mem::transmute::, Option>>(self) } - } - - /// SAFETY: self must have been constructed as `Option>` - #[cfg(feature = "alloc")] - pub unsafe fn as_mut_option_box_improper(&mut self) -> &mut Option> { - let _: () = assert_option_safe::>(); - unsafe { &mut *(self as *mut RustOption<*mut core::ffi::c_void> as *mut Option>) } - } - - /// SAFETY: Pointer must not be aliased and must have been constructed as an `Option<&mut T>` - pub unsafe fn into_option_mut_improper<'a, T>(self) -> Option<&'a mut T> { - let _: () = assert_option_safe::<&mut T>(); - unsafe { - core::mem::transmute::, Option<&'a mut T>>(self) + /// SAFETY: ptr must have originated from a `Option>` + pub unsafe fn from_raw_improper(ptr: *mut core::ffi::c_void) -> Self { + let mut this = RustOption::new(); + if !ptr.is_null() { + this.set(unsafe { Box::from_raw(ptr as *mut T) }); } - } - - /// SAFETY: Pointer must not be aliased and must have been constructed as an `Option<&mut T>` - pub unsafe fn as_mut_option_mut_improper<'a, T>(&mut self) -> &mut Option<&'a mut T> { - let _: () = assert_option_safe::<&mut T>(); - unsafe { &mut *(self as *mut RustOption<*mut core::ffi::c_void> as *mut Option<&'a mut T>) } + this } } #[cfg(feature = "alloc")] impl<'a, T> RustOption<&'a RustVec> { pub fn from_option_vec_ref(other: Option<&'a Vec>) -> Self { - let _: () = assert_option_safe::<&'a Vec>(); - match other { - None => Self::new(), - Some(r) => Self { - inner: OptionInner::new(RustVec::from_ref(r)), - }, + unsafe { + core::mem::transmute::>, RustOption<&RustVec>>(RustOption::from( + other, + )) } } pub fn into_option_vec_ref(self) -> Option<&'a Vec> { - let _: () = assert_option_safe::<&Vec>(); - match self.into_value() { - None => None, - Some(r) => Some(r.as_vec()), - } + unsafe { core::mem::transmute::>, RustOption<&Vec>>(self) } + .into_option() + } + + pub fn as_option_vec_ref(&self) -> &Option<&'a Vec> { + unsafe { &*(self as *const RustOption<&RustVec> as *const RustOption<&Vec>) } + .as_option() } - pub fn as_option_vec_ref(&mut self) -> &mut Option<&'a Vec> { - let _: () = assert_option_safe::<&Vec>(); - unsafe { &mut *(self as *mut RustOption<&'a RustVec> as *mut Option<&'a Vec>) } + pub fn as_option_vec_ref_mut(&mut self) -> &mut Option<&'a Vec> { + unsafe { &mut *(self as *mut RustOption<&RustVec> as *mut RustOption<&Vec>) } + .as_mut_option() } } #[cfg(feature = "alloc")] impl<'a, T> RustOption<&'a mut RustVec> { pub fn from_option_vec_mut(other: Option<&'a mut Vec>) -> Self { - let _: () = assert_option_safe::<&mut Vec>(); - match other { - None => Self::new(), - Some(r) => Self { - inner: OptionInner::new(RustVec::from_mut(r)), - }, + unsafe { + core::mem::transmute::>, RustOption<&mut RustVec>>( + RustOption::from(other), + ) } } pub fn into_option_vec_mut(self) -> Option<&'a mut Vec> { - let _: () = assert_option_safe::<&mut Vec>(); - match self.into_value() { - None => None, - Some(r) => Some(r.as_mut_vec()), + unsafe { + core::mem::transmute::>, RustOption<&mut Vec>>(self) + } + .into_option() + } + + pub fn as_option_vec_mut(&self) -> &Option<&'a mut Vec> { + unsafe { + &*(self as *const RustOption<&'a mut RustVec> as *const RustOption<&'a mut Vec>) } + .as_option() } - pub fn as_option_vec_mut(&mut self) -> &mut Option<&'a mut Vec> { - let _: () = assert_option_safe::<&mut Vec>(); + pub fn as_option_vec_mut_mut(&mut self) -> &mut Option<&'a mut Vec> { unsafe { - &mut *(self as *mut RustOption<&'a mut RustVec> as *mut Option<&'a mut Vec>) + &mut *(self as *mut RustOption<&'a mut RustVec> as *mut RustOption<&'a mut Vec>) } + .as_mut_option() } } #[cfg(feature = "alloc")] impl<'a> RustOption<&'a RustVec> { pub fn from_option_vec_string_ref(other: Option<&'a Vec>) -> Self { - let _: () = assert_option_safe::<&Vec>(); - match other { - None => Self::new(), - Some(r) => Self { - inner: OptionInner::new(RustVec::from_ref_vec_string(r)), - }, + unsafe { + core::mem::transmute::>, RustOption<&RustVec>>( + RustOption::from(other), + ) } } pub fn into_option_vec_string_ref(self) -> Option<&'a Vec> { - let _: () = assert_option_safe::<&Vec>(); - match self.into_value() { - None => None, - Some(r) => Some(r.as_vec_string()), + unsafe { + core::mem::transmute::>, RustOption<&Vec>>(self) } + .into_option() } - pub fn as_option_vec_string_ref(&mut self) -> &mut Option<&'a Vec> { - let _: () = assert_option_safe::<&Vec>(); + pub fn as_option_vec_string_ref_mut(&mut self) -> &mut Option<&'a Vec> { unsafe { - &mut *(self as *mut RustOption<&'a RustVec> as *mut Option<&'a Vec>) + &mut *(self as *mut RustOption<&RustVec> as *mut RustOption<&Vec>) } + .as_mut_option() } } #[cfg(feature = "alloc")] impl<'a> RustOption<&'a mut RustVec> { pub fn from_option_vec_string_mut(other: Option<&'a mut Vec>) -> Self { - let _: () = assert_option_safe::<&mut Vec>(); - match other { - None => Self::new(), - Some(r) => Self { - inner: OptionInner::new(RustVec::from_mut_vec_string(r)), - }, + unsafe { + core::mem::transmute::>, RustOption<&mut RustVec>>( + RustOption::from(other), + ) } } pub fn into_option_vec_string_mut(self) -> Option<&'a mut Vec> { - let _: () = assert_option_safe::<&mut Vec>(); - match self.into_value() { - None => None, - Some(r) => Some(r.as_mut_vec_string()), - } + unsafe { core::mem::transmute::>, RustOption<&mut Vec>>(self) }.into_option() } - pub fn as_option_vec_string_mut(&mut self) -> &mut Option<&'a mut Vec> { - let _: () = assert_option_safe::<&mut Vec>(); + pub fn as_option_vec_string_mut_mut(&mut self) -> &mut Option<&'a mut Vec> { unsafe { - &mut *(self as *mut RustOption<&'a mut RustVec> - as *mut Option<&'a mut Vec>) + core::mem::transmute::< + &mut RustOption<&mut RustVec>, + &mut RustOption<&mut Vec>, + >(self) + .as_mut_option() } } } @@ -494,53 +362,53 @@ impl<'a> RustOption<&'a mut RustVec> { #[cfg(feature = "alloc")] impl<'a> RustOption<&'a RustString> { pub fn from_option_string_ref(other: Option<&'a String>) -> Self { - let _: () = assert_option_safe::<&String>(); - match other { - None => Self::new(), - Some(r) => Self { - inner: OptionInner::new(RustString::from_ref(r)), - }, + unsafe { + core::mem::transmute::, RustOption<&RustString>>(RustOption::from( + other, + )) } } pub fn into_option_string_ref(self) -> Option<&'a String> { - let _: () = assert_option_safe::<&String>(); - match self.into_value() { - None => None, - Some(r) => Some(r.as_string()), - } + unsafe { core::mem::transmute::, RustOption<&String>>(self) } + .into_option() } - pub fn as_option_string_ref(&mut self) -> &mut Option<&'a String> { - let _: () = assert_option_safe::<&String>(); - unsafe { &mut *(self as *mut RustOption<&'a RustString> as *mut Option<&'a String>) } + pub fn as_option_string_ref_mut(&mut self) -> &mut Option<&'a String> { + unsafe { &mut *(self as *mut RustOption<&RustString> as *mut RustOption<&String>) } + .as_mut_option() } } #[cfg(feature = "alloc")] impl<'a> RustOption<&'a mut RustString> { pub fn from_option_string_mut(other: Option<&'a mut String>) -> Self { - let _: () = assert_option_safe::<&mut String>(); - match other { - None => Self::new(), - Some(r) => Self { - inner: OptionInner::new(RustString::from_mut(r)), - }, + unsafe { + core::mem::transmute::, RustOption<&mut RustString>>( + RustOption::from(other), + ) } } pub fn into_option_string_mut(self) -> Option<&'a mut String> { - let _: () = assert_option_safe::<&mut String>(); - match self.into_value() { - None => None, - Some(r) => Some(r.as_mut_string()), + unsafe { + core::mem::transmute::, RustOption<&mut String>>(self) } + .into_option() } - pub fn as_option_string_mut(&mut self) -> &mut Option<&'a mut String> { - let _: () = assert_option_safe::<&mut String>(); + pub fn as_option_string_mut_mut(&mut self) -> &mut Option<&'a mut String> { unsafe { - &mut *(self as *mut RustOption<&'a mut RustString> as *mut Option<&'a mut String>) + core::mem::transmute::<&mut RustOption<&mut RustString>, &mut RustOption<&mut String>>( + self, + ) + .as_mut_option() } } } + +impl Drop for RustOption { + fn drop(&mut self) { + self.as_mut_option().take(); + } +} diff --git a/src/symbols/rust_option.rs b/src/symbols/rust_option.rs index eeb3aad8c..4154ab8a5 100644 --- a/src/symbols/rust_option.rs +++ b/src/symbols/rust_option.rs @@ -18,49 +18,58 @@ macro_rules! rust_option_shims { const _: () = { #[export_name = concat!("cxxbridge1$rust_option$const$", $segment, "$new")] unsafe extern "C" fn __const_new(this: *mut RustOption<&$ty>) { - unsafe { ptr::write(this, RustOption::new()) }; + unsafe { ptr::write(this, RustOption::<&$ty>::new()) }; } #[export_name = concat!("cxxbridge1$rust_option$const$", $segment, "$drop")] unsafe extern "C" fn __const_drop(this: *mut RustOption<&$ty>) { unsafe { ptr::drop_in_place(this) } } #[export_name = concat!("cxxbridge1$rust_option$const$", $segment, "$has_value")] - unsafe extern "C" fn __const_has_value(this: *mut RustOption<&$ty>) -> bool { - unsafe { this.as_ref().unwrap().value().is_some() } + unsafe extern "C" fn __const_has_value(this: *const RustOption<&$ty>) -> bool { + let o: &RustOption<&$ty> = unsafe { this.as_ref().unwrap() }; + o.as_option().is_some() } - #[export_name = concat!("cxxbridge1$rust_option$const$", $segment, "$value_ptr")] - unsafe extern "C" fn __const_value_ptr(this: *mut RustOption<&$ty>) -> *mut &$ty { - unsafe { this.as_mut().unwrap().as_ref_mut_inner_unchecked() as _ } + #[export_name = concat!("cxxbridge1$rust_option$const$", $segment, "$value")] + unsafe extern "C" fn __const_value(this: *const RustOption<&$ty>) -> *const $ty { + unsafe { this.as_ref().unwrap().as_option().as_ref().copied().unwrap() as *const $ty } } #[export_name = concat!("cxxbridge1$rust_option$const$", $segment, "$set")] - unsafe extern "C" fn __const_set<'__cxx>( - this: *mut RustOption<&'__cxx $ty>, - value: *mut &'__cxx $ty, + unsafe extern "C" fn __const_set( + this: *mut RustOption<&$ty>, + value: *mut $ty, ) { - unsafe { this.as_mut().unwrap().set(*value) } + unsafe { this.as_mut().unwrap().set(&*value) } } #[export_name = concat!("cxxbridge1$rust_option$", $segment, "$new")] unsafe extern "C" fn __new(this: *mut RustOption<&mut $ty>) { - unsafe { ptr::write(this, RustOption::new()) } + unsafe { ptr::write(this, RustOption::<&mut $ty>::new()) } } #[export_name = concat!("cxxbridge1$rust_option$", $segment, "$drop")] unsafe extern "C" fn __drop(this: *mut RustOption<&mut $ty>) { unsafe { ptr::drop_in_place(this) } } #[export_name = concat!("cxxbridge1$rust_option$", $segment, "$has_value")] - unsafe extern "C" fn __has_value(this: *mut RustOption<&mut $ty>) -> bool { - unsafe { this.as_ref().unwrap().value().is_some() } + unsafe extern "C" fn __has_value(this: *const RustOption<&mut $ty>) -> bool { + let o: &RustOption<&mut $ty> = unsafe { this.as_ref().unwrap() }; + o.as_option().is_some() } - #[export_name = concat!("cxxbridge1$rust_option$", $segment, "$value_ptr")] - unsafe extern "C" fn __value_ptr(this: *mut RustOption<&mut $ty>) -> *mut &mut $ty { - unsafe { this.as_mut().unwrap().as_ref_mut_inner_unchecked() as _ } + #[export_name = concat!("cxxbridge1$rust_option$", $segment, "$value_const")] + unsafe extern "C" fn __value_const(this: *const RustOption<&mut $ty>) -> *const $ty { + let v: &$ty = unsafe { this.as_ref().unwrap().as_option().as_ref().unwrap() }; + v as *const $ty + } + #[export_name = concat!("cxxbridge1$rust_option$", $segment, "$value")] + unsafe extern "C" fn __value(this: *mut RustOption<&mut $ty>) -> *mut $ty { + let this = unsafe { this.as_mut().unwrap() }; + let ptr = this.as_mut_option().as_mut().unwrap(); + *ptr as _ } #[export_name = concat!("cxxbridge1$rust_option$", $segment, "$set")] - unsafe extern "C" fn __set<'__cxx>( - this: *mut RustOption<&'__cxx mut $ty>, - value: *mut &'__cxx mut $ty, + unsafe extern "C" fn __set( + this: *mut RustOption<&mut $ty>, + value: *mut $ty, ) { - unsafe { this.as_mut().unwrap().set(*value) } + unsafe { this.as_mut().unwrap().set(&mut *value) } } }; #[cfg(feature = "alloc")] @@ -68,49 +77,57 @@ macro_rules! rust_option_shims { /* Vec impl */ #[export_name = concat!("cxxbridge1$rust_option$const$rust_vec$", $segment, "$new")] unsafe extern "C" fn __const_new(this: *mut RustOption<&RustVec<$ty>>) { - unsafe { ptr::write(this, RustOption::new()) }; + unsafe { ptr::write(this, RustOption::<&RustVec<$ty>>::new()) }; } #[export_name = concat!("cxxbridge1$rust_option$const$rust_vec$", $segment, "$drop")] unsafe extern "C" fn __const_drop(this: *mut RustOption<&RustVec<$ty>>) { unsafe { ptr::drop_in_place(this) } } #[export_name = concat!("cxxbridge1$rust_option$const$rust_vec$", $segment, "$has_value")] - unsafe extern "C" fn __const_has_value(this: *mut RustOption<&RustVec<$ty>>) -> bool { - unsafe { this.as_ref().unwrap().value().is_some() } + unsafe extern "C" fn __const_has_value(this: *const RustOption<&RustVec<$ty>>) -> bool { + let o: &RustOption<&RustVec<$ty>> = unsafe { this.as_ref().unwrap() }; + o.as_option_vec_ref().is_some() } - #[export_name = concat!("cxxbridge1$rust_option$const$rust_vec$", $segment, "$value_ptr")] - unsafe extern "C" fn __const_value_ptr(this: *mut RustOption<&RustVec<$ty>>) -> *mut &RustVec<$ty> { - unsafe { this.as_mut().unwrap().as_ref_mut_inner_unchecked() as _ } + #[export_name = concat!("cxxbridge1$rust_option$const$rust_vec$", $segment, "$value")] + unsafe extern "C" fn __const_value(this: *const RustOption<&RustVec<$ty>>) -> *const RustVec<$ty> { + unsafe { this.as_ref().unwrap().as_option().as_ref().copied().unwrap() as *const RustVec<$ty> } } #[export_name = concat!("cxxbridge1$rust_option$const$rust_vec$", $segment, "$set")] - unsafe extern "C" fn __const_set<'__cxx>( - this: *mut RustOption<&'__cxx RustVec<$ty>>, - value: *mut &'__cxx RustVec<$ty>, + unsafe extern "C" fn __const_set( + this: *mut RustOption<&RustVec<$ty>>, + value: *mut RustVec<$ty>, ) { - unsafe { this.as_mut().unwrap().set(*value) } + unsafe { this.as_mut().unwrap().as_option_vec_ref_mut().replace((&*value).as_vec()); } } #[export_name = concat!("cxxbridge1$rust_option$rust_vec$", $segment, "$new")] unsafe extern "C" fn __new(this: *mut RustOption<&mut RustVec<$ty>>) { - unsafe { ptr::write(this, RustOption::new()) } + unsafe { ptr::write(this, RustOption::<&mut RustVec<$ty>>::new()) } } #[export_name = concat!("cxxbridge1$rust_option$rust_vec$", $segment, "$drop")] unsafe extern "C" fn __drop(this: *mut RustOption<&mut RustVec<$ty>>) { unsafe { ptr::drop_in_place(this) } } #[export_name = concat!("cxxbridge1$rust_option$rust_vec$", $segment, "$has_value")] - unsafe extern "C" fn __has_value(this: *mut RustOption<&mut RustVec<$ty>>) -> bool { - unsafe { this.as_ref().unwrap().value().is_some() } + unsafe extern "C" fn __has_value(this: *const RustOption<&mut RustVec<$ty>>) -> bool { + let o: &RustOption<&mut RustVec<$ty>> = unsafe { this.as_ref().unwrap() }; + o.as_option_vec_mut().is_some() + } + #[export_name = concat!("cxxbridge1$rust_option$rust_vec$", $segment, "$value_const")] + unsafe extern "C" fn __value_const(this: *const RustOption<&mut RustVec<$ty>>) -> *const RustVec<$ty> { + let v: &alloc::vec::Vec<_> = unsafe { this.as_ref().unwrap().as_option_vec_mut().as_ref().unwrap() }; + v as *const alloc::vec::Vec<$ty> as *const RustVec<$ty> } - #[export_name = concat!("cxxbridge1$rust_option$rust_vec$", $segment, "$value_ptr")] - unsafe extern "C" fn __value_ptr(this: *mut RustOption<&mut RustVec<$ty>>) -> *mut &mut RustVec<$ty> { - unsafe { this.as_mut().unwrap().as_ref_mut_inner_unchecked() as _ } + #[export_name = concat!("cxxbridge1$rust_option$rust_vec$", $segment, "$value")] + unsafe extern "C" fn __value(this: *mut RustOption<&mut RustVec<$ty>>) -> *mut RustVec<$ty> { + let ptr = unsafe { this.as_mut().unwrap().as_option_vec_mut_mut().as_mut().unwrap() }; + *ptr as *mut alloc::vec::Vec<$ty> as *mut RustVec<$ty> } #[export_name = concat!("cxxbridge1$rust_option$rust_vec$", $segment, "$set")] - unsafe extern "C" fn __set<'__cxx>( - this: *mut RustOption<&'__cxx mut RustVec<$ty>>, - value: *mut &'__cxx mut RustVec<$ty>, + unsafe extern "C" fn __set( + this: *mut RustOption<&mut RustVec<$ty>>, + value: *mut RustVec<$ty>, ) { - unsafe { this.as_mut().unwrap().set(*value) } + unsafe { this.as_mut().unwrap().as_option_vec_mut_mut().replace((&mut *value).as_mut_vec()); } } }; }; diff --git a/syntax/types.rs b/syntax/types.rs index 237eaec69..a82ef29bb 100644 --- a/syntax/types.rs +++ b/syntax/types.rs @@ -244,7 +244,7 @@ impl<'a> Types<'a> { pub(crate) fn needs_indirect_abi(&self, ty: &Type) -> bool { match ty { - Type::RustBox(_) | Type::UniquePtr(_) => false, + Type::RustBox(_) | Type::UniquePtr(_) | Type::RustOption(_) => false, Type::Array(_) => true, _ => !self.is_guaranteed_pod(ty), } diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 84e8e06c7..714816a4d 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -6,9 +6,4 @@ fn ui() { let check = trybuild::TestCases::new(); check.compile_fail("tests/ui/*.rs"); - // Tests that require cargo build instead of cargo check - let build = trybuild::TestCases::new(); - // Having passing cases forces cargo build instead of cargo check - build.pass("tests/ui_pass/*.rs"); - build.compile_fail("tests/ui_build/*.rs"); } diff --git a/tests/ffi/lib.rs b/tests/ffi/lib.rs index d38efee51..4f126121b 100644 --- a/tests/ffi/lib.rs +++ b/tests/ffi/lib.rs @@ -169,6 +169,7 @@ pub mod ffi { fn c_take_unique_ptr_vector_shared(v: UniquePtr>); fn c_take_ref_vector(v: &CxxVector); fn c_take_rust_vec(v: Vec); + fn c_take_rust_vec_char(v: Vec); fn c_take_rust_vec_shared(v: Vec); fn c_take_rust_vec_string(v: Vec); fn c_take_rust_vec_index(v: Vec); @@ -191,6 +192,10 @@ pub mod ffi { fn c_take_rust_pin_mut_option_opaque(rust: Option>); fn c_take_rust_ref_option_native(rust: Option<&u8>); fn c_take_rust_mut_option_native(rust: Option<&mut u8>); + fn c_take_rust_ref_option_bool(rust: Option<&bool>); + fn c_take_rust_mut_option_bool(rust: Option<&mut bool>); + fn c_take_rust_ref_option_char(rust: Option<&c_char>); + fn c_take_rust_mut_option_char(rust: Option<&mut c_char>); fn c_take_rust_pin_mut_option_native(rust: Option>); fn c_take_rust_ref_option_vec_native(rust: Option<&Vec>); fn c_take_rust_mut_option_vec_native(rust: Option<&mut Vec>); diff --git a/tests/ffi/tests.cc b/tests/ffi/tests.cc index d29650383..e91526af1 100644 --- a/tests/ffi/tests.cc +++ b/tests/ffi/tests.cc @@ -188,107 +188,108 @@ rust::Option> c_return_rust_option_box() { return opt2; } -rust::Option c_return_rust_ref_option_shared(const Shared& s) { - rust::Option opt; // Default constructor - opt.set(&s); // Set value - rust::Option opt2(std::move(opt)); // Move constructor +rust::Option c_return_rust_ref_option_shared(const Shared& s) { + rust::Option opt; // Default constructor + opt.set(s); // Set value + rust::Option opt2(std::move(opt)); // Move constructor + rust::Option opt3(opt); // Copy constructor + return opt2; // Not nulled out from copy +} + +rust::Option c_return_rust_mut_option_shared(Shared& s) { + rust::Option opt; // Default constructor + opt.set(s); // Set value + rust::Option opt2(std::move(opt)); // Move constructor return opt2; } -rust::Option c_return_rust_mut_option_shared(Shared& s) { - rust::Option opt; // Default constructor - opt.set(&s); // Set value - rust::Option opt2(std::move(opt)); // Move constructor +rust::Option c_return_rust_pin_mut_option_shared(Shared& s) { + rust::Option opt; // Default constructor + opt.set(s); // Set value + rust::Option opt2(std::move(opt)); // Move constructor return opt2; } -rust::Option c_return_rust_pin_mut_option_shared(Shared& s) { - rust::Option opt; // Default constructor - opt.set(&s); // Set value - rust::Option opt2(std::move(opt)); // Move constructor +rust::Option c_return_rust_ref_option_opaque(const C& c) { + rust::Option opt; // Default constructor + opt.set(c); // Set value + rust::Option opt2(std::move(opt)); // Move constructor return opt2; } -rust::Option c_return_rust_ref_option_opaque(const C& c) { - rust::Option opt; // Default constructor - opt.set(&c); // Set value - rust::Option opt2(std::move(opt)); // Move constructor +rust::Option c_return_rust_pin_mut_option_opaque(C& c) { + rust::Option opt; // Default constructor + opt.set(c); // Set value + rust::Option opt2(std::move(opt)); // Move constructor return opt2; } -rust::Option c_return_rust_pin_mut_option_opaque(C& c) { - rust::Option opt; // Default constructor - opt.set(&c); // Set value - rust::Option opt2(std::move(opt)); // Move constructor +rust::Option c_return_rust_ref_option_native(const uint8_t& u) { + rust::Option opt; // Default constructor + opt.set(u); // Set value + rust::Option opt2(std::move(opt)); // Move constructor return opt2; } -rust::Option c_return_rust_ref_option_native(const uint8_t& u) { - rust::Option opt; // Default constructor - opt.set(&u); // Set value - rust::Option opt2(std::move(opt)); // Move constructor +rust::Option c_return_rust_mut_option_native(uint8_t& u) { + rust::Option opt; // Default constructor + opt.set(u); // Set value + rust::Option opt2(std::move(opt)); // Move constructor return opt2; } -rust::Option c_return_rust_mut_option_native(uint8_t& u) { - rust::Option opt; // Default constructor - opt.set(&u); // Set value - rust::Option opt2(std::move(opt)); // Move constructor +rust::Option c_return_rust_pin_mut_option_native(uint8_t& u) { + rust::Option opt; // Default constructor + opt.set(u); // Set value + rust::Option opt2(std::move(opt)); // Move constructor return opt2; } -rust::Option c_return_rust_pin_mut_option_native(uint8_t& u) { - rust::Option opt; // Default constructor - opt.set(&u); // Set value - rust::Option opt2(std::move(opt)); // Move constructor - return opt2; -} - -rust::Option*> c_return_rust_ref_option_vec_native(const rust::Vec& v) { - rust::Option*> opt; // Default constructor - opt.set(&v); // Set value +rust::Option&> c_return_rust_ref_option_vec_native(const rust::Vec& v) { + rust::Option&> opt; // Default constructor + opt.set(v); // Set value return opt; } -rust::Option*> c_return_rust_mut_option_vec_native(rust::Vec& v) { - rust::Option*> opt; // Default constructor - opt.set(&v); // Set value +rust::Option&> c_return_rust_mut_option_vec_native(rust::Vec& v) { + rust::Option&> opt; // Default constructor + opt.set(v); // Set value return opt; } -rust::Option*> c_return_rust_ref_option_vec_shared(const rust::Vec& v) { - rust::Option*> opt; // Default constructor - opt.set(&v); // Set value +rust::Option&> c_return_rust_ref_option_vec_shared(const rust::Vec& v) { + rust::Option&> opt; // Default constructor + opt.set(v); // Set value return opt; } -rust::Option*> c_return_rust_mut_option_vec_shared(rust::Vec& v) { - rust::Option*> opt; // Default constructor - opt.set(&v); // Set value +rust::Option&> c_return_rust_mut_option_vec_shared(rust::Vec& v) { + rust::Option&> opt; // Default constructor + opt.set(v); // Set value return opt; } -rust::Option*> c_return_rust_ref_option_vec_string(const rust::Vec& v) { - rust::Option*> opt; // Default constructor - opt.set(&v); // Set value +rust::Option&> c_return_rust_ref_option_vec_string(const rust::Vec& v) { + rust::Option&> opt; // Default constructor + opt.set(v); // Set value return opt; } -rust::Option*> c_return_rust_mut_option_vec_string(rust::Vec& v) { - rust::Option*> opt; // Default constructor - opt.set(&v); // Set value +rust::Option&> c_return_rust_mut_option_vec_string(rust::Vec& v) { + rust::Option&> opt; // Default constructor + opt.set(v); // Set value return opt; } -rust::Option c_return_rust_ref_option_string(const rust::String& s) { - rust::Option opt; // Default constructor - opt.set(&s); // Set value +rust::Option c_return_rust_ref_option_string(const rust::String& s) { + rust::Option opt; // Default constructor + opt.set(s); // Set value return opt; } -rust::Option c_return_rust_mut_option_string(rust::String& s) { - rust::Option opt; // Default constructor - opt.set(&s); // Set value +rust::Option c_return_rust_mut_option_string(rust::String& s) { + rust::Option opt; // Default constructor + opt.set(s); // Set value return opt; } @@ -486,6 +487,12 @@ void c_take_ref_vector(const std::vector &v) { void c_take_rust_vec(rust::Vec v) { c_take_ref_rust_vec(v); } +void c_take_rust_vec_char(rust::Vec v) { + if (v.size() == 1 && v[0] == 'a') { + cxx_test_suite_set_correct(); + } +} + void c_take_rust_vec_index(rust::Vec v) { try { v.at(100); @@ -621,117 +628,141 @@ void c_take_ref_rust_vec_copy(const rust::Vec &v) { } void c_take_rust_option_box(rust::Option> opt) { - if (opt.has_value() && opt.value()->z == 2020) { + if (opt.has_value() && opt.value()->z == 2020 && (*opt)->z == 2020) { cxx_test_suite_set_correct(); } } -void c_take_rust_ref_option_shared(rust::Option opt) { - if (opt.has_value() && opt.value()->z == 2020) { +void c_take_rust_ref_option_shared(rust::Option opt) { + if (opt.has_value() && opt.value().z == 2020 && opt->z == 2020 && (*opt).z == 2020) { cxx_test_suite_set_correct(); } } -void c_take_rust_mut_option_shared(rust::Option opt) { - if (opt.has_value() && opt.value()->z == 2020) { - opt.value()->z = 2021; +void c_take_rust_mut_option_shared(rust::Option opt) { + if (opt.has_value() && opt.value().z == 2020 && opt->z == 2020 && (*opt).z == 2020) { cxx_test_suite_set_correct(); } } -void c_take_rust_pin_mut_option_shared(rust::Option opt) { - if (opt.has_value() && opt.value()->z == 2020) { - opt.value()->z = 2021; +void c_take_rust_pin_mut_option_shared(rust::Option opt) { + if (opt.has_value() && opt.value().z == 2020) { cxx_test_suite_set_correct(); } } -void c_take_rust_ref_option_opaque(rust::Option opt) { +void c_take_rust_ref_option_opaque(rust::Option opt) { if (opt.has_value()) { cxx_test_suite_set_correct(); } } -void c_take_rust_mut_option_opaque(rust::Option opt) { +void c_take_rust_mut_option_opaque(rust::Option opt) { if (opt.has_value()) { cxx_test_suite_set_correct(); } } -void c_take_rust_pin_mut_option_opaque(rust::Option opt) { +void c_take_rust_pin_mut_option_opaque(rust::Option opt) { if (opt.has_value()) { cxx_test_suite_set_correct(); } } -void c_take_rust_ref_option_native(rust::Option opt) { - if (opt.has_value() && *(opt.value()) == 200) { +void c_take_rust_ref_option_native(rust::Option opt) { + if (opt.has_value() && opt.value() == 200) { cxx_test_suite_set_correct(); } } -void c_take_rust_mut_option_native(rust::Option opt) { - if (opt.has_value() && *(opt.value()) == 200) { - *(opt.value()) = 201; +void c_take_rust_mut_option_native(rust::Option opt) { + if (opt.has_value() && opt.value() == 200) { cxx_test_suite_set_correct(); } } -void c_take_rust_pin_mut_option_native(rust::Option opt) { - if (opt.has_value() && *(opt.value()) == 200) { - *(opt.value()) = 201; +void c_take_rust_ref_option_bool(rust::Option opt) { + if (opt.has_value() && opt.value()) { cxx_test_suite_set_correct(); } } -void c_take_rust_ref_option_vec_shared(rust::Option*> opt) { - if (opt.has_value() && opt.value()->size() == 1 && (*opt.value())[0].z == 2020) { +void c_take_rust_mut_option_bool(rust::Option opt) { + if (opt.has_value() && opt.value()) { cxx_test_suite_set_correct(); } } -void c_take_rust_mut_option_vec_shared(rust::Option*> opt) { - if (opt.has_value() && opt.value()->size() == 1 && (*opt.value())[0].z == 2020) { - (*opt.value())[0].z = 43; +void c_take_rust_ref_option_char(rust::Option opt) { + if (opt.has_value() && opt.value() == 'a') { cxx_test_suite_set_correct(); } } -void c_take_rust_ref_option_vec_native(rust::Option*> opt) { - if (opt.has_value() && opt.value()->size() == 1 && (*(opt.value()))[0] == 200) { +void c_take_rust_mut_option_char(rust::Option opt) { + if (opt.has_value() && opt.value() == 'a') { + cxx_test_suite_set_correct(); + } +} +void c_take_rust_pin_mut_option_native(rust::Option opt) { + if (opt.has_value() && opt.value() == 200) { cxx_test_suite_set_correct(); } } -void c_take_rust_mut_option_vec_native(rust::Option*> opt) { - if (opt.has_value() && opt.value()->size() == 1 && (*(opt.value()))[0] == 200) { - (*opt.value())[0] = 201; +void c_take_rust_ref_option_vec_shared(rust::Option&> opt) { + if (opt.has_value() && opt.value().size() == 1 && opt.value()[0].z == 2020) { cxx_test_suite_set_correct(); } } -void c_take_rust_ref_option_vec_string(rust::Option*> opt) { - if (opt.has_value() && opt.value()->size() == 1 && (*(opt.value()))[0] == "2020") { +void c_take_rust_mut_option_vec_shared(rust::Option&> opt) { + if (opt.has_value()) { + auto& vec = opt.value(); + if (vec.size() == 1 && vec[0].z == 2020) { + cxx_test_suite_set_correct(); + } + } +} + +void c_take_rust_ref_option_vec_native(rust::Option&> opt) { + if (opt.has_value() && opt.value().size() == 1 && opt.value()[0] == 200) { cxx_test_suite_set_correct(); } } -void c_take_rust_mut_option_vec_string(rust::Option*> opt) { - if (opt.has_value() && opt.value()->size() == 1 && (*(opt.value()))[0] == "2020") { - (*opt.value())[0] = "2021"; +void c_take_rust_mut_option_vec_native(rust::Option&> opt) { + if (opt.has_value()) { + auto& vec = opt.value(); + if (vec.size() == 1 && vec[0] == 200) { + cxx_test_suite_set_correct(); + } + } +} + +void c_take_rust_ref_option_vec_string(rust::Option&> opt) { + if (opt.has_value() && opt.value().size() == 1 && opt.value()[0] == "2020") { cxx_test_suite_set_correct(); } } -void c_take_rust_ref_option_string(rust::Option opt) { - if (opt.has_value() && (*(opt.value())) == "2020") { +void c_take_rust_mut_option_vec_string(rust::Option&> opt) { + if (opt.has_value()) { + auto& vec = opt.value(); + if (vec.size() == 1 && vec[0] == "2020") { + cxx_test_suite_set_correct(); + } + } +} + +void c_take_rust_ref_option_string(rust::Option opt) { + if (opt.has_value() && opt.value() == "2020") { cxx_test_suite_set_correct(); } } -void c_take_rust_mut_option_string(rust::Option opt) { - if (opt.has_value() && *(opt.value()) == "2020") { - *(opt.value()) = "2021"; +void c_take_rust_mut_option_string(rust::Option opt) { + if (opt.has_value() && opt.value() == "2020") { cxx_test_suite_set_correct(); } } @@ -795,67 +826,67 @@ rust::Option> c_try_return_rust_option_box() { throw std::runtime_error("unimplemented"); } -rust::Option c_try_return_rust_ref_option_shared() { +rust::Option c_try_return_rust_ref_option_shared() { throw std::runtime_error("unimplemented"); } -rust::Option c_try_return_rust_mut_option_shared() { +rust::Option c_try_return_rust_mut_option_shared() { throw std::runtime_error("unimplemented"); } -rust::Option c_try_return_rust_pin_mut_option_shared() { +rust::Option c_try_return_rust_pin_mut_option_shared() { throw std::runtime_error("unimplemented"); } -rust::Option c_try_return_rust_ref_option_opaque() { +rust::Option c_try_return_rust_ref_option_opaque() { throw std::runtime_error("unimplemented"); } -rust::Option c_try_return_rust_pin_mut_option_opaque() { +rust::Option c_try_return_rust_pin_mut_option_opaque() { throw std::runtime_error("unimplemented"); } -rust::Option c_try_return_rust_ref_option_native() { +rust::Option c_try_return_rust_ref_option_native() { throw std::runtime_error("unimplemented"); } -rust::Option c_try_return_rust_mut_option_native() { +rust::Option c_try_return_rust_mut_option_native() { throw std::runtime_error("unimplemented"); } -rust::Option c_try_return_rust_pin_mut_option_native() { +rust::Option c_try_return_rust_pin_mut_option_native() { throw std::runtime_error("unimplemented"); } -rust::Option*> c_try_return_rust_ref_option_vec_native() { +rust::Option&> c_try_return_rust_ref_option_vec_native() { throw std::runtime_error("unimplemented"); } -rust::Option*> c_try_return_rust_mut_option_vec_native() { +rust::Option&> c_try_return_rust_mut_option_vec_native() { throw std::runtime_error("unimplemented"); } -rust::Option*> c_try_return_rust_ref_option_vec_shared() { +rust::Option&> c_try_return_rust_ref_option_vec_shared() { throw std::runtime_error("unimplemented"); } -rust::Option*> c_try_return_rust_mut_option_vec_shared() { +rust::Option&> c_try_return_rust_mut_option_vec_shared() { throw std::runtime_error("unimplemented"); } -rust::Option*> c_try_return_rust_ref_option_vec_string() { +rust::Option&> c_try_return_rust_ref_option_vec_string() { throw std::runtime_error("unimplemented"); } -rust::Option*> c_try_return_rust_mut_option_vec_string() { +rust::Option&> c_try_return_rust_mut_option_vec_string() { throw std::runtime_error("unimplemented"); } -rust::Option c_try_return_rust_ref_option_string() { +rust::Option c_try_return_rust_ref_option_string() { throw std::runtime_error("unimplemented"); } -rust::Option c_try_return_rust_mut_option_string() { +rust::Option c_try_return_rust_mut_option_string() { throw std::runtime_error("unimplemented"); } @@ -1202,8 +1233,8 @@ extern "C" const char *cxx_run_test() noexcept { ASSERT(!opt.has_value()); ASSERT(opt2.has_value()); ASSERT(sizeof(rust::Option>) == sizeof(void *)); - ASSERT(sizeof(rust::Option) == sizeof(void *)); - ASSERT(sizeof(rust::Option) == sizeof(void *)); + ASSERT(sizeof(rust::Option) == sizeof(void *)); + ASSERT(sizeof(rust::Option) == sizeof(void *)); cxx_test_suite_set_correct(); return nullptr; diff --git a/tests/ffi/tests.h b/tests/ffi/tests.h index 0b5eacf6e..8a6a76ed1 100644 --- a/tests/ffi/tests.h +++ b/tests/ffi/tests.h @@ -117,22 +117,22 @@ rust::Vec &c_return_mut_rust_vec(C &c); rust::Vec c_return_rust_vec_string(); rust::Vec c_return_rust_vec_bool(); rust::Option> c_return_rust_option_box(); -rust::Option c_return_rust_ref_option_shared(const Shared&); -rust::Option c_return_rust_mut_option_shared(Shared&); -rust::Option c_return_rust_pin_mut_option_shared(Shared&); -rust::Option c_return_rust_ref_option_opaque(const C&); -rust::Option c_return_rust_pin_mut_option_opaque(C&); -rust::Option c_return_rust_ref_option_native(const uint8_t&); -rust::Option c_return_rust_mut_option_native(uint8_t&); -rust::Option c_return_rust_pin_mut_option_native(uint8_t&); -rust::Option*> c_return_rust_ref_option_vec_native(const rust::Vec&); -rust::Option*> c_return_rust_mut_option_vec_native(rust::Vec&); -rust::Option*> c_return_rust_ref_option_vec_shared(const rust::Vec&); -rust::Option*> c_return_rust_mut_option_vec_shared(rust::Vec&); -rust::Option*> c_return_rust_ref_option_vec_string(const rust::Vec&); -rust::Option*> c_return_rust_mut_option_vec_string(rust::Vec&); -rust::Option c_return_rust_ref_option_string(const rust::String&); -rust::Option c_return_rust_mut_option_string(rust::String&); +rust::Option c_return_rust_ref_option_shared(const Shared&); +rust::Option c_return_rust_mut_option_shared(Shared&); +rust::Option c_return_rust_pin_mut_option_shared(Shared&); +rust::Option c_return_rust_ref_option_opaque(const C&); +rust::Option c_return_rust_pin_mut_option_opaque(C&); +rust::Option c_return_rust_ref_option_native(const uint8_t&); +rust::Option c_return_rust_mut_option_native(uint8_t&); +rust::Option c_return_rust_pin_mut_option_native(uint8_t&); +rust::Option&> c_return_rust_ref_option_vec_native(const rust::Vec&); +rust::Option&> c_return_rust_mut_option_vec_native(rust::Vec&); +rust::Option&> c_return_rust_ref_option_vec_shared(const rust::Vec&); +rust::Option&> c_return_rust_mut_option_vec_shared(rust::Vec&); +rust::Option&> c_return_rust_ref_option_vec_string(const rust::Vec&); +rust::Option&> c_return_rust_mut_option_vec_string(rust::Vec&); +rust::Option c_return_rust_ref_option_string(const rust::String&); +rust::Option c_return_rust_mut_option_string(rust::String&); size_t c_return_identity(size_t n); size_t c_return_sum(size_t n1, size_t n2); Enum c_return_enum(uint16_t n); @@ -166,6 +166,7 @@ void c_take_unique_ptr_vector_string( void c_take_unique_ptr_vector_shared(std::unique_ptr> v); void c_take_ref_vector(const std::vector &v); void c_take_rust_vec(rust::Vec v); +void c_take_rust_vec_char(rust::Vec v); void c_take_rust_vec_index(rust::Vec v); void c_take_rust_vec_shared(rust::Vec v); void c_take_rust_vec_ns_shared(rust::Vec<::A::AShared> v); @@ -182,23 +183,27 @@ void c_take_ref_rust_vec_string(const rust::Vec &v); void c_take_ref_rust_vec_index(const rust::Vec &v); void c_take_ref_rust_vec_copy(const rust::Vec &v); void c_take_rust_option_box(rust::Option>); -void c_take_rust_ref_option_shared(rust::Option); -void c_take_rust_mut_option_shared(rust::Option); -void c_take_rust_pin_mut_option_shared(rust::Option); -void c_take_rust_ref_option_opaque(rust::Option); -void c_take_rust_mut_option_opaque(rust::Option); -void c_take_rust_pin_mut_option_opaque(rust::Option); -void c_take_rust_ref_option_native(rust::Option); -void c_take_rust_mut_option_native(rust::Option); -void c_take_rust_pin_mut_option_native(rust::Option); -void c_take_rust_ref_option_vec_native(rust::Option*>); -void c_take_rust_mut_option_vec_native(rust::Option*>); -void c_take_rust_ref_option_vec_shared(rust::Option*>); -void c_take_rust_mut_option_vec_shared(rust::Option*>); -void c_take_rust_ref_option_vec_string(rust::Option*>); -void c_take_rust_mut_option_vec_string(rust::Option*>); -void c_take_rust_ref_option_string(rust::Option); -void c_take_rust_mut_option_string(rust::Option); +void c_take_rust_ref_option_shared(rust::Option); +void c_take_rust_mut_option_shared(rust::Option); +void c_take_rust_pin_mut_option_shared(rust::Option); +void c_take_rust_ref_option_opaque(rust::Option); +void c_take_rust_mut_option_opaque(rust::Option); +void c_take_rust_pin_mut_option_opaque(rust::Option); +void c_take_rust_ref_option_native(rust::Option); +void c_take_rust_mut_option_native(rust::Option); +void c_take_rust_ref_option_bool(rust::Option); +void c_take_rust_mut_option_bool(rust::Option); +void c_take_rust_ref_option_char(rust::Option); +void c_take_rust_mut_option_char(rust::Option); +void c_take_rust_pin_mut_option_native(rust::Option); +void c_take_rust_ref_option_vec_native(rust::Option&>); +void c_take_rust_mut_option_vec_native(rust::Option&>); +void c_take_rust_ref_option_vec_shared(rust::Option&>); +void c_take_rust_mut_option_vec_shared(rust::Option&>); +void c_take_rust_ref_option_vec_string(rust::Option&>); +void c_take_rust_mut_option_vec_string(rust::Option&>); +void c_take_rust_ref_option_string(rust::Option); +void c_take_rust_mut_option_string(rust::Option); const SharedString &c_take_ref_shared_string(const SharedString &s); void c_take_callback(rust::Fn callback); void c_take_callback_ref(rust::Fn callback); @@ -223,22 +228,22 @@ rust::Vec c_try_return_rust_vec(); rust::Vec c_try_return_rust_vec_string(); const rust::Vec &c_try_return_ref_rust_vec(const C &c); rust::Option> c_try_return_rust_option_box(); -rust::Option c_try_return_rust_ref_option_shared(); -rust::Option c_try_return_rust_mut_option_shared(); -rust::Option c_try_return_rust_pin_mut_option_shared(); -rust::Option c_try_return_rust_ref_option_opaque(); -rust::Option c_try_return_rust_pin_mut_option_opaque(); -rust::Option c_try_return_rust_ref_option_native(); -rust::Option c_try_return_rust_mut_option_native(); -rust::Option c_try_return_rust_pin_mut_option_native(); -rust::Option*> c_try_return_rust_ref_option_vec_native(); -rust::Option*> c_try_return_rust_mut_option_vec_native(); -rust::Option*> c_try_return_rust_ref_option_vec_shared(); -rust::Option*> c_try_return_rust_mut_option_vec_shared(); -rust::Option*> c_try_return_rust_ref_option_vec_string(); -rust::Option*> c_try_return_rust_mut_option_vec_string(); -rust::Option c_try_return_rust_ref_option_string(); -rust::Option c_try_return_rust_mut_option_string(); +rust::Option c_try_return_rust_ref_option_shared(); +rust::Option c_try_return_rust_mut_option_shared(); +rust::Option c_try_return_rust_pin_mut_option_shared(); +rust::Option c_try_return_rust_ref_option_opaque(); +rust::Option c_try_return_rust_pin_mut_option_opaque(); +rust::Option c_try_return_rust_ref_option_native(); +rust::Option c_try_return_rust_mut_option_native(); +rust::Option c_try_return_rust_pin_mut_option_native(); +rust::Option&> c_try_return_rust_ref_option_vec_native(); +rust::Option&> c_try_return_rust_mut_option_vec_native(); +rust::Option&> c_try_return_rust_ref_option_vec_shared(); +rust::Option&> c_try_return_rust_mut_option_vec_shared(); +rust::Option&> c_try_return_rust_ref_option_vec_string(); +rust::Option&> c_try_return_rust_mut_option_vec_string(); +rust::Option c_try_return_rust_ref_option_string(); +rust::Option c_try_return_rust_mut_option_string(); size_t c_get_use_count(const std::weak_ptr &weak) noexcept; diff --git a/tests/test.rs b/tests/test.rs index 70c476a07..e035e593f 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -231,6 +231,7 @@ fn test_c_take() { check!(ffi::c_take_ref_vector(&ffi::c_return_unique_ptr_vector_u8())); let test_vec = [86_u8, 75_u8, 30_u8, 9_u8].to_vec(); check!(ffi::c_take_rust_vec(test_vec.clone())); + check!(ffi::c_take_rust_vec_char(vec![97])); // 'a' check!(ffi::c_take_rust_vec_index(test_vec.clone())); let shared_test_vec = vec![ffi::Shared { z: 1010 }, ffi::Shared { z: 1011 }]; check!(ffi::c_take_rust_vec_shared(shared_test_vec.clone())); @@ -282,6 +283,10 @@ fn test_c_take() { )))); check!(ffi::c_take_rust_ref_option_native(Some(&200))); check!(ffi::c_take_rust_mut_option_native(Some(&mut 200))); + check!(ffi::c_take_rust_ref_option_bool(Some(&true))); + check!(ffi::c_take_rust_mut_option_bool(Some(&mut true))); + check!(ffi::c_take_rust_ref_option_char(Some(&97))); // 'a' + check!(ffi::c_take_rust_mut_option_char(Some(&mut 97))); check!(ffi::c_take_rust_pin_mut_option_native(Some(Pin::new( &mut 200 )))); diff --git a/tests/ui_build/option_not_sized.rs b/tests/ui/option_not_sized.rs similarity index 100% rename from tests/ui_build/option_not_sized.rs rename to tests/ui/option_not_sized.rs diff --git a/tests/ui_build/option_not_sized.stderr b/tests/ui/option_not_sized.stderr similarity index 85% rename from tests/ui_build/option_not_sized.stderr rename to tests/ui/option_not_sized.stderr index a7b5e8b84..888e32c87 100644 --- a/tests/ui_build/option_not_sized.stderr +++ b/tests/ui/option_not_sized.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time - --> tests/ui_build/option_not_sized.rs:2:14 + --> tests/ui/option_not_sized.rs:2:14 | 2 | const _: cxx::RustOption::<&dyn core::fmt::Debug> = cxx::RustOption::<&dyn core::fmt::Debug>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -8,8 +8,6 @@ error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be know = help: the following other types implement trait `cxx::rust_option::OptionTarget`: Box Pin<&mut T> - *const T - *mut T &T &mut T = note: required for `&'static (dyn Debug + 'static)` to implement `cxx::rust_option::OptionTarget` @@ -20,28 +18,36 @@ note: required by a bound in `RustOption` | ^^^^^^^^^^^^ required by this bound in `RustOption` error[E0599]: the function or associated item `new` exists for struct `RustOption<&dyn Debug>`, but its trait bounds were not satisfied - --> tests/ui_build/option_not_sized.rs:2:99 + --> tests/ui/option_not_sized.rs:2:99 | 2 | const _: cxx::RustOption::<&dyn core::fmt::Debug> = cxx::RustOption::<&dyn core::fmt::Debug>::new(); | ^^^ function or associated item cannot be called on `RustOption<&dyn Debug>` due to unsatisfied trait bounds | note: if you're trying to build a new `RustOption<&dyn Debug>` consider using one of the following associated functions: RustOption::::new - RustOption::<&'a T>::from_option_ref + RustOption::::from + RustOption::<&'a T>::from_raw + RustOption::<&'a T>::from_raw_improper --> src/rust_option.rs | | pub fn new() -> Self { | ^^^^^^^^^^^^^^^^^^^^ ... - | pub fn from_option_ref(other: Option<&'a T>) -> Self { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | pub fn from(o: Option) -> Self { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... + | pub unsafe fn from_raw(ptr: *const T) -> Self { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... + | pub unsafe fn from_raw_improper(ptr: *const core::ffi::c_void) -> Self { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: the following trait bounds were not satisfied: `&dyn Debug: cxx::rust_option::OptionTarget` `&dyn Debug: cxx::rust_option::private::Sealed` which is required by `&dyn Debug: cxx::rust_option::OptionTarget` error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time - --> tests/ui_build/option_not_sized.rs:2:57 + --> tests/ui/option_not_sized.rs:2:57 | 2 | const _: cxx::RustOption::<&dyn core::fmt::Debug> = cxx::RustOption::<&dyn core::fmt::Debug>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -50,8 +56,6 @@ error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be know = help: the following other types implement trait `cxx::rust_option::OptionTarget`: Box Pin<&mut T> - *const T - *mut T &T &mut T = note: required for `&'static (dyn Debug + 'static)` to implement `cxx::rust_option::OptionTarget` @@ -62,7 +66,7 @@ note: required by a bound in `RustOption` | ^^^^^^^^^^^^ required by this bound in `RustOption` error[E0277]: the size for values of type `dyn Debug` cannot be known at compilation time - --> tests/ui_build/option_not_sized.rs:2:57 + --> tests/ui/option_not_sized.rs:2:57 | 2 | const _: cxx::RustOption::<&dyn core::fmt::Debug> = cxx::RustOption::<&dyn core::fmt::Debug>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -71,8 +75,6 @@ error[E0277]: the size for values of type `dyn Debug` cannot be known at compila = help: the following other types implement trait `cxx::rust_option::OptionTarget`: Box Pin<&mut T> - *const T - *mut T &T &mut T = note: required for `&dyn Debug` to implement `cxx::rust_option::OptionTarget` diff --git a/tests/ui/option_safe_string.rs b/tests/ui/option_safe_string.rs deleted file mode 100644 index d13b208e0..000000000 --- a/tests/ui/option_safe_string.rs +++ /dev/null @@ -1,3 +0,0 @@ -const _: () = cxx::private::assert_option_safe::(); - -fn main() {} diff --git a/tests/ui/option_safe_string.stderr b/tests/ui/option_safe_string.stderr deleted file mode 100644 index af227f30b..000000000 --- a/tests/ui/option_safe_string.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0080]: evaluation of `cxx::private::assert_option_safe::__SizeCheck::::_IS_USIZE_SIZE` failed - --> src/rust_option.rs - | - | assert!(core::mem::size_of::>() == core::mem::size_of::()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: core::mem::size_of::>() == core::mem::size_of::()', $DIR/src/rust_option.rs:94:13 - | - = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) - -note: erroneous constant encountered - --> src/rust_option.rs - | - | let _: () = __SizeCheck::::_IS_USIZE_SIZE; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/option_safe_unsized.stderr b/tests/ui/option_safe_unsized.stderr index ce272f60d..0226ca9f0 100644 --- a/tests/ui/option_safe_unsized.stderr +++ b/tests/ui/option_safe_unsized.stderr @@ -1,13 +1,13 @@ -error[E0080]: evaluation of `cxx::private::assert_option_safe::__SizeCheck::<&str>::_IS_USIZE_SIZE` failed +error[E0080]: evaluation of `cxx::private::assert_option_safe::__SizeCheck::<&str>::_IS_OPTION_SIZE` failed --> src/rust_option.rs | - | assert!(core::mem::size_of::>() == core::mem::size_of::()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: core::mem::size_of::>() == core::mem::size_of::()', $DIR/src/rust_option.rs:94:13 + | assert!(mem::size_of::>() == mem::size_of::()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: mem::size_of::>() == mem::size_of::()', $DIR/src/rust_option.rs:50:13 | = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) note: erroneous constant encountered --> src/rust_option.rs | - | let _: () = __SizeCheck::::_IS_USIZE_SIZE; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | let _: () = __SizeCheck::::_IS_OPTION_SIZE; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/option_safe_usize.stderr b/tests/ui/option_safe_usize.stderr index 4014220b1..2271535ff 100644 --- a/tests/ui/option_safe_usize.stderr +++ b/tests/ui/option_safe_usize.stderr @@ -1,13 +1,13 @@ -error[E0080]: evaluation of `cxx::private::assert_option_safe::__SizeCheck::::_IS_NICHE` failed +error[E0080]: evaluation of `cxx::private::assert_option_safe::__SizeCheck::::_IS_OPTION_SIZE` failed --> src/rust_option.rs | - | assert!(core::mem::size_of::>() == core::mem::size_of::()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: core::mem::size_of::>() == core::mem::size_of::()', $DIR/src/rust_option.rs:92:13 + | assert!(mem::size_of::>() == mem::size_of::()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: mem::size_of::>() == mem::size_of::()', $DIR/src/rust_option.rs:50:13 | = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) note: erroneous constant encountered --> src/rust_option.rs | - | let _: () = __SizeCheck::::_IS_NICHE; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | let _: () = __SizeCheck::::_IS_OPTION_SIZE; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui_pass/empty.rs b/tests/ui_pass/empty.rs deleted file mode 100644 index 081a61102..000000000 --- a/tests/ui_pass/empty.rs +++ /dev/null @@ -1,4 +0,0 @@ -// This file only exists so that we have a passing example which changes trybuild -/// to use cargo build instead of cargo check. Some of the tests only fail with a -/// full build -fn main() {}