Skip to main content

active_uuid_registry/
raii.rs

1//! RAII capability handle for owned namespaces.
2
3use std::sync::atomic::{AtomicBool, Ordering};
4use std::sync::Arc;
5
6use uuid::Uuid;
7
8use crate::registry::{self, OwnedNamespaceSignature, WriteAccess};
9use crate::{ContextString, NamespaceString, UuidPoolError};
10
11struct OwnedNamespaceInner {
12    namespace: parking_lot::Mutex<NamespaceString>,
13    signature: OwnedNamespaceSignature,
14    /// Set once this handle group has explicitly released its namespace via
15    /// [`OwnedNamespace::remove`], so all clones immediately stop writing instead of
16    /// silently re-creating the namespace as unowned through auto-create-on-write.
17    invalidated: AtomicBool,
18}
19
20impl Drop for OwnedNamespaceInner {
21    fn drop(&mut self) {
22        // If ownership was already released explicitly, there is nothing left to clean up.
23        if self.invalidated.load(Ordering::Acquire) {
24            return;
25        }
26        let namespace = self.namespace.get_mut().clone();
27        // Best-effort: only removes data/ownership if the stored signature still matches
28        // ours, so a stale handle can never delete a namespace re-claimed by another owner.
29        let _ = registry::release_owned_namespace(&namespace, &self.signature);
30    }
31}
32
33/// A cloneable, opaque write-authorization capability for a namespace claimed via
34/// [`crate::interface::reserve_owned_namespace`].
35///
36/// All clones of an `OwnedNamespace` share the same underlying authorization and namespace
37/// data: any clone can write to the namespace, and renaming updates the name observed by
38/// every clone. The namespace, its data, and its ownership record are removed automatically
39/// once the last clone is dropped, or immediately via [`OwnedNamespace::remove`].
40///
41/// Free functions in [`crate::interface`] cannot write to a namespace owned by an
42/// `OwnedNamespace` handle; they return [`UuidPoolError::UnauthorizedNamespaceWriteAccessError`]
43/// instead. Only the handle's own methods (and clones of it) are authorized.
44pub struct OwnedNamespace {
45    inner: Arc<OwnedNamespaceInner>,
46}
47
48impl Clone for OwnedNamespace {
49    fn clone(&self) -> Self {
50        Self { inner: self.inner.clone() }
51    }
52}
53
54impl OwnedNamespace {
55    pub(crate) fn new(namespace: NamespaceString, signature: OwnedNamespaceSignature) -> Self {
56        Self {
57            inner: Arc::new(OwnedNamespaceInner {
58                namespace: parking_lot::Mutex::new(namespace),
59                signature,
60                invalidated: AtomicBool::new(false),
61            }),
62        }
63    }
64
65    fn access(&self) -> WriteAccess<'_> {
66        WriteAccess::owned(&self.inner.signature)
67    }
68
69    fn current_namespace(&self) -> NamespaceString {
70        self.inner.namespace.lock().clone()
71    }
72
73    fn ensure_active(&self) -> Result<(), UuidPoolError> {
74        if self.inner.invalidated.load(Ordering::Acquire) {
75            return Err(UuidPoolError::UnauthorizedNamespaceWriteAccessError(format!(
76                "Namespace '{}' ownership has already been released",
77                self.current_namespace()
78            )));
79        }
80        Ok(())
81    }
82
83    /// Returns the namespace name currently owned by this handle.
84    pub fn namespace(&self) -> NamespaceString {
85        self.current_namespace()
86    }
87
88    /// Reserves a new UUID in this namespace using [`crate::interface::DEFAULT_UUID_BASE`]
89    /// and [`crate::interface::DEFAULT_MAX_RETRIES`].
90    pub fn reserve_id(&self, context: &str) -> Result<Uuid, UuidPoolError> {
91        self.reserve_id_with(context, crate::interface::DEFAULT_UUID_BASE, crate::interface::DEFAULT_MAX_RETRIES)
92    }
93
94    /// Reserves a new UUID in this namespace with a custom base.
95    pub fn reserve_id_with_base(&self, context: &str, base: u32) -> Result<Uuid, UuidPoolError> {
96        self.reserve_id_with(context, base, crate::interface::DEFAULT_MAX_RETRIES)
97    }
98
99    /// Reserves a new UUID in this namespace with a custom base and retry count.
100    pub fn reserve_id_with(&self, context: &str, base: u32, max_retries: usize) -> Result<Uuid, UuidPoolError> {
101        self.ensure_active()?;
102        registry::random_uuid(&self.current_namespace(), context, base, max_retries, 0, self.access())
103    }
104
105    /// Adds an existing UUID to this namespace and context space.
106    pub fn add_id(&self, context: &str, uuid: Uuid) -> Result<(), UuidPoolError> {
107        self.ensure_active()?;
108        registry::add_uuid_to_pool(&self.current_namespace(), context, &uuid, self.access())
109    }
110
111    /// Removes an existing UUID from this namespace and context space.
112    pub fn remove_id(&self, context: &str, uuid: Uuid) -> Result<(), UuidPoolError> {
113        self.ensure_active()?;
114        registry::remove_uuid_from_pool(&self.current_namespace(), context, &uuid, self.access())
115    }
116
117    /// Replaces an existing UUID with a new UUID within a context.
118    pub fn replace_id(&self, context: &str, old_uuid: Uuid, new_uuid: Uuid) -> Result<(), UuidPoolError> {
119        self.ensure_active()?;
120        registry::replace_uuid_in_pool(&self.current_namespace(), context, &old_uuid, &new_uuid, self.access())
121    }
122
123    /// Clears the given context and all associated UUIDs.
124    pub fn clear_context(&self, context: &str) -> Result<(), UuidPoolError> {
125        self.ensure_active()?;
126        registry::clear_context(&self.current_namespace(), context, self.access())
127    }
128
129    /// Clears all contexts (and their UUIDs) within this namespace, retaining the namespace itself.
130    pub fn clear_all_contexts(&self) -> Result<(), UuidPoolError> {
131        self.ensure_active()?;
132        registry::clear_all_contexts(&self.current_namespace(), self.access())
133    }
134
135    /// Removes and returns all UUIDs from the given context.
136    pub fn drain_context(&self, context: &str) -> Result<Vec<(ContextString, Uuid)>, UuidPoolError> {
137        self.ensure_active()?;
138        registry::drain_context(&self.current_namespace(), context, self.access())
139    }
140
141    /// Removes and returns all contexts (and their UUIDs) within this namespace.
142    pub fn drain_all_contexts(&self) -> Result<Vec<(NamespaceString, ContextString, Uuid)>, UuidPoolError> {
143        self.ensure_active()?;
144        registry::drain_all_contexts(&self.current_namespace(), self.access())
145    }
146
147    /// Renames this namespace. The new name must be absent or empty, and not owned by
148    /// another handle. The new name is observed by every clone of this handle.
149    pub fn rename(&self, new_namespace: &str) -> Result<(), UuidPoolError> {
150        self.ensure_active()?;
151        let mut guard = self.inner.namespace.lock();
152        registry::replace_namespace(&guard, new_namespace, self.access())?;
153        *guard = new_namespace.to_string();
154        Ok(())
155    }
156
157    /// Explicitly removes this namespace, its data, and its ownership record.
158    ///
159    /// Immediately invalidates every clone of this handle: subsequent calls on any clone
160    /// return [`UuidPoolError::UnauthorizedNamespaceWriteAccessError`] instead of silently
161    /// re-creating the namespace as unowned.
162    pub fn remove(self) -> Result<(), UuidPoolError> {
163        self.ensure_active()?;
164        let namespace = self.current_namespace();
165        registry::release_owned_namespace(&namespace, &self.inner.signature)?;
166        self.inner.invalidated.store(true, Ordering::Release);
167        Ok(())
168    }
169}