sourcery_core/codec.rs
1//! Serialization strategy abstraction.
2//!
3//! `Codec` converts domain events to bytes and back. `SerializableEvent` and
4//! `ProjectionEvent` are implemented by aggregate event enums to bridge the gap
5//! between domain variants and stored representations.
6
7use thiserror::Error;
8
9/// Error returned when deserializing a stored event fails.
10#[derive(Debug, Error)]
11pub enum EventDecodeError<CodecError> {
12 /// The event kind was not recognized by this event enum.
13 #[error("unknown event kind `{kind}`, expected one of {expected:?}")]
14 UnknownKind {
15 /// The unrecognized event kind string.
16 kind: String,
17 /// The list of event kinds this enum can handle.
18 expected: &'static [&'static str],
19 },
20 /// The codec failed to deserialize the event data.
21 #[error("codec error: {0}")]
22 Codec(#[source] CodecError),
23}
24
25/// Serialisation strategy used by event stores.
26// ANCHOR: codec_trait
27pub trait Codec {
28 type Error: std::error::Error + Send + Sync + 'static;
29
30 /// Serialize a value for persistence.
31 ///
32 /// # Errors
33 ///
34 /// Returns an error from the codec if the value cannot be serialized.
35 fn serialize<T>(&self, value: &T) -> Result<Vec<u8>, Self::Error>
36 where
37 T: serde::Serialize;
38
39 /// Deserialize a value from stored bytes.
40 ///
41 /// # Errors
42 ///
43 /// Returns an error from the codec if the bytes cannot be decoded.
44 fn deserialize<T>(&self, data: &[u8]) -> Result<T, Self::Error>
45 where
46 T: serde::de::DeserializeOwned;
47}
48// ANCHOR_END: codec_trait
49
50/// Trait for event sum types that can serialize themselves for persistence.
51///
52/// Implemented by aggregate event enums to serialize variants for persistence.
53///
54/// The `Aggregate` derive macro generates this automatically; hand-written
55/// enums can implement it directly if preferred. The generic `M` parameter
56/// allows passing through custom metadata types supplied by the store.
57pub trait SerializableEvent {
58 /// Serialize this event to persistable form with generic metadata.
59 ///
60 /// # Errors
61 ///
62 /// Returns a codec error if serialization fails.
63 fn to_persistable<C: Codec, M>(
64 self,
65 codec: &C,
66 metadata: M,
67 ) -> Result<crate::store::PersistableEvent<M>, C::Error>;
68}
69
70/// Trait for event sum types that can deserialize themselves from stored
71/// events.
72///
73/// Implemented by event enums to deserialize stored events.
74///
75/// Deriving [`Aggregate`](crate::Aggregate) includes a `ProjectionEvent`
76/// implementation for the generated sum type. Custom enums can opt in manually
77/// using the pattern illustrated below.
78pub trait ProjectionEvent: Sized {
79 /// The list of event kinds this sum type can deserialize.
80 ///
81 /// This data is generated automatically when using the derive macros.
82 const EVENT_KINDS: &'static [&'static str];
83
84 /// Deserialize an event from stored representation.
85 ///
86 /// # Errors
87 ///
88 /// Returns [`EventDecodeError::UnknownKind`] if the event kind is not
89 /// recognized, or [`EventDecodeError::Codec`] if deserialization fails.
90 fn from_stored<C: Codec>(
91 kind: &str,
92 data: &[u8],
93 codec: &C,
94 ) -> Result<Self, EventDecodeError<C::Error>>;
95}