From: Owen Avery <[email protected]>

This should remove a use-after-free as well as simplify the FFI
interface.

gcc/rust/ChangeLog:

        * ast/rust-fmt.cc (Pieces::collect): Handle changes to ffi
        interface.
        (Pieces::~Pieces): Remove function definition.
        (Pieces::Pieces): Likewise.
        (Pieces::operator=): Likewise.
        * ast/rust-fmt.h: Include "optional.h".
        (rust_ffi_alloc): New extern "C" function declaration.
        (rust_ffi_dealloc): Likewise.
        (class FFIVec): New class.
        (class FFIOpt): Likewise.
        (RustHamster::RustHamster): New constructor accepting const
        std::string reference.
        (struct FormatSpec): Use FFIOpt.
        (struct PieceSlice): Remove struct.
        (struct RustString): Likewise.
        (struct FormatArgsHandle): Likewise.
        (collect_pieces): Change function signature.
        (clone_pieces): Likewise.
        (destroy_pieces): Remove extern "C" function declaration.
        (Pieces::~Pieces): Remove function declaration.
        (Pieces::operator=): Likewise.
        (Pieces::get_pieces): Handle changes to class fields.
        (Pieces::Pieces): Remove copy and move constructor declarations,
        adjust signature of remaining constructor declaration.
        (Pieces::pieces_vector): Remove member variable.
        (Pieces::handle): Likewise.
        (Pieces::data): Add member variable.
        * expand/rust-macro-builtins-asm.cc (expand_inline_asm_strings):
        Use references to avoid copying.

libgrust/ChangeLog:

        * libformat_parser/src/lib.rs (struct FFIVec): New.
        (trait StringLeakExt): Remove.
        (struct FFIOpt): New.
        (trait IntoFFI): Adjust implementation for Option.
        (struct RustHamster): Add lifetime and adjust conversion to and
        from &str.
        (enum Piece): Adjust definition to handle changes to
        RustHamster.
        (struct Argument): Likewise.
        (struct FormatSpec): Use FFIOpt and RustHamster.
        (enum Position): Use RustHamster.
        (enum Count): Likewise.
        (struct PieceSlice): Replace with...
        (typedef PieceVec): ...this.
        (struct RustString): Remove.
        (struct FormatArgsHandle): Likewise.
        (fn collect_pieces): Adjust signature, greatly simplifying
        implementation.
        (fn clone_pieces): Likewise.
        (fn destroy_pieces): Remove.
        (trait LayoutExt): New.
        (fn rust_ffi_alloc): New.
        (fn rust_ffi_dealloc): New.

Signed-off-by: Owen Avery <[email protected]>
---
 gcc/rust/ast/rust-fmt.cc                   |  38 +--
 gcc/rust/ast/rust-fmt.h                    | 195 +++++++----
 gcc/rust/expand/rust-macro-builtins-asm.cc |   4 +-
 libgrust/libformat_parser/src/lib.rs       | 359 +++++++++++++--------
 4 files changed, 378 insertions(+), 218 deletions(-)

diff --git a/gcc/rust/ast/rust-fmt.cc b/gcc/rust/ast/rust-fmt.cc
index a29c8203ae8..21f4f03bb6f 100644
--- a/gcc/rust/ast/rust-fmt.cc
+++ b/gcc/rust/ast/rust-fmt.cc
@@ -32,41 +32,11 @@ Pieces
 Pieces::collect (const std::string &to_parse, bool append_newline,
                 ffi::ParseMode parse_mode)
 {
-  auto handle
-    = ffi::collect_pieces (to_parse.c_str (), append_newline, parse_mode);
-
-  // this performs multiple copies, can we avoid them maybe?
-  // TODO: Instead of just creating a vec of, basically, `ffi::Piece`s, we
-  // should transform them into the proper C++ type which we can work with. so
-  // transform all the strings into C++ strings? all the Option<T> into
-  // tl::optional<T>?
-  auto pieces_vector = std::vector<ffi::Piece> (handle.piece_slice.base_ptr,
-                                               handle.piece_slice.base_ptr
-                                                 + handle.piece_slice.len);
-
-  return Pieces (handle, std::move (pieces_vector));
-}
-
-Pieces::~Pieces () { ffi::destroy_pieces (handle); }
-
-Pieces::Pieces (const Pieces &other) : pieces_vector (other.pieces_vector)
-{
-  handle = ffi::clone_pieces (other.handle);
+  Pieces ret (to_parse, ffi::FFIVec<ffi::Piece> ());
+  ret.data->second = ffi::collect_pieces (ffi::RustHamster (ret.data->first),
+                                         append_newline, parse_mode);
+  return ret;
 }
 
