Expand description
INI files (and git’s config files) for deser.
use deser::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize)]
struct Config {
name: String,
server: Server,
}
#[derive(Debug, Deserialize, Serialize)]
struct Server {
host: String,
port: u16,
#[deser(default)]
tags: Vec<String>,
}
let config: Config = deser_ini::from_str("
name = shop
[server]
host = localhost ; the host to bind to
port = 8080
tags = a
tags = b
").unwrap();
assert_eq!(config.name, "shop");
assert_eq!(config.server.port, 8080);
assert_eq!(config.server.tags, ["a", "b"]);
assert_eq!(
deser_ini::to_string(&config).unwrap(),
"name = shop\n\n[server]\nhost = localhost\nport = 8080\ntags = a\ntags = b\n"
);§Dialects
INI files have no specification, every implementation reads them a
little differently. The default (DeserializerConfig::new) reads
what is common today:
-
Lines that start with
;or#are comments. After values, a;that follows whitespace starts a comment and so does a#that follows whitespace after the value (key = value ; comment), so1;2;3,A;B;and#ff0000are values (seeInlineComments). -
=and:separate keys and values, whitespace around keys and values is removed. -
Lines that are indented more than the line of their key continue its value (see
Continuation), like in Python’sconfigparser:[options] install_requires = deser requests -
A value that is quoted as a whole (
"value"or'value') is read without the quotes (seeQuotes). This is how whitespace at the start or end of a value and comment characters are written. -
A key without value (
skip-name-resolve) is a key with a null value. -
Keys can come before the first section.
These choices are based on a survey of INI files on GitHub: values are
quoted for PHP, MySQL, Windows, Unreal and most other readers that are
not Python, values with indented continuation lines are common in Python
tools (tox.ini, setup.cfg, pylintrc) and PlatformIO, and keys are
rarely indented more than the key before them.
DeserializerConfig::python reads files of Python’s configparser
(no inline comments and quotes) and DeserializerConfig::git reads
git’s config files (Syntax::Git).
§Data Model
An INI file is a map of its sections and the keys before the first section, sections are maps of their keys:
| INI file | deser |
|---|---|
a = 1 | {"a": "1"} |
[s] a = 1 | {"s": {"a": "1"}} |
[s] a = 1 a = 2 | {"s": {"a": "1", "a": "2"}} (a repeated key) |
[s] a = 1 [s] b = 2 | {"s": {"a": "1", "b": "2"}} |
[s] a | {"s": {"a": null}} |
[s] | {"s": {}} |
[s "x"] a = 1 (git) | {"s": {"x": {"a": "1"}}} |
Sections that are given more than once are merged. Keys can repeat
(the maps are multimaps): fields and map values that are collections
(like Vec<T>) collect the values of all occurrences of their key, also
if other keys are between them. Types that expect a single value receive
the last one unless the Context has another
DuplicateKeys policy. A name that is
a key and a section is an error.
Everything in an INI file is text, the type of a value is only known to
the type it’s deserialized into. Keys and values are therefore passed
on as lexical atoms which are parsed by the
types they are delivered to: numbers parse them, strings take them as
they are. Booleans accept true, yes, on and 1 and false, no,
off and 0. Empty values are None for optionals of types that do
not accept them (port = is None for an Option<u16> and Some("")
for an Option<String>). Keys without value are null, the
Flag adapter reads them as true:
use deser::adapters::Flag;
#[derive(deser::Deserialize)]
struct Mysqld {
#[deser(as = Flag)]
skip_name_resolve: bool,
port: Option<u16>,
}
#[derive(deser::Deserialize)]
struct MyCnf {
mysqld: Mysqld,
}
let cnf: MyCnf =
deser_ini::from_str("[mysqld]\nskip_name_resolve\nport =\n").unwrap();
assert!(cnf.mysqld.skip_name_resolve);
assert_eq!(cnf.mysqld.port, None);Lists in a single value (hosts = a, b) use the
Separated adapter, values on
continuation lines are separated by line breaks
(Separated<'\n'>).
Interpolation (%(name)s, ${name}) and the DEFAULT section of
configparser are not supported, they are text.
§Errors
Errors point at the line and column of the input, also errors of values
that do not parse (like port = http for a u16). With deser-path
they also have the path of the value (server.port), see
Deserializer.
§Serialization
Values are written as INI files (see SerializerConfig): the value
has to be a map (like a struct), its entries with maps as values are
sections and the others are written before the first section.
Sequences are written as repeated keys.
§Streams
INI files are read from a Read with from_reader
and written to a Write with to_writer. The
configurations also create readers and writers of
deser::io (DeserializerConfig::reader and
SerializerConfig::writer). An INI file holds a single value, the
whole stream is read before it’s parsed.
§Features
io(enabled by default): reading and writing streams of the standard library, see streams.speedups(enabled by default): has no effect yet, it exists so that all formats have it.
Structs§
- Deserializer
- Deserializes INI files.
- Deserializer
Config - Configures how INI files are deserialized.
- Deserializer
Config Builder - Builds a
DeserializerConfig. - Serializer
- Serializes values into INI files.
- Serializer
Config - Configures how values are serialized to INI files.
- Serializer
Config Builder - Builds a
SerializerConfig. - Stream
Deserializer - Reads an INI file from a stream (see
deser::stream).
Enums§
- Continuation
- How values continue on the next lines.
- Inline
Comments - Where comments start after values.
- Quotes
- How quoted values are read.
- Syntax
- The syntax of the files.
Functions§
- from_
reader - Deserializes an INI file from a reader.
- from_
slice - Deserializes a value from an INI file in a byte slice.
- from_
str - Deserializes a value from an INI file.
- to_
string - Serializes a value to an INI file.
- to_
writer - Serializes a value to a writer.