use {
alloc::{borrow::ToOwned, string::String, vec::Vec},
core::fmt::Debug,
derive_more::{Display, Error},
};
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum ConfigOption {
Scalar(String),
List(Vec<String>),
}
impl ConfigOption {
pub fn try_as_bool(&self) -> Result<bool, OptionVariantMismatch> {
let s: &str = self.try_into()?;
match s {
"1" | "true" | "enabled" | "yes" | "on" => Ok(true),
"0" | "false" | "disabled" | "no" | "off" => Ok(false),
_ => Err(OptionVariantMismatch),
}
}
}
impl Debug for ConfigOption {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let inner: &dyn Debug = match self {
Self::Scalar(x) => x as _,
Self::List(x) => x,
};
Debug::fmt(inner, f)
}
}
impl IntoIterator for ConfigOption {
type Item = String;
type IntoIter = IntoIter;
fn into_iter(self) -> Self::IntoIter {
IntoIter(match self {
Self::Scalar(item) => AnyIterInner::Scalar(core::iter::once(item)),
Self::List(items) => AnyIterInner::List(items.into_iter()),
})
}
}
impl<'a> IntoIterator for &'a ConfigOption {
type Item = &'a str;
type IntoIter = Iter<'a>;
fn into_iter(self) -> Self::IntoIter {
Iter(match self {
ConfigOption::Scalar(item) => AnyIterInner::Scalar(core::iter::once(item)),
ConfigOption::List(items) => AnyIterInner::List(items.iter()),
})
}
}
impl From<&str> for ConfigOption {
fn from(value: &str) -> Self {
Self::Scalar(value.to_owned())
}
}
impl From<String> for ConfigOption {
fn from(value: String) -> Self {
Self::Scalar(value)
}
}
impl From<Vec<String>> for ConfigOption {
fn from(value: Vec<String>) -> Self {
Self::List(value)
}
}
impl From<&[String]> for ConfigOption {
fn from(value: &[String]) -> Self {
Self::List(value.to_owned())
}
}
impl From<&[&str]> for ConfigOption {
fn from(value: &[&str]) -> Self {
Self::List(value.iter().copied().map(ToOwned::to_owned).collect())
}
}
impl ConfigOption {
pub fn iter(&self) -> Iter<'_> {
<&Self>::into_iter(self)
}
}
#[must_use]
pub struct Iter<'a>(AnyIterInner<&'a str, core::slice::Iter<'a, String>>);
impl<'a> Iterator for Iter<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<Self::Item> {
match &mut self.0 {
AnyIterInner::Scalar(iter) => iter.next(),
AnyIterInner::List(iter) => iter.next().map(String::as_str),
}
}
}
#[must_use]
pub struct IntoIter(AnyIterInner<String, alloc::vec::IntoIter<String>>);
impl Iterator for IntoIter {
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
match &mut self.0 {
AnyIterInner::Scalar(iter) => iter.next(),
AnyIterInner::List(iter) => iter.next(),
}
}
}
enum AnyIterInner<Item, ListIter> {
Scalar(core::iter::Once<Item>),
List(ListIter),
}
#[derive(Clone, Copy, Display, Debug, Error, PartialEq, Eq)]
#[display("expected variant doesn't match")]
pub struct OptionVariantMismatch;
impl TryFrom<ConfigOption> for String {
type Error = OptionVariantMismatch;
fn try_from(value: ConfigOption) -> Result<Self, Self::Error> {
match value {
ConfigOption::Scalar(s) => Ok(s),
ConfigOption::List(_) => Err(OptionVariantMismatch),
}
}
}
impl TryFrom<ConfigOption> for Vec<String> {
type Error = OptionVariantMismatch;
fn try_from(value: ConfigOption) -> Result<Self, Self::Error> {
match value {
ConfigOption::List(l) => Ok(l),
ConfigOption::Scalar(_) => Err(OptionVariantMismatch),
}
}
}
impl<'a> TryFrom<&'a ConfigOption> for &'a str {
type Error = OptionVariantMismatch;
fn try_from(value: &'a ConfigOption) -> Result<Self, Self::Error> {
match value {
ConfigOption::Scalar(s) => Ok(s),
ConfigOption::List(_) => Err(OptionVariantMismatch),
}
}
}
impl<'a> TryFrom<&'a ConfigOption> for &'a [String] {
type Error = OptionVariantMismatch;
fn try_from(value: &'a ConfigOption) -> Result<Self, Self::Error> {
match value {
ConfigOption::List(l) => Ok(l),
ConfigOption::Scalar(_) => Err(OptionVariantMismatch),
}
}
}