rls_analysis/
raw.rs

1use data::config::Config;
2use data::Analysis;
3pub use data::{
4    CratePreludeData, Def, DefKind, GlobalCrateId as CrateId, Import, Ref, Relation, RelationKind,
5    SigElement, Signature, SpanData,
6};
7
8use std::collections::HashMap;
9use std::fmt::Debug;
10use std::fs::File;
11use std::io::{self, Read};
12use std::path::{Path, PathBuf};
13use std::time::{Instant, SystemTime};
14
15use crate::listings::{DirectoryListing, ListingKind};
16use crate::AnalysisLoader;
17
18#[derive(Debug)]
19pub struct Crate {
20    pub id: CrateId,
21    pub analysis: Analysis,
22    pub timestamp: SystemTime,
23    pub path: Option<PathBuf>,
24    pub path_rewrite: Option<PathBuf>,
25}
26
27impl Crate {
28    pub fn new(
29        analysis: Analysis,
30        timestamp: SystemTime,
31        path: Option<PathBuf>,
32        path_rewrite: Option<PathBuf>,
33    ) -> Crate {
34        Crate {
35            id: analysis.prelude.as_ref().unwrap().crate_id.clone(),
36            analysis,
37            timestamp,
38            path,
39            path_rewrite,
40        }
41    }
42}
43
44/// Reads raw analysis data for non-blacklisted crates from files in directories
45/// pointed by `loader`.
46pub fn read_analysis_from_files<L: AnalysisLoader>(
47    loader: &L,
48    crate_timestamps: HashMap<PathBuf, SystemTime>,
49    crate_blacklist: &[impl AsRef<str> + Debug],
50) -> Vec<Crate> {
51    let mut result = vec![];
52
53    loader
54        .search_directories()
55        .iter()
56        .inspect(|dir| trace!("Considering analysis files at {}", dir.path.display()))
57        .filter_map(|dir| DirectoryListing::from_path(&dir.path).ok().map(|list| (dir, list)))
58        .for_each(|(dir, listing)| {
59            let t = Instant::now();
60
61            for l in listing.files {
62                info!("Considering {:?}", l);
63                if let ListingKind::File(ref time) = l.kind {
64                    if ignore_data(&l.name, crate_blacklist) {
65                        continue;
66                    }
67
68                    let path = dir.path.join(&l.name);
69                    let is_fresh = crate_timestamps.get(&path).map_or(true, |t| time > t);
70                    if is_fresh {
71                        if let Some(analysis) = read_crate_data(&path) {
72                            result.push(Crate::new(
73                                analysis,
74                                *time,
75                                Some(path),
76                                dir.prefix_rewrite.clone(),
77                            ));
78                        };
79                    }
80                }
81            }
82
83            let d = t.elapsed();
84            info!(
85                "reading {} crates from {} in {}.{:09}s",
86                result.len(),
87                dir.path.display(),
88                d.as_secs(),
89                d.subsec_nanos()
90            );
91        });
92
93    result
94}
95
96fn ignore_data(file_name: &str, crate_blacklist: &[impl AsRef<str>]) -> bool {
97    crate_blacklist.iter().any(|name| file_name.starts_with(&format!("lib{}-", name.as_ref())))
98}
99
100fn read_file_contents(path: &Path) -> io::Result<String> {
101    let mut file = File::open(&path)?;
102    let mut buf = String::new();
103    file.read_to_string(&mut buf)?;
104    Ok(buf)
105}
106
107/// Attempts to read and deserialize `Analysis` data from a JSON file at `path`,
108/// returns `Some(data)` on success.
109pub fn read_crate_data(path: &Path) -> Option<Analysis> {
110    trace!("read_crate_data {:?}", path);
111    let t = Instant::now();
112
113    let buf = read_file_contents(path)
114        .or_else(|err| {
115            warn!("couldn't read file: {}", err);
116            Err(err)
117        })
118        .ok()?;
119    let s = deserialize_crate_data(&buf);
120
121    let d = t.elapsed();
122    info!("reading {:?} {}.{:09}s", path, d.as_secs(), d.subsec_nanos());
123
124    s
125}
126
127/// Attempts to deserialize `Analysis` data from file contents, returns
128/// `Some(data)` on success.
129pub fn deserialize_crate_data(buf: &str) -> Option<Analysis> {
130    trace!("deserialize_crate_data <buffer omitted>");
131    let t = Instant::now();
132
133    let s = ::serde_json::from_str(buf)
134        .or_else(|err| {
135            warn!("deserialisation error: {:?}", err);
136            json::parse(buf)
137                .map(|parsed| {
138                    if let json::JsonValue::Object(obj) = parsed {
139                        let expected =
140                            Some(json::JsonValue::from(Analysis::new(Config::default()).version));
141                        let actual = obj.get("version").cloned();
142                        if expected != actual {
143                            warn!(
144                                "Data version mismatch; expected {:?} but got {:?}",
145                                expected, actual
146                            );
147                        }
148                    } else {
149                        warn!("Data didn't have a JSON object at the root");
150                    }
151                })
152                .map_err(|err| {
153                    warn!("Data was not valid JSON: {:?}", err);
154                })
155                .ok();
156
157            Err(err)
158        })
159        .ok()?;
160
161    let d = t.elapsed();
162    info!("deserializing <buffer omitted> {}.{:09}s", d.as_secs(), d.subsec_nanos());
163
164    s
165}
166
167pub fn name_space_for_def_kind(dk: DefKind) -> char {
168    match dk {
169        DefKind::Enum
170        | DefKind::Struct
171        | DefKind::Union
172        | DefKind::Type
173        | DefKind::ExternType
174        | DefKind::Trait => 't',
175        DefKind::ForeignFunction
176        | DefKind::ForeignStatic
177        | DefKind::Function
178        | DefKind::Method
179        | DefKind::Mod
180        | DefKind::Local
181        | DefKind::Static
182        | DefKind::Const
183        | DefKind::Tuple
184        | DefKind::TupleVariant
185        | DefKind::StructVariant
186        | DefKind::Field => 'v',
187        DefKind::Macro => 'm',
188    }
189}