1use std::{2 borrow::Cow,3 fmt,4 path::{Component, Path, PathBuf},5 rc::Rc,6};78use jrsonnet_gcmodule::{Trace, Tracer};9use jrsonnet_interner::IStr;10#[cfg(feature = "serde")]11use serde::{Deserialize, Serialize};1213use crate::location::{location_to_offset, offset_to_location, CodeLocation};1415#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]16#[derive(PartialEq, Eq, Debug, Hash, Clone)]17pub enum SourcePath {18 19 Path(PathBuf),20 21 Custom(String),22 23 Virtual(Cow<'static, str>),24}25impl Trace for SourcePath {26 fn trace(&self, _tracer: &mut Tracer) {}2728 fn is_type_tracked() -> bool {29 false30 }31}3233impl SourcePath {34 35 pub fn can_load(&self) -> bool {36 matches!(self, Self::Path(_) | Self::Custom(_))37 }38}39404142#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]43#[derive(Clone, PartialEq, Eq, Debug)]44pub struct Source(Rc<(SourcePath, IStr)>);45static_assertions::assert_eq_size!(Source, *const ());4647impl Trace for Source {48 fn trace(&self, _tracer: &mut Tracer) {}4950 fn is_type_tracked() -> bool {51 false52 }53}5455impl Source {56 57 pub fn new(path: SourcePath, code: IStr) -> Option<Self> {58 if let SourcePath::Path(path) = &path {59 if !path.is_absolute()60 || path61 .components()62 .any(|c| matches!(c, Component::CurDir | Component::ParentDir))63 {64 return None;65 }66 }67 Some(Self(Rc::new((path, code))))68 }6970 pub fn new_virtual(n: Cow<'static, str>, code: IStr) -> Self {71 Self(Rc::new((SourcePath::Virtual(n), code)))72 }7374 pub fn short_display(&self) -> ShortDisplay {75 ShortDisplay(self.clone())76 }7778 79 pub fn path(&self) -> Option<&Path> {80 match self.source_path() {81 SourcePath::Path(r) => Some(r),82 SourcePath::Custom(_) => None,83 SourcePath::Virtual(_) => None,84 }85 }86 pub fn code(&self) -> &str {87 &self.0 .188 }8990 pub fn source_path(&self) -> &SourcePath {91 &self.0 .0 as &SourcePath92 }9394 pub fn map_source_locations(&self, locs: &[u32]) -> Vec<CodeLocation> {95 offset_to_location(&self.0 .1, locs)96 }97 pub fn map_from_source_location(&self, line: usize, column: usize) -> Option<usize> {98 location_to_offset(&self.0 .1, line, column)99 }100}101pub struct ShortDisplay(Source);102impl fmt::Display for ShortDisplay {103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {104 match &self.0 .0 .0 as &SourcePath {105 SourcePath::Path(r) => {106 write!(107 f,108 "{}",109 r.file_name().expect("path is valid").to_string_lossy()110 )111 }112 SourcePath::Custom(r) => write!(f, "{}", r),113 SourcePath::Virtual(n) => write!(f, "{}", n),114 }115 }116}