carbond_lib/metrics/
metric.rs1use async_trait::async_trait;
6use log::trace;
7use std::{fs, path::Path, str::FromStr};
8use thiserror::Error;
9use tokio::io;
10
11use crate::fs::create_file;
12
13#[derive(Error, Debug)]
14pub enum MetricError {
15 #[error("Could not read/write metric at {location}.")]
16 Io {
17 location: String,
18 #[source]
19 source: io::Error,
20 },
21 #[error("error while interacting with fs")]
22 Fs(#[from] io::Error),
23 #[error("Format of metric \"{0}\" is invalid for \"{1}\".")]
24 ParseMetric(String, String),
25 #[error("{0}: {1}.")]
26 Other(String, String),
27}
28
29#[async_trait]
30pub trait Metric: FromStr + ToString {
31 type Unit;
32 const NAME: &'static str;
33
34 fn get_value(&self) -> Self::Unit;
35 fn neutral() -> Self;
36 fn from_value(value: Self::Unit) -> Self;
37
38 async fn try_read_from_fs(file_path: &str) -> Result<Self, MetricError> {
40 let raw = tokio::fs::read_to_string(file_path)
41 .await
42 .map_err(|source| MetricError::Io {
43 location: file_path.to_owned(),
44 source,
45 })?;
46 let instance = Self::from_str(&raw)
47 .map_err(|_| MetricError::ParseMetric(Self::NAME.to_owned(), file_path.to_owned()))?;
48 Ok(instance)
49 }
50
51 fn try_read_from_fs_sync(file_path: &str) -> Result<Self, MetricError> {
53 let raw = fs::read_to_string(file_path).map_err(|source| MetricError::Io {
54 location: file_path.to_owned(),
55 source,
56 })?;
57 let instance = Self::from_str(&raw)
58 .map_err(|_| MetricError::ParseMetric(Self::NAME.to_owned(), file_path.to_owned()))?;
59 Ok(instance)
60 }
61
62 async fn try_read_from_path(file_path: &Path) -> Result<Self, MetricError> {
64 let path = file_path.to_str().ok_or(MetricError::Other(
65 Self::NAME.to_owned(),
66 "Could not convert path".to_owned(),
67 ))?;
68 Self::try_read_from_fs(path).await
69 }
70
71 fn try_read_from_path_sync(file_path: &Path) -> Result<Self, MetricError> {
73 let path = file_path.to_str().ok_or(MetricError::Other(
74 Self::NAME.to_owned(),
75 "Could not convert path".to_owned(),
76 ))?;
77 Self::try_read_from_fs_sync(path)
78 }
79
80 async fn try_write_to_fs(&self, file_path: &str) -> Result<(), MetricError> {
82 let path = Path::new(file_path);
83 trace!("Write {:#?} to {:#?}", self.to_string(), file_path);
84 create_file(path).await.map_err(|source| MetricError::Io {
85 location: file_path.to_owned(),
86 source,
87 })?;
88 tokio::fs::write(&path, self.to_string())
89 .await
90 .map_err(|source| MetricError::Io {
91 location: file_path.to_owned(),
92 source,
93 })?;
94 Ok(())
95 }
96
97 async fn try_write_to_path(&self, file_path: &Path) -> Result<(), MetricError> {
99 let path = file_path.to_str().ok_or(MetricError::Other(
100 Self::NAME.to_owned(),
101 "Could not convert path".to_owned(),
102 ))?;
103 self.try_write_to_fs(path).await
104 }
105}