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}