use std::path::PathBuf;
use compose_spec_macros::{AsShort, FromShort};
use serde::{Deserialize, Deserializer, Serialize};
use crate::{
serde::{default_true, skip_true, ItemOrListVisitor},
AsShort, ShortOrLong,
};
type List = Vec<ShortOrLong<PathBuf, Config>>;
#[derive(Serialize, Debug, Clone, PartialEq, Eq)]
#[serde(untagged)]
pub enum EnvFile {
Single(PathBuf),
List(List),
}
impl EnvFile {
pub fn as_single(&self) -> Option<&PathBuf> {
match self {
Self::Single(path) => Some(path),
Self::List(list) if list.len() == 1 => list.first().and_then(ShortOrLong::as_short),
Self::List(_) => None,
}
}
#[must_use]
pub fn into_list(self) -> List {
match self {
Self::Single(path) => vec![path.into()],
Self::List(list) => list,
}
}
}
impl From<PathBuf> for EnvFile {
fn from(value: PathBuf) -> Self {
Self::Single(value)
}
}
impl From<String> for EnvFile {
fn from(value: String) -> Self {
Self::Single(value.into())
}
}
impl From<List> for EnvFile {
fn from(value: List) -> Self {
Self::List(value)
}
}
impl<I> FromIterator<I> for EnvFile
where
I: Into<ShortOrLong<PathBuf, Config>>,
{
fn from_iter<T: IntoIterator<Item = I>>(iter: T) -> Self {
Self::List(iter.into_iter().map(Into::into).collect())
}
}
impl<'de> Deserialize<'de> for EnvFile {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
ItemOrListVisitor::<_, PathBuf, List>::new("a string or list of strings or maps")
.deserialize(deserializer)
}
}
#[derive(Serialize, Deserialize, AsShort, FromShort, Debug, Clone, PartialEq, Eq)]
pub struct Config {
#[as_short(short)]
pub path: PathBuf,
#[serde(default = "default_true", skip_serializing_if = "skip_true")]
#[as_short(default = default_true, if_fn = skip_true)]
pub required: bool,
}
impl From<String> for Config {
fn from(value: String) -> Self {
PathBuf::from(value).into()
}
}