mirror of
https://github.com/XRPLF/rippled.git
synced 2026-09-28 07:48:01 +00:00
Get that strong Bips field type working (mostly)
This commit is contained in:
@@ -49,13 +49,14 @@ template <int>
|
||||
class STBitString;
|
||||
template <class>
|
||||
class STInteger;
|
||||
template <class>
|
||||
class STTypedInteger;
|
||||
class STNumber;
|
||||
class STXChainBridge;
|
||||
class STVector256;
|
||||
class STCurrency;
|
||||
|
||||
template <class Integer>
|
||||
concept HasValue = requires(Integer i) { i.value(); };
|
||||
|
||||
#pragma push_macro("XMACRO")
|
||||
#undef XMACRO
|
||||
|
||||
@@ -366,8 +367,8 @@ using SF_UINT512 = TypedField<STBitString<512>>;
|
||||
// The tag is only applied when deserialized.
|
||||
//
|
||||
// Tenth of a basis point values:
|
||||
using SF_TENTHBIPS16 = TypedField<STTypedInteger<TenthBips16>>;
|
||||
using SF_TENTHBIPS32 = TypedField<STTypedInteger<TenthBips32>>;
|
||||
using SF_TENTHBIPS16 = TypedField<STInteger<TenthBips16>>;
|
||||
using SF_TENTHBIPS32 = TypedField<STInteger<TenthBips32>>;
|
||||
|
||||
using SF_ACCOUNT = TypedField<STAccount>;
|
||||
using SF_AMOUNT = TypedField<STAmount>;
|
||||
|
||||
@@ -62,22 +62,22 @@ struct STExchange<STInteger<U>, T>
|
||||
};
|
||||
|
||||
template <class U, class T>
|
||||
struct STExchange<STTypedInteger<U>, T>
|
||||
struct STExchange<STInteger<TenthBips<U>>, T>
|
||||
{
|
||||
explicit STExchange() = default;
|
||||
|
||||
using value_type = U;
|
||||
using value_type = TenthBips<U>;
|
||||
|
||||
static void
|
||||
get(std::optional<T>& t, STTypedInteger<U> const& u)
|
||||
get(std::optional<T>& t, STInteger<value_type> const& u)
|
||||
{
|
||||
t = u.value();
|
||||
}
|
||||
|
||||
static std::unique_ptr<STInteger<U>>
|
||||
static std::unique_ptr<STInteger<value_type>>
|
||||
set(SField const& f, T const& t)
|
||||
{
|
||||
return std::make_unique<STTypedInteger<U>>(f, t);
|
||||
return std::make_unique<STInteger<value_type>>(f, t);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ private:
|
||||
|
||||
public:
|
||||
explicit STInteger(Integer v);
|
||||
STInteger(SField const& n, Integer v = 0);
|
||||
STInteger(SField const& n, Integer v = {});
|
||||
STInteger(SerialIter& sit, SField const& name);
|
||||
|
||||
SerializedTypeID
|
||||
@@ -82,42 +82,9 @@ using STUInt16 = STInteger<std::uint16_t>;
|
||||
using STUInt32 = STInteger<std::uint32_t>;
|
||||
using STUInt64 = STInteger<std::uint64_t>;
|
||||
|
||||
template <class TypedInteger>
|
||||
class STTypedInteger : public STInteger<typename TypedInteger::value_type>,
|
||||
public CountedObject<STTypedInteger<TypedInteger>>
|
||||
{
|
||||
public:
|
||||
using value_type = TypedInteger;
|
||||
using base_value_type = TypedInteger::value_type;
|
||||
using base = STInteger<base_value_type>;
|
||||
|
||||
public:
|
||||
using base::add;
|
||||
using base::getJson;
|
||||
using base::getSType;
|
||||
using base::getText;
|
||||
using base::isDefault;
|
||||
using base::isEquivalent;
|
||||
using base::STInteger;
|
||||
|
||||
SerializedTypeID
|
||||
getSType() const override;
|
||||
|
||||
STTypedInteger&
|
||||
operator=(value_type const& v);
|
||||
|
||||
value_type
|
||||
value() const noexcept;
|
||||
|
||||
void
|
||||
setValue(TypedInteger v);
|
||||
|
||||
operator TypedInteger() const;
|
||||
};
|
||||
|
||||
// Tenth of a basis point values:
|
||||
using STTenthBips16 = STTypedInteger<TenthBips16>;
|
||||
using STTenthBips32 = STTypedInteger<TenthBips32>;
|
||||
using STTenthBips16 = STInteger<TenthBips16>;
|
||||
using STTenthBips32 = STInteger<TenthBips32>;
|
||||
|
||||
template <typename Integer>
|
||||
inline STInteger<Integer>::STInteger(Integer v) : value_(v)
|
||||
@@ -199,34 +166,6 @@ inline STInteger<Integer>::operator Integer() const
|
||||
return value_;
|
||||
}
|
||||
|
||||
template <typename TypedInteger>
|
||||
inline STTypedInteger<TypedInteger>&
|
||||
STTypedInteger<TypedInteger>::operator=(value_type const& v)
|
||||
{
|
||||
base::setValue(v.value());
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename TypedInteger>
|
||||
inline typename STTypedInteger<TypedInteger>::value_type
|
||||
STTypedInteger<TypedInteger>::value() const noexcept
|
||||
{
|
||||
return value_type(base::value());
|
||||
}
|
||||
|
||||
template <typename TypedInteger>
|
||||
inline void
|
||||
STTypedInteger<TypedInteger>::setValue(TypedInteger v)
|
||||
{
|
||||
base::setValue(v.value());
|
||||
}
|
||||
|
||||
template <typename TypedInteger>
|
||||
inline STTypedInteger<TypedInteger>::operator TypedInteger() const
|
||||
{
|
||||
return TypedInteger(base::value());
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -125,8 +125,17 @@ public:
|
||||
}
|
||||
|
||||
template <typename Integer>
|
||||
requires(!HasValue<Integer>)
|
||||
int addInteger(Integer);
|
||||
|
||||
template <typename Integer>
|
||||
requires HasValue<Integer>
|
||||
int
|
||||
addInteger(Integer i)
|
||||
{
|
||||
return addInteger(i.value());
|
||||
}
|
||||
|
||||
template <std::size_t Bits, class Tag>
|
||||
int
|
||||
addBitString(base_uint<Bits, Tag> const& v)
|
||||
|
||||
@@ -592,6 +592,17 @@ safe_cast(Src s) noexcept
|
||||
return Dest{safe_cast<typename Dest::value_type>(s.value())};
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
constexpr std::enable_if_t<
|
||||
std::is_integral_v<typename Dest::value_type> &&
|
||||
std::is_integral_v<typename Src>,
|
||||
Dest>
|
||||
safe_cast(Src s) noexcept
|
||||
{
|
||||
// Dest may not have an explicit value constructor
|
||||
return Dest{safe_cast<typename Dest::value_type>(s)};
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
constexpr std::enable_if_t<
|
||||
std::is_same_v<typename Dest::unit_type, typename Src::unit_type> &&
|
||||
@@ -604,6 +615,17 @@ unsafe_cast(Src s) noexcept
|
||||
return Dest{unsafe_cast<typename Dest::value_type>(s.value())};
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
constexpr std::enable_if_t<
|
||||
std::is_integral_v<typename Dest::value_type> &&
|
||||
std::is_integral_v<typename Src>,
|
||||
Dest>
|
||||
unsafe_cast(Src s) noexcept
|
||||
{
|
||||
// Dest may not have an explicit value constructor
|
||||
return Dest{unsafe_cast<typename Dest::value_type>(s)};
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif // PROTOCOL_UNITS_H_INCLUDED
|
||||
|
||||
@@ -229,18 +229,62 @@ STUInt64::getJson(JsonOptions) const
|
||||
return convertToString(value_, 16); // Convert to base 16
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <>
|
||||
STTenthBips16::STInteger(SerialIter& sit, SField const& name)
|
||||
: STInteger(name, TenthBips16(sit.get16()))
|
||||
{
|
||||
}
|
||||
|
||||
template <>
|
||||
SerializedTypeID
|
||||
STTenthBips16::getSType() const override
|
||||
STTenthBips16::getSType() const
|
||||
{
|
||||
return STI_TENTHBIPS16;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string
|
||||
STTenthBips16::getText() const
|
||||
{
|
||||
return std::to_string(value_.value());
|
||||
}
|
||||
|
||||
template <>
|
||||
Json::Value
|
||||
STTenthBips16::getJson(JsonOptions) const
|
||||
{
|
||||
return value_.value();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <>
|
||||
STTenthBips32::STInteger(SerialIter& sit, SField const& name)
|
||||
: STInteger(name, TenthBips32(sit.get32()))
|
||||
{
|
||||
}
|
||||
|
||||
template <>
|
||||
SerializedTypeID
|
||||
STTenthBips32::getSType() const override
|
||||
STTenthBips32::getSType() const
|
||||
{
|
||||
return STI_TENTHBIPS32;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string
|
||||
STTenthBips32::getText() const
|
||||
{
|
||||
return std::to_string(value_.value());
|
||||
}
|
||||
|
||||
template <>
|
||||
Json::Value
|
||||
STTenthBips32::getJson(JsonOptions) const
|
||||
{
|
||||
return value_.value();
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -82,6 +82,31 @@ constexpr std::
|
||||
return static_cast<U1>(value);
|
||||
}
|
||||
|
||||
template <typename U, typename S>
|
||||
requires HasValue<U>
|
||||
constexpr std::enable_if_t<
|
||||
std::is_unsigned<typename U::value_type>::value && std::is_signed<S>::value,
|
||||
U>
|
||||
to_unsigned(S value)
|
||||
{
|
||||
if (value < 0 || std::numeric_limits<typename U::value_type>::max() < value)
|
||||
Throw<std::runtime_error>("Value out of range");
|
||||
return safe_cast<U>(static_cast<typename U::value_type>(value));
|
||||
}
|
||||
|
||||
template <typename U1, typename U2>
|
||||
requires HasValue<U1>
|
||||
constexpr std::enable_if_t<
|
||||
std::is_unsigned<typename U1::value_type>::value &&
|
||||
std::is_unsigned<U2>::value,
|
||||
U1>
|
||||
to_unsigned(U2 value)
|
||||
{
|
||||
if (std::numeric_limits<typename U1::value_type>::max() < value)
|
||||
Throw<std::runtime_error>("Value out of range");
|
||||
return safe_cast<U1>(static_cast<typename U1::value_type>(value));
|
||||
}
|
||||
|
||||
static std::string
|
||||
make_name(std::string const& object, std::string const& field)
|
||||
{
|
||||
@@ -201,6 +226,119 @@ non_object_in_array(std::string const& item, Json::UInt index)
|
||||
" is not an object. Arrays may only contain objects.");
|
||||
}
|
||||
|
||||
template <class STResult, class Integer>
|
||||
static std::optional<detail::STVar>
|
||||
parseUnsigned(
|
||||
SField const& field,
|
||||
std::string const& json_name,
|
||||
std::string const& fieldName,
|
||||
SField const* name,
|
||||
Json::Value const& value,
|
||||
Json::Value& error)
|
||||
{
|
||||
std::optional<detail::STVar> ret;
|
||||
|
||||
try
|
||||
{
|
||||
if (value.isString())
|
||||
{
|
||||
ret = detail::make_stvar<STResult>(
|
||||
field,
|
||||
safe_cast<typename STResult::value_type>(
|
||||
beast::lexicalCastThrow<Integer>(value.asString())));
|
||||
}
|
||||
else if (value.isInt())
|
||||
{
|
||||
ret = detail::make_stvar<STResult>(
|
||||
field,
|
||||
to_unsigned<typename STResult::value_type>(value.asInt()));
|
||||
}
|
||||
else if (value.isUInt())
|
||||
{
|
||||
ret = detail::make_stvar<STResult>(
|
||||
field,
|
||||
to_unsigned<typename STResult::value_type>(value.asUInt()));
|
||||
}
|
||||
else
|
||||
{
|
||||
error = bad_type(json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
error = invalid_data(json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class STResult>
|
||||
static std::optional<detail::STVar>
|
||||
parseUint16(
|
||||
SField const& field,
|
||||
std::string const& json_name,
|
||||
std::string const& fieldName,
|
||||
SField const* name,
|
||||
Json::Value const& value,
|
||||
Json::Value& error)
|
||||
{
|
||||
std::optional<detail::STVar> ret;
|
||||
|
||||
try
|
||||
{
|
||||
if (value.isString())
|
||||
{
|
||||
std::string const strValue = value.asString();
|
||||
|
||||
if (!strValue.empty() &&
|
||||
((strValue[0] < '0') || (strValue[0] > '9')))
|
||||
{
|
||||
if (field == sfTransactionType)
|
||||
{
|
||||
ret = detail::make_stvar<STResult>(
|
||||
field,
|
||||
safe_cast<typename STResult::value_type>(
|
||||
static_cast<std::uint16_t>(
|
||||
TxFormats::getInstance().findTypeByName(
|
||||
strValue))));
|
||||
|
||||
if (*name == sfGeneric)
|
||||
name = &sfTransaction;
|
||||
}
|
||||
else if (field == sfLedgerEntryType)
|
||||
{
|
||||
ret = detail::make_stvar<STResult>(
|
||||
field,
|
||||
safe_cast<typename STResult::value_type>(
|
||||
static_cast<std::uint16_t>(
|
||||
LedgerFormats::getInstance().findTypeByName(
|
||||
strValue))));
|
||||
|
||||
if (*name == sfGeneric)
|
||||
name = &sfLedgerEntry;
|
||||
}
|
||||
else
|
||||
{
|
||||
error = invalid_data(json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ret)
|
||||
return parseUnsigned<STResult, std::uint16_t>(
|
||||
field, json_name, fieldName, name, value, error);
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
error = invalid_data(json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// This function is used by parseObject to parse any JSON type that doesn't
|
||||
// recurse. Everything represented here is a leaf-type.
|
||||
static std::optional<detail::STVar>
|
||||
@@ -301,105 +439,34 @@ parseLeaf(
|
||||
break;
|
||||
|
||||
case STI_UINT16:
|
||||
try
|
||||
{
|
||||
if (value.isString())
|
||||
{
|
||||
std::string const strValue = value.asString();
|
||||
|
||||
if (!strValue.empty() &&
|
||||
((strValue[0] < '0') || (strValue[0] > '9')))
|
||||
{
|
||||
if (field == sfTransactionType)
|
||||
{
|
||||
ret = detail::make_stvar<STUInt16>(
|
||||
field,
|
||||
static_cast<std::uint16_t>(
|
||||
TxFormats::getInstance().findTypeByName(
|
||||
strValue)));
|
||||
|
||||
if (*name == sfGeneric)
|
||||
name = &sfTransaction;
|
||||
}
|
||||
else if (field == sfLedgerEntryType)
|
||||
{
|
||||
ret = detail::make_stvar<STUInt16>(
|
||||
field,
|
||||
static_cast<std::uint16_t>(
|
||||
LedgerFormats::getInstance().findTypeByName(
|
||||
strValue)));
|
||||
|
||||
if (*name == sfGeneric)
|
||||
name = &sfLedgerEntry;
|
||||
}
|
||||
else
|
||||
{
|
||||
error = invalid_data(json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = detail::make_stvar<STUInt16>(
|
||||
field,
|
||||
beast::lexicalCastThrow<std::uint16_t>(strValue));
|
||||
}
|
||||
}
|
||||
else if (value.isInt())
|
||||
{
|
||||
ret = detail::make_stvar<STUInt16>(
|
||||
field, to_unsigned<std::uint16_t>(value.asInt()));
|
||||
}
|
||||
else if (value.isUInt())
|
||||
{
|
||||
ret = detail::make_stvar<STUInt16>(
|
||||
field, to_unsigned<std::uint16_t>(value.asUInt()));
|
||||
}
|
||||
else
|
||||
{
|
||||
error = bad_type(json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
error = invalid_data(json_name, fieldName);
|
||||
ret = parseUint16<STUInt16>(
|
||||
field, json_name, fieldName, name, value, error);
|
||||
if (!ret)
|
||||
return ret;
|
||||
|
||||
break;
|
||||
|
||||
case STI_TENTHBIPS16:
|
||||
ret = parseUnsigned<STTenthBips16, std::uint16_t>(
|
||||
field, json_name, fieldName, name, value, error);
|
||||
if (!ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case STI_UINT32:
|
||||
try
|
||||
{
|
||||
if (value.isString())
|
||||
{
|
||||
ret = detail::make_stvar<STUInt32>(
|
||||
field,
|
||||
beast::lexicalCastThrow<std::uint32_t>(
|
||||
value.asString()));
|
||||
}
|
||||
else if (value.isInt())
|
||||
{
|
||||
ret = detail::make_stvar<STUInt32>(
|
||||
field, to_unsigned<std::uint32_t>(value.asInt()));
|
||||
}
|
||||
else if (value.isUInt())
|
||||
{
|
||||
ret = detail::make_stvar<STUInt32>(
|
||||
field, safe_cast<std::uint32_t>(value.asUInt()));
|
||||
}
|
||||
else
|
||||
{
|
||||
error = bad_type(json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
error = invalid_data(json_name, fieldName);
|
||||
ret = parseUnsigned<STUInt32, std::uint32_t>(
|
||||
field, json_name, fieldName, name, value, error);
|
||||
if (!ret)
|
||||
return ret;
|
||||
|
||||
break;
|
||||
|
||||
case STI_TENTHBIPS32:
|
||||
ret = parseUnsigned<STTenthBips32, std::uint32_t>(
|
||||
field, json_name, fieldName, name, value, error);
|
||||
if (!ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
||||
@@ -805,7 +805,7 @@ class Simulate_test : public beast::unit_test::suite
|
||||
testTx(env, tx, testSimulation);
|
||||
|
||||
tx[sfSigningPubKey] = "";
|
||||
tx[sfTxnSignature] = "x";
|
||||
tx[sfTxnSignature] = "";
|
||||
tx[sfSequence] = env.seq(env.master);
|
||||
tx[sfFee] = env.current()->fees().base.jsonClipped().asString();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user