mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-03 08:46:46 +00:00
Bulk documentation pass covering 702 C++ source files in src/libxrpl, src/xrpld, and include/xrpl. Adds class, function, parameter, and invariant docs per docs/DOCUMENTATION_STANDARDS.md. Squashed from the original three-part series (part 1 / part 2 / part 3) to avoid merge-conflict noise when rebasing the work onto current develop.
654 lines
24 KiB
C++
654 lines
24 KiB
C++
/** @file
|
||
* Compile-time field identification and wire-type catalog for XRPL serialized
|
||
* objects.
|
||
*
|
||
* Every data field that can appear in an XRPL transaction, ledger entry,
|
||
* validation, or transaction metadata is identified by a singleton `SField`
|
||
* instance declared in this header. The `SerializedTypeID` enum defines the
|
||
* recognized wire types. `TypedField<T>` adds a compile-time C++ type so
|
||
* that callers can interact with fields in a type-safe way.
|
||
*
|
||
* @note Some fields distinguish between the default value and the absent
|
||
* state. For example, `sfQualityIn` on a trust line with value 0
|
||
* means "no quality set" (absent) versus 1,000,000,000 (parity rate
|
||
* when explicitly set). Keep this in mind when testing presence.
|
||
*
|
||
* @see SField, TypedField, SerializedTypeID
|
||
*/
|
||
#pragma once
|
||
|
||
#include <xrpl/basics/safe_cast.h>
|
||
#include <xrpl/json/json_value.h>
|
||
#include <xrpl/protocol/Units.h>
|
||
|
||
#include <cstdint>
|
||
#include <map>
|
||
|
||
namespace xrpl {
|
||
|
||
//------------------------------------------------------------------------------
|
||
|
||
// Forwards
|
||
class STAccount;
|
||
class STAmount;
|
||
class STIssue;
|
||
class STBlob;
|
||
template <int>
|
||
class STBitString;
|
||
template <class>
|
||
class STInteger;
|
||
class STNumber;
|
||
class STXChainBridge;
|
||
class STVector256;
|
||
class STCurrency;
|
||
|
||
// NOLINTBEGIN(readability-identifier-naming)
|
||
/** Wire-type codes for XRPL binary serialization.
|
||
*
|
||
* Each value identifies the on-the-wire encoding family used for a group of
|
||
* protocol fields. Codes 1–11 ("common" types) fit in a single nibble and
|
||
* share a compact one-byte field-ID prefix. Codes 16+ ("uncommon" types)
|
||
* require an extra byte for the type nibble. Codes 12–13 are reserved gaps.
|
||
* Codes 10001–10004 are top-level container types (`STI_TRANSACTION`, etc.)
|
||
* that cannot be embedded inside other serialized objects.
|
||
*
|
||
* The enum and the companion string-to-int map `kS_TYPE_MAP` are both
|
||
* generated from a single `XMACRO` expansion — adding a new type requires
|
||
* only one line in the macro.
|
||
*
|
||
* @note These numeric values are protocol-stable: changing them would break
|
||
* binary serialization compatibility with existing ledger data and peers.
|
||
*/
|
||
#pragma push_macro("XMACRO")
|
||
#undef XMACRO
|
||
|
||
#define XMACRO(STYPE) \
|
||
/* special types */ \
|
||
STYPE(STI_UNKNOWN, -2) \
|
||
STYPE(STI_NOTPRESENT, 0) \
|
||
STYPE(STI_UINT16, 1) \
|
||
\
|
||
/* types (common) */ \
|
||
STYPE(STI_UINT32, 2) \
|
||
STYPE(STI_UINT64, 3) \
|
||
STYPE(STI_UINT128, 4) \
|
||
STYPE(STI_UINT256, 5) \
|
||
STYPE(STI_AMOUNT, 6) \
|
||
STYPE(STI_VL, 7) \
|
||
STYPE(STI_ACCOUNT, 8) \
|
||
STYPE(STI_NUMBER, 9) \
|
||
STYPE(STI_INT32, 10) \
|
||
STYPE(STI_INT64, 11) \
|
||
\
|
||
/* 12-13 are reserved */ \
|
||
STYPE(STI_OBJECT, 14) \
|
||
STYPE(STI_ARRAY, 15) \
|
||
\
|
||
/* types (uncommon) */ \
|
||
STYPE(STI_UINT8, 16) \
|
||
STYPE(STI_UINT160, 17) \
|
||
STYPE(STI_PATHSET, 18) \
|
||
STYPE(STI_VECTOR256, 19) \
|
||
STYPE(STI_UINT96, 20) \
|
||
STYPE(STI_UINT192, 21) \
|
||
STYPE(STI_UINT384, 22) \
|
||
STYPE(STI_UINT512, 23) \
|
||
STYPE(STI_ISSUE, 24) \
|
||
STYPE(STI_XCHAIN_BRIDGE, 25) \
|
||
STYPE(STI_CURRENCY, 26) \
|
||
\
|
||
/* high-level types */ \
|
||
/* cannot be serialized inside other types */ \
|
||
STYPE(STI_TRANSACTION, 10001) \
|
||
STYPE(STI_LEDGERENTRY, 10002) \
|
||
STYPE(STI_VALIDATION, 10003) \
|
||
STYPE(STI_METADATA, 10004)
|
||
|
||
#pragma push_macro("TO_ENUM")
|
||
#undef TO_ENUM
|
||
#pragma push_macro("TO_MAP")
|
||
#undef TO_MAP
|
||
|
||
#define TO_ENUM(name, value) name = (value),
|
||
#define TO_MAP(name, value) {#name, value},
|
||
|
||
// Protocol infrastructure, 39+ files
|
||
// NOLINTNEXTLINE(cppcoreguidelines-use-enum-class)
|
||
enum SerializedTypeID { XMACRO(TO_ENUM) };
|
||
|
||
/** String-to-integer map of all `SerializedTypeID` values.
|
||
*
|
||
* Generated by the same `XMACRO` expansion as `SerializedTypeID`, so the two
|
||
* are always in sync. Used to resolve type names arriving as text (e.g. from
|
||
* JSON or RPC) to their integer wire codes.
|
||
*/
|
||
static std::map<std::string, int> const kS_TYPE_MAP = {XMACRO(TO_MAP)};
|
||
|
||
#undef XMACRO
|
||
#undef TO_ENUM
|
||
|
||
#pragma pop_macro("XMACRO")
|
||
#pragma pop_macro("TO_ENUM")
|
||
#pragma pop_macro("TO_MAP")
|
||
// NOLINTEND(readability-identifier-naming)
|
||
|
||
/** Pack a `SerializedTypeID` and per-type index into a single field code.
|
||
*
|
||
* The resulting integer is the canonical sort key used for deterministic
|
||
* binary serialization: the upper 16 bits hold the type family and the lower
|
||
* 16 bits hold the field's position within that family. Fields are always
|
||
* serialized in ascending `fieldCode` order.
|
||
*
|
||
* @param id The wire-type family (e.g. `STI_UINT32`).
|
||
* @param index The per-type field index (e.g. 4 for `sfSequence`).
|
||
* @return The packed field code `(id << 16) | index`.
|
||
*/
|
||
inline int
|
||
fieldCode(SerializedTypeID id, int index)
|
||
{
|
||
return (safeCast<int>(id) << 16) | index;
|
||
}
|
||
|
||
/** Pack a raw integer type ID and per-type index into a single field code.
|
||
*
|
||
* Overload for callers that already have the type as a plain `int` (e.g.
|
||
* when deserializing an unknown type from the wire).
|
||
*
|
||
* @param id The wire-type family as a raw integer.
|
||
* @param index The per-type field index.
|
||
* @return The packed field code `(id << 16) | index`.
|
||
*/
|
||
inline int
|
||
fieldCode(int id, int index)
|
||
{
|
||
return (id << 16) | index;
|
||
}
|
||
|
||
/** Identifies a single named field in XRPL's binary serialization protocol.
|
||
*
|
||
* Every field that can appear in a transaction, ledger entry, validation, or
|
||
* transaction metadata is represented by exactly one `SField` singleton. All
|
||
* instances are created at static-initialization time in `SField.cpp` and
|
||
* live until program termination; copy, move, and assignment are deleted to
|
||
* enforce the singleton guarantee.
|
||
*
|
||
* Each field carries a packed `fieldCode` (`(SerializedTypeID << 16) |
|
||
* fieldValue`) that serves as both the registry key and the canonical
|
||
* comparison value for determining binary serialization order. Fields are
|
||
* always serialized in ascending `fieldCode` order — required for
|
||
* deterministic transaction signing.
|
||
*
|
||
* Construction is restricted to `SField.cpp` via `PrivateAccessTagT`: the
|
||
* tag type is forward-declared public here but defined only in that
|
||
* translation unit, so external code can only look up existing fields through
|
||
* `getField()`.
|
||
*
|
||
* @note Debug builds assert that no two fields share the same code or name at
|
||
* registration time. Release builds do not check; a duplicate would
|
||
* silently shadow the earlier field.
|
||
*
|
||
* @see TypedField, fieldCode(), SerializedTypeID
|
||
*/
|
||
class SField
|
||
{
|
||
public:
|
||
/** Never capture this field's value in transaction metadata. */
|
||
static constexpr auto kSMD_NEVER = 0x00;
|
||
/** Capture the original value when the field changes. */
|
||
static constexpr auto kSMD_CHANGE_ORIG = 0x01;
|
||
/** Capture the new value when the field changes. */
|
||
static constexpr auto kSMD_CHANGE_NEW = 0x02;
|
||
/** Capture the final value when the enclosing object is deleted. */
|
||
static constexpr auto kSMD_DELETE_FINAL = 0x04;
|
||
/** Capture the value when the enclosing object is first created. */
|
||
static constexpr auto kSMD_CREATE = 0x08;
|
||
/** Capture the value whenever the enclosing ledger node is touched,
|
||
* regardless of whether the field itself changed (used by `sfRootIndex`). */
|
||
static constexpr auto kSMD_ALWAYS = 0x10;
|
||
/** Display the value in base-10 rather than hex in JSON metadata
|
||
* (used by MPT amount fields such as `sfMaximumAmount`). */
|
||
static constexpr auto kSMD_BASE_TEN = 0x20;
|
||
/** The field holds a 256-bit hash that identifies a pseudo-account
|
||
* (AMM, Vault, LoanBroker). Used by `sfAMMID`, `sfVaultID`,
|
||
* `sfLoanBrokerID`. */
|
||
static constexpr auto kSMD_PSEUDO_ACCOUNT = 0x40;
|
||
/** The field is an `STNumber` that must have `associateAsset()` called
|
||
* before the enclosing ledger object is serialized. The association
|
||
* rounds the value to the asset's precision and removes it if it becomes
|
||
* zero (pairs with `kSMD_DEFAULT`). */
|
||
static constexpr auto kSMD_NEEDS_ASSET = 0x80;
|
||
/** Default metadata flags: record original value, new value, deletion
|
||
* value, and creation value (`kSMD_CHANGE_ORIG | kSMD_CHANGE_NEW |
|
||
* kSMD_DELETE_FINAL | kSMD_CREATE`). */
|
||
static constexpr auto kSMD_DEFAULT =
|
||
kSMD_CHANGE_ORIG | kSMD_CHANGE_NEW | kSMD_DELETE_FINAL | kSMD_CREATE;
|
||
|
||
/** Controls whether a field is included in a transaction's signing payload.
|
||
*
|
||
* Fields that carry signatures (`sfTxnSignature`, `sfSigners`,
|
||
* `sfMasterSignature`, `sfSignature`, `sfCounterpartySignature`) are
|
||
* marked `No` to prevent the bootstrap paradox of a signature covering
|
||
* itself.
|
||
*/
|
||
enum class IsSigning : unsigned char { No, Yes };
|
||
|
||
/** Convenience constant for the non-signing value. */
|
||
static IsSigning const kNOT_SIGNING = IsSigning::No;
|
||
|
||
/** Packed field code: `(SerializedTypeID << 16) | fieldValue`.
|
||
* This is the canonical sort key for binary serialization order.
|
||
* Sentinel values: -1 for `kSF_INVALID`, 0 for `kSF_GENERIC`. */
|
||
int const fieldCodeMem;
|
||
/** Wire-type family for this field (e.g. `STI_UINT32`). */
|
||
SerializedTypeID const fieldType;
|
||
/** Per-type field index. Values < 256 are binary-serializable;
|
||
* values > 256 are JSON-only (discardable). */
|
||
int const fieldValue;
|
||
/** Human-readable field name without the `sf` prefix (e.g. `"Sequence"`). */
|
||
std::string const fieldName;
|
||
/** Bitmask of `kSMD_*` flags controlling transaction metadata capture. */
|
||
int const fieldMeta;
|
||
/** Monotonically increasing registration ordinal (1-based). */
|
||
int const fieldNum;
|
||
/** Whether this field is included in the signing payload. */
|
||
IsSigning const signingField;
|
||
/** JSON key for this field as a `StaticString` (pointer-stable). */
|
||
json::StaticString const jsonName;
|
||
|
||
SField(SField const&) = delete;
|
||
SField&
|
||
operator=(SField const&) = delete;
|
||
SField(SField&&) = delete;
|
||
SField&
|
||
operator=(SField&&) = delete;
|
||
|
||
public:
|
||
/** Construction access guard — public type, private definition.
|
||
*
|
||
* Forward-declared here so the constructor signatures are visible, but
|
||
* the struct body (and its constructor) is defined only in `SField.cpp`.
|
||
* Consequently, only `SField.cpp` can construct `SField` instances.
|
||
*/
|
||
struct PrivateAccessTagT;
|
||
|
||
/** Construct a typed, named protocol field and register it globally.
|
||
*
|
||
* Computes `fieldCode = (tid << 16) | fv` and inserts this field into
|
||
* the `knownCodeToField` and `knownNameToField` lookup tables. Only
|
||
* callable from `SField.cpp` (enforced by `PrivateAccessTagT`).
|
||
*
|
||
* @param tid Serialized type family (e.g. `STI_UINT32`).
|
||
* @param fv Per-type field index; must be < 256 to be
|
||
* binary-serializable.
|
||
* @param fn Human-readable field name (`sf` prefix already stripped
|
||
* by the calling macro).
|
||
* @param meta Bitmask of `kSMD_*` flags; defaults to `kSMD_DEFAULT`.
|
||
* @param signing Whether this field appears in signing payloads; defaults
|
||
* to `IsSigning::Yes`.
|
||
*/
|
||
SField(
|
||
PrivateAccessTagT,
|
||
SerializedTypeID tid,
|
||
int fv,
|
||
char const* fn,
|
||
int meta = kSMD_DEFAULT,
|
||
IsSigning signing = IsSigning::Yes);
|
||
|
||
/** Construct a special-purpose field from a raw field code.
|
||
*
|
||
* Used only for the four historical outlier fields (`kSF_INVALID`,
|
||
* `kSF_GENERIC`, `kSF_HASH`, `kSF_INDEX`) whose codes cannot be derived
|
||
* from the standard `(tid << 16) | fv` formula. Sets `fieldType` to
|
||
* `STI_UNKNOWN` and `fieldMeta` to `kSMD_NEVER`.
|
||
*
|
||
* @param fc Raw field code; -1 for `kSF_INVALID`, 0 for `kSF_GENERIC`.
|
||
* @param fn Human-readable field name.
|
||
*/
|
||
explicit SField(PrivateAccessTagT, int fc, char const* fn);
|
||
|
||
/** Look up a registered field by its packed field code.
|
||
*
|
||
* @param fieldCode Packed code `(SerializedTypeID << 16) | fieldValue`.
|
||
* @return The matching `SField`, or `kSF_INVALID` if none is registered
|
||
* with that code.
|
||
*/
|
||
static SField const&
|
||
getField(int fieldCode);
|
||
|
||
/** Look up a registered field by its human-readable name.
|
||
*
|
||
* Names are stored without the `sf` prefix (e.g. `"Sequence"` not
|
||
* `"sfSequence"`).
|
||
*
|
||
* @param fieldName The name to search for (no `sf` prefix).
|
||
* @return The matching `SField`, or `kSF_INVALID` if none is registered
|
||
* with that name.
|
||
*/
|
||
static SField const&
|
||
getField(std::string const& fieldName);
|
||
|
||
/** Look up a registered field by raw integer type ID and field index.
|
||
*
|
||
* @param type Wire-type family as a raw integer.
|
||
* @param value Per-type field index.
|
||
* @return The matching `SField`, or `kSF_INVALID` if not found.
|
||
*/
|
||
static SField const&
|
||
getField(int type, int value)
|
||
{
|
||
return getField(fieldCode(type, value));
|
||
}
|
||
|
||
/** Look up a registered field by `SerializedTypeID` and field index.
|
||
*
|
||
* @param type Wire-type family.
|
||
* @param value Per-type field index.
|
||
* @return The matching `SField`, or `kSF_INVALID` if not found.
|
||
*/
|
||
static SField const&
|
||
getField(SerializedTypeID type, int value)
|
||
{
|
||
return getField(fieldCode(type, value));
|
||
}
|
||
|
||
/** Return the human-readable field name (without the `sf` prefix). */
|
||
[[nodiscard]] std::string const&
|
||
getName() const
|
||
{
|
||
return fieldName;
|
||
}
|
||
|
||
/** Return true if this field has a meaningful name and positive field code.
|
||
*
|
||
* Returns false for `kSF_INVALID` (`fieldCode == -1`) and `kSF_GENERIC`
|
||
* (`fieldCode == 0`).
|
||
*/
|
||
[[nodiscard]] bool
|
||
hasName() const
|
||
{
|
||
return fieldCodeMem > 0;
|
||
}
|
||
|
||
/** Return the JSON key for this field as a pointer-stable `StaticString`. */
|
||
[[nodiscard]] json::StaticString const&
|
||
getJsonName() const
|
||
{
|
||
return jsonName;
|
||
}
|
||
|
||
/** Implicit conversion to `json::StaticString` for use as a JSON key. */
|
||
operator json::StaticString const&() const
|
||
{
|
||
return jsonName;
|
||
}
|
||
|
||
/** Return true if this field is the `kSF_INVALID` sentinel (`fieldCode == -1`).
|
||
*
|
||
* `getField()` returns `kSF_INVALID` on a lookup miss.
|
||
*/
|
||
[[nodiscard]] bool
|
||
isInvalid() const
|
||
{
|
||
return fieldCodeMem == -1;
|
||
}
|
||
|
||
/** Return true if this field has a positive field code and can carry data.
|
||
*
|
||
* Equivalent to `!isInvalid() && hasName()`; false for `kSF_INVALID` and
|
||
* `kSF_GENERIC`.
|
||
*/
|
||
[[nodiscard]] bool
|
||
isUseful() const
|
||
{
|
||
return fieldCodeMem > 0;
|
||
}
|
||
|
||
/** Return true if this field can be round-tripped through binary serialization.
|
||
*
|
||
* A field is binary-serializable when `fieldValue < 256`. Fields with
|
||
* `fieldValue >= 256` (e.g. `kSF_HASH`, `kSF_INDEX`) exist only in JSON
|
||
* representations and are excluded from binary encoding.
|
||
*/
|
||
[[nodiscard]] bool
|
||
isBinary() const
|
||
{
|
||
return fieldValue < 256;
|
||
}
|
||
|
||
/** Return true if this field must be silently dropped during binary serialization.
|
||
*
|
||
* Discardable fields (e.g. `sfHash`, `sfIndex`) have `fieldValue > 256`
|
||
* and exist only in the JSON form of an object. A round-trip through
|
||
* binary will lose them.
|
||
*/
|
||
[[nodiscard]] bool
|
||
isDiscardable() const
|
||
{
|
||
return fieldValue > 256;
|
||
}
|
||
|
||
/** Return the packed field code `(SerializedTypeID << 16) | fieldValue`. */
|
||
[[nodiscard]] int
|
||
getCode() const
|
||
{
|
||
return fieldCodeMem;
|
||
}
|
||
|
||
/** Return the 1-based registration ordinal assigned at static-init time. */
|
||
[[nodiscard]] int
|
||
getNum() const
|
||
{
|
||
return fieldNum;
|
||
}
|
||
|
||
/** Return the total number of `SField` instances registered so far. */
|
||
static int
|
||
getNumFields()
|
||
{
|
||
return num;
|
||
}
|
||
|
||
/** Return true if any of the bits in `c` are set in this field's metadata mask.
|
||
*
|
||
* @param c A bitmask of one or more `kSMD_*` constants.
|
||
*/
|
||
[[nodiscard]] bool
|
||
shouldMeta(int c) const
|
||
{
|
||
return (fieldMeta & c) != 0;
|
||
}
|
||
|
||
/** Return true if this field should be included in a serialization pass.
|
||
*
|
||
* A field is included when it is binary-serializable (`fieldValue < 256`)
|
||
* and either the caller wants all fields (`withSigningField == true`) or
|
||
* this field is marked `IsSigning::Yes`. Passing `withSigningField ==
|
||
* false` excludes non-signing fields (used when building the signing
|
||
* payload for a transaction).
|
||
*
|
||
* @param withSigningField If false, fields marked `IsSigning::No` are
|
||
* excluded.
|
||
*/
|
||
[[nodiscard]] bool
|
||
shouldInclude(bool withSigningField) const
|
||
{
|
||
return (fieldValue < 256) && (withSigningField || (signingField == IsSigning::Yes));
|
||
}
|
||
|
||
/** Equality based on packed field code. */
|
||
bool
|
||
operator==(SField const& f) const
|
||
{
|
||
return fieldCodeMem == f.fieldCodeMem;
|
||
}
|
||
|
||
/** Inequality based on packed field code. */
|
||
bool
|
||
operator!=(SField const& f) const
|
||
{
|
||
return fieldCodeMem != f.fieldCodeMem;
|
||
}
|
||
|
||
/** Compare two fields by canonical binary-serialization order.
|
||
*
|
||
* Fields are ordered by `fieldCode = (SerializedTypeID << 16) |
|
||
* fieldValue`, sorting first by wire-type family and then by per-type
|
||
* index — matching the canonical XRPL binary format required for
|
||
* deterministic transaction signing.
|
||
*
|
||
* @param f1 First field.
|
||
* @param f2 Second field.
|
||
* @return -1 if `f1` precedes `f2`, 1 if `f1` follows `f2`, or 0 if
|
||
* the comparison is illegal because either field has a non-positive
|
||
* code (`kSF_INVALID` or `kSF_GENERIC`).
|
||
*/
|
||
static int
|
||
compare(SField const& f1, SField const& f2);
|
||
|
||
/** Return a read-only reference to the global code-to-field registry.
|
||
*
|
||
* The map key is the packed field code `(SerializedTypeID << 16) |
|
||
* fieldValue`. Intended for diagnostic and introspection use only;
|
||
* prefer `getField()` for ordinary lookups.
|
||
*/
|
||
static std::unordered_map<int, SField const*> const&
|
||
getKnownCodeToField()
|
||
{
|
||
return knownCodeToField;
|
||
}
|
||
|
||
private:
|
||
static int num;
|
||
static std::unordered_map<int, SField const*> knownCodeToField;
|
||
static std::unordered_map<std::string, SField const*> knownNameToField;
|
||
};
|
||
|
||
/** An `SField` whose associated C++ type is known at compile time.
|
||
*
|
||
* Extends `SField` with a `type` alias so callers can statically verify that
|
||
* a field is read or written with the correct serialized C++ type. For
|
||
* example, `SF_UINT32` is `TypedField<STInteger<uint32_t>>`, making it a
|
||
* compile error to read it as an `STAmount`.
|
||
*
|
||
* All `TypedField` instances are singletons constructed in `SField.cpp`;
|
||
* external code cannot create new instances.
|
||
*
|
||
* @tparam T The serialized C++ type for this field (e.g. `STAmount`,
|
||
* `STInteger<uint32_t>`).
|
||
*
|
||
* @see OptionaledField, operator~
|
||
*/
|
||
template <class T>
|
||
struct TypedField : SField
|
||
{
|
||
using type = T;
|
||
|
||
template <class... Args>
|
||
explicit TypedField(PrivateAccessTagT pat, Args&&... args);
|
||
};
|
||
|
||
/** Wrapper indicating that a `TypedField` may be absent in a given object.
|
||
*
|
||
* Obtained via `operator~(TypedField<T> const&)`. The `STObject` proxy
|
||
* access pattern uses this to return `std::optional<T>` instead of throwing
|
||
* when the field is missing.
|
||
*
|
||
* @tparam T The serialized C++ type of the underlying field.
|
||
*
|
||
* @see operator~
|
||
*/
|
||
template <class T>
|
||
struct OptionaledField
|
||
{
|
||
TypedField<T> const* f;
|
||
|
||
explicit OptionaledField(TypedField<T> const& f) : f(&f)
|
||
{
|
||
}
|
||
};
|
||
|
||
/** Construct an `OptionaledField` from a `TypedField`, expressing optional semantics.
|
||
*
|
||
* Allows callers to write `~sfAmount` instead of `OptionaledField(sfAmount)`.
|
||
* The resulting value is used with the `STObject` proxy access API to obtain
|
||
* an `std::optional<T>` that is empty when the field is absent.
|
||
*
|
||
* @param f The typed field to treat as optional.
|
||
* @return An `OptionaledField<T>` wrapping `f`.
|
||
*/
|
||
template <class T>
|
||
inline OptionaledField<T>
|
||
operator~(TypedField<T> const& f)
|
||
{
|
||
return OptionaledField<T>(f);
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
|
||
/** @defgroup SFieldTypeAliases Typed SField aliases
|
||
* Convenience type aliases pairing each `SerializedTypeID` wire family with
|
||
* its C++ serialized type. Use these as the type of `extern` field
|
||
* declarations so that the field carries full type information at compile
|
||
* time.
|
||
* @{
|
||
*/
|
||
using SF_UINT8 = TypedField<STInteger<std::uint8_t>>;
|
||
using SF_UINT16 = TypedField<STInteger<std::uint16_t>>;
|
||
using SF_UINT32 = TypedField<STInteger<std::uint32_t>>;
|
||
using SF_UINT64 = TypedField<STInteger<std::uint64_t>>;
|
||
using SF_UINT96 = TypedField<STBitString<96>>;
|
||
using SF_UINT128 = TypedField<STBitString<128>>;
|
||
using SF_UINT160 = TypedField<STBitString<160>>;
|
||
using SF_UINT192 = TypedField<STBitString<192>>;
|
||
using SF_UINT256 = TypedField<STBitString<256>>;
|
||
using SF_UINT384 = TypedField<STBitString<384>>;
|
||
using SF_UINT512 = TypedField<STBitString<512>>;
|
||
|
||
using SF_INT32 = TypedField<STInteger<std::int32_t>>;
|
||
using SF_INT64 = TypedField<STInteger<std::int64_t>>;
|
||
|
||
using SF_ACCOUNT = TypedField<STAccount>;
|
||
using SF_AMOUNT = TypedField<STAmount>;
|
||
using SF_ISSUE = TypedField<STIssue>;
|
||
using SF_CURRENCY = TypedField<STCurrency>;
|
||
using SF_NUMBER = TypedField<STNumber>;
|
||
using SF_VL = TypedField<STBlob>;
|
||
using SF_VECTOR256 = TypedField<STVector256>;
|
||
using SF_XCHAIN_BRIDGE = TypedField<STXChainBridge>;
|
||
/** @} */
|
||
|
||
//------------------------------------------------------------------------------
|
||
|
||
// Use macros for most SField construction to enforce naming conventions.
|
||
#pragma push_macro("UNTYPED_SFIELD")
|
||
#undef UNTYPED_SFIELD
|
||
#pragma push_macro("TYPED_SFIELD")
|
||
#undef TYPED_SFIELD
|
||
|
||
#define UNTYPED_SFIELD(sfName, stiSuffix, fieldValue, ...) extern SField const sfName;
|
||
#define TYPED_SFIELD(sfName, stiSuffix, fieldValue, ...) extern SF_##stiSuffix const sfName;
|
||
|
||
/** Sentinel returned by `SField::getField()` on a lookup miss.
|
||
*
|
||
* `fieldCode == -1`; `isInvalid()` returns true. Callers that receive this
|
||
* value should treat the requested field as unrecognized.
|
||
*/
|
||
extern SField const kSF_INVALID;
|
||
|
||
/** Catch-all field for untyped serialization contexts.
|
||
*
|
||
* `fieldCode == 0`; `isUseful()` and `hasName()` return false. Used
|
||
* internally when a context requires an `SField` reference but no specific
|
||
* field is applicable.
|
||
*/
|
||
extern SField const kSF_GENERIC;
|
||
|
||
#include <xrpl/protocol/detail/sfields.macro>
|
||
|
||
#undef TYPED_SFIELD
|
||
#pragma pop_macro("TYPED_SFIELD")
|
||
#undef UNTYPED_SFIELD
|
||
#pragma pop_macro("UNTYPED_SFIELD")
|
||
|
||
} // namespace xrpl
|