1#[macro_use]
2extern crate serde;
3#[macro_use]
4extern crate thiserror;
5
6pub mod doc;
7pub mod location;
8pub mod search_index;
9
10use rayon::prelude::*;
11use std::{
12 fs::File,
13 io::{BufRead, BufReader},
14 path::Path
15};
16
17#[derive(Debug, Error)]
18pub enum Error {
19 #[error("Not supported format of search-index.json")]
20 InvalidFormat(String),
21 #[error(transparent)]
22 Io(#[from] std::io::Error),
23 #[error("{0:?} {1:?}")]
24 SerdeJson(String, serde_json::error::Error),
25 #[error(transparent)]
26 Metadata(#[from] cargo_metadata::Error),
27 #[error(transparent)]
28 Join(#[from] tokio::task::JoinError),
29 #[error(transparent)]
30 Location(#[from] location::LocationError)
31}
32
33pub fn read_search_index<P: AsRef<Path>>(
34 src: P
35) -> Result<impl rayon::iter::ParallelIterator<Item = Result<(String, doc::Crate), Error>>, Error> {
36 let file = File::open(src.as_ref())?;
37 let reader = BufReader::new(file);
38 let mut lines = reader.lines();
40 lines.next(); Ok(lines
42 .par_bridge()
43 .map(|l| l.map_err(Error::from))
44 .filter(|l| {
45 if let Ok(l) = &l {
46 l != "}');"
47 && l != "initSearch(searchIndex);"
48 && l != "if (window.initSearch) {window.initSearch(searchIndex)};"
49 && l != "if (typeof window !== 'undefined' && window.initSearch) {window.initSearch(searchIndex)};"
51 && l != "if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex};"
52 } else {
53 true
54 }
55 })
56 .map(|l: Result<String, Error>| l.and_then(parse_line)))
57}
58
59pub fn parse_line(line: String) -> Result<(String, doc::Crate), Error> {
61 let mut line = {
62 let mut line = line;
63 line.pop(); if &line[(line.len() - 1)..] == "," {
65 line.pop(); }
67 line
68 };
69 let colon_idx = line
70 .find(':')
71 .ok_or_else(|| Error::InvalidFormat(line.clone()))?;
72 let (mut name_colon, body) = {
73 let body = line.split_off(colon_idx + 1);
74 (line, body)
75 };
76 let mut quoted_name = {
77 let _colon = name_colon.split_off(colon_idx);
78 name_colon
79 };
80 let name = {
81 quoted_name.pop();
82 quoted_name.split_off(1)
83 };
84 let body = unescape::unescape(&body).ok_or_else(|| Error::InvalidFormat(body.clone()))?;
85 match serde_json::from_str(&body) {
86 Err(e) => Err(Error::SerdeJson(name, e)),
87 Ok(krate) => Ok((name, krate))
88 }
89}