wowlab_engine_application/enemies/
error.rs1use wowlab_engine_ports::ResolverError;
4
5use super::provenance::EnemyStatField;
6
7wowlab_engine_macros::define_error! {
8#[derive(Clone, Debug, PartialEq)]
10pub struct EnemyStatError {
11 kind: EnemyStatErrorKind,
12}
13
14#[derive(Clone, Debug, thiserror::Error, PartialEq)]
15enum EnemyStatErrorKind {
16 #[error("missing enemy data for {field}: {key}")]
17 Missing { field: EnemyStatField, key: String },
18 #[error("ambiguous enemy data for {field}: candidate rows {candidate_row_ids:?}")]
19 Ambiguous {
20 field: EnemyStatField,
21 candidate_row_ids: Vec<i32>,
22 },
23 #[error("invalid enemy data for {field} from {key}: {found}")]
24 Invalid {
25 field: EnemyStatField,
26 key: String,
27 found: f64,
28 },
29}
30}
31
32impl EnemyStatError {
33 pub(super) fn missing(field: EnemyStatField, key: String) -> Self {
34 Self {
35 kind: EnemyStatErrorKind::Missing { field, key },
36 }
37 }
38
39 pub(super) fn ambiguous(field: EnemyStatField, candidate_row_ids: Vec<i32>) -> Self {
40 Self {
41 kind: EnemyStatErrorKind::Ambiguous {
42 field,
43 candidate_row_ids,
44 },
45 }
46 }
47
48 pub(super) fn invalid(field: EnemyStatField, key: String, found: f64) -> Self {
49 Self {
50 kind: EnemyStatErrorKind::Invalid { field, key, found },
51 }
52 }
53
54 #[must_use]
55 pub fn is_missing(&self, field: EnemyStatField) -> bool {
56 matches!(self.kind, EnemyStatErrorKind::Missing { field: found, .. } if found == field)
57 }
58
59 #[must_use]
60 pub fn is_ambiguous(&self, field: EnemyStatField) -> bool {
61 matches!(self.kind, EnemyStatErrorKind::Ambiguous { field: found, .. } if found == field)
62 }
63}
64
65wowlab_engine_macros::define_error! {
66#[derive(Debug)]
68pub struct EnemyStatResolutionError {
69 kind: EnemyStatResolutionErrorKind,
70}
71
72#[derive(Debug, thiserror::Error)]
73enum EnemyStatResolutionErrorKind {
74 #[error(transparent)]
75 Data(EnemyStatError),
76 #[error("authored {name} {value} exceeds the i32 data key range")]
77 InputOutOfRange {
78 name: &'static str,
79 value: u32,
80 #[source]
81 source: std::num::TryFromIntError,
82 },
83 #[error("data backend failed during enemy stat resolution at {key}")]
84 Resolver {
85 key: String,
86 #[source]
87 source: ResolverError,
88 },
89}
90}
91
92impl EnemyStatResolutionError {
93 pub(super) fn input_out_of_range(
94 name: &'static str,
95 value: u32,
96 source: std::num::TryFromIntError,
97 ) -> Self {
98 Self {
99 kind: EnemyStatResolutionErrorKind::InputOutOfRange {
100 name,
101 value,
102 source,
103 },
104 }
105 }
106
107 pub(super) fn resolver(key: String, source: ResolverError) -> Self {
108 Self {
109 kind: EnemyStatResolutionErrorKind::Resolver { key, source },
110 }
111 }
112
113 pub fn into_data(self) -> Result<EnemyStatError, Self> {
114 match self.kind {
115 EnemyStatResolutionErrorKind::Data(error) => Ok(error),
116 kind => Err(Self { kind }),
117 }
118 }
119}
120
121impl From<EnemyStatError> for EnemyStatResolutionError {
122 fn from(error: EnemyStatError) -> Self {
123 Self {
124 kind: EnemyStatResolutionErrorKind::Data(error),
125 }
126 }
127}