use crate::error::BotError;
use crate::verb::Evaluate;
#[derive(Debug)]
pub struct Changed<T: Clone + PartialEq> {
last: std::cell::RefCell<Option<T>>,
}
impl<T: Clone + PartialEq> Changed<T> {
#[must_use]
pub fn new() -> Self {
Self {
last: std::cell::RefCell::new(None),
}
}
}
impl<T: Clone + PartialEq> Default for Changed<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: Clone + PartialEq + 'static> Evaluate<T> for Changed<T> {
fn check(&self, value: &T) -> Result<bool, BotError> {
let mut last = self.last.borrow_mut();
let changed = match last.as_ref() {
Some(prev) => prev != value,
None => true,
};
*last = Some(value.clone());
Ok(changed)
}
fn condition_id(&self) -> &str {
"changed"
}
}
#[derive(Debug)]
pub struct Below<T> {
threshold: T,
}
impl<T: PartialOrd + 'static> Below<T> {
#[must_use]
pub fn new(threshold: T) -> Self {
Self { threshold }
}
}
impl<T: PartialOrd + 'static> Evaluate<T> for Below<T> {
fn check(&self, value: &T) -> Result<bool, BotError> {
Ok(value < &self.threshold)
}
fn condition_id(&self) -> &str {
"threshold::below"
}
}
#[derive(Debug)]
pub struct Above<T> {
threshold: T,
}
impl<T: PartialOrd + 'static> Above<T> {
#[must_use]
pub fn new(threshold: T) -> Self {
Self { threshold }
}
}
impl<T: PartialOrd + 'static> Evaluate<T> for Above<T> {
fn check(&self, value: &T) -> Result<bool, BotError> {
Ok(value > &self.threshold)
}
fn condition_id(&self) -> &str {
"threshold::above"
}
}
#[derive(Debug)]
pub struct Contains {
pattern: String,
}
impl Contains {
#[must_use]
pub fn new(pattern: impl Into<String>) -> Self {
Self {
pattern: pattern.into(),
}
}
}
impl Evaluate<String> for Contains {
fn check(&self, value: &String) -> Result<bool, BotError> {
Ok(value.contains(&self.pattern))
}
fn condition_id(&self) -> &str {
"contains"
}
}
impl Evaluate<super::chat::ChatMessage> for Contains {
fn check(&self, value: &super::chat::ChatMessage) -> Result<bool, BotError> {
Ok(value.text().contains(&self.pattern))
}
fn condition_id(&self) -> &str {
"contains"
}
}
#[must_use]
pub fn contains(pattern: impl Into<String>) -> Contains {
Contains::new(pattern)
}
#[must_use]
pub fn changed<T: Clone + PartialEq>() -> Changed<T> {
Changed::new()
}
#[must_use]
pub fn below<T: PartialOrd + 'static>(threshold: T) -> Below<T> {
Below::new(threshold)
}
#[must_use]
pub fn above<T: PartialOrd + 'static>(threshold: T) -> Above<T> {
Above::new(threshold)
}
pub struct All<T> {
conditions: Vec<Box<dyn Evaluate<T>>>,
}
struct ConditionIds<'a, T>(&'a [Box<dyn Evaluate<T>>]);
impl<T> core::fmt::Debug for ConditionIds<'_, T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_list()
.entries(self.0.iter().map(|condition| condition.condition_id()))
.finish()
}
}
impl<T: 'static> core::fmt::Debug for All<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("All")
.field("conditions", &ConditionIds(&self.conditions))
.finish()
}
}
impl<T: 'static> All<T> {
#[must_use]
pub fn new(conditions: Vec<Box<dyn Evaluate<T>>>) -> Self {
Self { conditions }
}
}
impl<T: 'static> Evaluate<T> for All<T> {
fn check(&self, value: &T) -> Result<bool, BotError> {
for condition in &self.conditions {
if !condition.check(value)? {
return Ok(false);
}
}
Ok(true)
}
fn condition_id(&self) -> &str {
"all"
}
}
pub struct Any<T> {
conditions: Vec<Box<dyn Evaluate<T>>>,
}
impl<T: 'static> core::fmt::Debug for Any<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Any")
.field("conditions", &ConditionIds(&self.conditions))
.finish()
}
}
impl<T: 'static> Any<T> {
#[must_use]
pub fn new(conditions: Vec<Box<dyn Evaluate<T>>>) -> Self {
Self { conditions }
}
}
impl<T: 'static> Evaluate<T> for Any<T> {
fn check(&self, value: &T) -> Result<bool, BotError> {
for condition in &self.conditions {
if condition.check(value)? {
return Ok(true);
}
}
Ok(false)
}
fn condition_id(&self) -> &str {
"any"
}
}