From d90142b3ae9945d7a5adfca1565f6ec979e4d6c4 Mon Sep 17 00:00:00 2001 From: kerneyJ Date: Tue, 30 Jun 2026 11:26:44 -0700 Subject: [PATCH] trust_engine: add a formally verified derivation kernel Replace the trust engine's pure core with a Dafny-verified kernel, extracted to Rust and dropped in behind the `verified-kernel` cargo feature. With the feature off (default) the native fixed-point engine is unchanged; with it on, Derivation::derive routes through the kernel and the existing unit and e2e tests run against it. The kernel is built with Veri, an experimental verification system: the spec is written in the Veri DSL and compiled through its Dafny -> Rust toolchain. - src/trust_engine.veri.md: the Veri DSL spec of the derivation core (believed names + constraint delegation, IPs, authz, pattern-resolved endorser/target), carrying the types and contracts. - src/trust_engine/kernel/: the verified TrustEngine.dfy and its Dafny -> Rust extraction, as a self-contained crate excluded from the workspace (its own vendored dafny_runtime). - src/trust_engine/{marshal,runner}.rs: intern intermesh types into the kernel's relations, run it, and marshal results back into Derivation, keeping derive's signature identical. - finalize/expand_authz_side/imids_in_pattern move out of the native-only impl so both paths share them; MAX_DERIVATION_ITERATIONS is localized to the native loop. - .veri/veri.toml maps the spec to its committed output dir; xtask forwards INTERMESH_FEATURES so the e2e binary can build the kernel. --- .veri/.gitignore | 3 + .veri/veri.toml | 15 + Cargo.lock | 61 + Cargo.toml | 12 + src/trust_engine.rs | 165 +- src/trust_engine.veri.md | 683 +++ src/trust_engine/kernel/Cargo.lock | 119 + src/trust_engine/kernel/Cargo.toml | 11 + src/trust_engine/kernel/TrustEngine.dfy | 609 +++ src/trust_engine/kernel/runtime/Cargo.lock | 112 + src/trust_engine/kernel/runtime/Cargo.toml | 18 + src/trust_engine/kernel/runtime/Makefile | 28 + .../kernel/runtime/src/big_int.rs | 420 ++ src/trust_engine/kernel/runtime/src/lib.rs | 3853 ++++++++++++++++ .../kernel/runtime/src/small_int.rs | 335 ++ .../kernel/runtime/src/system/mod.rs | 3983 +++++++++++++++++ .../kernel/runtime/src/tests/mod.rs | 1324 ++++++ .../kernel/src/TrustEngine-rs.dtr | 5 + src/trust_engine/kernel/src/TrustEngine.rs | 2111 +++++++++ src/trust_engine/marshal.rs | 375 ++ src/trust_engine/runner.rs | 72 + xtask/src/main.rs | 12 +- 22 files changed, 14261 insertions(+), 65 deletions(-) create mode 100644 .veri/.gitignore create mode 100644 .veri/veri.toml create mode 100644 src/trust_engine.veri.md create mode 100644 src/trust_engine/kernel/Cargo.lock create mode 100644 src/trust_engine/kernel/Cargo.toml create mode 100644 src/trust_engine/kernel/TrustEngine.dfy create mode 100644 src/trust_engine/kernel/runtime/Cargo.lock create mode 100644 src/trust_engine/kernel/runtime/Cargo.toml create mode 100644 src/trust_engine/kernel/runtime/Makefile create mode 100644 src/trust_engine/kernel/runtime/src/big_int.rs create mode 100644 src/trust_engine/kernel/runtime/src/lib.rs create mode 100644 src/trust_engine/kernel/runtime/src/small_int.rs create mode 100644 src/trust_engine/kernel/runtime/src/system/mod.rs create mode 100644 src/trust_engine/kernel/runtime/src/tests/mod.rs create mode 100644 src/trust_engine/kernel/src/TrustEngine-rs.dtr create mode 100644 src/trust_engine/kernel/src/TrustEngine.rs create mode 100644 src/trust_engine/marshal.rs create mode 100644 src/trust_engine/runner.rs diff --git a/.veri/.gitignore b/.veri/.gitignore new file mode 100644 index 0000000..39bcad2 --- /dev/null +++ b/.veri/.gitignore @@ -0,0 +1,3 @@ +# Verifier build scratch (run_log, intermediate rounds, the dafny->rust crate). +# Clean artifacts are written to each module's configured output dir instead. +build/ diff --git a/.veri/veri.toml b/.veri/veri.toml new file mode 100644 index 0000000..e28dfe1 --- /dev/null +++ b/.veri/veri.toml @@ -0,0 +1,15 @@ +# Veri project configuration for intermesh. +# Run `python3 -m veri_build.pipeline build ` from this directory. + +[keys] +# Path to a file containing the raw Anthropic API key. Exported as +# ANTHROPIC_API_KEY for the build (an already-set env var wins). +anthropic = "~/.veri-api-key" + +# The verified trust-engine kernel. Spec → output paths are relative to this +# directory (the project root containing .veri/). +[[modules]] +name = "trust_engine" +spec = "src/trust_engine.veri.md" +output = "src/trust_engine/kernel/" +timeout = 1800 diff --git a/Cargo.lock b/Cargo.lock index 80a5067..223b077 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,13 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "TrustEngine" +version = "0.1.0" +dependencies = [ + "dafny_runtime", +] + [[package]] name = "aead" version = "0.5.2" @@ -566,6 +573,15 @@ dependencies = [ "syn 2.0.110", ] +[[package]] +name = "dafny_runtime" +version = "0.1.0" +dependencies = [ + "itertools", + "num", + "once_cell", +] + [[package]] name = "darling" version = "0.21.3" @@ -1500,6 +1516,7 @@ dependencies = [ name = "intermesh" version = "0.1.0" dependencies = [ + "TrustEngine", "anyhow", "arc-swap", "async-trait", @@ -1801,6 +1818,30 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + [[package]] name = "num-bigint-dig" version = "0.8.6" @@ -1817,6 +1858,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + [[package]] name = "num-conv" version = "0.2.0" @@ -1843,6 +1893,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" diff --git a/Cargo.toml b/Cargo.toml index ffe7a9a..15eba80 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,9 +6,16 @@ publish = false [workspace] members = ["xtask"] +# The verified trust-engine kernel is a generated, self-contained crate (its own +# vendored dafny_runtime). Keep it out of the workspace; intermesh depends on it +# only under the `verified-kernel` feature. +exclude = ["src/trust_engine/kernel"] [features] test-perf = [] +# Route Derivation::derive through the verified, Dafny-extracted kernel so the +# existing trust-engine tests run against it. +verified-kernel = ["dep:trust_engine_kernel"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -95,5 +102,10 @@ too_many_lines = "allow" missing_errors_doc = "allow" missing_panics_doc = "allow" +[dependencies.trust_engine_kernel] +package = "TrustEngine" +path = "src/trust_engine/kernel" +optional = true + [dev-dependencies] rayon = "1.11.0" diff --git a/src/trust_engine.rs b/src/trust_engine.rs index 6ef1ee6..2e965fa 100644 --- a/src/trust_engine.rs +++ b/src/trust_engine.rs @@ -1,17 +1,36 @@ -use crate::assert::UnwrapAssert; use crate::authorization::Authz; use crate::constraint::Constraint; use crate::endor; use crate::ident::{Name, NamePattern}; use crate::imid::Imid; use arc_swap::ArcSwap; -use ipnet::IpNet; use serde::{Deserialize, Serialize}; use std::collections::{BTreeMap, BTreeSet}; -use std::net::{IpAddr, Ipv4Addr}; +use std::net::IpAddr; use std::sync::Arc; use tokio::sync::Mutex; -use tracing::{info, instrument, warn}; +use tracing::instrument; + +// Used only by the native trust engine (the verified-kernel path replaces it). +#[cfg(not(feature = "verified-kernel"))] +use { + ipnet::IpNet, + std::net::Ipv4Addr, + tracing::{info, warn}, +}; +// Used by the native engine and by tests (the `.assert()` helper). +#[cfg(any(test, not(feature = "verified-kernel")))] +use crate::assert::UnwrapAssert; + +// The verified-kernel path. Under the `verified-kernel` feature, `derive` +// delegates to the Dafny-extracted kernel: `runner` orchestrates (marshal in → +// kernel → marshal out); `marshal` does the interning / claim explosion / +// relation building both directions. Both pull in the generated kernel crate. +#[cfg(feature = "verified-kernel")] +mod marshal; +#[cfg(feature = "verified-kernel")] +mod runner; + /* OPT: Regarding Optimizations * * This code is intentionally highly un-optimized. If you're reading this @@ -28,12 +47,6 @@ use tracing::{info, instrument, warn}; * that will change dramatically with a proper algorithmic optimization later. */ -// Maximum iterations for fixed-point derivation. Any reasonable trust policy -// should converge well before this limit. The cap exists primarily for DOS -// mitigation - malicious or misconfigured deep delegation chains could -// otherwise waste CPU indefinitely. -const MAX_DERIVATION_ITERATIONS: usize = 50; - // A TrustEngine holds the derived lookup tables from an endorsement base set. // It uses an internal datalog engine to process positive endorsement facts and // constraints to produce verified lookup tables. Signed-message preprocessing @@ -176,6 +189,82 @@ impl Derivation { } } + // Verified-kernel path: delegate to the Dafny-extracted kernel via the + // marshalling runner, preserving derive's bookkeeping (iteration, input) so + // the rest of the engine behaves identically. The kernel always derives from + // scratch — the same least fixed point the native loop converges to. + #[cfg(feature = "verified-kernel")] + fn derive(&self, bases: &BTreeSet) -> Derivation { + let mut result = runner::run(&self.my_imid, bases); + result.iteration = self.iteration + 1; + result.input.clone_from(bases); + result + } + + // Compute derived indexes after the fixed-point loop converges. + fn finalize(&mut self) { + // Build imid_to_names as inverse of name_to_imid + self.imid_to_names.clear(); + for (name, imids) in &self.name_to_imid { + for imid in imids { + self.imid_to_names + .entry(imid.clone()) + .or_default() + .insert(name.clone()); + } + } + + // Compute my_authz_to and my_authz_from from authorization rules. + // Done here rather than in apply_endor() because pattern matching + // depends on name_to_imid being complete. + self.my_authz_to.clear(); + self.my_authz_from.clear(); + for authz in &self.my_authz { + let sources = self.expand_authz_side(&authz.source_imids, &authz.source_patterns); + let destinations = + self.expand_authz_side(&authz.destination_imids, &authz.destination_patterns); + + if sources.contains(&self.my_imid) { + self.my_authz_to.extend(destinations.iter().cloned()); + } + if destinations.contains(&self.my_imid) { + self.my_authz_from.extend(sources); + } + } + } + + fn expand_authz_side( + &self, + imids: &BTreeSet, + patterns: &BTreeSet, + ) -> BTreeSet { + let mut expanded: BTreeSet = imids.iter().cloned().collect(); + for pattern in patterns { + expanded.extend(self.imids_in_pattern(pattern).cloned()); + } + expanded + } + + // OPT: an imid_to_name and a name_to_pattern index could optimize this. + fn imids_in_pattern<'a>(&'a self, pattern: &'a NamePattern) -> impl Iterator { + self.name_to_imid + .iter() + .filter(move |(name, _)| pattern.matches(name)) + .flat_map(|(_, imids)| imids) + } +} + +// The native trust engine: the fixed-point loop and its gating helpers. Under +// the `verified-kernel` feature the kernel replaces this whole path, so it +// compiles only when that feature is off. +#[cfg(not(feature = "verified-kernel"))] +impl Derivation { + // Maximum iterations for fixed-point derivation. Any reasonable trust policy + // should converge well before this limit. The cap exists primarily for DOS + // mitigation - malicious or misconfigured deep delegation chains could + // otherwise waste CPU indefinitely. + const MAX_DERIVATION_ITERATIONS: usize = 50; + fn derive(&self, bases: &BTreeSet) -> Derivation { info!("Trust Engine Derive"); @@ -222,7 +311,7 @@ impl Derivation { // convergence is mathematically guaranteed. MAX_DERIVATION_ITERATIONS // catches bugs or unexpectedly deep delegation chains before returning // an unsafe partial derivation. - for _ in 0..MAX_DERIVATION_ITERATIONS { + for _ in 0..Self::MAX_DERIVATION_ITERATIONS { let mut changed = false; for base in bases { changed = result.apply_endor(base) || changed; @@ -234,7 +323,7 @@ impl Derivation { panic!( "trust engine failed to converge after {} iterations ({} endorsements, {} names, {} IPs, {} constraints)", - MAX_DERIVATION_ITERATIONS, + Self::MAX_DERIVATION_ITERATIONS, result.input.len(), result.name_to_imid.len(), result.imid_to_ip.len(), @@ -338,50 +427,6 @@ impl Derivation { changed } - // Compute derived indexes after the fixed-point loop converges. - fn finalize(&mut self) { - // Build imid_to_names as inverse of name_to_imid - self.imid_to_names.clear(); - for (name, imids) in &self.name_to_imid { - for imid in imids { - self.imid_to_names - .entry(imid.clone()) - .or_default() - .insert(name.clone()); - } - } - - // Compute my_authz_to and my_authz_from from authorization rules. - // Done here rather than in apply_endor() because pattern matching - // depends on name_to_imid being complete. - self.my_authz_to.clear(); - self.my_authz_from.clear(); - for authz in &self.my_authz { - let sources = self.expand_authz_side(&authz.source_imids, &authz.source_patterns); - let destinations = - self.expand_authz_side(&authz.destination_imids, &authz.destination_patterns); - - if sources.contains(&self.my_imid) { - self.my_authz_to.extend(destinations.iter().cloned()); - } - if destinations.contains(&self.my_imid) { - self.my_authz_from.extend(sources); - } - } - } - - fn expand_authz_side( - &self, - imids: &BTreeSet, - patterns: &BTreeSet, - ) -> BTreeSet { - let mut expanded: BTreeSet = imids.iter().cloned().collect(); - for pattern in patterns { - expanded.extend(self.imids_in_pattern(pattern).cloned()); - } - expanded - } - fn constraint_permits_endorser(&self, constraint: &Constraint, endorser: &Imid) -> bool { // OPT: Once a target is permitted by a constraint it's always permitted // Memoization could be helpful here. @@ -396,14 +441,6 @@ impl Derivation { || self.patterns_contains(&constraint.target_patterns, target) } - // OPT: an imid_to_name and a name_to_pattern index could optimize this. - fn imids_in_pattern<'a>(&'a self, pattern: &'a NamePattern) -> impl Iterator { - self.name_to_imid - .iter() - .filter(move |(name, _)| pattern.matches(name)) - .flat_map(|(_, imids)| imids) - } - fn patterns_contains<'a>( &self, patterns: impl IntoIterator, diff --git a/src/trust_engine.veri.md b/src/trust_engine.veri.md new file mode 100644 index 0000000..dc13c79 --- /dev/null +++ b/src/trust_engine.veri.md @@ -0,0 +1,683 @@ +# Verifed Trust Engine + +## Overview + +This file is a formal specification of intermesh's trust engine. +The trust engine receives a set of endorsements and determines which +endorsements the user should believe. Correctness of the trust engine's +output is necessary for Intermesh to be secure. For correctness the +trust engine must be monotonic (i.e. endorsements only add information), +commutative (i.e. derived facts are independent of order), and terminate. + +To ensure correctness we split the trust engine in twain. First a marshaling +layer interns `Base` fields into `usize` and explodes each `Base` into +single-fact claims. Second a verified kernel consumes +the marshalled endorsements and returns the interned results. The interned results +are deinterned by the marshaller and returned to the user. + +This document uses Veri to specify correctness (i.e. monotonicity, commutativity and +termination) and contains enough context for an AI agent to implement a verified +trust engine kernel. + +```veri +TARGET dafny-rust +VERI_VERSION 0.0.2 +``` + +## What the marshaller computes + +The marshaller precomputes two relations from the live endorsement bag: + +- **`patterns`**: every `(Pattern, Name)` pair where that name falls in that + pattern, for all patterns and names observed. +- **`subnet_contains`**: every `(Subnet, Ip)` pair where that ip falls in that + subnet, for all subnets and ips observed. + +Both ride into the kernel as parameters (`patterns: set[PatName]`, +`subnet_contains: set[SubnetIp]`) and are **static**: the kernel reads them but +never extends them, and they are not part of the derivation `State`. They appear +in nearly every predicate below; in each one `patterns` is exactly this +precomputed `PatName` relation, never a field of the state being derived. + +It also builds the kernel's other inputs: the init state seeded with the +implicit self-constraint, and a closed `Universe` that bounds termination (see +"Derivable universe"). + +## What the kernel decides + +The kernel receives a set of **claims** and decides which to believe +based on the active constraint chain from self-trust. It produces four derived +facts: which `(Name, Imid)` edges are believed, which `(Ip, Imid)` edges are believed, +which `Constraint`s are active, and which `Authz` rules are believed. +They grow together: a newly active constraint can justify further name/ip beliefs, +and a newly believed name can satisfy a constraint's endorser or target pattern, +unlocking further claims. + +## Core definitions + +To implement the verified core, the kernel needs types for claims and the fields they contain. +This section defines a Claim and its fields. + +### Identifiers + +`Imid`, `Name`, `Pattern`, `Ip`, `Subnet` are opaque handles assigned by the marshaller. +For each identifier the marshaller assigns a unique natural number in its domain. +For example, Imid 0 refers to `my_imid`, since its the first interned Imid and +Imid 1 may refer to some `other_imid`. For the same reason pattern 0 refers `**` and higher +numbers refer to later interned patterns. + +```veri +type Imid = nat +type Name = nat +type Pattern = nat +type Ip = nat +type Subnet = nat +``` + +### Constraints + +A `Constraint` gates which claims the kernel believes: it specifies which endorsers are +trusted to assign attribute to which targets. The attributes endorsers assign to targets +are names, ip addresses, or constraints and authroization rules. + +```veri +class Constraint: + endorser_imids: set[Imid] + endorser_patterns: set[Pattern] + target_imids: set[Imid] + target_patterns: set[Pattern] + any_target: bool + permitted_patterns: set[Pattern] + permitted_subnets: set[Subnet] + authority: bool +``` + +An authoriation rule: `Authz` names a set of source and destination peers and permits +traffic between them. Peers are named directly by imid or indirectly by pattern. +The kernel only decides *which* authz rules we believe; expanding the source/destination patterns +into the `my_authz_to` / `my_authz_from` maps is a pure post-pass over the final believed +names (`finalize`), computed outside the kernel. + +```veri +class Authz: + source_imids: set[Imid] + source_patterns: set[Pattern] + destination_imids: set[Imid] + destination_patterns: set[Pattern] +``` + +### Claims + +**Claims** are the assertion that some target has some attribute by an endorser. +Each claim carries the endorsement's targets: `target_imids` and `target_patterns`. +Targets are computed inside the kernel: an imid is a target if it is named explicitly in +`target_imids`, or if a currently-believed name of that imid matches one of +`target_patterns` (a la `apply_endor`, `imids_in_pattern`). Since that resolution reads +the believed names, one claim can grant a fact to many targets, and the target set grows. +`GrantConstraint` activates only when `my_imid` is among the resolved targets. + +```veri +variant Claim: + | GrantName(endorser: Imid, target_imids: set[Imid], target_patterns: set[Pattern], name: Name) + | GrantIp(endorser: Imid, target_imids: set[Imid], target_patterns: set[Pattern], ip: Ip) + | GrantConstraint(endorser: Imid, target_imids: set[Imid], target_patterns: set[Pattern], constraint: Constraint) + | GrantAuthz(endorser: Imid, target_imids: set[Imid], target_patterns: set[Pattern], authz: Authz) +``` + +### Facts + +**Facts** are what the kernel derives over. `NameImid` / `IpImid` are the +believed assignment edges — the output the kernel grows. `PatName` / `SubnetIp` +are the precomputed carve-out relations (`patterns` / `subnet_contains`) the +kernel reads but never extends. + +```veri +class NameImid: + name: Name + imid: Imid + +class IpImid: + ip: Ip + imid: Imid + +class PatName: + pattern: Pattern + name: Name + +class SubnetIp: + subnet: Subnet + ip: Ip +``` + +### Derivation State + +`my_imid` is the kernel's own identity (fixed; used to filter `GrantConstraint` +claims). `names` is the set of `(Name, Imid)` bindings we currently believe; +`ips` is the set of `(Ip, Imid)` bindings we currently believe; `constraints` is the set of +active constraints (grows via `GrantConstraint` claims targeting self); `authz` +is the set of believed authorization rules (grows via `GrantAuthz` claims +targeting self under the same authority gate). + +```veri +class State: + my_imid: Imid + names: set[NameImid] + ips: set[IpImid] + constraints: set[Constraint] + authz: set[Authz] +``` + +### Size measure + +The number of facts derived so far. Bounded above by the finite derivable +universe (below), so it is the basis of the termination measure. + +```veri +def size(s: State) -> nat: + return len(s.names) + len(s.ips) + len(s.constraints) + len(s.authz) +``` + +### Permission and Authorization + +These predicates decide whether a constraint the kernel **already believes** +(`∈ s.constraints`) licenses a given claim. Each pairs a shared endorser/target +*gate* with a per-claim check: a name must match a `permitted_pattern`, an ip a +`permitted_subnet`, a delegation needs the `authority` bit. + +The gate permits an endorser (or target) either by an explicit imid *or* by a +currently-believed *name* of that imid matching one of the constraint's +`endorser_patterns` / `target_patterns`. The pattern arm reads `names` — the very +relation being derived — so the gate is a genuine fixpoint, not a one-pass filter. + +- **`endorser_ok` / `target_ok`**: returns whether or not the believed constraint `ct` permits + the endorser or target. Mirrors `constraint_permits_endorser` and `constraint_permits_target`. +- **`permits_name`**: returns whether or not a believed constraint grants a particular name (`GrantName`). +- **`permits_ip`**: IP analogue of `permits_name` +- **`authorizes`**: returns whether or not the believed constraint `ct` allows *delegation* (`GrantConstraint`). + +```veri +def endorser_ok(ct: Constraint, endorser: Imid, patterns: set[PatName], names: set[NameImid]) -> bool: + return (endorser in ct.endorser_imids + or (EXISTS nm IN names: (nm.imid == endorser + and (EXISTS p IN ct.endorser_patterns: PatName(p, nm.name) in patterns)))) + +def target_ok(ct: Constraint, target: Imid, patterns: set[PatName], names: set[NameImid]) -> bool: + return (ct.any_target + or target in ct.target_imids + or (EXISTS nm IN names: (nm.imid == target + and (EXISTS p IN ct.target_patterns: PatName(p, nm.name) in patterns)))) + +def permits_name(ct: Constraint, endorser: Imid, target: Imid, name: Name, patterns: set[PatName], names: set[NameImid]) -> bool: + return (endorser_ok(ct, endorser, patterns, names) + and target_ok(ct, target, patterns, names) + and (EXISTS p IN ct.permitted_patterns: PatName(p, name) in patterns)) + +def permits_ip(ct: Constraint, endorser: Imid, target: Imid, ip: Ip, subnet_contains: set[SubnetIp], patterns: set[PatName], names: set[NameImid]) -> bool: + return (endorser_ok(ct, endorser, patterns, names) + and target_ok(ct, target, patterns, names) + and (EXISTS sn IN ct.permitted_subnets: SubnetIp(sn, ip) in subnet_contains)) + +def authorizes(ct: Constraint, endorser: Imid, target: Imid, patterns: set[PatName], names: set[NameImid]) -> bool: + return (endorser_ok(ct, endorser, patterns, names) + and target_ok(ct, target, patterns, names) + and ct.authority) +``` + +### Targets of a Claim + +`resolves_target` decides whether an imid `t` is one of the targets a claim +addresses: explicitly in `target_imids`, or via a believed name of `t` matching +a pattern in `target_patterns` (this is distinct from `target_ok`, which is a +constraint's permission). Both `resolves_target` and `target_ok` must hold for a +fact to be believed. + +```veri +def resolves_target(target_imids: set[Imid], target_patterns: set[Pattern], t: Imid, patterns: set[PatName], names: set[NameImid]) -> bool: + return (t in target_imids + or (EXISTS nm IN names: (nm.imid == t + and (EXISTS p IN target_patterns: PatName(p, nm.name) in patterns)))) +``` + +### Which fact a claim grants + +These predicates define which fact a claim justifies, as a function of the +believed constraints and names (the gate resolves endorser/target patterns +through those names) plus the `patterns` and `subnet_contains` relations. Each +claim constructor justifies exactly one kind of fact — `GrantName` a believed +name, `GrantIp` a believed ip, `GrantConstraint` a believed constraint, +`GrantAuthz` a believed authz rule — so a single `match` dispatches all four: + +- **`grants`**: If the claim is justified, then its fact is present in the result + One predicate covers all four fact kinds of facts. +- **`grants_exact_name` / `grants_exact_ip` / `grants_exact_constraint` / + `grants_exact_authz`**: each asserts that one specific fact (a `NameImid` / + `IpImid` / `Constraint` / `Authz`) is justified by some claim against the + current believed state. The `round` and `apply_one` upper bounds quantify over + these as the per-fact-kind witnesses. + +The justified facts are pinned from both sides. Because one `GrantName` can +resolve to many targets (any imid whose believed name matches `target_patterns`), +the **lower bound** is a `FORALL t`: for every resolved target, the permitted +target's fact must appear. The **upper bound** (`grants_exact_*`) is the converse: +every fact in the result must trace back to a resolved, permitted target. +Together they pin the result to exactly the justified facts. + +`GrantConstraint` activation models the delegation branch in `apply_endor`: +install constraint `k` only when (1) `my_imid` is a resolved target (addressed to +us), (2) a believed constraint *authorizes* the endorser to delegate to us, and +(3) the self-only authority restriction — a constraint that itself carries +`authority` is installable only via a self-endorsement (`endorser == my_imid`). + +`GrantAuthz` rides the **same** authority gate (in the same `if +authority` block): install authz `a` when `my_imid` is a resolved target and a +believed constraint *authorizes* the endorser to delegate to us. There is **no** +self-only restriction — the real engine inserts every authz under `if authority` +with no per-entry authority check (unlike the constraint loop's self-only clause). + +```veri +def grants_name(endorser: Imid, tis: set[Imid], tps: set[Pattern], name: Name, constraints: set[Constraint], names: set[NameImid], patterns: set[PatName], result_names: set[NameImid]) -> bool: + return ((FORALL t IN tis: + ((EXISTS ct IN constraints: permits_name(ct, endorser, t, name, patterns, names)) + ==> NameImid(name, t) in result_names)) + and (FORALL nm IN names: + (((EXISTS p IN tps: PatName(p, nm.name) in patterns) + and (EXISTS ct IN constraints: permits_name(ct, endorser, nm.imid, name, patterns, names))) + ==> NameImid(name, nm.imid) in result_names))) + +def grants_ip(endorser: Imid, tis: set[Imid], tps: set[Pattern], ip: Ip, constraints: set[Constraint], names: set[NameImid], patterns: set[PatName], subnet_contains: set[SubnetIp], result_ips: set[IpImid]) -> bool: + return ((FORALL t IN tis: + ((EXISTS ct IN constraints: permits_ip(ct, endorser, t, ip, subnet_contains, patterns, names)) + ==> IpImid(ip, t) in result_ips)) + and (FORALL nm IN names: + (((EXISTS p IN tps: PatName(p, nm.name) in patterns) + and (EXISTS ct IN constraints: permits_ip(ct, endorser, nm.imid, ip, subnet_contains, patterns, names))) + ==> IpImid(ip, nm.imid) in result_ips))) + +def grants(c: Claim, my_imid: Imid, constraints: set[Constraint], names: set[NameImid], patterns: set[PatName], subnet_contains: set[SubnetIp], result_names: set[NameImid], result_ips: set[IpImid], result_constraints: set[Constraint], result_authz: set[Authz]) -> bool: + return match c: + case GrantName(endorser, tis, tps, name): + grants_name(endorser, tis, tps, name, constraints, names, patterns, result_names) + case GrantIp(endorser, tis, tps, ip): + grants_ip(endorser, tis, tps, ip, constraints, names, patterns, subnet_contains, result_ips) + case GrantConstraint(endorser, tis, tps, k): + ((resolves_target(tis, tps, my_imid, patterns, names) + and (EXISTS ct IN constraints: authorizes(ct, endorser, my_imid, patterns, names)) + and ((not k.authority) or endorser == my_imid)) + ==> k in result_constraints) + case GrantAuthz(endorser, tis, tps, a): + ((resolves_target(tis, tps, my_imid, patterns, names) + and (EXISTS ct IN constraints: authorizes(ct, endorser, my_imid, patterns, names))) + ==> a in result_authz) + +def grants_exact_name(c: Claim, nm: NameImid, constraints: set[Constraint], names: set[NameImid], patterns: set[PatName]) -> bool: + return match c: + case GrantName(endorser, tis, tps, name): + (name == nm.name + and resolves_target(tis, tps, nm.imid, patterns, names) + and (EXISTS ct IN constraints: permits_name(ct, endorser, nm.imid, name, patterns, names))) + case GrantIp(_, _, _, _): + False + case GrantConstraint(_, _, _, _): + False + case GrantAuthz(_, _, _, _): + False + +def grants_exact_ip(c: Claim, ii: IpImid, constraints: set[Constraint], names: set[NameImid], patterns: set[PatName], subnet_contains: set[SubnetIp]) -> bool: + return match c: + case GrantName(_, _, _, _): + False + case GrantIp(endorser, tis, tps, ip): + (ip == ii.ip + and resolves_target(tis, tps, ii.imid, patterns, names) + and (EXISTS ct IN constraints: permits_ip(ct, endorser, ii.imid, ip, subnet_contains, patterns, names))) + case GrantConstraint(_, _, _, _): + False + case GrantAuthz(_, _, _, _): + False + +def grants_exact_constraint(c: Claim, k: Constraint, my_imid: Imid, constraints: set[Constraint], names: set[NameImid], patterns: set[PatName]) -> bool: + return match c: + case GrantName(_, _, _, _): + False + case GrantIp(_, _, _, _): + False + case GrantConstraint(endorser, tis, tps, kc): + (kc == k + and resolves_target(tis, tps, my_imid, patterns, names) + and (EXISTS ct IN constraints: authorizes(ct, endorser, my_imid, patterns, names)) + and ((not kc.authority) or endorser == my_imid)) + case GrantAuthz(_, _, _, _): + False + +def grants_exact_authz(c: Claim, a: Authz, my_imid: Imid, constraints: set[Constraint], names: set[NameImid], patterns: set[PatName]) -> bool: + return match c: + case GrantName(_, _, _, _): + False + case GrantIp(_, _, _, _): + False + case GrantConstraint(_, _, _, _): + False + case GrantAuthz(endorser, tis, tps, ka): + (ka == a + and resolves_target(tis, tps, my_imid, patterns, names) + and (EXISTS ct IN constraints: authorizes(ct, endorser, my_imid, patterns, names))) +``` + +### Derivable universe + +The universe `u` is the finite ceiling that bounds termination (see the +"Termination" invariant below). `round` adds facts, so it needs a finite ceiling: +`u` is a finite set of facts containing everything that could be derived given +the claims observed, and each round strictly grows the believed set toward it. + +Since a claim justifies a fact per resolved target (see "Which fact a claim +grants") and which targets resolve grows with the fixpoint, the universe can't be +a per-claim fact list. It must be **closed** under the grant rules: applying a +round to any state inside `u` keeps it inside `u`. That closure (preserved every +round) is what makes `within` an invariant and the set-difference measure shrink. + +`claim_fact_in_universe` is the single-claim version of that closure: it says `u` +already holds every fact one claim could grant. It checks this **without the +permission gate** — it requires `u` to contain the fact for every resolved +target, whether or not a constraint actually permits it. That makes `u` a +deliberate over-shoot (it holds at least everything derivable), and it lets the +check look only at `u` and `patterns` instead of the believed constraints and +names — so the marshaller can compute `u` once, up front, as a fixed ceiling. +`GrantConstraint` and `GrantAuthz` grant just `k` / `a` (no per-target fan-out), +so their cases don't need the per-target quantifier. + +```veri +class Universe: + names: set[NameImid] + ips: set[IpImid] + constraints: set[Constraint] + authz: set[Authz] + +def name_in_universe(tis: set[Imid], tps: set[Pattern], name: Name, u: Universe, patterns: set[PatName]) -> bool: + return ((FORALL t IN tis: NameImid(name, t) in u.names) + and (FORALL nm IN u.names: + ((EXISTS p IN tps: PatName(p, nm.name) in patterns) + ==> NameImid(name, nm.imid) in u.names))) + +def ip_in_universe(tis: set[Imid], tps: set[Pattern], ip: Ip, u: Universe, patterns: set[PatName]) -> bool: + return ((FORALL t IN tis: IpImid(ip, t) in u.ips) + and (FORALL nm IN u.names: + ((EXISTS p IN tps: PatName(p, nm.name) in patterns) + ==> IpImid(ip, nm.imid) in u.ips))) + +def claim_fact_in_universe(c: Claim, u: Universe, patterns: set[PatName]) -> bool: + return match c: + case GrantName(endorser, tis, tps, name): + name_in_universe(tis, tps, name, u, patterns) + case GrantIp(endorser, tis, tps, ip): + ip_in_universe(tis, tps, ip, u, patterns) + case GrantConstraint(endorser, tis, tps, k): + k in u.constraints + case GrantAuthz(endorser, tis, tps, a): + a in u.authz + +def within(s: State, u: Universe) -> bool: + return s.names <= u.names and s.ips <= u.ips and s.constraints <= u.constraints and s.authz <= u.authz + +def fits(claims: set[Claim], u: Universe, patterns: set[PatName]) -> bool: + return FORALL c IN claims: claim_fact_in_universe(c, u, patterns) +``` + +## Derive + +`derive` is the public entry point: apply `round` until one adds nothing, +returning that fixed point. The recursion returns `s` when `round(s) == s`, +otherwise it recurses on `round(s)`. It carries the same parameters as `round`: +the state `s`, the claim set, the static `patterns` / `subnet_contains` +relations, and the universe ceiling `u`. The contract requires the inputs to +start consistent (`within(s, u)` and `fits(claims, u, patterns)`) and guarantees +the result still fits the universe (`within(result, u)`). It terminates on the +measure `len(u.names - s.names) + len(u.ips - s.ips) + len(u.constraints - +s.constraints) + len(u.authz - s.authz)`, the facts in `u` not yet derived: +non-negative by construction, and strictly shrinking as each round moves `s` +toward the constant ceiling `u`. + +The types and predicates `derive` and `round` reference (`State`, `Claim`, +`grants`, `Universe`, the permission gates, …) are defined under "Supporting +definitions" above; this section gives the entry point first, then drills into +`round`. + +```veri +def derive(s: State, claims: set[Claim], patterns: set[PatName], subnet_contains: set[SubnetIp], u: Universe) -> State: + REQUIRES (within(s, u) and fits(claims, u, patterns)) + ENSURES within(result, u) + DECREASES len(u.names - s.names) + len(u.ips - s.ips) + len(u.constraints - s.constraints) + len(u.authz - s.authz) + return (s if round(s, claims, patterns, subnet_contains, u) == s + else derive(round(s, claims, patterns, subnet_contains, u), claims, patterns, subnet_contains, u)) +``` + +### Round + +Apply every claim once against the current state. The body is filled in by agents during +Veri compile, for now we specify the contract. The contract pins `round` to **exactly** the +immediate-consequence operator: + +- **inflationary**: only adds facts (`s ⊆ result`) +- **bounded**: `result` stays `within` the derivable universe `u`. Since a + subset is no larger than its superset, this caps `size(result)` at + `len(u.names) + len(u.ips) + len(u.constraints) + len(u.authz)`, the + termination ceiling. +- **strict growth on change**: if a round changes the state, `size` strictly + increases. This follows from *inflationary* on finite sets, but is stated + explicitly because the `decreases` measures in `derive` / `saturate_seq` need + it as a discharged fact. +- **lower bound** — every fact a believed constraint justifies (a name via + `permits_name`, an ip via `permits_ip`, or a delegated constraint / authz rule via + `authorizes`) *is* in the result. This is what kills the degenerate identity + body. +- **upper bound** — every fact in the result was either already in `s` or is + justified by some claim against `s`. No invention. Stated separately over + `result.names`, `result.ips`, `result.constraints`, and `result.authz` + (different fact types). + +Together these clauses tie `round` to the correctness goals. The lower bound is +**completeness**: every fact some claim justifies against `s` is in the result, +so a round derives everything currently derivable. The upper bound is +**soundness**: every derived fact traces back to a claim that justifies it, with +no invention. Inflationary, bounded, and strict-growth are the **termination** +ingredients: each round stays under the finite ceiling `u` and strictly grows +when it changes. **Monotonicity** rides on `Claim` having no `Deny`/`Ignore` +constructor, so a round can only add. **Commutativity** then falls out of the two +bounds: the lower bound makes a saturated result *closed* (a fixed point), and +the upper bound makes it sit *below every* fixed point, so it is the unique least +fixed point. Since that argument never refers to claim order, every ordering +lands on the same set as `derive`. + +```veri +def round(s: State, claims: set[Claim], patterns: set[PatName], subnet_contains: set[SubnetIp], u: Universe) -> State: + REQUIRES (within(s, u) and fits(claims, u, patterns)) + ENSURES (s.names <= result.names + and s.ips <= result.ips + and s.constraints <= result.constraints + and s.authz <= result.authz + and within(result, u) + and (result != s ==> size(s) < size(result)) + and (FORALL c IN claims: grants(c, s.my_imid, s.constraints, s.names, patterns, subnet_contains, result.names, result.ips, result.constraints, result.authz)) + and (FORALL nm IN result.names: + (nm in s.names + or (EXISTS c IN claims: grants_exact_name(c, nm, s.constraints, s.names, patterns)))) + and (FORALL ii IN result.ips: + (ii in s.ips + or (EXISTS c IN claims: grants_exact_ip(c, ii, s.constraints, s.names, patterns, subnet_contains)))) + and (FORALL k IN result.constraints: + (k in s.constraints + or (EXISTS c IN claims: grants_exact_constraint(c, k, s.my_imid, s.constraints, s.names, patterns)))) + and (FORALL a IN result.authz: + (a in s.authz + or (EXISTS c IN claims: grants_exact_authz(c, a, s.my_imid, s.constraints, s.names, patterns))))) + +#TODO +``` + +## Invariants + +`derive`'s correctness rests on three properties: **monotonicity** (more claims +only add facts), **commutativity** (the result is independent of claim order), +and **termination** (the fixed point is reached in finitely many rounds). +Monotonicity and commutativity are stated as **lemmas** — the proposition is the +`ENSURES`, and the proof is a `#TODO` body filled in downstream (`-> Lemma` emits +a Dafny `lemma`). Termination is discharged directly by the `decreases` measures +on `derive` and `saturate_seq`. + +### Monotonicity + +Adding claims can only *add* derived facts: `D(S) ⊆ D(T)` when `S ⊆ T`, for the +believed names, the believed ips, the constraints, and the authz rules. +Enabled by `variant Claim` having no `Deny` or `Ignore` constructor. +`names_of` / `ips_of` / `constraints_of` / `authz_of` each take a `State` and +return one of its fields (`names_of(s)` is `s.names`, and so on). They let the +lemma compare a single fact set of one `derive` result against another's: +`names_of(derive(s, claims1, …)) <= names_of(derive(s, claims2, …))`. + +```veri +def names_of(s: State) -> set[NameImid]: + return s.names + +def ips_of(s: State) -> set[IpImid]: + return s.ips + +def constraints_of(s: State) -> set[Constraint]: + return s.constraints + +def authz_of(s: State) -> set[Authz]: + return s.authz + +def monotone(s: State, claims1: set[Claim], claims2: set[Claim], patterns: set[PatName], subnet_contains: set[SubnetIp], u: Universe) -> Lemma: + REQUIRES (within(s, u) and fits(claims2, u, patterns) and claims1 <= claims2) + ENSURES (names_of(derive(s, claims1, patterns, subnet_contains, u)) <= names_of(derive(s, claims2, patterns, subnet_contains, u)) + and ips_of(derive(s, claims1, patterns, subnet_contains, u)) <= ips_of(derive(s, claims2, patterns, subnet_contains, u)) + and constraints_of(derive(s, claims1, patterns, subnet_contains, u)) <= constraints_of(derive(s, claims2, patterns, subnet_contains, u)) + and authz_of(derive(s, claims1, patterns, subnet_contains, u)) <= authz_of(derive(s, claims2, patterns, subnet_contains, u))) + +#TODO +``` + +### Commutativity + +Commutativity means claim order doesn't matter: for *any* ordering `cs` of the +claim set (`cs` and `claims` contain the same elements), the order-sensitive +sequential saturation lands on the same facts as `derive`'s canonical set-based +fixed point. Since this holds for every ordering, all orderings agree with each +other (transitivity through `derive`), which is what justifies modeling claims as +an unordered set and certifies the real engine loop. + +```veri +def commutative(s: State, cs: seq[Claim], claims: set[Claim], patterns: set[PatName], subnet_contains: set[SubnetIp], u: Universe) -> Lemma: + REQUIRES (within(s, u) + and fits(claims, u, patterns) + and (FORALL c IN cs: c in claims) + and (FORALL c IN claims: c in cs)) + ENSURES saturate_seq(s, cs, patterns, subnet_contains, u) == derive(s, claims, patterns, subnet_contains, u) + +#TODO +``` + +To state and prove that, we model the real engine loop directly, then show it +equals `derive`. `derive` is the *set-based* fixed point. Within a `round`, every +claim is evaluated against the same input state: the names and constraints +believed at the start of the round. A fact one claim would grant is not visible +to the others in that round, since they all read the start-of-round snapshot. +(`round`'s body is a `#TODO`, but this semantics is pinned by its contract: every +clause justifies facts against the `s.constraints` / `s.names` passed in, never a +partially-updated state.) The real engine doesn't run that way. +`Derivation::derive` loops passes over the endorsements until one changes +nothing, and within a pass it applies each endorsement against the **running** +state, so a constraint granted by an earlier endorsement is already visible to a +later one in the same pass. + +Three pieces mirror the loop, from the inside out: + +- **`apply_one`**: attempt to derive a fact from a claim within the running state. + The single-claim consequence operator: it reads the gate from `s.constraints` (the + accumulator so far, not a per-round snapshot — this is the running-state + semantics) and inserts that claim's one justified fact. Its contract is the + one-claim specialization of `round`'s: inflationary, bounded, and pinned to + `grants` / `grants_exact_*` so it adds *exactly* the fact `c` justifies and + nothing else. +- **`pass_seq`** — one ordered sweep: fold `apply_one` along `cs` by index `i`. + Because each step feeds the *updated* state into the next, claim order changes + the intermediate states (and how much a single sweep derives) — exactly the + Rust's `for base in bases` over a live-mutating `result`. +- **`saturate_seq`** — iterate sweeps until one adds nothing (`pass_seq(s) == s`), + mirroring the outer `!changed` fixed-point check. + +`apply_one` is the only `#TODO` here (it needs set insertion, so it is +hand-Dafny, pinned by contract); `pass_seq` and `saturate_seq` are **defined** +recursive bodies, so neither can collapse the sequence back into a set — the +order genuinely participates. + +```veri +def apply_one(s: State, c: Claim, patterns: set[PatName], subnet_contains: set[SubnetIp], u: Universe) -> State: + REQUIRES (within(s, u) and claim_fact_in_universe(c, u, patterns)) + ENSURES (s.names <= result.names + and s.ips <= result.ips + and s.constraints <= result.constraints + and s.authz <= result.authz + and result.my_imid == s.my_imid + and within(result, u) + and (result != s ==> size(s) < size(result)) + and grants(c, s.my_imid, s.constraints, s.names, patterns, subnet_contains, result.names, result.ips, result.constraints, result.authz) + and (FORALL nm IN result.names: + (nm in s.names or grants_exact_name(c, nm, s.constraints, s.names, patterns))) + and (FORALL ii IN result.ips: + (ii in s.ips or grants_exact_ip(c, ii, s.constraints, s.names, patterns, subnet_contains))) + and (FORALL k IN result.constraints: + (k in s.constraints or grants_exact_constraint(c, k, s.my_imid, s.constraints, s.names, patterns))) + and (FORALL a IN result.authz: + (a in s.authz or grants_exact_authz(c, a, s.my_imid, s.constraints, s.names, patterns)))) + +#TODO +``` + +`pass_seq` recurses on an index because the DSL has sequence indexing (`cs[i]`) +but not tail slicing (`cs[1..]`); `DECREASES len(cs) - i` is the remaining +suffix. Its ENSURES carries the same structural clauses as `round` — inflationary, +bounded, `my_imid`-preserving, strict-growth-on-change — which is exactly what +`saturate_seq`'s termination measure needs. + +```veri +def pass_seq(s: State, cs: seq[Claim], patterns: set[PatName], subnet_contains: set[SubnetIp], u: Universe, i: nat) -> State: + REQUIRES (within(s, u) and i <= len(cs) and (FORALL c IN cs: claim_fact_in_universe(c, u, patterns))) + ENSURES (s.names <= result.names + and s.ips <= result.ips + and s.constraints <= result.constraints + and s.authz <= result.authz + and result.my_imid == s.my_imid + and within(result, u) + and (result != s ==> size(s) < size(result))) + DECREASES len(cs) - i + return (s if i == len(cs) + else pass_seq(apply_one(s, cs[i], patterns, subnet_contains, u), cs, patterns, subnet_contains, u, i + 1)) +``` + +`saturate_seq` iterates `pass_seq` (started at index 0) to a fixed point, on the +same set-difference universe measure as `derive` — non-negative, and strictly +shrinking on each non-trivial sweep by `pass_seq`'s strict-growth clause. + +```veri +def saturate_seq(s: State, cs: seq[Claim], patterns: set[PatName], subnet_contains: set[SubnetIp], u: Universe) -> State: + REQUIRES (within(s, u) and (FORALL c IN cs: claim_fact_in_universe(c, u, patterns))) + ENSURES within(result, u) + DECREASES len(u.names - s.names) + len(u.ips - s.ips) + len(u.constraints - s.constraints) + len(u.authz - s.authz) + return (s if pass_seq(s, cs, patterns, subnet_contains, u, 0) == s + else saturate_seq(pass_seq(s, cs, patterns, subnet_contains, u, 0), cs, patterns, subnet_contains, u)) +``` + +### Termination + +`derive` reaches its fixed point in a **finite** number of rounds. Every round +only adds facts and stays within a finite ceiling, the **derivable universe** `u` +— a finite set of facts containing everything that could be derived given the +claims observed. So the set of universe facts not yet derived strictly shrinks on +each round that changes the state, and the recursion is well-founded. The +universe, the `within` containment it bounds, and the set-difference measure are +defined under "Derivable universe" above. + +This is well-foundedness, *not* a claim that the `MAX_DERIVATION_ITERATIONS` cap +is never hit. That cap is an anti-DoS cutoff and a long legitimate delegation +chain may exceed it; whether to keep it is a later, separate decision. diff --git a/src/trust_engine/kernel/Cargo.lock b/src/trust_engine/kernel/Cargo.lock new file mode 100644 index 0000000..98aad3c --- /dev/null +++ b/src/trust_engine/kernel/Cargo.lock @@ -0,0 +1,119 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "TrustEngine" +version = "0.1.0" +dependencies = [ + "dafny_runtime", +] + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "dafny_runtime" +version = "0.1.0" +dependencies = [ + "itertools", + "num", + "once_cell", +] + +[[package]] +name = "either" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" diff --git a/src/trust_engine/kernel/Cargo.toml b/src/trust_engine/kernel/Cargo.toml new file mode 100644 index 0000000..648934c --- /dev/null +++ b/src/trust_engine/kernel/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "TrustEngine" +version = "0.1.0" +edition = "2021" + +[dependencies] +dafny_runtime = { path = "runtime" } + +[lib] +path = "src/TrustEngine.rs" + diff --git a/src/trust_engine/kernel/TrustEngine.dfy b/src/trust_engine/kernel/TrustEngine.dfy new file mode 100644 index 0000000..34e5b23 --- /dev/null +++ b/src/trust_engine/kernel/TrustEngine.dfy @@ -0,0 +1,609 @@ +module TrustEngine { + + type Imid = nat + + type Name = nat + + type Pattern = nat + + type Ip = nat + + type Subnet = nat + + datatype Constraint = Constraint(endorser_imids: set, endorser_patterns: set, target_imids: set, target_patterns: set, any_target: bool, permitted_patterns: set, permitted_subnets: set, authority: bool) + + datatype Authz = Authz(source_imids: set, source_patterns: set, destination_imids: set, destination_patterns: set) + + datatype Claim = + | GrantName(endorser: Imid, target_imids: set, target_patterns: set, name: Name) + | GrantIp(endorser: Imid, target_imids: set, target_patterns: set, ip: Ip) + | GrantConstraint(endorser: Imid, target_imids: set, target_patterns: set, constraint: Constraint) + | GrantAuthz(endorser: Imid, target_imids: set, target_patterns: set, authz: Authz) + + datatype NameImid = NameImid(name: Name, imid: Imid) + + datatype IpImid = IpImid(ip: Ip, imid: Imid) + + datatype PatName = PatName(pattern: Pattern, name: Name) + + datatype SubnetIp = SubnetIp(subnet: Subnet, ip: Ip) + + datatype State = State(my_imid: Imid, names: set, ips: set, constraints: set, authz: set) + + function size(s: State): nat + { + |s.names| + |s.ips| + |s.constraints| + |s.authz| + } + + function endorser_ok(ct: Constraint, endorser: Imid, patterns: set, names: set): bool + { + endorser in ct.endorser_imids || (exists nm: NameImid :: nm in names && nm.imid == endorser && (exists p: Pattern :: p in ct.endorser_patterns && PatName(p, nm.name) in patterns)) + } + + function target_ok(ct: Constraint, target: Imid, patterns: set, names: set): bool + { + ct.any_target || target in ct.target_imids || (exists nm: NameImid :: nm in names && nm.imid == target && (exists p: Pattern :: p in ct.target_patterns && PatName(p, nm.name) in patterns)) + } + + function permits_name(ct: Constraint, endorser: Imid, target: Imid, name: Name, patterns: set, names: set): bool + { + endorser_ok(ct, endorser, patterns, names) && target_ok(ct, target, patterns, names) && (exists p: Pattern :: p in ct.permitted_patterns && PatName(p, name) in patterns) + } + + function permits_ip(ct: Constraint, endorser: Imid, target: Imid, ip: Ip, subnet_contains: set, patterns: set, names: set): bool + { + endorser_ok(ct, endorser, patterns, names) && target_ok(ct, target, patterns, names) && (exists sn: Subnet :: sn in ct.permitted_subnets && SubnetIp(sn, ip) in subnet_contains) + } + + function authorizes(ct: Constraint, endorser: Imid, target: Imid, patterns: set, names: set): bool + { + endorser_ok(ct, endorser, patterns, names) && target_ok(ct, target, patterns, names) && ct.authority + } + + function resolves_target(target_imids: set, target_patterns: set, t: Imid, patterns: set, names: set): bool + { + t in target_imids || (exists nm: NameImid :: nm in names && nm.imid == t && (exists p: Pattern :: p in target_patterns && PatName(p, nm.name) in patterns)) + } + + function grants_name(endorser: Imid, tis: set, tps: set, name: Name, constraints: set, names: set, patterns: set, result_names: set): bool + { + (forall t: Imid :: t in tis ==> (exists ct: Constraint :: ct in constraints && permits_name(ct, endorser, t, name, patterns, names)) ==> NameImid(name, t) in result_names) && (forall nm: NameImid :: nm in names ==> (exists p: Pattern :: p in tps && PatName(p, nm.name) in patterns) && (exists ct: Constraint :: ct in constraints && permits_name(ct, endorser, nm.imid, name, patterns, names)) ==> NameImid(name, nm.imid) in result_names) + } + + function grants_ip(endorser: Imid, tis: set, tps: set, ip: Ip, constraints: set, names: set, patterns: set, subnet_contains: set, result_ips: set): bool + { + (forall t: Imid :: t in tis ==> (exists ct: Constraint :: ct in constraints && permits_ip(ct, endorser, t, ip, subnet_contains, patterns, names)) ==> IpImid(ip, t) in result_ips) && (forall nm: NameImid :: nm in names ==> (exists p: Pattern :: p in tps && PatName(p, nm.name) in patterns) && (exists ct: Constraint :: ct in constraints && permits_ip(ct, endorser, nm.imid, ip, subnet_contains, patterns, names)) ==> IpImid(ip, nm.imid) in result_ips) + } + + function grants(c: Claim, my_imid: Imid, constraints: set, names: set, patterns: set, subnet_contains: set, result_names: set, result_ips: set, result_constraints: set, result_authz: set): bool + { + match c { + case GrantName(endorser, tis, tps, name) => grants_name(endorser, tis, tps, name, constraints, names, patterns, result_names) + case GrantIp(endorser, tis, tps, ip) => grants_ip(endorser, tis, tps, ip, constraints, names, patterns, subnet_contains, result_ips) + case GrantConstraint(endorser, tis, tps, k) => resolves_target(tis, tps, my_imid, patterns, names) && (exists ct: Constraint :: ct in constraints && authorizes(ct, endorser, my_imid, patterns, names)) && (!k.authority || endorser == my_imid) ==> k in result_constraints + case GrantAuthz(endorser, tis, tps, a) => resolves_target(tis, tps, my_imid, patterns, names) && (exists ct: Constraint :: ct in constraints && authorizes(ct, endorser, my_imid, patterns, names)) ==> a in result_authz + } + } + + function grants_exact_name(c: Claim, nm: NameImid, constraints: set, names: set, patterns: set): bool + { + match c { + case GrantName(endorser, tis, tps, name) => name == nm.name && resolves_target(tis, tps, nm.imid, patterns, names) && (exists ct: Constraint :: ct in constraints && permits_name(ct, endorser, nm.imid, name, patterns, names)) + case GrantIp(_, _, _, _) => false + case GrantConstraint(_, _, _, _) => false + case GrantAuthz(_, _, _, _) => false + } + } + + function grants_exact_ip(c: Claim, ii: IpImid, constraints: set, names: set, patterns: set, subnet_contains: set): bool + { + match c { + case GrantName(_, _, _, _) => false + case GrantIp(endorser, tis, tps, ip) => ip == ii.ip && resolves_target(tis, tps, ii.imid, patterns, names) && (exists ct: Constraint :: ct in constraints && permits_ip(ct, endorser, ii.imid, ip, subnet_contains, patterns, names)) + case GrantConstraint(_, _, _, _) => false + case GrantAuthz(_, _, _, _) => false + } + } + + function grants_exact_constraint(c: Claim, k: Constraint, my_imid: Imid, constraints: set, names: set, patterns: set): bool + { + match c { + case GrantName(_, _, _, _) => false + case GrantIp(_, _, _, _) => false + case GrantConstraint(endorser, tis, tps, kc) => kc == k && resolves_target(tis, tps, my_imid, patterns, names) && (exists ct: Constraint :: ct in constraints && authorizes(ct, endorser, my_imid, patterns, names)) && (!kc.authority || endorser == my_imid) + case GrantAuthz(_, _, _, _) => false + } + } + + function grants_exact_authz(c: Claim, a: Authz, my_imid: Imid, constraints: set, names: set, patterns: set): bool + { + match c { + case GrantName(_, _, _, _) => false + case GrantIp(_, _, _, _) => false + case GrantConstraint(_, _, _, _) => false + case GrantAuthz(endorser, tis, tps, ka) => ka == a && resolves_target(tis, tps, my_imid, patterns, names) && (exists ct: Constraint :: ct in constraints && authorizes(ct, endorser, my_imid, patterns, names)) + } + } + + datatype Universe = Universe(names: set, ips: set, constraints: set, authz: set) + + function name_in_universe(tis: set, tps: set, name: Name, u: Universe, patterns: set): bool + { + (forall t: Imid :: t in tis ==> NameImid(name, t) in u.names) && (forall nm: NameImid :: nm in u.names ==> (exists p: Pattern :: p in tps && PatName(p, nm.name) in patterns) ==> NameImid(name, nm.imid) in u.names) + } + + function ip_in_universe(tis: set, tps: set, ip: Ip, u: Universe, patterns: set): bool + { + (forall t: Imid :: t in tis ==> IpImid(ip, t) in u.ips) && (forall nm: NameImid :: nm in u.names ==> (exists p: Pattern :: p in tps && PatName(p, nm.name) in patterns) ==> IpImid(ip, nm.imid) in u.ips) + } + + function claim_fact_in_universe(c: Claim, u: Universe, patterns: set): bool + { + match c { + case GrantName(endorser, tis, tps, name) => name_in_universe(tis, tps, name, u, patterns) + case GrantIp(endorser, tis, tps, ip) => ip_in_universe(tis, tps, ip, u, patterns) + case GrantConstraint(endorser, tis, tps, k) => k in u.constraints + case GrantAuthz(endorser, tis, tps, a) => a in u.authz + } + } + + function within(s: State, u: Universe): bool + { + s.names <= u.names && s.ips <= u.ips && s.constraints <= u.constraints && s.authz <= u.authz + } + + function fits(claims: set, u: Universe, patterns: set): bool + { + (forall c: Claim :: c in claims ==> claim_fact_in_universe(c, u, patterns)) + } + + function derive(s: State, claims: set, patterns: set, subnet_contains: set, u: Universe): (result: State) + requires within(s, u) && fits(claims, u, patterns) + ensures within(result, u) + decreases |u.names - s.names| + |u.ips - s.ips| + |u.constraints - s.constraints| + |u.authz - s.authz| + { + if round(s, claims, patterns, subnet_contains, u) == s then s else derive(round(s, claims, patterns, subnet_contains, u), claims, patterns, subnet_contains, u) + } + + function names_of(s: State): set + { + s.names + } + + function ips_of(s: State): set + { + s.ips + } + + function constraints_of(s: State): set + { + s.constraints + } + + function authz_of(s: State): set + { + s.authz + } + + function pass_seq(s: State, cs: seq, patterns: set, subnet_contains: set, u: Universe, i: nat): (result: State) + requires within(s, u) && i <= |cs| && (forall c: Claim :: c in cs ==> claim_fact_in_universe(c, u, patterns)) + ensures s.names <= result.names && s.ips <= result.ips && s.constraints <= result.constraints && s.authz <= result.authz && result.my_imid == s.my_imid && within(result, u) && (result != s ==> size(s) < size(result)) + decreases |cs| - i + { + if i == |cs| then s else pass_seq(apply_one(s, cs[i], patterns, subnet_contains, u), cs, patterns, subnet_contains, u, i + 1) + } + + function saturate_seq(s: State, cs: seq, patterns: set, subnet_contains: set, u: Universe): (result: State) + requires within(s, u) && (forall c: Claim :: c in cs ==> claim_fact_in_universe(c, u, patterns)) + ensures within(result, u) + decreases |u.names - s.names| + |u.ips - s.ips| + |u.constraints - s.constraints| + |u.authz - s.authz| + { + if pass_seq(s, cs, patterns, subnet_contains, u, 0) == s then s else saturate_seq(pass_seq(s, cs, patterns, subnet_contains, u, 0), cs, patterns, subnet_contains, u) + } + + +lemma SubsetCard(a: set, b: set) + requires a <= b + ensures |a| <= |b| + ensures a != b ==> |a| < |b| + decreases |b| +{ + if a != b { + var x :| x in b && x !in a; + SubsetCard(a, b - {x}); + } +} + +predicate subState(a: State, b: State) +{ + a.names <= b.names && a.ips <= b.ips && a.constraints <= b.constraints && a.authz <= b.authz +} + +lemma StateAntisym(a: State, b: State) + requires subState(a, b) && subState(b, a) && a.my_imid == b.my_imid + ensures a == b +{ +} + +lemma GrantsExactNameMono(c: Claim, nm: NameImid, C1: set, C2: set, N1: set, N2: set, patterns: set) + requires C1 <= C2 && N1 <= N2 + requires grants_exact_name(c, nm, C1, N1, patterns) + ensures grants_exact_name(c, nm, C2, N2, patterns) +{ +} + +lemma GrantsExactIpMono(c: Claim, ii: IpImid, C1: set, C2: set, N1: set, N2: set, patterns: set, subnet_contains: set) + requires C1 <= C2 && N1 <= N2 + requires grants_exact_ip(c, ii, C1, N1, patterns, subnet_contains) + ensures grants_exact_ip(c, ii, C2, N2, patterns, subnet_contains) +{ +} + +lemma GrantsExactConstraintMono(c: Claim, k: Constraint, my_imid: Imid, C1: set, C2: set, N1: set, N2: set, patterns: set) + requires C1 <= C2 && N1 <= N2 + requires grants_exact_constraint(c, k, my_imid, C1, N1, patterns) + ensures grants_exact_constraint(c, k, my_imid, C2, N2, patterns) +{ +} + +lemma GrantsExactAuthzMono(c: Claim, a: Authz, my_imid: Imid, C1: set, C2: set, N1: set, N2: set, patterns: set) + requires C1 <= C2 && N1 <= N2 + requires grants_exact_authz(c, a, my_imid, C1, N1, patterns) + ensures grants_exact_authz(c, a, my_imid, C2, N2, patterns) +{ +} + +lemma RoundMono(s1: State, s2: State, claims1: set, claims2: set, patterns: set, subnet_contains: set, u: Universe) + requires within(s1, u) && within(s2, u) && fits(claims1, u, patterns) && fits(claims2, u, patterns) + requires subState(s1, s2) && s1.my_imid == s2.my_imid && claims1 <= claims2 + ensures subState(round(s1, claims1, patterns, subnet_contains, u), round(s2, claims2, patterns, subnet_contains, u)) +{ + forall nm | nm in round(s1, claims1, patterns, subnet_contains, u).names + ensures nm in round(s2, claims2, patterns, subnet_contains, u).names + { + if nm !in s1.names { + var c :| c in claims1 && grants_exact_name(c, nm, s1.constraints, s1.names, patterns); + GrantsExactNameMono(c, nm, s1.constraints, s2.constraints, s1.names, s2.names, patterns); + } + } + forall ii | ii in round(s1, claims1, patterns, subnet_contains, u).ips + ensures ii in round(s2, claims2, patterns, subnet_contains, u).ips + { + if ii !in s1.ips { + var c :| c in claims1 && grants_exact_ip(c, ii, s1.constraints, s1.names, patterns, subnet_contains); + GrantsExactIpMono(c, ii, s1.constraints, s2.constraints, s1.names, s2.names, patterns, subnet_contains); + } + } + forall k | k in round(s1, claims1, patterns, subnet_contains, u).constraints + ensures k in round(s2, claims2, patterns, subnet_contains, u).constraints + { + if k !in s1.constraints { + var c :| c in claims1 && grants_exact_constraint(c, k, s1.my_imid, s1.constraints, s1.names, patterns); + GrantsExactConstraintMono(c, k, s1.my_imid, s1.constraints, s2.constraints, s1.names, s2.names, patterns); + } + } + forall a | a in round(s1, claims1, patterns, subnet_contains, u).authz + ensures a in round(s2, claims2, patterns, subnet_contains, u).authz + { + if a !in s1.authz { + var c :| c in claims1 && grants_exact_authz(c, a, s1.my_imid, s1.constraints, s1.names, patterns); + GrantsExactAuthzMono(c, a, s1.my_imid, s1.constraints, s2.constraints, s1.names, s2.names, patterns); + } + } +} + +lemma ApplyOneMonoState(s1: State, s2: State, c: Claim, patterns: set, subnet_contains: set, u: Universe) + requires within(s1, u) && within(s2, u) && claim_fact_in_universe(c, u, patterns) + requires subState(s1, s2) && s1.my_imid == s2.my_imid + ensures subState(apply_one(s1, c, patterns, subnet_contains, u), apply_one(s2, c, patterns, subnet_contains, u)) +{ + forall nm | nm in apply_one(s1, c, patterns, subnet_contains, u).names + ensures nm in apply_one(s2, c, patterns, subnet_contains, u).names + { + if nm !in s1.names { + GrantsExactNameMono(c, nm, s1.constraints, s2.constraints, s1.names, s2.names, patterns); + } + } + forall ii | ii in apply_one(s1, c, patterns, subnet_contains, u).ips + ensures ii in apply_one(s2, c, patterns, subnet_contains, u).ips + { + if ii !in s1.ips { + GrantsExactIpMono(c, ii, s1.constraints, s2.constraints, s1.names, s2.names, patterns, subnet_contains); + } + } + forall k | k in apply_one(s1, c, patterns, subnet_contains, u).constraints + ensures k in apply_one(s2, c, patterns, subnet_contains, u).constraints + { + if k !in s1.constraints { + GrantsExactConstraintMono(c, k, s1.my_imid, s1.constraints, s2.constraints, s1.names, s2.names, patterns); + } + } + forall a | a in apply_one(s1, c, patterns, subnet_contains, u).authz + ensures a in apply_one(s2, c, patterns, subnet_contains, u).authz + { + if a !in s1.authz { + GrantsExactAuthzMono(c, a, s1.my_imid, s1.constraints, s2.constraints, s1.names, s2.names, patterns); + } + } +} + +lemma DeriveInflationary(s: State, claims: set, patterns: set, subnet_contains: set, u: Universe) + requires within(s, u) && fits(claims, u, patterns) + ensures subState(s, derive(s, claims, patterns, subnet_contains, u)) && derive(s, claims, patterns, subnet_contains, u).my_imid == s.my_imid + decreases |u.names - s.names| + |u.ips - s.ips| + |u.constraints - s.constraints| + |u.authz - s.authz| +{ + if round(s, claims, patterns, subnet_contains, u) == s { + } else { + DeriveInflationary(round(s, claims, patterns, subnet_contains, u), claims, patterns, subnet_contains, u); + } +} + +lemma DeriveFixpoint(s: State, claims: set, patterns: set, subnet_contains: set, u: Universe) + requires within(s, u) && fits(claims, u, patterns) + ensures round(derive(s, claims, patterns, subnet_contains, u), claims, patterns, subnet_contains, u) == derive(s, claims, patterns, subnet_contains, u) + decreases |u.names - s.names| + |u.ips - s.ips| + |u.constraints - s.constraints| + |u.authz - s.authz| +{ + if round(s, claims, patterns, subnet_contains, u) == s { + } else { + DeriveFixpoint(round(s, claims, patterns, subnet_contains, u), claims, patterns, subnet_contains, u); + } +} + +lemma DeriveLeast(s: State, F: State, claims: set, patterns: set, subnet_contains: set, u: Universe) + requires within(s, u) && within(F, u) && fits(claims, u, patterns) + requires subState(s, F) && s.my_imid == F.my_imid + requires round(F, claims, patterns, subnet_contains, u) == F + ensures subState(derive(s, claims, patterns, subnet_contains, u), F) + decreases |u.names - s.names| + |u.ips - s.ips| + |u.constraints - s.constraints| + |u.authz - s.authz| +{ + if round(s, claims, patterns, subnet_contains, u) == s { + } else { + RoundMono(s, F, claims, claims, patterns, subnet_contains, u); + DeriveLeast(round(s, claims, patterns, subnet_contains, u), F, claims, patterns, subnet_contains, u); + } +} + +lemma PassSeqMonoState(s1: State, s2: State, cs: seq, patterns: set, subnet_contains: set, u: Universe, i: nat) + requires within(s1, u) && within(s2, u) && i <= |cs| && (forall c: Claim :: c in cs ==> claim_fact_in_universe(c, u, patterns)) + requires subState(s1, s2) && s1.my_imid == s2.my_imid + ensures subState(pass_seq(s1, cs, patterns, subnet_contains, u, i), pass_seq(s2, cs, patterns, subnet_contains, u, i)) + decreases |cs| - i +{ + if i < |cs| { + ApplyOneMonoState(s1, s2, cs[i], patterns, subnet_contains, u); + PassSeqMonoState(apply_one(s1, cs[i], patterns, subnet_contains, u), apply_one(s2, cs[i], patterns, subnet_contains, u), cs, patterns, subnet_contains, u, i + 1); + } +} + +lemma SaturateInflationary(s: State, cs: seq, patterns: set, subnet_contains: set, u: Universe) + requires within(s, u) && (forall c: Claim :: c in cs ==> claim_fact_in_universe(c, u, patterns)) + ensures subState(s, saturate_seq(s, cs, patterns, subnet_contains, u)) && saturate_seq(s, cs, patterns, subnet_contains, u).my_imid == s.my_imid + decreases |u.names - s.names| + |u.ips - s.ips| + |u.constraints - s.constraints| + |u.authz - s.authz| +{ + if pass_seq(s, cs, patterns, subnet_contains, u, 0) == s { + } else { + SaturateInflationary(pass_seq(s, cs, patterns, subnet_contains, u, 0), cs, patterns, subnet_contains, u); + } +} + +lemma SaturateFixpoint(s: State, cs: seq, patterns: set, subnet_contains: set, u: Universe) + requires within(s, u) && (forall c: Claim :: c in cs ==> claim_fact_in_universe(c, u, patterns)) + ensures pass_seq(saturate_seq(s, cs, patterns, subnet_contains, u), cs, patterns, subnet_contains, u, 0) == saturate_seq(s, cs, patterns, subnet_contains, u) + decreases |u.names - s.names| + |u.ips - s.ips| + |u.constraints - s.constraints| + |u.authz - s.authz| +{ + if pass_seq(s, cs, patterns, subnet_contains, u, 0) == s { + } else { + SaturateFixpoint(pass_seq(s, cs, patterns, subnet_contains, u, 0), cs, patterns, subnet_contains, u); + } +} + +lemma SaturateLeast(s: State, F: State, cs: seq, patterns: set, subnet_contains: set, u: Universe) + requires within(s, u) && within(F, u) && (forall c: Claim :: c in cs ==> claim_fact_in_universe(c, u, patterns)) + requires subState(s, F) && s.my_imid == F.my_imid + requires pass_seq(F, cs, patterns, subnet_contains, u, 0) == F + ensures subState(saturate_seq(s, cs, patterns, subnet_contains, u), F) + decreases |u.names - s.names| + |u.ips - s.ips| + |u.constraints - s.constraints| + |u.authz - s.authz| +{ + if pass_seq(s, cs, patterns, subnet_contains, u, 0) == s { + } else { + PassSeqMonoState(s, F, cs, patterns, subnet_contains, u, 0); + SaturateLeast(pass_seq(s, cs, patterns, subnet_contains, u, 0), F, cs, patterns, subnet_contains, u); + } +} + +lemma PassCollapse(s: State, cs: seq, patterns: set, subnet_contains: set, u: Universe, i: nat) + requires within(s, u) && i <= |cs| && (forall c: Claim :: c in cs ==> claim_fact_in_universe(c, u, patterns)) + requires pass_seq(s, cs, patterns, subnet_contains, u, i) == s + ensures forall j: nat :: i <= j < |cs| ==> apply_one(s, cs[j], patterns, subnet_contains, u) == s + decreases |cs| - i +{ + if i < |cs| { + assert pass_seq(apply_one(s, cs[i], patterns, subnet_contains, u), cs, patterns, subnet_contains, u, i + 1) == s; + assert subState(apply_one(s, cs[i], patterns, subnet_contains, u), s); + StateAntisym(apply_one(s, cs[i], patterns, subnet_contains, u), s); + assert pass_seq(s, cs, patterns, subnet_contains, u, i + 1) == s; + PassCollapse(s, cs, patterns, subnet_contains, u, i + 1); + } +} + +lemma ApplyOneNoGrowth(s: State, c: Claim, claims: set, patterns: set, subnet_contains: set, u: Universe) + requires within(s, u) && fits(claims, u, patterns) && c in claims + requires round(s, claims, patterns, subnet_contains, u) == s + ensures apply_one(s, c, patterns, subnet_contains, u) == s +{ + assert claim_fact_in_universe(c, u, patterns); + forall nm: NameImid | nm in apply_one(s, c, patterns, subnet_contains, u).names + ensures nm in s.names + { + if nm !in s.names { + assert nm in round(s, claims, patterns, subnet_contains, u).names; + } + } + forall ii: IpImid | ii in apply_one(s, c, patterns, subnet_contains, u).ips + ensures ii in s.ips + { + if ii !in s.ips { + assert ii in round(s, claims, patterns, subnet_contains, u).ips; + } + } + forall k: Constraint | k in apply_one(s, c, patterns, subnet_contains, u).constraints + ensures k in s.constraints + { + if k !in s.constraints { + assert k in round(s, claims, patterns, subnet_contains, u).constraints; + } + } + forall a: Authz | a in apply_one(s, c, patterns, subnet_contains, u).authz + ensures a in s.authz + { + if a !in s.authz { + assert a in round(s, claims, patterns, subnet_contains, u).authz; + } + } + StateAntisym(apply_one(s, c, patterns, subnet_contains, u), s); +} + +lemma PassStaysFix(s: State, cs: seq, claims: set, patterns: set, subnet_contains: set, u: Universe, i: nat) + requires within(s, u) && fits(claims, u, patterns) && i <= |cs| + requires (forall c: Claim :: c in cs ==> c in claims) + requires round(s, claims, patterns, subnet_contains, u) == s + ensures pass_seq(s, cs, patterns, subnet_contains, u, i) == s + decreases |cs| - i +{ + if i < |cs| { + assert cs[i] in cs; + ApplyOneNoGrowth(s, cs[i], claims, patterns, subnet_contains, u); + PassStaysFix(s, cs, claims, patterns, subnet_contains, u, i + 1); + } +} + +lemma RoundFixImpliesPassFix(s: State, cs: seq, claims: set, patterns: set, subnet_contains: set, u: Universe) + requires within(s, u) && fits(claims, u, patterns) + requires (forall c: Claim :: c in cs ==> c in claims) && (forall c: Claim :: c in claims ==> c in cs) + requires round(s, claims, patterns, subnet_contains, u) == s + ensures pass_seq(s, cs, patterns, subnet_contains, u, 0) == s +{ + PassStaysFix(s, cs, claims, patterns, subnet_contains, u, 0); +} + +lemma PassFixImpliesRoundFix(s: State, cs: seq, claims: set, patterns: set, subnet_contains: set, u: Universe) + requires within(s, u) && fits(claims, u, patterns) + requires (forall c: Claim :: c in cs ==> c in claims) && (forall c: Claim :: c in claims ==> c in cs) + requires pass_seq(s, cs, patterns, subnet_contains, u, 0) == s + ensures round(s, claims, patterns, subnet_contains, u) == s +{ + PassCollapse(s, cs, patterns, subnet_contains, u, 0); + forall nm: NameImid | nm in round(s, claims, patterns, subnet_contains, u).names + ensures nm in s.names + { + if nm !in s.names { + var c :| c in claims && grants_exact_name(c, nm, s.constraints, s.names, patterns); + assert c in cs; + var j: nat :| 0 <= j < |cs| && cs[j] == c; + assert apply_one(s, c, patterns, subnet_contains, u) == s; + assert nm in apply_one(s, c, patterns, subnet_contains, u).names; + } + } + forall ii: IpImid | ii in round(s, claims, patterns, subnet_contains, u).ips + ensures ii in s.ips + { + if ii !in s.ips { + var c :| c in claims && grants_exact_ip(c, ii, s.constraints, s.names, patterns, subnet_contains); + assert c in cs; + var j: nat :| 0 <= j < |cs| && cs[j] == c; + assert apply_one(s, c, patterns, subnet_contains, u) == s; + assert ii in apply_one(s, c, patterns, subnet_contains, u).ips; + } + } + forall k: Constraint | k in round(s, claims, patterns, subnet_contains, u).constraints + ensures k in s.constraints + { + if k !in s.constraints { + var c :| c in claims && grants_exact_constraint(c, k, s.my_imid, s.constraints, s.names, patterns); + assert c in cs; + var j: nat :| 0 <= j < |cs| && cs[j] == c; + assert apply_one(s, c, patterns, subnet_contains, u) == s; + assert k in apply_one(s, c, patterns, subnet_contains, u).constraints; + } + } + forall a: Authz | a in round(s, claims, patterns, subnet_contains, u).authz + ensures a in s.authz + { + if a !in s.authz { + var c :| c in claims && grants_exact_authz(c, a, s.my_imid, s.constraints, s.names, patterns); + assert c in cs; + var j: nat :| 0 <= j < |cs| && cs[j] == c; + assert apply_one(s, c, patterns, subnet_contains, u) == s; + assert a in apply_one(s, c, patterns, subnet_contains, u).authz; + } + } + StateAntisym(round(s, claims, patterns, subnet_contains, u), s); +} + +function round(s: State, claims: set, patterns: set, subnet_contains: set, u: Universe): (result: State) + requires within(s, u) && fits(claims, u, patterns) + ensures s.names <= result.names && s.ips <= result.ips && s.constraints <= result.constraints && s.authz <= result.authz && within(result, u) && (result != s ==> size(s) < size(result)) && (forall c: Claim :: c in claims ==> grants(c, s.my_imid, s.constraints, s.names, patterns, subnet_contains, result.names, result.ips, result.constraints, result.authz)) && (forall nm: NameImid :: nm in result.names ==> nm in s.names || (exists c: Claim :: c in claims && grants_exact_name(c, nm, s.constraints, s.names, patterns))) && (forall ii: IpImid :: ii in result.ips ==> ii in s.ips || (exists c: Claim :: c in claims && grants_exact_ip(c, ii, s.constraints, s.names, patterns, subnet_contains))) && (forall k: Constraint :: k in result.constraints ==> k in s.constraints || (exists c: Claim :: c in claims && grants_exact_constraint(c, k, s.my_imid, s.constraints, s.names, patterns))) && (forall a: Authz :: a in result.authz ==> a in s.authz || (exists c: Claim :: c in claims && grants_exact_authz(c, a, s.my_imid, s.constraints, s.names, patterns))) +{ + assert (forall a: State, b: State :: a.my_imid == b.my_imid && a.names <= b.names && a.ips <= b.ips && a.constraints <= b.constraints && a.authz <= b.authz && a != b ==> size(a) < size(b)) by { + forall a: State, b: State | a.my_imid == b.my_imid && a.names <= b.names && a.ips <= b.ips && a.constraints <= b.constraints && a.authz <= b.authz && a != b + ensures size(a) < size(b) + { + SubsetCard(a.names, b.names); + SubsetCard(a.ips, b.ips); + SubsetCard(a.constraints, b.constraints); + SubsetCard(a.authz, b.authz); + assert a.names != b.names || a.ips != b.ips || a.constraints != b.constraints || a.authz != b.authz; + } + } + State(s.my_imid, + s.names + (set nm: NameImid | nm in u.names && (exists c: Claim :: c in claims && grants_exact_name(c, nm, s.constraints, s.names, patterns))), + s.ips + (set ii: IpImid | ii in u.ips && (exists c: Claim :: c in claims && grants_exact_ip(c, ii, s.constraints, s.names, patterns, subnet_contains))), + s.constraints + (set k: Constraint | k in u.constraints && (exists c: Claim :: c in claims && grants_exact_constraint(c, k, s.my_imid, s.constraints, s.names, patterns))), + s.authz + (set a: Authz | a in u.authz && (exists c: Claim :: c in claims && grants_exact_authz(c, a, s.my_imid, s.constraints, s.names, patterns)))) +} + +lemma monotone(s: State, claims1: set, claims2: set, patterns: set, subnet_contains: set, u: Universe) + requires within(s, u) && fits(claims2, u, patterns) && claims1 <= claims2 + ensures names_of(derive(s, claims1, patterns, subnet_contains, u)) <= names_of(derive(s, claims2, patterns, subnet_contains, u)) && ips_of(derive(s, claims1, patterns, subnet_contains, u)) <= ips_of(derive(s, claims2, patterns, subnet_contains, u)) && constraints_of(derive(s, claims1, patterns, subnet_contains, u)) <= constraints_of(derive(s, claims2, patterns, subnet_contains, u)) && authz_of(derive(s, claims1, patterns, subnet_contains, u)) <= authz_of(derive(s, claims2, patterns, subnet_contains, u)) +{ + var F := derive(s, claims2, patterns, subnet_contains, u); + DeriveInflationary(s, claims2, patterns, subnet_contains, u); + DeriveFixpoint(s, claims2, patterns, subnet_contains, u); + assert round(F, claims2, patterns, subnet_contains, u) == F; + RoundMono(F, F, claims1, claims2, patterns, subnet_contains, u); + assert subState(round(F, claims1, patterns, subnet_contains, u), F); + assert subState(F, round(F, claims1, patterns, subnet_contains, u)); + StateAntisym(round(F, claims1, patterns, subnet_contains, u), F); + assert round(F, claims1, patterns, subnet_contains, u) == F; + DeriveLeast(s, F, claims1, patterns, subnet_contains, u); +} + +function apply_one(s: State, c: Claim, patterns: set, subnet_contains: set, u: Universe): (result: State) + requires within(s, u) && claim_fact_in_universe(c, u, patterns) + ensures s.names <= result.names && s.ips <= result.ips && s.constraints <= result.constraints && s.authz <= result.authz && result.my_imid == s.my_imid && within(result, u) && (result != s ==> size(s) < size(result)) && grants(c, s.my_imid, s.constraints, s.names, patterns, subnet_contains, result.names, result.ips, result.constraints, result.authz) && (forall nm: NameImid :: nm in result.names ==> nm in s.names || grants_exact_name(c, nm, s.constraints, s.names, patterns)) && (forall ii: IpImid :: ii in result.ips ==> ii in s.ips || grants_exact_ip(c, ii, s.constraints, s.names, patterns, subnet_contains)) && (forall k: Constraint :: k in result.constraints ==> k in s.constraints || grants_exact_constraint(c, k, s.my_imid, s.constraints, s.names, patterns)) && (forall a: Authz :: a in result.authz ==> a in s.authz || grants_exact_authz(c, a, s.my_imid, s.constraints, s.names, patterns)) +{ + State(s.my_imid, + s.names + (set nm: NameImid | nm in u.names && grants_exact_name(c, nm, s.constraints, s.names, patterns)), + s.ips + (set ii: IpImid | ii in u.ips && grants_exact_ip(c, ii, s.constraints, s.names, patterns, subnet_contains)), + s.constraints + (set k: Constraint | k in u.constraints && grants_exact_constraint(c, k, s.my_imid, s.constraints, s.names, patterns)), + s.authz + (set a: Authz | a in u.authz && grants_exact_authz(c, a, s.my_imid, s.constraints, s.names, patterns))) +} + +lemma commutative(s: State, cs: seq, claims: set, patterns: set, subnet_contains: set, u: Universe) + requires within(s, u) && fits(claims, u, patterns) && (forall c: Claim :: c in cs ==> c in claims) && (forall c: Claim :: c in claims ==> c in cs) + ensures saturate_seq(s, cs, patterns, subnet_contains, u) == derive(s, claims, patterns, subnet_contains, u) +{ + assert forall c: Claim :: c in cs ==> claim_fact_in_universe(c, u, patterns); + var P := saturate_seq(s, cs, patterns, subnet_contains, u); + var D := derive(s, claims, patterns, subnet_contains, u); + SaturateInflationary(s, cs, patterns, subnet_contains, u); + SaturateFixpoint(s, cs, patterns, subnet_contains, u); + DeriveInflationary(s, claims, patterns, subnet_contains, u); + DeriveFixpoint(s, claims, patterns, subnet_contains, u); + RoundFixImpliesPassFix(D, cs, claims, patterns, subnet_contains, u); + SaturateLeast(s, D, cs, patterns, subnet_contains, u); + PassFixImpliesRoundFix(P, cs, claims, patterns, subnet_contains, u); + DeriveLeast(s, P, claims, patterns, subnet_contains, u); + StateAntisym(P, D); +} +} \ No newline at end of file diff --git a/src/trust_engine/kernel/runtime/Cargo.lock b/src/trust_engine/kernel/runtime/Cargo.lock new file mode 100644 index 0000000..f94c7f1 --- /dev/null +++ b/src/trust_engine/kernel/runtime/Cargo.lock @@ -0,0 +1,112 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "dafny_runtime" +version = "0.1.0" +dependencies = [ + "itertools", + "num", + "once_cell", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" diff --git a/src/trust_engine/kernel/runtime/Cargo.toml b/src/trust_engine/kernel/runtime/Cargo.toml new file mode 100644 index 0000000..5010231 --- /dev/null +++ b/src/trust_engine/kernel/runtime/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "dafny_runtime" +version = "0.1.0" +edition = "2021" + +[dependencies] +once_cell = "1.21.3" +num = "0.4.3" +itertools = "0.14.0" + +[features] +# Use `dafny translate rs --rust-sync --include-runtime file.dfy` +# to compile to code where values can be sent safely through threads +# This will include the runtime with the sync feature + +# Use --features small-int to make DafnyInt use i128 instead of num::BigInt +sync = [] +small-int = [] diff --git a/src/trust_engine/kernel/runtime/Makefile b/src/trust_engine/kernel/runtime/Makefile new file mode 100644 index 0000000..2e9fd4e --- /dev/null +++ b/src/trust_engine/kernel/runtime/Makefile @@ -0,0 +1,28 @@ + +# Invoking the CLI this way just to stay platform-independent +DAFNY = dotnet run --project ../../Dafny --no-build -- + +GENERATED_SYSTEM_MODULE_SOURCE=../obj/systemModulePopulator-rust/src/systemModulePopulator.rs +GENERATED_SYSTEM_MODULE_TARGET=src/system/mod.rs + +all: check-system-module test + +build-system-module: + $(DAFNY) translate rs --no-verify --enforce-determinism --use-basename-for-filename --optimize-erasable-datatype-wrapper:false --system-module:OmitAllOtherModules ../systemModulePopulator.dfy --output:../obj/systemModulePopulator + python -c "import sys; data = sys.stdin.read(); sys.stdout.write(data.replace('::dafny_runtime', 'crate').replace('pub use ::std::rc::Rc;', '#[cfg(feature = \"sync\")] pub use ::std::sync::{Arc as Rc}; #[cfg(not(feature = \"sync\"))] pub use ::std::rc::Rc;'))" < $(GENERATED_SYSTEM_MODULE_SOURCE) > $(GENERATED_SYSTEM_MODULE_SOURCE).tmp && mv $(GENERATED_SYSTEM_MODULE_SOURCE).tmp $(GENERATED_SYSTEM_MODULE_SOURCE) + +check-system-module: build-system-module + diff $(GENERATED_SYSTEM_MODULE_SOURCE) $(GENERATED_SYSTEM_MODULE_TARGET) + +update-system-module: build-system-module + cp $(GENERATED_SYSTEM_MODULE_SOURCE) $(GENERATED_SYSTEM_MODULE_TARGET) + +test: + cargo test + cargo test --features sync + cargo test --features small-int + cargo test --features sync,small-int + (cd ../../DafnyRuntime.Tests/DafnyRuntimeRustTest; cargo test) + (cd ../../DafnyRuntime.Tests/DafnyRuntimeRustTest; cargo test --features sync) + (cd ../../DafnyRuntime.Tests/DafnyRuntimeRustTest; cargo test --features small-int) + (cd ../../DafnyRuntime.Tests/DafnyRuntimeRustTest; cargo test --features sync,small-int) diff --git a/src/trust_engine/kernel/runtime/src/big_int.rs b/src/trust_engine/kernel/runtime/src/big_int.rs new file mode 100644 index 0000000..859cd77 --- /dev/null +++ b/src/trust_engine/kernel/runtime/src/big_int.rs @@ -0,0 +1,420 @@ +use crate::DafnyPrint; +use crate::Rc; +use num::bigint::BigInt; +use num::rational::BigRational; +use num::FromPrimitive; +use num::ToPrimitive; +use num::{bigint::ParseBigIntError, Integer, Num, One, Signed, Zero}; +use std::{ + clone::Clone, + cmp::Ordering, + convert::From, + fmt::Formatter, + hash::Hash, + ops::{Add, Div, Mul, Neg, Rem, Sub}, +}; + +// Zero-cost abstraction over a Rc + +#[derive(Clone)] +pub struct DafnyInt { + data: Rc, +} + +impl DafnyInt { + pub fn new(data: Rc) -> DafnyInt { + DafnyInt { data } + } + pub fn strong_count(&self) -> usize { + Rc::strong_count(&self.data) + } +} + +impl AsRef for DafnyInt { + fn as_ref(&self) -> &BigInt { + &self.data + } +} + +impl Default for DafnyInt { + fn default() -> Self { + DafnyInt::new(Rc::new(BigInt::zero())) + } +} + +pub fn dafny_int_to_bigint(i: &DafnyInt) -> BigInt { + i.data.as_ref().clone() +} +pub fn bigint_to_dafny_int(i: &BigInt) -> DafnyInt { + DafnyInt { + data: Rc::new(i.clone()), + } +} + +impl Zero for DafnyInt { + #[inline] + fn zero() -> Self { + DafnyInt { + data: Rc::new(BigInt::zero()), + } + } + #[inline] + fn is_zero(&self) -> bool { + self.data.is_zero() + } +} +impl One for DafnyInt { + #[inline] + fn one() -> Self { + DafnyInt { + data: Rc::new(BigInt::one()), + } + } +} +impl Num for DafnyInt { + type FromStrRadixErr = ParseBigIntError; + + #[inline] + fn from_str_radix(s: &str, radix: u32) -> Result { + Ok(DafnyInt { + data: Rc::new(BigInt::from_str_radix(s, radix)?), + }) + } +} +impl Ord for DafnyInt { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + self.data.cmp(&other.data) + } +} +impl Signed for DafnyInt { + #[inline] + fn abs(&self) -> Self { + DafnyInt { + data: Rc::new(self.data.as_ref().abs()), + } + } + + #[inline] + fn abs_sub(&self, other: &Self) -> Self { + DafnyInt { + data: Rc::new(self.data.as_ref().abs_sub(other.data.as_ref())), + } + } + + #[inline] + fn signum(&self) -> Self { + DafnyInt { + data: Rc::new(self.data.as_ref().signum()), + } + } + + #[inline] + fn is_positive(&self) -> bool { + self.data.as_ref().is_positive() + } + + #[inline] + fn is_negative(&self) -> bool { + self.data.as_ref().is_negative() + } +} + +// Comparison +impl PartialOrd for DafnyInt { + #[inline] + fn partial_cmp(&self, other: &DafnyInt) -> Option { + Some(self.cmp(other)) + } +} + +impl DafnyInt { + #[inline] + pub fn parse_bytes(number: &[u8], radix: u32) -> DafnyInt { + DafnyInt { + data: Rc::new(BigInt::parse_bytes(number, radix).unwrap()), + } + } + pub fn from_usize(usize: usize) -> DafnyInt { + DafnyInt { + data: Rc::new(BigInt::from(usize)), + } + } + pub fn from_i32(i: i32) -> DafnyInt { + DafnyInt { + data: Rc::new(BigInt::from(i)), + } + } +} + +// fn dafny_rational_to_int(r: &BigRational) -> BigInt { +// euclidian_division(r.numer().clone(), r.denom().clone()) +// } + +impl DafnyPrint for BigInt { + fn fmt_print(&self, f: &mut Formatter<'_>, _in_seq: bool) -> std::fmt::Result { + write!(f, "{}", self) + } +} + +fn divides_a_power_of_10(mut i: BigInt) -> (bool, BigInt, usize) { + let one: BigInt = One::one(); + + let mut factor = one.clone(); + let mut log10 = 0; + + let zero = Zero::zero(); + let ten = BigInt::from_i32(10).unwrap(); + + if i <= zero { + return (false, factor, log10); + } + + while i.is_multiple_of(&ten) { + i /= BigInt::from_i32(10).unwrap(); + log10 += 1; + } + + let two = BigInt::from_i32(2).unwrap(); + let five = BigInt::from_i32(5).unwrap(); + + while i.is_multiple_of(&five) { + i /= &five; + factor *= &two; + log10 += 1; + } + + while i.is_multiple_of(&two) { + i /= &two; + factor *= &two; + log10 += 1; + } + + (i == one, factor, log10) +} + +impl DafnyPrint for BigRational { + fn fmt_print(&self, f: &mut Formatter<'_>, _in_seq: bool) -> std::fmt::Result { + if self.denom() == &One::one() || self.numer() == &Zero::zero() { + write!(f, "{}.0", self.numer()) + } else { + let (divides, factor, log10) = divides_a_power_of_10(self.denom().clone()); + if divides { + let mut num = self.numer().clone(); + num *= factor; + + if num.is_negative() { + write!(f, "-")?; + num = -num; + } + + let digits = num.to_string(); + + if log10 < digits.len() { + let digit_count = digits.len() - log10; + write!(f, "{}", &digits[..digit_count])?; + write!(f, ".")?; + write!(f, "{}", &digits[digit_count..]) + } else { + let z = log10 - digits.len(); + write!(f, "0.")?; + for _ in 0..z { + write!(f, "0")?; + } + write!(f, "{}", digits) + } + } else { + write!(f, "({}.0 / {}.0)", self.numer(), self.denom()) + } + } + } +} + +impl From for u8 { + fn from(val: DafnyInt) -> Self { + val.data.to_u8().unwrap() + } +} +impl From for u16 { + fn from(val: DafnyInt) -> Self { + val.data.to_u16().unwrap() + } +} +impl From for u32 { + fn from(val: DafnyInt) -> Self { + val.data.to_u32().unwrap() + } +} +impl From for u64 { + fn from(val: DafnyInt) -> Self { + val.data.to_u64().unwrap() + } +} +impl From for u128 { + fn from(val: DafnyInt) -> Self { + val.data.to_u128().unwrap() + } +} +impl From for i8 { + fn from(val: DafnyInt) -> Self { + val.data.to_i8().unwrap() + } +} +impl From for i16 { + fn from(val: DafnyInt) -> Self { + val.data.to_i16().unwrap() + } +} +impl From for i32 { + fn from(val: DafnyInt) -> Self { + val.data.to_i32().unwrap() + } +} +impl From for i64 { + fn from(val: DafnyInt) -> Self { + val.data.to_i64().unwrap() + } +} +impl From for i128 { + fn from(val: DafnyInt) -> Self { + val.data.to_i128().unwrap() + } +} +impl From for usize { + fn from(val: DafnyInt) -> Self { + val.data.to_usize().unwrap() + } +} + +impl ToPrimitive for DafnyInt { + fn to_i64(&self) -> Option { + self.data.to_i64() + } + + fn to_u64(&self) -> Option { + self.data.to_u64() + } + + // Override of functions + fn to_u128(&self) -> Option { + self.data.to_u128() + } + + fn to_i128(&self) -> Option { + self.data.to_i128() + } +} + +impl PartialEq for DafnyInt { + fn eq(&self, other: &DafnyInt) -> bool { + self.data.eq(&other.data) + } +} +impl Eq for DafnyInt {} +impl Hash for DafnyInt { + fn hash(&self, state: &mut H) { + self.data.hash(state); + } +} + +impl DafnyPrint for DafnyInt { + fn fmt_print(&self, f: &mut Formatter<'_>, _in_seq: bool) -> std::fmt::Result { + write!(f, "{}", self.data) + } +} + +impl ::std::fmt::Debug for DafnyInt { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.data) + } +} + +impl Add for DafnyInt { + type Output = DafnyInt; + + fn add(self, rhs: DafnyInt) -> Self::Output { + DafnyInt { + data: Rc::new(self.data.as_ref() + rhs.data.as_ref()), + } + } +} + +impl Mul for DafnyInt { + type Output = DafnyInt; + + fn mul(self, rhs: DafnyInt) -> Self::Output { + DafnyInt { + data: Rc::new(self.data.as_ref() * rhs.data.as_ref()), + } + } +} + +impl Div for DafnyInt { + type Output = DafnyInt; + + fn div(self, rhs: DafnyInt) -> Self::Output { + DafnyInt { + data: Rc::new(self.data.as_ref() / rhs.data.as_ref()), + } + } +} + +impl Sub for DafnyInt { + type Output = DafnyInt; + + fn sub(self, rhs: DafnyInt) -> Self::Output { + DafnyInt { + data: Rc::new(self.data.as_ref() - rhs.data.as_ref()), + } + } +} +impl Rem for DafnyInt { + type Output = DafnyInt; + + fn rem(self, rhs: DafnyInt) -> Self::Output { + DafnyInt { + data: Rc::new(self.data.as_ref() % rhs.data.as_ref()), + } + } +} +impl Neg for DafnyInt { + type Output = DafnyInt; + + #[inline] + fn neg(self) -> Self::Output { + DafnyInt { + data: Rc::new(-self.data.as_ref()), + } + } +} + +macro_rules! impl_dafnyint_from { + () => {}; + ($type:ident) => { + impl ::std::convert::From<$type> for $crate::DafnyInt { + fn from(n: $type) -> Self { + $crate::DafnyInt { + data: $crate::Rc::new(n.into()), + } + } + } + #[allow(trivial_numeric_casts)] + impl $crate::DafnyUsize for $type { + fn into_usize(self) -> usize { + self as usize + } + } + }; +} + +impl_dafnyint_from! { u8 } +impl_dafnyint_from! { u16 } +impl_dafnyint_from! { u32 } +impl_dafnyint_from! { u64 } +impl_dafnyint_from! { u128 } +impl_dafnyint_from! { i8 } +impl_dafnyint_from! { i16 } +impl_dafnyint_from! { i32 } +impl_dafnyint_from! { i64 } +impl_dafnyint_from! { i128 } +impl_dafnyint_from! { usize } diff --git a/src/trust_engine/kernel/runtime/src/lib.rs b/src/trust_engine/kernel/runtime/src/lib.rs new file mode 100644 index 0000000..fd8a07d --- /dev/null +++ b/src/trust_engine/kernel/runtime/src/lib.rs @@ -0,0 +1,3853 @@ +#![allow(clippy::collapsible_else_if)] +#![allow(clippy::multiple_bound_locations)] +#![allow(clippy::missing_safety_doc)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::clone_on_copy)] +#![warn( + absolute_paths_not_starting_with_crate, + explicit_outlives_requirements, + deprecated_in_future, + keyword_idents, + let_underscore_drop, + macro_use_extern_crate, + // missing_debug_implementations, + non_ascii_idents, + noop_method_call, + rust_2021_incompatible_closure_captures, + rust_2021_incompatible_or_patterns, + rust_2021_prefixes_incompatible_syntax, + rust_2021_prelude_collisions, + rust_2018_idioms, + single_use_lifetimes, + trivial_numeric_casts, + unit_bindings, + unreachable_pub, + unsafe_op_in_unsafe_fn, + unused_extern_crates, + unused_lifetimes, + unused_qualifications, +)] + +#[cfg(test)] +mod tests; + +mod system; +pub use mem::MaybeUninit; +use num::{One, Signed}; +pub use once_cell::unsync::Lazy; +use std::{ + borrow::Borrow, + boxed::Box, + clone::Clone, + cmp::Ordering, + collections::{HashMap, HashSet}, + convert::From, + fmt::{Debug, Display, Formatter}, + hash::{Hash, Hasher}, + mem, + ops::{Add, Deref, Fn, Sub}, + ptr::NonNull, + vec::Vec, +}; + +#[cfg(not(feature = "small-int"))] +mod big_int; +#[cfg(not(feature = "small-int"))] +pub use big_int::*; + +#[cfg(feature = "small-int")] +mod small_int; +#[cfg(feature = "small-int")] +pub use small_int::*; + +#[cfg(not(feature = "sync"))] +pub use ::std::{ + cell::RefCell, + rc::{Rc, Weak}, +}; + +#[cfg(feature = "sync")] +pub use ::std::sync::{Arc as Rc, Mutex as RefCell, Weak}; + +pub use system::*; + +pub use itertools; +pub use num::FromPrimitive; +pub use num::NumCast; +pub use num::ToPrimitive; +pub use num::Zero; +pub use std::convert::Into; + +pub use ::std::any::Any; +pub use ::std::marker::Send; +pub use ::std::marker::Sync; + +#[cfg(not(feature = "sync"))] +pub type DynAny = dyn Any; +#[cfg(feature = "sync")] +pub type DynAny = dyn Any + Send + Sync; + +#[cfg(not(feature = "sync"))] +pub use ::std::cell::UnsafeCell; + +#[cfg(feature = "sync")] +pub struct UnsafeCell { + data: ::std::cell::UnsafeCell, // UnsafeCell for interior mutability +} +// SAFETY: UnsafeCell is not possibly sync normally. +// However, we use it only for raw pointers, and fields and access to read and write +// to fields will be subject to mutexes in any cases. +#[cfg(feature = "sync")] +unsafe impl Sync for UnsafeCell where T: Send {} +#[cfg(feature = "sync")] +impl UnsafeCell { + pub fn new(data: T) -> Self { + UnsafeCell { + data: ::std::cell::UnsafeCell::new(data), + } + } +} +#[cfg(feature = "sync")] +impl UnsafeCell { + pub fn get(&self) -> *mut T { + ::std::cell::UnsafeCell::get(&self.data) + } + pub fn raw_get(this: *const UnsafeCell) -> *mut T { + unsafe { ::std::cell::UnsafeCell::raw_get(&(*this).data) } + } +} + +// An atomic box is just a RefCell in Rust +pub type SizeT = usize; + +#[cfg(not(feature = "sync"))] +pub trait DafnyType: Clone + DafnyPrint + 'static {} +#[cfg(feature = "sync")] +pub trait DafnyType: Clone + DafnyPrint + Send + Sync + 'static {} + +#[cfg(not(feature = "sync"))] +impl DafnyType for T where T: Clone + DafnyPrint + 'static {} +#[cfg(feature = "sync")] +impl DafnyType for T where T: Clone + DafnyPrint + Send + Sync + 'static {} + +pub trait DafnyTypeEq: DafnyType + Hash + Eq {} + +impl DafnyTypeEq for T where T: DafnyType + Hash + Eq {} + +// Dafny's type (0) compiles to NontrivialDefault to prevent subset types from being considered as Default if their witness is nonzero +pub trait NontrivialDefault { + fn nontrivial_default() -> Self; +} + +pub mod dafny_runtime_conversions { + use crate::DafnyType; + use crate::DafnyTypeEq; + pub type DafnyInt = crate::DafnyInt; + pub type DafnySequence = crate::Sequence; + pub type DafnyMap = crate::Map; + pub type DafnySet = crate::Set; + pub type DafnyMultiset = crate::Multiset; + pub type DafnyBool = bool; + pub type DafnyChar = crate::DafnyChar; + pub type DafnyCharUTF16 = crate::DafnyCharUTF16; + + use ::std::collections::HashMap; + use ::std::collections::HashSet; + use ::std::hash::Hash; + + pub use super::Rc; + + pub mod object { + pub use super::Rc; + pub type DafnyClass = crate::Object; + pub type DafnyArray = crate::Object<[T]>; + pub type DafnyArray2 = crate::Object>; + pub type DafnyArray3 = crate::Object>; + // Conversion to and from Dafny reference-counted classes. All these methods take ownership of the class. + pub fn dafny_class_to_struct(ptr: DafnyClass) -> T { + let t: &T = crate::rd!(ptr); + t.clone() + } + pub fn dafny_class_to_boxed_struct(ptr: DafnyClass) -> Box { + Box::new(dafny_class_to_struct(ptr)) + } + pub unsafe fn dafny_class_to_rc_struct(ptr: DafnyClass) -> Rc { + unsafe { crate::rcmut::to_rc(ptr.0.unwrap()) } + } + pub fn struct_to_dafny_class(t: T) -> DafnyClass { + crate::Object::new(t) + } + pub fn boxed_struct_to_dafny_class(t: Box) -> DafnyClass { + struct_to_dafny_class(*t) + } + pub unsafe fn rc_struct_to_dafny_class(t: Rc) -> DafnyClass { + unsafe { crate::Object::from_rc(t) } + } + // Conversions to and from Dafny arrays. They all take ownership + pub unsafe fn dafny_array_to_vec(ptr: DafnyArray) -> Vec { + ptr.as_ref().to_vec() + } + pub fn vec_to_dafny_array(array: Vec) -> DafnyArray { + // SAFETY: We own the array + unsafe { crate::Object::from_rc(Rc::from(array.into_boxed_slice())) } + } + pub unsafe fn dafny_array2_to_vec(ptr: DafnyArray2) -> Vec> { + crate::rd!(ptr).to_vec() + } + } + + pub mod ptr { + pub use super::Rc; + pub type DafnyClass = crate::Ptr; + pub type DafnyArray = crate::Ptr<[T]>; + pub type DafnyArray2 = crate::Ptr>; + pub type DafnyArray3 = crate::Ptr>; + // Conversion to and from Dafny reference-counted classes. All these methods take ownership of the class. + pub unsafe fn dafny_class_to_struct(ptr: DafnyClass) -> T { + unsafe { *dafny_class_to_boxed_struct(ptr) } + } + pub unsafe fn dafny_class_to_boxed_struct(ptr: DafnyClass) -> Box { + unsafe { Box::from_raw(crate::Ptr::into_raw(ptr)) } + } + pub fn struct_to_dafny_class(t: T) -> DafnyClass { + boxed_struct_to_dafny_class(Box::new(t)) + } + pub fn boxed_struct_to_dafny_class(t: Box) -> DafnyClass { + crate::Ptr::from_raw_nonnull(Box::into_raw(t)) + } + // Conversions to and from Dafny arrays. They all take ownership + pub unsafe fn dafny_array_to_vec(ptr: DafnyArray) -> Vec { + ptr.as_ref().to_vec() + } + pub fn vec_to_dafny_array(array: Vec) -> DafnyArray { + crate::Ptr::from_box(array.into_boxed_slice()) + } + pub unsafe fn dafny_array2_to_vec(ptr: DafnyArray2) -> Vec> { + unsafe { Box::from_raw(crate::Ptr::into_raw(ptr)).to_vec() } + } + } + + pub fn dafny_sequence_to_vec(s: &DafnySequence, elem_converter: fn(&T) -> X) -> Vec + where + T: DafnyType, + { + let mut array: Vec = Vec::with_capacity(s.cardinality_usize()); + DafnySequence::::append_recursive(&mut array, s); + array.iter().map(elem_converter).collect() + } + + // Used for external conversions + pub fn vec_to_dafny_sequence( + array: &Vec, + elem_converter: fn(&X) -> T, + ) -> DafnySequence + where + T: DafnyType, + { + let mut result: Vec = Vec::with_capacity(array.len()); + for elem in array.iter() { + result.push(elem_converter(elem)); + } + DafnySequence::::from_array_owned(result) + } + + pub fn dafny_map_to_hashmap( + m: &DafnyMap, + converter_k: fn(&K) -> K2, + converter_v: fn(&V) -> V2, + ) -> HashMap + where + K: DafnyTypeEq, + V: DafnyTypeEq, + K2: Eq + Hash, + V2: Clone, + { + m.to_hashmap_owned(converter_k, converter_v) + } + + pub fn hashmap_to_dafny_map( + map: &HashMap, + converter_k: fn(&K2) -> K, + converter_v: fn(&V2) -> V, + ) -> DafnyMap + where + K: DafnyTypeEq, + V: DafnyTypeEq, + K2: Eq + Hash, + V2: Clone, + { + DafnyMap::::from_hashmap(map, converter_k, converter_v) + } + + // --unicode-char:true + pub mod unicode_chars_true { + use crate::Sequence; + + type DafnyChar = crate::DafnyChar; + type DafnyString = Sequence; + + pub fn string_to_dafny_string(s: &str) -> DafnyString { + Sequence::from_array_owned(s.chars().map(crate::DafnyChar).collect()) + } + pub fn dafny_string_to_string(s: &DafnyString) -> String { + let characters = s.to_array(); + characters.iter().map(|v| v.0).collect::() + } + } + + // --unicode-char:false + pub mod unicode_chars_false { + use crate::Sequence; + + type DafnyCharUTF16 = crate::DafnyCharUTF16; + type DafnyString = Sequence; + + pub fn string_to_dafny_string(s: &str) -> DafnyString { + Sequence::from_array_owned(s.encode_utf16().map(crate::DafnyCharUTF16).collect()) + } + pub fn dafny_string_to_string(s: &DafnyString) -> String { + let characters = s + .to_array() + .as_ref() + .iter() + .map(|v| v.0) + .collect::>(); + String::from_utf16_lossy(&characters) + } + } + + pub fn set_to_dafny_set( + set: &HashSet, + converter: fn(&U) -> T, + ) -> DafnySet { + DafnySet::from_iterator(set.iter().map(converter)) + } + pub fn dafny_set_to_set(set: &DafnySet, converter: fn(&T) -> U) -> HashSet + where + T: DafnyTypeEq, + U: Clone + Eq + Hash, + { + let mut result: HashSet = HashSet::new(); + for s in set.data.iter() { + result.insert(converter(s)); + } + result + } + + pub fn dafny_multiset_to_owned_vec( + ms: &DafnyMultiset, + converter: fn(&T) -> U, + ) -> Vec + where + T: DafnyTypeEq, + U: Clone + Eq, + { + let mut result: Vec = Vec::new(); + for s in ms.data.iter() { + // Push T as many times as its size + for _ in 0..s.1.as_usize() { + result.push(converter(s.0)); + } + } + result + } + + pub fn vec_to_dafny_multiset(vec: &Vec, converter: fn(&U) -> T) -> DafnyMultiset + where + T: DafnyTypeEq, + U: Clone + Eq + Hash, + { + DafnyMultiset::from_iterator(vec.iter().map(|u: &U| converter(u))) + } +} + +pub trait DafnyUsize { + fn into_usize(self) -> usize; +} + +// ************** +// Dafny integers +// ************** + +impl DafnyInt { + pub fn as_usize(&self) -> usize { + self.to_usize().unwrap() + } +} + +impl DafnyUsize for DafnyInt { + fn into_usize(self) -> usize { + self.as_usize() + } +} + +// truncate_u(x, u64) +// = ::to_u128(&x).unwrap() as u64; +#[macro_export] +macro_rules! truncate { + ($x:expr, $t:ty) => { + <$crate::DafnyInt as ::std::convert::Into<$t>>::into($x) + }; +} + +impl NontrivialDefault for DafnyInt { + fn nontrivial_default() -> Self { + Self::default() + } +} + +impl From<&[u8]> for DafnyInt { + fn from(number: &[u8]) -> Self { + DafnyInt::parse_bytes(number, 10) + } +} + +// Now the same but for &[u8, N] for any kind of such references +impl From<&[u8; N]> for DafnyInt { + fn from(number: &[u8; N]) -> Self { + DafnyInt::parse_bytes(number, 10) + } +} + +impl From for DafnyInt { + fn from(c: char) -> Self { + let cu32: u32 = c.into(); + int!(cu32) + } +} + +impl From for DafnyInt { + fn from(c: DafnyChar) -> Self { + int!(c.0) + } +} + +impl From for DafnyInt { + fn from(c: DafnyCharUTF16) -> Self { + int!(c.0) + } +} + +// ************** +// Immutable sequences +// ************** + +impl Eq for Sequence {} + +impl Add<&Sequence> for &Sequence { + type Output = Sequence; + + fn add(self, rhs: &Sequence) -> Self::Output { + Sequence::new_concat_sequence(self, rhs) + } +} + +impl Hash for Sequence { + fn hash(&self, state: &mut H) { + self.cardinality_usize().hash(state); + let array = self.to_array(); + // Iterate over the elements + for elt in array.iter() { + elt.hash(state); + } + } +} + +// Clone can be derived automatically +#[derive(Clone)] +pub enum Sequence +where + T: DafnyType, +{ + ArraySequence { + // Values could be a native array because we will know statically that all + // accesses are in bounds when using this data structure + values: Rc>, + }, + ConcatSequence { + left: Rc>>, + right: Rc>>, + length: SizeT, + cache: Rc>>>>, + }, +} + +impl Sequence +where + T: DafnyType, +{ + pub fn from_array(values: Ptr<[T]>) -> Sequence { + let mut v = vec![]; + v.extend_from_slice(read!(values)); + Sequence::ArraySequence { values: Rc::new(v) } + } + pub fn from_array_object(values: &Object<[T]>) -> Sequence { + let mut v = vec![]; + v.extend_from_slice(rd!(values)); + Sequence::ArraySequence { values: Rc::new(v) } + } + pub fn from_array_slice(values: Ptr<[T]>, start: &DafnyInt, end: &DafnyInt) -> Sequence { + let mut v = vec![]; + v.extend_from_slice(&read!(values)[start.to_usize().unwrap()..end.to_usize().unwrap()]); + Sequence::ArraySequence { values: Rc::new(v) } + } + pub fn from_array_slice_object( + values: &Object<[T]>, + start: &DafnyInt, + end: &DafnyInt, + ) -> Sequence { + let mut v = vec![]; + v.extend_from_slice(&rd!(values)[start.to_usize().unwrap()..end.to_usize().unwrap()]); + Sequence::ArraySequence { values: Rc::new(v) } + } + pub fn from_array_take(values: Ptr<[T]>, n: &DafnyInt) -> Sequence { + let mut v = vec![]; + v.extend_from_slice(&read!(values)[..n.to_usize().unwrap()]); + Sequence::ArraySequence { values: Rc::new(v) } + } + pub fn from_array_take_object(values: &Object<[T]>, n: &DafnyInt) -> Sequence { + let mut v = vec![]; + v.extend_from_slice(&rd!(values)[..n.to_usize().unwrap()]); + Sequence::ArraySequence { values: Rc::new(v) } + } + pub fn from_array_drop(values: Ptr<[T]>, n: &DafnyInt) -> Sequence { + let mut v = vec![]; + v.extend_from_slice(&read!(values)[n.to_usize().unwrap()..]); + Sequence::ArraySequence { values: Rc::new(v) } + } + pub fn from_array_drop_object(values: &Object<[T]>, n: &DafnyInt) -> Sequence { + let mut v = vec![]; + v.extend_from_slice(&rd!(values)[n.to_usize().unwrap()..]); + Sequence::ArraySequence { values: Rc::new(v) } + } + pub fn from_array_owned(values: Vec) -> Sequence { + Sequence::ArraySequence { + values: Rc::new(values), + } + } + pub(crate) fn new_concat_sequence(left: &Sequence, right: &Sequence) -> Sequence { + Sequence::ConcatSequence { + left: Rc::new(RefCell::new(left.clone())), + right: Rc::new(RefCell::new(right.clone())), + length: left.cardinality_usize() + right.cardinality_usize(), + cache: Rc::new(RefCell::new(None)), + } + } + pub fn to_array(&self) -> Rc> { + // Let's convert the if then else below to a proper match statement + match self { + Sequence::ArraySequence { values, .. } => + // The length of the elements + { + Rc::clone(values) + } + Sequence::ConcatSequence { + length, + cache, + left, + right, + } => { + #[cfg(feature = "sync")] + { + let guard = cache.as_ref().lock().unwrap(); + let cache_borrow: Option<&Rc>> = guard.as_ref(); + if let Some(cache) = cache_borrow { + return Rc::clone(cache); + } + } + + #[cfg(not(feature = "sync"))] + { + let cache_opened = cache.as_ref().clone(); + let cache_opened_borrowed = cache_opened.borrow(); + let cache_borrow: Option<&Rc>> = cache_opened_borrowed.as_ref(); + if let Some(cache) = cache_borrow { + return Rc::clone(cache); + } + } + // Let's create an array of size length and fill it up recursively + // We don't materialize nested arrays because most of the time they are forgotten + let mut array: Vec = Vec::with_capacity(*length); + Sequence::::append_recursive(&mut array, self); + let result = Rc::new(array); + #[cfg(not(feature = "sync"))] + { + *left.borrow_mut() = seq!(); + *right.borrow_mut() = seq!(); + } + #[cfg(feature = "sync")] + { + let mut left_guard = left.as_ref().lock().unwrap(); + let mut right_guard = right.as_ref().lock().unwrap(); + *left_guard = seq!(); + *right_guard = seq!(); + } + #[cfg(not(feature = "sync"))] + let mut guard = cache.borrow_mut(); + #[cfg(feature = "sync")] + let mut guard = cache.as_ref().lock().unwrap(); + *guard = Some(result.clone()); + result + } + } + } + + pub fn append_simple(array: &mut Vec, this: &Sequence) -> bool { + match this { + Sequence::ArraySequence { values, .. } => { + for value in values.iter() { + array.push(value.clone()); + } + true + } + _ => false, + } + } + + pub fn append_recursive(array: &mut Vec, this: &Sequence) { + let mut this_ptr: *const Sequence = this; + loop { + // SAFETY: The invariant is that this_ptr is always a pointer to a sub-sequence of the original `this`parameter when following the field name 'right', which are allocated in this scope + match unsafe { &*this_ptr } { + Sequence::ArraySequence { values, .. } => { + for value in values.iter() { + array.push(value.clone()); + } + return; + } + Sequence::ConcatSequence { + cache: boxed, + left, + right, + .. + } => + // Let's create an array of size length and fill it up recursively + { + #[cfg(feature = "sync")] + let into_boxed = boxed.as_ref(); + #[cfg(feature = "sync")] + let into_boxed_borrowed = into_boxed; + #[cfg(feature = "sync")] + let guard = into_boxed_borrowed.lock().unwrap(); + #[cfg(feature = "sync")] + let borrowed: Option<&Rc>> = guard.as_ref(); + + #[cfg(not(feature = "sync"))] + let into_boxed = boxed.as_ref().clone(); + #[cfg(not(feature = "sync"))] + let into_boxed_borrowed = into_boxed.borrow(); + #[cfg(not(feature = "sync"))] + let borrowed: Option<&Rc>> = into_boxed_borrowed.as_ref(); + if let Some(values) = borrowed.as_ref() { + for value in values.iter() { + array.push(value.clone()); + } + return; + } + #[cfg(not(feature = "sync"))] + { + let left_empty = left.as_ref().borrow().cardinality_usize() == 0; + let right_empty = right.as_ref().borrow().cardinality_usize() == 0; + if left_empty && right_empty { + return; + } else if left_empty { + this_ptr = right.as_ref().as_ptr(); + } else if right_empty { + this_ptr = left.as_ref().as_ptr(); + } else { + if !Sequence::::append_simple(array, &left.as_ref().borrow()) { + Sequence::::append_recursive(array, &left.as_ref().borrow()); + } + this_ptr = right.as_ref().as_ptr(); + } + } + #[cfg(feature = "sync")] + { + let left_guard = left.as_ref().lock().unwrap(); + let right_guard = right.as_ref().lock().unwrap(); + let left_empty: bool = left_guard.cardinality_usize() == 0; + let right_empty: bool = right_guard.cardinality_usize() == 0; + if left_empty && right_empty { + return; + } else if left_empty { + this_ptr = right_guard.deref(); + } else if right_empty { + this_ptr = left_guard.deref(); + } else { + if !Sequence::::append_simple(array, &left_guard) { + Sequence::::append_recursive(array, &left_guard); + } + this_ptr = right_guard.deref(); + } + } + } + } + } + } + /// Returns the cardinality or length of this [`Sequence`]. + pub fn cardinality_usize(&self) -> SizeT { + match self { + Sequence::ArraySequence { values, .. } => + // The length of the elements + { + values.len() + } + Sequence::ConcatSequence { length, .. } => *length, + } + } + pub fn cardinality(&self) -> DafnyInt { + DafnyInt::from_usize(self.cardinality_usize()) + } + pub fn get_usize(&self, index: SizeT) -> T { + let array = self.to_array(); + array[index].clone() + } + + pub fn slice(&self, start: &DafnyInt, end: &DafnyInt) -> Sequence { + let start_index = start.as_usize(); + let end_index = end.as_usize(); + Sequence::from_array_owned(self.to_array()[start_index..end_index].to_vec()) + } + pub fn take(&self, end: &DafnyInt) -> Sequence { + let end_index = end.as_usize(); + Sequence::from_array_owned(self.to_array()[..end_index].to_vec()) + } + pub fn drop(&self, start: &DafnyInt) -> Sequence { + let start_index = start.as_usize(); + Sequence::from_array_owned(self.to_array()[start_index..].to_vec()) + } + + pub fn update_index(&self, index: &DafnyInt, value: &T) -> Self { + let mut result = self.to_array().as_ref().clone(); + result[index.as_usize()] = value.clone(); + Sequence::from_array_owned(result) + } + + pub fn concat(&self, other: &Sequence) -> Sequence { + Sequence::new_concat_sequence(self, other) + } + + pub fn get(&self, index: &DafnyInt) -> T { + self.get_usize(index.as_usize()) + } + pub fn iter(&self) -> SequenceIter { + SequenceIter { + array: self.to_array(), + index: 0, + } + } +} + +pub struct SequenceIter { + array: Rc>, + index: SizeT, +} +impl Iterator for SequenceIter { + type Item = T; + fn next(&mut self) -> Option { + if self.index < self.array.len() { + let result = self.array[self.index].clone(); + self.index += 1; + Some(result) + } else { + None + } + } +} + +impl Default for Sequence { + fn default() -> Self { + Sequence::from_array_owned(vec![]) + } +} +impl NontrivialDefault for Sequence { + fn nontrivial_default() -> Self { + Self::default() + } +} + +impl Sequence { + pub fn as_dafny_multiset(&self) -> Multiset { + Multiset::from_array(&self.to_array()) + } +} + +// Makes it possible to write iterator.collect::> and obtain a sequence +impl FromIterator for Sequence { + fn from_iter>(iter: I) -> Self { + Sequence::from_array_owned(iter.into_iter().collect()) + } +} + +impl Sequence { + pub fn contains(&self, value: &T) -> bool { + self.to_array().contains(value) + } +} +impl PartialEq> for Sequence +where + T: DafnyType + PartialEq, +{ + fn eq(&self, other: &Sequence) -> bool { + // Iterate through both elements and verify that they are equal + let values: Rc> = self.to_array(); + if other.cardinality_usize() != values.len() { + return false; + } + for (i, value) in values.iter().enumerate() { + if value != &other.get_usize(i) { + return false; + } + } + true + } +} + +impl PartialOrd for Sequence { + fn partial_cmp(&self, other: &Sequence) -> Option { + // Comparison is only prefix-based + match self.cardinality_usize().cmp(&other.cardinality_usize()) { + Ordering::Equal => { + if self == other { + Some(Ordering::Equal) + } else { + None + } + } + Ordering::Less => { + for i in 0..self.cardinality_usize() { + if self.get_usize(i) != other.get_usize(i) { + return None; + } + } + Some(Ordering::Less) + } + Ordering::Greater => { + for i in 0..other.cardinality_usize() { + if self.get_usize(i) != other.get_usize(i) { + return None; + } + } + Some(Ordering::Greater) + } + } + } +} + +impl DafnyPrint for Sequence { + fn fmt_print(&self, f: &mut Formatter<'_>, _in_seq: bool) -> std::fmt::Result { + if !V::is_char() { + write!(f, "[")?; + } + let mut first = true; + for value in self.to_array().iter() { + if !first && !V::is_char() { + write!(f, ", ")?; + } + first = false; + value.fmt_print(f, true)?; + } + if !V::is_char() { + write!(f, "]") + } else { + write!(f, "") + } + } +} + +impl Debug for Sequence { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.fmt_print(f, false) + } +} + +// ************** +// Immutable maps +// ************** + +#[derive(Clone)] +pub struct Map +where + K: DafnyTypeEq, + V: DafnyType, +{ + data: Rc>, +} + +impl Default for Map { + fn default() -> Self { + Map { + data: Rc::new(HashMap::new()), + } + } +} + +impl NontrivialDefault for Map { + fn nontrivial_default() -> Self { + Self::default() + } +} + +impl Hash for Map { + fn hash(&self, state: &mut H) { + self.data.len().hash(state); // Worst performance for things that are not hashable like maps + } +} + +impl PartialEq> for Map +where + K: DafnyTypeEq, + V: DafnyTypeEq, +{ + fn eq(&self, other: &Map) -> bool { + if self.data.len() != other.data.len() { + return false; + } + for (k, v) in self.data.iter() { + if other.data.get(k) != Some(v) { + return false; + } + } + true + } +} + +impl Eq for Map {} + +impl Map { + pub fn new_empty() -> Map { + Map { + data: Rc::new(HashMap::new()), + } + } + pub fn from_array(values: &Vec<(K, V)>) -> Map { + Self::from_iterator(values.iter().map(|(k, v)| (k.clone(), v.clone()))) + } + pub fn from_iterator(data: I) -> Map + where + I: Iterator, + { + let mut result: HashMap = HashMap::new(); + for (k, v) in data { + result.insert(k, v); + } + Self::from_hashmap_owned(result) + } + pub fn from_hashmap_owned(values: HashMap) -> Map { + Map { + data: Rc::new(values), + } + } + pub fn to_hashmap_owned( + &self, + converter_k: fn(&K) -> K2, + converter_v: fn(&V) -> V2, + ) -> HashMap + where + K2: Eq + Hash, + V2: Clone, + { + let mut result: HashMap = HashMap::new(); + for (k, v) in self.data.iter() { + result.insert(converter_k(k), converter_v(v)); + } + result + } + pub fn cardinality_usize(&self) -> usize { + self.data.len() + } + pub fn cardinality(&self) -> DafnyInt { + DafnyInt::from_usize(self.cardinality_usize()) + } + pub fn contains(&self, key: &K) -> bool { + self.data.contains_key(key) + } + pub fn get_or_none(&self, key: &K) -> Option { + self.data.get(key).cloned() + } + // Dafny will normally guarantee that the key exists. + pub fn get(&self, key: &K) -> V { + self.data[key].clone() + } + pub fn merge(&self, other: &Map) -> Map { + if other.cardinality_usize() == 0 { + return self.clone(); + } + if self.cardinality_usize() == 0 { + return other.clone(); + } + let mut new_data = (*other.data).clone(); + // Overriding self's keys with other's keys if there are some. + for (k, v) in self.data.iter() { + if !other.contains(k) { + new_data.insert(k.clone(), v.clone()); + } + } + Self::from_hashmap_owned(new_data) + } + pub fn subtract(&self, keys: &Set) -> Self { + if keys.cardinality_usize() == 0 { + return self.clone(); + } + let mut result: HashMap = HashMap::new(); + for (k, v) in self.data.iter() { + if !keys.contains(k) { + result.insert(k.clone(), v.clone()); + } + } + Self::from_hashmap_owned(result) + } + + pub fn from_hashmap( + map: &HashMap, + converter_k: fn(&K2) -> K, + converter_v: fn(&V2) -> V, + ) -> Map + where + K: DafnyTypeEq, + V: DafnyTypeEq, + K2: Eq + Hash, + V2: Clone, + { + let mut result: HashMap = HashMap::new(); + for (k, v) in map.iter() { + result.insert(converter_k(k), converter_v(v)); + } + Map { + data: Rc::new(result), + } + } + pub fn keys(&self) -> Set { + let mut result: HashSet = HashSet::new(); + for (k, _) in self.data.iter() { + result.insert(k.clone()); + } + Set::from_hashset_owned(result) + } + + pub fn update_index(&self, index: &K, value: &V) -> Self { + let mut result = self.data.as_ref().clone(); + result.insert(index.clone(), value.clone()); + Map::from_hashmap_owned(result) + } + + pub fn update_index_owned(&self, index: K, value: V) -> Self { + let mut result = self.data.as_ref().clone(); + result.insert(index, value); + Map::from_hashmap_owned(result) + } + + pub fn iter_raw(&self) -> std::collections::hash_map::Iter<'_, K, V> { + self.data.iter() + } + + pub fn iter(&self) -> impl Iterator + '_ { + self.data.iter().map(|(k, _v)| k).cloned() + } +} + +impl Map { + pub fn values(&self) -> Set { + let mut result: Vec = Vec::new(); + for (_, v) in self.data.iter() { + result.push(v.clone()); + } + Set::from_array(&result) + } + pub fn items(&self) -> Set<(K, V)> { + let mut result: Vec<(K, V)> = Vec::new(); + for (k, v) in self.data.iter() { + result.push((k.clone(), v.clone())); + } + Set::from_array(&result) + } +} + +impl Map { + pub fn as_dafny_multiset(&self) -> Multiset { + Multiset::from_hashmap(&self.data) + } +} + +pub struct MapBuilder +where + K: Clone + Eq + Hash, + V: Clone, +{ + data: HashMap, +} + +impl Default for MapBuilder +where + K: DafnyTypeEq, + V: DafnyType, +{ + fn default() -> Self { + Self::new() + } +} + +impl MapBuilder +where + K: DafnyTypeEq, + V: DafnyType, +{ + pub fn new() -> MapBuilder { + MapBuilder { + data: HashMap::new(), + } + } + pub fn add(&mut self, key: &K, value: &V) { + // Dafny will prove that overriding has the same value anyway + self.data.insert(key.clone(), value.clone()); + } + pub fn build(self) -> Map { + Map::from_hashmap_owned(self.data) + } +} + +impl DafnyPrint for Map +where + K: DafnyTypeEq, + V: DafnyType, +{ + fn fmt_print(&self, f: &mut Formatter<'_>, in_seq: bool) -> std::fmt::Result { + f.write_str("map[")?; + let mut first = true; + for (k, v) in self.data.iter() { + if !first { + f.write_str(", ")?; + } + first = false; + k.fmt_print(f, in_seq)?; + f.write_str(" := ")?; + v.fmt_print(f, in_seq)?; + } + f.write_str("]") + } +} + +impl Debug for Map +where + K: DafnyTypeEq, + V: DafnyTypeEq, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.fmt_print(f, false) + } +} + +// ************** +// Immutable sets +// ************** + +#[derive(Clone)] +pub struct Set { + data: Rc>, +} + +// Since there is no canonical way to iterate over a set to compute the hash. +impl ::std::hash::Hash for Set { + fn hash<_H: ::std::hash::Hasher>(&self, _state: &mut _H) { + self.cardinality_usize().hash(_state) + } +} + +impl Eq for Set {} + +impl Default for Set +where + T: DafnyTypeEq, +{ + fn default() -> Self { + Self::new_empty() + } +} +impl NontrivialDefault for Set { + fn nontrivial_default() -> Self { + Self::default() + } +} + +impl PartialEq> for Set +where + V: DafnyTypeEq, +{ + fn eq(&self, other: &Set) -> bool { + // 1. Same cardinality + // 2. All the elements of self are in the other + if self.cardinality_usize() != other.cardinality_usize() { + false + } else { + for value in self.data.iter() { + if !other.contains(value) { + return false; + } + } + for value in other.data.iter() { + if !self.contains(value) { + return false; + } + } + true + } + } +} + +impl PartialOrd for Set { + fn partial_cmp(&self, other: &Self) -> Option { + // Partial ordering is inclusion + if self.cardinality_usize() <= other.cardinality_usize() { + for value in self.data.iter() { + if !other.contains(value) { + return None; + } + } + if self.cardinality_usize() == other.cardinality_usize() { + Some(Ordering::Equal) + } else { + Some(Ordering::Less) + } + } else { + for value in other.data.iter() { + if !self.contains(value) { + return None; + } + } + Some(Ordering::Greater) + } + } +} + +impl Set { + pub fn new_empty() -> Set { + Self::from_hashset_owned(HashSet::new()) + } + pub fn from_array(array: &Vec) -> Set { + Self::from_iterator(array.iter().cloned()) + } + pub fn from_iterator(data: I) -> Set + where + I: Iterator, + { + let mut set: HashSet = HashSet::new(); + for value in data { + set.insert(value); + } + Self::from_hashset_owned(set) + } + pub fn from_sequence(data: &Rc>) -> Set { + Self::from_array(data.to_array().borrow()) + } + pub fn from_hashset_owned(hashset: HashSet) -> Set { + Set { + data: Rc::new(hashset), + } + } + pub fn cardinality_usize(&self) -> usize { + self.data.len() + } + pub fn cardinality(&self) -> DafnyInt { + DafnyInt::from_usize(self.data.len()) + } + pub fn contains(&self, value: &V) -> bool { + self.data.contains(value) + } + pub fn merge(&self, other: &Set) -> Set { + if self.cardinality_usize() == 0 { + return other.clone(); + } + if other.cardinality_usize() == 0 { + return self.clone(); + } + let mut result = self.data.as_ref().clone(); + // iterate over the other, add only not contained elements + for value in other.data.iter() { + if !result.contains(value) { + result.insert(value.clone()); + } + } + Set::from_hashset_owned(result) + } + + pub fn intersect(&self, other: &Set) -> Set { + if self.cardinality_usize() == 0 { + return self.clone(); + } + if other.cardinality_usize() == 0 { + return other.clone(); + } + // Start with an empty vec with capacity the smallest of both sets + let mut result = HashSet::new(); + + // iterate over the other, take only elements in common + for value in self.data.iter() { + if other.data.contains(value) { + result.insert(value.clone()); + } + } + Set::from_hashset_owned(result) + } + + pub fn subtract(&self, other: &Set) -> Set { + if self.cardinality_usize() == 0 { + return self.clone(); + } + if other.cardinality_usize() == 0 { + return self.clone(); + } + // Start with a vec the size of the first one + let mut result = HashSet::new(); + + // iterate over the other, take only elements not in second + for value in self.data.iter() { + if !other.contains(value) { + result.insert(value.clone()); + } + } + Set::from_hashset_owned(result) + } + + pub fn disjoint(&self, other: &Set) -> bool { + if self.cardinality_usize() == 0 { + return true; + } + if other.cardinality_usize() == 0 { + return true; + } + if other.data.len() < self.data.len() { + // iterate over the other, take only elements not in self + for value in other.data.iter() { + if self.contains(value) { + return false; + } + } + } else { + // iterate over the self, take only elements not in other + for value in self.data.iter() { + if other.contains(value) { + return false; + } + } + } + true + } + + pub fn equals(&self, other: &Set) -> bool { + if self.cardinality_usize() != other.cardinality_usize() { + return false; + } + // iterate over the other, take only elements not in second + for value in other.data.iter() { + if !self.contains(value) { + return false; + } + } + true + } + + pub fn elements(&self) -> Set { + self.clone() + } + + pub fn as_dafny_multiset(&self) -> Multiset { + Multiset::from_set(self) + } + + pub fn iter(&self) -> std::collections::hash_set::Iter<'_, V> { + self.data.iter() + } + + pub fn peek(&self) -> V { + self.data.iter().next().unwrap().clone() + } +} + +pub struct SetBuilder +where + T: Clone + Eq + Hash, +{ + data: HashMap, +} + +impl Default for SetBuilder { + fn default() -> Self { + Self::new() + } +} + +impl SetBuilder { + pub fn new() -> SetBuilder { + SetBuilder { + data: HashMap::new(), + } + } + pub fn add(&mut self, value: &T) { + // Dafny will prove that overriding has the same value anyway + self.data.insert(value.clone(), true); + } + pub fn build(self) -> Set { + // Iterate over all the key values of the hashmap and add them to an array + let mut result: Vec = Vec::new(); + for (k, _v) in self.data.iter() { + result.push(k.clone()); + } + + Set::from_array(&result) + } +} + +impl DafnyPrint for Set { + fn fmt_print(&self, f: &mut Formatter<'_>, in_seq: bool) -> std::fmt::Result { + f.write_str("{")?; + let mut first = true; + for value in self.data.iter() { + if !first { + f.write_str(", ")?; + } + first = false; + value.fmt_print(f, in_seq)?; + } + f.write_str("}") + } +} + +impl Debug for Set +where + V: DafnyTypeEq, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.fmt_print(f, false) + } +} + +// ******************* +// Immutable multisets +// ******************* + +#[derive(Clone)] +pub struct Multiset { + pub data: HashMap, + pub size: DafnyInt, +} + +impl Multiset { + pub fn new_empty() -> Multiset { + Self::from_array(&vec![]) + } + pub fn get_total(map: &HashMap) -> DafnyInt { + let mut total = DafnyInt::zero(); + for (_, v) in map.iter() { + total = total + v.clone(); + } + total + } + pub fn from_hashmap_owned(map: HashMap) -> Multiset { + Multiset { + size: Self::get_total(&map), + data: map, + } + } + pub fn from_hashmap(map: &HashMap) -> Multiset { + Self::from_hashmap_owned(map.clone()) + } + pub fn from_array(data: &Vec) -> Multiset { + Self::from_iterator(data.iter().cloned()) + } + pub fn from_iterator(data: I) -> Multiset + where + I: Iterator, + { + let mut hashmap: HashMap = HashMap::new(); + let mut total: DafnyInt = DafnyInt::zero(); + for value in data { + let count = hashmap.entry(value.clone()).or_insert(DafnyInt::zero()); + *count = count.clone() + DafnyInt::one(); + total = total + DafnyInt::one(); + } + Multiset { + data: hashmap, + size: total, + } + } + pub fn from_set(set: &Set) -> Multiset { + Self::from_iterator(set.data.iter().cloned()) + } + + pub fn cardinality_usize(&self) -> SizeT { + self.size.as_usize() + } + pub fn cardinality(&self) -> DafnyInt { + self.size.clone() + } + pub fn contains(&self, value: &V) -> bool { + self.data.contains_key(value) && self.data.get(value).unwrap() > &DafnyInt::zero() + } + pub fn get(&self, value: &V) -> DafnyInt { + if self.data.contains_key(value) { + self.data.get(value).unwrap().clone() + } else { + DafnyInt::zero() + } + } + pub fn update_count(&self, value: &V, new_count: &DafnyInt) -> Multiset { + let mut result = self.clone(); + let old_count = self.get(value); + if new_count == &DafnyInt::zero() { + result.data.remove(value); + } else { + result.data.insert(value.clone(), new_count.clone()); + } + result.size = self.size.clone() + new_count.clone() - old_count; + result + } + pub fn merge(&self, other: &Multiset) -> Multiset { + if other.size.is_zero() { + return self.clone(); + } + if self.size.is_zero() { + return other.clone(); + } + let mut result = self.data.clone(); + for (k, v) in other.data.iter() { + let old_count = self.get(k); + let new_count = old_count.clone() + v.clone(); + result.insert(k.clone(), new_count); + } + Multiset { + data: result, + size: self.size.clone() + other.size.clone(), + } + } + pub fn intersect(&self, other: &Multiset) -> Multiset { + if other.size.is_zero() { + return other.clone(); + } + if self.size.is_zero() { + return self.clone(); + } + let mut result = HashMap::::new(); + let mut total = DafnyInt::zero(); + for (k, other_count) in other.data.iter() { + let self_count = self.get(k); + let resulting_count = if self_count < *other_count { + self_count + } else { + other_count.clone() + }; + if resulting_count.is_positive() { + result.insert(k.clone(), resulting_count.clone()); + total = total + resulting_count; + } + } + Multiset { + data: result, + size: total, + } + } + pub fn subtract(&self, other: &Multiset) -> Multiset { + if other.size.is_zero() { + return self.clone(); + } + if self.size.is_zero() { + return self.clone(); + } + let mut result = self.data.clone(); + let mut total = self.size.clone(); + for (k, v) in other.data.iter() { + let old_count = self.get(k); + let new_count = old_count.clone() - v.clone(); + if !new_count.is_positive() { + total = total - old_count.clone(); + result.remove(k); + } else { + total = total - v.clone(); + result.insert(k.clone(), new_count); + } + } + Multiset { + data: result, + size: total, + } + } + pub fn disjoint(&self, other: &Multiset) -> bool { + for value in other.data.keys() { + if self.contains(value) { + return false; + } + } + true + } + + pub fn as_dafny_multiset(&self) -> Multiset { + self.clone() + } + + pub fn peek(&self) -> V { + self.data.iter().next().unwrap().0.clone() + } + + pub fn iter_raw(&self) -> std::collections::hash_map::Iter<'_, V, DafnyInt> { + self.data.iter() + } + + pub fn iter(&self) -> impl Iterator + '_ { + self.data + .iter() + .flat_map(|(k, v)| ::std::iter::repeat(k).take(v.clone().as_usize())) + .cloned() + } +} + +impl Default for Multiset +where + T: DafnyTypeEq, +{ + fn default() -> Self { + Self::new_empty() + } +} +impl NontrivialDefault for Multiset { + fn nontrivial_default() -> Self { + Self::default() + } +} + +impl PartialOrd> for Multiset { + fn partial_cmp(&self, other: &Multiset) -> Option { + match self.cardinality().cmp(&other.cardinality()) { + Ordering::Less => { + for value in self.data.keys() { + if !other.contains(value) || self.get(value) > other.get(value) { + return None; + } + } + Some(Ordering::Less) + } + Ordering::Equal => { + for value in self.data.keys() { + if self.get(value) != other.get(value) { + return None; + } + } + Some(Ordering::Equal) + } + Ordering::Greater => { + for value in other.data.keys() { + if !self.contains(value) || self.get(value) < other.get(value) { + return None; + } + } + Some(Ordering::Greater) + } + } + } +} + +impl DafnyPrint for Multiset { + fn fmt_print(&self, f: &mut Formatter<'_>, in_seq: bool) -> std::fmt::Result { + f.write_str("multiset{")?; + let mut first = true; + for value in self.data.iter() { + for _count in 0..value.1.as_usize() { + if !first { + f.write_str(", ")?; + } + first = false; + value.0.fmt_print(f, in_seq)?; + } + } + f.write_str("}") + } +} + +impl Debug for Multiset +where + V: DafnyTypeEq, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.fmt_print(f, false) + } +} + +impl PartialEq> for Multiset { + fn eq(&self, other: &Multiset) -> bool { + if self.cardinality() != other.cardinality() { + return false; + } + // iterate over the other, take only elements not in second + for value in other.data.iter() { + if !self.contains(value.0) || self.get(value.0) != *value.1 { + return false; + } + } + true + } +} +impl Eq for Multiset {} +impl Hash for Multiset { + fn hash(&self, state: &mut H) { + self.cardinality().hash(state); + } +} + +pub fn euclidian_division(a: A, b: A) -> A { + if !a.is_negative() { + if !b.is_negative() { + a / b + } else { + -(a / -b) + } + } else { + if !b.is_negative() { + -((-(a + One::one())) / b) - One::one() + } else { + (-(a + One::one())) / (-b) + One::one() + } + } +} + +pub fn euclidian_modulo(a: A, b: A) -> A { + if !a.is_negative() { + if !b.is_negative() { + a % b + } else { + a % -b + } + } else { + let bp = b.abs(); + let c = (-a) % bp.clone(); + if c == Zero::zero() { + Zero::zero() + } else { + bp - c + } + } +} + +pub struct IntegerRange + One + Ord + Clone> { + hi: A, + current: A, +} + +impl + One + Ord + Clone> Iterator for IntegerRange { + type Item = A; + + fn next(&mut self) -> Option { + if self.current < self.hi { + let result = self.current.clone(); + self.current = self.current.clone() + One::one(); + Some(result) + } else { + None + } + } +} + +pub fn integer_range + One + Ord + Clone>( + low: A, + hi: A, +) -> impl Iterator { + IntegerRange { hi, current: low } +} + +pub struct IntegerRangeDown + One + Ord + Clone> { + current: A, + low: A, +} + +impl + One + Ord + Clone> Iterator for IntegerRangeDown { + type Item = A; + + fn next(&mut self) -> Option { + if self.current > self.low { + self.current = self.current.clone() - One::one(); + Some(self.current.clone()) + } else { + None + } + } +} + +pub fn integer_range_down + One + Ord + Clone>( + hi: A, + low: A, +) -> impl Iterator { + IntegerRangeDown { current: hi, low } +} + +// Unbounded versions + +pub struct IntegerRangeUnbounded + One + Clone> { + current: A, +} +impl + One + Clone> Iterator for IntegerRangeUnbounded { + type Item = A; + + fn next(&mut self) -> Option { + let result = self.current.clone(); + self.current = self.current.clone() + One::one(); + Some(result) + } +} +pub fn integer_range_unbounded + One + Clone>( + low: A, +) -> impl Iterator { + IntegerRangeUnbounded { current: low } +} + +pub struct IntegerRangeDownUnbounded + One + Clone> { + current: A, +} + +impl + One + Clone> Iterator for IntegerRangeDownUnbounded { + type Item = A; + + fn next(&mut self) -> Option { + self.current = self.current.clone() - One::one(); + Some(self.current.clone()) + } +} + +pub fn integer_range_down_unbounded + One + Clone>( + hi: A, +) -> impl Iterator { + IntegerRangeDownUnbounded { current: hi } +} + +pub struct LazyFieldWrapper(pub Lazy A>>); + +impl PartialEq for LazyFieldWrapper { + fn eq(&self, other: &Self) -> bool { + self.0.deref() == other.0.deref() + } +} + +impl Default for LazyFieldWrapper { + fn default() -> Self { + Self(Lazy::new(Box::new(A::default))) + } +} + +impl DafnyPrint for LazyFieldWrapper { + fn fmt_print(&self, f: &mut Formatter<'_>, in_seq: bool) -> std::fmt::Result { + self.0.deref().fmt_print(f, in_seq) + } +} + +#[cfg(feature = "sync")] +// Convert the DafnyPrint above into a macro so that we can create it for functions of any input arity +macro_rules! dafny_print_function { + ($($n:tt)*) => { + impl $crate::DafnyPrint for $crate::Rc B + Send + Sync> { + fn fmt_print(&self, f: &mut ::std::fmt::Formatter<'_>, _in_seq: bool) -> ::std::fmt::Result { + write!(f, "") + } + } + } +} +#[cfg(not(feature = "sync"))] +// Convert the DafnyPrint above into a macro so that we can create it for functions of any input arity +macro_rules! dafny_print_function { + ($($n:tt)*) => { + impl $crate::DafnyPrint for $crate::Rc B> { + fn fmt_print(&self, f: &mut ::std::fmt::Formatter<'_>, _in_seq: bool) -> ::std::fmt::Result { + write!(f, "") + } + } + } +} + +// Now create a loop like impl_tuple_print_loop so that we can create functions up to size 32 +macro_rules! dafny_print_function_loop { + ($first:ident $($rest:ident)*) => { + dafny_print_function_loop! { $($rest)* } + dafny_print_function! { $first $($rest)* } + }; + () => { + } +} +// Emit functions till 32 parameters +dafny_print_function_loop! { A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15 A16 +A17 A18 A19 A20 A21 A22 A23 A24 A25 A26 A27 A28 A29 A30 A31 A32 } + +pub struct FunctionWrapper(pub A); +impl DafnyPrint for FunctionWrapper { + fn fmt_print(&self, f: &mut Formatter<'_>, _in_seq: bool) -> std::fmt::Result { + write!(f, "") + } +} + +impl Clone for FunctionWrapper { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} + +impl PartialEq for FunctionWrapper> { + fn eq(&self, other: &Self) -> bool { + Rc::ptr_eq(&self.0, &other.0) + } +} + +pub struct DafnyPrintWrapper(pub T); +impl Display for DafnyPrintWrapper<&T> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.0.fmt_print(f, false) + } +} + +pub trait DafnyPrint { + fn fmt_print(&self, f: &mut Formatter<'_>, in_seq: bool) -> std::fmt::Result; + + // Vec gets special treatment so we carry that information here + #[inline] + fn is_char() -> bool { + false + } +} + +impl DafnyPrint for *const T { + fn fmt_print(&self, f: &mut Formatter<'_>, _in_seq: bool) -> std::fmt::Result { + write!(f, "<{} object>", std::any::type_name::()) + } +} + +macro_rules! impl_print_display { + ($name:ty) => { + impl $crate::DafnyPrint for $name { + fn fmt_print( + &self, + f: &mut ::std::fmt::Formatter<'_>, + _in_seq: bool, + ) -> ::std::fmt::Result { + ::std::fmt::Display::fmt(&self, f) + } + } + }; +} + +impl_print_display! { String } +impl_print_display! { bool } +impl_print_display! { u8 } +impl_print_display! { u16 } +impl_print_display! { u32 } +impl_print_display! { u64 } +impl_print_display! { u128 } +impl_print_display! { i8 } +impl_print_display! { i16 } +impl_print_display! { i32 } +impl_print_display! { i64 } +impl_print_display! { i128 } +impl_print_display! { usize } + +impl DafnyPrint for f32 { + fn fmt_print(&self, f: &mut Formatter<'_>, _in_seq: bool) -> std::fmt::Result { + write!(f, "{:.1}", self) + } +} + +impl DafnyPrint for f64 { + fn fmt_print(&self, f: &mut Formatter<'_>, _in_seq: bool) -> std::fmt::Result { + write!(f, "{:.1}", self) + } +} + +impl DafnyPrint for () { + fn fmt_print(&self, f: &mut Formatter<'_>, _in_seq: bool) -> std::fmt::Result { + write!(f, "()") + } +} + +#[derive(Clone, Copy)] +pub struct DafnyCharUTF16(pub u16); +pub type DafnyStringUTF16 = Sequence; + +impl Default for DafnyCharUTF16 { + fn default() -> Self { + Self('a' as u16) + } +} + +impl DafnyPrint for DafnyCharUTF16 { + #[inline] + fn fmt_print(&self, f: &mut Formatter<'_>, in_seq: bool) -> std::fmt::Result { + let real_char = char::decode_utf16([*self].iter().map(|v| v.0)) + .map(|r| r.map_err(|e| e.unpaired_surrogate())) + .collect::>()[0]; + let rendered_char = match real_char { + Ok(c) => c, + Err(e) => { + return write!(f, "Invalid UTF-16 code point: {}", e); + } + }; + + if in_seq { + write!(f, "{}", rendered_char) + } else { + write!(f, "'{}'", rendered_char) + } + } + + #[inline] + fn is_char() -> bool { + true + } +} + +impl Debug for DafnyCharUTF16 { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.fmt_print(f, false) + } +} + +impl PartialEq for DafnyCharUTF16 { + fn eq(&self, other: &DafnyCharUTF16) -> bool { + self.0 == other.0 + } +} +impl Eq for DafnyCharUTF16 {} +impl Hash for DafnyCharUTF16 { + fn hash(&self, state: &mut H) { + self.0.hash(state) + } +} + +impl PartialOrd for DafnyCharUTF16 { + fn partial_cmp(&self, other: &DafnyCharUTF16) -> Option { + (self.0).partial_cmp(&other.0) + } +} + +impl Add for DafnyCharUTF16 { + type Output = DafnyCharUTF16; + + fn add(self, rhs: DafnyCharUTF16) -> Self::Output { + DafnyCharUTF16(self.0 + rhs.0) + } +} + +impl Sub for DafnyCharUTF16 { + type Output = DafnyCharUTF16; + + fn sub(self, rhs: DafnyCharUTF16) -> Self::Output { + DafnyCharUTF16(self.0 - rhs.0) + } +} + +#[derive(Clone, Copy)] +pub struct DafnyChar(pub char); +pub type DafnyString = Sequence; + +impl Default for DafnyChar { + fn default() -> Self { + Self('a') + } +} + +impl DafnyPrint for DafnyChar { + #[inline] + fn fmt_print(&self, f: &mut Formatter<'_>, in_seq: bool) -> std::fmt::Result { + if in_seq { + write!(f, "{}", self.0) + } else { + write!(f, "'{}'", self.0) + } + } + + #[inline] + fn is_char() -> bool { + true + } +} + +impl Debug for DafnyChar { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.fmt_print(f, false) + } +} + +impl PartialEq for DafnyChar { + fn eq(&self, other: &DafnyChar) -> bool { + self.0 == other.0 + } +} + +impl PartialOrd for DafnyChar { + fn partial_cmp(&self, other: &DafnyChar) -> Option { + (self.0 as u32).partial_cmp(&(other.0 as u32)) + } +} +impl Eq for DafnyChar {} +impl Hash for DafnyChar { + fn hash(&self, state: &mut H) { + self.0.hash(state) + } +} + +impl Add for DafnyChar { + type Output = DafnyChar; + + fn add(self, rhs: DafnyChar) -> Self::Output { + DafnyChar(unsafe { char::from_u32_unchecked(self.0 as u32 + rhs.0 as u32) }) + } +} + +impl Sub for DafnyChar { + type Output = DafnyChar; + + fn sub(self, rhs: DafnyChar) -> Self::Output { + DafnyChar(unsafe { char::from_u32_unchecked(self.0 as u32 - rhs.0 as u32) }) + } +} + +impl DafnyPrint for Option { + fn fmt_print(&self, f: &mut Formatter<'_>, _in_seq: bool) -> std::fmt::Result { + match self { + Some(x) => x.fmt_print(f, false), + None => write!(f, "null"), + } + } +} + +impl DafnyPrint for Rc { + fn fmt_print(&self, f: &mut Formatter<'_>, in_seq: bool) -> std::fmt::Result { + self.as_ref().fmt_print(f, in_seq) + } +} + +impl DafnyPrint for &Rc { + fn fmt_print(&self, f: &mut Formatter<'_>, in_seq: bool) -> std::fmt::Result { + self.as_ref().fmt_print(f, in_seq) + } +} + +impl DafnyPrint for Vec { + fn fmt_print(&self, f: &mut Formatter<'_>, _in_seq: bool) -> std::fmt::Result { + if !T::is_char() { + write!(f, "[")?; + } + + for (i, item) in self.iter().enumerate() { + if !T::is_char() { + if i > 0 { + write!(f, ", ")?; + } + + item.fmt_print(f, false)?; + } else { + item.fmt_print(f, true)?; + } + } + + if !T::is_char() { + write!(f, "]") + } else { + Ok(()) + } + } +} + +#[cfg(not(feature = "sync"))] +impl DafnyPrint for RefCell { + fn fmt_print(&self, f: &mut Formatter<'_>, _in_seq: bool) -> std::fmt::Result { + self.borrow().fmt_print(f, _in_seq) + } +} + +#[cfg(feature = "sync")] +impl DafnyPrint for RefCell { + fn fmt_print(&self, f: &mut Formatter<'_>, _in_seq: bool) -> std::fmt::Result { + self.lock().unwrap().fmt_print(f, _in_seq) + } +} + +impl DafnyPrint for HashSet { + fn fmt_print(&self, f: &mut Formatter<'_>, _in_seq: bool) -> std::fmt::Result { + write!(f, "{{")?; + + for (i, item) in self.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + item.fmt_print(f, false)?; + } + + write!(f, "}}") + } +} + +pub fn char_lt(left: char, right: char) -> bool { + let left_code = left as u32; + let right_code = right as u32; + + left_code < right_code +} + +pub fn string_of(s: &str) -> DafnyString { + s.chars().map(DafnyChar).collect::>() +} + +pub fn string_utf16_of(s: &str) -> DafnyStringUTF16 { + Sequence::from_array_owned(s.encode_utf16().map(DafnyCharUTF16).collect()) +} + +macro_rules! impl_tuple_print { + ($($items:ident)*) => { + impl <$($items,)*> $crate::DafnyPrint for ($($items,)*) + where + $($items: $crate::DafnyPrint,)* + { + #[allow(unused_assignments)] + fn fmt_print(&self, f: &mut ::std::fmt::Formatter<'_>, _in_seq: bool) -> ::std::fmt::Result { + #[allow(non_snake_case)] + let ($($items,)*) = self; + + write!(f, "(")?; + + let mut i = 0; + + $( + if (i > 0) { + write!(f, ", ")?; + } + + $items.fmt_print(f, false)?; + + i += 1; + )* + + write!(f, ")") + } + } + }; +} + +macro_rules! impl_tuple_print_loop { + () => {}; + ($first:ident $($rest:ident)*) => { + impl_tuple_print_loop! { $($rest)* } + impl_tuple_print! { $first $($rest)* } + }; +} + +// 32 elements ought to be enough for everyone +impl_tuple_print_loop! { + A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 + A11 A12 A13 A14 A15 A16 A17 A18 A19 A20 + A21 A22 A23 A24 A25 A26 A27 A28 A29 A30 + A31 +} + +// seq!(1, 2, 3) is rewritten to Sequence::from_array_owned(vec!(1, 2, 3)) +#[macro_export] +macro_rules! seq { + ($($x:expr),*) => { + $crate::Sequence::from_array_owned(vec![$($x), *]) + } +} + +#[macro_export] +macro_rules! set { + ($($x:expr), *) => { + { + // No warning about this variable not needing to be mut in the case of an empty set + #[allow(unused_mut)] + let mut temp_hash = ::std::collections::HashSet::new(); + $( + temp_hash.insert($x); + )* + $crate::Set::from_hashset_owned(temp_hash) + } + } +} + +#[macro_export] +macro_rules! multiset { + ($($x:expr), *) => { + { + #[allow(unused_mut)] + let mut temp_hash = ::std::collections::HashMap::new(); + #[allow(unused_mut)] + let mut total_size: usize = 0; + $( { + #[allow(unused_mut)] + let mut entry = temp_hash.entry($x).or_insert($crate::DafnyInt::from(0)); + *entry = (*entry).clone() + $crate::DafnyInt::from(1); + total_size += 1; + } + )* + $crate::Multiset { + data: temp_hash, + size: $crate::DafnyInt::from(total_size), + } + } + } +} + +// we enable the syntax map![k1 => v1, k2 => v2] +#[macro_export] +macro_rules! map { + ($($k:expr => $v:expr), *) => { + { + #[allow(unused_mut)] + let mut temp_hash = ::std::collections::HashMap::new(); + $( + temp_hash.insert($k.clone(), $v.clone()); + )* + $crate::Map::from_hashmap_owned(temp_hash) + } + } +} + +#[macro_export] +macro_rules! int { + ($x:expr) => { + $crate::DafnyInt::from($x) + }; +} + +////////// +// Arrays +////////// + +macro_rules! ARRAY_GETTER_LENGTH0 { + () => { + #[inline] + pub fn length0(&self) -> $crate::DafnyInt { + $crate::DafnyInt::from(self.length0_usize()) + } + #[inline] + pub fn length0_usize(&self) -> usize { + self.data.len() + } + }; +} +macro_rules! ARRAY_GETTER_LENGTH { + ($field: ident, $field_usize: ident) => { + #[inline] + pub fn $field(&self) -> $crate::DafnyInt { + $crate::DafnyInt::from(self.$field_usize()) + } + #[inline] + pub fn $field_usize(&self) -> usize { + self.$field + } + }; +} + +// An 1-dimensional Dafny array is a zero-cost abstraction over a pointer on a native array +#[macro_export] +macro_rules! array { + ($($x:expr), *) => { + $crate::array::from_native(::std::boxed::Box::new([$($x), *])) + } +} + +macro_rules! ARRAY_INIT { + {$length: ident, $inner: expr} => { + $crate::array::initialize_box_usize($length, { + $crate::Rc::new(move |_| { $inner }) + }) + } +} + +macro_rules! ARRAY_INIT_INNER { + ($length: ident) => { + $crate::array::placebos_box_usize::($length) + }; +} + +// ARRAY_DATA_TYPE(length0, length1, length2) will return +// Box<[Box<[Box<[T]>]>]> +macro_rules! ARRAY_DATA_TYPE { + ($length:ident) => { + ::std::boxed::Box<[T]> + }; + ($length:ident, $($rest_length:ident),+) => { + ::std::boxed::Box<[ARRAY_DATA_TYPE!($($rest_length),+)]> + }; +} + +// Macro to generate generalizations of the function placebos_usize to higher-dimensions arrays + +#[macro_export] +macro_rules! INIT_ARRAY_DATA { + // Handle the innermost array initialization + ($ArrayType:ident, $last_length:ident) => { + ARRAY_INIT_INNER!($last_length) + }; + // Handle recursive array initialization for multiple dimensions + ($ArrayType:ident, $first_length:ident, $($rest_length:ident),+) => { + ARRAY_INIT!($first_length, INIT_ARRAY_DATA!($ArrayType, $($rest_length),+)) + }; +} + +macro_rules! ARRAY_METHODS { + // Accepts any number of length identifiers + ($ArrayType:ident, $length0: ident, $($length:ident),+) => { + pub fn placebos_box_usize( + $length0: usize, + $($length: usize),+ + ) -> ::std::boxed::Box<$ArrayType<$crate::MaybeUninit>> { + ::std::boxed::Box::new($ArrayType { + $($length: $length),+, + data: INIT_ARRAY_DATA!($ArrayType, $length0, $($length),+), + }) + } + + pub fn placebos_usize( + $length0: usize, + $($length: usize),+ + ) -> $crate::Ptr<$ArrayType<$crate::MaybeUninit>> { + $crate::Ptr::from_box(Self::placebos_box_usize( + $length0, + $($length),+ + )) + } + + pub fn placebos_usize_object( + $length0: usize, + $($length: usize),+ + ) -> $crate::Object<$ArrayType<$crate::MaybeUninit>> { + // SAFETY: We know the object is owned and never referred to by anything else + $crate::Object::new($ArrayType { + $($length: $length),+, + data: INIT_ARRAY_DATA!($ArrayType, $length0, $($length),+), + }) + } + + pub fn placebos( + $length0: &$crate::DafnyInt, + $($length: &$crate::DafnyInt),+ + ) -> $crate::Ptr<$ArrayType<$crate::MaybeUninit>> { + Self::placebos_usize( + $length0.as_usize(), + $($length.as_usize()),+ + ) + } + + // Once all the elements have been initialized, transform the signature of the pointer + pub fn construct(p: $crate::Ptr<$ArrayType<$crate::MaybeUninit>>) -> $crate::Ptr<$ArrayType> { + unsafe { std::mem::transmute(p) } + } + // Once all the elements have been initialized, transform the signature of the pointer + pub fn construct_object(p: $crate::Object<$ArrayType<$crate::MaybeUninit>>) -> $crate::Object<$ArrayType> { + unsafe { std::mem::transmute(p) } + } + }; +} + +macro_rules! ARRAY_STRUCT { + ($ArrayType:ident, $length0: ident, $($length:ident),+) => { + pub struct $ArrayType { + $($length: usize),+, + pub data: ARRAY_DATA_TYPE!($length0, $($length),+), + } + } +} + +macro_rules! ARRAY_TO_VEC_LOOP { + (@inner $self: ident, $tmp: ident, $data: expr) => { + $tmp.push($data.clone()); + }; + (@for $self: ident, $tmp: ident, $data: expr, $length_usize: ident $(, $rest_length_usize: ident)*) => { + for i in 0..$self.$length_usize() { + ARRAY_TO_VEC_LOOP!(@inner $self, $tmp, $data[i] $(, $rest_length_usize)*); + } + }; + (@inner $self: ident, $outerTmp: ident, $data: expr $(, $rest_length_usize: ident)*) => { + { + let mut tmp = ::std::vec::Vec::new(); + ARRAY_TO_VEC_LOOP!(@for $self, tmp, $data $(, $rest_length_usize)*); + $outerTmp.push(tmp); + } + }; + + ($self: ident, $data: expr $(, $rest_length_usize: ident)*) => { + { + let mut tmp = ::std::vec::Vec::new(); + ARRAY_TO_VEC_LOOP!(@for $self, tmp, $data $(, $rest_length_usize)*); + tmp + } + }; +} + +macro_rules! ARRAY_TO_VEC_TYPE { + ($length0: ident) => { + ::std::vec::Vec + }; + ($length0: ident $(, $res_length: ident)*) => { + ::std::vec::Vec + } +} + +macro_rules! ARRAY_TO_VEC { + ($length0_usize: ident $(, $res_length_usize: ident)*) => { + pub fn to_vec(&self) -> ARRAY_TO_VEC_TYPE!($length0_usize, $($res_length_usize),*) { + ARRAY_TO_VEC_LOOP!(self, self.data, $length0_usize, $($res_length_usize),*) + } + } +} + +macro_rules! ARRAY_LENGTHS { + () => { + + }; + (($length0: ident, $length0_usize: ident) $(, $rest: tt)*) => { + ARRAY_GETTER_LENGTH0!(); + ARRAY_LENGTHS!($(, $rest)*); + }; + (, ($length: ident, $length_usize: ident) $(, $rest: tt)*) => { + ARRAY_GETTER_LENGTH!($length, $length_usize); + ARRAY_LENGTHS!($(, $rest)*); + } +} + +macro_rules! ARRAY_METHODS_WRAPPER { + ($ArrayType:ident, $(($length:ident, $length_usize: ident)), +) => { + ARRAY_METHODS!($ArrayType, $($length), +); + } +} + +macro_rules! ARRAY_TO_VEC_WRAPPER { + ($(($length:ident, $length_usize: ident)), +) => { + ARRAY_TO_VEC!($($length_usize), +); + } +} + +macro_rules! ARRAY_STRUCT_WRAPPER { + ($ArrayType:ident, $(($length:ident, $length_usize: ident)), +) => { + ARRAY_STRUCT!($ArrayType, $($length), +); + } +} + +macro_rules! ARRAY_DEF { + ($ArrayType:ident, $(($length:ident, $length_usize: ident)), +) => { + ARRAY_STRUCT_WRAPPER!($ArrayType, $(($length, $length_usize)), +); + impl $ArrayType { + ARRAY_LENGTHS!{ + $(($length, $length_usize)), + + } + ARRAY_METHODS_WRAPPER!{$ArrayType, + $(($length, $length_usize)), + + } + } + impl $ArrayType { + ARRAY_TO_VEC_WRAPPER!{ + $(($length, $length_usize)), + + } + } + } +} + +// Array2 to Array16 + +ARRAY_DEF! {Array2, + (length0, length0_usize), + (length1, length1_usize) +} + +ARRAY_DEF! {Array3, + (length0, length0_usize), + (length1, length1_usize), + (length2, length2_usize) +} + +ARRAY_DEF! {Array4, + (length0, length0_usize), + (length1, length1_usize), + (length2, length2_usize), + (length3, length3_usize) +} + +ARRAY_DEF! {Array5, + (length0, length0_usize), + (length1, length1_usize), + (length2, length2_usize), + (length3, length3_usize), + (length4, length4_usize) +} + +ARRAY_DEF! {Array6, + (length0, length0_usize), + (length1, length1_usize), + (length2, length2_usize), + (length3, length3_usize), + (length4, length4_usize), + (length5, length5_usize) +} + +ARRAY_DEF! {Array7, + (length0, length0_usize), + (length1, length1_usize), + (length2, length2_usize), + (length3, length3_usize), + (length4, length4_usize), + (length5, length5_usize), + (length6, length6_usize) +} + +ARRAY_DEF! {Array8, + (length0, length0_usize), + (length1, length1_usize), + (length2, length2_usize), + (length3, length3_usize), + (length4, length4_usize), + (length5, length5_usize), + (length6, length6_usize), + (length7, length7_usize) +} + +ARRAY_DEF! {Array9, + (length0, length0_usize), + (length1, length1_usize), + (length2, length2_usize), + (length3, length3_usize), + (length4, length4_usize), + (length5, length5_usize), + (length6, length6_usize), + (length7, length7_usize), + (length8, length8_usize) +} + +ARRAY_DEF! {Array10, + (length0, length0_usize), + (length1, length1_usize), + (length2, length2_usize), + (length3, length3_usize), + (length4, length4_usize), + (length5, length5_usize), + (length6, length6_usize), + (length7, length7_usize), + (length8, length8_usize), + (length9, length9_usize) +} + +ARRAY_DEF! {Array11, + (length0, length0_usize), + (length1, length1_usize), + (length2, length2_usize), + (length3, length3_usize), + (length4, length4_usize), + (length5, length5_usize), + (length6, length6_usize), + (length7, length7_usize), + (length8, length8_usize), + (length9, length9_usize), + (length10, length10_usize) +} + +ARRAY_DEF! {Array12, + (length0, length0_usize), + (length1, length1_usize), + (length2, length2_usize), + (length3, length3_usize), + (length4, length4_usize), + (length5, length5_usize), + (length6, length6_usize), + (length7, length7_usize), + (length8, length8_usize), + (length9, length9_usize), + (length10, length10_usize), + (length11, length11_usize) +} + +ARRAY_DEF! {Array13, + (length0, length0_usize), + (length1, length1_usize), + (length2, length2_usize), + (length3, length3_usize), + (length4, length4_usize), + (length5, length5_usize), + (length6, length6_usize), + (length7, length7_usize), + (length8, length8_usize), + (length9, length9_usize), + (length10, length10_usize), + (length11, length11_usize), + (length12, length12_usize) +} + +ARRAY_DEF! {Array14, + (length0, length0_usize), + (length1, length1_usize), + (length2, length2_usize), + (length3, length3_usize), + (length4, length4_usize), + (length5, length5_usize), + (length6, length6_usize), + (length7, length7_usize), + (length8, length8_usize), + (length9, length9_usize), + (length10, length10_usize), + (length11, length11_usize), + (length12, length12_usize), + (length13, length13_usize) +} + +ARRAY_DEF! {Array15, + (length0, length0_usize), + (length1, length1_usize), + (length2, length2_usize), + (length3, length3_usize), + (length4, length4_usize), + (length5, length5_usize), + (length6, length6_usize), + (length7, length7_usize), + (length8, length8_usize), + (length9, length9_usize), + (length10, length10_usize), + (length11, length11_usize), + (length12, length12_usize), + (length13, length13_usize), + (length14, length14_usize) +} + +ARRAY_DEF! {Array16, + (length0, length0_usize), + (length1, length1_usize), + (length2, length2_usize), + (length3, length3_usize), + (length4, length4_usize), + (length5, length5_usize), + (length6, length6_usize), + (length7, length7_usize), + (length8, length8_usize), + (length9, length9_usize), + (length10, length10_usize), + (length11, length11_usize), + (length12, length12_usize), + (length13, length13_usize), + (length14, length14_usize), + (length15, length15_usize) +} + +pub mod array { + use super::DafnyInt; + use super::Ptr; + use super::Rc; + use ::std::boxed::Box; + use ::std::mem::MaybeUninit; + use ::std::vec::Vec; + use num::ToPrimitive; + + #[inline] + pub fn from_native(v: Box<[T]>) -> Ptr<[T]> { + Ptr::from_box(v) + } + #[inline] + pub fn from_vec(v: Vec) -> Ptr<[T]> { + from_native(v.into_boxed_slice()) + } + pub fn to_vec(v: Ptr<[T]>) -> Vec { + unsafe { Box::<[T]>::from_raw(v.into_raw()) }.into_vec() + } + pub fn initialize_usize(n: usize, initializer: Rc T>) -> Ptr<[T]> { + let mut v = Vec::with_capacity(n); + for i in 0..n { + v.push(initializer(i)); + } + from_vec(v) + } + + pub fn placebos(n: &DafnyInt) -> Ptr<[MaybeUninit]> { + placebos_usize(n.as_usize()) + } + pub fn placebos_usize(n: usize) -> Ptr<[MaybeUninit]> { + Ptr::from_box(placebos_box_usize(n)) + } + pub fn placebos_usize_object(n: usize) -> super::Object<[MaybeUninit]> { + super::rcmut::array_object_from_box(placebos_box_usize(n)) + } + // Once all the elements have been initialized, transform the signature of the pointer + pub fn construct(p: Ptr<[MaybeUninit]>) -> Ptr<[T]> { + unsafe { std::mem::transmute(p) } + } + pub fn construct_object(p: super::Object<[MaybeUninit]>) -> super::Object<[T]> { + unsafe { std::mem::transmute(p) } + } + + pub fn placebos_box(n: &DafnyInt) -> Box<[MaybeUninit]> { + placebos_box_usize(n.to_usize().unwrap()) + } + pub fn placebos_box_usize(n_usize: usize) -> Box<[MaybeUninit]> { + // This code is optimized to take a constant time. See: + // https://users.rust-lang.org/t/allocate-a-boxed-array-of-maybeuninit/110169/7 + std::iter::repeat_with(MaybeUninit::uninit) + .take(n_usize) + .collect() + } + + pub fn initialize(n: &DafnyInt, initializer: Rc T>) -> Ptr<[T]> { + Ptr::from_box(initialize_box(n, initializer)) + } + + pub fn initialize_box(n: &DafnyInt, initializer: Rc T>) -> Box<[T]> { + initialize_box_usize(n.to_usize().unwrap(), initializer) + } + pub fn initialize_box_usize( + n_usize: usize, + initializer: Rc T>, + ) -> Box<[T]> { + let mut v = Vec::with_capacity(n_usize); + for i in 0..n_usize { + v.push(initializer(&int!(i))); + } + v.into_boxed_slice() + } + + #[inline] + pub fn length_usize(this: Ptr<[T]>) -> usize { + // safety: Dafny won't call this function unless it can guarantee the array is still allocated + super::read!(this).len() + } + #[inline] + pub fn length(this: Ptr<[T]>) -> DafnyInt { + int!(length_usize(this)) + } + #[inline] + pub fn get_usize(this: Ptr<[T]>, i: usize) -> T { + // safety: Dafny won't call this function unless it can guarantee the array is still allocated + this.as_ref()[i].clone() + } + #[inline] + pub fn get(this: Ptr<[T]>, i: &DafnyInt) -> T { + get_usize(this, i.to_usize().unwrap()) + } + #[inline] + pub fn update_usize(this: Ptr<[T]>, i: usize, val: T) { + // safety: Dafny won't call this function unless it can guarantee the array is still allocated + crate::modify!(this)[i] = val; + } + #[inline] + pub fn update(this: Ptr<[T]>, i: &DafnyInt, val: T) { + update_usize(this, i.to_usize().unwrap(), val); + } +} + +/////////////////// +// Class helpers // +/////////////////// +pub fn allocate() -> Ptr { + let this_ptr = Box::into_raw(Box::new(MaybeUninit::uninit())) as *mut MaybeUninit as *mut T; + Ptr::from_raw_nonnull(this_ptr) +} +// Generic function to safely deallocate a raw pointer +#[inline] +pub fn deallocate(pointer: Ptr) { + // safety: Dafny won't call this function unless it can guarantee the object is still allocated + unsafe { + // Takes ownership of the reference, + // so that it's deallocated at the end of the method + drop(Box::from_raw(pointer.into_raw())); + } +} + +pub struct ExactPool { + current: T, + yielded: bool, +} + +// Implement iterator for an exact pool, yielding +impl Iterator for ExactPool { + type Item = T; + fn next(&mut self) -> Option { + if self.yielded { + None + } else { + self.yielded = true; + Some(self.current.clone()) + } + } +} +pub fn exact_range(value: T) -> ExactPool { + ExactPool { + current: value, + yielded: false, + } +} + +// Any Dafny trait must require classes extending it to have a method "as_any_mut" +// that can convert the reference from that trait to a reference of Any + +// 'is' is meant to be used on references only, to check if a trait reference is a class reference +#[macro_export] +macro_rules! is { + ($raw:expr, $id:ty) => { + $crate::modify!($crate::cast_any!($raw)) + .downcast_mut::<$id>() + .is_some() + }; +} + +#[macro_export] +macro_rules! is_object { + ($raw:expr, $id:ty) => { + $crate::md!($crate::cast_any_object!($raw)) + .downcast_mut::<$id>() + .is_some() + }; +} + +// cast_any is meant to be used on references only, to convert any references (classes or traits)* +// to an Any reference trait +#[macro_export] +macro_rules! cast_any { + ($raw:expr) => { + $crate::Upcast::<$crate::DynAny>::upcast($crate::read!($raw)) + }; +} +// cast_any_object is meant to be used on references only, to convert any references (classes or traits)* +// to an Any reference trait +#[macro_export] +macro_rules! cast_any_object { + ($obj:expr) => { + $crate::UpcastObject::<$crate::DynAny>::upcast($crate::md!($obj)) + }; +} + +// When initializing an uninitialized field for the first time, +// we ensure we don't drop the previous content +// This is problematic if the same field is overwritten multiple times +/// In that case, prefer to use update_uninit +#[macro_export] +macro_rules! update_field_nodrop { + ($ptr:expr, $field:ident, $value:expr) => { + $crate::update_nodrop!($crate::modify!($ptr).$field, $value) + }; +} + +// Same as update_field_nodrop but for mutable fields +#[macro_export] +macro_rules! update_field_mut_nodrop { + ($ptr:expr, $field:ident, $value:expr) => { + let lhs = $ptr; + let value = $value; + unsafe { $crate::read!(lhs).$field.get().write(value) } + }; +} + +// When initializing an uninitialized field for the first time, +// we ensure we don't drop the previous content +#[macro_export] +macro_rules! update_nodrop { + ($ptr:expr, $value:expr) => { + // safety: Dafny won't call this function unless it can guarantee the value at the address was not + // yet initialized, so that not dropping it won't create a memory leak + unsafe { ::std::ptr::addr_of_mut!($ptr).write($value) } + } +} + +// Given a class or array pointer, transforms it to a mutable reference +#[macro_export] +macro_rules! modify { + ($ptr:expr) => {{ + #[allow(unused_unsafe)] + let tmp = + unsafe { &mut *($crate::UnsafeCell::raw_get($ptr.0.unwrap_unchecked().as_ptr())) }; + tmp + }}; +} + +// Given a class or array pointer, transforms it to a read-only reference +#[macro_export] +macro_rules! read { + ($ptr:expr) => {{ + #[allow(unused_unsafe)] + let tmp = unsafe { &*($crate::UnsafeCell::raw_get($ptr.0.unwrap_unchecked().as_ptr())) }; + tmp + }}; +} + +// If the field is guaranteed to be assigned only once, update_field_nodrop is sufficient +#[macro_export] +macro_rules! update_field_uninit { + ($t:expr, $field:ident, $field_assigned:expr, $value:expr) => {{ + let computed_value = $value; + #[allow(unused_assignments)] + if $field_assigned { + $crate::modify!($t).$field = computed_value; + } else { + $crate::update_field_nodrop!($t, $field, computed_value); + $field_assigned = true; + } + }}; +} + +// Same as update_field_uninit but for mutable fields +#[macro_export] +macro_rules! update_field_mut_uninit { + ($t:expr, $field:ident, $field_assigned:expr, $value:expr) => {{ + let computed_value = $value; + #[allow(unused_assignments)] + if $field_assigned { + $crate::modify_field!($crate::read!($t).$field, computed_value); + } else { + $crate::update_field_mut_nodrop!($t, $field, computed_value); + $field_assigned = true; + } + }}; +} + +// Macro to call at the end of the first new; constructor when not every field is guaranteed to be assigned. +#[macro_export] +macro_rules! update_field_if_uninit { + ($t:expr, $field:ident, $field_assigned:expr, $value:expr) => {{ + let computed_value = $value; + if !$field_assigned { + $crate::update_field_nodrop!($t, $field, computed_value); + $field_assigned = true; + } + }}; +} + +// Same as update_field_if_uninit but for mutable fields +#[macro_export] +macro_rules! update_field_mut_if_uninit { + ($t:expr, $field:ident, $field_assigned:expr, $value:expr) => {{ + let computed_value = $value; + if !$field_assigned { + $crate::update_field_mut_nodrop!($t, $field, computed_value); + $field_assigned = true; + } + }}; +} + +///////////////// +// Raw pointers (require wrapping because of equality) +///////////////// + +// This Ptr has the same run-time space as *mut +pub struct Ptr(pub Option>>); + +#[cfg(feature = "sync")] +unsafe impl Send for Ptr {} + +#[cfg(feature = "sync")] +unsafe impl Sync for Ptr {} + +impl Ptr { + pub fn null() -> Self { + Ptr(None) + } + pub fn is_null(&self) -> bool { + self.0.is_none() + } + #[inline] + pub fn from_raw_nonnull(t: *mut T) -> Ptr { + unsafe { + Ptr(Some(::std::mem::transmute::< + NonNull, + NonNull>, + >(NonNull::new_unchecked(t)))) + } + } + pub fn from_box(t: Box) -> Ptr { + Self::from_raw_nonnull(Box::into_raw(t)) + } + pub fn into_raw(self) -> *mut T { + if self.is_null() { + panic!("Cannot turn a null pointer into a raw pointer"); + } + let nonnull = unsafe { self.0.unwrap_unchecked() }; + unsafe { ::std::mem::transmute::<_, *mut T>(nonnull.as_ptr()) } + } +} + +impl> Ptr { + pub fn is_instance_of(self) -> bool { + if self.is_null() { + false + } else { + read!(Upcast::::upcast(read!(self))) + .downcast_ref::() + .is_some() + } + } +} + +impl NontrivialDefault for Ptr { + fn nontrivial_default() -> Self { + // Create a null pointer + Self::null() + } +} + +impl Ptr { + pub fn new(val: T) -> Ptr { + Self::from_box(Box::new(val)) + } +} + +impl Eq for Ptr {} + +impl Clone for Ptr { + fn clone(&self) -> Self { + *self + } +} + +impl Copy for Ptr {} + +impl Default for Ptr { + fn default() -> Self { + Ptr::null() + } +} + +impl Debug for Ptr { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.fmt_print(f, false) + } +} +impl DafnyPrint for Ptr { + fn fmt_print(&self, f: &mut Formatter<'_>, _in_seq: bool) -> std::fmt::Result { + write!(f, "") + } +} + +impl PartialEq> for Ptr { + fn eq(&self, other: &Ptr) -> bool { + if !self.is_null() { + if !other.is_null() { + // To compare addresses, we need to ensure we only compare thin pointers + // https://users.rust-lang.org/t/comparing-addresses-between-fat-and-thin-pointers/89008 + ::std::ptr::eq( + self.clone().into_raw() as *const (), + other.clone().into_raw() as *const (), + ) + } else { + false + } + } else if !other.is_null() { + false + } else { + true + } + } +} + +impl Hash for Ptr { + fn hash(&self, state: &mut H) { + if !self.is_null() { + (read!(self.clone()) as *const T as *const ()).hash(state); + } else { + 0.hash(state); + } + } +} + +impl AsMut for Ptr { + fn as_mut(&mut self) -> &mut T { + modify!(self.clone()) + } +} +impl AsRef for Ptr { + fn as_ref(&self) -> &T { + read!(self.clone()) + } +} + +impl Ptr { + // Never use on local values, only on &self types previously called on Ptr types. + pub fn from_ref(r: &T) -> Ptr { + Ptr(unsafe { ::std::mem::transmute::<_, Option>>>(r as *const T) }) + } +} +// cast is meant to be used on references only, to downcast a trait reference to a class reference +#[macro_export] +macro_rules! cast { + ($raw:expr, $id:ty) => {{ + #[allow(unused_unsafe)] + let tmp = unsafe { + let expr = $raw; + let res: $crate::Ptr<$id> = if expr.is_null() { + $crate::Ptr::null() + } else { + $crate::Ptr::from_raw_nonnull(expr.into_raw() as *mut $id) + }; + res + }; + tmp + }}; +} + +///////////////// +// Reference-counted classes mode +///////////////// + +pub struct Object(pub Option>); + +impl Object { + // For safety, it requires the Rc to have been created with Rc::new() + pub unsafe fn from_rc(rc: Rc) -> Object { + unsafe { Object(Some(rcmut::from_rc(rc))) } + } + pub fn null() -> Object { + Object(None) + } + pub fn is_null(&self) -> bool { + self.0.is_none() + } +} +impl> Object { + pub fn is_instance_of(self) -> bool { + // safety: Dafny won't call this function unless it can guarantee the object is still allocated + rd!(UpcastObject::::upcast(rd!(self))) + .downcast_ref::() + .is_some() + } +} +impl Object { + pub fn new(val: T) -> Object { + Object(Some(rcmut::new(val))) + } +} +impl Eq for Object {} + +impl Clone for Object { + fn clone(&self) -> Self { + Object(self.0.clone()) + } +} + +impl Default for Object { + fn default() -> Self { + Object(None) + } +} + +impl> Debug for Object { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.fmt_print(f, false) + } +} +impl> DafnyPrint for Object { + fn fmt_print(&self, f: &mut Formatter<'_>, _in_seq: bool) -> std::fmt::Result { + let obj_any = UpcastObject::::upcast(self.as_ref()); + let option_string = obj_any.as_ref().downcast_ref::(); + match option_string { + Some(s) => write!(f, "{}", s), + None => write!(f, ""), + } + } +} + +impl DafnyPrint for Object<[T]> { + fn fmt_print(&self, f: &mut Formatter<'_>, _in_seq: bool) -> std::fmt::Result { + write!(f, "") + } +} +impl UpcastObject for String { + fn upcast(&self) -> Object { + // SAFETY: RC was just created + unsafe { Object::from_rc(Rc::new(self.clone()) as Rc) } + } +} + +impl PartialEq> for Object { + fn eq(&self, other: &Object) -> bool { + if let Some(p) = &self.0 { + if let Some(q) = &other.0 { + // To compare addresses, we need to ensure we only compare thin pointers + // https://users.rust-lang.org/t/comparing-addresses-between-fat-and-thin-pointers/89008 + ::std::ptr::eq(p.as_ref().get() as *const (), q.as_ref().get() as *const ()) + } else { + false + } + } else if let Some(_q) = &other.0 { + false + } else { + true + } + } +} + +impl Hash for Object { + fn hash(&self, state: &mut H) { + if let Some(p) = &self.0 { + (p.as_ref().get() as *const ()).hash(state); + } else { + 0.hash(state); + } + } +} + +impl AsMut for Object { + fn as_mut(&mut self) -> &mut T { + unsafe { &mut *(self.0).as_ref().unwrap_unchecked().as_ref().get() } + } +} +impl AsRef for Object { + fn as_ref(&self) -> &T { + unsafe { &*(self.0).as_ref().unwrap_unchecked().as_ref().get() } + } +} + +// Never inline because, when compiling with cargo --release, sometimes it gets rid of this statement +#[inline(never)] +fn increment_strong_count(data: *const T) { + // SAFETY: This method is called only on values that were constructed from an Rc + unsafe { + // Black box avoids the compiler wrongly inferring that increment strong count does nothing since the data it was applied to can be traced to be borrowed + ::std::hint::black_box(Rc::increment_strong_count(data)); + } +} + +impl Object { + // SAFETY: This function needs to be called from a reference obtained by calling read!(o) on an object + // We never inline this function, otherwise the compiler might figure out a way to remove the increment_strong_count + #[inline(never)] + pub fn from_ref(r: &T) -> Object { + let pt = r as *const T as *const UnsafeCell; + // SAFETY: Not guaranteed unfortunately. But looking at the sources of from_raw as of today 10/24/2024 + // it will will correctly rebuilt the Rc + let rebuilt = ::std::hint::black_box(unsafe { Rc::from_raw(pt) }); + let _previous_strong_count = ::std::hint::black_box(Rc::strong_count(&rebuilt)); + ::std::hint::black_box(increment_strong_count(pt)); + let _new_strong_count = ::std::hint::black_box(Rc::strong_count(&rebuilt)); + #[cfg(not(feature = "sync"))] + assert_eq!(_new_strong_count, _previous_strong_count + 1); // Will panic if not. Asserted only in sequential mode + Object(Some(rebuilt)) + } +} + +#[macro_export] +macro_rules! cast_object { + ($raw:expr, $id:ty) => { + unsafe { + let res: $crate::Object<$id> = $crate::Object(Some($crate::Rc::from_raw( + $crate::Rc::into_raw($raw.0.unwrap()) as _, + ))); + res + } + }; +} + +// Returns an object whose fields are yet initialized. Only use update_field_uninit_object and update_field_if_uninit_object to initialize fields. +pub fn allocate_object() -> Object { + unsafe { mem::transmute(object::new::>(MaybeUninit::uninit())) } +} + +pub struct AllocationTracker { + allocations: Vec>, +} + +#[cfg(feature = "sync")] +pub fn allocate_object_track( + allocation_tracker: &mut AllocationTracker, +) -> Object { + let res = allocate_object::(); + allocation_tracker + .allocations + .push(Rc::>::downgrade(&res.0.clone().unwrap())); + res +} +#[cfg(not(feature = "sync"))] +pub fn allocate_object_track(allocation_tracker: &mut AllocationTracker) -> Object { + let res = allocate_object::(); + allocation_tracker + .allocations + .push(Rc::>::downgrade(&res.0.clone().unwrap())); + res +} + +// Equivalent of update_field_nodrop but for rcmut +#[macro_export] +macro_rules! update_field_nodrop_object { + ($ptr:expr, $field: ident, $value:expr) => { + $crate::update_nodrop_object!( + ($crate::rcmut::borrow_mut(&mut $ptr.0.clone().unwrap())).$field, + $value + ) + }; +} + +// Same but for mutable fields +#[macro_export] +macro_rules! update_field_mut_nodrop_object { + ($ptr:expr, $field: ident, $value:expr) => { + unsafe { + ($crate::rcmut::borrow_mut(&mut $ptr.0.clone().unwrap())) + .$field + .get() + .write($value) + } + }; +} + +// Equivalent of update_nodrop but for rcmut +#[macro_export] +macro_rules! update_nodrop_object { + ($ptr:expr, $value:expr) => { + unsafe { ::std::ptr::addr_of_mut!($ptr).write($value) } + }; +} + +// Equivalent of update_field_if_uninit but for rcmut +#[macro_export] +macro_rules! update_field_if_uninit_object { + ($t:expr, $field:ident, $field_assigned:expr, $value:expr) => {{ + #[allow(unused_assignments)] + if !$field_assigned { + let computed_value = $value; + $crate::update_field_nodrop_object!($t, $field, computed_value); + $field_assigned = true; + } + }}; +} + +// Same for mutable fields +#[macro_export] +macro_rules! update_field_mut_if_uninit_object { + ($t:expr, $field:ident, $field_assigned:expr, $value:expr) => {{ + #[allow(unused_assignments)] + if !$field_assigned { + let computed_value = $value; + $crate::update_field_mut_nodrop_object!($t, $field, computed_value); + $field_assigned = true; + } + }}; +} + +// Equivalent of update_field_uninit but for rcmut +#[macro_export] +macro_rules! update_field_uninit_object { + ($t:expr, $field:ident, $field_assigned:expr, $value:expr) => {{ + let computed_value = $value; + #[allow(unused_assignments)] + if $field_assigned { + $crate::md!($t).$field = computed_value; + } else { + $crate::update_field_nodrop_object!($t, $field, computed_value); + $field_assigned = true; + } + }}; +} + +// Same but for mutable fields +#[macro_export] +macro_rules! update_field_mut_uninit_object { + ($t:expr, $field:ident, $field_assigned:expr, $value:expr) => {{ + let computed_value = $value; + #[allow(unused_assignments)] + if $field_assigned { + $crate::modify_field!($crate::rd!($t).$field, computed_value); + } else { + $crate::update_field_mut_nodrop_object!($t, $field, computed_value); + $field_assigned = true; + } + }}; +} + +// Equivalent of modify but for rcmut +#[macro_export] +macro_rules! md { + ($x:expr) => { + $x.clone().as_mut() + }; +} + +// Equivalent of read but for rcmut +#[macro_export] +macro_rules! rd { + ($x:expr) => { + $x.as_ref() + }; +} + +// To use when modifying a mutable field that is wrapped with UnsafeCell +#[macro_export] +macro_rules! modify_field { + ($pointer:expr, $rhs:expr) => {{ + let lhs = $pointer.get(); + let rhs = $rhs; + unsafe { *lhs = rhs } + }}; +} + +// To use when reading a mutable field that is wrapped with UnsafeCell +#[macro_export] +macro_rules! read_field { + ($pointer:expr) => {{ + let lhs = $pointer.get(); + unsafe { (*lhs).clone() } + }}; +} + +pub type Field = UnsafeCell; +pub fn new_field(t: T) -> Field { + UnsafeCell::new(t) +} + +// Count the number of references to the given object +#[macro_export] +macro_rules! refcount { + ($x:expr) => { + $crate::Rc::strong_count(unsafe { $crate::rcmut::as_rc($x.0.as_ref().unwrap()) }) + }; +} + +pub mod object { + use crate::{Any, DynAny}; + + pub fn downcast(_self: crate::Object) -> crate::Object { + super::cast_object!(_self, T) + } + + pub fn new(val: T) -> crate::Object { + crate::Object(Some(crate::rcmut::new(val))) + } + #[inline] + pub fn is(_self: crate::Object) -> bool { + is_object!(_self, T) + } +} + +// Inspired from https://crates.io/crates/rcmut +pub mod rcmut { + use crate::Rc; + use crate::UnsafeCell; + use ::std::mem::{self, MaybeUninit}; + + pub fn array_object_from_rc(data: Rc<[T]>) -> crate::Object<[T]> { + crate::Object(Some(unsafe { from_rc(data) })) + } + pub fn array_object_from_box(data: Box<[T]>) -> crate::Object<[T]> { + let data: Rc<[T]> = data.into(); + crate::Object(Some(unsafe { from_rc(data) })) + } + pub struct Array { + pub data: Box<[T]>, + } + impl Array { + pub fn new(data: Box<[T]>) -> crate::Object> { + crate::Object(Some(new(Array { data }))) + } + + pub fn placebos_usize_object(length: usize) -> crate::Object>> { + let x = crate::array::placebos_box_usize::(length); + Array::>::new(x) + } + } + /// A reference counted smart pointer with unrestricted mutability. + pub type RcMut = Rc>; + + /// Create a new RcMut for a value. + pub fn new(val: T) -> RcMut { + Rc::new(UnsafeCell::new(val)) + } + /// Retrieve the inner Rc as a reference. + pub unsafe fn from(value: Box) -> RcMut { + unsafe { mem::transmute(Rc::new(*value)) } + } + + pub unsafe fn from_rc(value: Rc) -> RcMut { + unsafe { mem::transmute(value) } + } + + pub unsafe fn as_rc(this: &RcMut) -> &Rc { + unsafe { mem::transmute(this) } + } + pub unsafe fn to_rc(this: RcMut) -> Rc { + unsafe { mem::transmute(this) } + } + + /// Retrieve the inner Rc as a mutable reference. + pub unsafe fn as_rc_mut(this: &mut RcMut) -> &mut Rc { + unsafe { mem::transmute(this) } + } + + /// Get a reference to the value. + #[inline] + pub unsafe fn borrow(this: &RcMut) -> &T { + unsafe { &*this.get() } + } + + /// Get a mutable reference to the value. + #[inline] + pub unsafe fn borrow_mut(this: &mut RcMut) -> &mut T { + unsafe { &mut *this.get() } + } + + #[cfg(feature = "sync")] + pub unsafe fn downcast( + this: RcMut, + ) -> Option> { + let t: Rc = unsafe { to_rc(this) }; + let t: Rc = Rc::downcast::(t).ok()?; + unsafe { mem::transmute(t) } + } + + #[cfg(not(feature = "sync"))] + pub unsafe fn downcast(this: RcMut) -> Option> { + let t: Rc = unsafe { to_rc(this) }; + let t: Rc = Rc::downcast::(t).ok()?; + unsafe { mem::transmute(t) } + } +} + +///////////////// +// Method helpers +///////////////// + +// A MaybePlacebo is a value that is either a placebo or a real value. +// It is a wrapper around a MaybeUninit value, but knowing whether the value is a placebo or not. +// That way, when it is dropped, the underlying value is only dropped if it is not a placebo. + +#[derive(Clone)] +pub struct MaybePlacebo(Option); +impl MaybePlacebo { + #[inline] + pub fn read(&self) -> T { + // safety: Dafny will guarantee we will never read a placebo value + unsafe { self.0.clone().unwrap_unchecked() } + } +} + +impl MaybePlacebo { + #[inline] + pub fn new() -> Self { + MaybePlacebo(None) + } + #[inline] + pub fn from(v: T) -> Self { + MaybePlacebo(Some(v)) + } +} + +#[macro_export] +macro_rules! tuple_extract_index { + ($x:expr, $i:expr) => { + $x.$i + }; +} + +// A macro that maps tuple (a, b, c...) to produce (MaybePlacebo::from(a), MaybePlacebo::from(b), MaybePlacebo::from(c)) +// maybe_placebos_from!(expr, 0, 1, 2, 3) +// = let x = expr; +// (MaybePlacebo::from(x.0), MaybePlacebo::from(x.1), MaybePlacebo::from(x.2), MaybePlacebo::from(x.3)) +#[macro_export] +macro_rules! maybe_placebos_from { + ($x:expr, $($i:tt), *) => { + { + let x = $x; + ( + $( $crate::MaybePlacebo::from(x.$i), )* + ) + } + } +} + +//////////////// +// Coercion +//////////////// + +pub fn upcast_object() -> Rc) -> Object> +where + A: UpcastObject, +{ + Rc::new(|x: Object| x.as_ref().upcast()) +} + +pub fn upcast() -> Rc) -> Ptr> +where + A: Upcast, +{ + Rc::new(|x: Ptr| read!(x).upcast()) +} + +pub fn upcast_box() -> Rc Box> +where + A: UpcastBox, +{ + Rc::new(|x: A| UpcastBox::upcast(&x)) +} +pub fn upcast_box_box() -> Rc) -> Box> +where + A: UpcastBox, +{ + Rc::new(|x: Box| UpcastBox::upcast(x.as_ref())) +} + +pub fn upcast_id() -> Rc A> { + Rc::new(|x: A| x) +} + +pub fn rc_coerce(f: Rc U>) -> Rc) -> Rc> { + Rc::new(move |x: Rc| Rc::new(f.as_ref()(x.as_ref().clone()))) +} +pub fn box_coerce(f: Box U>) -> Box) -> Box> { + Box::new(move |x: Box| Box::new(f.as_ref()(x.as_ref().clone()))) +} + +pub fn fn1_coerce( + a_to_r: Rc R + 'static>, +) -> Rc A>) -> Rc R> + 'static> { + Rc::new(move |t_to_a: Rc A>| { + let a_to_r = a_to_r.clone(); + let t_to_a = t_to_a.clone(); + let r: Rc R + 'static> = Rc::new(move |t: &T| a_to_r(t_to_a(t))); + r + }) +} + +// For pointers +pub trait Upcast { + fn upcast(&self) -> Ptr; +} +pub trait UpcastObject { + fn upcast(&self) -> Object; +} +impl Upcast for T { + fn upcast(&self) -> Ptr { + Ptr::from_raw_nonnull(self as *const T as *mut T) + } +} +impl UpcastObject for T { + fn upcast(&self) -> Object { + Object::from_ref(self) + } +} + +// For general traits +pub trait UpcastBox { + fn upcast(&self) -> Box; +} + +impl UpcastBox for Rc +where + U: UpcastBox, +{ + fn upcast(&self) -> Box { + UpcastBox::upcast(AsRef::as_ref(self)) + } +} + +pub trait AnyRef { + fn as_any_ref(&self) -> &dyn Any; +} + +impl AnyRef for T { + fn as_any_ref(&self) -> &dyn Any { + self + } +} + +#[macro_export] +macro_rules! Extends { + ($traitType: tt) => { + $traitType + ::dafny_runtime::Upcast + } +} + +#[macro_export] +macro_rules! UpcastFn { + ($B:ty) => { + fn upcast(&self) -> $crate::Ptr<$B> { + $crate::Ptr::from_raw_nonnull(self as *const Self as *mut Self as *mut $B) + } + }; +} + +#[macro_export] +macro_rules! UpcastObjectFn { + ($B:ty) => { + fn upcast(&self) -> $crate::Object<$B> { + $crate::Object::from_ref(self as &$B) + } + }; +} + +// It works only when there is no type parameters for $A... +#[macro_export] +macro_rules! UpcastDef { + ($A:ty, $B:ty) => { + impl $crate::Upcast<$B> for $A { + $crate::UpcastFn!($B); + } + }; + + ($A:ty, $B:ty, $($C: ty),*) => { + $crate::UpcastDef!($A, $B); + $crate::UpcastDef!($A, $($C),*); + } +} + +#[macro_export] +macro_rules! UpcastDefObject { + ($A:ty, $B:ty) => { + impl $crate::UpcastObject<$B> for $A { + $crate::UpcastObjectFn!($B); + } + }; + + ($A:ty, $B:ty, $($C: ty),*) => { + $crate::UpcastDefObject!($A, $B); + $crate::UpcastDefObject!($A, $($C),*); + } +} + +// Coercions for sets +impl Set { + pub fn coerce(f: Rc V>) -> Rc) -> Set> { + Rc::new(move |x: Set| { + // We need to upcast individual elements + let f2 = f.clone(); + let mut new_set: HashSet = HashSet::::default(); + for value in x.data.iter() { + new_set.insert(f2(value.clone())); + } + Set::from_hashset_owned(new_set) + }) + } +} + +// Coercions for sequences +impl Sequence { + pub fn coerce(f: Rc V>) -> Rc) -> Sequence> { + // We need to upcast individual elements + Rc::new(move |x: Sequence| { + let mut new_seq: Vec = Vec::::default(); + let f2 = f.clone(); + for value in x.to_array().iter() { + new_seq.push(f2(value.clone())); + } + Sequence::from_array_owned(new_seq) + }) + } +} + +// Coercions for multisets +impl Multiset { + pub fn coerce( + f: Rc V>, + ) -> Rc) -> Multiset> { + // We need to upcast individual elements + Rc::new(move |x: Multiset| { + let f2 = f.clone(); + // We need to upcast individual elements + let mut new_multiset: HashMap = HashMap::::default(); + for (value, count) in x.data.into_iter() { + new_multiset.insert(f2(value), count.clone()); + } + Multiset::from_hashmap_owned(new_multiset) + }) + } +} + +// Coercions for Maps +impl Map { + pub fn coerce(f: Rc V>) -> Rc) -> Map> { + // We need to upcast individual elements + Rc::new(move |x: Map| { + let f2 = f.clone(); + let mut new_map: HashMap = HashMap::::default(); + for (key, value) in x.data.iter() { + new_map.insert(key.clone(), f2(value.clone())); + } + Map::from_hashmap_owned(new_map) + }) + } +} diff --git a/src/trust_engine/kernel/runtime/src/small_int.rs b/src/trust_engine/kernel/runtime/src/small_int.rs new file mode 100644 index 0000000..cba1e1a --- /dev/null +++ b/src/trust_engine/kernel/runtime/src/small_int.rs @@ -0,0 +1,335 @@ +#![allow(unused_imports)] + +use crate::DafnyPrint; +use crate::Rc; +use num::FromPrimitive; +use num::ToPrimitive; +use num::{bigint::ParseBigIntError, Integer, Num, One, Signed, Zero}; +use std::{ + clone::Clone, + cmp::Ordering, + convert::From, + fmt::Formatter, + hash::Hash, + ops::{Add, Div, Mul, Neg, Rem, Sub}, +}; + +type InternalInt = i128; + +#[derive(Clone, Copy)] +pub struct DafnyInt { + data: InternalInt, +} + +const ONE: DafnyInt = DafnyInt { data: 1 }; +const ZERO: DafnyInt = DafnyInt { data: 0 }; + +impl DafnyInt { + pub fn new(data: InternalInt) -> DafnyInt { + DafnyInt { data } + } +} + +impl AsRef for DafnyInt { + fn as_ref(&self) -> &InternalInt { + &self.data + } +} + +impl Default for DafnyInt { + fn default() -> Self { + ZERO + } +} + +impl Zero for DafnyInt { + #[inline] + fn zero() -> Self { + ZERO + } + #[inline] + fn is_zero(&self) -> bool { + self.data == 0 + } +} +impl One for DafnyInt { + #[inline] + fn one() -> Self { + ONE + } +} + +impl Num for DafnyInt { + type FromStrRadixErr = std::num::ParseIntError; + + #[inline] + fn from_str_radix(s: &str, radix: u32) -> Result { + let x = InternalInt::from_str_radix(s, radix)?; + Ok(DafnyInt::new(x)) + } +} + +impl Ord for DafnyInt { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + self.data.cmp(&other.data) + } +} +impl Signed for DafnyInt { + #[inline] + fn abs(&self) -> Self { + DafnyInt { + data: self.data.abs(), + } + } + + #[inline] + fn abs_sub(&self, other: &Self) -> Self { + DafnyInt { + data: self.data.abs_sub(&other.data), + } + } + + #[inline] + fn signum(&self) -> Self { + DafnyInt { + data: self.data.signum(), + } + } + + #[inline] + fn is_positive(&self) -> bool { + self.data.is_positive() + } + + #[inline] + fn is_negative(&self) -> bool { + self.data.is_negative() + } +} + +// Comparison +impl PartialOrd for DafnyInt { + #[inline] + fn partial_cmp(&self, other: &DafnyInt) -> Option { + Some(self.cmp(other)) + } +} + +impl DafnyInt { + #[inline] + pub fn parse_bytes(number: &[u8], radix: u32) -> DafnyInt { + let x = InternalInt::from_str_radix(std::str::from_utf8(number).unwrap(), radix).unwrap(); + DafnyInt::new(x) + } + pub fn from_usize(usize: usize) -> DafnyInt { + DafnyInt { + data: usize as InternalInt, + } + } + pub fn from_i32(i: i32) -> DafnyInt { + DafnyInt { + data: i as InternalInt, + } + } +} + +// impl From<&[u8; N]> for DafnyInt { +// fn from(number: &[u8; N]) -> Self { +// DafnyInt::parse_bytes(number, 10) +// } +// } + +// impl From<&[u8]> for DafnyInt { +// fn from(val: &[u8]) -> DafnyInt { +// DafnyInt::parse_bytes(val, 10) +// } +// } + +impl From for u8 { + fn from(val: DafnyInt) -> Self { + val.data.to_u8().unwrap() + } +} +impl From for u16 { + fn from(val: DafnyInt) -> Self { + val.data.to_u16().unwrap() + } +} +impl From for u32 { + fn from(val: DafnyInt) -> Self { + val.data.to_u32().unwrap() + } +} +impl From for u64 { + fn from(val: DafnyInt) -> Self { + val.data.to_u64().unwrap() + } +} +impl From for u128 { + fn from(val: DafnyInt) -> Self { + val.data.to_u128().unwrap() + } +} +impl From for i8 { + fn from(val: DafnyInt) -> Self { + val.data.to_i8().unwrap() + } +} +impl From for i16 { + fn from(val: DafnyInt) -> Self { + val.data.to_i16().unwrap() + } +} +impl From for i32 { + fn from(val: DafnyInt) -> Self { + val.data.to_i32().unwrap() + } +} +impl From for i64 { + fn from(val: DafnyInt) -> Self { + val.data.to_i64().unwrap() + } +} +impl From for i128 { + fn from(val: DafnyInt) -> Self { + val.data.to_i128().unwrap() + } +} +impl From for usize { + fn from(val: DafnyInt) -> Self { + val.data.to_usize().unwrap() + } +} + +impl ToPrimitive for DafnyInt { + fn to_i64(&self) -> Option { + self.data.to_i64() + } + + fn to_u64(&self) -> Option { + self.data.to_u64() + } + + // Override of functions + fn to_u128(&self) -> Option { + self.data.to_u128() + } + + fn to_i128(&self) -> Option { + self.data.to_i128() + } +} + +impl PartialEq for DafnyInt { + fn eq(&self, other: &DafnyInt) -> bool { + self.data.eq(&other.data) + } +} +impl Eq for DafnyInt {} +impl Hash for DafnyInt { + fn hash(&self, state: &mut H) { + self.data.hash(state); + } +} + +impl DafnyPrint for DafnyInt { + fn fmt_print(&self, f: &mut Formatter<'_>, _in_seq: bool) -> std::fmt::Result { + write!(f, "{}", self.data) + } +} + +impl ::std::fmt::Debug for DafnyInt { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.data) + } +} + +impl Add for DafnyInt { + type Output = DafnyInt; + + fn add(self, rhs: DafnyInt) -> Self::Output { + DafnyInt { + data: self.data + rhs.data, + } + } +} + +impl Mul for DafnyInt { + type Output = DafnyInt; + + fn mul(self, rhs: DafnyInt) -> Self::Output { + DafnyInt { + data: self.data * rhs.data, + } + } +} + +impl Div for DafnyInt { + type Output = DafnyInt; + + fn div(self, rhs: DafnyInt) -> Self::Output { + DafnyInt { + data: self.data / rhs.data, + } + } +} + +impl Sub for DafnyInt { + type Output = DafnyInt; + + fn sub(self, rhs: DafnyInt) -> Self::Output { + DafnyInt { + data: self.data - rhs.data, + } + } +} +impl Rem for DafnyInt { + type Output = DafnyInt; + + fn rem(self, rhs: DafnyInt) -> Self::Output { + DafnyInt { + data: self.data % rhs.data, + } + } +} +impl Neg for DafnyInt { + type Output = DafnyInt; + + #[inline] + fn neg(self) -> Self::Output { + DafnyInt { data: -self.data } + } +} + +macro_rules! impl_dafnyint_from { + () => {}; + ($type:ident) => { + #[allow(trivial_numeric_casts)] + impl ::std::convert::From<$type> for $crate::DafnyInt { + fn from(n: $type) -> Self { + $crate::DafnyInt { + data: n as InternalInt, + } + } + } + #[allow(trivial_numeric_casts)] + impl $crate::DafnyUsize for $type { + fn into_usize(self) -> usize { + self as usize + } + } + }; +} + +impl_dafnyint_from! { u8 } +impl_dafnyint_from! { u16 } +impl_dafnyint_from! { u32 } +impl_dafnyint_from! { u64 } +impl_dafnyint_from! { u128 } +impl_dafnyint_from! { i8 } +impl_dafnyint_from! { i16 } +impl_dafnyint_from! { i32 } +impl_dafnyint_from! { i64 } +impl_dafnyint_from! { i128 } +impl_dafnyint_from! { usize } diff --git a/src/trust_engine/kernel/runtime/src/system/mod.rs b/src/trust_engine/kernel/runtime/src/system/mod.rs new file mode 100644 index 0000000..1324293 --- /dev/null +++ b/src/trust_engine/kernel/runtime/src/system/mod.rs @@ -0,0 +1,3983 @@ +#![allow(warnings, unconditional_panic)] +#![allow(nonstandard_style)] +#![cfg_attr(any(), rustfmt::skip)] + +pub mod _System { + pub use crate::DafnyInt; + pub use crate::DafnyType; + pub use ::std::fmt::Debug; + pub use ::std::fmt::Formatter; + pub use ::std::fmt::Result; + pub use crate::DafnyPrint; + #[cfg(feature = "sync")] pub use ::std::sync::{Arc as Rc}; #[cfg(not(feature = "sync"))] pub use ::std::rc::Rc; + pub use ::std::cmp::Eq; + pub use ::std::hash::Hash; + pub use ::std::cmp::PartialEq; + pub use ::std::hash::Hasher; + pub use ::std::convert::AsRef; + pub use crate::SequenceIter; + pub use crate::seq; + + pub type nat = DafnyInt; + + #[derive(Clone)] + pub enum Tuple2 { + _T2 { + _0: T0, + _1: T1 + } + } + + impl Tuple2 { + /// Returns a borrow of the field _0 + pub fn _0(&self) -> &T0 { + match self { + Tuple2::_T2{_0, _1, } => _0, + } + } + /// Returns a borrow of the field _1 + pub fn _1(&self) -> &T1 { + match self { + Tuple2::_T2{_0, _1, } => _1, + } + } + } + + impl Debug + for Tuple2 { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for Tuple2 { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + Tuple2::_T2{_0, _1, } => { + write!(_formatter, "(")?; + DafnyPrint::fmt_print(_0, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_1, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl Tuple2 { + /// Given type parameter conversions, returns a lambda to convert this structure + pub fn coerce<__T0: DafnyType, __T1: DafnyType>(f_0: Rc __T0 + 'static>, f_1: Rc __T1 + 'static>) -> Rc) -> Tuple2<__T0, __T1>> { + Rc::new(move |this: Self| -> Tuple2<__T0, __T1>{ + match this { + Tuple2::_T2{_0, _1, } => { + Tuple2::_T2 { + _0: f_0.clone()(_0), + _1: f_1.clone()(_1) + } + }, + } + }) + } + } + + impl PartialEq + for Tuple2 { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (Tuple2::_T2{_0, _1, }, Tuple2::_T2{_0: _2__0, _1: _2__1, }) => { + _0 == _2__0 && _1 == _2__1 + }, + _ => { + false + }, + } + } + } + + impl Eq + for Tuple2 {} + + impl Hash + for Tuple2 { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + Tuple2::_T2{_0, _1, } => { + Hash::hash(_0, _state); + Hash::hash(_1, _state) + }, + } + } + } + + impl AsRef> + for Tuple2 { + fn as_ref(&self) -> &Self { + self + } + } + + #[derive(Clone)] + pub enum Tuple0 { + _T0 {} + } + + impl Tuple0 {} + + impl Debug + for Tuple0 { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for Tuple0 { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + Tuple0::_T0{} => { + write!(_formatter, "")?; + Ok(()) + }, + } + } + } + + impl Tuple0 { + /// Enumerates all possible values of Tuple0 + pub fn _AllSingletonConstructors() -> SequenceIter> { + seq![Rc::new(Tuple0::_T0 {})].iter() + } + } + + impl PartialEq + for Tuple0 { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (Tuple0::_T0{}, Tuple0::_T0{}) => { + true + }, + _ => { + false + }, + } + } + } + + impl Eq + for Tuple0 {} + + impl Hash + for Tuple0 { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + Tuple0::_T0{} => { + + }, + } + } + } + + impl AsRef + for Tuple0 { + fn as_ref(&self) -> &Self { + self + } + } + + #[derive(Clone)] + pub enum Tuple1 { + _T1 { + _0: T0 + } + } + + impl Tuple1 { + /// Returns a borrow of the field _0 + pub fn _0(&self) -> &T0 { + match self { + Tuple1::_T1{_0, } => _0, + } + } + } + + impl Debug + for Tuple1 { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for Tuple1 { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + Tuple1::_T1{_0, } => { + write!(_formatter, "(")?; + DafnyPrint::fmt_print(_0, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl Tuple1 { + /// Given type parameter conversions, returns a lambda to convert this structure + pub fn coerce<__T0: DafnyType>(f_0: Rc __T0 + 'static>) -> Rc) -> Tuple1<__T0>> { + Rc::new(move |this: Self| -> Tuple1<__T0>{ + match this { + Tuple1::_T1{_0, } => { + Tuple1::_T1 { + _0: f_0.clone()(_0) + } + }, + } + }) + } + } + + impl PartialEq + for Tuple1 { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (Tuple1::_T1{_0, }, Tuple1::_T1{_0: _2__0, }) => { + _0 == _2__0 + }, + _ => { + false + }, + } + } + } + + impl Eq + for Tuple1 {} + + impl Hash + for Tuple1 { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + Tuple1::_T1{_0, } => { + Hash::hash(_0, _state) + }, + } + } + } + + impl AsRef> + for Tuple1 { + fn as_ref(&self) -> &Self { + self + } + } + + #[derive(Clone)] + pub enum Tuple3 { + _T3 { + _0: T0, + _1: T1, + _2: T2 + } + } + + impl Tuple3 { + /// Returns a borrow of the field _0 + pub fn _0(&self) -> &T0 { + match self { + Tuple3::_T3{_0, _1, _2, } => _0, + } + } + /// Returns a borrow of the field _1 + pub fn _1(&self) -> &T1 { + match self { + Tuple3::_T3{_0, _1, _2, } => _1, + } + } + /// Returns a borrow of the field _2 + pub fn _2(&self) -> &T2 { + match self { + Tuple3::_T3{_0, _1, _2, } => _2, + } + } + } + + impl Debug + for Tuple3 { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for Tuple3 { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + Tuple3::_T3{_0, _1, _2, } => { + write!(_formatter, "(")?; + DafnyPrint::fmt_print(_0, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_1, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_2, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl Tuple3 { + /// Given type parameter conversions, returns a lambda to convert this structure + pub fn coerce<__T0: DafnyType, __T1: DafnyType, __T2: DafnyType>(f_0: Rc __T0 + 'static>, f_1: Rc __T1 + 'static>, f_2: Rc __T2 + 'static>) -> Rc) -> Tuple3<__T0, __T1, __T2>> { + Rc::new(move |this: Self| -> Tuple3<__T0, __T1, __T2>{ + match this { + Tuple3::_T3{_0, _1, _2, } => { + Tuple3::_T3 { + _0: f_0.clone()(_0), + _1: f_1.clone()(_1), + _2: f_2.clone()(_2) + } + }, + } + }) + } + } + + impl PartialEq + for Tuple3 { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (Tuple3::_T3{_0, _1, _2, }, Tuple3::_T3{_0: _2__0, _1: _2__1, _2: _2__2, }) => { + _0 == _2__0 && _1 == _2__1 && _2 == _2__2 + }, + _ => { + false + }, + } + } + } + + impl Eq + for Tuple3 {} + + impl Hash + for Tuple3 { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + Tuple3::_T3{_0, _1, _2, } => { + Hash::hash(_0, _state); + Hash::hash(_1, _state); + Hash::hash(_2, _state) + }, + } + } + } + + impl AsRef> + for Tuple3 { + fn as_ref(&self) -> &Self { + self + } + } + + #[derive(Clone)] + pub enum Tuple4 { + _T4 { + _0: T0, + _1: T1, + _2: T2, + _3: T3 + } + } + + impl Tuple4 { + /// Returns a borrow of the field _0 + pub fn _0(&self) -> &T0 { + match self { + Tuple4::_T4{_0, _1, _2, _3, } => _0, + } + } + /// Returns a borrow of the field _1 + pub fn _1(&self) -> &T1 { + match self { + Tuple4::_T4{_0, _1, _2, _3, } => _1, + } + } + /// Returns a borrow of the field _2 + pub fn _2(&self) -> &T2 { + match self { + Tuple4::_T4{_0, _1, _2, _3, } => _2, + } + } + /// Returns a borrow of the field _3 + pub fn _3(&self) -> &T3 { + match self { + Tuple4::_T4{_0, _1, _2, _3, } => _3, + } + } + } + + impl Debug + for Tuple4 { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for Tuple4 { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + Tuple4::_T4{_0, _1, _2, _3, } => { + write!(_formatter, "(")?; + DafnyPrint::fmt_print(_0, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_1, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_2, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_3, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl Tuple4 { + /// Given type parameter conversions, returns a lambda to convert this structure + pub fn coerce<__T0: DafnyType, __T1: DafnyType, __T2: DafnyType, __T3: DafnyType>(f_0: Rc __T0 + 'static>, f_1: Rc __T1 + 'static>, f_2: Rc __T2 + 'static>, f_3: Rc __T3 + 'static>) -> Rc) -> Tuple4<__T0, __T1, __T2, __T3>> { + Rc::new(move |this: Self| -> Tuple4<__T0, __T1, __T2, __T3>{ + match this { + Tuple4::_T4{_0, _1, _2, _3, } => { + Tuple4::_T4 { + _0: f_0.clone()(_0), + _1: f_1.clone()(_1), + _2: f_2.clone()(_2), + _3: f_3.clone()(_3) + } + }, + } + }) + } + } + + impl PartialEq + for Tuple4 { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (Tuple4::_T4{_0, _1, _2, _3, }, Tuple4::_T4{_0: _2__0, _1: _2__1, _2: _2__2, _3: _2__3, }) => { + _0 == _2__0 && _1 == _2__1 && _2 == _2__2 && _3 == _2__3 + }, + _ => { + false + }, + } + } + } + + impl Eq + for Tuple4 {} + + impl Hash + for Tuple4 { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + Tuple4::_T4{_0, _1, _2, _3, } => { + Hash::hash(_0, _state); + Hash::hash(_1, _state); + Hash::hash(_2, _state); + Hash::hash(_3, _state) + }, + } + } + } + + impl AsRef> + for Tuple4 { + fn as_ref(&self) -> &Self { + self + } + } + + #[derive(Clone)] + pub enum Tuple5 { + _T5 { + _0: T0, + _1: T1, + _2: T2, + _3: T3, + _4: T4 + } + } + + impl Tuple5 { + /// Returns a borrow of the field _0 + pub fn _0(&self) -> &T0 { + match self { + Tuple5::_T5{_0, _1, _2, _3, _4, } => _0, + } + } + /// Returns a borrow of the field _1 + pub fn _1(&self) -> &T1 { + match self { + Tuple5::_T5{_0, _1, _2, _3, _4, } => _1, + } + } + /// Returns a borrow of the field _2 + pub fn _2(&self) -> &T2 { + match self { + Tuple5::_T5{_0, _1, _2, _3, _4, } => _2, + } + } + /// Returns a borrow of the field _3 + pub fn _3(&self) -> &T3 { + match self { + Tuple5::_T5{_0, _1, _2, _3, _4, } => _3, + } + } + /// Returns a borrow of the field _4 + pub fn _4(&self) -> &T4 { + match self { + Tuple5::_T5{_0, _1, _2, _3, _4, } => _4, + } + } + } + + impl Debug + for Tuple5 { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for Tuple5 { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + Tuple5::_T5{_0, _1, _2, _3, _4, } => { + write!(_formatter, "(")?; + DafnyPrint::fmt_print(_0, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_1, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_2, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_3, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_4, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl Tuple5 { + /// Given type parameter conversions, returns a lambda to convert this structure + pub fn coerce<__T0: DafnyType, __T1: DafnyType, __T2: DafnyType, __T3: DafnyType, __T4: DafnyType>(f_0: Rc __T0 + 'static>, f_1: Rc __T1 + 'static>, f_2: Rc __T2 + 'static>, f_3: Rc __T3 + 'static>, f_4: Rc __T4 + 'static>) -> Rc) -> Tuple5<__T0, __T1, __T2, __T3, __T4>> { + Rc::new(move |this: Self| -> Tuple5<__T0, __T1, __T2, __T3, __T4>{ + match this { + Tuple5::_T5{_0, _1, _2, _3, _4, } => { + Tuple5::_T5 { + _0: f_0.clone()(_0), + _1: f_1.clone()(_1), + _2: f_2.clone()(_2), + _3: f_3.clone()(_3), + _4: f_4.clone()(_4) + } + }, + } + }) + } + } + + impl PartialEq + for Tuple5 { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (Tuple5::_T5{_0, _1, _2, _3, _4, }, Tuple5::_T5{_0: _2__0, _1: _2__1, _2: _2__2, _3: _2__3, _4: _2__4, }) => { + _0 == _2__0 && _1 == _2__1 && _2 == _2__2 && _3 == _2__3 && _4 == _2__4 + }, + _ => { + false + }, + } + } + } + + impl Eq + for Tuple5 {} + + impl Hash + for Tuple5 { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + Tuple5::_T5{_0, _1, _2, _3, _4, } => { + Hash::hash(_0, _state); + Hash::hash(_1, _state); + Hash::hash(_2, _state); + Hash::hash(_3, _state); + Hash::hash(_4, _state) + }, + } + } + } + + impl AsRef> + for Tuple5 { + fn as_ref(&self) -> &Self { + self + } + } + + #[derive(Clone)] + pub enum Tuple6 { + _T6 { + _0: T0, + _1: T1, + _2: T2, + _3: T3, + _4: T4, + _5: T5 + } + } + + impl Tuple6 { + /// Returns a borrow of the field _0 + pub fn _0(&self) -> &T0 { + match self { + Tuple6::_T6{_0, _1, _2, _3, _4, _5, } => _0, + } + } + /// Returns a borrow of the field _1 + pub fn _1(&self) -> &T1 { + match self { + Tuple6::_T6{_0, _1, _2, _3, _4, _5, } => _1, + } + } + /// Returns a borrow of the field _2 + pub fn _2(&self) -> &T2 { + match self { + Tuple6::_T6{_0, _1, _2, _3, _4, _5, } => _2, + } + } + /// Returns a borrow of the field _3 + pub fn _3(&self) -> &T3 { + match self { + Tuple6::_T6{_0, _1, _2, _3, _4, _5, } => _3, + } + } + /// Returns a borrow of the field _4 + pub fn _4(&self) -> &T4 { + match self { + Tuple6::_T6{_0, _1, _2, _3, _4, _5, } => _4, + } + } + /// Returns a borrow of the field _5 + pub fn _5(&self) -> &T5 { + match self { + Tuple6::_T6{_0, _1, _2, _3, _4, _5, } => _5, + } + } + } + + impl Debug + for Tuple6 { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for Tuple6 { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + Tuple6::_T6{_0, _1, _2, _3, _4, _5, } => { + write!(_formatter, "(")?; + DafnyPrint::fmt_print(_0, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_1, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_2, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_3, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_4, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_5, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl Tuple6 { + /// Given type parameter conversions, returns a lambda to convert this structure + pub fn coerce<__T0: DafnyType, __T1: DafnyType, __T2: DafnyType, __T3: DafnyType, __T4: DafnyType, __T5: DafnyType>(f_0: Rc __T0 + 'static>, f_1: Rc __T1 + 'static>, f_2: Rc __T2 + 'static>, f_3: Rc __T3 + 'static>, f_4: Rc __T4 + 'static>, f_5: Rc __T5 + 'static>) -> Rc) -> Tuple6<__T0, __T1, __T2, __T3, __T4, __T5>> { + Rc::new(move |this: Self| -> Tuple6<__T0, __T1, __T2, __T3, __T4, __T5>{ + match this { + Tuple6::_T6{_0, _1, _2, _3, _4, _5, } => { + Tuple6::_T6 { + _0: f_0.clone()(_0), + _1: f_1.clone()(_1), + _2: f_2.clone()(_2), + _3: f_3.clone()(_3), + _4: f_4.clone()(_4), + _5: f_5.clone()(_5) + } + }, + } + }) + } + } + + impl PartialEq + for Tuple6 { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (Tuple6::_T6{_0, _1, _2, _3, _4, _5, }, Tuple6::_T6{_0: _2__0, _1: _2__1, _2: _2__2, _3: _2__3, _4: _2__4, _5: _2__5, }) => { + _0 == _2__0 && _1 == _2__1 && _2 == _2__2 && _3 == _2__3 && _4 == _2__4 && _5 == _2__5 + }, + _ => { + false + }, + } + } + } + + impl Eq + for Tuple6 {} + + impl Hash + for Tuple6 { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + Tuple6::_T6{_0, _1, _2, _3, _4, _5, } => { + Hash::hash(_0, _state); + Hash::hash(_1, _state); + Hash::hash(_2, _state); + Hash::hash(_3, _state); + Hash::hash(_4, _state); + Hash::hash(_5, _state) + }, + } + } + } + + impl AsRef> + for Tuple6 { + fn as_ref(&self) -> &Self { + self + } + } + + #[derive(Clone)] + pub enum Tuple7 { + _T7 { + _0: T0, + _1: T1, + _2: T2, + _3: T3, + _4: T4, + _5: T5, + _6: T6 + } + } + + impl Tuple7 { + /// Returns a borrow of the field _0 + pub fn _0(&self) -> &T0 { + match self { + Tuple7::_T7{_0, _1, _2, _3, _4, _5, _6, } => _0, + } + } + /// Returns a borrow of the field _1 + pub fn _1(&self) -> &T1 { + match self { + Tuple7::_T7{_0, _1, _2, _3, _4, _5, _6, } => _1, + } + } + /// Returns a borrow of the field _2 + pub fn _2(&self) -> &T2 { + match self { + Tuple7::_T7{_0, _1, _2, _3, _4, _5, _6, } => _2, + } + } + /// Returns a borrow of the field _3 + pub fn _3(&self) -> &T3 { + match self { + Tuple7::_T7{_0, _1, _2, _3, _4, _5, _6, } => _3, + } + } + /// Returns a borrow of the field _4 + pub fn _4(&self) -> &T4 { + match self { + Tuple7::_T7{_0, _1, _2, _3, _4, _5, _6, } => _4, + } + } + /// Returns a borrow of the field _5 + pub fn _5(&self) -> &T5 { + match self { + Tuple7::_T7{_0, _1, _2, _3, _4, _5, _6, } => _5, + } + } + /// Returns a borrow of the field _6 + pub fn _6(&self) -> &T6 { + match self { + Tuple7::_T7{_0, _1, _2, _3, _4, _5, _6, } => _6, + } + } + } + + impl Debug + for Tuple7 { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for Tuple7 { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + Tuple7::_T7{_0, _1, _2, _3, _4, _5, _6, } => { + write!(_formatter, "(")?; + DafnyPrint::fmt_print(_0, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_1, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_2, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_3, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_4, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_5, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_6, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl Tuple7 { + /// Given type parameter conversions, returns a lambda to convert this structure + pub fn coerce<__T0: DafnyType, __T1: DafnyType, __T2: DafnyType, __T3: DafnyType, __T4: DafnyType, __T5: DafnyType, __T6: DafnyType>(f_0: Rc __T0 + 'static>, f_1: Rc __T1 + 'static>, f_2: Rc __T2 + 'static>, f_3: Rc __T3 + 'static>, f_4: Rc __T4 + 'static>, f_5: Rc __T5 + 'static>, f_6: Rc __T6 + 'static>) -> Rc) -> Tuple7<__T0, __T1, __T2, __T3, __T4, __T5, __T6>> { + Rc::new(move |this: Self| -> Tuple7<__T0, __T1, __T2, __T3, __T4, __T5, __T6>{ + match this { + Tuple7::_T7{_0, _1, _2, _3, _4, _5, _6, } => { + Tuple7::_T7 { + _0: f_0.clone()(_0), + _1: f_1.clone()(_1), + _2: f_2.clone()(_2), + _3: f_3.clone()(_3), + _4: f_4.clone()(_4), + _5: f_5.clone()(_5), + _6: f_6.clone()(_6) + } + }, + } + }) + } + } + + impl PartialEq + for Tuple7 { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (Tuple7::_T7{_0, _1, _2, _3, _4, _5, _6, }, Tuple7::_T7{_0: _2__0, _1: _2__1, _2: _2__2, _3: _2__3, _4: _2__4, _5: _2__5, _6: _2__6, }) => { + _0 == _2__0 && _1 == _2__1 && _2 == _2__2 && _3 == _2__3 && _4 == _2__4 && _5 == _2__5 && _6 == _2__6 + }, + _ => { + false + }, + } + } + } + + impl Eq + for Tuple7 {} + + impl Hash + for Tuple7 { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + Tuple7::_T7{_0, _1, _2, _3, _4, _5, _6, } => { + Hash::hash(_0, _state); + Hash::hash(_1, _state); + Hash::hash(_2, _state); + Hash::hash(_3, _state); + Hash::hash(_4, _state); + Hash::hash(_5, _state); + Hash::hash(_6, _state) + }, + } + } + } + + impl AsRef> + for Tuple7 { + fn as_ref(&self) -> &Self { + self + } + } + + #[derive(Clone)] + pub enum Tuple8 { + _T8 { + _0: T0, + _1: T1, + _2: T2, + _3: T3, + _4: T4, + _5: T5, + _6: T6, + _7: T7 + } + } + + impl Tuple8 { + /// Returns a borrow of the field _0 + pub fn _0(&self) -> &T0 { + match self { + Tuple8::_T8{_0, _1, _2, _3, _4, _5, _6, _7, } => _0, + } + } + /// Returns a borrow of the field _1 + pub fn _1(&self) -> &T1 { + match self { + Tuple8::_T8{_0, _1, _2, _3, _4, _5, _6, _7, } => _1, + } + } + /// Returns a borrow of the field _2 + pub fn _2(&self) -> &T2 { + match self { + Tuple8::_T8{_0, _1, _2, _3, _4, _5, _6, _7, } => _2, + } + } + /// Returns a borrow of the field _3 + pub fn _3(&self) -> &T3 { + match self { + Tuple8::_T8{_0, _1, _2, _3, _4, _5, _6, _7, } => _3, + } + } + /// Returns a borrow of the field _4 + pub fn _4(&self) -> &T4 { + match self { + Tuple8::_T8{_0, _1, _2, _3, _4, _5, _6, _7, } => _4, + } + } + /// Returns a borrow of the field _5 + pub fn _5(&self) -> &T5 { + match self { + Tuple8::_T8{_0, _1, _2, _3, _4, _5, _6, _7, } => _5, + } + } + /// Returns a borrow of the field _6 + pub fn _6(&self) -> &T6 { + match self { + Tuple8::_T8{_0, _1, _2, _3, _4, _5, _6, _7, } => _6, + } + } + /// Returns a borrow of the field _7 + pub fn _7(&self) -> &T7 { + match self { + Tuple8::_T8{_0, _1, _2, _3, _4, _5, _6, _7, } => _7, + } + } + } + + impl Debug + for Tuple8 { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for Tuple8 { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + Tuple8::_T8{_0, _1, _2, _3, _4, _5, _6, _7, } => { + write!(_formatter, "(")?; + DafnyPrint::fmt_print(_0, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_1, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_2, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_3, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_4, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_5, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_6, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_7, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl Tuple8 { + /// Given type parameter conversions, returns a lambda to convert this structure + pub fn coerce<__T0: DafnyType, __T1: DafnyType, __T2: DafnyType, __T3: DafnyType, __T4: DafnyType, __T5: DafnyType, __T6: DafnyType, __T7: DafnyType>(f_0: Rc __T0 + 'static>, f_1: Rc __T1 + 'static>, f_2: Rc __T2 + 'static>, f_3: Rc __T3 + 'static>, f_4: Rc __T4 + 'static>, f_5: Rc __T5 + 'static>, f_6: Rc __T6 + 'static>, f_7: Rc __T7 + 'static>) -> Rc) -> Tuple8<__T0, __T1, __T2, __T3, __T4, __T5, __T6, __T7>> { + Rc::new(move |this: Self| -> Tuple8<__T0, __T1, __T2, __T3, __T4, __T5, __T6, __T7>{ + match this { + Tuple8::_T8{_0, _1, _2, _3, _4, _5, _6, _7, } => { + Tuple8::_T8 { + _0: f_0.clone()(_0), + _1: f_1.clone()(_1), + _2: f_2.clone()(_2), + _3: f_3.clone()(_3), + _4: f_4.clone()(_4), + _5: f_5.clone()(_5), + _6: f_6.clone()(_6), + _7: f_7.clone()(_7) + } + }, + } + }) + } + } + + impl PartialEq + for Tuple8 { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (Tuple8::_T8{_0, _1, _2, _3, _4, _5, _6, _7, }, Tuple8::_T8{_0: _2__0, _1: _2__1, _2: _2__2, _3: _2__3, _4: _2__4, _5: _2__5, _6: _2__6, _7: _2__7, }) => { + _0 == _2__0 && _1 == _2__1 && _2 == _2__2 && _3 == _2__3 && _4 == _2__4 && _5 == _2__5 && _6 == _2__6 && _7 == _2__7 + }, + _ => { + false + }, + } + } + } + + impl Eq + for Tuple8 {} + + impl Hash + for Tuple8 { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + Tuple8::_T8{_0, _1, _2, _3, _4, _5, _6, _7, } => { + Hash::hash(_0, _state); + Hash::hash(_1, _state); + Hash::hash(_2, _state); + Hash::hash(_3, _state); + Hash::hash(_4, _state); + Hash::hash(_5, _state); + Hash::hash(_6, _state); + Hash::hash(_7, _state) + }, + } + } + } + + impl AsRef> + for Tuple8 { + fn as_ref(&self) -> &Self { + self + } + } + + #[derive(Clone)] + pub enum Tuple9 { + _T9 { + _0: T0, + _1: T1, + _2: T2, + _3: T3, + _4: T4, + _5: T5, + _6: T6, + _7: T7, + _8: T8 + } + } + + impl Tuple9 { + /// Returns a borrow of the field _0 + pub fn _0(&self) -> &T0 { + match self { + Tuple9::_T9{_0, _1, _2, _3, _4, _5, _6, _7, _8, } => _0, + } + } + /// Returns a borrow of the field _1 + pub fn _1(&self) -> &T1 { + match self { + Tuple9::_T9{_0, _1, _2, _3, _4, _5, _6, _7, _8, } => _1, + } + } + /// Returns a borrow of the field _2 + pub fn _2(&self) -> &T2 { + match self { + Tuple9::_T9{_0, _1, _2, _3, _4, _5, _6, _7, _8, } => _2, + } + } + /// Returns a borrow of the field _3 + pub fn _3(&self) -> &T3 { + match self { + Tuple9::_T9{_0, _1, _2, _3, _4, _5, _6, _7, _8, } => _3, + } + } + /// Returns a borrow of the field _4 + pub fn _4(&self) -> &T4 { + match self { + Tuple9::_T9{_0, _1, _2, _3, _4, _5, _6, _7, _8, } => _4, + } + } + /// Returns a borrow of the field _5 + pub fn _5(&self) -> &T5 { + match self { + Tuple9::_T9{_0, _1, _2, _3, _4, _5, _6, _7, _8, } => _5, + } + } + /// Returns a borrow of the field _6 + pub fn _6(&self) -> &T6 { + match self { + Tuple9::_T9{_0, _1, _2, _3, _4, _5, _6, _7, _8, } => _6, + } + } + /// Returns a borrow of the field _7 + pub fn _7(&self) -> &T7 { + match self { + Tuple9::_T9{_0, _1, _2, _3, _4, _5, _6, _7, _8, } => _7, + } + } + /// Returns a borrow of the field _8 + pub fn _8(&self) -> &T8 { + match self { + Tuple9::_T9{_0, _1, _2, _3, _4, _5, _6, _7, _8, } => _8, + } + } + } + + impl Debug + for Tuple9 { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for Tuple9 { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + Tuple9::_T9{_0, _1, _2, _3, _4, _5, _6, _7, _8, } => { + write!(_formatter, "(")?; + DafnyPrint::fmt_print(_0, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_1, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_2, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_3, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_4, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_5, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_6, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_7, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_8, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl Tuple9 { + /// Given type parameter conversions, returns a lambda to convert this structure + pub fn coerce<__T0: DafnyType, __T1: DafnyType, __T2: DafnyType, __T3: DafnyType, __T4: DafnyType, __T5: DafnyType, __T6: DafnyType, __T7: DafnyType, __T8: DafnyType>(f_0: Rc __T0 + 'static>, f_1: Rc __T1 + 'static>, f_2: Rc __T2 + 'static>, f_3: Rc __T3 + 'static>, f_4: Rc __T4 + 'static>, f_5: Rc __T5 + 'static>, f_6: Rc __T6 + 'static>, f_7: Rc __T7 + 'static>, f_8: Rc __T8 + 'static>) -> Rc) -> Tuple9<__T0, __T1, __T2, __T3, __T4, __T5, __T6, __T7, __T8>> { + Rc::new(move |this: Self| -> Tuple9<__T0, __T1, __T2, __T3, __T4, __T5, __T6, __T7, __T8>{ + match this { + Tuple9::_T9{_0, _1, _2, _3, _4, _5, _6, _7, _8, } => { + Tuple9::_T9 { + _0: f_0.clone()(_0), + _1: f_1.clone()(_1), + _2: f_2.clone()(_2), + _3: f_3.clone()(_3), + _4: f_4.clone()(_4), + _5: f_5.clone()(_5), + _6: f_6.clone()(_6), + _7: f_7.clone()(_7), + _8: f_8.clone()(_8) + } + }, + } + }) + } + } + + impl PartialEq + for Tuple9 { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (Tuple9::_T9{_0, _1, _2, _3, _4, _5, _6, _7, _8, }, Tuple9::_T9{_0: _2__0, _1: _2__1, _2: _2__2, _3: _2__3, _4: _2__4, _5: _2__5, _6: _2__6, _7: _2__7, _8: _2__8, }) => { + _0 == _2__0 && _1 == _2__1 && _2 == _2__2 && _3 == _2__3 && _4 == _2__4 && _5 == _2__5 && _6 == _2__6 && _7 == _2__7 && _8 == _2__8 + }, + _ => { + false + }, + } + } + } + + impl Eq + for Tuple9 {} + + impl Hash + for Tuple9 { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + Tuple9::_T9{_0, _1, _2, _3, _4, _5, _6, _7, _8, } => { + Hash::hash(_0, _state); + Hash::hash(_1, _state); + Hash::hash(_2, _state); + Hash::hash(_3, _state); + Hash::hash(_4, _state); + Hash::hash(_5, _state); + Hash::hash(_6, _state); + Hash::hash(_7, _state); + Hash::hash(_8, _state) + }, + } + } + } + + impl AsRef> + for Tuple9 { + fn as_ref(&self) -> &Self { + self + } + } + + #[derive(Clone)] + pub enum Tuple10 { + _T10 { + _0: T0, + _1: T1, + _2: T2, + _3: T3, + _4: T4, + _5: T5, + _6: T6, + _7: T7, + _8: T8, + _9: T9 + } + } + + impl Tuple10 { + /// Returns a borrow of the field _0 + pub fn _0(&self) -> &T0 { + match self { + Tuple10::_T10{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, } => _0, + } + } + /// Returns a borrow of the field _1 + pub fn _1(&self) -> &T1 { + match self { + Tuple10::_T10{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, } => _1, + } + } + /// Returns a borrow of the field _2 + pub fn _2(&self) -> &T2 { + match self { + Tuple10::_T10{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, } => _2, + } + } + /// Returns a borrow of the field _3 + pub fn _3(&self) -> &T3 { + match self { + Tuple10::_T10{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, } => _3, + } + } + /// Returns a borrow of the field _4 + pub fn _4(&self) -> &T4 { + match self { + Tuple10::_T10{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, } => _4, + } + } + /// Returns a borrow of the field _5 + pub fn _5(&self) -> &T5 { + match self { + Tuple10::_T10{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, } => _5, + } + } + /// Returns a borrow of the field _6 + pub fn _6(&self) -> &T6 { + match self { + Tuple10::_T10{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, } => _6, + } + } + /// Returns a borrow of the field _7 + pub fn _7(&self) -> &T7 { + match self { + Tuple10::_T10{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, } => _7, + } + } + /// Returns a borrow of the field _8 + pub fn _8(&self) -> &T8 { + match self { + Tuple10::_T10{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, } => _8, + } + } + /// Returns a borrow of the field _9 + pub fn _9(&self) -> &T9 { + match self { + Tuple10::_T10{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, } => _9, + } + } + } + + impl Debug + for Tuple10 { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for Tuple10 { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + Tuple10::_T10{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, } => { + write!(_formatter, "(")?; + DafnyPrint::fmt_print(_0, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_1, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_2, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_3, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_4, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_5, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_6, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_7, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_8, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_9, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl Tuple10 { + /// Given type parameter conversions, returns a lambda to convert this structure + pub fn coerce<__T0: DafnyType, __T1: DafnyType, __T2: DafnyType, __T3: DafnyType, __T4: DafnyType, __T5: DafnyType, __T6: DafnyType, __T7: DafnyType, __T8: DafnyType, __T9: DafnyType>(f_0: Rc __T0 + 'static>, f_1: Rc __T1 + 'static>, f_2: Rc __T2 + 'static>, f_3: Rc __T3 + 'static>, f_4: Rc __T4 + 'static>, f_5: Rc __T5 + 'static>, f_6: Rc __T6 + 'static>, f_7: Rc __T7 + 'static>, f_8: Rc __T8 + 'static>, f_9: Rc __T9 + 'static>) -> Rc) -> Tuple10<__T0, __T1, __T2, __T3, __T4, __T5, __T6, __T7, __T8, __T9>> { + Rc::new(move |this: Self| -> Tuple10<__T0, __T1, __T2, __T3, __T4, __T5, __T6, __T7, __T8, __T9>{ + match this { + Tuple10::_T10{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, } => { + Tuple10::_T10 { + _0: f_0.clone()(_0), + _1: f_1.clone()(_1), + _2: f_2.clone()(_2), + _3: f_3.clone()(_3), + _4: f_4.clone()(_4), + _5: f_5.clone()(_5), + _6: f_6.clone()(_6), + _7: f_7.clone()(_7), + _8: f_8.clone()(_8), + _9: f_9.clone()(_9) + } + }, + } + }) + } + } + + impl PartialEq + for Tuple10 { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (Tuple10::_T10{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, }, Tuple10::_T10{_0: _2__0, _1: _2__1, _2: _2__2, _3: _2__3, _4: _2__4, _5: _2__5, _6: _2__6, _7: _2__7, _8: _2__8, _9: _2__9, }) => { + _0 == _2__0 && _1 == _2__1 && _2 == _2__2 && _3 == _2__3 && _4 == _2__4 && _5 == _2__5 && _6 == _2__6 && _7 == _2__7 && _8 == _2__8 && _9 == _2__9 + }, + _ => { + false + }, + } + } + } + + impl Eq + for Tuple10 {} + + impl Hash + for Tuple10 { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + Tuple10::_T10{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, } => { + Hash::hash(_0, _state); + Hash::hash(_1, _state); + Hash::hash(_2, _state); + Hash::hash(_3, _state); + Hash::hash(_4, _state); + Hash::hash(_5, _state); + Hash::hash(_6, _state); + Hash::hash(_7, _state); + Hash::hash(_8, _state); + Hash::hash(_9, _state) + }, + } + } + } + + impl AsRef> + for Tuple10 { + fn as_ref(&self) -> &Self { + self + } + } + + #[derive(Clone)] + pub enum Tuple11 { + _T11 { + _0: T0, + _1: T1, + _2: T2, + _3: T3, + _4: T4, + _5: T5, + _6: T6, + _7: T7, + _8: T8, + _9: T9, + _10: T10 + } + } + + impl Tuple11 { + /// Returns a borrow of the field _0 + pub fn _0(&self) -> &T0 { + match self { + Tuple11::_T11{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, } => _0, + } + } + /// Returns a borrow of the field _1 + pub fn _1(&self) -> &T1 { + match self { + Tuple11::_T11{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, } => _1, + } + } + /// Returns a borrow of the field _2 + pub fn _2(&self) -> &T2 { + match self { + Tuple11::_T11{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, } => _2, + } + } + /// Returns a borrow of the field _3 + pub fn _3(&self) -> &T3 { + match self { + Tuple11::_T11{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, } => _3, + } + } + /// Returns a borrow of the field _4 + pub fn _4(&self) -> &T4 { + match self { + Tuple11::_T11{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, } => _4, + } + } + /// Returns a borrow of the field _5 + pub fn _5(&self) -> &T5 { + match self { + Tuple11::_T11{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, } => _5, + } + } + /// Returns a borrow of the field _6 + pub fn _6(&self) -> &T6 { + match self { + Tuple11::_T11{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, } => _6, + } + } + /// Returns a borrow of the field _7 + pub fn _7(&self) -> &T7 { + match self { + Tuple11::_T11{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, } => _7, + } + } + /// Returns a borrow of the field _8 + pub fn _8(&self) -> &T8 { + match self { + Tuple11::_T11{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, } => _8, + } + } + /// Returns a borrow of the field _9 + pub fn _9(&self) -> &T9 { + match self { + Tuple11::_T11{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, } => _9, + } + } + /// Returns a borrow of the field _10 + pub fn _10(&self) -> &T10 { + match self { + Tuple11::_T11{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, } => _10, + } + } + } + + impl Debug + for Tuple11 { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for Tuple11 { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + Tuple11::_T11{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, } => { + write!(_formatter, "(")?; + DafnyPrint::fmt_print(_0, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_1, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_2, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_3, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_4, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_5, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_6, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_7, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_8, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_9, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_10, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl Tuple11 { + /// Given type parameter conversions, returns a lambda to convert this structure + pub fn coerce<__T0: DafnyType, __T1: DafnyType, __T2: DafnyType, __T3: DafnyType, __T4: DafnyType, __T5: DafnyType, __T6: DafnyType, __T7: DafnyType, __T8: DafnyType, __T9: DafnyType, __T10: DafnyType>(f_0: Rc __T0 + 'static>, f_1: Rc __T1 + 'static>, f_2: Rc __T2 + 'static>, f_3: Rc __T3 + 'static>, f_4: Rc __T4 + 'static>, f_5: Rc __T5 + 'static>, f_6: Rc __T6 + 'static>, f_7: Rc __T7 + 'static>, f_8: Rc __T8 + 'static>, f_9: Rc __T9 + 'static>, f_10: Rc __T10 + 'static>) -> Rc) -> Tuple11<__T0, __T1, __T2, __T3, __T4, __T5, __T6, __T7, __T8, __T9, __T10>> { + Rc::new(move |this: Self| -> Tuple11<__T0, __T1, __T2, __T3, __T4, __T5, __T6, __T7, __T8, __T9, __T10>{ + match this { + Tuple11::_T11{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, } => { + Tuple11::_T11 { + _0: f_0.clone()(_0), + _1: f_1.clone()(_1), + _2: f_2.clone()(_2), + _3: f_3.clone()(_3), + _4: f_4.clone()(_4), + _5: f_5.clone()(_5), + _6: f_6.clone()(_6), + _7: f_7.clone()(_7), + _8: f_8.clone()(_8), + _9: f_9.clone()(_9), + _10: f_10.clone()(_10) + } + }, + } + }) + } + } + + impl PartialEq + for Tuple11 { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (Tuple11::_T11{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, }, Tuple11::_T11{_0: _2__0, _1: _2__1, _2: _2__2, _3: _2__3, _4: _2__4, _5: _2__5, _6: _2__6, _7: _2__7, _8: _2__8, _9: _2__9, _10: _2__10, }) => { + _0 == _2__0 && _1 == _2__1 && _2 == _2__2 && _3 == _2__3 && _4 == _2__4 && _5 == _2__5 && _6 == _2__6 && _7 == _2__7 && _8 == _2__8 && _9 == _2__9 && _10 == _2__10 + }, + _ => { + false + }, + } + } + } + + impl Eq + for Tuple11 {} + + impl Hash + for Tuple11 { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + Tuple11::_T11{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, } => { + Hash::hash(_0, _state); + Hash::hash(_1, _state); + Hash::hash(_2, _state); + Hash::hash(_3, _state); + Hash::hash(_4, _state); + Hash::hash(_5, _state); + Hash::hash(_6, _state); + Hash::hash(_7, _state); + Hash::hash(_8, _state); + Hash::hash(_9, _state); + Hash::hash(_10, _state) + }, + } + } + } + + impl AsRef> + for Tuple11 { + fn as_ref(&self) -> &Self { + self + } + } + + #[derive(Clone)] + pub enum Tuple12 { + _T12 { + _0: T0, + _1: T1, + _2: T2, + _3: T3, + _4: T4, + _5: T5, + _6: T6, + _7: T7, + _8: T8, + _9: T9, + _10: T10, + _11: T11 + } + } + + impl Tuple12 { + /// Returns a borrow of the field _0 + pub fn _0(&self) -> &T0 { + match self { + Tuple12::_T12{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, } => _0, + } + } + /// Returns a borrow of the field _1 + pub fn _1(&self) -> &T1 { + match self { + Tuple12::_T12{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, } => _1, + } + } + /// Returns a borrow of the field _2 + pub fn _2(&self) -> &T2 { + match self { + Tuple12::_T12{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, } => _2, + } + } + /// Returns a borrow of the field _3 + pub fn _3(&self) -> &T3 { + match self { + Tuple12::_T12{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, } => _3, + } + } + /// Returns a borrow of the field _4 + pub fn _4(&self) -> &T4 { + match self { + Tuple12::_T12{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, } => _4, + } + } + /// Returns a borrow of the field _5 + pub fn _5(&self) -> &T5 { + match self { + Tuple12::_T12{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, } => _5, + } + } + /// Returns a borrow of the field _6 + pub fn _6(&self) -> &T6 { + match self { + Tuple12::_T12{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, } => _6, + } + } + /// Returns a borrow of the field _7 + pub fn _7(&self) -> &T7 { + match self { + Tuple12::_T12{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, } => _7, + } + } + /// Returns a borrow of the field _8 + pub fn _8(&self) -> &T8 { + match self { + Tuple12::_T12{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, } => _8, + } + } + /// Returns a borrow of the field _9 + pub fn _9(&self) -> &T9 { + match self { + Tuple12::_T12{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, } => _9, + } + } + /// Returns a borrow of the field _10 + pub fn _10(&self) -> &T10 { + match self { + Tuple12::_T12{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, } => _10, + } + } + /// Returns a borrow of the field _11 + pub fn _11(&self) -> &T11 { + match self { + Tuple12::_T12{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, } => _11, + } + } + } + + impl Debug + for Tuple12 { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for Tuple12 { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + Tuple12::_T12{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, } => { + write!(_formatter, "(")?; + DafnyPrint::fmt_print(_0, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_1, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_2, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_3, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_4, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_5, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_6, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_7, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_8, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_9, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_10, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_11, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl Tuple12 { + /// Given type parameter conversions, returns a lambda to convert this structure + pub fn coerce<__T0: DafnyType, __T1: DafnyType, __T2: DafnyType, __T3: DafnyType, __T4: DafnyType, __T5: DafnyType, __T6: DafnyType, __T7: DafnyType, __T8: DafnyType, __T9: DafnyType, __T10: DafnyType, __T11: DafnyType>(f_0: Rc __T0 + 'static>, f_1: Rc __T1 + 'static>, f_2: Rc __T2 + 'static>, f_3: Rc __T3 + 'static>, f_4: Rc __T4 + 'static>, f_5: Rc __T5 + 'static>, f_6: Rc __T6 + 'static>, f_7: Rc __T7 + 'static>, f_8: Rc __T8 + 'static>, f_9: Rc __T9 + 'static>, f_10: Rc __T10 + 'static>, f_11: Rc __T11 + 'static>) -> Rc) -> Tuple12<__T0, __T1, __T2, __T3, __T4, __T5, __T6, __T7, __T8, __T9, __T10, __T11>> { + Rc::new(move |this: Self| -> Tuple12<__T0, __T1, __T2, __T3, __T4, __T5, __T6, __T7, __T8, __T9, __T10, __T11>{ + match this { + Tuple12::_T12{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, } => { + Tuple12::_T12 { + _0: f_0.clone()(_0), + _1: f_1.clone()(_1), + _2: f_2.clone()(_2), + _3: f_3.clone()(_3), + _4: f_4.clone()(_4), + _5: f_5.clone()(_5), + _6: f_6.clone()(_6), + _7: f_7.clone()(_7), + _8: f_8.clone()(_8), + _9: f_9.clone()(_9), + _10: f_10.clone()(_10), + _11: f_11.clone()(_11) + } + }, + } + }) + } + } + + impl PartialEq + for Tuple12 { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (Tuple12::_T12{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, }, Tuple12::_T12{_0: _2__0, _1: _2__1, _2: _2__2, _3: _2__3, _4: _2__4, _5: _2__5, _6: _2__6, _7: _2__7, _8: _2__8, _9: _2__9, _10: _2__10, _11: _2__11, }) => { + _0 == _2__0 && _1 == _2__1 && _2 == _2__2 && _3 == _2__3 && _4 == _2__4 && _5 == _2__5 && _6 == _2__6 && _7 == _2__7 && _8 == _2__8 && _9 == _2__9 && _10 == _2__10 && _11 == _2__11 + }, + _ => { + false + }, + } + } + } + + impl Eq + for Tuple12 {} + + impl Hash + for Tuple12 { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + Tuple12::_T12{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, } => { + Hash::hash(_0, _state); + Hash::hash(_1, _state); + Hash::hash(_2, _state); + Hash::hash(_3, _state); + Hash::hash(_4, _state); + Hash::hash(_5, _state); + Hash::hash(_6, _state); + Hash::hash(_7, _state); + Hash::hash(_8, _state); + Hash::hash(_9, _state); + Hash::hash(_10, _state); + Hash::hash(_11, _state) + }, + } + } + } + + impl AsRef> + for Tuple12 { + fn as_ref(&self) -> &Self { + self + } + } + + #[derive(Clone)] + pub enum Tuple13 { + _T13 { + _0: T0, + _1: T1, + _2: T2, + _3: T3, + _4: T4, + _5: T5, + _6: T6, + _7: T7, + _8: T8, + _9: T9, + _10: T10, + _11: T11, + _12: T12 + } + } + + impl Tuple13 { + /// Returns a borrow of the field _0 + pub fn _0(&self) -> &T0 { + match self { + Tuple13::_T13{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, } => _0, + } + } + /// Returns a borrow of the field _1 + pub fn _1(&self) -> &T1 { + match self { + Tuple13::_T13{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, } => _1, + } + } + /// Returns a borrow of the field _2 + pub fn _2(&self) -> &T2 { + match self { + Tuple13::_T13{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, } => _2, + } + } + /// Returns a borrow of the field _3 + pub fn _3(&self) -> &T3 { + match self { + Tuple13::_T13{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, } => _3, + } + } + /// Returns a borrow of the field _4 + pub fn _4(&self) -> &T4 { + match self { + Tuple13::_T13{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, } => _4, + } + } + /// Returns a borrow of the field _5 + pub fn _5(&self) -> &T5 { + match self { + Tuple13::_T13{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, } => _5, + } + } + /// Returns a borrow of the field _6 + pub fn _6(&self) -> &T6 { + match self { + Tuple13::_T13{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, } => _6, + } + } + /// Returns a borrow of the field _7 + pub fn _7(&self) -> &T7 { + match self { + Tuple13::_T13{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, } => _7, + } + } + /// Returns a borrow of the field _8 + pub fn _8(&self) -> &T8 { + match self { + Tuple13::_T13{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, } => _8, + } + } + /// Returns a borrow of the field _9 + pub fn _9(&self) -> &T9 { + match self { + Tuple13::_T13{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, } => _9, + } + } + /// Returns a borrow of the field _10 + pub fn _10(&self) -> &T10 { + match self { + Tuple13::_T13{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, } => _10, + } + } + /// Returns a borrow of the field _11 + pub fn _11(&self) -> &T11 { + match self { + Tuple13::_T13{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, } => _11, + } + } + /// Returns a borrow of the field _12 + pub fn _12(&self) -> &T12 { + match self { + Tuple13::_T13{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, } => _12, + } + } + } + + impl Debug + for Tuple13 { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for Tuple13 { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + Tuple13::_T13{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, } => { + write!(_formatter, "(")?; + DafnyPrint::fmt_print(_0, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_1, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_2, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_3, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_4, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_5, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_6, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_7, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_8, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_9, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_10, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_11, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_12, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl Tuple13 { + /// Given type parameter conversions, returns a lambda to convert this structure + pub fn coerce<__T0: DafnyType, __T1: DafnyType, __T2: DafnyType, __T3: DafnyType, __T4: DafnyType, __T5: DafnyType, __T6: DafnyType, __T7: DafnyType, __T8: DafnyType, __T9: DafnyType, __T10: DafnyType, __T11: DafnyType, __T12: DafnyType>(f_0: Rc __T0 + 'static>, f_1: Rc __T1 + 'static>, f_2: Rc __T2 + 'static>, f_3: Rc __T3 + 'static>, f_4: Rc __T4 + 'static>, f_5: Rc __T5 + 'static>, f_6: Rc __T6 + 'static>, f_7: Rc __T7 + 'static>, f_8: Rc __T8 + 'static>, f_9: Rc __T9 + 'static>, f_10: Rc __T10 + 'static>, f_11: Rc __T11 + 'static>, f_12: Rc __T12 + 'static>) -> Rc) -> Tuple13<__T0, __T1, __T2, __T3, __T4, __T5, __T6, __T7, __T8, __T9, __T10, __T11, __T12>> { + Rc::new(move |this: Self| -> Tuple13<__T0, __T1, __T2, __T3, __T4, __T5, __T6, __T7, __T8, __T9, __T10, __T11, __T12>{ + match this { + Tuple13::_T13{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, } => { + Tuple13::_T13 { + _0: f_0.clone()(_0), + _1: f_1.clone()(_1), + _2: f_2.clone()(_2), + _3: f_3.clone()(_3), + _4: f_4.clone()(_4), + _5: f_5.clone()(_5), + _6: f_6.clone()(_6), + _7: f_7.clone()(_7), + _8: f_8.clone()(_8), + _9: f_9.clone()(_9), + _10: f_10.clone()(_10), + _11: f_11.clone()(_11), + _12: f_12.clone()(_12) + } + }, + } + }) + } + } + + impl PartialEq + for Tuple13 { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (Tuple13::_T13{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, }, Tuple13::_T13{_0: _2__0, _1: _2__1, _2: _2__2, _3: _2__3, _4: _2__4, _5: _2__5, _6: _2__6, _7: _2__7, _8: _2__8, _9: _2__9, _10: _2__10, _11: _2__11, _12: _2__12, }) => { + _0 == _2__0 && _1 == _2__1 && _2 == _2__2 && _3 == _2__3 && _4 == _2__4 && _5 == _2__5 && _6 == _2__6 && _7 == _2__7 && _8 == _2__8 && _9 == _2__9 && _10 == _2__10 && _11 == _2__11 && _12 == _2__12 + }, + _ => { + false + }, + } + } + } + + impl Eq + for Tuple13 {} + + impl Hash + for Tuple13 { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + Tuple13::_T13{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, } => { + Hash::hash(_0, _state); + Hash::hash(_1, _state); + Hash::hash(_2, _state); + Hash::hash(_3, _state); + Hash::hash(_4, _state); + Hash::hash(_5, _state); + Hash::hash(_6, _state); + Hash::hash(_7, _state); + Hash::hash(_8, _state); + Hash::hash(_9, _state); + Hash::hash(_10, _state); + Hash::hash(_11, _state); + Hash::hash(_12, _state) + }, + } + } + } + + impl AsRef> + for Tuple13 { + fn as_ref(&self) -> &Self { + self + } + } + + #[derive(Clone)] + pub enum Tuple14 { + _T14 { + _0: T0, + _1: T1, + _2: T2, + _3: T3, + _4: T4, + _5: T5, + _6: T6, + _7: T7, + _8: T8, + _9: T9, + _10: T10, + _11: T11, + _12: T12, + _13: T13 + } + } + + impl Tuple14 { + /// Returns a borrow of the field _0 + pub fn _0(&self) -> &T0 { + match self { + Tuple14::_T14{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, } => _0, + } + } + /// Returns a borrow of the field _1 + pub fn _1(&self) -> &T1 { + match self { + Tuple14::_T14{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, } => _1, + } + } + /// Returns a borrow of the field _2 + pub fn _2(&self) -> &T2 { + match self { + Tuple14::_T14{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, } => _2, + } + } + /// Returns a borrow of the field _3 + pub fn _3(&self) -> &T3 { + match self { + Tuple14::_T14{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, } => _3, + } + } + /// Returns a borrow of the field _4 + pub fn _4(&self) -> &T4 { + match self { + Tuple14::_T14{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, } => _4, + } + } + /// Returns a borrow of the field _5 + pub fn _5(&self) -> &T5 { + match self { + Tuple14::_T14{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, } => _5, + } + } + /// Returns a borrow of the field _6 + pub fn _6(&self) -> &T6 { + match self { + Tuple14::_T14{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, } => _6, + } + } + /// Returns a borrow of the field _7 + pub fn _7(&self) -> &T7 { + match self { + Tuple14::_T14{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, } => _7, + } + } + /// Returns a borrow of the field _8 + pub fn _8(&self) -> &T8 { + match self { + Tuple14::_T14{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, } => _8, + } + } + /// Returns a borrow of the field _9 + pub fn _9(&self) -> &T9 { + match self { + Tuple14::_T14{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, } => _9, + } + } + /// Returns a borrow of the field _10 + pub fn _10(&self) -> &T10 { + match self { + Tuple14::_T14{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, } => _10, + } + } + /// Returns a borrow of the field _11 + pub fn _11(&self) -> &T11 { + match self { + Tuple14::_T14{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, } => _11, + } + } + /// Returns a borrow of the field _12 + pub fn _12(&self) -> &T12 { + match self { + Tuple14::_T14{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, } => _12, + } + } + /// Returns a borrow of the field _13 + pub fn _13(&self) -> &T13 { + match self { + Tuple14::_T14{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, } => _13, + } + } + } + + impl Debug + for Tuple14 { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for Tuple14 { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + Tuple14::_T14{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, } => { + write!(_formatter, "(")?; + DafnyPrint::fmt_print(_0, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_1, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_2, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_3, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_4, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_5, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_6, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_7, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_8, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_9, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_10, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_11, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_12, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_13, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl Tuple14 { + /// Given type parameter conversions, returns a lambda to convert this structure + pub fn coerce<__T0: DafnyType, __T1: DafnyType, __T2: DafnyType, __T3: DafnyType, __T4: DafnyType, __T5: DafnyType, __T6: DafnyType, __T7: DafnyType, __T8: DafnyType, __T9: DafnyType, __T10: DafnyType, __T11: DafnyType, __T12: DafnyType, __T13: DafnyType>(f_0: Rc __T0 + 'static>, f_1: Rc __T1 + 'static>, f_2: Rc __T2 + 'static>, f_3: Rc __T3 + 'static>, f_4: Rc __T4 + 'static>, f_5: Rc __T5 + 'static>, f_6: Rc __T6 + 'static>, f_7: Rc __T7 + 'static>, f_8: Rc __T8 + 'static>, f_9: Rc __T9 + 'static>, f_10: Rc __T10 + 'static>, f_11: Rc __T11 + 'static>, f_12: Rc __T12 + 'static>, f_13: Rc __T13 + 'static>) -> Rc) -> Tuple14<__T0, __T1, __T2, __T3, __T4, __T5, __T6, __T7, __T8, __T9, __T10, __T11, __T12, __T13>> { + Rc::new(move |this: Self| -> Tuple14<__T0, __T1, __T2, __T3, __T4, __T5, __T6, __T7, __T8, __T9, __T10, __T11, __T12, __T13>{ + match this { + Tuple14::_T14{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, } => { + Tuple14::_T14 { + _0: f_0.clone()(_0), + _1: f_1.clone()(_1), + _2: f_2.clone()(_2), + _3: f_3.clone()(_3), + _4: f_4.clone()(_4), + _5: f_5.clone()(_5), + _6: f_6.clone()(_6), + _7: f_7.clone()(_7), + _8: f_8.clone()(_8), + _9: f_9.clone()(_9), + _10: f_10.clone()(_10), + _11: f_11.clone()(_11), + _12: f_12.clone()(_12), + _13: f_13.clone()(_13) + } + }, + } + }) + } + } + + impl PartialEq + for Tuple14 { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (Tuple14::_T14{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, }, Tuple14::_T14{_0: _2__0, _1: _2__1, _2: _2__2, _3: _2__3, _4: _2__4, _5: _2__5, _6: _2__6, _7: _2__7, _8: _2__8, _9: _2__9, _10: _2__10, _11: _2__11, _12: _2__12, _13: _2__13, }) => { + _0 == _2__0 && _1 == _2__1 && _2 == _2__2 && _3 == _2__3 && _4 == _2__4 && _5 == _2__5 && _6 == _2__6 && _7 == _2__7 && _8 == _2__8 && _9 == _2__9 && _10 == _2__10 && _11 == _2__11 && _12 == _2__12 && _13 == _2__13 + }, + _ => { + false + }, + } + } + } + + impl Eq + for Tuple14 {} + + impl Hash + for Tuple14 { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + Tuple14::_T14{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, } => { + Hash::hash(_0, _state); + Hash::hash(_1, _state); + Hash::hash(_2, _state); + Hash::hash(_3, _state); + Hash::hash(_4, _state); + Hash::hash(_5, _state); + Hash::hash(_6, _state); + Hash::hash(_7, _state); + Hash::hash(_8, _state); + Hash::hash(_9, _state); + Hash::hash(_10, _state); + Hash::hash(_11, _state); + Hash::hash(_12, _state); + Hash::hash(_13, _state) + }, + } + } + } + + impl AsRef> + for Tuple14 { + fn as_ref(&self) -> &Self { + self + } + } + + #[derive(Clone)] + pub enum Tuple15 { + _T15 { + _0: T0, + _1: T1, + _2: T2, + _3: T3, + _4: T4, + _5: T5, + _6: T6, + _7: T7, + _8: T8, + _9: T9, + _10: T10, + _11: T11, + _12: T12, + _13: T13, + _14: T14 + } + } + + impl Tuple15 { + /// Returns a borrow of the field _0 + pub fn _0(&self) -> &T0 { + match self { + Tuple15::_T15{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, } => _0, + } + } + /// Returns a borrow of the field _1 + pub fn _1(&self) -> &T1 { + match self { + Tuple15::_T15{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, } => _1, + } + } + /// Returns a borrow of the field _2 + pub fn _2(&self) -> &T2 { + match self { + Tuple15::_T15{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, } => _2, + } + } + /// Returns a borrow of the field _3 + pub fn _3(&self) -> &T3 { + match self { + Tuple15::_T15{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, } => _3, + } + } + /// Returns a borrow of the field _4 + pub fn _4(&self) -> &T4 { + match self { + Tuple15::_T15{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, } => _4, + } + } + /// Returns a borrow of the field _5 + pub fn _5(&self) -> &T5 { + match self { + Tuple15::_T15{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, } => _5, + } + } + /// Returns a borrow of the field _6 + pub fn _6(&self) -> &T6 { + match self { + Tuple15::_T15{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, } => _6, + } + } + /// Returns a borrow of the field _7 + pub fn _7(&self) -> &T7 { + match self { + Tuple15::_T15{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, } => _7, + } + } + /// Returns a borrow of the field _8 + pub fn _8(&self) -> &T8 { + match self { + Tuple15::_T15{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, } => _8, + } + } + /// Returns a borrow of the field _9 + pub fn _9(&self) -> &T9 { + match self { + Tuple15::_T15{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, } => _9, + } + } + /// Returns a borrow of the field _10 + pub fn _10(&self) -> &T10 { + match self { + Tuple15::_T15{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, } => _10, + } + } + /// Returns a borrow of the field _11 + pub fn _11(&self) -> &T11 { + match self { + Tuple15::_T15{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, } => _11, + } + } + /// Returns a borrow of the field _12 + pub fn _12(&self) -> &T12 { + match self { + Tuple15::_T15{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, } => _12, + } + } + /// Returns a borrow of the field _13 + pub fn _13(&self) -> &T13 { + match self { + Tuple15::_T15{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, } => _13, + } + } + /// Returns a borrow of the field _14 + pub fn _14(&self) -> &T14 { + match self { + Tuple15::_T15{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, } => _14, + } + } + } + + impl Debug + for Tuple15 { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for Tuple15 { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + Tuple15::_T15{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, } => { + write!(_formatter, "(")?; + DafnyPrint::fmt_print(_0, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_1, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_2, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_3, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_4, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_5, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_6, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_7, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_8, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_9, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_10, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_11, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_12, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_13, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_14, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl Tuple15 { + /// Given type parameter conversions, returns a lambda to convert this structure + pub fn coerce<__T0: DafnyType, __T1: DafnyType, __T2: DafnyType, __T3: DafnyType, __T4: DafnyType, __T5: DafnyType, __T6: DafnyType, __T7: DafnyType, __T8: DafnyType, __T9: DafnyType, __T10: DafnyType, __T11: DafnyType, __T12: DafnyType, __T13: DafnyType, __T14: DafnyType>(f_0: Rc __T0 + 'static>, f_1: Rc __T1 + 'static>, f_2: Rc __T2 + 'static>, f_3: Rc __T3 + 'static>, f_4: Rc __T4 + 'static>, f_5: Rc __T5 + 'static>, f_6: Rc __T6 + 'static>, f_7: Rc __T7 + 'static>, f_8: Rc __T8 + 'static>, f_9: Rc __T9 + 'static>, f_10: Rc __T10 + 'static>, f_11: Rc __T11 + 'static>, f_12: Rc __T12 + 'static>, f_13: Rc __T13 + 'static>, f_14: Rc __T14 + 'static>) -> Rc) -> Tuple15<__T0, __T1, __T2, __T3, __T4, __T5, __T6, __T7, __T8, __T9, __T10, __T11, __T12, __T13, __T14>> { + Rc::new(move |this: Self| -> Tuple15<__T0, __T1, __T2, __T3, __T4, __T5, __T6, __T7, __T8, __T9, __T10, __T11, __T12, __T13, __T14>{ + match this { + Tuple15::_T15{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, } => { + Tuple15::_T15 { + _0: f_0.clone()(_0), + _1: f_1.clone()(_1), + _2: f_2.clone()(_2), + _3: f_3.clone()(_3), + _4: f_4.clone()(_4), + _5: f_5.clone()(_5), + _6: f_6.clone()(_6), + _7: f_7.clone()(_7), + _8: f_8.clone()(_8), + _9: f_9.clone()(_9), + _10: f_10.clone()(_10), + _11: f_11.clone()(_11), + _12: f_12.clone()(_12), + _13: f_13.clone()(_13), + _14: f_14.clone()(_14) + } + }, + } + }) + } + } + + impl PartialEq + for Tuple15 { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (Tuple15::_T15{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, }, Tuple15::_T15{_0: _2__0, _1: _2__1, _2: _2__2, _3: _2__3, _4: _2__4, _5: _2__5, _6: _2__6, _7: _2__7, _8: _2__8, _9: _2__9, _10: _2__10, _11: _2__11, _12: _2__12, _13: _2__13, _14: _2__14, }) => { + _0 == _2__0 && _1 == _2__1 && _2 == _2__2 && _3 == _2__3 && _4 == _2__4 && _5 == _2__5 && _6 == _2__6 && _7 == _2__7 && _8 == _2__8 && _9 == _2__9 && _10 == _2__10 && _11 == _2__11 && _12 == _2__12 && _13 == _2__13 && _14 == _2__14 + }, + _ => { + false + }, + } + } + } + + impl Eq + for Tuple15 {} + + impl Hash + for Tuple15 { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + Tuple15::_T15{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, } => { + Hash::hash(_0, _state); + Hash::hash(_1, _state); + Hash::hash(_2, _state); + Hash::hash(_3, _state); + Hash::hash(_4, _state); + Hash::hash(_5, _state); + Hash::hash(_6, _state); + Hash::hash(_7, _state); + Hash::hash(_8, _state); + Hash::hash(_9, _state); + Hash::hash(_10, _state); + Hash::hash(_11, _state); + Hash::hash(_12, _state); + Hash::hash(_13, _state); + Hash::hash(_14, _state) + }, + } + } + } + + impl AsRef> + for Tuple15 { + fn as_ref(&self) -> &Self { + self + } + } + + #[derive(Clone)] + pub enum Tuple16 { + _T16 { + _0: T0, + _1: T1, + _2: T2, + _3: T3, + _4: T4, + _5: T5, + _6: T6, + _7: T7, + _8: T8, + _9: T9, + _10: T10, + _11: T11, + _12: T12, + _13: T13, + _14: T14, + _15: T15 + } + } + + impl Tuple16 { + /// Returns a borrow of the field _0 + pub fn _0(&self) -> &T0 { + match self { + Tuple16::_T16{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, } => _0, + } + } + /// Returns a borrow of the field _1 + pub fn _1(&self) -> &T1 { + match self { + Tuple16::_T16{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, } => _1, + } + } + /// Returns a borrow of the field _2 + pub fn _2(&self) -> &T2 { + match self { + Tuple16::_T16{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, } => _2, + } + } + /// Returns a borrow of the field _3 + pub fn _3(&self) -> &T3 { + match self { + Tuple16::_T16{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, } => _3, + } + } + /// Returns a borrow of the field _4 + pub fn _4(&self) -> &T4 { + match self { + Tuple16::_T16{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, } => _4, + } + } + /// Returns a borrow of the field _5 + pub fn _5(&self) -> &T5 { + match self { + Tuple16::_T16{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, } => _5, + } + } + /// Returns a borrow of the field _6 + pub fn _6(&self) -> &T6 { + match self { + Tuple16::_T16{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, } => _6, + } + } + /// Returns a borrow of the field _7 + pub fn _7(&self) -> &T7 { + match self { + Tuple16::_T16{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, } => _7, + } + } + /// Returns a borrow of the field _8 + pub fn _8(&self) -> &T8 { + match self { + Tuple16::_T16{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, } => _8, + } + } + /// Returns a borrow of the field _9 + pub fn _9(&self) -> &T9 { + match self { + Tuple16::_T16{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, } => _9, + } + } + /// Returns a borrow of the field _10 + pub fn _10(&self) -> &T10 { + match self { + Tuple16::_T16{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, } => _10, + } + } + /// Returns a borrow of the field _11 + pub fn _11(&self) -> &T11 { + match self { + Tuple16::_T16{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, } => _11, + } + } + /// Returns a borrow of the field _12 + pub fn _12(&self) -> &T12 { + match self { + Tuple16::_T16{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, } => _12, + } + } + /// Returns a borrow of the field _13 + pub fn _13(&self) -> &T13 { + match self { + Tuple16::_T16{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, } => _13, + } + } + /// Returns a borrow of the field _14 + pub fn _14(&self) -> &T14 { + match self { + Tuple16::_T16{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, } => _14, + } + } + /// Returns a borrow of the field _15 + pub fn _15(&self) -> &T15 { + match self { + Tuple16::_T16{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, } => _15, + } + } + } + + impl Debug + for Tuple16 { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for Tuple16 { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + Tuple16::_T16{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, } => { + write!(_formatter, "(")?; + DafnyPrint::fmt_print(_0, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_1, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_2, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_3, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_4, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_5, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_6, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_7, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_8, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_9, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_10, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_11, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_12, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_13, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_14, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_15, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl Tuple16 { + /// Given type parameter conversions, returns a lambda to convert this structure + pub fn coerce<__T0: DafnyType, __T1: DafnyType, __T2: DafnyType, __T3: DafnyType, __T4: DafnyType, __T5: DafnyType, __T6: DafnyType, __T7: DafnyType, __T8: DafnyType, __T9: DafnyType, __T10: DafnyType, __T11: DafnyType, __T12: DafnyType, __T13: DafnyType, __T14: DafnyType, __T15: DafnyType>(f_0: Rc __T0 + 'static>, f_1: Rc __T1 + 'static>, f_2: Rc __T2 + 'static>, f_3: Rc __T3 + 'static>, f_4: Rc __T4 + 'static>, f_5: Rc __T5 + 'static>, f_6: Rc __T6 + 'static>, f_7: Rc __T7 + 'static>, f_8: Rc __T8 + 'static>, f_9: Rc __T9 + 'static>, f_10: Rc __T10 + 'static>, f_11: Rc __T11 + 'static>, f_12: Rc __T12 + 'static>, f_13: Rc __T13 + 'static>, f_14: Rc __T14 + 'static>, f_15: Rc __T15 + 'static>) -> Rc) -> Tuple16<__T0, __T1, __T2, __T3, __T4, __T5, __T6, __T7, __T8, __T9, __T10, __T11, __T12, __T13, __T14, __T15>> { + Rc::new(move |this: Self| -> Tuple16<__T0, __T1, __T2, __T3, __T4, __T5, __T6, __T7, __T8, __T9, __T10, __T11, __T12, __T13, __T14, __T15>{ + match this { + Tuple16::_T16{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, } => { + Tuple16::_T16 { + _0: f_0.clone()(_0), + _1: f_1.clone()(_1), + _2: f_2.clone()(_2), + _3: f_3.clone()(_3), + _4: f_4.clone()(_4), + _5: f_5.clone()(_5), + _6: f_6.clone()(_6), + _7: f_7.clone()(_7), + _8: f_8.clone()(_8), + _9: f_9.clone()(_9), + _10: f_10.clone()(_10), + _11: f_11.clone()(_11), + _12: f_12.clone()(_12), + _13: f_13.clone()(_13), + _14: f_14.clone()(_14), + _15: f_15.clone()(_15) + } + }, + } + }) + } + } + + impl PartialEq + for Tuple16 { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (Tuple16::_T16{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, }, Tuple16::_T16{_0: _2__0, _1: _2__1, _2: _2__2, _3: _2__3, _4: _2__4, _5: _2__5, _6: _2__6, _7: _2__7, _8: _2__8, _9: _2__9, _10: _2__10, _11: _2__11, _12: _2__12, _13: _2__13, _14: _2__14, _15: _2__15, }) => { + _0 == _2__0 && _1 == _2__1 && _2 == _2__2 && _3 == _2__3 && _4 == _2__4 && _5 == _2__5 && _6 == _2__6 && _7 == _2__7 && _8 == _2__8 && _9 == _2__9 && _10 == _2__10 && _11 == _2__11 && _12 == _2__12 && _13 == _2__13 && _14 == _2__14 && _15 == _2__15 + }, + _ => { + false + }, + } + } + } + + impl Eq + for Tuple16 {} + + impl Hash + for Tuple16 { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + Tuple16::_T16{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, } => { + Hash::hash(_0, _state); + Hash::hash(_1, _state); + Hash::hash(_2, _state); + Hash::hash(_3, _state); + Hash::hash(_4, _state); + Hash::hash(_5, _state); + Hash::hash(_6, _state); + Hash::hash(_7, _state); + Hash::hash(_8, _state); + Hash::hash(_9, _state); + Hash::hash(_10, _state); + Hash::hash(_11, _state); + Hash::hash(_12, _state); + Hash::hash(_13, _state); + Hash::hash(_14, _state); + Hash::hash(_15, _state) + }, + } + } + } + + impl AsRef> + for Tuple16 { + fn as_ref(&self) -> &Self { + self + } + } + + #[derive(Clone)] + pub enum Tuple17 { + _T17 { + _0: T0, + _1: T1, + _2: T2, + _3: T3, + _4: T4, + _5: T5, + _6: T6, + _7: T7, + _8: T8, + _9: T9, + _10: T10, + _11: T11, + _12: T12, + _13: T13, + _14: T14, + _15: T15, + _16: T16 + } + } + + impl Tuple17 { + /// Returns a borrow of the field _0 + pub fn _0(&self) -> &T0 { + match self { + Tuple17::_T17{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, } => _0, + } + } + /// Returns a borrow of the field _1 + pub fn _1(&self) -> &T1 { + match self { + Tuple17::_T17{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, } => _1, + } + } + /// Returns a borrow of the field _2 + pub fn _2(&self) -> &T2 { + match self { + Tuple17::_T17{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, } => _2, + } + } + /// Returns a borrow of the field _3 + pub fn _3(&self) -> &T3 { + match self { + Tuple17::_T17{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, } => _3, + } + } + /// Returns a borrow of the field _4 + pub fn _4(&self) -> &T4 { + match self { + Tuple17::_T17{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, } => _4, + } + } + /// Returns a borrow of the field _5 + pub fn _5(&self) -> &T5 { + match self { + Tuple17::_T17{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, } => _5, + } + } + /// Returns a borrow of the field _6 + pub fn _6(&self) -> &T6 { + match self { + Tuple17::_T17{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, } => _6, + } + } + /// Returns a borrow of the field _7 + pub fn _7(&self) -> &T7 { + match self { + Tuple17::_T17{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, } => _7, + } + } + /// Returns a borrow of the field _8 + pub fn _8(&self) -> &T8 { + match self { + Tuple17::_T17{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, } => _8, + } + } + /// Returns a borrow of the field _9 + pub fn _9(&self) -> &T9 { + match self { + Tuple17::_T17{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, } => _9, + } + } + /// Returns a borrow of the field _10 + pub fn _10(&self) -> &T10 { + match self { + Tuple17::_T17{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, } => _10, + } + } + /// Returns a borrow of the field _11 + pub fn _11(&self) -> &T11 { + match self { + Tuple17::_T17{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, } => _11, + } + } + /// Returns a borrow of the field _12 + pub fn _12(&self) -> &T12 { + match self { + Tuple17::_T17{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, } => _12, + } + } + /// Returns a borrow of the field _13 + pub fn _13(&self) -> &T13 { + match self { + Tuple17::_T17{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, } => _13, + } + } + /// Returns a borrow of the field _14 + pub fn _14(&self) -> &T14 { + match self { + Tuple17::_T17{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, } => _14, + } + } + /// Returns a borrow of the field _15 + pub fn _15(&self) -> &T15 { + match self { + Tuple17::_T17{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, } => _15, + } + } + /// Returns a borrow of the field _16 + pub fn _16(&self) -> &T16 { + match self { + Tuple17::_T17{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, } => _16, + } + } + } + + impl Debug + for Tuple17 { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for Tuple17 { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + Tuple17::_T17{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, } => { + write!(_formatter, "(")?; + DafnyPrint::fmt_print(_0, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_1, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_2, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_3, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_4, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_5, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_6, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_7, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_8, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_9, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_10, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_11, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_12, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_13, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_14, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_15, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_16, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl Tuple17 { + /// Given type parameter conversions, returns a lambda to convert this structure + pub fn coerce<__T0: DafnyType, __T1: DafnyType, __T2: DafnyType, __T3: DafnyType, __T4: DafnyType, __T5: DafnyType, __T6: DafnyType, __T7: DafnyType, __T8: DafnyType, __T9: DafnyType, __T10: DafnyType, __T11: DafnyType, __T12: DafnyType, __T13: DafnyType, __T14: DafnyType, __T15: DafnyType, __T16: DafnyType>(f_0: Rc __T0 + 'static>, f_1: Rc __T1 + 'static>, f_2: Rc __T2 + 'static>, f_3: Rc __T3 + 'static>, f_4: Rc __T4 + 'static>, f_5: Rc __T5 + 'static>, f_6: Rc __T6 + 'static>, f_7: Rc __T7 + 'static>, f_8: Rc __T8 + 'static>, f_9: Rc __T9 + 'static>, f_10: Rc __T10 + 'static>, f_11: Rc __T11 + 'static>, f_12: Rc __T12 + 'static>, f_13: Rc __T13 + 'static>, f_14: Rc __T14 + 'static>, f_15: Rc __T15 + 'static>, f_16: Rc __T16 + 'static>) -> Rc) -> Tuple17<__T0, __T1, __T2, __T3, __T4, __T5, __T6, __T7, __T8, __T9, __T10, __T11, __T12, __T13, __T14, __T15, __T16>> { + Rc::new(move |this: Self| -> Tuple17<__T0, __T1, __T2, __T3, __T4, __T5, __T6, __T7, __T8, __T9, __T10, __T11, __T12, __T13, __T14, __T15, __T16>{ + match this { + Tuple17::_T17{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, } => { + Tuple17::_T17 { + _0: f_0.clone()(_0), + _1: f_1.clone()(_1), + _2: f_2.clone()(_2), + _3: f_3.clone()(_3), + _4: f_4.clone()(_4), + _5: f_5.clone()(_5), + _6: f_6.clone()(_6), + _7: f_7.clone()(_7), + _8: f_8.clone()(_8), + _9: f_9.clone()(_9), + _10: f_10.clone()(_10), + _11: f_11.clone()(_11), + _12: f_12.clone()(_12), + _13: f_13.clone()(_13), + _14: f_14.clone()(_14), + _15: f_15.clone()(_15), + _16: f_16.clone()(_16) + } + }, + } + }) + } + } + + impl PartialEq + for Tuple17 { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (Tuple17::_T17{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, }, Tuple17::_T17{_0: _2__0, _1: _2__1, _2: _2__2, _3: _2__3, _4: _2__4, _5: _2__5, _6: _2__6, _7: _2__7, _8: _2__8, _9: _2__9, _10: _2__10, _11: _2__11, _12: _2__12, _13: _2__13, _14: _2__14, _15: _2__15, _16: _2__16, }) => { + _0 == _2__0 && _1 == _2__1 && _2 == _2__2 && _3 == _2__3 && _4 == _2__4 && _5 == _2__5 && _6 == _2__6 && _7 == _2__7 && _8 == _2__8 && _9 == _2__9 && _10 == _2__10 && _11 == _2__11 && _12 == _2__12 && _13 == _2__13 && _14 == _2__14 && _15 == _2__15 && _16 == _2__16 + }, + _ => { + false + }, + } + } + } + + impl Eq + for Tuple17 {} + + impl Hash + for Tuple17 { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + Tuple17::_T17{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, } => { + Hash::hash(_0, _state); + Hash::hash(_1, _state); + Hash::hash(_2, _state); + Hash::hash(_3, _state); + Hash::hash(_4, _state); + Hash::hash(_5, _state); + Hash::hash(_6, _state); + Hash::hash(_7, _state); + Hash::hash(_8, _state); + Hash::hash(_9, _state); + Hash::hash(_10, _state); + Hash::hash(_11, _state); + Hash::hash(_12, _state); + Hash::hash(_13, _state); + Hash::hash(_14, _state); + Hash::hash(_15, _state); + Hash::hash(_16, _state) + }, + } + } + } + + impl AsRef> + for Tuple17 { + fn as_ref(&self) -> &Self { + self + } + } + + #[derive(Clone)] + pub enum Tuple18 { + _T18 { + _0: T0, + _1: T1, + _2: T2, + _3: T3, + _4: T4, + _5: T5, + _6: T6, + _7: T7, + _8: T8, + _9: T9, + _10: T10, + _11: T11, + _12: T12, + _13: T13, + _14: T14, + _15: T15, + _16: T16, + _17: T17 + } + } + + impl Tuple18 { + /// Returns a borrow of the field _0 + pub fn _0(&self) -> &T0 { + match self { + Tuple18::_T18{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, } => _0, + } + } + /// Returns a borrow of the field _1 + pub fn _1(&self) -> &T1 { + match self { + Tuple18::_T18{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, } => _1, + } + } + /// Returns a borrow of the field _2 + pub fn _2(&self) -> &T2 { + match self { + Tuple18::_T18{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, } => _2, + } + } + /// Returns a borrow of the field _3 + pub fn _3(&self) -> &T3 { + match self { + Tuple18::_T18{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, } => _3, + } + } + /// Returns a borrow of the field _4 + pub fn _4(&self) -> &T4 { + match self { + Tuple18::_T18{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, } => _4, + } + } + /// Returns a borrow of the field _5 + pub fn _5(&self) -> &T5 { + match self { + Tuple18::_T18{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, } => _5, + } + } + /// Returns a borrow of the field _6 + pub fn _6(&self) -> &T6 { + match self { + Tuple18::_T18{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, } => _6, + } + } + /// Returns a borrow of the field _7 + pub fn _7(&self) -> &T7 { + match self { + Tuple18::_T18{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, } => _7, + } + } + /// Returns a borrow of the field _8 + pub fn _8(&self) -> &T8 { + match self { + Tuple18::_T18{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, } => _8, + } + } + /// Returns a borrow of the field _9 + pub fn _9(&self) -> &T9 { + match self { + Tuple18::_T18{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, } => _9, + } + } + /// Returns a borrow of the field _10 + pub fn _10(&self) -> &T10 { + match self { + Tuple18::_T18{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, } => _10, + } + } + /// Returns a borrow of the field _11 + pub fn _11(&self) -> &T11 { + match self { + Tuple18::_T18{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, } => _11, + } + } + /// Returns a borrow of the field _12 + pub fn _12(&self) -> &T12 { + match self { + Tuple18::_T18{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, } => _12, + } + } + /// Returns a borrow of the field _13 + pub fn _13(&self) -> &T13 { + match self { + Tuple18::_T18{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, } => _13, + } + } + /// Returns a borrow of the field _14 + pub fn _14(&self) -> &T14 { + match self { + Tuple18::_T18{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, } => _14, + } + } + /// Returns a borrow of the field _15 + pub fn _15(&self) -> &T15 { + match self { + Tuple18::_T18{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, } => _15, + } + } + /// Returns a borrow of the field _16 + pub fn _16(&self) -> &T16 { + match self { + Tuple18::_T18{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, } => _16, + } + } + /// Returns a borrow of the field _17 + pub fn _17(&self) -> &T17 { + match self { + Tuple18::_T18{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, } => _17, + } + } + } + + impl Debug + for Tuple18 { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for Tuple18 { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + Tuple18::_T18{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, } => { + write!(_formatter, "(")?; + DafnyPrint::fmt_print(_0, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_1, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_2, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_3, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_4, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_5, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_6, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_7, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_8, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_9, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_10, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_11, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_12, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_13, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_14, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_15, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_16, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_17, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl Tuple18 { + /// Given type parameter conversions, returns a lambda to convert this structure + pub fn coerce<__T0: DafnyType, __T1: DafnyType, __T2: DafnyType, __T3: DafnyType, __T4: DafnyType, __T5: DafnyType, __T6: DafnyType, __T7: DafnyType, __T8: DafnyType, __T9: DafnyType, __T10: DafnyType, __T11: DafnyType, __T12: DafnyType, __T13: DafnyType, __T14: DafnyType, __T15: DafnyType, __T16: DafnyType, __T17: DafnyType>(f_0: Rc __T0 + 'static>, f_1: Rc __T1 + 'static>, f_2: Rc __T2 + 'static>, f_3: Rc __T3 + 'static>, f_4: Rc __T4 + 'static>, f_5: Rc __T5 + 'static>, f_6: Rc __T6 + 'static>, f_7: Rc __T7 + 'static>, f_8: Rc __T8 + 'static>, f_9: Rc __T9 + 'static>, f_10: Rc __T10 + 'static>, f_11: Rc __T11 + 'static>, f_12: Rc __T12 + 'static>, f_13: Rc __T13 + 'static>, f_14: Rc __T14 + 'static>, f_15: Rc __T15 + 'static>, f_16: Rc __T16 + 'static>, f_17: Rc __T17 + 'static>) -> Rc) -> Tuple18<__T0, __T1, __T2, __T3, __T4, __T5, __T6, __T7, __T8, __T9, __T10, __T11, __T12, __T13, __T14, __T15, __T16, __T17>> { + Rc::new(move |this: Self| -> Tuple18<__T0, __T1, __T2, __T3, __T4, __T5, __T6, __T7, __T8, __T9, __T10, __T11, __T12, __T13, __T14, __T15, __T16, __T17>{ + match this { + Tuple18::_T18{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, } => { + Tuple18::_T18 { + _0: f_0.clone()(_0), + _1: f_1.clone()(_1), + _2: f_2.clone()(_2), + _3: f_3.clone()(_3), + _4: f_4.clone()(_4), + _5: f_5.clone()(_5), + _6: f_6.clone()(_6), + _7: f_7.clone()(_7), + _8: f_8.clone()(_8), + _9: f_9.clone()(_9), + _10: f_10.clone()(_10), + _11: f_11.clone()(_11), + _12: f_12.clone()(_12), + _13: f_13.clone()(_13), + _14: f_14.clone()(_14), + _15: f_15.clone()(_15), + _16: f_16.clone()(_16), + _17: f_17.clone()(_17) + } + }, + } + }) + } + } + + impl PartialEq + for Tuple18 { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (Tuple18::_T18{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, }, Tuple18::_T18{_0: _2__0, _1: _2__1, _2: _2__2, _3: _2__3, _4: _2__4, _5: _2__5, _6: _2__6, _7: _2__7, _8: _2__8, _9: _2__9, _10: _2__10, _11: _2__11, _12: _2__12, _13: _2__13, _14: _2__14, _15: _2__15, _16: _2__16, _17: _2__17, }) => { + _0 == _2__0 && _1 == _2__1 && _2 == _2__2 && _3 == _2__3 && _4 == _2__4 && _5 == _2__5 && _6 == _2__6 && _7 == _2__7 && _8 == _2__8 && _9 == _2__9 && _10 == _2__10 && _11 == _2__11 && _12 == _2__12 && _13 == _2__13 && _14 == _2__14 && _15 == _2__15 && _16 == _2__16 && _17 == _2__17 + }, + _ => { + false + }, + } + } + } + + impl Eq + for Tuple18 {} + + impl Hash + for Tuple18 { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + Tuple18::_T18{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, } => { + Hash::hash(_0, _state); + Hash::hash(_1, _state); + Hash::hash(_2, _state); + Hash::hash(_3, _state); + Hash::hash(_4, _state); + Hash::hash(_5, _state); + Hash::hash(_6, _state); + Hash::hash(_7, _state); + Hash::hash(_8, _state); + Hash::hash(_9, _state); + Hash::hash(_10, _state); + Hash::hash(_11, _state); + Hash::hash(_12, _state); + Hash::hash(_13, _state); + Hash::hash(_14, _state); + Hash::hash(_15, _state); + Hash::hash(_16, _state); + Hash::hash(_17, _state) + }, + } + } + } + + impl AsRef> + for Tuple18 { + fn as_ref(&self) -> &Self { + self + } + } + + #[derive(Clone)] + pub enum Tuple19 { + _T19 { + _0: T0, + _1: T1, + _2: T2, + _3: T3, + _4: T4, + _5: T5, + _6: T6, + _7: T7, + _8: T8, + _9: T9, + _10: T10, + _11: T11, + _12: T12, + _13: T13, + _14: T14, + _15: T15, + _16: T16, + _17: T17, + _18: T18 + } + } + + impl Tuple19 { + /// Returns a borrow of the field _0 + pub fn _0(&self) -> &T0 { + match self { + Tuple19::_T19{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, } => _0, + } + } + /// Returns a borrow of the field _1 + pub fn _1(&self) -> &T1 { + match self { + Tuple19::_T19{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, } => _1, + } + } + /// Returns a borrow of the field _2 + pub fn _2(&self) -> &T2 { + match self { + Tuple19::_T19{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, } => _2, + } + } + /// Returns a borrow of the field _3 + pub fn _3(&self) -> &T3 { + match self { + Tuple19::_T19{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, } => _3, + } + } + /// Returns a borrow of the field _4 + pub fn _4(&self) -> &T4 { + match self { + Tuple19::_T19{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, } => _4, + } + } + /// Returns a borrow of the field _5 + pub fn _5(&self) -> &T5 { + match self { + Tuple19::_T19{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, } => _5, + } + } + /// Returns a borrow of the field _6 + pub fn _6(&self) -> &T6 { + match self { + Tuple19::_T19{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, } => _6, + } + } + /// Returns a borrow of the field _7 + pub fn _7(&self) -> &T7 { + match self { + Tuple19::_T19{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, } => _7, + } + } + /// Returns a borrow of the field _8 + pub fn _8(&self) -> &T8 { + match self { + Tuple19::_T19{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, } => _8, + } + } + /// Returns a borrow of the field _9 + pub fn _9(&self) -> &T9 { + match self { + Tuple19::_T19{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, } => _9, + } + } + /// Returns a borrow of the field _10 + pub fn _10(&self) -> &T10 { + match self { + Tuple19::_T19{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, } => _10, + } + } + /// Returns a borrow of the field _11 + pub fn _11(&self) -> &T11 { + match self { + Tuple19::_T19{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, } => _11, + } + } + /// Returns a borrow of the field _12 + pub fn _12(&self) -> &T12 { + match self { + Tuple19::_T19{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, } => _12, + } + } + /// Returns a borrow of the field _13 + pub fn _13(&self) -> &T13 { + match self { + Tuple19::_T19{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, } => _13, + } + } + /// Returns a borrow of the field _14 + pub fn _14(&self) -> &T14 { + match self { + Tuple19::_T19{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, } => _14, + } + } + /// Returns a borrow of the field _15 + pub fn _15(&self) -> &T15 { + match self { + Tuple19::_T19{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, } => _15, + } + } + /// Returns a borrow of the field _16 + pub fn _16(&self) -> &T16 { + match self { + Tuple19::_T19{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, } => _16, + } + } + /// Returns a borrow of the field _17 + pub fn _17(&self) -> &T17 { + match self { + Tuple19::_T19{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, } => _17, + } + } + /// Returns a borrow of the field _18 + pub fn _18(&self) -> &T18 { + match self { + Tuple19::_T19{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, } => _18, + } + } + } + + impl Debug + for Tuple19 { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for Tuple19 { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + Tuple19::_T19{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, } => { + write!(_formatter, "(")?; + DafnyPrint::fmt_print(_0, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_1, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_2, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_3, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_4, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_5, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_6, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_7, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_8, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_9, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_10, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_11, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_12, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_13, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_14, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_15, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_16, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_17, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_18, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl Tuple19 { + /// Given type parameter conversions, returns a lambda to convert this structure + pub fn coerce<__T0: DafnyType, __T1: DafnyType, __T2: DafnyType, __T3: DafnyType, __T4: DafnyType, __T5: DafnyType, __T6: DafnyType, __T7: DafnyType, __T8: DafnyType, __T9: DafnyType, __T10: DafnyType, __T11: DafnyType, __T12: DafnyType, __T13: DafnyType, __T14: DafnyType, __T15: DafnyType, __T16: DafnyType, __T17: DafnyType, __T18: DafnyType>(f_0: Rc __T0 + 'static>, f_1: Rc __T1 + 'static>, f_2: Rc __T2 + 'static>, f_3: Rc __T3 + 'static>, f_4: Rc __T4 + 'static>, f_5: Rc __T5 + 'static>, f_6: Rc __T6 + 'static>, f_7: Rc __T7 + 'static>, f_8: Rc __T8 + 'static>, f_9: Rc __T9 + 'static>, f_10: Rc __T10 + 'static>, f_11: Rc __T11 + 'static>, f_12: Rc __T12 + 'static>, f_13: Rc __T13 + 'static>, f_14: Rc __T14 + 'static>, f_15: Rc __T15 + 'static>, f_16: Rc __T16 + 'static>, f_17: Rc __T17 + 'static>, f_18: Rc __T18 + 'static>) -> Rc) -> Tuple19<__T0, __T1, __T2, __T3, __T4, __T5, __T6, __T7, __T8, __T9, __T10, __T11, __T12, __T13, __T14, __T15, __T16, __T17, __T18>> { + Rc::new(move |this: Self| -> Tuple19<__T0, __T1, __T2, __T3, __T4, __T5, __T6, __T7, __T8, __T9, __T10, __T11, __T12, __T13, __T14, __T15, __T16, __T17, __T18>{ + match this { + Tuple19::_T19{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, } => { + Tuple19::_T19 { + _0: f_0.clone()(_0), + _1: f_1.clone()(_1), + _2: f_2.clone()(_2), + _3: f_3.clone()(_3), + _4: f_4.clone()(_4), + _5: f_5.clone()(_5), + _6: f_6.clone()(_6), + _7: f_7.clone()(_7), + _8: f_8.clone()(_8), + _9: f_9.clone()(_9), + _10: f_10.clone()(_10), + _11: f_11.clone()(_11), + _12: f_12.clone()(_12), + _13: f_13.clone()(_13), + _14: f_14.clone()(_14), + _15: f_15.clone()(_15), + _16: f_16.clone()(_16), + _17: f_17.clone()(_17), + _18: f_18.clone()(_18) + } + }, + } + }) + } + } + + impl PartialEq + for Tuple19 { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (Tuple19::_T19{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, }, Tuple19::_T19{_0: _2__0, _1: _2__1, _2: _2__2, _3: _2__3, _4: _2__4, _5: _2__5, _6: _2__6, _7: _2__7, _8: _2__8, _9: _2__9, _10: _2__10, _11: _2__11, _12: _2__12, _13: _2__13, _14: _2__14, _15: _2__15, _16: _2__16, _17: _2__17, _18: _2__18, }) => { + _0 == _2__0 && _1 == _2__1 && _2 == _2__2 && _3 == _2__3 && _4 == _2__4 && _5 == _2__5 && _6 == _2__6 && _7 == _2__7 && _8 == _2__8 && _9 == _2__9 && _10 == _2__10 && _11 == _2__11 && _12 == _2__12 && _13 == _2__13 && _14 == _2__14 && _15 == _2__15 && _16 == _2__16 && _17 == _2__17 && _18 == _2__18 + }, + _ => { + false + }, + } + } + } + + impl Eq + for Tuple19 {} + + impl Hash + for Tuple19 { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + Tuple19::_T19{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, } => { + Hash::hash(_0, _state); + Hash::hash(_1, _state); + Hash::hash(_2, _state); + Hash::hash(_3, _state); + Hash::hash(_4, _state); + Hash::hash(_5, _state); + Hash::hash(_6, _state); + Hash::hash(_7, _state); + Hash::hash(_8, _state); + Hash::hash(_9, _state); + Hash::hash(_10, _state); + Hash::hash(_11, _state); + Hash::hash(_12, _state); + Hash::hash(_13, _state); + Hash::hash(_14, _state); + Hash::hash(_15, _state); + Hash::hash(_16, _state); + Hash::hash(_17, _state); + Hash::hash(_18, _state) + }, + } + } + } + + impl AsRef> + for Tuple19 { + fn as_ref(&self) -> &Self { + self + } + } + + #[derive(Clone)] + pub enum Tuple20 { + _T20 { + _0: T0, + _1: T1, + _2: T2, + _3: T3, + _4: T4, + _5: T5, + _6: T6, + _7: T7, + _8: T8, + _9: T9, + _10: T10, + _11: T11, + _12: T12, + _13: T13, + _14: T14, + _15: T15, + _16: T16, + _17: T17, + _18: T18, + _19: T19 + } + } + + impl Tuple20 { + /// Returns a borrow of the field _0 + pub fn _0(&self) -> &T0 { + match self { + Tuple20::_T20{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, } => _0, + } + } + /// Returns a borrow of the field _1 + pub fn _1(&self) -> &T1 { + match self { + Tuple20::_T20{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, } => _1, + } + } + /// Returns a borrow of the field _2 + pub fn _2(&self) -> &T2 { + match self { + Tuple20::_T20{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, } => _2, + } + } + /// Returns a borrow of the field _3 + pub fn _3(&self) -> &T3 { + match self { + Tuple20::_T20{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, } => _3, + } + } + /// Returns a borrow of the field _4 + pub fn _4(&self) -> &T4 { + match self { + Tuple20::_T20{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, } => _4, + } + } + /// Returns a borrow of the field _5 + pub fn _5(&self) -> &T5 { + match self { + Tuple20::_T20{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, } => _5, + } + } + /// Returns a borrow of the field _6 + pub fn _6(&self) -> &T6 { + match self { + Tuple20::_T20{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, } => _6, + } + } + /// Returns a borrow of the field _7 + pub fn _7(&self) -> &T7 { + match self { + Tuple20::_T20{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, } => _7, + } + } + /// Returns a borrow of the field _8 + pub fn _8(&self) -> &T8 { + match self { + Tuple20::_T20{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, } => _8, + } + } + /// Returns a borrow of the field _9 + pub fn _9(&self) -> &T9 { + match self { + Tuple20::_T20{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, } => _9, + } + } + /// Returns a borrow of the field _10 + pub fn _10(&self) -> &T10 { + match self { + Tuple20::_T20{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, } => _10, + } + } + /// Returns a borrow of the field _11 + pub fn _11(&self) -> &T11 { + match self { + Tuple20::_T20{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, } => _11, + } + } + /// Returns a borrow of the field _12 + pub fn _12(&self) -> &T12 { + match self { + Tuple20::_T20{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, } => _12, + } + } + /// Returns a borrow of the field _13 + pub fn _13(&self) -> &T13 { + match self { + Tuple20::_T20{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, } => _13, + } + } + /// Returns a borrow of the field _14 + pub fn _14(&self) -> &T14 { + match self { + Tuple20::_T20{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, } => _14, + } + } + /// Returns a borrow of the field _15 + pub fn _15(&self) -> &T15 { + match self { + Tuple20::_T20{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, } => _15, + } + } + /// Returns a borrow of the field _16 + pub fn _16(&self) -> &T16 { + match self { + Tuple20::_T20{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, } => _16, + } + } + /// Returns a borrow of the field _17 + pub fn _17(&self) -> &T17 { + match self { + Tuple20::_T20{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, } => _17, + } + } + /// Returns a borrow of the field _18 + pub fn _18(&self) -> &T18 { + match self { + Tuple20::_T20{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, } => _18, + } + } + /// Returns a borrow of the field _19 + pub fn _19(&self) -> &T19 { + match self { + Tuple20::_T20{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, } => _19, + } + } + } + + impl Debug + for Tuple20 { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for Tuple20 { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + Tuple20::_T20{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, } => { + write!(_formatter, "(")?; + DafnyPrint::fmt_print(_0, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_1, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_2, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_3, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_4, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_5, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_6, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_7, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_8, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_9, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_10, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_11, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_12, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_13, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_14, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_15, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_16, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_17, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_18, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(_19, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl Tuple20 { + /// Given type parameter conversions, returns a lambda to convert this structure + pub fn coerce<__T0: DafnyType, __T1: DafnyType, __T2: DafnyType, __T3: DafnyType, __T4: DafnyType, __T5: DafnyType, __T6: DafnyType, __T7: DafnyType, __T8: DafnyType, __T9: DafnyType, __T10: DafnyType, __T11: DafnyType, __T12: DafnyType, __T13: DafnyType, __T14: DafnyType, __T15: DafnyType, __T16: DafnyType, __T17: DafnyType, __T18: DafnyType, __T19: DafnyType>(f_0: Rc __T0 + 'static>, f_1: Rc __T1 + 'static>, f_2: Rc __T2 + 'static>, f_3: Rc __T3 + 'static>, f_4: Rc __T4 + 'static>, f_5: Rc __T5 + 'static>, f_6: Rc __T6 + 'static>, f_7: Rc __T7 + 'static>, f_8: Rc __T8 + 'static>, f_9: Rc __T9 + 'static>, f_10: Rc __T10 + 'static>, f_11: Rc __T11 + 'static>, f_12: Rc __T12 + 'static>, f_13: Rc __T13 + 'static>, f_14: Rc __T14 + 'static>, f_15: Rc __T15 + 'static>, f_16: Rc __T16 + 'static>, f_17: Rc __T17 + 'static>, f_18: Rc __T18 + 'static>, f_19: Rc __T19 + 'static>) -> Rc) -> Tuple20<__T0, __T1, __T2, __T3, __T4, __T5, __T6, __T7, __T8, __T9, __T10, __T11, __T12, __T13, __T14, __T15, __T16, __T17, __T18, __T19>> { + Rc::new(move |this: Self| -> Tuple20<__T0, __T1, __T2, __T3, __T4, __T5, __T6, __T7, __T8, __T9, __T10, __T11, __T12, __T13, __T14, __T15, __T16, __T17, __T18, __T19>{ + match this { + Tuple20::_T20{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, } => { + Tuple20::_T20 { + _0: f_0.clone()(_0), + _1: f_1.clone()(_1), + _2: f_2.clone()(_2), + _3: f_3.clone()(_3), + _4: f_4.clone()(_4), + _5: f_5.clone()(_5), + _6: f_6.clone()(_6), + _7: f_7.clone()(_7), + _8: f_8.clone()(_8), + _9: f_9.clone()(_9), + _10: f_10.clone()(_10), + _11: f_11.clone()(_11), + _12: f_12.clone()(_12), + _13: f_13.clone()(_13), + _14: f_14.clone()(_14), + _15: f_15.clone()(_15), + _16: f_16.clone()(_16), + _17: f_17.clone()(_17), + _18: f_18.clone()(_18), + _19: f_19.clone()(_19) + } + }, + } + }) + } + } + + impl PartialEq + for Tuple20 { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (Tuple20::_T20{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, }, Tuple20::_T20{_0: _2__0, _1: _2__1, _2: _2__2, _3: _2__3, _4: _2__4, _5: _2__5, _6: _2__6, _7: _2__7, _8: _2__8, _9: _2__9, _10: _2__10, _11: _2__11, _12: _2__12, _13: _2__13, _14: _2__14, _15: _2__15, _16: _2__16, _17: _2__17, _18: _2__18, _19: _2__19, }) => { + _0 == _2__0 && _1 == _2__1 && _2 == _2__2 && _3 == _2__3 && _4 == _2__4 && _5 == _2__5 && _6 == _2__6 && _7 == _2__7 && _8 == _2__8 && _9 == _2__9 && _10 == _2__10 && _11 == _2__11 && _12 == _2__12 && _13 == _2__13 && _14 == _2__14 && _15 == _2__15 && _16 == _2__16 && _17 == _2__17 && _18 == _2__18 && _19 == _2__19 + }, + _ => { + false + }, + } + } + } + + impl Eq + for Tuple20 {} + + impl Hash + for Tuple20 { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + Tuple20::_T20{_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, } => { + Hash::hash(_0, _state); + Hash::hash(_1, _state); + Hash::hash(_2, _state); + Hash::hash(_3, _state); + Hash::hash(_4, _state); + Hash::hash(_5, _state); + Hash::hash(_6, _state); + Hash::hash(_7, _state); + Hash::hash(_8, _state); + Hash::hash(_9, _state); + Hash::hash(_10, _state); + Hash::hash(_11, _state); + Hash::hash(_12, _state); + Hash::hash(_13, _state); + Hash::hash(_14, _state); + Hash::hash(_15, _state); + Hash::hash(_16, _state); + Hash::hash(_17, _state); + Hash::hash(_18, _state); + Hash::hash(_19, _state) + }, + } + } + } + + impl AsRef> + for Tuple20 { + fn as_ref(&self) -> &Self { + self + } + } +} \ No newline at end of file diff --git a/src/trust_engine/kernel/runtime/src/tests/mod.rs b/src/trust_engine/kernel/runtime/src/tests/mod.rs new file mode 100644 index 0000000..6bcc6e5 --- /dev/null +++ b/src/trust_engine/kernel/runtime/src/tests/mod.rs @@ -0,0 +1,1324 @@ +#![allow(nonstandard_style)] + +// Test module +#[cfg(test)] +mod tests { + use crate::*; + #[cfg(feature = "sync")] + use std::thread; + + #[test] + fn test_int() { + let x = int!(37); + assert_eq!(x.to_u8().unwrap(), truncate!(x.clone(), u8)); + assert_eq!(x.to_u16().unwrap(), truncate!(x.clone(), u16)); + assert_eq!(x.to_u32().unwrap(), truncate!(x.clone(), u32)); + assert_eq!(x.to_u64().unwrap(), truncate!(x.clone(), u64)); + assert_eq!(x.to_u128().unwrap(), truncate!(x.clone(), u128)); + assert_eq!(x.to_i8().unwrap(), truncate!(x.clone(), i8)); + assert_eq!(x.to_i16().unwrap(), truncate!(x.clone(), i16)); + assert_eq!(x.to_i32().unwrap(), truncate!(x.clone(), i32)); + assert_eq!(x.to_i64().unwrap(), truncate!(x.clone(), i64)); + assert_eq!(x.to_i128().unwrap(), truncate!(x.clone(), i128)); + } + + #[cfg(feature = "sync")] + #[test] + fn test_sequence_sync() { + // We are going to create 2 sequences of length 5, a and b. + // From these two, we create 2 new sequences a + b and b + a + // Two threads will transform the first a + b to a vec while two more threads will transform the second one to a vec + // At the end, everything should work fine, the sequences of each pair of thread should be equal + // and there should have been no run-time issue. + // We are going to repeat this 100 times + let a: Sequence = seq![0, 1, 2, 3, 4]; + let b: Sequence = seq![5, 6, 7, 8, 9]; + for _ in 0..100 { + let a_copy_1 = a.clone(); + let b_copy_1 = b.clone(); + let a_copy_2 = a.clone(); + let b_copy_2 = b.clone(); + let a_copy_3 = a.clone(); + let b_copy_3 = b.clone(); + let a_copy_4 = a.clone(); + let b_copy_4 = b.clone(); + let handle_ab = thread::spawn(move || { + let a_plus_b = a_copy_1.concat(&b_copy_1); + let a_plus_b_vec = a_plus_b.to_array(); + a_plus_b_vec + }); + let handle_ba = thread::spawn(move || { + let b_plus_a = b_copy_2.concat(&a_copy_2); + let b_plus_a_vec = b_plus_a.to_array(); + b_plus_a_vec + }); + let handle_ab_2 = thread::spawn(move || { + let a_plus_b = a_copy_3.concat(&b_copy_3); + let a_plus_b_vec = a_plus_b.to_array(); + a_plus_b_vec + }); + let handle_ba_2 = thread::spawn(move || { + let b_plus_a = b_copy_4.concat(&a_copy_4); + let b_plus_a_vec = b_plus_a.to_array(); + b_plus_a_vec + }); + // Now let's join on all these threads + let a_plus_b_vec = handle_ab.join().unwrap(); + let b_plus_a_vec = handle_ba.join().unwrap(); + let a_plus_b_vec_2 = handle_ab_2.join().unwrap(); + let b_plus_a_vec_2 = handle_ba_2.join().unwrap(); + // Let's test equalities + assert_eq!(a_plus_b_vec, a_plus_b_vec_2); + assert_eq!(b_plus_a_vec, b_plus_a_vec_2); + } + } + + // This one is still the bad kind of recursive + #[test] + fn test_sequence_right() { + let a: Sequence = seq![1, 2]; + let b = seq![3, 4]; + let c = seq![5, 6]; + let d = seq![7, 8]; + let e = seq![9, 10]; + let f = seq![11, 12]; + let g = seq![13, 14]; + let h = seq![15, 16]; + let c1 = Sequence::::new_concat_sequence(&a, &b); + let c2 = Sequence::::new_concat_sequence(&c1, &c); + let c3 = Sequence::::new_concat_sequence(&c2, &d); + let c4 = Sequence::::new_concat_sequence(&c3, &e); + let c5 = Sequence::::new_concat_sequence(&c4, &f); + let c6 = Sequence::::new_concat_sequence(&c5, &g); + let c7 = Sequence::::new_concat_sequence(&c6, &h); + let arr = c7.to_array(); + assert_eq!( + *arr, + vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] + ); + } + + // This one is successfully tail recursive + #[test] + fn test_sequence_left() { + let a = seq![1, 2]; + let b = seq![3, 4]; + let c = seq![5, 6]; + let d = seq![7, 8]; + let e = seq![9, 10]; + let f = seq![11, 12]; + let g = seq![13, 14]; + let h = seq![15, 16]; + let c1 = Sequence::::new_concat_sequence(&g, &h); + let c2 = Sequence::::new_concat_sequence(&f, &c1); + let c3 = Sequence::::new_concat_sequence(&e, &c2); + let c4 = Sequence::::new_concat_sequence(&d, &c3); + let c5 = Sequence::::new_concat_sequence(&c, &c4); + let c6 = Sequence::::new_concat_sequence(&b, &c5); + let c7 = Sequence::::new_concat_sequence(&a, &c6); + let arr = c7.to_array(); + assert_eq!( + *arr, + vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] + ); + } + + #[test] + fn test_sequence() { + let values = vec![1, 2, 3]; + let seq = Sequence::::from_array_owned(values.clone()); + assert_eq!(seq.cardinality_usize(), 3); + assert_eq!(seq.to_array(), values.into()); + + // Create a concat array, wrap it into a lazy one, get the i-th element, + // and verify that this operation flattened the array + let left = seq![1, 2, 3]; + let right = seq![4, 5, 6]; + let concat = Sequence::::new_concat_sequence(&left, &right); + + assert_eq!(concat.cardinality_usize(), 6); + match &concat { + Sequence::ConcatSequence { + cache: boxed, + length, + left, + .. + } => { + assert_eq!(*length, 6); + #[cfg(not(feature = "sync"))] + assert_eq!(left.as_ref().borrow().cardinality_usize(), 3); + #[cfg(feature = "sync")] + assert_eq!(left.as_ref().lock().unwrap().cardinality_usize(), 3); + // Test that boxed is None + #[cfg(not(feature = "sync"))] + assert!(boxed.as_ref().clone().borrow().as_ref().is_none()); + #[cfg(feature = "sync")] + assert!(boxed.as_ref().lock().unwrap().as_ref().is_none()); + } + _ => panic!("This should never happen"), + } + let value = concat.get_usize(0); + assert_eq!(value, 1); + match &concat { + Sequence::ConcatSequence { cache: boxed, .. } => { + #[cfg(not(feature = "sync"))] + assert_eq!( + *boxed.as_ref().clone().borrow().as_ref().unwrap().as_ref(), + vec![1, 2, 3, 4, 5, 6] + ); + #[cfg(feature = "sync")] + assert_eq!( + *boxed.as_ref().lock().unwrap().as_ref().unwrap().as_ref(), + vec![1, 2, 3, 4, 5, 6] + ); + } + _ => panic!("This should never happen"), + } + } + + #[test] + fn test_dafny_int() { + assert_eq!(int!(0).to_usize(), Some(0)); + assert_eq!(int!(42).to_usize(), Some(42)); + } + + #[test] + fn test_dafny_sequence_print() { + let hello: DafnyString = seq![ + DafnyChar('H'), + DafnyChar('e'), + DafnyChar('l'), + DafnyChar('l'), + DafnyChar('o') + ]; + assert_eq!(DafnyPrintWrapper(&hello).to_string(), "Hello"); + let hello: DafnyStringUTF16 = seq![ + DafnyCharUTF16(0x0048), + DafnyCharUTF16(0x0065), + DafnyCharUTF16(0x006c), + DafnyCharUTF16(0x006c), + DafnyCharUTF16(0x006f) + ]; + assert_eq!(DafnyPrintWrapper(&hello).to_string(), "Hello"); + assert_eq!(DafnyPrintWrapper(&string_of("Hello")).to_string(), "Hello"); + let hello = seq![1, 2, 3]; + assert_eq!(DafnyPrintWrapper(&hello).to_string(), "[1, 2, 3]"); + } + #[test] + fn test_dafny_sequence() { + let s = seq![55, 56, 57]; + assert_eq!(seq![55, 56] != s, true); + assert_eq!(s.cardinality_usize(), 3); + assert_eq!(s.cardinality(), int!(3)); + assert_eq!(s.get(&int!(1)), 56); + assert_eq!(s.slice(&int!(1), &int!(2)), seq![56]); + assert_eq!(s.take(&int!(2)), seq![55, 56]); + assert_eq!(s.drop(&int!(1)), seq![56, 57]); + assert_eq!(s.update_index(&int!(1), &8), seq![55, 8, 57]); + assert_eq!(s.concat(&seq![58, 59]), seq!(55, 56, 57, 58, 59)); + } + + #[test] + fn test_dafny_set() { + let s = set! {55, 56, 57, 56, 58}; + let t = set! {59, 58, 57}; + assert_eq!(s.cardinality_usize(), 4); + assert_eq!(s.cardinality(), int!(4)); + assert_eq!(s.contains(&55), true); + assert_eq!(s.contains(&54), false); + assert_eq!(s.merge(&set! {}), s); + assert_eq!(set! {}.merge(&s), s); + assert_eq!(s.merge(&t), set! {59, 58, 57, 56, 55}); + assert_eq!(s.intersect(&t), set! {57, 58}); + assert_eq!(s.subtract(&set! {}), s); + assert_eq!(set! {}.subtract(&s), set! {}); + let smt = s.subtract(&t); + assert_eq!(smt, set! {55, 56}); + assert_eq!(t.subtract(&s), set! {59}); + assert_eq!(s.disjoint(&set! {}), true); + assert_eq!(set! {}.disjoint(&s), true); + assert_eq!(s.disjoint(&t), false); + assert_eq!(t.disjoint(&s), false); + assert_eq!(smt.disjoint(&t), true); + assert_eq!(t.disjoint(&smt), true); + assert_eq!(s.elements(), s); + assert_eq!( + s.as_dafny_multiset(), + Multiset::from_array(&vec!(55, 56, 57, 58)) + ); + } + + #[test] + fn test_dafny_multisubset() { + let s = multiset! {55, 56, 57, 58, 59}; + let t = multiset! {55, 56, 57, 58}; + assert!(t < s); + assert!(t <= s); + assert!(s > t); + assert!(s >= t); + assert!(s != t); + assert!(t != s); + + assert!(!(t > s)); + assert!(!(t >= s)); + assert!(!(s < t)); + assert!(!(s <= t)); + assert!(!(s == t)); + assert!(!(t == s)); + + let s = multiset! {55, 56, 57, 58, 58}; + let t = multiset! {55, 56, 57, 58}; + assert!(t < s); + assert!(t <= s); + assert!(s > t); + assert!(s >= t); + assert!(s != t); + assert!(t != s); + + assert!(!(t > s)); + assert!(!(t >= s)); + assert!(!(s < t)); + assert!(!(s <= t)); + assert!(!(s == t)); + assert!(!(t == s)); + + let s = multiset! {55, 56, 57, 58, 59}; + let t = multiset! {55, 56, 57, 58, 59}; + assert!(t <= s); + assert!(s <= t); + assert!(s >= t); + assert!(t >= s); + assert!(s == t); + assert!(t == s); + + assert!(!(t < s)); + assert!(!(t > s)); + assert!(!(s > t)); + assert!(!(s < t)); + assert!(!(s != t)); + assert!(!(t != s)); + + let s = multiset! {55, 56, 57, 58, 59}; + let t = multiset! {55, 56, 57, 58, 58}; + assert!(s != t); + assert!(t != s); + + assert!(!(t < s)); + assert!(!(t <= s)); + assert!(!(t > s)); + assert!(!(t >= s)); + assert!(!(s < t)); + assert!(!(s <= t)); + assert!(!(s > t)); + assert!(!(s >= t)); + assert!(!(s == t)); + assert!(!(t == s)); + } + + #[test] + fn test_dafny_multiset() { + let s = multiset! {55, 56, 57, 56, 58}; + let t = multiset! {59, 58, 57, 56}; + assert_eq!(s.cardinality_usize(), 5); + assert_eq!(s.cardinality(), int!(5)); + assert_eq!(s.contains(&55), true); + assert_eq!(s.contains(&54), false); + assert_eq!(s.get(&54), int!(0)); + assert_eq!(s.get(&55), int!(1)); + assert_eq!(s.get(&56), int!(2)); + assert_eq!(s.get(&57), int!(1)); + assert_eq!(s.merge(&multiset! {}), s); + assert_eq!(multiset! {}.merge(&s), s); + let merged = multiset! {59, 58, 58, 57, 57, 56, 56, 56, 55}; + assert_eq!(s.merge(&t), merged); + assert_eq!(merged.cardinality_usize(), 9); + assert_eq!(s.intersect(&t), multiset! {57, 58, 56}); + assert_eq!(s.subtract(&multiset! {}), s); + assert_eq!(multiset! {}.subtract(&s), multiset! {}); + let smt = s.subtract(&t); + assert_eq!(smt, multiset! {55, 56}); + let tms = t.subtract(&s); + assert_eq!(tms, multiset! {59}); + assert_eq!(s.disjoint(&multiset! {}), true); + assert_eq!(multiset! {}.disjoint(&s), true); + assert_eq!(s.disjoint(&t), false); + assert_eq!(t.disjoint(&s), false); + assert_eq!(smt.disjoint(&t), false); + assert_eq!(t.disjoint(&smt), false); + assert_eq!(tms.disjoint(&s), true); + assert_eq!(s.disjoint(&tms), true); + assert_eq!(s.as_dafny_multiset(), s); + } + + #[test] + fn test_dafny_map() { + let m_empty: Map = map![]; + let m_3 = map![1 => 2, 3 => 6, 5 => 10]; + let k_3 = set! {1, 3, 5}; + let v_3 = set! {2, 6, 10}; + assert_eq!(m_empty.cardinality_usize(), 0); + assert_eq!(m_empty.cardinality(), int!(0)); + assert_eq!(m_3.cardinality_usize(), 3); + assert_eq!(m_3.cardinality(), int!(3)); + assert_eq!(m_3.contains(&1), true); + assert_eq!(m_3.contains(&0), false); + assert_eq!(m_3.keys(), k_3); + assert_eq!(m_3.values(), v_3); + assert_eq!(m_3.get(&1), 2); + assert_eq!(m_3.get_or_none(&1), Some(2)); + assert_eq!(m_3.get_or_none(&0), None); + let mut m_4 = m_3.update_index(&0, &2); + assert_eq!(m_3.contains(&0), false); + assert_eq!(m_4.contains(&0), true); + m_4 = m_4.update_index_owned(0, 7); + assert_eq!(m_4.contains(&0), true); + + assert_eq!(m_4.get(&0), 7); + assert_eq!(m_4.cardinality_usize(), 4); + assert_eq!(m_4.merge(&map![]), m_4); + assert_eq!(map![].merge(&m_4), m_4); + let m_5 = m_4.merge(&map![3 => 9, 6 => 12]); + assert_eq!(m_5.cardinality_usize(), 5); + assert_eq!(m_4.get(&3), 6); + assert_eq!(m_5.get(&3), 9); + assert_eq!(m_5.subtract(&set! {}), m_5); + let m_4b = m_5.subtract(&set! {3}); + assert_eq!(m_4b.cardinality_usize(), 4); + assert_eq!(m_4b.contains(&3), false) + } + + #[test] + fn test_dafny_array() { + let a = array![1, 2, 3]; + assert_eq!(array::length_usize(a), 3); + assert_eq!(array::length(a), int!(3)); + assert_eq!(array::get_usize(a, 0), 1); + assert_eq!(array::get_usize(a, 1), 2); + assert_eq!(array::get_usize(a, 2), 3); + array::update_usize(a, 0, 4); + array::update_usize(a, 1, 5); + array::update_usize(a, 2, 6); + assert_eq!(array::get_usize(a, 0), 4); + assert_eq!(array::get_usize(a, 1), 5); + assert_eq!(array::get_usize(a, 2), 6); + deallocate(a); + } + + #[test] + fn test_dafny_array_init() { + // test from_vec, and initialize + let mut v = Vec::new(); + v.push(1); + v.push(2); + v.push(3); + let a = array::from_vec(v); + assert_eq!(array::length_usize(a), 3); + assert_eq!(array::get_usize(a, 0), 1); + let v2 = array::initialize_usize(3, Rc::new(|i| i + 1)); + assert_eq!(array::length_usize(v2), 3); + assert_eq!(array::get_usize(v2, 0), 1); + assert_eq!(array::get_usize(v2, 1), 2); + assert_eq!(array::get_usize(v2, 2), 3); + array::update_usize(v2, 1, 10); + assert_eq!(array::get_usize(v2, 1), 10); + + let v3 = array::initialize(&int!(3), Rc::new(|i| i.clone() + int!(1))); + assert_eq!(array::length_usize(v3), 3); + assert_eq!(array::get_usize(v3, 0), int!(1)); + assert_eq!(array::get_usize(v3, 1), int!(2)); + assert_eq!(array::get_usize(v3, 2), int!(3)); + array::update(v3, &int!(1), int!(10)); + assert_eq!(array::get_usize(v3, 1), int!(10)); + + deallocate(a); + deallocate(v2); + deallocate(v3); + } + + #[test] + fn test_array2() { + let p = Array2::::placebos(&int!(3), &int!(4)); + for i in 0..3 { + for j in 0..4 { + modify!(p).data[i][j] = MaybeUninit::new(int!(i + j)); + } + } + let p = Array2::construct(p); + assert_eq!(read!(p).length0_usize(), 3); + assert_eq!(read!(p).length1_usize(), 4); + let v = read!(p).to_vec(); + assert_eq!(v.len(), 3); + assert_eq!( + v, + vec![ + vec![int!(0), int!(1), int!(2), int!(3)], + vec![int!(1), int!(2), int!(3), int!(4)], + vec![int!(2), int!(3), int!(4), int!(5)] + ] + ); + + deallocate(p); + // Allocate an array whose first dimension is zero + let p = Array2::::placebos(&int!(0), &int!(4)); + let p = Array2::construct(p); + assert_eq!(read!(p).length0_usize(), 0); + assert_eq!(read!(p).length1_usize(), 4); + deallocate(p); + } + + #[test] + fn test_array3() { + let a = Array3::::placebos(&int!(3), &int!(2), &int!(4)); + for i in 0..3 { + for j in 0..2 { + for k in 0..4 { + modify!(a).data[i][j][k] = MaybeUninit::new(DafnyInt::from(i * j + k)); + } + } + } + let a = Array3::construct(a); + assert_eq!(read!(a).length0(), int!(3)); + assert_eq!(read!(a).length1(), int!(2)); + assert_eq!(read!(a).length2(), int!(4)); + let v = read!(a).to_vec(); + assert_eq!(v.len(), 3); + for i in 0..3 { + for j in 0..2 { + for k in 0..4 { + assert_eq!(read!(a).data[i][j][k], DafnyInt::from(i * j + k)); + assert_eq!(v[i][j][k], DafnyInt::from(i * j + k)); + } + } + } + deallocate(a); + // Even if the first two dimensions are zero, the third dimension should not be zero + let a = Array3::::placebos(&int!(0), &int!(0), &int!(4)); + let a = Array3::construct(a); + assert_eq!(read!(a).length0(), int!(0)); + assert_eq!(read!(a).length1(), int!(0)); + assert_eq!(read!(a).length2(), int!(4)); + deallocate(a); + } + + struct ClassWrapper { + /*var*/ t: Field, + /*var*/ x: Field, + /*const*/ next: Ptr>, + /*const*/ constant: DafnyInt, + } + impl ClassWrapper { + fn constant_plus_x(&self) -> DafnyInt { + self.constant.clone() + read_field!(self.x) + } + fn increment_x(&mut self) { + modify_field!(self.x, read_field!(self.x) + int!(1)); + } + } + + impl ClassWrapper { + fn constructor(t: T) -> Ptr> { + let this = allocate::>(); + update_field_mut_nodrop!(this, t, t); + update_field_nodrop!(this, next, this); + // If x is assigned twice, we need to keep track of whether it's assigned + // like in methods. + let mut x_assigned = false; + update_field_mut_uninit!(this, x, x_assigned, int!(2)); + update_field_mut_uninit!(this, x, x_assigned, int!(1)); + // If we can prove that x is assigned, we can even write this + modify_field!(read!(this).x, int!(0)); + update_field_nodrop!(this, constant, int!(42)); + update_field_mut_if_uninit!(this, x, x_assigned, int!(0)); + assert_eq!(x_assigned, true); + let mut next_assigned = true; + update_field_if_uninit!(this, next, next_assigned, this); + assert_eq!(next_assigned, true); + this + } + + fn constructor_object(t: T) -> Object> { + let mut this = allocate_object::>(); + update_field_mut_nodrop_object!(this, t, t); + update_field_nodrop_object!(this, next, Ptr::from_raw_nonnull(this.as_mut())); + // If x is assigned twice, we need to keep track of whether it's assigned + // like in methods. + let mut x_assigned = false; + update_field_mut_uninit_object!(this, x, x_assigned, int!(2)); + update_field_mut_uninit_object!(this, x, x_assigned, int!(1)); + // If we can prove that x is assigned, we can even write this + modify_field!(rd!(this).x, int!(0)); + update_field_nodrop_object!(this, constant, int!(42)); + update_field_mut_if_uninit_object!(this, x, x_assigned, int!(0)); + assert_eq!(x_assigned, true); + let mut next_assigned = true; + update_field_if_uninit_object!( + this, + next, + next_assigned, + Ptr::from_raw_nonnull(this.as_mut()) + ); + assert_eq!(next_assigned, true); + this + } + } + + impl Upcast for ClassWrapper { + UpcastFn!(DynAny); + } + impl UpcastObject for ClassWrapper { + UpcastObjectFn!(DynAny); + } + + #[test] + #[allow(unused_unsafe)] + fn test_class_wrapper() { + let c: Ptr> = ClassWrapper::constructor(53); + assert_eq!(read!(c).constant, int!(42)); + assert_eq!(read_field!(read!(c).t), 53); + assert_eq!(read_field!(read!(c).x), int!(0)); + assert_eq!(read_field!(read!(read!(c).next).t), 53); + assert_eq!(read!(c).constant_plus_x(), int!(42)); + modify!(c).increment_x(); + assert_eq!(read!(c).constant_plus_x(), int!(43)); + modify_field!(read!(c).x, int!(40)); + assert_eq!(read!(c).constant_plus_x(), int!(82)); + modify_field!(read!(c).t, 54); + assert_eq!(read_field!(read!(c).t), 54); + #[cfg(not(feature = "small-int"))] + let x_copy = read_field!(read!(c).x); + #[cfg(not(feature = "small-int"))] + assert_eq!(x_copy.strong_count(), 2); + #[cfg(not(feature = "small-int"))] + deallocate(c); + #[cfg(not(feature = "small-int"))] + assert_eq!(x_copy.strong_count(), 1); + } + + #[test] + #[allow(unused_unsafe)] + fn test_class_wrapper_object() { + let c: Object> = ClassWrapper::constructor_object(53); + assert_eq!(rd!(c).constant, int!(42)); + assert_eq!(read_field!(rd!(c).t), 53); + assert_eq!(read_field!(rd!(c).x), int!(0)); + assert_eq!(read_field!(rd!(rd!(c).next).t), 53); + assert_eq!(rd!(c).constant_plus_x(), int!(42)); + md!(c).increment_x(); + assert_eq!(rd!(c).constant_plus_x(), int!(43)); + if true { + modify_field!(rd!(c).x, int!(40)) + } + assert_eq!(rd!(c).constant_plus_x(), int!(82)); + modify_field!(rd!(c).t, 54); + assert_eq!(read_field!(rd!(c).t), 54); + } + + // Requires test1 || test2 + // We will not do that as it enables the compiler to assume that t contains a valid Rc when it does not. + // Prefer MaybePlacebo + fn assign_lazy_in_method(test1: bool, test2: bool) -> Rc { + let mut t = MaybePlacebo::>::new(); + if test1 { + t = MaybePlacebo::from(Rc::new(5)); + } + if test2 { + t = MaybePlacebo::from(Rc::new(7 + if test1 { *MaybePlacebo::read(&t) } else { 0 })); + } + MaybePlacebo::read(&t) + } + + #[test] + fn assign_lazy_in_method_test() { + let mut t = assign_lazy_in_method(true, false); + assert_eq!(*t, 5); + t = assign_lazy_in_method(false, true); + assert_eq!(*t, 7); + t = assign_lazy_in_method(true, true); + assert_eq!(*t, 12); + } + + fn override_placebo(o: T, do_override: bool) { + let mut _x: MaybePlacebo = MaybePlacebo::::new(); + if do_override { + _x = MaybePlacebo::from(o.clone()); + } + } + + #[test] + fn test_placebo() { + override_placebo::(int!(1), false); + override_placebo::(int!(1), true); + let _x: MaybePlacebo>> = + MaybePlacebo::>>::new(); + //let mut f: Rc Class> = Class> as Placebo>::new(); + } + + #[test] + fn test_maybe_placebos_from() { + let x = (1, 2, 3, 4); + let (a, b, c, d) = maybe_placebos_from!(x, 0, 1, 2, 3); + assert_eq!(a.read(), 1); + assert_eq!(b.read(), 2); + assert_eq!(c.read(), 3); + assert_eq!(d.read(), 4); + } + + #[test] + fn test_coercion_immutable() { + let o = ClassWrapper::::constructor(1); + let a: Ptr = Upcast::::upcast(read!(o)); + assert_eq!(cast!(a, ClassWrapper), o); + let seq_o = seq![o]; + let seq_a = Sequence::>>::coerce( + upcast::, DynAny>(), + )(seq_o); + assert_eq!(cast!(seq_a.get_usize(0), ClassWrapper), o); + let set_o = set! {o}; + let set_a = + Set::>>::coerce(upcast::, DynAny>())(set_o); + assert_eq!(cast!(set_a.peek(), ClassWrapper), o); + let multiset_o = multiset! {o, o}; + let multiset_a = Multiset::>>::coerce(upcast::< + ClassWrapper, + DynAny, + >())(multiset_o); + assert_eq!(cast!(multiset_a.peek(), ClassWrapper), o); + let map_o = map![1 => o, 2 => o]; + let map_a = Map::>>::coerce( + upcast::, DynAny>(), + )(map_o); + assert_eq!(cast!(map_a.get(&1), ClassWrapper), o); + deallocate(o); + } + + #[test] + fn test_defaults() { + let set_i32 = as Default>::default(); + let seq_i32 = as Default>::default(); + let map_i32 = as Default>::default(); + let multiset_i32 = as Default>::default(); + assert_eq!(set_i32.cardinality_usize(), 0); + assert_eq!(seq_i32.cardinality_usize(), 0); + assert_eq!(map_i32.cardinality_usize(), 0); + assert_eq!(multiset_i32.cardinality_usize(), 0); + } + + #[test] + fn test_nontrivial_defaults() { + let set_i32 = as NontrivialDefault>::nontrivial_default(); + let seq_i32 = as NontrivialDefault>::nontrivial_default(); + let map_i32 = as NontrivialDefault>::nontrivial_default(); + let multiset_i32 = as NontrivialDefault>::nontrivial_default(); + assert_eq!(set_i32.cardinality_usize(), 0); + assert_eq!(seq_i32.cardinality_usize(), 0); + assert_eq!(map_i32.cardinality_usize(), 0); + assert_eq!(multiset_i32.cardinality_usize(), 0); + let ptr_i32 = as NontrivialDefault>::nontrivial_default(); + assert_eq!(ptr_i32, Ptr::::null()); + } + + #[test] + fn test_function_wrappers() { + #[cfg(feature = "sync")] + let f: Rc i32 + Send + Sync> = Rc::new(|i: &i32| *i + 1); + #[cfg(not(feature = "sync"))] + let f: Rc i32> = Rc::new(|i: &i32| *i + 1); + let g = f.clone(); + let _h = seq![g]; + } + + #[test] + fn test_forall_exists() { + assert!(integer_range(Zero::zero(), int!(10)) + .all(Rc::new(|i: DafnyInt| i.clone() < int!(10)).as_ref())); + assert!(integer_range(int!(0), int!(10)) + .all(Rc::new(|i: DafnyInt| i.clone() < int!(10)).as_ref())); + assert!(!integer_range(int!(0), int!(11)) + .all(Rc::new(|i: DafnyInt| i.clone() < int!(10)).as_ref())); + assert!(!integer_range(int!(0), int!(10)) + .any(Rc::new(|i: DafnyInt| i.clone() >= int!(10)).as_ref())); + assert!(integer_range(int!(0), int!(11)) + .any(Rc::new(|i: DafnyInt| i.clone() >= int!(10)).as_ref())); + + assert!(integer_range(int!(0), int!(10)).all( + Rc::new(|i: DafnyInt| !(i.clone() % int!(4) == int!(0)) + || i.clone() < int!(10) && i.clone() % int!(2) == int!(0)) + .as_ref() + )); + assert!(integer_range(int!(0), int!(11)).all( + Rc::new(|i: DafnyInt| !(i.clone() % int!(4) == int!(0)) + || i.clone() < int!(10) && i.clone() % int!(2) == int!(0)) + .as_ref() + )); + assert!(!integer_range(int!(0), int!(10)).any( + Rc::new(|i: DafnyInt| i.clone() % int!(4) == int!(0) + && i.clone() >= int!(10) + && i.clone() % int!(2) == int!(0)) + .as_ref() + )); + assert!(!integer_range(int!(0), int!(11)).any( + Rc::new(|i: DafnyInt| i.clone() % int!(4) == int!(0) + && i.clone() >= int!(10) + && i.clone() % int!(2) == int!(0)) + .as_ref() + )); + + assert!(exact_range(10).all(Rc::new(|i: i32| i == 10).as_ref())); + assert!(exact_range(10).any(Rc::new(|i: i32| i == 10).as_ref())); + assert!(!exact_range(10).all(Rc::new(|i: i32| i != 10).as_ref())); + assert!(!exact_range(10).any(Rc::new(|i: i32| i != 10).as_ref())); + + assert!(seq![1, 3, 5, 7] + .iter() + .all(Rc::new(|i: u32| i % 2 == 1).as_ref())); + assert!(!seq![1, 3, 5, 7] + .iter() + .any(Rc::new(|i: u32| i % 2 == 0).as_ref())); + assert!(!seq![1, 3, 5, 7, 8] + .iter() + .all(Rc::new(|i: u32| i % 2 == 1).as_ref())); + assert!(seq![1, 3, 5, 7, 8] + .iter() + .any(Rc::new(|i: u32| i % 2 == 0).as_ref())); + + assert!(set! {1, 3, 5, 7} + .iter() + .cloned() + .all(Rc::new(|i: u32| i % 2 == 1).as_ref())); + assert!(!set! {1, 3, 5, 7} + .iter() + .cloned() + .any(Rc::new(|i: u32| i % 2 == 0).as_ref())); + assert!(!set! {1, 3, 5, 7, 8} + .iter() + .cloned() + .all(Rc::new(|i: u32| i % 2 == 1).as_ref())); + assert!(set! {1, 3, 5, 7, 8} + .iter() + .cloned() + .any(Rc::new(|i: u32| i % 2 == 0).as_ref())); + assert!(multiset! {1, 1, 5, 7} + .iter() + .all(Rc::new(|i: u32| i % 2 == 1).as_ref())); + assert!(!multiset! {1, 1, 5, 7} + .iter() + .any(Rc::new(|i: u32| i % 2 == 0).as_ref())); + assert!(!multiset! {1, 1, 5, 7, 8} + .iter() + .all(Rc::new(|i: u32| i % 2 == 1).as_ref())); + assert!(multiset! {1, 1, 5, 7, 8} + .iter() + .any(Rc::new(|i: u32| i % 2 == 0).as_ref())); + let count = Rc::new(RefCell::new(0)); + let count_inner = count.clone(); + multiset! {1, 1, 5, 7, 8}.iter().for_each(move |_i: u32| { + #[cfg(not(feature = "sync"))] + { + let c: i32 = *count_inner.as_ref().borrow(); + *count_inner.borrow_mut() = c + 1; + } + #[cfg(feature = "sync")] + { + let mut guard = count_inner.as_ref().lock().unwrap(); + let c: i32 = *guard; + *guard = c + 1; + } + }); + #[cfg(not(feature = "sync"))] + assert_eq!(*count.as_ref().borrow(), 5); + #[cfg(feature = "sync")] + assert_eq!(*count.as_ref().lock().unwrap(), 5); + + let m = map![1 => 4, 3 => 6, 5 => 8]; + let m2 = m.clone(); + let m3 = m.clone(); + assert!(m + .clone() + .iter() + .all(Rc::new(move |i: u32| i + 3 == m2.get(&i)).as_ref())); + assert!(!m + .iter() + .any(Rc::new(move |i: u32| i + 2 == m3.get(&i)).as_ref())); + let m = map![1 => 4, 3 => 7, 5 => 7]; + let m2 = m.clone(); + let m3 = m.clone(); + assert!(!m + .clone() + .iter() + .all(Rc::new(move |i: u32| i + 3 == m2.get(&i)).as_ref())); + assert!(m + .iter() + .any(Rc::new(move |i: u32| i + 2 == m3.get(&i)).as_ref())); + } + + #[test] + fn test_for_loops() { + let mut sum: i32 = 0; + for i in integer_range(1, 11) { + sum += i; + } + assert_eq!(sum, 55); + + let mut sum: i32 = 0; + for i in integer_range_down(11, 1) { + sum += i; + } + assert_eq!(sum, 55); + + let mut sum: i32 = 0; + for i in integer_range_unbounded(1) { + sum += i; + if i == 10 { + break; + } + } + assert_eq!(sum, 55); + + let mut sum: i32 = 0; + for i in integer_range_down_unbounded(11) { + sum += i; + if i == 1 { + break; + } + } + assert_eq!(sum, 55); + } + + trait SuperTrait: Upcast + UpcastObject {} + + trait NodeRcMutTrait: SuperTrait + Upcast + UpcastObject {} + + struct NodeRcMut { + val: DafnyInt, + next: Object, + } + impl NodeRcMut { + fn _ctor(this: Object, val: DafnyInt) { + let mut val_assign = false; + let mut next_assign = false; + update_field_uninit_object!(this.clone(), val, val_assign, val); + update_field_if_uninit_object!(this.clone(), next, next_assign, Object(None)); + } + } + impl SuperTrait for NodeRcMut {} + impl UpcastObject for NodeRcMut { + UpcastObjectFn!(DynAny); + } + impl Upcast for NodeRcMut { + UpcastFn!(DynAny); + } + impl UpcastObject for NodeRcMut { + UpcastObjectFn!(dyn NodeRcMutTrait); + } + impl Upcast for NodeRcMut { + UpcastFn!(dyn NodeRcMutTrait); + } + impl UpcastObject for NodeRcMut { + UpcastObjectFn!(dyn SuperTrait); + } + impl Upcast for NodeRcMut { + UpcastFn!(dyn SuperTrait); + } + impl NodeRcMutTrait for NodeRcMut {} + + #[test] + fn test_object() { + let mut x: Object = allocate_object::(); + NodeRcMut::_ctor(x.clone(), int!(42)); + assert_eq!(refcount!(x), 1); + assert_eq!(x.as_ref().val, int!(42)); + x.as_mut().next = x.clone(); + assert_eq!(refcount!(x), 2); + assert_eq!(x.as_ref().next.as_ref().val, int!(42)); + md!(rd!(x).next).next = Object(None); + assert_eq!(refcount!(x), 1); + let y: Object = upcast_object::<_, _>()(x.clone()); + assert_eq!(refcount!(x), 2); + let z: Object = upcast_object::<_, _>()(x.clone()); + assert_eq!(refcount!(x), 3); + let a2: Object = cast_object!(y.clone(), NodeRcMut); + assert_eq!(refcount!(x), 4); + assert_eq!(rd!(a2).val, int!(42)); + let a3: Object = cast_object!(z.clone(), NodeRcMut); + assert_eq!(refcount!(x), 5); + assert_eq!(rd!(a3).val, int!(42)); + + // Other way to create objects + let direct: Object = Object::::new(NodeRcMut { + val: int!(1), + next: Object::::null(), + }); + assert_eq!(rd!(direct).val, int!(1)); + let tail: Object = Object::::null(); + assert_eq!(tail, rd!(direct).next); + assert!(tail.is_null()); + assert!(!direct.is_null()); + + let a: Object<[i32]> = rcmut::array_object_from_rc(Rc::new([42, 43, 44])); + assert_eq!(rd!(a).len(), 3); + assert_eq!(rd!(a)[0], 42); + assert_eq!(rd!(a)[1], 43); + assert_eq!(rd!(a)[2], 44); + let b: Object<[i32]> = a.clone(); + md!(b)[0] = 45; + assert_eq!(rd!(a)[0], 45); + + let previous_count = refcount!(x); + { + let z = Object::::from_ref(x.as_ref()); + assert_eq!(refcount!(z), previous_count + 1); + assert_eq!(refcount!(x), previous_count + 1); + } + assert_eq!(refcount!(x), previous_count); + + let objects: Set> = crate::set! {y.clone(), cast_any_object!(x.clone())}; + assert_eq!(objects.cardinality_usize(), 1); + test_dafny_type(a.clone()); + } + + struct NodeRawMut { + val: DafnyInt, + next: Ptr, + } + impl NodeRawMut { + fn _ctor(this: Ptr, val: DafnyInt) { + let mut val_assign = false; + update_field_uninit!(this, val, val_assign, val); + } + } + impl NodeRcMutTrait for NodeRawMut {} + UpcastDefObject!(NodeRawMut, dyn NodeRcMutTrait, dyn SuperTrait, DynAny); + UpcastDef!(NodeRawMut, dyn NodeRcMutTrait, dyn SuperTrait, DynAny); + + impl SuperTrait for NodeRawMut {} + + #[test] + fn test_rawmut() { + let x: Ptr = allocate::(); + NodeRawMut::_ctor(x.clone(), int!(42)); + assert_eq!(read!(x.clone()).val, int!(42)); + modify!(x.clone()).next = x.clone(); + assert_eq!(read!(read!(x.clone()).next.clone()).val, int!(42)); + modify!(read!(x.clone()).next.clone()).next = Ptr::null(); + let y: Ptr = upcast::<_, _>()(x); + assert!(y.is_instance_of::()); + assert!(!y.is_instance_of::()); + let z: Ptr = upcast::<_, _>()(x); + let _a2: Ptr = cast!(y, NodeRawMut); + let _a3: Ptr = cast!(z, NodeRawMut); + deallocate(x); + + let a = array::from_native(Box::new([42, 43, 44])); + assert_eq!(read!(a.clone()).len(), 3); + assert_eq!(read!(a.clone())[0], 42); + assert_eq!(read!(a.clone())[1], 43); + assert_eq!(read!(a.clone())[2], 44); + let b = a.clone(); + modify!(b.clone())[0] = 45; + assert_eq!(read!(a.clone())[0], 45); + + deallocate(a); + } + + // Conversion of any usize-compatible value into usize + #[test] + fn test_usize() { + let a: u128 = 1; + let b: i8 = 1; + let u: usize = 1; + assert_eq!(DafnyUsize::into_usize(int!(a)), u); + assert_eq!(DafnyUsize::into_usize(a), u); + assert_eq!(DafnyUsize::into_usize(b), u); + assert_eq!(DafnyUsize::into_usize(int!(b)), u); + } + + // Tests that we can compose Dafny types, like a sequence of maps + fn _test(_input: Sequence>) {} + // Tests that the input type is a DafnyType + fn test_dafny_type(_input: X) {} + + #[derive(Clone)] + struct InternalOpaqueError { + message: String, + } + + crate::UpcastDefObject!(InternalOpaqueError, DynAny); + + #[test] + fn test_native_string_upcast() { + let s = InternalOpaqueError { + message: "Hello, World!".to_string(), + }; + let o: Object = Object::new(s); + let n: Object = upcast_object::()(o); + let x = cast_object!(n, InternalOpaqueError); + let s2 = dafny_runtime_conversions::object::dafny_class_to_struct(x); + assert_eq!(s2.message, "Hello, World!"); + } + + #[test] + fn test_native_string_upcast_raw() { + let message = "Hello, World!".to_string(); + let object = Object::new(message.clone()); + let object_any: Object = UpcastObject::::upcast(object.as_ref()); + let resulting_message = format!("{:?}", object_any); + assert_eq!(resulting_message, message); + } + + /** Hierarchy implemented + * GeneralTraitSuper + * | \____________________, + * | | + * GeneralTraitSuper GeneralTraitSuperChild + * | | (via i32) + * GeneralTrait CDatatype + * | | + * ADatatype BDatatype + */ + + trait _Downcast_GeneralTrait { + fn _is(&self) -> bool; + fn _as(&self) -> Box; // For trait objects, Object or Ptr instead of Box + } + + trait _Downcast_ADatatype { + fn _is(&self) -> bool; + fn _as(&self) -> ADatatype; // For trait objects, Object or Ptr instead of Box + } + trait _Downcast_CDatatype { + fn _is(&self) -> bool; + fn _as(&self) -> CDatatype; // For trait objects, Object or Ptr instead of Box + } + + // Every general trait must declare how to clone a Box of itself + trait GeneralTraitSuper: + _Downcast_GeneralTrait + AnyRef + _Downcast_GeneralTraitSuperChild + { + fn _clone(&self) -> Box>; + } + trait GeneralTraitSuperChild: GeneralTraitSuper { + fn _clone(&self) -> Box>; + } + + trait _Downcast_GeneralTraitSuperChild { + fn _is(&self) -> bool; + fn _as(&self) -> Box>; // For trait objects, Object or Ptr instead of Box + } + + impl Clone for Box> { + fn clone(&self) -> Self { + GeneralTraitSuper::_clone(self.as_ref()) + } + } + impl DafnyPrint for Box> { + fn fmt_print(&self, f: &mut Formatter<'_>, _in_seq: bool) -> std::fmt::Result { + write!(f, "GeneralTraitSuper") + } + } + // Traits extending other traits also implement a direct way to upcast their Box of themselves + trait GeneralTrait: GeneralTraitSuper + UpcastBox> { + fn _clone(&self) -> Box; + } + impl Clone for Box { + fn clone(&self) -> Self { + GeneralTrait::_clone(self.as_ref()) + } + } + impl DafnyPrint for Box { + fn fmt_print(&self, f: &mut Formatter<'_>, _in_seq: bool) -> std::fmt::Result { + write!(f, "GeneralTrait") + } + } + + #[derive(Clone, PartialEq, Debug)] + struct ADatatype { + i: i32, + } + impl GeneralTrait for ADatatype { + fn _clone(&self) -> Box { + Box::new(self.clone()) as Box + } + } + impl _Downcast_ADatatype for dyn Any { + fn _is(&self) -> bool { + self.downcast_ref::().is_some() + } + fn _as(&self) -> ADatatype { + self.downcast_ref::().unwrap().clone() // Optimization: Could be unwrap_unchecked + } + } + impl _Downcast_GeneralTrait for T { + fn _is(&self) -> bool { + true + } + fn _as(&self) -> Box { + GeneralTrait::_clone(self) + } + } + impl GeneralTraitSuper for ADatatype { + fn _clone(&self) -> Box> { + Box::new(self.clone()) + } + } + impl _Downcast_GeneralTraitSuperChild for ADatatype { + fn _is(&self) -> bool { + false + } + fn _as(&self) -> Box> { + panic!("cannot") + } + } + impl UpcastBox for ADatatype { + fn upcast(&self) -> ::std::boxed::Box { + GeneralTrait::_clone(self) + } + } + impl UpcastBox> for ADatatype { + fn upcast(&self) -> ::std::boxed::Box> { + GeneralTraitSuper::::_clone(self) + } + } + + #[derive(Clone, PartialEq, Debug)] + struct CDatatype { + i: u32, + } + impl _Downcast_CDatatype for dyn Any { + fn _is(&self) -> bool { + self.downcast_ref::().is_some() + } + fn _as(&self) -> CDatatype { + self.downcast_ref::().unwrap().clone() // Optimization: Could be unwrap_unchecked + } + } + impl UpcastBox> for CDatatype { + fn upcast(&self) -> ::std::boxed::Box> { + GeneralTraitSuper::::_clone(self) + } + } + impl UpcastBox> for CDatatype { + fn upcast(&self) -> ::std::boxed::Box> { + GeneralTraitSuperChild::::_clone(self) + } + } + + impl GeneralTraitSuper for CDatatype { + fn _clone(&self) -> Box> { + Box::new(self.clone()) + } + } + impl GeneralTraitSuperChild for CDatatype { + fn _clone(&self) -> Box> { + Box::new(self.clone()) + } + } + impl _Downcast_GeneralTraitSuperChild for CDatatype { + fn _is(&self) -> bool { + true + } + fn _as(&self) -> Box> { + GeneralTraitSuperChild::::_clone(self) + } + } + impl _Downcast_GeneralTrait for CDatatype { + // CDatatype does not extend general trait + fn _is(&self) -> bool { + false + } + fn _as(&self) -> Box { + panic!("CDatatype does not extend GeneralTrait") + } + } + #[test] + fn test_general_traits() { + let x = ADatatype { i: 3 }; + let gt = upcast_box::()(x.clone()); + let gts = upcast_box::>()(x.clone()); + let gtgts = upcast_box_box::>()(gt.clone()); + assert!(_Downcast_ADatatype::_is(AnyRef::as_any_ref(AsRef::as_ref( + > + )))); + assert!(_Downcast_ADatatype::_is(AnyRef::as_any_ref(AsRef::as_ref( + >s + )))); + assert!(_Downcast_ADatatype::_is(AnyRef::as_any_ref(AsRef::as_ref( + >gts + )))); + assert!(_Downcast_GeneralTrait::_is(AsRef::as_ref(>s))); + assert!(_Downcast_GeneralTrait::_is(AsRef::as_ref(>gts))); + assert_eq!( + _Downcast_ADatatype::_as(AnyRef::as_any_ref(AsRef::as_ref(>))), + x + ); + assert_eq!( + _Downcast_ADatatype::_as(AnyRef::as_any_ref(AsRef::as_ref(>s))), + x + ); + assert_eq!( + _Downcast_ADatatype::_as(AnyRef::as_any_ref(AsRef::as_ref(>gts))), + x + ); + let gtsgt = _Downcast_GeneralTrait::_as(AsRef::as_ref(>s)); + let gtgtsgt = _Downcast_GeneralTrait::_as(AsRef::as_ref(>gts)); + assert!(_Downcast_ADatatype::_is(AnyRef::as_any_ref(AsRef::as_ref( + >sgt + )))); + assert!(_Downcast_ADatatype::_is(AnyRef::as_any_ref(AsRef::as_ref( + >gtsgt + )))); + assert_eq!( + _Downcast_ADatatype::_as(AnyRef::as_any_ref(AsRef::as_ref(>sgt))), + x + ); + assert_eq!( + _Downcast_ADatatype::_as(AnyRef::as_any_ref(AsRef::as_ref(>sgt))), + x + ); + let xc = CDatatype { i: 3 }; + let gtc = upcast_box::>()(xc.clone()); + let gcsc = upcast_box::>()(xc.clone()); + let gtcsc = _Downcast_GeneralTraitSuperChild::::_as(AsRef::as_ref(>c)); + let xc1 = _Downcast_CDatatype::_as(AnyRef::as_any_ref(AsRef::as_ref(&gcsc))); + let xc2 = _Downcast_CDatatype::_as(AnyRef::as_any_ref(AsRef::as_ref(>csc))); + assert_eq!(xc, xc1); + assert_eq!(xc, xc2); + } + + #[test] + fn test_chars_copy() { + let c = DafnyChar('a'); + let c2 = c; + let c3 = c; + assert_eq!(c3, c2); + let c = DafnyCharUTF16(213); + let c2 = c; + let c3 = c; + assert_eq!(c3, c2); + } + + #[cfg(feature = "sync")] + #[test] + fn test_object_share_async() { + let obj = ClassWrapper::constructor_object(53); + let objClone = obj.clone(); + + let handle: thread::JoinHandle = thread::spawn(move || { + // Thread code here + let mut result: *const ClassWrapper = objClone.as_ref(); + for _i in 0..10000 { + let obj2 = Object::from_ref(objClone.as_ref()); + result = obj2.as_ref() as *const ClassWrapper; + } + result as i32 + }); + let mut result: *const ClassWrapper = obj.as_ref(); + for _i in 0..10000 { + let obj2 = Object::from_ref(obj.as_ref()); + result = obj2.as_ref() as *const ClassWrapper; + } + + // Wait for thread to finish + assert_eq!(handle.join().unwrap(), result as i32); + assert_eq!(result as i32, obj.as_ref() as *const ClassWrapper as i32); + } +} diff --git a/src/trust_engine/kernel/src/TrustEngine-rs.dtr b/src/trust_engine/kernel/src/TrustEngine-rs.dtr new file mode 100644 index 0000000..4549d49 --- /dev/null +++ b/src/trust_engine/kernel/src/TrustEngine-rs.dtr @@ -0,0 +1,5 @@ +file_format_version = "1.0" +dafny_version = "4.11.0.0" +[options_by_module.TrustEngine] +legacy-module-names = false +rust-sync = false diff --git a/src/trust_engine/kernel/src/TrustEngine.rs b/src/trust_engine/kernel/src/TrustEngine.rs new file mode 100644 index 0000000..9c22a3d --- /dev/null +++ b/src/trust_engine/kernel/src/TrustEngine.rs @@ -0,0 +1,2111 @@ +#![allow(warnings, unconditional_panic)] +#![allow(nonstandard_style)] +#![cfg_attr(any(), rustfmt::skip)] + +pub mod _module { + +} +/// ../output/TrustEngine.dfy(1,1) +pub mod TrustEngine { + pub use ::std::rc::Rc; + pub use ::dafny_runtime::_System::nat; + pub use ::dafny_runtime::Set; + pub use ::dafny_runtime::DafnyInt; + pub use ::dafny_runtime::int; + pub use crate::TrustEngine::Claim::GrantName; + pub use crate::TrustEngine::Claim::GrantIp; + pub use crate::TrustEngine::Claim::GrantConstraint; + pub use ::dafny_runtime::Sequence; + pub use ::dafny_runtime::SetBuilder; + pub use ::std::fmt::Debug; + pub use ::std::fmt::Formatter; + pub use ::std::fmt::Result; + pub use ::dafny_runtime::DafnyPrint; + pub use ::std::cmp::PartialEq; + pub use ::std::cmp::Eq; + pub use ::std::hash::Hash; + pub use ::std::hash::Hasher; + pub use ::std::convert::AsRef; + + pub struct _default {} + + impl _default { + /// ../output/TrustEngine.dfy(33,5) + pub fn size(s: &Rc) -> nat { + s.names().cardinality() + s.ips().cardinality() + s.constraints().cardinality() + s.authz().cardinality() + } + /// ../output/TrustEngine.dfy(38,5) + pub fn endorser_ok(ct: &Rc, endorser: &nat, patterns: &Set>, names: &Set>) -> bool { + ct.endorser_imids().contains(endorser) || names.iter().any(({ + let mut ct = ct.clone(); + let mut names = names.clone(); + let mut endorser = endorser.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__exists_var_0: &Rc| -> bool{ + let mut nm: Rc = __exists_var_0.clone(); + names.contains(&nm) && nm.imid().clone() == endorser.clone() && ct.endorser_patterns().iter().any(({ + let mut ct = ct.clone(); + let mut nm = nm.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__exists_var_1: &nat| -> bool{ + let mut p: nat = __exists_var_1.clone(); + if { + let x: DafnyInt = p.clone(); + int!(0) <= x.clone() + } { + ct.endorser_patterns().contains(&p) && patterns.contains(&Rc::new(PatName::PatName { + pattern: p.clone(), + name: nm.name().clone() + })) + } else { + false + } + }) as Rc _> + }).as_ref()) + }) as Rc _> + }).as_ref()) + } + /// ../output/TrustEngine.dfy(43,5) + pub fn target_ok(ct: &Rc, target: &nat, patterns: &Set>, names: &Set>) -> bool { + ct.any_target().clone() || ct.target_imids().contains(target) || names.iter().any(({ + let mut ct = ct.clone(); + let mut names = names.clone(); + let mut target = target.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__exists_var_0: &Rc| -> bool{ + let mut nm: Rc = __exists_var_0.clone(); + names.contains(&nm) && nm.imid().clone() == target.clone() && ct.target_patterns().iter().any(({ + let mut ct = ct.clone(); + let mut nm = nm.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__exists_var_1: &nat| -> bool{ + let mut p: nat = __exists_var_1.clone(); + if { + let x: DafnyInt = p.clone(); + int!(0) <= x.clone() + } { + ct.target_patterns().contains(&p) && patterns.contains(&Rc::new(PatName::PatName { + pattern: p.clone(), + name: nm.name().clone() + })) + } else { + false + } + }) as Rc _> + }).as_ref()) + }) as Rc _> + }).as_ref()) + } + /// ../output/TrustEngine.dfy(48,5) + pub fn permits_name(ct: &Rc, endorser: &nat, target: &nat, name: &nat, patterns: &Set>, names: &Set>) -> bool { + _default::endorser_ok(ct, endorser, patterns, names) && _default::target_ok(ct, target, patterns, names) && ct.permitted_patterns().iter().any(({ + let mut ct = ct.clone(); + let mut name = name.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__exists_var_0: &nat| -> bool{ + let mut p: nat = __exists_var_0.clone(); + if { + let x: DafnyInt = p.clone(); + int!(0) <= x.clone() + } { + ct.permitted_patterns().contains(&p) && patterns.contains(&Rc::new(PatName::PatName { + pattern: p.clone(), + name: name.clone() + })) + } else { + false + } + }) as Rc _> + }).as_ref()) + } + /// ../output/TrustEngine.dfy(53,5) + pub fn permits_ip(ct: &Rc, endorser: &nat, target: &nat, ip: &nat, subnet_contains: &Set>, patterns: &Set>, names: &Set>) -> bool { + _default::endorser_ok(ct, endorser, patterns, names) && _default::target_ok(ct, target, patterns, names) && ct.permitted_subnets().iter().any(({ + let mut subnet_contains = subnet_contains.clone(); + let mut ip = ip.clone(); + let mut ct = ct.clone(); + Rc::new(move |__exists_var_0: &nat| -> bool{ + let mut sn: nat = __exists_var_0.clone(); + if { + let x: DafnyInt = sn.clone(); + int!(0) <= x.clone() + } { + ct.permitted_subnets().contains(&sn) && subnet_contains.contains(&Rc::new(SubnetIp::SubnetIp { + subnet: sn.clone(), + ip: ip.clone() + })) + } else { + false + } + }) as Rc _> + }).as_ref()) + } + /// ../output/TrustEngine.dfy(58,5) + pub fn authorizes(ct: &Rc, endorser: &nat, target: &nat, patterns: &Set>, names: &Set>) -> bool { + _default::endorser_ok(ct, endorser, patterns, names) && _default::target_ok(ct, target, patterns, names) && ct.authority().clone() + } + /// ../output/TrustEngine.dfy(63,5) + pub fn resolves_target(target_imids: &Set, target_patterns: &Set, t: &nat, patterns: &Set>, names: &Set>) -> bool { + target_imids.contains(t) || names.iter().any(({ + let mut target_patterns = target_patterns.clone(); + let mut t = t.clone(); + let mut names = names.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__exists_var_0: &Rc| -> bool{ + let mut nm: Rc = __exists_var_0.clone(); + names.contains(&nm) && nm.imid().clone() == t.clone() && (&target_patterns).iter().any(({ + let mut target_patterns = target_patterns.clone(); + let mut nm = nm.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__exists_var_1: &nat| -> bool{ + let mut p: nat = __exists_var_1.clone(); + if { + let x: DafnyInt = p.clone(); + int!(0) <= x.clone() + } { + target_patterns.contains(&p) && patterns.contains(&Rc::new(PatName::PatName { + pattern: p.clone(), + name: nm.name().clone() + })) + } else { + false + } + }) as Rc _> + }).as_ref()) + }) as Rc _> + }).as_ref()) + } + /// ../output/TrustEngine.dfy(68,5) + pub fn grants_name(endorser: &nat, tis: &Set, tps: &Set, name: &nat, constraints: &Set>, names: &Set>, patterns: &Set>, result_names: &Set>) -> bool { + tis.iter().all(({ + let mut constraints = constraints.clone(); + let mut result_names = result_names.clone(); + let mut tis = tis.clone(); + let mut name = name.clone(); + let mut names = names.clone(); + let mut endorser = endorser.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__forall_var_0: &nat| -> bool{ + let mut t: nat = __forall_var_0.clone(); + if { + let x: DafnyInt = t.clone(); + int!(0) <= x.clone() + } { + !tis.contains(&t) || (!(&constraints).iter().any(({ + let mut constraints = constraints.clone(); + let mut t = t.clone(); + let mut name = name.clone(); + let mut names = names.clone(); + let mut endorser = endorser.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__exists_var_0: &Rc| -> bool{ + let mut ct: Rc = __exists_var_0.clone(); + constraints.contains(&ct) && _default::permits_name(&ct, &endorser, &t, &name, &patterns, &names) + }) as Rc _> + }).as_ref()) || result_names.contains(&Rc::new(NameImid::NameImid { + name: name.clone(), + imid: t.clone() + }))) + } else { + true + } + }) as Rc _> + }).as_ref()) && names.iter().all(({ + let mut constraints = constraints.clone(); + let mut result_names = result_names.clone(); + let mut tps = tps.clone(); + let mut name = name.clone(); + let mut names = names.clone(); + let mut endorser = endorser.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__forall_var_1: &Rc| -> bool{ + let mut nm: Rc = __forall_var_1.clone(); + !names.contains(&nm) || (!((&tps).iter().any(({ + let mut nm = nm.clone(); + let mut tps = tps.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__exists_var_1: &nat| -> bool{ + let mut p: nat = __exists_var_1.clone(); + if { + let x: DafnyInt = p.clone(); + int!(0) <= x.clone() + } { + tps.contains(&p) && patterns.contains(&Rc::new(PatName::PatName { + pattern: p.clone(), + name: nm.name().clone() + })) + } else { + false + } + }) as Rc _> + }).as_ref()) && (&constraints).iter().any(({ + let mut constraints = constraints.clone(); + let mut nm = nm.clone(); + let mut name = name.clone(); + let mut names = names.clone(); + let mut endorser = endorser.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__exists_var_2: &Rc| -> bool{ + let mut ct: Rc = __exists_var_2.clone(); + constraints.contains(&ct) && _default::permits_name(&ct, &endorser, nm.imid(), &name, &patterns, &names) + }) as Rc _> + }).as_ref())) || result_names.contains(&Rc::new(NameImid::NameImid { + name: name.clone(), + imid: nm.imid().clone() + }))) + }) as Rc _> + }).as_ref()) + } + /// ../output/TrustEngine.dfy(73,5) + pub fn grants_ip(endorser: &nat, tis: &Set, tps: &Set, ip: &nat, constraints: &Set>, names: &Set>, patterns: &Set>, subnet_contains: &Set>, result_ips: &Set>) -> bool { + tis.iter().all(({ + let mut result_ips = result_ips.clone(); + let mut constraints = constraints.clone(); + let mut subnet_contains = subnet_contains.clone(); + let mut ip = ip.clone(); + let mut tis = tis.clone(); + let mut names = names.clone(); + let mut endorser = endorser.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__forall_var_0: &nat| -> bool{ + let mut t: nat = __forall_var_0.clone(); + if { + let x: DafnyInt = t.clone(); + int!(0) <= x.clone() + } { + !tis.contains(&t) || (!(&constraints).iter().any(({ + let mut constraints = constraints.clone(); + let mut subnet_contains = subnet_contains.clone(); + let mut t = t.clone(); + let mut ip = ip.clone(); + let mut names = names.clone(); + let mut endorser = endorser.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__exists_var_0: &Rc| -> bool{ + let mut ct: Rc = __exists_var_0.clone(); + constraints.contains(&ct) && _default::permits_ip(&ct, &endorser, &t, &ip, &subnet_contains, &patterns, &names) + }) as Rc _> + }).as_ref()) || result_ips.contains(&Rc::new(IpImid::IpImid { + ip: ip.clone(), + imid: t.clone() + }))) + } else { + true + } + }) as Rc _> + }).as_ref()) && names.iter().all(({ + let mut result_ips = result_ips.clone(); + let mut constraints = constraints.clone(); + let mut subnet_contains = subnet_contains.clone(); + let mut ip = ip.clone(); + let mut tps = tps.clone(); + let mut names = names.clone(); + let mut endorser = endorser.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__forall_var_1: &Rc| -> bool{ + let mut nm: Rc = __forall_var_1.clone(); + !names.contains(&nm) || (!((&tps).iter().any(({ + let mut nm = nm.clone(); + let mut tps = tps.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__exists_var_1: &nat| -> bool{ + let mut p: nat = __exists_var_1.clone(); + if { + let x: DafnyInt = p.clone(); + int!(0) <= x.clone() + } { + tps.contains(&p) && patterns.contains(&Rc::new(PatName::PatName { + pattern: p.clone(), + name: nm.name().clone() + })) + } else { + false + } + }) as Rc _> + }).as_ref()) && (&constraints).iter().any(({ + let mut constraints = constraints.clone(); + let mut subnet_contains = subnet_contains.clone(); + let mut ip = ip.clone(); + let mut nm = nm.clone(); + let mut names = names.clone(); + let mut endorser = endorser.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__exists_var_2: &Rc| -> bool{ + let mut ct: Rc = __exists_var_2.clone(); + constraints.contains(&ct) && _default::permits_ip(&ct, &endorser, nm.imid(), &ip, &subnet_contains, &patterns, &names) + }) as Rc _> + }).as_ref())) || result_ips.contains(&Rc::new(IpImid::IpImid { + ip: ip.clone(), + imid: nm.imid().clone() + }))) + }) as Rc _> + }).as_ref()) + } + /// ../output/TrustEngine.dfy(78,5) + pub fn grants(c: &Rc, my_imid: &nat, constraints: &Set>, names: &Set>, patterns: &Set>, subnet_contains: &Set>, result_names: &Set>, result_ips: &Set>, result_constraints: &Set>, result_authz: &Set>) -> bool { + let mut _source0: Rc = c.clone(); + if matches!((&_source0).as_ref(), GrantName{ .. }) { + let mut ___mcc_h0: nat = _source0.endorser().clone(); + let mut ___mcc_h1: Set = _source0.target_imids().clone(); + let mut ___mcc_h2: Set = _source0.target_patterns().clone(); + let mut ___mcc_h3: nat = _source0.name().clone(); + let mut name: nat = ___mcc_h3.clone(); + let mut tps: Set = ___mcc_h2.clone(); + let mut tis: Set = ___mcc_h1.clone(); + let mut endorser: nat = ___mcc_h0.clone(); + _default::grants_name(&endorser, &tis, &tps, &name, constraints, names, patterns, result_names) + } else { + if matches!((&_source0).as_ref(), GrantIp{ .. }) { + let mut ___mcc_h4: nat = _source0.endorser().clone(); + let mut ___mcc_h5: Set = _source0.target_imids().clone(); + let mut ___mcc_h6: Set = _source0.target_patterns().clone(); + let mut ___mcc_h7: nat = _source0.ip().clone(); + let mut ip: nat = ___mcc_h7.clone(); + let mut tps: Set = ___mcc_h6.clone(); + let mut tis: Set = ___mcc_h5.clone(); + let mut endorser: nat = ___mcc_h4.clone(); + _default::grants_ip(&endorser, &tis, &tps, &ip, constraints, names, patterns, subnet_contains, result_ips) + } else { + if matches!((&_source0).as_ref(), GrantConstraint{ .. }) { + let mut ___mcc_h8: nat = _source0.endorser().clone(); + let mut ___mcc_h9: Set = _source0.target_imids().clone(); + let mut ___mcc_h10: Set = _source0.target_patterns().clone(); + let mut ___mcc_h11: Rc = _source0.constraint().clone(); + let mut k: Rc = ___mcc_h11.clone(); + let mut tps: Set = ___mcc_h10.clone(); + let mut tis: Set = ___mcc_h9.clone(); + let mut endorser: nat = ___mcc_h8.clone(); + !(_default::resolves_target(&tis, &tps, my_imid, patterns, names) && constraints.iter().any(({ + let mut constraints = constraints.clone(); + let mut names = names.clone(); + let mut my_imid = my_imid.clone(); + let mut endorser = endorser.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__exists_var_0: &Rc| -> bool{ + let mut ct: Rc = __exists_var_0.clone(); + constraints.contains(&ct) && _default::authorizes(&ct, &endorser, &my_imid, &patterns, &names) + }) as Rc _> + }).as_ref()) && (!k.authority().clone() || endorser.clone() == my_imid.clone())) || result_constraints.contains(&k) + } else { + let mut ___mcc_h12: nat = _source0.endorser().clone(); + let mut ___mcc_h13: Set = _source0.target_imids().clone(); + let mut ___mcc_h14: Set = _source0.target_patterns().clone(); + let mut ___mcc_h15: Rc = _source0.authz().clone(); + let mut a: Rc = ___mcc_h15.clone(); + let mut tps: Set = ___mcc_h14.clone(); + let mut tis: Set = ___mcc_h13.clone(); + let mut endorser: nat = ___mcc_h12.clone(); + !(_default::resolves_target(&tis, &tps, my_imid, patterns, names) && constraints.iter().any(({ + let mut constraints = constraints.clone(); + let mut names = names.clone(); + let mut my_imid = my_imid.clone(); + let mut endorser = endorser.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__exists_var_1: &Rc| -> bool{ + let mut ct: Rc = __exists_var_1.clone(); + constraints.contains(&ct) && _default::authorizes(&ct, &endorser, &my_imid, &patterns, &names) + }) as Rc _> + }).as_ref())) || result_authz.contains(&a) + } + } + } + } + /// ../output/TrustEngine.dfy(88,5) + pub fn grants_exact_name(c: &Rc, nm: &Rc, constraints: &Set>, names: &Set>, patterns: &Set>) -> bool { + let mut _source0: Rc = c.clone(); + if matches!((&_source0).as_ref(), GrantName{ .. }) { + let mut ___mcc_h0: nat = _source0.endorser().clone(); + let mut ___mcc_h1: Set = _source0.target_imids().clone(); + let mut ___mcc_h2: Set = _source0.target_patterns().clone(); + let mut ___mcc_h3: nat = _source0.name().clone(); + let mut name: nat = ___mcc_h3.clone(); + let mut tps: Set = ___mcc_h2.clone(); + let mut tis: Set = ___mcc_h1.clone(); + let mut endorser: nat = ___mcc_h0.clone(); + name.clone() == nm.name().clone() && _default::resolves_target(&tis, &tps, nm.imid(), patterns, names) && constraints.iter().any(({ + let mut constraints = constraints.clone(); + let mut nm = nm.clone(); + let mut name = name.clone(); + let mut names = names.clone(); + let mut endorser = endorser.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__exists_var_0: &Rc| -> bool{ + let mut ct: Rc = __exists_var_0.clone(); + constraints.contains(&ct) && _default::permits_name(&ct, &endorser, nm.imid(), &name, &patterns, &names) + }) as Rc _> + }).as_ref()) + } else { + if matches!((&_source0).as_ref(), GrantIp{ .. }) { + let mut ___mcc_h4: nat = _source0.endorser().clone(); + let mut ___mcc_h5: Set = _source0.target_imids().clone(); + let mut ___mcc_h6: Set = _source0.target_patterns().clone(); + let mut ___mcc_h7: nat = _source0.ip().clone(); + false + } else { + if matches!((&_source0).as_ref(), GrantConstraint{ .. }) { + let mut ___mcc_h8: nat = _source0.endorser().clone(); + let mut ___mcc_h9: Set = _source0.target_imids().clone(); + let mut ___mcc_h10: Set = _source0.target_patterns().clone(); + let mut ___mcc_h11: Rc = _source0.constraint().clone(); + false + } else { + let mut ___mcc_h12: nat = _source0.endorser().clone(); + let mut ___mcc_h13: Set = _source0.target_imids().clone(); + let mut ___mcc_h14: Set = _source0.target_patterns().clone(); + let mut ___mcc_h15: Rc = _source0.authz().clone(); + false + } + } + } + } + /// ../output/TrustEngine.dfy(98,5) + pub fn grants_exact_ip(c: &Rc, ii: &Rc, constraints: &Set>, names: &Set>, patterns: &Set>, subnet_contains: &Set>) -> bool { + let mut _source0: Rc = c.clone(); + if matches!((&_source0).as_ref(), GrantName{ .. }) { + let mut ___mcc_h0: nat = _source0.endorser().clone(); + let mut ___mcc_h1: Set = _source0.target_imids().clone(); + let mut ___mcc_h2: Set = _source0.target_patterns().clone(); + let mut ___mcc_h3: nat = _source0.name().clone(); + false + } else { + if matches!((&_source0).as_ref(), GrantIp{ .. }) { + let mut ___mcc_h4: nat = _source0.endorser().clone(); + let mut ___mcc_h5: Set = _source0.target_imids().clone(); + let mut ___mcc_h6: Set = _source0.target_patterns().clone(); + let mut ___mcc_h7: nat = _source0.ip().clone(); + let mut ip: nat = ___mcc_h7.clone(); + let mut tps: Set = ___mcc_h6.clone(); + let mut tis: Set = ___mcc_h5.clone(); + let mut endorser: nat = ___mcc_h4.clone(); + ip.clone() == ii.ip().clone() && _default::resolves_target(&tis, &tps, ii.imid(), patterns, names) && constraints.iter().any(({ + let mut constraints = constraints.clone(); + let mut subnet_contains = subnet_contains.clone(); + let mut ii = ii.clone(); + let mut ip = ip.clone(); + let mut names = names.clone(); + let mut endorser = endorser.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__exists_var_0: &Rc| -> bool{ + let mut ct: Rc = __exists_var_0.clone(); + constraints.contains(&ct) && _default::permits_ip(&ct, &endorser, ii.imid(), &ip, &subnet_contains, &patterns, &names) + }) as Rc _> + }).as_ref()) + } else { + if matches!((&_source0).as_ref(), GrantConstraint{ .. }) { + let mut ___mcc_h8: nat = _source0.endorser().clone(); + let mut ___mcc_h9: Set = _source0.target_imids().clone(); + let mut ___mcc_h10: Set = _source0.target_patterns().clone(); + let mut ___mcc_h11: Rc = _source0.constraint().clone(); + false + } else { + let mut ___mcc_h12: nat = _source0.endorser().clone(); + let mut ___mcc_h13: Set = _source0.target_imids().clone(); + let mut ___mcc_h14: Set = _source0.target_patterns().clone(); + let mut ___mcc_h15: Rc = _source0.authz().clone(); + false + } + } + } + } + /// ../output/TrustEngine.dfy(108,5) + pub fn grants_exact_constraint(c: &Rc, k: &Rc, my_imid: &nat, constraints: &Set>, names: &Set>, patterns: &Set>) -> bool { + let mut _source0: Rc = c.clone(); + if matches!((&_source0).as_ref(), GrantName{ .. }) { + let mut ___mcc_h0: nat = _source0.endorser().clone(); + let mut ___mcc_h1: Set = _source0.target_imids().clone(); + let mut ___mcc_h2: Set = _source0.target_patterns().clone(); + let mut ___mcc_h3: nat = _source0.name().clone(); + false + } else { + if matches!((&_source0).as_ref(), GrantIp{ .. }) { + let mut ___mcc_h4: nat = _source0.endorser().clone(); + let mut ___mcc_h5: Set = _source0.target_imids().clone(); + let mut ___mcc_h6: Set = _source0.target_patterns().clone(); + let mut ___mcc_h7: nat = _source0.ip().clone(); + false + } else { + if matches!((&_source0).as_ref(), GrantConstraint{ .. }) { + let mut ___mcc_h8: nat = _source0.endorser().clone(); + let mut ___mcc_h9: Set = _source0.target_imids().clone(); + let mut ___mcc_h10: Set = _source0.target_patterns().clone(); + let mut ___mcc_h11: Rc = _source0.constraint().clone(); + let mut kc: Rc = ___mcc_h11.clone(); + let mut tps: Set = ___mcc_h10.clone(); + let mut tis: Set = ___mcc_h9.clone(); + let mut endorser: nat = ___mcc_h8.clone(); + kc.clone() == k.clone() && _default::resolves_target(&tis, &tps, my_imid, patterns, names) && constraints.iter().any(({ + let mut constraints = constraints.clone(); + let mut names = names.clone(); + let mut my_imid = my_imid.clone(); + let mut endorser = endorser.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__exists_var_0: &Rc| -> bool{ + let mut ct: Rc = __exists_var_0.clone(); + constraints.contains(&ct) && _default::authorizes(&ct, &endorser, &my_imid, &patterns, &names) + }) as Rc _> + }).as_ref()) && (!kc.authority().clone() || endorser.clone() == my_imid.clone()) + } else { + let mut ___mcc_h12: nat = _source0.endorser().clone(); + let mut ___mcc_h13: Set = _source0.target_imids().clone(); + let mut ___mcc_h14: Set = _source0.target_patterns().clone(); + let mut ___mcc_h15: Rc = _source0.authz().clone(); + false + } + } + } + } + /// ../output/TrustEngine.dfy(118,5) + pub fn grants_exact_authz(c: &Rc, a: &Rc, my_imid: &nat, constraints: &Set>, names: &Set>, patterns: &Set>) -> bool { + let mut _source0: Rc = c.clone(); + if matches!((&_source0).as_ref(), GrantName{ .. }) { + let mut ___mcc_h0: nat = _source0.endorser().clone(); + let mut ___mcc_h1: Set = _source0.target_imids().clone(); + let mut ___mcc_h2: Set = _source0.target_patterns().clone(); + let mut ___mcc_h3: nat = _source0.name().clone(); + false + } else { + if matches!((&_source0).as_ref(), GrantIp{ .. }) { + let mut ___mcc_h4: nat = _source0.endorser().clone(); + let mut ___mcc_h5: Set = _source0.target_imids().clone(); + let mut ___mcc_h6: Set = _source0.target_patterns().clone(); + let mut ___mcc_h7: nat = _source0.ip().clone(); + false + } else { + if matches!((&_source0).as_ref(), GrantConstraint{ .. }) { + let mut ___mcc_h8: nat = _source0.endorser().clone(); + let mut ___mcc_h9: Set = _source0.target_imids().clone(); + let mut ___mcc_h10: Set = _source0.target_patterns().clone(); + let mut ___mcc_h11: Rc = _source0.constraint().clone(); + false + } else { + let mut ___mcc_h12: nat = _source0.endorser().clone(); + let mut ___mcc_h13: Set = _source0.target_imids().clone(); + let mut ___mcc_h14: Set = _source0.target_patterns().clone(); + let mut ___mcc_h15: Rc = _source0.authz().clone(); + let mut ka: Rc = ___mcc_h15.clone(); + let mut tps: Set = ___mcc_h14.clone(); + let mut tis: Set = ___mcc_h13.clone(); + let mut endorser: nat = ___mcc_h12.clone(); + ka.clone() == a.clone() && _default::resolves_target(&tis, &tps, my_imid, patterns, names) && constraints.iter().any(({ + let mut constraints = constraints.clone(); + let mut names = names.clone(); + let mut my_imid = my_imid.clone(); + let mut endorser = endorser.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__exists_var_0: &Rc| -> bool{ + let mut ct: Rc = __exists_var_0.clone(); + constraints.contains(&ct) && _default::authorizes(&ct, &endorser, &my_imid, &patterns, &names) + }) as Rc _> + }).as_ref()) + } + } + } + } + /// ../output/TrustEngine.dfy(130,5) + pub fn name_in_universe(tis: &Set, tps: &Set, name: &nat, u: &Rc, patterns: &Set>) -> bool { + tis.iter().all(({ + let mut u = u.clone(); + let mut tis = tis.clone(); + let mut name = name.clone(); + Rc::new(move |__forall_var_0: &nat| -> bool{ + let mut t: nat = __forall_var_0.clone(); + if { + let x: DafnyInt = t.clone(); + int!(0) <= x.clone() + } { + !tis.contains(&t) || u.names().contains(&Rc::new(NameImid::NameImid { + name: name.clone(), + imid: t.clone() + })) + } else { + true + } + }) as Rc _> + }).as_ref()) && u.names().iter().all(({ + let mut u = u.clone(); + let mut tps = tps.clone(); + let mut name = name.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__forall_var_1: &Rc| -> bool{ + let mut nm: Rc = __forall_var_1.clone(); + !u.names().contains(&nm) || (!(&tps).iter().any(({ + let mut nm = nm.clone(); + let mut tps = tps.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__exists_var_0: &nat| -> bool{ + let mut p: nat = __exists_var_0.clone(); + if { + let x: DafnyInt = p.clone(); + int!(0) <= x.clone() + } { + tps.contains(&p) && patterns.contains(&Rc::new(PatName::PatName { + pattern: p.clone(), + name: nm.name().clone() + })) + } else { + false + } + }) as Rc _> + }).as_ref()) || u.names().contains(&Rc::new(NameImid::NameImid { + name: name.clone(), + imid: nm.imid().clone() + }))) + }) as Rc _> + }).as_ref()) + } + /// ../output/TrustEngine.dfy(135,5) + pub fn ip_in_universe(tis: &Set, tps: &Set, ip: &nat, u: &Rc, patterns: &Set>) -> bool { + tis.iter().all(({ + let mut u = u.clone(); + let mut ip = ip.clone(); + let mut tis = tis.clone(); + Rc::new(move |__forall_var_0: &nat| -> bool{ + let mut t: nat = __forall_var_0.clone(); + if { + let x: DafnyInt = t.clone(); + int!(0) <= x.clone() + } { + !tis.contains(&t) || u.ips().contains(&Rc::new(IpImid::IpImid { + ip: ip.clone(), + imid: t.clone() + })) + } else { + true + } + }) as Rc _> + }).as_ref()) && u.names().iter().all(({ + let mut u = u.clone(); + let mut ip = ip.clone(); + let mut tps = tps.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__forall_var_1: &Rc| -> bool{ + let mut nm: Rc = __forall_var_1.clone(); + !u.names().contains(&nm) || (!(&tps).iter().any(({ + let mut nm = nm.clone(); + let mut tps = tps.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__exists_var_0: &nat| -> bool{ + let mut p: nat = __exists_var_0.clone(); + if { + let x: DafnyInt = p.clone(); + int!(0) <= x.clone() + } { + tps.contains(&p) && patterns.contains(&Rc::new(PatName::PatName { + pattern: p.clone(), + name: nm.name().clone() + })) + } else { + false + } + }) as Rc _> + }).as_ref()) || u.ips().contains(&Rc::new(IpImid::IpImid { + ip: ip.clone(), + imid: nm.imid().clone() + }))) + }) as Rc _> + }).as_ref()) + } + /// ../output/TrustEngine.dfy(140,5) + pub fn claim_fact_in_universe(c: &Rc, u: &Rc, patterns: &Set>) -> bool { + let mut _source0: Rc = c.clone(); + if matches!((&_source0).as_ref(), GrantName{ .. }) { + let mut ___mcc_h0: nat = _source0.endorser().clone(); + let mut ___mcc_h1: Set = _source0.target_imids().clone(); + let mut ___mcc_h2: Set = _source0.target_patterns().clone(); + let mut ___mcc_h3: nat = _source0.name().clone(); + let mut name: nat = ___mcc_h3.clone(); + let mut tps: Set = ___mcc_h2.clone(); + let mut tis: Set = ___mcc_h1.clone(); + let mut endorser: nat = ___mcc_h0.clone(); + _default::name_in_universe(&tis, &tps, &name, u, patterns) + } else { + if matches!((&_source0).as_ref(), GrantIp{ .. }) { + let mut ___mcc_h4: nat = _source0.endorser().clone(); + let mut ___mcc_h5: Set = _source0.target_imids().clone(); + let mut ___mcc_h6: Set = _source0.target_patterns().clone(); + let mut ___mcc_h7: nat = _source0.ip().clone(); + let mut ip: nat = ___mcc_h7.clone(); + let mut tps: Set = ___mcc_h6.clone(); + let mut tis: Set = ___mcc_h5.clone(); + let mut endorser: nat = ___mcc_h4.clone(); + _default::ip_in_universe(&tis, &tps, &ip, u, patterns) + } else { + if matches!((&_source0).as_ref(), GrantConstraint{ .. }) { + let mut ___mcc_h8: nat = _source0.endorser().clone(); + let mut ___mcc_h9: Set = _source0.target_imids().clone(); + let mut ___mcc_h10: Set = _source0.target_patterns().clone(); + let mut ___mcc_h11: Rc = _source0.constraint().clone(); + let mut k: Rc = ___mcc_h11.clone(); + let mut tps: Set = ___mcc_h10.clone(); + let mut tis: Set = ___mcc_h9.clone(); + let mut endorser: nat = ___mcc_h8.clone(); + u.constraints().contains(&k) + } else { + let mut ___mcc_h12: nat = _source0.endorser().clone(); + let mut ___mcc_h13: Set = _source0.target_imids().clone(); + let mut ___mcc_h14: Set = _source0.target_patterns().clone(); + let mut ___mcc_h15: Rc = _source0.authz().clone(); + let mut a: Rc = ___mcc_h15.clone(); + let mut tps: Set = ___mcc_h14.clone(); + let mut tis: Set = ___mcc_h13.clone(); + let mut endorser: nat = ___mcc_h12.clone(); + u.authz().contains(&a) + } + } + } + } + /// ../output/TrustEngine.dfy(150,5) + pub fn within(s: &Rc, u: &Rc) -> bool { + s.names().clone() <= u.names().clone() && s.ips().clone() <= u.ips().clone() && s.constraints().clone() <= u.constraints().clone() && s.authz().clone() <= u.authz().clone() + } + /// ../output/TrustEngine.dfy(155,5) + pub fn fits(claims: &Set>, u: &Rc, patterns: &Set>) -> bool { + claims.iter().all(({ + let mut u = u.clone(); + let mut claims = claims.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__forall_var_0: &Rc| -> bool{ + let mut c: Rc = __forall_var_0.clone(); + !claims.contains(&c) || _default::claim_fact_in_universe(&c, &u, &patterns) + }) as Rc _> + }).as_ref()) + } + /// ../output/TrustEngine.dfy(160,5) + pub fn derive(s: &Rc, claims: &Set>, patterns: &Set>, subnet_contains: &Set>, u: &Rc) -> Rc { + let mut _r0 = s.clone(); + let mut _r1 = claims.clone(); + let mut _r2 = patterns.clone(); + let mut _r3 = subnet_contains.clone(); + let mut _r4 = u.clone(); + 'TAIL_CALL_START: loop { + let s = _r0; + let claims = _r1; + let patterns = _r2; + let subnet_contains = _r3; + let u = _r4; + if _default::round(&s, &claims, &patterns, &subnet_contains, &u) == s.clone() { + return s.clone(); + } else { + let mut _in0: Rc = _default::round(&s, &claims, &patterns, &subnet_contains, &u); + let mut _in1: Set> = claims.clone(); + let mut _in2: Set> = patterns.clone(); + let mut _in3: Set> = subnet_contains.clone(); + let mut _in4: Rc = u.clone(); + _r0 = _in0.clone(); + _r1 = _in1.clone(); + _r2 = _in2.clone(); + _r3 = _in3.clone(); + _r4 = _in4.clone(); + continue 'TAIL_CALL_START; + } + } + } + /// ../output/TrustEngine.dfy(168,5) + pub fn names_of(s: &Rc) -> Set> { + s.names().clone() + } + /// ../output/TrustEngine.dfy(173,5) + pub fn ips_of(s: &Rc) -> Set> { + s.ips().clone() + } + /// ../output/TrustEngine.dfy(178,5) + pub fn constraints_of(s: &Rc) -> Set> { + s.constraints().clone() + } + /// ../output/TrustEngine.dfy(183,5) + pub fn authz_of(s: &Rc) -> Set> { + s.authz().clone() + } + /// ../output/TrustEngine.dfy(188,5) + pub fn pass_seq(s: &Rc, cs: &Sequence>, patterns: &Set>, subnet_contains: &Set>, u: &Rc, i: &nat) -> Rc { + let mut _r0 = s.clone(); + let mut _r1 = cs.clone(); + let mut _r2 = patterns.clone(); + let mut _r3 = subnet_contains.clone(); + let mut _r4 = u.clone(); + let mut _r5 = i.clone(); + 'TAIL_CALL_START: loop { + let s = _r0; + let cs = _r1; + let patterns = _r2; + let subnet_contains = _r3; + let u = _r4; + let i = _r5; + if i.clone() == cs.cardinality() { + return s.clone(); + } else { + let mut _in0: Rc = _default::apply_one(&s, &cs.get(&i), &patterns, &subnet_contains, &u); + let mut _in1: Sequence> = cs.clone(); + let mut _in2: Set> = patterns.clone(); + let mut _in3: Set> = subnet_contains.clone(); + let mut _in4: Rc = u.clone(); + let mut _in5: DafnyInt = i.clone() + int!(1); + _r0 = _in0.clone(); + _r1 = _in1.clone(); + _r2 = _in2.clone(); + _r3 = _in3.clone(); + _r4 = _in4.clone(); + _r5 = _in5.clone(); + continue 'TAIL_CALL_START; + } + } + } + /// ../output/TrustEngine.dfy(196,5) + pub fn saturate_seq(s: &Rc, cs: &Sequence>, patterns: &Set>, subnet_contains: &Set>, u: &Rc) -> Rc { + let mut _r0 = s.clone(); + let mut _r1 = cs.clone(); + let mut _r2 = patterns.clone(); + let mut _r3 = subnet_contains.clone(); + let mut _r4 = u.clone(); + 'TAIL_CALL_START: loop { + let s = _r0; + let cs = _r1; + let patterns = _r2; + let subnet_contains = _r3; + let u = _r4; + if _default::pass_seq(&s, &cs, &patterns, &subnet_contains, &u, &int!(0)) == s.clone() { + return s.clone(); + } else { + let mut _in0: Rc = _default::pass_seq(&s, &cs, &patterns, &subnet_contains, &u, &int!(0)); + let mut _in1: Sequence> = cs.clone(); + let mut _in2: Set> = patterns.clone(); + let mut _in3: Set> = subnet_contains.clone(); + let mut _in4: Rc = u.clone(); + _r0 = _in0.clone(); + _r1 = _in1.clone(); + _r2 = _in2.clone(); + _r3 = _in3.clone(); + _r4 = _in4.clone(); + continue 'TAIL_CALL_START; + } + } + } + /// ../output/TrustEngine.dfy(217,1) + pub fn subState(a: &Rc, b: &Rc) -> bool { + a.names().clone() <= b.names().clone() && a.ips().clone() <= b.ips().clone() && a.constraints().clone() <= b.constraints().clone() && a.authz().clone() <= b.authz().clone() + } + /// ../output/TrustEngine.dfy(543,1) + pub fn round(s: &Rc, claims: &Set>, patterns: &Set>, subnet_contains: &Set>, u: &Rc) -> Rc { + Rc::new(State::State { + my_imid: s.my_imid().clone(), + names: s.names().merge(&(&({ + let mut s = s.clone(); + let mut u = u.clone(); + let mut claims = claims.clone(); + let mut patterns = patterns.clone(); + Rc::new(move || -> Set>{ + let mut _coll0: SetBuilder> = SetBuilder::>::new(); + for __compr_0 in u.names().iter().cloned() { + let mut nm: Rc = __compr_0.clone(); + if u.names().contains(&nm) && (&claims).iter().any(({ + let mut s = s.clone(); + let mut nm = nm.clone(); + let mut claims = claims.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__exists_var_0: &Rc| -> bool{ + let mut c: Rc = __exists_var_0.clone(); + claims.contains(&c) && _default::grants_exact_name(&c, &nm, s.constraints(), s.names(), &patterns) + }) as Rc _> + }).as_ref()) { + _coll0.add(&nm) + } + } + _coll0.build() + }) as Rc _> + }))()), + ips: s.ips().merge(&(&({ + let mut subnet_contains = subnet_contains.clone(); + let mut s = s.clone(); + let mut u = u.clone(); + let mut claims = claims.clone(); + let mut patterns = patterns.clone(); + Rc::new(move || -> Set>{ + let mut _coll1: SetBuilder> = SetBuilder::>::new(); + for __compr_1 in u.ips().iter().cloned() { + let mut ii: Rc = __compr_1.clone(); + if u.ips().contains(&ii) && (&claims).iter().any(({ + let mut subnet_contains = subnet_contains.clone(); + let mut s = s.clone(); + let mut ii = ii.clone(); + let mut claims = claims.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__exists_var_1: &Rc| -> bool{ + let mut c: Rc = __exists_var_1.clone(); + claims.contains(&c) && _default::grants_exact_ip(&c, &ii, s.constraints(), s.names(), &patterns, &subnet_contains) + }) as Rc _> + }).as_ref()) { + _coll1.add(&ii) + } + } + _coll1.build() + }) as Rc _> + }))()), + constraints: s.constraints().merge(&(&({ + let mut s = s.clone(); + let mut u = u.clone(); + let mut claims = claims.clone(); + let mut patterns = patterns.clone(); + Rc::new(move || -> Set>{ + let mut _coll2: SetBuilder> = SetBuilder::>::new(); + for __compr_2 in u.constraints().iter().cloned() { + let mut k: Rc = __compr_2.clone(); + if u.constraints().contains(&k) && (&claims).iter().any(({ + let mut k = k.clone(); + let mut s = s.clone(); + let mut claims = claims.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__exists_var_2: &Rc| -> bool{ + let mut c: Rc = __exists_var_2.clone(); + claims.contains(&c) && _default::grants_exact_constraint(&c, &k, s.my_imid(), s.constraints(), s.names(), &patterns) + }) as Rc _> + }).as_ref()) { + _coll2.add(&k) + } + } + _coll2.build() + }) as Rc _> + }))()), + authz: s.authz().merge(&(&({ + let mut s = s.clone(); + let mut u = u.clone(); + let mut claims = claims.clone(); + let mut patterns = patterns.clone(); + Rc::new(move || -> Set>{ + let mut _coll3: SetBuilder> = SetBuilder::>::new(); + for __compr_3 in u.authz().iter().cloned() { + let mut a: Rc = __compr_3.clone(); + if u.authz().contains(&a) && (&claims).iter().any(({ + let mut a = a.clone(); + let mut s = s.clone(); + let mut claims = claims.clone(); + let mut patterns = patterns.clone(); + Rc::new(move |__exists_var_3: &Rc| -> bool{ + let mut c: Rc = __exists_var_3.clone(); + claims.contains(&c) && _default::grants_exact_authz(&c, &a, s.my_imid(), s.constraints(), s.names(), &patterns) + }) as Rc _> + }).as_ref()) { + _coll3.add(&a) + } + } + _coll3.build() + }) as Rc _> + }))()) + }) + } + /// ../output/TrustEngine.dfy(581,1) + pub fn apply_one(s: &Rc, c: &Rc, patterns: &Set>, subnet_contains: &Set>, u: &Rc) -> Rc { + Rc::new(State::State { + my_imid: s.my_imid().clone(), + names: s.names().merge(&(&({ + let mut c = c.clone(); + let mut s = s.clone(); + let mut u = u.clone(); + let mut patterns = patterns.clone(); + Rc::new(move || -> Set>{ + let mut _coll0: SetBuilder> = SetBuilder::>::new(); + for __compr_0 in u.names().iter().cloned() { + let mut nm: Rc = __compr_0.clone(); + if u.names().contains(&nm) && _default::grants_exact_name(&c, &nm, s.constraints(), s.names(), &patterns) { + _coll0.add(&nm) + } + } + _coll0.build() + }) as Rc _> + }))()), + ips: s.ips().merge(&(&({ + let mut subnet_contains = subnet_contains.clone(); + let mut c = c.clone(); + let mut s = s.clone(); + let mut u = u.clone(); + let mut patterns = patterns.clone(); + Rc::new(move || -> Set>{ + let mut _coll1: SetBuilder> = SetBuilder::>::new(); + for __compr_1 in u.ips().iter().cloned() { + let mut ii: Rc = __compr_1.clone(); + if u.ips().contains(&ii) && _default::grants_exact_ip(&c, &ii, s.constraints(), s.names(), &patterns, &subnet_contains) { + _coll1.add(&ii) + } + } + _coll1.build() + }) as Rc _> + }))()), + constraints: s.constraints().merge(&(&({ + let mut c = c.clone(); + let mut s = s.clone(); + let mut u = u.clone(); + let mut patterns = patterns.clone(); + Rc::new(move || -> Set>{ + let mut _coll2: SetBuilder> = SetBuilder::>::new(); + for __compr_2 in u.constraints().iter().cloned() { + let mut k: Rc = __compr_2.clone(); + if u.constraints().contains(&k) && _default::grants_exact_constraint(&c, &k, s.my_imid(), s.constraints(), s.names(), &patterns) { + _coll2.add(&k) + } + } + _coll2.build() + }) as Rc _> + }))()), + authz: s.authz().merge(&(&({ + let mut c = c.clone(); + let mut s = s.clone(); + let mut u = u.clone(); + let mut patterns = patterns.clone(); + Rc::new(move || -> Set>{ + let mut _coll3: SetBuilder> = SetBuilder::>::new(); + for __compr_3 in u.authz().iter().cloned() { + let mut a: Rc = __compr_3.clone(); + if u.authz().contains(&a) && _default::grants_exact_authz(&c, &a, s.my_imid(), s.constraints(), s.names(), &patterns) { + _coll3.add(&a) + } + } + _coll3.build() + }) as Rc _> + }))()) + }) + } + } + + /// ../output/TrustEngine.dfy(13,5) + #[derive(Clone)] + pub enum Constraint { + Constraint { + endorser_imids: Set, + endorser_patterns: Set, + target_imids: Set, + target_patterns: Set, + any_target: bool, + permitted_patterns: Set, + permitted_subnets: Set, + authority: bool + } + } + + impl Constraint { + /// Returns a borrow of the field endorser_imids + pub fn endorser_imids(&self) -> &Set { + match self { + Constraint::Constraint{endorser_imids, endorser_patterns, target_imids, target_patterns, any_target, permitted_patterns, permitted_subnets, authority, } => endorser_imids, + } + } + /// Returns a borrow of the field endorser_patterns + pub fn endorser_patterns(&self) -> &Set { + match self { + Constraint::Constraint{endorser_imids, endorser_patterns, target_imids, target_patterns, any_target, permitted_patterns, permitted_subnets, authority, } => endorser_patterns, + } + } + /// Returns a borrow of the field target_imids + pub fn target_imids(&self) -> &Set { + match self { + Constraint::Constraint{endorser_imids, endorser_patterns, target_imids, target_patterns, any_target, permitted_patterns, permitted_subnets, authority, } => target_imids, + } + } + /// Returns a borrow of the field target_patterns + pub fn target_patterns(&self) -> &Set { + match self { + Constraint::Constraint{endorser_imids, endorser_patterns, target_imids, target_patterns, any_target, permitted_patterns, permitted_subnets, authority, } => target_patterns, + } + } + /// Returns a borrow of the field any_target + pub fn any_target(&self) -> &bool { + match self { + Constraint::Constraint{endorser_imids, endorser_patterns, target_imids, target_patterns, any_target, permitted_patterns, permitted_subnets, authority, } => any_target, + } + } + /// Returns a borrow of the field permitted_patterns + pub fn permitted_patterns(&self) -> &Set { + match self { + Constraint::Constraint{endorser_imids, endorser_patterns, target_imids, target_patterns, any_target, permitted_patterns, permitted_subnets, authority, } => permitted_patterns, + } + } + /// Returns a borrow of the field permitted_subnets + pub fn permitted_subnets(&self) -> &Set { + match self { + Constraint::Constraint{endorser_imids, endorser_patterns, target_imids, target_patterns, any_target, permitted_patterns, permitted_subnets, authority, } => permitted_subnets, + } + } + /// Returns a borrow of the field authority + pub fn authority(&self) -> &bool { + match self { + Constraint::Constraint{endorser_imids, endorser_patterns, target_imids, target_patterns, any_target, permitted_patterns, permitted_subnets, authority, } => authority, + } + } + } + + impl Debug + for Constraint { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for Constraint { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + Constraint::Constraint{endorser_imids, endorser_patterns, target_imids, target_patterns, any_target, permitted_patterns, permitted_subnets, authority, } => { + write!(_formatter, "TrustEngine.Constraint.Constraint(")?; + DafnyPrint::fmt_print(endorser_imids, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(endorser_patterns, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(target_imids, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(target_patterns, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(any_target, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(permitted_patterns, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(permitted_subnets, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(authority, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl PartialEq + for Constraint { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (Constraint::Constraint{endorser_imids, endorser_patterns, target_imids, target_patterns, any_target, permitted_patterns, permitted_subnets, authority, }, Constraint::Constraint{endorser_imids: _2_endorser_imids, endorser_patterns: _2_endorser_patterns, target_imids: _2_target_imids, target_patterns: _2_target_patterns, any_target: _2_any_target, permitted_patterns: _2_permitted_patterns, permitted_subnets: _2_permitted_subnets, authority: _2_authority, }) => { + endorser_imids == _2_endorser_imids && endorser_patterns == _2_endorser_patterns && target_imids == _2_target_imids && target_patterns == _2_target_patterns && any_target == _2_any_target && permitted_patterns == _2_permitted_patterns && permitted_subnets == _2_permitted_subnets && authority == _2_authority + }, + _ => { + false + }, + } + } + } + + impl Eq + for Constraint {} + + impl Hash + for Constraint { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + Constraint::Constraint{endorser_imids, endorser_patterns, target_imids, target_patterns, any_target, permitted_patterns, permitted_subnets, authority, } => { + Hash::hash(endorser_imids, _state); + Hash::hash(endorser_patterns, _state); + Hash::hash(target_imids, _state); + Hash::hash(target_patterns, _state); + Hash::hash(any_target, _state); + Hash::hash(permitted_patterns, _state); + Hash::hash(permitted_subnets, _state); + Hash::hash(authority, _state) + }, + } + } + } + + impl AsRef + for Constraint { + fn as_ref(&self) -> &Self { + self + } + } + + /// ../output/TrustEngine.dfy(15,5) + #[derive(Clone)] + pub enum Authz { + Authz { + source_imids: Set, + source_patterns: Set, + destination_imids: Set, + destination_patterns: Set + } + } + + impl Authz { + /// Returns a borrow of the field source_imids + pub fn source_imids(&self) -> &Set { + match self { + Authz::Authz{source_imids, source_patterns, destination_imids, destination_patterns, } => source_imids, + } + } + /// Returns a borrow of the field source_patterns + pub fn source_patterns(&self) -> &Set { + match self { + Authz::Authz{source_imids, source_patterns, destination_imids, destination_patterns, } => source_patterns, + } + } + /// Returns a borrow of the field destination_imids + pub fn destination_imids(&self) -> &Set { + match self { + Authz::Authz{source_imids, source_patterns, destination_imids, destination_patterns, } => destination_imids, + } + } + /// Returns a borrow of the field destination_patterns + pub fn destination_patterns(&self) -> &Set { + match self { + Authz::Authz{source_imids, source_patterns, destination_imids, destination_patterns, } => destination_patterns, + } + } + } + + impl Debug + for Authz { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for Authz { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + Authz::Authz{source_imids, source_patterns, destination_imids, destination_patterns, } => { + write!(_formatter, "TrustEngine.Authz.Authz(")?; + DafnyPrint::fmt_print(source_imids, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(source_patterns, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(destination_imids, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(destination_patterns, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl PartialEq + for Authz { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (Authz::Authz{source_imids, source_patterns, destination_imids, destination_patterns, }, Authz::Authz{source_imids: _2_source_imids, source_patterns: _2_source_patterns, destination_imids: _2_destination_imids, destination_patterns: _2_destination_patterns, }) => { + source_imids == _2_source_imids && source_patterns == _2_source_patterns && destination_imids == _2_destination_imids && destination_patterns == _2_destination_patterns + }, + _ => { + false + }, + } + } + } + + impl Eq + for Authz {} + + impl Hash + for Authz { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + Authz::Authz{source_imids, source_patterns, destination_imids, destination_patterns, } => { + Hash::hash(source_imids, _state); + Hash::hash(source_patterns, _state); + Hash::hash(destination_imids, _state); + Hash::hash(destination_patterns, _state) + }, + } + } + } + + impl AsRef + for Authz { + fn as_ref(&self) -> &Self { + self + } + } + + /// ../output/TrustEngine.dfy(17,5) + #[derive(Clone)] + pub enum Claim { + GrantName { + endorser: nat, + target_imids: Set, + target_patterns: Set, + name: nat + }, + GrantIp { + endorser: nat, + target_imids: Set, + target_patterns: Set, + ip: nat + }, + GrantConstraint { + endorser: nat, + target_imids: Set, + target_patterns: Set, + constraint: Rc + }, + GrantAuthz { + endorser: nat, + target_imids: Set, + target_patterns: Set, + authz: Rc + } + } + + impl Claim { + /// Gets the field endorser for all enum members which have it + pub fn endorser(&self) -> &nat { + match self { + Claim::GrantName{endorser, target_imids, target_patterns, name, } => endorser, + Claim::GrantIp{endorser, target_imids, target_patterns, ip, } => endorser, + Claim::GrantConstraint{endorser, target_imids, target_patterns, constraint, } => endorser, + Claim::GrantAuthz{endorser, target_imids, target_patterns, authz, } => endorser, + } + } + /// Gets the field target_imids for all enum members which have it + pub fn target_imids(&self) -> &Set { + match self { + Claim::GrantName{endorser, target_imids, target_patterns, name, } => target_imids, + Claim::GrantIp{endorser, target_imids, target_patterns, ip, } => target_imids, + Claim::GrantConstraint{endorser, target_imids, target_patterns, constraint, } => target_imids, + Claim::GrantAuthz{endorser, target_imids, target_patterns, authz, } => target_imids, + } + } + /// Gets the field target_patterns for all enum members which have it + pub fn target_patterns(&self) -> &Set { + match self { + Claim::GrantName{endorser, target_imids, target_patterns, name, } => target_patterns, + Claim::GrantIp{endorser, target_imids, target_patterns, ip, } => target_patterns, + Claim::GrantConstraint{endorser, target_imids, target_patterns, constraint, } => target_patterns, + Claim::GrantAuthz{endorser, target_imids, target_patterns, authz, } => target_patterns, + } + } + /// Gets the field name for all enum members which have it + pub fn name(&self) -> &nat { + match self { + Claim::GrantName{endorser, target_imids, target_patterns, name, } => name, + Claim::GrantIp{endorser, target_imids, target_patterns, ip, } => panic!("field does not exist on this variant"), + Claim::GrantConstraint{endorser, target_imids, target_patterns, constraint, } => panic!("field does not exist on this variant"), + Claim::GrantAuthz{endorser, target_imids, target_patterns, authz, } => panic!("field does not exist on this variant"), + } + } + /// Gets the field ip for all enum members which have it + pub fn ip(&self) -> &nat { + match self { + Claim::GrantName{endorser, target_imids, target_patterns, name, } => panic!("field does not exist on this variant"), + Claim::GrantIp{endorser, target_imids, target_patterns, ip, } => ip, + Claim::GrantConstraint{endorser, target_imids, target_patterns, constraint, } => panic!("field does not exist on this variant"), + Claim::GrantAuthz{endorser, target_imids, target_patterns, authz, } => panic!("field does not exist on this variant"), + } + } + /// Gets the field constraint for all enum members which have it + pub fn constraint(&self) -> &Rc { + match self { + Claim::GrantName{endorser, target_imids, target_patterns, name, } => panic!("field does not exist on this variant"), + Claim::GrantIp{endorser, target_imids, target_patterns, ip, } => panic!("field does not exist on this variant"), + Claim::GrantConstraint{endorser, target_imids, target_patterns, constraint, } => constraint, + Claim::GrantAuthz{endorser, target_imids, target_patterns, authz, } => panic!("field does not exist on this variant"), + } + } + /// Gets the field authz for all enum members which have it + pub fn authz(&self) -> &Rc { + match self { + Claim::GrantName{endorser, target_imids, target_patterns, name, } => panic!("field does not exist on this variant"), + Claim::GrantIp{endorser, target_imids, target_patterns, ip, } => panic!("field does not exist on this variant"), + Claim::GrantConstraint{endorser, target_imids, target_patterns, constraint, } => panic!("field does not exist on this variant"), + Claim::GrantAuthz{endorser, target_imids, target_patterns, authz, } => authz, + } + } + } + + impl Debug + for Claim { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for Claim { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + Claim::GrantName{endorser, target_imids, target_patterns, name, } => { + write!(_formatter, "TrustEngine.Claim.GrantName(")?; + DafnyPrint::fmt_print(endorser, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(target_imids, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(target_patterns, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(name, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + Claim::GrantIp{endorser, target_imids, target_patterns, ip, } => { + write!(_formatter, "TrustEngine.Claim.GrantIp(")?; + DafnyPrint::fmt_print(endorser, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(target_imids, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(target_patterns, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(ip, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + Claim::GrantConstraint{endorser, target_imids, target_patterns, constraint, } => { + write!(_formatter, "TrustEngine.Claim.GrantConstraint(")?; + DafnyPrint::fmt_print(endorser, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(target_imids, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(target_patterns, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(constraint, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + Claim::GrantAuthz{endorser, target_imids, target_patterns, authz, } => { + write!(_formatter, "TrustEngine.Claim.GrantAuthz(")?; + DafnyPrint::fmt_print(endorser, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(target_imids, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(target_patterns, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(authz, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl PartialEq + for Claim { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (Claim::GrantName{endorser, target_imids, target_patterns, name, }, Claim::GrantName{endorser: _2_endorser, target_imids: _2_target_imids, target_patterns: _2_target_patterns, name: _2_name, }) => { + endorser == _2_endorser && target_imids == _2_target_imids && target_patterns == _2_target_patterns && name == _2_name + }, + (Claim::GrantIp{endorser, target_imids, target_patterns, ip, }, Claim::GrantIp{endorser: _2_endorser, target_imids: _2_target_imids, target_patterns: _2_target_patterns, ip: _2_ip, }) => { + endorser == _2_endorser && target_imids == _2_target_imids && target_patterns == _2_target_patterns && ip == _2_ip + }, + (Claim::GrantConstraint{endorser, target_imids, target_patterns, constraint, }, Claim::GrantConstraint{endorser: _2_endorser, target_imids: _2_target_imids, target_patterns: _2_target_patterns, constraint: _2_constraint, }) => { + endorser == _2_endorser && target_imids == _2_target_imids && target_patterns == _2_target_patterns && constraint == _2_constraint + }, + (Claim::GrantAuthz{endorser, target_imids, target_patterns, authz, }, Claim::GrantAuthz{endorser: _2_endorser, target_imids: _2_target_imids, target_patterns: _2_target_patterns, authz: _2_authz, }) => { + endorser == _2_endorser && target_imids == _2_target_imids && target_patterns == _2_target_patterns && authz == _2_authz + }, + _ => { + false + }, + } + } + } + + impl Eq + for Claim {} + + impl Hash + for Claim { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + Claim::GrantName{endorser, target_imids, target_patterns, name, } => { + Hash::hash(endorser, _state); + Hash::hash(target_imids, _state); + Hash::hash(target_patterns, _state); + Hash::hash(name, _state) + }, + Claim::GrantIp{endorser, target_imids, target_patterns, ip, } => { + Hash::hash(endorser, _state); + Hash::hash(target_imids, _state); + Hash::hash(target_patterns, _state); + Hash::hash(ip, _state) + }, + Claim::GrantConstraint{endorser, target_imids, target_patterns, constraint, } => { + Hash::hash(endorser, _state); + Hash::hash(target_imids, _state); + Hash::hash(target_patterns, _state); + Hash::hash(constraint, _state) + }, + Claim::GrantAuthz{endorser, target_imids, target_patterns, authz, } => { + Hash::hash(endorser, _state); + Hash::hash(target_imids, _state); + Hash::hash(target_patterns, _state); + Hash::hash(authz, _state) + }, + } + } + } + + impl AsRef + for Claim { + fn as_ref(&self) -> &Self { + self + } + } + + /// ../output/TrustEngine.dfy(23,5) + #[derive(Clone)] + pub enum NameImid { + NameImid { + name: nat, + imid: nat + } + } + + impl NameImid { + /// Returns a borrow of the field name + pub fn name(&self) -> &nat { + match self { + NameImid::NameImid{name, imid, } => name, + } + } + /// Returns a borrow of the field imid + pub fn imid(&self) -> &nat { + match self { + NameImid::NameImid{name, imid, } => imid, + } + } + } + + impl Debug + for NameImid { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for NameImid { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + NameImid::NameImid{name, imid, } => { + write!(_formatter, "TrustEngine.NameImid.NameImid(")?; + DafnyPrint::fmt_print(name, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(imid, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl PartialEq + for NameImid { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (NameImid::NameImid{name, imid, }, NameImid::NameImid{name: _2_name, imid: _2_imid, }) => { + name == _2_name && imid == _2_imid + }, + _ => { + false + }, + } + } + } + + impl Eq + for NameImid {} + + impl Hash + for NameImid { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + NameImid::NameImid{name, imid, } => { + Hash::hash(name, _state); + Hash::hash(imid, _state) + }, + } + } + } + + impl AsRef + for NameImid { + fn as_ref(&self) -> &Self { + self + } + } + + /// ../output/TrustEngine.dfy(25,5) + #[derive(Clone)] + pub enum IpImid { + IpImid { + ip: nat, + imid: nat + } + } + + impl IpImid { + /// Returns a borrow of the field ip + pub fn ip(&self) -> &nat { + match self { + IpImid::IpImid{ip, imid, } => ip, + } + } + /// Returns a borrow of the field imid + pub fn imid(&self) -> &nat { + match self { + IpImid::IpImid{ip, imid, } => imid, + } + } + } + + impl Debug + for IpImid { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for IpImid { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + IpImid::IpImid{ip, imid, } => { + write!(_formatter, "TrustEngine.IpImid.IpImid(")?; + DafnyPrint::fmt_print(ip, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(imid, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl PartialEq + for IpImid { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (IpImid::IpImid{ip, imid, }, IpImid::IpImid{ip: _2_ip, imid: _2_imid, }) => { + ip == _2_ip && imid == _2_imid + }, + _ => { + false + }, + } + } + } + + impl Eq + for IpImid {} + + impl Hash + for IpImid { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + IpImid::IpImid{ip, imid, } => { + Hash::hash(ip, _state); + Hash::hash(imid, _state) + }, + } + } + } + + impl AsRef + for IpImid { + fn as_ref(&self) -> &Self { + self + } + } + + /// ../output/TrustEngine.dfy(27,5) + #[derive(Clone)] + pub enum PatName { + PatName { + pattern: nat, + name: nat + } + } + + impl PatName { + /// Returns a borrow of the field pattern + pub fn pattern(&self) -> &nat { + match self { + PatName::PatName{pattern, name, } => pattern, + } + } + /// Returns a borrow of the field name + pub fn name(&self) -> &nat { + match self { + PatName::PatName{pattern, name, } => name, + } + } + } + + impl Debug + for PatName { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for PatName { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + PatName::PatName{pattern, name, } => { + write!(_formatter, "TrustEngine.PatName.PatName(")?; + DafnyPrint::fmt_print(pattern, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(name, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl PartialEq + for PatName { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (PatName::PatName{pattern, name, }, PatName::PatName{pattern: _2_pattern, name: _2_name, }) => { + pattern == _2_pattern && name == _2_name + }, + _ => { + false + }, + } + } + } + + impl Eq + for PatName {} + + impl Hash + for PatName { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + PatName::PatName{pattern, name, } => { + Hash::hash(pattern, _state); + Hash::hash(name, _state) + }, + } + } + } + + impl AsRef + for PatName { + fn as_ref(&self) -> &Self { + self + } + } + + /// ../output/TrustEngine.dfy(29,5) + #[derive(Clone)] + pub enum SubnetIp { + SubnetIp { + subnet: nat, + ip: nat + } + } + + impl SubnetIp { + /// Returns a borrow of the field subnet + pub fn subnet(&self) -> &nat { + match self { + SubnetIp::SubnetIp{subnet, ip, } => subnet, + } + } + /// Returns a borrow of the field ip + pub fn ip(&self) -> &nat { + match self { + SubnetIp::SubnetIp{subnet, ip, } => ip, + } + } + } + + impl Debug + for SubnetIp { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for SubnetIp { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + SubnetIp::SubnetIp{subnet, ip, } => { + write!(_formatter, "TrustEngine.SubnetIp.SubnetIp(")?; + DafnyPrint::fmt_print(subnet, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(ip, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl PartialEq + for SubnetIp { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (SubnetIp::SubnetIp{subnet, ip, }, SubnetIp::SubnetIp{subnet: _2_subnet, ip: _2_ip, }) => { + subnet == _2_subnet && ip == _2_ip + }, + _ => { + false + }, + } + } + } + + impl Eq + for SubnetIp {} + + impl Hash + for SubnetIp { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + SubnetIp::SubnetIp{subnet, ip, } => { + Hash::hash(subnet, _state); + Hash::hash(ip, _state) + }, + } + } + } + + impl AsRef + for SubnetIp { + fn as_ref(&self) -> &Self { + self + } + } + + /// ../output/TrustEngine.dfy(31,5) + #[derive(Clone)] + pub enum State { + State { + my_imid: nat, + names: Set>, + ips: Set>, + constraints: Set>, + authz: Set> + } + } + + impl State { + /// Returns a borrow of the field my_imid + pub fn my_imid(&self) -> &nat { + match self { + State::State{my_imid, names, ips, constraints, authz, } => my_imid, + } + } + /// Returns a borrow of the field names + pub fn names(&self) -> &Set> { + match self { + State::State{my_imid, names, ips, constraints, authz, } => names, + } + } + /// Returns a borrow of the field ips + pub fn ips(&self) -> &Set> { + match self { + State::State{my_imid, names, ips, constraints, authz, } => ips, + } + } + /// Returns a borrow of the field constraints + pub fn constraints(&self) -> &Set> { + match self { + State::State{my_imid, names, ips, constraints, authz, } => constraints, + } + } + /// Returns a borrow of the field authz + pub fn authz(&self) -> &Set> { + match self { + State::State{my_imid, names, ips, constraints, authz, } => authz, + } + } + } + + impl Debug + for State { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for State { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + State::State{my_imid, names, ips, constraints, authz, } => { + write!(_formatter, "TrustEngine.State.State(")?; + DafnyPrint::fmt_print(my_imid, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(names, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(ips, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(constraints, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(authz, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl PartialEq + for State { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (State::State{my_imid, names, ips, constraints, authz, }, State::State{my_imid: _2_my_imid, names: _2_names, ips: _2_ips, constraints: _2_constraints, authz: _2_authz, }) => { + my_imid == _2_my_imid && names == _2_names && ips == _2_ips && constraints == _2_constraints && authz == _2_authz + }, + _ => { + false + }, + } + } + } + + impl Eq + for State {} + + impl Hash + for State { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + State::State{my_imid, names, ips, constraints, authz, } => { + Hash::hash(my_imid, _state); + Hash::hash(names, _state); + Hash::hash(ips, _state); + Hash::hash(constraints, _state); + Hash::hash(authz, _state) + }, + } + } + } + + impl AsRef + for State { + fn as_ref(&self) -> &Self { + self + } + } + + /// ../output/TrustEngine.dfy(128,5) + #[derive(Clone)] + pub enum Universe { + Universe { + names: Set>, + ips: Set>, + constraints: Set>, + authz: Set> + } + } + + impl Universe { + /// Returns a borrow of the field names + pub fn names(&self) -> &Set> { + match self { + Universe::Universe{names, ips, constraints, authz, } => names, + } + } + /// Returns a borrow of the field ips + pub fn ips(&self) -> &Set> { + match self { + Universe::Universe{names, ips, constraints, authz, } => ips, + } + } + /// Returns a borrow of the field constraints + pub fn constraints(&self) -> &Set> { + match self { + Universe::Universe{names, ips, constraints, authz, } => constraints, + } + } + /// Returns a borrow of the field authz + pub fn authz(&self) -> &Set> { + match self { + Universe::Universe{names, ips, constraints, authz, } => authz, + } + } + } + + impl Debug + for Universe { + fn fmt(&self, f: &mut Formatter) -> Result { + DafnyPrint::fmt_print(self, f, true) + } + } + + impl DafnyPrint + for Universe { + fn fmt_print(&self, _formatter: &mut Formatter, _in_seq: bool) -> std::fmt::Result { + match self { + Universe::Universe{names, ips, constraints, authz, } => { + write!(_formatter, "TrustEngine.Universe.Universe(")?; + DafnyPrint::fmt_print(names, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(ips, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(constraints, _formatter, false)?; + write!(_formatter, ", ")?; + DafnyPrint::fmt_print(authz, _formatter, false)?; + write!(_formatter, ")")?; + Ok(()) + }, + } + } + } + + impl PartialEq + for Universe { + fn eq(&self, other: &Self) -> bool { + match ( + self, + other + ) { + (Universe::Universe{names, ips, constraints, authz, }, Universe::Universe{names: _2_names, ips: _2_ips, constraints: _2_constraints, authz: _2_authz, }) => { + names == _2_names && ips == _2_ips && constraints == _2_constraints && authz == _2_authz + }, + _ => { + false + }, + } + } + } + + impl Eq + for Universe {} + + impl Hash + for Universe { + fn hash<_H: Hasher>(&self, _state: &mut _H) { + match self { + Universe::Universe{names, ips, constraints, authz, } => { + Hash::hash(names, _state); + Hash::hash(ips, _state); + Hash::hash(constraints, _state); + Hash::hash(authz, _state) + }, + } + } + } + + impl AsRef + for Universe { + fn as_ref(&self) -> &Self { + self + } + } +} \ No newline at end of file diff --git a/src/trust_engine/marshal.rs b/src/trust_engine/marshal.rs new file mode 100644 index 0000000..19e8cb3 --- /dev/null +++ b/src/trust_engine/marshal.rs @@ -0,0 +1,375 @@ +//! Translation between intermesh's types and the verified trust-engine kernel. +//! +//! The kernel (`src/trust_engine/kernel/`, generated by `veri build +//! trust_engine`) decides belief over opaque `nat` handles. This module knows +//! nothing about *running* it (see `runner`); it only translates: intern +//! intermesh's `Imid`/`Name`/`NamePattern`/`Ip`/`Subnet` to handles, explode +//! endorsements into single-fact claims, precompute the `patterns` / +//! `subnet_contains` carve-out relations (the impure glob / CIDR predicates the +//! kernel trusts), build a closed universe — and de-intern the kernel's believed +//! facts back into a `Derivation`. + +use std::collections::{BTreeMap, BTreeSet, HashMap}; +use std::hash::Hash; +use std::net::{IpAddr, Ipv4Addr}; +use std::rc::Rc; + +use ipnet::IpNet; + +use crate::authorization::Authz; +use crate::constraint::Constraint; +use crate::endor; +use crate::ident::{Name, NamePattern}; +use crate::imid::Imid; + +use super::Derivation; + +use trust_engine_kernel::TrustEngine::{ + Authz as KAuthz, Claim as KClaim, Constraint as KConstraint, DafnyInt, IpImid as KIpImid, + NameImid as KNameImid, PatName as KPatName, Set, State as KState, SubnetIp as KSubnetIp, + Universe as KUniverse, +}; + +/// Bidirectional map between a domain value and a dense `nat` handle. The kernel +/// speaks only `nat`, so each opaque type is interned to a `usize` (lowered to +/// `DafnyInt`) on the way in and resolved back on the way out. +struct Interner { + fwd: HashMap, + rev: Vec, +} + +impl Interner { + fn new() -> Self { + Interner { + fwd: HashMap::new(), + rev: Vec::new(), + } + } + + fn intern(&mut self, v: &T) -> usize { + if let Some(&id) = self.fwd.get(v) { + return id; + } + let id = self.rev.len(); + self.fwd.insert(v.clone(), id); + self.rev.push(v.clone()); + id + } + + fn resolve(&self, id: usize) -> &T { + &self.rev[id] + } +} + +/// One interner per opaque domain. +struct Interns { + imid: Interner, + name: Interner, + pattern: Interner, + ip: Interner, + subnet: Interner, +} + +fn nat(id: usize) -> DafnyInt { + DafnyInt::from_usize(id) +} + +/// Intern every element of a set into a kernel `Set`. +fn set_of(intr: &mut Interner, items: &BTreeSet) -> Set { + let ids: Vec = items.iter().map(|x| nat(intr.intern(x))).collect(); + Set::from_array(&ids) +} + +/// The five kernel arguments to `derive`, built from a set of endorsements. +pub(super) struct Inputs { + pub(super) init: Rc, + pub(super) claims: Set>, + pub(super) patterns: Set>, + pub(super) subnet_contains: Set>, + pub(super) universe: Rc, +} + +/// Holds the interning state across one kernel run, so `inputs` and `derivation` +/// agree on which handle means what. +pub(super) struct Marshaller { + interns: Interns, +} + +impl Marshaller { + pub(super) fn new() -> Self { + Marshaller { + interns: Interns { + imid: Interner::new(), + name: Interner::new(), + pattern: Interner::new(), + ip: Interner::new(), + subnet: Interner::new(), + }, + } + } + + /// Build the kernel's `derive` arguments from `bases`. + pub(super) fn inputs(&mut self, my_imid: &Imid, bases: &BTreeSet) -> Inputs { + let my = nat(self.interns.imid.intern(my_imid)); + + // The implicit self-constraint the real engine injects at derive start + // (`Derivation::derive`): self may endorse any target as any name in any + // subnet, with authority. + let self_constraint = Constraint { + endorser_imids: std::iter::once(my_imid.clone()).collect(), + any_target: true, + permitted_patterns: std::iter::once("**".parse::().unwrap()).collect(), + permitted_subnets: std::iter::once( + IpNet::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0).unwrap(), + ) + .collect(), + authority: true, + ..Default::default() + }; + let self_k = self.intern_constraint(&self_constraint); + + // Explode each base into single-fact claims, and accumulate every + // constraint / authz that could be believed (for the universe). + let mut claims: Vec> = Vec::new(); + let mut uni_constraints: Vec> = vec![self_k.clone()]; + let mut uni_authz: Vec> = Vec::new(); + + for base in bases { + let endorser = nat(self.interns.imid.intern(&base.endorser)); + let tis = set_of(&mut self.interns.imid, &base.target_imids); + let tps = set_of(&mut self.interns.pattern, &base.target_patterns); + for name in &base.names { + let n = nat(self.interns.name.intern(name)); + claims.push(Rc::new(KClaim::GrantName { + endorser: endorser.clone(), + target_imids: tis.clone(), + target_patterns: tps.clone(), + name: n, + })); + } + for ip in &base.ips { + let p = nat(self.interns.ip.intern(ip)); + claims.push(Rc::new(KClaim::GrantIp { + endorser: endorser.clone(), + target_imids: tis.clone(), + target_patterns: tps.clone(), + ip: p, + })); + } + for c in &base.constraints { + let kc = self.intern_constraint(c); + uni_constraints.push(kc.clone()); + claims.push(Rc::new(KClaim::GrantConstraint { + endorser: endorser.clone(), + target_imids: tis.clone(), + target_patterns: tps.clone(), + constraint: kc, + })); + } + for a in &base.authz { + let ka = self.intern_authz(a); + uni_authz.push(ka.clone()); + claims.push(Rc::new(KClaim::GrantAuthz { + endorser: endorser.clone(), + target_imids: tis.clone(), + target_patterns: tps.clone(), + authz: ka, + })); + } + } + + let patterns = self.build_patterns(); + let subnet_contains = self.build_subnet_contains(); + let universe = self.cartesian_universe(&uni_constraints, &uni_authz); + + let init = Rc::new(KState::State { + my_imid: my, + names: Set::new_empty(), + ips: Set::new_empty(), + constraints: Set::from_array(&vec![self_k]), + authz: Set::new_empty(), + }); + + Inputs { + init, + claims: Set::from_array(&claims), + patterns, + subnet_contains, + universe, + } + } + + /// De-intern the kernel's believed facts into a `Derivation` struct. The + /// kernel did the derivation; this only translates its `nat`-handle result + /// back into intermesh types. Fills only the belief fields the native + /// `derive` produces; `imid_to_names` / `my_authz_to` / `my_authz_from` are + /// the out-of-kernel `finalize` post-pass. + pub(super) fn deintern(&self, my_imid: &Imid, out: &KState) -> Derivation { + let mut d = Derivation { + my_imid: my_imid.clone(), + iteration: 0, + name_to_imid: BTreeMap::new(), + imid_to_names: BTreeMap::new(), + imid_to_ip: BTreeMap::new(), + my_authz_to: BTreeSet::new(), + my_authz_from: BTreeSet::new(), + my_constraints: BTreeSet::new(), + my_authz: BTreeSet::new(), + derived_at: 0, + input: BTreeSet::new(), + }; + for nm in out.names().iter() { + let name = self.interns.name.resolve(nm.name().as_usize()).clone(); + let imid = self.interns.imid.resolve(nm.imid().as_usize()).clone(); + d.name_to_imid.entry(name).or_default().insert(imid); + } + for ii in out.ips().iter() { + let ip = *self.interns.ip.resolve(ii.ip().as_usize()); + let imid = self.interns.imid.resolve(ii.imid().as_usize()).clone(); + d.imid_to_ip.entry(imid).or_default().insert(ip); + } + for k in out.constraints().iter() { + d.my_constraints.insert(self.deintern_constraint(k)); + } + for a in out.authz().iter() { + d.my_authz.insert(self.deintern_authz(a)); + } + d + } + + // ---- native -> kernel -------------------------------------------------- + + fn intern_constraint(&mut self, c: &Constraint) -> Rc { + Rc::new(KConstraint::Constraint { + endorser_imids: set_of(&mut self.interns.imid, &c.endorser_imids), + endorser_patterns: set_of(&mut self.interns.pattern, &c.endorser_patterns), + target_imids: set_of(&mut self.interns.imid, &c.target_imids), + target_patterns: set_of(&mut self.interns.pattern, &c.target_patterns), + any_target: c.any_target, + permitted_patterns: set_of(&mut self.interns.pattern, &c.permitted_patterns), + permitted_subnets: set_of(&mut self.interns.subnet, &c.permitted_subnets), + authority: c.authority, + }) + } + + fn intern_authz(&mut self, a: &Authz) -> Rc { + Rc::new(KAuthz::Authz { + source_imids: set_of(&mut self.interns.imid, &a.source_imids), + source_patterns: set_of(&mut self.interns.pattern, &a.source_patterns), + destination_imids: set_of(&mut self.interns.imid, &a.destination_imids), + destination_patterns: set_of(&mut self.interns.pattern, &a.destination_patterns), + }) + } + + // ---- kernel -> native -------------------------------------------------- + + fn imids_of(&self, s: &Set) -> BTreeSet { + s.iter() + .map(|n| self.interns.imid.resolve(n.as_usize()).clone()) + .collect() + } + + fn patterns_of(&self, s: &Set) -> BTreeSet { + s.iter() + .map(|n| self.interns.pattern.resolve(n.as_usize()).clone()) + .collect() + } + + fn deintern_constraint(&self, k: &KConstraint) -> Constraint { + Constraint { + endorser_imids: self.imids_of(k.endorser_imids()), + endorser_patterns: self.patterns_of(k.endorser_patterns()), + target_imids: self.imids_of(k.target_imids()), + target_patterns: self.patterns_of(k.target_patterns()), + any_target: *k.any_target(), + permitted_patterns: self.patterns_of(k.permitted_patterns()), + permitted_subnets: k + .permitted_subnets() + .iter() + .map(|n| *self.interns.subnet.resolve(n.as_usize())) + .collect(), + authority: *k.authority(), + } + } + + fn deintern_authz(&self, a: &KAuthz) -> Authz { + Authz { + source_imids: self.imids_of(a.source_imids()), + source_patterns: self.patterns_of(a.source_patterns()), + destination_imids: self.imids_of(a.destination_imids()), + destination_patterns: self.patterns_of(a.destination_patterns()), + } + } + + // ---- relations + universe --------------------------------------------- + + /// Tabulate the glob predicate over every (pattern, name) pair observed. + fn build_patterns(&self) -> Set> { + let mut v: Vec> = Vec::new(); + for (pid, pat) in self.interns.pattern.rev.iter().enumerate() { + for (nid, nm) in self.interns.name.rev.iter().enumerate() { + if pat.matches(nm) { + v.push(Rc::new(KPatName::PatName { + pattern: nat(pid), + name: nat(nid), + })); + } + } + } + Set::from_array(&v) + } + + /// Tabulate the CIDR predicate over every (subnet, ip) pair observed. + fn build_subnet_contains(&self) -> Set> { + let mut v: Vec> = Vec::new(); + for (sid, sn) in self.interns.subnet.rev.iter().enumerate() { + for (iid, ip) in self.interns.ip.rev.iter().enumerate() { + if sn.contains(ip) { + v.push(Rc::new(KSubnetIp::SubnetIp { + subnet: nat(sid), + ip: nat(iid), + })); + } + } + } + Set::from_array(&v) + } + + /// A closed universe = the full cartesian product: the simplest + /// over-approximation that satisfies the kernel's `fits` precondition. Names + /// and IPs are crossed with every imid (which `(name, imid)` edges actually + /// get believed is decided inside the kernel by the `grants_exact_*` upper + /// bound); constraints/authz are just the observed set, since the kernel + /// never fabricates a constraint or authz value. + fn cartesian_universe( + &self, + constraints: &[Rc], + authz: &[Rc], + ) -> Rc { + let imid_count = self.interns.imid.rev.len(); + let mut names: Vec> = Vec::new(); + for nid in 0..self.interns.name.rev.len() { + for iid in 0..imid_count { + names.push(Rc::new(KNameImid::NameImid { + name: nat(nid), + imid: nat(iid), + })); + } + } + let mut ips: Vec> = Vec::new(); + for pid in 0..self.interns.ip.rev.len() { + for iid in 0..imid_count { + ips.push(Rc::new(KIpImid::IpImid { + ip: nat(pid), + imid: nat(iid), + })); + } + } + Rc::new(KUniverse::Universe { + names: Set::from_array(&names), + ips: Set::from_array(&ips), + constraints: Set::from_iterator(constraints.iter().cloned()), + authz: Set::from_iterator(authz.iter().cloned()), + }) + } +} diff --git a/src/trust_engine/runner.rs b/src/trust_engine/runner.rs new file mode 100644 index 0000000..545ca55 --- /dev/null +++ b/src/trust_engine/runner.rs @@ -0,0 +1,72 @@ +//! Runs the verified trust-engine kernel. +//! +//! This is the orchestration `Derivation::derive` delegates to under the +//! `verified-kernel` feature: marshal the endorsements into the kernel's +//! `nat`-handle world (`marshal::Marshaller::inputs`), run the Dafny-extracted +//! `derive`, then de-intern the believed facts back into a `Derivation` +//! (`marshal::Marshaller::deintern`). The kernel does the derivation; `marshal` +//! only translates either side of it. + +use std::collections::BTreeSet; + +use crate::endor; +use crate::imid::Imid; + +use super::marshal::Marshaller; +use super::Derivation; + +use trust_engine_kernel::TrustEngine; + +/// Derive belief from `bases` using the verified kernel. Returns a `Derivation` +/// with the belief fields filled (the `finalize` post-pass runs separately, as +/// in the native path); `derive` sets `iteration` / `input` afterward. +pub(super) fn run(my_imid: &Imid, bases: &BTreeSet) -> Derivation { + let mut m = Marshaller::new(); + let inputs = m.inputs(my_imid, bases); + let out = TrustEngine::_default::derive( + &inputs.init, + &inputs.claims, + &inputs.patterns, + &inputs.subnet_contains, + &inputs.universe, + ); + m.deintern(my_imid, &out) +} + +#[cfg(test)] +mod tests { + use std::rc::Rc; + + use trust_engine_kernel::TrustEngine::{ + self, Claim, DafnyInt, PatName, Set, State, SubnetIp, Universe, + }; + + // No claims => one `round` is already a fixed point, so `derive` returns its + // input unchanged. Calling it at all proves the kernel crate links, the + // runtime `Set`/`DafnyInt`/`Rc` construction works, and the + // `!Send`/`!Sync` kernel types are fine single-threaded. + #[test] + fn derive_on_empty_input_is_identity() { + let s = Rc::new(State::State { + my_imid: DafnyInt::from(0), + names: Set::new_empty(), + ips: Set::new_empty(), + constraints: Set::new_empty(), + authz: Set::new_empty(), + }); + let u = Rc::new(Universe::Universe { + names: Set::new_empty(), + ips: Set::new_empty(), + constraints: Set::new_empty(), + authz: Set::new_empty(), + }); + let out = TrustEngine::_default::derive( + &s, + &Set::>::new_empty(), + &Set::>::new_empty(), + &Set::>::new_empty(), + &u, + ); + assert!(out == s, "no claims should leave the state unchanged"); + } +} diff --git a/xtask/src/main.rs b/xtask/src/main.rs index fe85a7f..d098e58 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -153,7 +153,17 @@ fn build_binary(sh: &Shell) -> Result { let rustflags_env = musl_rustflags_env(target); let _flags = sh.push_env(rustflags_env, "-Clink-self-contained=yes -Clinker=rust-lld"); - cmd!(sh, "cargo build --target {target} --bin intermesh").run()?; + // Optionally add cargo features via INTERMESH_FEATURES. + let feature_args: Vec = match std::env::var("INTERMESH_FEATURES") { + Ok(f) if !f.trim().is_empty() => vec!["--features".to_string(), f], + _ => Vec::new(), + }; + + cmd!( + sh, + "cargo build --target {target} {feature_args...} --bin intermesh" + ) + .run()?; let path = cargo_target_dir() .join(target)