magpies 0.1.0

Command-line tool for polling and visualizing JSON-formatted time series metrics
Documentation
use std::{
    num::{NonZeroU64, ParseIntError},
    str::FromStr,
    time::{Duration, UNIX_EPOCH},
};

use serde::{Deserialize, Serialize};

#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)]
pub struct SecondsF64(f64);

impl SecondsF64 {
    pub fn to_duration(self) -> Duration {
        Duration::from_secs_f64(self.0)
    }

    pub fn timestamp() -> Self {
        Self(UNIX_EPOCH.elapsed().unwrap_or_default().as_secs_f64())
    }
}

#[derive(
    Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize,
)]
pub struct SecondsU64(u64);

impl SecondsU64 {
    pub const fn new(seconds: u64) -> Self {
        Self(seconds)
    }

    pub const fn get(self) -> u64 {
        self.0
    }

    pub const fn to_duration(self) -> Duration {
        Duration::from_secs(self.0)
    }
}

impl FromStr for SecondsU64 {
    type Err = ParseIntError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let v: u64 = s.parse()?;
        Ok(Self(v))
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
pub struct SecondsNonZeroU64(NonZeroU64);

impl SecondsNonZeroU64 {
    pub const fn new(seconds: NonZeroU64) -> Self {
        Self(seconds)
    }

    pub const fn get(self) -> u64 {
        self.0.get()
    }

    pub const fn to_duration(self) -> Duration {
        Duration::from_secs(self.0.get())
    }
}

impl FromStr for SecondsNonZeroU64 {
    type Err = ParseIntError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let v: NonZeroU64 = s.parse()?;
        Ok(Self(v))
    }
}

pub fn fmt_u64(mut n: u64) -> String {
    if n == 0 {
        return n.to_string();
    }

    let mut s = Vec::new();
    let mut i = 0;
    while n > 0 {
        if i > 0 && i % 3 == 0 {
            s.push(',');
        }
        let d = (n % 10) as u8;
        s.push(char::from(b'0' + d));
        n /= 10;
        i += 1;
    }
    s.reverse();
    s.into_iter().collect()
}

pub fn fmt_i64(n: i64) -> String {
    if n < 0 {
        format!("-{}", fmt_u64(n.unsigned_abs()))
    } else {
        fmt_u64(n.unsigned_abs())
    }
}

pub fn fmt_f64(n: f64, decimal_places: usize) -> String {
    let s = format!("{:.1$}", n, decimal_places);
    let mut iter = s.splitn(2, '.');
    let integer = iter.next().expect("unreachable");
    let fraction = iter.next();

    let mut s = Vec::new();
    for (i, c) in integer.chars().rev().enumerate() {
        if c != '-' && i > 0 && i % 3 == 0 {
            s.push(',');
        }
        s.push(c);
    }
    s.reverse();

    if let Some(fraction) = fraction {
        s.push('.');
        for (i, c) in fraction.chars().enumerate() {
            if i > 0 && i % 3 == 0 {
                s.push(',');
            }
            s.push(c);
        }
    }

    s.into_iter().collect()
}