use content_addressable::{ContentAddressable, ContentError, ContentId, RawContentId};
use serde::{Deserialize, Serialize};
use crate::op::Op;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Span {
pub start: u64,
pub end: u64,
}
impl Span {
#[must_use]
pub const fn new(start: u64, end: u64) -> Self {
Self { start, end }
}
#[must_use]
pub const fn len(&self) -> u64 {
self.end.saturating_sub(self.start)
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.end <= self.start
}
#[must_use]
pub fn slice<'a>(&self, source: &'a [u8]) -> Option<&'a [u8]> {
let start = usize::try_from(self.start).ok()?;
let end = usize::try_from(self.end).ok()?;
if end < start || end > source.len() {
return None;
}
source.get(start..end)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Derivation {
pub op: Op,
pub source: RawContentId,
pub span: Span,
pub elided: RawContentId,
pub root: ContentId,
}
impl Derivation {
#[must_use]
pub fn over(op: Op, source: &[u8], span: Span, root: ContentId) -> Option<Self> {
let addressed = span.slice(source)?;
Some(Self {
op,
source: RawContentId::from_content(source),
span,
elided: RawContentId::from_content(addressed),
root,
})
}
pub fn id(&self) -> Result<ContentId, ContentError> {
self.content_id()
}
}
impl ContentAddressable for Derivation {
fn canonical_form(&self) -> Result<Vec<u8>, ContentError> {
content_addressable::canonical::to_canonical_dagcbor(self)
}
}