use uuid::Uuid;
#[derive(Debug, Clone)]
pub struct WatchExpression {
pub id: String,
pub expression: String,
pub last_value: Option<String>,
pub value_type: Option<String>,
pub has_error: bool,
pub error_message: Option<String>,
pub evaluation_count: u64,
}
impl WatchExpression {
pub fn new(expression: &str) -> Self {
Self {
id: Uuid::new_v4().to_string(),
expression: expression.to_string(),
last_value: None,
value_type: None,
has_error: false,
error_message: None,
evaluation_count: 0,
}
}
pub fn format(&self) -> String {
if self.has_error {
format!(
"{}: <error: {}>",
self.expression,
self.error_message.as_ref().unwrap_or(&"Unknown error".to_string())
)
} else if let Some(ref value) = self.last_value {
let type_str: _ = self.value_type.as_ref()
.map(|t| format!(" ({})", t))
.unwrap_or_default();
format!("{}: {}{}", self.expression, value, type_str)
} else {
format!("{}: <not evaluated>", self.expression)
}
}
pub fn reset(&mut self) {
self.last_value = None;
self.value_type = None;
self.has_error = false;
self.error_message = None;
}
}
#[derive(Debug)]
pub struct WatchManager {
watches: HashMap<String, WatchExpression>,
order: Vec<String>,
}
impl WatchManager {
pub fn new() -> Self {
Self {
watches: HashMap::new(),
order: Vec::new(),
}
}
pub fn add(&mut self, expression: &str) -> Result<WatchExpression, String> {
let watch: _ = WatchExpression::new(expression);
let id: _ = watch.id.clone();
self.order.push(id.clone());
self.watches.insert(id, watch.clone());
Ok(watch)
}
pub fn remove(&mut self, id: &str) -> Result<(), String> {
if self.watches.remove(id).is_some() {
self.order.retain(|i| i != id);
Ok(())
} else {
Err(format!("Watch with ID '{}' not found", id))
}
}
pub fn get(&self, id: &str) -> Option<&WatchExpression> {
self.watches.get(id)
}
pub fn get_mut(&mut self, id: &str) -> Option<&mut WatchExpression> {
self.watches.get_mut(id)
}
pub fn list(&self) -> Vec<&WatchExpression> {
self.order
.iter()
.filter_map(|id| self.watches.get(id))
.collect()
}
pub fn count(&self) -> usize {
self.watches.len()
}
pub fn update_value(
&mut self,
id: &str,
value: &str,
value_type: &str,
) -> Result<(), String> {
if let Some(watch) = self.watches.get_mut(id) {
watch.last_value = Some(value.to_string());
watch.value_type = Some(value_type.to_string());
watch.has_error = false;
watch.error_message = None;
watch.evaluation_count += 1;
Ok(())
} else {
Err(format!("Watch with ID '{}' not found", id))
}
}
pub fn set_error(&mut self, id: &str, error: &str) -> Result<(), String> {
if let Some(watch) = self.watches.get_mut(id) {
watch.has_error = true;
watch.error_message = Some(error.to_string());
watch.last_value = None;
watch.evaluation_count += 1;
Ok(())
} else {
Err(format!("Watch with ID '{}' not found", id))
}
}
pub fn clear(&mut self) {
self.watches.clear();
self.order.clear();
}
pub fn reset_all(&mut self) {
for watch in self.watches.values_mut() {
watch.reset();
}
}
}
impl Default for WatchManager {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod unit_tests {
use super::*;
#[test]
fn test_watch_expression_creation() {
let watch: _ = WatchExpression::new("x + 1");
assert_eq!(watch.expression, "x + 1");
assert!(!watch.id.is_empty());
assert!(watch.last_value.is_none());
}
#[test]
fn test_watch_manager_basic_operations() {
let mut manager = WatchManager::new();
let watch: _ = manager.add("counter").unwrap();
assert_eq!(manager.count(), 1);
let retrieved: _ = manager.get(&watch.id).unwrap();
assert_eq!(retrieved.expression, "counter");
manager.remove(&watch.id).unwrap();
assert_eq!(manager.count(), 0);
}
#[test]
fn test_watch_ordering() {
let mut manager = WatchManager::new();
manager.add("first").unwrap();
manager.add("second").unwrap();
manager.add("third").unwrap();
let list: _ = manager.list();
assert_eq!(list[0].expression, "first");
assert_eq!(list[1].expression, "second");
assert_eq!(list[2].expression, "third");
}
}
use std::collections::{BTreeMap, HashMap};