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};12#[cfg(feature = "structdump")]13use structdump::Codegen;1415use crate::location::{location_to_offset, offset_to_location, CodeLocation};1617#[cfg_attr(feature = "structdump", derive(Codegen))]18#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]19#[derive(PartialEq, Eq, Debug, Hash, Clone)]20pub enum SourcePath {21 22 Path(PathBuf),23 24 Custom(String),25 26 Virtual(Cow<'static, str>),27}28impl Trace for SourcePath {29 fn trace(&self, _tracer: &mut Tracer) {}3031 fn is_type_tracked() -> bool {32 false33 }34}3536impl SourcePath {37 38 pub fn can_load(&self) -> bool {39 matches!(self, Self::Path(_) | Self::Custom(_))40 }41}42434445#[cfg_attr(feature = "structdump", derive(Codegen))]46#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]47#[derive(Clone, PartialEq, Eq, Debug)]48pub struct Source(pub Rc<(SourcePath, IStr)>);49static_assertions::assert_eq_size!(Source, *const ());5051impl Trace for Source {52 fn trace(&self, _tracer: &mut Tracer) {}5354 fn is_type_tracked() -> bool {55 false56 }57}5859impl Source {60 61 pub fn new(path: SourcePath, code: IStr) -> Option<Self> {62 if let SourcePath::Path(path) = &path {63 if !path.is_absolute()64 || path65 .components()66 .any(|c| matches!(c, Component::CurDir | Component::ParentDir))67 {68 return None;69 }70 }71 Some(Self(Rc::new((path, code))))72 }7374 pub fn new_virtual(n: Cow<'static, str>, code: IStr) -> Self {75 Self(Rc::new((SourcePath::Virtual(n), code)))76 }7778 pub fn short_display(&self) -> ShortDisplay {79 ShortDisplay(self.clone())80 }8182 83 pub fn path(&self) -> Option<&Path> {84 match self.source_path() {85 SourcePath::Path(r) => Some(r),86 SourcePath::Custom(_) => None,87 SourcePath::Virtual(_) => None,88 }89 }90 pub fn code(&self) -> &str {91 &self.0 .192 }9394 pub fn source_path(&self) -> &SourcePath {95 &self.0 .0 as &SourcePath96 }9798 pub fn map_source_locations(&self, locs: &[u32]) -> Vec<CodeLocation> {99 offset_to_location(&self.0 .1, locs)100 }101 pub fn map_from_source_location(&self, line: usize, column: usize) -> Option<usize> {102 location_to_offset(&self.0 .1, line, column)103 }104}105pub struct ShortDisplay(Source);106impl fmt::Display for ShortDisplay {107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {108 match &self.0 .0 .0 as &SourcePath {109 SourcePath::Path(r) => {110 write!(111 f,112 "{}",113 r.file_name().expect("path is valid").to_string_lossy()114 )115 }116 SourcePath::Custom(r) => write!(f, "{}", r),117 SourcePath::Virtual(n) => write!(f, "{}", n),118 }119 }120}