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
//! Handle idempotency in event-sourced systems.
/// Signals if a mutation is applied or was skipped.
///
/// Distinguishes between operations that were executed versus those that were
/// ignored due to idempotency checks.
/// The [`idempotency_guard`][crate::idempotency_guard] macro provides an easy way to do such checks.
///
/// # Examples
///
/// ```rust
/// use es_entity::{idempotency_guard, Idempotent};
/// pub enum UserEvent{
/// Initialized {id: u64, name: String},
/// NameUpdated {name: String}
/// }
///
/// pub struct User{
/// events: Vec<UserEvent>
/// }
///
/// impl User{
/// // This returns `Idempotent<T>` where T is the return value we get after the event is processed
/// pub fn update_name(&mut self, new_name: impl Into<String>) -> Idempotent<()>{
/// let name = new_name.into();
/// idempotency_guard!(
/// self.events.iter().rev(),
/// already_applied: UserEvent::NameUpdated { name: existing_name } if existing_name == &name
/// );
/// self.events.push(UserEvent::NameUpdated{name});
/// Idempotent::Executed(())
/// }
/// }
///
/// fn example(){
/// let mut user = User{ events: vec![] };
/// assert!(user.update_name("Alice").did_execute());
/// // updating "Alice" executes as no such event has been processed before.
/// // Signalled by returning `Idempotent::Executed(T)`, validated with `did_execute` helper method
///
/// assert!(user.update_name("Alice").was_already_applied());
/// // updating "Alice" again ignored because same event has been processed before.
/// // Signalled by returning `Idempotent::AlreadyApplied` early, validated with `was_already_applied` helper method
/// }
/// ```
/// Internal trait used by the [`idempotency_guard`][crate::idempotency_guard] macro.
///
/// This internal-only trait is implemented on [`idempotency_guard`][crate::idempotency_guard] for it to create
/// both `Idempotent<T>` and `Result<Idempotent<T>, E>` return types for returning `AlreadyApplied` variant.