1use super::types::*;
11
12#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13pub(crate) enum ArgKind { Target, Ty, Expr, Ident }
14
15#[derive(Clone, Copy, Debug, PartialEq, Eq)]
17pub(crate) enum BuildKind {
18 Uniform,
20 Size,
22 Allocated,
24 InBound,
26 NonOverlap,
28 ValidNum,
30 Pinned,
32 SplitTransmute,
34 Targets,
36 TobeSpecified,
38}
39
40pub(crate) struct PropertySpec {
41 pub tag: &'static str,
42 pub kind: PropertyKind,
43 pub forms: &'static [&'static [ArgKind]],
46 pub contract_kind: ContractKind,
47 pub build: BuildKind,
48 pub meaning: &'static str,
55}
56
57const fn ps(
58 tag: &'static str,
59 kind: PropertyKind,
60 forms: &'static [&'static [ArgKind]],
61 contract_kind: ContractKind,
62 build: BuildKind,
63 meaning: &'static str,
64) -> PropertySpec {
65 PropertySpec { tag, kind, forms, contract_kind, build, meaning }
66}
67
68use ArgKind::{Expr, Ident, Target, Ty};
69
70static SPECS: &[PropertySpec] = &[
73 ps("NonNull", PropertyKind::NonNull, &[&[Target]], ContractKind::Precond, BuildKind::Uniform, "{0} as usize != 0"),
75 ps("Owning", PropertyKind::Owning, &[&[Target]], ContractKind::Precond, BuildKind::Uniform, "ownership(*{0}) = none: no live owner aliases the pointee"),
76 ps("Opened", PropertyKind::Opened, &[&[Target]], ContractKind::Precond, BuildKind::Uniform, "{0} is a valid open file descriptor"),
77 ps("Unreachable", PropertyKind::Unreachable, &[&[]], ContractKind::Precond, BuildKind::Uniform, "not Reachable()"),
78 ps("Align", PropertyKind::Align, &[&[Target, Ty]], ContractKind::Precond, BuildKind::Uniform, "({0} as usize) % align_of::<{1}>() == 0"),
79 ps("Typed", PropertyKind::Typed, &[&[Target, Ty]], ContractKind::Precond, BuildKind::Uniform, "*{0} holds TypeInvariant({1})"),
80 ps("Init", PropertyKind::Init, &[&[Target, Ty, Expr]], ContractKind::Precond, BuildKind::Uniform, "forall i in 0..{2}: *({0} + i*sizeof({1})) |= type_invariant({1}), and the {2} value(s) are initialized"),
81 ps("ValidString", PropertyKind::ValidString, &[&[Target, Ty, Expr]], ContractKind::Precond, BuildKind::Uniform, "{0} is valid UTF-8"),
82 ps("NonVolatile", PropertyKind::NonVolatile, &[&[Target, Ty, Expr]], ContractKind::Precond, BuildKind::Uniform, "{0} does not reference volatile memory"),
83 ps("ValidTransmute", PropertyKind::ValidTransmute, &[&[Ty, Ty]], ContractKind::Precond, BuildKind::Uniform, "bytes_of({1}) within bytes_of({0})"),
84 ps("Trait", PropertyKind::Trait, &[&[Ty, Ident]], ContractKind::Precond, BuildKind::Uniform, "{0} satisfies the trait bound {1}"),
85 ps("NoPadding", PropertyKind::NoPadding, &[&[Ty]], ContractKind::Precond, BuildKind::Uniform, "{0} has no padding bytes between fields"),
86 ps("ValidCStr", PropertyKind::ValidCStr, &[&[Target, Expr]], ContractKind::Precond, BuildKind::Uniform, "{0} is a null-terminated valid UTF-8 byte sequence"),
87 ps("Unwrap", PropertyKind::Unwrap, &[&[Target, Ident]], ContractKind::Precond, BuildKind::Uniform, "unwrap({0}) = {1}"),
88 ps("Size", PropertyKind::Size, &[&[Ty, Ident], &[Ty, Expr]], ContractKind::Precond, BuildKind::Size, "sizeof({0}) = {1}"),
90 ps("NonSize", PropertyKind::Size, &[&[Ty, Ident], &[Ty, Expr]], ContractKind::Precond, BuildKind::Size, "sizeof({0}) = {1}"),
91 ps("Allocated", PropertyKind::Allocated, &[&[Target], &[Target, Ty, Expr], &[Target, Ty, Expr, Ident]], ContractKind::Precond, BuildKind::Allocated, "{0} points to a live allocation of size: size_of({1}) * {2}"),
92 ps("InBound", PropertyKind::InBound, &[&[Expr], &[Target, Expr], &[Target, Ty, Expr]], ContractKind::Precond, BuildKind::InBound, "same_alloc([{0}, {0} + sizeof({1})*{2}])"),
93 ps("InBounded", PropertyKind::InBound, &[&[Expr], &[Target, Expr], &[Target, Ty, Expr]], ContractKind::Precond, BuildKind::InBound, "same_alloc([{0}, {0} + sizeof({1})*{2}])"),
94 ps("NonOverlap", PropertyKind::NonOverlap, &[&[Target], &[Target, Target, Ty, Expr]], ContractKind::Precond, BuildKind::NonOverlap, "[{0}] are pairwise disjoint memory ranges"),
95 ps("ValidNum", PropertyKind::ValidNum, &[&[Expr], &[Expr, Expr]], ContractKind::Precond, BuildKind::ValidNum, "{0}"),
96 ps("Alias", PropertyKind::Alias, &[&[Target, Target]], ContractKind::Hazard, BuildKind::Targets, "{0} and {1} alias each other (hazard)"),
97 ps("Alive", PropertyKind::Alive, &[&[Target, Target]], ContractKind::Precond, BuildKind::Targets, "*{0} outlives '{1}"),
98 ps("Pinned", PropertyKind::Pinned, &[&[Target, Ident]], ContractKind::Precond, BuildKind::Pinned, "{0} will not be moved"),
99 ps("SplitTransmute", PropertyKind::SplitTransmute, &[&[Ty, Ty]], ContractKind::Precond, BuildKind::SplitTransmute, "[{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}) \\ align_of({1})"),
100 ps("TobeSpecified", PropertyKind::Unknown, &[], ContractKind::Precond, BuildKind::TobeSpecified, "(unresolved contract)"),
101];
102
103pub(crate) fn find_spec(name: &str) -> Option<&'static PropertySpec> {
104 SPECS.iter().find(|s| s.tag == name)
105}
106
107pub(crate) fn kind_meaning(kind: PropertyKind) -> &'static str {
110 SPECS.iter()
111 .find(|s| s.kind == kind)
112 .map(|s| s.meaning)
113 .unwrap_or("(unresolved contract)")
114}