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 }5455 56 pub fn path(&self) -> Option<&Path> {57 match self.inner() {58 Inner::Real(r) => Some(r),59 Inner::Virtual(_) => None,60 }61 }62 pub fn repr(&self) -> Result<&Path, &str> {63 match self.inner() {64 Inner::Real(r) => Ok(r),65 Inner::Virtual(v) => Err(v.as_ref()),66 }67 }6869 fn inner(&self) -> &Inner {70 &self.0 as &Inner71 }72}73pub struct ShortDisplay(Source);74impl fmt::Display for ShortDisplay {75 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {76 match &self.0 .0 as &Inner {77 Inner::Real(r) => {78 write!(79 f,80 "{}",81 r.file_name().expect("path is valid").to_string_lossy()82 )83 }84 Inner::Virtual(n) => write!(f, "{}", n),85 }86 }87}