1use super::types::*;
15
16#[derive(Clone, Copy, Debug, PartialEq, Eq)]
17pub(crate) enum ArgKind {
18 Target,
19 Ty,
20 Expr,
21 Ident,
22}
23
24#[derive(Clone, Copy, Debug, PartialEq, Eq)]
26pub(crate) enum BuildKind {
27 Uniform,
29 Size,
31 Allocated,
33 InBound,
35 NonOverlap,
37 ValidNum,
39 Pinned,
41 SplitTransmute,
43 Targets,
45 ContainNoType,
48 TobeSpecified,
50}
51
52pub(crate) struct PropertySpec {
53 pub tag: &'static str,
54 pub kind: PropertyKind,
55 pub forms: &'static [&'static [ArgKind]],
60 pub contract_kind: ContractKind,
61 pub build: BuildKind,
62 pub meaning: &'static str,
69}
70
71const fn ps(
72 tag: &'static str,
73 kind: PropertyKind,
74 forms: &'static [&'static [ArgKind]],
75 contract_kind: ContractKind,
76 build: BuildKind,
77 meaning: &'static str,
78) -> PropertySpec {
79 PropertySpec {
80 tag,
81 kind,
82 forms,
83 contract_kind,
84 build,
85 meaning,
86 }
87}
88
89use ArgKind::{Expr, Ident, Target, Ty};
90
91static SPECS: &[PropertySpec] = &[
94 ps(
96 "NonNull",
97 PropertyKind::NonNull,
98 &[&[Target]],
99 ContractKind::Precond,
100 BuildKind::Uniform,
101 "{0} as usize != 0",
102 ),
103 ps(
104 "Null",
105 PropertyKind::Null,
106 &[&[Target]],
107 ContractKind::Precond,
108 BuildKind::Uniform,
109 "{0} is the null pointer",
110 ),
111 ps(
112 "Owning",
113 PropertyKind::Owning,
114 &[&[Target]],
115 ContractKind::Precond,
116 BuildKind::Uniform,
117 "ownership(*{0}) = none: no live owner aliases the pointee",
118 ),
119 ps(
121 "Opened",
122 PropertyKind::Opened,
123 &[&[Target]],
124 ContractKind::Precond,
125 BuildKind::Uniform,
126 "{0} is a valid open file descriptor",
127 ),
128 ps(
130 "Unreachable",
131 PropertyKind::Unreachable,
132 &[&[]],
133 ContractKind::Precond,
134 BuildKind::Uniform,
135 "this branch is unreachable",
136 ),
137 ps(
138 "Align",
139 PropertyKind::Align,
140 &[&[Target, Ty]],
141 ContractKind::Precond,
142 BuildKind::Uniform,
143 "({0} as usize) % align_of::<{1}>() == 0",
144 ),
145 ps(
146 "Typed",
147 PropertyKind::Typed,
148 &[&[Target, Ty]],
149 ContractKind::Precond,
150 BuildKind::Uniform,
151 "*{0} holds TypeInvariant({1})",
152 ),
153 ps(
154 "Init",
155 PropertyKind::Init,
156 &[&[Target, Ty, Expr], &[Target, Expr]],
157 ContractKind::Precond,
158 BuildKind::Uniform,
159 "forall i in 0..{2}: *({0} + i*sizeof({1})) |= type_invariant({1}), and the {2} value(s) are initialized",
160 ),
161 ps(
162 "ValidString",
163 PropertyKind::ValidString,
164 &[&[Target, Ty, Expr], &[Target]],
165 ContractKind::Precond,
166 BuildKind::Uniform,
167 "{0} is valid UTF-8",
168 ),
169 ps(
171 "NonVolatile",
172 PropertyKind::NonVolatile,
173 &[&[Target, Ty, Expr]],
174 ContractKind::Precond,
175 BuildKind::Uniform,
176 "{0} does not reference volatile memory",
177 ),
178 ps(
179 "ValidTransmute",
180 PropertyKind::ValidTransmute,
181 &[&[Ty, Ty]],
182 ContractKind::Precond,
183 BuildKind::Uniform,
184 "bytes_of({1}) within bytes_of({0})",
185 ),
186 ps(
187 "Trait",
188 PropertyKind::Trait,
189 &[&[Ty, Ident]],
190 ContractKind::Precond,
191 BuildKind::Uniform,
192 "{0} satisfies the trait bound {1}",
193 ),
194 ps(
198 "ContainNoType",
199 PropertyKind::ContainNoType,
200 &[&[Ty, Ident]],
201 ContractKind::Precond,
202 BuildKind::ContainNoType,
203 "{0} does not structurally contain {1}",
204 ),
205 ps(
209 "RefSend",
210 PropertyKind::RefSend,
211 &[&[Ty]],
212 ContractKind::Precond,
213 BuildKind::Uniform,
214 "&{0} is Send: all shared mutations of {0} go through a synchronization primitive",
215 ),
216 ps(
218 "NoRawPtr",
219 PropertyKind::NoRawPtr,
220 &[&[Ty]],
221 ContractKind::Precond,
222 BuildKind::Uniform,
223 "{0} has no raw pointers",
224 ),
225 ps(
226 "NoInternalMut",
227 PropertyKind::NoInternalMut,
228 &[&[Ty]],
229 ContractKind::Precond,
230 BuildKind::Uniform,
231 "{0} has no interior mutation through raw pointers",
232 ),
233 ps(
234 "UniInternalMut",
235 PropertyKind::UniInternalMut,
236 &[&[Ty]],
237 ContractKind::Precond,
238 BuildKind::Uniform,
239 "{0} has unique interior mutation (exclusive owner, no aliasing Clone)",
240 ),
241 ps(
242 "AtomicUpdate",
243 PropertyKind::AtomicUpdate,
244 &[&[Ty]],
245 ContractKind::Precond,
246 BuildKind::Uniform,
247 "{0} updates its raw pointers under synchronization or atomically",
248 ),
249 ps(
250 "NoPadding",
251 PropertyKind::NoPadding,
252 &[&[Ty]],
253 ContractKind::Precond,
254 BuildKind::Uniform,
255 "{0} has no padding bytes between fields",
256 ),
257 ps(
258 "ValidCStr",
259 PropertyKind::ValidCStr,
260 &[&[Target, Expr]],
261 ContractKind::Precond,
262 BuildKind::Uniform,
263 "{0} is a null-terminated valid UTF-8 byte sequence",
264 ),
265 ps(
267 "Unwrap",
268 PropertyKind::Unwrap,
269 &[&[Target, Ident]],
270 ContractKind::Precond,
271 BuildKind::Uniform,
272 "unwrap({0}) = {1}",
273 ),
274 ps(
276 "Size",
277 PropertyKind::Size,
278 &[&[Ty, Ident], &[Ty, Expr]],
279 ContractKind::Precond,
280 BuildKind::Size,
281 "sizeof({0}) = {1}",
282 ),
283 ps(
284 "Allocated",
285 PropertyKind::Allocated,
286 &[&[Target], &[Target, Ty, Expr], &[Target, Ty, Expr, Ident]],
287 ContractKind::Precond,
288 BuildKind::Allocated,
289 "{0} points to a live allocation of size: size_of({1}) * {2}",
290 ),
291 ps(
292 "InBound",
293 PropertyKind::InBound,
294 &[&[Expr], &[Target, Expr], &[Target, Ty, Expr]],
295 ContractKind::Precond,
296 BuildKind::InBound,
297 "same_alloc([{0}, {0} + sizeof({1})*{2}])",
298 ),
299 ps(
300 "NonOverlap",
301 PropertyKind::NonOverlap,
302 &[&[Target], &[Target, Target, Ty, Expr]],
303 ContractKind::Precond,
304 BuildKind::NonOverlap,
305 "[{0}] are pairwise disjoint memory ranges",
306 ),
307 ps(
308 "ValidNum",
309 PropertyKind::ValidNum,
310 &[&[Expr], &[Expr, Expr]],
311 ContractKind::Precond,
312 BuildKind::ValidNum,
313 "{0}",
314 ),
315 ps(
316 "Alias",
317 PropertyKind::Alias,
318 &[&[Target, Target]],
319 ContractKind::Hazard,
320 BuildKind::Targets,
321 "{0} and {1} alias each other (hazard)",
322 ),
323 ps(
324 "Alive",
325 PropertyKind::Alive,
326 &[&[Target, Target]],
327 ContractKind::Precond,
328 BuildKind::Targets,
329 "*{0} outlives '{1}",
330 ),
331 ps(
333 "Pinned",
334 PropertyKind::Pinned,
335 &[&[Target, Ident]],
336 ContractKind::Precond,
337 BuildKind::Pinned,
338 "{0} will not be moved",
339 ),
340 ps(
341 "SplitTransmute",
342 PropertyKind::SplitTransmute,
343 &[&[Ty, Ty]],
344 ContractKind::Precond,
345 BuildKind::SplitTransmute,
346 "[{0}] as [{1}]: every size_of({1})-byte contiguous chunk of [{0}] is a valid bit-pattern of {1} (type_invariant satisfied, alignment not required)\nforall w subset bytes([{0}]), |w| == |{1}|: reinterpret_as_{1}(w) |= type_invariant({1})",
347 ),
348 ps(
349 "TobeSpecified",
350 PropertyKind::Unknown,
351 &[],
352 ContractKind::Precond,
353 BuildKind::TobeSpecified,
354 "(unresolved contract)",
355 ),
356];
357
358pub(crate) fn find_spec(name: &str) -> Option<&'static PropertySpec> {
359 SPECS.iter().find(|s| s.tag == name)
360}
361
362pub(crate) fn tag_name_for_kind(kind: PropertyKind) -> Option<&'static str> {
364 SPECS.iter().find(|s| s.kind == kind).map(|s| s.tag)
365}
366
367pub(crate) fn kind_meaning(kind: PropertyKind) -> &'static str {
370 SPECS
371 .iter()
372 .find(|s| s.kind == kind)
373 .map(|s| s.meaning)
374 .unwrap_or("(unresolved contract)")
375}