use std::marker::PhantomData;
use tokio_util::sync::CancellationToken;
use super::scope::ScopeInner;
use super::{
CapabilityCeiling, CapabilityDescriptor, CapabilityId, CapabilityScopeError, CapabilityScopeId,
CapabilityScopeKind, CodeCatalogGeneration, ScopeKind, Sha256Digest, UseCapabilityGeneration,
};
pub trait RetainedUseGeneration: Send + Sync + 'static {
fn use_generation(&self) -> &UseCapabilityGeneration;
}
impl<T> RetainedUseGeneration for Box<T>
where
T: RetainedUseGeneration + ?Sized,
{
fn use_generation(&self) -> &UseCapabilityGeneration {
self.as_ref().use_generation()
}
}
#[must_use = "a capability lease borrows and pins one active scope"]
pub struct CapabilityLease<'scope, K: ScopeKind> {
inner: &'scope ScopeInner,
_kind: PhantomData<K>,
}
impl<'scope, K: ScopeKind> CapabilityLease<'scope, K> {
pub(super) fn new(inner: &'scope ScopeInner) -> Self {
Self {
inner,
_kind: PhantomData,
}
}
pub fn scope_id(&self) -> &CapabilityScopeId {
self.inner.id()
}
pub const fn kind(&self) -> CapabilityScopeKind {
K::KIND
}
pub fn parent_id(&self) -> Option<&CapabilityScopeId> {
self.inner.parent_id()
}
pub fn catalog_generation(&self) -> CodeCatalogGeneration {
self.inner.set().generation()
}
pub fn catalog_digest(&self) -> &Sha256Digest {
self.inner.set().digest()
}
pub fn use_generation(&self) -> Option<&UseCapabilityGeneration> {
self.inner.use_generation()
}
pub fn ceiling(&self) -> &CapabilityCeiling {
self.inner.ceiling()
}
pub fn cancellation(&self) -> CancellationToken {
self.inner.supervisor_cancellation()
}
pub fn get(
&self,
id: &CapabilityId,
) -> Result<Option<&'scope CapabilityDescriptor>, CapabilityScopeError> {
self.inner.ensure_active()?;
if !self.inner.ceiling().allows(id) {
return Ok(None);
}
Ok(self.inner.set().get(id))
}
pub fn contains(&self, id: &CapabilityId) -> Result<bool, CapabilityScopeError> {
self.get(id).map(|descriptor| descriptor.is_some())
}
pub fn iter(
&self,
) -> Result<
impl Iterator<Item = (&'scope CapabilityId, &'scope CapabilityDescriptor)> + 'scope,
CapabilityScopeError,
> {
self.inner.ensure_active()?;
let ceiling = self.inner.ceiling();
Ok(self
.inner
.set()
.iter()
.filter(move |(id, _)| ceiling.allows(id)))
}
}
impl<K: ScopeKind> std::fmt::Debug for CapabilityLease<'_, K> {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter
.debug_struct("CapabilityLease")
.field("scope_id", &self.scope_id())
.field("kind", &K::KIND)
.field("catalog_digest", &self.catalog_digest())
.finish()
}
}