use std::path::{Path, PathBuf};
use crate::error::Error;
use crate::source::{Probe, Source, SourceKind};
use crate::sources::util::{normalize, read_capped};
#[derive(Debug, Clone)]
pub struct EnvOverride {
var: String,
}
impl EnvOverride {
#[must_use]
pub fn new(var: impl Into<String>) -> Self {
Self { var: var.into() }
}
}
impl Source for EnvOverride {
fn kind(&self) -> SourceKind {
SourceKind::EnvOverride
}
fn probe(&self) -> Result<Option<Probe>, Error> {
match std::env::var(&self.var) {
Ok(value) => Ok(normalize(&value).map(|v| Probe::new(SourceKind::EnvOverride, v))),
Err(_) => Ok(None),
}
}
}
#[derive(Debug, Clone)]
pub struct FileOverride {
path: PathBuf,
}
impl FileOverride {
#[must_use]
pub fn new(path: impl Into<PathBuf>) -> Self {
Self { path: path.into() }
}
#[must_use]
pub fn path(&self) -> &Path {
&self.path
}
}
impl Source for FileOverride {
fn kind(&self) -> SourceKind {
SourceKind::FileOverride
}
fn probe(&self) -> Result<Option<Probe>, Error> {
match read_capped(&self.path) {
Ok(content) => Ok(normalize(&content).map(|v| Probe::new(SourceKind::FileOverride, v))),
Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(None),
Err(source) => Err(Error::Io {
source_kind: SourceKind::FileOverride,
path: self.path.clone(),
source,
}),
}
}
}
pub struct FnSource<F> {
kind: SourceKind,
f: F,
}
impl<F> FnSource<F>
where
F: Fn() -> Result<Option<String>, Error> + Send + Sync,
{
pub fn new(kind: SourceKind, f: F) -> Self {
Self { kind, f }
}
}
impl<F> std::fmt::Debug for FnSource<F> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FnSource")
.field("kind", &self.kind)
.finish_non_exhaustive()
}
}
impl<F> Source for FnSource<F>
where
F: Fn() -> Result<Option<String>, Error> + Send + Sync,
{
fn kind(&self) -> SourceKind {
self.kind
}
fn probe(&self) -> Result<Option<Probe>, Error> {
Ok((self.f)()?
.as_deref()
.and_then(normalize)
.map(|v| Probe::new(self.kind, v)))
}
}