-Pieces &
-Pieces::operator= (const Pieces &other)
-{
-  handle = ffi::clone_pieces (other.handle);
-  pieces_vector = other.pieces_vector;
-
-  return *this;
-}
-
-Pieces::Pieces (Pieces &&other)
-  : pieces_vector (std::move (other.pieces_vector)),
-    handle (clone_pieces (other.handle))
-{}
-
 } // namespace Fmt
 } // namespace Rust
diff --git a/gcc/rust/ast/rust-fmt.h b/gcc/rust/ast/rust-fmt.h
index 3722db291ab..c23499c3709 100644
--- a/gcc/rust/ast/rust-fmt.h
+++ b/gcc/rust/ast/rust-fmt.h
@@ -20,20 +20,138 @@
 #define RUST_FMT_H
 
 #include "rust-system.h"
-
-// FIXME: How to encode Option?
+#include "optional.h"
 
 namespace Rust {
 namespace Fmt {
 
 namespace ffi {
 
+extern "C" {
+
+unsigned char *rust_ffi_alloc (size_t count, size_t elem_size, size_t align);
+
+void rust_ffi_dealloc (unsigned char *data, size_t count, size_t elem_size,
+                      size_t align);
+
+} // extern "C"
+
+template <typename T> class FFIVec
+{
+  T *data;
+  size_t len;
+  size_t cap;
+
+public:
+  FFIVec () : data ((T *) alignof (T)), len (0), cap (0) {}
+
+  FFIVec (const FFIVec &) = delete;
+  FFIVec &operator= (const FFIVec &) = delete;
+
+  FFIVec (FFIVec &&other) : data (other.data), len (other.len), cap (other.cap)
+  {
+    other.data = (T *) alignof (T);
+    other.len = 0;
+    other.cap = 0;
+  }
+
+  FFIVec &operator= (FFIVec &&other)
+  {
+    this->~FFIVec ();
+    new (this) FFIVec (std::move (other));
+    return *this;
+  }
+
+  ~FFIVec ()
+  {
+    // T can't be zero-sized
+    if (cap)
+      rust_ffi_dealloc ((unsigned char *) data, cap, sizeof (T), alignof (T));
+  }
+
+  size_t size () const { return len; }
+
+  const T &operator[] (size_t idx) const
+  {
+    rust_assert (idx <= len);
+    return data[idx];
+  }
+
+  T *begin () { return data; }
+  const T *begin () const { return data; }
+  T *end () { return data + len; }
+  const T *end () const { return data + len; }
+};
+
+template <typename T> 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));
+  }
+
+  FFIOpt () : is_some (false) {}
+
+  FFIOpt (const FFIOpt &other) : is_some (other.is_some)
+  {
+    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));
+  }
+
+  ~FFIOpt ()
+  {
+    if (is_some)
+      ((T *) inner.data)->~T ();
+  }
+
+  FFIOpt &operator= (const FFIOpt &other)
+  {
+    this->~FFIOpt ();
+    new (this) FFIOpt (other);
+    return *this;
+  }
+
+  FFIOpt &operator= (FFIOpt &&other)
+  {
+    this->~FFIOpt ();
+    new (this) FFIOpt (std::move (other));
+    return *this;
+  }
+
+  tl::optional<std::reference_wrapper<T>> get_opt ()
+  {
+    return (T *) inner.data;
+  }
+
+  tl::optional<std::reference_wrapper<const T>> get_opt () const
+  {
+    return (const T *) inner.data;
+  }
+};
+
 struct RustHamster
 {
   const char *ptr;
   size_t len;
 
   std::string to_string () const;
+
+  explicit RustHamster (const std::string &str)
+    : ptr (str.data ()), len (str.size ())
+  {}
 };
 
 /// Enum of alignments which are supported.
