use crate::SequenceHash;
pub trait EventEmissionPolicy: Send + Sync {
fn should_emit(&self, seq_hash: SequenceHash) -> bool;
}
#[derive(Debug, Clone)]
pub struct PowerOfTwoPolicy {
min_position: u64,
max_position: u64,
}
impl PowerOfTwoPolicy {
pub fn new() -> Self {
Self {
min_position: 16, max_position: 65536, }
}
pub fn with_range(min_position: u64, max_position: u64) -> Self {
Self {
min_position,
max_position,
}
}
}
impl Default for PowerOfTwoPolicy {
fn default() -> Self {
Self::new()
}
}
impl EventEmissionPolicy for PowerOfTwoPolicy {
fn should_emit(&self, seq_hash: SequenceHash) -> bool {
let position = seq_hash.position();
if position < self.min_position || position > self.max_position {
return false;
}
position.is_power_of_two()
}
}
#[derive(Debug, Clone, Default)]
pub struct AllEventsPolicy;
impl AllEventsPolicy {
pub fn new() -> Self {
Self
}
}
impl EventEmissionPolicy for AllEventsPolicy {
fn should_emit(&self, _seq_hash: SequenceHash) -> bool {
true
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{KvbmSequenceHashProvider, SequenceHash};
use dynamo_tokens::TokenBlockSequence;
fn create_seq_hash_at_position(position: usize) -> SequenceHash {
let tokens_per_block = 4;
let total_tokens = (position + 1) * tokens_per_block;
let tokens: Vec<u32> = (0..total_tokens as u32).collect();
let seq = TokenBlockSequence::from_slice(&tokens, tokens_per_block as u32, Some(1337));
seq.blocks()[position].kvbm_sequence_hash()
}
#[test]
fn test_power_of_two_policy_accepts_valid_positions() {
let policy = PowerOfTwoPolicy::new();
let valid_positions = vec![
16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536,
];
for pos in valid_positions {
let seq_hash = create_seq_hash_at_position(pos);
assert!(
policy.should_emit(seq_hash),
"Should emit for position {}",
pos
);
}
}
#[test]
fn test_power_of_two_policy_rejects_non_power_of_two() {
let policy = PowerOfTwoPolicy::new();
let invalid_positions = vec![15, 17, 31, 33, 63, 65, 100, 1000, 10000];
for pos in invalid_positions {
let seq_hash = create_seq_hash_at_position(pos);
assert!(
!policy.should_emit(seq_hash),
"Should not emit for position {}",
pos
);
}
}
#[test]
fn test_power_of_two_policy_rejects_out_of_range() {
let policy = PowerOfTwoPolicy::new();
let out_of_range = vec![1, 2, 4, 8];
for pos in out_of_range {
let seq_hash = create_seq_hash_at_position(pos);
assert!(
!policy.should_emit(seq_hash),
"Should not emit for position {} (below min)",
pos
);
}
}
#[test]
fn test_power_of_two_policy_custom_range() {
let policy = PowerOfTwoPolicy::with_range(32, 128);
assert!(policy.should_emit(create_seq_hash_at_position(32)));
assert!(policy.should_emit(create_seq_hash_at_position(64)));
assert!(policy.should_emit(create_seq_hash_at_position(128)));
assert!(!policy.should_emit(create_seq_hash_at_position(16)));
assert!(!policy.should_emit(create_seq_hash_at_position(256)));
}
}