#ifndef XRPL_PROTOCOL_STBASE_H_INCLUDED #define XRPL_PROTOCOL_STBASE_H_INCLUDED #include #include #include #include #include #include #include #include namespace ripple { /// Note, should be treated as flags that can be | and & struct JsonOptions { using underlying_t = unsigned int; underlying_t value; enum values : underlying_t { // clang-format off none = 0b0000'0000, include_date = 0b0000'0001, disable_API_prior_V2 = 0b0000'0010, // IMPORTANT `_all` must be union of all of the above; see also operator~ _all = 0b0000'0011 // clang-format on }; constexpr JsonOptions(underlying_t v) noexcept : value(v) { } [[nodiscard]] constexpr explicit operator underlying_t() const noexcept { return value; } [[nodiscard]] constexpr explicit operator bool() const noexcept { return value != 0u; } [[nodiscard]] constexpr auto friend operator==(JsonOptions lh, JsonOptions rh) noexcept -> bool = default; [[nodiscard]] constexpr auto friend operator!=(JsonOptions lh, JsonOptions rh) noexcept -> bool = default; /// Returns JsonOptions union of lh and rh [[nodiscard]] constexpr JsonOptions friend operator|(JsonOptions lh, JsonOptions rh) noexcept { return {lh.value | rh.value}; } /// Returns JsonOptions intersection of lh and rh [[nodiscard]] constexpr JsonOptions friend operator&(JsonOptions lh, JsonOptions rh) noexcept { return {lh.value & rh.value}; } /// Returns JsonOptions binary negation, can be used with & (above) for set /// difference e.g. `(options & ~JsonOptions::include_date)` [[nodiscard]] constexpr JsonOptions friend operator~(JsonOptions v) noexcept { return {~v.value & static_cast(_all)}; } }; template requires requires(T const& t) { { t.getJson(JsonOptions::none) } -> std::convertible_to; } Json::Value to_json(T const& t) { return t.getJson(JsonOptions::none); } namespace detail { class STVar; } // VFALCO TODO fix this restriction on copy assignment. // // CAUTION: Do not create a vector (or similar container) of any object derived // from STBase. Use Boost ptr_* containers. The copy assignment operator // of STBase has semantics that will cause contained types to change // their names when an object is deleted because copy assignment is used to // "slide down" the remaining types and this will not copy the field // name. Changing the copy assignment operator to copy the field name breaks the // use of copy assignment just to copy values, which is used in the transaction // engine code. //------------------------------------------------------------------------------ /** A type which can be exported to a well known binary format. A STBase: - Always a field - Can always go inside an eligible enclosing STBase (such as STArray) - Has a field name Like JSON, a SerializedObject is a basket which has rules on what it can hold. @note "ST" stands for "Serialized Type." */ class STBase { SField const* fName; public: virtual ~STBase() = default; STBase(); STBase(STBase const&) = default; STBase& operator=(STBase const& t); explicit STBase(SField const& n); bool operator==(STBase const& t) const; bool operator!=(STBase const& t) const; template D& downcast(); template D const& downcast() const; virtual SerializedTypeID getSType() const; virtual std::string getFullText() const; virtual std::string getText() const; virtual Json::Value getJson(JsonOptions = JsonOptions::none) const; virtual void add(Serializer& s) const; virtual bool isEquivalent(STBase const& t) const; virtual bool isDefault() const; /** A STBase is a field. This sets the name. */ void setFName(SField const& n); SField const& getFName() const; void addFieldID(Serializer& s) const; protected: template static STBase* emplace(std::size_t n, void* buf, T&& val); private: virtual STBase* copy(std::size_t n, void* buf) const; virtual STBase* move(std::size_t n, void* buf); friend class detail::STVar; }; //------------------------------------------------------------------------------ std::ostream& operator<<(std::ostream& out, STBase const& t); template D& STBase::downcast() { D* ptr = dynamic_cast(this); if (ptr == nullptr) Throw(); return *ptr; } template D const& STBase::downcast() const { D const* ptr = dynamic_cast(this); if (ptr == nullptr) Throw(); return *ptr; } template STBase* STBase::emplace(std::size_t n, void* buf, T&& val) { using U = std::decay_t; if (sizeof(U) > n) return new U(std::forward(val)); return new (buf) U(std::forward(val)); } } // namespace ripple #endif