weiss_core/error.rs
1use thiserror::Error;
2
3use crate::db::CardId;
4
5/// Stable error categories for environment configuration validation.
6#[derive(Clone, Copy, Debug, Error, PartialEq, Eq)]
7pub enum ConfigError {
8 /// A player's deck length did not match the expected size.
9 #[error("deck length invalid for player {player}: got {got}, expected {expected}")]
10 DeckLength {
11 /// Player index.
12 player: u8,
13 /// Observed deck length.
14 got: usize,
15 /// Expected deck length.
16 expected: usize,
17 },
18 /// A player's deck referenced a card id that is not present in the database.
19 #[error("unknown card id {card_id} in player {player} deck")]
20 UnknownCardId {
21 /// Player index.
22 player: u8,
23 /// Unknown card id.
24 card_id: CardId,
25 },
26 /// A player's deck contained too many climax cards.
27 #[error("too many climax cards for player {player}: got {got}, max {max}")]
28 ClimaxCount {
29 /// Player index.
30 player: u8,
31 /// Observed climax count.
32 got: usize,
33 /// Maximum allowed climax count.
34 max: usize,
35 },
36 /// A player's deck contained too many copies of a single card id.
37 #[error("too many copies of card {card_id} for player {player}: got {got}, max {max}")]
38 CardCopyCount {
39 /// Player index.
40 player: u8,
41 /// Card id with excessive copies.
42 card_id: CardId,
43 /// Observed copy count.
44 got: usize,
45 /// Maximum allowed copies.
46 max: usize,
47 },
48}
49
50/// Stable error categories for game-state construction.
51#[derive(Clone, Copy, Debug, Error, PartialEq, Eq)]
52pub enum StateError {
53 /// Starting player must be either player 0 or player 1.
54 #[error("starting player must be 0 or 1 (got {got})")]
55 InvalidStartingPlayer {
56 /// Provided starting player index.
57 got: u8,
58 },
59 /// A player's deck length did not match the expected size for state construction.
60 #[error("deck length invalid for owner {owner}: got {got}, expected {expected}")]
61 DeckLength {
62 /// Player index.
63 owner: u8,
64 /// Observed deck length.
65 got: usize,
66 /// Expected deck length.
67 expected: usize,
68 },
69}
70
71/// Stable error categories for action application.
72#[derive(Clone, Copy, Debug, Error, PartialEq, Eq)]
73pub enum ActionError {
74 /// An action was attempted when no decision is pending.
75 #[error("no pending decision")]
76 NoPendingDecision,
77 /// An action id could not be decoded or is outside the action space.
78 #[error("invalid action id {action_id}")]
79 InvalidActionId {
80 /// Provided action id.
81 action_id: usize,
82 },
83 /// An action id was decoded but is not legal for the current decision.
84 #[error("action is not legal for current decision")]
85 ActionNotLegal,
86}
87
88/// Stable error categories for runtime invariant violations.
89#[derive(Clone, Copy, Debug, Error, PartialEq, Eq)]
90pub enum InvariantError {
91 /// Internal choice paging index exceeded the available options.
92 #[error("choice paging index out of range: {index}")]
93 ChoicePagingIndexOutOfRange {
94 /// Provided choice paging index.
95 index: usize,
96 },
97 /// Trigger id counter overflowed its representable range.
98 #[error("trigger id overflow")]
99 TriggerIdOverflow,
100 /// Action mask bit buffer size did not match the expected capacity.
101 #[error("mask bits buffer size mismatch")]
102 MaskBitsBufferSizeMismatch,
103 /// A computed action id exceeded `u16::MAX`.
104 #[error("action id out of u16 range: {id}")]
105 ActionIdOutOfU16Range {
106 /// Computed action id.
107 id: usize,
108 },
109 /// A generic stage mover received an invalid stage zone target.
110 #[error("invalid stage zone target for generic zone mover")]
111 InvalidStageZoneTarget,
112 /// Fingerprint serialization failed unexpectedly.
113 #[error("fingerprint serialization failed")]
114 FingerprintSerializationFailed,
115}
116
117/// Top-level environment construction errors.
118#[derive(Debug, Error)]
119pub enum EnvError {
120 /// Environment configuration validation failed.
121 #[error(transparent)]
122 Config(#[from] ConfigError),
123 /// Initial game-state construction failed.
124 #[error(transparent)]
125 State(#[from] StateError),
126 /// The initial reset trapped a fault and returned a status code.
127 #[error("initial reset faulted with engine status code {code}")]
128 InitialResetFault {
129 /// Engine error code returned by reset.
130 code: u8,
131 },
132}