• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use proc_macro2::Span;
2 use std::ops::{Deref, DerefMut};
3 use syn::spanned::Spanned;
4 
5 use crate::{
6     FromDeriveInput, FromField, FromGenericParam, FromGenerics, FromMeta, FromTypeParam,
7     FromVariant, Result,
8 };
9 
10 /// A value and an associated position in source code. The main use case for this is
11 /// to preserve position information to emit warnings from proc macros. You can use
12 /// a `SpannedValue<T>` as a field in any struct that implements or derives any of
13 /// `darling`'s core traits.
14 ///
15 /// To access the underlying value, use the struct's `Deref` implementation.
16 ///
17 /// # Defaulting
18 /// This type is meant to be used in conjunction with attribute-extracted options,
19 /// but the user may not always explicitly set those options in their source code.
20 /// In this case, using `Default::default()` will create an instance which points
21 /// to `Span::call_site()`.
22 #[derive(Debug, Clone, Copy)]
23 pub struct SpannedValue<T> {
24     value: T,
25     span: Span,
26 }
27 
28 impl<T> SpannedValue<T> {
new(value: T, span: Span) -> Self29     pub fn new(value: T, span: Span) -> Self {
30         SpannedValue { value, span }
31     }
32 
33     /// Get the source code location referenced by this struct.
span(&self) -> Span34     pub fn span(&self) -> Span {
35         self.span
36     }
37 
38     /// Apply a mapping function to a reference to the spanned value.
map_ref<U>(&self, map_fn: impl FnOnce(&T) -> U) -> SpannedValue<U>39     pub fn map_ref<U>(&self, map_fn: impl FnOnce(&T) -> U) -> SpannedValue<U> {
40         SpannedValue::new(map_fn(&self.value), self.span)
41     }
42 }
43 
44 impl<T: Default> Default for SpannedValue<T> {
default() -> Self45     fn default() -> Self {
46         SpannedValue::new(Default::default(), Span::call_site())
47     }
48 }
49 
50 impl<T> Deref for SpannedValue<T> {
51     type Target = T;
52 
deref(&self) -> &T53     fn deref(&self) -> &T {
54         &self.value
55     }
56 }
57 
58 impl<T> DerefMut for SpannedValue<T> {
deref_mut(&mut self) -> &mut T59     fn deref_mut(&mut self) -> &mut T {
60         &mut self.value
61     }
62 }
63 
64 impl<T> AsRef<T> for SpannedValue<T> {
as_ref(&self) -> &T65     fn as_ref(&self) -> &T {
66         &self.value
67     }
68 }
69 
70 macro_rules! spanned {
71     ($trayt:ident, $method:ident, $syn:path) => {
72         impl<T: $trayt> $trayt for SpannedValue<T> {
73             fn $method(value: &$syn) -> Result<Self> {
74                 Ok(SpannedValue::new(
75                     $trayt::$method(value).map_err(|e| e.with_span(value))?,
76                     value.span(),
77                 ))
78             }
79         }
80     };
81 }
82 
83 impl<T: FromMeta> FromMeta for SpannedValue<T> {
from_meta(item: &syn::Meta) -> Result<Self>84     fn from_meta(item: &syn::Meta) -> Result<Self> {
85         let value = T::from_meta(item).map_err(|e| e.with_span(item))?;
86         let span = match item {
87             // Example: `#[darling(skip)]` as SpannedValue<bool>
88             // should have the span pointing to the word `skip`.
89             syn::Meta::Path(path) => path.span(),
90             // Example: `#[darling(attributes(Value))]` as a SpannedValue<Vec<String>>
91             // should have the span pointing to the list contents.
92             syn::Meta::List(list) => list.tokens.span(),
93             // Example: `#[darling(skip = true)]` as SpannedValue<bool>
94             // should have the span pointing to the word `true`.
95             syn::Meta::NameValue(nv) => nv.value.span(),
96         };
97 
98         Ok(Self::new(value, span))
99     }
100 }
101 
102 spanned!(FromGenericParam, from_generic_param, syn::GenericParam);
103 spanned!(FromGenerics, from_generics, syn::Generics);
104 spanned!(FromTypeParam, from_type_param, syn::TypeParam);
105 spanned!(FromDeriveInput, from_derive_input, syn::DeriveInput);
106 spanned!(FromField, from_field, syn::Field);
107 spanned!(FromVariant, from_variant, syn::Variant);
108 
109 impl<T: Spanned> From<T> for SpannedValue<T> {
from(value: T) -> Self110     fn from(value: T) -> Self {
111         let span = value.span();
112         SpannedValue::new(value, span)
113     }
114 }
115 
116 #[cfg(test)]
117 mod tests {
118     use super::*;
119     use proc_macro2::Span;
120 
121     /// Make sure that `SpannedValue` can be seamlessly used as its underlying type.
122     #[test]
deref()123     fn deref() {
124         let test = SpannedValue::new("hello", Span::call_site());
125         assert_eq!("hello", test.trim());
126     }
127 }
128