synthez_core/
spanned.rs

1//! Batteries for [`Span`] and [`syn::spanned`].
2
3use std::{
4    cmp::{Eq, PartialEq},
5    ops::{Deref, DerefMut},
6};
7
8use proc_macro2::Span;
9use sealed::sealed;
10use syn::spanned::Spanned;
11
12/// Helper coercion for [`Span`] and [`Spanned`] types to use in function
13/// arguments.
14#[sealed]
15pub trait IntoSpan {
16    /// Returns the coerced [`Span`].
17    #[must_use]
18    fn into_span(self) -> Span;
19}
20
21#[sealed]
22impl IntoSpan for Span {
23    #[inline]
24    fn into_span(self) -> Self {
25        self
26    }
27}
28
29#[sealed]
30impl<T: Spanned> IntoSpan for &T {
31    #[inline]
32    fn into_span(self) -> Span {
33        self.span()
34    }
35}
36
37#[sealed]
38impl<T> IntoSpan for &Spanning<T> {
39    #[inline]
40    fn into_span(self) -> Span {
41        self.span()
42    }
43}
44
45/// Wrapper for non-[`Spanned`] types to hold their [`Span`].
46#[derive(Clone, Copy, Debug)]
47pub struct Spanning<T: ?Sized> {
48    /// [`Span`] of the `item`.
49    span: Span,
50
51    /// Item the [`Span`] is held for.
52    item: T,
53}
54
55impl<T> Spanning<T> {
56    /// Creates a new [`Spanning`] `item` out of the given value and its
57    /// [`Span`].
58    #[must_use]
59    pub fn new<S: IntoSpan>(item: T, span: S) -> Self {
60        Self { span: span.into_span(), item }
61    }
62
63    /// Destructures this [`Spanning`] wrapper returning the underlying value.
64    // false positive: constant functions cannot evaluate destructors
65    #[allow(clippy::missing_const_for_fn)]
66    #[must_use]
67    pub fn into_inner(self) -> T {
68        self.item
69    }
70}
71
72impl<T: ?Sized> Spanning<T> {
73    /// Returns the [`Span`] contained in this [`Spanning`] wrapper.
74    #[must_use]
75    pub const fn span(&self) -> Span {
76        self.span
77    }
78}
79
80impl<T: ?Sized> Deref for Spanning<T> {
81    type Target = T;
82
83    fn deref(&self) -> &Self::Target {
84        &self.item
85    }
86}
87
88impl<T: ?Sized> DerefMut for Spanning<T> {
89    fn deref_mut(&mut self) -> &mut Self::Target {
90        &mut self.item
91    }
92}
93
94impl<T, V> PartialEq<Spanning<V>> for Spanning<T>
95where
96    T: PartialEq<V> + ?Sized,
97    V: ?Sized,
98{
99    fn eq(&self, other: &Spanning<V>) -> bool {
100        self.item.eq(&other.item)
101    }
102}
103
104impl<T: PartialEq + ?Sized> Eq for Spanning<T> {}
105
106impl From<Spanning<&str>> for syn::LitStr {
107    fn from(s: Spanning<&str>) -> Self {
108        Self::new(s.item, s.span)
109    }
110}
111
112impl From<Spanning<String>> for syn::LitStr {
113    fn from(s: Spanning<String>) -> Self {
114        Self::new(&s.item, s.span)
115    }
116}