Skip to main content

fyrox_resource/
state.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! A module that handles resource states.
22
23use crate::{core::reflect::prelude::*, ResourceData, ResourceLoadError, TypedResourceData};
24use fyrox_core::reflect::ReflectHandle;
25use std::any::{Any, TypeId};
26use std::fmt::{Debug, Display};
27use std::path::PathBuf;
28use std::{
29    ops::{Deref, DerefMut},
30    sync::Arc,
31    task::Waker,
32};
33
34#[doc(hidden)]
35#[derive(Reflect, Debug, Default, Clone)]
36#[reflect(hide_all)]
37pub struct WakersList(Vec<Waker>);
38
39impl Deref for WakersList {
40    type Target = Vec<Waker>;
41
42    fn deref(&self) -> &Self::Target {
43        &self.0
44    }
45}
46
47impl WakersList {
48    pub fn add_waker(&mut self, cx_waker: &Waker) {
49        if let Some(pos) = self.iter().position(|waker| waker.will_wake(cx_waker)) {
50            self[pos].clone_from(cx_waker);
51        } else {
52            self.push(cx_waker.clone())
53        }
54    }
55}
56
57impl DerefMut for WakersList {
58    fn deref_mut(&mut self) -> &mut Self::Target {
59        &mut self.0
60    }
61}
62
63/// Arbitrary loading error, that could be optionally be empty.
64#[derive(Reflect, Debug, Clone, Default)]
65#[reflect(hide_all)]
66pub struct LoadError(pub Option<Arc<dyn ResourceLoadError>>);
67
68impl std::error::Error for LoadError {}
69
70impl LoadError {
71    /// Creates new loading error from a value of the given type.
72    pub fn new<T: ResourceLoadError>(value: T) -> Self {
73        Self(Some(Arc::new(value)))
74    }
75}
76
77impl Display for LoadError {
78    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79        match &self.0 {
80            None => f.write_str("None"),
81            Some(x) => Display::fmt(x, f),
82        }
83    }
84}
85
86#[doc(hidden)]
87#[derive(Debug)]
88pub struct ResourceDataWrapper(pub Box<dyn ResourceData>);
89
90impl Reflect for ResourceDataWrapper {
91    fn source_path() -> &'static str
92    where
93        Self: Sized,
94    {
95        file!()
96    }
97
98    fn derived_types() -> &'static [TypeId]
99    where
100        Self: Sized,
101    {
102        &[]
103    }
104
105    fn try_clone_box(&self) -> Option<Box<dyn Reflect>> {
106        Reflect::try_clone_box(&*self.0)
107    }
108
109    fn query_derived_types(&self) -> &'static [TypeId] {
110        self.deref().query_derived_types()
111    }
112
113    fn type_name(&self) -> &'static str {
114        self.deref().type_name()
115    }
116
117    fn doc(&self) -> &'static str {
118        self.deref().doc()
119    }
120
121    fn fields_ref(&self, func: &mut dyn FnMut(&[FieldRef])) {
122        self.deref().fields_ref(func)
123    }
124
125    fn fields_mut(&mut self, func: &mut dyn FnMut(&mut [FieldMut])) {
126        self.deref_mut().fields_mut(func)
127    }
128
129    fn into_any(self: Box<Self>) -> Box<dyn Any> {
130        self
131    }
132
133    fn as_any(&self, func: &mut dyn FnMut(&dyn Any)) {
134        self.deref().as_any(func)
135    }
136
137    fn as_any_mut(&mut self, func: &mut dyn FnMut(&mut dyn Any)) {
138        self.deref_mut().as_any_mut(func)
139    }
140
141    fn as_reflect(&self, func: &mut dyn FnMut(&dyn Reflect)) {
142        self.deref().as_reflect(func)
143    }
144
145    fn as_reflect_mut(&mut self, func: &mut dyn FnMut(&mut dyn Reflect)) {
146        self.deref_mut().as_reflect_mut(func)
147    }
148
149    fn set(&mut self, value: Box<dyn Reflect>) -> Result<Box<dyn Reflect>, Box<dyn Reflect>> {
150        self.deref_mut().set(value)
151    }
152
153    fn assembly_name(&self) -> &'static str {
154        env!("CARGO_PKG_NAME")
155    }
156
157    fn type_assembly_name() -> &'static str
158    where
159        Self: Sized,
160    {
161        env!("CARGO_PKG_NAME")
162    }
163
164    fn set_field(
165        &mut self,
166        field: &str,
167        value: Box<dyn Reflect>,
168        func: &mut dyn FnMut(Result<Box<dyn Reflect>, SetFieldError>),
169    ) {
170        self.deref_mut().set_field(field, value, func)
171    }
172
173    fn field(&self, name: &str, func: &mut dyn FnMut(Option<&dyn Reflect>)) {
174        self.deref().field(name, func)
175    }
176
177    fn field_mut(&mut self, name: &str, func: &mut dyn FnMut(Option<&mut dyn Reflect>)) {
178        self.deref_mut().field_mut(name, func)
179    }
180
181    fn as_array(&self, func: &mut dyn FnMut(Option<&dyn ReflectArray>)) {
182        self.deref().as_array(func)
183    }
184
185    fn as_array_mut(&mut self, func: &mut dyn FnMut(Option<&mut dyn ReflectArray>)) {
186        self.deref_mut().as_array_mut(func)
187    }
188
189    fn as_list(&self, func: &mut dyn FnMut(Option<&dyn ReflectList>)) {
190        self.deref().as_list(func)
191    }
192
193    fn as_list_mut(&mut self, func: &mut dyn FnMut(Option<&mut dyn ReflectList>)) {
194        self.deref_mut().as_list_mut(func)
195    }
196
197    fn as_inheritable_variable(
198        &self,
199        func: &mut dyn FnMut(Option<&dyn ReflectInheritableVariable>),
200    ) {
201        self.deref().as_inheritable_variable(func)
202    }
203
204    fn as_inheritable_variable_mut(
205        &mut self,
206        func: &mut dyn FnMut(Option<&mut dyn ReflectInheritableVariable>),
207    ) {
208        self.deref_mut().as_inheritable_variable_mut(func)
209    }
210
211    fn as_hash_map(&self, func: &mut dyn FnMut(Option<&dyn ReflectHashMap>)) {
212        self.deref().as_hash_map(func)
213    }
214
215    fn as_hash_map_mut(&mut self, func: &mut dyn FnMut(Option<&mut dyn ReflectHashMap>)) {
216        self.deref_mut().as_hash_map_mut(func)
217    }
218
219    fn as_handle(&self, func: &mut dyn FnMut(Option<&dyn ReflectHandle>)) {
220        self.deref().as_handle(func)
221    }
222
223    fn as_handle_mut(&mut self, func: &mut dyn FnMut(Option<&mut dyn ReflectHandle>)) {
224        self.deref_mut().as_handle_mut(func)
225    }
226}
227
228impl Deref for ResourceDataWrapper {
229    type Target = dyn ResourceData;
230
231    fn deref(&self) -> &Self::Target {
232        &*self.0
233    }
234}
235
236impl DerefMut for ResourceDataWrapper {
237    fn deref_mut(&mut self) -> &mut Self::Target {
238        &mut *self.0
239    }
240}
241
242impl Clone for ResourceDataWrapper {
243    fn clone(&self) -> Self {
244        Self(ResourceData::try_clone_box(&*self.0).unwrap())
245    }
246}
247
248/// Resource could be in three possible states (a small state machine):
249///
250/// 1. Pending - it is loading or queued for loading.
251/// 2. LoadError - an error has occurred during the load.
252/// 3. Ok - resource is fully loaded and ready to use.
253///
254/// ## Why is it so complex?
255///
256/// Short answer: asynchronous loading.
257/// Long answer: when you're loading a scene, you expect it to be loaded as fast as possible, use
258/// all available power of the CPU. To achieve that, each resource ideally should be loaded on
259/// separate core of the CPU, but since this is asynchronous, we must be able to track the state
260/// of the resource.
261///
262/// ## Path
263///
264/// Resources do not store their paths to respective files in the file system, instead resource only
265/// stores their unique identifiers (UUID). Use [`crate::registry::ResourceRegistry`] to get a path
266/// associated with the resource uuid.
267///
268/// ## UUID
269///
270/// Resource UUID is available only if the resource is fully loaded. This is because there's no way
271/// to get the UUID earlier: the UUID is stored in a metadata file which exists only if the resource
272/// is present. It is somewhat possible to get a UUID when a resource is failed to load, but not in
273/// 100% cases.
274#[derive(Clone, Reflect)]
275pub enum ResourceState {
276    /// Resource is not loaded. In some situations, having a handle to a resource
277    /// can be sufficient even without the resource's data.
278    Unloaded,
279    /// Resource is loading from external resource or in the queue to load.
280    Pending {
281        /// List of wakers to wake future when resource is fully loaded.
282        wakers: WakersList,
283    },
284    /// An error has occurred during the load.
285    LoadError {
286        /// A resource path, it is stored only to be able to reload the resources that failed to
287        /// load previously.
288        path: PathBuf,
289        /// An error. This wrapped in Option only to be Default_ed.
290        error: LoadError,
291    },
292    /// Actual resource data when it is fully loaded.
293    Ok {
294        /// Actual data of the resource.
295        data: ResourceDataWrapper,
296    },
297}
298
299impl Debug for ResourceState {
300    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
301        match self {
302            Self::Unloaded => write!(f, "Unloaded"),
303            Self::Pending { .. } => write!(f, "Pending"),
304            Self::LoadError { path, error } => write!(f, "LoadError {:?}: {:?}", error, path),
305            Self::Ok { .. } => write!(f, "Ok"),
306        }
307    }
308}
309
310impl Display for ResourceState {
311    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
312        match self {
313            Self::Unloaded => write!(f, "Unloaded"),
314            Self::Pending { .. } => write!(f, "Pending"),
315            Self::LoadError { path, error } => {
316                if path.as_os_str().is_empty() {
317                    write!(f, "{} (for unknown path)", error)
318                } else {
319                    write!(f, "{} (for {:?})", error, path)
320                }
321            }
322            Self::Ok { .. } => write!(f, "Ok"),
323        }
324    }
325}
326
327impl Default for ResourceState {
328    fn default() -> Self {
329        ResourceState::new_load_error(
330            Default::default(),
331            LoadError::new("Default resource state of unknown type."),
332        )
333    }
334}
335
336impl Drop for ResourceState {
337    fn drop(&mut self) {
338        if let ResourceState::Pending { wakers, .. } = self {
339            assert_eq!(wakers.len(), 0);
340        }
341    }
342}
343
344impl ResourceState {
345    /// Creates new resource in pending state.
346    #[inline]
347    pub fn new_pending() -> Self {
348        Self::Pending {
349            wakers: Default::default(),
350        }
351    }
352
353    /// Creates new resource in error state.
354    #[inline]
355    pub fn new_load_error(path: PathBuf, error: LoadError) -> Self {
356        Self::LoadError { path, error }
357    }
358
359    /// Creates new resource in [`ResourceState::Ok`] state.
360    #[inline]
361    pub fn new_ok<T: ResourceData>(data: T) -> Self {
362        Self::Ok {
363            data: ResourceDataWrapper(Box::new(data)),
364        }
365    }
366
367    /// Creates a new resource in [`ResourceState::Ok`] state using arbitrary data.
368    #[inline]
369    pub fn new_ok_untyped(data: Box<dyn ResourceData>) -> Self {
370        Self::Ok {
371            data: ResourceDataWrapper(data),
372        }
373    }
374
375    /// Checks whether the resource is still loading or not.
376    pub fn is_loading(&self) -> bool {
377        matches!(self, ResourceState::Pending { .. })
378    }
379
380    /// Checks whether the resource is loaded without errors.
381    pub fn is_ok(&self) -> bool {
382        matches!(self, ResourceState::Ok { .. })
383    }
384
385    /// Switches the internal state of the resource to [`ResourceState::Pending`].
386    pub fn switch_to_pending_state(&mut self) {
387        *self = ResourceState::Pending {
388            wakers: Default::default(),
389        };
390    }
391
392    /// Changes ResourceState::Pending state to ResourceState::Ok(data) with given `data`.
393    /// Additionally it wakes all futures.
394    #[inline]
395    pub fn commit(&mut self, state: ResourceState) {
396        assert!(!matches!(state, ResourceState::Pending { .. }));
397
398        let wakers = if let ResourceState::Pending { ref mut wakers, .. } = self {
399            std::mem::take(wakers)
400        } else {
401            WakersList::default()
402        };
403
404        *self = state;
405
406        for waker in wakers.0 {
407            waker.wake();
408        }
409    }
410
411    /// Changes internal state to [`ResourceState::Ok`]
412    pub fn commit_ok<T: ResourceData>(&mut self, data: T) {
413        self.commit(ResourceState::Ok {
414            data: ResourceDataWrapper(Box::new(data)),
415        })
416    }
417
418    /// Changes internal state to [`ResourceState::LoadError`].
419    pub fn commit_error<E: ResourceLoadError>(&mut self, path: PathBuf, error: E) {
420        self.commit(ResourceState::LoadError {
421            path,
422            error: LoadError::new(error),
423        })
424    }
425
426    /// Tries to get the resource data. Will fail if the resource is not in [`ResourceState::Ok`].
427    pub fn data_ref(&self) -> Option<&ResourceDataWrapper> {
428        match self {
429            ResourceState::Pending { .. }
430            | ResourceState::LoadError { .. }
431            | ResourceState::Unloaded => None,
432            ResourceState::Ok { data, .. } => Some(data),
433        }
434    }
435
436    /// Tries to get the resource data. Will fail if the resource is not in [`ResourceState::Ok`].
437    pub fn data_mut(&mut self) -> Option<&mut ResourceDataWrapper> {
438        match self {
439            ResourceState::Pending { .. }
440            | ResourceState::LoadError { .. }
441            | ResourceState::Unloaded => None,
442            ResourceState::Ok { data, .. } => Some(data),
443        }
444    }
445
446    /// Tries to get the resource data of the given type. Will fail if the resource is not in
447    /// [`ResourceState::Ok`].
448    pub fn data_ref_of_type<T: TypedResourceData>(&self) -> Option<&T> {
449        match self {
450            ResourceState::Pending { .. }
451            | ResourceState::LoadError { .. }
452            | ResourceState::Unloaded => None,
453            ResourceState::Ok { data, .. } => (&**data as &dyn Any).downcast_ref::<T>(),
454        }
455    }
456
457    /// Tries to get the resource data of the given type. Will fail if the resource is not in
458    /// [`ResourceState::Ok`].
459    pub fn data_mut_of_type<T: TypedResourceData>(&mut self) -> Option<&mut T> {
460        match self {
461            ResourceState::Pending { .. }
462            | ResourceState::LoadError { .. }
463            | ResourceState::Unloaded => None,
464            ResourceState::Ok { data, .. } => (&mut **data as &mut dyn Any).downcast_mut::<T>(),
465        }
466    }
467}
468
469#[cfg(test)]
470mod test {
471    use fyrox_core::{
472        reflect::{FieldRef, Reflect},
473        uuid::Uuid,
474        visitor::prelude::*,
475        TypeUuidProvider,
476    };
477    use std::error::Error;
478    use std::path::Path;
479
480    use super::*;
481
482    #[derive(Debug, Default, Clone, Reflect, Visit)]
483    struct Stub {}
484
485    impl ResourceData for Stub {
486        fn type_uuid(&self) -> Uuid {
487            Uuid::default()
488        }
489
490        fn save(&mut self, _path: &Path) -> Result<(), Box<dyn Error>> {
491            Err("Saving is not supported!".to_string().into())
492        }
493
494        fn can_be_saved(&self) -> bool {
495            false
496        }
497
498        fn try_clone_box(&self) -> Option<Box<dyn ResourceData>> {
499            Some(Box::new(self.clone()))
500        }
501    }
502
503    impl TypeUuidProvider for Stub {
504        fn type_uuid() -> Uuid {
505            Uuid::default()
506        }
507    }
508
509    #[test]
510    fn resource_state_new_pending() {
511        let state = ResourceState::new_pending();
512
513        assert!(matches!(state, ResourceState::Pending { .. }));
514        assert!(state.is_loading());
515    }
516
517    #[test]
518    fn resource_state_new_load_error() {
519        let state = ResourceState::new_load_error(Default::default(), Default::default());
520
521        assert!(matches!(state, ResourceState::LoadError { .. }));
522        assert!(!state.is_loading());
523    }
524
525    #[test]
526    fn resource_state_new_ok() {
527        let state = ResourceState::new_ok(Stub {});
528        assert!(matches!(state, ResourceState::Ok { .. }));
529        assert!(!state.is_loading());
530    }
531
532    #[test]
533    fn resource_state_switch_to_pending_state() {
534        // from Ok
535        let mut state = ResourceState::new_ok(Stub {});
536        state.switch_to_pending_state();
537
538        assert!(matches!(state, ResourceState::Pending { .. }));
539
540        // from LoadError
541        let mut state = ResourceState::new_load_error(Default::default(), Default::default());
542        state.switch_to_pending_state();
543
544        assert!(matches!(state, ResourceState::Pending { .. }));
545
546        // from Pending
547        let mut state = ResourceState::new_pending();
548        state.switch_to_pending_state();
549
550        assert!(matches!(state, ResourceState::Pending { .. }));
551    }
552}