Skip to main content

reifydb_codec/row/operator/
state.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use std::{cell::RefCell, collections::BTreeMap, mem};
5
6use postcard::{from_bytes, to_extend};
7use reifydb_value::{
8	error::{Error as ValueError, TypeError},
9	value::datetime::DateTime,
10};
11use serde::{Serialize, de::DeserializeOwned};
12use thiserror::Error;
13
14use crate::row::pod::EncodedPodRow;
15
16#[derive(Debug, Error, PartialEq)]
17pub enum StateError {
18	#[error("operator state serialization failed: {0}")]
19	Serialization(String),
20
21	#[error("operator state deserialization failed: {0}")]
22	Deserialization(String),
23}
24
25impl From<StateError> for ValueError {
26	fn from(err: StateError) -> Self {
27		match err {
28			StateError::Serialization(_) => TypeError::SerdeSerialize {
29				message: err.to_string(),
30			}
31			.into(),
32			StateError::Deserialization(_) => TypeError::SerdeDeserialize {
33				message: err.to_string(),
34			}
35			.into(),
36		}
37	}
38}
39
40pub trait OperatorState: Sized + Send + 'static {
41	fn encode_state(&self) -> Result<EncodedPodRow, StateError>;
42
43	fn decode_state(row: &EncodedPodRow) -> Result<Self, StateError>;
44}
45
46thread_local! {
47	static ENCODE_BUFFER: RefCell<Vec<u8>> = const { RefCell::new(Vec::new()) };
48}
49
50pub fn encode<T>(value: &T) -> Result<EncodedPodRow, StateError>
51where
52	T: Serialize,
53{
54	let mut buffer = ENCODE_BUFFER.with(|cell| mem::take(&mut *cell.borrow_mut()));
55	buffer.clear();
56	let mut filled = to_extend(value, buffer).map_err(|e| StateError::Serialization(e.to_string()))?;
57	let result = EncodedPodRow::new(&filled);
58	filled.clear();
59	ENCODE_BUFFER.with(|cell| *cell.borrow_mut() = filled);
60	Ok(result)
61}
62
63pub fn decode_body<T>(row: &EncodedPodRow) -> Result<T, StateError>
64where
65	T: DeserializeOwned,
66{
67	from_bytes(row.body()).map_err(|e| StateError::Deserialization(e.to_string()))
68}
69
70pub fn decode<T: OperatorState>(row: &EncodedPodRow) -> Result<T, StateError> {
71	T::decode_state(row)
72}
73
74pub mod derive {
75	pub use serde::{self, Deserialize, Serialize};
76}
77
78pub trait StateCodec: Sized + Send + 'static + Serialize + DeserializeOwned {}
79
80impl<T> StateCodec for T where T: Sized + Send + 'static + Serialize + DeserializeOwned {}
81
82macro_rules! leaf_operator_state {
83	($($ty:ty),* $(,)?) => {
84		$(impl OperatorState for $ty {
85			fn encode_state(&self) -> Result<EncodedPodRow, StateError> {
86				encode(self)
87			}
88
89			fn decode_state(row: &EncodedPodRow) -> Result<Self, StateError> {
90				decode_body::<Self>(row)
91			}
92		})*
93	};
94}
95
96leaf_operator_state!(u64, i64, Vec<u8>, (i64, i64, i64), DateTime);
97
98impl<K, V> OperatorState for BTreeMap<K, V>
99where
100	K: Send + 'static,
101	V: Send + 'static,
102	Self: Serialize + DeserializeOwned,
103{
104	fn encode_state(&self) -> Result<EncodedPodRow, StateError> {
105		encode(self)
106	}
107
108	fn decode_state(row: &EncodedPodRow) -> Result<Self, StateError> {
109		decode_body::<Self>(row)
110	}
111}