1use std::fmt;
2
3#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
5#[repr(C)]
6pub struct Address(pub [u8; 20]);
7
8impl Address {
9 pub unsafe fn from_raw(bytes: *const u8) -> Self {
11 let mut addr = Self::default();
12 addr.0
13 .copy_from_slice(std::slice::from_raw_parts(bytes, Self::size()));
14 addr
15 }
16
17 pub fn as_ptr(&self) -> *const u8 {
18 self.0.as_ptr()
19 }
20
21 pub const fn size() -> usize {
23 std::mem::size_of::<Self>()
24 }
25
26 pub fn path_repr(&self) -> std::path::PathBuf {
27 std::path::PathBuf::from(hex::encode(self))
28 }
29
30 pub fn zero() -> Self {
32 Self::default()
33 }
34}
35
36impl AsRef<[u8]> for Address {
37 fn as_ref(&self) -> &[u8] {
38 &self.0
39 }
40}
41
42impl std::str::FromStr for Address {
43 type Err = hex::FromHexError;
44 fn from_str(s: &str) -> Result<Self, Self::Err> {
45 let bytes: Vec<u8> = hex::decode(s)?;
46 if bytes.len() != Address::size() {
47 return Err(hex::FromHexError::InvalidStringLength);
48 }
49 let mut addr = Self::default();
50 addr.0.copy_from_slice(&bytes);
51 Ok(addr)
52 }
53}
54
55impl fmt::Display for Address {
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 write!(f, "0x{}", hex::encode(self.0))
58 }
59}
60
61impl fmt::LowerHex for Address {
62 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63 f.write_str(&hex::encode(self.0))
64 }
65}
66
67const _IMPL_SERDE_FOR_ADDRESS: () = {
68 impl oasis_borsh::BorshSerialize for Address {
69 fn serialize<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
70 writer.write_all(&self.0)
71 }
72 }
73
74 impl oasis_borsh::BorshDeserialize for Address {
75 fn deserialize<R: std::io::Read>(reader: &mut R) -> Result<Self, std::io::Error> {
76 let mut addr = Address::default();
77 reader.read_exact(&mut addr.0)?;
78 Ok(addr)
79 }
80 }
81};
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86
87 #[test]
88 fn convert_str() {
89 use std::str::FromStr;
90
91 let addr = Address([
92 96, 255, 103, 244, 45, 95, 214, 205, 158, 83, 176, 57, 114, 69, 94, 82, 182, 223, 75,
93 28,
94 ]);
95 let addr_str = "60ff67f42d5fd6cd9e53b03972455e52b6df4b1c";
96 assert_eq!(&addr.path_repr(), std::path::Path::new(addr_str));
97 assert_eq!(&format!("{:x}", addr), addr_str);
98 assert_eq!(format!("{}", addr), format!("0x{}", addr_str));
99 assert_eq!(Address::from_str(addr_str).unwrap(), addr);
100 assert!(Address::from_str(&addr_str[1..]).is_err());
101 assert!(Address::from_str(&format!("{}ab", addr_str)).is_err());
102 assert!(Address::from_str("zz").is_err());
103 }
104
105 #[test]
106 fn convert_raw() {
107 let addr = Address([
108 96, 255, 103, 244, 45, 95, 214, 205, 158, 83, 176, 57, 114, 69, 94, 82, 182, 223, 75,
109 28,
110 ]);
111 assert_eq!(unsafe { Address::from_raw(addr.as_ptr()) }, addr);
112 }
113}
114
115#[cfg(all(test, feature = "serde"))]
116mod serde_tests {
117 use super::*;
118
119 use oasis_borsh::{BorshDeserialize as _, BorshSerialize as _};
120
121 #[test]
122 fn roundtrip_serialize_address() {
123 let bytes = [1u8; 20];
124 let addr = Address::try_from_slice(&Address(bytes).try_to_vec().unwrap()).unwrap();
125 assert_eq!(addr.0, bytes);
126 }
127
128 #[test]
129 #[should_panic]
130 fn fail_deserialize_address_short() {
131 let bytes = [1u8; 19];
132 Address::try_from_slice(&bytes.try_to_vec().unwrap()).unwrap();
133 }
134
135 #[test]
136 #[should_panic]
137 fn fail_deserialize_address_long() {
138 let bytes = [1u8; 21];
139 Address::try_from_slice(&bytes.as_ref().try_to_vec().unwrap()).unwrap();
140 }
141}