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

std json #159

Merged
merged 9 commits into from
Jul 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,9 @@ jobs:
- stable
- 1.65.0 # keep in sync with manifest MSRV
args:
- --all-features
- ""
- --no-default-features
- --no-default-features --features json
- --no-default-features --features json-core

steps:
- uses: actions/checkout@v2
Expand Down
1 change: 0 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* [breaking] `iter_paths`/`MiniconfIter` 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>>()`.
* The `mqtt-client` feature has been renamed into `mqtt` with backward compatibility.
* [breaking] Re-exports of `heapless` and `serde-json-core` have been removed as they are
not needed to work with the public API.

Expand Down
21 changes: 12 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,20 @@ 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}
log = {version = "0.4", optional = true}
heapless = { version = "0.7", features = ["serde"], optional=true }
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 }
log = {version = "0.4", optional = true }
heapless = { version = "0.7", optional=true }
minimq = { version = "0.7", optional = true }
smlang = { version = "0.6", optional = true }

[features]
default = ["mqtt"]
json = ["dep:serde-json-core", "dep:heapless"]
mqtt = ["dep:minimq", "dep:smlang", "dep:log", "json"]
mqtt-client = ["mqtt"] # backwards compat
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"]

[dev-dependencies]
machine = "0.3"
Expand All @@ -43,8 +46,8 @@ branch = "feature/0.7"

[[example]]
name = "mqtt"
required-features = ["mqtt"]
required-features = ["mqtt-client"]

[[example]]
name = "readback"
required-features = ["json"]
required-features = ["json-core"]
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,10 @@ Deferred (non-atomic) access to inner elements of some types is not yet supporte
* Tuple structs (other than [Option], [Array])

## Features
* `mqtt` Enable the MQTT client feature. See the example in [MqttClient].
* `json` Enable the [SerDe] implementation for the [JsonCoreSlash] style.
* `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`).

Both features are enabled by default.
The `mqtt-client` and `json-core` features are enabled by default.
39 changes: 12 additions & 27 deletions src/json.rs
Original file line number Diff line number Diff line change
@@ -1,46 +1,31 @@
use crate::{Error, Miniconf, SerDe};
use serde_json_core::{de, ser};

/// Marker struct for the "JSON and `/`" [SerDe] specification.
///
/// Access items with `'/'` as path separator and JSON (from `serde-json-core`)
/// Access items with `'/'` as path separator and JSON (from `serde-json`)
/// as serialization/deserialization payload format.
pub struct JsonCoreSlash;
pub struct JsonSlash;

impl<T> SerDe<JsonCoreSlash> for T
impl<T> SerDe<JsonSlash> for T
where
T: Miniconf,
{
const SEPARATOR: char = '/';
type DeError = de::Error;
type SerError = ser::Error;
type DeError = serde_json::Error;
type SerError = serde_json::Error;

fn set(&mut self, path: &str, data: &[u8]) -> Result<usize, Error<Self::DeError>> {
let mut de = de::Deserializer::new(data);
let mut de = serde_json::Deserializer::from_slice(data);
self.set_path(&mut path.split(Self::SEPARATOR).skip(1), &mut de)?;
de.end().map_err(Error::PostDeserialization)
de.end()
.map_err(Error::PostDeserialization)
.map(|_| data.len())
}

fn get(&self, path: &str, data: &mut [u8]) -> Result<usize, Error<Self::SerError>> {
let mut ser = ser::Serializer::new(data);
let mut buf = std::io::Cursor::new(data);
let mut ser = serde_json::Serializer::new(&mut buf);
self.get_path(&mut path.split(Self::SEPARATOR).skip(1), &mut ser)?;
Ok(ser.end())
}
}

// These allow unifying serde error information to make writing examples
// and tests easier. Doing this conversion is optional.
// #[cfg(any(test, doctest))]
impl From<Error<ser::Error>> for Error<de::Error> {
fn from(value: Error<ser::Error>) -> Self {
match value {
Error::BadIndex => Self::BadIndex,
Error::PathAbsent => Self::PathAbsent,
Error::PathNotFound => Self::PathNotFound,
Error::PathTooLong => Self::PathTooLong,
Error::PathTooShort => Self::PathTooShort,
Error::PostDeserialization(_) => Error::PostDeserialization(de::Error::CustomError),
Error::SerDe(_) => Self::SerDe(de::Error::CustomError),
}
Ok(buf.position() as _)
}
}
46 changes: 46 additions & 0 deletions src/json_core.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use crate::{Error, Miniconf, SerDe};
use serde_json_core::{de, ser};

/// Marker struct for the "JSON and `/`" [SerDe] specification.
///
/// Access items with `'/'` as path separator and JSON (from `serde-json-core`)
/// as serialization/deserialization payload format.
pub struct JsonCoreSlash;

impl<T> SerDe<JsonCoreSlash> for T
where
T: Miniconf,
{
const SEPARATOR: char = '/';
type DeError = de::Error;
type SerError = ser::Error;

fn set(&mut self, path: &str, data: &[u8]) -> Result<usize, Error<Self::DeError>> {
let mut de = de::Deserializer::new(data);
self.set_path(&mut path.split(Self::SEPARATOR).skip(1), &mut de)?;
de.end().map_err(Error::PostDeserialization)
}

fn get(&self, path: &str, data: &mut [u8]) -> Result<usize, Error<Self::SerError>> {
let mut ser = ser::Serializer::new(data);
self.get_path(&mut path.split(Self::SEPARATOR).skip(1), &mut ser)?;
Ok(ser.end())
}
}

// These allow unifying serde error information to make writing examples
// and tests easier. Doing this conversion is optional.
// #[cfg(any(test, doctest))]
impl From<Error<ser::Error>> for Error<de::Error> {
fn from(value: Error<ser::Error>) -> Self {
match value {
Error::BadIndex => Self::BadIndex,
Error::PathAbsent => Self::PathAbsent,
Error::PathNotFound => Self::PathNotFound,
Error::PathTooLong => Self::PathTooLong,
Error::PathTooShort => Self::PathTooShort,
Error::PostDeserialization(_) => Error::PostDeserialization(de::Error::CustomError),
Error::SerDe(_) => Self::SerDe(de::Error::CustomError),
}
}
}
15 changes: 10 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![cfg_attr(not(any(test, doctest)), no_std)]
#![cfg_attr(feature = "json", doc = include_str!("../README.md"))]
#![cfg_attr(not(any(test, doctest, feature = "std")), no_std)]
#![cfg_attr(feature = "json-core", doc = include_str!("../README.md"))]

use core::fmt::Write;

Expand All @@ -11,16 +11,21 @@ pub use iter::*;
mod option;
pub use option::*;

#[cfg(feature = "json-core")]
mod json_core;
#[cfg(feature = "json-core")]
pub use json_core::*;

#[cfg(feature = "json")]
mod json;
#[cfg(feature = "json")]
pub use json::*;

#[cfg(feature = "mqtt")]
#[cfg(feature = "mqtt-client")]
pub use minimq; // re-export
#[cfg(feature = "mqtt")]
#[cfg(feature = "mqtt-client")]
mod mqtt_client;
#[cfg(feature = "mqtt")]
#[cfg(feature = "mqtt-client")]
pub use mqtt_client::*;

pub use serde; // re-export
Expand Down
2 changes: 1 addition & 1 deletion src/mqtt_client/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use crate::{JsonCoreSlash, Miniconf, SerDe};
use core::fmt::Write;
use heapless::{String, Vec};
use minimq::{
embedded_nal::{IpAddr, TcpClientStack},
embedded_time,
types::{SubscriptionOptions, TopicFilter},
Publication, QoS, Retain,
};
use serde_json_core::heapless::{String, Vec};

// The maximum topic length of any settings path.
const MAX_TOPIC_LENGTH: usize = 128;
Expand Down
2 changes: 1 addition & 1 deletion tests/arrays.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg(feature = "json")]
#![cfg(feature = "json-core")]

use miniconf::{Array, Error, Miniconf, SerDe};
use serde::Deserialize;
Expand Down
2 changes: 1 addition & 1 deletion tests/enums.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg(feature = "json")]
#![cfg(feature = "json-core")]

use miniconf::{Miniconf, SerDe};
use serde::{Deserialize, Serialize};
Expand Down
2 changes: 1 addition & 1 deletion tests/generics.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg(feature = "json")]
#![cfg(feature = "json-core")]

use miniconf::{Miniconf, SerDe};
use serde::{Deserialize, Serialize};
Expand Down
2 changes: 1 addition & 1 deletion tests/integration_test.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg(features = "mqtt")]
#![cfg(features = "mqtt-client")]

use machine::*;
use miniconf::{
Expand Down
2 changes: 1 addition & 1 deletion tests/iter.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg(feature = "json")]
#![cfg(feature = "json-core")]

use miniconf::{Miniconf, SerDe};

Expand Down
20 changes: 20 additions & 0 deletions tests/json.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#![cfg(feature = "json")]

use miniconf::{Miniconf, SerDe};

#[test]
fn struct_with_string() {
#[derive(Miniconf, Default)]
struct Settings {
string: String,
}

let mut s = Settings::default();

let mut buf = [0u8; 256];
let len = s.get("/string", &mut buf).unwrap();
assert_eq!(&buf[..len], b"\"\"");

s.set("/string", br#""test""#).unwrap();
assert_eq!(s.string, "test");
}
2 changes: 1 addition & 1 deletion tests/option.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg(feature = "json")]
#![cfg(feature = "json-core")]

use miniconf::{Error, Miniconf, SerDe};

Expand Down
2 changes: 1 addition & 1 deletion tests/republish.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg(features = "mqtt")]
#![cfg(features = "mqtt-client")]

use miniconf::{
minimq::{self, types::TopicFilter},
Expand Down
19 changes: 1 addition & 18 deletions tests/structs.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg(feature = "json")]
#![cfg(feature = "json-core")]

use miniconf::{Miniconf, SerDe};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -78,23 +78,6 @@ fn recursive_struct() {
assert_eq!(metadata.count, 3);
}

#[test]
fn struct_with_string() {
#[derive(Miniconf, Default)]
struct Settings {
string: heapless::String<10>,
}

let mut s = Settings::default();

let mut buf = [0u8; 256];
let len = s.get("/string", &mut buf).unwrap();
assert_eq!(&buf[..len], b"\"\"");

s.set("/string", br#""test""#).unwrap();
assert_eq!(s.string, "test");
}

#[test]
fn empty_struct() {
#[derive(Miniconf, Default)]
Expand Down
2 changes: 1 addition & 1 deletion tests/validation_failure.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg(features = "mqtt")]
#![cfg(features = "mqtt-client")]

use miniconf::{minimq, Miniconf};
use serde::Deserialize;
Expand Down
Loading