Skip to content

Commit

Permalink
add missing const generic types; fix no-std
Browse files Browse the repository at this point in the history
  • Loading branch information
olekspickle committed Jan 15, 2024
1 parent 834aa37 commit faebc4a
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 19 deletions.
8 changes: 6 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
[package]
name = "serde_default_utils"
authors = ["Oleks Pickle <[email protected]>"]
version = "0.1.0"
version = "0.2.0"
edition = "2021"
categories = ["encoding", "no-std", "no-std::no-alloc"]
description = "A set of simple helper functions to cut corners with serde_default"
keywords = ["serde", "serialization", "no_std"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/alekspickle/serde_default_utils"

[features]
default = ["std"]
std = []

[dependencies]
paste = "1.0.14"

[dev-dependencies]
expect-test = "1.4.1"
serde = { version = "1.0.195", features = ["derive"] }
serde_json = "1.0.111"

serde_default_utils = { path = ".", features = ["std"] }
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# serde_default_utils

[![v](https://img.shields.io/badge/v-0.1.0-blueviolet)]()
[![v](https://img.shields.io/badge/v-0.2.0-blueviolet)]()

## Overview
This is a simple set of functions to make your life easier while working with defaults in serde.
Based on [const generic parameters](https://doc.rust-lang.org/reference/items/generics.html#const-generics).
Heavily inspired by discussions on issues about serde defaults, but mostly [this one](https://github.com/serde-rs/serde/issues/368)

## Kudos
Expand All @@ -15,7 +16,7 @@ helps to generate another const generic function for any const generic type.
use serde_default_utils::*;
use serde::{Deserialize, Serialize};

const JSON: &str = r#"{"yes_or_no":false,"max":60,"delta":-77}"#;
const JSON: &str = r#"{"yes_or_no":false,"max":60,"delta":-77,"delimeter":"☀"}"#;
const EMPTY_JSON: &str = r#"{}"#;
const MAX: u32 = 7;

Expand All @@ -28,21 +29,23 @@ helps to generate another const generic function for any const generic type.
// you can even use consts right here
#[serde(default = "default_u32::<MAX>")]
max: u32,
#[serde(default = "default_char::<'☀'>")]
delimeter: char,
}

fn main() {
// existing json fields are not changed
let config: Config = serde_json::from_str(JSON).unwrap();
let s = serde_json::to_string(&config).unwrap();
assert_eq!(r#"{"yes_or_no":false,"delta":-77,"max":60}"#, &s);
assert_eq!(r#"{"yes_or_no":false,"delta":-77,"max":60,"delimeter":"☀"}"#, &s);
// if the field is not present - it is substituted with defaults
let config: Config = serde_json::from_str(EMPTY_JSON).unwrap();
let s = serde_json::to_string(&config).unwrap();
assert_eq!(r#"{"yes_or_no":true,"delta":-3,"max":7}"#, &s);
assert_eq!(r#"{"yes_or_no":true,"delta":-3,"max":7,"delimeter":"☀"}"#, &s);
// the default impl is just calling underlying type defaults unless you have a custom impl Default
let config = Config::default();
let s = serde_json::to_string(&config).unwrap();
assert_eq!(r#"{"yes_or_no":false,"delta":0,"max":0}"#, &s);
assert_eq!(r#"{"yes_or_no":false,"delta":0,"max":0,"delimeter":"\u0000"}"#, &s);
}

```
Expand Down
68 changes: 56 additions & 12 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
//! [![v](https://img.shields.io/badge/v-0.1.0-blueviolet)]()
//! [![v](https://img.shields.io/badge/v-0.2.0-blueviolet)]()
//!
//! # Overview
//! This is a simple set of functions to make your life easier while working with defaults in serde.
//! Based on [const generic parameters](https://doc.rust-lang.org/reference/items/generics.html#const-generics).
//! Heavily inspired by discussions on issues about serde defaults, but mostly [this one](https://github.com/serde-rs/serde/issues/368)
//!
//! # Kudos
Expand All @@ -13,7 +14,7 @@
//! use serde_default_utils::*;
//! use serde::{Deserialize, Serialize};
//!
//! const JSON: &str = r#"{"yes_or_no":false,"max":60,"delta":-77}"#;
//! const JSON: &str = r#"{"yes_or_no":false,"max":60,"delta":-77,"delimeter":"☀"}"#;
//! const EMPTY_JSON: &str = r#"{}"#;
//! const MAX: u32 = 7;
//!
Expand All @@ -26,44 +27,85 @@
//! // you can even use consts right here
//! #[serde(default = "default_u32::<MAX>")]
//! max: u32,
//! #[serde(default = "default_char::<'☀'>")]
//! delimeter: char,
//! }
//!
//! fn main() {
//! // existing json fields are not changed
//! let config: Config = serde_json::from_str(JSON).unwrap();
//! let s = serde_json::to_string(&config).unwrap();
//! assert_eq!(r#"{"yes_or_no":false,"delta":-77,"max":60}"#, &s);
//! assert_eq!(r#"{"yes_or_no":false,"delta":-77,"max":60,"delimeter":"☀"}"#, &s);
//! // if the field is not present - it is substituted with defaults
//! let config: Config = serde_json::from_str(EMPTY_JSON).unwrap();
//! let s = serde_json::to_string(&config).unwrap();
//! assert_eq!(r#"{"yes_or_no":true,"delta":-3,"max":7}"#, &s);
//! assert_eq!(r#"{"yes_or_no":true,"delta":-3,"max":7,"delimeter":"☀"}"#, &s);
//! // the default impl is just calling underlying type defaults unless you have a custom impl Default
//! let config = Config::default();
//! let s = serde_json::to_string(&config).unwrap();
//! assert_eq!(r#"{"yes_or_no":false,"delta":0,"max":0}"#, &s);
//! assert_eq!(r#"{"yes_or_no":false,"delta":0,"max":0,"delimeter":"\u0000"}"#, &s);
//! }
//!
//! ```
#![cfg_attr(not(feature = "std"), no_std)]

/// Generates a function for a type provided or a custom default function
/// This is not supposed to be used outside since const generic parameter approach
/// is [pretty limited](https://doc.rust-lang.org/reference/items/generics.html#const-generics) at the moment
///
/// # Limitations
/// Slices are limited to only `&'static [u8]` and parcing it from JSON
/// using `serde_json::from_str`` will not work, only `serde_json::from_str`.
///
/// # Output
/// Generates something like
/// ```rust
/// use serde_default_utils::*;
///
/// // Generates
/// // pub const fn default_u8<const V: u8>() -> u8 {
/// // V
/// // }
/// serde_default!(u8);
///
/// // !Experimental!
/// // Generates
/// // pub const fn default_hey<const V: &'static u8>() -> &'static [u8] {
/// // &[1, 2, 3, 4]
/// // }
/// serde_default!(hey, &'static str, "hey");
///
/// assert!(default_u8::<6>() == 6u8);
/// assert_eq!(default_hey(), "hey");
///
/// ```
#[macro_export]
macro_rules! serde_default {
($kind:ty) => {
::paste::paste! {
pub const fn [<default_$kind>]<const V: $kind>() -> $kind {
pub const fn [<default_$kind:lower>]<const V: $kind>() -> $kind {
V
}
}
};
($name:ident,$ty:ty,$val:expr) => {
::paste::paste! {
pub const fn [<default_$name:lower>]() -> $ty {
$val
}
}
};
}
serde_default!(usize);

serde_default!(bool);
serde_default!(char);
serde_default!(usize);
serde_default!(u8);
serde_default!(u16);
serde_default!(u32);
serde_default!(u64);
serde_default!(u128);
serde_default!(isize);
serde_default!(i8);
serde_default!(i16);
serde_default!(i32);
Expand All @@ -84,21 +126,23 @@ mod tests {
delta: i32,
#[serde(default = "default_u32::<7>")]
max: u32,
#[serde(default = "default_char::<'☀'>")]
delimeter: char,
}

const JSON: &str = r#"{"yes_or_no":false,"max":60,"delta":-77}"#;
const JSON: &str = r#"{"yes_or_no":false,"max":60,"delta":-77,"delimeter":"☀"}"#;
const EMPTY_JSON: &str = r#"{}"#;

#[test]
fn deserialization_works() {
let config: Config = serde_json::from_str(JSON).unwrap();
let s = serde_json::to_string(&config).unwrap();
expect![[r#"{"yes_or_no":false,"delta":-77,"max":60}"#]].assert_eq(&s);
expect![[r#"{"yes_or_no":false,"delta":-77,"max":60,"delimeter":"☀"}"#]].assert_eq(&s);
let config: Config = serde_json::from_str(EMPTY_JSON).unwrap();
let s = serde_json::to_string(&config).unwrap();
expect![[r#"{"yes_or_no":true,"delta":-3,"max":7}"#]].assert_eq(&s);
expect![[r#"{"yes_or_no":true,"delta":-3,"max":7,"delimeter":"☀"}"#]].assert_eq(&s);
let config = Config::default();
let s = serde_json::to_string(&config).unwrap();
expect![[r#"{"yes_or_no":false,"delta":0,"max":0}"#]].assert_eq(&s);
expect![[r#"{"yes_or_no":false,"delta":0,"max":0,"delimeter":"\u0000"}"#]].assert_eq(&s);
}
}

0 comments on commit faebc4a

Please sign in to comment.