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
44pub 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
107pub 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
127pub 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}