aster_forge_cloud_files_core/
local_content.rs

1//! Immutable local-content snapshots used by dirty tracking and upload recovery.
2
3use std::{fmt, num::NonZeroU64};
4
5use crate::{CloudFilesCoreError, CloudItemKey, ContentDigest, Result};
6
7/// Opaque product-neutral reference to immutable local bytes.
8#[derive(Clone, PartialEq, Eq, Hash)]
9pub struct LocalContentReference(String);
10
11impl LocalContentReference {
12    /// Creates a non-empty local-content reference and preserves it exactly.
13    /// # Errors
14    ///
15    /// Returns an error when validation fails or an underlying backend, store, or platform
16    /// operation fails.
17    pub fn new(value: impl Into<String>) -> Result<Self> {
18        let value = value.into();
19        if value.is_empty() {
20            return Err(CloudFilesCoreError::empty("local content reference"));
21        }
22        Ok(Self(value))
23    }
24
25    /// Returns the opaque reference.
26    #[must_use]
27    pub fn as_str(&self) -> &str {
28        &self.0
29    }
30
31    /// Consumes the wrapper and returns the opaque reference.
32    #[must_use]
33    pub fn into_string(self) -> String {
34        self.0
35    }
36}
37
38impl fmt::Debug for LocalContentReference {
39    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
40        formatter
41            .debug_struct("LocalContentReference")
42            .field("byte_len", &self.0.len())
43            .finish()
44    }
45}
46
47/// Monotonic item-local generation of an immutable local-content snapshot.
48#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
49pub struct LocalContentGeneration(NonZeroU64);
50
51impl LocalContentGeneration {
52    /// Creates a non-zero local generation.
53    /// # Errors
54    ///
55    /// Returns an error when validation fails or an underlying backend, store, or platform
56    /// operation fails.
57    pub const fn new(value: u64) -> Result<Self> {
58        match NonZeroU64::new(value) {
59            Some(value) => Ok(Self(value)),
60            None => Err(CloudFilesCoreError::InvalidLocalContentGeneration),
61        }
62    }
63
64    /// Returns the numeric generation fence value.
65    #[must_use]
66    pub const fn get(self) -> u64 {
67        self.0.get()
68    }
69}
70
71/// Immutable local bytes captured for dirty tracking and upload.
72#[derive(Debug, Clone, PartialEq, Eq)]
73pub struct LocalContentSnapshot {
74    item_key: CloudItemKey,
75    generation: LocalContentGeneration,
76    reference: LocalContentReference,
77    size: u64,
78    digest: Option<ContentDigest>,
79}
80
81impl LocalContentSnapshot {
82    /// Creates a snapshot. The referenced bytes must remain immutable for this generation.
83    #[must_use]
84    pub const fn new(
85        item_key: CloudItemKey,
86        generation: LocalContentGeneration,
87        reference: LocalContentReference,
88        size: u64,
89        digest: Option<ContentDigest>,
90    ) -> Self {
91        Self {
92            item_key,
93            generation,
94            reference,
95            size,
96            digest,
97        }
98    }
99
100    /// Returns the stable item identity whose local bytes were captured.
101    #[must_use]
102    pub const fn item_key(&self) -> &CloudItemKey {
103        &self.item_key
104    }
105
106    /// Returns the item-local generation used to fence stale upload completion.
107    #[must_use]
108    pub const fn generation(&self) -> LocalContentGeneration {
109        self.generation
110    }
111
112    /// Returns the opaque reference used by the platform/host content reader.
113    #[must_use]
114    pub const fn reference(&self) -> &LocalContentReference {
115        &self.reference
116    }
117
118    /// Returns the immutable byte length.
119    #[must_use]
120    pub const fn size(&self) -> u64 {
121        self.size
122    }
123
124    /// Returns the optional real integrity digest.
125    #[must_use]
126    pub const fn digest(&self) -> Option<&ContentDigest> {
127        self.digest.as_ref()
128    }
129}