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