1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3use std::borrow::Cow;
4use std::fmt;
5use std::ops::Deref;
6
7use crate::{binary::Binary, HexBinary};
8
9#[derive(
26 Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, JsonSchema,
27)]
28pub struct Addr(String);
29
30impl Addr {
31 pub fn unchecked(input: impl Into<String>) -> Addr {
47 Addr(input.into())
48 }
49
50 #[inline]
51 pub fn as_str(&self) -> &str {
52 self.0.as_str()
53 }
54
55 #[inline]
59 pub fn as_bytes(&self) -> &[u8] {
60 self.0.as_bytes()
61 }
62
63 #[inline]
65 pub fn into_string(self) -> String {
66 self.0
67 }
68}
69
70impl fmt::Display for Addr {
71 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72 write!(f, "{}", &self.0)
73 }
74}
75
76impl AsRef<str> for Addr {
77 #[inline]
78 fn as_ref(&self) -> &str {
79 self.as_str()
80 }
81}
82
83impl PartialEq<&str> for Addr {
85 fn eq(&self, rhs: &&str) -> bool {
86 self.0 == *rhs
87 }
88}
89
90impl PartialEq<Addr> for &str {
92 fn eq(&self, rhs: &Addr) -> bool {
93 *self == rhs.0
94 }
95}
96
97impl PartialEq<String> for Addr {
99 fn eq(&self, rhs: &String) -> bool {
100 &self.0 == rhs
101 }
102}
103
104impl PartialEq<Addr> for String {
106 fn eq(&self, rhs: &Addr) -> bool {
107 self == &rhs.0
108 }
109}
110
111impl From<Addr> for String {
115 fn from(addr: Addr) -> Self {
116 addr.0
117 }
118}
119
120impl From<&Addr> for String {
121 fn from(addr: &Addr) -> Self {
122 addr.0.clone()
123 }
124}
125
126impl From<Addr> for Cow<'_, Addr> {
127 fn from(addr: Addr) -> Self {
128 Cow::Owned(addr)
129 }
130}
131
132impl<'a> From<&'a Addr> for Cow<'a, Addr> {
133 fn from(addr: &'a Addr) -> Self {
134 Cow::Borrowed(addr)
135 }
136}
137
138#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash, JsonSchema)]
154pub struct CanonicalAddr(pub Binary);
155
156impl PartialEq<Binary> for CanonicalAddr {
158 fn eq(&self, rhs: &Binary) -> bool {
159 &self.0 == rhs
160 }
161}
162
163impl PartialEq<CanonicalAddr> for Binary {
165 fn eq(&self, rhs: &CanonicalAddr) -> bool {
166 self == &rhs.0
167 }
168}
169
170impl PartialEq<HexBinary> for CanonicalAddr {
172 fn eq(&self, rhs: &HexBinary) -> bool {
173 self.as_slice() == rhs.as_slice()
174 }
175}
176
177impl PartialEq<CanonicalAddr> for HexBinary {
179 fn eq(&self, rhs: &CanonicalAddr) -> bool {
180 self.as_slice() == rhs.0.as_slice()
181 }
182}
183
184impl From<&[u8]> for CanonicalAddr {
185 fn from(source: &[u8]) -> Self {
186 Self(source.into())
187 }
188}
189
190impl<const LENGTH: usize> From<&[u8; LENGTH]> for CanonicalAddr {
192 fn from(source: &[u8; LENGTH]) -> Self {
193 Self(source.into())
194 }
195}
196
197impl<const LENGTH: usize> From<[u8; LENGTH]> for CanonicalAddr {
199 fn from(source: [u8; LENGTH]) -> Self {
200 Self(source.into())
201 }
202}
203
204impl From<Vec<u8>> for CanonicalAddr {
206 fn from(source: Vec<u8>) -> Self {
207 Self(source.into())
208 }
209}
210
211impl From<CanonicalAddr> for Vec<u8> {
213 fn from(source: CanonicalAddr) -> Vec<u8> {
214 source.0.into()
215 }
216}
217
218impl From<Binary> for CanonicalAddr {
220 fn from(source: Binary) -> Self {
221 Self(source)
222 }
223}
224
225impl From<CanonicalAddr> for Binary {
227 fn from(source: CanonicalAddr) -> Binary {
228 source.0
229 }
230}
231
232impl From<HexBinary> for CanonicalAddr {
234 fn from(source: HexBinary) -> Self {
235 Self(source.into())
236 }
237}
238
239impl From<CanonicalAddr> for HexBinary {
241 fn from(source: CanonicalAddr) -> HexBinary {
242 source.0.into()
243 }
244}
245
246impl Deref for CanonicalAddr {
252 type Target = [u8];
253
254 fn deref(&self) -> &Self::Target {
255 self.as_slice()
256 }
257}
258
259impl CanonicalAddr {
260 pub fn as_slice(&self) -> &[u8] {
261 self.0.as_slice()
262 }
263}
264
265impl fmt::Display for CanonicalAddr {
266 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
267 for byte in self.0.as_slice() {
268 write!(f, "{:02X}", byte)?;
269 }
270 Ok(())
271 }
272}
273
274#[cfg(test)]
275mod tests {
276 use super::*;
277 use std::collections::hash_map::DefaultHasher;
278 use std::collections::HashSet;
279 use std::hash::{Hash, Hasher};
280
281 #[test]
282 fn addr_unchecked_works() {
283 let a = Addr::unchecked("123");
284 let aa = Addr::unchecked(String::from("123"));
285 let b = Addr::unchecked("be");
286 assert_eq!(a, aa);
287 assert_ne!(a, b);
288 }
289
290 #[test]
291 fn addr_as_str_works() {
292 let addr = Addr::unchecked("literal-string");
293 assert_eq!(addr.as_str(), "literal-string");
294 }
295
296 #[test]
297 fn addr_as_bytes_works() {
298 let addr = Addr::unchecked("literal-string");
299 assert_eq!(
300 addr.as_bytes(),
301 [108, 105, 116, 101, 114, 97, 108, 45, 115, 116, 114, 105, 110, 103]
302 );
303 }
304
305 #[test]
306 fn addr_implements_display() {
307 let addr = Addr::unchecked("cos934gh9034hg04g0h134");
308 let embedded = format!("Address: {}", addr);
309 assert_eq!(embedded, "Address: cos934gh9034hg04g0h134");
310 assert_eq!(addr.to_string(), "cos934gh9034hg04g0h134");
311 }
312
313 #[test]
314 fn addr_implements_as_ref_for_str() {
315 let addr = Addr::unchecked("literal-string");
316 assert_eq!(addr.as_ref(), "literal-string");
317 }
318
319 #[test]
320 fn addr_implements_partial_eq_with_str() {
321 let addr = Addr::unchecked("cos934gh9034hg04g0h134");
322
323 assert_eq!(addr, "cos934gh9034hg04g0h134");
325 assert_eq!("cos934gh9034hg04g0h134", addr);
327 }
328
329 #[test]
330 fn addr_implements_partial_eq_with_string() {
331 let addr = Addr::unchecked("cos934gh9034hg04g0h134");
332
333 assert_eq!(addr, String::from("cos934gh9034hg04g0h134"));
335 assert_eq!(String::from("cos934gh9034hg04g0h134"), addr);
337 }
338
339 #[test]
340 fn addr_implements_into_string() {
341 let addr = Addr::unchecked("cos934gh9034hg04g0h134");
343 let string: String = addr.into();
344 assert_eq!(string, "cos934gh9034hg04g0h134");
345
346 let addr = Addr::unchecked("cos934gh9034hg04g0h134");
348 let addr_ref = &addr;
349 let string: String = addr_ref.into();
350 assert_eq!(string, "cos934gh9034hg04g0h134");
351 }
352
353 #[test]
355 fn canonical_addr_from_slice() {
356 let bytes: &[u8] = &[0u8, 187, 61, 11, 250, 0];
358 let canonical_addr_slice = CanonicalAddr::from(bytes);
359 assert_eq!(canonical_addr_slice.as_slice(), &[0u8, 187, 61, 11, 250, 0]);
360
361 let bytes: Vec<u8> = vec![0u8, 187, 61, 11, 250, 0];
363 let canonical_addr_vec = CanonicalAddr::from(bytes);
364 assert_eq!(canonical_addr_vec.as_slice(), &[0u8, 187, 61, 11, 250, 0]);
365 }
366
367 #[test]
368 fn canonical_addr_implements_partial_eq_with_binary() {
369 let addr = CanonicalAddr::from([1, 2, 3]);
370 let bin1 = Binary::from([1, 2, 3]);
371 let bin2 = Binary::from([42, 43]);
372
373 assert_eq!(addr, bin1);
374 assert_eq!(bin1, addr);
375 assert_ne!(addr, bin2);
376 assert_ne!(bin2, addr);
377 }
378
379 #[test]
380 fn canonical_addr_implements_partial_eq_with_hex_binary() {
381 let addr = CanonicalAddr::from([1, 2, 3]);
382 let bin1 = HexBinary::from([1, 2, 3]);
383 let bin2 = HexBinary::from([42, 43]);
384
385 assert_eq!(addr, bin1);
386 assert_eq!(bin1, addr);
387 assert_ne!(addr, bin2);
388 assert_ne!(bin2, addr);
389 }
390
391 #[test]
392 fn canonical_addr_implements_from_array() {
393 let array = [1, 2, 3];
394 let addr = CanonicalAddr::from(array);
395 assert_eq!(addr.as_slice(), [1, 2, 3]);
396
397 let array_ref = b"foo";
398 let addr = CanonicalAddr::from(array_ref);
399 assert_eq!(addr.as_slice(), [0x66, 0x6f, 0x6f]);
400 }
401
402 #[test]
403 fn canonical_addr_implements_from_and_to_vector() {
404 let original = vec![0u8, 187, 61, 11, 250, 0];
407 let original_ptr = original.as_ptr();
408 let addr: CanonicalAddr = original.into();
409 assert_eq!(addr.as_slice(), [0u8, 187, 61, 11, 250, 0]);
410 assert_eq!((addr.0).0.as_ptr(), original_ptr, "must not be copied");
411
412 let original = vec![0u8, 187, 61, 11, 250, 0];
414 let original_ptr = original.as_ptr();
415 let addr = CanonicalAddr::from(original);
416 assert_eq!(addr.as_slice(), [0u8, 187, 61, 11, 250, 0]);
417 assert_eq!((addr.0).0.as_ptr(), original_ptr, "must not be copied");
418
419 let original = CanonicalAddr::from(vec![0u8, 187, 61, 11, 250, 0]);
422 let original_ptr = (original.0).0.as_ptr();
423 let vec: Vec<u8> = original.into();
424 assert_eq!(vec.as_slice(), [0u8, 187, 61, 11, 250, 0]);
425 assert_eq!(vec.as_ptr(), original_ptr, "must not be copied");
426
427 let original = CanonicalAddr::from(vec![7u8, 35, 49, 101, 0, 255]);
429 let original_ptr = (original.0).0.as_ptr();
430 let vec = Vec::<u8>::from(original);
431 assert_eq!(vec.as_slice(), [7u8, 35, 49, 101, 0, 255]);
432 assert_eq!(vec.as_ptr(), original_ptr, "must not be copied");
433 }
434
435 #[test]
436 fn canonical_addr_implements_from_and_to_binary() {
437 let original = Binary::from([0u8, 187, 61, 11, 250, 0]);
439 let original_ptr = original.as_ptr();
440 let addr = CanonicalAddr::from(original);
441 assert_eq!(addr.as_slice(), [0u8, 187, 61, 11, 250, 0]);
442 assert_eq!((addr.0).0.as_ptr(), original_ptr, "must not be copied");
443
444 let original = CanonicalAddr::from(vec![7u8, 35, 49, 101, 0, 255]);
446 let original_ptr = (original.0).0.as_ptr();
447 let bin = Binary::from(original);
448 assert_eq!(bin.as_slice(), [7u8, 35, 49, 101, 0, 255]);
449 assert_eq!(bin.as_ptr(), original_ptr, "must not be copied");
450 }
451
452 #[test]
453 fn canonical_addr_implements_from_and_to_hex_binary() {
454 let original = HexBinary::from([0u8, 187, 61, 11, 250, 0]);
456 let original_ptr = original.as_ptr();
457 let addr = CanonicalAddr::from(original);
458 assert_eq!(addr.as_slice(), [0u8, 187, 61, 11, 250, 0]);
459 assert_eq!((addr.0).0.as_ptr(), original_ptr, "must not be copied");
460
461 let original = CanonicalAddr::from(vec![7u8, 35, 49, 101, 0, 255]);
463 let original_ptr = (original.0).0.as_ptr();
464 let bin = HexBinary::from(original);
465 assert_eq!(bin.as_slice(), [7u8, 35, 49, 101, 0, 255]);
466 assert_eq!(bin.as_ptr(), original_ptr, "must not be copied");
467 }
468
469 #[test]
470 fn canonical_addr_len() {
471 let bytes: &[u8] = &[0u8, 187, 61, 11, 250, 0];
472 let canonical_addr = CanonicalAddr::from(bytes);
473 assert_eq!(canonical_addr.len(), bytes.len());
474 }
475
476 #[test]
477 fn canonical_addr_is_empty() {
478 let bytes: &[u8] = &[0u8, 187, 61, 11, 250, 0];
479 let canonical_addr = CanonicalAddr::from(bytes);
480 assert!(!canonical_addr.is_empty());
481 let empty_canonical_addr = CanonicalAddr::from(vec![]);
482 assert!(empty_canonical_addr.is_empty());
483 }
484
485 #[test]
486 fn canonical_addr_implements_display() {
487 let bytes: &[u8] = &[
488 0x12, 0x03, 0xab, 0x00, 0xff,
493 ];
494 let address = CanonicalAddr::from(bytes);
495 let embedded = format!("Address: {}", address);
496 assert_eq!(embedded, "Address: 1203AB00FF");
497 assert_eq!(address.to_string(), "1203AB00FF");
498 }
499
500 #[test]
501 fn canonical_addr_implements_deref() {
502 let bytes: &[u8] = &[0u8, 187, 61, 11, 250, 0];
504 let canonical_addr = CanonicalAddr::from(bytes);
505 assert_eq!(*canonical_addr, [0u8, 187, 61, 11, 250, 0]);
506
507 let bytes: &[u8] = &[0u8, 187, 61, 11, 250, 0];
509 let canonical_addr = CanonicalAddr::from(bytes);
510 assert_eq!(canonical_addr.len(), 6);
511 let canonical_addr_slice: &[u8] = &canonical_addr;
512 assert_eq!(canonical_addr_slice, &[0u8, 187, 61, 11, 250, 0]);
513 }
514
515 #[test]
516 fn canonical_addr_implements_hash() {
517 let alice1 = CanonicalAddr::from([0, 187, 61, 11, 250, 0]);
518 let mut hasher = DefaultHasher::new();
519 alice1.hash(&mut hasher);
520 let alice1_hash = hasher.finish();
521
522 let alice2 = CanonicalAddr::from([0, 187, 61, 11, 250, 0]);
523 let mut hasher = DefaultHasher::new();
524 alice2.hash(&mut hasher);
525 let alice2_hash = hasher.finish();
526
527 let bob = CanonicalAddr::from([16, 21, 33, 0, 255, 9]);
528 let mut hasher = DefaultHasher::new();
529 bob.hash(&mut hasher);
530 let bob_hash = hasher.finish();
531
532 assert_eq!(alice1_hash, alice2_hash);
533 assert_ne!(alice1_hash, bob_hash);
534 }
535
536 #[test]
538 fn canonical_addr_can_be_used_in_hash_set() {
539 let alice1 = CanonicalAddr::from([0, 187, 61, 11, 250, 0]);
540 let alice2 = CanonicalAddr::from([0, 187, 61, 11, 250, 0]);
541 let bob = CanonicalAddr::from([16, 21, 33, 0, 255, 9]);
542
543 let mut set = HashSet::new();
544 set.insert(alice1.clone());
545 set.insert(alice2.clone());
546 set.insert(bob.clone());
547 assert_eq!(set.len(), 2);
548
549 let set1 = HashSet::<CanonicalAddr>::from_iter(vec![bob.clone(), alice1.clone()]);
550 let set2 = HashSet::from_iter(vec![alice1, alice2, bob]);
551 assert_eq!(set1, set2);
552 }
553
554 fn flexible<'a>(a: impl Into<Cow<'a, Addr>>) -> String {
556 a.into().into_owned().to_string()
557 }
558
559 #[test]
560 fn addr_into_cow() {
561 let value = "wasmeucn0ur0ncny2308ry";
563 let addr = Addr::unchecked(value);
564
565 assert_eq!(value, &flexible(&addr));
567 assert_eq!(value, &flexible(addr));
569 }
570}