Miniconf enables lightweight (no_std
) partial serialization (retrieval) and deserialization
(updates, modification) within a tree by key. The tree is backed by
structs/arrays/Options of serializable types.
Miniconf can be used as a very simple and flexible backend for run-time settings management in embedded devices
over any transport. It was originally designed to work with JSON (serdejsoncore)
payloads over MQTT (minimq) and provides a comlete MQTT settings management
client and a Python reference implementation to ineract with it.
Miniconf
is completely generic over the serde::Serializer
/serde::Deserializer
backend and the path hierarchy separator.
```rust use miniconf::{Error, Miniconf, JsonCoreSlash}; use serde::{Deserialize, Serialize};
enum Either { #[default] Bad, Good, }
struct Inner { a: i32, b: i32, }
struct Settings {
// Atomic updtes by field name
foo: bool,
enum: Either,
struct: Inner,
array: [i32; 2],
option: Option
// Exposing elements of containers
// ... by field name
#[miniconf(defer)]
struct_defer: Inner,
// ... or by index
#[miniconf(defer)]
array_defer: [i32; 2],
// ... or deferring to two levels (index and then inner field name)
#[miniconf(defer(2))]
array_miniconf: [Inner; 2],
// Hiding paths by setting the Option to `None` at runtime
#[miniconf(defer)]
option_defer: Option<i32>,
// Hiding a path and deferring to the inner
#[miniconf(defer(2))]
option_miniconf: Option<Inner>,
// Hiding elements of an Array of Miniconf items
#[miniconf(defer(3))]
array_option_miniconf: [Option<Inner>; 2],
}
let mut settings = Settings::default(); let mut buf = [0; 64];
// Atomic updates by field name settings.setjson("/foo", b"true")?; asserteq!(settings.foo, true); settings.setjson("/enum", br#""Good""#)?; settings.setjson("/struct", br#"{"a": 3, "b": 3}"#)?; settings.setjson("/array", b"[6, 6]")?; settings.setjson("/option", b"12")?; settings.set_json("/option", b"null")?;
// Deep access by field name in a struct settings.setjson("/structdefer/a", b"4")?; // ... or by index in an array settings.setjson("/arraydefer/0", b"7")?; // ... or by index and then struct field name settings.setjson("/arrayminiconf/1/b", b"11")?;
// If a deferred Option is None
it is hidden at runtime and can't be accessed
settings.optiondefer = None;
asserteq!(settings.setjson("/optiondefer", b"13"), Err(Error::Absent(1)));
settings.optiondefer = Some(0);
settings.setjson("/optiondefer", b"13")?;
settings.optionminiconf = Some(Inner::default()).into();
settings.setjson("/optionminiconf/a", b"14")?;
settings.arrayoptionminiconf[1] = Some(Inner::default()).into();
settings.setjson("/arrayoption_miniconf/1/a", b"15")?;
// Serializing elements by path let len = settings.getjson("/struct", &mut buf)?; assert_eq!(&buf[..len], br#"{"a":3,"b":3}"#);
// Iterating over all paths
for path in Settings::iterpaths::None
and thus their paths are expected to be absent
Err(Error::Absent()) => {}
e => {
e?;
}
}
}
```
There is an MQTT-based client that implements settings management over the MQTT protocol with JSON payloads. A Python reference library is provided that interfaces with it.
```sh
quartiq/application/12345
and set its foo
setting to true
.python -m miniconf -d quartiq/application/+ foo=true ```
For structs Miniconf offers a [macro@Miniconf
] derive macro.
The macro implements the [Miniconf] trait that exposes access to serialized field values through their path.
All types supported by either [serde] (and the serde::Serializer
/serde::Deserializer
backend) or Miniconf
can be used as fields.
Structs, arrays, and Options can then be cascaded to construct more complex trees.
When using the derive macro, the behavior and tree recursion depth can be configured for each
struct field using the #[miniconf(defer(Y))]
attribute.
See also the [Miniconf
] trait documentation for details.
Lookup into the tree is done using an iterator over [Key] items. usize
indices or &str
names are supported.
Path iteration is supported with arbitrary separator between names.
Miniconf is generic over the serde
backend/payload format and the path hierarchy separator.
Currently support for /
as the path hierarchy separator and JSON (serde_json_core
) is implemented
through the [JsonCoreSlash] super trait.
Miniconf is designed to be protocol-agnostic. Any means that can receive key-value input from some external source can be used to modify values by path.
Deferred/deep/non-atomic access to inner elements of some types is not yet supported, e.g. enums
other than [core::option::Option]. These are still however usable in their atomic serde
form as leaves.
mqtt-client
Enable the MQTT client feature. See the example in [MqttClient].json-core
Enable the [JsonCoreSlash] implementation of serializing from and
into json slices (using serde_json_core
).The mqtt-client
and json-core
features are enabled by default.