13 Commits

Author SHA1 Message Date
5d0f313523 build: update version to 0.2.1 2024-09-24 13:01:00 +02:00
c020a6e0e4 Suppress rust-analyzer's "Non Snake Case" warning for generated idents (#5) 2024-09-24 12:49:40 +02:00
7130dc8927 build: update version to 0.2.0 2024-01-27 00:19:41 +01:00
cbd26efdd4 chore: highlight required the macro position even more 2024-01-23 15:34:42 +01:00
85b1fbdfcd fix: apply syn update changes 2023-03-27 20:48:52 +00:00
cc8120fb4a build(deps): update syn requirement from 1.0 to 2.0
Updates the requirements on [syn](https://github.com/dtolnay/syn) to permit the latest version.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/1.0.0...2.0.10)

---
updated-dependencies:
- dependency-name: syn
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-27 20:48:52 +00:00
b0489edfaf chore: add dependabot 2023-02-24 14:22:26 +01:00
ba2c2133a5 test: add string default to test 2023-02-24 14:22:16 +01:00
6bb8576fa8 test(examples): add examples 2023-02-24 14:21:56 +01:00
8d1d49150f build: update version to 0.1.1 2023-02-11 19:45:26 +01:00
76727e73f4 docs: add documentation to macro function 2023-02-11 19:36:54 +01:00
d8a0dff1af docs: add README as library documentation 2023-02-11 18:51:49 +01:00
81b089be37 docs: fix docs.rs link 2023-02-11 18:49:17 +01:00
8 changed files with 114 additions and 12 deletions

6
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: cargo
directory: /
schedule:
interval: weekly

View File

@ -1,22 +1,23 @@
[package] [package]
name = "serde-inline-default" name = "serde-inline-default"
version = "0.1.0" version = "0.2.1"
authors = ["ByteDream"] authors = ["bytedream"]
edition = "2021" edition = "2021"
description = "Serde default values via inline declaration" description = "Serde default values via inline declaration"
readme = "README.md" readme = "README.md"
repository = "https://github.com/ByteDream/serde-inline-default" repository = "https://github.com/bytedream/serde-inline-default"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
keywords = ["serde", "serialization"] keywords = ["serde", "serialization"]
categories = ["encoding"] categories = ["encoding"]
[lib] [lib]
proc-macro = true proc-macro = true
doctest = false
[dependencies] [dependencies]
proc-macro2 = "1.0" proc-macro2 = "1.0"
quote = "1.0" quote = "1.0"
syn = { version = "1.0", features = ["full"] } syn = { version = "2.0", features = ["full"] }
[dev-dependencies] [dev-dependencies]
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }

View File

@ -1,10 +1,10 @@
# serde-inline-default [![ci](https://github.com/ByteDream/serde-inline-default/actions/workflows/ci.yml/badge.svg)](https://github.com/ByteDream/serde-inline-default/actions/workflows/ci.yml) [![crates.io](https://img.shields.io/crates/v/serde-inline-default)](https://crates.io/crates/serde-inline-default) [![docs](https://img.shields.io/docsrs/serde-inline-default)](https://docs.rs/crunchyroll-rs/latest/serde-inline-default/) # serde-inline-default [![ci](https://github.com/ByteDream/serde-inline-default/actions/workflows/ci.yml/badge.svg)](https://github.com/ByteDream/serde-inline-default/actions/workflows/ci.yml) [![crates.io](https://img.shields.io/crates/v/serde-inline-default)](https://crates.io/crates/serde-inline-default) [![docs](https://img.shields.io/docsrs/serde-inline-default)](https://docs.rs/serde-inline-default/latest/serde_inline_default/)
Tiny crate to set default values for serde fields via inline attribute declaration. Tiny crate to set default values for serde fields via inline attribute declaration.
## Overview ## Overview
This crate is an approach to do what serde-rs/serde#368 purposes. This crate is an approach to do what [serde-rs/serde#368](https://github.com/serde-rs/serde/issues/368) purposes.
If you want to set default values in plain [`serde`](https://serde.rs/), you have to create a function and link to it with `#[serde(default = "...")`. If you want to set default values in plain [`serde`](https://serde.rs/), you have to create a function and link to it with `#[serde(default = "...")`.
This may be good if you need to do calculations to get the default value, but often you just want a simple integer or string to be the default value and have to create a whole function to return a hard-coded value. This may be good if you need to do calculations to get the default value, but often you just want a simple integer or string to be the default value and have to create a whole function to return a hard-coded value.
```rust ```rust
@ -19,7 +19,7 @@ fn value_default() -> u32 { 42 }
That can get quiet messy if you have many fields with many (different) default values. That can get quiet messy if you have many fields with many (different) default values.
This crate tries to solve this issue by providing the `#[serde_inline_default]` proc macro. This crate tries to solve this issue by providing the `#[serde_inline_default]` proc macro.
With this macro set at the struct level (_before `#[derive(Deserialize)]`/`#[derive(Serialize)]`!_, otherwise it's not working correctly), you can set default values via `#[serde_inline_default(...)]` for your serde fields inline, without creating an extra function. With this macro set at the struct level (_**before `#[derive(Deserialize)]`/`#[derive(Serialize)]`!, otherwise it's not working correctly**_), you can set default values via `#[serde_inline_default(...)]` for your serde fields inline, without creating an extra function.
```rust ```rust
#[serde_inline_default] #[serde_inline_default]
@ -37,5 +37,5 @@ So this macro is just some syntax sugar for you, but can get quiet handy if you
This project is licensed under either of the following licenses, at your option: This project is licensed under either of the following licenses, at your option:
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0>)
- MIT License ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - MIT License ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)

29
examples/basic.rs Normal file
View File

