mirror of
https://github.com/bytedream/serde-inline-default.git
synced 2026-11-04 15:12:09 +01:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0cc4052eaf | ||
|
|
d197326c32 | ||
|
|
71cdef9d6e | ||
|
|
6132d5369f | ||
|
|
2865e49da3 | ||
|
|
a44606e99c | ||
|
|
5cafcf3e3f | ||
|
|
ba08395a42 | ||
|
|
5427bdffe7 | ||
|
|
ce70ea4365 | ||
|
|
017080244a | ||
|
|
12b209ad49 | ||
|
|
8cac0af5c0 | ||
|
|
8a863f3b32 | ||
|
|
6c014e41a6 | ||
|
|
5fbcd2eb14 | ||
|
|
baeb1969fe | ||
|
|
0a12ee6b3f | ||
|
|
6f0f9f9799 | ||
|
|
985eca392c | ||
|
|
6eddcf38fe | ||
|
|
c5d874a3ad | ||
|
|
5d0f313523 | ||
|
|
c020a6e0e4 | ||
|
|
7130dc8927 | ||
|
|
cbd26efdd4 | ||
|
|
85b1fbdfcd | ||
|
|
cc8120fb4a | ||
|
|
b0489edfaf | ||
|
|
ba2c2133a5 | ||
|
|
6bb8576fa8 | ||
|
|
8d1d49150f | ||
|
|
76727e73f4 | ||
|
|
d8a0dff1af | ||
|
|
81b089be37 |
No files matched your search
+27
-14
@@ -2,30 +2,43 @@ name: ci
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "**"
|
||||
tags-ignore:
|
||||
- "**"
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Generate cargo lockfile
|
||||
run: cargo generate-lockfile
|
||||
|
||||
- name: Cargo cache
|
||||
uses: actions/cache@v3
|
||||
- name: Setup Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
~/.cargo/git/db/
|
||||
target/
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
toolchain: stable
|
||||
|
||||
- name: Test
|
||||
run: cargo test
|
||||
|
||||
verify-msrv:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Install cargo-msrv
|
||||
uses: taiki-e/install-action@v2
|
||||
with:
|
||||
tool: cargo-msrv
|
||||
|
||||
- name: Verify msrv
|
||||
run: cargo msrv verify --all-features
|
||||
@@ -8,10 +8,16 @@ on:
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Publish crate
|
||||
run: cargo publish --token ${{ secrets.CRATES_TOKEN }}
|
||||
env:
|
||||
CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_TOKEN }}
|
||||
run: cargo publish
|
||||
+14
-4
@@ -1,22 +1,32 @@
|
||||
[package]
|
||||
name = "serde-inline-default"
|
||||
version = "0.1.0"
|
||||
authors = ["ByteDream"]
|
||||
version = "1.0.2"
|
||||
authors = ["bytedream"]
|
||||
edition = "2021"
|
||||
rust-version = "1.71.0"
|
||||
description = "Serde default values via inline declaration"
|
||||
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"
|
||||
keywords = ["serde", "serialization"]
|
||||
categories = ["encoding"]
|
||||
include = [
|
||||
"/Cargo.toml",
|
||||
"/LICENSE-APACHE",
|
||||
"/LICENSE-MIT",
|
||||
"/README.md",
|
||||
"/src/**",
|
||||
"/tests/**"
|
||||
]
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "1.0"
|
||||
quote = "1.0"
|
||||
syn = { version = "1.0", features = ["full"] }
|
||||
syn = { version = "3.0", features = ["full"] }
|
||||
|
||||
[dev-dependencies]
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# serde-inline-default [](https://github.com/ByteDream/serde-inline-default/actions/workflows/ci.yml) [](https://crates.io/crates/serde-inline-default) [](https://docs.rs/crunchyroll-rs/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.
|
||||
A tiny crate to set default values for serde struct fields via inline attribute declaration.
|
||||
|
||||
## Overview
|
||||
|
||||
This crate is an approach to do what serde-rs/serde#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 = "...")`.
|
||||
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 crate is an approach to do what [serde-rs/serde#368](https://github.com/serde-rs/serde/issues/368) purposes: Defining default values for struct fields via inline declaration instead of creating a separate function for it.
|
||||
|
||||
So instead of writing something like this, which can get very verbose quickly with many fields:
|
||||
```rust
|
||||
#[derive(Deserialize)]
|
||||
struct Test {
|
||||
@@ -16,11 +16,7 @@ struct Test {
|
||||
|
||||
fn value_default() -> u32 { 42 }
|
||||
```
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
you can just do this:
|
||||
```rust
|
||||
#[serde_inline_default]
|
||||
#[derive(Deserialize)]
|
||||
@@ -30,12 +26,57 @@ struct Test {
|
||||
}
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **`#[serde_inline_default]` must be set before `#[derive(Deserialize)]`/`#[derive(Serialize)]`!**
|
||||
|
||||
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 quite 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
|
||||
|
||||
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)
|
||||
- MIT License ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||
- 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>)
|
||||
@@ -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(())
|
||||
}
|
||||
@@ -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(())
|
||||
}
|
||||
+57
-41
@@ -1,54 +1,70 @@
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::quote;
|
||||
use syn::{parse_quote, ItemStruct};
|
||||
use syn::{spanned::Spanned, Error, Fields, ItemEnum, ItemStruct};
|
||||
|
||||
use crate::utils::{check_field_for_default_expr, ATTR_NAME, DEFAULT_FN_PREFIX};
|
||||
|
||||
pub(crate) fn expand_struct(mut item: ItemStruct) -> proc_macro::TokenStream {
|
||||
let mut inline_fns: Vec<(String, TokenStream, TokenStream)> = vec![];
|
||||
let mut default_fns = vec![];
|
||||
|
||||
for (i, field) in item.fields.iter_mut().enumerate() {
|
||||
for (j, attr) in field.attrs.iter_mut().enumerate() {
|
||||
if !attr.path.is_ident("serde_inline_default") {
|
||||
continue;
|
||||
default_fns.extend(check_field_for_default_expr(field, || {
|
||||
format!("{}_{}_Field{}", DEFAULT_FN_PREFIX, item.ident, i)
|
||||
}));
|
||||
}
|
||||
|
||||
quote! {
|
||||
#( #default_fns )*
|
||||
|
||||
#item
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
pub(crate) fn expand_enum(mut item: ItemEnum) -> proc_macro::TokenStream {
|
||||
let mut default_fns = vec![];
|
||||
|
||||
for (i, variant) in item.variants.iter_mut().enumerate() {
|
||||
if variant.attrs.iter().any(|a| a.path().is_ident(ATTR_NAME)) {
|
||||
return Error::new(
|
||||
variant.span(),
|
||||
format!(
|
||||
"#[{}] can only be used on named enum variant fields",
|
||||
ATTR_NAME
|
||||
),
|
||||
)
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
|
||||
let fields = match &mut variant.fields {
|
||||
Fields::Named(fields) => fields,
|
||||
_ => {
|
||||
return Error::new(
|
||||
variant.span(),
|
||||
format!(
|
||||
"#[{}] can only be used on named enum variant fields",
|
||||
ATTR_NAME
|
||||
),
|
||||
)
|
||||
.to_compile_error()
|
||||
.into()
|
||||
}
|
||||
};
|
||||
|
||||
let _default_str = attr.tokens.to_string();
|
||||
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,
|
||||
// this function gets used.
|
||||
let fn_name_lit = if let Some((fn_name_lit, _, _)) = inline_fns
|
||||
.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 return_type = &field.ty;
|
||||
|
||||
let inline_fn = quote! {
|
||||
#[doc(hidden)]
|
||||
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
|
||||
.insert(j, parse_quote!( #[serde(default = #fn_name_lit)] ));
|
||||
break;
|
||||
for (j, field) in fields.named.iter_mut().enumerate() {
|
||||
default_fns.extend(check_field_for_default_expr(field, || {
|
||||
format!(
|
||||
"{}_{}_Variant{}_Field{}",
|
||||
DEFAULT_FN_PREFIX, item.ident, i, j
|
||||
)
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
let real_inline_fns: Vec<TokenStream> =
|
||||
inline_fns.into_iter().map(|(_, _, func)| func).collect();
|
||||
let expanded = quote! {
|
||||
#( #real_inline_fns )*
|
||||
quote! {
|
||||
#( #default_fns )*
|
||||
|
||||
#item
|
||||
};
|
||||
expanded.into()
|
||||
}
|
||||
.into()
|
||||
}
|
||||
+37
-3
@@ -1,14 +1,48 @@
|
||||
#![doc = include_str!("../README.md")]
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use syn::{parse_macro_input, Item};
|
||||
use syn::{parse_macro_input, spanned::Spanned, Error, Item};
|
||||
|
||||
mod expand;
|
||||
mod utils;
|
||||
|
||||
/// 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 an 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 an 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 won't work properly if it's 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]
|
||||
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);
|
||||
|
||||
match item {
|
||||
Item::Struct(s) => expand::expand_struct(s),
|
||||
_ => panic!("can only be used on structs"),
|
||||
Item::Enum(e) => expand::expand_enum(e),
|
||||
_ => Error::new(
|
||||
proc_macro2::TokenStream::from(attr).span(),
|
||||
"can only be used on structs and enums",
|
||||
)
|
||||
.to_compile_error()
|
||||
.into(),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::quote;
|
||||
use syn::{parse_quote, Field, GenericArgument, Ident, PathArguments, Type};
|
||||
|
||||
pub(crate) const ATTR_NAME: &str = "serde_inline_default";
|
||||
pub(crate) const DEFAULT_FN_PREFIX: &str = "__serde_inline_default";
|
||||
|
||||
pub(crate) fn type_lifetimes_to_static(ty: &mut Type) {
|
||||
match ty {
|
||||
Type::Array(array) => type_lifetimes_to_static(array.elem.as_mut()),
|
||||
Type::Group(group) => type_lifetimes_to_static(&mut group.elem),
|
||||
Type::Path(path) => {
|
||||
for segment in &mut path.path.segments {
|
||||
match &mut segment.arguments {
|
||||
PathArguments::None => (),
|
||||
PathArguments::AngleBracketed(angle_bracketed) => {
|
||||
for arg in &mut angle_bracketed.args {
|
||||
match arg {
|
||||
GenericArgument::Lifetime(lifetime) => {
|
||||
*lifetime = parse_quote!('static);
|
||||
}
|
||||
GenericArgument::Type(ty) => type_lifetimes_to_static(ty),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
PathArguments::Parenthesized(parenthesized) => {
|
||||
for input in &mut parenthesized.inputs {
|
||||
type_lifetimes_to_static(&mut input.ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Type::Ptr(ptr) => type_lifetimes_to_static(&mut ptr.elem),
|
||||
Type::Reference(reference) => reference.lifetime = Some(parse_quote!('static)),
|
||||
Type::Slice(slice) => type_lifetimes_to_static(&mut slice.elem),
|
||||
Type::Tuple(tuple) => {
|
||||
for elem in &mut tuple.elems {
|
||||
type_lifetimes_to_static(elem)
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn check_field_for_default_expr(
|
||||
field: &mut Field,
|
||||
identifier_fn: impl FnOnce() -> String,
|
||||
) -> Option<TokenStream> {
|
||||
for (i, attr) in field.attrs.iter_mut().enumerate() {
|
||||
if !attr.path().is_ident(ATTR_NAME) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let default_expr: TokenStream = attr.parse_args().unwrap();
|
||||
|
||||
// copy all the same #[cfg] conditional compilations flags for the field onto our built
|
||||
// default function.
|
||||
// otherwise, it's possible to create a constructor for a type that may be filtered by
|
||||
// the same #[cfg]'s, breaking compilation
|
||||
let cfg_attrs = field.attrs.iter().filter(|a| a.path().is_ident("cfg"));
|
||||
|
||||
let default_fn_lit = identifier_fn();
|
||||
let default_fn_ident = Ident::new(&default_fn_lit, Span::call_site());
|
||||
let mut return_type = field.ty.clone();
|
||||
|
||||
// replace lifetimes with 'static.
|
||||
// the built default function / default values in general can only be static as they're
|
||||
// generated without reference to the parent struct
|
||||
type_lifetimes_to_static(&mut return_type);
|
||||
|
||||
let default_fn_expr = quote! {
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
#( #cfg_attrs )*
|
||||
fn #default_fn_ident () -> #return_type {
|
||||
#default_expr
|
||||
}
|
||||
};
|
||||
|
||||
field.attrs[i] = parse_quote!( #[serde(default = #default_fn_lit)] );
|
||||
return Some(default_fn_expr);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
use serde::Deserialize;
|
||||
use serde_inline_default::serde_inline_default;
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn enum_default() {
|
||||
#[serde_inline_default]
|
||||
#[derive(Debug, PartialEq, Eq, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum Test {
|
||||
VariantWithFields {
|
||||
#[serde_inline_default(255)]
|
||||
test_int: u8,
|
||||
},
|
||||
}
|
||||
|
||||
let enum_test: Test = serde_json::from_value(json!({"VariantWithFields": {}})).unwrap();
|
||||
|
||||
assert_eq!(enum_test, Test::VariantWithFields { test_int: 255 })
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde_inline_default::serde_inline_default;
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn struct_normal() {
|
||||
fn native_default() -> u32 {
|
||||
69
|
||||
}
|
||||
|
||||
#[serde_inline_default]
|
||||
#[derive(Deserialize)]
|
||||
struct Test {
|
||||
#[serde(default = "native_default")]
|
||||
native: u32,
|
||||
#[serde_inline_default(420)]
|
||||
inline: u32,
|
||||
#[serde_inline_default(-1337)]
|
||||
inline_negative: i32,
|
||||
#[serde_inline_default("string".to_string())]
|
||||
string: String,
|
||||
}
|
||||
|
||||
let test: Test = serde_json::from_value(json!({})).unwrap();
|
||||
|
||||
assert_eq!(test.native, 69);
|
||||
assert_eq!(test.inline, 420);
|
||||
assert_eq!(test.inline_negative, -1337);
|
||||
assert_eq!(test.string, "string".to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lifetime() {
|
||||
#[serde_inline_default]
|
||||
#[derive(Deserialize)]
|
||||
struct LifetimeTest<'a> {
|
||||
#[serde_inline_default("test".into())]
|
||||
test_str: Cow<'a, str>,
|
||||
}
|
||||
|
||||
let lifetime_test: LifetimeTest = serde_json::from_value(json!({})).unwrap();
|
||||
|
||||
assert_eq!(lifetime_test.test_str, "test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(dead_code)]
|
||||
fn conditional_compilation() {
|
||||
#[cfg(debug_assertions)]
|
||||
#[derive(Deserialize)]
|
||||
struct TypeA(u8);
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
#[derive(Deserialize)]
|
||||
struct TypeB(u8);
|
||||
|
||||
#[serde_inline_default]
|
||||
#[derive(Deserialize)]
|
||||
struct Test {
|
||||
#[cfg(debug_assertions)]
|
||||
#[serde_inline_default(TypeA(1))]
|
||||
val_a: TypeA,
|
||||
#[cfg(not(debug_assertions))]
|
||||
#[serde_inline_default(TypeB(1))]
|
||||
val_b: TypeB,
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
use serde::Deserialize;
|
||||
use serde_inline_default::serde_inline_default;
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn test_serde_inline_default() {
|
||||
fn native_default() -> u32 {
|
||||
69
|
||||
}
|
||||
|
||||
#[serde_inline_default]
|
||||
#[derive(Deserialize)]
|
||||
struct Test {
|
||||
#[serde(default = "native_default")]
|
||||
native: u32,
|
||||
#[serde_inline_default(420)]
|
||||
inline: u32,
|
||||
#[serde_inline_default(-1337)]
|
||||
inline_negative: i32,
|
||||
}
|
||||
|
||||
let test: Test = serde_json::from_value(json!({})).unwrap();
|
||||
|
||||
assert_eq!(test.native, 69);
|
||||
assert_eq!(test.inline, 420);
|
||||
assert_eq!(test.inline_negative, -1337);
|
||||
}
|
||||
Reference in new issue
Block a user