1use std::str::FromStr;
2
3use crate::cell::*;
4use crate::error::{Error, ParseAddrError};
5use crate::models::block::ShardIdent;
6use crate::num::*;
7use crate::util::*;
8
9pub trait Addr {
11 fn workchain(&self) -> i32;
13 fn prefix(&self) -> u64;
15}
16
17#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
19pub enum IntAddr {
20 Std(StdAddr),
22 Var(VarAddr),
24}
25
26impl Default for IntAddr {
27 #[inline]
28 fn default() -> Self {
29 Self::Std(StdAddr::default())
30 }
31}
32
33impl IntAddr {
34 pub const BITS_MAX: u16 = 1 + VarAddr::BITS_MAX;
36
37 #[inline]
41 pub const fn is_masterchain(&self) -> bool {
42 self.workchain() == ShardIdent::MASTERCHAIN.workchain()
43 }
44
45 #[inline]
47 pub const fn workchain(&self) -> i32 {
48 match self {
49 Self::Std(addr) => addr.workchain as i32,
50 Self::Var(addr) => addr.workchain,
51 }
52 }
53
54 #[inline]
56 pub const fn anycast(&self) -> &Option<Box<Anycast>> {
57 match self {
58 Self::Std(addr) => &addr.anycast,
59 Self::Var(addr) => &addr.anycast,
60 }
61 }
62
63 #[inline]
65 pub const fn as_std(&self) -> Option<&StdAddr> {
66 match self {
67 Self::Std(addr) => Some(addr),
68 Self::Var(_) => None,
69 }
70 }
71
72 #[inline]
74 pub const fn as_var(&self) -> Option<&VarAddr> {
75 match self {
76 Self::Std(_) => None,
77 Self::Var(addr) => Some(addr),
78 }
79 }
80
81 pub const fn bit_len(&self) -> u16 {
83 match self {
84 Self::Std(addr) => addr.bit_len(),
85 Self::Var(addr) => addr.bit_len(),
86 }
87 }
88
89 pub fn prefix(&self) -> u64 {
91 match self {
92 Self::Std(addr) => addr.prefix(),
93 Self::Var(addr) => addr.prefix(),
94 }
95 }
96}
97
98impl Addr for IntAddr {
99 #[inline]
100 fn workchain(&self) -> i32 {
101 IntAddr::workchain(self)
102 }
103
104 #[inline]
105 fn prefix(&self) -> u64 {
106 IntAddr::prefix(self)
107 }
108}
109
110impl From<(i8, HashBytes)> for IntAddr {
111 #[inline]
112 fn from((workchain, address): (i8, HashBytes)) -> Self {
113 IntAddr::Std(StdAddr::new(workchain, address))
114 }
115}
116
117impl FromStr for IntAddr {
118 type Err = ParseAddrError;
119
120 fn from_str(s: &str) -> Result<Self, Self::Err> {
121 Ok(Self::Std(ok!(StdAddr::from_str(s))))
123 }
124}
125
126impl std::fmt::Display for IntAddr {
127 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128 match self {
129 IntAddr::Std(addr) => std::fmt::Display::fmt(addr, f),
130 IntAddr::Var(_) => f.write_str("varaddr"), }
132 }
133}
134
135impl Store for IntAddr {
136 fn store_into(
137 &self,
138 builder: &mut CellBuilder,
139 context: &mut dyn CellContext,
140 ) -> Result<(), Error> {
141 match self {
142 Self::Std(addr) => addr.store_into(builder, context),
143 Self::Var(addr) => addr.store_into(builder, context),
144 }
145 }
146}
147
148impl<'a> Load<'a> for IntAddr {
149 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
150 if !ok!(slice.load_bit()) {
151 return Err(Error::InvalidTag);
152 }
153
154 Ok(if unlikely(ok!(slice.load_bit())) {
155 let anycast = ok!(Option::<Box<Anycast>>::load_from(slice));
156 let address_len = ok!(Uint9::load_from(slice));
157 let workchain = ok!(slice.load_u32()) as i32;
158 if !slice.has_remaining(address_len.into_inner(), 0) {
159 return Err(Error::CellUnderflow);
160 }
161
162 let mut address = vec![0; (address_len.into_inner() as usize + 7) / 8];
163 ok!(slice.load_raw(&mut address, address_len.into_inner()));
164
165 Self::Var(VarAddr {
166 anycast,
167 address_len,
168 workchain,
169 address,
170 })
171 } else {
172 Self::Std(StdAddr {
173 anycast: ok!(Option::<Box<Anycast>>::load_from(slice)),
174 workchain: ok!(slice.load_u8()) as i8,
175 address: ok!(slice.load_u256()),
176 })
177 })
178 }
179}
180
181#[cfg(feature = "serde")]
182impl serde::Serialize for IntAddr {
183 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
184 where
185 S: serde::Serializer,
186 {
187 match self {
188 Self::Std(addr) => addr.serialize(serializer),
189 Self::Var(_) => {
190 serializer.serialize_str("varaddr")
192 }
193 }
194 }
195}
196
197#[cfg(feature = "serde")]
198impl<'de> serde::Deserialize<'de> for IntAddr {
199 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
200 where
201 D: serde::Deserializer<'de>,
202 {
203 StdAddr::deserialize(deserializer).map(IntAddr::Std)
205 }
206}
207
208#[derive(Debug, Default, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
210pub struct StdAddr {
211 pub anycast: Option<Box<Anycast>>,
213 pub workchain: i8,
215 pub address: HashBytes,
217}
218
219impl StdAddr {
220 pub const BITS_WITHOUT_ANYCAST: u16 = 2 + 1 + 8 + 256;
227
228 pub const BITS_MAX: u16 = Self::BITS_WITHOUT_ANYCAST + Anycast::BITS_MAX;
230
231 #[inline]
233 pub const fn new(workchain: i8, address: HashBytes) -> Self {
234 Self {
235 anycast: None,
236 workchain,
237 address,
238 }
239 }
240
241 #[cfg(feature = "base64")]
243 pub fn from_str_ext(
244 s: &str,
245 format: StdAddrFormat,
246 ) -> Result<(Self, Base64StdAddrFlags), ParseAddrError> {
247 use base64::prelude::{Engine as _, BASE64_STANDARD, BASE64_URL_SAFE};
248
249 match s.len() {
250 0 => Err(ParseAddrError::Empty),
251 66..=69 if format.allow_raw => Self::from_str(s).map(|addr| (addr, Default::default())),
252 48 if format.allow_base64 || format.allow_base64_url => {
253 let mut buffer = [0u8; 36];
254
255 let base64_url = s.contains(['_', '-']);
256
257 let Ok(36) = if base64_url {
258 BASE64_URL_SAFE
259 } else {
260 BASE64_STANDARD
261 }
262 .decode_slice(s, &mut buffer) else {
263 return Err(ParseAddrError::BadFormat);
264 };
265
266 #[cfg(not(fuzzing))]
267 {
268 let crc = crc_16(&buffer[..34]);
269 if buffer[34] as u16 != (crc >> 8) || buffer[35] as u16 != (crc & 0xff) {
270 return Err(ParseAddrError::BadFormat);
271 }
272 }
273
274 let addr = StdAddr::new(
275 buffer[1] as i8,
276 HashBytes(buffer[2..34].try_into().unwrap()),
277 );
278 let flags = Base64StdAddrFlags {
279 testnet: buffer[0] & 0x80 != 0,
280 base64_url,
281 bounceable: buffer[0] & 0x40 == 0,
282 };
283 Ok((addr, flags))
284 }
285 _ => Err(ParseAddrError::BadFormat),
286 }
287 }
288
289 #[inline]
293 pub const fn is_masterchain(&self) -> bool {
294 self.workchain as i32 == ShardIdent::MASTERCHAIN.workchain()
295 }
296
297 pub const fn bit_len(&self) -> u16 {
299 let mut bit_len = Self::BITS_WITHOUT_ANYCAST;
300 if let Some(anycast) = &self.anycast {
301 bit_len += anycast.bit_len();
302 }
303 bit_len
304 }
305
306 pub const fn prefix(&self) -> u64 {
308 u64::from_be_bytes(*self.address.first_chunk())
309 }
310
311 #[cfg(feature = "base64")]
313 pub const fn display_base64(&self, bounceable: bool) -> DisplayBase64StdAddr<'_> {
314 DisplayBase64StdAddr {
315 addr: self,
316 flags: Base64StdAddrFlags {
317 testnet: false,
318 base64_url: false,
319 bounceable,
320 },
321 }
322 }
323
324 #[cfg(feature = "base64")]
326 pub const fn display_base64_url(&self, bounceable: bool) -> DisplayBase64StdAddr<'_> {
327 DisplayBase64StdAddr {
328 addr: self,
329 flags: Base64StdAddrFlags {
330 testnet: false,
331 base64_url: true,
332 bounceable,
333 },
334 }
335 }
336}
337
338impl Addr for StdAddr {
339 #[inline]
340 fn workchain(&self) -> i32 {
341 self.workchain as i32
342 }
343
344 #[inline]
345 fn prefix(&self) -> u64 {
346 StdAddr::prefix(self)
347 }
348}
349
350impl std::fmt::Display for StdAddr {
351 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
352 if let Some(anycast) = &self.anycast {
353 ok!(f.write_fmt(format_args!("{anycast}:")))
354 }
355
356 f.write_fmt(format_args!("{}:{}", self.workchain, self.address))
357 }
358}
359
360impl From<(i8, HashBytes)> for StdAddr {
361 #[inline]
362 fn from((workchain, address): (i8, HashBytes)) -> Self {
363 Self::new(workchain, address)
364 }
365}
366
367impl From<(i8, [u8; 32])> for StdAddr {
368 #[inline]
369 fn from((workchain, address): (i8, [u8; 32])) -> Self {
370 Self::new(workchain, HashBytes(address))
371 }
372}
373
374impl From<StdAddr> for IntAddr {
375 #[inline]
376 fn from(value: StdAddr) -> Self {
377 Self::Std(value)
378 }
379}
380
381impl FromStr for StdAddr {
382 type Err = ParseAddrError;
383
384 fn from_str(s: &str) -> Result<Self, Self::Err> {
385 if s.is_empty() {
386 return Err(ParseAddrError::Empty);
387 }
388
389 let mut result = Self::default();
390
391 let mut parts = s.split(':');
392 match parts.next() {
393 Some(part) => match part.parse() {
394 Ok(workchain) => result.workchain = workchain,
395 Err(_) => return Err(ParseAddrError::InvalidWorkchain),
396 },
397 None => return Err(ParseAddrError::Empty),
398 }
399
400 match parts.next() {
401 Some(part) => match hex::decode_to_slice(part, &mut result.address.0) {
402 Ok(()) => {}
403 Err(_) => return Err(ParseAddrError::InvalidAccountId),
404 },
405 None => return Err(ParseAddrError::InvalidAccountId),
406 }
407
408 if parts.next().is_none() {
409 Ok(result)
410 } else {
411 Err(ParseAddrError::UnexpectedPart)
412 }
413 }
414}
415
416impl Store for StdAddr {
417 fn store_into(
418 &self,
419 builder: &mut CellBuilder,
420 context: &mut dyn CellContext,
421 ) -> Result<(), Error> {
422 if !builder.has_capacity(self.bit_len(), 0) {
423 return Err(Error::CellOverflow);
424 }
425 ok!(builder.store_small_uint(0b10, 2));
426 ok!(self.anycast.store_into(builder, context));
427 ok!(builder.store_u8(self.workchain as u8));
428 builder.store_u256(&self.address)
429 }
430}
431
432impl<'a> Load<'a> for StdAddr {
433 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
434 if !ok!(slice.load_bit()) || ok!(slice.load_bit()) {
435 return Err(Error::InvalidTag);
436 }
437
438 Ok(Self {
439 anycast: ok!(Option::<Box<Anycast>>::load_from(slice)),
440 workchain: ok!(slice.load_u8()) as i8,
441 address: ok!(slice.load_u256()),
442 })
443 }
444}
445
446impl crate::dict::DictKey for StdAddr {
447 const BITS: u16 = StdAddr::BITS_WITHOUT_ANYCAST;
448
449 fn from_raw_data([first_byte, second_byte, data @ ..]: &[u8; 128]) -> Option<Self> {
450 const PREFIX_BITS: u8 = 0b1000_0000;
453 const PREFIX_MASK: u8 = 0b1110_0000;
454
455 const R: u8 = 3;
456 const SHIFT: u8 = 8 - R;
457 const REV_SHIFT: u8 = 120 + R;
458
459 if unlikely((first_byte ^ PREFIX_BITS) & PREFIX_MASK != 0) {
460 return None;
461 }
462
463 let mut result = Self {
464 anycast: None,
465 workchain: ((first_byte << R) | (second_byte >> SHIFT)) as i8,
467 address: HashBytes::ZERO,
468 };
469
470 let [mut hi, mut lo]: [u128; 2] =
472 unsafe { std::mem::transmute::<[u8; 32], _>(data[..32].try_into().unwrap()) };
473
474 #[cfg(target_endian = "little")]
476 {
477 hi = hi.swap_bytes();
478 lo = lo.swap_bytes();
479 }
480
481 result.address = unsafe {
483 std::mem::transmute::<[[u8; 16]; 2], HashBytes>([
484 (hi >> SHIFT | ((*second_byte as u128) << REV_SHIFT)).to_be_bytes(),
485 (lo >> SHIFT | (hi << REV_SHIFT)).to_be_bytes(),
486 ])
487 };
488
489 Some(result)
490 }
491}
492
493#[cfg(feature = "serde")]
494impl serde::Serialize for StdAddr {
495 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
496 where
497 S: serde::Serializer,
498 {
499 if serializer.is_human_readable() {
500 serializer.collect_str(self)
501 } else {
502 (self.workchain, &self.address).serialize(serializer)
503 }
504 }
505}
506
507#[cfg(feature = "serde")]
508impl<'de> serde::Deserialize<'de> for StdAddr {
509 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
510 where
511 D: serde::Deserializer<'de>,
512 {
513 use serde::de::{Error, Visitor};
514
515 struct StdAddrVisitor;
516
517 impl<'de> Visitor<'de> for StdAddrVisitor {
518 type Value = StdAddr;
519
520 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
521 f.write_str("a standard address")
522 }
523
524 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
525 where
526 E: Error,
527 {
528 StdAddr::from_str(v).map_err(E::custom)
529 }
530 }
531
532 if deserializer.is_human_readable() {
533 deserializer.deserialize_str(StdAddrVisitor)
534 } else {
535 <(i8, HashBytes)>::deserialize(deserializer)
536 .map(|(workchain, address)| Self::new(workchain, address))
537 }
538 }
539}
540
541#[cfg(feature = "base64")]
543pub struct StdAddrBase64Repr<const URL_SAFE: bool = true>;
544
545#[cfg(all(feature = "base64", feature = "serde"))]
546impl<const URL_SAFE: bool> StdAddrBase64Repr<URL_SAFE> {
547 pub fn serialize<S>(addr: &StdAddr, serializer: S) -> Result<S::Ok, S::Error>
549 where
550 S: serde::Serializer,
551 {
552 serializer.collect_str(&DisplayBase64StdAddr {
553 addr,
554 flags: Base64StdAddrFlags {
555 testnet: false,
556 base64_url: URL_SAFE,
557 bounceable: false,
558 },
559 })
560 }
561
562 pub fn deserialize<'de, D>(deserializer: D) -> Result<StdAddr, D::Error>
564 where
565 D: serde::Deserializer<'de>,
566 {
567 use serde::de::{Error, Visitor};
568
569 struct StdAddrBase64Visitor;
570
571 impl<'de> Visitor<'de> for StdAddrBase64Visitor {
572 type Value = StdAddr;
573
574 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
575 f.write_str("a standard address")
576 }
577
578 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
579 where
580 E: Error,
581 {
582 StdAddr::from_str_ext(v, StdAddrFormat::any())
583 .map(|(addr, _)| addr)
584 .map_err(E::custom)
585 }
586 }
587
588 deserializer.deserialize_str(StdAddrBase64Visitor)
589 }
590}
591
592#[cfg(feature = "base64")]
594#[derive(Debug, Clone, Copy)]
595pub struct StdAddrFormat {
596 pub allow_raw: bool,
598 pub allow_base64: bool,
600 pub allow_base64_url: bool,
602}
603
604#[cfg(feature = "base64")]
605impl StdAddrFormat {
606 pub const fn any() -> Self {
608 StdAddrFormat {
609 allow_raw: true,
610 allow_base64: true,
611 allow_base64_url: true,
612 }
613 }
614}
615
616#[cfg(feature = "base64")]
618#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
619pub struct Base64StdAddrFlags {
620 pub testnet: bool,
622 pub base64_url: bool,
624 pub bounceable: bool,
626}
627
628#[cfg(feature = "base64")]
630pub struct DisplayBase64StdAddr<'a> {
631 pub addr: &'a StdAddr,
633 pub flags: Base64StdAddrFlags,
635}
636
637#[cfg(feature = "base64")]
638impl std::fmt::Display for DisplayBase64StdAddr<'_> {
639 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
640 use base64::prelude::{Engine as _, BASE64_STANDARD, BASE64_URL_SAFE};
641
642 let mut buffer = [0u8; 36];
643 buffer[0] = (0x51 - (self.flags.bounceable as i32) * 0x40
644 + (self.flags.testnet as i32) * 0x80) as u8;
645 buffer[1] = self.addr.workchain as u8;
646 buffer[2..34].copy_from_slice(self.addr.address.as_array());
647
648 let crc = crc_16(&buffer[..34]);
649 buffer[34] = (crc >> 8) as u8;
650 buffer[35] = (crc & 0xff) as u8;
651
652 let mut output = [0u8; 48];
653 if self.flags.base64_url {
654 BASE64_URL_SAFE
655 } else {
656 BASE64_STANDARD
657 }
658 .encode_slice(buffer, &mut output)
659 .unwrap();
660
661 let output = unsafe { std::str::from_utf8_unchecked(&output) };
663 f.write_str(output)
664 }
665}
666
667#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
669pub struct VarAddr {
670 pub anycast: Option<Box<Anycast>>,
672 pub address_len: Uint9,
674 pub workchain: i32,
676 pub address: Vec<u8>,
678}
679
680impl VarAddr {
681 pub const BITS_MAX: u16 =
689 2 + 1 + Anycast::BITS_MAX + Uint9::BITS + 32 + Uint9::MAX.into_inner();
690
691 #[inline]
695 pub const fn is_masterchain(&self) -> bool {
696 self.workchain == ShardIdent::MASTERCHAIN.workchain()
697 }
698
699 pub const fn bit_len(&self) -> u16 {
701 let mut bit_len = 2 + 1 + Uint9::BITS + 32 + self.address_len.into_inner();
702 if let Some(anycast) = &self.anycast {
703 bit_len += anycast.bit_len();
704 }
705 bit_len
706 }
707
708 pub fn prefix(&self) -> u64 {
710 let mut prefix = [0; 8];
711 let total_bytes = std::cmp::min(self.address.len(), 8);
712 prefix[..total_bytes].copy_from_slice(&self.address[..total_bytes]);
713 u64::from_be_bytes(prefix)
714 }
715}
716
717impl From<VarAddr> for IntAddr {
718 #[inline]
719 fn from(value: VarAddr) -> Self {
720 Self::Var(value)
721 }
722}
723
724impl Store for VarAddr {
725 fn store_into(
726 &self,
727 builder: &mut CellBuilder,
728 context: &mut dyn CellContext,
729 ) -> Result<(), Error> {
730 if !builder.has_capacity(self.bit_len(), 0) {
731 return Err(Error::CellOverflow);
732 }
733 ok!(builder.store_small_uint(0b11, 2));
734 ok!(self.anycast.store_into(builder, context));
735 ok!(self.address_len.store_into(builder, context));
736 ok!(builder.store_u32(self.workchain as u32));
737 builder.store_raw(&self.address, self.address_len.into_inner())
738 }
739}
740
741impl Addr for VarAddr {
742 #[inline]
743 fn workchain(&self) -> i32 {
744 self.workchain
745 }
746
747 #[inline]
748 fn prefix(&self) -> u64 {
749 VarAddr::prefix(self)
750 }
751}
752
753#[derive(Debug, Default, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
760pub struct ExtAddr {
761 pub data_bit_len: Uint9,
763 pub data: Vec<u8>,
765}
766
767impl ExtAddr {
768 pub fn new<T>(data_bit_len: u16, data: T) -> Option<Self>
770 where
771 T: Into<Vec<u8>>,
772 {
773 let data_bit_len = Uint9::new(data_bit_len);
774 if data_bit_len.is_valid() {
775 Some(Self {
776 data_bit_len,
777 data: data.into(),
778 })
779 } else {
780 None
781 }
782 }
783
784 pub const fn bit_len(&self) -> u16 {
786 Uint9::BITS + self.data_bit_len.into_inner()
787 }
788}
789
790impl std::fmt::Display for ExtAddr {
791 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
792 let bitstring = Bitstring {
793 bytes: &self.data,
794 bit_len: self.data_bit_len.into_inner(),
795 };
796 write!(f, ":{bitstring}")
797 }
798}
799
800impl FromStr for ExtAddr {
801 type Err = ParseAddrError;
802
803 fn from_str(s: &str) -> Result<Self, Self::Err> {
804 if s.is_empty() {
805 return Err(ParseAddrError::Empty);
806 }
807
808 let Some(s) = s.strip_prefix(':') else {
809 return Err(ParseAddrError::UnexpectedPart);
810 };
811
812 let Ok((data, bit_len)) = Bitstring::from_hex_str(s) else {
813 return Err(ParseAddrError::InvalidAccountId);
814 };
815
816 ExtAddr::new(bit_len, data).ok_or(ParseAddrError::UnexpectedPart)
817 }
818}
819
820#[cfg(feature = "serde")]
821impl serde::Serialize for ExtAddr {
822 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
823 if serializer.is_human_readable() {
824 serializer.collect_str(self)
825 } else {
826 (self.data_bit_len.into_inner(), &self.data).serialize(serializer)
827 }
828 }
829}
830
831#[cfg(feature = "serde")]
832impl<'de> serde::Deserialize<'de> for ExtAddr {
833 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
834 use serde::de::{Error, Visitor};
835
836 struct ExtAddrVisitor;
837
838 impl<'de> Visitor<'de> for ExtAddrVisitor {
839 type Value = ExtAddr;
840
841 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
842 f.write_str("an external address")
843 }
844
845 fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
846 ExtAddr::from_str(v).map_err(E::custom)
847 }
848 }
849
850 if deserializer.is_human_readable() {
851 deserializer.deserialize_str(ExtAddrVisitor)
852 } else {
853 <(u16, Vec<u8>)>::deserialize(deserializer).and_then(|(data_bit_len, data)| {
854 ExtAddr::new(data_bit_len, data)
855 .ok_or_else(|| Error::custom("invalid external address data length"))
856 })
857 }
858 }
859}
860
861#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
867pub struct Anycast {
868 pub depth: SplitDepth,
870 pub rewrite_prefix: Vec<u8>,
872}
873
874impl Anycast {
875 pub const MIN_DEPTH: u8 = 1;
877 pub const MAX_DEPTH: u8 = 30;
879
880 pub const BITS_MAX: u16 = SplitDepth::BITS + Self::MAX_DEPTH as u16;
882
883 pub fn from_slice(rewrite_prefix: &CellSlice<'_>) -> Result<Self, Error> {
885 let depth = ok!(SplitDepth::from_bit_len(rewrite_prefix.size_bits()));
886
887 let mut data = vec![0; (depth.into_bit_len() as usize + 7) / 8];
888 ok!(rewrite_prefix.get_raw(0, &mut data, depth.into_bit_len()));
889
890 Ok(Self {
891 depth,
892 rewrite_prefix: data,
893 })
894 }
895
896 pub const fn bit_len(&self) -> u16 {
898 SplitDepth::BITS + self.depth.into_bit_len()
899 }
900}
901
902impl std::fmt::Display for Anycast {
903 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
904 let bitstring = Bitstring {
905 bytes: &self.rewrite_prefix,
906 bit_len: self.depth.into_bit_len(),
907 };
908 std::fmt::Display::fmt(&bitstring, f)
909 }
910}
911
912impl Store for Anycast {
913 fn store_into(
914 &self,
915 builder: &mut CellBuilder,
916 context: &mut dyn CellContext,
917 ) -> Result<(), Error> {
918 if !builder.has_capacity(self.bit_len(), 0) {
919 return Err(Error::CellOverflow);
920 }
921 ok!(self.depth.store_into(builder, context));
922 builder.store_raw(&self.rewrite_prefix, self.depth.into_bit_len())
923 }
924}
925
926impl<'a> Load<'a> for Anycast {
927 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
928 let depth = ok!(SplitDepth::load_from(slice));
929 if !slice.has_remaining(depth.into_bit_len(), 0) {
930 return Err(Error::CellUnderflow);
931 }
932
933 let mut rewrite_prefix = vec![0; (depth.into_bit_len() as usize + 7) / 8];
934 ok!(slice.load_raw(&mut rewrite_prefix, depth.into_bit_len()));
935
936 Ok(Self {
937 depth,
938 rewrite_prefix,
939 })
940 }
941}
942
943#[cfg(test)]
944mod tests {
945 use super::*;
946 use crate::dict::Dict;
947
948 #[test]
949 fn dict_with_std_addr_keys() {
950 let mut dict = Dict::<StdAddr, u32>::new();
951 dict.set(StdAddr::new(-1, HashBytes([0x33; 32])), 123)
952 .unwrap();
953 dict.set(StdAddr::new(0, HashBytes([0x10; 32])), 321)
954 .unwrap();
955 dict.set(StdAddr::new(-1, HashBytes([0x55; 32])), 234)
956 .unwrap();
957 dict.set(StdAddr::new(0, HashBytes([0x20; 32])), 432)
958 .unwrap();
959
960 for entry in dict.iter() {
961 let (addr, value) = entry.unwrap();
962 println!("{addr}: {value}");
963 }
964 }
965
966 #[test]
967 fn anycast_str() {
968 let empty_res = Anycast::from_slice(&Cell::empty_cell().as_slice().unwrap());
970 assert_eq!(empty_res.unwrap_err(), Error::IntOverflow);
971
972 let mut prefix = CellBuilder::new();
974 prefix.store_bit_one().unwrap();
975 let anycast = Anycast::from_slice(&prefix.as_data_slice()).unwrap();
976 assert_eq!(anycast.to_string(), "c_");
977
978 let mut prefix = CellBuilder::new();
980 prefix.store_u8(0xa5).unwrap();
981 let anycast = Anycast::from_slice(&prefix.as_data_slice()).unwrap();
982 assert_eq!(anycast.to_string(), "a5");
983
984 let mut prefix = CellBuilder::new();
986 prefix.store_uint(0xb00b1e5, 28).unwrap();
987 prefix.store_zeros(2).unwrap();
988 let anycast = Anycast::from_slice(&prefix.as_data_slice()).unwrap();
989 assert_eq!(anycast.to_string(), "b00b1e52_");
990 }
991
992 #[test]
993 fn address_prefix() {
994 let addr = "0:ece57bcc6c530283becbbd8a3b24d3c5987cdddc3c8b7b33be6e4a6312490415"
995 .parse::<StdAddr>()
996 .unwrap();
997 assert_eq!(addr.prefix(), 0xece57bcc6c530283);
998
999 let var_addr = VarAddr {
1000 anycast: None,
1001 address_len: Uint9::new(32),
1002 workchain: 0,
1003 address: vec![0xb0, 0xba, 0xca, 0xfe],
1004 };
1005 assert_eq!(var_addr.prefix(), 0xb0bacafe00000000);
1006
1007 let var_addr = VarAddr {
1008 anycast: None,
1009 address_len: Uint9::new(72),
1010 workchain: 0,
1011 address: vec![0xb0, 0xba, 0xca, 0xfe, 0xb0, 0x0b, 0x1e, 0x5a, 0xff],
1012 };
1013 assert_eq!(var_addr.prefix(), 0xb0bacafeb00b1e5a);
1014 }
1015
1016 #[test]
1017 fn base64_address() {
1018 let addr = "0:84545d4d2cada0ce811705d534c298ca42d29315d03a16eee794cefd191dfa79"
1019 .parse::<StdAddr>()
1020 .unwrap();
1021 assert_eq!(
1022 addr.display_base64(true).to_string(),
1023 "EQCEVF1NLK2gzoEXBdU0wpjKQtKTFdA6Fu7nlM79GR36eWpw"
1024 );
1025 assert_eq!(
1026 StdAddr::from_str_ext(
1027 "EQCEVF1NLK2gzoEXBdU0wpjKQtKTFdA6Fu7nlM79GR36eWpw",
1028 StdAddrFormat::any()
1029 )
1030 .unwrap(),
1031 (
1032 addr,
1033 Base64StdAddrFlags {
1034 testnet: false,
1035 base64_url: false,
1036 bounceable: true,
1037 }
1038 )
1039 );
1040
1041 let addr = "0:dddde93b1d3398f0b4305c08de9a032e0bc1b257c4ce2c72090aea1ff3e9ecfd"
1042 .parse::<StdAddr>()
1043 .unwrap();
1044 assert_eq!(
1045 addr.display_base64_url(false).to_string(),
1046 "UQDd3ek7HTOY8LQwXAjemgMuC8GyV8TOLHIJCuof8-ns_Tyv"
1047 );
1048 assert_eq!(
1049 addr.display_base64(false).to_string(),
1050 "UQDd3ek7HTOY8LQwXAjemgMuC8GyV8TOLHIJCuof8+ns/Tyv"
1051 );
1052
1053 assert_eq!(
1054 StdAddr::from_str_ext(
1055 "UQDd3ek7HTOY8LQwXAjemgMuC8GyV8TOLHIJCuof8+ns/Tyv",
1056 StdAddrFormat::any()
1057 )
1058 .unwrap(),
1059 (
1060 addr.clone(),
1061 Base64StdAddrFlags {
1062 testnet: false,
1063 base64_url: false,
1064 bounceable: false,
1065 }
1066 )
1067 );
1068
1069 assert_eq!(
1070 addr.display_base64_url(true).to_string(),
1071 "EQDd3ek7HTOY8LQwXAjemgMuC8GyV8TOLHIJCuof8-ns_WFq"
1072 );
1073 assert_eq!(
1074 addr.display_base64(true).to_string(),
1075 "EQDd3ek7HTOY8LQwXAjemgMuC8GyV8TOLHIJCuof8+ns/WFq"
1076 );
1077
1078 assert_eq!(
1079 StdAddr::from_str_ext(
1080 "EQDd3ek7HTOY8LQwXAjemgMuC8GyV8TOLHIJCuof8-ns_WFq",
1081 StdAddrFormat::any()
1082 )
1083 .unwrap(),
1084 (
1085 addr,
1086 Base64StdAddrFlags {
1087 testnet: false,
1088 base64_url: true,
1089 bounceable: true,
1090 }
1091 )
1092 );
1093 }
1094}