Skip to main content

ankurah_proto/
data.rs

1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize};
4use sha2::{Digest, Sha256};
5
6use crate::{auth::Attested, clock::Clock, collection::CollectionId, id::EntityId, AttestationSet, DecodeError};
7
8#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
9pub struct EventId([u8; 32]);
10
11impl std::fmt::Debug for EventId {
12    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "EventId({})", self.to_base64()) }
13}
14
15impl EventId {
16    /// Generate an EventID from the parts of an Event
17    /// notably, we are not including the collection in the hash because collection is getting excised from identity
18    pub fn from_parts(entity_id: &EntityId, operations: &OperationSet, parent: &Clock) -> Self {
19        let mut hasher = Sha256::new();
20        hasher.update(bincode::serialize(&entity_id).unwrap());
21        hasher.update(bincode::serialize(&operations).unwrap());
22        hasher.update(bincode::serialize(&parent).unwrap());
23        Self(hasher.finalize().into())
24    }
25    pub fn to_base64(&self) -> String {
26        use base64::{engine::general_purpose, Engine as _};
27        general_purpose::URL_SAFE_NO_PAD.encode(self.0)
28    }
29    pub fn to_base64_short(&self) -> String {
30        // take the last 6 characters of the base64 encoded string
31        let value = self.to_base64();
32        value[value.len() - 6..].to_string()
33    }
34    pub fn from_base64<T: AsRef<[u8]>>(input: T) -> Result<Self, DecodeError> {
35        use base64::{engine::general_purpose, Engine as _};
36        let decoded = general_purpose::URL_SAFE_NO_PAD.decode(input)?;
37        let v: [u8; 32] = decoded.try_into().map_err(|_| DecodeError::InvalidLength)?;
38
39        Ok(Self(v))
40    }
41    pub fn to_bytes(self) -> [u8; 32] { self.0 }
42    pub fn from_bytes(bytes: [u8; 32]) -> Self { Self(bytes) }
43    pub fn as_bytes(&self) -> &[u8] { &self.0 }
44}
45
46impl std::fmt::Display for EventId {
47    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48        if f.alternate() {
49            write!(f, "{}", self.to_base64_short())
50        } else {
51            write!(f, "{}", self.to_base64())
52        }
53    }
54}
55
56impl TryFrom<String> for EventId {
57    type Error = DecodeError;
58
59    fn try_from(s: String) -> Result<Self, Self::Error> { Self::from_base64(&s) }
60}
61
62impl From<[u8; 32]> for EventId {
63    fn from(bytes: [u8; 32]) -> Self { Self(bytes) }
64}
65impl TryFrom<Vec<u8>> for EventId {
66    type Error = DecodeError;
67
68    fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
69        let v: [u8; 32] = bytes.try_into().map_err(|_| DecodeError::InvalidLength)?;
70        Ok(Self(v))
71    }
72}
73
74impl Serialize for EventId {
75    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
76    where S: serde::Serializer {
77        if serializer.is_human_readable() {
78            // Use base64 for human-readable formats like JSON
79            serializer.serialize_str(&self.to_base64())
80        } else {
81            // Use raw bytes as a fixed-size array for binary formats like bincode
82            self.0.serialize(serializer)
83        }
84    }
85}
86
87impl<'de> Deserialize<'de> for EventId {
88    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
89    where D: serde::Deserializer<'de> {
90        if deserializer.is_human_readable() {
91            // Deserialize from base64 string for human-readable formats
92            let s = String::deserialize(deserializer)?;
93            EventId::from_base64(s).map_err(serde::de::Error::custom)
94        } else {
95            // Deserialize from raw bytes as a fixed-size array for binary formats
96            let bytes = <[u8; 32]>::deserialize(deserializer)?;
97            Ok(EventId::from_bytes(bytes))
98        }
99    }
100}
101
102#[derive(Debug, Serialize, Deserialize, Clone)]
103pub struct Event {
104    pub collection: CollectionId,
105    pub entity_id: EntityId,
106    pub operations: OperationSet,
107    /// The set of concurrent events (usually only one) which is the precursor of this event
108    pub parent: Clock,
109}
110
111impl Event {
112    // TODO: figure out how we actually want to signify entity creation. This is a hack for now
113    pub fn is_entity_create(&self) -> bool { self.parent.is_empty() }
114}
115
116#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
117pub struct EventFragment {
118    pub operations: OperationSet,
119    pub parent: Clock,
120    pub attestations: AttestationSet,
121}
122
123impl From<Attested<Event>> for EventFragment {
124    fn from(attested: Attested<Event>) -> Self {
125        Self { operations: attested.payload.operations, parent: attested.payload.parent, attestations: attested.attestations }
126    }
127}
128
129impl From<(EntityId, CollectionId, EventFragment)> for Attested<Event> {
130    fn from(value: (EntityId, CollectionId, EventFragment)) -> Self {
131        let event = Event { entity_id: value.0, collection: value.1, operations: value.2.operations, parent: value.2.parent };
132        Attested { payload: event, attestations: value.2.attestations }
133    }
134}
135
136#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
137pub struct StateFragment {
138    pub state: State,
139    pub attestations: AttestationSet,
140}
141
142impl From<Attested<EntityState>> for StateFragment {
143    fn from(attested: Attested<EntityState>) -> Self { Self { state: attested.payload.state, attestations: attested.attestations } }
144}
145impl From<(EntityId, CollectionId, StateFragment)> for Attested<EntityState> {
146    fn from(value: (EntityId, CollectionId, StateFragment)) -> Self {
147        let entity_state = EntityState { entity_id: value.0, collection: value.1, state: value.2.state };
148        Attested { payload: entity_state, attestations: value.2.attestations }
149    }
150}
151
152impl Event {
153    pub fn id(&self) -> EventId { EventId::from_parts(&self.entity_id, &self.operations, &self.parent) }
154}
155
156#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
157pub struct OperationSet(pub BTreeMap<String, Vec<Operation>>);
158
159impl std::fmt::Display for OperationSet {
160    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
161        write!(
162            f,
163            "OperationSet({})",
164            self.0
165                .iter()
166                .map(|(backend, ops)| format!("{} => {}b", backend, ops.iter().map(|op| op.diff.len()).sum::<usize>()))
167                .collect::<Vec<_>>()
168                .join(" ")
169        )
170    }
171}
172
173impl std::ops::Deref for OperationSet {
174    type Target = BTreeMap<String, Vec<Operation>>;
175    fn deref(&self) -> &Self::Target { &self.0 }
176}
177
178#[derive(Debug, Serialize, Deserialize, Clone, Hash, Eq, PartialEq)]
179pub struct Operation {
180    pub diff: Vec<u8>,
181}
182
183#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
184pub struct EntityState {
185    pub entity_id: EntityId,
186    pub collection: CollectionId,
187    pub state: State,
188}
189
190#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
191pub struct State {
192    /// The current accumulated state of the entity inclusive of all events up to this point
193    pub state_buffers: StateBuffers,
194    /// The set of concurrent events (usually only one) which have been applied to the entity state above
195    pub head: Clock,
196}
197
198#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
199pub struct StateBuffers(pub BTreeMap<String, Vec<u8>>);
200
201impl std::ops::Deref for StateBuffers {
202    type Target = BTreeMap<String, Vec<u8>>;
203    fn deref(&self) -> &Self::Target { &self.0 }
204}
205
206impl std::fmt::Display for Event {
207    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
208        write!(
209            f,
210            "Event({} {}/{} {}{} {})",
211            self.id().to_base64_short(),
212            self.collection,
213            self.entity_id.to_base64_short(),
214            if self.is_entity_create() { "(create) " } else { "" },
215            self.parent.to_base64_short(),
216            self.operations
217                .iter()
218                .map(|(backend, ops)| format!("{} => {}b", backend, ops.iter().map(|op| op.diff.len()).sum::<usize>()))
219                .collect::<Vec<_>>()
220                .join(" ")
221        )
222    }
223}
224
225impl std::fmt::Display for EventFragment {
226    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
227        write!(f, "EventFragment(parent {} operations {})", self.parent, self.operations)
228    }
229}
230
231impl std::fmt::Display for State {
232    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
233        write!(
234            f,
235            "State({:#} buffers {})",
236            self.head,
237            self.state_buffers.iter().map(|(backend, buf)| format!("{} => {}b", backend, buf.len())).collect::<Vec<_>>().join(" ")
238        )
239    }
240}
241
242impl std::fmt::Display for StateFragment {
243    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
244        write!(f, "StateFragment(state {} attestations: {})", self.state, self.attestations.len())
245    }
246}
247
248impl std::fmt::Display for EntityState {
249    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
250        write!(f, "EntityState({} {})", self.entity_id.to_base64_short(), self.state)
251    }
252}
253
254impl Attested<Event> {
255    pub fn collection(&self) -> &CollectionId { &self.payload.collection }
256}
257
258impl From<Event> for Attested<Event> {
259    fn from(val: Event) -> Self { Attested { payload: val, attestations: AttestationSet::default() } }
260}
261
262impl From<EntityState> for Attested<EntityState> {
263    fn from(val: EntityState) -> Self { Attested { payload: val, attestations: AttestationSet::default() } }
264}
265
266impl Attested<EntityState> {
267    pub fn to_parts(self) -> (EntityId, CollectionId, StateFragment) {
268        (self.payload.entity_id, self.payload.collection, StateFragment { state: self.payload.state, attestations: self.attestations })
269    }
270    pub fn from_parts(entity_id: EntityId, collection: CollectionId, fragment: StateFragment) -> Self {
271        Self { payload: EntityState { entity_id, collection, state: fragment.state }, attestations: fragment.attestations }
272    }
273}
274
275impl Attested<Event> {
276    pub fn from_parts(entity_id: EntityId, collection: CollectionId, frag: EventFragment) -> Self {
277        Self { payload: Event { entity_id, collection, operations: frag.operations, parent: frag.parent }, attestations: frag.attestations }
278    }
279}
280
281#[cfg(test)]
282mod tests {
283    use super::*;
284
285    #[test]
286    fn test_event_id_json_serialization() {
287        let id = EventId::from_bytes([
288            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,
289        ]);
290        let json = serde_json::to_string(&id).unwrap();
291        assert_eq!(json, "\"AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA\"");
292        assert_eq!(id, serde_json::from_str(&json).unwrap());
293    }
294
295    #[test]
296    fn test_event_id_bincode_serialization() {
297        let id = EventId::from_bytes([
298            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,
299        ]);
300        let bytes = bincode::serialize(&id).unwrap();
301        assert_eq!(
302            bytes,
303            [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]
304        );
305        assert_eq!(id, bincode::deserialize(&bytes).unwrap());
306    }
307}