use std::sync::atomic::Ordering::Relaxed;
use super::support::lock;
use crate::store::Shared;
pub(super) fn range_span(header: Option<&str>) -> Option<(usize, Option<usize>)> {
let value = header?;
let (unit, spec) = value.split_once('=')?;
if !unit.trim().eq_ignore_ascii_case("bytes") {
return None;
}
if spec.contains(',') {
return None;
}
let (start, end) = spec.split_once('-')?;
let start = start.trim().parse().ok()?;
let end = end.trim();
if end.is_empty() {
return Some((start, None));
}
let end = end.parse::<usize>().ok()?;
if end < start {
return None;
}
Some((start, Some(end)))
}
pub(super) fn is_version_path(path: &str) -> bool {
path.ends_with("/version.json")
}
pub(super) fn first_segment(path: &str) -> &str {
path.split('/').next().unwrap_or_default()
}
pub(super) fn drift_doc(version: &str) -> Vec<u8> {
format!("{{\"schema_version\":1,\"version\":\"{version}\",\"artifacts\":[\"ghost.zip\"]}}")
.into_bytes()
}
pub(super) fn zero_digest(marker: &[u8]) -> Vec<u8> {
let line_end = marker
.iter()
.position(|&b| b == b'\n')
.unwrap_or(marker.len());
let mut out = marker.to_vec();
if line_end >= 64 {
out[..64].fill(b'0');
}
out
}
pub(super) fn transform_put(shared: &Shared, path: &str, body: &[u8]) -> Option<Vec<u8>> {
if !path.ends_with(".sha256") {
return Some(body.to_vec());
}
if shared.spec.markerless {
return None;
}
if shared.spec.foreign_marker {
return Some(zero_digest(body));
}
Some(body.to_vec())
}
pub(super) fn drift_or_store(shared: &Shared, path: &str) -> Option<Vec<u8>> {
if shared.drift.load(Relaxed) && is_version_path(path) {
return Some(drift_doc(first_segment(path)));
}
lock(&shared.store).get(path).cloned()
}