use alec::{
channel::{Channel, ChannelPair, MemoryChannel},
Classifier, Context, Decoder, Encoder, Priority, RawData,
};
use std::time::Duration;
struct Emitter {
encoder: Encoder,
classifier: Classifier,
context: Context,
channel: MemoryChannel,
}
impl Emitter {
fn new(channel: MemoryChannel) -> Self {
Self {
encoder: Encoder::new(),
classifier: Classifier::default(),
context: Context::new(),
channel,
}
}
fn send_measurement(&mut self, value: f64, timestamp: u64) -> Option<usize> {
let data = RawData::new(value, timestamp);
let classification = self.classifier.classify(&data, &self.context);
if classification.priority.should_transmit() {
let message = self.encoder.encode(&data, &classification, &self.context);
let size = message.len();
self.channel.send(message).ok()?;
self.context.observe(&data);
Some(size)
} else {
self.context.observe(&data);
None
}
}
}
struct Receiver {
decoder: Decoder,
context: Context,
channel: MemoryChannel,
received_values: Vec<(u64, f64)>,
}
impl Receiver {
fn new(channel: MemoryChannel) -> Self {
Self {
decoder: Decoder::new(),
context: Context::new(),
channel,
received_values: Vec::new(),
}
}
fn process_incoming(&mut self) -> usize {
let mut count = 0;
while let Ok(message) = self.channel.receive(Duration::from_millis(0)) {
if let Ok(decoded) = self.decoder.decode(&message, &self.context) {
self.received_values
.push((decoded.timestamp, decoded.value));
self.context
.observe(&RawData::new(decoded.value, decoded.timestamp));
count += 1;
}
}
count
}
}
fn main() {
println!("=== ALEC Emitter-Receiver Example ===\n");
let _pair = ChannelPair::new();
let mut emitter = Emitter::new(MemoryChannel::new());
let mut receiver = Receiver::new(MemoryChannel::new());
let data = generate_sensor_data();
println!("Simulating {} measurements over 24 hours...\n", data.len());
println!(
"{:<8} {:<10} {:<12} {:<10}",
"Time", "Value", "Transmitted", "Size"
);
println!("{}", "-".repeat(45));
let mut total_transmitted = 0;
let mut total_bytes = 0;
let mut anomaly_count = 0;
for (timestamp, value) in &data {
let result = emitter.send_measurement(*value, *timestamp);
while let Some(msg) = emitter.channel.pop_outgoing() {
receiver.channel.push_incoming(msg);
}
receiver.process_incoming();
if timestamp % 4 == 0 {
let transmitted = if result.is_some() { "✓" } else { "✗" };
let size_str = result.map_or("-".to_string(), |s| s.to_string());
println!(
"{:>6}h {:<10.1} {:<12} {:<10}",
timestamp / 4,
value,
transmitted,
size_str
);
}
if let Some(size) = result {
total_transmitted += 1;
total_bytes += size;
let classification = emitter
.classifier
.classify(&RawData::new(*value, *timestamp), &emitter.context);
if matches!(
classification.priority,
Priority::P1Critical | Priority::P2Important
) {
anomaly_count += 1;
}
}
}
println!("{}", "-".repeat(45));
println!("\n=== Communication Statistics ===\n");
println!("Total measurements: {}", data.len());
println!(
"Messages transmitted: {} ({:.1}%)",
total_transmitted,
total_transmitted as f64 / data.len() as f64 * 100.0
);
println!(
"Messages suppressed: {}",
data.len() - total_transmitted
);
println!("Anomalies detected: {}", anomaly_count);
println!();
println!("Total bytes transmitted: {}", total_bytes);
println!(
"Average message size: {:.1} bytes",
total_bytes as f64 / total_transmitted as f64
);
println!();
println!("=== Verification ===\n");
println!("Received {} values", receiver.received_values.len());
if receiver.received_values.len() == total_transmitted {
println!("✓ All transmitted values received correctly!");
} else {
println!("✗ Mismatch in received values!");
}
println!("\n=== Context Status ===\n");
println!("Emitter context version: {}", emitter.context.version());
println!("Receiver context version: {}", receiver.context.version());
println!("Emitter context hash: {:016x}", emitter.context.hash());
println!("Receiver context hash: {:016x}", receiver.context.hash());
}
fn generate_sensor_data() -> Vec<(u64, f64)> {
let mut data = Vec::new();
let mut temp = 18.0;
for hour in 0..24u64 {
for quarter in 0..4u64 {
let timestamp = hour * 4 + quarter;
let hour_factor = match hour {
0..=5 => -0.1, 6..=9 => 0.3, 10..=14 => 0.1, 15..=18 => -0.1, _ => -0.2, };
let noise = (((timestamp * 7919) % 100) as f64 - 50.0) / 500.0;
temp += hour_factor + noise;
temp = temp.clamp(15.0, 30.0);
let anomaly_temp = match (hour, quarter) {
(10, 2) => Some(35.0), (18, 0) => Some(12.0), _ => None,
};
let value = anomaly_temp.unwrap_or(temp);
data.push((timestamp, value));
if anomaly_temp.is_some() {
temp = 20.0;
}
}
}
data
}