1use std::{
5 borrow::Cow,
6 fmt::{Display, Formatter, Result as FmtResult},
7 ops::Bound,
8};
9
10use reifydb_codec::key::{
11 deserializer::KeyDeserializer,
12 encode_u8,
13 encoded::{EncodedKey, EncodedKeyRange},
14 serializer::KeySerializer,
15};
16use reifydb_macro::KeyCodec;
17use reifydb_value::util::hash::{Hash128, xxh3_128};
18use serde::{Deserialize, Serialize};
19
20use super::super::KeyTag;
21use crate::{
22 common::OperatorClass,
23 interface::catalog::flow::OperatorId,
24 key::{
25 any::{ByteEncoding, Field, KeyFields, RawEncoding, TaggedKey, Width},
26 bound::{TaggedKeyBound, TaggedKeyBoundRange},
27 operator::{
28 keyspace::{
29 KEYSPACES, KeyspaceVisitor, REGISTERED, dispatch,
30 root::{
31 CustomManagedSuffix, CustomUnmanagedSuffix, NodeCounter, NodeCounterKey,
32 NodeCounterKind,
33 },
34 suffix_width_of,
35 },
36 traits::Keyspace,
37 },
38 typed::{BoundedKey, layout::KeyLayout},
39 },
40 metrics::heap::HeapSize,
41 state::typed::{SuffixBytes, typed_key},
42};
43
44#[repr(transparent)]
45#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
46pub struct GroupId([u8; GroupId::WIDTH]);
47
48impl GroupId {
49 pub const WIDTH: usize = 24;
50
51 const HASH_OFFSET: usize = size_of::<u64>();
52
53 const NOT_A_WINDOW: u64 = u64::MAX;
54
55 pub const ROOT: Self = Self([0; Self::WIDTH]);
56
57 pub const FIRST_NON_ROOT: Self = {
58 let mut bytes = [0u8; Self::WIDTH];
59 bytes[Self::WIDTH - 1] = 1;
60 Self(bytes)
61 };
62
63 pub const UNKEYED: Self = {
64 let mut bytes = [0u8; Self::WIDTH];
65 let mut idx = 0;
66 while idx < Self::HASH_OFFSET {
67 bytes[idx] = u8::MAX;
68 idx += 1;
69 }
70 Self(bytes)
71 };
72
73 pub const MIN: Self = Self([u8::MIN; Self::WIDTH]);
74
75 pub const MAX: Self = Self([u8::MAX; Self::WIDTH]);
76
77 pub const fn from_bytes(bytes: [u8; Self::WIDTH]) -> Self {
78 Self(bytes)
79 }
80
81 pub const fn as_bytes(&self) -> &[u8; Self::WIDTH] {
82 &self.0
83 }
84
85 pub fn of(key: &EncodedKey) -> Self {
86 Self::hashed(xxh3_128(key.as_slice()))
87 }
88
89 pub fn hashed(hash: Hash128) -> Self {
90 match hash.0 {
91 0 => Self::FIRST_NON_ROOT,
92 carried => Self::at(Self::NOT_A_WINDOW, carried),
93 }
94 }
95
96 pub fn window(partition: Hash128, window_id: u64) -> Self {
97 assert!(
98 window_id != Self::NOT_A_WINDOW,
99 "window id {window_id} is the sentinel that marks a group as having no window; a window \
100 minted at it would collide with the join and distinct groups of the same operator"
101 );
102 Self::at(window_id, partition.0)
103 }
104
105 pub fn window_span(window_id: u64) -> (Self, Self) {
106 (Self::at(window_id, u128::MIN), Self::at(window_id, u128::MAX))
107 }
108
109 pub fn window_id(&self) -> Option<u64> {
110 let mut leading = [0u8; size_of::<u64>()];
111 leading.copy_from_slice(&self.0[..Self::HASH_OFFSET]);
112 match !u64::from_be_bytes(leading) {
113 Self::NOT_A_WINDOW => None,
114 window_id => Some(window_id),
115 }
116 }
117
118 pub fn partition(&self) -> Hash128 {
119 let mut hash = [0u8; size_of::<u128>()];
120 hash.copy_from_slice(&self.0[Self::HASH_OFFSET..]);
121 Hash128(u128::from_be_bytes(hash))
122 }
123
124 fn at(window_id: u64, hash: u128) -> Self {
125 let mut bytes = [0u8; Self::WIDTH];
126 bytes[..Self::HASH_OFFSET].copy_from_slice(&(!window_id).to_be_bytes());
127 bytes[Self::HASH_OFFSET..].copy_from_slice(&hash.to_be_bytes());
128 Self(bytes)
129 }
130
131 pub fn is_root(&self) -> bool {
132 *self == Self::ROOT
133 }
134
135 pub fn successor(&self) -> Option<Self> {
136 let mut bytes = self.0;
137 for byte in bytes.iter_mut().rev() {
138 let (stepped, carried) = byte.overflowing_add(1);
139 *byte = stepped;
140 if !carried {
141 return Some(Self(bytes));
142 }
143 }
144 None
145 }
146
147 pub fn predecessor(&self) -> Option<Self> {
148 let mut bytes = self.0;
149 for byte in bytes.iter_mut().rev() {
150 let (stepped, borrowed) = byte.overflowing_sub(1);
151 *byte = stepped;
152 if !borrowed {
153 return Some(Self(bytes));
154 }
155 }
156 None
157 }
158}
159
160impl Display for GroupId {
161 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
162 for byte in self.0 {
163 write!(f, "{byte:02x}")?;
164 }
165 Ok(())
166 }
167}
168
169impl HeapSize for GroupId {
170 fn heap_size(&self) -> usize {
171 0
172 }
173}
174
175#[derive(Debug, Clone, Default, PartialEq, Eq)]
176pub struct GroupSet(Vec<GroupId>);
177
178impl GroupSet {
179 pub fn new(groups: impl IntoIterator<Item = GroupId>) -> Self {
180 let mut groups: Vec<GroupId> = groups.into_iter().filter(|g| !g.is_root()).collect();
181 groups.sort_unstable();
182 groups.dedup();
183 Self(groups)
184 }
185
186 pub fn contains(&self, group: GroupId) -> bool {
187 self.0.binary_search(&group).is_ok()
188 }
189
190 pub fn as_slice(&self) -> &[GroupId] {
191 &self.0
192 }
193
194 pub fn len(&self) -> usize {
195 self.0.len()
196 }
197
198 pub fn is_empty(&self) -> bool {
199 self.0.is_empty()
200 }
201}
202
203pub fn group_data_of_inner(inner: &[u8]) -> Option<GroupId> {
204 let mut de = KeyDeserializer::from_bytes(inner);
205 let group = GroupId::from_bytes(de.read_fixed().ok()?);
206 let keyspace = KeyspaceId(de.read_u8().ok()?);
207 if !keyspace.is_data() {
208 return None;
209 }
210 inner.starts_with(&group_inner_prefix(group)).then_some(group)
211}
212
213#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
214pub struct KeyspaceId(pub u8);
215
216impl KeyspaceId {
217 pub const HIGHEST_DATA: u8 = 0x2F;
218
219 pub const NODE_COUNTER: Self = Self(0xFF);
220
221 pub const SOURCE_WATERMARK: Self = Self(0xFE);
222
223 pub const TIMER_WHEEL: Self = Self(0xFD);
224
225 pub const TIMER_INDEX: Self = Self(0xFC);
226
227 pub const JOIN_ROW_MAPPING: Self = Self(0xFB);
228
229 pub const GROUP_ROW_MAPPING: Self = Self(0xFA);
230
231 pub const GUEST_ROW_MAPPING: Self = Self(0xF9);
232
233 pub const ACCUMULATOR: Self = Self(0x00);
234
235 pub const BUFFER: Self = Self(0x01);
236
237 pub const RUNNING: Self = Self(0x02);
238
239 pub const EMIT: Self = Self(0x03);
240
241 pub const ROLLING_EXPIRY: Self = Self(0x04);
242
243 pub const COUNT: Self = Self(0x05);
244
245 pub const ROW_INDEX: Self = Self(0x06);
246
247 pub const SESSION: Self = Self(0x07);
248
249 pub const ROLLING_META: Self = Self(0x08);
250
251 pub const ENGINE_META: Self = Self(0x09);
252
253 pub const DISTINCT_ENTRY: Self = Self(0x0A);
254
255 pub const WINDOW_META: Self = Self(0x0B);
256
257 pub const JOIN_LEFT: Self = Self(0x0C);
258
259 pub const JOIN_RIGHT: Self = Self(0x0D);
260
261 pub const JOIN_SCHEMA: Self = Self(0x0E);
262
263 pub const RINGBUFFER_FORWARD: Self = Self(0x0F);
264
265 pub const RINGBUFFER_ENTRY: Self = Self(0x10);
266
267 pub const GATE_VISIBILITY: Self = Self(0x11);
268
269 pub const DISTINCT_LAYOUT: Self = Self(0x12);
270
271 pub const RINGBUFFER_EXPIRY: Self = Self(0x13);
272
273 pub const RINGBUFFER_TTL_ARM: Self = Self(0x14);
274
275 pub const SEAL_LEDGER: Self = Self(0x15);
276
277 pub const JOIN_PUBLISHED: Self = Self(0x16);
278
279 pub const JOIN_PIN: Self = Self(0x17);
280
281 pub const RINGBUFFER_META: Self = Self(0x18);
282
283 pub const REAP_QUEUE: Self = Self(0x19);
284
285 pub const JOIN_ROW_EXPIRY: Self = Self(0x1A);
286
287 pub const GUEST_ACCUMULATOR: Self = Self(0x1B);
288
289 pub const GUEST_BUFFER: Self = Self(0x1C);
290
291 pub const GUEST_RUNNING: Self = Self(0x1D);
292
293 pub const TUMBLING_EXPIRY: Self = Self(0x1E);
294
295 pub const PARTITIONED_RINGBUFFER_ENTRY: Self = Self(0x1F);
296
297 pub const PARTITIONED_RINGBUFFER_EXPIRY: Self = Self(0x20);
298
299 pub const PARTITIONED_RINGBUFFER_TTL_ARM: Self = Self(0x21);
300
301 pub const PARTITIONED_RINGBUFFER_META: Self = Self(0x22);
302
303 pub const CUSTOM_UNMANAGED: Self = Self(0x23);
304
305 pub const JOIN_EXPIRY_DUE: Self = Self(0x24);
306
307 pub const CUSTOM_MANAGED: Self = Self(0x25);
308
309 pub const CUSTOM_MANAGED_DUE: Self = Self(0x26);
310
311 pub const CUSTOM_MANAGED_LATEST: Self = Self(0x27);
312
313 pub const GUEST_WINDOW_PUBLISH: Self = Self(0x28);
314
315 pub const GUEST_RETAINED_ENTRY: Self = Self(0x29);
316
317 pub const LOOKUP_READ: Self = Self(0x2A);
318
319 pub const SESSION_MEMBER: Self = Self(0x2B);
320
321 pub const ROLLING_PANE: Self = Self(0x2D);
322
323 pub const TAKE_ROW: Self = Self(0x2E);
324
325 pub const RINGBUFFER_NEXT_ROW: Self = Self(0x2F);
326
327 pub fn name(&self) -> Cow<'static, str> {
328 match *self {
329 Self::NODE_COUNTER => "NODE_COUNTER",
330 Self::SOURCE_WATERMARK => "SOURCE_WATERMARK",
331 Self::TIMER_WHEEL => "TIMER_WHEEL",
332 Self::TIMER_INDEX => "TIMER_INDEX",
333 Self::JOIN_ROW_MAPPING => "JOIN_ROW_MAPPING",
334 Self::GROUP_ROW_MAPPING => "GROUP_ROW_MAPPING",
335 Self::GUEST_ROW_MAPPING => "GUEST_ROW_MAPPING",
336 Self::ACCUMULATOR => "ACCUMULATOR",
337 Self::BUFFER => "BUFFER",
338 Self::RUNNING => "RUNNING",
339 Self::EMIT => "EMIT",
340 Self::ROLLING_EXPIRY => "ROLLING_EXPIRY",
341 Self::COUNT => "COUNT",
342 Self::ROW_INDEX => "ROW_INDEX",
343 Self::SESSION => "SESSION",
344 Self::ROLLING_META => "ROLLING_META",
345 Self::ENGINE_META => "ENGINE_META",
346 Self::DISTINCT_ENTRY => "DISTINCT_ENTRY",
347 Self::WINDOW_META => "WINDOW_META",
348 Self::JOIN_LEFT => "JOIN_LEFT",
349 Self::JOIN_RIGHT => "JOIN_RIGHT",
350 Self::JOIN_SCHEMA => "JOIN_SCHEMA",
351 Self::RINGBUFFER_FORWARD => "RINGBUFFER_FORWARD",
352 Self::RINGBUFFER_ENTRY => "RINGBUFFER_ENTRY",
353 Self::GATE_VISIBILITY => "GATE_VISIBILITY",
354 Self::DISTINCT_LAYOUT => "DISTINCT_LAYOUT",
355 Self::RINGBUFFER_EXPIRY => "RINGBUFFER_EXPIRY",
356 Self::RINGBUFFER_TTL_ARM => "RINGBUFFER_TTL_ARM",
357 Self::SEAL_LEDGER => "SEAL_LEDGER",
358 Self::JOIN_PUBLISHED => "JOIN_PUBLISHED",
359 Self::JOIN_PIN => "JOIN_PIN",
360 Self::RINGBUFFER_META => "RINGBUFFER_META",
361 Self::REAP_QUEUE => "REAP_QUEUE",
362 Self::JOIN_ROW_EXPIRY => "JOIN_ROW_EXPIRY",
363 Self::JOIN_EXPIRY_DUE => "JOIN_EXPIRY_DUE",
364 Self::GUEST_ACCUMULATOR => "GUEST_ACCUMULATOR",
365 Self::GUEST_BUFFER => "GUEST_BUFFER",
366 Self::GUEST_RUNNING => "GUEST_RUNNING",
367 Self::TUMBLING_EXPIRY => "TUMBLING_EXPIRY",
368 Self::PARTITIONED_RINGBUFFER_ENTRY => "PARTITIONED_RINGBUFFER_ENTRY",
369 Self::PARTITIONED_RINGBUFFER_EXPIRY => "PARTITIONED_RINGBUFFER_EXPIRY",
370 Self::PARTITIONED_RINGBUFFER_TTL_ARM => "PARTITIONED_RINGBUFFER_TTL_ARM",
371 Self::PARTITIONED_RINGBUFFER_META => "PARTITIONED_RINGBUFFER_META",
372 Self::CUSTOM_UNMANAGED => "CUSTOM_UNMANAGED",
373 Self::CUSTOM_MANAGED => "CUSTOM_MANAGED",
374 Self::CUSTOM_MANAGED_DUE => "CUSTOM_MANAGED_DUE",
375 Self::CUSTOM_MANAGED_LATEST => "CUSTOM_MANAGED_LATEST",
376 Self::GUEST_WINDOW_PUBLISH => "GUEST_WINDOW_PUBLISH",
377 Self::GUEST_RETAINED_ENTRY => "GUEST_RETAINED_ENTRY",
378 Self::LOOKUP_READ => "LOOKUP_READ",
379 Self::SESSION_MEMBER => "SESSION_MEMBER",
380 Self::ROLLING_PANE => "ROLLING_PANE",
381 Self::TAKE_ROW => "TAKE_ROW",
382 Self::RINGBUFFER_NEXT_ROW => "RINGBUFFER_NEXT_ROW",
383 _ => return Cow::Owned(format!("{:#04x}", self.0)),
384 }
385 .into()
386 }
387
388 pub fn is_data(&self) -> bool {
389 self.0 <= Self::HIGHEST_DATA
390 }
391
392 pub fn is_identity(&self) -> bool {
393 !self.is_data()
394 }
395
396 pub const fn is_known(&self) -> bool {
397 REGISTERED[(self.0 >> 6) as usize] & (1u64 << (self.0 & 63)) != 0
398 }
399}
400
401pub fn is_framed_inner(inner: &[u8]) -> bool {
402 inner.is_empty() || OperatorStateKey::decode_inner(inner).is_some_and(|(_, keyspace, _)| keyspace.is_known())
403}
404
405const WINDOWED_KEYSPACES: [KeyspaceId; 12] = [
406 KeyspaceId::GUEST_ACCUMULATOR,
407 KeyspaceId::GUEST_BUFFER,
408 KeyspaceId::GUEST_RUNNING,
409 KeyspaceId::EMIT,
410 KeyspaceId::WINDOW_META,
411 KeyspaceId::SEAL_LEDGER,
412 KeyspaceId::ROLLING_EXPIRY,
413 KeyspaceId::TUMBLING_EXPIRY,
414 KeyspaceId::REAP_QUEUE,
415 KeyspaceId::GUEST_WINDOW_PUBLISH,
416 KeyspaceId::GUEST_RETAINED_ENTRY,
417 KeyspaceId::GUEST_ROW_MAPPING,
418];
419
420const LOWEST_META: u8 = KeyspaceId::GUEST_ROW_MAPPING.0;
421
422#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
423pub struct KeyspaceMask(u64);
424
425impl KeyspaceMask {
426 pub const fn all() -> Self {
427 Self(u64::MAX)
428 }
429
430 pub const fn from_bits(bits: u64) -> Self {
431 Self(bits)
432 }
433
434 pub fn windowed() -> Self {
435 Self::of(WINDOWED_KEYSPACES)
436 }
437
438 pub fn data() -> Self {
439 Self::of((0..=KeyspaceId::HIGHEST_DATA).map(KeyspaceId))
440 }
441
442 pub fn of(keyspaces: impl IntoIterator<Item = KeyspaceId>) -> Self {
443 let mut mask = Self::default();
444 for keyspace in keyspaces {
445 mask.insert(keyspace);
446 }
447 mask
448 }
449
450 pub fn holds(self, keyspace: KeyspaceId) -> bool {
451 keyspace_bit(keyspace).is_some_and(|bit| self.0 & bit != 0)
452 }
453
454 pub fn held(self) -> Vec<KeyspaceId> {
455 let mut ids: Vec<KeyspaceId> =
456 KEYSPACES.iter().map(|spec| spec.id).filter(|id| self.holds(*id)).collect();
457 ids.sort_unstable();
458 ids
459 }
460
461 pub fn insert(&mut self, keyspace: KeyspaceId) {
462 if let Some(bit) = keyspace_bit(keyspace) {
463 self.0 |= bit;
464 }
465 }
466
467 pub fn intersect(self, other: Self) -> Self {
468 Self(self.0 & other.0)
469 }
470
471 pub fn bits(self) -> u64 {
472 self.0
473 }
474}
475
476fn keyspace_bit(keyspace: KeyspaceId) -> Option<u64> {
477 let index = match keyspace.0 {
478 id if id <= KeyspaceId::HIGHEST_DATA => id as u32,
479 id if id >= LOWEST_META => (KeyspaceId::HIGHEST_DATA as u32) + 1 + (id - LOWEST_META) as u32,
480 _ => return None,
481 };
482 (index < u64::BITS).then(|| 1u64 << index)
483}
484
485pub fn guest_may_address(class: OperatorClass, keyspace: KeyspaceId) -> bool {
486 match class {
487 OperatorClass::Managed => keyspace == KeyspaceId::CUSTOM_MANAGED,
488 OperatorClass::Unmanaged => keyspace == KeyspaceId::CUSTOM_UNMANAGED,
489 OperatorClass::Nostate => false,
490 OperatorClass::Windowed => WINDOWED_KEYSPACES.contains(&keyspace),
491 }
492}
493
494pub fn is_class_framed_inner(class: OperatorClass, inner: &[u8]) -> bool {
495 OperatorStateKey::decode_inner(inner).is_some_and(|(_, keyspace, suffix)| {
496 guest_may_address(class, keyspace) && suffix_width_of(keyspace) == Some(suffix.len())
497 })
498}
499
500#[derive(Debug, Clone, PartialEq, KeyCodec, Eq, Hash)]
501#[key(tag = OperatorState)]
502pub struct OperatorStateKey {
503 pub operator: OperatorId,
504 pub group: GroupId,
505 pub keyspace: KeyspaceId,
506 pub suffix: Vec<u8>,
507}
508
509impl OperatorStateKey {
510 pub fn new(operator: OperatorId, group: GroupId, keyspace: KeyspaceId, suffix: impl Into<Vec<u8>>) -> Self {
511 Self {
512 operator,
513 group,
514 keyspace,
515 suffix: suffix.into(),
516 }
517 }
518
519 pub fn root(operator: OperatorId, keyspace: KeyspaceId, suffix: impl Into<Vec<u8>>) -> Self {
520 Self::new(operator, GroupId::ROOT, keyspace, suffix)
521 }
522
523 pub fn encoded(
524 operator: OperatorId,
525 group: GroupId,
526 keyspace: KeyspaceId,
527 suffix: impl AsRef<[u8]>,
528 ) -> EncodedKey {
529 let suffix = suffix.as_ref();
530 let mut serializer = KeySerializer::with_capacity(NODE_GROUP_PREFIX_LEN + 1 + suffix.len());
531 serializer
532 .extend_u8(KeyTag::OperatorState as u8)
533 .extend_u64(operator.0)
534 .extend_fixed(*group.as_bytes())
535 .extend_u8(keyspace.0)
536 .extend_raw(suffix);
537 serializer.to_encoded_key()
538 }
539
540 pub fn inner(&self) -> EncodedKey {
541 let mut serializer = KeySerializer::with_capacity(KEYSPACE_INNER_PREFIX_LEN + self.suffix.len());
542 serializer.extend_fixed(*self.group.as_bytes()).extend_u8(self.keyspace.0).extend_raw(&self.suffix);
543 serializer.to_encoded_key()
544 }
545
546 pub const KEYSPACE_INNER_OFFSET: u32 = GroupId::WIDTH as u32;
547
548 pub fn decode_keyspace(stored: u8) -> KeyspaceId {
549 KeyspaceId(KeyDeserializer::from_bytes(&[stored]).read_u8().expect("a single byte decodes as u8"))
550 }
551
552 pub fn inner_encoded(group: GroupId, keyspace: KeyspaceId, suffix: impl AsRef<[u8]>) -> GroupStateKey {
553 let suffix = suffix.as_ref();
554 let mut serializer = KeySerializer::with_capacity(KEYSPACE_INNER_PREFIX_LEN + suffix.len());
555 serializer.extend_fixed(*group.as_bytes()).extend_u8(keyspace.0).extend_raw(suffix);
556 GroupStateKey(serializer.to_encoded_key())
557 }
558
559 pub fn decode_inner(inner: &[u8]) -> Option<(GroupId, KeyspaceId, &[u8])> {
560 let mut de = KeyDeserializer::from_bytes(inner);
561 let group = de.read_fixed().ok()?;
562 let keyspace = de.read_u8().ok()?;
563 let suffix = de.read_raw(de.remaining()).ok()?;
564 Some((GroupId::from_bytes(group), KeyspaceId(keyspace), suffix))
565 }
566
567 pub fn node_range(operator: OperatorId) -> TaggedKeyBoundRange {
568 node_range(operator)
569 }
570
571 pub fn decode_operator(key: &EncodedKey) -> Option<(OperatorId, EncodedKey)> {
572 let mut de = KeyDeserializer::from_bytes(key.as_slice());
573 let kind: KeyTag = de.read_u8().ok()?.try_into().ok()?;
574 if kind != KeyTag::OperatorState {
575 return None;
576 }
577 let operator = de.read_u64().ok()?;
578 let inner = de.read_raw(de.remaining()).ok()?;
579 Some((OperatorId(operator), EncodedKey::new(inner)))
580 }
581}
582
583#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
584pub struct GroupStateKey(EncodedKey);
585
586impl GroupStateKey {
587 pub fn new(group: GroupId, keyspace: KeyspaceId, suffix: impl AsRef<[u8]>) -> Self {
588 OperatorStateKey::inner_encoded(group, keyspace, suffix)
589 }
590
591 pub fn root(keyspace: KeyspaceId, suffix: impl AsRef<[u8]>) -> Self {
592 Self::new(GroupId::ROOT, keyspace, suffix)
593 }
594
595 pub fn from_framed(key: EncodedKey) -> Option<Self> {
596 is_framed_inner(key.as_slice()).then_some(Self(key))
597 }
598
599 pub fn from_class_framed(class: OperatorClass, key: EncodedKey) -> Option<Self> {
600 is_class_framed_inner(class, key.as_slice()).then_some(Self(key))
601 }
602
603 pub fn bound_unchecked(key: EncodedKey) -> Self {
604 Self(key)
605 }
606
607 pub fn as_encoded(&self) -> &EncodedKey {
608 &self.0
609 }
610
611 pub fn into_encoded(self) -> EncodedKey {
612 self.0
613 }
614
615 pub fn as_slice(&self) -> &[u8] {
616 self.0.as_slice()
617 }
618
619 pub fn as_bytes(&self) -> &[u8] {
620 self.0.as_bytes()
621 }
622
623 pub fn group(&self) -> Option<GroupId> {
624 OperatorStateKey::decode_inner(self.0.as_slice()).map(|(group, _, _)| group)
625 }
626
627 pub fn keyspace(&self) -> Option<KeyspaceId> {
628 let bytes = self.0.as_slice();
629 let offset = OperatorStateKey::KEYSPACE_INNER_OFFSET as usize;
630 (bytes.len() > offset).then(|| KeyspaceId(encode_u8(bytes[offset])))
631 }
632}
633
634#[derive(Debug, Clone, PartialEq, Eq)]
635pub enum GroupStateRange {
636 Keyspace {
637 group: GroupId,
638 keyspace: KeyspaceId,
639 start: Bound<Vec<u8>>,
640 end: Bound<Vec<u8>>,
641 },
642 Group(GroupId),
643 GroupData(GroupId),
644 GroupIdentity(GroupId),
645}
646
647impl GroupStateRange {
648 pub fn for_operator(self, operator: OperatorId) -> TaggedKeyBoundRange {
649 match self {
650 Self::Keyspace {
651 group,
652 keyspace,
653 start,
654 end,
655 } => {
656 let whole = keyspace_range(operator, group, keyspace);
657 let at = |suffix: &[u8], edge: SuffixEdge| {
658 TaggedKeyBound::Key(TaggedKey::OperatorState(OperatorStateKey::new(
659 operator,
660 group,
661 keyspace,
662 suffix_at_edge(keyspace, suffix, edge),
663 )))
664 };
665 let start = match start {
666 Bound::Unbounded => whole.start,
667 Bound::Included(suffix) => Bound::Included(at(&suffix, SuffixEdge::Low)),
668 Bound::Excluded(suffix) => Bound::Excluded(at(&suffix, SuffixEdge::High)),
669 };
670 let end = match end {
671 Bound::Unbounded => whole.end,
672 Bound::Included(suffix) => Bound::Included(at(&suffix, SuffixEdge::High)),
673 Bound::Excluded(suffix) => Bound::Excluded(at(&suffix, SuffixEdge::Low)),
674 };
675 TaggedKeyBoundRange {
676 start,
677 end,
678 }
679 }
680 Self::Group(group) => group_range(operator, group),
681 Self::GroupData(group) => group_data_range(operator, group),
682 Self::GroupIdentity(group) => group_identity_range(operator, group),
683 }
684 }
685}
686
687#[derive(Debug, Clone, PartialEq, Eq, Hash)]
688pub struct ManagedKey(GroupStateKey);
689
690impl AsRef<GroupStateKey> for ManagedKey {
691 fn as_ref(&self) -> &GroupStateKey {
692 &self.0
693 }
694}
695
696impl From<ManagedKey> for GroupStateKey {
697 fn from(key: ManagedKey) -> Self {
698 key.0
699 }
700}
701
702#[derive(Debug, Clone, PartialEq, Eq, Hash)]
703pub struct UnmanagedKey(GroupStateKey);
704
705impl AsRef<GroupStateKey> for UnmanagedKey {
706 fn as_ref(&self) -> &GroupStateKey {
707 &self.0
708 }
709}
710
711impl From<UnmanagedKey> for GroupStateKey {
712 fn from(key: UnmanagedKey) -> Self {
713 key.0
714 }
715}
716
717impl AsRef<[u8]> for GroupStateKey {
718 fn as_ref(&self) -> &[u8] {
719 self.0.as_slice()
720 }
721}
722
723impl AsRef<EncodedKey> for GroupStateKey {
724 fn as_ref(&self) -> &EncodedKey {
725 &self.0
726 }
727}
728
729pub trait IntoGroupStateKey {
730 fn into_group_state_key(self) -> GroupStateKey;
731}
732
733impl IntoGroupStateKey for GroupStateKey {
734 fn into_group_state_key(self) -> GroupStateKey {
735 self
736 }
737}
738
739fn group_inner_prefix(group: GroupId) -> Vec<u8> {
740 let mut serializer = KeySerializer::with_capacity(GroupId::WIDTH);
741 serializer.extend_fixed(*group.as_bytes());
742 serializer.finish().as_ref().to_vec()
743}
744
745fn keyspace_inner_prefix(group: GroupId, keyspace: KeyspaceId) -> Vec<u8> {
746 let mut prefix = group_inner_prefix(group);
747 prefix.push(encode_u8(keyspace.0));
748 prefix
749}
750
751pub fn group_inner_range(group: GroupId) -> EncodedKeyRange {
752 EncodedKeyRange::prefix(&group_inner_prefix(group))
753}
754
755pub fn keyspace_inner_range(group: GroupId, keyspace: KeyspaceId) -> EncodedKeyRange {
756 EncodedKeyRange::prefix(&keyspace_inner_prefix(group, keyspace))
757}
758
759enum SuffixEdge {
760 Low,
761 High,
762}
763
764fn suffix_at_edge(keyspace: KeyspaceId, suffix: &[u8], edge: SuffixEdge) -> Vec<u8> {
765 struct Pad<'a> {
766 suffix: &'a [u8],
767 edge: SuffixEdge,
768 }
769
770 impl KeyspaceVisitor for Pad<'_> {
771 type Output = Vec<u8>;
772
773 fn visit<K: Keyspace>(self) -> Self::Output {
774 let template = match self.edge {
775 SuffixEdge::Low => <K::Suffix as BoundedKey>::low().to_suffix_bytes(),
776 SuffixEdge::High => <K::Suffix as KeyLayout>::high().to_suffix_bytes(),
777 };
778 let mut bytes = self.suffix.to_vec();
779 bytes.truncate(template.len());
780 bytes.extend_from_slice(&template[bytes.len()..]);
781 bytes
782 }
783 }
784
785 dispatch(
786 keyspace,
787 Pad {
788 suffix,
789 edge,
790 },
791 )
792 .unwrap_or_else(|| suffix.to_vec())
793}
794
795pub type KeyspaceInnerRangeSplit = (GroupId, KeyspaceId, Bound<Vec<u8>>, Bound<Vec<u8>>);
796
797pub fn keyspace_inner_range_split(range: &EncodedKeyRange) -> Option<KeyspaceInnerRangeSplit> {
798 let (group, keyspace, start) = match &range.start {
799 Bound::Included(key) => {
800 let (group, keyspace, suffix) = OperatorStateKey::decode_inner(key.as_slice())?;
801 (group, keyspace, Bound::Included(suffix.to_vec()))
802 }
803 Bound::Excluded(key) => {
804 let (group, keyspace, suffix) = OperatorStateKey::decode_inner(key.as_slice())?;
805 (group, keyspace, Bound::Excluded(suffix.to_vec()))
806 }
807 Bound::Unbounded => return None,
808 };
809 let whole = EncodedKeyRange::prefix(&keyspace_inner_prefix(group, keyspace));
810 let end = if range.end == whole.end {
811 Bound::Unbounded
812 } else {
813 match &range.end {
814 Bound::Included(key) => match OperatorStateKey::decode_inner(key.as_slice())? {
815 (g, k, suffix) if g == group && k == keyspace => Bound::Included(suffix.to_vec()),
816 _ => return None,
817 },
818 Bound::Excluded(key) => match OperatorStateKey::decode_inner(key.as_slice())? {
819 (g, k, suffix) if g == group && k == keyspace => Bound::Excluded(suffix.to_vec()),
820 _ => return None,
821 },
822 Bound::Unbounded => return None,
823 }
824 };
825 Some((group, keyspace, start, end))
826}
827
828pub fn group_inner_range_split(range: &EncodedKeyRange) -> Option<GroupId> {
829 let key = match &range.start {
830 Bound::Included(key) | Bound::Excluded(key) => key,
831 Bound::Unbounded => return None,
832 };
833 let group = GroupId::from_bytes(KeyDeserializer::from_bytes(key.as_slice()).read_fixed().ok()?);
834 for candidate in [group_inner_range(group), group_data_inner_range(group), group_identity_inner_range(group)] {
835 if range.start == candidate.start && range.end == candidate.end {
836 return Some(group);
837 }
838 }
839 None
840}
841
842pub fn unmanaged_key_in(group: GroupId, id: &[u8]) -> Option<UnmanagedKey> {
843 CustomUnmanagedSuffix::of(id).map(|key| {
844 UnmanagedKey(OperatorStateKey::inner_encoded(
845 group,
846 KeyspaceId::CUSTOM_UNMANAGED,
847 key.to_suffix_bytes(),
848 ))
849 })
850}
851
852pub fn unmanaged_key(id: &[u8]) -> Option<UnmanagedKey> {
853 unmanaged_key_in(GroupId::ROOT, id)
854}
855
856pub fn managed_key_in(group: GroupId, id: &[u8]) -> Option<ManagedKey> {
857 CustomManagedSuffix::of(id).map(|key| {
858 ManagedKey(OperatorStateKey::inner_encoded(group, KeyspaceId::CUSTOM_MANAGED, key.to_suffix_bytes()))
859 })
860}
861
862pub fn node_counter_key(kind: NodeCounterKind) -> GroupStateKey {
863 typed_key::<NodeCounter>(GroupId::ROOT, &NodeCounterKey::of(kind))
864}
865
866pub fn row_number_counter_key() -> GroupStateKey {
867 node_counter_key(NodeCounterKind::RowNumber)
868}
869
870pub fn group_data_inner_range(group: GroupId) -> EncodedKeyRange {
871 let prefix = group_inner_prefix(group);
872 let mut start = prefix.clone();
873 start.push(encode_u8(KeyspaceId::HIGHEST_DATA));
874 EncodedKeyRange::new(Bound::Included(EncodedKey::new(start)), EncodedKeyRange::prefix(&prefix).end)
875}
876
877pub fn group_identity_inner_range(group: GroupId) -> EncodedKeyRange {
878 let prefix = group_inner_prefix(group);
879 let mut end = prefix.clone();
880 end.push(encode_u8(KeyspaceId::HIGHEST_DATA));
881 EncodedKeyRange::new(Bound::Included(EncodedKey::new(prefix)), Bound::Excluded(EncodedKey::new(end)))
882}
883
884pub const NODE_PREFIX_LEN: usize = 9;
885
886pub const KEYSPACE_INNER_PREFIX_LEN: usize = GroupId::WIDTH + size_of::<u8>();
887
888pub const NODE_GROUP_PREFIX_LEN: usize = NODE_PREFIX_LEN + GroupId::WIDTH;
889
890pub fn extend_node_prefix(serializer: &mut KeySerializer, operator: OperatorId) {
891 serializer.extend_u8(KeyTag::OperatorState as u8).extend_u64(operator.0);
892}
893
894pub fn node_prefix(operator: OperatorId) -> Vec<u8> {
895 let mut serializer = KeySerializer::with_capacity(NODE_PREFIX_LEN);
896 extend_node_prefix(&mut serializer, operator);
897 serializer.finish().as_ref().to_vec()
898}
899
900pub fn inner_range(range: &TaggedKeyBoundRange) -> Option<(OperatorId, EncodedKeyRange)> {
901 let encoded = range.encode();
902 let start_key = match encoded.start.as_ref() {
903 Bound::Included(key) | Bound::Excluded(key) => key,
904 Bound::Unbounded => return None,
905 };
906 let (operator, _) = OperatorStateKey::decode_operator(start_key)?;
907 let prefix = node_prefix(operator);
908 let strip = |bound: Bound<&EncodedKey>| match bound {
909 Bound::Included(key) if key.as_slice().starts_with(&prefix) => {
910 Bound::Included(EncodedKey::new(&key.as_slice()[prefix.len()..]))
911 }
912 Bound::Excluded(key) if key.as_slice().starts_with(&prefix) => {
913 Bound::Excluded(EncodedKey::new(&key.as_slice()[prefix.len()..]))
914 }
915 _ => Bound::Unbounded,
916 };
917 Some((operator, EncodedKeyRange::new(strip(encoded.start.as_ref()), strip(encoded.end.as_ref()))))
918}
919
920pub fn node_range(operator: OperatorId) -> TaggedKeyBoundRange {
921 TaggedKeyBoundRange::prefix(KeyTag::OperatorState, [Field::UDesc(Width::U64, operator.0 as u128)])
922}
923
924pub fn group_range(operator: OperatorId, group: GroupId) -> TaggedKeyBoundRange {
925 TaggedKeyBoundRange::prefix(
926 KeyTag::OperatorState,
927 [
928 Field::UDesc(Width::U64, operator.0 as u128),
929 Field::BytesDesc(ByteEncoding::Fixed, Cow::Owned(group.as_bytes().to_vec())),
930 ],
931 )
932}
933
934pub fn keyspace_range(operator: OperatorId, group: GroupId, keyspace: KeyspaceId) -> TaggedKeyBoundRange {
935 TaggedKeyBoundRange::prefix(
936 KeyTag::OperatorState,
937 [
938 Field::UDesc(Width::U64, operator.0 as u128),
939 Field::BytesDesc(ByteEncoding::Fixed, Cow::Owned(group.as_bytes().to_vec())),
940 Field::UDesc(Width::U8, keyspace.0 as u128),
941 ],
942 )
943}
944
945pub fn group_data_range(operator: OperatorId, group: GroupId) -> TaggedKeyBoundRange {
946 TaggedKeyBoundRange {
947 start: Bound::Included(TaggedKeyBound::prefix(
948 KeyTag::OperatorState,
949 [
950 Field::UDesc(Width::U64, operator.0 as u128),
951 Field::BytesDesc(ByteEncoding::Fixed, Cow::Owned(group.as_bytes().to_vec())),
952 Field::UDesc(Width::U8, KeyspaceId::HIGHEST_DATA as u128),
953 ],
954 )),
955 end: Bound::Excluded(TaggedKeyBound::prefix_end(
956 KeyTag::OperatorState,
957 [
958 Field::UDesc(Width::U64, operator.0 as u128),
959 Field::BytesDesc(ByteEncoding::Fixed, Cow::Owned(group.as_bytes().to_vec())),
960 ],
961 )),
962 }
963}
964
965pub fn group_identity_range(operator: OperatorId, group: GroupId) -> TaggedKeyBoundRange {
966 TaggedKeyBoundRange {
967 start: Bound::Included(TaggedKeyBound::prefix(
968 KeyTag::OperatorState,
969 [
970 Field::UDesc(Width::U64, operator.0 as u128),
971 Field::BytesDesc(ByteEncoding::Fixed, Cow::Owned(group.as_bytes().to_vec())),
972 ],
973 )),
974 end: Bound::Excluded(TaggedKeyBound::prefix(
975 KeyTag::OperatorState,
976 [
977 Field::UDesc(Width::U64, operator.0 as u128),
978 Field::BytesDesc(ByteEncoding::Fixed, Cow::Owned(group.as_bytes().to_vec())),
979 Field::UDesc(Width::U8, KeyspaceId::HIGHEST_DATA as u128),
980 ],
981 )),
982 }
983}
984
985#[cfg(test)]
986mod tests {
987 use std::ops::Bound;
988
989 use reifydb_value::util::hash::Hash128;
990
991 use super::{
992 EncodedKey, EncodedKeyRange, GroupId, GroupSet, GroupStateKey, GroupStateRange, KeySerializer,
993 KeyspaceId, OperatorStateKey, group_data_inner_range, group_data_of_inner, group_data_range,
994 group_identity_inner_range, group_identity_range, group_inner_prefix, group_inner_range, group_range,
995 guest_may_address, is_class_framed_inner, is_framed_inner, keyspace_range, managed_key_in, node_prefix,
996 node_range, suffix_width_of, unmanaged_key_in,
997 };
998 use crate::{common::OperatorClass, interface::catalog::flow::OperatorId, key::operator::keyspace::KEYSPACES};
999
1000 const NODES: [u64; 4] = [1, 17, 300, 70_000];
1001 const GROUPS: [u128; 8] = [1, 2, 127, 128, 1000, 100_000, 1 << 30, u128::MAX];
1002 const DATA_KEYSPACES: [KeyspaceId; 5] = [
1003 KeyspaceId::ACCUMULATOR,
1004 KeyspaceId::BUFFER,
1005 KeyspaceId::RUNNING,
1006 KeyspaceId::CUSTOM_UNMANAGED,
1007 KeyspaceId::CUSTOM_MANAGED,
1008 ];
1009 const IDENTITY_KEYSPACES: [KeyspaceId; 1] = [KeyspaceId::GUEST_ROW_MAPPING];
1010
1011 #[derive(Clone, Copy, PartialEq, Debug)]
1012 enum Phase {
1013 Data,
1014 Identity,
1015 }
1016
1017 const CENSUS: [(&str, KeyspaceId, Phase, bool); 54] = [
1021 ("NODE_COUNTER", KeyspaceId::NODE_COUNTER, Phase::Identity, true),
1022 ("SOURCE_WATERMARK", KeyspaceId::SOURCE_WATERMARK, Phase::Identity, true),
1023 ("TIMER_WHEEL", KeyspaceId::TIMER_WHEEL, Phase::Identity, true),
1024 ("TIMER_INDEX", KeyspaceId::TIMER_INDEX, Phase::Identity, true),
1025 ("JOIN_ROW_MAPPING", KeyspaceId::JOIN_ROW_MAPPING, Phase::Identity, true),
1026 ("GROUP_ROW_MAPPING", KeyspaceId::GROUP_ROW_MAPPING, Phase::Identity, true),
1027 ("GUEST_ROW_MAPPING", KeyspaceId::GUEST_ROW_MAPPING, Phase::Identity, true),
1028 ("ACCUMULATOR", KeyspaceId::ACCUMULATOR, Phase::Data, true),
1029 ("BUFFER", KeyspaceId::BUFFER, Phase::Data, true),
1030 ("RUNNING", KeyspaceId::RUNNING, Phase::Data, true),
1031 ("EMIT", KeyspaceId::EMIT, Phase::Data, true),
1032 ("ROLLING_EXPIRY", KeyspaceId::ROLLING_EXPIRY, Phase::Data, true),
1033 ("COUNT", KeyspaceId::COUNT, Phase::Data, true),
1034 ("ROW_INDEX", KeyspaceId::ROW_INDEX, Phase::Data, true),
1035 ("SESSION", KeyspaceId::SESSION, Phase::Data, true),
1036 ("ROLLING_META", KeyspaceId::ROLLING_META, Phase::Data, true),
1037 ("ENGINE_META", KeyspaceId::ENGINE_META, Phase::Data, true),
1038 ("DISTINCT_ENTRY", KeyspaceId::DISTINCT_ENTRY, Phase::Data, true),
1039 ("WINDOW_META", KeyspaceId::WINDOW_META, Phase::Data, true),
1040 ("JOIN_LEFT", KeyspaceId::JOIN_LEFT, Phase::Data, true),
1041 ("JOIN_RIGHT", KeyspaceId::JOIN_RIGHT, Phase::Data, true),
1042 ("JOIN_SCHEMA", KeyspaceId::JOIN_SCHEMA, Phase::Data, true),
1043 ("RINGBUFFER_FORWARD", KeyspaceId::RINGBUFFER_FORWARD, Phase::Data, true),
1044 ("RINGBUFFER_ENTRY", KeyspaceId::RINGBUFFER_ENTRY, Phase::Data, true),
1045 ("GATE_VISIBILITY", KeyspaceId::GATE_VISIBILITY, Phase::Data, true),
1046 ("DISTINCT_LAYOUT", KeyspaceId::DISTINCT_LAYOUT, Phase::Data, true),
1047 ("RINGBUFFER_EXPIRY", KeyspaceId::RINGBUFFER_EXPIRY, Phase::Data, true),
1048 ("RINGBUFFER_TTL_ARM", KeyspaceId::RINGBUFFER_TTL_ARM, Phase::Data, true),
1049 ("SEAL_LEDGER", KeyspaceId::SEAL_LEDGER, Phase::Data, true),
1050 ("JOIN_PUBLISHED", KeyspaceId::JOIN_PUBLISHED, Phase::Data, true),
1051 ("JOIN_PIN", KeyspaceId::JOIN_PIN, Phase::Data, true),
1052 ("RINGBUFFER_META", KeyspaceId::RINGBUFFER_META, Phase::Data, true),
1053 ("REAP_QUEUE", KeyspaceId::REAP_QUEUE, Phase::Data, true),
1054 ("JOIN_ROW_EXPIRY", KeyspaceId::JOIN_ROW_EXPIRY, Phase::Data, true),
1055 ("JOIN_EXPIRY_DUE", KeyspaceId::JOIN_EXPIRY_DUE, Phase::Data, true),
1056 ("GUEST_ACCUMULATOR", KeyspaceId::GUEST_ACCUMULATOR, Phase::Data, true),
1057 ("GUEST_BUFFER", KeyspaceId::GUEST_BUFFER, Phase::Data, true),
1058 ("GUEST_RUNNING", KeyspaceId::GUEST_RUNNING, Phase::Data, true),
1059 ("TUMBLING_EXPIRY", KeyspaceId::TUMBLING_EXPIRY, Phase::Data, true),
1060 ("PARTITIONED_RINGBUFFER_ENTRY", KeyspaceId::PARTITIONED_RINGBUFFER_ENTRY, Phase::Data, true),
1061 ("PARTITIONED_RINGBUFFER_EXPIRY", KeyspaceId::PARTITIONED_RINGBUFFER_EXPIRY, Phase::Data, true),
1062 ("PARTITIONED_RINGBUFFER_TTL_ARM", KeyspaceId::PARTITIONED_RINGBUFFER_TTL_ARM, Phase::Data, true),
1063 ("PARTITIONED_RINGBUFFER_META", KeyspaceId::PARTITIONED_RINGBUFFER_META, Phase::Data, true),
1064 ("CUSTOM_UNMANAGED", KeyspaceId::CUSTOM_UNMANAGED, Phase::Data, false),
1065 ("CUSTOM_MANAGED", KeyspaceId::CUSTOM_MANAGED, Phase::Data, false),
1066 ("CUSTOM_MANAGED_DUE", KeyspaceId::CUSTOM_MANAGED_DUE, Phase::Data, true),
1067 ("CUSTOM_MANAGED_LATEST", KeyspaceId::CUSTOM_MANAGED_LATEST, Phase::Data, true),
1068 ("GUEST_WINDOW_PUBLISH", KeyspaceId::GUEST_WINDOW_PUBLISH, Phase::Data, true),
1069 ("GUEST_RETAINED_ENTRY", KeyspaceId::GUEST_RETAINED_ENTRY, Phase::Data, true),
1070 ("LOOKUP_READ", KeyspaceId::LOOKUP_READ, Phase::Data, true),
1071 ("SESSION_MEMBER", KeyspaceId::SESSION_MEMBER, Phase::Data, true),
1072 ("ROLLING_PANE", KeyspaceId::ROLLING_PANE, Phase::Data, true),
1073 ("TAKE_ROW", KeyspaceId::TAKE_ROW, Phase::Data, true),
1074 ("RINGBUFFER_NEXT_ROW", KeyspaceId::RINGBUFFER_NEXT_ROW, Phase::Data, true),
1075 ];
1076
1077 fn declared_keyspaces() -> usize {
1080 let source = include_str!("state.rs");
1081 let body = source
1082 .split("impl KeyspaceId {")
1083 .nth(1)
1084 .expect("the KeyspaceId impl block is where the constants are declared");
1085 let body = body.split("\n}\n").next().expect("the impl block is closed");
1086 body.lines()
1087 .filter(|line| {
1088 let line = line.trim_start();
1089 line.starts_with("pub const") && line.contains("Self(")
1090 })
1091 .count()
1092 }
1093
1094 #[test]
1095 fn a_bare_row_number_key_is_too_short_to_be_read_as_a_framed_key() {
1096 let mut bare = KeySerializer::with_capacity(4);
1098 bare.extend_u64(7u64);
1099 let bare = bare.finish().as_ref().to_vec();
1100
1101 assert!(
1102 bare.len() < group_inner_prefix(GroupId::hashed(Hash128(7))).len(),
1103 "a bare row number cannot span a group"
1104 );
1105 assert!(OperatorStateKey::decode_inner(&bare).is_none());
1106 assert!(!is_framed_inner(&bare));
1107
1108 let framed = OperatorStateKey::inner_encoded(
1109 GroupId::ROOT,
1110 KeyspaceId::CUSTOM_UNMANAGED,
1111 7u64.to_be_bytes(),
1112 );
1113 assert!(is_framed_inner(framed.as_slice()));
1114 assert!(
1115 !contains(&group_identity_inner_range(GroupId::hashed(Hash128(7))), framed.as_slice()),
1116 "the framed form must sit outside every other group's range"
1117 );
1118 }
1119
1120 #[test]
1121 fn the_empty_key_is_framing_because_it_sorts_below_every_group() {
1122 let empty: &[u8] = &[];
1124 assert!(is_framed_inner(empty));
1125
1126 for group in GROUPS {
1127 let range = group_inner_range(GroupId::hashed(Hash128(group)));
1128 assert!(
1129 !contains(&range, empty),
1130 "the empty key must sit outside group {group}'s range, not merely be unattributed"
1131 );
1132 }
1133 }
1134
1135 #[test]
1136 fn the_empty_key_is_not_guest_framing_even_though_it_is_host_framing() {
1137 let empty: &[u8] = &[];
1141 assert!(is_framed_inner(empty));
1142 assert!(!is_class_framed_inner(OperatorClass::Unmanaged, empty));
1143 assert!(GroupStateKey::from_class_framed(OperatorClass::Unmanaged, EncodedKey::new(Vec::new()))
1144 .is_none());
1145
1146 assert!(is_class_framed_inner(
1147 OperatorClass::Unmanaged,
1148 unmanaged_key_in(GroupId::hashed(Hash128(3)), &[])
1149 .expect("an empty id fits the keyspace")
1150 .as_ref()
1151 .as_slice()
1152 ));
1153 assert!(
1154 !is_class_framed_inner(
1155 OperatorClass::Unmanaged,
1156 OperatorStateKey::inner_encoded(
1157 GroupId::hashed(Hash128(3)),
1158 KeyspaceId::CUSTOM_UNMANAGED,
1159 []
1160 )
1161 .as_slice()
1162 ),
1163 "a suffix narrower than its keyspace declares must be refused at the wall, or it reaches the typed bucket and panics there instead"
1164 );
1165 }
1166
1167 #[test]
1168 fn a_keyspace_this_substrate_never_defines_is_not_framing() {
1169 let mut stray = KeySerializer::with_capacity(4);
1171 stray.extend_u64(3u64).extend_u8(0x90u8);
1172 assert!(!is_framed_inner(stray.finish().as_ref()));
1173
1174 for keyspace in DATA_KEYSPACES.iter().chain(IDENTITY_KEYSPACES.iter()) {
1175 assert!(
1176 is_framed_inner(
1177 OperatorStateKey::inner_encoded(GroupId::hashed(Hash128(3)), *keyspace, [])
1178 .as_slice()
1179 ),
1180 "keyspace {keyspace:?} is one the substrate writes and must pass"
1181 );
1182 }
1183 }
1184
1185 fn contains(range: &EncodedKeyRange, key: &[u8]) -> bool {
1186 let after_start = match &range.start {
1187 Bound::Included(start) => key >= start.as_slice(),
1188 Bound::Excluded(start) => key > start.as_slice(),
1189 Bound::Unbounded => true,
1190 };
1191 let before_end = match &range.end {
1192 Bound::Included(end) => key <= end.as_slice(),
1193 Bound::Excluded(end) => key < end.as_slice(),
1194 Bound::Unbounded => true,
1195 };
1196 after_start && before_end
1197 }
1198
1199 fn population() -> Vec<OperatorStateKey> {
1200 let mut keys = Vec::new();
1201 for operator in NODES {
1202 for group in GROUPS {
1203 for keyspace in DATA_KEYSPACES.iter().chain(IDENTITY_KEYSPACES.iter()) {
1204 for coord in [0u64, 1, 999, u64::MAX] {
1205 keys.push(OperatorStateKey::new(
1206 OperatorId(operator),
1207 GroupId::hashed(Hash128(group)),
1208 *keyspace,
1209 coord.to_be_bytes().to_vec(),
1210 ));
1211 }
1212 }
1213 }
1214 keys.push(OperatorStateKey::root(
1215 OperatorId(operator),
1216 KeyspaceId::NODE_COUNTER,
1217 b"7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU".to_vec(),
1218 ));
1219 }
1220 keys
1221 }
1222
1223 #[test]
1224 fn a_group_range_contains_exactly_that_groups_keys() {
1225 let population = population();
1227 for operator in NODES {
1228 for group in GROUPS {
1229 let group_id = GroupId::hashed(Hash128(group));
1230 let range = group_range(OperatorId(operator), group_id).encode();
1231 for key in &population {
1232 let encoded = key.encode();
1233 let expected = key.operator.0 == operator && key.group == group_id;
1234 assert_eq!(
1235 contains(&range, encoded.as_slice()),
1236 expected,
1237 "operator {operator} group {group} range disagreed about a key of operator {} \
1238 group {}",
1239 key.operator.0,
1240 key.group
1241 );
1242 }
1243 }
1244 }
1245 }
1246
1247 #[test]
1248 fn variable_length_group_ids_cannot_prefix_one_another() {
1249 let encodings: Vec<Vec<u8>> = GROUPS
1252 .iter()
1253 .map(|group| {
1254 OperatorStateKey::new(
1255 OperatorId(1),
1256 GroupId::hashed(Hash128(*group)),
1257 KeyspaceId::ACCUMULATOR,
1258 vec![],
1259 )
1260 .encode()
1261 .as_slice()
1262 .to_vec()
1263 })
1264 .collect();
1265
1266 for (i, a) in encodings.iter().enumerate() {
1267 for (j, b) in encodings.iter().enumerate() {
1268 if i != j {
1269 assert!(
1270 !b.starts_with(a.as_slice()),
1271 "group {} encodes as a prefix of group {}",
1272 GROUPS[i],
1273 GROUPS[j]
1274 );
1275 }
1276 }
1277 }
1278 }
1279
1280 #[test]
1281 fn the_data_and_identity_ranges_partition_the_group() {
1282 for operator in NODES {
1284 for group in GROUPS {
1285 let group = GroupId::hashed(Hash128(group));
1286 let data = group_data_range(OperatorId(operator), group).encode();
1287 let identity = group_identity_range(OperatorId(operator), group).encode();
1288
1289 for keyspace in DATA_KEYSPACES {
1290 let key = OperatorStateKey::new(
1291 OperatorId(operator),
1292 group,
1293 keyspace,
1294 vec![7, 7],
1295 )
1296 .encode();
1297 assert!(
1298 contains(&data, key.as_slice()),
1299 "data keyspace {keyspace:?} must fall in the phase-1 range"
1300 );
1301 assert!(
1302 !contains(&identity, key.as_slice()),
1303 "data keyspace {keyspace:?} must not fall in the phase-2 range"
1304 );
1305 }
1306
1307 for keyspace in IDENTITY_KEYSPACES {
1308 let key = OperatorStateKey::new(
1309 OperatorId(operator),
1310 group,
1311 keyspace,
1312 vec![7, 7],
1313 )
1314 .encode();
1315 assert!(
1316 contains(&identity, key.as_slice()),
1317 "identity keyspace {keyspace:?} must fall in the phase-2 range"
1318 );
1319 assert!(
1320 !contains(&data, key.as_slice()),
1321 "identity keyspace {keyspace:?} must survive phase 1"
1322 );
1323 }
1324 }
1325 }
1326 }
1327
1328 #[test]
1329 fn every_declared_keyspace_names_itself_for_offline_attribution() {
1330 for (name, keyspace, _, _) in CENSUS {
1332 assert_eq!(
1333 keyspace.name(),
1334 name,
1335 "{name} ({:#04x}) does not name itself, so an offline census reports it as CUSTOM",
1336 keyspace.0
1337 );
1338 }
1339
1340 assert_eq!(
1341 KeyspaceId::CUSTOM_UNMANAGED.name(),
1342 "CUSTOM_UNMANAGED",
1343 "a custom keyspace names the admission side it sits on; there is no unnamed fallback to absorb it"
1344 );
1345 }
1346
1347 #[test]
1348 fn every_declared_keyspace_states_whether_it_may_be_range_cached() {
1349 for (name, keyspace, _, policy) in CENSUS {
1352 let range_cached =
1353 KEYSPACES.iter().find(|spec| spec.id == keyspace).map(|spec| spec.range_cached);
1354 assert_eq!(
1355 range_cached,
1356 Some(policy),
1357 "{name} ({:#04x}) is cached on a different side than the census records",
1358 keyspace.0
1359 );
1360 }
1361
1362 let uncached: Vec<&str> = CENSUS.iter().filter(|(_, _, _, p)| !*p).map(|(n, ..)| *n).collect();
1363 assert_eq!(
1364 uncached,
1365 ["CUSTOM_UNMANAGED", "CUSTOM_MANAGED"],
1366 "widening the set the tier refuses turns that tier into an off switch and only shows up as a \
1367 throughput loss in a replay, so every move in or out is a measured decision"
1368 );
1369 }
1370
1371 #[test]
1372 fn every_declared_keyspace_is_distinct_framing_and_swept_by_exactly_one_phase() {
1373 assert_eq!(
1375 CENSUS.len(),
1376 declared_keyspaces(),
1377 "a keyspace was added to KeyspaceId without being added to the census, so nothing below \
1378 ever looks at its byte"
1379 );
1380
1381 let mut seen: Vec<(&str, u8)> = Vec::new();
1382 for (name, keyspace, phase, _) in CENSUS {
1383 if let Some((other, _)) = seen.iter().find(|(_, byte)| *byte == keyspace.0) {
1384 panic!("{name} and {other} both claim keyspace byte {:#04x}", keyspace.0);
1385 }
1386 seen.push((name, keyspace.0));
1387
1388 assert!(
1389 keyspace.is_known(),
1390 "{name} is declared but not framing, so the sweep panics on the first row it holds"
1391 );
1392
1393 let group = GroupId::hashed(Hash128(4));
1394 let key = OperatorStateKey::new(OperatorId(9), group, keyspace, vec![7, 7]).encode();
1395 let data = contains(&group_data_range(OperatorId(9), group).encode(), key.as_slice());
1396 let identity = contains(&group_identity_range(OperatorId(9), group).encode(), key.as_slice());
1397
1398 assert!(data != identity, "{name} must fall in exactly one phase, not {data} and {identity}");
1399 assert_eq!(
1400 data,
1401 phase == Phase::Data,
1402 "{name} is declared {phase:?} but the phase-1 range says data={data}"
1403 );
1404 assert_eq!(
1405 keyspace.is_data(),
1406 phase == Phase::Data,
1407 "{name} is declared {phase:?} but is_data says {}",
1408 keyspace.is_data()
1409 );
1410 }
1411 }
1412
1413 #[test]
1414 fn root_entries_sit_outside_every_group_range() {
1415 for operator in NODES {
1417 let counter = OperatorStateKey::root(
1418 OperatorId(operator),
1419 KeyspaceId::NODE_COUNTER,
1420 b"mint".to_vec(),
1421 )
1422 .encode();
1423 for group in GROUPS {
1424 let range = group_range(OperatorId(operator), GroupId::hashed(Hash128(group))).encode();
1425 assert!(
1426 !contains(&range, counter.as_slice()),
1427 "group {group} range must not contain the root group's counter"
1428 );
1429 }
1430 }
1431 }
1432
1433 #[test]
1434 fn a_node_range_contains_exactly_that_nodes_keys() {
1435 let population = population();
1437 for operator in NODES {
1438 let range = node_range(OperatorId(operator)).encode();
1439 for key in &population {
1440 let encoded = key.encode();
1441 assert_eq!(
1442 contains(&range, encoded.as_slice()),
1443 key.operator.0 == operator,
1444 "operator {operator} range disagreed about a key of operator {}",
1445 key.operator.0
1446 );
1447 }
1448 }
1449 }
1450
1451 #[test]
1452 fn a_keyspace_range_isolates_one_keyspace_of_one_group() {
1453 let operator = OperatorId(17);
1455 let group = GroupId::hashed(Hash128(42));
1456 let range = keyspace_range(operator, group, KeyspaceId::BUFFER).encode();
1457
1458 let inside = OperatorStateKey::new(operator, group, KeyspaceId::BUFFER, vec![1]).encode();
1459 assert!(contains(&range, inside.as_slice()));
1460
1461 for other in [KeyspaceId::ACCUMULATOR, KeyspaceId::RUNNING, KeyspaceId::GUEST_ROW_MAPPING] {
1462 let key = OperatorStateKey::new(operator, group, other, vec![1]).encode();
1463 assert!(!contains(&range, key.as_slice()), "keyspace {other:?} leaked into the buffer range");
1464 }
1465
1466 let other_group =
1467 OperatorStateKey::new(operator, GroupId::hashed(Hash128(43)), KeyspaceId::BUFFER, vec![1])
1468 .encode();
1469 assert!(!contains(&range, other_group.as_slice()), "another group's buffer leaked into the range");
1470 }
1471
1472 #[test]
1473 fn encode_decode_round_trips_every_component() {
1474 let key = OperatorStateKey::new(
1475 OperatorId(0xDEAD_BEEF),
1476 GroupId::hashed(Hash128(123_456)),
1477 KeyspaceId::CUSTOM_UNMANAGED,
1478 vec![1, 2, 3, 4],
1479 );
1480 assert_eq!(OperatorStateKey::decode(&key.encode()), Some(key));
1481 }
1482
1483 #[test]
1484 fn keys_still_decode_as_operator_state_of_their_node() {
1485 let key = OperatorStateKey::new(
1487 OperatorId(9),
1488 GroupId::hashed(Hash128(4)),
1489 KeyspaceId::ACCUMULATOR,
1490 vec![1],
1491 )
1492 .encode();
1493
1494 let decoded = OperatorStateKey::decode(&key).expect("must remain decodable as its key kind");
1495 assert_eq!(decoded.operator, OperatorId(9));
1496 }
1497
1498 #[test]
1499 fn an_inner_key_composed_with_its_node_prefix_reproduces_the_full_key() {
1500 let key = OperatorStateKey::new(
1503 OperatorId(17),
1504 GroupId::hashed(Hash128(42)),
1505 KeyspaceId::BUFFER,
1506 vec![9, 9],
1507 );
1508
1509 let mut composed = node_prefix(OperatorId(17));
1510 composed.extend_from_slice(key.inner().as_slice());
1511
1512 assert_eq!(composed, key.encode().as_slice(), "inner key plus operator prefix must equal the full key");
1513 }
1514
1515 #[test]
1516 fn the_root_group_range_stays_inside_its_node() {
1517 let range = GroupStateRange::Group(GroupId::ROOT).for_operator(OperatorId(17)).encode();
1519
1520 let own = OperatorStateKey::root(OperatorId(17), KeyspaceId::NODE_COUNTER, vec![1]).encode();
1521 assert!(contains(&range, own.as_slice()), "the operator's own counter must be in range");
1522
1523 for operator in NODES {
1524 if operator == 17 {
1525 continue;
1526 }
1527 for keyspace in [KeyspaceId::NODE_COUNTER, KeyspaceId::ACCUMULATOR] {
1528 let foreign =
1529 OperatorStateKey::new(OperatorId(operator), GroupId::ROOT, keyspace, vec![1])
1530 .encode();
1531 assert!(
1532 !contains(&range, foreign.as_slice()),
1533 "operator {operator} leaked into operator 17's root-group range"
1534 );
1535 }
1536 }
1537 }
1538
1539 #[test]
1540 fn inner_ranges_partition_the_group_like_their_full_key_counterparts() {
1541 let operator = OperatorId(17);
1544 for group in GROUPS {
1545 let group = GroupId::hashed(Hash128(group));
1546 let data = GroupStateRange::GroupData(group).for_operator(operator).encode();
1547 let identity = GroupStateRange::GroupIdentity(group).for_operator(operator).encode();
1548
1549 for keyspace in DATA_KEYSPACES {
1550 let key = OperatorStateKey::new(operator, group, keyspace, vec![7]).encode();
1551 assert!(contains(&data, key.as_slice()));
1552 assert!(!contains(&identity, key.as_slice()));
1553 }
1554 for keyspace in IDENTITY_KEYSPACES {
1555 let key = OperatorStateKey::new(operator, group, keyspace, vec![7]).encode();
1556 assert!(contains(&identity, key.as_slice()));
1557 assert!(!contains(&data, key.as_slice()));
1558 }
1559 }
1560 }
1561
1562 #[test]
1563 fn decode_inner_round_trips_the_tail() {
1564 let key = OperatorStateKey::new(
1565 OperatorId(3),
1566 GroupId::hashed(Hash128(77)),
1567 KeyspaceId::EMIT,
1568 vec![4, 5, 6],
1569 );
1570 let inner = key.inner();
1571 let (group, keyspace, suffix) =
1572 OperatorStateKey::decode_inner(inner.as_slice()).expect("inner must decode");
1573
1574 assert_eq!(group, GroupId::hashed(Hash128(77)));
1575 assert_eq!(keyspace, KeyspaceId::EMIT);
1576 assert_eq!(suffix, [4, 5, 6]);
1577 }
1578
1579 #[test]
1580 fn a_state_key_stays_compact_however_long_the_group_key_is() {
1581 let long = b"7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU\
1583 So11111111111111111111111111111111111111112";
1584 let hashed = OperatorStateKey::new(
1585 OperatorId(17),
1586 GroupId::of(&EncodedKey::new(long)),
1587 KeyspaceId::ACCUMULATOR,
1588 vec![0; 8],
1589 )
1590 .encode();
1591 let short = OperatorStateKey::new(
1592 OperatorId(17),
1593 GroupId::of(&EncodedKey::new(b"g")),
1594 KeyspaceId::ACCUMULATOR,
1595 vec![0; 8],
1596 )
1597 .encode();
1598
1599 assert_eq!(hashed.as_slice().len(), short.as_slice().len(), "group key length must not reach the key");
1600 assert!(hashed.as_slice().len() * 2 < long.len() + 8, "and must stay far below embedding the bytes");
1601 }
1602
1603 #[test]
1604 fn the_ram_predicate_and_the_disk_range_agree_on_every_key() {
1605 for group in GROUPS.map(|group| GroupId::hashed(Hash128(group))) {
1608 let range = group_data_inner_range(group);
1609 for other in GROUPS.map(|group| GroupId::hashed(Hash128(group))) {
1610 for keyspace in DATA_KEYSPACES.iter().chain(IDENTITY_KEYSPACES.iter()) {
1611 let key = OperatorStateKey::inner_encoded(other, *keyspace, vec![7, 7]);
1612 let in_range = contains(&range, key.as_slice());
1613 let in_predicate = group_data_of_inner(key.as_slice()) == Some(group);
1614 assert_eq!(
1615 in_range, in_predicate,
1616 "disk range and RAM predicate disagree for group {group:?} on a \
1617 {keyspace:?} key of group {other:?}"
1618 );
1619 }
1620 }
1621 }
1622 }
1623
1624 #[test]
1625 fn the_ram_predicate_refuses_identity_keyspaces() {
1626 for keyspace in IDENTITY_KEYSPACES {
1628 let key = OperatorStateKey::inner_encoded(GroupId::hashed(Hash128(9)), keyspace, vec![1]);
1629 assert_eq!(
1630 group_data_of_inner(key.as_slice()),
1631 None,
1632 "{keyspace:?} must not be reported as reclaimable group data"
1633 );
1634 }
1635 }
1636
1637 #[test]
1638 fn a_key_too_short_to_carry_a_keyspace_is_refused() {
1639 assert_eq!(group_data_of_inner(&[]), None);
1641 assert_eq!(group_data_of_inner(&[0xAB]), None, "a group with no keyspace byte must not decode");
1642 }
1643
1644 #[test]
1645 fn the_predicate_agrees_with_the_disk_range_on_arbitrary_bytes() {
1646 let mut seed = 0x2545F4914F6CDD1Du64;
1648 let mut next = move || {
1649 seed ^= seed << 13;
1650 seed ^= seed >> 7;
1651 seed ^= seed << 17;
1652 seed
1653 };
1654
1655 for _ in 0..2000 {
1656 let len = (next() % 12) as usize;
1657 let key: Vec<u8> = (0..len).map(|_| (next() % 256) as u8).collect();
1658 let Some(group) = group_data_of_inner(&key) else {
1659 continue;
1660 };
1661 assert!(
1662 contains(&group_data_inner_range(group), &key),
1663 "predicate attributed {key:?} to {group:?} but the disk range excludes it"
1664 );
1665 }
1666 }
1667
1668 #[test]
1669 fn a_group_set_is_sorted_deduped_and_never_admits_root() {
1670 let two = GroupId::hashed(Hash128(2));
1672 let five = GroupId::hashed(Hash128(5));
1673 let nine = GroupId::hashed(Hash128(9));
1674 let set = GroupSet::new([nine, two, nine, GroupId::ROOT, five]);
1675
1676 assert_eq!(set.as_slice(), &[two, five, nine]);
1677 assert_eq!(set.len(), 3);
1678 assert!(set.contains(five));
1679 assert!(!set.contains(GroupId::hashed(Hash128(3))));
1680 assert!(!set.contains(GroupId::ROOT), "the root group must be filtered out, not merely unsorted");
1681 }
1682
1683 #[test]
1684 fn an_empty_group_set_matches_nothing() {
1685 let set = GroupSet::new([]);
1686
1687 assert!(set.is_empty());
1688 assert!(!set.contains(GroupId::FIRST_NON_ROOT));
1689 }
1690
1691 #[test]
1692 fn a_managed_key_is_guest_framed_in_the_managed_keyspace() {
1693 let group = GroupId::hashed(Hash128(3));
1695 let key = managed_key_in(group, b"id").expect("a two byte id fits the keyspace");
1696 let (decoded, keyspace, _) =
1697 OperatorStateKey::decode_inner(key.as_ref().as_slice()).expect("a managed key decodes");
1698 assert_eq!(decoded, group);
1699 assert_eq!(keyspace, KeyspaceId::CUSTOM_MANAGED);
1700 assert!(is_class_framed_inner(OperatorClass::Managed, key.as_ref().as_slice()));
1701 assert!(
1702 managed_key_in(group, &[0u8; 17]).is_none(),
1703 "an id wider than the suffix must be refused, not cut"
1704 );
1705 }
1706
1707 #[test]
1708 fn each_class_addresses_exactly_the_keyspaces_it_owns() {
1709 let owned = |class| {
1711 (0..=u8::MAX).map(KeyspaceId).filter(|id| guest_may_address(class, *id)).collect::<Vec<_>>()
1712 };
1713 assert_eq!(owned(OperatorClass::Managed), [KeyspaceId::CUSTOM_MANAGED]);
1714 assert_eq!(owned(OperatorClass::Unmanaged), [KeyspaceId::CUSTOM_UNMANAGED]);
1715 assert_eq!(owned(OperatorClass::Nostate), Vec::<KeyspaceId>::new());
1716 assert_eq!(
1717 owned(OperatorClass::Windowed),
1718 [
1719 KeyspaceId::EMIT,
1720 KeyspaceId::ROLLING_EXPIRY,
1721 KeyspaceId::WINDOW_META,
1722 KeyspaceId::SEAL_LEDGER,
1723 KeyspaceId::REAP_QUEUE,
1724 KeyspaceId::GUEST_ACCUMULATOR,
1725 KeyspaceId::GUEST_BUFFER,
1726 KeyspaceId::GUEST_RUNNING,
1727 KeyspaceId::TUMBLING_EXPIRY,
1728 KeyspaceId::GUEST_WINDOW_PUBLISH,
1729 KeyspaceId::GUEST_RETAINED_ENTRY,
1730 KeyspaceId::GUEST_ROW_MAPPING,
1731 ]
1732 );
1733 }
1734
1735 #[test]
1736 fn a_class_framed_key_must_name_an_owned_keyspace_at_its_exact_width() {
1737 let group = GroupId::hashed(Hash128(3));
1740 let at_width = |keyspace| {
1741 let width = suffix_width_of(keyspace).expect("every owned keyspace declares a width");
1742 OperatorStateKey::inner_encoded(group, keyspace, vec![0u8; width])
1743 };
1744 let managed = at_width(KeyspaceId::CUSTOM_MANAGED);
1745 assert!(is_class_framed_inner(OperatorClass::Managed, managed.as_slice()));
1746 for class in [OperatorClass::Unmanaged, OperatorClass::Nostate, OperatorClass::Windowed] {
1747 assert!(
1748 !is_class_framed_inner(class, managed.as_slice()),
1749 "{class:?} must not address a managed key"
1750 );
1751 }
1752 for keyspace in
1753 (0..=u8::MAX).map(KeyspaceId).filter(|id| guest_may_address(OperatorClass::Windowed, *id))
1754 {
1755 assert!(
1756 is_class_framed_inner(OperatorClass::Windowed, at_width(keyspace).as_slice()),
1757 "{keyspace:?}"
1758 );
1759 }
1760 let narrow = OperatorStateKey::inner_encoded(group, KeyspaceId::GUEST_ACCUMULATOR, []);
1761 assert!(!is_class_framed_inner(OperatorClass::Windowed, narrow.as_slice()));
1762 }
1763}