rapx/verify/contract/
assets.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 crate::helpers::name::get_cleaned_def_path_name;
8
9#[derive(Debug, Serialize, Deserialize, Clone)]
41pub struct PropertyEntry {
42 pub tag: String,
43 #[serde(default)]
44 pub args: Vec<String>,
45 #[serde(default)]
46 pub kind: Option<String>,
47 #[serde(default)]
50 pub any: Option<Vec<AnyItem>>,
51}
52
53#[derive(Debug, Serialize, Deserialize, Clone)]
58#[serde(untagged)]
59pub enum AnyItem {
60 Single(PropertyEntry),
61 Group(Vec<PropertyEntry>),
62}
63
64pub fn get_std_contracts_from_assets(tcx: TyCtxt<'_>, def_id: DefId) -> &'static [PropertyEntry] {
77 let lookup_def_id = resolve_trait_method(tcx, def_id);
78 let cleaned_path_name = get_cleaned_def_path_name(tcx, lookup_def_id);
79 let db = get_std_contracts_from_json();
80
81 if let Some(entries) = db.get(&cleaned_path_name) {
83 return entries.as_slice();
84 }
85
86 {
89 let stripped: Vec<&str> = cleaned_path_name
90 .split("::")
91 .filter(|s| !s.starts_with('[') && !s.starts_with('<'))
92 .collect();
93 if stripped.len() != cleaned_path_name.matches("::").count() + 1 {
94 let stripped_path = stripped.join("::");
95 if let Some(entries) = db.get(&stripped_path) {
96 return entries.as_slice();
97 }
98 }
99 }
100
101 let mut segments: Vec<&str> = cleaned_path_name.split("::").collect();
103 for i in (1..segments.len()).rev() {
104 segments[i] = "*";
105 if segments[i..].iter().all(|s| *s == "*") {
106 segments.truncate(i + 1);
107 }
108 let pattern = segments.join("::");
109 if let Some(entries) = db.get(&pattern) {
110 return entries.as_slice();
111 }
112 }
113
114 if let Some(entries) = db.get("*") {
116 return entries.as_slice();
117 }
118
119 &[]
120}
121
122fn resolve_trait_method(tcx: TyCtxt<'_>, def_id: DefId) -> DefId {
125 if let Some(assoc_item) = tcx.opt_associated_item(def_id) {
126 if let Some(trait_def_id) = assoc_item.trait_item_def_id() {
127 return trait_def_id;
128 }
129 }
130 def_id
131}
132
133fn get_std_contracts_from_json() -> &'static HashMap<String, Vec<PropertyEntry>> {
135 static STD_CONTRACTS: OnceLock<HashMap<String, Vec<PropertyEntry>>> = OnceLock::new();
136 STD_CONTRACTS.get_or_init(|| {
137 serde_json::from_str(include_str!("assets/std-public-contracts.json"))
138 .unwrap_or_else(|err| panic!("failed to parse verify std contracts backup: {err}"))
139 })
140}
141
142#[derive(Debug, Serialize, Deserialize, Clone)]
144pub struct TypeInvariantEntry {
145 #[serde(default)]
146 pub comment: Option<String>,
147 pub invariants: Vec<PropertyEntry>,
148}
149
150pub fn get_std_type_invariants() -> &'static HashMap<String, TypeInvariantEntry> {
153 static TYPE_INVARIANTS: OnceLock<HashMap<String, TypeInvariantEntry>> = OnceLock::new();
154 TYPE_INVARIANTS.get_or_init(|| {
155 serde_json::from_str(include_str!("assets/std-type-invariants.json"))
156 .unwrap_or_else(|err| panic!("failed to parse std type invariants: {err}"))
157 })
158}