Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add traverse_by_key and {get,set}_by_key methods and refactor several things #160

Merged
merged 48 commits into from
Jul 28, 2023
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
abd5689
graph
jordens Jul 26, 2023
74a5f99
closures
jordens Jul 26, 2023
61c2478
traverse
jordens Jul 26, 2023
70d59d6
names
jordens Jul 26, 2023
4577b89
trait rework
jordens Jul 27, 2023
cc4acb6
trait rework
jordens Jul 27, 2023
d10ab95
rewrite tests
jordens Jul 27, 2023
080bb64
released serde-json-core
jordens Jul 27, 2023
9eb88f7
remove enum tests as they only test serde
jordens Jul 27, 2023
5857927
remove separator from metadata
jordens Jul 27, 2023
8f3890e
cleanup and refactor tests
jordens Jul 27, 2023
ce88198
move iter_paths to miniconf
jordens Jul 27, 2023
0a57ea5
disentangle the SerDe mess
jordens Jul 27, 2023
499b7b2
clippy
jordens Jul 27, 2023
73ed3f8
add helper to Metadata
jordens Jul 27, 2023
a9243d8
remove internal from api, add to func()
jordens Jul 27, 2023
3fbae5b
docs, take separator in Metadata.separator()
jordens Jul 27, 2023
ebefe3e
remove json style
jordens Jul 27, 2023
acf2eac
docs and changelog
jordens Jul 27, 2023
fca8abc
derive: peel Some() in common path
jordens Jul 27, 2023
2a036d2
remove lifetime bound
jordens Jul 27, 2023
516677c
remove more lifetimes
jordens Jul 27, 2023
da528b4
add {get,set}_by_index()
jordens Jul 27, 2023
09a9a98
{set/get}_json_index() and unittests
jordens Jul 27, 2023
ad892cc
add '_by'
jordens Jul 27, 2023
29d19c1
hide Iter ctors
jordens Jul 27, 2023
e8011fd
Iter -> PathIter
jordens Jul 27, 2023
1396d0a
fix docs
jordens Jul 27, 2023
d6a9f4f
more concise code
jordens Jul 27, 2023
8f573ba
cleanup
jordens Jul 27, 2023
a96ad7d
be generic over the key
jordens Jul 27, 2023
59faa4c
remove old set_by_{index,name}
jordens Jul 27, 2023
7e39c51
remove _by_{name,index} in favor of _by_key
jordens Jul 27, 2023
7de1e74
fix
jordens Jul 27, 2023
6e3c097
Key trait
jordens Jul 28, 2023
843cb04
docs
jordens Jul 28, 2023
99d8695
add a bunch of deny() attributes and more docs
jordens Jul 28, 2023
8fda89b
docs
jordens Jul 28, 2023
b769403
doc for no features
jordens Jul 28, 2023
054b05f
fewer string in derive
jordens Jul 28, 2023
7239c21
use auto-conversion
jordens Jul 28, 2023
6337e1e
leave path and indices generic
jordens Jul 28, 2023
954846c
simplify iterator passing
jordens Jul 28, 2023
98ca0d7
rename type parameters for consistency
jordens Jul 28, 2023
9997ac1
Update src/lib.rs
jordens Jul 28, 2023
2b6bf8a
Error::Internal->TooShort
jordens Jul 28, 2023
b6e61fd
make precedence test explicit
jordens Jul 28, 2023
939703e
panic context
jordens Jul 28, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ jobs:
- 1.65.0 # keep in sync with manifest MSRV
args:
- ""
- --all-features
- --no-default-features
- --no-default-features --features json-core

Expand Down
21 changes: 13 additions & 8 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,38 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

* `json` feature to enable the `Serde<JsonCoreSlash>` spec. Enabled by default.
* Traversal by names or indices has been added through `Miniconf::traverse_by_key()`.

### Changed

