parent
b097c3b5ae
commit
d3c644836a
@ -0,0 +1,126 @@
|
||||
//! 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>{}
|
||||
|
Loading…
Reference in new issue