@@ -166,33 +284,33 @@ struct Count
 struct FormatSpec
 {
   /// Optionally specified character to fill alignment with.
-  const uint32_t *fill;
+  FFIOpt<uint32_t> fill;
   /// Span of the optionally specified fill character.
-  const InnerSpan *fill_span;
+  FFIOpt<InnerSpan> fill_span;
   /// Optionally specified alignment.
   Alignment align;
   /// The `+` or `-` flag.
-  const Sign *sign;
+  FFIOpt<Sign> sign;
   /// The `#` flag.
   bool alternate;
   /// The `0` flag.
   bool zero_pad;
   /// The `x` or `X` flag. (Only for `Debug`.)
-  const DebugHex *debug_hex;
+  FFIOpt<DebugHex> debug_hex;
   /// The integer precision to use.
   Count precision;
   /// The span of the precision formatting flag (for diagnostics).
-  const InnerSpan *precision_span;
+  FFIOpt<InnerSpan> precision_span;
   /// The string width requested for the resulting format.
   Count width;
   /// The span of the width formatting flag (for diagnostics).
-  const InnerSpan *width_span;
+  FFIOpt<InnerSpan> width_span;
   /// The descriptor string representing the name of the format desired for
   /// this argument, this can be empty or any number of characters, although
   /// it is required to be one word.
   RustHamster ty;
   /// The span of the descriptor string (for diagnostics).
-  const InnerSpan *ty_span;
+  FFIOpt<InnerSpan> ty_span;
 };
 
 /// Representation of an argument specification.
@@ -238,26 +356,6 @@ struct Piece
   };
 };
 
-struct PieceSlice
-{
-  const Piece *base_ptr;
-  size_t len;
-  size_t cap;
-};
-
-struct RustString
-{
-  const unsigned char *ptr;
-  size_t len;
-  size_t cap;
-};
-
-struct FormatArgsHandle
-{
-  PieceSlice piece_slice;
-  RustString rust_string;
-};
-
 enum ParseMode
 {
   Format = 0,
@@ -266,12 +364,10 @@ enum ParseMode
 
 extern "C" {
 
-FormatArgsHandle collect_pieces (const char *input, bool append_newline,
-                                ParseMode parse_mode);
+FFIVec<Piece> collect_pieces (RustHamster input, bool append_newline,
+                             ParseMode parse_mode);
 
-FormatArgsHandle clone_pieces (const FormatArgsHandle &);
-
-void destroy_pieces (FormatArgsHandle);
+FFIVec<Piece> clone_pieces (const FFIVec<Piece> &);
 
 } // extern "C"
 
@@ -281,33 +377,20 @@ struct Pieces
 {
   static Pieces collect (const std::string &to_parse, bool append_newline,
                         ffi::ParseMode parse_mode);
-  ~Pieces ();
-
-  Pieces (const Pieces &other);
-  Pieces &operator= (const Pieces &other);
 
-  Pieces (Pieces &&other);
-
-  const std::vector<ffi::Piece> &get_pieces () const { return pieces_vector; }
-
-  // {
-  //   slice = clone_pieces (&other.slice);
-  //   to_parse = other.to_parse;
-
-  //   return *this;
-  // }
+  const ffi::FFIVec<ffi::Piece> &get_pieces () const { return data->second; }
 
 private:
-  Pieces (ffi::FormatArgsHandle handle, std::vector<ffi::Piece> 
&&pieces_vector)
-    : pieces_vector (std::move (pieces_vector)), handle (handle)
+  Pieces (std::string str, ffi::FFIVec<ffi::Piece> pieces)
+    : data (
+      std::make_shared<decltype (data)::element_type> (std::move (str),
+                                                      std::move (pieces)))
   {}
 
-  std::vector<ffi::Piece> pieces_vector;
-
-  // this memory is held for FFI reasons - it needs to be released and cloned
-  // precisely, so try to not access it/modify it if possible. you should
-  // instead work with `pieces_vector`
-  ffi::FormatArgsHandle handle;
+  // makes copying simpler
+  // also, we'd need to keep the parsed string in a shared_ptr anyways
+  // since we store pointers into the parsed string
+  std::shared_ptr<std::pair<std::string, ffi::FFIVec<ffi::Piece>>> data;
 };
 
 } // namespace Fmt
