1use std::fmt;
2
3#[non_exhaustive]
5#[derive(Debug, Clone, PartialEq)]
6pub enum EncoderError {
7 NonFiniteRate { parameter: &'static str },
9 RateOrder,
11 InvalidRange { parameter: &'static str },
13 CountMustBePositive { parameter: &'static str },
15 NonPositiveOrNonFinite { parameter: &'static str },
17 NonNegativeFinite { parameter: &'static str },
19 NumChannelsTooLarge,
21 HistoryDepthTooSmall { minimum: usize },
23 StateLengthMismatch {
25 left: &'static str,
26 right: &'static str,
27 },
28 HistoryLengthExceedsDepth { channel: usize },
30 WindowMustBePositive { parameter: &'static str },
32}
33
34impl fmt::Display for EncoderError {
35 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36 match self {
37 Self::NonFiniteRate { parameter } => write!(f, "{parameter} must be finite"),
38 Self::RateOrder => write!(f, "base_rate must be less than or equal to max_rate"),
39 Self::InvalidRange { parameter } => write!(
40 f,
41 "{parameter} must be finite and min must be less than max"
42 ),
43 Self::CountMustBePositive { parameter } => {
44 write!(f, "{parameter} must be greater than 0")
45 }
46 Self::NonPositiveOrNonFinite { parameter } => {
47 write!(f, "{parameter} must be finite and greater than 0")
48 }
49 Self::NonNegativeFinite { parameter } => {
50 write!(f, "{parameter} must be finite and non-negative")
51 }
52 Self::NumChannelsTooLarge => write!(
53 f,
54 "num_channels exceeds u16::MAX as usize + 1 (max addressable spike channels)"
55 ),
56 Self::HistoryDepthTooSmall { minimum } => {
57 write!(f, "history_depth must be at least {minimum}")
58 }
59 Self::StateLengthMismatch { left, right } => {
60 write!(f, "mismatched {left} and {right} lengths")
61 }
62 Self::HistoryLengthExceedsDepth { channel } => {
63 write!(f, "history channel {channel} length exceeds history_depth")
64 }
65 Self::WindowMustBePositive { parameter } => {
66 write!(f, "{parameter} must be greater than 0")
67 }
68 }
69 }
70}
71
72impl std::error::Error for EncoderError {}
73
74pub(crate) const MAX_SPIKE_CHANNELS: usize = u16::MAX as usize + 1;
75
76pub(crate) fn validate_range(
77 parameter: &'static str,
78 range: (f32, f32),
79) -> Result<(), EncoderError> {
80 if range.0.is_finite() && range.1.is_finite() && range.0 < range.1 {
81 Ok(())
82 } else {
83 Err(EncoderError::InvalidRange { parameter })
84 }
85}
86
87pub(crate) fn validate_range_f32_span(
94 parameter: &'static str,
95 range: (f32, f32),
96) -> Result<(), EncoderError> {
97 validate_range(parameter, range)?;
98 if (range.1 - range.0).is_finite() {
99 Ok(())
100 } else {
101 Err(EncoderError::InvalidRange { parameter })
102 }
103}
104
105pub(crate) fn validate_channel_count(num_channels: usize) -> Result<(), EncoderError> {
106 if num_channels <= MAX_SPIKE_CHANNELS {
107 Ok(())
108 } else {
109 Err(EncoderError::NumChannelsTooLarge)
110 }
111}
112
113pub(crate) fn validate_non_negative_finite(
115 parameter: &'static str,
116 value: f32,
117) -> Result<(), EncoderError> {
118 if value.is_finite() && value >= 0.0 {
119 Ok(())
120 } else {
121 Err(EncoderError::NonNegativeFinite { parameter })
122 }
123}