use super::{
depth::{Depth, NormalDepth},
TopologyObject,
};
use crate::topology::Topology;
#[allow(unused)]
#[cfg(test)]
use similar_asserts::assert_eq;
use std::iter::FusedIterator;
#[cfg(test)]
use std::sync::OnceLock;
impl Topology {
pub fn objects(&self) -> impl FusedIterator<Item = &TopologyObject> + Clone {
self.normal_objects().chain(self.virtual_objects())
}
#[cfg(test)]
pub(crate) fn test_objects() -> &'static [&'static TopologyObject] {
static OBJECTS: OnceLock<Box<[&'static TopologyObject]>> = OnceLock::new();
&OBJECTS.get_or_init(|| Self::test_instance().objects().collect())[..]
}
#[cfg(test)]
pub(crate) fn foreign_objects() -> &'static [&'static TopologyObject] {
static OBJECTS: OnceLock<Box<[&'static TopologyObject]>> = OnceLock::new();
&OBJECTS.get_or_init(|| Self::foreign_instance().objects().collect())[..]
}
pub fn normal_objects(&self) -> impl FusedIterator<Item = &TopologyObject> + Clone {
NormalDepth::iter_range(NormalDepth::MIN, self.depth())
.flat_map(|depth| self.objects_at_depth(depth))
}
pub fn virtual_objects(&self) -> impl FusedIterator<Item = &TopologyObject> + Clone {
Depth::VIRTUAL_DEPTHS
.iter()
.flat_map(|&depth| self.objects_at_depth(depth))
}
pub fn memory_objects(&self) -> impl FusedIterator<Item = &TopologyObject> + Clone {
Depth::MEMORY_DEPTHS
.iter()
.flat_map(|&depth| self.objects_at_depth(depth))
}
pub fn io_objects(&self) -> impl FusedIterator<Item = &TopologyObject> + Clone {
Depth::IO_DEPTHS
.iter()
.flat_map(|&depth| self.objects_at_depth(depth))
}
}
#[cfg(test)]
pub(crate) mod tests {
use super::*;
use crate::object::ObjectType;
use proptest::prelude::*;
use similar_asserts::assert_eq;
use std::collections::{HashMap, HashSet};
pub(crate) fn checked_object_set<'a>(
it: impl Iterator<Item = &'a TopologyObject>,
) -> HashMap<u64, &'a TopologyObject> {
let mut set = HashMap::new();
for obj in it {
assert!(
set.insert(obj.global_persistent_index(), obj).is_none(),
"global_persistent_index should be unique across the topology"
);
}
set
}
pub(crate) fn object_ids_from_set(map: &HashMap<u64, &TopologyObject>) -> HashSet<u64> {
map.keys().copied().collect()
}
pub(crate) fn compare_object_sets<'a>(
result: impl Iterator<Item = &'a TopologyObject>,
reference: impl Iterator<Item = &'a TopologyObject>,
) -> Result<(), TestCaseError> {
prop_assert_eq!(
object_ids_from_set(&checked_object_set(result)),
object_ids_from_set(&checked_object_set(reference))
);
Ok(())
}
#[test]
fn object_lists() {
let topology = Topology::test_instance();
let objects = checked_object_set(topology.objects());
let keys = object_ids_from_set(&objects);
let normal_objects = checked_object_set(topology.normal_objects());
assert!(normal_objects
.values()
.all(|obj| obj.object_type().is_normal()));
let normal_keys = object_ids_from_set(&normal_objects);
let virtual_objects = checked_object_set(topology.virtual_objects());
assert!(virtual_objects
.values()
.all(|obj| !obj.object_type().is_normal()));
let virtual_keys = object_ids_from_set(&virtual_objects);
assert_eq!(keys, &normal_keys | &virtual_keys);
assert_eq!(normal_keys, &keys - &virtual_keys);
assert_eq!(virtual_keys, &keys - &normal_keys);
let memory_objects = checked_object_set(topology.memory_objects());
assert!(memory_objects
.values()
.all(|obj| obj.object_type().is_memory()));
let memory_keys = object_ids_from_set(&memory_objects);
let io_objects = checked_object_set(topology.io_objects());
assert!(io_objects.values().all(|obj| obj.object_type().is_io()));
let io_keys = object_ids_from_set(&io_objects);
let misc_objects = checked_object_set(topology.objects_with_type(ObjectType::Misc));
assert!(misc_objects
.values()
.all(|obj| obj.object_type() == ObjectType::Misc));
let misc_keys = object_ids_from_set(&misc_objects);
assert_eq!(virtual_keys, &(&memory_keys | &io_keys) | &misc_keys);
assert_eq!(memory_keys, &(&virtual_keys - &io_keys) - &misc_keys);
assert_eq!(io_keys, &(&virtual_keys - &memory_keys) - &misc_keys);
assert_eq!(misc_keys, &(&virtual_keys - &memory_keys) - &io_keys);
}
}