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 天前
Mojo vs Python vs Rust: 2025年搞AI,该学哪个?
后端·python·rust
大卫小东(Sheldon)2 天前
写了一个BBP算法的实现库,欢迎讨论
数学·rust
echoarts2 天前
Rayon Rust中的数据并行库入门教程
开发语言·其他·算法·rust
ftpeak3 天前
从零开始使用 axum-server 构建 HTTP/HTTPS 服务
网络·http·https·rust·web·web app
咸甜适中3 天前
rust语言 (1.88) 学习笔记:客户端和服务器端同在一个项目中
笔记·学习·rust
咸甜适中3 天前
rust语言 (1.88) egui (0.32.2) 学习笔记(逐行注释)(二十八)使用图片控件显示图片
笔记·学习·rust·egui
huli33203 天前
pingora_web:首款基于 Cloudflare Pingora 的企业级 Rust Web 框架
rust
Pomelo_刘金3 天前
如何优雅地抽离 Rust 子工程:以 rumqttd 为例
rust
几颗流星3 天前
Rust 常用语法速记 - 错误处理
后端·rust
向上的车轮3 天前
如何用 Rust 重写 SQLite 数据库(二):是否有市场空间?
数据库·rust·sqlite