rapx/verify/
assets_parser.rs1use rustc_hir::def_id::DefId;
2use rustc_middle::ty::TyCtxt;
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5use std::sync::OnceLock;
6
7use super::helpers::get_cleaned_def_path_name;
8
9#[derive(Debug, Serialize, Deserialize, Clone)]
12pub struct PropertyEntry {
13 pub tag: String,
14 pub args: Vec<String>,
15}
16
17pub fn get_std_contracts_from_assets(tcx: TyCtxt<'_>, def_id: DefId) -> &'static [PropertyEntry] {
19 let cleaned_path_name = get_cleaned_def_path_name(tcx, def_id);
20 get_std_contracts_from_json()
21 .get(&cleaned_path_name)
22 .map(Vec::as_slice)
23 .unwrap_or(&[])
24}
25
26fn get_std_contracts_from_json() -> &'static HashMap<String, Vec<PropertyEntry>> {
28 static STD_CONTRACTS: OnceLock<HashMap<String, Vec<PropertyEntry>>> = OnceLock::new();
29 STD_CONTRACTS.get_or_init(|| {
30 let raw = include_str!("assets/std-contracts.json");
31 let normalized = normalize_json_trailing_commas(raw);
32 serde_json::from_str(normalized.as_str())
33 .unwrap_or_else(|err| panic!("failed to parse verify std contracts backup: {err}"))
34 })
35}
36
37fn normalize_json_trailing_commas(input: &str) -> String {
42 let mut normalized = String::with_capacity(input.len());
43 let mut iter = input.char_indices().peekable();
44
45 while let Some((_, ch)) = iter.next() {
46 if ch == ',' {
47 let mut lookahead = iter.clone();
48 while let Some((_, next_ch)) = lookahead.peek() {
49 if next_ch.is_whitespace() {
50 lookahead.next();
51 } else {
52 break;
53 }
54 }
55 if let Some((_, next_ch)) = lookahead.peek()
56 && (*next_ch == '}' || *next_ch == ']')
57 {
58 continue;
59 }
60 }
61 normalized.push(ch);
62 }
63
64 normalized
65}