attribute_derive/from_partial.rs
1//! Contains utilities for implementing [`FromPartial`].
2use crate::*;
3
4/// Converts from a [`Partial`](AttributeBase::Partial) value.
5pub trait FromPartial<T>: Sized {
6 /// Creates `Self` from `T`.
7 ///
8 /// # Errors
9 /// Returns a [`syn::Error`] when `T` does not represent a valid `Self`,
10 /// e.g., due to missing or conflicting fields.
11 fn from(partial: T) -> Result<Self>;
12
13 /// Creates `Self` from optional `T`.
14 ///
15 /// # Errors
16 /// The default implementation errors with `error_missing` when `partial` is
17 /// [`None`], or when `Self::from` errors.
18 ///
19 /// Implementors might override this for types with expected default values.
20 fn from_option(partial: Option<T>, error_missing: &str) -> Result<Self> {
21 // Pass in surrounding span
22 partial
23 .map(Self::from)
24 .transpose()?
25 .ok_or_else(|| syn::Error::new(Span::call_site(), error_missing))
26 }
27
28 /// Defines how two arguments for the same parameter should be handled.
29 ///
30 /// # Errors
31 /// The default implementation errors if `first` is already present and
32 /// `specified_twice_error` is returned with the correct spans.
33 fn join(
34 first: Option<SpannedValue<T>>,
35 second: SpannedValue<T>,
36 specified_twice_error: &str,
37 ) -> Result<Option<SpannedValue<T>>> {
38 if let Some(first) = first {
39 if let Some(span) = first
40 .span()
41 .span_joined()
42 .and_then(|s| Some((s, second.span().span_joined()?)))
43 .and_then(|(a, b)| a.join(b))
44 {
45 Err(Error::new(span, specified_twice_error))
46 } else {
47 let mut error = Error::new(first.span().start, specified_twice_error);
48 error.combine(Error::new(second.span().start, specified_twice_error));
49 Err(error)
50 }
51 } else {
52 Ok(Some(second))
53 }
54 }
55}
56
57impl<T> FromPartial<T> for T {
58 fn from(partial: T) -> Result<Self> {
59 Ok(partial)
60 }
61}
62
63/// [`FromPartial`] wrapper that uses [`Default`] value when not specified.
64#[derive(Clone)]
65pub struct Defaulting<T>(pub T);
66
67impl<P, T: Default + FromPartial<P>> FromPartial<Defaulting<P>> for T {
68 fn from(partial: Defaulting<P>) -> Result<Self> {
69 Self::from(partial.0)
70 }
71
72 fn from_option(partial: Option<Defaulting<P>>, _error: &str) -> Result<Self> {
73 partial
74 .map(|d| Self::from(d.0))
75 .transpose()
76 .map(Option::unwrap_or_default)
77 }
78}
79
80/// Utility struct to avoid duplicate trait definition when using `Self<A>` for
81/// `<Self<B> as BaseAttribute>::Partial`.
82pub struct Partial<T>(pub T);