use crate::{
Conf, ConfBuilder, ConfContext, ConfSerde, ConfSerdeContext, ConfSerdeSeed, Error, InnerError,
ParsedArgs, introspection::ConfigEvent,
};
use serde::de::{DeserializeSeed, Deserializer};
use std::{cell::RefCell, ffi::OsString, marker::PhantomData};
impl<S, F> ConfBuilder<S, F>
where
S: ConfSerde,
F: FnMut(&dyn ConfigEvent),
{
pub fn doc<'de, D: Deserializer<'de>>(
self,
document_name: impl Into<String>,
deserializer: D,
) -> ConfSerdeBuilder<'de, D, S, F> {
ConfSerdeBuilder {
inner: self,
document_name: document_name.into(),
document: deserializer,
_marker: Default::default(),
}
}
}
pub struct ConfSerdeBuilder<'de, D, S, F>
where
S: ConfSerde,
F: FnMut(&dyn ConfigEvent),
D: Deserializer<'de>,
{
inner: ConfBuilder<S, F>,
document_name: String,
document: D,
_marker: PhantomData<&'de u8>,
}
impl<'de, D, S, F> ConfSerdeBuilder<'de, D, S, F>
where
S: ConfSerde,
F: FnMut(&dyn ConfigEvent),
D: Deserializer<'de>,
{
pub fn env<K, V>(mut self, env: impl IntoIterator<Item = (K, V)>) -> Self
where
K: Into<OsString>,
V: Into<OsString>,
{
self.inner = self.inner.env(env);
self
}
pub fn args(mut self, args: impl IntoIterator<Item: Into<OsString>>) -> Self {
self.inner = self.inner.args(args);
self
}
pub fn config_logger<F2: FnMut(&dyn ConfigEvent)>(
self,
f: F2,
) -> ConfSerdeBuilder<'de, D, S, F2> {
ConfSerdeBuilder {
inner: self.inner.config_logger(f),
document_name: self.document_name,
document: self.document,
_marker: PhantomData,
}
}
pub fn parse(self) -> S {
match self.try_parse() {
Ok(result) => result,
Err(err) => err.exit(),
}
}
pub fn try_parse(self) -> Result<S, Error> {
let Self {
inner,
document,
document_name,
..
} = self;
let (parsed_env, args, mut config_logger) = inner.into_tuple();
let config_logger_refcell = config_logger
.as_mut()
.map(|cb| RefCell::new(&mut *cb as &mut dyn FnMut(&dyn ConfigEvent)));
let config_logger = config_logger_refcell.as_ref();
let program_options = <S as Conf>::PROGRAM_OPTIONS.iter().collect::<Vec<_>>();
let mut parser = <S as Conf>::get_parser(&parsed_env, program_options)?;
let arg_matches = parser.parse(args)?;
let parsed_args = ParsedArgs::new(&arg_matches, &parser);
let conf_context = ConfContext::new(
parsed_args,
&parsed_env,
parser.get_program_options(),
config_logger,
);
let conf_serde_context = ConfSerdeContext::new(conf_context, document_name.as_str());
let seed = ConfSerdeSeed::<S>::from(conf_serde_context);
DeserializeSeed::<'de>::deserialize(seed, document)
.expect("Internal error, Deserializer Error should not be returned here")
.map_err(|errs| InnerError::vec_to_clap_error(errs, parser.get_command()))
}
}