use std::env::VarError;
use std::borrow::Cow;
use schemars::{JsonSchema, Schema, SchemaGenerator, json_schema};
use serde::de::Deserializer;
use serde::ser::Serializer;
use serde::{Deserialize, Serialize};
use thiserror::Error;
use super::env_ref::parse_env_ref;
#[derive(Debug, Error)]
pub enum EnvValueError {
#[error("env var {var} is not set")]
NotPresent { var: String },
#[error("env var {var} value is not valid UTF-8")]
NotUnicode { var: String },
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EnvValue {
Literal(String),
EnvRef(String),
}
impl EnvValue {
pub fn from_raw(raw: String) -> Self {
match parse_env_ref(&raw) {
Some(var) => Self::EnvRef(var.to_string()),
None => Self::Literal(raw),
}
}
pub fn resolve(&self) -> Result<String, EnvValueError> {
match self {
Self::Literal(s) => Ok(s.clone()),
Self::EnvRef(var) => std::env::var(var).map_err(|err| match err {
VarError::NotPresent => EnvValueError::NotPresent { var: var.clone() },
VarError::NotUnicode(_) => EnvValueError::NotUnicode { var: var.clone() },
}),
}
}
}
impl Serialize for EnvValue {
fn serialize<S: Serializer>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> {
match self {
Self::Literal(s) => serializer.serialize_str(s),
Self::EnvRef(var) => serializer.collect_str(&format_args!("${{{var}}}")),
}
}
}
impl<'de> Deserialize<'de> for EnvValue {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> std::result::Result<Self, D::Error> {
let raw = String::deserialize(deserializer)?;
Ok(Self::from_raw(raw))
}
}
impl JsonSchema for EnvValue {
fn inline_schema() -> bool {
true
}
fn schema_name() -> Cow<'static, str> {
"EnvValue".into()
}
fn json_schema(_generator: &mut SchemaGenerator) -> Schema {
json_schema!({ "type": "string" })
}
}