diff --git a/gcc/rust/expand/rust-macro-builtins-asm.cc 
b/gcc/rust/expand/rust-macro-builtins-asm.cc
index 6cbcf87ebc9..c991ca703e9 100644
--- a/gcc/rust/expand/rust-macro-builtins-asm.cc
+++ b/gcc/rust/expand/rust-macro-builtins-asm.cc
@@ -787,12 +787,12 @@ expand_inline_asm_strings (InlineAsmContext 
inline_asm_ctx)
 
       auto pieces = Fmt::Pieces::collect (template_str.symbol, false,
                                          Fmt::ffi::ParseMode::InlineAsm);
-      auto pieces_vec = pieces.get_pieces ();
+      auto &pieces_vec = pieces.get_pieces ();
 
       std::string transformed_template_str = "";
       for (size_t i = 0; i < pieces_vec.size (); i++)
        {
-         auto piece = pieces_vec[i];
+         auto &piece = pieces_vec[i];
          if (piece.tag == Fmt::ffi::Piece::Tag::String)
            {
              transformed_template_str += piece.string._0.to_string ();
diff --git a/libgrust/libformat_parser/src/lib.rs 
b/libgrust/libformat_parser/src/lib.rs
index 72e5971ae80..049403db0b7 100644
--- a/libgrust/libformat_parser/src/lib.rs
+++ b/libgrust/libformat_parser/src/lib.rs
@@ -1,56 +1,197 @@
 //! FFI interface for `rustc_format_parser`
 
+use std::alloc::Layout;
+
 // what's the plan? Have a function return something that can be constructed 
into a vector?
 // or an iterator?
 
-use std::ffi::CStr;
-
 trait IntoFFI<T> {
     fn into_ffi(self) -> T;
 }
 
-impl<T> IntoFFI<*const T> for Option<T>
-where
-    T: Sized,
-{
-    fn into_ffi(self) -> *const T {
-        match self.as_ref() {
-            None => std::ptr::null(),
-            Some(r) => r as *const T,
+// FIXME: Make an ffi module in a separate file
+// FIXME: Remember to leak the boxed type somehow
+// FIXME: How to encode the Option type? As a pointer? Option<T> -> Option<&T> 
-> *const T could work maybe?
+pub mod ffi {
+    use super::IntoFFI;
+    use std::marker::PhantomData;
+    use std::mem::MaybeUninit;
+
+    #[repr(C)]
+    pub struct FFIVec<T> {
+        data: *mut T,
+        len: usize,
+        cap: usize
+    }
+
+    impl<T> IntoFFI<FFIVec<T>> for Vec<T> {
+        fn into_ffi(mut self) -> FFIVec<T> {
+            let ret = FFIVec {
+                data: self.as_mut_ptr(),
+                len: self.len(),
+                cap: self.capacity()
+            };
+            self.leak();
+            ret
         }
     }
-}
 
-// Extension trait to provide `String::leak` which did not exist in Rust 1.49
-pub trait StringLeakExt {
-    fn leak<'a>(self) -> &'a mut str;
-}
+    impl<T> Drop for FFIVec<T> {
+        fn drop(&mut self) {
+            unsafe {
+                Vec::from_raw_parts(self.data, self.len, self.cap);
+            }
+        }
+    }
 
-impl StringLeakExt for String {
-    fn leak<'a>(self) -> &'a mut str {
-        Box::leak(self.into_boxed_str())
+    impl<T> FFIVec<T> {
+        fn with_vec_ref<R, F: for<'a> FnOnce(&'a Vec<T>) -> R>(
+            &self, f: F
+        ) -> R {
+            let v = unsafe {
+                Vec::from_raw_parts(self.data, self.len, self.cap)
+            };
+            let ret = f(&v);
+            v.leak();
+            ret
+        }
+
+        // currently unused
+        // may be nice to have later, though
+        #[allow(unused)]
+        fn with_vec_mut_ref<R, F: for<'a> FnOnce(&'a mut Vec<T>) -> R>(
+            &mut self, f: F
+        ) -> R {
+            let mut v = unsafe {
+                Vec::from_raw_parts(self.data, self.len, self.cap)
+            };
+            let ret = f(&mut v);
+            self.data = v.as_mut_ptr();
+            self.len = v.len();
+            self.cap = v.capacity();
+            v.leak();
+            ret
+        }
     }
-}
 
-// FIXME: Make an ffi module in a separate file
-// FIXME: Remember to leak the boxed type somehow
-// FIXME: How to encode the Option type? As a pointer? Option<T> -> Option<&T> 
-> *const T could work maybe?
-pub mod ffi {
-    use super::IntoFFI;
+    impl<T> Clone for FFIVec<T>
+    where
+        T: Clone
+    {
+        fn clone(&self) -> FFIVec<T> {
+            self.with_vec_ref(|v| v.clone().into_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()) }
+            }
+        }
+    }
+
+    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
+            }
+        }
+    }
 
     // FIXME: We need to ensure we deal with memory properly - whether it's 
