Analyze dependencies of cargo projects
use cargo_metadata::PackageId;
use serde::{Deserialize, Serialize};

/// See https://doc.rust-lang.org/nightly/nightly-rustc/cargo/core/profiles/enum.PanicStrategy.html
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum PanicStrategy {
    Unwind,
    Abort,
}

/// See https://doc.rust-lang.org/nightly/nightly-rustc/cargo/core/profiles/struct.Profile.html
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Profile {
    pub name: String,
    pub opt_level: String,
    pub lto: String,
    pub codegen_units: Option<usize>,
    pub debuginfo: usize,
    pub debug_assertions: bool,
    pub overflow_checks: bool,
    pub rpath: bool,
    pub incremental: bool,
    pub panic: PanicStrategy,
}

/// See https://doc.rust-lang.org/nightly/nightly-rustc/cargo/core/compiler/unit_graph/struct.UnitDep.html
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct UnitDep {
    pub index: usize,
    pub extern_crate_name: String,
    pub public: bool,
    pub noprelude: bool,
}

/// See https://doc.rust-lang.org/nightly/nightly-rustc/cargo/core/compiler/unit/struct.UnitInner.html
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Unit {
    pub pkg_id: PackageId,
    pub target: super::Target,
    pub profile: Profile,
    pub platform: Option<String>,
    pub mode: super::Mode,
    pub features: Vec<String>,
    pub is_std: Option<bool>,
    pub dependencies: Vec<UnitDep>,
}

/// See https://doc.rust-lang.org/cargo/reference/unstable.html#unit-graph
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct UnitGraph {
    version: usize,
    pub units: Vec<Unit>,
    pub roots: Vec<usize>,
}

impl UnitGraph {
    pub fn new(source: &str) -> Result<Self, serde_json::Error> {
        let graph: Self = serde_json::from_str(source)?;
        assert_eq!(graph.version, 1);

        Ok(graph)
    }
}