ouisync/
device_id.rs

1use hex::FromHexError;
2use serde::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer};
3use std::str::FromStr;
4
5define_byte_array_wrapper! {
6    /// DeviceId uniquely identifies machines on which this software is running. Its only purpose is
7    /// to ensure that one WriterId (which currently equates to sing::PublicKey) will never create two
8    /// or more concurrent snapshots as that would break the whole repository.  This is achieved by
9    /// ensuring that there is always only a single DeviceId associated with a single WriterId.
10    ///
11    /// This means that whenever the database is copied/moved from one device to another, the database
12    /// containing the DeviceId MUST either not be migrated with it, OR ensure that it'll never be
13    /// used from its original place.
14    ///
15    /// ReplicaIds are private and thus not shared over the network.
16    pub struct DeviceId([u8; 32]);
17}
18
19derive_rand_for_wrapper!(DeviceId);
20derive_sqlx_traits_for_byte_array_wrapper!(DeviceId);
21
22impl FromStr for DeviceId {
23    type Err = FromHexError;
24
25    fn from_str(s: &str) -> Result<Self, Self::Err> {
26        let mut buffer = [0; Self::SIZE];
27        hex::decode_to_slice(s.trim(), &mut buffer)?;
28        Ok(Self(buffer))
29    }
30}
31
32impl Serialize for DeviceId {
33    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
34    where
35        S: Serializer,
36    {
37        if s.is_human_readable() {
38            self.to_string().serialize(s)
39        } else {
40            self.0.serialize(s)
41        }
42    }
43}
44
45impl<'de> Deserialize<'de> for DeviceId {
46    fn deserialize<D>(d: D) -> Result<Self, D::Error>
47    where
48        D: Deserializer<'de>,
49    {
50        if d.is_human_readable() {
51            <&str>::deserialize(d)?.parse().map_err(D::Error::custom)
52        } else {
53            <[u8; Self::SIZE]>::deserialize(d).map(Self)
54        }
55    }
56}