1use crate::game::errors::database::GameDatabaseError;
2use crate::game::errors::item_event::GameItemEventError;
3use crate::game::errors::repository::GameRepositoryError;
4use crate::game::errors::resource::GameResourceError;
5use thiserror::Error;
6
7pub mod database;
8pub mod item_event;
9pub mod repository;
10pub mod resource;
11
12pub type GameResult<T> = Result<T, GameError>;
13
14#[derive(Error, Debug)]
15pub enum GameError {
16 #[error(transparent)]
17 Database(#[from] GameDatabaseError),
18 #[error(transparent)]
19 ItemEvent(#[from] GameItemEventError),
20 #[error(transparent)]
21 Repository(#[from] GameRepositoryError),
22 #[error(transparent)]
23 Resource(#[from] GameResourceError),
24 #[error("Unexpected error: {msg}")]
25 Unexpected {
26 msg: String,
27 #[source]
28 source: Box<dyn std::error::Error>,
29 },
30}
31
32impl GameError {
33 pub fn unexpected(error: Box<dyn std::error::Error>) -> Self {
34 Self::Unexpected {
35 msg: error.to_string(),
36 source: error,
37 }
38 }
39
40 pub fn as_database_error(&self) -> Option<&GameDatabaseError> {
41 match self {
42 Self::Database(e) => Some(e),
43 _ => None,
44 }
45 }
46
47 pub fn as_item_event_error(&self) -> Option<&GameItemEventError> {
48 match self {
49 Self::ItemEvent(e) => Some(e),
50 _ => None,
51 }
52 }
53
54 pub fn as_repository_error(&self) -> Option<&GameRepositoryError> {
55 match self {
56 Self::Repository(e) => Some(e),
57 _ => None,
58 }
59 }
60
61 pub fn as_resource_error(&self) -> Option<&GameResourceError> {
62 match self {
63 Self::Resource(e) => Some(e),
64 _ => None,
65 }
66 }
67
68 pub fn is_database_error(&self) -> bool {
69 matches!(self, Self::Database(_))
70 }
71
72 pub fn is_item_event_error(&self) -> bool {
73 matches!(self, Self::ItemEvent(_))
74 }
75
76 pub fn is_repository_error(&self) -> bool {
77 matches!(self, Self::Repository(_))
78 }
79
80 pub fn is_resource_error(&self) -> bool {
81 matches!(self, Self::Resource(_))
82 }
83
84 pub fn is_already_exists(&self) -> bool {
85 matches!(
86 self,
87 Self::Resource(GameResourceError::UserAlreadyExists { .. })
88 | Self::Resource(GameResourceError::LocationAlreadyUnlocked { .. })
89 )
90 }
91
92 pub fn is_not_found(&self) -> bool {
93 matches!(
94 self,
95 Self::Resource(GameResourceError::UserNotFound { .. })
96 | Self::Resource(GameResourceError::FishingHistoryNotFound { .. })
97 | Self::Resource(GameResourceError::LocationNotFound { .. })
98 | Self::Resource(GameResourceError::SpeciesNotFound { .. })
99 | Self::Resource(GameResourceError::NoFishingHistory { .. })
100 | Self::Repository(GameRepositoryError::Database(GameDatabaseError::NotFound))
101 | Self::Resource(GameResourceError::ItemNotFound { .. })
102 )
103 }
104
105 pub fn is_unmet_requirements(&self) -> bool {
106 matches!(
107 self,
108 Self::Resource(GameResourceError::UnmetLocationUnlockRequirements { .. })
109 )
110 }
111}
112
113impl From<Box<dyn std::error::Error>> for GameError {
114 fn from(error: Box<dyn std::error::Error>) -> Self {
115 match error {
116 e if e.is::<GameError>() => *e.downcast::<GameError>().unwrap(),
117 e if e.is::<GameDatabaseError>() => {
118 GameError::Database(*e.downcast::<GameDatabaseError>().unwrap())
119 }
120 e if e.is::<GameRepositoryError>() => {
121 GameError::Repository(*e.downcast::<GameRepositoryError>().unwrap())
122 }
123 e if e.is::<GameResourceError>() => {
124 GameError::Resource(*e.downcast::<GameResourceError>().unwrap())
125 }
126 e => Self::unexpected(e),
127 }
128 }
129}