All Projects → ErichDonGubler → adhesion-rs

ErichDonGubler / adhesion-rs

Licence: other
D-inspired contract programming in Rust using macros

Programming Languages

rust
11053 projects

Projects that are alternatives of or similar to adhesion-rs

contract
Contract programming for C++
Stars: ✭ 28 (-42.86%)
Mutual labels:  design-by-contracts, contracts-programming, design-by-contract
djburger
Framework for safe and maintainable web-projects.
Stars: ✭ 75 (+53.06%)
Mutual labels:  contracts-programming, design-by-contract
nim-contra
Lightweight Self-Documenting Design by Contract Programming and Security Hardened mode.
Stars: ✭ 46 (-6.12%)
Mutual labels:  contracts-programming, design-by-contract
quid-pro-quo
A contract programming library for Common Lisp in the style of Eiffel’s Design by Contract ™.
Stars: ✭ 85 (+73.47%)
Mutual labels:  design-by-contract
here-we-go
Contains hundreds of samples for learning Go.
Stars: ✭ 93 (+89.8%)
Mutual labels:  design-patterns
vala-design-patterns-for-humans
A Vala version of "Design Patterns for Humans"
Stars: ✭ 15 (-69.39%)
Mutual labels:  design-patterns
chuxiuhong-rust-patterns-zh
Rust设计模式中文翻译
Stars: ✭ 36 (-26.53%)
Mutual labels:  design-patterns
OOP-Design-Patterns
MET CS665 - OOP Design Patterns Code Examples
Stars: ✭ 74 (+51.02%)
Mutual labels:  design-patterns
DataStructures Algorithms Java
Collection of data structures and algorithms challenges that I've solved. 💤
Stars: ✭ 12 (-75.51%)
Mutual labels:  design-patterns
mvc-tree
🌳 A chronological visualization of the family of MVC patterns.
Stars: ✭ 40 (-18.37%)
Mutual labels:  design-patterns
enterprise-applications-patterns
Collection of enterprise application patterns
Stars: ✭ 17 (-65.31%)
Mutual labels:  design-patterns
php-design-patterns
Learn how to implement the most important Design Patterns into your PHP application. This project uses PHP 8.1. it has examples for each Pattern and an Article explaining how to use them step by step, their advantages, and disadvantages.
Stars: ✭ 151 (+208.16%)
Mutual labels:  design-patterns
design-patterns-for-humans-cn
Design patterns for humans 中文版 - 对设计模式超简单的解释
Stars: ✭ 2,432 (+4863.27%)
Mutual labels:  design-patterns
design-patterns-php7
Design Patterns com PHP 7: Desenvolva com as melhores soluções. Repositório com os exemplos de código do livro. Repository with the code examples in the book.
Stars: ✭ 51 (+4.08%)
Mutual labels:  design-patterns
dumb delegator
Delegator and SimpleDelegator in Ruby's stdlib are useful, but they pull in most of Kernel. This is not appropriate for many uses; for instance, delegation to Rails models.
Stars: ✭ 62 (+26.53%)
Mutual labels:  design-patterns
vala
design-patterns-for-humans in Vala (programming language)
Stars: ✭ 52 (+6.12%)
Mutual labels:  design-patterns
TestableDesignExample
Sample App to learn a testable design (Smalltalk flavored MVC)
Stars: ✭ 80 (+63.27%)
Mutual labels:  design-patterns
java-design-patterns
设计模式专题,共 23 种设计模式。GOF design patterns,implement of Java。
Stars: ✭ 32 (-34.69%)
Mutual labels:  design-patterns
ezyfox
Java library supports for reflection, generic, annotations parsing, bean management and object binding
Stars: ✭ 14 (-71.43%)
Mutual labels:  design-patterns
Kodkod
https://github.com/alirizaadiyahsi/Nucleus Web API layered architecture startup template with ASP.NET Core 2.1, EF Core 2.1 and Vue Client
Stars: ✭ 45 (-8.16%)
Mutual labels:  design-patterns