* [breaking] The `Miniconf` trait is now generic over the `Deserializer`/`Serializer`. It
doesn't enforce `serde-json-core` or `u8` buffers or `/` as the path hierarchy
separator anymore.
* [breaking] `MiniconfIter` takes the path hierarchy separator from `SerDe` and passes it on to
`Miniconf::next_path` and `Miniconf::metadata`.
* [breaking] `Miniconf::iter_paths()` takes the path hierarchy separator and passes
it on to `Miniconf::path()` and `Metadata::separator()`.
* [breaking] The `Miniconf` trait has been stripped of the provided functions that depended
on the `serde`-backend and path hierarchy separator. Those have been
moved into a super trait `SerDe<S>` that is generic over a specification marker
struct `S`. `SerDe<JsonCoreSlash>` has been implemented for all `Miniconf`
moved into the `JsonCoreSlash` trait that has been implemented for all `Miniconf`
to provide the previously existing functionality.
* The only required change for most downstream crates to adapt to the above is to
make sure the `SerDe` trait is in scope (`use miniconf::SerDe`).
make sure the `JsonCoreSlash` trait is in scope (`use miniconf::JsonCoreSlash`).
* [breaking] Paths now start with the path separator (unless they are empty).
This affects the `Miniconf` derive macro and the `Miniconf` implementation pairs
for `Option`/`Array`.
Downstram crates should ensure non-empty paths start with the separator and
expect `next_path` paths to start with the separator or be empty.
* `set()` and `get()` have been renamed to `set_json()` and `get_json()` respectively to
avoid overlap.
* The path iterator does not need to be `Peekable` anymore.
* [breaking] `iter_paths`/`MiniconfIter` is now generic over the type
* [breaking] `iter_paths`/`PathIter` is now generic over the type
to write the path into. Downstream crates should replace `iter_paths::<L, TS>()` with
`iter_paths::<L, heapless::String<TS>>()`.
e.g. `iter_paths::<L, heapless::String<TS>>()`.
* [breaking] Re-exports of `heapless` and `serde-json-core` have been removed as they are
not needed to work with the public API.
* [breaking] Metadata is now computed by default without taking account path separators.
These can be included using `Metadata::separator()`.
* The main serialization/deserialization methods are now `Miniconf::{set,get}_by_key()`
They are generic over the key iterator `Iterator<Item: miniconf::Key>`.

## [0.7.1] (https://github.com/quartiq/miniconf/compare/v0.7.0...v0.7.1)

Expand Down
9 changes: 3 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ version = "0.7.1"
authors = ["James Irwin <[email protected]>", "Ryan Summers <[email protected]", "Robert Jördens <[email protected]>"]
edition = "2021"
license = "MIT"
description = "Inspect serde namespaces by path"
description = "Serialize/deserialize/access Inspect serde namespaces by path"
repository = "https://github.com/quartiq/miniconf"
keywords = ["settings", "serde", "no_std", "json", "mqtt"]
categories = ["no-std", "config", "rust-patterns", "parsing"]
Expand All @@ -17,9 +17,7 @@ serde = { version = "1.0.120", features = ["derive"], default-features = false }
miniconf_derive = { path = "miniconf_derive" , version = "0.6" }
itoa = "1.0.4"

serde-json-core = { git = "https://github.com/rust-embedded-community/serde-json-core.git" , optional = true }
serde_json = { version = "1.0", optional = true }
tinyvec = { version = "1.6", optional = true }
serde-json-core = { version = "0.5.1" , optional = true }
log = {version = "0.4", optional = true }
heapless = { version = "0.7", optional=true }
minimq = { version = "0.7", optional = true }
Expand All @@ -28,9 +26,8 @@ smlang = { version = "0.6", optional = true }
[features]
default = ["mqtt-client"]
json-core = ["dep:serde-json-core"]
json = ["dep:serde_json", "dep:tinyvec", "std"]
std = []
mqtt-client = ["json-core", "dep:minimq", "dep:smlang", "dep:log", "dep:heapless"]
std = []

[dev-dependencies]
machine = "0.3"
Expand Down
52 changes: 26 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ client](MqttClient) and a Python reference implementation to ineract with it.

