use core::str::FromStr;
use ibc_primitives::prelude::*;
use super::ClientId;
use crate::error::IdentifierError;
use crate::validate::validate_client_type;
#[cfg_attr(
feature = "parity-scale-codec",
derive(
parity_scale_codec::Encode,
parity_scale_codec::Decode,
scale_info::TypeInfo
)
)]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, derive_more::Display)]
pub struct ClientType(String);
impl ClientType {
pub fn new(client_type: &str) -> Result<Self, IdentifierError> {
let client_type = client_type.trim();
validate_client_type(client_type).map(|()| Self(client_type.into()))
}
pub fn build_client_id(&self, counter: u64) -> ClientId {
ClientId::format(self.as_str(), counter)
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl FromStr for ClientType {
type Err = IdentifierError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::new(s)
}
}
#[cfg(test)]
mod test {
use rstest::rstest;
use super::*;
#[rstest]
#[case::tendermint("07-tendermint")]
#[case::wasm("08-wasm")]
#[case::zero_double_digits("00-dummy")]
#[case::zero_single_digit("0-dummy")]
#[case::length_seven("1234567")]
fn client_type_from_str(#[case] client_str: &str) {
let client_type = ClientType::from_str(client_str).unwrap();
assert_eq!(client_type.as_str(), client_str);
}
#[rstest]
#[case::length_less_than_seven("00-foo")]
#[case::length_six("123456")]
fn client_type_from_str_fails(#[case] client_str: &str) {
let client_type = ClientType::from_str(client_str);
assert!(client_type.is_err());
}
#[rstest]
#[case::tendermint("07-tendermint", 118)]
#[case::wasm("08-wasm", 2)]
#[case::zero_counter("01-dummy", 0)]
fn client_type_build_client_id(#[case] client_str: &str, #[case] counter: u64) {
let client_type = ClientType::from_str(client_str).unwrap();
let client_id = client_type.build_client_id(counter);
assert_eq!(client_id.as_str(), format!("{}-{}", client_str, counter));
}
}