1#![expect(missing_docs)]
16
17use std::cmp::Ordering;
18use std::fmt::Debug;
19use std::fmt::Error;
20use std::fmt::Formatter;
21use std::hash::Hash;
22use std::hash::Hasher;
23use std::iter;
24use std::sync::Arc;
25
26use pollster::FutureExt as _;
27
28use crate::backend::CommitId;
29use crate::op_store;
30use crate::op_store::OpStore;
31use crate::op_store::OpStoreResult;
32use crate::op_store::OperationId;
33use crate::op_store::OperationMetadata;
34use crate::op_store::ViewId;
35use crate::view::View;
36
37#[derive(Clone, serde::Serialize)]
40pub struct Operation {
41 #[serde(skip)]
42 op_store: Arc<dyn OpStore>,
43 id: OperationId,
44 #[serde(flatten)]
45 data: Arc<op_store::Operation>, }
47
48impl Debug for Operation {
49 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
50 f.debug_struct("Operation").field("id", &self.id).finish()
51 }
52}
53
54impl PartialEq for Operation {
55 fn eq(&self, other: &Self) -> bool {
56 self.id == other.id
57 }
58}
59
60impl Eq for Operation {}
61
62impl Ord for Operation {
63 fn cmp(&self, other: &Self) -> Ordering {
64 self.id.cmp(&other.id)
65 }
66}
67
68impl PartialOrd for Operation {
69 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
70 Some(self.cmp(other))
71 }
72}
73
74impl Hash for Operation {
75 fn hash<H: Hasher>(&self, state: &mut H) {
76 self.id.hash(state);
77 }
78}
79
80impl Operation {
81 pub fn new(
82 op_store: Arc<dyn OpStore>,
83 id: OperationId,
84 data: impl Into<Arc<op_store::Operation>>,
85 ) -> Self {
86 Self {
87 op_store,
88 id,
89 data: data.into(),
90 }
91 }
92
93 pub fn op_store(&self) -> Arc<dyn OpStore> {
94 self.op_store.clone()
95 }
96
97 pub fn id(&self) -> &OperationId {
98 &self.id
99 }
100
101 pub fn view_id(&self) -> &ViewId {
102 &self.data.view_id
103 }
104
105 pub fn parent_ids(&self) -> &[OperationId] {
106 &self.data.parents
107 }
108
109 pub fn parents(&self) -> impl ExactSizeIterator<Item = OpStoreResult<Self>> {
110 let op_store = &self.op_store;
111 self.data.parents.iter().map(|parent_id| {
112 let data = op_store.read_operation(parent_id).block_on()?;
113 Ok(Self::new(op_store.clone(), parent_id.clone(), data))
114 })
115 }
116
117 pub fn view(&self) -> OpStoreResult<View> {
118 let data = self.op_store.read_view(&self.data.view_id).block_on()?;
119 Ok(View::new(data))
120 }
121
122 pub fn metadata(&self) -> &OperationMetadata {
123 &self.data.metadata
124 }
125
126 pub fn stores_commit_predecessors(&self) -> bool {
130 self.data.commit_predecessors.is_some()
131 }
132
133 pub fn predecessors_for_commit(&self, commit_id: &CommitId) -> Option<&[CommitId]> {
135 let map = self.data.commit_predecessors.as_ref()?;
136 Some(map.get(commit_id)?)
137 }
138
139 pub fn all_referenced_commit_ids(&self) -> impl Iterator<Item = &CommitId> {
148 self.data.commit_predecessors.iter().flat_map(|map| {
149 map.iter()
150 .flat_map(|(new_id, old_ids)| iter::once(new_id).chain(old_ids))
151 })
152 }
153
154 pub fn store_operation(&self) -> &op_store::Operation {
155 &self.data
156 }
157}