diff --git a/src/cache.rs b/src/cache.rs new file mode 100644 index 0000000..fcf7fc2 --- /dev/null +++ b/src/cache.rs @@ -0,0 +1,84 @@ +//! Caching utilities +use std::mem::{self, MaybeUninit}; +use std::error; +use std::borrow::Borrow; +use std::sync::RwLock; + +/// A trait for objects that can cache an operation in themselves +pub trait Cache +{ + type Cached; + + /// Compute the `Cached` value. + fn cache(&self) -> Self::Cached; +} + +/// A value that might be cached or not. +#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] +pub enum MaybeCached +{ + Uncached(T), + Cached(T::Cached), +} + +impl MaybeCached +{ + /// Cache the operation + #[inline] pub fn cache(&mut self) + { + match self { + Self::Uncached(val) => *self = Self::Cached(val.cache()), + _ => (), + } + } + + /// Has this value been cached + pub fn is_cached(&self) -> bool + { + if let Self::Cached(_) = &self { + true + } else { + false + } + } + + /// Consume into the cached operation + #[inline] pub fn into_cached(mut self) -> Self + { + self.cache(); + self + } + + /// Compute the operation + #[inline] pub fn compute(self) -> T::Cached + { + match self { + Self::Cached(c) => c, + Self::Uncached(val) => val.cache(), + } + } +} + +impl Cache for F +where F: Fn() -> T +{ + type Cached = T; + #[inline] fn cache(&self) -> Self::Cached + { + self() + } +} + +/* +#[derive(Debug)] +pub struct LazyCached(RwLock>, T); + +impl LazyCached +{ + pub fn new(value: T) -> Self + { + Self(RwLock::new(None), value) + } +} + */ +//TODO:idfk.. diff --git a/src/ext.rs b/src/ext.rs index 50d05d6..bc4a558 100644 --- a/src/ext.rs +++ b/src/ext.rs @@ -341,12 +341,12 @@ impl UnwrapErrInfallible for Result (priv $name:ident $(; $doc:literal)?) => { $(#[doc=$doc])? mod $name; - use $name::*; + use self::$name::*; }; ($vis:vis $name:ident $(; $doc:literal)?) => { $(#[doc=$doc])? mod $name; - $vis use $name::*; + $vis use self::$name::*; }; ($name:ident $(; $doc:literal)?) => ($crate::submod!(pub $name $(; $doc)?)); } diff --git a/src/main.rs b/src/main.rs index 920815a..6f94157 100644 --- a/src/main.rs +++ b/src/main.rs @@ -38,6 +38,7 @@ fn install() -> eyre::Result<()> Ok(()) } +mod cache; mod ext; use ext::*; mod util; diff --git a/src/server/user.rs b/src/server/user.rs index 1a7e6e2..53c516a 100644 --- a/src/server/user.rs +++ b/src/server/user.rs @@ -31,6 +31,7 @@ pub struct User groups: Vec, } +submod!(user; "impls for `User`."); //TODO: Iterator over all `Group`s a user is a part of (i.e. each group they're in's deduped & flattened inheritance graph) diff --git a/src/server/user/user.rs b/src/server/user/user.rs new file mode 100644 index 0000000..3e613e4 --- /dev/null +++ b/src/server/user/user.rs @@ -0,0 +1,113 @@ +//! impls for `User` +use super::*; +use std::borrow::Cow; +use std::iter; + +/// A container of `Group` references in a `Userspace` from `GroupID`s +#[derive(Debug, Clone)] +pub struct Groups<'u>(usize, Cow<'u, [GroupID]>, &'u Userspace); +/// An iterator over all groups a user is a part of. +#[derive(Debug, Clone)] +pub struct AllGroups<'u>(Vec<(Option<&'u Group>, GroupInheritanceIter<'u>)>); + +impl User +{ + /// All groups the user is explicitly a part of + pub fn groups_explicit<'a, 'u>(&'a self, space: &'u Userspace) -> Groups<'u> + where 'a: 'u + { + Groups(0, Cow::Borrowed(&self.groups[..]), space) + } + + /// All groups the user is a part of, including inherited groups and implcit (todo) ones + pub fn all_groups<'a, 'u>(&'a self, space: &'u Userspace) -> AllGroups<'u> + where 'a: 'u + { + AllGroups(self.groups_explicit(space).map(|group| (Some(group), group.inherits_from(space))).rev().collect()) + } +} + +impl<'u> Groups<'u> +{ + /// The group IDs remaining in this iterator. + pub fn ids(&self) -> &[GroupID] + { + &self.1[self.0..] + } + /// The userspace for this iterator. + pub fn space(&self) -> &Userspace + { + &self.2 + } + /// Copy as a reference with a lower lifetime. + pub fn copied<'a>(&'a self) -> Groups<'a> + { + Groups(self.0, Cow::Borrowed(&self.1[..]), self.2) + } +} +impl<'u> Iterator for Groups<'u> +{ + type Item = &'u Group; + fn next(&mut self) -> Option + { + (if self.0>=self.1.len() { + None + } else { + Some(self.2.groups.get(&self.1[self.0]).expect("Groups contained invalid group ID for its userspace")) + }, self.0+=1).0 + } + #[inline] fn nth(&mut self, n: usize) -> Option + { + if (..self.len()).contains(&n) { + Some(self.2.groups.get(&self.1[n]).expect("Groups contained invalid group ID for its userspace")) + } else { + None + } + } + fn size_hint(&self) -> (usize, Option) { + let v = self.1.len() - self.0; + (v, Some(v)) + } +} + +impl<'u> iter::DoubleEndedIterator for Groups<'u> +{ + fn next_back(&mut self) -> Option + { + if self.0 == 0 { + None + } else { + self.0-=1; + debug_assert!(self.0 iter::ExactSizeIterator for Groups<'u>{} +impl<'u> iter::FusedIterator for Groups<'u>{} + +impl<'u> Iterator for AllGroups<'u> +{ + type Item = &'u Group; + fn next(&mut self) -> Option + { + match self.0.last_mut() + { + Some((mut v @ Some(_), _)) => v.take(), + Some((None, iter)) => { + if let Some(igroup) = iter.next() { + Some(igroup) + } else { + self.0.pop(); + self.next() + } + }, + _ => None + } + } + + fn size_hint(&self) -> (usize, Option) { + (self.0.iter().map(|(g, i)| (g.is_some() as usize) + i.size_hint().0).sum(), None) + } +} +impl<'u> iter::FusedIterator for AllGroups<'u>{} diff --git a/src/util.rs b/src/util.rs index c72c54b..c8ed1b4 100644 --- a/src/util.rs +++ b/src/util.rs @@ -12,3 +12,9 @@ pub fn jitter(min: T, max: T) -> T thread.sample(dist) } +/// Compare pointer identity +#[inline(always)] pub fn ptr_eq(ptr: &T, other: &T) -> bool +{ + ptr as *const T as usize == + other as *const T as usize +}