use std::fmt;
use std::future::Future;
use std::sync::{Arc, Mutex};
use async_trait::async_trait;
use crate::error::{GoapError, Result};
#[derive(Debug, Clone)]
pub struct SensorResponse {
stdout: String,
stderr: String,
return_code: i32,
}
impl SensorResponse {
pub fn new(stdout: String, stderr: String, return_code: i32) -> Self {
Self {
stdout: Self::trim(&stdout),
stderr: Self::trim(&stderr),
return_code,
}
}
pub fn stdout(&self) -> &str {
&self.stdout
}
pub fn stderr(&self) -> &str {
&self.stderr
}
pub fn return_code(&self) -> i32 {
self.return_code
}
pub fn response(&self) -> &str {
if !self.stdout.is_empty() {
&self.stdout
} else {
&self.stderr
}
}
pub fn is_success(&self) -> bool {
self.return_code == 0
}
fn trim(s: &str) -> String {
s.trim_end_matches("\r\n")
.trim_end_matches('\n')
.to_string()
}
}
impl fmt::Display for SensorResponse {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Response: {}, ReturnCode: {}",
self.response(),
self.return_code
)
}
}
#[async_trait]
pub trait SensorFn: Send + Sync {
async fn exec(&self) -> Result<SensorResponse>;
}
#[derive(Clone)]
pub struct Sensor {
name: String,
binding: String,
func: Arc<dyn SensorFn>,
response: Arc<Mutex<Option<SensorResponse>>>,
}
impl Sensor {
pub fn new<F>(name: impl Into<String>, binding: impl Into<String>, func: F) -> Self
where
F: SensorFn + 'static,
{
Self {
name: name.into(),
binding: binding.into(),
func: Arc::new(func),
response: Arc::new(Mutex::new(None)),
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn binding(&self) -> &str {
&self.binding
}
pub async fn exec(&self) -> Result<SensorResponse> {
let response = self.func.exec().await?;
let mut resp_lock = self
.response
.lock()
.map_err(|_| GoapError::Other("Lock poisoned".into()))?;
*resp_lock = Some(response.clone());
Ok(response)
}
pub fn response(&self) -> Result<Option<SensorResponse>> {
let resp_lock = self
.response
.lock()
.map_err(|_| GoapError::Other("Lock poisoned".into()))?;
Ok(resp_lock.clone())
}
}
impl fmt::Debug for Sensor {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Sensor")
.field("name", &self.name)
.field("binding", &self.binding)
.finish()
}
}
impl fmt::Display for Sensor {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.name)
}
}
#[derive(Clone, Default)]
pub struct Sensors {
sensors: Vec<Sensor>,
}
impl Sensors {
pub fn new() -> Self {
Self {
sensors: Vec::new(),
}
}
pub fn from_vec(sensors: Vec<Sensor>) -> Self {
Self { sensors }
}
pub fn add<F>(
&mut self,
name: impl Into<String>,
binding: impl Into<String>,
func: F,
) -> Result<()>
where
F: SensorFn + 'static,
{
let name_str = name.into();
if self.get(&name_str).is_some() {
return Err(GoapError::SensorAlreadyInCollection(name_str));
}
self.sensors.push(Sensor::new(name_str, binding, func));
Ok(())
}
pub fn get(&self, name: &str) -> Option<&Sensor> {
self.sensors.iter().find(|s| s.name() == name)
}
pub fn remove(&mut self, name: &str) -> bool {
let initial_len = self.sensors.len();
self.sensors.retain(|s| s.name() != name);
self.sensors.len() != initial_len
}
pub async fn run_all(&self) -> Result<Vec<SensorResponse>> {
let mut responses = Vec::new();
for sensor in &self.sensors {
let response = sensor.exec().await?;
responses.push(response);
}
Ok(responses)
}
pub fn len(&self) -> usize {
self.sensors.len()
}
pub fn is_empty(&self) -> bool {
self.sensors.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = &Sensor> {
self.sensors.iter()
}
}
impl fmt::Debug for Sensors {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.sensors.iter()).finish()
}
}
impl fmt::Display for Sensors {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let names: Vec<_> = self.sensors.iter().map(|s| s.name()).collect();
write!(f, "{:?}", names)
}
}
pub struct FnSensor<F> {
func: F,
}
impl<F, Fut> FnSensor<F>
where
F: Fn() -> Fut + Send + Sync,
Fut: Future<Output = Result<(String, String, i32)>> + Send,
{
pub fn new(func: F) -> Self {
Self { func }
}
}
#[async_trait]
impl<F, Fut> SensorFn for FnSensor<F>
where
F: Fn() -> Fut + Send + Sync,
Fut: Future<Output = Result<(String, String, i32)>> + Send,
{
async fn exec(&self) -> Result<SensorResponse> {
let (stdout, stderr, return_code) = (self.func)().await?;
Ok(SensorResponse::new(stdout, stderr, return_code))
}
}
#[cfg(test)]
mod tests {
use super::*;
struct TestSensor;
#[async_trait]
impl SensorFn for TestSensor {
async fn exec(&self) -> Result<SensorResponse> {
Ok(SensorResponse::new(
"test output".to_string(),
"".to_string(),
0,
))
}
}
#[tokio::test]
async fn test_sensor_exec() {
let sensor = Sensor::new("test", "test_binding", TestSensor);
let response = sensor.exec().await.unwrap();
assert_eq!(response.stdout(), "test output");
assert_eq!(response.return_code(), 0);
}
#[tokio::test]
async fn test_sensors_collection() {
let mut sensors = Sensors::new();
sensors.add("test1", "binding1", TestSensor).unwrap();
let result = sensors.add("test1", "binding2", TestSensor);
assert!(result.is_err());
sensors.add("test2", "binding2", TestSensor).unwrap();
assert_eq!(sensors.len(), 2);
assert!(sensors.get("test1").is_some());
assert!(sensors.get("test2").is_some());
assert!(sensors.get("nonexistent").is_none());
assert!(sensors.remove("test1"));
assert_eq!(sensors.len(), 1);
assert!(sensors.get("test1").is_none());
assert!(!sensors.remove("nonexistent"));
}
#[tokio::test]
async fn test_fn_sensor() {
let sensor_fn = FnSensor::new(|| async { Ok(("output".to_string(), "".to_string(), 0)) });
let response = sensor_fn.exec().await.unwrap();
assert_eq!(response.stdout(), "output");
}
}