defuse_token_id/
nep245.rs1pub use defuse_nep245::TokenId;
2
3use std::{fmt, str::FromStr};
4
5use near_sdk::{AccountId, near};
6use serde_with::{DeserializeFromStr, SerializeDisplay};
7
8use crate::{TokenIdType, error::TokenIdError};
9
10#[cfg_attr(any(feature = "arbitrary", test), derive(::arbitrary::Arbitrary))]
11#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, SerializeDisplay, DeserializeFromStr)]
12#[near(serializers = [borsh])]
13pub struct Nep245TokenId {
14 pub contract_id: AccountId,
15
16 pub mt_token_id: TokenId,
17}
18
19impl Nep245TokenId {
20 pub fn new(contract_id: impl Into<AccountId>, mt_token_id: impl Into<TokenId>) -> Self {
21 Self {
22 contract_id: contract_id.into(),
23 mt_token_id: mt_token_id.into(),
24 }
25 }
26}
27
28impl std::fmt::Debug for Nep245TokenId {
29 #[inline]
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 write!(f, "{}:{}", &self.contract_id, &self.mt_token_id)
32 }
33}
34
35impl std::fmt::Display for Nep245TokenId {
36 #[inline]
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 fmt::Debug::fmt(&self, f)
39 }
40}
41
42impl FromStr for Nep245TokenId {
43 type Err = TokenIdError;
44
45 fn from_str(data: &str) -> Result<Self, Self::Err> {
46 let (contract_id, token_id) = data
47 .split_once(':')
48 .ok_or(strum::ParseError::VariantNotFound)?;
49 Ok(Self::new(contract_id.parse::<AccountId>()?, token_id))
50 }
51}
52
53impl From<&Nep245TokenId> for TokenIdType {
54 #[inline]
55 fn from(_: &Nep245TokenId) -> Self {
56 Self::Nep245
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63
64 use defuse_test_utils::random::make_arbitrary;
65 use rstest::rstest;
66
67 #[rstest]
68 #[trace]
69 fn display_from_str_roundtrip(#[from(make_arbitrary)] token_id: Nep245TokenId) {
70 let s = token_id.to_string();
71 let got: Nep245TokenId = s.parse().unwrap();
72 assert_eq!(got, token_id);
73 }
74}