diff options
Diffstat (limited to 'rola-bucket/src')
| -rw-r--r-- | rola-bucket/src/bucket.rs | 135 | ||||
| -rw-r--r-- | rola-bucket/src/bucket/init.rs | 1 | ||||
| -rw-r--r-- | rola-bucket/src/bucket/space.rs | 22 | ||||
| -rw-r--r-- | rola-bucket/src/lib.rs | 3 |
4 files changed, 161 insertions, 0 deletions
diff --git a/rola-bucket/src/bucket.rs b/rola-bucket/src/bucket.rs index e69de29..b70afd8 100644 --- a/rola-bucket/src/bucket.rs +++ b/rola-bucket/src/bucket.rs @@ -0,0 +1,135 @@ +use crate::AsyncBucketTransferProtocol; + +#[cfg(test)] +use crate::LocalFileSystemProtocol; +use space_system::SpaceRootTest; + +mod init; +// pub use init::*; + +mod space; + +/// Represents the state of a bucket in the transfer protocol. +/// +/// # Variants +/// +/// * `Uninit` - The bucket has not been initialized. This is the default state. +/// **Warning:** Most mutation methods (e.g., `set_extra_info`, `remove_extra_info`) will **panic** +/// when called on an `Uninit` bucket. Always ensure the bucket is in a `Local` or `Remote` state +/// before attempting to modify its `extra_info`. +/// +/// * `Local` - The bucket is on the local side of the transfer, with optional extra information. +/// +/// * `Remote` - The bucket is on the remote side of the transfer, with optional extra information. +#[derive(Default, Clone, SpaceRootTest)] +#[space_root_test_generic(LocalFileSystemProtocol)] +pub enum Bucket<Protocol> +where + Protocol: AsyncBucketTransferProtocol + Send + Sync, +{ + #[default] + Uninit, + + Local { + extra_info: Option<Protocol::ExtraInfo>, + }, + Remote { + extra_info: Option<Protocol::ExtraInfo>, + }, +} + +impl<Protocol: AsyncBucketTransferProtocol + Send + Sync> Bucket<Protocol> { + /// Creates a new `Bucket::Local` + pub fn new_local() -> Self { + Self::Local { extra_info: None } + } + + /// Creates a new `Bucket::Local` with extra information. + pub fn local_with_extra_info(extra_info: Protocol::ExtraInfo) -> Self { + Self::Local { + extra_info: Some(extra_info), + } + } + + /// Creates a new `Bucket::Remote` + pub fn new_remote() -> Self { + Self::Remote { extra_info: None } + } + + /// Creates a new `Bucket::Remote` with extra information. + pub fn remote_with_extra_info(extra_info: Protocol::ExtraInfo) -> Self { + Self::Remote { + extra_info: Some(extra_info), + } + } + + /// Returns a mutable reference to the extra_info field regardless of variant. + fn extra_info_mut(&mut self) -> &mut Option<Protocol::ExtraInfo> { + match self { + Self::Local { extra_info } | Self::Remote { extra_info } => extra_info, + Self::Uninit => panic!("Cannot access extra_info on an Uninit bucket"), + } + } + + /// Sets extra info on an existing bucket, returning the previous value if any. + pub fn set_extra_info( + &mut self, + extra_info: Protocol::ExtraInfo, + ) -> Option<Protocol::ExtraInfo> { + self.extra_info_mut().replace(extra_info) + } + + /// Removes extra info from the bucket, returning it if present. + pub fn remove_extra_info(&mut self) -> Option<Protocol::ExtraInfo> { + self.extra_info_mut().take() + } + + /// Checks if the bucket has extra information. + pub fn has_extra_info(&self) -> bool { + match self { + Self::Local { extra_info } | Self::Remote { extra_info } => extra_info.is_some(), + Self::Uninit => false, + } + } + + /// Gets a reference to the extra info, if present. + pub fn extra_info(&self) -> Option<&Protocol::ExtraInfo> { + match self { + Self::Local { extra_info } | Self::Remote { extra_info } => extra_info.as_ref(), + Self::Uninit => None, + } + } + + /// Returns true if this is a local bucket. + pub fn is_local(&self) -> bool { + matches!(self, Self::Local { .. }) + } + + /// Returns true if this is a remote bucket. + pub fn is_remote(&self) -> bool { + matches!(self, Self::Remote { .. }) + } + + /// Returns true if this bucket is uninitialized. + pub fn is_uninit(&self) -> bool { + matches!(self, Self::Uninit) + } + + /// Converts the bucket to a Remote variant, keeping extra_info if present. + pub fn force_to_remote(self) -> Self { + let extra_info = match self { + Self::Local { extra_info } | Self::Remote { extra_info } => extra_info, + Self::Uninit => None, + }; + Self::Remote { extra_info } + } + + /// Converts the bucket to a Local variant, keeping extra_info if present. + pub fn force_to_local(self) -> Self { + let extra_info = match self { + Self::Local { extra_info } | Self::Remote { extra_info } => extra_info, + Self::Uninit => None, + }; + Self::Local { extra_info } + } +} diff --git a/rola-bucket/src/bucket/init.rs b/rola-bucket/src/bucket/init.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/rola-bucket/src/bucket/init.rs @@ -0,0 +1 @@ + diff --git a/rola-bucket/src/bucket/space.rs b/rola-bucket/src/bucket/space.rs new file mode 100644 index 0000000..9559b1d --- /dev/null +++ b/rola-bucket/src/bucket/space.rs @@ -0,0 +1,22 @@ +use shared_constants::common::DRAFT_META_DIR; +use space_system::{SpaceError, SpaceRoot, SpaceRootFindPattern}; +use tokio::fs::create_dir_all; + +use crate::{AsyncBucketTransferProtocol, Bucket}; + +impl<Protocol: AsyncBucketTransferProtocol + Send + Sync> SpaceRoot for Bucket<Protocol> { + fn get_pattern() -> SpaceRootFindPattern { + SpaceRootFindPattern::IncludeDotDir(DRAFT_META_DIR.into()) + } + + async fn create_space(path: &std::path::Path) -> Result<(), space_system::SpaceError> { + let draft_meta_dir = path.join(DRAFT_META_DIR); + + // Create workspace directory + create_dir_all(&draft_meta_dir) + .await + .map_err(SpaceError::from)?; + + Ok(()) + } +} diff --git a/rola-bucket/src/lib.rs b/rola-bucket/src/lib.rs index c45452c..1f3470f 100644 --- a/rola-bucket/src/lib.rs +++ b/rola-bucket/src/lib.rs @@ -12,5 +12,8 @@ //! //! This module does **not** implement any **specific transport method**; it only implements the workflow for file storage and retrieval. +mod bucket; +pub use bucket::*; + mod protocol; pub use protocol::*; |
