#![expect(missing_docs)]
use std::cmp::Ordering;
use std::fmt::Debug;
use std::fmt::Error;
use std::fmt::Formatter;
use std::hash::Hash;
use std::hash::Hasher;
use std::iter;
use std::sync::Arc;
use futures::future::try_join_all;
use crate::backend::CommitId;
use crate::op_store;
use crate::op_store::OpStore;
use crate::op_store::OpStoreResult;
use crate::op_store::OperationId;
use crate::op_store::OperationMetadata;
use crate::op_store::ViewId;
use crate::view::View;
#[derive(Clone, serde::Serialize)]
pub struct Operation {
#[serde(skip)]
op_store: Arc<dyn OpStore>,
id: OperationId,
#[serde(flatten)]
data: Arc<op_store::Operation>, }
impl Debug for Operation {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
f.debug_struct("Operation").field("id", &self.id).finish()
}
}
impl PartialEq for Operation {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl Eq for Operation {}
impl Ord for Operation {
fn cmp(&self, other: &Self) -> Ordering {
self.id.cmp(&other.id)
}
}
impl PartialOrd for Operation {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Hash for Operation {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}
impl Operation {
pub fn new(
op_store: Arc<dyn OpStore>,
id: OperationId,
data: impl Into<Arc<op_store::Operation>>,
) -> Self {
Self {
op_store,
id,
data: data.into(),
}
}
pub fn op_store(&self) -> Arc<dyn OpStore> {
self.op_store.clone()
}
pub fn id(&self) -> &OperationId {
&self.id
}
pub fn view_id(&self) -> &ViewId {
&self.data.view_id
}
pub fn parent_ids(&self) -> &[OperationId] {
&self.data.parents
}
pub async fn parents(&self) -> OpStoreResult<Vec<Self>> {
try_join_all(self.data.parents.iter().map(async |parent_id| {
let data = self.op_store.read_operation(parent_id).await?;
Ok(Self::new(self.op_store.clone(), parent_id.clone(), data))
}))
.await
}
pub async fn view(&self) -> OpStoreResult<View> {
let data = self.op_store.read_view(&self.data.view_id).await?;
Ok(View::new(data))
}
pub fn metadata(&self) -> &OperationMetadata {
&self.data.metadata
}
pub fn stores_commit_predecessors(&self) -> bool {
self.data.commit_predecessors.is_some()
}
pub fn predecessors_for_commit(&self, commit_id: &CommitId) -> Option<&[CommitId]> {
let map = self.data.commit_predecessors.as_ref()?;
Some(map.get(commit_id)?)
}
pub fn all_referenced_commit_ids(&self) -> impl Iterator<Item = &CommitId> {
self.data.commit_predecessors.iter().flat_map(|map| {
map.iter()
.flat_map(|(new_id, old_ids)| iter::once(new_id).chain(old_ids))
})
}
pub fn store_operation(&self) -> &op_store::Operation {
&self.data
}
}