#![deny(missing_docs)]
use crate::error::{RrdError, RrdResult};
use std::time;
pub mod data;
pub mod error;
pub mod ops;
pub mod util;
pub type Timestamp = std::time::SystemTime;
pub(crate) trait TimestampExt {
fn try_as_time_t(&self) -> RrdResult<rrd_sys::time_t>;
fn try_from_time_t(time_t: rrd_sys::time_t) -> RrdResult<Self>
where
Self: Sized;
}
impl TimestampExt for Timestamp {
fn try_as_time_t(&self) -> RrdResult<rrd_sys::time_t> {
let duration = self.duration_since(std::time::UNIX_EPOCH).map_err(|_| {
RrdError::InvalidArgument("timestamp must be after UNIX_EPOCH".to_string())
})?;
i64::try_from(duration.as_secs())
.map_err(|_| RrdError::InvalidArgument("timestamp is too large for librrd".to_string()))
}
fn try_from_time_t(time_t: rrd_sys::time_t) -> RrdResult<Self> {
let secs = u64::try_from(time_t).map_err(|_| {
RrdError::Internal(format!("librrd returned negative timestamp {time_t}"))
})?;
Ok(time::UNIX_EPOCH + time::Duration::from_secs(secs))
}
}
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConsolidationFn {
Avg,
Min,
Max,
Last,
}
impl ConsolidationFn {
pub(crate) fn as_arg_str(&self) -> &str {
match self {
ConsolidationFn::Avg => "AVERAGE",
ConsolidationFn::Min => "MIN",
ConsolidationFn::Max => "MAX",
ConsolidationFn::Last => "LAST",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn timestamp_before_epoch_is_invalid_argument() {
let timestamp = time::UNIX_EPOCH - time::Duration::from_secs(1);
assert_eq!(
Err(RrdError::InvalidArgument(
"timestamp must be after UNIX_EPOCH".to_string()
)),
timestamp.try_as_time_t()
);
}
#[test]
fn negative_time_t_is_internal_error() {
assert_eq!(
Err(RrdError::Internal(
"librrd returned negative timestamp -1".to_string()
)),
Timestamp::try_from_time_t(-1)
);
}
}