1use core::fmt;
2use core::num;
3
4#[cfg(feature = "std")]
5use std::path::Path;
6
7#[cfg(feature = "musli")]
8use musli_core::{Decode, Encode};
9#[cfg(feature = "serde")]
10use serde::{Deserialize, Serialize};
11
12use crate as rune;
13use crate::alloc;
14use crate::alloc::prelude::*;
15use crate::ast::Span;
16use crate::source::Source;
17#[cfg(feature = "codespan-reporting")]
18use codespan_reporting::files;
19
20#[macro_export]
37macro_rules! sources {
38 ($($name:ident => {$($tt:tt)*}),* $(,)?) => {{
39 let mut sources = $crate::Sources::new();
40 $(sources.insert($crate::Source::new(stringify!($name), stringify!($($tt)*))?)?;)*
41 sources
42 }};
43}
44
45#[derive(Debug, Default)]
47pub struct Sources {
48 sources: Vec<Source>,
50}
51
52impl Sources {
53 #[inline]
55 pub fn new() -> Self {
56 Self {
57 sources: Vec::new(),
58 }
59 }
60
61 #[inline]
75 pub fn insert(&mut self, source: Source) -> alloc::Result<SourceId> {
76 let id =
77 SourceId::try_from(self.sources.len()).expect("could not build a source identifier");
78 self.sources.try_push(source)?;
79 Ok(id)
80 }
81
82 #[inline]
99 pub fn get(&self, id: SourceId) -> Option<&Source> {
100 self.sources.get(id.into_index())
101 }
102
103 #[inline]
105 pub(crate) fn name(&self, id: SourceId) -> Option<&str> {
106 let source = self.sources.get(id.into_index())?;
107 Some(source.name())
108 }
109
110 #[inline]
112 pub(crate) fn source(&self, id: SourceId, span: Span) -> Option<&str> {
113 let source = self.sources.get(id.into_index())?;
114 source.get(span.range())
115 }
116
117 #[cfg(feature = "std")]
119 #[inline]
120 pub(crate) fn path(&self, id: SourceId) -> Option<&Path> {
121 let source = self.sources.get(id.into_index())?;
122 source.path()
123 }
124
125 #[inline]
127 pub(crate) fn source_ids(&self) -> impl Iterator<Item = SourceId> {
128 (0..self.sources.len()).map(|index| SourceId::new(index as u32))
129 }
130
131 #[cfg(feature = "cli")]
133 #[inline]
134 pub(crate) fn iter(&self) -> impl Iterator<Item = &Source> {
135 self.sources.iter()
136 }
137}
138
139#[cfg(feature = "codespan-reporting")]
140impl<'a> files::Files<'a> for Sources {
141 type FileId = SourceId;
142 type Name = &'a str;
143 type Source = &'a str;
144
145 #[inline]
146 fn name(&'a self, file_id: SourceId) -> Result<Self::Name, files::Error> {
147 let source = self.get(file_id).ok_or(files::Error::FileMissing)?;
148 Ok(source.name())
149 }
150
151 #[inline]
152 fn source(&'a self, file_id: SourceId) -> Result<Self::Source, files::Error> {
153 let source = self.get(file_id).ok_or(files::Error::FileMissing)?;
154 Ok(source.as_str())
155 }
156
157 #[cfg(feature = "emit")]
158 #[inline]
159 fn line_index(&self, file_id: SourceId, byte_index: usize) -> Result<usize, files::Error> {
160 let source = self.get(file_id).ok_or(files::Error::FileMissing)?;
161 Ok(source.line_index(byte_index))
162 }
163
164 #[cfg(feature = "emit")]
165 #[inline]
166 fn line_range(
167 &self,
168 file_id: SourceId,
169 line_index: usize,
170 ) -> Result<std::ops::Range<usize>, files::Error> {
171 let source = self.get(file_id).ok_or(files::Error::FileMissing)?;
172 let range = source
173 .line_range(line_index)
174 .ok_or_else(|| files::Error::LineTooLarge {
175 given: line_index,
176 max: source.line_count(),
177 })?;
178 Ok(range)
179 }
180}
181
182#[derive(TryClone, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
188#[try_clone(copy)]
189#[repr(transparent)]
190#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(transparent))]
191#[cfg_attr(feature = "musli", derive(Decode, Encode), musli(crate = musli_core, transparent))]
192pub struct SourceId {
193 index: u32,
194}
195
196impl SourceId {
197 pub const EMPTY: Self = Self::empty();
199
200 #[inline]
202 pub const fn new(index: u32) -> Self {
203 Self { index }
204 }
205
206 #[inline]
208 pub const fn empty() -> Self {
209 Self { index: u32::MAX }
210 }
211
212 #[inline]
214 pub fn into_index(self) -> usize {
215 usize::try_from(self.index).expect("source id out of bounds")
216 }
217}
218
219impl fmt::Debug for SourceId {
220 #[inline]
221 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222 self.index.fmt(f)
223 }
224}
225
226impl fmt::Display for SourceId {
227 #[inline]
228 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
229 self.index.fmt(f)
230 }
231}
232
233impl Default for SourceId {
234 #[inline]
235 fn default() -> Self {
236 Self::empty()
237 }
238}
239
240impl TryFrom<usize> for SourceId {
241 type Error = num::TryFromIntError;
242
243 #[inline]
244 fn try_from(value: usize) -> Result<Self, Self::Error> {
245 Ok(Self {
246 index: u32::try_from(value)?,
247 })
248 }
249}