1 unstable release
Uses old Rust 2015
0.1.0 | Apr 17, 2018 |
---|
#11 in #updating
13KB
221 lines
Stringly-Typed Rust
A crate for updating values using a stringly-typed API.
Typical Use Case
Imagine you're working on a system that uses a lot of runtime configuration to alter the behaviour of the application. For whatever reason it isn't practical to stop the entire system just to update a single configuration key, so you need the ability to update configuration on the fly... How do you do it?
- Re-upload the entire configuration file for every change
- The caller sends just the key-value pair they want to update and you execute
the update by:
- Serializing to a more loosly-typed form (e.g.
serde_json::Value
), make the update (e.g.config["foo"]["bar"][3] = 42
), then deserialize back to the original type - Write a massive switch-case statement which will update different fields
depending on the provided key (e.g.
match key { "foo.bar" => config.foo.bar = value }
)
- Serializing to a more loosly-typed form (e.g.
In terms of difficulty the first option is quite nice. You just wrap your
config
with a RWLock
and all your configuration update issues go away,
however you now pay the price of serializing/deserializing and network transfer.
Plus it can feel awfully wasteful to copy around an entire file just to change
one key.
TODO: Mention how serialize-deserialize is expensive
TODO: Mention this is essentially automating the massive switch-case statement
#[macro_use]
extern crate stringly_typed;
use stringly_typed::{StringlyTyped, Value};
#[derive(StringlyTyped)]
struct Config {
motion_parameters: MotionParameters,
target_bed_temp: f64,
version: String,
...
}
#[derive(StringlyTyped)]
struct MotionParameters {
max_translation_velocity: f64,
max_vertical_velocity: f64,
}
// Assume we were told which key and value to update over the network or some
// other dynamic source
let key = "motion_parameters.max_vertical_velocity";
let value = Value::Double(40.0);
cfg.set(key, value)?;
assert_eq!(cfg.motion_parameters.max_vertical_velocity, 40.0);
Features
- Works with
no_std
- Supports enums
- Supports arrays
Benchmarks
The main goal of this crate isn't performance, however it performs quite well compared to the "usual" static assignment (i.e. normal Rust with the dot operator), and still beats the serialize-update-deserialize method.
test static_assign ... bench: 81 ns/iter (+/- 6)
test stringly_update ... bench: 167 ns/iter (+/- 12)
test serialize_deserialize ... bench: 1,243 ns/iter (+/- 343)
As with any benchmark, we're only comparing three contrived use cases so take these numbers with a grain of salt.
Dependencies
~2MB
~48K SLoC