darling_core/util/
spanned_value.rs1use proc_macro2::Span;
2use quote::{quote_spanned, ToTokens, TokenStreamExt};
3use std::ops::{Deref, DerefMut};
4use syn::spanned::Spanned;
5
6use crate::{
7 FromDeriveInput, FromField, FromGenericParam, FromGenerics, FromMeta, FromTypeParam,
8 FromVariant, Result,
9};
10
11#[derive(Debug, Clone, Copy)]
24pub struct SpannedValue<T> {
25 value: T,
26 span: Span,
27}
28
29impl<T> SpannedValue<T> {
30 pub fn new(value: T, span: Span) -> Self {
31 SpannedValue { value, span }
32 }
33
34 pub fn span(&self) -> Span {
36 self.span
37 }
38
39 pub fn map_ref<U>(&self, map_fn: impl FnOnce(&T) -> U) -> SpannedValue<U> {
41 SpannedValue::new(map_fn(&self.value), self.span)
42 }
43
44 pub fn into_inner(self) -> T {
46 self.value
47 }
48}
49
50impl<T: Default> Default for SpannedValue<T> {
51 fn default() -> Self {
52 SpannedValue::new(Default::default(), Span::call_site())
53 }
54}
55
56impl<T> Deref for SpannedValue<T> {
57 type Target = T;
58
59 fn deref(&self) -> &T {
60 &self.value
61 }
62}
63
64impl<T> DerefMut for SpannedValue<T> {
65 fn deref_mut(&mut self) -> &mut T {
66 &mut self.value
67 }
68}
69
70impl<T> AsRef<T> for SpannedValue<T> {
71 fn as_ref(&self) -> &T {
72 &self.value
73 }
74}
75
76macro_rules! spanned {
77 ($trayt:ident, $method:ident, $syn:path) => {
78 impl<T: $trayt> $trayt for SpannedValue<T> {
79 fn $method(value: &$syn) -> Result<Self> {
80 Ok(SpannedValue::new(
81 $trayt::$method(value).map_err(|e| e.with_span(value))?,
82 value.span(),
83 ))
84 }
85 }
86 };
87}
88
89impl<T: FromMeta> FromMeta for SpannedValue<T> {
90 fn from_meta(item: &syn::Meta) -> Result<Self> {
91 let value = T::from_meta(item).map_err(|e| e.with_span(item))?;
92 let span = match item {
93 syn::Meta::Path(path) => path.span(),
96 syn::Meta::List(list) => list.tokens.span(),
99 syn::Meta::NameValue(nv) => nv.value.span(),
102 };
103
104 Ok(Self::new(value, span))
105 }
106
107 fn from_nested_meta(item: &crate::ast::NestedMeta) -> Result<Self> {
108 T::from_nested_meta(item)
109 .map(|value| Self::new(value, item.span()))
110 .map_err(|e| e.with_span(item))
111 }
112
113 fn from_value(literal: &syn::Lit) -> Result<Self> {
114 T::from_value(literal)
115 .map(|value| Self::new(value, literal.span()))
116 .map_err(|e| e.with_span(literal))
117 }
118
119 fn from_expr(expr: &syn::Expr) -> Result<Self> {
120 T::from_expr(expr)
121 .map(|value| Self::new(value, expr.span()))
122 .map_err(|e| e.with_span(expr))
123 }
124}
125
126spanned!(FromGenericParam, from_generic_param, syn::GenericParam);
127spanned!(FromGenerics, from_generics, syn::Generics);
128spanned!(FromTypeParam, from_type_param, syn::TypeParam);
129spanned!(FromDeriveInput, from_derive_input, syn::DeriveInput);
130spanned!(FromField, from_field, syn::Field);
131spanned!(FromVariant, from_variant, syn::Variant);
132
133impl<T: Spanned> From<T> for SpannedValue<T> {
134 fn from(value: T) -> Self {
135 let span = value.span();
136 SpannedValue::new(value, span)
137 }
138}
139
140impl<T: ToTokens> ToTokens for SpannedValue<T> {
141 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
142 let value = &self.value;
143 tokens.append_all(quote_spanned!(self.span()=> #value));
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150 use proc_macro2::Span;
151
152 #[test]
154 fn deref() {
155 let test = SpannedValue::new("hello", Span::call_site());
156 assert_eq!("hello", test.trim());
157 }
158}