You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

127 lines
3.1 KiB

//! Group specific impls
use super::*;
use std::collections::{
VecDeque,
HashSet, hash_set,
};
impl Group
{
/// Is this group hidden from searches?
#[inline(always)] pub fn is_hidden(&self) -> bool
{
self.hidden
}
/// Set if this group should be hidden from searches.
#[inline(always)] pub fn set_hidden(&mut self, hide: bool)
{
self.hidden = hide;
}
/// The flattened inheritance graph of this `Group` within this `Userspace`.
pub fn inherits_from<'g, 'u>(&'g self, space: &'u Userspace) -> GroupInheritanceIter<'u>
where 'g: 'u
{
GroupInheritanceIter {
group: self,
space,
level: self.inherits.clone().unwrap_or_default().into(),
done: HashSet::new(),
is_cyclic: false,
cyclic_refs: Default::default(),
}
}
}
/// An iterator over a `Group`'s entire inheritance graph.
#[derive(Debug, Clone)]
pub struct GroupInheritanceIter<'u>
{
group: &'u Group,
space: &'u Userspace,
level: VecDeque<GroupID>,
done: HashSet<GroupID>,
is_cyclic: bool,
cyclic_refs: HashSet<&'u GroupID>,
}
impl<'a> GroupInheritanceIter<'a>
{
/// The group this iterator is working for
#[inline] pub fn base_group(&self) -> &Group
{
self.group
}
/// The userspace this iterator is searching in
#[inline] pub fn userspace(&self) -> &Userspace
{
self.space
}
/// Does this inheritance graph contain cyclic references so far?
#[inline] pub fn contains_cyclic_references(&self) -> bool
{
self.is_cyclic
}
/// The cyclic references found by this iterator so far (if any).
#[inline] pub fn cyclic_refs(&self) -> hash_set::Iter<'_, &'a GroupID>
{
self.cyclic_refs.iter()
}
/// All group IDs that have been processed by the iterator so far
#[inline] pub fn processed_group_ids(&self) -> hash_set::Iter<'_, GroupID>
{
self.done.iter()
}
}
impl<'u> Iterator for GroupInheritanceIter<'u>
{
type Item = &'u Group;
fn next(&mut self) -> Option<Self::Item>
{
match self.level
.pop_front()
.map(|id| (self.space.groups.get(&id),
self.done.insert(id)))
{
#[cold] Some((None, _)) => panic!("Group inheritance graph for group ID {:?} contained invalid ID not found within this userspace", self.group.id),
Some((Some(group), false)) => {
// We've already processed this ID, it is a cyclic reference.
// Ignore it and continue
if cfg!(debug_assertions) && !self.is_cyclic {
warn!("Cyclic reference found for group ID {:?} while calculating the inheritance graph of group {:?}", group.id, self.group.id);
}
self.is_cyclic = true;
self.cyclic_refs.insert(&group.id);
self.next()
},
Some((Some(group), _)) => {
if let Some(high) = &group.inherits {
self.level.reserve(high.len());
for high in high.iter().cloned().rev() {
self.level.push_front(high);
}
}
Some(group)
},
_ => None,
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
match self.level.len() {
0 => (0, Some(0)),
n => (n, None),
}
}
}
impl<'a> std::iter::FusedIterator for GroupInheritanceIter<'a>{}