use std::{
fmt,
fmt::{Debug, Display, Formatter, Write},
marker::PhantomData,
ops::Deref,
str::FromStr,
};
use fastcrypto::encoding::Hex;
use iota_protocol_config::ProtocolVersion;
use move_core_types::{
account_address::AccountAddress,
language_storage::{StructTag, TypeTag},
};
use schemars::JsonSchema;
use serde::{
self, Deserialize, Serialize,
de::{Deserializer, Error},
ser::{Error as SerError, Serializer},
};
use serde_with::{Bytes, DeserializeAs, DisplayFromStr, SerializeAs, serde_as};
use crate::{
IOTA_CLOCK_ADDRESS, IOTA_FRAMEWORK_ADDRESS, IOTA_SYSTEM_ADDRESS, IOTA_SYSTEM_STATE_ADDRESS,
STARDUST_ADDRESS, parse_iota_struct_tag, parse_iota_type_tag,
};
#[inline]
fn to_custom_error<'de, D, E>(e: E) -> D::Error
where
E: Debug,
D: Deserializer<'de>,
{
Error::custom(format!("byte deserialization failed, cause by: {:?}", e))
}
#[inline]
fn to_custom_ser_error<S, E>(e: E) -> S::Error
where
E: Debug,
S: Serializer,
{
S::Error::custom(format!("byte serialization failed, cause by: {:?}", e))
}
pub struct Readable<H, R> {
human_readable: PhantomData<H>,
non_human_readable: PhantomData<R>,
}
impl<T: ?Sized, H, R> SerializeAs<T> for Readable<H, R>
where
H: SerializeAs<T>,
R: SerializeAs<T>,
{
fn serialize_as<S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if serializer.is_human_readable() {
H::serialize_as(value, serializer)
} else {
R::serialize_as(value, serializer)
}
}
}
impl<'de, R, H, T> DeserializeAs<'de, T> for Readable<H, R>
where
H: DeserializeAs<'de, T>,
R: DeserializeAs<'de, T>,
{
fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
{
if deserializer.is_human_readable() {
H::deserialize_as(deserializer)
} else {
R::deserialize_as(deserializer)
}
}
}
pub struct HexAccountAddress;
impl SerializeAs<AccountAddress> for HexAccountAddress {
fn serialize_as<S>(value: &AccountAddress, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
Hex::serialize_as(value, serializer)
}
}
impl<'de> DeserializeAs<'de, AccountAddress> for HexAccountAddress {
fn deserialize_as<D>(deserializer: D) -> Result<AccountAddress, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
if s.starts_with("0x") {
AccountAddress::from_hex_literal(&s)
} else {
AccountAddress::from_hex(&s)
}
.map_err(to_custom_error::<'de, D, _>)
}
}
pub struct IotaBitmap;
impl SerializeAs<roaring::RoaringBitmap> for IotaBitmap {
fn serialize_as<S>(source: &roaring::RoaringBitmap, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut bytes = vec![];
source
.serialize_into(&mut bytes)
.map_err(to_custom_ser_error::<S, _>)?;
Bytes::serialize_as(&bytes, serializer)
}
}
impl<'de> DeserializeAs<'de, roaring::RoaringBitmap> for IotaBitmap {
fn deserialize_as<D>(deserializer: D) -> Result<roaring::RoaringBitmap, D::Error>
where
D: Deserializer<'de>,
{
let bytes: Vec<u8> = Bytes::deserialize_as(deserializer)?;
roaring::RoaringBitmap::deserialize_from(&bytes[..]).map_err(to_custom_error::<'de, D, _>)
}
}
pub struct IotaStructTag;
impl SerializeAs<StructTag> for IotaStructTag {
fn serialize_as<S>(value: &StructTag, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let f = to_iota_struct_tag_string(value).map_err(S::Error::custom)?;
f.serialize(serializer)
}
}
const IOTA_ADDRESSES: [AccountAddress; 7] = [
AccountAddress::ZERO,
AccountAddress::ONE,
IOTA_FRAMEWORK_ADDRESS,
IOTA_SYSTEM_ADDRESS,
STARDUST_ADDRESS,
IOTA_SYSTEM_STATE_ADDRESS,
IOTA_CLOCK_ADDRESS,
];
pub fn to_iota_struct_tag_string(value: &StructTag) -> Result<String, fmt::Error> {
let mut f = String::new();
let address = if IOTA_ADDRESSES.contains(&value.address) {
value.address.short_str_lossless()
} else {
value.address.to_canonical_string(false)
};
write!(f, "0x{}::{}::{}", address, value.module, value.name)?;
if let Some(first_ty) = value.type_params.first() {
write!(f, "<")?;
write!(f, "{}", to_iota_type_tag_string(first_ty)?)?;
for ty in value.type_params.iter().skip(1) {
write!(f, ", {}", to_iota_type_tag_string(ty)?)?;
}
write!(f, ">")?;
}
Ok(f)
}
fn to_iota_type_tag_string(value: &TypeTag) -> Result<String, fmt::Error> {
match value {
TypeTag::Vector(t) => Ok(format!("vector<{}>", to_iota_type_tag_string(t)?)),
TypeTag::Struct(s) => to_iota_struct_tag_string(s),
_ => Ok(value.to_string()),
}
}
impl<'de> DeserializeAs<'de, StructTag> for IotaStructTag {
fn deserialize_as<D>(deserializer: D) -> Result<StructTag, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
parse_iota_struct_tag(&s).map_err(D::Error::custom)
}
}
pub struct IotaTypeTag;
impl SerializeAs<TypeTag> for IotaTypeTag {
fn serialize_as<S>(value: &TypeTag, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = to_iota_type_tag_string(value).map_err(S::Error::custom)?;
s.serialize(serializer)
}
}
impl<'de> DeserializeAs<'de, TypeTag> for IotaTypeTag {
fn deserialize_as<D>(deserializer: D) -> Result<TypeTag, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
parse_iota_type_tag(&s).map_err(D::Error::custom)
}
}
#[serde_as]
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Copy, JsonSchema)]
pub struct BigInt<T>(
#[schemars(with = "String")]
#[serde_as(as = "DisplayFromStr")]
T,
)
where
T: Display + FromStr,
<T as FromStr>::Err: Display;
impl<T> BigInt<T>
where
T: Display + FromStr,
<T as FromStr>::Err: Display,
{
pub fn into_inner(self) -> T {
self.0
}
}
impl<T> SerializeAs<T> for BigInt<T>
where
T: Display + FromStr + Copy,
<T as FromStr>::Err: Display,
{
fn serialize_as<S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
BigInt(*value).serialize(serializer)
}
}
impl<'de, T> DeserializeAs<'de, T> for BigInt<T>
where
T: Display + FromStr + Copy,
<T as FromStr>::Err: Display,
{
fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
{
Ok(*BigInt::deserialize(deserializer)?)
}
}
impl<T> From<T> for BigInt<T>
where
T: Display + FromStr,
<T as FromStr>::Err: Display,
{
fn from(v: T) -> BigInt<T> {
BigInt(v)
}
}
impl<T> Deref for BigInt<T>
where
T: Display + FromStr,
<T as FromStr>::Err: Display,
{
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> Display for BigInt<T>
where
T: Display + FromStr,
<T as FromStr>::Err: Display,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[serde_as]
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Copy, JsonSchema)]
pub struct SequenceNumber(#[schemars(with = "BigInt<u64>")] u64);
impl SerializeAs<crate::base_types::SequenceNumber> for SequenceNumber {
fn serialize_as<S>(
value: &crate::base_types::SequenceNumber,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = value.value().to_string();
s.serialize(serializer)
}
}
impl<'de> DeserializeAs<'de, crate::base_types::SequenceNumber> for SequenceNumber {
fn deserialize_as<D>(deserializer: D) -> Result<crate::base_types::SequenceNumber, D::Error>
where
D: Deserializer<'de>,
{
let b = BigInt::deserialize(deserializer)?;
Ok(crate::base_types::SequenceNumber::from_u64(*b))
}
}
#[serde_as]
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Copy, JsonSchema)]
#[serde(rename = "ProtocolVersion")]
pub struct AsProtocolVersion(#[schemars(with = "BigInt<u64>")] u64);
impl SerializeAs<ProtocolVersion> for AsProtocolVersion {
fn serialize_as<S>(value: &ProtocolVersion, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = value.as_u64().to_string();
s.serialize(serializer)
}
}
impl<'de> DeserializeAs<'de, ProtocolVersion> for AsProtocolVersion {
fn deserialize_as<D>(deserializer: D) -> Result<ProtocolVersion, D::Error>
where
D: Deserializer<'de>,
{
let b = BigInt::<u64>::deserialize(deserializer)?;
Ok(ProtocolVersion::from(*b))
}
}