1#![doc = include_str!("../README.md")]
2
3pub mod config;
4#[cfg(feature = "parsers")]
5pub mod parsers;
6#[cfg(test)]
7mod tests;
8pub mod value;
9
10use crate::value::SerdeError;
11pub use crate::{
12 config::{Config, ConfigBuilder},
13 value::{json, Value},
14};
15use std::{
16 borrow::Cow, error::Error as StdError, fmt::Debug, io::Error as IoError,
17 result::Result as StdResult,
18};
19
20pub type Result<T> = StdResult<T, Error>;
22
23type AnyError = Box<dyn StdError + Send + Sync + 'static>;
24
25pub type AnyResult<T> = StdResult<T, AnyError>;
27
28type CowString<'a> = Cow<'a, str>;
29type AnyParser = Box<dyn Parse>;
30
31pub const DEFAULT_KEYS_SEPARATOR: &str = ":";
33
34#[non_exhaustive]
36#[derive(thiserror::Error, Debug)]
37pub enum Error {
38 #[error("Failed to {0} path: '{1}' with empty key path separator")]
39 EmptySeparator(&'static str, String),
40 #[error("Mapping object expected")]
41 NotMap,
42 #[error("{1}")]
43 SerdeError(#[source] SerdeError, Cow<'static, str>),
44 #[error("Failed to parse value for parser #{1}")]
45 ParseValue(#[source] AnyError, usize),
46 #[error("{1}")]
47 IO(#[source] IoError, Cow<'static, str>),
48}
49
50#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
52pub enum MergeCase {
53 #[default]
55 Auto,
56 Sensitive,
58 Insensitive,
60}
61
62pub trait Case {
64 #[inline]
66 fn is_case_sensitive(&self) -> bool {
67 true
68 }
69}
70
71pub trait Parse: Case {
73 fn parse(&mut self, value: &Value) -> AnyResult<Value>;
82}
83
84impl Case for AnyParser {
85 #[inline]
86 fn is_case_sensitive(&self) -> bool {
87 self.as_ref().is_case_sensitive()
88 }
89}
90
91impl Parse for AnyParser {
92 #[inline]
93 fn parse(&mut self, value: &Value) -> AnyResult<Value> {
94 self.as_mut().parse(value)
95 }
96}
97
98#[inline]
99fn unicase(data: &str) -> String {
100 data.to_lowercase()
101}
102
103#[inline]
104fn normalize_case(data: &str, case_on: bool) -> CowString {
105 if case_on {
106 CowString::Borrowed(data)
107 } else {
108 CowString::Owned(unicase(data))
109 }
110}