#![doc = include_str!("../README.md")]
pub mod config;
#[cfg(feature = "parsers")]
pub mod parsers;
#[cfg(test)]
mod tests;
pub mod value;
use crate::value::SerdeError;
pub use crate::{
config::{Config, ConfigBuilder},
value::{json, Value},
};
use std::{
borrow::Cow, error::Error as StdError, fmt::Debug, io::Error as IoError,
result::Result as StdResult,
};
pub type Result<T> = StdResult<T, Error>;
type AnyError = Box<dyn StdError + Send + Sync + 'static>;
pub type AnyResult<T> = StdResult<T, AnyError>;
type CowString<'a> = Cow<'a, str>;
type AnyParser = Box<dyn Parse>;
pub const DEFAULT_KEYS_SEPARATOR: &str = ":";
#[non_exhaustive]
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("Failed to {0} path: '{1}' with empty key path separator")]
EmptySeparator(&'static str, String),
#[error("Mapping object expected")]
NotMap,
#[error("{1}")]
SerdeError(#[source] SerdeError, Cow<'static, str>),
#[error("Failed to parse value for parser #{1}")]
ParseValue(#[source] AnyError, usize),
#[error("{1}")]
IO(#[source] IoError, Cow<'static, str>),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum MergeCase {
#[default]
Auto,
Sensitive,
Insensitive,
}
pub trait Case {
#[inline]
fn is_case_sensitive(&self) -> bool {
true
}
}
pub trait Parse: Case {
fn parse(&mut self, value: &Value) -> AnyResult<Value>;
}
impl Case for AnyParser {
#[inline]
fn is_case_sensitive(&self) -> bool {
self.as_ref().is_case_sensitive()
}
}
impl Parse for AnyParser {
#[inline]
fn parse(&mut self, value: &Value) -> AnyResult<Value> {
self.as_mut().parse(value)
}
}
#[inline]
fn unicase(data: &str) -> String {
data.to_lowercase()
}
#[inline]
fn normalize_case(data: &str, case_on: bool) -> CowString {
if case_on {
CowString::Borrowed(data)
} else {
CowString::Owned(unicase(data))
}
}