Skip to main content

source2_demo/
error.rs

1//! Error types for the parser.
2//!
3//! This module defines all error types that can occur during replay parsing.
4//! All errors implement the standard [`std::error::Error`] trait using
5//! [`thiserror`].
6//!
7//! # Error Types
8//!
9//! - [`ParserError`] - Main error type for parsing operations
10//! - [`EntityError`] - Errors related to entity operations
11//! - [`ClassError`] - Errors related to entity class lookups
12//! - [`StringTableError`] - Errors related to string table operations
13//! - [`GameEventError`] - Errors related to game event operations
14//! - [`FieldValueError`] - Errors related to field value conversions
15//!
16//! # Examples
17//!
18//! ## Handling errors
19//!
20//! ```no_run
21//! use source2_demo::error::*;
22//! use source2_demo::prelude::*;
23//!
24//! # fn example(ctx: &Context) {
25//! match ctx.entities().get_by_index(0) {
26//!     Ok(entity) => println!("Entity: {}", entity.class().name()),
27//!     Err(EntityError::IndexNotFound(idx)) => {
28//!         println!("No entity at index {}", idx);
29//!     }
30//!     Err(e) => println!("Other error: {}", e),
31//! }
32//! # }
33//! ```
34
35/// Main error type for parser operations.
36///
37/// This error type covers all parsing-related errors including protobuf
38/// decoding, decompression, and various domain-specific errors.
39#[derive(thiserror::Error, Debug)]
40pub enum ParserError {
41    /// Protobuf decoding error
42    #[error(transparent)]
43    ProtobufDecode(#[from] crate::proto::prost::DecodeError),
44
45    /// Unknown enum value in protobuf
46    #[error(transparent)]
47    UnknownEnumValue(#[from] crate::proto::prost::UnknownEnumValue),
48
49    /// Snappy decompression error
50    #[error(transparent)]
51    SnapDecompress(#[from] snap::Error),
52
53    /// String table related error
54    #[error(transparent)]
55    StringTable(#[from] StringTableError),
56
57    /// Class lookup error
58    #[error(transparent)]
59    Class(#[from] ClassError),
60
61    /// Entity related error
62    #[error(transparent)]
63    Entity(#[from] EntityError),
64
65    /// Field value conversion error
66    #[error(transparent)]
67    FieldValue(#[from] FieldValueError),
68
69    /// Game event error
70    #[error(transparent)]
71    GameEvent(#[from] GameEventError),
72
73    /// Observer callback error
74    #[error(transparent)]
75    ObserverError(#[from] anyhow::Error),
76
77    /// Invalid CDemoFileInfo offset
78    #[error("Wrong CDemoFileInfo offset")]
79    ReplayEncodingError,
80
81    /// Missing rewrite state for a string table
82    #[error("Missing rewrite state for string table {table_id}")]
83    MissingStringTableRewriteState {
84        /// String table id that lacked rewrite state.
85        table_id: usize,
86    },
87
88    /// File is not a valid Source 2 demo
89    #[error("Supports only Source 2 replays")]
90    WrongMagic,
91
92    /// I/O error occurred during file operations
93    #[error("IO error: {0}")]
94    IoError(String),
95
96    #[cfg(feature = "dota")]
97    /// Combat log parsing error (Dota 2)
98    #[error(transparent)]
99    CombatLog(#[from] CombatLogError),
100
101    #[cfg(feature = "deadlock")]
102    /// Match details not found in Deadlock replay
103    #[error("CCitadelUserMsgPostMatchDetails not found")]
104    MatchDetailsNotFound,
105}
106
107/// Errors related to entity class operations.
108#[derive(thiserror::Error, Debug)]
109pub enum ClassError {
110    /// Class not found for the given ID
111    #[error("Class not found for the given id {0}")]
112    ClassNotFoundById(i32),
113
114    /// Class not found for the given name
115    #[error("Class not found for the given name {0}")]
116    ClassNotFoundByName(String),
117}
118
119/// Errors related to entity operations.
120#[derive(thiserror::Error, Debug)]
121pub enum EntityError {
122    /// No entity exists at the specified index
123    #[error("No entities found at index {0}")]
124    IndexNotFound(usize),
125
126    /// No entity exists with the specified handle
127    #[error("No entities found for handle {0}")]
128    HandleNotFound(usize),
129
130    /// No entity exists with the specified class ID
131    #[error("No entities found for class with id {0}")]
132    ClassIdNotFound(i32),
133
134    /// No entity exists with the specified class name
135    #[error("No entities found for class with name {0}")]
136    ClassNameNotFound(String),
137
138    /// Property not found on the entity
139    #[error("No property found for name {0} (Class: {1}, FieldPath: {2})")]
140    PropertyNameNotFound(String, String, String),
141
142    /// Field path not found in serializer
143    #[error(transparent)]
144    FieldPathNotFound(#[from] SerializerError),
145}
146
147/// Errors related to field value conversions.
148#[derive(thiserror::Error, Debug)]
149pub enum FieldValueError {
150    /// Failed to convert field value to target type
151    #[error("Cannot convert {0} into {1}")]
152    ConversionError(String, String),
153}
154
155/// Errors related to game event operations.
156#[derive(thiserror::Error, Debug)]
157pub enum GameEventError {
158    /// Unknown key in game event
159    #[error("Unknown key: {0}")]
160    UnknownKey(String),
161    /// Failed to convert event value to target type
162    #[error("Conversion error: {0} -> {1}")]
163    ConversionError(String, String),
164}
165
166/// Errors related to serializer operations.
167#[derive(thiserror::Error, Debug)]
168pub enum SerializerError {
169    /// No field path found for property name
170    #[error("No field path for given name {0}")]
171    NoFieldPath(String),
172}
173
174/// Errors related to string table operations.
175#[derive(thiserror::Error, Debug)]
176pub enum StringTableError {
177    /// String table not found with the given ID
178    #[error("String table not found for the given id {0}")]
179    TableNotFoundById(i32),
180
181    /// String table not found with the given name
182    #[error("String table not found for the given name {0}")]
183    TableNotFoundByName(String),
184
185    /// String table row not found at the given index
186    #[error("String table entry not found for the given index {0} ({1})")]
187    RowNotFoundByIndex(i32, String),
188}
189
190/// Errors related to combat log operations (Dota 2 only).
191#[derive(thiserror::Error, Debug)]
192pub enum CombatLogError {
193    /// Missing property in combat log entry
194    #[error("No {0} for {1}")]
195    EmptyProperty(String, String),
196    /// Missing name in combat log entry
197    #[error("No {0} for {1}")]
198    EmptyName(String, String),
199}
200
201impl From<std::io::Error> for ParserError {
202    fn from(value: std::io::Error) -> Self {
203        ParserError::IoError(value.to_string())
204    }
205}