{"id":25650032,"url":"https://github.com/itsjunetime/kathy","last_synced_at":"2025-04-15T18:32:39.182Z","repository":{"id":251634685,"uuid":"837787322","full_name":"itsjunetime/kathy","owner":"itsjunetime","description":"Compile-time swift-style keypaths for Rust ","archived":false,"fork":false,"pushed_at":"2025-03-10T15:08:06.000Z","size":34,"stargazers_count":20,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-28T23:34:29.209Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/itsjunetime.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2024-08-04T03:15:17.000Z","updated_at":"2025-03-25T12:44:36.000Z","dependencies_parsed_at":null,"dependency_job_id":"884ae16d-225e-4d8f-a8cb-606e2073b369","html_url":"https://github.com/itsjunetime/kathy","commit_stats":null,"previous_names":["itsjunetime/kathy"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itsjunetime%2Fkathy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itsjunetime%2Fkathy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itsjunetime%2Fkathy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itsjunetime%2Fkathy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/itsjunetime","download_url":"https://codeload.github.com/itsjunetime/kathy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249129016,"owners_count":21217268,"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":[],"created_at":"2025-02-23T14:37:31.201Z","updated_at":"2025-04-15T18:32:39.157Z","avatar_url":"https://github.com/itsjunetime.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# kathy\n\nConst-evaluated, zero-cost, very simple keypath functionality for rust.\n\nRequires nightly and `env RUSTFLAGS=\"-Znext-solver=globally\"` to work and use correctly :)\n\n## 0 runtime cost\n\nLet's take this simply example of a struct that implements `kathy::KeyPathIndexable` (the trait that makes this all work), and modify it via `IndexMut` (which the `Keyable` macro implements for you):\n\n```rust\nuse kathy::Keyable;\nuse std::ops::IndexMut;\n\n#[derive(Keyable)]\nstruct Person {\n\tage: u16\n};\n\nfn main() {\n\tstd::hint::black_box(modify(\n\t\tPerson { age: 40 },\n\t\tPerson::age,\n\t\t500\n\t));\n}\n\n#[inline(never)]\nfn modify\u003cKP, F\u003e(person: \u0026mut Person, path: KP, field: F)\nwhere\n\tPerson: IndexMut\u003cKP, Output = F\u003e\n{\n\tperson[path] = field;\n}\n```\n\nNow, to see what this actually generates, let's run it through [`cargo-show-asm`](https://crates.io/crates/cargo-show-asm) to see what this generates:\n\n```shell\n$ RUSTFLAGS=\"-Znext-solver=globally\" cargo +nightly asm demo::modify\n.section .text.demo::modify,\"ax\",@progbits\n\t.p2align\t2\n\t.type\tdemo::modify,@function\ndemo::modify:\n\t.cfi_startproc\n\tmov w8, #5\n\tstrh w8, [x0, #32]\n\tret\n```\n\nWith no optimizations enabled, doing only the bare minimum to ensure nothing is inlined *too* aggressively, (and assuming this is the only monomorphization of the requested fn) we get an extremely simple, basically transparent, implementation of the function.\n\nThere is no runtime checking or processing - everything is completely transparent and exists only as types at compile-time.\n\nAnd this works at arbitrary nested depths as well, even including working with `usize`-based keypaths/indices. For example:\n\n```rust\n// create a keypath to the `people` field of the `Family` struct\nlet height_kp = Family::people\n\t// extend that keypath into the first item inside `people`\n\t.idx::\u003c0\u003e()\n\t// extend that kp into the `dimensions` field of the first person\n\t.kp::\u003c\"dimensions\"\u003e()\n\t// and finally finish the keypath off by telling it to retrieve the height.\n\t.kp::\u003c\"height\"\u003e();\n```\n\n## usage\n\nThe main building block of this crate is the [`Keyable`] derive macro - this implements [`std::ops::Index`](https://doc.rust-lang.org/std/ops/trait.Index.html) and [`std::ops::IndexMut`](https://doc.rust-lang.org/std/ops/trait.IndexMut.html) traits for all types which it is used on (along with a few other things).\n\nThe specific types which `Keyable`-derived structs can be `Index`ed by, however, are unimportant. They're increasingly annoying to name the more nested they get, and are the most likely part of this library to change from version to version.\n\nThe way to create these Index types, however, is by using the named helpers that are provided by the `Keyable` macro. For example, in the first example up above, a `Person::age` constant was generated by the macro, which was then used to index into a `Person`.\n\nThese keypaths can then be extended by two methods:\n1. `fn kp\u003cconst FIELD: \u0026'static str\u003e() -\u003e _`, which takes no arguments and uses the single generic argument, a const `\u0026'static str`, to create another, nested, keypath.\n2. `fn idx\u003cconst I: usize\u003e() -\u003e _`, which also takes no arguments ans uses the single generic argument, a const `usize`, to create the nested keypath.\n\nDue to the way this API works, all information about which field or index is being accessed is encoded at the type level, and every `KeyPath`-adjacent type in `kathy` is 0-sized.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fitsjunetime%2Fkathy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fitsjunetime%2Fkathy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fitsjunetime%2Fkathy/lists"}