mirror of git://gcc.gnu.org/git/gcc.git
gccrs: Improve FFIOpt
Also fixes https://github.com/Rust-GCC/gccrs/issues/4171. gcc/rust/ChangeLog: * ast/rust-fmt.h (class FFIOpt): Adjust internal structure to match a repr(C) rust enum. libgrust/ChangeLog: * libformat_parser/src/lib.rs (struct FFIOpt): Likewise and remove some now-redundant methods. Signed-off-by: Owen Avery <powerboat9.gamer@gmail.com>
This commit is contained in:
parent
22baf6c75f
commit
626812ff96
|
|
@ -83,38 +83,41 @@ public:
|
|||
const T *end () const { return data + len; }
|
||||
};
|
||||
|
||||
template <typename T> class FFIOpt
|
||||
// https://github.com/rust-lang/rfcs/blob/master/text/2195-really-tagged-unions.md
|
||||
template <typename T,
|
||||
typename =
|
||||
typename std::enable_if<std::is_standard_layout<T>::value>::type>
|
||||
class FFIOpt
|
||||
{
|
||||
struct alignas (T) Inner
|
||||
{
|
||||
char data[sizeof (T)];
|
||||
} inner;
|
||||
bool is_some;
|
||||
|
||||
public:
|
||||
template <typename U> FFIOpt (U &&val) : is_some (true)
|
||||
template <typename U>
|
||||
FFIOpt (U &&val) : some{Some::KIND, std::forward<U> (val)}
|
||||
{}
|
||||
|
||||
FFIOpt () : none{None::KIND} {}
|
||||
|
||||
FFIOpt (const FFIOpt &other)
|
||||
{
|
||||
new (inner.data) T (std::forward<U> (val));
|
||||
if (other.has_value ())
|
||||
new (&some) Some{Some::KIND, other.some.val};
|
||||
else
|
||||
new (&none) None{None::KIND};
|
||||
}
|
||||
|
||||
FFIOpt () : is_some (false) {}
|
||||
|
||||
FFIOpt (const FFIOpt &other) : is_some (other.is_some)
|
||||
FFIOpt (FFIOpt &&other)
|
||||
{
|
||||
if (is_some)
|
||||
new (inner.data) T (*(const T *) other.inner.data);
|
||||
}
|
||||
|
||||
FFIOpt (FFIOpt &&other) : is_some (other.is_some)
|
||||
{
|
||||
if (is_some)
|
||||
new (inner.data) T (std::move (*(const T *) other.inner.data));
|
||||
if (other.has_value ())
|
||||
new (&some) Some{Some::KIND, std::move (other.some.val)};
|
||||
else
|
||||
new (&none) None{None::KIND};
|
||||
}
|
||||
|
||||
~FFIOpt ()
|
||||
{
|
||||
if (is_some)
|
||||
((T *) inner.data)->~T ();
|
||||
if (has_value ())
|
||||
some.~Some ();
|
||||
else
|
||||
none.~None ();
|
||||
}
|
||||
|
||||
FFIOpt &operator= (const FFIOpt &other)
|
||||
|
|
@ -133,13 +136,43 @@ public:
|
|||
|
||||
tl::optional<std::reference_wrapper<T>> get_opt ()
|
||||
{
|
||||
return (T *) inner.data;
|
||||
if (has_value ())
|
||||
return std::ref (some.val);
|
||||
else
|
||||
return tl::nullopt;
|
||||
}
|
||||
|
||||
tl::optional<std::reference_wrapper<const T>> get_opt () const
|
||||
{
|
||||
return (const T *) inner.data;
|
||||
if (has_value ())
|
||||
return std::ref (some.val);
|
||||
else
|
||||
return tl::nullopt;
|
||||
}
|
||||
|
||||
bool has_value () const { return some.kind == Some::KIND; }
|
||||
|
||||
operator bool () const { return has_value (); }
|
||||
|
||||
private:
|
||||
struct Some
|
||||
{
|
||||
static constexpr uint8_t KIND = 0;
|
||||
uint8_t kind;
|
||||
T val;
|
||||
};
|
||||
|
||||
struct None
|
||||
{
|
||||
static constexpr uint8_t KIND = 1;
|
||||
uint8_t kind;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
Some some;
|
||||
None none;
|
||||
};
|
||||
};
|
||||
|
||||
struct RustHamster
|
||||
|
|
|
|||
|
|
@ -83,87 +83,19 @@ pub mod ffi {
|
|||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct FFIOpt<T> {
|
||||
val: MaybeUninit<T>,
|
||||
is_some: bool
|
||||
}
|
||||
|
||||
impl<T> Clone for FFIOpt<T>
|
||||
where
|
||||
T: Clone
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
match self.get_opt_ref() {
|
||||
Some(r) => FFIOpt::new_val(r.clone()),
|
||||
None => FFIOpt::new_none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PartialEq for FFIOpt<T>
|
||||
where
|
||||
T: PartialEq
|
||||
{
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self.get_opt_ref(), other.get_opt_ref()) {
|
||||
(Some(a), Some(b)) => a.eq(b),
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Eq for FFIOpt<T>
|
||||
where
|
||||
T: Eq
|
||||
{}
|
||||
|
||||
impl<T> Drop for FFIOpt<T>
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
if self.is_some {
|
||||
unsafe { std::ptr::drop_in_place(self.val.as_mut_ptr()) }
|
||||
}
|
||||
}
|
||||
// https://github.com/rust-lang/rfcs/blob/master/text/2195-really-tagged-unions.md
|
||||
#[repr(u8)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum FFIOpt<T> {
|
||||
Some(T),
|
||||
None
|
||||
}
|
||||
|
||||
impl<T> IntoFFI<FFIOpt<T>> for Option<T> {
|
||||
fn into_ffi(self) -> FFIOpt<T> {
|
||||
match self {
|
||||
Some(v) => FFIOpt::new_val(v),
|
||||
None => FFIOpt::new_none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FFIOpt<T> {
|
||||
pub fn new_val(v: T) -> Self {
|
||||
FFIOpt {
|
||||
val: MaybeUninit::new(v),
|
||||
is_some: true
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_none() -> Self {
|
||||
FFIOpt {
|
||||
val: MaybeUninit::uninit(),
|
||||
is_some: false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_opt_ref(&self) -> Option<&T> {
|
||||
if self.is_some {
|
||||
Some(unsafe {&*self.val.as_ptr()})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_opt_ref_mut(&mut self) -> Option<&mut T> {
|
||||
if self.is_some {
|
||||
Some(unsafe {&mut *self.val.as_mut_ptr()})
|
||||
} else {
|
||||
None
|
||||
Some(v) => FFIOpt::Some(v),
|
||||
None => FFIOpt::None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue