weasel/
serde.rs

1//! Module to handle serialization and deserialization.
2
3use crate::ability::ActivateAbility;
4use crate::actor::{AlterAbilities, RegenerateAbilities};
5use crate::battle::{BattleRules, EndBattle, Version};
6use crate::character::{AlterStatistics, RegenerateStatistics};
7use crate::creature::{ConvertCreature, CreateCreature, RemoveCreature};
8use crate::entropy::ResetEntropy;
9use crate::event::{
10    ClientEventPrototype, DummyEvent, Event, EventId, EventKind, EventWrapper,
11    VersionedEventWrapper,
12};
13use crate::fight::ApplyImpact;
14use crate::object::{CreateObject, RemoveObject};
15use crate::player::PlayerId;
16use crate::power::InvokePower;
17use crate::round::{EndRound, EndTurn, EnvironmentTurn, ResetRounds, StartTurn};
18use crate::space::{AlterSpace, MoveEntity, ResetSpace};
19use crate::status::{AlterStatuses, ClearStatus, InflictStatus};
20use crate::team::{
21    AlterPowers, ConcludeObjectives, CreateTeam, RegeneratePowers, RemoveTeam, ResetObjectives,
22    SetRelations,
23};
24use crate::user::{UserEventPackage, UserEventPacker};
25use serde::{Deserialize, Serialize};
26
27/// Macro to panic on incorrect cast.
28macro_rules! bad_cast {
29    () => {{
30        panic!("incorrect cast!")
31    }};
32}
33
34/// Generates the boxed() method for `FlatEvent`.
35macro_rules! flat_event_boxed {
36    ($( $x:ident ),* $(,)?) => {
37        /// Transforms this flattened event into a boxed event trait object.
38        pub fn boxed(self) -> Box<dyn Event<R> + Send> {
39            // Generate a match with an arm for every concrete event type.
40            match self {
41                $(FlatEvent::$x(flat) => {
42                    Box::new(flat) as Box<dyn Event<R> + Send>
43                })*
44                FlatEvent::UserEventPackage(packer) => {
45                    packer.boxed().unwrap_or_else(|err| {
46                        panic!("{:?}", err)
47                    })
48                }
49            }
50        }
51    }
52}
53
54/// Generates the flattened() method for `FlatEvent`.
55macro_rules! flat_event_flattened {
56    ($( $x:ident ),* $(,)?) => {
57        /// Transforms a boxed event trait object into a flattened event.
58        pub fn flattened(event: Box<dyn Event<R> + Send>) -> FlatEvent<R> {
59            // Generate a match with an arm for every concrete event type.
60            match event.kind() {
61                $(EventKind::$x => {
62                    match event.as_any().downcast_ref::<$x<R>>() {
63                        Some(event) => {
64                            FlatEvent::$x(event.clone())
65                        },
66                        None => bad_cast!(),
67                    }
68                })*
69                EventKind::UserEvent(_) => {
70                    let package = UserEventPackage::<R>::flattened(event).unwrap_or_else(|err| {
71                        panic!("{:?}", err)
72                    });
73                    FlatEvent::UserEventPackage(package)
74                }
75            }
76        }
77    }
78}
79
80/// Generates the FlatEvent enum starting from a list of event identifiers.
81macro_rules! flat_event {
82    ($( $x:ident, $ser:expr, $de:expr ),* $(,)?) => {
83        /// An enum representation of event trait objects.
84        #[derive(Serialize, Deserialize)]
85        pub enum FlatEvent<R: BattleRules> {
86            $(#[allow(missing_docs)]
87            #[serde(bound(
88                serialize = $ser,
89                deserialize = $de
90            ))]
91            $x($x<R>),)*
92            #[allow(missing_docs)]
93            #[serde(bound(
94                serialize = "UserEventPackage<R>: Serialize",
95                deserialize = "UserEventPackage<R>: Deserialize<'de>"
96            ))]
97            UserEventPackage(UserEventPackage<R>),
98        }
99
100        impl<R: BattleRules + 'static> FlatEvent<R> {
101            flat_event_boxed! { $($x),* }
102
103            flat_event_flattened! { $($x),* }
104        }
105    };
106}
107
108flat_event! {
109    DummyEvent, "DummyEvent<R>: Serialize", "DummyEvent<R>: Deserialize<'de>",
110    CreateTeam, "CreateTeam<R>: Serialize", "CreateTeam<R>: Deserialize<'de>",
111    CreateCreature, "CreateCreature<R>: Serialize", "CreateCreature<R>: Deserialize<'de>",
112    CreateObject, "CreateObject<R>: Serialize", "CreateObject<R>: Deserialize<'de>",
113    MoveEntity, "MoveEntity<R>: Serialize", "MoveEntity<R>: Deserialize<'de>",
114    StartTurn, "StartTurn<R>: Serialize", "StartTurn<R>: Deserialize<'de>",
115    EndTurn, "EndTurn<R>: Serialize", "EndTurn<R>: Deserialize<'de>",
116    EndRound, "EndRound<R>: Serialize", "EndRound<R>: Deserialize<'de>",
117    EnvironmentTurn, "EnvironmentTurn<R>: Serialize", "EnvironmentTurn<R>: Deserialize<'de>",
118    ActivateAbility, "ActivateAbility<R>: Serialize", "ActivateAbility<R>: Deserialize<'de>",
119    InvokePower, "InvokePower<R>: Serialize", "InvokePower<R>: Deserialize<'de>",
120    ApplyImpact, "ApplyImpact<R>: Serialize", "ApplyImpact<R>: Deserialize<'de>",
121    AlterStatistics, "AlterStatistics<R>: Serialize", "AlterStatistics<R>: Deserialize<'de>",
122    AlterStatuses, "AlterStatuses<R>: Serialize", "AlterStatuses<R>: Deserialize<'de>",
123    AlterAbilities, "AlterAbilities<R>: Serialize", "AlterAbilities<R>: Deserialize<'de>",
124    AlterPowers, "AlterPowers<R>: Serialize", "AlterPowers<R>: Deserialize<'de>",
125    RegenerateStatistics, "RegenerateStatistics<R>: Serialize", "RegenerateStatistics<R>: Deserialize<'de>",
126    RegenerateAbilities, "RegenerateAbilities<R>: Serialize", "RegenerateAbilities<R>: Deserialize<'de>",
127    RegeneratePowers, "RegeneratePowers<R>: Serialize", "RegeneratePowers<R>: Deserialize<'de>",
128    InflictStatus, "InflictStatus<R>: Serialize", "InflictStatus<R>: Deserialize<'de>",
129    ClearStatus, "ClearStatus<R>: Serialize", "ClearStatus<R>: Deserialize<'de>",
130    ConvertCreature, "ConvertCreature<R>: Serialize", "ConvertCreature<R>: Deserialize<'de>",
131    SetRelations, "SetRelations<R>: Serialize", "SetRelations<R>: Deserialize<'de>",
132    ConcludeObjectives, "ConcludeObjectives<R>: Serialize", "ConcludeObjectives<R>: Deserialize<'de>",
133    RemoveCreature, "RemoveCreature<R>: Serialize", "RemoveCreature<R>: Deserialize<'de>",
134    RemoveObject, "RemoveObject<R>: Serialize", "RemoveObject<R>: Deserialize<'de>",
135    RemoveTeam, "RemoveTeam<R>: Serialize", "RemoveTeam<R>: Deserialize<'de>",
136    AlterSpace, "AlterSpace<R>: Serialize", "AlterSpace<R>: Deserialize<'de>",
137    ResetEntropy, "ResetEntropy<R>: Serialize", "ResetEntropy<R>: Deserialize<'de>",
138    ResetObjectives, "ResetObjectives<R>: Serialize", "ResetObjectives<R>: Deserialize<'de>",
139    ResetRounds, "ResetRounds<R>: Serialize", "ResetRounds<R>: Deserialize<'de>",
140    ResetSpace, "ResetSpace<R>: Serialize", "ResetSpace<R>: Deserialize<'de>",
141    EndBattle, "EndBattle<R>: Serialize", "EndBattle<R>: Deserialize<'de>",
142}
143
144/// A versioned event wrapper containing a flattened event.
145/// Use this struct to serialize/deserialize a `VersionedEventWrapper`.
146#[derive(Serialize, Deserialize)]
147pub struct FlatVersionedEvent<R: BattleRules> {
148    id: EventId,
149    origin: Option<EventId>,
150
151    #[serde(bound(
152        serialize = "FlatEvent<R>: Serialize",
153        deserialize = "FlatEvent<R>: Deserialize<'de>"
154    ))]
155    event: FlatEvent<R>,
156
157    #[serde(bound(
158        serialize = "Version<R>: Serialize",
159        deserialize = "Version<R>: Deserialize<'de>"
160    ))]
161    version: Version<R>,
162}
163
164impl<R: BattleRules> FlatVersionedEvent<R> {
165    /// Returns the id of this event.
166    pub fn id(&self) -> EventId {
167        self.id
168    }
169
170    /// Returns the origin of this event.
171    pub fn origin(&self) -> Option<EventId> {
172        self.origin
173    }
174
175    /// Returns the inner `FlatEvent`.
176    pub fn event(&self) -> &FlatEvent<R> {
177        &self.event
178    }
179
180    /// Returns the rules' version under which this event was created.
181    pub fn version(&self) -> &Version<R> {
182        &self.version
183    }
184}
185
186impl<R: BattleRules + 'static> From<VersionedEventWrapper<R>> for FlatVersionedEvent<R> {
187    fn from(event: VersionedEventWrapper<R>) -> Self {
188        Self {
189            id: event.wrapper().id(),
190            origin: event.wrapper().origin(),
191            event: FlatEvent::flattened(event.wrapper.event),
192            version: event.version,
193        }
194    }
195}
196
197impl<R: BattleRules + 'static> From<FlatVersionedEvent<R>> for VersionedEventWrapper<R> {
198    fn from(event: FlatVersionedEvent<R>) -> Self {
199        Self::new(
200            EventWrapper::new(event.id, event.origin, event.event.boxed()),
201            event.version,
202        )
203    }
204}
205
206/// A versioned client event containing a flattened event.
207/// Use this struct to serialize/deserialize a `ClientEventPrototype`.
208#[derive(Serialize, Deserialize)]
209pub struct FlatClientEvent<R: BattleRules> {
210    origin: Option<EventId>,
211
212    #[serde(bound(
213        serialize = "FlatEvent<R>: Serialize",
214        deserialize = "FlatEvent<R>: Deserialize<'de>"
215    ))]
216    event: FlatEvent<R>,
217
218    #[serde(bound(
219        serialize = "Version<R>: Serialize",
220        deserialize = "Version<R>: Deserialize<'de>"
221    ))]
222    version: Version<R>,
223
224    player: Option<PlayerId>,
225}
226
227impl<R: BattleRules> FlatClientEvent<R> {
228    /// Returns the origin of this event.
229    pub fn origin(&self) -> Option<EventId> {
230        self.origin
231    }
232
233    /// Returns the inner `FlatEvent`.
234    pub fn event(&self) -> &FlatEvent<R> {
235        &self.event
236    }
237
238    /// Returns the rules' version under which this event was created.
239    pub fn version(&self) -> &Version<R> {
240        &self.version
241    }
242
243    /// Returns the player to whom this event belongs.
244    pub fn player(&self) -> Option<PlayerId> {
245        self.player
246    }
247}
248
249impl<R: BattleRules + 'static> From<ClientEventPrototype<R>> for FlatClientEvent<R> {
250    fn from(event: ClientEventPrototype<R>) -> Self {
251        let player = event.player();
252        Self {
253            origin: event.origin(),
254            event: FlatEvent::flattened(event.event),
255            version: event.version,
256            player,
257        }
258    }
259}
260
261impl<R: BattleRules + 'static> From<FlatClientEvent<R>> for ClientEventPrototype<R> {
262    fn from(event: FlatClientEvent<R>) -> Self {
263        Self::new(
264            event.origin,
265            event.event.boxed(),
266            event.version,
267            event.player,
268        )
269    }
270}