query_flow/loading.rs
1//! Loading state for async resource handling.
2
3use std::sync::Arc;
4
5use crate::asset::{AssetKey, PendingAsset};
6use crate::QueryError;
7
8/// Loading state with asset key information for error reporting.
9///
10/// This is returned by [`Db::asset_state()`](crate::Db::asset_state) and provides
11/// information about whether an asset is loading or ready.
12///
13/// For most use cases, prefer [`Db::asset()`](crate::Db::asset) which automatically
14/// suspends on loading. Use `asset_state()` when you need to explicitly check
15/// the loading state without triggering suspension.
16///
17/// # Example
18///
19/// ```ignore
20/// #[query]
21/// fn process_file(db: &impl Db, path: FilePath) -> Result<Output, QueryError> {
22/// // Most common: just use db.asset() which suspends automatically
23/// let content = db.asset(path)?;
24/// Ok(process(&content))
25/// }
26///
27/// #[query]
28/// fn check_loading(db: &impl Db, path: FilePath) -> Result<bool, QueryError> {
29/// // Use asset_state() when you need to check loading status explicitly
30/// let state = db.asset_state(path)?;
31/// Ok(state.is_loading())
32/// }
33/// ```
34pub struct AssetLoadingState<K: AssetKey> {
35 value: Option<Arc<K::Asset>>,
36 key: K,
37}
38
39impl<K: AssetKey> AssetLoadingState<K> {
40 /// Create a loading state (asset not yet available).
41 pub fn loading(key: K) -> Self {
42 Self { value: None, key }
43 }
44
45 /// Create a ready state with the asset value.
46 pub fn ready(key: K, value: Arc<K::Asset>) -> Self {
47 Self {
48 value: Some(value),
49 key,
50 }
51 }
52
53 /// Check if the resource is still loading.
54 pub fn is_loading(&self) -> bool {
55 self.value.is_none()
56 }
57
58 /// Check if the resource is ready.
59 pub fn is_ready(&self) -> bool {
60 self.value.is_some()
61 }
62
63 /// Get the value if ready, None if loading.
64 pub fn get(&self) -> Option<&Arc<K::Asset>> {
65 self.value.as_ref()
66 }
67
68 /// Get the value if ready, None if loading (consuming version).
69 pub fn into_inner(self) -> Option<Arc<K::Asset>> {
70 self.value
71 }
72
73 /// Convert to Result - Loading becomes Err(QueryError::Suspend).
74 ///
75 /// This method is used internally by [`Db::asset()`](crate::Db::asset).
76 /// You can also use it when working with [`Db::asset_state()`](crate::Db::asset_state).
77 ///
78 /// # Example
79 ///
80 /// ```ignore
81 /// fn query(&self, db: &impl Db) -> Result<MyOutput, QueryError> {
82 /// // Preferred: use db.asset() directly
83 /// let data = db.asset(key)?;
84 ///
85 /// // Alternative: use asset_state() + suspend()
86 /// let state = db.asset_state(key)?;
87 /// let data = state.suspend()?;
88 ///
89 /// Ok(process(&data))
90 /// }
91 /// ```
92 pub fn suspend(self) -> Result<Arc<K::Asset>, QueryError> {
93 match self.value {
94 None => Err(QueryError::Suspend {
95 asset: PendingAsset::new(self.key),
96 }),
97 Some(v) => Ok(v),
98 }
99 }
100
101 /// Get a reference to the key.
102 pub fn key(&self) -> &K {
103 &self.key
104 }
105}
106
107impl<K: AssetKey> std::fmt::Debug for AssetLoadingState<K>
108where
109 K::Asset: std::fmt::Debug,
110{
111 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112 match &self.value {
113 None => write!(f, "AssetLoadingState::Loading({:?})", self.key),
114 Some(v) => write!(f, "AssetLoadingState::Ready({:?}, {:?})", self.key, v),
115 }
116 }
117}