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