1use std::{2 borrow::Cow,3 fmt,4 path::{Component, Path, PathBuf},5 rc::Rc,6};78use jrsonnet_gcmodule::{Trace, Tracer};9#[cfg(feature = "serde")]10use serde::{Deserialize, Serialize};1112#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]13#[derive(PartialEq, Eq, Debug, Hash)]14enum Inner {15 Real(PathBuf),16 Virtual(Cow<'static, str>),17}18192021#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]22#[derive(Clone, PartialEq, Eq, Debug)]23pub struct Source(Rc<Inner>);24static_assertions::assert_eq_size!(Source, *const ());2526impl Trace for Source {27 fn trace(&self, _tracer: &mut Tracer) {}2829 fn is_type_tracked() -> bool {30 false31 }32}3334impl Source {35 36 pub fn new(path: PathBuf) -> Option<Self> {37 if !path.is_absolute()38 || path39 .components()40 .any(|c| matches!(c, Component::CurDir | Component::ParentDir))41 {42 return None;43 }44 Some(Self(Rc::new(Inner::Real(path))))45 }4647 pub fn new_virtual(n: Cow<'static, str>) -> Self {48 Self(Rc::new(Inner::Virtual(n)))49 }5051 pub fn short_display(&self) -> ShortDisplay {52 ShortDisplay(self.clone())53 }54 pub fn full_path(&self) -> String {55 match self.inner() {56 Inner::Real(r) => r.display().to_string(),57 Inner::Virtual(v) => v.to_string(),58 }59 }6061 62 pub fn path(&self) -> Option<&Path> {63 match self.inner() {64 Inner::Real(r) => Some(r),65 Inner::Virtual(_) => None,66 }67 }68 pub fn repr(&self) -> Result<&Path, &str> {69 match self.inner() {70 Inner::Real(r) => Ok(r),71 Inner::Virtual(v) => Err(v.as_ref()),72 }73 }7475 fn inner(&self) -> &Inner {76 &self.0 as &Inner77 }78}79pub struct ShortDisplay(Source);80impl fmt::Display for ShortDisplay {81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {82 match &self.0 .0 as &Inner {83 Inner::Real(r) => {84 write!(85 f,86 "{}",87 r.file_name().expect("path is valid").to_string_lossy()88 )89 }90 Inner::Virtual(n) => write!(f, "{}", n),91 }92 }93}