keket_graph/node.rs
1use crate::protocol::AssetTree;
2use keket::{
3 database::{
4 AssetDatabase,
5 handle::AssetHandle,
6 path::AssetPathStatic,
7 reference::{AssetRef, AssetResolved},
8 },
9 third_party::anput::component::Component,
10};
11use serde::{Deserialize, Serialize};
12use std::{
13 error::Error,
14 marker::PhantomData,
15 ops::{Deref, DerefMut},
16};
17
18/// AssetNode represents a node in the asset graph, which is a reference to an
19/// asset that can be resolved to a specific component in asset.
20#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
21#[serde(from = "AssetPathStatic", into = "AssetPathStatic")]
22pub struct AssetNode<T: AssetTree> {
23 inner: AssetRef,
24 #[serde(skip)]
25 _phantom: PhantomData<fn() -> T>,
26}
27
28impl<T: AssetTree> AssetNode<T> {
29 /// Creates a new AssetNode from a static asset path.
30 ///
31 /// # Arguments
32 /// - `path`: The path to the asset, which can be any type that can be
33 /// converted into `AssetPathStatic`.
34 ///
35 /// # Returns
36 /// A new `AssetNode` instance that references the asset at the given path.
37 pub fn new(path: impl Into<AssetPathStatic>) -> Self {
38 Self::from_ref(AssetRef::new(path))
39 }
40
41 /// Creates a new AssetNode from an existing AssetRef.
42 ///
43 /// # Arguments
44 /// - `inner`: The `AssetRef` that this node will reference.
45 ///
46 /// # Returns
47 /// A new `AssetNode` instance that wraps the provided `AssetRef`.
48 pub fn from_ref(inner: AssetRef) -> Self {
49 Self {
50 inner,
51 _phantom: PhantomData,
52 }
53 }
54
55 /// Returns a reference to the inner `AssetRef` of this node.
56 pub fn as_ref(&self) -> AssetRef {
57 self.inner.clone()
58 }
59
60 /// Invalidates the asset node, making internal `AssetRef` unresolved.
61 ///
62 /// # Returns
63 /// A `Result` indicating success or failure. If successful, the asset node
64 /// is marked as invalidated, and any future attempts to resolve it will
65 /// require re-fetching or re-resolving the asset.
66 pub fn invalidate(&self) -> Result<(), Box<dyn Error>> {
67 self.inner.invalidate()
68 }
69
70 /// Returns the path of the asset node.
71 ///
72 /// # Returns
73 /// A reference to the `AssetPathStatic` associated with this node.
74 pub fn path(&self) -> &AssetPathStatic {
75 self.inner.path()
76 }
77
78 /// Returns the handle of the asset node.
79 ///
80 /// # Returns
81 /// A `Result` containing the `AssetHandle` if successful, or an error if
82 /// the handle cannot be retrieved.
83 pub fn handle(&self) -> Result<AssetHandle, Box<dyn Error>> {
84 self.inner.handle()
85 }
86
87 /// Resolves the asset node to a specific component in the asset database.
88 ///
89 /// # Arguments
90 /// - `database`: A reference to the `AssetDatabase` where the asset is stored.
91 ///
92 /// # Returns
93 /// A `Result` containing an `AssetNodeResolved` instance if successful, or an
94 /// error if the resolution fails. The `AssetNodeResolved` provides access to
95 /// the resolved component, allowing read and write operations.
96 pub fn resolve<'a>(
97 &'a self,
98 database: &'a AssetDatabase,
99 ) -> Result<AssetNodeResolved<'a, T>, Box<dyn Error>> {
100 self.inner
101 .resolve(database)
102 .map(|resolved| AssetNodeResolved {
103 inner: resolved,
104 _phantom: PhantomData,
105 })
106 }
107
108 /// Ensures that the asset node is resolved and available in the asset database.
109 ///
110 /// # Arguments
111 /// - `database`: A mutable reference to the `AssetDatabase` where the asset is stored.
112 ///
113 /// # Returns
114 /// A `Result` containing an `AssetNodeResolved` instance if successful, or an
115 /// error if the resolution fails. The `AssetNodeResolved` provides access to
116 /// the resolved component, allowing read and write operations.
117 pub fn ensure<'a>(
118 &'a self,
119 database: &'a mut AssetDatabase,
120 ) -> Result<AssetNodeResolved<'a, T>, Box<dyn Error>> {
121 self.inner
122 .ensure(database)
123 .map(|resolved| AssetNodeResolved {
124 inner: resolved,
125 _phantom: PhantomData,
126 })
127 }
128}
129
130impl<T: AssetTree> Clone for AssetNode<T> {
131 fn clone(&self) -> Self {
132 Self {
133 inner: self.inner.clone(),
134 _phantom: PhantomData,
135 }
136 }
137}
138
139impl<T: AssetTree> From<AssetPathStatic> for AssetNode<T> {
140 fn from(path: AssetPathStatic) -> Self {
141 Self::new(path)
142 }
143}
144
145impl<T: AssetTree> From<AssetNode<T>> for AssetPathStatic {
146 fn from(value: AssetNode<T>) -> Self {
147 value.path().clone()
148 }
149}
150
151impl<T: AssetTree> AssetTree for AssetNode<T> {
152 fn asset_dependencies(&self) -> impl IntoIterator<Item = AssetPathStatic> {
153 std::iter::once(self.inner.path().clone().into_static())
154 }
155}
156
157/// AssetNodeResolved represents a resolved asset node, providing access to the
158/// component associated with the asset. It allows both read and write access
159/// to the component, ensuring that the asset is properly resolved before
160/// accessing its data.
161pub struct AssetNodeResolved<'a, T: Component> {
162 inner: AssetResolved<'a>,
163 _phantom: PhantomData<fn() -> T>,
164}
165
166impl<'a, T: Component> AssetNodeResolved<'a, T> {
167 /// Gives read access to component of the asset.
168 ///
169 /// # Returns
170 /// An `Option` containing a reference to the component if it is accessible,
171 /// or `None` if the component is not accessible.
172 pub fn read(&self) -> Option<&T> {
173 self.inner.access_checked::<&T>()
174 }
175
176 /// Gives write access to component of the asset.
177 ///
178 /// # Returns
179 /// An `Option` containing a mutable reference to the component if it is
180 /// accessible, or `None` if the component is not accessible.
181 pub fn write(&self) -> Option<&mut T> {
182 self.inner.access_checked::<&mut T>()
183 }
184
185 /// Gives unchecked read access to component of the asset.
186 ///
187 /// # Returns
188 /// A reference to the component, allowing read access without checking
189 /// if the component is accessible. This method can panic if the component
190 /// is not accessible, so it should be used with caution.
191 pub fn read_unchecked(&self) -> &T {
192 self.inner.access::<&T>()
193 }
194
195 /// Gives unchecked write access to component of the asset.
196 ///
197 /// # Returns
198 /// A mutable reference to the component, allowing write access without
199 /// checking if the component is accessible. This method can panic if the
200 /// component is not accessible, so it should be used with caution.
201 pub fn write_unchecked(&self) -> &mut T {
202 self.inner.access::<&mut T>()
203 }
204}
205
206impl<'a, T: Component> Deref for AssetNodeResolved<'a, T> {
207 type Target = AssetResolved<'a>;
208
209 fn deref(&self) -> &Self::Target {
210 &self.inner
211 }
212}
213
214impl<'a, T: Component> DerefMut for AssetNodeResolved<'a, T> {
215 fn deref_mut(&mut self) -> &mut Self::Target {
216 &mut self.inner
217 }
218}