use super::types::*;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum ArgKind {
Target,
Ty,
Expr,
Ident,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum BuildKind {
Uniform,
Size,
Allocated,
InBound,
NonOverlap,
ValidNum,
Pinned,
SplitTransmute,
Targets,
ContainNoType,
TobeSpecified,
}
pub(crate) struct PropertySpec {
pub tag: &'static str,
pub kind: PropertyKind,
pub forms: &'static [&'static [ArgKind]],
pub contract_kind: ContractKind,
pub build: BuildKind,
pub meaning: &'static str,
}
const fn ps(
tag: &'static str,
kind: PropertyKind,
forms: &'static [&'static [ArgKind]],
contract_kind: ContractKind,
build: BuildKind,
meaning: &'static str,
) -> PropertySpec {
PropertySpec {
tag,
kind,
forms,
contract_kind,
build,
meaning,
}
}
use ArgKind::{Expr, Ident, Target, Ty};
static SPECS: &[PropertySpec] = &[
ps(
"NonNull",
PropertyKind::NonNull,
&[&[Target]],
ContractKind::Precond,
BuildKind::Uniform,
"{0} as usize != 0",
),
ps(
"Null",
PropertyKind::Null,
&[&[Target]],
ContractKind::Precond,
BuildKind::Uniform,
"{0} is the null pointer",
),
ps(
"Owning",
PropertyKind::Owning,
&[&[Target]],
ContractKind::Precond,
BuildKind::Uniform,
"ownership(*{0}) = none: no live owner aliases the pointee",
),
ps(
"Opened",
PropertyKind::Opened,
&[&[Target]],
ContractKind::Precond,
BuildKind::Uniform,
"{0} is a valid open file descriptor",
),
ps(
"Unreachable",
PropertyKind::Unreachable,
&[&[]],
ContractKind::Precond,
BuildKind::Uniform,
"this branch is unreachable",
),
ps(
"Align",
PropertyKind::Align,
&[&[Target, Ty]],
ContractKind::Precond,
BuildKind::Uniform,
"({0} as usize) % align_of::<{1}>() == 0",
),
ps(
"Typed",
PropertyKind::Typed,
&[&[Target, Ty]],
ContractKind::Precond,
BuildKind::Uniform,
"*{0} holds TypeInvariant({1})",
),
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",
),
ps(
"ValidString",
PropertyKind::ValidString,
&[&[Target, Ty, Expr]],
ContractKind::Precond,
BuildKind::Uniform,
"{0} is valid UTF-8",
),
ps(
"NonVolatile",
PropertyKind::NonVolatile,
&[&[Target, Ty, Expr]],
ContractKind::Precond,
BuildKind::Uniform,
"{0} does not reference volatile memory",
),
ps(
"ValidTransmute",
PropertyKind::ValidTransmute,
&[&[Ty, Ty]],
ContractKind::Precond,
BuildKind::Uniform,
"bytes_of({1}) within bytes_of({0})",
),
ps(
"Trait",
PropertyKind::Trait,
&[&[Ty, Ident]],
ContractKind::Precond,
BuildKind::Uniform,
"{0} satisfies the trait bound {1}",
),
ps(
"ContainNoType",
PropertyKind::ContainNoType,
&[&[Ty, Ident]],
ContractKind::Precond,
BuildKind::ContainNoType,
"{0} does not structurally contain {1}",
),
ps(
"RefSend",
PropertyKind::RefSend,
&[&[Ty]],
ContractKind::Precond,
BuildKind::Uniform,
"&{0} is Send: all shared mutations of {0} go through a synchronization primitive",
),
ps(
"NoRawPtr",
PropertyKind::NoRawPtr,
&[&[Ty]],
ContractKind::Precond,
BuildKind::Uniform,
"{0} has no raw pointers",
),
ps(
"NoInternalMut",
PropertyKind::NoInternalMut,
&[&[Ty]],
ContractKind::Precond,
BuildKind::Uniform,
"{0} has no interior mutation through raw pointers",
),
ps(
"UniInternalMut",
PropertyKind::UniInternalMut,
&[&[Ty]],
ContractKind::Precond,
BuildKind::Uniform,
"{0} has unique interior mutation (exclusive owner, no aliasing Clone)",
),
ps(
"AtomicUpdate",
PropertyKind::AtomicUpdate,
&[&[Ty]],
ContractKind::Precond,
BuildKind::Uniform,
"{0} updates its raw pointers under synchronization or atomically",
),
ps(
"NoPadding",
PropertyKind::NoPadding,
&[&[Ty]],
ContractKind::Precond,
BuildKind::Uniform,
"{0} has no padding bytes between fields",
),
ps(
"ValidCStr",
PropertyKind::ValidCStr,
&[&[Target, Expr]],
ContractKind::Precond,
BuildKind::Uniform,
"{0} is a null-terminated valid UTF-8 byte sequence",
),
ps(
"Unwrap",
PropertyKind::Unwrap,
&[&[Target, Ident]],
ContractKind::Precond,
BuildKind::Uniform,
"unwrap({0}) = {1}",
),
ps(
"Size",
PropertyKind::Size,
&[&[Ty, Ident], &[Ty, Expr]],
ContractKind::Precond,
BuildKind::Size,
"sizeof({0}) = {1}",
),
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}",
),
ps(
"InBound",
PropertyKind::InBound,
&[&[Expr], &[Target, Expr], &[Target, Ty, Expr]],
ContractKind::Precond,
BuildKind::InBound,
"same_alloc([{0}, {0} + sizeof({1})*{2}])",
),
ps(
"NonOverlap",
PropertyKind::NonOverlap,
&[&[Target], &[Target, Target, Ty, Expr]],
ContractKind::Precond,
BuildKind::NonOverlap,
"[{0}] are pairwise disjoint memory ranges",
),
ps(
"ValidNum",
PropertyKind::ValidNum,
&[&[Expr], &[Expr, Expr]],
ContractKind::Precond,
BuildKind::ValidNum,
"{0}",
),
ps(
"Alias",
PropertyKind::Alias,
&[&[Target, Target]],
ContractKind::Hazard,
BuildKind::Targets,
"{0} and {1} alias each other (hazard)",
),
ps(
"Alive",
PropertyKind::Alive,
&[&[Target, Target]],
ContractKind::Precond,
BuildKind::Targets,
"*{0} outlives '{1}",
),
ps(
"Pinned",
PropertyKind::Pinned,
&[&[Target, Ident]],
ContractKind::Precond,
BuildKind::Pinned,
"{0} will not be moved",
),
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})",
),
ps(
"TobeSpecified",
PropertyKind::Unknown,
&[],
ContractKind::Precond,
BuildKind::TobeSpecified,
"(unresolved contract)",
),
];
pub(crate) fn find_spec(name: &str) -> Option<&'static PropertySpec> {
SPECS.iter().find(|s| s.tag == name)
}
pub(crate) fn tag_name_for_kind(kind: PropertyKind) -> Option<&'static str> {
SPECS.iter().find(|s| s.kind == kind).map(|s| s.tag)
}
pub(crate) fn kind_meaning(kind: PropertyKind) -> &'static str {
SPECS
.iter()
.find(|s| s.kind == kind)
.map(|s| s.meaning)
.unwrap_or("(unresolved contract)")
}