use bon::Builder;
use conflaguration::{Settings, Validate};
use serde::{Deserialize, Serialize};
use crate::anchor::AnchorCell;
use crate::ticks::Ticks;
use crate::unix_nanos::UnixNanos;
#[derive(Debug, Clone, PartialEq, Eq, Builder, Serialize, Deserialize, Settings)]
#[settings(prefix = "PROXIMA_CLOCK")]
#[builder(derive(Clone, Debug))]
pub struct AnchorConfig {
#[setting(default = 0)]
#[serde(default)]
#[builder(default)]
pub anchor_ticks: u64,
#[setting(default = 0)]
#[serde(default)]
#[builder(default)]
pub anchor_unix_nanos: u64,
}
impl Default for AnchorConfig {
fn default() -> Self {
Self::builder().build()
}
}
impl Validate for AnchorConfig {
fn validate(&self) -> conflaguration::Result<()> {
Ok(())
}
}
impl AnchorConfig {
#[must_use]
pub fn build(&self) -> AnchorCell {
AnchorCell::new(
Ticks::from_raw(self.anchor_ticks),
UnixNanos::from_nanos(self.anchor_unix_nanos),
)
}
pub fn from_path_then_env<Path: AsRef<std::path::Path>>(
path: Path,
) -> conflaguration::Result<Self> {
conflaguration::from_file_then_env(path.as_ref())
}
}
impl AnchorCell {
#[must_use]
pub fn to_config(&self) -> AnchorConfig {
let (ticks, unix_nanos) = self.get();
AnchorConfig {
anchor_ticks: ticks.as_raw(),
anchor_unix_nanos: unix_nanos.as_nanos(),
}
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod tests {
use super::AnchorConfig;
use crate::ticks::Ticks;
use crate::unix_nanos::UnixNanos;
use conflaguration::Settings;
use std::io::Write;
#[test]
fn default_equals_builder_build() {
assert_eq!(AnchorConfig::default(), AnchorConfig::builder().build());
}
#[test]
fn builder_and_env_loader_agree_on_an_equivalent_config() {
temp_env::with_vars(
[
("PROXIMA_CLOCK_ANCHOR_TICKS", Some("24000000")),
(
"PROXIMA_CLOCK_ANCHOR_UNIX_NANOS",
Some("1753500000000000000"),
),
],
|| {
let from_env = AnchorConfig::from_env().expect("from_env");
let from_builder = AnchorConfig::builder()
.anchor_ticks(24_000_000)
.anchor_unix_nanos(1_753_500_000_000_000_000)
.build();
assert_eq!(from_env, from_builder);
},
);
}
#[test]
fn from_path_then_env_layers_file_under_env() {
let mut file = tempfile::Builder::new()
.suffix(".toml")
.tempfile()
.expect("tempfile");
write!(file, "anchor_ticks = 100\nanchor_unix_nanos = 200\n").expect("write toml");
temp_env::with_var("PROXIMA_CLOCK_ANCHOR_TICKS", Some("999"), || {
let loaded = AnchorConfig::from_path_then_env(file.path()).expect("load");
assert_eq!(loaded.anchor_ticks, 999, "env overrides the file");
assert_eq!(loaded.anchor_unix_nanos, 200, "file value passes through");
});
}
#[test]
fn build_and_to_config_round_trip() {
let config = AnchorConfig::builder()
.anchor_ticks(24_000_000)
.anchor_unix_nanos(1_753_500_000_000_000_000)
.build();
let cell = config.build();
assert_eq!(cell.to_config(), config);
}
#[test]
fn build_lowers_into_a_cell_reading_the_configured_anchor() {
let config = AnchorConfig::builder()
.anchor_ticks(500)
.anchor_unix_nanos(9_000)
.build();
let cell = config.build();
assert_eq!(
cell.get(),
(Ticks::from_raw(500), UnixNanos::from_nanos(9_000))
);
}
}