1use std::borrow::Cow;
2
3use crate::{MietteError, MietteSpanContents, SourceCode, SpanContents};
4
5#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
9pub struct NamedSource<S: SourceCode + 'static> {
10 source: S,
11 name: String,
12 language: Option<String>,
13}
14
15impl<S: SourceCode> std::fmt::Debug for NamedSource<S> {
16 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17 f.debug_struct("NamedSource")
18 .field("name", &self.name)
19 .field("source", &"<redacted>")
20 .field("language", &self.language);
21 Ok(())
22 }
23}
24
25impl<S: SourceCode + 'static> NamedSource<S> {
26 pub fn new(name: impl AsRef<str>, source: S) -> Self
29 where
30 S: Send + Sync,
31 {
32 Self { source, name: name.as_ref().to_string(), language: None }
33 }
34
35 pub fn name(&self) -> &str {
37 &self.name
38 }
39
40 pub fn inner(&self) -> &S {
43 &self.source
44 }
45
46 #[must_use]
48 pub fn with_language(mut self, language: impl Into<String>) -> Self {
49 self.language = Some(language.into());
50 self
51 }
52}
53
54impl<S: SourceCode + 'static> SourceCode for NamedSource<S> {
55 fn read_span<'a>(
56 &'a self,
57 span: &crate::SourceSpan,
58 context_lines_before: usize,
59 context_lines_after: usize,
60 ) -> Result<MietteSpanContents<'a>, MietteError> {
61 let inner_contents =
62 self.inner().read_span(span, context_lines_before, context_lines_after)?;
63 let mut contents = MietteSpanContents::new_named(
64 Cow::Borrowed(self.name.as_str()),
65 inner_contents.data(),
66 *inner_contents.span(),
67 inner_contents.line(),
68 inner_contents.column(),
69 inner_contents.line_count(),
70 );
71 if let Some(language) = &self.language {
72 contents = contents.with_language(language);
73 }
74 Ok(contents)
75 }
76
77 fn name(&self) -> Option<&str> {
78 Some(&self.name)
79 }
80}