a3s_code_core/capability/
lease.rs1use std::marker::PhantomData;
2
3use tokio_util::sync::CancellationToken;
4
5use super::scope::ScopeInner;
6use super::{
7 CapabilityCeiling, CapabilityDescriptor, CapabilityId, CapabilityScopeError, CapabilityScopeId,
8 CapabilityScopeKind, CodeCatalogGeneration, ScopeKind, Sha256Digest, UseCapabilityGeneration,
9};
10
11pub trait RetainedUseGeneration: Send + Sync + 'static {
18 fn use_generation(&self) -> &UseCapabilityGeneration;
19}
20
21impl<T> RetainedUseGeneration for Box<T>
22where
23 T: RetainedUseGeneration + ?Sized,
24{
25 fn use_generation(&self) -> &UseCapabilityGeneration {
26 self.as_ref().use_generation()
27 }
28}
29
30#[must_use = "a capability lease borrows and pins one active scope"]
54pub struct CapabilityLease<'scope, K: ScopeKind> {
55 inner: &'scope ScopeInner,
56 _kind: PhantomData<K>,
57}
58
59impl<'scope, K: ScopeKind> CapabilityLease<'scope, K> {
60 pub(super) fn new(inner: &'scope ScopeInner) -> Self {
61 Self {
62 inner,
63 _kind: PhantomData,
64 }
65 }
66
67 pub fn scope_id(&self) -> &CapabilityScopeId {
68 self.inner.id()
69 }
70
71 pub const fn kind(&self) -> CapabilityScopeKind {
72 K::KIND
73 }
74
75 pub fn parent_id(&self) -> Option<&CapabilityScopeId> {
76 self.inner.parent_id()
77 }
78
79 pub fn catalog_generation(&self) -> CodeCatalogGeneration {
80 self.inner.set().generation()
81 }
82
83 pub fn catalog_digest(&self) -> &Sha256Digest {
84 self.inner.set().digest()
85 }
86
87 pub fn use_generation(&self) -> Option<&UseCapabilityGeneration> {
88 self.inner.use_generation()
89 }
90
91 pub fn ceiling(&self) -> &CapabilityCeiling {
92 self.inner.ceiling()
93 }
94
95 pub fn cancellation(&self) -> CancellationToken {
96 self.inner.supervisor_cancellation()
97 }
98
99 pub fn get(
100 &self,
101 id: &CapabilityId,
102 ) -> Result<Option<&'scope CapabilityDescriptor>, CapabilityScopeError> {
103 self.inner.ensure_active()?;
104 if !self.inner.ceiling().allows(id) {
105 return Ok(None);
106 }
107 Ok(self.inner.set().get(id))
108 }
109
110 pub fn contains(&self, id: &CapabilityId) -> Result<bool, CapabilityScopeError> {
111 self.get(id).map(|descriptor| descriptor.is_some())
112 }
113
114 pub fn iter(
115 &self,
116 ) -> Result<
117 impl Iterator<Item = (&'scope CapabilityId, &'scope CapabilityDescriptor)> + 'scope,
118 CapabilityScopeError,
119 > {
120 self.inner.ensure_active()?;
121 let ceiling = self.inner.ceiling();
122 Ok(self
123 .inner
124 .set()
125 .iter()
126 .filter(move |(id, _)| ceiling.allows(id)))
127 }
128}
129
130impl<K: ScopeKind> std::fmt::Debug for CapabilityLease<'_, K> {
131 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132 formatter
133 .debug_struct("CapabilityLease")
134 .field("scope_id", &self.scope_id())
135 .field("kind", &K::KIND)
136 .field("catalog_digest", &self.catalog_digest())
137 .finish()
138 }
139}