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
46impl Serializable for Location {
47    fn write_into<W: ByteWriter>(&self, target: &mut W) {
48        self.uri.write_into(target);
49        self.start.to_u32().write_into(target);
50        self.end.to_u32().write_into(target);
51    }
52}
53
54impl Deserializable for Location {
55    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
56        let uri = Uri::read_from(source)?;
57        let start = ByteIndex::from(source.read_u32()?);
58        let end = ByteIndex::from(source.read_u32()?);
59        Ok(Self::new(uri, start, end))
60    }
61}
62
63/// A [FileLineCol] represents traditional file/line/column information for use in rendering.
64#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
65#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
66#[cfg_attr(
67    all(feature = "arbitrary", test),
68    miden_test_serde_macros::serde_test(binary_serde(true))
69)]
70pub struct FileLineCol {
71    /// The path to the source file in which the relevant source code can be found
72    pub uri: Uri,
73    /// The one-indexed number of the line to which this location refers
74    pub line: LineNumber,
75    /// The one-indexed column of the line on which this location starts
76    pub column: ColumnNumber,
77}
78
79impl FileLineCol {
80    /// Creates a new [Location].
81    pub fn new(
82        uri: impl Into<Uri>,
83        line: impl Into<LineNumber>,
84        column: impl Into<ColumnNumber>,
85    ) -> Self {
86        Self {
87            uri: uri.into(),
88            line: line.into(),
89            column: column.into(),
90        }
91    }
92
93    /// Get the name (or path) of the source file
94    pub fn uri(&self) -> &Uri {
95        &self.uri
96    }
97
98    /// Returns the line of the location.
99    pub const fn line(&self) -> LineNumber {
100        self.line
101    }
102
103    /// Moves the column by the given offset.
104    pub fn move_column(&mut self, offset: i32) {
105        self.column += offset;
106    }
107}
108
109impl fmt::Display for FileLineCol {
110    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111        write!(f, "[{}@{}:{}]", self.uri, self.line, self.column)
112    }
113}
114
115impl Serializable for FileLineCol {
116    fn write_into<W: ByteWriter>(&self, target: &mut W) {
117        self.uri.write_into(target);
118        self.line.write_into(target);
119        self.column.write_into(target);
120    }
121}
122
123impl Deserializable for FileLineCol {
124    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
125        let uri = Uri::read_from(source)?;
126        let line = LineNumber::read_from(source)?;
127        let column = ColumnNumber::read_from(source)?;
128        Ok(Self::new(uri, line, column))
129    }
130}
131
132#[cfg(feature = "arbitrary")]
133impl Arbitrary for Location {
134    type Parameters = ();
135    type Strategy = BoxedStrategy<Self>;
136
137    fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
138        (any::<Uri>(), any::<u32>(), any::<u32>())
139            .prop_map(|(uri, start, end)| {
140                let (start, end) = if start <= end { (start, end) } else { (end, start) };
141                Self::new(uri, ByteIndex::new(start), ByteIndex::new(end))
142            })
143            .boxed()
144    }
145}
146
147#[cfg(feature = "arbitrary")]
148impl Arbitrary for FileLineCol {
149    type Parameters = ();
150    type Strategy = BoxedStrategy<Self>;
151
152    fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
153        (any::<Uri>(), any::<LineNumber>(), any::<ColumnNumber>())
154            .prop_map(|(uri, line, column)| Self::new(uri, line, column))
155            .boxed()
156    }
157}