{"id":18925106,"url":"https://github.com/lyonsyonii/akin","last_synced_at":"2025-08-08T13:20:25.746Z","repository":{"id":57481970,"uuid":"465906203","full_name":"LyonSyonII/akin","owner":"LyonSyonII","description":"Rust crate for writing repetitive code easier and faster. ","archived":false,"fork":false,"pushed_at":"2023-01-03T13:20:08.000Z","size":53,"stargazers_count":43,"open_issues_count":3,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-15T14:56:04.841Z","etag":null,"topics":["code","duplicate","duplicates","repeat","repetition","rust","rust-crate","similar","similars","simpler","write"],"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/LyonSyonII.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}},"created_at":"2022-03-03T22:34:28.000Z","updated_at":"2024-09-07T17:32:05.000Z","dependencies_parsed_at":"2023-02-01T06:16:03.956Z","dependency_job_id":null,"html_url":"https://github.com/LyonSyonII/akin","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/LyonSyonII%2Fakin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LyonSyonII%2Fakin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LyonSyonII%2Fakin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LyonSyonII%2Fakin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LyonSyonII","download_url":"https://codeload.github.com/LyonSyonII/akin/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249094937,"owners_count":21211836,"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":["code","duplicate","duplicates","repeat","repetition","rust","rust-crate","similar","similars","simpler","write"],"created_at":"2024-11-08T11:09:37.103Z","updated_at":"2025-04-15T14:56:11.767Z","avatar_url":"https://github.com/LyonSyonII.png","language":"Rust","readme":"# akin\n\u003e A zero-dependency crate for writing repetitive code easier and faster  \n\n[![Tests](https://github.com/LyonSyonII/akin/actions/workflows/rust.yml/badge.svg)](https://github.com/LyonSyonII/akin/actions/workflows/rust.yml)         [![Crates.io](https://img.shields.io/crates/v/akin)](https://crates.io/crates/akin)\n\nCheck [Syntax](#syntax) for information on how to use it.  \n\n1. [Why?](#why)\n2. [Example](#example)\n3. [Syntax](#syntax)\n4. [NONE](#none)\n5. [Joint modifier](#joint-modifier)\n6. [Zero dependencies? Really?](#zero-dependencies-really)\n\n## Why?\nI've found myself having to write a lot of repetitive code (mostly when matching against enums in parsing).  \nThe fantastic [duplicate](https://crates.io/crates/duplicate) had an unintuitive syntax for me, so I decided to make my own tool.\n\n## Example\n```rust\ntrait Sqrt {\n    fn dumb_sqrt(self) -\u003e Result\u003cf64, \u0026'static str\u003e;\n}\n\nakin! {\n    let \u0026int_type = [i64, u64];\n    let \u0026negative_check = [\n        {\n            if self \u003c 0 {\n                return Err(\"Sqrt of negative number\")\n            }\n        }, \n        NONE\n    ];\n    \n    let \u0026num = [1,     2,    3,  4];\n    let \u0026res = [1., 1.41, 1.73,  2.];\n    let \u0026branch = {\n        *num =\u003e Ok(*res),\n    };\n    \n    impl Sqrt for *int_type {\n        fn dumb_sqrt(self) -\u003e Result\u003cf64, \u0026'static str\u003e {\n            *negative_check\n            \n            match self {\n                *branch\n                _ =\u003e Err(\"Sqrt of num not in [1, 4]\")\n            }\n        }\n    }\n}\n```\nIs expanded to:\n```rust\ntrait Sqrt {\n    fn dumb_sqrt(self) -\u003e Result\u003cf64, \u0026'static str\u003e;\n}\n\nimpl Sqrt for i64 {\n    fn dumb_sqrt(self) -\u003e Result\u003cf64, \u0026'static str\u003e {\n        if self \u003c 0 {\n            return Err(\"Sqrt of negative number\")\n        }\n        \n        match self {\n            1 =\u003e Ok(1.),\n            2 =\u003e Ok(1.41),\n            3 =\u003e Ok(1.73),\n            4 =\u003e Ok(2.),\n            _ =\u003e Err(\"Sqrt of num not in [1, 4]\")\n        }\n    }\n}\n\nimpl Sqrt for u64 {\n    fn dumb_sqrt(self) -\u003e Result\u003cf64, \u0026'static str\u003e {\n        match self {\n            1 =\u003e Ok(1.),\n            2 =\u003e Ok(1.41),\n            3 =\u003e Ok(1.73),\n            4 =\u003e Ok(2.),\n            _ =\u003e Err(\"Sqrt of num not in [1, 4]\")\n        }\n    }\n}\n```\n\nThe good thing about **akin** is that it detects automatically the number of values of each variable *for each scope*, so for example \"branch\" will get copied 4 times (as \"num\" and \"res\" both have 4 values), but the main function will only be duplicated once, as all the variables it has have 2 values.\n\nCheck the [tests/](https://github.com/LyonSyonII/akin/tree/main/tests) folder of the repository for more examples.\n\n## Syntax\nThe crate only provides one macro, `akin!`.\nThe syntax is as follows:\n\nFirst, you declare the variables you'll use. \nA variable name must start with `\u0026`, as it's the only way it can differentiate between macro or real declarations.  \nAlso notice that variables end with `;`\n\n```rust\nlet \u0026variable = [v1, v2, v3, ...];\nlet \u0026variable2 = [...];\n    \nlet \u0026code = {\n    ...\n};\n```\n\nThen, when all variables have been declared, you can write the code snippet you want to duplicate.  \nThe amount of times it will be duplicated depends on the variables that are used.  \n\n```rust\nlet \u0026lhs = [1, 2, 3];\nlet \u0026rhs = [4, 5, 6];\nprintln!(\"*lhs + *rhs = {}\", *lhs + *rhs);\n```\n\nWill get expanded to:\n\n```rust\nprintln!(\"1 + 4 = {}\", 1 + 4);\nprintln!(\"2 + 5 = {}\", 2 + 5);\nprintln!(\"3 + 6 = {}\", 3 + 6);\n```\nBecause the variables `\u0026lhs` and `\u0026rhs` both have 3 values.\n\nAs you can see, `\u0026` is used to declare variables and `*` is used to \"dereference\" them to the current value.\n\nAs a matter of convenience, the range syntax is also accepted, when declaring a variable,\ne.g. `0..3` and `0..=3`, which are equivalent to `[0,1,2]` and `[0,1,2,3]` respectively.\nSo the above example could also be written like\n\n```rust\nlet \u0026lhs = 1..=3;\nlet \u0026rhs = 4..=6;\nprintln!(\"*lhs + *rhs = {}\", *lhs + *rhs);\n```\n\nPresently, only unsigned integers that can fit in `u64` are supported in ranges, i.e. ranges\nlike `-10..-1` or `'a'..'c'`, which are fine in regular Rust, aren't accepted by `akin`.\n\nIf a used variable has less values than another, the last one will be used.\n\n```rust\nakin! {\n    let \u0026v1 = [c];\n    let \u0026v2 = [a, b];\n    println!(\"*v1*v2\");\n}\n```\nExpands to\n```rust\nprintln!(\"ca\");\nprintln!(\"cb\");\n```\n\nAll code in variables must be enclosed in brackets `{...}`.\n```rust\nakin! {\n    let \u0026var = [-1, 1];\n    let \u0026code = [\n        {\n            println!(\"true\");\n        },\n        {\n            println!(\"false\");\n        }\n    ];\n    \n    if *var \u003c 0 {\n        *code\n    }\n}\n```\nWill expand to\n```rust\nif -1 \u003c 0 {\n    println!(\"true\");\n}\nif 1 \u003c 0 {\n    println!(\"false\")\n}\n```\n\nCheck the [tests/](https://github.com/LyonSyonII/akin/tree/main/tests) folder of the repository for more examples.\n\n## NONE\n`NONE` is the way you can tell `akin` to simply skip that value and not write anything.  \nIt is useful for when you want to have elements in a duplication that do not have to be in the others.\n```rust\n\nakin! {\n    let \u0026num = [1, 2, 3];\n    let \u0026code = [\n        NONE,\n        {\n            .pow(2)\n        }\n    ];\n    \n    println!(\"*num^2 = {}\", *num~u32*code);\n    // *num~u32 is necessary to ensure the type is written correctly (it would be \"1 u32\" otherwise)\n}\n```\n\n## Joint modifier\nBy default, `akin` places a space between all identifiers\n\n```rust    \nlet name = 5; // 'name' is an identifier\n    ^^^^\n```\nSometimes, this is not desirable, for example, if trying to interpolate between a function name\n```rust\nlet \u0026name = [1];\nfn _*name()...\n\n// Will get wrongly expanded because '_' is an identifier\nfn _ 1()\n```\nTo avoid it, use the joint modifier `~`, making the next identifier not to be separated.\n```rust    \nlet \u0026name = [1];\nfn _~*name()... // *name is affected by the modifier\n\n// Will get correctly expanded to\nfn _1()\n```\nInside string literals `\"...\"` it is not necessary to use the modifier, as Rust does not count them as identifiers.\n\nThis is a limitation on proc-macro parsing, so I doubt it'll be fixed soon.\n\n## Zero dependencies? Really?\nYes, this crate does not use `syn` nor `quote`, as parsing the syntax is pretty simple and both add a lot of overhead.  \nFor this reason, `akin` should not impact compile times as much as most proc-macros, try using it and see it by yourself!\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flyonsyonii%2Fakin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flyonsyonii%2Fakin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flyonsyonii%2Fakin/lists"}