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::prelude::*;
22//! use source2_demo::error::*;
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    /// File is not a valid Source 2 demo
82    #[error("Supports only Source 2 replays")]
83    WrongMagic,
84
85    /// I/O error occurred during file operations
86    #[error("IO error: {0}")]
87    IoError(String),
88
89    #[cfg(feature = "dota")]
90    /// Combat log parsing error (Dota 2)
91    #[error(transparent)]
92    CombatLog(#[from] CombatLogError),
93
94    #[cfg(feature = "deadlock")]
95    /// Match details not found in Deadlock replay
96    #[error("CCitadelUserMsgPostMatchDetails not found")]
97    MatchDetailsNotFound,
98}
99
100/// Errors related to entity class operations.
101#[derive(thiserror::Error, Debug)]
102pub enum ClassError {
103    /// Class not found for the given ID
104    #[error("Class not found for the given id {0}")]
105    ClassNotFoundById(i32),
106
107    /// Class not found for the given name
108    #[error("Class not found for the given name {0}")]
109    ClassNotFoundByName(String),
110}
111
112/// Errors related to entity operations.
113#[derive(thiserror::Error, Debug)]
114pub enum EntityError {
115    /// No entity exists at the specified index
116    #[error("No entities found at index {0}")]
117    IndexNotFound(usize),
118
119    /// No entity exists with the specified handle
120    #[error("No entities found for handle {0}")]
121    HandleNotFound(usize),
122
123    /// No entity exists with the specified class ID
124    #[error("No entities found for class with id {0}")]
125    ClassIdNotFound(i32),
126
127    /// No entity exists with the specified class name
128    #[error("No entities found for class with name {0}")]
129    ClassNameNotFound(String),
130
131    /// Property not found on the entity
132    #[error("No property found for name {0} (Class: {1}, FieldPath: {2})")]
133    PropertyNameNotFound(String, String, String),
134
135    /// Field path not found in serializer
136    #[error(transparent)]
137    FieldPathNotFound(#[from] SerializerError),
138}
139
140/// Errors related to field value conversions.
141#[derive(thiserror::Error, Debug)]
142pub enum FieldValueError {
143    /// Failed to convert field value to target type
144    #[error("Cannot convert {0} into {1}")]
145    ConversionError(String, String),
146}
147
148/// Errors related to game event operations.
149#[derive(thiserror::Error, Debug)]
150pub enum GameEventError {
151    /// Unknown key in game event
152    #[error("Unknown key: {0}")]
153    UnknownKey(String),
154    /// Failed to convert event value to target type
155    #[error("Conversion error: {0} -> {1}")]
156    ConversionError(String, String),
157}
158
159/// Errors related to serializer operations.
160#[derive(thiserror::Error, Debug)]
161pub enum SerializerError {
162    /// No field path found for property name
163    #[error("No field path for given name {0}")]
164    NoFieldPath(String),
165}
166
167/// Errors related to string table operations.
168#[derive(thiserror::Error, Debug)]
169pub enum StringTableError {
170    /// String table not found with the given ID
171    #[error("String table not found for the given id {0}")]
172    TableNotFoundById(i32),
173
174    /// String table not found with the given name
175    #[error("String table not found for the given name {0}")]
176    TableNotFoundByName(String),
177
178    /// String table row not found at the given index
179    #[error("String table entry not found for the given index {0} ({1})")]
180    RowNotFoundByIndex(i32, String),
181}
182
183/// Errors related to combat log operations (Dota 2 only).
184#[derive(thiserror::Error, Debug)]
185pub enum CombatLogError {
186    /// Missing property in combat log entry
187    #[error("No {0} for {1}")]
188    EmptyProperty(String, String),
189    /// Missing name in combat log entry
190    #[error("No {0} for {1}")]
191    EmptyName(String, String),
192}