config/
format.rs

1use std::error::Error;
2
3use crate::error::{ConfigError, Unexpected};
4use crate::map::Map;
5use crate::value::{Value, ValueKind};
6
7/// Describes a format of configuration source data
8///
9/// Implementations of this trait can be used to convert [`File`](crate::File) sources to configuration data.
10///
11/// There can be various formats, some of them provided by this library, such as JSON, Yaml and other.
12/// This trait enables users of the library to easily define their own, even proprietary formats without
13/// the need to alter library sources.
14///
15/// What is more, it is recommended to use this trait with custom [`Source`](crate::Source)s and their async counterparts.
16pub trait Format {
17    /// Parses provided content into configuration values understood by the library.
18    ///
19    /// It also allows specifying optional URI of the source associated with format instance that can facilitate debugging.
20    fn parse(
21        &self,
22        uri: Option<&String>,
23        text: &str,
24    ) -> Result<Map<String, Value>, Box<dyn Error + Send + Sync>>;
25}
26
27// Have a proper error fire if the root of a file is ever not a Table
28pub(crate) fn extract_root_table(
29    uri: Option<&String>,
30    value: Value,
31) -> Result<Map<String, Value>, Box<dyn Error + Send + Sync>> {
32    match value.kind {
33        ValueKind::Table(map) => Ok(map),
34        ValueKind::Nil => Err(Unexpected::Unit),
35        ValueKind::Array(_value) => Err(Unexpected::Seq),
36        ValueKind::Boolean(value) => Err(Unexpected::Bool(value)),
37        ValueKind::I64(value) => Err(Unexpected::I64(value)),
38        ValueKind::I128(value) => Err(Unexpected::I128(value)),
39        ValueKind::U64(value) => Err(Unexpected::U64(value)),
40        ValueKind::U128(value) => Err(Unexpected::U128(value)),
41        ValueKind::Float(value) => Err(Unexpected::Float(value)),
42        ValueKind::String(value) => Err(Unexpected::Str(value)),
43    }
44    .map_err(|err| ConfigError::invalid_root(uri, err))
45    .map_err(|err| Box::new(err) as Box<dyn Error + Send + Sync>)
46}