 2b6e67f4cb
			
		
	
	
		2b6e67f4cb
		
	
	
	
	
		
			
			### Problem
It currently isn't possible to construct the default value of a reflected type. Because of that, it isn't possible to use `add_component` of `ReflectComponent` to add a new component to an entity because you can't know what the initial value should be.
### Solution
1. add `ReflectDefault` type
```rust
#[derive(Clone)]
pub struct ReflectDefault {
    default: fn() -> Box<dyn Reflect>,
}
impl ReflectDefault {
    pub fn default(&self) -> Box<dyn Reflect> {
        (self.default)()
    }
}
impl<T: Reflect + Default> FromType<T> for ReflectDefault {
    fn from_type() -> Self {
        ReflectDefault {
            default: || Box::new(T::default()),
        }
    }
}
```
2. add `#[reflect(Default)]` to all component types that implement `Default` and are user facing (so not `ComputedSize`, `CubemapVisibleEntities` etc.)
This makes it possible to add the default value of a component to an entity without any compile-time information:
```rust
fn main() {
    let mut app = App::new();
    app.register_type::<Camera>();
    let type_registry = app.world.get_resource::<TypeRegistry>().unwrap();
    let type_registry = type_registry.read();
    let camera_registration = type_registry.get(std::any::TypeId::of::<Camera>()).unwrap();
    let reflect_default = camera_registration.data::<ReflectDefault>().unwrap();
    let reflect_component = camera_registration
        .data::<ReflectComponent>()
        .unwrap()
        .clone();
    let default = reflect_default.default();
    drop(type_registry);
    let entity = app.world.spawn().id();
    reflect_component.add_component(&mut app.world, entity, &*default);
    let camera = app.world.entity(entity).get::<Camera>().unwrap();
    dbg!(&camera);
}
```
### Open questions
- should we have `ReflectDefault` or `ReflectFromWorld` or both?
		
	
			
		
			
				
	
	
		
			153 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			153 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use bevy_ecs::{component::Component, reflect::ReflectComponent};
 | |
| use bevy_reflect::std_traits::ReflectDefault;
 | |
| use bevy_reflect::Reflect;
 | |
| use bevy_utils::AHasher;
 | |
| use std::{
 | |
|     borrow::Cow,
 | |
|     hash::{Hash, Hasher},
 | |
|     ops::Deref,
 | |
| };
 | |
| 
 | |
| /// Component used to identify an entity. Stores a hash for faster comparisons
 | |
| /// The hash is eagerly re-computed upon each update to the name.
 | |
| ///
 | |
| /// [`Name`] should not be treated as a globally unique identifier for entities,
 | |
| /// as multiple entities can have the same name.  [`bevy_ecs::entity::Entity`] should be
 | |
| /// used instead as the default unique identifier.
 | |
| #[derive(Component, Debug, Clone, Reflect)]
 | |
| #[reflect(Component, Default)]
 | |
| pub struct Name {
 | |
|     hash: u64, // TODO: Shouldn't be serialized
 | |
|     name: Cow<'static, str>,
 | |
| }
 | |
| 
 | |
| impl Default for Name {
 | |
|     fn default() -> Self {
 | |
|         Name::new("")
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl Name {
 | |
|     /// Creates a new [`Name`] from any string-like type.
 | |
|     ///
 | |
|     /// The internal hash will be computed immediately.
 | |
|     pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
 | |
|         let name = name.into();
 | |
|         let mut name = Name { name, hash: 0 };
 | |
|         name.update_hash();
 | |
|         name
 | |
|     }
 | |
| 
 | |
|     /// Sets the entity's name.
 | |
|     ///
 | |
|     /// The internal hash will be re-computed.
 | |
|     #[inline(always)]
 | |
|     pub fn set(&mut self, name: impl Into<Cow<'static, str>>) {
 | |
|         *self = Name::new(name);
 | |
|     }
 | |
| 
 | |
|     /// Updates the name of the entity in place.
 | |
|     ///
 | |
|     /// This will allocate a new string if the name was previously
 | |
|     /// created from a borrow.
 | |
|     #[inline(always)]
 | |
|     pub fn mutate<F: FnOnce(&mut String)>(&mut self, f: F) {
 | |
|         f(self.name.to_mut());
 | |
|         self.update_hash();
 | |
|     }
 | |
| 
 | |
|     /// Gets the name of the entity as a `&str`.
 | |
|     #[inline(always)]
 | |
|     pub fn as_str(&self) -> &str {
 | |
|         &self.name
 | |
|     }
 | |
| 
 | |
|     fn update_hash(&mut self) {
 | |
|         let mut hasher = AHasher::default();
 | |
|         self.name.hash(&mut hasher);
 | |
|         self.hash = hasher.finish();
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl std::fmt::Display for Name {
 | |
|     #[inline(always)]
 | |
|     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
 | |
|         std::fmt::Display::fmt(&self.name, f)
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* Conversions from strings */
 | |
| 
 | |
| impl From<&str> for Name {
 | |
|     #[inline(always)]
 | |
|     fn from(name: &str) -> Self {
 | |
|         Name::new(name.to_owned())
 | |
|     }
 | |
| }
 | |
| impl From<String> for Name {
 | |
|     #[inline(always)]
 | |
|     fn from(name: String) -> Self {
 | |
|         Name::new(name)
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* Conversions to strings */
 | |
| 
 | |
| impl AsRef<str> for Name {
 | |
|     #[inline(always)]
 | |
|     fn as_ref(&self) -> &str {
 | |
|         &self.name
 | |
|     }
 | |
| }
 | |
| impl From<&Name> for String {
 | |
|     #[inline(always)]
 | |
|     fn from(val: &Name) -> String {
 | |
|         val.as_str().to_owned()
 | |
|     }
 | |
| }
 | |
| impl From<Name> for String {
 | |
|     #[inline(always)]
 | |
|     fn from(val: Name) -> String {
 | |
|         val.name.into_owned()
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl Hash for Name {
 | |
|     fn hash<H: Hasher>(&self, state: &mut H) {
 | |
|         self.name.hash(state);
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl PartialEq for Name {
 | |
|     fn eq(&self, other: &Self) -> bool {
 | |
|         if self.hash != other.hash {
 | |
|             // Makes the common case of two strings not been equal very fast
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         self.name.eq(&other.name)
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl Eq for Name {}
 | |
| 
 | |
| impl PartialOrd for Name {
 | |
|     fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
 | |
|         self.name.partial_cmp(&other.name)
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl Ord for Name {
 | |
|     fn cmp(&self, other: &Self) -> std::cmp::Ordering {
 | |
|         self.name.cmp(&other.name)
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl Deref for Name {
 | |
|     type Target = str;
 | |
| 
 | |
|     fn deref(&self) -> &Self::Target {
 | |
|         self.name.as_ref()
 | |
|     }
 | |
| }
 |