mirror of
https://github.com/bytedream/serde-inline-default.git
synced 2025-05-09 20:25:13 +02:00
Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
6c014e41a6 | |||
5fbcd2eb14 | |||
baeb1969fe | |||
0a12ee6b3f | |||
6f0f9f9799 | |||
985eca392c |
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde-inline-default"
|
name = "serde-inline-default"
|
||||||
version = "0.2.2"
|
version = "0.2.3"
|
||||||
authors = ["bytedream"]
|
authors = ["bytedream"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "Serde default values via inline declaration"
|
description = "Serde default values via inline declaration"
|
||||||
|
49
README.md
49
README.md
@ -1,4 +1,4 @@
|
|||||||
# serde-inline-default [](https://github.com/ByteDream/serde-inline-default/actions/workflows/ci.yml) [](https://crates.io/crates/serde-inline-default) [](https://docs.rs/serde-inline-default/latest/serde_inline_default/)
|
# serde-inline-default [](https://github.com/ByteDream/serde-inline-default/actions/workflows/ci.yml) [](https://crates.io/crates/serde-inline-default) [](https://crates.io/crates/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.
|
||||||
|
|
||||||
@ -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, 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]
|
||||||
@ -30,9 +30,54 @@ struct Test {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> **`#[serde_inline_default]` must be set before `#[derive(Deserialize)]`/`#[derive(Serialize)]`, otherwise it's not working correctly!**
|
||||||
|
|
||||||
Internally, `#[serde_inline_default(...)]` gets expanded to a function which returns the set value and the attribute is replaced with `#[serde(default = "<function name>")]`.
|
Internally, `#[serde_inline_default(...)]` gets expanded to a function which returns the set value and the attribute is replaced with `#[serde(default = "<function name>")]`.
|
||||||
So this macro is just some syntax sugar for you, but can get quiet handy if you want to keep your code clean or write declarative macros / `macro_rules!`.
|
So this macro is just some syntax sugar for you, but can get quiet handy if you want to keep your code clean or write declarative macros / `macro_rules!`.
|
||||||
|
|
||||||
|
## Alternatives
|
||||||
|
|
||||||
|
This crate isn't perfect. Thus, you might be more satisfied with alternatives `serde` provides.
|
||||||
|
|
||||||
|
With `#[serde(default)]` + `impl Default` on a struct, `serde` uses the default implementation of the struct to get default values for each field ([docs](https://serde.rs/container-attrs.html#default)):
|
||||||
|
```rust
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
|
struct Test {
|
||||||
|
value: u32
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Test {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
value: 42
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If you still need/want `serde-inline-default` features, you also can combine them with `#[serde(default))` and `impl Default`:
|
||||||
|
```rust
|
||||||
|
#[serde_inline_default]
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
|
struct Test {
|
||||||
|
value: u32,
|
||||||
|
#[serde_inline_default(0)]
|
||||||
|
other_value: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Test {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
value: 42,
|
||||||
|
other_value: 42
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
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:
|
||||||
|
@ -4,7 +4,7 @@ use quote::quote;
|
|||||||
use syn::{parse_quote, ItemStruct};
|
use syn::{parse_quote, ItemStruct};
|
||||||
|
|
||||||
pub(crate) fn expand_struct(mut item: ItemStruct) -> proc_macro::TokenStream {
|
pub(crate) fn expand_struct(mut item: ItemStruct) -> proc_macro::TokenStream {
|
||||||
let mut inline_fns: Vec<(String, TokenStream, TokenStream)> = vec![];
|
let mut inline_fns: Vec<TokenStream> = vec![];
|
||||||
|
|
||||||
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() {
|
||||||
@ -14,31 +14,21 @@ pub(crate) fn expand_struct(mut item: ItemStruct) -> proc_macro::TokenStream {
|
|||||||
|
|
||||||
let default: TokenStream = attr.parse_args().unwrap();
|
let default: TokenStream = attr.parse_args().unwrap();
|
||||||
|
|
||||||
// we check here if a function with the exact same return value already exists. if so,
|
let fn_name_lit = format!("__serde_inline_default_{}_{}", item.ident, i);
|
||||||
// this function gets used.
|
let fn_name_ident = Ident::new(&fn_name_lit, Span::call_site());
|
||||||
let fn_name_lit = if let Some((fn_name_lit, _, _)) = inline_fns
|
let mut return_type = field.ty.clone();
|
||||||
.iter()
|
|
||||||
.find(|(_, def, _)| def.to_string() == default.to_string())
|
|
||||||
{
|
|
||||||
fn_name_lit.clone()
|
|
||||||
} else {
|
|
||||||
let fn_name_lit = format!("__serde_inline_default_{}_{}", item.ident, i);
|
|
||||||
let fn_name_ident = Ident::new(&fn_name_lit, Span::call_site());
|
|
||||||
let mut return_type = field.ty.clone();
|
|
||||||
|
|
||||||
// replaces most lifetimes with 'static
|
// replaces most lifetimes with 'static
|
||||||
type_lifetimes_to_static(&mut return_type);
|
type_lifetimes_to_static(&mut return_type);
|
||||||
|
|
||||||
|
inline_fns.push(quote! {
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn #fn_name_ident () -> #return_type {
|
||||||
|
#default
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let inline_fn = quote! {
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
fn #fn_name_ident () -> #return_type {
|
|
||||||
#default
|
|
||||||
}
|
|
||||||
};
|
|
||||||
inline_fns.push((fn_name_lit.clone(), default, inline_fn));
|
|
||||||
fn_name_lit
|
|
||||||
};
|
|
||||||
field.attrs.remove(j);
|
field.attrs.remove(j);
|
||||||
field
|
field
|
||||||
.attrs
|
.attrs
|
||||||
@ -47,10 +37,8 @@ pub(crate) fn expand_struct(mut item: ItemStruct) -> proc_macro::TokenStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let real_inline_fns: Vec<TokenStream> =
|
|
||||||
inline_fns.into_iter().map(|(_, _, func)| func).collect();
|
|
||||||
let expanded = quote! {
|
let expanded = quote! {
|
||||||
#( #real_inline_fns )*
|
#( #inline_fns )*
|
||||||
|
|
||||||
#item
|
#item
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user