Group inheritance graph flattening iterator

master
Avril 3 years ago
parent b097c3b5ae
commit d3c644836a
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -29,6 +29,8 @@ pub struct User
groups: Vec<GroupID>,
}
//TODO: Iterator over all `Group`s a user is a part of (i.e. each group they're in's deduped & flattened inheritance graph)
/// A reference to a user in a userspace from their ID.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UserRef<'a>(UserID, &'a Userspace);
@ -121,9 +123,6 @@ impl<'a> Deref for GroupRef<'a>
}
}
/// A group is a way of setting permissions for a whole set of users.
///
/// Users have groups, not the other way around.
@ -147,6 +146,8 @@ pub struct Group
inherits: Option<Vec<GroupID>>,
}
submod!(group; "impls for `Group` related things");
pub trait AsEntityId
{
fn entity_id(&self) -> Cow<'_, EntityID>;
@ -324,12 +325,13 @@ bitflags! {
struct Permission: u16 {
/// Cannot read or write the item.
///
/// However they can see it, unless it is marked "hidden".
/// However they can see it, unless it is marked with tag attr "hidden".
const NONE = 0;
/// Can read from the item but cannot write to it
/// Can read from the item
const READ = 1;
/// Can write to the item
///
/// # Note
/// This does not imply `READ`.
const WRITE = 2;

@ -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>{}

@ -1,4 +1,6 @@
use super::*;
use std::collections::hash_map;
use std::iter;
impl Userspace
{
@ -27,6 +29,115 @@ impl Userspace
None
}
}
/// An iterator over the users in this instance
pub fn users(&self) -> UserIter<'_>
{
UserIter(self.users.iter())
}
/// A mutable iterator over the users in this instance
pub fn users_mut(&mut self) -> UserIterMut<'_>
{
UserIterMut(self.users.iter_mut())
}
/// An iterator over the groups in this instance
pub fn groups(&self) -> GroupIter<'_>
{
GroupIter(self.groups.iter())
}
/// A mutable iterator over the groups in this instance
pub fn groups_mut(&mut self) -> GroupIterMut<'_>
{
GroupIterMut(self.groups.iter_mut())
}
/// Number of users
pub fn users_len(&self) -> usize
{
self.users.len()
}
/// Number of groups
pub fn groups_len(&self) -> usize
{
self.groups.len()
}
}
/// Iterator over users
#[derive(Debug, Clone)]
pub struct UserIter<'a>(hash_map::Iter<'a, UserID, User>);
impl<'a> Iterator for UserIter<'a>
{
type Item = &'a User;
fn next(&mut self) -> Option<Self::Item>
{
self.0.next().map(|x| x.1)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<'a> iter::FusedIterator for UserIter<'a>{}
impl<'a> iter::ExactSizeIterator for UserIter<'a>{}
//TODO: `UserIter`, `GroupIter`
/// Mutable iterator over users
#[derive(Debug)]
pub struct UserIterMut<'a>(hash_map::IterMut<'a, UserID, User>);
impl<'a> Iterator for UserIterMut<'a>
{
type Item = &'a mut User;
fn next(&mut self) -> Option<Self::Item>
{
self.0.next().map(|x| x.1)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<'a> iter::FusedIterator for UserIterMut<'a>{}
impl<'a> iter::ExactSizeIterator for UserIterMut<'a>{}
/// Iterator over groups in a `Userspace`
#[derive(Debug, Clone)]
pub struct GroupIter<'a>(hash_map::Iter<'a, GroupID, Group>);
impl<'a> Iterator for GroupIter<'a>
{
type Item = &'a Group;
fn next(&mut self) -> Option<Self::Item>
{
self.0.next().map(|x| x.1)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<'a> iter::FusedIterator for GroupIter<'a>{}
impl<'a> iter::ExactSizeIterator for GroupIter<'a>{}
/// Mutable iterator over groups in a `Userspace`
#[derive(Debug)]
pub struct GroupIterMut<'a>(hash_map::IterMut<'a, GroupID, Group>);
impl<'a> Iterator for GroupIterMut<'a>
{
type Item = &'a mut Group;
fn next(&mut self) -> Option<Self::Item>
{
self.0.next().map(|x| x.1)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<'a> iter::FusedIterator for GroupIterMut<'a>{}
impl<'a> iter::ExactSizeIterator for GroupIterMut<'a>{}

Loading…
Cancel
Save