#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::error::{RcfError, Result};
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MStreamConfig {
numeric_dim: usize,
categorical_dim: usize,
num_rows: usize,
num_buckets: usize,
alpha: f64,
}
impl MStreamConfig {
pub fn new(numeric_dim: usize, categorical_dim: usize) -> Self {
Self {
numeric_dim,
categorical_dim,
num_rows: 2,
num_buckets: 1024,
alpha: 0.8,
}
}
pub fn with_num_rows(mut self, value: usize) -> Self {
self.num_rows = value;
self
}
pub fn with_num_buckets(mut self, value: usize) -> Self {
self.num_buckets = value;
self
}
pub fn with_alpha(mut self, value: f64) -> Self {
self.alpha = value;
self
}
pub fn numeric_dim(&self) -> usize {
self.numeric_dim
}
pub fn categorical_dim(&self) -> usize {
self.categorical_dim
}
pub fn num_rows(&self) -> usize {
self.num_rows
}
pub fn num_buckets(&self) -> usize {
self.num_buckets
}
pub fn alpha(&self) -> f64 {
self.alpha
}
pub(crate) fn validate(&self) -> Result<()> {
if self.numeric_dim == 0 && self.categorical_dim == 0 {
return Err(RcfError::InvalidArgument(
"at least one of numeric_dim or categorical_dim must be > 0".into(),
));
}
if self.num_rows == 0 {
return Err(RcfError::InvalidArgument("num_rows must be > 0".into()));
}
if self.num_buckets < 2 {
return Err(RcfError::InvalidArgument("num_buckets must be >= 2".into()));
}
if !self.alpha.is_finite() || self.alpha <= 0.0 || self.alpha >= 1.0 {
return Err(RcfError::InvalidArgument(
"alpha must be in range (0, 1)".into(),
));
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use crate::error::RcfError;
use super::*;
#[test]
fn rejects_empty_dimensions() {
let err = MStreamConfig::new(0, 0).validate().unwrap_err();
assert!(matches!(err, RcfError::InvalidArgument(_)));
}
#[rstest]
#[case(0.0)]
#[case(1.0)]
#[case(f64::NAN)]
fn rejects_invalid_alpha(#[case] alpha: f64) {
let err = MStreamConfig::new(1, 0)
.with_alpha(alpha)
.validate()
.unwrap_err();
assert!(matches!(err, RcfError::InvalidArgument(_)));
}
}