-
-
Notifications
You must be signed in to change notification settings - Fork 3.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FilteredResource returns a Result instead of a simple Option #18265
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -55,3 +55,14 @@ pub enum EntityMutableFetchError { | |
#[error("The entity with ID {0} was requested mutably more than once")] | ||
AliasedMutability(Entity), | ||
} | ||
|
||
/// An error that occurs when getting a resource of a given type in a world. | ||
#[derive(thiserror::Error, Debug, Clone, Copy, PartialEq, Eq)] | ||
pub enum ResourceFetchError { | ||
/// The resource does not exist in the world. | ||
#[error("The resource does not exist in the world.")] | ||
MissingResource, | ||
/// No access to the resource with the given [`ComponentId`] in the world. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These docs / error message should be clearer. What sort of access are we talking about here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmmm, how about something like "Cannot get access to resource as it conflicts with an on going operation"? Something along this line, I am not a native speaker so feel free to suggest something that is better! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Something like that is better, but I think the key thing to mention is that the conflicting access is with respect to the world :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The main way to use (The other way to get one is to convert from |
||
#[error("No access to the resource with ID {0:?} in the world.")] | ||
NoResourceAccess(ComponentId), | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,8 @@ use crate::{ | |
}; | ||
use bevy_ptr::{Ptr, UnsafeCellDeref}; | ||
|
||
use super::error::ResourceFetchError; | ||
|
||
/// Provides read-only access to a set of [`Resource`]s defined by the contained [`Access`]. | ||
/// | ||
/// Use [`FilteredResourcesMut`] if you need mutable access to some resources. | ||
|
@@ -151,21 +153,27 @@ impl<'w, 's> FilteredResources<'w, 's> { | |
} | ||
|
||
/// Gets a reference to the resource of the given type if it exists and the `FilteredResources` has access to it. | ||
pub fn get<R: Resource>(&self) -> Option<Ref<'w, R>> { | ||
let component_id = self.world.components().resource_id::<R>()?; | ||
pub fn get<R: Resource>(&self) -> Result<Ref<'w, R>, ResourceFetchError> { | ||
let component_id = self | ||
.world | ||
.components() | ||
.resource_id::<R>() | ||
.ok_or(ResourceFetchError::MissingResource)?; | ||
if !self.access.has_resource_read(component_id) { | ||
return None; | ||
return Err(ResourceFetchError::NoResourceAccess(component_id)); | ||
} | ||
|
||
// SAFETY: We have read access to this resource | ||
unsafe { self.world.get_resource_with_ticks(component_id) }.map(|(value, ticks, caller)| { | ||
Ref { | ||
// SAFETY: `component_id` was obtained from the type ID of `R`. | ||
value: unsafe { value.deref() }, | ||
// SAFETY: We have read access to the resource, so no mutable reference can exist. | ||
ticks: unsafe { Ticks::from_tick_cells(ticks, self.last_run, self.this_run) }, | ||
// SAFETY: We have read access to the resource, so no mutable reference can exist. | ||
changed_by: unsafe { caller.map(|caller| caller.deref()) }, | ||
} | ||
let (value, ticks, caller) = unsafe { self.world.get_resource_with_ticks(component_id) } | ||
.ok_or(ResourceFetchError::MissingResource)?; | ||
|
||
Ok(Ref { | ||
// SAFETY: `component_id` was obtained from the type ID of `R`. | ||
value: unsafe { value.deref() }, | ||
// SAFETY: We have read access to the resource, so no mutable reference can exist. | ||
ticks: unsafe { Ticks::from_tick_cells(ticks, self.last_run, self.this_run) }, | ||
// SAFETY: We have read access to the resource, so no mutable reference can exist. | ||
changed_by: unsafe { caller.map(|caller| caller.deref()) }, | ||
}) | ||
Comment on lines
+156
to
177
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. very idiomatic, I like it. |
||
} | ||
|
||
|
@@ -419,7 +427,7 @@ impl<'w, 's> FilteredResourcesMut<'w, 's> { | |
} | ||
|
||
/// Gets a reference to the resource of the given type if it exists and the `FilteredResources` has access to it. | ||
pub fn get<R: Resource>(&self) -> Option<Ref<'_, R>> { | ||
pub fn get<R: Resource>(&self) -> Result<Ref<'_, R>, ResourceFetchError> { | ||
self.as_readonly().get() | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You included
ComponentId
in theNoResourceAccess
variant, but not inMissingResource
. Would it be useful to include it there, as well? I guess it's not available in the case where the resource isn't even initialized, but you could doOption<ComponentId>
, or even separate variants for "not initialized" and "not present".