mod cipherstash;
mod cipherstash_secret;
mod file;
mod user;
use super::errors::ConfigError;
use serde::{Deserialize, Deserializer, Serialize};
use std::fmt::Debug;

pub use cipherstash::{CipherStashConfigFile, CipherStashConfigFileBuilder};
pub use cipherstash_secret::{CipherStashSecretConfigFile, CipherStashSecretConfigFileBuilder};
pub use file::{FileSource, IntoFileSource};
pub use user::UserConfigSource;

// TODO: Document this
pub trait ConfigSource<B>: Debug {
    fn add_to_builder(&self, builder: B) -> Result<B, ConfigError>;
}

/// Wrapper used to disallow a field in a TOML file.
/// If a field is specified as `Disallowed`, it will always fail to deserialize.
#[derive(Debug)]
pub struct Disallowed<T>(#[allow(unused)] Option<T>);

impl<'de, T> Deserialize<'de> for Disallowed<T>
where
    T: Deserialize<'de>,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let value = Option::<T>::deserialize(deserializer)?;
        if value.is_some() {
            Err(serde::de::Error::custom(
                "Field is not allowed in this file",
            ))
        } else {
            Ok(Disallowed(value))
        }
    }
}

impl<T> Serialize for Disallowed<T> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        if self.0.is_some() {
            return Err(serde::ser::Error::custom("This field is not allowed"));
        }
        serializer.serialize_none()
    }
}
