#![allow(clippy::map_clone)] use std::collections::HashMap; #[cfg(feature = "parallel")] use std::sync::atomic::{AtomicUsize, Ordering}; use legion::*; use query::Query; #[derive(Clone, Copy, Debug, PartialEq)] struct Pos(f32, f32, f32); #[derive(Clone, Copy, Debug, PartialEq)] struct Rot(f32, f32, f32); #[derive(Clone, Copy, Debug, PartialEq)] struct Scale(f32, f32, f32); #[derive(Clone, Copy, Debug, PartialEq)] struct Vel(f32, f32, f32); #[derive(Clone, Copy, Debug, PartialEq)] struct Accel(f32, f32, f32); #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] struct Model(u32); #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] struct Static; #[test] fn query_read_entity_data() { let mut world = World::default(); let components = vec![ (Pos(1., 2., 3.), Rot(0.1, 0.2, 0.3)), (Pos(4., 5., 6.), Rot(0.4, 0.5, 0.6)), ]; let mut expected = HashMap::::new(); for (i, e) in world.extend(components.clone()).iter().enumerate() { if let Some((pos, rot)) = components.get(i) { expected.insert(*e, (*pos, *rot)); } } let mut query = <(Entity, Read)>::query(); let mut count = 0; for (entity, pos) in query.iter_mut(&mut world) { assert_eq!(expected.get(&entity).unwrap().0, *pos); count += 1; } assert_eq!(components.len(), count); } #[test] fn query_try_read_entity_data() { let mut world = World::default(); world.push((Pos(1., 2., 3.),)); world.push((Pos(4., 5., 6.), Rot(0.4, 0.5, 0.6))); let mut query = TryRead::::query(); let rots = query .iter(&world) .map(|x| x.map(|x| *x)) .collect::>(); assert_eq!(rots.iter().filter(|x| x.is_none()).count(), 1); assert_eq!( rots.iter().cloned().flatten().collect::>(), &[Rot(0.4, 0.5, 0.6)] ); } #[test] fn query_try_write_entity_data() { let mut world = World::default(); world.push((Pos(1., 2., 3.),)); let entity = world.push((Pos(4., 5., 6.), Rot(0.4, 0.5, 0.6))); let mut query = TryWrite::::query(); for x in query.iter_mut(&mut world).flatten() { *x = Rot(9.0, 9.0, 9.0); } assert_eq!( world.entry(entity).unwrap().get_component::(), Ok(&Rot(9.0, 9.0, 9.0)) ); } #[test] fn query_cached_read_entity_data() { let mut world = World::default(); let components = vec![ (Pos(1., 2., 3.), Rot(0.1, 0.2, 0.3)), (Pos(4., 5., 6.), Rot(0.4, 0.5, 0.6)), ]; let mut expected = HashMap::::new(); for (i, e) in world.extend(components.clone()).iter().enumerate() { if let Some((pos, rot)) = components.get(i) { expected.insert(*e, (*pos, *rot)); } } let mut query = Query::<(Entity, &Pos)>::default(); let mut count = 0; for (entity, pos) in query.iter_mut(&mut world) { assert_eq!(expected.get(&entity).unwrap().0, *pos); count += 1; } assert_eq!(components.len(), count); } #[test] #[cfg(feature = "parallel")] fn query_read_entity_data_par() { let mut world = World::default(); let components = vec![ (Pos(1., 2., 3.), Rot(0.1, 0.2, 0.3)), (Pos(4., 5., 6.), Rot(0.4, 0.5, 0.6)), ]; let mut expected = HashMap::::new(); for (i, e) in world.extend(components.clone()).iter().enumerate() { if let Some((pos, rot)) = components.get(i) { expected.insert(*e, (*pos, *rot)); } } let count = AtomicUsize::new(0); let mut query = Read::::query(); query.par_for_each_chunk_mut(&mut world, |chunk| { for (entity, pos) in chunk.into_iter_entities() { assert_eq!(expected.get(&entity).unwrap().0, *pos); count.fetch_add(1, Ordering::SeqCst); } }); assert_eq!(components.len(), count.load(Ordering::SeqCst)); } #[test] #[cfg(feature = "parallel")] fn query_read_entity_data_par_foreach() { let mut world = World::default(); let components = vec![ (Pos(1., 2., 3.), Rot(0.1, 0.2, 0.3)), (Pos(4., 5., 6.), Rot(0.4, 0.5, 0.6)), ]; let mut expected = HashMap::::new(); for (i, e) in world.extend(components.clone()).iter().enumerate() { if let Some((pos, rot)) = components.get(i) { expected.insert(*e, (*pos, *rot)); } } let count = AtomicUsize::new(0); let mut query = Read::::query(); query.par_for_each_mut(&mut world, |_pos| { count.fetch_add(1, Ordering::SeqCst); }); assert_eq!(components.len(), count.load(Ordering::SeqCst)); } #[test] fn query_read_entity_data_tuple() { let mut world = World::default(); let components = vec![ (Pos(1., 2., 3.), Rot(0.1, 0.2, 0.3)), (Pos(4., 5., 6.), Rot(0.4, 0.5, 0.6)), ]; let mut expected = HashMap::::new(); for (i, e) in world.extend(components.clone()).iter().enumerate() { if let Some((pos, rot)) = components.get(i) { expected.insert(*e, (*pos, *rot)); } } let mut query = <(Entity, Read, Read)>::query(); let mut count = 0; for (entity, pos, rot) in query.iter_mut(&mut world) { assert_eq!(expected.get(&entity).unwrap().0, *pos); assert_eq!(expected.get(&entity).unwrap().1, *rot); count += 1; } assert_eq!(components.len(), count); } #[test] fn query_write_entity_data() { let mut world = World::default(); let components = vec![ (Pos(1., 2., 3.), Rot(0.1, 0.2, 0.3)), (Pos(4., 5., 6.), Rot(0.4, 0.5, 0.6)), ]; let mut expected = HashMap::::new(); for (i, e) in world.extend(components.clone()).iter().enumerate() { if let Some((pos, rot)) = components.get(i) { expected.insert(*e, (*pos, *rot)); } } let mut query = <(Entity, Write)>::query(); let mut count = 0; for (entity, pos) in query.iter_mut(&mut world) { assert_eq!(expected.get(&entity).unwrap().0, *pos); count += 1; pos.0 = 0.0; } assert_eq!(components.len(), count); } #[test] fn query_write_entity_data_tuple() { let mut world = World::default(); let components = vec![ (Pos(1., 2., 3.), Rot(0.1, 0.2, 0.3)), (Pos(4., 5., 6.), Rot(0.4, 0.5, 0.6)), ]; let mut expected = HashMap::::new(); for (i, e) in world.extend(components.clone()).iter().enumerate() { if let Some((pos, rot)) = components.get(i) { expected.insert(*e, (*pos, *rot)); } } let mut query = <(Entity, Write, Write)>::query(); let mut count = 0; for (entity, pos, rot) in query.iter_mut(&mut world) { assert_eq!(expected.get(&entity).unwrap().0, *pos); assert_eq!(expected.get(&entity).unwrap().1, *rot); count += 1; pos.0 = 0.0; rot.0 = 0.0; } assert_eq!(components.len(), count); } #[test] fn query_mixed_entity_data_tuple() { let mut world = World::default(); let components = vec![ (Pos(1., 2., 3.), Rot(0.1, 0.2, 0.3)), (Pos(4., 5., 6.), Rot(0.4, 0.5, 0.6)), ]; let mut expected = HashMap::::new(); for (i, e) in world.extend(components.clone()).iter().enumerate() { if let Some((pos, rot)) = components.get(i) { expected.insert(*e, (*pos, *rot)); } } let mut query = <(Entity, Read, Write)>::query(); let mut count = 0; for (entity, pos, rot) in query.iter_mut(&mut world) { assert_eq!(expected.get(&entity).unwrap().0, *pos); assert_eq!(expected.get(&entity).unwrap().1, *rot); count += 1; rot.0 = 0.0; } assert_eq!(components.len(), count); } #[test] fn query_partial_match() { let mut world = World::default(); let components = vec![ (Pos(1., 2., 3.), Rot(0.1, 0.2, 0.3)), (Pos(4., 5., 6.), Rot(0.4, 0.5, 0.6)), ]; let mut expected = HashMap::::new(); for (i, e) in world.extend(components.clone()).iter().enumerate() { if let Some((pos, rot)) = components.get(i) { expected.insert(*e, (*pos, *rot)); } } let mut query = <(Entity, Read, Write)>::query(); let mut count = 0; for (entity, pos, rot) in query.iter_mut(&mut world) { assert_eq!(expected.get(&entity).unwrap().0, *pos); assert_eq!(expected.get(&entity).unwrap().1, *rot); count += 1; rot.0 = 0.0; } assert_eq!(components.len(), count); } #[test] fn query_on_changed_first() { let mut world = World::default(); let components = vec![ (Pos(1., 2., 3.), Rot(0.1, 0.2, 0.3)), (Pos(4., 5., 6.), Rot(0.4, 0.5, 0.6)), ]; let mut expected = HashMap::::new(); for (i, e) in world.extend(components.clone()).iter().enumerate() { if let Some((pos, rot)) = components.get(i) { expected.insert(*e, (*pos, *rot)); } } let mut query = <(Entity, Read, Read)>::query() .filter(maybe_changed::() | maybe_changed::()); let mut count = 0; for (entity, pos, _) in query.iter_mut(&mut world) { assert_eq!(expected.get(&entity).unwrap().0, *pos); count += 1; } assert_eq!(components.len(), count); } #[test] fn query_on_changed_no_changes() { let mut world = World::default(); let components = vec![ (Pos(1., 2., 3.), Rot(0.1, 0.2, 0.3)), (Pos(4., 5., 6.), Rot(0.4, 0.5, 0.6)), ]; let mut expected = HashMap::::new(); for (i, e) in world.extend(components.clone()).iter().enumerate() { if let Some((pos, rot)) = components.get(i) { expected.insert(*e, (*pos, *rot)); } } let mut query = <(Entity, Read)>::query().filter(maybe_changed::()); let mut count = 0; for (entity, pos) in query.iter_mut(&mut world) { assert_eq!(expected.get(&entity).unwrap().0, *pos); count += 1; } assert_eq!(components.len(), count); count = 0; for (entity, pos) in query.iter_mut(&mut world) { assert_eq!(expected.get(&entity).unwrap().0, *pos); count += 1; } assert_eq!(0, count); } #[test] fn query_on_changed_self_changes() { let mut world = World::default(); let components = vec![ (Pos(1., 2., 3.), Rot(0.1, 0.2, 0.3)), (Pos(4., 5., 6.), Rot(0.4, 0.5, 0.6)), ]; let mut expected = HashMap::::new(); for (i, e) in world.extend(components.clone()).iter().enumerate() { if let Some((pos, rot)) = components.get(i) { expected.insert(*e, (*pos, *rot)); } } let mut query = <(Entity, Write)>::query().filter(maybe_changed::()); let mut count = 0; for (entity, pos) in query.iter_mut(&mut world) { assert_eq!(expected.get(&entity).unwrap().0, *pos); *pos = Pos(1., 1., 1.); count += 1; } assert_eq!(components.len(), count); count = 0; for (_, pos) in query.iter_mut(&mut world) { assert_eq!(Pos(1., 1., 1.), *pos); count += 1; } assert_eq!(components.len(), count); } #[test] fn query_try_with_changed_filter() { #[derive(Clone, Copy, Debug, PartialEq)] struct Sum(f32); #[derive(Clone, Copy, Debug, PartialEq)] struct A(f32); #[derive(Clone, Copy, Debug, PartialEq)] struct B(f32); let mut world = World::default(); let sum_entity = world.push((Sum(0.),)); let a_entity = world.push((Sum(0.), A(1.))); let b_entity = world.push((Sum(0.), B(2.))); let a_b_entity = world.push((Sum(0.), A(1.), B(2.))); let mut query = <(Write, TryRead, TryRead)>::query() .filter((maybe_changed::() | maybe_changed::()) | !any()); let mut count = 0; for (sum, a, b) in query.iter_mut(&mut world) { sum.0 = a.map_or(0., |x| x.0) + b.map_or(0., |x| x.0); count += 1; } assert_eq!(3, count); assert_eq!( world .entry(sum_entity) .unwrap() .get_component::() .map(|x| *x), Ok(Sum(0.)) ); assert_eq!( world .entry(a_entity) .unwrap() .get_component::() .map(|x| *x), Ok(Sum(1.)) ); assert_eq!( world .entry(b_entity) .unwrap() .get_component::() .map(|x| *x), Ok(Sum(2.)) ); assert_eq!( world .entry(a_b_entity) .unwrap() .get_component::() .map(|x| *x), Ok(Sum(3.)) ); count = 0; for (sum, a, b) in query.iter_mut(&mut world) { sum.0 = a.map_or(0., |x| x.0) + b.map_or(0., |x| x.0); count += 1; } assert_eq!(0, count); *world .entry(a_b_entity) .unwrap() .get_component_mut::() .unwrap() = B(3.0); count = 0; for (sum, a, b) in query.iter_mut(&mut world) { sum.0 = a.map_or(0., |x| x.0) + b.map_or(0., |x| x.0); count += 1; } assert_eq!(1, count); assert_eq!( world .entry(a_b_entity) .unwrap() .get_component::() .map(|x| *x), Ok(Sum(4.)) ); }