corpus_ipc/
rust_backend.rs1use crate::{BackendError, IpcBackend};
6
7pub struct RustBackend {
16 initialized: bool,
17}
18
19impl RustBackend {
20 pub fn new() -> Self {
22 Self { initialized: false }
23 }
24}
25
26impl Default for RustBackend {
27 fn default() -> Self {
28 Self::new()
29 }
30}
31
32impl IpcBackend for RustBackend {
33 fn process_batch(&mut self, inputs: &[f32]) -> Result<Vec<f32>, BackendError> {
34 if !self.initialized {
35 return Err(BackendError::InitializationError(
36 "RustBackend not initialized — call initialize() first".to_string(),
37 ));
38 }
39
40 let mut output = vec![0.0f32; inputs.len() * 2];
42 for i in 0..inputs.len() {
43 let val = inputs[i];
44 if val > 0.0 {
45 output[i * 2] = val;
46 output[i * 2 + 1] = 0.0;
47 } else {
48 output[i * 2] = 0.0;
49 output[i * 2 + 1] = val.abs();
50 }
51 }
52 Ok(output)
53 }
54
55 fn initialize(&mut self, _model_path: Option<&str>) -> Result<(), BackendError> {
56 self.initialized = true;
57 Ok(())
58 }
59
60 fn save_state(&self, _model_path: &str) -> Result<(), BackendError> {
61 Ok(()) }
63
64 fn get_spike_states(&self) -> Vec<bool> {
65 Vec::new()
67 }
68
69 fn reset(&mut self) -> Result<(), BackendError> {
70 self.initialized = false;
74 Ok(())
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 #[test]
83 fn process_before_init_returns_error() {
84 let mut b = RustBackend::new();
85 assert!(b.process_batch(&[0.0; 4]).is_err());
86 }
87
88 #[test]
89 fn positive_input_goes_to_even_channel() {
90 let mut b = RustBackend::new();
91 b.initialize(None).unwrap();
92 let inputs = vec![0.8, 0.0, 0.0];
93 let out = b.process_batch(&inputs).unwrap();
94 assert!((out[0] - 0.8).abs() < 1e-5);
95 assert_eq!(out[1], 0.0);
96 }
97
98 #[test]
99 fn negative_input_goes_to_odd_channel() {
100 let mut b = RustBackend::new();
101 b.initialize(None).unwrap();
102 let inputs = vec![0.0, 0.0, -0.5];
103 let out = b.process_batch(&inputs).unwrap();
104 assert_eq!(out[4], 0.0); assert!((out[5] - 0.5).abs() < 1e-5); }
107
108 #[test]
109 fn output_has_double_the_elements() {
110 let mut b = RustBackend::new();
111 b.initialize(None).unwrap();
112 let out = b.process_batch(&[0.1; 8]).unwrap();
113 assert_eq!(out.len(), 16);
114 let out_5 = b.process_batch(&[0.1; 5]).unwrap();
115 assert_eq!(out_5.len(), 10);
116 }
117
118 #[test]
119 fn spike_states_is_empty() {
120 let b = RustBackend::new();
121 assert!(b.get_spike_states().is_empty());
122 }
123
124 #[test]
125 fn reset_clears_initialized_and_next_process_fails() {
126 let mut b = RustBackend::new();
127 b.initialize(None).unwrap();
128 let _ = b.process_batch(&[0.1; 2]).unwrap();
129 b.reset().unwrap();
130 assert!(b.process_batch(&[0.1; 2]).is_err());
132 }
133}