Skip to main content

sim_kernel/catalog/
row.rs

1use std::{collections::BTreeMap, fmt, sync::Arc};
2
3use crate::{
4    Expr, NumberBinaryOp, NumberReductionOp, NumberUnaryOp, PromotionRule, Symbol, Test, Value,
5    ValueNumberBinaryOp, ValueNumberReductionOp, ValueNumberUnaryOp, ValuePromotionRule,
6};
7
8/// A single catalog row: deterministic [`Expr`] field data plus private live
9/// payload cells.
10///
11/// The `data` map is serializable and participates in snapshots and deltas; the
12/// live cells (runtime values, tests, number ops, promotion rules) are host-only
13/// payloads kept out of serialized row data.
14#[derive(Clone, Debug, PartialEq, Eq)]
15pub struct CatalogRow {
16    /// Table this row belongs to.
17    pub table: Symbol,
18    /// Key identifying the row within its table.
19    pub key: Symbol,
20    /// Catalog epoch at which the row was last written.
21    pub epoch: u64,
22    /// Deterministic, serializable field data.
23    pub data: BTreeMap<Symbol, Expr>,
24    pub(crate) live: BTreeMap<Symbol, CatalogLiveCell>,
25}
26
27impl CatalogRow {
28    /// Creates an empty row at epoch 0 for `table`/`key`.
29    pub fn new(table: Symbol, key: Symbol) -> Self {
30        Self {
31            table,
32            key,
33            epoch: 0,
34            data: BTreeMap::new(),
35            live: BTreeMap::new(),
36        }
37    }
38
39    /// Returns the row with one deterministic data field set.
40    pub fn with_data(mut self, field: Symbol, value: Expr) -> Self {
41        self.data.insert(field, value);
42        self
43    }
44
45    /// Stores a live runtime [`Value`] payload in `field`.
46    pub fn insert_live_value(&mut self, field: Symbol, value: Value) {
47        self.live.insert(field, CatalogLiveCell::Value(value));
48    }
49
50    /// Returns the live [`Value`] payload in `field`, if present.
51    pub fn live_value(&self, field: &Symbol) -> Option<&Value> {
52        match self.live.get(field) {
53            Some(CatalogLiveCell::Value(value)) => Some(value),
54            _ => None,
55        }
56    }
57
58    /// Stores a live [`Test`] payload in `field`.
59    pub fn insert_live_test(&mut self, field: Symbol, test: Arc<dyn Test>) {
60        self.live.insert(field, CatalogLiveCell::Test(test));
61    }
62
63    /// Returns the live [`Test`] payload in `field`, if present.
64    pub fn live_test(&self, field: &Symbol) -> Option<&Arc<dyn Test>> {
65        match self.live.get(field) {
66            Some(CatalogLiveCell::Test(test)) => Some(test),
67            _ => None,
68        }
69    }
70
71    /// Stores a live [`NumberUnaryOp`] payload in `field`.
72    pub fn insert_live_number_unary_op(&mut self, field: Symbol, op: NumberUnaryOp) {
73        self.live.insert(field, CatalogLiveCell::NumberUnaryOp(op));
74    }
75
76    /// Stores a live [`NumberReductionOp`] payload in `field`.
77    pub fn insert_live_number_reduction_op(&mut self, field: Symbol, op: NumberReductionOp) {
78        self.live
79            .insert(field, CatalogLiveCell::NumberReductionOp(op));
80    }
81
82    /// Stores a live [`NumberBinaryOp`] payload in `field`.
83    pub fn insert_live_number_binary_op(&mut self, field: Symbol, op: NumberBinaryOp) {
84        self.live.insert(field, CatalogLiveCell::NumberBinaryOp(op));
85    }
86
87    /// Stores a live [`ValueNumberUnaryOp`] payload in `field`.
88    pub fn insert_live_value_number_unary_op(&mut self, field: Symbol, op: ValueNumberUnaryOp) {
89        self.live
90            .insert(field, CatalogLiveCell::ValueNumberUnaryOp(op));
91    }
92
93    /// Stores a live [`ValueNumberReductionOp`] payload in `field`.
94    pub fn insert_live_value_number_reduction_op(
95        &mut self,
96        field: Symbol,
97        op: ValueNumberReductionOp,
98    ) {
99        self.live
100            .insert(field, CatalogLiveCell::ValueNumberReductionOp(op));
101    }
102
103    /// Stores a live [`ValueNumberBinaryOp`] payload in `field`.
104    pub fn insert_live_value_number_binary_op(&mut self, field: Symbol, op: ValueNumberBinaryOp) {
105        self.live
106            .insert(field, CatalogLiveCell::ValueNumberBinaryOp(op));
107    }
108
109    /// Stores a live [`PromotionRule`] payload in `field`.
110    pub fn insert_live_promotion_rule(&mut self, field: Symbol, rule: PromotionRule) {
111        self.live
112            .insert(field, CatalogLiveCell::PromotionRule(rule));
113    }
114
115    /// Stores a live [`ValuePromotionRule`] payload in `field`.
116    pub fn insert_live_value_promotion_rule(&mut self, field: Symbol, rule: ValuePromotionRule) {
117        self.live
118            .insert(field, CatalogLiveCell::ValuePromotionRule(rule));
119    }
120
121    pub(crate) fn has_field(&self, field: &Symbol) -> bool {
122        self.data.contains_key(field) || self.live.contains_key(field)
123    }
124
125    pub(crate) fn set_epoch(&mut self, epoch: u64) {
126        self.epoch = epoch;
127    }
128}
129
130#[derive(Clone)]
131pub(crate) enum CatalogLiveCell {
132    Value(Value),
133    Test(Arc<dyn Test>),
134    NumberUnaryOp(NumberUnaryOp),
135    NumberReductionOp(NumberReductionOp),
136    NumberBinaryOp(NumberBinaryOp),
137    ValueNumberUnaryOp(ValueNumberUnaryOp),
138    ValueNumberReductionOp(ValueNumberReductionOp),
139    ValueNumberBinaryOp(ValueNumberBinaryOp),
140    PromotionRule(PromotionRule),
141    ValuePromotionRule(ValuePromotionRule),
142}
143
144impl fmt::Debug for CatalogLiveCell {
145    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146        match self {
147            Self::Value(value) => f.debug_tuple("Value").field(value).finish(),
148            Self::Test(_) => f.write_str("Test(..)"),
149            Self::NumberUnaryOp(_) => f.write_str("NumberUnaryOp(..)"),
150            Self::NumberReductionOp(_) => f.write_str("NumberReductionOp(..)"),
151            Self::NumberBinaryOp(_) => f.write_str("NumberBinaryOp(..)"),
152            Self::ValueNumberUnaryOp(_) => f.write_str("ValueNumberUnaryOp(..)"),
153            Self::ValueNumberReductionOp(_) => f.write_str("ValueNumberReductionOp(..)"),
154            Self::ValueNumberBinaryOp(_) => f.write_str("ValueNumberBinaryOp(..)"),
155            Self::PromotionRule(_) => f.write_str("PromotionRule(..)"),
156            Self::ValuePromotionRule(_) => f.write_str("ValuePromotionRule(..)"),
157        }
158    }
159}
160
161impl PartialEq for CatalogLiveCell {
162    fn eq(&self, other: &Self) -> bool {
163        match (self, other) {
164            (Self::Value(left), Self::Value(right)) => left == right,
165            (Self::Test(left), Self::Test(right)) => Arc::ptr_eq(left, right),
166            (Self::NumberUnaryOp(left), Self::NumberUnaryOp(right)) => {
167                number_unary_op_eq(left, right)
168            }
169            (Self::NumberReductionOp(left), Self::NumberReductionOp(right)) => {
170                number_reduction_op_eq(left, right)
171            }
172            (Self::NumberBinaryOp(left), Self::NumberBinaryOp(right)) => {
173                number_binary_op_eq(left, right)
174            }
175            (Self::ValueNumberUnaryOp(left), Self::ValueNumberUnaryOp(right)) => {
176                value_number_unary_op_eq(left, right)
177            }
178            (Self::ValueNumberReductionOp(left), Self::ValueNumberReductionOp(right)) => {
179                value_number_reduction_op_eq(left, right)
180            }
181            (Self::ValueNumberBinaryOp(left), Self::ValueNumberBinaryOp(right)) => {
182                value_number_binary_op_eq(left, right)
183            }
184            (Self::PromotionRule(left), Self::PromotionRule(right)) => {
185                promotion_rule_eq(left, right)
186            }
187            (Self::ValuePromotionRule(left), Self::ValuePromotionRule(right)) => {
188                value_promotion_rule_eq(left, right)
189            }
190            _ => false,
191        }
192    }
193}
194
195impl Eq for CatalogLiveCell {}
196
197fn number_unary_op_eq(left: &NumberUnaryOp, right: &NumberUnaryOp) -> bool {
198    left.operator == right.operator
199        && left.operand_domain == right.operand_domain
200        && left.cost == right.cost
201}
202
203fn number_reduction_op_eq(left: &NumberReductionOp, right: &NumberReductionOp) -> bool {
204    left.operator == right.operator
205        && left.operand_domain == right.operand_domain
206        && left.cost == right.cost
207}
208
209fn number_binary_op_eq(left: &NumberBinaryOp, right: &NumberBinaryOp) -> bool {
210    left.operator == right.operator
211        && left.left_domain == right.left_domain
212        && left.right_domain == right.right_domain
213        && left.cost == right.cost
214}
215
216fn value_number_unary_op_eq(left: &ValueNumberUnaryOp, right: &ValueNumberUnaryOp) -> bool {
217    left.operator == right.operator
218        && left.operand_domain == right.operand_domain
219        && left.cost == right.cost
220}
221
222fn value_number_reduction_op_eq(
223    left: &ValueNumberReductionOp,
224    right: &ValueNumberReductionOp,
225) -> bool {
226    left.operator == right.operator
227        && left.operand_domain == right.operand_domain
228        && left.cost == right.cost
229}
230
231fn value_number_binary_op_eq(left: &ValueNumberBinaryOp, right: &ValueNumberBinaryOp) -> bool {
232    left.operator == right.operator
233        && left.left_domain == right.left_domain
234        && left.right_domain == right.right_domain
235        && left.cost == right.cost
236}
237
238fn promotion_rule_eq(left: &PromotionRule, right: &PromotionRule) -> bool {
239    left.from_domain == right.from_domain
240        && left.to_domain == right.to_domain
241        && left.cost == right.cost
242}
243
244fn value_promotion_rule_eq(left: &ValuePromotionRule, right: &ValuePromotionRule) -> bool {
245    left.from_domain == right.from_domain
246        && left.to_domain == right.to_domain
247        && left.cost == right.cost
248}