1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
use spacetimedb_bindings_macro::{Deserialize, Serialize};
use spacetimedb_sats::hex::HexString;
use spacetimedb_sats::{hash, impl_st, AlgebraicType, AlgebraicValue, ProductValue};
use std::{fmt, str::FromStr};

pub type RequestId = u32;

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct AuthCtx {
    pub owner: Identity,
    pub caller: Identity,
}

impl AuthCtx {
    pub fn new(owner: Identity, caller: Identity) -> Self {
        Self { owner, caller }
    }
    /// For when the owner == caller
    pub fn for_current(owner: Identity) -> Self {
        Self { owner, caller: owner }
    }
    /// WARNING: Use this only for simple test were the `auth` don't matter
    pub fn for_testing() -> Self {
        AuthCtx {
            owner: Identity::__dummy(),
            caller: Identity::__dummy(),
        }
    }
}

#[derive(Default, Eq, PartialEq, PartialOrd, Ord, Clone, Copy, Hash, Serialize, Deserialize)]
pub struct Identity {
    __identity_bytes: [u8; 32],
}

impl_st!([] Identity, _ts => Identity::get_type());

impl spacetimedb_metrics::typed_prometheus::AsPrometheusLabel for Identity {
    fn as_prometheus_str(&self) -> impl AsRef<str> + '_ {
        self.to_hex()
    }
}

impl Identity {
    pub const ZERO: Self = Self {
        __identity_bytes: [0; 32],
    };

    /// Returns an `Identity` defined as the given `bytes` byte array.
    pub const fn from_byte_array(bytes: [u8; 32]) -> Self {
        Self {
            __identity_bytes: bytes,
        }
    }

    /// Returns an `Identity` defined as the given byte `slice`.
    pub fn from_slice(slice: &[u8]) -> Self {
        Self::from_byte_array(slice.try_into().unwrap())
    }

    #[doc(hidden)]
    pub fn __dummy() -> Self {
        Self::from_byte_array([0; 32])
    }

    pub fn get_type() -> AlgebraicType {
        AlgebraicType::product([("__identity_bytes", AlgebraicType::bytes())])
    }

    /// Returns a borrowed view of the byte array defining this `Identity`.
    pub fn as_bytes(&self) -> &[u8; 32] {
        &self.__identity_bytes
    }

    pub fn to_vec(&self) -> Vec<u8> {
        self.__identity_bytes.to_vec()
    }

    pub fn to_hex(&self) -> HexString<32> {
        spacetimedb_sats::hex::encode(&self.__identity_bytes)
    }

    pub fn abbreviate(&self) -> &[u8; 8] {
        self.__identity_bytes[..8].try_into().unwrap()
    }

    pub fn to_abbreviated_hex(&self) -> HexString<8> {
        spacetimedb_sats::hex::encode(self.abbreviate())
    }

    pub fn from_hex(hex: impl AsRef<[u8]>) -> Result<Self, hex::FromHexError> {
        hex::FromHex::from_hex(hex)
    }

    pub fn from_hashing_bytes(bytes: impl AsRef<[u8]>) -> Self {
        Identity::from_byte_array(hash::hash_bytes(bytes).data)
    }
}

impl fmt::Display for Identity {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad(&self.to_hex())
    }
}

impl fmt::Debug for Identity {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_tuple("Identity").field(&self.to_hex()).finish()
    }
}

impl hex::FromHex for Identity {
    type Error = hex::FromHexError;

    fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
        let data = hex::FromHex::from_hex(hex)?;
        Ok(Identity { __identity_bytes: data })
    }
}

impl FromStr for Identity {
    type Err = <Self as hex::FromHex>::Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Self::from_hex(s)
    }
}

impl From<Identity> for AlgebraicValue {
    fn from(value: Identity) -> Self {
        AlgebraicValue::Product(ProductValue::from(AlgebraicValue::Bytes(value.to_vec().into())))
    }
}

#[cfg(feature = "serde")]
impl serde::Serialize for Identity {
    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        spacetimedb_sats::ser::serde::serialize_to(self.as_bytes(), serializer)
    }
}

#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for Identity {
    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        let arr = spacetimedb_sats::de::serde::deserialize_from(deserializer)?;
        Ok(Identity::from_byte_array(arr))
    }
}