Adhesion

Linux build status Windows build status crates.io latest published version docs.rs latest published version

A set of macros for design by contract in Rust. The design of this library was inspired by D's contract programming facilities. Here's a quick example:

use std::i32;

contract! {
    fn add_one_to_odd(x: i32) -> i32 {
        post(y) {
            assert!(y - 1 == x, "reverse operation did not produce input");
        }
        body {
            x + 1
        }
        pre {
            assert!(x != i32::MAX, "cannot add one to input at max of number range");
            assert!(x % 2 != 0, "evens ain't appropriate here");
        }
    }
}

assert!(add_one_to_odd(3) == 4);
assert!(add_one_to_odd(5) == 6);
assert_that!(add_one_to_odd(2), panics);
assert_that!(add_one_to_odd(i32::MAX), panics);

In the above example, pre runs before body, and post, which has the return value of this function bound to y, runs after. We can also define checks with the double_check block, which will be checked before and after body has run:

struct Counter {
    count: u32,
    max: u32
}

contract! {
    fn increment_counter(c: &mut Counter) {
        double_check {
            assert!(c.count <= c.max, "counter max has been exceeded");
        }
        body {
            c.count += 1;
        }
    }
}

let mut counter = Counter { count: 0, max: 3 };

macro_rules! assert_incremented_eq {
    ($e: expr) => ({
        increment_counter(&mut counter);
        assert!(counter.count == $e, format!("expected counter to be {}, got {}", $e, counter.count));
    })
}

assert_incremented_eq!(1);
assert_incremented_eq!(2);
assert_incremented_eq!(3);
assert_incremented_eq!(4); // panics!

Actually, the above example can use a top-level double_check block inside of an impl block instead, so that invariants can be maintained for each method without needing to duplicate code:

struct Counter {
    count: u32,
    max: u32
}

impl Counter {
    contract! {
        double_check {
            assert!(self.count <= self.max, "counter max has been exceeded");
        }

        fn increment(&mut self) {
            body {
                self.count.checked_add();
            }
        }
    }

}

let mut counter = Counter { count: 0, max: 3 };

macro_rules! assert_incremented_eq {
    ($e: expr) => ({
        counter.increment();
        assert!(counter.count == $e, format!("expected counter to be {}, got {}", $e, counter.count));
    })
}

assert_incremented_eq!(1);
assert_incremented_eq!(2);
assert_incremented_eq!(3);
assert_incremented_eq!(4); // panics!

Nifty, right? Check out the docs if you want more detail about this crate and what you can do with it.

FAQ

Why "Adhesion"?

This library is called "Adhesion" in reference to a particular type of contract called a "contract of adhesion", also known as a "take-it-or-leave-it" contract. Assertions in programming are definitely "take it or leave it" -- if an assertion is failing, you either have to fix the conditions of the assertion, or change the assertion itself. It sounded appropriate!

Why has D's invariant been renamed to double_check?

After the v0.2.0 release, @eternaleye pointed out in this Reddit thread that technically an "invariant" connotes a strong guarantee that must be rigorously maintained between ALL operations in code. This sort of guarantee is NOT provided by the behavior D's invariant block, as demonstrated by the link that @eternaleye provided.

Semantics are important, especially in systems that attempt to introduce more rigor to software development like design by contract. For this reason, the combined pre- and post-check block that D calls invariant is called double_check in this library.

Licensing

This project is dual-licensed under your choice of the MIT license or the Apache 2.0 license.

  • Adhesion uses a modified version of components from the rust-parse-generics project. Both the original and modified versions here use the same dual license as this project.

Contributors

  • @ErichDonGubler, original author
  • @dzamlo, for providing assistance with various important features.
  • @DanielKeep, for his incredible help making it possible for generics to be parsed and used in macros generally, and for his mentoring during Adhesion's development of its features involving generics.
  • @eternaleye, for bringing some security expertise to bear and motivating the double_check divergence from D's invariant.
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].