Skip to main content

bytesandbrains_core/
op.rs

1use std::fmt;
2
3/// Identifies an in-flight operation.
4///
5/// `OpId` provides a unique identifier for asynchronous operations across the
6/// system. It is used to:
7/// - Track index operations (search, add, remove, train)
8/// - Correlate distributed search operations across the network
9/// - Enable progress tracking and cancellation
10///
11/// The ID is unique within the lifetime of the component that issued it and
12/// can be used to correlate log messages, metrics, or external tracking with
13/// a specific operation.
14#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Default)]
15pub struct OpId(pub u64);
16
17impl fmt::Display for OpId {
18    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19        write!(f, "OpId({})", self.0)
20    }
21}
22
23/// A handle to an in-flight operation.
24///
25/// `OpRef` provides a unified API for both local and networked implementations:
26///
27/// - **Local implementations** can complete the work eagerly inside the method
28///   that creates the handle, making [`is_finished`](OpRef::is_finished) return
29///   `true` immediately and [`finish`](OpRef::finish) simply unwrap the
30///   pre-computed result.
31///
32/// - **Networked implementations** can return a handle that tracks a remote RPC.
33///   The caller polls [`is_finished`](OpRef::is_finished) (or awaits a
34///   notification) and calls [`finish`](OpRef::finish) once the remote side has
35///   responded.
36///
37/// This design lets generic code work identically regardless of whether the
38/// underlying operation is in-process or across a network boundary.
39pub trait OpRef {
40    /// Metadata describing the operation (e.g. query parameters, batch size).
41    type Info;
42
43    /// Runtime statistics collected during the operation (e.g. distances
44    /// computed, nodes visited).
45    type Stats;
46
47    /// The successful outcome of the operation.
48    type Result;
49
50    /// The error type returned when the operation fails.
51    type Error;
52
53    /// Returns the unique identifier assigned to this operation.
54    /// Can represent some sort of ID for the entry in an eager operation
55    /// context is up to the implementation (for example a entry tag for a local
56    /// index)
57    fn id(&self) -> &OpId;
58
59    /// Returns metadata describing the operation.
60    ///
61    /// Returns `None` if the operation no longer exists (e.g., already finished
62    /// and removed from tracking).
63    fn info(&self) -> Option<Self::Info>;
64
65    /// Returns runtime statistics collected so far.
66    ///
67    /// Returns `None` if the operation no longer exists.
68    fn stats(&self) -> Option<Self::Stats>;
69
70    /// Returns `true` once the operation has completed (successfully or not).
71    ///
72    /// For local implementations this is typically `true` immediately after
73    /// creation. For networked implementations the caller should poll this or
74    /// await a notification before calling [`finish`](OpRef::finish).
75    fn is_finished(&self) -> bool;
76
77    /// Consumes the pending operation and returns its result.
78    ///
79    /// # Errors
80    ///
81    /// Returns `Self::Error` if the operation failed.
82    fn finish(&mut self) -> Result<Self::Result, Self::Error>;
83}
84
85/// An immediate no-op operation reference.
86///
87/// Useful for protocols that don't support certain operations (e.g., bootstrap)
88/// or for stub implementations. Always returns `is_finished() == true` and
89/// `finish()` returns `Ok(())`.
90pub struct NoopOpRef {
91    id: OpId,
92}
93
94impl NoopOpRef {
95    /// Create a new no-op operation reference with the given ID.
96    pub fn new(id: u64) -> Self {
97        Self { id: OpId(id) }
98    }
99}
100
101impl OpRef for NoopOpRef {
102    type Info = ();
103    type Stats = ();
104    type Result = ();
105    type Error = std::convert::Infallible;
106
107    fn id(&self) -> &OpId {
108        &self.id
109    }
110
111    fn info(&self) -> Option<Self::Info> {
112        Some(())
113    }
114
115    fn stats(&self) -> Option<Self::Stats> {
116        Some(())
117    }
118
119    fn is_finished(&self) -> bool {
120        true
121    }
122
123    fn finish(&mut self) -> Result<Self::Result, Self::Error> {
124        Ok(())
125    }
126}