1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use std::collections::HashMap;

use serde::{Deserialize, Serialize};

use crate::internal::{
    conversion::{FromBindgen, IntoBindgen},
    wit::{self},
};

use super::{
    Component, ComponentIndex, ComponentValue, SupportedValue, SupportedValueRef, UntypedComponent,
};

/// An [Entity] is a collection of components and associated values.
///
/// Use the [spawn](Entity::spawn) method to insert the [Entity] into the world.
#[derive(Clone, Default, Serialize, Deserialize, PartialEq)]
pub struct Entity(pub(crate) HashMap<ComponentIndex, ComponentValue>);
impl Entity {
    /// Creates a new `Entity`.
    pub fn new() -> Self {
        Self::default()
    }

    /// Returns the number of component (values) in the entity.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Returns true if the entity has no components (values).
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    /// Returns true if this has `component`.
    pub fn has<T: SupportedValue>(&self, component: Component<T>) -> bool {
        self.0.contains_key(&component.index())
    }

    /// Returns true if this has all of `components`.
    pub fn has_components(&self, components: &[&dyn UntypedComponent]) -> bool {
        components
            .iter()
            .all(|component| self.0.contains_key(&component.index()))
    }

    /// Gets the data for `component` in this, if it exists.
    pub fn get<T: SupportedValue>(&self, component: Component<T>) -> Option<T> {
        T::from_value(self.0.get(&component.index())?.clone())
    }

    /// Gets a reference to the data for `component` in this, if it exists.
    pub fn get_ref<T: SupportedValueRef>(&self, component: Component<T>) -> Option<&T> {
        T::from_value_ref(self.0.get(&component.index())?)
    }

    /// Adds `component` to this with `value`. It will replace an existing component if present.
    pub fn set<T: SupportedValue>(&mut self, component: Component<T>, value: T) {
        self.0.insert(component.index(), value.into_value());
    }

    /// Sets the `component` in this to the default value for `T`.
    pub fn set_default<T: SupportedValue + Default>(&mut self, component: Component<T>) {
        self.set(component, T::default())
    }

    /// Adds `component` to this with `value`, and returns `self` to allow for easy chaining.
    pub fn with<T: SupportedValue>(mut self, component: Component<T>, value: T) -> Self {
        self.set(component, value);
        self
    }

    /// Merges in the `other` Entity and returns this; any fields that were present in both will be replaced by `other`'s.
    pub fn with_merge(mut self, other: impl Into<Entity>) -> Self {
        self.merge(other.into());
        self
    }

    /// Removes `component` to this with `value`, and returns `self` to allow for easy chaining.
    pub fn without<T: SupportedValue>(mut self, component: Component<T>) -> Self {
        self.0.remove(&component.index());
        self
    }

    /// Removes the specified component from this, and returns the value if it was present.
    pub fn remove<T: SupportedValue>(&mut self, component: Component<T>) -> Option<T> {
        T::from_value(self.0.remove(&component.index())?)
    }

    /// Merges in the `other` Entity; any fields that were present in both will be replaced by `other`'s.
    pub fn merge(&mut self, other: Entity) {
        self.0.extend(other.0);
    }

    /// Spawns an entity with these components.
    ///
    /// Returns `spawned_entity_uid`.
    pub fn spawn(&self) -> crate::prelude::EntityId {
        crate::entity::spawn(self)
    }
}
impl FromBindgen for wit::component::Entity {
    type Item = Entity;

    fn from_bindgen(self) -> Self::Item {
        Entity(
            self.into_iter()
                .map(|(k, v)| (k, v.from_bindgen()))
                .collect(),
        )
    }
}
impl IntoBindgen for Entity {
    type Item = wit::component::Entity;

    fn into_bindgen(self) -> Self::Item {
        self.0
            .into_iter()
            .map(|(k, v)| (k, v.into_bindgen()))
            .collect()
    }
}
impl std::fmt::Debug for Entity {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_map()
            .entries(self.0.iter().map(|(k, v)| {
                (
                    wit::component::get_id(*k).unwrap_or_else(|| format!("unknown component {k}")),
                    v,
                )
            }))
            .finish()
    }
}