Skip to main content

subtr_actor/domain/
error.rs

1//! Crate-wide error type and result alias.
2//!
3//! Most fallible operations return [`SubtrActorResult`], whose error is
4//! [`SubtrActorError`] (a [`SubtrActorErrorVariant`] plus a captured backtrace).
5
6use crate::*;
7use std::backtrace::Backtrace;
8use thiserror::Error;
9
10/// [`SubtrActorErrorVariant`] is an enumeration of all the specific error
11/// variants that can occur while processing game replays in the subtr-actor
12/// domain. These include errors related to network frames, frame indexing,
13/// player sets, actor states, object ids, team identities, and data types
14/// amongst others.
15#[derive(Error, Debug, Clone)]
16pub enum SubtrActorErrorVariant {
17    #[error("Replay has no network frames")]
18    NoNetworkFrames,
19
20    #[error("Frame index out of bounds")]
21    FrameIndexOutOfBounds,
22
23    #[error(
24        "Players found in frames that were not part of original set. Found: {found:?}, Original: {original:?}"
25    )]
26    InconsistentPlayerSet {
27        found: std::collections::HashSet<PlayerId>,
28        original: std::collections::HashSet<PlayerId>,
29    },
30
31    #[error(
32        "No update for ActorId {actor_id:?} of ObjectId {object_id:?} after frame {frame_index}"
33    )]
34    NoUpdateAfterFrame {
35        actor_id: boxcars::ActorId,
36        object_id: boxcars::ObjectId,
37        frame_index: usize,
38    },
39
40    #[error("No boost amount value.")]
41    NoBoostAmountValue,
42
43    #[error(
44        "The attribute value that was found was not of the expected type {expected_type} {actual_type:?}"
45    )]
46    UnexpectedAttributeType {
47        expected_type: &'static str,
48        actual_type: &'static str,
49    },
50
51    #[error("ActorId {actor_id:?} has no matching player id")]
52    NoMatchingPlayerId { actor_id: boxcars::ActorId },
53
54    #[error("No game actor")]
55    NoGameActor,
56
57    #[error("ActorId {actor_id:} already exists with object_id {object_id:}")]
58    ActorIdAlreadyExists {
59        actor_id: boxcars::ActorId,
60        object_id: boxcars::ObjectId,
61    },
62
63    #[error("{name:?} actor for player {player_id:?} not found")]
64    ActorNotFound {
65        name: &'static str,
66        player_id: PlayerId,
67    },
68
69    #[error("There was no actor state for actor_id: {actor_id:?}")]
70    NoStateForActorId { actor_id: boxcars::ActorId },
71
72    #[error("Couldn't find object id for {name}")]
73    ObjectIdNotFound { name: &'static str },
74
75    #[error("No value found for derived key {name:?}")]
76    DerivedKeyValueNotFound { name: String },
77
78    #[error("Ball actor not found")]
79    BallActorNotFound,
80
81    #[error("Player team unknown, {player_id:?}")]
82    UnknownPlayerTeam { player_id: PlayerId },
83
84    #[error("Team object id not known {object_id:?}, for player {player_id:?}")]
85    UnknownTeamObjectId {
86        object_id: boxcars::ObjectId,
87        player_id: PlayerId,
88    },
89
90    #[error("Team name was empty for {player_id:?}")]
91    EmptyTeamName { player_id: PlayerId },
92
93    #[error("Error returned to deliberately end processing early")]
94    FinishProcessingEarly,
95
96    #[error("Player stats header not found")]
97    PlayerStatsHeaderNotFound,
98
99    #[error("Interpolation time order was incorrect start_time {start_time:} {time:} {end_time:}")]
100    InterpolationTimeOrderError {
101        start_time: f32,
102        time: f32,
103        end_time: f32,
104    },
105
106    #[error("The updated actor id does not exist {update:?}")]
107    UpdatedActorIdDoesNotExist { update: boxcars::UpdatedAttribute },
108
109    #[error("Could not find {property:} in state")]
110    PropertyNotFoundInState { property: &'static str },
111
112    #[error("Could not build replay meta")]
113    CouldNotBuildReplayMeta,
114
115    #[error("Error converting float")]
116    FloatConversionError,
117
118    #[error(transparent)]
119    NDArrayShapeError(#[from] ::ndarray::ShapeError),
120
121    #[error("{0:?} was not a recognized feature adder")]
122    UnknownFeatureAdderName(String),
123
124    #[error("Callback error: {0}")]
125    CallbackError(String),
126
127    #[error("Unknown builtin stats module '{0}'")]
128    UnknownStatsModuleName(String),
129
130    #[error("Stats serialization error: {0}")]
131    StatsSerializationError(String),
132}
133
134/// [`SubtrActorError`] struct provides an error variant
135/// [`SubtrActorErrorVariant`] along with its backtrace.
136#[derive(Debug)]
137pub struct SubtrActorError {
138    pub backtrace: Backtrace,
139    pub variant: SubtrActorErrorVariant,
140}
141
142impl SubtrActorError {
143    pub fn new(variant: SubtrActorErrorVariant) -> Self {
144        Self {
145            backtrace: if std::env::var_os("SUBTR_ACTOR_ERROR_BACKTRACE").is_some() {
146                Backtrace::capture()
147            } else {
148                Backtrace::disabled()
149            },
150            variant,
151        }
152    }
153
154    pub fn new_result<T>(variant: SubtrActorErrorVariant) -> Result<T, Self> {
155        Err(Self::new(variant))
156    }
157}
158
159#[allow(clippy::result_large_err)]
160pub type SubtrActorResult<T> = Result<T, SubtrActorError>;