use crate::download_graph::DownloadsGraph;
use crate::templates;
use crate::urler::Urler;
use crate::Page;
use categories::Category;
use categories::CATEGORIES;
use chrono::prelude::*;
use chrono::Duration;
use futures::future::Future;
use futures::stream::StreamExt;
use kitchen_sink::CResult;
use kitchen_sink::CrateAuthor;
use kitchen_sink::DepInfMap;
use kitchen_sink::{DepTy, KitchenSink, Origin};
use locale::Numeric;
use render_readme::Links;
use render_readme::Renderer;
use rich_crate::Readme;
use rich_crate::RepoHost;
use rich_crate::RichCrate;
use rich_crate::RichCrateVersion;
use rich_crate::RichDep;
use semver::Version as SemVer;
use semver_parser;
use std::borrow::Cow;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::collections::HashSet;
use std::f64::consts::PI;
use std::fmt::Display;
use std::hash::Hash;
use std::sync::Arc;
use tokio::runtime::Handle;
use udedokei::LanguageExt;
use udedokei::{Language, Lines, Stats};
use crate::url_domain;
pub struct CrateLicense {
pub origin: Origin,
pub license: Box<str>,
pub optional: bool,
}
pub struct CrateSizes {
pub tarball: usize,
pub uncompressed: usize,
pub minimal: DepsSize,
pub typical: DepsSize,
}
/// Data sources used in `crate_page.rs.html`
pub struct CratePage<'a> {
pub all: &'a RichCrate,
pub ver: &'a RichCrateVersion,
pub kitchen_sink: &'a KitchenSink,
pub markup: &'a Renderer,
pub top_keyword: Option<(u32, String)>,
pub all_contributors: (Vec<CrateAuthor<'a>>, Vec<CrateAuthor<'a>>, bool, usize),
/// own, deps (tarball, uncompressed source); last one is sloc
pub sizes: Option<CrateSizes>,
pub lang_stats: Option<(usize, Stats)>,
pub viral_license: Option<CrateLicense>,
top_category: Option<(u32, &'static Category)>,
is_build_or_dev: (bool, bool),
handle: Handle,
api_reference_url: Option<String>,
}
/// Helper used to find most "interesting" versions
#[derive(Debug)]
pub struct VersionGroup<'a> {
pub ver: Version<'a>,
pub count: usize,
}
#[derive(Debug)]
pub struct Version<'a> {
pub num: &'a str,
pub semver: SemVer,
pub yanked: bool,
pub created_at: DateTime<FixedOffset>,
}
///
#[derive(Debug, Default)]
struct ReleaseCounts {
total: u32,
stable: u32,
major: u32,
major_recent: u32,
patch: u32,
unstable: u32,
breaking: u32,
breaking_recent: u32,
}
pub(crate) struct Contributors<'a> {
pub authors: Vec<CrateAuthor<'a>>,
pub owners: Vec<CrateAuthor<'a>>,
pub co_owned: bool,
pub contributors: usize,
pub period_after_authors: bool,
pub contributors_as_a_team: bool,
}
impl<'a> CratePage<'a> {
pub async fn new(all: &'a RichCrate, ver: &'a RichCrateVersion, kitchen_sink: &'a KitchenSink, markup: &'a Renderer) -> CResult<CratePage<'a>> {
let top_category = kitchen_sink.top_category(ver).await
.and_then(|(top, slug)| CATEGORIES.from_slug(slug).0.last().map(|&c| (top, c)));
let is_build_or_dev = kitchen_sink.is_build_or_dev(ver.origin()).await?;
let (top_keyword, all_contributors) = futures::try_join!(
kitchen_sink.top_keyword(all),
kitchen_sink.all_contributors(ver))?;
let deps = kitchen_sink.all_dependencies_flattened(ver);
let api_reference_url = if kitchen_sink.has_docs_rs(ver.origin(), ver.short_name(), ver.version()).await {
Some(format!("https://docs.rs/{}", ver.short_name()))
} else {
None
};
let mut page = Self {
top_keyword,
all_contributors,
all,
ver,
kitchen_sink,
markup