1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
use crate::metadata::{Metadata, Package, PackageId, Resolve, ResolveNode, Target};
use racer_interner::InternedString;
use std::collections::HashMap;
use std::path::{Path, PathBuf};

/// Cached dependencies for racer
#[derive(Clone, Debug)]
pub struct PackageMap {
    manifest_to_idx: HashMap<PathBuf, PackageIdx>,
    id_to_idx: HashMap<PackageId, PackageIdx>,
    packages: Vec<PackageInner>,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum Edition {
    Ed2015,
    Ed2018,
    Ed2021,
}

impl Edition {
    pub fn from_str(s: &str) -> Self {
        match s {
            "2015" => Edition::Ed2015,
            "2018" => Edition::Ed2018,
            "2021" => Edition::Ed2021,
            _ => unreachable!("got unexpected edition {}", s),
        }
    }
}

#[derive(Clone, Debug)]
struct PackageInner {
    edition: Edition,
    deps: Vec<(InternedString, PathBuf)>,
    lib: Option<Target>,
    id: PackageId,
}

impl PackageInner {
    fn new(ed: InternedString, id: PackageId, lib: Option<Target>) -> Self {
        PackageInner {
            edition: Edition::from_str(ed.as_str()),
            deps: Vec::new(),
            id,
            lib,
        }
    }
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct PackageIdx(usize);

impl PackageMap {
    pub fn from_metadata(meta: Metadata) -> Self {
        let Metadata {
            packages, resolve, ..
        } = meta;
        PackageMap::new(packages, resolve)
    }
    pub fn new(packages: Vec<Package>, resolve: Option<Resolve>) -> Self {
        let mut manifest_to_idx = HashMap::new();
        let mut id_to_idx = HashMap::new();
        let mut inner = Vec::new();
        for (i, package) in packages.into_iter().enumerate() {
            let Package {
                id,
                targets,
                manifest_path,
                edition,
                ..
            } = package;
            id_to_idx.insert(id, PackageIdx(i));
            manifest_to_idx.insert(manifest_path, PackageIdx(i));
            let lib = targets.into_iter().find(|t| t.is_lib()).to_owned();
            inner.push(PackageInner::new(edition, id, lib));
        }
        if let Some(res) = resolve {
            construct_deps(res.nodes, &id_to_idx, &mut inner);
        }
        PackageMap {
            manifest_to_idx,
            id_to_idx,
            packages: inner,
        }
    }
    pub fn ids<'a>(&'a self) -> impl 'a + Iterator<Item = PackageId> {
        self.packages.iter().map(|p| p.id)
    }
    pub fn id_to_idx(&self, id: PackageId) -> Option<PackageIdx> {
        self.id_to_idx.get(&id).map(|&x| x)
    }
    pub fn get_idx(&self, path: &Path) -> Option<PackageIdx> {
        self.manifest_to_idx.get(path).map(|&id| id)
    }
    pub fn get_id(&self, idx: PackageIdx) -> PackageId {
        self.packages[idx.0].id
    }
    pub fn get_edition(&self, idx: PackageIdx) -> Edition {
        self.packages[idx.0].edition
    }
    pub fn get_lib(&self, idx: PackageIdx) -> Option<&Target> {
        self.packages[idx.0].lib.as_ref()
    }
    pub fn get_lib_src_path(&self, idx: PackageIdx) -> Option<&Path> {
        self.get_lib(idx).map(|t| t.src_path.as_ref())
    }
    pub fn get_dependencies(&self, idx: PackageIdx) -> &[(InternedString, PathBuf)] {
        self.packages[idx.0].deps.as_ref()
    }
    pub fn get_src_path_from_libname(&self, id: PackageIdx, s: &str) -> Option<&Path> {
        let deps = self.get_dependencies(id);
        let query_str = InternedString::new_if_exists(s)?;
        deps.iter().find(|t| t.0 == query_str).map(|t| t.1.as_ref())
    }
}

fn construct_deps(
    nodes: Vec<ResolveNode>,
    id_to_idx: &HashMap<PackageId, PackageIdx>,
    res: &mut [PackageInner],
) -> Option<()> {
    for node in nodes {
        let idx = id_to_idx.get(&node.id)?;
        let deps: Vec<_> = node
            .dependencies
            .into_iter()
            .filter_map(|id| {
                let idx = id_to_idx.get(&id)?;
                res[idx.0]
                    .lib
                    .as_ref()
                    .map(|l| (l.name, l.src_path.clone()))
            })
            .collect();
        res[idx.0].deps.extend(deps);
    }
    Some(())
}