oasis_types/
address.rs

1use std::fmt;
2
3/// A 160-bit little-endian hash address type.
4#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
5#[repr(C)]
6pub struct Address(pub [u8; 20]);
7
8impl Address {
9    /// Creates an `Address` from a little-endian byte array.
10    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    // Alias for `mem::size_of::<Address>()`.
22    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    /// Alias for `Address::default()`.
31    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}