stellar_xdr/next/
str.rs

1//# Custom string representations of the following types, also used for JSON
2//# formatting.
3//#
4//# The types that has impls in this file are given to the xdrgen
5//# --rust-types-custom-str-impl cli option, so that xdrgen does not generate
6//# FromStr and Display impls for them.
7//#
8//# ## Strkey Types (SEP-23)
9//# - PublicKey
10//# - AccountId
11//# - MuxedAccount
12//# - MuxedAccountMed25519
13//# - SignerKey
14//# - SignerKeyEd25519SignedPayload
15//# - NodeId
16//#
17//# ## Asset Codes
18//# - AssetCode
19//# - AssetCode4
20//# - AssetCode12
21//#
22//# ## Integers
23//# - Int128Parts
24//# - UInt128Parts
25//# - Int256Parts
26//# - UInt256Parts
27//#
28//# ## Other
29//# - ClaimableBalanceId
30//# - PoolId
31#![cfg(feature = "alloc")]
32
33use super::{
34    super::num128::{
35        i128_str_from_pieces, i128_str_into_pieces, u128_str_from_pieces, u128_str_into_pieces,
36    },
37    super::num256::{
38        i256_str_from_pieces, i256_str_into_pieces, u256_str_from_pieces, u256_str_into_pieces,
39    },
40    AccountId, AssetCode, AssetCode12, AssetCode4, ClaimableBalanceId, ContractId, Error, Hash,
41    Int128Parts, Int256Parts, MuxedAccount, MuxedAccountMed25519, MuxedEd25519Account, NodeId,
42    PoolId, PublicKey, ScAddress, SignerKey, SignerKeyEd25519SignedPayload, UInt128Parts,
43    UInt256Parts, Uint256,
44};
45
46impl From<stellar_strkey::DecodeError> for Error {
47    fn from(_: stellar_strkey::DecodeError) -> Self {
48        Error::Invalid
49    }
50}
51
52impl core::fmt::Display for PublicKey {
53    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
54        match self {
55            PublicKey::PublicKeyTypeEd25519(Uint256(k)) => {
56                let k = stellar_strkey::ed25519::PublicKey::from_payload(k)
57                    .map_err(|_| core::fmt::Error)?;
58                let s = k.to_string();
59                f.write_str(&s)?;
60            }
61        }
62        Ok(())
63    }
64}
65
66impl core::str::FromStr for PublicKey {
67    type Err = Error;
68    fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
69        let stellar_strkey::ed25519::PublicKey(k) =
70            stellar_strkey::ed25519::PublicKey::from_str(s)?;
71        Ok(PublicKey::PublicKeyTypeEd25519(Uint256(k)))
72    }
73}
74
75impl core::fmt::Display for AccountId {
76    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
77        self.0.fmt(f)
78    }
79}
80
81impl core::str::FromStr for AccountId {
82    type Err = Error;
83    fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
84        Ok(AccountId(PublicKey::from_str(s)?))
85    }
86}
87
88impl core::fmt::Display for ContractId {
89    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
90        let k = stellar_strkey::Contract(self.0 .0);
91        let s = k.to_string();
92        f.write_str(&s)?;
93        Ok(())
94    }
95}
96
97impl core::str::FromStr for ContractId {
98    type Err = Error;
99    fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
100        let stellar_strkey::Contract(h) = stellar_strkey::Contract::from_str(s)?;
101        Ok(ContractId(Hash(h)))
102    }
103}
104
105impl core::fmt::Display for PoolId {
106    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
107        let PoolId(Hash(p_id)) = self.clone();
108        let key = stellar_strkey::Strkey::LiquidityPool(stellar_strkey::LiquidityPool(p_id));
109        key.fmt(f)
110    }
111}
112
113impl core::str::FromStr for PoolId {
114    type Err = Error;
115    fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
116        let pool_key = stellar_strkey::LiquidityPool::from_str(s)?;
117        Ok(PoolId(Hash(pool_key.0)))
118    }
119}
120
121impl core::fmt::Display for MuxedAccountMed25519 {
122    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
123        let MuxedAccountMed25519 {
124            ed25519: Uint256(ed25519),
125            id,
126        } = self;
127        let k = stellar_strkey::ed25519::MuxedAccount {
128            ed25519: *ed25519,
129            id: *id,
130        };
131        let s = k.to_string();
132        f.write_str(&s)?;
133        Ok(())
134    }
135}
136
137impl core::str::FromStr for MuxedAccountMed25519 {
138    type Err = Error;
139    fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
140        let stellar_strkey::ed25519::MuxedAccount { ed25519, id } =
141            stellar_strkey::ed25519::MuxedAccount::from_str(s)?;
142        Ok(MuxedAccountMed25519 {
143            ed25519: Uint256(ed25519),
144            id,
145        })
146    }
147}
148
149impl core::str::FromStr for MuxedAccount {
150    type Err = Error;
151    fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
152        let strkey = stellar_strkey::Strkey::from_str(s)?;
153        match strkey {
154            stellar_strkey::Strkey::PublicKeyEd25519(stellar_strkey::ed25519::PublicKey(k)) => {
155                Ok(MuxedAccount::Ed25519(Uint256(k)))
156            }
157            stellar_strkey::Strkey::MuxedAccountEd25519(
158                stellar_strkey::ed25519::MuxedAccount { ed25519, id },
159            ) => Ok(MuxedAccount::MuxedEd25519(MuxedAccountMed25519 {
160                ed25519: Uint256(ed25519),
161                id,
162            })),
163            stellar_strkey::Strkey::PrivateKeyEd25519(_)
164            | stellar_strkey::Strkey::PreAuthTx(_)
165            | stellar_strkey::Strkey::HashX(_)
166            | stellar_strkey::Strkey::SignedPayloadEd25519(_)
167            | stellar_strkey::Strkey::Contract(_)
168            | stellar_strkey::Strkey::LiquidityPool(_)
169            | stellar_strkey::Strkey::ClaimableBalance(_) => Err(Error::Invalid),
170        }
171    }
172}
173
174impl core::fmt::Display for MuxedAccount {
175    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
176        match self {
177            MuxedAccount::Ed25519(Uint256(k)) => {
178                let k = stellar_strkey::ed25519::PublicKey(*k);
179                let s = k.to_string();
180                f.write_str(&s)?;
181            }
182            MuxedAccount::MuxedEd25519(m) => m.fmt(f)?,
183        }
184        Ok(())
185    }
186}
187
188impl core::fmt::Display for NodeId {
189    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
190        self.0.fmt(f)
191    }
192}
193
194impl core::str::FromStr for NodeId {
195    type Err = Error;
196    fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
197        Ok(NodeId(PublicKey::from_str(s)?))
198    }
199}
200
201impl core::fmt::Display for SignerKeyEd25519SignedPayload {
202    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
203        let SignerKeyEd25519SignedPayload {
204            ed25519: Uint256(ed25519),
205            payload,
206        } = self;
207        let k = stellar_strkey::ed25519::SignedPayload {
208            ed25519: *ed25519,
209            payload: payload.into(),
210        };
211        let s = k.to_string();
212        f.write_str(&s)?;
213        Ok(())
214    }
215}
216
217impl core::str::FromStr for SignerKeyEd25519SignedPayload {
218    type Err = Error;
219    fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
220        let stellar_strkey::ed25519::SignedPayload { ed25519, payload } =
221            stellar_strkey::ed25519::SignedPayload::from_str(s)?;
222        Ok(SignerKeyEd25519SignedPayload {
223            ed25519: Uint256(ed25519),
224            payload: payload.try_into()?,
225        })
226    }
227}
228
229impl core::str::FromStr for SignerKey {
230    type Err = Error;
231    fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
232        let strkey = stellar_strkey::Strkey::from_str(s)?;
233        match strkey {
234            stellar_strkey::Strkey::PublicKeyEd25519(stellar_strkey::ed25519::PublicKey(k)) => {
235                Ok(SignerKey::Ed25519(Uint256(k)))
236            }
237            stellar_strkey::Strkey::PreAuthTx(stellar_strkey::PreAuthTx(h)) => {
238                Ok(SignerKey::PreAuthTx(Uint256(h)))
239            }
240            stellar_strkey::Strkey::HashX(stellar_strkey::HashX(h)) => {
241                Ok(SignerKey::HashX(Uint256(h)))
242            }
243            stellar_strkey::Strkey::SignedPayloadEd25519(
244                stellar_strkey::ed25519::SignedPayload { ed25519, payload },
245            ) => Ok(SignerKey::Ed25519SignedPayload(
246                SignerKeyEd25519SignedPayload {
247                    ed25519: Uint256(ed25519),
248                    payload: payload.try_into()?,
249                },
250            )),
251            stellar_strkey::Strkey::PrivateKeyEd25519(_)
252            | stellar_strkey::Strkey::Contract(_)
253            | stellar_strkey::Strkey::MuxedAccountEd25519(_)
254            | stellar_strkey::Strkey::LiquidityPool(_)
255            | stellar_strkey::Strkey::ClaimableBalance(_) => Err(Error::Invalid),
256        }
257    }
258}
259
260impl core::fmt::Display for SignerKey {
261    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
262        match self {
263            SignerKey::Ed25519(Uint256(k)) => {
264                let k = stellar_strkey::ed25519::PublicKey(*k);
265                let s = k.to_string();
266                f.write_str(&s)?;
267            }
268            SignerKey::PreAuthTx(Uint256(h)) => {
269                let k = stellar_strkey::PreAuthTx(*h);
270                let s = k.to_string();
271                f.write_str(&s)?;
272            }
273            SignerKey::HashX(Uint256(h)) => {
274                let k = stellar_strkey::HashX(*h);
275                let s = k.to_string();
276                f.write_str(&s)?;
277            }
278            SignerKey::Ed25519SignedPayload(p) => p.fmt(f)?,
279        }
280        Ok(())
281    }
282}
283
284impl core::str::FromStr for MuxedEd25519Account {
285    type Err = Error;
286    fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
287        let strkey = stellar_strkey::Strkey::from_str(s)?;
288        match strkey {
289            stellar_strkey::Strkey::MuxedAccountEd25519(muxed_ed25519) => Ok(MuxedEd25519Account {
290                id: muxed_ed25519.id,
291                ed25519: Uint256(muxed_ed25519.ed25519),
292            }),
293            _ => Err(Error::Invalid),
294        }
295    }
296}
297
298impl core::fmt::Display for MuxedEd25519Account {
299    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
300        let k =
301            stellar_strkey::Strkey::MuxedAccountEd25519(stellar_strkey::ed25519::MuxedAccount {
302                ed25519: self.ed25519.0,
303                id: self.id,
304            });
305        let s = k.to_string();
306        f.write_str(&s)
307    }
308}
309
310impl core::str::FromStr for ScAddress {
311    type Err = Error;
312    fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
313        let strkey = stellar_strkey::Strkey::from_str(s)?;
314        match strkey {
315            stellar_strkey::Strkey::PublicKeyEd25519(stellar_strkey::ed25519::PublicKey(k)) => Ok(
316                ScAddress::Account(AccountId(PublicKey::PublicKeyTypeEd25519(Uint256(k)))),
317            ),
318            stellar_strkey::Strkey::Contract(stellar_strkey::Contract(h)) => {
319                Ok(ScAddress::Contract(ContractId(Hash(h))))
320            }
321            stellar_strkey::Strkey::MuxedAccountEd25519(muxed_ed25519) => {
322                Ok(ScAddress::MuxedAccount(MuxedEd25519Account {
323                    id: muxed_ed25519.id,
324                    ed25519: Uint256(muxed_ed25519.ed25519),
325                }))
326            }
327            stellar_strkey::Strkey::LiquidityPool(liquidity_pool) => {
328                Ok(ScAddress::LiquidityPool(PoolId(Hash(liquidity_pool.0))))
329            }
330            stellar_strkey::Strkey::ClaimableBalance(stellar_strkey::ClaimableBalance::V0(
331                claimable_balance,
332            )) => Ok(ScAddress::ClaimableBalance(
333                ClaimableBalanceId::ClaimableBalanceIdTypeV0(Hash(claimable_balance)),
334            )),
335            stellar_strkey::Strkey::PrivateKeyEd25519(_)
336            | stellar_strkey::Strkey::PreAuthTx(_)
337            | stellar_strkey::Strkey::HashX(_)
338            | stellar_strkey::Strkey::SignedPayloadEd25519(_) => Err(Error::Invalid),
339        }
340    }
341}
342
343impl core::fmt::Display for ScAddress {
344    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
345        match self {
346            ScAddress::Account(a) => a.fmt(f),
347            ScAddress::Contract(ContractId(Hash(h))) => {
348                let k = stellar_strkey::Contract(*h);
349                let s = k.to_string();
350                f.write_str(&s)
351            }
352            ScAddress::MuxedAccount(muxed_ed25519_account) => {
353                let k = stellar_strkey::Strkey::MuxedAccountEd25519(
354                    stellar_strkey::ed25519::MuxedAccount {
355                        ed25519: muxed_ed25519_account.ed25519.0,
356                        id: muxed_ed25519_account.id,
357                    },
358                );
359                let s = k.to_string();
360                f.write_str(&s)
361            }
362            ScAddress::ClaimableBalance(claimable_balance_id) => claimable_balance_id.fmt(f),
363            ScAddress::LiquidityPool(pool_id) => pool_id.fmt(f),
364        }
365    }
366}
367
368impl core::str::FromStr for AssetCode4 {
369    type Err = Error;
370    fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
371        let mut code = AssetCode4([0u8; 4]);
372        escape_bytes::unescape_into(&mut code.0, s.as_bytes()).map_err(|_| Error::Invalid)?;
373        Ok(code)
374    }
375}
376
377impl core::fmt::Display for AssetCode4 {
378    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
379        if let Some(last_idx) = self.0.iter().rposition(|c| *c != 0) {
380            for b in escape_bytes::Escape::new(&self.0[..=last_idx]) {
381                write!(f, "{}", b as char)?;
382            }
383        }
384        Ok(())
385    }
386}
387
388impl core::str::FromStr for AssetCode12 {
389    type Err = Error;
390    fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
391        let mut code = AssetCode12([0u8; 12]);
392        escape_bytes::unescape_into(&mut code.0, s.as_bytes()).map_err(|_| Error::Invalid)?;
393        Ok(code)
394    }
395}
396
397impl core::fmt::Display for AssetCode12 {
398    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
399        if let Some(last_idx) = self.0.iter().rposition(|c| *c != 0) {
400            for b in escape_bytes::Escape::new(&self.0[..=last_idx]) {
401                write!(f, "{}", b as char)?;
402            }
403        }
404        Ok(())
405    }
406}
407
408impl core::str::FromStr for AssetCode {
409    type Err = Error;
410    fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
411        let mut code = [0u8; 12];
412        let n = escape_bytes::unescape_into(&mut code, s.as_bytes()).map_err(|_| Error::Invalid)?;
413        if n <= 4 {
414            Ok(AssetCode::CreditAlphanum4(AssetCode4([
415                code[0], code[1], code[2], code[3],
416            ])))
417        } else if n <= 12 {
418            Ok(AssetCode::CreditAlphanum12(AssetCode12(code)))
419        } else {
420            Err(Error::Invalid)
421        }
422    }
423}
424
425impl core::fmt::Display for AssetCode {
426    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
427        match self {
428            AssetCode::CreditAlphanum4(c) => c.fmt(f),
429            AssetCode::CreditAlphanum12(c) => c.fmt(f),
430        }
431    }
432}
433
434impl core::str::FromStr for ClaimableBalanceId {
435    type Err = Error;
436    fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
437        let stellar_strkey::ClaimableBalance::V0(cb_id) =
438            stellar_strkey::ClaimableBalance::from_str(s)?;
439        Ok(ClaimableBalanceId::ClaimableBalanceIdTypeV0(Hash(cb_id)))
440    }
441}
442
443impl core::fmt::Display for ClaimableBalanceId {
444    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
445        let ClaimableBalanceId::ClaimableBalanceIdTypeV0(Hash(cb_id)) = self.clone();
446        let key =
447            stellar_strkey::Strkey::ClaimableBalance(stellar_strkey::ClaimableBalance::V0(cb_id));
448        key.fmt(f)
449    }
450}
451
452impl core::fmt::Display for UInt128Parts {
453    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
454        let v = u128_str_from_pieces(self.hi, self.lo);
455        write!(f, "{v}")
456    }
457}
458
459impl core::str::FromStr for UInt128Parts {
460    type Err = Error;
461    fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
462        let (hi, lo) = u128_str_into_pieces(s).map_err(|_| Error::Invalid)?;
463        Ok(Self { hi, lo })
464    }
465}
466
467impl core::fmt::Display for Int128Parts {
468    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
469        let v = i128_str_from_pieces(self.hi, self.lo);
470        write!(f, "{v}")
471    }
472}
473
474impl core::str::FromStr for Int128Parts {
475    type Err = Error;
476    fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
477        let (hi, lo) = i128_str_into_pieces(s).map_err(|_| Error::Invalid)?;
478        Ok(Self { hi, lo })
479    }
480}
481
482impl core::fmt::Display for UInt256Parts {
483    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
484        let u256 = u256_str_from_pieces(self.hi_hi, self.hi_lo, self.lo_hi, self.lo_lo);
485        write!(f, "{u256}")
486    }
487}
488
489impl core::str::FromStr for UInt256Parts {
490    type Err = Error;
491    fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
492        let (hi_hi, hi_lo, lo_hi, lo_lo) = u256_str_into_pieces(s).map_err(|_| Error::Invalid)?;
493        Ok(Self {
494            hi_hi,
495            hi_lo,
496            lo_hi,
497            lo_lo,
498        })
499    }
500}
501
502impl core::fmt::Display for Int256Parts {
503    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
504        let i256 = i256_str_from_pieces(self.hi_hi, self.hi_lo, self.lo_hi, self.lo_lo);
505        write!(f, "{i256}")
506    }
507}
508
509impl core::str::FromStr for Int256Parts {
510    type Err = Error;
511    fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
512        let (hi_hi, hi_lo, lo_hi, lo_lo) = i256_str_into_pieces(s).map_err(|_| Error::Invalid)?;
513        Ok(Self {
514            hi_hi,
515            hi_lo,
516            lo_hi,
517            lo_lo,
518        })
519    }
520}