1#![warn(missing_docs)]
4
5use crate::core::parking_lot::{Mutex, MutexGuard};
6use crate::core::visitor::prelude::*;
7use std::{
8 borrow::Cow,
9 fmt::Debug,
10 future::Future,
11 ops::{Deref, DerefMut},
12 path::{Path, PathBuf},
13 pin::Pin,
14 sync::Arc,
15 task::{Context, Poll, Waker},
16};
17
18pub use rg3d_core as core;
19
20pub trait ResourceData: 'static + Default + Debug + Visit + Send {
22 fn path(&self) -> Cow<Path>;
24
25 fn set_path(&mut self, path: PathBuf);
27}
28
29pub trait ResourceLoadError: 'static + Debug + Send + Sync {}
31
32impl<T> ResourceLoadError for T where T: 'static + Debug + Send + Sync {}
33
34#[derive(Debug)]
46pub enum ResourceState<T: ResourceData, E: ResourceLoadError> {
47 Pending {
49 path: PathBuf,
51 wakers: Vec<Waker>,
53 },
54 LoadError {
56 path: PathBuf,
58 error: Option<Arc<E>>,
60 },
61 Ok(T),
63}
64
65impl<T: ResourceData, E: ResourceLoadError> Visit for ResourceState<T, E> {
66 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
67 visitor.enter_region(name)?;
68
69 let mut id = self.id();
70 id.visit("Id", visitor)?;
71 if visitor.is_reading() {
72 *self = Self::from_id(id)?;
73 }
74
75 match self {
76 Self::Pending { path, .. } => panic!(
77 "Resource {} must be .await_ed before serialization",
78 path.display()
79 ),
80 Self::LoadError { path, .. } => path.visit("Path", visitor)?,
83 Self::Ok(details) => details.visit("Details", visitor)?,
84 }
85
86 visitor.leave_region()
87 }
88}
89
90#[derive(Debug, Visit)]
92pub struct Resource<T: ResourceData, E: ResourceLoadError> {
93 state: Option<Arc<Mutex<ResourceState<T, E>>>>,
94}
95
96impl<T: ResourceData, E: ResourceLoadError> PartialEq for Resource<T, E> {
97 fn eq(&self, other: &Self) -> bool {
98 match (self.state.as_ref(), other.state.as_ref()) {
99 (Some(state), Some(other_state)) => std::ptr::eq(&**state, &**other_state),
100 (None, None) => true,
101 _ => false,
102 }
103 }
104}
105
106#[doc(hidden)]
107pub struct ResourceDataRef<'a, T: ResourceData, E: ResourceLoadError> {
108 guard: MutexGuard<'a, ResourceState<T, E>>,
109}
110
111impl<'a, T: ResourceData, E: ResourceLoadError> Deref for ResourceDataRef<'a, T, E> {
112 type Target = T;
113
114 fn deref(&self) -> &Self::Target {
115 match *self.guard {
116 ResourceState::Pending { ref path, .. } => {
117 panic!(
118 "Attempt to get reference to resource data while it is not loaded! Path is {}",
119 path.display()
120 )
121 }
122 ResourceState::LoadError { ref path, .. } => {
123 panic!(
124 "Attempt to get reference to resource data which failed to load! Path is {}",
125 path.display()
126 )
127 }
128 ResourceState::Ok(ref data) => data,
129 }
130 }
131}
132
133impl<'a, T: ResourceData, E: ResourceLoadError> DerefMut for ResourceDataRef<'a, T, E> {
134 fn deref_mut(&mut self) -> &mut Self::Target {
135 match *self.guard {
136 ResourceState::Pending { ref path, .. } => {
137 panic!(
138 "Attempt to get reference to resource data while it is not loaded! Path is {}",
139 path.display()
140 )
141 }
142 ResourceState::LoadError { ref path, .. } => {
143 panic!(
144 "Attempt to get reference to resource data which failed to load! Path is {}",
145 path.display()
146 )
147 }
148 ResourceState::Ok(ref mut data) => data,
149 }
150 }
151}
152
153impl<T: ResourceData, E: ResourceLoadError> Resource<T, E> {
154 #[inline]
156 pub fn new(state: ResourceState<T, E>) -> Self {
157 Self {
158 state: Some(Arc::new(Mutex::new(state))),
159 }
160 }
161
162 #[inline]
164 pub fn into_inner(self) -> Arc<Mutex<ResourceState<T, E>>> {
165 self.state.unwrap()
166 }
167
168 #[inline]
170 pub fn state(&self) -> MutexGuard<'_, ResourceState<T, E>> {
171 self.state.as_ref().unwrap().lock()
172 }
173
174 #[inline]
176 pub fn try_acquire_state(&self) -> Option<MutexGuard<'_, ResourceState<T, E>>> {
177 self.state.as_ref().unwrap().try_lock()
178 }
179
180 #[inline]
182 pub fn use_count(&self) -> usize {
183 Arc::strong_count(self.state.as_ref().unwrap())
184 }
185
186 #[inline]
188 pub fn key(&self) -> usize {
189 (&**self.state.as_ref().unwrap() as *const _) as usize
190 }
191
192 #[inline]
202 pub fn data_ref(&self) -> ResourceDataRef<'_, T, E> {
203 ResourceDataRef {
204 guard: self.state(),
205 }
206 }
207}
208
209impl<T: ResourceData, E: ResourceLoadError> Default for Resource<T, E> {
210 #[inline]
211 fn default() -> Self {
212 Self { state: None }
213 }
214}
215
216impl<T: ResourceData, E: ResourceLoadError> Clone for Resource<T, E> {
217 #[inline]
218 fn clone(&self) -> Self {
219 Self {
220 state: self.state.clone(),
221 }
222 }
223}
224
225impl<T: ResourceData, E: ResourceLoadError> From<Arc<Mutex<ResourceState<T, E>>>>
226 for Resource<T, E>
227{
228 #[inline]
229 fn from(state: Arc<Mutex<ResourceState<T, E>>>) -> Self {
230 Self { state: Some(state) }
231 }
232}
233
234#[allow(clippy::from_over_into)]
235impl<T: ResourceData, E: ResourceLoadError> Into<Arc<Mutex<ResourceState<T, E>>>>
236 for Resource<T, E>
237{
238 #[inline]
239 fn into(self) -> Arc<Mutex<ResourceState<T, E>>> {
240 self.state.unwrap()
241 }
242}
243
244impl<T: ResourceData, E: ResourceLoadError> Future for Resource<T, E> {
245 type Output = Result<Self, Option<Arc<E>>>;
246
247 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
248 let state = self.as_ref().state.clone();
249 match *state.unwrap().lock() {
250 ResourceState::Pending { ref mut wakers, .. } => {
251 let cx_waker = cx.waker();
253 if let Some(pos) = wakers.iter().position(|waker| waker.will_wake(cx_waker)) {
254 wakers[pos] = cx_waker.clone();
255 } else {
256 wakers.push(cx_waker.clone())
257 }
258
259 Poll::Pending
260 }
261 ResourceState::LoadError { ref error, .. } => Poll::Ready(Err(error.clone())),
262 ResourceState::Ok(_) => Poll::Ready(Ok(self.clone())),
263 }
264 }
265}
266
267impl<T: ResourceData, E: ResourceLoadError> ResourceState<T, E> {
268 #[inline]
270 pub fn new_pending(path: PathBuf) -> Self {
271 Self::Pending {
272 path,
273 wakers: Default::default(),
274 }
275 }
276
277 #[inline]
278 fn id(&self) -> u32 {
279 match self {
280 Self::Pending { .. } => 0,
281 Self::LoadError { .. } => 1,
282 Self::Ok(_) => 2,
283 }
284 }
285
286 #[inline]
287 fn from_id(id: u32) -> Result<Self, String> {
288 match id {
289 0 => Ok(Self::Pending {
290 path: Default::default(),
291 wakers: Default::default(),
292 }),
293 1 => Ok(Self::LoadError {
294 path: Default::default(),
295 error: None,
296 }),
297 2 => Ok(Self::Ok(Default::default())),
298 _ => Err(format!("Invalid resource id {}", id)),
299 }
300 }
301
302 #[inline]
304 pub fn path(&self) -> Cow<Path> {
305 match self {
306 Self::Pending { path, .. } => Cow::Borrowed(path.as_path()),
307 Self::LoadError { path, .. } => Cow::Borrowed(path.as_path()),
308 Self::Ok(details) => details.path(),
309 }
310 }
311
312 #[inline]
315 pub fn commit(&mut self, state: ResourceState<T, E>) {
316 let wakers = if let ResourceState::Pending { ref mut wakers, .. } = self {
317 std::mem::take(wakers)
318 } else {
319 unreachable!()
320 };
321
322 *self = state;
323
324 for waker in wakers {
325 waker.wake();
326 }
327 }
328}
329
330impl<T: ResourceData, E: ResourceLoadError> Default for ResourceState<T, E> {
331 fn default() -> Self {
332 Self::Ok(Default::default())
333 }
334}
335
336#[macro_export]
338macro_rules! define_new_resource {
339 ($(#[$meta:meta])* $name:ident<$state:ty, $error:ty>) => {
340 $(#[$meta])*
341 #[derive(Clone, Debug, Default, PartialEq)]
342 #[repr(transparent)]
343 pub struct $name(pub Resource<$state, $error>);
344
345 impl Visit for $name {
346 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
347 self.0.visit(name, visitor)
348 }
349 }
350
351 impl std::ops::Deref for $name {
352 type Target = Resource<$state, $error>;
353
354 fn deref(&self) -> &Self::Target {
355 &self.0
356 }
357 }
358
359 impl std::ops::DerefMut for $name {
360 fn deref_mut(&mut self) -> &mut Self::Target {
361 &mut self.0
362 }
363 }
364
365 impl std::future::Future for $name {
366 type Output = Result<Self, Option<std::sync::Arc<$error>>>;
367
368 fn poll(
369 mut self: std::pin::Pin<&mut Self>,
370 cx: &mut std::task::Context<'_>,
371 ) -> std::task::Poll<Self::Output> {
372 std::pin::Pin::new(&mut self.0)
373 .poll(cx)
374 .map(|r| r.map(|_| self.clone()))
375 }
376 }
377 };
378}