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
//! Standalone declarations checked by the build hook and matched by the macro.
use serde::{Deserialize, Serialize};
use std::{
error::Error,
fs,
path::{Path, PathBuf},
};
/// Compiler signal carrying the complete declaration file's path.
pub const ENV: &str = "TYPE_HISTORY_ADMISSION";
/// Exact authored identifier position, independent of normalized Rust spelling.
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Invocation {
/// Canonical containing file.
pub path: PathBuf,
/// One-based line.
pub line: usize,
/// Zero-based Unicode character column.
pub column: usize,
/// ASCII history identity.
pub stable_name: String,
}
/// One discovered invocation and its full library module path.
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Declaration {
/// Exact source position and history identity.
pub invocation: Invocation,
/// Library crate name followed by normalized module names.
pub module_path: Vec<String>,
/// Authored current-record alias, resolved by rustc within that module.
pub rust_name: String,
}
/// Disposable declaration inventory for one successful Cargo build hook.
#[derive(Debug, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Admission {
/// Effective policy selected by the build hook.
pub strict: bool,
/// Complete sorted declaration set.
pub declarations: Vec<Declaration>,
}
impl Admission {
/// Read the build output and require this actual declaration to be accounted for.
/// Return effective strictness and the declaration for compiler checking.
pub fn read(
path: &Path,
invocation: &Invocation,
) -> Result<(bool, Declaration), Box<dyn Error>> {
let admission: Self = serde_json::from_slice(&fs::read(path)?)?;
let declaration = admission.declarations.into_iter()
.find(|declaration| declaration.invocation == *invocation)
.filter(|declaration| !declaration.module_path.is_empty())
.ok_or("unsupported history declaration: use a directly declared module-level record discovered by the build hook")?;
Ok((admission.strict, declaration))
}
}
#[cfg(test)]
mod tests;