partial_default_derive/
lib.rs

1//
2// Original Copyright 2017 Idan Arye
3// Modifications Copyright 2023 Signal Messenger, LLC.
4// SPDX-License-Identifier: AGPL-3.0-only
5//
6
7#![doc = include_str!("../README.md")]
8
9use syn::{parse_macro_input, DeriveInput};
10
11mod body_impl;
12mod default_attr;
13mod util;
14
15/// Derive the `PartialDefault` trait.
16///
17/// The value used for a field can be overridden using the `#[partial_default(value =
18/// "alternative()")]` syntax, where `alternative()` is a Rust expression that evaluates to the
19/// correct type.
20///
21/// By default, the derived implementation will add a `T: PartialDefault` trait for every generic
22/// parameter, like the built-in `derive(Default)`. You can override this by adding
23/// `#[partial_default(bound = "T: MyTrait")]` to the type, which replaces any inferred bounds. Use
24/// an empty string to impose no restrictions at all.
25///
26/// # Examples
27///
28/// ```
29/// use partial_default::PartialDefault;
30///
31/// # fn main() {
32/// #[derive(PartialDefault)]
33/// #[partial_default(bound = "")]
34/// # #[derive(PartialEq)]
35/// # #[allow(dead_code)]
36/// enum Foo<T> {
37///     Bar,
38///     #[partial_default]
39///     Baz {
40///         #[partial_default(value = "12")]
41///         a: i32,
42///         b: i32,
43///         #[partial_default(value = "Some(Default::default())")]
44///         c: Option<i32>,
45///         #[partial_default(value = "vec![1, 2, 3]")]
46///         d: Vec<u32>,
47///         #[partial_default(value = r#""four".to_owned()"#)]
48///         e: String,
49///     },
50///     Qux(T),
51/// }
52///
53/// assert!(Foo::<&u8>::partial_default() == Foo::<&u8>::Baz {
54///     a: 12,
55///     b: 0,
56///     c: Some(0),
57///     d: vec![1, 2, 3],
58///     e: "four".to_owned(),
59/// });
60/// # }
61/// ```
62#[proc_macro_derive(PartialDefault, attributes(partial_default))]
63pub fn derive_partial_default(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
64    let input = parse_macro_input!(input as DeriveInput);
65    match body_impl::impl_my_derive(&input) {
66        Ok(output) => output.into(),
67        Err(error) => error.to_compile_error().into(),
68    }
69}