Skip to main content

reifydb_sub_flow/operator/context/
in_process.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use std::{marker::PhantomData, mem, ops::Bound};
5
6use reifydb_codec::{
7	key::encoded::{EncodedKey, EncodedKeyRange},
8	row::operator::{EncodedOperatorRow, OperatorState},
9};
10use reifydb_core::{
11	interface::{catalog::flow::OperatorId, change::Diff},
12	key::operator_state::{GroupId, GroupStateKey},
13	state::store::TimerKind,
14};
15use reifydb_flow::operator::{host::HostContext, state::reclaim::ReclaimOutcome};
16use reifydb_sdk::{
17	error::{Result as SdkResult, SdkError},
18	flow::operator::{
19		column::{row::Row, sink::in_process::InProcessRowSink},
20		context::{GuestContext, GuestDictionary, GuestEmit, GuestState, GuestUpdateEmit},
21		state::{decode_payload, encode_payload},
22	},
23};
24use reifydb_value::value::{
25	Value,
26	datetime::DateTime,
27	dictionary::{DictionaryEntryId, DictionaryId},
28	row_number::RowNumber,
29};
30
31fn to_sdk_err<E: ToString>(e: E) -> SdkError {
32	SdkError::Other(e.to_string())
33}
34
35fn decode<T: OperatorState>(row: &EncodedOperatorRow) -> SdkResult<T> {
36	decode_payload(row)
37}
38
39fn encode<T: OperatorState>(value: &T, now: DateTime) -> SdkResult<EncodedOperatorRow> {
40	encode_payload(value, now)
41}
42
43pub struct InProcessContext<'a> {
44	host: *mut (dyn HostContext + 'a),
45	operator: OperatorId,
46	now: DateTime,
47	diffs: Vec<Diff>,
48	_marker: PhantomData<&'a mut (dyn HostContext + 'a)>,
49}
50
51impl<'a> InProcessContext<'a> {
52	pub fn new(host: &'a mut (dyn HostContext + 'a), operator: OperatorId) -> Self {
53		let now = host.written_at();
54		Self {
55			host: host as *mut (dyn HostContext + 'a),
56			operator,
57			now,
58			diffs: Vec::new(),
59			_marker: PhantomData,
60		}
61	}
62
63	pub fn take_diffs(&mut self) -> Vec<Diff> {
64		mem::take(&mut self.diffs)
65	}
66}
67
68pub struct InProcessInsertEmit<'a> {
69	sink: InProcessRowSink,
70	diffs: &'a mut Vec<Diff>,
71	now: DateTime,
72}
73
74impl GuestEmit for InProcessInsertEmit<'_> {
75	type Sink = InProcessRowSink;
76	fn sink(&mut self) -> &mut InProcessRowSink {
77		&mut self.sink
78	}
79	fn finish(self, row_numbers: &[RowNumber]) -> SdkResult<()> {
80		let columns = self.sink.finish(row_numbers.to_vec(), self.now)?;
81		self.diffs.push(Diff::insert(columns));
82		Ok(())
83	}
84}
85
86pub struct InProcessRemoveEmit<'a> {
87	sink: InProcessRowSink,
88	diffs: &'a mut Vec<Diff>,
89	now: DateTime,
90}
91
92impl GuestEmit for InProcessRemoveEmit<'_> {
93	type Sink = InProcessRowSink;
94	fn sink(&mut self) -> &mut InProcessRowSink {
95		&mut self.sink
96	}
97	fn finish(self, row_numbers: &[RowNumber]) -> SdkResult<()> {
98		let columns = self.sink.finish(row_numbers.to_vec(), self.now)?;
99		self.diffs.push(Diff::remove(columns));
100		Ok(())
101	}
102}
103
104pub struct InProcessUpdateEmit<'a> {
105	pre: InProcessRowSink,
106	post: InProcessRowSink,
107	diffs: &'a mut Vec<Diff>,
108	now: DateTime,
109}
110
111impl GuestUpdateEmit for InProcessUpdateEmit<'_> {
112	type Sink = InProcessRowSink;
113	fn pre(&mut self) -> &mut InProcessRowSink {
114		&mut self.pre
115	}
116	fn post(&mut self) -> &mut InProcessRowSink {
117		&mut self.post
118	}
119	fn finish(self, row_numbers: &[RowNumber]) -> SdkResult<()> {
120		let pre_columns = self.pre.finish(row_numbers.to_vec(), self.now)?;
121		let post_columns = self.post.finish(row_numbers.to_vec(), self.now)?;
122		self.diffs.push(Diff::update(pre_columns, post_columns));
123		Ok(())
124	}
125}
126
127pub struct InProcessState<'a> {
128	host: *mut (dyn HostContext + 'a),
129	now: DateTime,
130	_marker: PhantomData<&'a mut (dyn HostContext + 'a)>,
131}
132
133impl GuestState for InProcessState<'_> {
134	fn get<T: OperatorState>(&self, key: &GroupStateKey) -> SdkResult<Option<T>> {
135		// SAFETY: host is the &'a mut dyn HostContext InProcessContext::new was built from;
136		// PhantomData keeps that borrow live for 'a and this handle holds it exclusively.
137		match unsafe { (*self.host).state_get(key) }.map_err(to_sdk_err)? {
138			Some(row) => Ok(Some(decode(&row)?)),
139			None => Ok(None),
140		}
141	}
142	fn set<T: OperatorState>(&mut self, key: &GroupStateKey, value: &T) -> SdkResult<()> {
143		let now = self.now;
144		// SAFETY: host is the &'a mut dyn HostContext InProcessContext::new was built from;
145		// PhantomData keeps that borrow live for 'a and this handle holds it exclusively.
146		unsafe { (*self.host).state_set(key, encode(value, now)?) }.map_err(to_sdk_err)
147	}
148	fn remove(&mut self, key: &GroupStateKey) -> SdkResult<()> {
149		// SAFETY: host is the &'a mut dyn HostContext InProcessContext::new was built from;
150		// PhantomData keeps that borrow live for 'a and this handle holds it exclusively.
151		unsafe { (*self.host).state_remove(key) }.map_err(to_sdk_err)
152	}
153	fn contains(&self, key: &GroupStateKey) -> SdkResult<bool> {
154		// SAFETY: host is the &'a mut dyn HostContext InProcessContext::new was built from;
155		// PhantomData keeps that borrow live for 'a and this handle holds it exclusively.
156		Ok(unsafe { (*self.host).state_get(key) }.map_err(to_sdk_err)?.is_some())
157	}
158	fn clear(&mut self) -> SdkResult<()> {
159		// SAFETY: host is the &'a mut dyn HostContext InProcessContext::new was built from;
160		// PhantomData keeps that borrow live for 'a and this handle holds it exclusively.
161		unsafe { (*self.host).state_clear() }.map_err(to_sdk_err)
162	}
163	fn scan_prefix<T: OperatorState>(&self, prefix: &GroupStateKey) -> SdkResult<Vec<(GroupStateKey, T)>> {
164		// SAFETY: host is the &'a mut dyn HostContext InProcessContext::new was built from;
165		// PhantomData keeps that borrow live for 'a and this handle holds it exclusively.
166		let rows = unsafe { (*self.host).state_range(EncodedKeyRange::prefix(prefix.as_slice())) }
167			.map_err(to_sdk_err)?;
168		rows.into_iter().map(|(k, r)| Ok((k, decode(&r)?))).collect()
169	}
170	fn get_many<T: OperatorState>(&self, keys: &[GroupStateKey]) -> SdkResult<Vec<(GroupStateKey, T)>> {
171		// SAFETY: host is the &'a mut dyn HostContext InProcessContext::new was built from;
172		// PhantomData keeps that borrow live for 'a and this handle holds it exclusively.
173		let rows = unsafe { (*self.host).state_get_many(keys) }.map_err(to_sdk_err)?;
174		rows.into_iter().map(|(k, r)| Ok((k, decode(&r)?))).collect()
175	}
176	fn keys_with_prefix(&self, prefix: &GroupStateKey) -> SdkResult<Vec<GroupStateKey>> {
177		// SAFETY: host is the &'a mut dyn HostContext InProcessContext::new was built from;
178		// PhantomData keeps that borrow live for 'a and this handle holds it exclusively.
179		let rows = unsafe { (*self.host).state_range(EncodedKeyRange::prefix(prefix.as_slice())) }
180			.map_err(to_sdk_err)?;
181		Ok(rows.into_iter().map(|(k, _)| k).collect())
182	}
183	fn range<T: OperatorState>(
184		&self,
185		start: Bound<&GroupStateKey>,
186		end: Bound<&GroupStateKey>,
187	) -> SdkResult<Vec<(GroupStateKey, T)>> {
188		let range = EncodedKeyRange::new(
189			start.map(|k| k.as_encoded().clone()),
190			end.map(|k| k.as_encoded().clone()),
191		);
192		// SAFETY: host is the &'a mut dyn HostContext InProcessContext::new was built from;
193		// PhantomData keeps that borrow live for 'a and this handle holds it exclusively.
194		let rows = unsafe { (*self.host).state_range(range) }.map_err(to_sdk_err)?;
195		rows.into_iter().map(|(k, r)| Ok((k, decode(&r)?))).collect()
196	}
197	fn get_bytes(&self, key: &GroupStateKey) -> SdkResult<Option<EncodedOperatorRow>> {
198		// SAFETY: host is the &'a mut dyn HostContext InProcessContext::new was built from;
199		// PhantomData keeps that borrow live for 'a and this handle holds it exclusively.
200		unsafe { (*self.host).state_get(key) }.map_err(to_sdk_err)
201	}
202
203	fn set_bytes(&mut self, key: &GroupStateKey, payload: EncodedOperatorRow) -> SdkResult<()> {
204		// SAFETY: host is the &'a mut dyn HostContext InProcessContext::new was built from;
205		// PhantomData keeps that borrow live for 'a and this handle holds it exclusively.
206		unsafe { (*self.host).state_set(key, payload) }.map_err(to_sdk_err)
207	}
208
209	fn get_many_bytes_visit(
210		&self,
211		keys: &[GroupStateKey],
212		visit: &mut dyn FnMut(GroupStateKey, EncodedOperatorRow) -> SdkResult<()>,
213	) -> SdkResult<()> {
214		// SAFETY: host is the &'a mut dyn HostContext InProcessContext::new was built from;
215		// PhantomData keeps that borrow live for 'a and this handle holds it exclusively; the visitor
216		// cannot reach the context, so it cannot re-enter the host while this borrow is live.
217		unsafe { (*self.host).state_get_many_visit(keys, &mut |k, row| Ok(visit(k, row)?)) }.map_err(to_sdk_err)
218	}
219
220	fn range_bytes_visit(
221		&self,
222		start: Bound<&GroupStateKey>,
223		end: Bound<&GroupStateKey>,
224		visit: &mut dyn FnMut(GroupStateKey, EncodedOperatorRow) -> SdkResult<()>,
225	) -> SdkResult<()> {
226		let range = EncodedKeyRange::new(
227			start.map(|k| k.as_encoded().clone()),
228			end.map(|k| k.as_encoded().clone()),
229		);
230		// SAFETY: host is the &'a mut dyn HostContext InProcessContext::new was built from;
231		// PhantomData keeps that borrow live for 'a and this handle holds it exclusively.
232		let rows = unsafe { (*self.host).state_range(range) }.map_err(to_sdk_err)?;
233		for (k, row) in rows {
234			visit(k, row)?;
235		}
236		Ok(())
237	}
238}
239
240pub struct InProcessDictionary<'a> {
241	host: *mut (dyn HostContext + 'a),
242	_marker: PhantomData<&'a mut (dyn HostContext + 'a)>,
243}
244
245impl GuestDictionary for InProcessDictionary<'_> {
246	fn id_by_name(&mut self, name: &str) -> SdkResult<Option<DictionaryId>> {
247		// SAFETY: host is the &'a mut dyn HostContext InProcessContext::new was built from;
248		// PhantomData keeps that borrow live for 'a and this handle holds it exclusively.
249		unsafe { (*self.host).dictionary_id_by_name(name) }.map_err(to_sdk_err)
250	}
251	fn find(&mut self, dictionary: DictionaryId, value: &Value) -> SdkResult<Option<DictionaryEntryId>> {
252		// SAFETY: host is the &'a mut dyn HostContext InProcessContext::new was built from;
253		// PhantomData keeps that borrow live for 'a and this handle holds it exclusively.
254		unsafe { (*self.host).dictionary_find(dictionary, value) }.map_err(to_sdk_err)
255	}
256	fn get(&mut self, dictionary: DictionaryId, id: DictionaryEntryId) -> SdkResult<Option<Value>> {
257		// SAFETY: host is the &'a mut dyn HostContext InProcessContext::new was built from;
258		// PhantomData keeps that borrow live for 'a and this handle holds it exclusively.
259		unsafe { (*self.host).dictionary_get(dictionary, id) }.map_err(to_sdk_err)
260	}
261}
262
263impl GuestContext for InProcessContext<'_> {
264	type InsertEmit<'a>
265		= InProcessInsertEmit<'a>
266	where
267		Self: 'a;
268	type UpdateEmit<'a>
269		= InProcessUpdateEmit<'a>
270	where
271		Self: 'a;
272	type RemoveEmit<'a>
273		= InProcessRemoveEmit<'a>
274	where
275		Self: 'a;
276
277	fn operator_id(&self) -> OperatorId {
278		self.operator
279	}
280	fn written_at(&self) -> DateTime {
281		self.now
282	}
283	fn state(&mut self) -> impl GuestState + '_ {
284		InProcessState {
285			host: self.host,
286			now: self.now,
287			_marker: PhantomData,
288		}
289	}
290	fn dictionary(&mut self) -> impl GuestDictionary + '_ {
291		InProcessDictionary {
292			host: self.host,
293			_marker: PhantomData,
294		}
295	}
296	fn intern_groups(&mut self, groups: &[EncodedKey]) -> SdkResult<Vec<(GroupId, bool)>> {
297		// SAFETY: host is the &'a mut dyn HostContext this context was built from; PhantomData keeps
298		// that borrow live for 'a and &mut self makes the deref unique.
299		unsafe { (*self.host).intern_groups(groups) }.map_err(to_sdk_err)
300	}
301	fn lookup_groups(&mut self, groups: &[EncodedKey]) -> SdkResult<Vec<Option<GroupId>>> {
302		// SAFETY: host is the &'a mut dyn HostContext this context was built from; PhantomData keeps
303		// that borrow live for 'a and &mut self makes the deref unique.
304		unsafe { (*self.host).lookup_groups(groups) }.map_err(to_sdk_err)
305	}
306	fn arm_timer(&mut self, due: DateTime, kind: TimerKind, key: &EncodedKey) -> SdkResult<()> {
307		// SAFETY: host is the &'a mut dyn HostContext this context was built from; PhantomData keeps
308		// that borrow live for 'a and &mut self makes the deref unique.
309		unsafe { (*self.host).arm_timer(due, kind, key) }.map_err(to_sdk_err)
310	}
311	fn disarm_timer(&mut self, due: DateTime, kind: TimerKind, key: &EncodedKey) -> SdkResult<()> {
312		// SAFETY: host is the &'a mut dyn HostContext this context was built from; PhantomData keeps
313		// that borrow live for 'a and &mut self makes the deref unique.
314		unsafe { (*self.host).disarm_timer(due, kind, key) }.map_err(to_sdk_err)
315	}
316
317	fn flow_watermark(&mut self) -> SdkResult<Option<DateTime>> {
318		// SAFETY: host is the &'a mut dyn HostContext this context was built from; PhantomData keeps
319		// that borrow live for 'a and &mut self makes the deref unique.
320		unsafe { (*self.host).flow_watermark() }.map_err(to_sdk_err)
321	}
322	fn get_or_create_row_numbers(
323		&mut self,
324		group: GroupId,
325		keys: &[EncodedKey],
326	) -> SdkResult<Vec<(RowNumber, bool)>> {
327		// SAFETY: host is the &'a mut dyn HostContext this context was built from; PhantomData keeps
328		// that borrow live for 'a and &mut self makes the deref unique.
329		unsafe { (*self.host).get_or_create_row_numbers(group, keys) }.map_err(to_sdk_err)
330	}
331	fn get_or_create_row_numbers_for_pairs(
332		&mut self,
333		pairs: &[(GroupId, EncodedKey)],
334	) -> SdkResult<Vec<(RowNumber, bool)>> {
335		// SAFETY: host is the &'a mut dyn HostContext this context was built from; PhantomData keeps
336		// that borrow live for 'a and &mut self makes the deref unique.
337		unsafe { (*self.host).get_or_create_row_numbers_for_pairs(pairs) }.map_err(to_sdk_err)
338	}
339	fn remove_row_number(&mut self, group: GroupId, key: &EncodedKey) -> SdkResult<()> {
340		// SAFETY: host is the &'a mut dyn HostContext this context was built from; PhantomData keeps
341		// that borrow live for 'a and &mut self makes the deref unique.
342		unsafe { (*self.host).remove_row_number(group, key) }.map_err(to_sdk_err)
343	}
344	fn remove_row_numbers_below(&mut self, group: GroupId, upper: &EncodedKey) -> SdkResult<Vec<RowNumber>> {
345		// SAFETY: host is the &'a mut dyn HostContext this context was built from; PhantomData keeps
346		// that borrow live for 'a and &mut self makes the deref unique.
347		unsafe { (*self.host).remove_row_numbers_below(group, upper) }.map_err(to_sdk_err)
348	}
349	fn reclaim_group_identity(&mut self, group: GroupId, limit: usize) -> SdkResult<ReclaimOutcome> {
350		// SAFETY: host is the &'a mut dyn HostContext this context was built from; PhantomData keeps
351		// that borrow live for 'a and &mut self makes the deref unique.
352		unsafe { (*self.host).reclaim_group_identity(group, limit) }.map_err(to_sdk_err)
353	}
354	fn insert_emit<R: Row>(&mut self, _row_capacity: usize) -> SdkResult<InProcessInsertEmit<'_>> {
355		let now = self.now;
356		Ok(InProcessInsertEmit {
357			sink: InProcessRowSink::new(R::COLUMNS)?,
358			diffs: &mut self.diffs,
359			now,
360		})
361	}
362	fn update_emit<R: Row>(&mut self, _row_capacity: usize) -> SdkResult<InProcessUpdateEmit<'_>> {
363		let now = self.now;
364		Ok(InProcessUpdateEmit {
365			pre: InProcessRowSink::new(R::COLUMNS)?,
366			post: InProcessRowSink::new(R::COLUMNS)?,
367			diffs: &mut self.diffs,
368			now,
369		})
370	}
371	fn remove_emit<R: Row>(&mut self, _row_capacity: usize) -> SdkResult<InProcessRemoveEmit<'_>> {
372		let now = self.now;
373		Ok(InProcessRemoveEmit {
374			sink: InProcessRowSink::new(R::COLUMNS)?,
375			diffs: &mut self.diffs,
376			now,
377		})
378	}
379}