use serde::{Deserialize, Serialize};
use crate::validation::{
ProtocolLimits, Validate, ValidationError, check_count, check_finite_slice, check_opt_string,
};
use super::BatchMetadata;
use super::de::{de_opt_session_id, de_valid_mask, de_values, validate_optional_metadata};
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
#[serde(try_from = "StimulusBatchWire")]
pub struct StimulusBatch {
pub session_id: Option<String>,
pub batch_id: u64,
pub timestamp: u64,
pub values: Vec<f32>,
pub valid_mask: Option<Vec<bool>>,
pub metadata: Option<BatchMetadata>,
}
impl Validate for StimulusBatch {
fn validate_with(&self, limits: ProtocolLimits) -> Result<(), ValidationError> {
check_opt_string("session_id", self.session_id.as_deref(), limits)?;
check_count("values", self.values.len(), limits.max_channel_values)?;
check_finite_slice("values", &self.values)?;
if let Some(mask) = &self.valid_mask {
check_count("valid_mask", mask.len(), limits.max_channel_values)?;
if mask.len() != self.values.len() {
return Err(ValidationError::length_mismatch(
"valid_mask",
mask.len(),
self.values.len(),
));
}
}
validate_optional_metadata(&self.metadata, limits, self.values.len())
}
}
#[derive(Deserialize)]
struct StimulusBatchWire {
#[serde(deserialize_with = "de_opt_session_id")]
session_id: Option<String>,
batch_id: u64,
timestamp: u64,
#[serde(deserialize_with = "de_values")]
values: Vec<f32>,
#[serde(deserialize_with = "de_valid_mask")]
valid_mask: Option<Vec<bool>>,
metadata: Option<BatchMetadata>,
}
impl TryFrom<StimulusBatchWire> for StimulusBatch {
type Error = ValidationError;
fn try_from(wire: StimulusBatchWire) -> Result<Self, Self::Error> {
let batch = StimulusBatch {
session_id: wire.session_id,
batch_id: wire.batch_id,
timestamp: wire.timestamp,
values: wire.values,
valid_mask: wire.valid_mask,
metadata: wire.metadata,
};
batch.validate()?;
Ok(batch)
}
}