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}