## Example
```rust
use miniconf::{Error, Miniconf, SerDe};
use miniconf::{Error, Miniconf, JsonCoreSlash};
use serde::{Deserialize, Serialize};

#[derive(Deserialize, Serialize, Copy, Clone, Default)]
Expand Down Expand Up @@ -67,45 +67,47 @@ let mut settings = Settings::default();
let mut buf = [0; 64];

// Atomic updates by field name
settings.set("/foo", b"true")?;
settings.set_json("/foo", b"true")?;
assert_eq!(settings.foo, true);
settings.set("/enum_", br#""Good""#)?;
settings.set("/struct_", br#"{"a": 3, "b": 3}"#)?;
settings.set("/array", b"[6, 6]")?;
settings.set("/option", b"12")?;
settings.set("/option", b"null")?;
settings.set_json("/enum_", br#""Good""#)?;
settings.set_json("/struct_", br#"{"a": 3, "b": 3}"#)?;
settings.set_json("/array", b"[6, 6]")?;
settings.set_json("/option", b"12")?;
settings.set_json("/option", b"null")?;

// Deep access by field name in a struct
settings.set("/struct_defer/a", b"4")?;
settings.set_json("/struct_defer/a", b"4")?;
// ... or by index in an array
settings.set("/array_defer/0", b"7")?;
settings.set_json("/array_defer/0", b"7")?;
// ... or by index and then struct field name
settings.set("/array_miniconf/1/b", b"11")?;
settings.set_json("/array_miniconf/1/b", b"11")?;

// If a deferred Option is `None` it is hidden at runtime and can't be accessed
settings.option_defer = None;
assert_eq!(settings.set("/option_defer", b"13"), Err(Error::PathAbsent));
assert_eq!(settings.set_json("/option_defer", b"13"), Err(Error::Absent(1)));
settings.option_defer = Some(0);
settings.set("/option_defer", b"13")?;
settings.set_json("/option_defer", b"13")?;
settings.option_miniconf = Some(Inner::default()).into();
settings.set("/option_miniconf/a", b"14")?;
settings.set_json("/option_miniconf/a", b"14")?;
settings.array_option_miniconf[1] = Some(Inner::default()).into();
settings.set("/array_option_miniconf/1/a", b"15")?;
settings.set_json("/array_option_miniconf/1/a", b"15")?;

// Serializing elements by path
let len = settings.get("/struct_", &mut buf)?;
let len = settings.get_json("/struct_", &mut buf)?;
assert_eq!(&buf[..len], br#"{"a":3,"b":3}"#);

// Iterating over and serializing all paths
for path in Settings::iter_paths::<3, String>().unwrap() {
match settings.get(&path, &mut buf) {
// Iterating over all paths
for path in Settings::iter_paths::<3, String>("/").unwrap() {
// Serializing each
match settings.get_json(&path, &mut buf) {
Ok(len) => {
settings.set(&path, &buf[..len]).unwrap();
// Deserialize again
settings.set_json(&path, &buf[..len])?;
}
// Some settings are still `None` and thus their paths are expected to be absent
Err(Error::PathAbsent) => {}
Err(Error::Absent(_)) => {}
e => {
e.unwrap();
e?;
}
}
}
Expand Down Expand Up @@ -148,7 +150,7 @@ Miniconf is generic over the `serde` backend/payload format and the path hierarc
(as long as the path can be split by it unambiguously).

Currently support for `/` as the path hierarchy separator and JSON (`serde_json_core`) is implemented
through [SerDe] for the [JsonCoreSlash] style.
through the [JsonCoreSlash] style.

## Transport
Miniconf is designed to be protocol-agnostic. Any means that can receive key-value input from
Expand All @@ -161,9 +163,7 @@ Deferred (non-atomic) access to inner elements of some types is not yet supporte

## Features
* `mqtt-client` Enable the MQTT client feature. See the example in [MqttClient].
* `json-core` Enable the [SerDe] implementation for the [JsonCoreSlash] style
(using `serde_json_core`).
* `json` Enable the [SerDe] implementation for the [JsonSlash] style (using
`serde_json`).
* `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.
8 changes: 4 additions & 4 deletions examples/readback.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use miniconf::{Miniconf, SerDe};
use miniconf::{JsonCoreSlash, Miniconf};

#[derive(Debug, Default, Miniconf)]
struct AdditionalSettings {
Expand All @@ -23,12 +23,12 @@ fn main() {
};

// Maintains our state of iteration.
let mut settings_iter = Settings::iter_paths::<5, String>().unwrap();
let mut settings_iter = Settings::iter_paths::<5, String>("/").unwrap();

// Just get one topic/value from the iterator
if let Some(topic) = settings_iter.next() {
let mut value = [0; 256];
let len = s.get(&topic, &mut value).unwrap();
let len = s.get_json(&topic, &mut value).unwrap();
println!(
"{:?}: {:?}",
topic,
Expand All @@ -42,7 +42,7 @@ fn main() {

for topic in settings_iter {
let mut value = [0; 256];
let len = s.get(&topic, &mut value).unwrap();
let len = s.get_json(&topic, &mut value).unwrap();
println!(
"{:?}: {:?}",
topic,
Expand Down
10 changes: 5 additions & 5 deletions miniconf_derive/src/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ use syn::{parse_quote, Generics};

pub struct StructField {
pub field: syn::Field,
pub deferred: bool,
pub defer: bool,
}

impl StructField {
pub fn new(field: syn::Field) -> Self {
let mut deferred = false;
let mut defer = false;

for attr in field.attrs.iter() {
if attr.path().is_ident("miniconf") {
attr.parse_nested_meta(|meta| {
if meta.path.is_ident("defer") {
deferred = true;
defer = true;
Ok(())
} else {
Err(meta.error(format!("unrecognized miniconf attribute {:?}", meta.path)))
Expand All @@ -23,7 +23,7 @@ impl StructField {
}
}

Self { deferred, field }
Self { defer, field }
}

fn bound_type(&self, ident: &syn::Ident, generics: &mut Generics, array: bool) {
Expand All @@ -32,7 +32,7 @@ impl StructField {
if type_param.ident == *ident {
// Deferred array types are a special case. These types defer directly into a
// manual implementation of Miniconf that calls serde functions directly.
if self.deferred && !array {
if self.defer && !array {
// For deferred, non-array data types, we will recursively call into
// Miniconf trait functions.
type_param.bounds.push(parse_quote!(miniconf::Miniconf));
Expand Down
Loading
Loading