#![forbid(unsafe_code)]
#![deny(
rust_2018_idioms,
clippy::all,
clippy::pedantic,
clippy::print_stderr,
clippy::print_stdout
)]
#![allow(clippy::missing_errors_doc)]
use std::{borrow::Cow, collections::BTreeMap};
use serde::{Deserialize, Serialize};
use crate::error::{Error, Result};
pub use crate::{simple_path::SimplePath, version::Version};
mod crates;
pub mod error;
mod index;
mod simple_path;
mod version;
pub(crate) const STD_CRATES: &[&str] = &["alloc", "core", "proc_macro", "std", "test"];
#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Index {
pub name: String,
pub version: Version,
pub mapping: BTreeMap<String, String>,
pub std: bool,
}
impl Index {
#[must_use]
pub fn find_link(&self, path: &SimplePath) -> Option<String> {
let link = if path.is_crate_only() {
path.crate_name()
} else {
self.mapping.get(path.as_ref())?
};
Some(if self.std {
format!("https://doc.rust-lang.org/nightly/{link}")
} else {
format!("https://docs.rs/{}/{}/{link}", self.name, self.version)
})
}
}
#[must_use]
pub fn start_search(name: &str, version: Version) -> SearchPage<'_> {
let std = STD_CRATES.contains(&name);
let url = crates::get_page_url(std, name, &version);
SearchPage {
name,
version,
std,
url,
}
}
pub struct SearchPage<'a> {
name: &'a str,
version: Version,
std: bool,
url: Cow<'static, str>,
}
impl<'a> SearchPage<'a> {
#[must_use]
pub fn url(&self) -> &str {
&self.url
}
pub fn find_index(self, body: &str) -> Result<SearchIndex<'a>> {
let (version, url) = crates::find_index_url(self.std, self.name, self.version, body)?;
Ok(SearchIndex {
name: self.name,
version,
std: self.std,
url,
})
}
}
pub struct SearchIndex<'a> {
name: &'a str,
version: Version,
std: bool,
url: String,
}
impl<'a> SearchIndex<'a> {
#[must_use]
pub fn url(&self) -> &str {
&self.url
}
pub fn transform_index(self, index_content: &str) -> Result<Index> {
let mappings = index::load(index_content)?;
mappings
.into_iter()
.find(|(crate_name, _)| crate_name == self.name)
.map(|(name, mapping)| Index {
name,
version: self.version.clone(),
mapping,
std: self.std,
})
.ok_or(Error::CrateDataMissing)
}
}