use super::{
Arc, ContentUpload, Error, Result, SealedContent, UPLOAD_ID_TOMBSTONE_LEN,
UPLOAD_ID_TOMBSTONE_MAGIC, UploadId, array_at,
};
#[derive(Debug)]
pub enum ContentUploadResume {
Open(ContentUpload),
Sealed(SealedContent),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum UploadIdRetirement {
Aborted,
Sealed,
}
pub(crate) fn encode_upload_id_tombstone(
upload_id: UploadId,
retirement: UploadIdRetirement,
) -> Arc<[u8]> {
let mut bytes = Vec::with_capacity(UPLOAD_ID_TOMBSTONE_LEN);
bytes.extend_from_slice(UPLOAD_ID_TOMBSTONE_MAGIC);
bytes.push(match retirement {
UploadIdRetirement::Aborted => 0,
UploadIdRetirement::Sealed => 1,
});
bytes.extend_from_slice(&upload_id.to_bytes());
debug_assert_eq!(bytes.len(), UPLOAD_ID_TOMBSTONE_LEN);
Arc::from(bytes)
}
pub(crate) fn decode_upload_id_tombstone(
bytes: &[u8],
expected: UploadId,
) -> Result<Option<UploadIdRetirement>> {
if bytes.get(..8) != Some(UPLOAD_ID_TOMBSTONE_MAGIC) {
return Ok(None);
}
if bytes.len() != UPLOAD_ID_TOMBSTONE_LEN {
return Err(Error::InvalidFormat {
message: "invalid retired upload-id marker length".to_owned(),
});
}
let retirement = match bytes[8] {
0 => UploadIdRetirement::Aborted,
1 => UploadIdRetirement::Sealed,
_ => {
return Err(Error::InvalidFormat {
message: "invalid retired upload-id marker state".to_owned(),
});
}
};
let encoded = UploadId(array_at::<16>(bytes, 9, "retired upload identity")?);
if encoded != expected {
return Err(Error::InvalidFormat {
message: "retired upload-id marker identity mismatch".to_owned(),
});
}
Ok(Some(retirement))
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ContentUploadState {
Open,
Sealing,
Sealed,
Aborting,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ContentUploadInfo {
pub(in crate::content::upload) upload_id: UploadId,
pub(in crate::content::upload) state: ContentUploadState,
pub(in crate::content::upload) updated_at_unix_ms: u64,
pub(in crate::content::upload) length: u64,
}
impl ContentUploadInfo {
#[must_use]
pub const fn upload_id(self) -> UploadId {
self.upload_id
}
#[must_use]
pub const fn state(self) -> ContentUploadState {
self.state
}
#[must_use]
pub const fn updated_at_unix_ms(self) -> u64 {
self.updated_at_unix_ms
}
#[must_use]
pub const fn len(self) -> u64 {
self.length
}
#[must_use]
pub const fn is_empty(self) -> bool {
self.length == 0
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct ContentUploadMaintenanceReport {
pub(crate) scanned: u64,
pub(crate) aborted: u64,
pub(crate) pruned_sealed: u64,
}
impl ContentUploadMaintenanceReport {
#[must_use]
pub const fn scanned(self) -> u64 {
self.scanned
}
#[must_use]
pub const fn aborted(self) -> u64 {
self.aborted
}
#[must_use]
pub const fn pruned_sealed(self) -> u64 {
self.pruned_sealed
}
}
impl ContentUploadResume {
#[must_use]
pub fn into_open(self) -> Option<ContentUpload> {
match self {
Self::Open(upload) => Some(upload),
Self::Sealed(_) => None,
}
}
#[must_use]
pub const fn sealed(&self) -> Option<SealedContent> {
match self {
Self::Open(_) => None,
Self::Sealed(sealed) => Some(*sealed),
}
}
}