@ -0,0 +1,29 @@
use serde::Deserialize;
use serde_inline_default::serde_inline_default;
use serde_json::json;
#[serde_inline_default]
#[derive(Deserialize)]
struct Basic {
// if using `String` you have to call `.to_string()`
#[serde_inline_default("0.0.0.0".to_string())]
host: String,
// works without specifying the integer type at the end of the value (8080u16)
#[serde_inline_default(8080)]
port: u16,
// expressions are working too
#[serde_inline_default(serde_json::json!({}))]
random_third_party_type: serde_json::Value,
}
fn main() -> Result<(), serde_json::Error> {
// creating a empty json object to use the default value of all fields
let json_object = json!({});
let basic: Basic = serde_json::from_value(json_object)?;
assert_eq!(basic.host, "0.0.0.0".to_string());
assert_eq!(basic.port, 8080);
assert_eq!(basic.random_third_party_type, json!({}));
Ok(())
}

39
examples/macro_rules.rs Normal file
View File

@ -0,0 +1,39 @@
use serde_json::json;
macro_rules! simple_macro {
(struct $name:ident { $($field:ident: $type:ty $(= $default:expr)?),*$(,)? }) => {
#[serde_inline_default::serde_inline_default]
#[derive(serde::Deserialize)]
struct $name {
$(
$(
#[serde_inline_default($default)]
)?
$field: $type
),*
}
}
}
fn main() -> Result<(), serde_json::Error> {
// `username` and `password` must be set when deserializing as no default value is defined for
// them. `secret` not as we're defining a default value for it
simple_macro! {
struct Example {
username: String,
password: String,
secret: String = "verysecretsecret".to_string()
}
}
let json_object = json!({
"username": "testuser",
"password": "testpassword"
});
let example: Example = serde_json::from_value(json_object)?;
assert_eq!(example.username, "testuser");
assert_eq!(example.password, "testpassword");
assert_eq!(example.secret, "verysecretsecret");
Ok(())
}

View File

@ -7,12 +7,11 @@ pub(crate) fn expand_struct(mut item: ItemStruct) -> proc_macro::TokenStream {
for (i, field) in item.fields.iter_mut().enumerate() { for (i, field) in item.fields.iter_mut().enumerate() {
for (j, attr) in field.attrs.iter_mut().enumerate() { for (j, attr) in field.attrs.iter_mut().enumerate() {
if !attr.path.is_ident("serde_inline_default") { if !attr.path().is_ident("serde_inline_default") {
continue; continue;
} }
let _default_str = attr.tokens.to_string(); let default: TokenStream = attr.parse_args().unwrap();
let default: TokenStream = _default_str[1.._default_str.len() - 1].parse().unwrap();
// we check here if a function with the exact same return value already exists. if so, // we check here if a function with the exact same return value already exists. if so,
// this function gets used. // this function gets used.
@ -28,6 +27,7 @@ pub(crate) fn expand_struct(mut item: ItemStruct) -> proc_macro::TokenStream {
let inline_fn = quote! { let inline_fn = quote! {
#[doc(hidden)] #[doc(hidden)]
#[allow(non_snake_case)]
fn #fn_name_ident () -> #return_type { fn #fn_name_ident () -> #return_type {
#default #default
} }

View File

@ -1,8 +1,32 @@
#![doc = include_str!("../README.md")]
use proc_macro::TokenStream; use proc_macro::TokenStream;
use syn::{parse_macro_input, Item}; use syn::{parse_macro_input, Item};
mod expand; mod expand;
/// The main macro of this crate.
/// Use it to define default values of fields in structs you [`Serialize`] or [`Deserialize`].
/// You do not need to create a extra function to provide the default value, as it is the case in serdes' implementation of default (`#[serde(default = "...")]`).
///
/// Set this macro on a struct where you use [`Serialize`] or [`Deserialize`] and use `#[serde_inline_default(...)]` on the field you want to have a inline default value.
/// Replace the `...` with the value you want and it will be set as default if serde needs it.
///
/// Note that you must set this macro _before_ `#[derive(Serialize)]` / `#[derive(Deserialize)]` as it wouldn't work properly if set after the derive.
///
/// # Examples
///
/// ```rust
/// #[serde_inline_default]
/// #[derive(Deserialize)]
/// struct Test {
/// #[serde_inline_default(42)]
/// value: u32
/// }
/// ```
///
/// [`Serialize`]: https://docs.rs/serde/*/serde/trait.Serialize.html
/// [`Deserialize`]: https://docs.rs/serde/*/serde/trait.Deserialize.html
#[proc_macro_attribute] #[proc_macro_attribute]
pub fn serde_inline_default(_attr: TokenStream, input: TokenStream) -> TokenStream { pub fn serde_inline_default(_attr: TokenStream, input: TokenStream) -> TokenStream {
let item = parse_macro_input!(input as Item); let item = parse_macro_input!(input as Item);

View File

@ -17,6 +17,8 @@ fn test_serde_inline_default() {
inline: u32, inline: u32,
#[serde_inline_default(-1337)] #[serde_inline_default(-1337)]
inline_negative: i32, inline_negative: i32,
#[serde_inline_default("string".to_string())]
string: String,
} }
let test: Test = serde_json::from_value(json!({})).unwrap(); let test: Test = serde_json::from_value(json!({})).unwrap();
@ -24,4 +26,5 @@ fn test_serde_inline_default() {
assert_eq!(test.native, 69); assert_eq!(test.native, 69);
assert_eq!(test.inline, 420); assert_eq!(test.inline, 420);
assert_eq!(test.inline_negative, -1337); assert_eq!(test.inline_negative, -1337);
assert_eq!(test.string, "string".to_string());
} }