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)
- {
- new (inner.data) T (std::forward<U> (val));
- }
+ template <typename U>
+ FFIOpt (U &&val) : some{Some::KIND, std::forward<U> (val)}
+ {}
- FFIOpt () : is_some (false) {}
+ FFIOpt () : none{None::KIND} {}
- FFIOpt (const FFIOpt &other) : is_some (other.is_some)
+ FFIOpt (const FFIOpt &other)
{
- if (is_some)
- new (inner.data) T (*(const T *) other.inner.data);
+ if (other.has_value ())
+ new (&some) Some{Some::KIND, other.some.val};
+ else
+ new (&none) None{None::KIND};
}
- FFIOpt (FFIOpt &&other) : is_some (other.is_some)
+ FFIOpt (FFIOpt &&other)
{
- 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)
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
}
}
- #[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
}
}
}