Skip to main content

libsignal_protocol/
address.rs

1use libsignal_protocol_sys as sys;
2use std::{
3    fmt::{self, Debug, Formatter},
4    hash::{Hash, Hasher},
5    os::raw::c_char,
6    pin::Pin,
7    rc::Rc,
8};
9
10/// A reference-counted pointer to a signal address (recipient name, device ID
11/// tuple).
12#[derive(PartialEq, Eq, Hash)]
13pub struct Address(Rc<OwnedAddress>);
14
15impl Address {
16    /// Create a new [`Address`].
17    pub fn new<N: AsRef<[u8]>>(name: N, device_id: i32) -> Address {
18        Address(Rc::new(OwnedAddress::new(name.as_ref(), device_id)))
19    }
20
21    /// Create a new [`Address`] from the raw struct.
22    ///
23    /// # Safety
24    ///
25    /// The `name` pointed to by the [`sys::signal_protocol_address`] must
26    /// outlive this [`Address`].
27    pub(crate) unsafe fn from_raw(
28        raw: sys::signal_protocol_address,
29    ) -> Address {
30        let name =
31            std::slice::from_raw_parts(raw.name as *const _, raw.name_len);
32        Address::new(name, raw.device_id)
33    }
34
35    /// Create an [`Address`] from a pointer to the raw struct.
36    ///
37    /// # Safety
38    ///
39    /// (See the notes on [`Address::from_raw`])
40    pub(crate) unsafe fn from_ptr(
41        raw: *const sys::signal_protocol_address,
42    ) -> Address {
43        Address::from_raw(raw.read())
44    }
45
46    /// Get a string of bytes identifying a recipient (usually their name as a
47    /// utf-8 string).
48    ///
49    /// You may also be looking for the [`Address::as_str`] method.
50    pub fn bytes(&self) -> &[u8] { self.0.name_bytes() }
51
52    /// Get the name attached to this address, converted to a `&str`.
53    pub fn as_str(&self) -> Result<&str, std::str::Utf8Error> {
54        self.0.name_utf8()
55    }
56
57    /// Get the device ID attached to this address.
58    pub fn device_id(&self) -> i32 { self.0.device_id() }
59
60    pub(crate) fn raw(&self) -> &sys::signal_protocol_address { &self.0.raw }
61}
62
63impl Debug for Address {
64    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { self.0.fmt(f) }
65}
66
67impl Clone for Address {
68    fn clone(&self) -> Address { Address(Rc::clone(&self.0)) }
69}
70
71struct OwnedAddress {
72    raw: sys::signal_protocol_address,
73    name: Pin<Box<[u8]>>,
74}
75
76impl OwnedAddress {
77    fn new(name: &[u8], device_id: i32) -> OwnedAddress {
78        let name = name.to_vec().into_boxed_slice();
79        let name = Pin::new(name);
80
81        OwnedAddress {
82            raw: sys::signal_protocol_address {
83                name: name.as_ptr() as *const c_char,
84                name_len: name.len(),
85                device_id,
86            },
87            name,
88        }
89    }
90
91    pub fn name_bytes(&self) -> &[u8] { &self.name }
92
93    pub fn name_utf8(&self) -> Result<&str, std::str::Utf8Error> {
94        std::str::from_utf8(self.name_bytes())
95    }
96
97    pub const fn device_id(&self) -> i32 { self.raw.device_id }
98}
99
100impl Debug for OwnedAddress {
101    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
102        let mut f = f.debug_struct("Address");
103
104        match self.name_utf8() {
105            Ok(name) => {
106                f.field("name", &name);
107            },
108            Err(_) => {
109                f.field("name", &self.name_bytes());
110            },
111        }
112
113        f.field("device_id", &self.device_id()).finish()
114    }
115}
116
117impl Clone for OwnedAddress {
118    fn clone(&self) -> OwnedAddress {
119        OwnedAddress::new(&self.name, self.raw.device_id)
120    }
121}
122
123impl PartialEq for OwnedAddress {
124    fn eq(&self, other: &OwnedAddress) -> bool {
125        self.device_id() == other.device_id()
126            && self.name_bytes() == other.name_bytes()
127    }
128}
129
130impl Eq for OwnedAddress {}
131
132impl Hash for OwnedAddress {
133    fn hash<H: Hasher>(&self, h: &mut H) {
134        h.write_i32(self.device_id());
135        h.write(self.name_bytes());
136    }
137}