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 `ctx.asset()` and provides information about
11/// whether an asset is loading or ready, along with the key for
12/// error reporting on suspend.
13///
14/// # Example
15///
16/// ```ignore
17/// #[query]
18/// fn process_file(ctx: &mut QueryContext, path: FilePath) -> Result<Output, QueryError> {
19///     let content = ctx.asset(path)?.suspend()?;
20///     // Process content...
21///     Ok(output)
22/// }
23/// ```
24pub struct AssetLoadingState<K: AssetKey> {
25    value: Option<Arc<K::Asset>>,
26    key: K,
27}
28
29impl<K: AssetKey> AssetLoadingState<K> {
30    /// Create a loading state (asset not yet available).
31    pub fn loading(key: K) -> Self {
32        Self { value: None, key }
33    }
34
35    /// Create a ready state with the asset value.
36    pub fn ready(key: K, value: Arc<K::Asset>) -> Self {
37        Self {
38            value: Some(value),
39            key,
40        }
41    }
42
43    /// Check if the resource is still loading.
44    pub fn is_loading(&self) -> bool {
45        self.value.is_none()
46    }
47
48    /// Check if the resource is ready.
49    pub fn is_ready(&self) -> bool {
50        self.value.is_some()
51    }
52
53    /// Get the value if ready, None if loading.
54    pub fn get(&self) -> Option<&Arc<K::Asset>> {
55        self.value.as_ref()
56    }
57
58    /// Get the value if ready, None if loading (consuming version).
59    pub fn into_inner(self) -> Option<Arc<K::Asset>> {
60        self.value
61    }
62
63    /// Convert to Result - Loading becomes Err(QueryError::Suspend).
64    ///
65    /// Use this with the `?` operator to propagate loading state upward.
66    /// The returned error includes the asset key for debugging.
67    ///
68    /// # Example
69    ///
70    /// ```ignore
71    /// fn query(&self, ctx: &mut QueryContext) -> Result<MyOutput, QueryError> {
72    ///     let data = ctx.asset(key)?.suspend()?;
73    ///     // `data` is guaranteed to be ready here
74    ///     Ok(process(data))
75    /// }
76    /// ```
77    pub fn suspend(self) -> Result<Arc<K::Asset>, QueryError> {
78        match self.value {
79            None => Err(QueryError::Suspend {
80                asset: PendingAsset::new(self.key),
81            }),
82            Some(v) => Ok(v),
83        }
84    }
85
86    /// Get a reference to the key.
87    pub fn key(&self) -> &K {
88        &self.key
89    }
90}
91
92impl<K: AssetKey> std::fmt::Debug for AssetLoadingState<K>
93where
94    K::Asset: std::fmt::Debug,
95{
96    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97        match &self.value {
98            None => write!(f, "AssetLoadingState::Loading({:?})", self.key),
99            Some(v) => write!(f, "AssetLoadingState::Ready({:?}, {:?})", self.key, v),
100        }
101    }
102}