Skip to main content

miden_debug_types/
location.rs

1use core::{fmt, ops::Range};
2
3use miden_crypto::utils::{
4    ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
5};
6#[cfg(feature = "arbitrary")]
7use proptest::prelude::*;
8#[cfg(feature = "serde")]
9use serde::{Deserialize, Serialize};
10
11use super::{
12    ByteIndex, Uri,
13    source_file::{ColumnNumber, LineNumber},
14};
15
16/// A [Location] represents file and span information for portability across source managers
17#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
18#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
19#[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)]
20pub struct Location {
21    /// The path to the source file in which the relevant source code can be found
22    pub uri: Uri,
23    /// The starting byte index (inclusive) of this location
24    pub start: ByteIndex,
25    /// The ending byte index (exclusive) of this location
26    pub end: ByteIndex,
27}
28
29impl Location {
30    /// Creates a new [Location].
31    pub const fn new(uri: Uri, start: ByteIndex, end: ByteIndex) -> Self {
32        Self { uri, start, end }
33    }
34
35    /// Get the name (or path) of the source file
36    pub fn uri(&self) -> &Uri {
37        &self.uri
38    }
39
40    /// Returns the byte range represented by this location
41    pub const fn range(&self) -> Range<ByteIndex> {
42        self.start..self.end
43    }
44}
45
46/// A [FileLineCol] represents traditional file/line/column information for use in rendering.
47#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
48#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
49#[cfg_attr(
50    all(feature = "arbitrary", test),
51    miden_test_serde_macros::serde_test(binary_serde(true))
52)]
53pub struct FileLineCol {
54    /// The path to the source file in which the relevant source code can be found
55    pub uri: Uri,
56    /// The one-indexed number of the line to which this location refers
57    pub line: LineNumber,
58    /// The one-indexed column of the line on which this location starts
59    pub column: ColumnNumber,
60}
61
62impl FileLineCol {
63    /// Creates a new [Location].
64    pub fn new(
65        uri: impl Into<Uri>,
66        line: impl Into<LineNumber>,
67        column: impl Into<ColumnNumber>,
68    ) -> Self {
69        Self {
70            uri: uri.into(),
71            line: line.into(),
72            column: column.into(),
73        }
74    }
75
76    /// Get the name (or path) of the source file
77    pub fn uri(&self) -> &Uri {
78        &self.uri
79    }
80
81    /// Returns the line of the location.
82    pub const fn line(&self) -> LineNumber {
83        self.line
84    }
85
86    /// Moves the column by the given offset.
87    pub fn move_column(&mut self, offset: i32) {
88        self.column += offset;
89    }
90}
91
92impl fmt::Display for FileLineCol {
93    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94        write!(f, "[{}@{}:{}]", &self.uri, self.line, self.column)
95    }
96}
97
98impl Serializable for FileLineCol {
99    fn write_into<W: ByteWriter>(&self, target: &mut W) {
100        self.uri.write_into(target);
101        self.line.write_into(target);
102        self.column.write_into(target);
103    }
104}
105
106impl Deserializable for FileLineCol {
107    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
108        let uri = Uri::read_from(source)?;
109        let line = LineNumber::read_from(source)?;
110        let column = ColumnNumber::read_from(source)?;
111        Ok(Self::new(uri, line, column))
112    }
113}
114
115#[cfg(feature = "arbitrary")]
116impl Arbitrary for Location {
117    type Parameters = ();
118    type Strategy = BoxedStrategy<Self>;
119
120    fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
121        (any::<Uri>(), any::<u32>(), any::<u32>())
122            .prop_map(|(uri, start, end)| {
123                let (start, end) = if start <= end { (start, end) } else { (end, start) };
124                Self::new(uri, ByteIndex::new(start), ByteIndex::new(end))
125            })
126            .boxed()
127    }
128}
129
130#[cfg(feature = "arbitrary")]
131impl Arbitrary for FileLineCol {
132    type Parameters = ();
133    type Strategy = BoxedStrategy<Self>;
134
135    fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
136        (any::<Uri>(), any::<LineNumber>(), any::<ColumnNumber>())
137            .prop_map(|(uri, line, column)| Self::new(uri, line, column))
138            .boxed()
139    }
140}