{"id":26601369,"url":"https://github.com/calebwin/rep","last_synced_at":"2025-08-13T06:06:29.875Z","repository":{"id":35832694,"uuid":"219446758","full_name":"calebwin/rep","owner":"calebwin","description":"enforce representation/class invariants in your Rust data structures","archived":false,"fork":false,"pushed_at":"2023-02-11T07:30:14.000Z","size":54651,"stargazers_count":12,"open_issues_count":3,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-23T18:50:53.189Z","etag":null,"topics":["invariants","oop","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/calebwin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-11-04T07:57:07.000Z","updated_at":"2024-11-18T18:45:49.000Z","dependencies_parsed_at":"2025-03-23T18:49:55.191Z","dependency_job_id":null,"html_url":"https://github.com/calebwin/rep","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/calebwin%2Frep","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/calebwin%2Frep/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/calebwin%2Frep/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/calebwin%2Frep/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/calebwin","download_url":"https://codeload.github.com/calebwin/rep/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248067776,"owners_count":21042354,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["invariants","oop","rust"],"created_at":"2025-03-23T18:39:35.117Z","updated_at":"2025-04-09T16:34:11.474Z","avatar_url":"https://github.com/calebwin.png","language":"Rust","readme":"# `rep`\n[![](http://meritbadge.herokuapp.com/rep)](https://crates.io/crates/rep)\n[![](https://docs.rs/rep/badge.svg)](https://docs.rs/rep)\n\n`rep` is a tiny utility that lets you easily enforce [representation/class invariants](https://en.wikipedia.org/wiki/Class_invariant) throughout your Rust data structures.\n\nRepresentation invariants are logical assertions that must hold true for every mutation of your data structure. For example, in your GIS application, you may have the following rep invariant for a `LatLong`.\n```rust\nself.lat \u003e= -90.0 \u0026\u0026 self.lat \u003c= 90 \u0026\u0026 self.long \u003e= -180.0 \u0026\u0026 self.long \u003c= 180\n```\n\nEnforcing representation invariants is easy with `rep`. Adding invariants to your data structures is just 2 easy steps.\n1. Define a correct representation (by implementing `CheckRep` either manually or with a macro)\n2. Insert runtime checks (either manually or with a macro)\n\n# some examples\n\nWe can start off with a simple data structure.\n```rust\nuse rep::*;\n\npub struct Line {\n    x1: i32,\n    y1: i32,\n    x2: i32,\n    y2: i32\n}\n```\nThe `CheckRep` trait can be implemented. This serves as a definition of correct representation.\n```rust\nimpl CheckRep for Line {\n    fn is_correct(\u0026self) -\u003e bool {\n        self.x1 != self.x2 \u0026\u0026 self.y1 != self.y2\n    }\n}\n```\nNow we can use the `#[check_rep]` macro to automatically insert calls to `check_rep` at start and end of all methods that are `pub` and mutate `\u0026mut self`. We can also manually make calls to `check_rep` wherever we so desire.\n```rust\n#[check_rep] // \u003c-- this inserts calls to check_rep at start and end of move_by\nimpl Line {\n    pub fn new() -\u003e Self {\n        let new_line = Self {\n            x1: -1,\n            y1: -1,\n            x1: 1,\n            y1: 1\n        };\n        \n        new_line.check_rep();\n        new_line\n    }\n    \n    pub fn move_by(\u0026mut self, x: i32, y: i32) {\n        self.x1 += x;\n        self.x2 += x;\n        self.y1 += y;\n        self.y2 += y;\n    }\n}\n```\n\n# some more examples\nFor simple representations, we can even derive an implementation of `CheckRep`.\n```rust\n#[derive(CheckRep)]\nstruct Circle {\n    x: i32,\n    y: i32,\n    #[rep(assert_gt = 0)]\n    #[rep(assert_le = 2048)]\n    r: i32,\n}\n```\n```rust\nstruct Parser {\n    #[rep(assert_default)]\n    unclosed_delims: (usize, usize, usize) // this is representing (parens, braces, brackets)\n}\n```\n\nWe can recursively check representation and use custom functions per field.\n```rust\nfn is_health_valid(h: u32) -\u003e bool {\n    h \u003e 0 \u0026\u0026 h \u003c 100\n}\n\n#[derive(CheckRep)]\nstruct Player {\n    #[rep(check)]\n    position: Point,\n    #[rep(assert_with = \"is_health_valid\")]\n    health: u32\n}\n```\n\nMore advanced rep-checking can be done through custom checking.\n```rust\nfn is_health_valid(h: u32) -\u003e bool {\n    h \u003e 0 \u0026\u0026 h \u003c 100\n}\n\n#[derive(CheckRep)]\nstruct Player {\n    #[rep(use_custom)]  // indicates that custom code should be used\n    #[rep(check)]\n    position: Point,\n    #[rep(assert_with = \"is_health_valid\")]\n    health: u32\n}\n\nimpl CustomCheckRep for Line {\n    fn c_correctness(\u0026self) -\u003e Result\u003c(), Vec\u003cString\u003e\u003e {\n        let mut errors = vec![];\n        if self.x2 != self.y2 {\n            errors.push(String::from(\"self.x2 must equal self.y2\"));\n        }\n\n        if errors.len() == 0 { Ok(()) } else { Err(errors) }\n    }\n}\n```\n```rust\nstruct Player {\n    position: Point,\n    health: u32\n}\n\nimpl CheckRep for Player {\n    fn correctness(\u0026self) -\u003e Result\u003c(), Vec\u003cString\u003e\u003e {\n        let mut errors = vec![];\n        // your code here...\n        if errors.len() == 0 { Ok(()) } else { Err(errors) }\n    }\n}\n```\n\nOnce `CheckRep` is implemented, you may use it with the `#[check_rep`, `#[require_rep`, and `#[check_rep` macros.\n```rust\n// this adds `check_rep` at start and end of all public mutating methods\n#[check_rep]\nimpl Device {\n    pub fn turn_on(\u0026mut self) {}\n    // require_rep, ensure_rep, check_rep add to start, end, start and end respectively\n    #[require_rep]\n    pub fn get_voltage(\u0026mut self, p: Position) {}\n    #[ensure_rep]\n    pub fn actuate(\u0026mut self, p: Position, v: Voltage) {}\n    #[check_rep]\n    fn do_something(\u0026self) {}\n}\n```\n\nIf a logger is present invariant violation will be logged instead of panicked.\n\n# usage\n\nJust add the following to your `Cargo.toml` file.\n```toml\n[dependencies]\nrep = \"0.3.0\"\n```\n\nThen, in your module.\n```rust\nuse rep::*;\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcalebwin%2Frep","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcalebwin%2Frep","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcalebwin%2Frep/lists"}