Skip to main content

matchcore/outcome/
command_failure.rs

1use crate::{CommandError, SequenceNumber, Timestamp};
2
3use std::fmt;
4
5/// Reason for the command execution failure
6#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub enum CommandFailure {
9    /// The sequence number of the command is invalid
10    /// This happens when the command is received out of order
11    InvalidSequenceNumber {
12        /// The expected sequence number
13        expected_sequence_number: SequenceNumber,
14        /// The received sequence number
15        received_sequence_number: SequenceNumber,
16    },
17    /// The timestamp of the command is invalid
18    /// This happens when the command is received before the last seen timestamp
19    InvalidTimestamp {
20        /// The last seen timestamp
21        last_seen_timestamp: Timestamp,
22        /// The received timestamp
23        received_timestamp: Timestamp,
24    },
25    /// The command is invalid
26    /// This happens when the command violates the invariants of a command
27    InvalidCommand(CommandError),
28    /// The order was not found in the order book
29    OrderNotFound,
30}
31
32impl fmt::Display for CommandFailure {
33    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34        match self {
35            CommandFailure::InvalidSequenceNumber {
36                expected_sequence_number,
37                received_sequence_number,
38            } => write!(
39                f,
40                "invalid sequence number: expected {}, received {}",
41                expected_sequence_number, received_sequence_number
42            ),
43            CommandFailure::InvalidTimestamp {
44                last_seen_timestamp,
45                received_timestamp,
46            } => write!(
47                f,
48                "invalid timestamp: received timestamp {} is before the last seen timestamp {}",
49                received_timestamp, last_seen_timestamp
50            ),
51            CommandFailure::InvalidCommand(e) => write!(f, "invalid command: {e}"),
52            CommandFailure::OrderNotFound => write!(f, "order not found"),
53        }
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60
61    #[test]
62    fn test_display() {
63        assert_eq!(
64            CommandFailure::InvalidSequenceNumber {
65                expected_sequence_number: SequenceNumber(1),
66                received_sequence_number: SequenceNumber(2),
67            }
68            .to_string(),
69            "invalid sequence number: expected 1, received 2"
70        );
71        assert_eq!(
72            CommandFailure::InvalidTimestamp {
73                last_seen_timestamp: Timestamp(100),
74                received_timestamp: Timestamp(10),
75            }
76            .to_string(),
77            "invalid timestamp: received timestamp 10 is before the last seen timestamp 100"
78        );
79        assert_eq!(
80            CommandFailure::InvalidCommand(CommandError::ZeroPrice).to_string(),
81            "invalid command: price is zero"
82        );
83        assert_eq!(CommandFailure::OrderNotFound.to_string(), "order not found");
84    }
85}