Skip to main content

miden_debug_types/
lib.rs

1#![no_std]
2
3extern crate alloc;
4
5#[cfg(any(feature = "std", test))]
6extern crate std;
7
8mod location;
9mod selection;
10mod source_file;
11mod source_manager;
12mod span;
13
14use alloc::{string::String, sync::Arc};
15
16use miden_crypto::utils::{
17    ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
18};
19#[cfg(feature = "serde")]
20use serde::{Deserialize, Serialize};
21#[cfg(feature = "serde")]
22pub use serde_spanned;
23
24#[cfg(feature = "std")]
25pub use self::source_manager::SourceManagerExt;
26pub use self::{
27    location::{FileLineCol, Location},
28    selection::{Position, Selection},
29    source_file::{
30        ByteIndex, ByteOffset, ColumnIndex, ColumnNumber, LineIndex, LineNumber, SourceContent,
31        SourceContentUpdateError, SourceFile, SourceFileRef, SourceLanguage,
32    },
33    source_manager::{DefaultSourceManager, SourceId, SourceManager, SourceManagerSync},
34    span::{SourceSpan, Span, Spanned},
35};
36
37// URI
38// ================================================================================================
39
40/// A [URI reference](https://datatracker.ietf.org/doc/html/rfc3986#section-4.1) that specifies
41/// the location of a source file, whether on disk, on the network, or elsewhere.
42#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
43#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
44pub struct Uri(Arc<str>);
45
46impl Uri {
47    pub fn new(uri: impl AsRef<str>) -> Self {
48        uri.as_ref().into()
49    }
50
51    #[inline]
52    pub fn as_str(&self) -> &str {
53        self.0.as_ref()
54    }
55
56    #[inline]
57    pub fn as_bytes(&self) -> &[u8] {
58        self.0.as_bytes()
59    }
60
61    /// Returns the scheme portion of this URI, if present.
62    pub fn scheme(&self) -> Option<&str> {
63        match self.0.split_once(':') {
64            Some((prefix, _))
65                if prefix.contains(|c: char| {
66                    !c.is_ascii_alphanumeric() && !matches!(c, '+' | '-' | '.')
67                }) =>
68            {
69                None
70            },
71            Some((prefix, _)) => Some(prefix),
72            None => None,
73        }
74    }
75
76    /// Returns the authority portion of this URI, if present.
77    pub fn authority(&self) -> Option<&str> {
78        let uri = self.0.as_ref();
79        let (_, rest) = uri.split_once("//")?;
80        match rest.split_once(['/', '?', '#']) {
81            Some((authority, _)) => Some(authority),
82            None => Some(rest),
83        }
84    }
85
86    /// Returns the path portion of this URI.
87    pub fn path(&self) -> &str {
88        let uri = self.0.as_ref();
89        let path = match uri.split_once("//") {
90            Some((_, rest)) => match rest.find('/').map(|pos| rest.split_at(pos)) {
91                Some((_, path)) => path,
92                None => return "",
93            },
94            None => match uri.split_once(':') {
95                Some((prefix, _))
96                    if prefix.contains(|c: char| {
97                        !c.is_ascii_alphanumeric() && !matches!(c, '+' | '-' | '.')
98                    }) =>
99                {
100                    uri
101                },
102                Some((_, path)) => path,
103                None => uri,
104            },
105        };
106        match path.split_once(['?', '#']) {
107            Some((path, _)) => path,
108            None => path,
109        }
110    }
111}
112
113impl core::fmt::Display for Uri {
114    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
115        core::fmt::Display::fmt(&self.0, f)
116    }
117}
118
119impl AsRef<str> for Uri {
120    fn as_ref(&self) -> &str {
121        self.0.as_ref()
122    }
123}
124
125impl From<&str> for Uri {
126    #[inline]
127    fn from(value: &str) -> Self {
128        use alloc::string::ToString;
129
130        value.to_string().into()
131    }
132}
133
134impl From<Uri> for Arc<str> {
135    fn from(value: Uri) -> Self {
136        value.0
137    }
138}
139
140impl From<Arc<str>> for Uri {
141    #[inline]
142    fn from(uri: Arc<str>) -> Self {
143        Self(uri)
144    }
145}
146
147impl From<alloc::boxed::Box<str>> for Uri {
148    #[inline]
149    fn from(uri: alloc::boxed::Box<str>) -> Self {
150        Self(uri.into())
151    }
152}
153
154impl From<String> for Uri {
155    #[inline]
156    fn from(uri: String) -> Self {
157        Self(uri.into_boxed_str().into())
158    }
159}
160
161#[cfg(feature = "std")]
162impl<'a> From<&'a std::path::Path> for Uri {
163    fn from(path: &'a std::path::Path) -> Self {
164        use alloc::string::ToString;
165
166        Self::from(path.display().to_string())
167    }
168}
169
170impl Serializable for Uri {
171    fn write_into<W: ByteWriter>(&self, target: &mut W) {
172        self.as_str().write_into(target);
173    }
174}
175
176impl Deserializable for Uri {
177    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
178        String::read_from(source).map(Self::from)
179    }
180}
181
182impl core::str::FromStr for Uri {
183    type Err = ();
184
185    fn from_str(s: &str) -> Result<Self, Self::Err> {
186        Ok(Self::from(s))
187    }
188}
189
190// TESTS
191// ================================================================================================
192
193#[cfg(test)]
194mod tests {
195    use super::*;
196
197    #[test]
198    fn uri_scheme_extraction() {
199        let relative_file = Uri::new("foo.masm");
200        let relative_file_path = Uri::new("./foo.masm");
201        let relative_file_path_with_scheme = Uri::new("file:foo.masm");
202        let absolute_file_path = Uri::new("file:///tmp/foo.masm");
203        let http_simple_uri = Uri::new("http://www.example.com");
204        let http_simple_uri_with_userinfo = Uri::new("http://foo:bar@www.example.com");
205        let http_simple_uri_with_userinfo_and_port = Uri::new("http://foo:bar@www.example.com:443");
206        let http_simple_uri_with_userinfo_and_path =
207            Uri::new("http://foo:bar@www.example.com/api/v1");
208        let http_simple_uri_with_userinfo_and_query =
209            Uri::new("http://foo:bar@www.example.com?param=1");
210        let http_simple_uri_with_userinfo_and_fragment =
211            Uri::new("http://foo:bar@www.example.com#about");
212        let http_simple_uri_with_userinfo_and_path_and_query =
213            Uri::new("http://foo:bar@www.example.com/api/v1/user?id=1");
214        let http_simple_uri_with_userinfo_and_path_and_query_and_fragment =
215            Uri::new("http://foo:bar@www.example.com/api/v1/user?id=1#redirect=/home");
216
217        assert_eq!(relative_file.scheme(), None);
218        assert_eq!(relative_file_path.scheme(), None);
219        assert_eq!(relative_file_path_with_scheme.scheme(), Some("file"));
220        assert_eq!(absolute_file_path.scheme(), Some("file"));
221        assert_eq!(http_simple_uri.scheme(), Some("http"));
222        assert_eq!(http_simple_uri_with_userinfo.scheme(), Some("http"));
223        assert_eq!(http_simple_uri_with_userinfo_and_port.scheme(), Some("http"));
224        assert_eq!(http_simple_uri_with_userinfo_and_path.scheme(), Some("http"));
225        assert_eq!(http_simple_uri_with_userinfo_and_query.scheme(), Some("http"));
226        assert_eq!(http_simple_uri_with_userinfo_and_fragment.scheme(), Some("http"));
227        assert_eq!(http_simple_uri_with_userinfo_and_path_and_query.scheme(), Some("http"));
228        assert_eq!(
229            http_simple_uri_with_userinfo_and_path_and_query_and_fragment.scheme(),
230            Some("http")
231        );
232    }
233
234    #[test]
235    fn uri_authority_extraction() {
236        let relative_file = Uri::new("foo.masm");
237        let relative_file_path = Uri::new("./foo.masm");
238        let relative_file_path_with_scheme = Uri::new("file:foo.masm");
239        let absolute_file_path = Uri::new("file:///tmp/foo.masm");
240        let http_simple_uri = Uri::new("http://www.example.com");
241        let http_simple_uri_with_userinfo = Uri::new("http://foo:bar@www.example.com");
242        let http_simple_uri_with_userinfo_and_port = Uri::new("http://foo:bar@www.example.com:443");
243        let http_simple_uri_with_userinfo_and_path =
244            Uri::new("http://foo:bar@www.example.com/api/v1");
245        let http_simple_uri_with_userinfo_and_query =
246            Uri::new("http://foo:bar@www.example.com?param=1");
247        let http_simple_uri_with_userinfo_and_fragment =
248            Uri::new("http://foo:bar@www.example.com#about");
249        let http_simple_uri_with_userinfo_and_path_and_query =
250            Uri::new("http://foo:bar@www.example.com/api/v1/user?id=1");
251        let http_simple_uri_with_userinfo_and_path_and_query_and_fragment =
252            Uri::new("http://foo:bar@www.example.com/api/v1/user?id=1#redirect=/home");
253
254        assert_eq!(relative_file.authority(), None);
255        assert_eq!(relative_file_path.authority(), None);
256        assert_eq!(relative_file_path_with_scheme.authority(), None);
257        assert_eq!(absolute_file_path.authority(), Some(""));
258        assert_eq!(http_simple_uri.authority(), Some("www.example.com"));
259        assert_eq!(http_simple_uri_with_userinfo.authority(), Some("foo:bar@www.example.com"));
260        assert_eq!(
261            http_simple_uri_with_userinfo_and_port.authority(),
262            Some("foo:bar@www.example.com:443")
263        );
264        assert_eq!(
265            http_simple_uri_with_userinfo_and_path.authority(),
266            Some("foo:bar@www.example.com")
267        );
268        assert_eq!(
269            http_simple_uri_with_userinfo_and_query.authority(),
270            Some("foo:bar@www.example.com")
271        );
272        assert_eq!(
273            http_simple_uri_with_userinfo_and_fragment.authority(),
274            Some("foo:bar@www.example.com")
275        );
276        assert_eq!(
277            http_simple_uri_with_userinfo_and_path_and_query.authority(),
278            Some("foo:bar@www.example.com")
279        );
280        assert_eq!(
281            http_simple_uri_with_userinfo_and_path_and_query_and_fragment.authority(),
282            Some("foo:bar@www.example.com")
283        );
284    }
285
286    #[test]
287    fn uri_path_extraction() {
288        let relative_file = Uri::new("foo.masm");
289        let relative_file_path = Uri::new("./foo.masm");
290        let relative_file_path_with_scheme = Uri::new("file:foo.masm");
291        let absolute_file_path = Uri::new("file:///tmp/foo.masm");
292        let http_simple_uri = Uri::new("http://www.example.com");
293        let http_simple_uri_with_userinfo = Uri::new("http://foo:bar@www.example.com");
294        let http_simple_uri_with_userinfo_and_port = Uri::new("http://foo:bar@www.example.com:443");
295        let http_simple_uri_with_userinfo_and_path =
296            Uri::new("http://foo:bar@www.example.com/api/v1");
297        let http_simple_uri_with_userinfo_and_query =
298            Uri::new("http://foo:bar@www.example.com?param=1");
299        let http_simple_uri_with_userinfo_and_fragment =
300            Uri::new("http://foo:bar@www.example.com#about");
301        let http_simple_uri_with_userinfo_and_path_and_query =
302            Uri::new("http://foo:bar@www.example.com/api/v1/user?id=1");
303        let http_simple_uri_with_userinfo_and_path_and_query_and_fragment =
304            Uri::new("http://foo:bar@www.example.com/api/v1/user?id=1#redirect=/home");
305
306        assert_eq!(relative_file.path(), "foo.masm");
307        assert_eq!(relative_file_path.path(), "./foo.masm");
308        assert_eq!(relative_file_path_with_scheme.path(), "foo.masm");
309        assert_eq!(absolute_file_path.path(), "/tmp/foo.masm");
310        assert_eq!(http_simple_uri.path(), "");
311        assert_eq!(http_simple_uri_with_userinfo.path(), "");
312        assert_eq!(http_simple_uri_with_userinfo_and_port.path(), "");
313        assert_eq!(http_simple_uri_with_userinfo_and_path.path(), "/api/v1");
314        assert_eq!(http_simple_uri_with_userinfo_and_query.path(), "");
315        assert_eq!(http_simple_uri_with_userinfo_and_fragment.path(), "");
316        assert_eq!(http_simple_uri_with_userinfo_and_path_and_query.path(), "/api/v1/user");
317        assert_eq!(
318            http_simple_uri_with_userinfo_and_path_and_query_and_fragment.path(),
319            "/api/v1/user"
320        );
321    }
322}