1use std::collections::{BTreeMap, BTreeSet};
2
3use anyhow::Context as _;
4use serde::{Deserialize, Serialize};
5
6use crate::{CrateName, Symbol, cap_rule::SymbolRules, symbol::FunctionOrPath};
7
8pub type CapabilitySet = BTreeSet<Capability>;
9
10#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
13pub enum Capability {
14 #[serde(rename = "build.rs")]
19 BuildRs,
20
21 #[serde(rename = "alloc")]
23 Alloc,
24
25 #[serde(rename = "panic")]
27 Panic,
28
29 #[serde(rename = "time")]
31 Time,
32
33 #[serde(rename = "sysinfo")]
35 Sysinfo,
36
37 #[serde(rename = "stdio")]
39 Stdio,
40
41 #[serde(rename = "thread")]
43 Thread,
44
45 #[serde(rename = "net")]
47 Net,
48
49 #[serde(rename = "fs")]
51 FS,
52
53 #[serde(rename = "*")]
55 Any,
56}
57
58impl std::fmt::Display for Capability {
59 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60 match self {
61 Self::BuildRs => write!(f, "build.rs"),
62 Self::Alloc => write!(f, "alloc"),
63 Self::Panic => write!(f, "panic"),
64 Self::Time => write!(f, "time"),
65 Self::Sysinfo => write!(f, "sysinfo"),
66 Self::Stdio => write!(f, "stdio"),
67 Self::Thread => write!(f, "thread"),
68 Self::Net => write!(f, "net"),
69 Self::FS => write!(f, "fs"),
70 Self::Any => write!(f, "any"),
71 }
72 }
73}
74
75impl Capability {
76 pub fn emoji(&self) -> &'static str {
77 match self {
78 Self::BuildRs => "๐ ๏ธ ",
79 Self::Alloc => "๐ฆ",
80 Self::Panic => "โ๏ธ",
81 Self::Time => "โฐ",
82 Self::Sysinfo => "๐ฅ๏ธ ",
83 Self::Stdio => "๐",
84 Self::Thread => "๐งต",
85 Self::Net => "๐",
86 Self::FS => "๐",
87 Self::Any => "โ ๏ธ ",
88 }
89 }
90}
91
92#[derive(Clone, Debug, Default)]
93pub struct DeducedCapabilities {
94 pub own_caps: BTreeMap<Capability, Reasons>,
96
97 pub known_crates: BTreeMap<CrateName, CapabilitySet>,
99
100 pub unknown_symbols: BTreeSet<Symbol>,
102
103 pub unknown_crates: BTreeMap<CrateName, BTreeSet<Symbol>>,
105}
106
107pub type Reasons = BTreeSet<Reason>;
109
110pub type Reason = Symbol;
111
112impl DeducedCapabilities {
113 pub fn from_symbols(
114 rules: &SymbolRules,
115 symbols: impl IntoIterator<Item = Symbol>,
116 ) -> anyhow::Result<Self> {
117 let mut slf = Self::default();
118 for symbol in symbols {
119 slf.add(rules, &symbol)?;
120 }
121 Ok(slf)
122 }
123
124 pub fn total_capabilities(&self) -> CapabilitySet {
125 let Self {
126 own_caps,
127 known_crates,
128 unknown_symbols,
129 unknown_crates,
130 } = self;
131
132 let mut total = BTreeSet::default();
133
134 for cap in own_caps.keys() {
135 total.insert(*cap);
136 }
137 for caps in known_crates.values() {
138 for &cap in caps {
139 total.insert(cap);
140 }
141 }
142 if !unknown_symbols.is_empty() || !unknown_crates.is_empty() {
143 total.insert(Capability::Any);
144 }
145
146 if total.contains(&Capability::Any) {
147 return std::iter::once(Capability::Any).collect();
148 }
149
150 total
151 }
152
153 fn add(&mut self, rules: &SymbolRules, symbol: &Symbol) -> anyhow::Result<()> {
155 for path in symbol.paths() {
156 match path {
157 FunctionOrPath::Function(fun_name) => {
158 let fun_name = fun_name.trim_start_matches('_');
159
160 if let Some(capabilities) = rules.match_symbol(fun_name) {
162 for &capability in capabilities {
163 self.own_caps
164 .entry(capability)
165 .or_default()
166 .insert(symbol.clone());
167 }
168 } else {
169 self.unknown_symbols.insert(symbol.clone());
170 }
171 }
172
173 FunctionOrPath::RustPath(rust_path) => {
174 let path_str = rust_path.to_string();
175 if let Some(capabilities) = rules.match_symbol(&path_str) {
177 for &capability in capabilities {
178 self.own_caps
179 .entry(capability)
180 .or_default()
181 .insert(symbol.clone());
182 }
183 } else {
184 let segments = rust_path.segments();
186
187 let crate_name = segments[0];
188 let crate_name = CrateName::new(crate_name)
189 .with_context(|| format!("mangled: {:?}", symbol.mangled))
190 .with_context(|| format!("demangled: {:?}", symbol.demangled))?;
191 self.unknown_crates
192 .entry(crate_name)
193 .or_default()
194 .insert(symbol.clone());
195 }
196 }
197 }
198 }
199
200 Ok(())
201 }
202}