titanrt 0.7.0

Typed reactive runtime for real-time systems
Documentation
use std::{str::FromStr, time::Duration};

use anyhow::{Result, anyhow};
use regex::Regex;
use serde::{Deserialize, Serialize};

use super::TimeUnit;

#[derive(Debug, Clone, PartialEq)]
pub enum TimeframeType {
    StringValue(String),
    StructValue(Timeframe),
}

#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct Timeframe {
    pub value: u64,
    pub unit: TimeUnit,
}

impl Timeframe {
    pub fn new(value: u64, unit: TimeUnit) -> Self {
        Self { value, unit }
    }

    pub fn convert(&self, target_unit: TimeUnit) -> u64 {
        self.unit.convert(self.value, target_unit)
    }

    pub fn duration(&self) -> Duration {
        self.unit.duration(self.value)
    }
}

impl FromStr for Timeframe {
    type Err = anyhow::Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let trimmed = s.trim();
        let re = Regex::new(r"(\d+)([a-zA-Z]+)")
            .map_err(|_| anyhow!("Ошибка при компиляции регулярного выражения"))?;
        let caps = re
            .captures(trimmed)
            .ok_or_else(|| anyhow!("Неверный формат таймфрейма: {}", trimmed))?;

        let value_str = &caps[1];
        let unit_str = &caps[2].to_lowercase();
        let value = value_str
            .parse()
            .map_err(|_| anyhow!("Неверный формат таймфрейма: {}", trimmed))?;

        let unit = match unit_str.as_str() {
            "sec" => TimeUnit::Second,
            "min" => TimeUnit::Minute,
            "h" => TimeUnit::Hour,
            "d" => TimeUnit::Day,
            "w" => TimeUnit::Week,
            "m" => TimeUnit::Month,
            _ => {
                return Err(anyhow!(
                    "Не поддерживаемая единица таймфрейма: '{}'",
                    unit_str
                ));
            }
        };

        Ok(Timeframe { value, unit })
    }
}