A simple example on how to make extendable configurations from TOML files.
Example of a common config file you can have for your project.
[base]
param1 = value1
param2 = value2
# optional_param_with_default
# optional_param_no_default
Another example that extends the base
config from the previous example, and includes a new plugin
section.
[base]
param1 = value1
param2 = value2
# optional_param_with_default = value3
# optional_param_no_default = value4
[plugin]
param1 = value1
param2 = value2
# optional_param_with_default = value3
# optional_param_no_default = value4
TOML configurations are loaded into Rust structs. And these structs are composed of Config
and Block
structs:
Here, BaseConfig
defines a block
with fields we want:
#[derive(Default, Debug, Deserialize, PartialEq)]
pub struct BaseConfig {
pub name: String,
pub version: String,
#[serde(default = "default_host")]
pub host: String,
#[serde(default = "default_port")]
pub port: u16,
}
We provide default values for optional fields:
fn default_host() -> String {
"localhost".to_string()
}
fn default_port() -> u16 {
8080
}
Finally we define AppConfig
as our config
, which uses the BaseConfig
as a section.
#[derive(Default, Debug, Deserialize, Serialize, PartialEq)]
pub struct AppConfig {
pub base: BaseConfig,
}
We can use load_config
to read a TOML file and return our AppConfig
struct. However, first we need AppConfig
to implement Config
which is the generic type accepted by the load_config
function.
# the Config trait
pub trait Config: Default + Debug + Serialize + for<'de> Deserialize<'de> {}
# Implementing the trait for other configs
impl Config for AppConfig {}
Thenm, you can call load_config
, using type annotation to specify the config type.
let config: plugin::AppConfig = load_config("path/to/config.toml").unwrap();
We can call to_file
from a parsed config, providing a name, to save it as a TOML file.
config.to_file("test_toml.toml")