Skip to main content

dbt_yaml/spanned/
mod.rs

1//! The
2
3use serde::{ser::Serializer, Deserialize, Deserializer, Serialize};
4use std::{
5    fmt::{self, Debug, Display},
6    hash::{Hash, Hasher},
7    ops::Deref,
8};
9
10mod span;
11
12pub use span::Marker;
13pub use span::Span;
14
15/// A wrapper type that can be used to capture the source location of a
16/// deserialized value.
17///
18/// NOTE:
19/// - Only works with the dbt_yaml deserializer.
20/// - May contain leading and trailing whitespace.
21pub struct Spanned<T> {
22    span: Span,
23    node: T,
24}
25
26impl<'de, T> Spanned<T>
27where
28    T: Deserialize<'de>,
29{
30    /// Create a new `Spanned` value with the given node.
31    pub fn new(node: T) -> Self {
32        Spanned {
33            span: Default::default(),
34            node,
35        }
36    }
37}
38
39impl<T> Spanned<T> {
40    /// Transform the inner node by applying the given function.
41    pub fn map<U, F>(self, f: F) -> Spanned<U>
42    where
43        F: FnOnce(T) -> U,
44    {
45        Spanned {
46            span: self.span,
47            node: f(self.node),
48        }
49    }
50
51    /// Transform the captured span by applying the given function.
52    pub fn map_span<F>(self, f: F) -> Self
53    where
54        F: FnOnce(Span) -> Span,
55    {
56        Self {
57            span: f(self.span),
58            ..self
59        }
60    }
61
62    /// Consumes the [Spanned] and returns the inner node.
63    pub fn into_inner(self) -> T {
64        self.node
65    }
66
67    /// Get the captured source span.
68    pub fn span(&self) -> &Span {
69        &self.span
70    }
71
72    /// True if this [Spanned] actually contains a valid span.
73    pub fn has_valid_span(&self) -> bool {
74        self.span.is_valid()
75    }
76}
77
78impl<T> Deref for Spanned<T> {
79    type Target = T;
80
81    fn deref(&self) -> &Self::Target {
82        &self.node
83    }
84}
85
86impl<T> AsRef<T> for Spanned<T> {
87    fn as_ref(&self) -> &T {
88        &self.node
89    }
90}
91
92impl<T> AsMut<T> for Spanned<T> {
93    fn as_mut(&mut self) -> &mut T {
94        &mut self.node
95    }
96}
97
98impl<T> Clone for Spanned<T>
99where
100    T: Clone,
101{
102    fn clone(&self) -> Self {
103        Spanned {
104            span: self.span.clone(),
105            node: self.node.clone(),
106        }
107    }
108}
109
110impl<T> Debug for Spanned<T>
111where
112    T: Debug,
113{
114    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115        write!(f, "{{{:?}}} ", self.span)?;
116        Debug::fmt(&self.node, f)
117    }
118}
119
120impl<T> Default for Spanned<T>
121where
122    T: Default,
123{
124    fn default() -> Self {
125        Spanned {
126            span: Default::default(),
127            node: T::default(),
128        }
129    }
130}
131
132impl<'de, T> From<T> for Spanned<T>
133where
134    T: Deserialize<'de>,
135{
136    fn from(node: T) -> Self {
137        Spanned::new(node)
138    }
139}
140
141impl<T> PartialEq for Spanned<T>
142where
143    T: PartialEq,
144{
145    fn eq(&self, other: &Self) -> bool {
146        self.node == other.node
147    }
148}
149
150impl<T> Eq for Spanned<T> where T: Eq {}
151
152impl<T> PartialOrd for Spanned<T>
153where
154    T: PartialOrd,
155{
156    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
157        self.node.partial_cmp(&other.node)
158    }
159}
160
161impl<T> Ord for Spanned<T>
162where
163    T: Ord,
164{
165    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
166        self.node.cmp(&other.node)
167    }
168}
169
170impl<T> Hash for Spanned<T>
171where
172    T: Hash,
173{
174    fn hash<H: Hasher>(&self, state: &mut H) {
175        self.node.hash(state);
176    }
177}
178
179impl<T> Display for Spanned<T>
180where
181    T: Display,
182{
183    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184        <T as Display>::fmt(&self.node, f)
185    }
186}
187
188impl<T> Serialize for Spanned<T>
189where
190    T: Serialize,
191{
192    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
193    where
194        S: Serializer,
195    {
196        set_span(self.span.clone());
197        T::serialize(&self.node, serializer)
198    }
199}
200
201impl<'de, T> Deserialize<'de> for Spanned<T>
202where
203    T: Deserialize<'de>,
204{
205    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
206    where
207        D: Deserializer<'de>,
208    {
209        let start_marker = get_marker();
210        let node = T::deserialize(deserializer)?;
211        let end_marker = get_marker();
212        let span: Span = (start_marker..end_marker).into();
213
214        #[cfg(feature = "filename")]
215        let span = span.maybe_capture_filename();
216
217        Ok(Spanned { span, node })
218    }
219}
220
221#[cfg(feature = "schemars")]
222impl<T> schemars::JsonSchema for Spanned<T>
223where
224    T: schemars::JsonSchema,
225{
226    fn schema_name() -> String {
227        T::schema_name()
228    }
229
230    fn json_schema(generator: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
231        T::json_schema(generator)
232    }
233
234    fn is_referenceable() -> bool {
235        T::is_referenceable()
236    }
237
238    fn schema_id() -> std::borrow::Cow<'static, str> {
239        T::schema_id()
240    }
241
242    #[doc(hidden)]
243    fn _schemars_private_non_optional_json_schema(
244        generator: &mut schemars::gen::SchemaGenerator,
245    ) -> schemars::schema::Schema {
246        T::_schemars_private_non_optional_json_schema(generator)
247    }
248
249    #[doc(hidden)]
250    fn _schemars_private_is_option() -> bool {
251        T::_schemars_private_is_option()
252    }
253}
254
255#[cfg(feature = "filename")]
256/// A scope guard that sets the current source filename.
257pub struct WithFilenameScope {
258    original: Option<std::sync::Arc<std::path::PathBuf>>,
259}
260
261#[cfg(feature = "filename")]
262impl Drop for WithFilenameScope {
263    fn drop(&mut self) {
264        FILENAME.with(|f| *f.borrow_mut() = std::mem::take(&mut self.original));
265    }
266}
267
268#[cfg(feature = "filename")]
269/// Set or clear the source filename for subsequent deserialization.
270///
271/// Returns a scope guard that restores the original filename when dropped.
272pub fn with_filename(filename: Option<std::path::PathBuf>) -> WithFilenameScope {
273    let original = FILENAME.with(|f| f.borrow_mut().take());
274    FILENAME.with(|f| *f.borrow_mut() = filename.map(std::sync::Arc::new));
275    WithFilenameScope { original }
276}
277
278/// Set the current source location marker.
279///
280/// This is called by [Deserializer] implementations to inform the
281/// [crate::Spanned] and [crate::Value] types about the current source location.
282pub fn set_marker(marker: impl Into<Marker>) {
283    MARKER.with(|m| *m.borrow_mut() = Some(marker.into()));
284}
285
286/// Reset the source location marker.
287pub fn reset_marker() {
288    MARKER.with(|m| *m.borrow_mut() = None);
289}
290
291/// Get the current source location marker.
292pub(crate) fn get_marker() -> Option<Marker> {
293    MARKER.with(|m| *m.borrow())
294}
295
296pub(crate) fn set_span(span: Span) {
297    SPAN.with(|s| *s.borrow_mut() = Some(span));
298}
299
300pub(crate) fn take_span() -> Option<Span> {
301    SPAN.with(|s| s.borrow_mut().take())
302}
303
304#[cfg(feature = "filename")]
305/// Set the current source filename.
306pub(crate) fn set_filename(filename: std::sync::Arc<std::path::PathBuf>) {
307    FILENAME.with(|f| *f.borrow_mut() = Some(filename));
308}
309
310#[cfg(feature = "filename")]
311/// Get the current source filename.
312pub(crate) fn get_filename() -> Option<std::sync::Arc<std::path::PathBuf>> {
313    FILENAME.with(|f| f.borrow().clone())
314}
315
316// Internal states for deserialization.
317thread_local! {
318    static MARKER: std::cell::RefCell<Option<Marker>> = const {
319        std::cell::RefCell::new(None)
320    };
321
322    #[cfg(feature = "filename")]
323    static FILENAME: std::cell::RefCell<Option<std::sync::Arc<std::path::PathBuf>>> = const {
324        std::cell::RefCell::new(None)
325    };
326}
327
328// Internal states for serialization.
329thread_local! {
330    static SPAN: std::cell::RefCell<Option<Span>> = const {
331        std::cell::RefCell::new(None)
332    };
333}