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:
Owen Avery 2025-09-16 19:31:39 -04:00 committed by Arthur Cohen
parent 22baf6c75f
commit 626812ff96
2 changed files with 65 additions and 100 deletions

View File

@ -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

View File

@ -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
}
}
}