diff options
Diffstat (limited to 'gcc/rust/ast/rust-fmt.h')
| -rw-r--r-- | gcc/rust/ast/rust-fmt.h | 228 |
1 files changed, 172 insertions, 56 deletions
diff --git a/gcc/rust/ast/rust-fmt.h b/gcc/rust/ast/rust-fmt.h index 3722db2..e59bed3 100644 --- a/gcc/rust/ast/rust-fmt.h +++ b/gcc/rust/ast/rust-fmt.h @@ -20,20 +20,171 @@ #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; } +}; + +// 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 +{ +public: + template <typename U> + FFIOpt (U &&val) : some{Some::KIND, std::forward<U> (val)} + {} + + FFIOpt () : none{None::KIND} {} + + FFIOpt (const FFIOpt &other) + { + if (other.has_value ()) + new (&some) Some{Some::KIND, other.some.val}; + else + new (&none) None{None::KIND}; + } + + FFIOpt (FFIOpt &&other) + { + if (other.has_value ()) + new (&some) Some{Some::KIND, std::move (other.some.val)}; + else + new (&none) None{None::KIND}; + } + + ~FFIOpt () + { + if (has_value ()) + some.~Some (); + else + none.~None (); + } + + 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 () + { + if (has_value ()) + return std::ref (some.val); + else + return tl::nullopt; + } + + tl::optional<std::reference_wrapper<const T>> get_opt () const + { + 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 { 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 +317,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 +389,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 +397,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 +410,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 |
