ariadne
ariadne copied to clipboard
FileCache broken due to Path ?Sized requirementes for Span, and due to ?Sized requirements on tuples.
FileCache implements Cache<Path>, but Path being !Sized leading to some issues.
Types like Report are generic over a Span, which is implemented for (Id, Range<usize>) for a few relevant types, but when used with FileCache this has the issue that the implementation for Span for (Id, Range<usize>) doesn't allow for an unsized Id.
Aditionally, trying to just add that constraint won't work, as it leaves an unsized element be non-last in a tuple, which won't work as per rust rules.
Yep, this is an annoying gap in the API. In ariadne2 I've made an attempt at improving this.
If you have a suggested solution that leaves the existing API broadly intact (to minimise the changes that dependent code needs to make), I'm all ears!
First idea that popped in my mind, for files & Paths specifically, would be to make FileCache generic over some additional generic type T: AsRef<Path>, such that it stores those internally & passes it around, but then when it needs to do the actual accessing the FS for reading files it calls id.as_ref().
With this, users could use either String, Box<Path>, Cow<Path>, Arc<Path>, or any similar type as they please to work as the id for file caches.
For anyone who wonders how to use FileCache with PathBuf. You can create your own implementation of a Span and work around it that way:
#[derive(Debug, Clone)]
pub struct ErrorSpan {
file_path: PathBuf,
span: MySpan,
}
impl ariadne::Span for ErrorSpan {
type SourceId = std::path::Path;
fn source(&self) -> &Self::SourceId {
&self.file_path.as_path()
}
fn start(&self) -> usize {
self.span.start()
}
fn end(&self) -> usize {
self.span.end()
}
}
then you can build a report with a signature like this:
pub fn build<'a>(diagnostic: &Diagnostic) -> Report<'a, ErrorSpan> {
...
}
and finally create a string like this:
pub fn render(diagnostic: &Diagnostic) -> String {
let report = build(diagnostic);
let mut buf = Vec::new();
let cache = ariadne::FileCache::default();
report.write(cache, &mut buf).unwrap();
String::from_utf8_lossy(&buf).to_string()
}