DocumentsPersonal
Configuration Deserialization
Configuration Deserialization
Type
Topic
Status
Published
Created
Jul 8, 2026
Updated
Jul 8, 2026

Configuration Deserialization in OpenDAL#

OpenDAL maps flat HashMap<String, String> key-value pairs — sourced from environment variables, URI query parameters, or in-process code — into typed Rust service configuration structs. The pipeline has three layers: the Configurator trait, the ConfigDeserializer bridge, and the serde-derived config structs.

The Configurator Trait#

Every service config struct implements Configurator, defined in core/src/types/builder.rs. The trait provides a default from_iter method that:

  1. Collects the iterator of (String, String) pairs into a HashMap.
  2. Wraps it in a ConfigDeserializer.
  3. Calls Self::deserialize(cfg), mapping errors to ErrorKind::ConfigInvalid.

This means any type with #[derive(Deserialize)] automatically supports deserialization from flat string maps — no manual parsing code required per service.

ConfigDeserializer — The Bridge#

ConfigDeserializer lives in core/src/raw/serde_util.rs. It wraps serde's MapDeserializer over a custom Pairs iterator. Key behaviors:

  • Key normalization: All map keys are lowercased before dispatching to struct fields , so DEFAULT_TTL and default_ttl both work.
  • Typed Pair deserializer: Each value is wrapped in a Pair that implements custom deserialize_* methods for every primitive type, producing error messages that include the key name and raw value for debuggability.
  • Bool aliases: In addition to "true"/"false", the values "on" and "off" are accepted as booleans .
  • Option<T> handling: An empty string "" deserializes as None; a non-empty string delegates to visit_some .
  • Sequence handling: A comma-separated string like "us-east-1,eu-west-1" deserializes as a Vec<T> by splitting on , and trimming whitespace. An empty string becomes an empty Vec rather than [""] .

Service Config Structs#

Service configs are plain Rust structs with #[derive(Default, Debug, Serialize, Deserialize)] and #[serde(default)]. The #[serde(default)] attribute means that any key absent from the map falls back to the field's Default value — no error for missing optional keys.

Examples:

  • MemcachedConfig: fields for endpoint, root, credentials, and default_ttl: Option<Duration>.
  • RedisConfig: fields for endpoint, cluster_endpoints, credentials, db: i64, and default_ttl: Option<Duration>.

Duration Fields#

Duration-typed fields (e.g., default_ttl) appear in multiple service configs and are marked Option<Duration>. Because std::time::Duration has a native serde Deserialize implementation (from the standard serde support, serialized as a {secs, nanos} struct), these fields work when deserializing from structured formats like JSON or TOML. However, ConfigDeserializer only handles flat string values — it does not have a built-in string-to-Duration parser for ISO-8601 or "friendly" formats like "30s".

PR #6668 (merged 2025-10-16) added from_uri support to all services and introduced a signed_to_duration(value: &str) -> Result<Duration> utility (using jiff::SignedDuration) that parses both ISO-8601 durations (e.g., PT5M) and friendly formats (e.g., 5m), with validation against negative values and overflow. The established pattern for services that need configurable timeouts via string config is: store the raw value as Option<String> in the config struct (passable via ConfigDeserializer), then call signed_to_duration in the builder's build() method when constructing the service. PR #7423 (adding connect_timeout and acquire_timeout to SFTP) is a concrete example of this pattern, including unit tests for invalid duration strings returning ErrorKind::ConfigInvalid.

Entry Points for Debugging#

ConcernLocation
ConfigDeserializer and Pair implcore/src/raw/serde_util.rs
Configurator trait / from_itercore/src/types/builder.rs:125-142
MemcachedConfig examplecore/src/services/memcached/config.rs
RedisConfig examplecore/src/services/redis/config.rs
from_uri / Duration string parsingPR #6668
SFTP timeout config pattern examplePR #7423
Configuration Deserialization | Dosu