use std::any::TypeId;
use seq_macro::seq;
use super::entity::{Entity, EntityId};
use super::property::Property;
use super::property_store::PropertyStore;
use crate::entity::ContextEntitiesExt;
use crate::{Context, IxaError};
pub trait PropertyList<E: Entity>: Copy + 'static {
fn validate() -> Result<(), IxaError>;
fn contains_properties(property_type_ids: &[TypeId]) -> bool;
fn contains_required_properties() -> bool {
Self::contains_properties(E::required_property_ids())
}
fn set_values_for_new_entity(
&self,
entity_id: EntityId<E>,
property_store: &mut PropertyStore<E>,
);
fn get_values_for_entity(context: &Context, entity_id: EntityId<E>) -> Self;
}
pub trait PropertyInitializationList<E: Entity>: PropertyList<E> {}
impl<E: Entity> PropertyList<E> for () {
fn validate() -> Result<(), IxaError> {
Ok(())
}
fn contains_properties(property_type_ids: &[TypeId]) -> bool {
property_type_ids.is_empty()
}
fn set_values_for_new_entity(
&self,
_entity_id: EntityId<E>,
_property_store: &mut PropertyStore<E>,
) {
}
fn get_values_for_entity(_context: &Context, _entity_id: EntityId<E>) -> Self {}
}
impl<E: Entity + Copy> PropertyList<E> for E {
fn validate() -> Result<(), IxaError> {
Ok(())
}
fn contains_properties(property_type_ids: &[TypeId]) -> bool {
property_type_ids.is_empty()
}
fn set_values_for_new_entity(
&self,
_entity_id: EntityId<E>,
_property_store: &mut PropertyStore<E>,
) {
}
fn get_values_for_entity(_context: &Context, _entity_id: EntityId<E>) -> E {
E::default()
}
}
impl<E: Entity + Copy> PropertyInitializationList<E> for E {}
impl<E: Entity, P: Property<E>> PropertyList<E> for (P,) {
fn validate() -> Result<(), IxaError> {
Ok(())
}
fn contains_properties(property_type_ids: &[TypeId]) -> bool {
property_type_ids.is_empty()
|| property_type_ids.len() == 1 && property_type_ids[0] == P::type_id()
}
fn set_values_for_new_entity(
&self,
entity_id: EntityId<E>,
property_store: &mut PropertyStore<E>,
) {
let property_value_store = property_store.get_mut::<P>();
property_value_store.set(entity_id, self.0);
}
fn get_values_for_entity(context: &Context, entity_id: EntityId<E>) -> Self {
(context.get_property::<E, P>(entity_id),)
}
}
macro_rules! impl_property_list {
($ct:literal) => {
seq!(N in 0..$ct {
impl<E: Entity, #( P~N: Property<E>,)*> PropertyList<E> for (#(P~N, )*){
fn validate() -> Result<(), IxaError> {
let property_type_ids: [TypeId; $ct] = [#(<P~N as $crate::entity::property::Property<E>>::type_id(),)*];
for i in 0..$ct - 1 {
for j in (i + 1)..$ct {
if property_type_ids[i] == property_type_ids[j] {
return Err(IxaError::DuplicatePropertyInPropertyList {
first_index: i,
second_index: j,
});
}
}
}
Ok(())
}
fn contains_properties(property_type_ids: &[TypeId]) -> bool {
let self_property_type_ids: [TypeId; $ct] = [#(<P~N as $crate::entity::property::Property<E>>::type_id(),)*];
property_type_ids.len() <= $ct && property_type_ids.iter().all(|id| self_property_type_ids.contains(id))
}
fn set_values_for_new_entity(&self, entity_id: EntityId<E>, property_store: &mut PropertyStore<E>){
#({
let property_value_store = property_store.get_mut::<P~N>();
property_value_store.set(entity_id, self.N);
})*
}
fn get_values_for_entity(context: &Context, entity_id: EntityId<E>) -> Self {
(#(context.get_property::<E, P~N>(entity_id), )*)
}
}
});
};
}
seq!(Z in 2..=20 {
impl_property_list!(Z);
});