rune/
sources.rs

1use core::fmt;
2use core::num;
3
4use crate as rune;
5use crate::alloc;
6use crate::alloc::path::Path;
7use crate::alloc::prelude::*;
8use crate::ast::Span;
9use crate::source::Source;
10#[cfg(feature = "codespan-reporting")]
11use codespan_reporting::files;
12
13/// Helper macro to define a collection of sources populatedc with the given
14/// entries.
15///
16/// Calling this macro is fallible with [alloc::Error], so you should do it in a
17/// function that returns a `Result`.
18///
19/// ```
20/// let sources = rune::sources! {
21///     entry => {
22///         pub fn main() {
23///             42
24///         }
25///     }
26/// };
27///
28/// Ok::<_, rune::support::Error>(())
29/// ```
30#[macro_export]
31macro_rules! sources {
32    ($($name:ident => {$($tt:tt)*}),* $(,)?) => {{
33        let mut sources = $crate::Sources::new();
34        $(sources.insert($crate::Source::new(stringify!($name), stringify!($($tt)*))?)?;)*
35        sources
36    }};
37}
38
39/// A collection of source files.
40#[derive(Debug, Default)]
41pub struct Sources {
42    /// Sources associated.
43    sources: Vec<Source>,
44}
45
46impl Sources {
47    /// Construct a new collection of sources.
48    pub fn new() -> Self {
49        Self {
50            sources: Vec::new(),
51        }
52    }
53
54    /// Insert a source and return its [`SourceId`].
55    ///
56    /// # Examples
57    ///
58    /// ```
59    /// use rune::{Sources, Source};
60    ///
61    /// let mut sources = Sources::new();
62    /// let id = sources.insert(Source::new("<memory>", "pub fn main() { 10 }")?)?;
63    /// let id2 = sources.insert(Source::new("<memory>", "pub fn main() { 10 }")?)?;
64    /// assert_ne!(id, id2);
65    /// # Ok::<_, rune::support::Error>(())
66    /// ```
67    pub fn insert(&mut self, source: Source) -> alloc::Result<SourceId> {
68        let id =
69            SourceId::try_from(self.sources.len()).expect("could not build a source identifier");
70        self.sources.try_push(source)?;
71        Ok(id)
72    }
73
74    /// Get the source matching the given source id.
75    ///
76    /// # Examples
77    ///
78    /// ```
79    /// # use anyhow::Context;
80    /// use rune::{Sources, Source};
81    ///
82    /// let mut sources = Sources::new();
83    /// let id = sources.insert(Source::new("<memory>", "pub fn main() { 10 }")?)?;
84    ///
85    /// let source = sources.get(id).context("expected source")?;
86    ///
87    /// assert_eq!(source.name(), "<memory>");
88    /// # Ok::<_, rune::support::Error>(())
89    /// ```
90    pub fn get(&self, id: SourceId) -> Option<&Source> {
91        self.sources.get(id.into_index())
92    }
93
94    /// Fetch name for the given source id.
95    pub(crate) fn name(&self, id: SourceId) -> Option<&str> {
96        let source = self.sources.get(id.into_index())?;
97        Some(source.name())
98    }
99
100    /// Fetch source for the given span.
101    pub(crate) fn source(&self, id: SourceId, span: Span) -> Option<&str> {
102        let source = self.sources.get(id.into_index())?;
103        source.get(span.range())
104    }
105
106    /// Access the optional path of the given source id.
107    pub(crate) fn path(&self, id: SourceId) -> Option<&Path> {
108        let source = self.sources.get(id.into_index())?;
109        source.path()
110    }
111
112    /// Get all available source ids.
113    pub(crate) fn source_ids(&self) -> impl Iterator<Item = SourceId> {
114        (0..self.sources.len()).map(|index| SourceId::new(index as u32))
115    }
116
117    /// Iterate over all registered sources.
118    #[cfg(feature = "cli")]
119    pub(crate) fn iter(&self) -> impl Iterator<Item = &Source> {
120        self.sources.iter()
121    }
122}
123
124#[cfg(feature = "codespan-reporting")]
125impl<'a> files::Files<'a> for Sources {
126    type FileId = SourceId;
127    type Name = &'a str;
128    type Source = &'a str;
129
130    fn name(&'a self, file_id: SourceId) -> Result<Self::Name, files::Error> {
131        let source = self.get(file_id).ok_or(files::Error::FileMissing)?;
132        Ok(source.name())
133    }
134
135    fn source(&'a self, file_id: SourceId) -> Result<Self::Source, files::Error> {
136        let source = self.get(file_id).ok_or(files::Error::FileMissing)?;
137        Ok(source.as_str())
138    }
139
140    #[cfg(feature = "emit")]
141    fn line_index(&self, file_id: SourceId, byte_index: usize) -> Result<usize, files::Error> {
142        let source = self.get(file_id).ok_or(files::Error::FileMissing)?;
143        Ok(source.line_index(byte_index))
144    }
145
146    #[cfg(feature = "emit")]
147    fn line_range(
148        &self,
149        file_id: SourceId,
150        line_index: usize,
151    ) -> Result<std::ops::Range<usize>, files::Error> {
152        let source = self.get(file_id).ok_or(files::Error::FileMissing)?;
153        let range = source
154            .line_range(line_index)
155            .ok_or_else(|| files::Error::LineTooLarge {
156                given: line_index,
157                max: source.line_count(),
158            })?;
159        Ok(range)
160    }
161}
162
163/// The opaque identifier of a source file, as returned by
164/// [`Sources::insert`].
165///
166/// It can be used to reference the inserted source file in the future through
167/// methods such as [`Sources::get`].
168#[derive(TryClone, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
169#[try_clone(copy)]
170#[repr(transparent)]
171pub struct SourceId {
172    index: u32,
173}
174
175impl SourceId {
176    /// The empty source identifier.
177    pub const EMPTY: Self = Self::empty();
178
179    /// Construct a source identifier from an index.
180    pub const fn new(index: u32) -> Self {
181        Self { index }
182    }
183
184    /// Define an empty source identifier that cannot reference a source.
185    pub const fn empty() -> Self {
186        Self { index: u32::MAX }
187    }
188
189    /// Access the source identifier as an index.
190    pub fn into_index(self) -> usize {
191        usize::try_from(self.index).expect("source id out of bounds")
192    }
193}
194
195impl fmt::Debug for SourceId {
196    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197        self.index.fmt(f)
198    }
199}
200
201impl fmt::Display for SourceId {
202    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
203        self.index.fmt(f)
204    }
205}
206
207impl Default for SourceId {
208    fn default() -> Self {
209        Self::empty()
210    }
211}
212
213impl TryFrom<usize> for SourceId {
214    type Error = num::TryFromIntError;
215
216    fn try_from(value: usize) -> Result<Self, Self::Error> {
217        Ok(Self {
218            index: u32::try_from(value)?,
219        })
220    }
221}
222
223impl serde::Serialize for SourceId {
224    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
225    where
226        S: serde::Serializer,
227    {
228        self.index.serialize(serializer)
229    }
230}
231
232impl<'de> serde::Deserialize<'de> for SourceId {
233    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
234    where
235        D: serde::Deserializer<'de>,
236    {
237        Ok(Self {
238            index: u32::deserialize(deserializer)?,
239        })
240    }
241}