use crate::{blob::BlobLocation, repofile::RusticTime};
use std::{cmp::Ordering, num::NonZeroU32};
use jiff::Timestamp;
use serde_derive::{Deserialize, Serialize};
use serde_with::{serde_as, skip_serializing_none};
use crate::{
backend::FileType,
blob::{BlobId, BlobType},
impl_repoid,
repofile::{RepoFile, packfile::PackHeaderRef},
};
use super::packfile::PackId;
impl_repoid!(IndexId, FileType::Index);
#[skip_serializing_none]
#[derive(Serialize, Deserialize, Debug, Default)]
pub struct IndexFile {
pub supersedes: Option<Vec<IndexId>>,
pub packs: Vec<IndexPack>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub packs_to_delete: Vec<IndexPack>,
}
impl RepoFile for IndexFile {
const TYPE: FileType = FileType::Index;
type Id = IndexId;
}
impl IndexFile {
pub(crate) fn add(&mut self, p: IndexPack, delete: bool) {
if delete {
self.packs_to_delete.push(p);
} else {
self.packs.push(p);
}
}
pub(crate) fn all_packs(self) -> impl Iterator<Item = (IndexPack, bool)> {
self.packs
.into_iter()
.map(|pack| (pack, false))
.chain(self.packs_to_delete.into_iter().map(|pack| (pack, true)))
}
}
#[serde_as]
#[skip_serializing_none]
#[derive(Serialize, Deserialize, Default, Debug, Clone)]
pub struct IndexPack {
pub id: PackId,
pub blobs: Vec<IndexBlob>,
#[serde_as(as = "Option<RusticTime>")]
pub time: Option<Timestamp>,
pub size: Option<u32>,
}
impl IndexPack {
pub(crate) fn add(
&mut self,
id: BlobId,
tpe: BlobType,
offset: u32,
length: u32,
uncompressed_length: Option<NonZeroU32>,
) {
self.blobs.push(IndexBlob {
id,
tpe,
location: BlobLocation {
offset,
length,
uncompressed_length,
},
});
}
#[must_use]
pub fn pack_size(&self) -> u32 {
self.size
.unwrap_or_else(|| PackHeaderRef::from_index_pack(self).pack_size())
}
#[must_use]
pub fn blob_type(&self) -> BlobType {
if self.blobs.is_empty() {
BlobType::Data
} else {
self.blobs[0].tpe
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Copy)]
pub struct IndexBlob {
pub id: BlobId,
#[serde(rename = "type")]
pub tpe: BlobType,
#[serde(flatten)]
pub location: BlobLocation,
}
impl PartialOrd<Self> for IndexBlob {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for IndexBlob {
fn cmp(&self, other: &Self) -> Ordering {
self.location.cmp(&other.location)
}
}