HomeServer/src/action.rs

153 lines
3.6 KiB
Rust
Raw Normal View History

2023-10-23 08:03:16 +00:00
use core::slice::Iter;
use std::{fmt::Display, str::FromStr};
use anyhow::{bail, Result};
2023-10-23 11:30:45 +00:00
use serde::Serialize;
2023-10-23 08:03:16 +00:00
2023-10-23 11:30:45 +00:00
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize)]
2023-10-23 08:03:16 +00:00
pub enum ActionType {
GreaterThan,
LessThan,
Push,
Receive,
Update,
}
impl Display for ActionType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::GreaterThan => write!(f, "GreaterThan"),
Self::LessThan => write!(f, "LessThan"),
Self::Push => write!(f, "Push"),
Self::Receive => write!(f, "Receive"),
Self::Update => write!(f, "Update"),
}
}
}
impl FromStr for ActionType {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"GreaterThan" => Ok(Self::GreaterThan),
"LessThan" => Ok(Self::LessThan),
"Push" => Ok(Self::Push),
"Receive" => Ok(Self::Receive),
"Update" => Ok(Self::Update),
_ => bail!("could not parse ActionType from {s}"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct ActionID(pub(crate) i64);
2023-10-23 11:30:45 +00:00
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize)]
2023-10-23 08:03:16 +00:00
pub struct Action {
2023-10-23 11:30:45 +00:00
#[serde(skip)]
pub(crate) id: Option<ActionID>,
2023-10-23 08:03:16 +00:00
pub device_id: String,
pub action_type: ActionType,
pub parameter: String,
}
impl Action {
pub fn new(
device_id: impl ToString,
action_type: ActionType,
parameter: impl ToString,
) -> Self {
Self {
id: None,
2023-10-23 08:03:16 +00:00
device_id: device_id.to_string(),
action_type,
parameter: parameter.to_string(),
}
}
}
2023-10-23 11:30:45 +00:00
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize)]
2023-10-23 08:03:16 +00:00
pub struct ActionSet {
actions: Vec<Action>,
}
impl ActionSet {
2023-10-23 08:32:52 +00:00
pub fn push_device(&self) -> Option<String> {
self.iter()
.find(|action| action.action_type == ActionType::Push)
.map(|action| action.device_id.clone())
}
pub fn receive_device(&self) -> Option<String> {
self.iter()
.find(|action| action.action_type == ActionType::Receive)
.map(|action| action.device_id.clone())
}
pub fn begins_with_device(&self, device_name: &str) -> bool {
match self.actions.get(0) {
Some(action) => action.device_id == device_name,
None => false,
}
}
pub(crate) fn first_id(&self) -> Option<ActionID> {
self.actions.get(0).map(|action| action.id).flatten()
}
2023-10-23 08:32:52 +00:00
pub fn parameter(&self, parameter: &str) -> bool {
match self.actions.get(0) {
Some(action) => action.parameter == parameter,
None => false,
}
}
2023-10-23 08:03:16 +00:00
pub fn chain(&mut self, action: Action) {
self.actions.push(action);
}
pub fn iter(&self) -> Iter<'_, Action> {
self.actions.iter()
}
}
impl<I> From<I> for ActionSet
where
I: IntoIterator<Item = Action>,
{
fn from(value: I) -> Self {
Self {
actions: value.into_iter().collect(),
}
}
}
#[cfg(test)]
mod test {
use super::*;
use anyhow::Result;
#[test]
fn example_chain() -> Result<()> {
let mut action_set = ActionSet::default();
action_set.chain(Action::new(
"shelly_plus_ht",
ActionType::Push,
"temperature",
));
action_set.chain(Action::new(
"shelly_trv",
ActionType::Receive,
"temperature",
));
Ok(())
}
}