use crate::de::{DecoderConfig, IDLDeserialize};
use crate::ser::IDLBuilder;
use crate::{CandidType, Error, Result};
use serde::de::Deserialize;
pub fn check_unique<'a, I, T>(sorted: I) -> Result<()>
where
T: 'a + PartialEq + std::fmt::Display,
I: Iterator<Item = &'a T>,
{
let mut prev: Option<&T> = None;
for lab in sorted {
if let Some(prev) = prev {
if lab == prev {
return Err(Error::msg(format!(
"label '{lab}' hash collision with '{prev}'"
)));
}
}
prev = Some(lab);
}
Ok(())
}
pub fn pp_num_str(s: &str) -> String {
let mut groups = Vec::new();
for chunk in s.as_bytes().rchunks(3) {
let str = String::from_utf8_lossy(chunk);
groups.push(str);
}
groups.reverse();
if "-" == groups.first().unwrap() {
"-".to_string() + &groups[1..].join("_")
} else {
groups.join("_")
}
}
#[macro_export]
macro_rules! Encode {
( $($x:expr),* ) => {{
let mut builder = $crate::ser::IDLBuilder::new();
Encode!(@PutValue builder $($x,)*)
}};
( @PutValue $builder:ident $x:expr, $($tail:expr,)* ) => {{
$builder.arg($x).and_then(|builder| Encode!(@PutValue builder $($tail,)*))
}};
( @PutValue $builder:ident ) => {{
$builder.serialize_to_vec()
}};
}
#[macro_export]
macro_rules! Decode {
( $hex:expr $(,$ty:ty)* ) => {{
Decode!([$crate::de::DecoderConfig::new()]; $hex $(,$ty)*)
}};
( [ $config:expr ] ; $hex:expr $(,$ty:ty)* ) => {{
$crate::de::IDLDeserialize::new_with_config($hex, &$config)
.and_then(|mut de| Decode!(@GetValue [] de $($ty,)*)
.and_then(|res| de.done().and(Ok(res))))
}};
(@Debug [ $config:expr ] ; $hex:expr $(,$ty:ty)* ) => {{
$crate::de::IDLDeserialize::new_with_config($hex, &$config)
.and_then(|mut de| Decode!(@GetValue [] de $($ty,)*)
.and_then(|res| de.done().and(Ok((res, de.get_config().compute_cost(&$config))))))
}};
(@GetValue [$($ans:ident)*] $de:ident $ty:ty, $($tail:ty,)* ) => {{
$de.get_value::<$ty>()
.and_then(|val| Decode!(@GetValue [$($ans)* val] $de $($tail,)* ))
}};
(@GetValue [$($ans:ident)*] $de:ident) => {{
Ok(($($ans),*))
}};
}
pub fn decode_args<'a, Tuple>(bytes: &'a [u8]) -> Result<Tuple>
where
Tuple: ArgumentDecoder<'a>,
{
let mut de = IDLDeserialize::new(bytes)?;
let res = ArgumentDecoder::decode(&mut de)?;
de.done()?;
Ok(res)
}
pub fn decode_args_with_config<'a, Tuple>(bytes: &'a [u8], config: &DecoderConfig) -> Result<Tuple>
where
Tuple: ArgumentDecoder<'a>,
{
let mut de = IDLDeserialize::new_with_config(bytes, config)?;
let res = ArgumentDecoder::decode(&mut de)?;
de.done()?;
Ok(res)
}
pub fn decode_args_with_config_debug<'a, Tuple>(
bytes: &'a [u8],
config: &DecoderConfig,
) -> Result<(Tuple, DecoderConfig)>
where
Tuple: ArgumentDecoder<'a>,
{
let mut de = IDLDeserialize::new_with_config(bytes, config)?;
let res = ArgumentDecoder::decode(&mut de)?;
de.done()?;
let cost = de.get_config().compute_cost(config);
Ok((res, cost))
}
pub fn decode_one<'a, T>(bytes: &'a [u8]) -> Result<T>
where
T: Deserialize<'a> + CandidType,
{
let (res,) = decode_args(bytes)?;
Ok(res)
}
pub fn decode_one_with_config<'a, T>(bytes: &'a [u8], config: &DecoderConfig) -> Result<T>
where
T: Deserialize<'a> + CandidType,
{
let (res,) = decode_args_with_config(bytes, config)?;
Ok(res)
}
pub fn write_args<Tuple: ArgumentEncoder, Writer: std::io::Write>(
writer: &mut Writer,
arguments: Tuple,
) -> Result<()> {
let mut ser = IDLBuilder::new();
arguments.encode(&mut ser)?;
ser.serialize(writer)
}
pub fn encode_args<Tuple: ArgumentEncoder>(arguments: Tuple) -> Result<Vec<u8>> {
let mut result = Vec::new();
write_args(&mut result, arguments)?;
Ok(result)
}
pub fn encode_one<T: CandidType>(argument: T) -> Result<Vec<u8>> {
encode_args((argument,))
}
pub trait ArgumentDecoder<'a>: Sized {
fn decode(de: &mut IDLDeserialize<'a>) -> Result<Self>;
}
impl<'a> ArgumentDecoder<'a> for () {
fn decode(_de: &mut IDLDeserialize<'a>) -> Result<()> {
Ok(())
}
}
pub trait ArgumentEncoder {
fn encode(self, ser: &mut IDLBuilder) -> Result<()>;
}
impl ArgumentEncoder for () {
fn encode(self, _de: &mut IDLBuilder) -> Result<()> {
Ok(())
}
}
macro_rules! decode_impl {
( $($id: ident : $typename: ident),* ) => {
impl<'a, $( $typename ),*> ArgumentDecoder<'a> for ($($typename,)*)
where
$( $typename: Deserialize<'a> + CandidType ),*
{
fn decode(de: &mut IDLDeserialize<'a>) -> Result<Self> {
$(
let $id: $typename = de.get_value()?;
)*
Ok(($( $id, )*))
}
}
}
}
macro_rules! encode_impl {
( $($id: ident : $typename: ident),* ) => {
impl<$( $typename ),*> ArgumentEncoder for ($($typename,)*)
where
$( $typename: CandidType ),*
{
fn encode(self, ser: &mut IDLBuilder) -> Result<()> {
let ( $( $id, )* ) = self;
$(
ser.arg(&$id)?;
)*
Ok(())
}
}
}
}
decode_impl!(a: A);
decode_impl!(a: A, b: B);
decode_impl!(a: A, b: B, c: C);
decode_impl!(a: A, b: B, c: C, d: D);
decode_impl!(a: A, b: B, c: C, d: D, e: E);
decode_impl!(a: A, b: B, c: C, d: D, e: E, f: F);
decode_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
decode_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
decode_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
decode_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
#[rustfmt::skip]
decode_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
#[rustfmt::skip]
decode_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L);
#[rustfmt::skip]
decode_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M);
#[rustfmt::skip]
decode_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N);
#[rustfmt::skip]
decode_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O);
#[rustfmt::skip]
decode_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P);
encode_impl!(a: A);
encode_impl!(a: A, b: B);
encode_impl!(a: A, b: B, c: C);
encode_impl!(a: A, b: B, c: C, d: D);
encode_impl!(a: A, b: B, c: C, d: D, e: E);
encode_impl!(a: A, b: B, c: C, d: D, e: E, f: F);
encode_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
encode_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
encode_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
encode_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
#[rustfmt::skip]
encode_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
#[rustfmt::skip]
encode_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L);
#[rustfmt::skip]
encode_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M);
#[rustfmt::skip]
encode_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N);
#[rustfmt::skip]
encode_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O);
#[rustfmt::skip]
encode_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P);