Skip to main content

cargo/diagnostics/
report.rs

1use std::borrow::Cow;
2use std::ops::Range;
3use std::path::Path;
4
5use pathdiff::diff_paths;
6
7use crate::GlobalContext;
8
9/// Gets the relative path to a manifest from the current working directory, or
10/// the absolute path of the manifest if a relative path cannot be constructed
11pub fn rel_cwd_manifest_path(path: &Path, gctx: &GlobalContext) -> String {
12    diff_paths(path, gctx.cwd())
13        .unwrap_or_else(|| path.to_path_buf())
14        .display()
15        .to_string()
16}
17
18pub fn get_key_value<'doc, 'i>(
19    document: &'doc toml::Spanned<toml::de::DeTable<'static>>,
20    path: &[impl AsIndex],
21) -> Option<(
22    &'doc toml::Spanned<Cow<'doc, str>>,
23    &'doc toml::Spanned<toml::de::DeValue<'static>>,
24)> {
25    let table = document.get_ref();
26    let mut iter = path.into_iter();
27    let index0 = iter.next()?.as_index();
28    let key0 = index0.as_key()?;
29    let (mut current_key, mut current_item) = table.get_key_value(key0)?;
30
31    while let Some(index) = iter.next() {
32        match index.as_index() {
33            TomlIndex::Key(key) => {
34                if let Some(table) = current_item.get_ref().as_table() {
35                    (current_key, current_item) = table.get_key_value(key)?;
36                } else if let Some(array) = current_item.get_ref().as_array() {
37                    current_item = array.iter().find(|item| match item.get_ref() {
38                        toml::de::DeValue::String(s) => s == key,
39                        _ => false,
40                    })?;
41                } else {
42                    return None;
43                }
44            }
45            TomlIndex::Offset(offset) => {
46                let array = current_item.get_ref().as_array()?;
47                current_item = array.get(offset)?;
48            }
49        }
50    }
51    Some((current_key, current_item))
52}
53
54pub fn get_key_value_span<'i>(
55    document: &toml::Spanned<toml::de::DeTable<'static>>,
56    path: &[impl AsIndex],
57) -> Option<TomlSpan> {
58    get_key_value(document, path).map(|(k, v)| TomlSpan {
59        key: k.span(),
60        value: v.span(),
61    })
62}
63
64#[derive(Clone)]
65pub struct TomlSpan {
66    pub key: Range<usize>,
67    pub value: Range<usize>,
68}
69
70#[derive(Copy, Clone)]
71pub enum TomlIndex<'i> {
72    Key(&'i str),
73    Offset(usize),
74}
75
76impl<'i> TomlIndex<'i> {
77    fn as_key(&self) -> Option<&'i str> {
78        match self {
79            TomlIndex::Key(key) => Some(key),
80            TomlIndex::Offset(_) => None,
81        }
82    }
83}
84
85pub trait AsIndex {
86    fn as_index<'i>(&'i self) -> TomlIndex<'i>;
87}
88
89impl AsIndex for TomlIndex<'_> {
90    fn as_index<'i>(&'i self) -> TomlIndex<'i> {
91        match self {
92            TomlIndex::Key(key) => TomlIndex::Key(key),
93            TomlIndex::Offset(offset) => TomlIndex::Offset(*offset),
94        }
95    }
96}
97
98impl AsIndex for &str {
99    fn as_index<'i>(&'i self) -> TomlIndex<'i> {
100        TomlIndex::Key(self)
101    }
102}
103
104impl AsIndex for String {
105    fn as_index<'i>(&'i self) -> TomlIndex<'i> {
106        TomlIndex::Key(self.as_str())
107    }
108}
109
110impl AsIndex for usize {
111    fn as_index<'i>(&'i self) -> TomlIndex<'i> {
112        TomlIndex::Offset(*self)
113    }
114}