owned by the C++ side or the Rust side
     #[derive(Copy, Clone, PartialEq, Eq, Debug)]
     #[repr(C)]
-    pub struct RustHamster {
+    pub struct RustHamster<'a> {
         ptr: *const u8,
         len: usize,
+        phantom: PhantomData<&'a u8>
     }
 
-    impl<'a> From<&'a str> for RustHamster {
-        fn from(s: &'a str) -> RustHamster {
+    impl<'a> IntoFFI<RustHamster<'a>> for &'a str {
+        fn into_ffi(self) -> RustHamster<'a> {
             RustHamster {
-                ptr: s.as_ptr(),
-                len: s.len(),
+                ptr: self.as_ptr(),
+                len: self.len(),
+                phantom: PhantomData,
+            }
+        }
+    }
+
+    impl<'a> RustHamster<'a> {
+        pub fn as_str(&self) -> &'a str {
+            unsafe {
+                let slice: &'a [u8] = std::slice::from_raw_parts(self.ptr, 
self.len);
+                std::str::from_utf8_unchecked(slice)
             }
         }
     }
@@ -101,11 +242,11 @@ pub mod ffi {
 
     /// A piece is a portion of the format string which represents the next 
part
     /// to emit. These are emitted as a stream by the `Parser` class.
-    #[derive(Debug, Clone, PartialEq)]
+    #[derive(Clone)]
     #[repr(C)]
     pub enum Piece<'a> {
         /// A literal string which should directly be emitted
-        String(RustHamster),
+        String(RustHamster<'a>),
         /// This describes that formatting should process the next argument (as
         /// specified inside) for emission.
         // do we need a pointer here? we're doing big cloning anyway
@@ -113,7 +254,7 @@ pub mod ffi {
     }
 
     /// Representation of an argument specification.
-    #[derive(Copy, Clone, Debug, PartialEq)]
+    #[derive(Clone)]
     #[repr(C)]
     pub struct Argument<'a> {
         /// Where to find this argument
@@ -126,37 +267,37 @@ pub mod ffi {
     }
 
     /// Specification for the formatting of an argument in the format string.
-    #[derive(Copy, Clone, Debug, PartialEq)]
+    #[derive(Clone)]
     #[repr(C)]
     pub struct FormatSpec<'a> {
         /// Optionally specified character to fill alignment with.
-        pub fill: Option<char>,
+        pub fill: FFIOpt<char>,
         /// Span of the optionally specified fill character.
-        pub fill_span: *const InnerSpan,
+        pub fill_span: FFIOpt<InnerSpan>,
         /// Optionally specified alignment.
         pub align: Alignment,
         /// The `+` or `-` flag.
-        pub sign: *const Sign,
+        pub sign: FFIOpt<Sign>,
         /// The `#` flag.
         pub alternate: bool,
         /// The `0` flag.
         pub zero_pad: bool,
         /// The `x` or `X` flag. (Only for `Debug`.)
-        pub debug_hex: *const DebugHex,
+        pub debug_hex: FFIOpt<DebugHex>,
         /// The integer precision to use.
         pub precision: Count<'a>,
         /// The span of the precision formatting flag (for diagnostics).
-        pub precision_span: *const InnerSpan,
+        pub precision_span: FFIOpt<InnerSpan>,
         /// The string width requested for the resulting format.
         pub width: Count<'a>,
         /// The span of the width formatting flag (for diagnostics).
-        pub width_span: *const InnerSpan,
+        pub width_span: FFIOpt<InnerSpan>,
         /// The descriptor string representing the name of the format desired 
for
         /// this argument, this can be empty or any number of characters, 
although
         /// it is required to be one word.
-        pub ty: &'a str,
+        pub ty: RustHamster<'a>,
         /// The span of the descriptor string (for diagnostics).
-        pub ty_span: *const InnerSpan,
+        pub ty_span: FFIOpt<InnerSpan>,
     }
 
     /// Enum describing where an argument for a format can be located.
@@ -168,7 +309,7 @@ pub mod ffi {
         /// The argument is located at a specific index given in the format,
         ArgumentIs(usize),
         /// The argument has a name.
-        ArgumentNamed(&'a str),
+        ArgumentNamed(RustHamster<'a>),
     }
 
     /// Enum of alignments which are supported.
@@ -213,7 +354,7 @@ pub mod ffi {
         /// The count is specified explicitly.
         CountIs(usize),
         /// The count is specified by the argument with the given name.
-        CountIsName(&'a str, InnerSpan),
+        CountIsName(RustHamster<'a>, InnerSpan),
         /// The count is specified by the argument at the given index.
         CountIsParam(usize),
         /// The count is specified by a star (like in `{:.*}`) that refers to 
the argument at the given index.
@@ -225,7 +366,7 @@ pub mod ffi {
     impl<'a> From<generic_format_parser::Piece<'a>> for Piece<'a> {
         fn from(old: generic_format_parser::Piece<'a>) -> Self {
             match old {
-                generic_format_parser::Piece::String(x) => 
Piece::String(x.into()),
+                generic_format_parser::Piece::String(x) => 
Piece::String(x.into_ffi()),
                 generic_format_parser::Piece::NextArgument(x) => {
                     // FIXME: This is problematic - if we do this, then we 
probably run into the issue that the Box
                     // is freed at the end of the call to collect_pieces. if 
we just .leak() it, then we have
@@ -259,7 +400,7 @@ pub mod ffi {
                 }
                 generic_format_parser::Position::ArgumentIs(x) => 
Position::ArgumentIs(x.into()),
                 generic_format_parser::Position::ArgumentNamed(x) => {
-                    Position::ArgumentNamed(x.into())
+                    Position::ArgumentNamed(x.into_ffi())
                 }
             }
         }
@@ -277,7 +418,7 @@ pub mod ffi {
     impl<'a> From<generic_format_parser::FormatSpec<'a>> for FormatSpec<'a> {
         fn from(old: generic_format_parser::FormatSpec<'a>) -> Self {
             FormatSpec {
-                fill: old.fill,
+                fill: old.fill.into_ffi(),
                 fill_span: old.fill_span.map(Into::into).into_ffi(),
                 align: old.align.into(),
                 sign: old.sign.map(Into::into).into_ffi(),
@@ -288,7 +429,7 @@ pub mod ffi {
                 precision_span: old.precision_span.map(Into::into).into_ffi(),
                 width: old.width.into(),
                 width_span: old.width_span.map(Into::into).into_ffi(),
-                ty: old.ty,
+                ty: old.ty.into_ffi(),
                 ty_span: old.ty_span.map(Into::into).into_ffi(),
             }
         }
@@ -307,7 +448,7 @@ pub mod ffi {
         fn from(old: generic_format_parser::Count<'a>) -> Self {
             match old {
                 generic_format_parser::Count::CountIs(x) => Count::CountIs(x),
-                generic_format_parser::Count::CountIsName(x, y) => 
Count::CountIsName(x, y.into()),
+                generic_format_parser::Count::CountIsName(x, y) => 
Count::CountIsName(x.into_ffi(), y.into()),
                 generic_format_parser::Count::CountIsParam(x) => 
Count::CountIsParam(x),
                 generic_format_parser::Count::CountIsStar(x) => 
Count::CountIsStar(x),
                 generic_format_parser::Count::CountImplied => 
Count::CountImplied,
@@ -357,100 +498,66 @@ pub mod rust {
 }
 
 // TODO: Should we instead make an FFIVector struct?
-#[repr(C)]
-pub struct PieceSlice {
-    base_ptr: *mut ffi::Piece<'static /* FIXME: That's wrong */>,
-    len: usize,
-    cap: usize,
-}
-
-#[repr(C)]
-// FIXME: we should probably use FFIString here
-pub struct RustString {
-    ptr: *const u8,
-    len: usize,
-    cap: usize,
-}
-
-#[repr(C)]
-pub struct FormatArgsHandle(PieceSlice, RustString);
+type PieceVec<'a> = ffi::FFIVec<ffi::Piece<'a>>;
 
 #[no_mangle]
-pub extern "C" fn collect_pieces(
-    input: *const libc::c_char,
+pub extern "C" fn collect_pieces<'a>(
+    input: ffi::RustHamster<'a>,
     append_newline: bool,
     parse_mode: crate::ffi::ParseMode,
-) -> FormatArgsHandle {
-    // FIXME: Add comment
-    let str = unsafe { CStr::from_ptr(input) };
-    let str = str.to_str().unwrap().to_owned();
-
-    // we are never going to free this string here (we leak it later on), so 
we can extend its lifetime
-    // to send it across an FFI boundary.
-    // FIXME: Is that correct?
-    let s = &str;
-    let s = unsafe { std::mem::transmute::<&'_ str, &'static str>(s) };
-
+) -> PieceVec<'a> {
     // FIXME: No unwrap
     let pieces: Vec<ffi::Piece<'_>> =
-        rust::collect_pieces(s, None, None, append_newline, parse_mode)
+        rust::collect_pieces(input.as_str(), None, None, append_newline, 
parse_mode)
             .into_iter()
             .map(Into::into)
             .collect();
 
-    let piece_slice = PieceSlice {
-        len: pieces.len(),
-        cap: pieces.capacity(),
-        base_ptr: pieces.leak().as_mut_ptr(),
-    };
-    let rust_string = RustString {
-        len: str.len(),
-        cap: str.capacity(),
-        ptr: str.leak().as_ptr(),
-    };
-
-    FormatArgsHandle(piece_slice, rust_string)
+    pieces.into_ffi()
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn destroy_pieces(FormatArgsHandle(piece_slice, s): 
FormatArgsHandle) {
-    let PieceSlice { base_ptr, len, cap } = piece_slice;
-    drop(Vec::from_raw_parts(base_ptr, len, cap));
-
-    let RustString { ptr, len, cap } = s;
-    drop(String::from_raw_parts(ptr as *mut u8, len, cap));
+pub extern "C" fn clone_pieces<'a, 'b>(
+    piece_vec: &'a PieceVec<'b>
+) -> PieceVec<'b> {
+    piece_vec.clone()
 }
 
-#[no_mangle]
-pub extern "C" fn clone_pieces(
-    FormatArgsHandle(piece_slice, s): &FormatArgsHandle,
-) -> FormatArgsHandle {
-    let PieceSlice { base_ptr, len, cap } = *piece_slice;
-
-    let v = unsafe { Vec::from_raw_parts(base_ptr, len, cap) };
-    let cloned_v = v.clone();
-
-    // FIXME: Add documentation
-    v.leak();
-
-    let piece_slice = PieceSlice {
-        len: cloned_v.len(),
-        cap: cloned_v.capacity(),
-        base_ptr: cloned_v.leak().as_mut_ptr(),
-    };
-
-    let RustString { ptr, len, cap } = *s;
-    let s = unsafe { String::from_raw_parts(ptr as *mut u8, len, cap) };
-    let cloned_s = s.clone();
+// we need Layout::repeat
+// function signature is a bit different, so call it repeat_x
+trait LayoutExt {
+    fn repeat_x(&self, n: usize) -> Layout;
+}
 
-    // FIXME: Documentation
-    s.leak();
+impl LayoutExt for Layout {
+    fn repeat_x(&self, n: usize) -> Layout {
+        let elem = self.pad_to_align();
+        let total_size = elem.size().checked_mul(n).unwrap();
+        Layout::from_size_align(total_size, elem.align()).unwrap()
+    }
+}
 
-    let rust_string = RustString {
-        len: cloned_s.len(),
-        cap: cloned_s.capacity(),
-        ptr: cloned_s.leak().as_ptr(),
-    };
+#[no_mangle]
+pub unsafe extern "C" fn rust_ffi_alloc(
+    count: usize, elem_size: usize, align: usize
+) -> *mut u8 {
+    unsafe {
+        std::alloc::alloc(
+            Layout::from_size_align_unchecked(elem_size, align)
+                .repeat_x(count)
+        )
+    }
+}
 
-    FormatArgsHandle(piece_slice, rust_string)
+#[no_mangle]
+pub unsafe extern "C" fn rust_ffi_dealloc(
+    data: *mut u8, count: usize, elem_size: usize, align: usize
+) {
+    unsafe {
+        std::alloc::dealloc(
+            data,
+            Layout::from_size_align_unchecked(elem_size, align)
+                .repeat_x(count)
+        )
+    }
 }
-- 
2.50.1

Reply via email to