inline_config/
lib.rs

1//! Effortlessly embed config modules and access with any compatible types.
2//!
3//! ## Example
4//!
5//! Below is a basic example illustrating how to declare a config module and access data from it.
6//!
7//! ```
8//! use inline_config::{config, path};
9//!
10//! // Declare a config module containing literal sources.
11//! // With `export(static = MY_CONFIG)`,
12//! // a static variable `MY_CONFIG` will be brought into scope.
13//! #[config(export(static = MY_CONFIG))]
14//! mod my_config {
15//!     // When there are multiple sources,
16//!     // latter ones overwrite former ones.
17//!     toml!(
18//!         r#"
19//!         title = "TOML example"
20//!
21//!         [server]
22//!         owner = "Tom"
23//!         timeout = 2000
24//!         ports = [ 8000, 8001, 8002 ]
25//!         "#
26//!     );
27//!     toml!(
28//!         r#"
29//!         [server]
30//!         timeout = 5000
31//!         "#
32//!     );
33//!
34//!     // Including a file from disk is also possible,
35//!     // see `examples/include.rs`.
36//! }
37//!
38//! // Use `Index`, `From` traits to access data.
39//! // Different types may be accessible from a field.
40//! let title: &str = MY_CONFIG[path!(title)].into();
41//! assert_eq!("TOML example", title);
42//! let title: String = MY_CONFIG[path!(title)].into();
43//! assert_eq!("TOML example", title);
44//!
45//! // A deeper path.
46//! let owner: &str = MY_CONFIG[path!(server.owner)].into();
47//! assert_eq!("Tom", owner);
48//!
49//! // Any numerical types.
50//! let timeout: u32 = MY_CONFIG[path!(server.timeout)].into();
51//! assert_eq!(5000, timeout);
52//! let timeout: f32 = MY_CONFIG[path!(server.timeout)].into();
53//!
54//! // A homogeneous array can be accessed as `Vec<T>`.
55//! let ports: Vec<u64> = MY_CONFIG[path!(server.ports)].into();
56//! assert_eq!([8000, 8001, 8002].to_vec(), ports);
57//! ```
58//!
59//! See [`config`] and [`path!()`] for specs on those macros.
60//!
61//! ## Compatible types
62//!
63//! Internally, data from config sources are parsed into one of the seven variants:
64//! booleans, unsigned integers, signed integers, floats, strings, arrays, tables.
65//! Each of them has a specific storage representation, and have different compatible types.
66//!
67//! | Representation variant | Compatible types |
68//! | --- | --- |
69//! | Boolean | [`bool`] |
70//! | Unsigned Integer | [`i8`], [`i16`], [`i32`], [`i64`], [`i128`], [`isize`],<br>[`u8`], [`u16`], [`u32`], [`u64`], [`u128`], [`usize`],<br>[`f32`], [`f64`] |
71//! | Signed Integer | [`i8`], [`i16`], [`i32`], [`i64`], [`i128`], [`isize`],<br>[`f32`], [`f64`] |
72//! | Float | [`f32`], [`f64`] |
73//! | String | [`&str`], [`String`] |
74//! | Array | [`Vec<T>`] if homogeneous,<br>User-defined structs deriving [`ConfigData`] with unnamed fields |
75//! | Table | [`std::collections::BTreeMap<&str, T>`] if homogeneous,<br>[`std::collections::BTreeMap<String, T>`] if homogeneous,<br>[`indexmap::IndexMap<&str, T>`] if homogeneous\*,<br>[`indexmap::IndexMap<String, T>`] if homogeneous\*,<br>User-defined structs deriving [`ConfigData`] with named fields |
76//!
77//! \* Only available when enabling `indexmap` feature flag.
78//!
79//! [`indexmap::IndexMap<&str, T>`]: https://docs.rs/indexmap/latest/indexmap/map/struct.IndexMap.html
80//! [`indexmap::IndexMap<String, T>`]: https://docs.rs/indexmap/latest/indexmap/map/struct.IndexMap.html
81//!
82//! ### Container types
83//!
84//! Arrays and tables are both "containers" in the sense of containing children data, therefore you can use [`path!()`] to access children data.
85//! The only difference between the two containers is that arrays have unnamed but ordered fields, while tables have named but unamed fields.
86//! This suggests you should use indices when accessing a field of an array, but use names when accessing a field of a table.
87//!
88//! Note that they are inhomogeneous in general (children are of different types).
89//! You need to define custom types and derive [`ConfigData`] if you want to access structured data.
90//! Define structs with unnamed fields to model an array, while structs with named fields to model a table.
91//! Specially, in the case when they do contain homogeneous data,
92//! arrays can be accessed as [`Vec<T>`], and tables can be accessed as [`std::collections::BTreeMap<&str, T>`] or [`std::collections::BTreeMap<String, T>`],
93//! as long as the representation of children can be accessed as `T`.
94//! For containers, this type compatibility comes with a recursive sense.
95//! There's a relevant concept from functional programming, known as [transmogrifying].
96//!
97//! [transmogrifying]: https://docs.rs/frunk/0.4.4/frunk/#transmogrifying
98//!
99//! ## Feature flags
100//!
101//! * `json` - supports JSON file format. Enabled by default.
102//! * `yaml` - supports YAML file format. Enabled by default.
103//! * `toml` - supports TOML file format. Enabled by default.
104//! * `indexmap` - enables preserving orders of tables.
105
106pub use inline_config_macros::*;
107
108#[doc(hidden)]
109pub mod __private {
110    use std::marker::PhantomData;
111
112    // Borrowed from `frunk_core::labelled::chars`.
113    pub mod chars {
114        macro_rules! create_enums_for {
115            ($($ident:ident)*) => {
116                $(
117                    #[allow(non_camel_case_types)]
118                    pub struct $ident;
119                )*
120            };
121        }
122
123        create_enums_for!(
124            A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
125            a b c d e f g h i j k l m n o p q r s t u v w x y z
126            _0 _1 _2 _3 _4 _5 _6 _7 _8 _9 __
127        );
128
129        // For all other chars.
130        pub struct Ch<const CHAR: char>;
131    }
132
133    #[derive(Default)]
134    pub struct KeyIndex<const INDEX: usize>;
135
136    pub struct KeyName<Name>(PhantomData<Name>);
137
138    impl<Name> Default for KeyName<Name> {
139        fn default() -> Self {
140            Self(PhantomData)
141        }
142    }
143
144    #[derive(Default)]
145    pub struct PathNil;
146
147    #[derive(Default)]
148    pub struct PathCons<K, KS>(K, KS);
149}