kmp_domain/value_objects/
temporal_cursor.rs1use crate::DomainError;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4pub enum TemporalDirection {
5 Goto,
6 Near,
7 Rewind,
8 Forward,
9}
10
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub enum TemporalCursor {
13 Ref(String),
14 Time(String),
15 Sequence(u32),
16}
17
18impl TemporalCursor {
19 pub fn ref_id(value: impl Into<String>) -> Result<Self, DomainError> {
20 let value = normalize_required(value.into(), "temporal cursor ref")?;
21 Ok(Self::Ref(value))
22 }
23
24 pub fn time(value: impl Into<String>) -> Result<Self, DomainError> {
25 let value = normalize_required(value.into(), "temporal cursor time")?;
26 Ok(Self::Time(value))
27 }
28
29 pub fn sequence(value: u32) -> Result<Self, DomainError> {
30 if value == 0 {
31 return Err(DomainError::InvalidState(
32 "temporal cursor sequence must be greater than zero".to_string(),
33 ));
34 }
35 Ok(Self::Sequence(value))
36 }
37}
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40pub struct TemporalWindow {
41 before_entries: usize,
42 after_entries: usize,
43}
44
45impl TemporalWindow {
46 pub fn new(before_entries: usize, after_entries: usize) -> Self {
47 Self {
48 before_entries,
49 after_entries,
50 }
51 }
52
53 pub fn before_entries(&self) -> usize {
54 self.before_entries
55 }
56
57 pub fn after_entries(&self) -> usize {
58 self.after_entries
59 }
60}
61
62impl Default for TemporalWindow {
63 fn default() -> Self {
64 Self {
65 before_entries: 2,
66 after_entries: 2,
67 }
68 }
69}
70
71fn normalize_required(value: String, field: &'static str) -> Result<String, DomainError> {
72 let value = value.trim();
73 if value.is_empty() {
74 Err(DomainError::EmptyValue(field))
75 } else {
76 Ok(value.to_string())
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use crate::{DomainError, TemporalCursor};
83
84 #[test]
85 fn cursor_requires_non_empty_values() {
86 assert_eq!(
87 TemporalCursor::ref_id(" ").expect_err("empty ref must fail"),
88 DomainError::EmptyValue("temporal cursor ref")
89 );
90 assert!(TemporalCursor::sequence(1).is_ok());
91 assert!(TemporalCursor::sequence(0).is_err());
92 }
93}