Files
rippled/include/xrpl/protocol/STBase.h
2025-10-23 11:04:30 -04:00

225 lines
5.2 KiB
C++

#ifndef XRPL_PROTOCOL_STBASE_H_INCLUDED
#define XRPL_PROTOCOL_STBASE_H_INCLUDED
#include <xrpl/basics/contract.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/Serializer.h>
#include <ostream>
#include <string>
#include <type_traits>
#include <typeinfo>
#include <utility>
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<underlying_t>(_all)};
}
};
template <typename T>
requires requires(T const& t) {
{ t.getJson(JsonOptions::none) } -> std::convertible_to<Json::Value>;
}
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 <class D>
D&
downcast();
template <class D>
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 <class T>
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 <class D>
D&
STBase::downcast()
{
D* ptr = dynamic_cast<D*>(this);
if (ptr == nullptr)
Throw<std::bad_cast>();
return *ptr;
}
template <class D>
D const&
STBase::downcast() const
{
D const* ptr = dynamic_cast<D const*>(this);
if (ptr == nullptr)
Throw<std::bad_cast>();
return *ptr;
}
template <class T>
STBase*
STBase::emplace(std::size_t n, void* buf, T&& val)
{
using U = std::decay_t<T>;
if (sizeof(U) > n)
return new U(std::forward<T>(val));
return new (buf) U(std::forward<T>(val));
}
} // namespace ripple
#endif