Skip to main content

dbt_yaml/
path.rs

1//! Path to the current value in the input.
2
3use std::{
4    cell::OnceCell,
5    fmt::{self, Display},
6};
7
8/// A structured representation of a path to the current value in the input,
9/// like `dependencies.serde.typo1`.
10#[derive(Copy, Clone)]
11pub enum Path<'a> {
12    /// The root of the input.
13    Root,
14    /// A sequence index.
15    Seq {
16        /// The path to the parent value.
17        parent: &'a Path<'a>,
18        /// The index of the current value.
19        index: usize,
20    },
21    /// A map key.
22    Map {
23        /// The path to the parent value.
24        parent: &'a Path<'a>,
25        /// The key of the current value.
26        key: &'a str,
27    },
28    /// An alias.
29    Alias {
30        /// The path to the parent value.
31        parent: &'a Path<'a>,
32    },
33    /// An unknown path.
34    Unknown {
35        /// The path to the parent value.
36        parent: &'a Path<'a>,
37    },
38}
39
40impl Display for Path<'_> {
41    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
42        struct Parent<'a>(&'a Path<'a>);
43
44        impl Display for Parent<'_> {
45            fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
46                match self.0 {
47                    Path::Root => Ok(()),
48                    path => write!(formatter, "{}.", path),
49                }
50            }
51        }
52
53        match self {
54            Path::Root => formatter.write_str("."),
55            Path::Seq { parent, index } => write!(formatter, "{}[{}]", parent, index),
56            Path::Map { parent, key } => write!(formatter, "{}{}", Parent(parent), key),
57            Path::Alias { parent } => write!(formatter, "{}", parent),
58            Path::Unknown { parent } => write!(formatter, "{}?", Parent(parent)),
59        }
60    }
61}
62
63impl<'a> Path<'a> {
64    /// Returns an owned version of this path.
65    pub fn to_owned_path(&self) -> OwnedPath {
66        match self {
67            Path::Root => OwnedPath::Root,
68            Path::Seq { parent, index } => OwnedPath::Seq {
69                parent: Box::new(parent.to_owned_path()),
70                index: *index,
71                borrowed: OnceCell::new(),
72            },
73            Path::Map { parent, key } => OwnedPath::Map {
74                parent: Box::new(parent.to_owned_path()),
75                key: key.to_string(),
76                borrowed: OnceCell::new(),
77            },
78            Path::Alias { parent } => OwnedPath::Alias {
79                parent: Box::new(parent.to_owned_path()),
80                borrowed: OnceCell::new(),
81            },
82            Path::Unknown { parent } => OwnedPath::Unknown {
83                parent: Box::new(parent.to_owned_path()),
84                borrowed: OnceCell::new(),
85            },
86        }
87    }
88}
89
90/// An owned version of a [Path].
91pub enum OwnedPath {
92    /// The root of the input.
93    Root,
94    /// A sequence index.
95    Seq {
96        /// The path to the parent value.
97        parent: Box<OwnedPath>,
98        /// The index of the current value.
99        index: usize,
100        /// A cell to hold the borrowed path.
101        borrowed: OnceCell<Path<'static>>,
102    },
103    /// A map key.
104    Map {
105        /// The path to the parent value.
106        parent: Box<OwnedPath>,
107        /// The key of the current value.
108        key: String,
109        /// A cell to hold the borrowed path.
110        borrowed: OnceCell<Path<'static>>,
111    },
112    /// An alias.
113    Alias {
114        /// The path to the parent value.
115        parent: Box<OwnedPath>,
116        /// A cell to hold the borrowed path.
117        borrowed: OnceCell<Path<'static>>,
118    },
119    /// An unknown path.
120    Unknown {
121        /// The path to the parent value.
122        parent: Box<OwnedPath>,
123        /// A cell to hold the borrowed path.
124        borrowed: OnceCell<Path<'static>>,
125    },
126}
127
128impl<'a> OwnedPath {
129    /// Returns a borrowed version of this path.
130    pub fn as_path(&'a self) -> &'a Path<'a> {
131        static ROOT: Path<'static> = Path::Root;
132
133        match self {
134            OwnedPath::Root => &ROOT,
135            OwnedPath::Seq {
136                parent,
137                index,
138                borrowed,
139            } => {
140                let borrowed = borrowed.get_or_init(|| {
141                    let parent = parent.as_path();
142                    // SAFETY: self-reference
143                    unsafe {
144                        std::mem::transmute(Path::Seq {
145                            parent,
146                            index: *index,
147                        })
148                    }
149                });
150                borrowed
151            }
152            OwnedPath::Map {
153                parent,
154                key,
155                borrowed,
156            } => {
157                let borrowed = borrowed.get_or_init(|| {
158                    let parent = parent.as_path();
159                    // SAFETY: self-reference
160                    unsafe {
161                        std::mem::transmute(Path::Map {
162                            parent,
163                            key: key.as_ref(),
164                        })
165                    }
166                });
167                borrowed
168            }
169            OwnedPath::Alias { parent, borrowed } => {
170                let borrowed = borrowed.get_or_init(|| {
171                    let parent = parent.as_path();
172                    // SAFETY: self-reference
173                    unsafe { std::mem::transmute(Path::Alias { parent }) }
174                });
175                borrowed
176            }
177            OwnedPath::Unknown { parent, borrowed } => {
178                let borrowed = borrowed.get_or_init(|| {
179                    let parent = parent.as_path();
180                    // SAFETY: self-reference
181                    unsafe { std::mem::transmute(Path::Unknown { parent }) }
182                });
183                borrowed
184            }
185        }
186    }
187}