#[cfg(not(feature = "std"))]
use alloc::{string::String, vec::Vec};
#[cfg(not(feature = "std"))]
use core::{convert, fmt, iter, ops, str};
#[cfg(feature = "std")]
use std::{convert, fmt, iter, ops, str};
pub const ACCOUNT_ADDRESS_SIZE: usize = 32;
#[cfg(feature = "derive-serde")]
use serde::{Deserialize as SerdeDeserialize, Serialize as SerdeSerialize};
#[repr(transparent)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Amount {
pub micro_gtu: u64,
}
#[cfg(feature = "derive-serde")]
impl SerdeSerialize for Amount {
fn serialize<S: serde::Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
ser.serialize_str(&self.micro_gtu.to_string())
}
}
#[cfg(feature = "derive-serde")]
impl<'de> SerdeDeserialize<'de> for Amount {
fn deserialize<D: serde::de::Deserializer<'de>>(des: D) -> Result<Self, D::Error> {
let s = String::deserialize(des)?;
let micro_gtu = s.parse::<u64>().map_err(|e| serde::de::Error::custom(format!("{}", e)))?;
Ok(Amount {
micro_gtu,
})
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum AmountParseError {
Overflow,
ExpectedDot,
ExpectedDigit,
ExpectedMore,
ExpectedDigitOrDot,
AtMostSixDecimals,
}
impl fmt::Display for AmountParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use AmountParseError::*;
match self {
Overflow => write!(f, "Amount overflow."),
ExpectedDot => write!(f, "Expected dot."),
ExpectedDigit => write!(f, "Expected digit."),
ExpectedMore => write!(f, "Expected more input."),
ExpectedDigitOrDot => write!(f, "Expected digit or dot."),
AtMostSixDecimals => write!(f, "Amounts can have at most six decimals."),
}
}
}
impl str::FromStr for Amount {
type Err = AmountParseError;
fn from_str(v: &str) -> Result<Self, Self::Err> {
let mut micro_gtu: u64 = 0;
let mut after_dot = 0;
let mut state = 0;
for c in v.chars() {
match state {
0 => {
if let Some(d) = c.to_digit(10) {
if d == 0 {
state = 1;
} else {
micro_gtu = u64::from(d);
state = 2;
}
} else {
return Err(AmountParseError::ExpectedDigit);
}
}
1 => {
if c != '.' {
return Err(AmountParseError::ExpectedDot);
} else {
state = 3;
}
}
2 => {
if let Some(d) = c.to_digit(10) {
micro_gtu = micro_gtu.checked_mul(10).ok_or(AmountParseError::Overflow)?;
micro_gtu = micro_gtu
.checked_add(u64::from(d))
.ok_or(AmountParseError::Overflow)?;
} else if c == '.' {
state = 3;
} else {
return Err(AmountParseError::ExpectedDigitOrDot);
}
}
3 => {
if after_dot >= 6 {
return Err(AmountParseError::AtMostSixDecimals);
}
if let Some(d) = c.to_digit(10) {
micro_gtu = micro_gtu.checked_mul(10).ok_or(AmountParseError::Overflow)?;
micro_gtu = micro_gtu
.checked_add(u64::from(d))
.ok_or(AmountParseError::Overflow)?;
after_dot += 1;
} else {
return Err(AmountParseError::ExpectedDigit);
}
}
_ => unreachable!(),
}
}
if state == 0 || state >= 3 && after_dot == 0 {
return Err(AmountParseError::ExpectedMore);
}
for _ in 0..6 - after_dot {
micro_gtu = micro_gtu.checked_mul(10).ok_or(AmountParseError::Overflow)?;
}
Ok(Amount {
micro_gtu,
})
}
}
impl Amount {
#[inline(always)]
pub fn from_micro_gtu(micro_gtu: u64) -> Amount {
Amount {
micro_gtu,
}
}
#[inline(always)]
pub fn from_gtu(gtu: u64) -> Amount {
Amount {
micro_gtu: gtu * 1000000,
}
}
#[inline(always)]
pub fn zero() -> Amount {
Amount {
micro_gtu: 0,
}
}
#[inline(always)]
pub fn add_micro_gtu(self, micro_gtu: u64) -> Amount {
Amount {
micro_gtu: self.micro_gtu + micro_gtu,
}
}
#[inline(always)]
pub fn checked_add(self, other: Amount) -> Option<Amount> {
self.micro_gtu.checked_add(other.micro_gtu).map(Amount::from_micro_gtu)
}
#[inline(always)]
pub fn add_gtu(self, gtu: u64) -> Amount {
Amount {
micro_gtu: self.micro_gtu + gtu * 1000000,
}
}
#[inline(always)]
pub fn subtract_micro_gtu(self, micro_gtu: u64) -> Amount {
Amount {
micro_gtu: self.micro_gtu - micro_gtu,
}
}
#[inline(always)]
pub fn subtract_gtu(self, gtu: u64) -> Amount {
Amount {
micro_gtu: self.micro_gtu - gtu * 1000000,
}
}
#[inline(always)]
pub fn quotient_remainder(self, denominator: u64) -> (Amount, Amount) {
let div = Amount {
micro_gtu: self.micro_gtu / denominator,
};
let rem = self % denominator;
(div, rem)
}
}
impl ops::Mul<u64> for Amount {
type Output = Self;
#[inline(always)]
fn mul(self, other: u64) -> Self::Output {
Amount {
micro_gtu: self.micro_gtu * other,
}
}
}
impl ops::Mul<Amount> for u64 {
type Output = Amount;
#[inline(always)]
fn mul(self, other: Amount) -> Self::Output {
Amount {
micro_gtu: self * other.micro_gtu,
}
}
}
impl ops::Add<Amount> for Amount {
type Output = Self;
#[inline(always)]
fn add(self, other: Amount) -> Self::Output {
Amount {
micro_gtu: self.micro_gtu + other.micro_gtu,
}
}
}
impl ops::Sub<Amount> for Amount {
type Output = Self;
#[inline(always)]
fn sub(self, other: Amount) -> Self::Output {
Amount {
micro_gtu: self.micro_gtu - other.micro_gtu,
}
}
}
impl ops::Rem<u64> for Amount {
type Output = Self;
#[inline(always)]
fn rem(self, other: u64) -> Self::Output {
Amount {
micro_gtu: self.micro_gtu % other,
}
}
}
impl iter::Sum for Amount {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Amount::from_micro_gtu(0), ops::Add::add)
}
}
impl ops::AddAssign for Amount {
#[inline(always)]
fn add_assign(&mut self, other: Amount) { *self = *self + other; }
}
impl ops::SubAssign for Amount {
#[inline(always)]
fn sub_assign(&mut self, other: Amount) { *self = *self - other; }
}
impl ops::MulAssign<u64> for Amount {
#[inline(always)]
fn mul_assign(&mut self, other: u64) { *self = *self * other; }
}
impl ops::RemAssign<u64> for Amount {
#[inline(always)]
fn rem_assign(&mut self, other: u64) { *self = *self % other; }
}
#[repr(transparent)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Timestamp {
pub(crate) milliseconds: u64,
}
impl Timestamp {
#[inline(always)]
pub fn from_timestamp_millis(milliseconds: u64) -> Self {
Self {
milliseconds,
}
}
#[inline(always)]
pub fn timestamp_millis(&self) -> u64 { self.milliseconds }
#[inline(always)]
pub fn checked_add(self, duration: Duration) -> Option<Self> {
self.milliseconds.checked_add(duration.milliseconds).map(Self::from_timestamp_millis)
}
#[inline(always)]
pub fn checked_sub(self, duration: Duration) -> Option<Self> {
self.milliseconds.checked_sub(duration.milliseconds).map(Self::from_timestamp_millis)
}
#[inline(always)]
pub fn duration_between(self, other: Timestamp) -> Duration {
let millis = if self >= other {
self.milliseconds - other.milliseconds
} else {
other.milliseconds - self.milliseconds
};
Duration::from_millis(millis)
}
#[inline(always)]
pub fn duration_since(self, before: Timestamp) -> Option<Duration> {
self.milliseconds.checked_sub(before.milliseconds).map(Duration::from_millis)
}
}
#[cfg(feature = "derive-serde")]
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ParseTimestampError {
ParseError(chrono::format::ParseError),
BeforeUnixEpoch,
}
#[cfg(feature = "derive-serde")]
impl fmt::Display for ParseTimestampError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use ParseTimestampError::*;
match self {
ParseError(err) => err.fmt(f),
BeforeUnixEpoch => write!(f, "Timestamp is before January 1st 1970 00:00."),
}
}
}
#[cfg(feature = "derive-serde")]
impl str::FromStr for Timestamp {
type Err = ParseTimestampError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
use convert::TryInto;
let datetime =
chrono::DateTime::parse_from_rfc3339(s).map_err(ParseTimestampError::ParseError)?;
let millis = datetime
.timestamp_millis()
.try_into()
.map_err(|_| ParseTimestampError::BeforeUnixEpoch)?;
Ok(Timestamp::from_timestamp_millis(millis))
}
}
#[cfg(feature = "derive-serde")]
impl fmt::Display for Timestamp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use chrono::offset::TimeZone;
let time = self.timestamp_millis() as i64;
let date = chrono::Utc.timestamp_millis(time);
write!(f, "{}", date.to_rfc3339())
}
}
#[cfg(feature = "derive-serde")]
impl SerdeSerialize for Timestamp {
fn serialize<S: serde::Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
ser.serialize_str(&self.to_string())
}
}
#[cfg(feature = "derive-serde")]
impl<'de> SerdeDeserialize<'de> for Timestamp {
fn deserialize<D: serde::de::Deserializer<'de>>(des: D) -> Result<Self, D::Error> {
let s = String::deserialize(des)?;
let t = str::FromStr::from_str(&s).map_err(serde::de::Error::custom)?;
Ok(t)
}
}
#[repr(transparent)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Duration {
pub(crate) milliseconds: u64,
}
impl Duration {
#[inline(always)]
pub fn from_millis(milliseconds: u64) -> Self {
Self {
milliseconds,
}
}
#[inline(always)]
pub fn from_seconds(seconds: u64) -> Self { Self::from_millis(seconds * 1000) }
#[inline(always)]
pub fn from_minutes(minutes: u64) -> Self { Self::from_millis(minutes * 1000 * 60) }
#[inline(always)]
pub fn from_hours(hours: u64) -> Self { Self::from_millis(hours * 1000 * 60 * 60) }
#[inline(always)]
pub fn from_days(days: u64) -> Self { Self::from_millis(days * 1000 * 60 * 60 * 24) }
#[inline(always)]
pub fn millis(&self) -> u64 { self.milliseconds }
#[inline(always)]
pub fn seconds(&self) -> u64 { self.milliseconds / 1000 }
#[inline(always)]
pub fn minutes(&self) -> u64 { self.milliseconds / (1000 * 60) }
#[inline(always)]
pub fn hours(&self) -> u64 { self.milliseconds / (1000 * 60 * 60) }
#[inline(always)]
pub fn days(&self) -> u64 { self.milliseconds / (1000 * 60 * 60 * 24) }
#[inline(always)]
pub fn checked_add(self, other: Duration) -> Option<Self> {
self.milliseconds.checked_add(other.milliseconds).map(Self::from_millis)
}
#[inline(always)]
pub fn checked_sub(self, other: Duration) -> Option<Self> {
self.milliseconds.checked_sub(other.milliseconds).map(Self::from_millis)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ParseDurationError {
MissingUnit,
FailedParsingNumber,
InvalidUnit(String),
}
impl fmt::Display for ParseDurationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use ParseDurationError::*;
match self {
MissingUnit => write!(f, "Missing unit on duration measure."),
FailedParsingNumber => write!(f, "Failed parsing number"),
InvalidUnit(s) => write!(f, "Unknown unit \"{}\".", s),
}
}
}
impl str::FromStr for Duration {
type Err = ParseDurationError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
use ParseDurationError::*;
let mut duration = 0;
for measure in s.split_whitespace() {
let split_index = measure.find(|c: char| !c.is_ascii_digit()).ok_or(MissingUnit)?;
let (n, unit) = measure.split_at(split_index);
let n: u64 = n.parse().map_err(|_| FailedParsingNumber)?;
let unit: u64 = match unit {
"ms" => 1,
"s" => 1000,
"m" => 1000 * 60,
"h" => 1000 * 60 * 60,
"d" => 1000 * 60 * 60 * 24,
other => return Err(InvalidUnit(String::from(other))),
};
duration += n * unit;
}
Ok(Duration::from_millis(duration))
}
}
impl fmt::Display for Duration {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
let days = self.days();
let hours = Duration::from_millis(self.millis() % (1000 * 60 * 60 * 24)).hours();
let minutes = Duration::from_millis(self.millis() % (1000 * 60 * 60)).minutes();
let seconds = Duration::from_millis(self.millis() % (1000 * 60)).seconds();
let milliseconds = Duration::from_millis(self.millis() % 1000).millis();
write!(formatter, "{}d {}h {}m {}s {}ms", days, hours, minutes, seconds, milliseconds)
}
}
#[derive(Eq, PartialEq, Copy, Clone, PartialOrd, Ord, Debug)]
pub struct AccountAddress(pub [u8; ACCOUNT_ADDRESS_SIZE]);
impl convert::AsRef<[u8; 32]> for AccountAddress {
fn as_ref(&self) -> &[u8; 32] { &self.0 }
}
impl convert::AsRef<[u8]> for AccountAddress {
fn as_ref(&self) -> &[u8] { &self.0 }
}
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
#[cfg_attr(feature = "derive-serde", derive(SerdeSerialize, SerdeDeserialize))]
pub struct ContractAddress {
pub index: u64,
pub subindex: u64,
}
#[cfg_attr(
feature = "derive-serde",
derive(SerdeSerialize, SerdeDeserialize),
serde(tag = "type", content = "address", rename_all = "lowercase")
)]
#[derive(PartialEq, Eq, Copy, Clone)]
pub enum Address {
Account(AccountAddress),
Contract(ContractAddress),
}
pub type SlotNumber = u64;
pub type BlockHeight = u64;
pub type FinalizedHeight = u64;
pub type SlotTime = Timestamp;
#[cfg_attr(
feature = "derive-serde",
derive(SerdeSerialize, SerdeDeserialize),
serde(rename_all = "camelCase")
)]
pub struct ChainMetadata {
pub slot_time: SlotTime,
}
pub struct Cursor<T> {
pub offset: usize,
pub data: T,
}
#[repr(transparent)]
#[derive(Clone, Copy, Debug, Ord, PartialOrd, Eq, PartialEq)]
pub struct AttributeTag(pub u8);
pub type AttributeValue<'a> = &'a [u8];
pub type OwnedAttributeValue = Vec<u8>;
pub type OwnedPolicy = Policy<Vec<(AttributeTag, OwnedAttributeValue)>>;
pub type IdentityProvider = u32;
#[derive(Debug, Clone)]
pub struct Policy<Attributes> {
pub identity_provider: IdentityProvider,
pub created_at: Timestamp,
pub valid_to: Timestamp,
pub items: Attributes,
}
#[cfg(feature = "derive-serde")]
impl<'de> SerdeDeserialize<'de> for OwnedPolicy {
fn deserialize<D>(deserializer: D) -> Result<OwnedPolicy, D::Error>
where
D: serde::Deserializer<'de>, {
deserializer.deserialize_map(policy_json::OwnedPolicyVisitor)
}
}
#[cfg(feature = "derive-serde")]
mod policy_json {
use super::*;
use convert::{TryFrom, TryInto};
pub(crate) struct OwnedPolicyVisitor;
impl<'de> serde::de::Visitor<'de> for OwnedPolicyVisitor {
type Value = OwnedPolicy;
fn visit_map<A: serde::de::MapAccess<'de>>(
self,
mut map: A,
) -> Result<Self::Value, A::Error> {
let mut idp = None;
let mut ca = None;
let mut vt = None;
let mut items = Vec::new();
let parse_date = |s: &str| {
if !s.chars().all(|c| c.is_numeric() && c.is_ascii()) || s.len() != 6 {
return Err(serde::de::Error::custom("Incorrect YYYYMM format."));
}
let (s_year, s_month) = s.split_at(4);
let year =
s_year.parse::<u16>().map_err(|_| serde::de::Error::custom("Invalid year."))?;
let month = s_month
.parse::<u8>()
.map_err(|_| serde::de::Error::custom("Invalid month."))?;
if month > 12 {
return Err(serde::de::Error::custom("Month out of range."));
}
if year < 1000 {
return Err(serde::de::Error::custom("Year out of range."));
}
let dt = chrono::naive::NaiveDate::from_ymd(i32::from(year), u32::from(month), 1)
.and_hms(0, 0, 0);
let timestamp: u64 = dt.timestamp_millis().try_into().map_err(|_| {
serde::de::Error::custom("Times before 1970 are not supported.")
})?;
Ok(timestamp)
};
while let Some((k, v)) = map.next_entry::<String, serde_json::Value>()? {
match k.as_str() {
"identityProvider" => {
idp = Some(serde_json::from_value(v).map_err(|_| {
serde::de::Error::custom("Unsupported identity provider value.")
})?)
}
"createdAt" => {
if let Some(s) = v.as_str() {
ca = Some(parse_date(s)?);
} else {
return Err(serde::de::Error::custom("Unsupported creation format."));
}
}
"validTo" => {
if let Some(s) = v.as_str() {
vt = Some(parse_date(s)?);
} else {
return Err(serde::de::Error::custom("Unsupported valid to format."));
}
}
s => {
if let Ok(tag) = AttributeTag::try_from(s) {
match v {
serde_json::Value::String(value_string)
if value_string.as_bytes().len() <= 31 =>
{
items.push((tag, value_string.into_bytes()))
}
_ => {
return Err(serde::de::Error::custom(
"Invalid attribute value. Attributes must be at most 31 \
characters in utf8 encoding.",
))
}
}
}
}
}
}
let identity_provider =
idp.ok_or_else(|| serde::de::Error::custom("Missing field 'identityProvider'"))?;
let created_at =
ca.ok_or_else(|| serde::de::Error::custom("Missing field 'createdAt'"))?;
let valid_to = vt.ok_or_else(|| serde::de::Error::custom("Missing field 'validTo'"))?;
Ok(Policy {
identity_provider,
created_at: Timestamp::from_timestamp_millis(created_at),
valid_to: Timestamp::from_timestamp_millis(valid_to),
items,
})
}
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("an object representing a policy.")
}
}
}
pub mod attributes {
use super::{convert, AttributeTag};
pub const FIRST_NAME: AttributeTag = AttributeTag(0u8);
pub const LAST_NAME: AttributeTag = AttributeTag(1u8);
pub const SEX: AttributeTag = AttributeTag(2u8);
pub const DOB: AttributeTag = AttributeTag(3u8);
pub const COUNTRY_OF_RESIDENCE: AttributeTag = AttributeTag(4u8);
pub const NATIONALITY: AttributeTag = AttributeTag(5u8);
pub const ID_DOC_TYPE: AttributeTag = AttributeTag(6u8);
pub const ID_DOC_NUMBER: AttributeTag = AttributeTag(7u8);
pub const ID_DOC_ISSUER: AttributeTag = AttributeTag(8u8);
pub const ID_DOC_ISSUED_AT: AttributeTag = AttributeTag(9u8);
pub const ID_DOC_EXPIRES_AT: AttributeTag = AttributeTag(10u8);
pub const NATIONAL_ID_NO: AttributeTag = AttributeTag(11u8);
pub const TAX_ID_NO: AttributeTag = AttributeTag(12u8);
impl<'a> convert::TryFrom<&'a str> for AttributeTag {
type Error = super::ParseError;
fn try_from(v: &'a str) -> Result<Self, Self::Error> {
match v {
"firstName" => Ok(FIRST_NAME),
"lastName" => Ok(LAST_NAME),
"sex" => Ok(SEX),
"dob" => Ok(DOB),
"countryOfResidence" => Ok(COUNTRY_OF_RESIDENCE),
"nationality" => Ok(NATIONALITY),
"idDocType" => Ok(ID_DOC_TYPE),
"idDocNo" => Ok(ID_DOC_NUMBER),
"idDocIssuer" => Ok(ID_DOC_ISSUER),
"idDocIssuedAt" => Ok(ID_DOC_ISSUED_AT),
"idDocExpiresAt" => Ok(ID_DOC_EXPIRES_AT),
"nationalIdNo" => Ok(NATIONAL_ID_NO),
"taxIdNo" => Ok(TAX_ID_NO),
_ => Err(super::ParseError {}),
}
}
}
}
#[derive(Debug, Default, PartialEq, Eq)]
pub struct ParseError {}
pub type ParseResult<A> = Result<A, ParseError>;
#[cfg(feature = "derive-serde")]
mod serde_impl {
use super::*;
use base58check::*;
use serde::{de, de::Visitor, Deserializer, Serializer};
use std::fmt;
impl str::FromStr for AccountAddress {
type Err = ();
fn from_str(v: &str) -> Result<Self, Self::Err> {
let (version, body) = v.from_base58check().map_err(|_| ())?;
if version == 1 && body.len() == ACCOUNT_ADDRESS_SIZE {
let mut buf = [0u8; ACCOUNT_ADDRESS_SIZE];
buf.copy_from_slice(&body);
Ok(AccountAddress(buf))
} else {
Err(())
}
}
}
impl fmt::Display for AccountAddress {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0.to_base58check(1))
}
}
impl SerdeSerialize for AccountAddress {
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
let b58_str = self.to_string();
ser.serialize_str(&b58_str)
}
}
impl<'de> SerdeDeserialize<'de> for AccountAddress {
fn deserialize<D: Deserializer<'de>>(des: D) -> Result<Self, D::Error> {
des.deserialize_str(Base58Visitor)
}
}
impl fmt::Display for ContractAddress {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "<{},{}>", self.index, self.subindex)
}
}
impl fmt::Display for Amount {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let q = self.micro_gtu / 1000000;
let r = self.micro_gtu % 1000000;
if r == 0 {
write!(f, "{}.0", q)
} else {
write!(f, "{}.{:06}", q, r)
}
}
}
struct Base58Visitor;
impl<'de> Visitor<'de> for Base58Visitor {
type Value = AccountAddress;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "A base58 string, version 1.")
}
fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
v.parse::<AccountAddress>().map_err(|_| de::Error::custom("Wrong Base58 version."))
}
}
}
#[cfg(test)]
mod test {
use super::*;
use std::str::FromStr;
#[test]
fn test_duration_from_string_simple() {
let duration = Duration::from_str("12d 1h 39s 3m 2h").unwrap();
assert_eq!(
duration.millis(),
1000 * 60 * 60 * 24 * 12
+ 1000 * 60 * 60
+ 1000 * 39
+ 1000 * 60 * 3
+ 1000 * 60 * 60 * 2
)
}
}