How to set_default() using config-rs crate

How to set_default() using config-rs crate

(Jin Qing's Column, Nov., 2024)

config is a configuration system for Rust applications.

Example of examples\hierarchical-env:

rust 复制代码
#[derive(Debug, Deserialize)]
#[allow(unused)]
struct Database {
    url: String,
}

#[derive(Debug, Deserialize)]
#[allow(unused)]
pub(crate) struct Settings {
    debug: bool,
    database: Database,
}

impl Settings {
    pub(crate) fn new() -> Result<Self, ConfigError> {
        let s = Config::builder()
            .add_source(File::with_name("examples/hierarchical-env/config/default"))
            .build()?;

        // You can deserialize (and thus freeze) the entire configuration as
        s.try_deserialize()
    }
}

ConfigBuilder::set_default sets a default value at key:

rust 复制代码
pub fn set_default<S, T>(self, key: S, value: T) -> Result<Self, ConfigError>
where
    S: AsRef<str>,
    T: Into<Value>,

Such as:

rust 复制代码
        let s = Config::builder()
            .set_default("debug", true)?
            ...

But how to set a member like Database struct?

rust 复制代码
        let s = Config::builder()
            .set_default("database", Database{url: "".into()})?
            ...

fails:

error[E0277]: the trait bound `ValueKind: From<Database>` is not satisfied
   --> examples\hierarchical-env\settings.rs:50:38
    |
50  |             .set_default("database", Database{url: "".into()})?
    |              -----------             ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<Database>` is not implemented for `ValueKind`, which is required by `Database: Into<Value>`
    |              |
    |              required by a bound introduced by this call
    |
    = help: the following other types implement trait `From<T>`:
              <ValueKind as From<&'a str>>
              ...
              <ValueKind as From<i32>>
            and 9 others
    = note: required for `Database` to implement `Into<ValueKind>`
    = note: required for `Value` to implement `From<Database>`
    = note: 1 redundant requirement hidden
    = note: required for `Database` to implement `Into<Value>`
note: required by a bound in `ConfigBuilder::<St>::set_default`
   --> D:\github\config-rs\src\builder.rs:156:12
    |
153 |     pub fn set_default<S, T>(mut self, key: S, value: T) -> Result<Self>
    |            ----------- required by a bound in this associated function
...
156 |         T: Into<Value>,
    |            ^^^^^^^^^^^ required by this bound in `ConfigBuilder::<St>::set_default`

The above links suggest to use ValueKind:

        let s = Config::builder()
            .set_default(
                "database",
                ValueKind::Table(HashMap::<String, Value>::from([("url".into(), "".into())])),
            )?
            ...

The ergonomic way is to implement From<Database> for ValueKind:

rust 复制代码
impl From<Database> for ValueKind {
    fn from(value: Database) -> Self {
        let t = HashMap::<String, Value>::from([("url".into(), value.url.into())]);
        ValueKind::Table(t)
    }
}
rust 复制代码
        let s = Config::builder()
            .set_default("database", Database { url: "".into() })?
            ...

For nested struct:

rust 复制代码
#[derive(Debug, Default, Deserialize)]
#[allow(unused)]
struct Database {
    url: String,
    other: Other,
}

#[derive(Debug, Default, Deserialize)]
#[allow(unused)]
struct Other {}

impl From<Database> for ValueKind {
    fn from(value: Database) -> Self {
        let t = HashMap::<String, Value>::from([
            ("url".into(), value.url.into()),
            ("other".into(), value.other.into()),
        ]);
        ValueKind::Table(t)
    }
}

impl From<Other> for ValueKind {
    fn from(_value: Other) -> Self {
        ValueKind::Table(HashMap::new())
    }
}
rust 复制代码
        let s = Config::builder()
            .set_default("database", Database::default())?
            ...
相关推荐
老猿讲编程2 小时前
用示例来看C2Rust工具的使用和功能介绍
rust
许野平4 小时前
Rust: 利用 chrono 库实现日期和字符串互相转换
开发语言·后端·rust·字符串·转换·日期·chrono
‍。。。15 小时前
使用Rust实现http/https正向代理
http·https·rust
Source.Liu15 小时前
【用Rust写CAD】第二章 第四节 函数
开发语言·rust
monkey_meng15 小时前
【Rust中的迭代器】
开发语言·后端·rust
余衫马15 小时前
Rust-Trait 特征编程
开发语言·后端·rust
monkey_meng15 小时前
【Rust中多线程同步机制】
开发语言·redis·后端·rust
hikktn1 天前
如何在 Rust 中实现内存安全:与 C/C++ 的对比分析
c语言·安全·rust
睡觉谁叫~~~1 天前
一文解秘Rust如何与Java互操作
java·开发语言·后端·rust