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#[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#[derive(Debug, Default)]
41pub struct Sources {
42 sources: Vec<Source>,
44}
45
46impl Sources {
47 pub fn new() -> Self {
49 Self {
50 sources: Vec::new(),
51 }
52 }
53
54 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 pub fn get(&self, id: SourceId) -> Option<&Source> {
91 self.sources.get(id.into_index())
92 }
93
94 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 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 pub(crate) fn path(&self, id: SourceId) -> Option<&Path> {
108 let source = self.sources.get(id.into_index())?;
109 source.path()
110 }
111
112 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 #[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#[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 pub const EMPTY: Self = Self::empty();
178
179 pub const fn new(index: u32) -> Self {
181 Self { index }
182 }
183
184 pub const fn empty() -> Self {
186 Self { index: u32::MAX }
187 }
188
189 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}