{"id":28085634,"url":"https://github.com/voltairenoir/chained","last_synced_at":"2025-05-13T10:40:13.607Z","repository":{"id":65924178,"uuid":"588997149","full_name":"VoltaireNoir/chained","owner":"VoltaireNoir","description":"A Rust library for lazily chaining functions","archived":false,"fork":false,"pushed_at":"2024-01-15T17:09:50.000Z","size":50,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-28T14:00:34.445Z","etag":null,"topics":["chaining","functional-programming","lazy-evaluation","library","pipeline","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/VoltaireNoir.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}},"created_at":"2023-01-14T18:18:40.000Z","updated_at":"2024-10-08T13:30:48.000Z","dependencies_parsed_at":"2023-03-09T10:45:11.982Z","dependency_job_id":null,"html_url":"https://github.com/VoltaireNoir/chained","commit_stats":{"total_commits":39,"total_committers":1,"mean_commits":39.0,"dds":0.0,"last_synced_commit":"360bd533f438fac434e3914f44a3c715951c0302"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VoltaireNoir%2Fchained","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VoltaireNoir%2Fchained/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VoltaireNoir%2Fchained/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VoltaireNoir%2Fchained/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/VoltaireNoir","download_url":"https://codeload.github.com/VoltaireNoir/chained/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253924624,"owners_count":21985147,"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":["chaining","functional-programming","lazy-evaluation","library","pipeline","rust"],"created_at":"2025-05-13T10:40:12.728Z","updated_at":"2025-05-13T10:40:13.569Z","avatar_url":"https://github.com/VoltaireNoir.png","language":"Rust","readme":"\u003cdiv align=\"center\"\u003e\n\n![](chained.png)\n\n[![Rust](https://github.com/VoltaireNoir/chained/actions/workflows/rust.yml/badge.svg)](https://github.com/VoltaireNoir/chained/actions/workflows/rust.yml) [![](https://img.shields.io/crates/l/chained)](https://github.com/VoltaireNoir/chained/blob/main/LICENSE) [![](https://img.shields.io/crates/d/chained)](https://crates.io/crates/chained) [![](https://img.shields.io/crates/v/chained)](https://crates.io/crates/chained)\n\n\u003c/div\u003e\n\n## A Rust library for lazily chaining functions\nThe core data types and traits are modeled after Rust's [iterator](https://doc.rust-lang.org/std/iter/trait.Iterator.html) trait and its [map](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.map) method. But instead of working with collections, the traits and data types in this crate are designed to work with single values. Just like iterators in Rust, chains are also **lazy** by default.\n\n| :exclamation:  Chained is currently experimental. Future updates might bring breaking changes   |\n|----------------------------------------------------------------------------------------------------|\n\n\u003e This crate is inspired by both [pipe-trait](https://crates.io/crates/pipe-trait) and [pipeline](https://crates.io/crates/pipeline) crates.\n\u003e If you do not require lazy evaluation and just want a simple way to chain function calls or method calls, the aforementioned crates might serve you better.\n\n## Usage Examples\n```rust\nuse chained::*;\n\nuse std::{env, fmt::Display};\n\nfn main() {\n    let count_chars = |s: String| s.chars().count();\n    \n    fn print_count(count: impl Display) {\n        println!(\"Args have a total of {count} chars\");\n    }\n\n    // Chaining function calls with regular method syntax\n    env::args()\n        .collect::\u003cString\u003e()\n        .into_chained(count_chars) // Owns value, chains the given Fn/Closure and returns a Chain type\n        .chain(print_count) // Now you can call chain to add more Fns/Closures \n        .eval(); // Everything is evaluated only after eval() is called\n\n    // Writing the same code more concisely using the macro\n    // Note: `\u003e\u003e` in the beginning tells the macro to call eval() at the end of the chain\n    chained!(\u003e\u003e env::args().collect::\u003cString\u003e()\n             =\u003e count_chars\n             =\u003e print_count\n    );\n    // You can also use commas as separators in the macro\n    // This produces the same code as above\n    chained!(\u003e\u003e env::args().collect::\u003cString\u003e(), count_chars, print_count);\n\n    // Making use of lazy evaluation\n    // Note: Since '\u003e\u003e' is not specified in the macro, eval() is not automatically called on this chain\n    let lazy = chained!(env::args().collect::\u003cString\u003e(), count_chars);\n    let still_lazy = squared_sqrt(lazy); // Take a look at the fn defined below\n    // All chained functions are evaluated only after eval() is called\n    still_lazy.chain(|x| println!(\"{x}\")).eval();\n}\n\n// Use impl Chained just like you'd use impl Iterator\nfn squared_sqrt(x: impl Chained\u003cItem = usize\u003e) -\u003e impl Chained\u003cItem = f32\u003e {\n    let squared = |x: usize| x.pow(2);\n    let sqrt = |x| (x as f32).sqrt();\n    x.chain(squared).chain(sqrt)\n}\n```\n\n## A note on object safety\nWhile the *Chained* trait appears to be [object safe](https://doc.rust-lang.org/reference/items/traits.html#object-safety) on the surface, as you can turn an existing type that implements the *Chained* trait into a trait object, but any chain that is turned into a trait object will be rendered useless as you cannot call either `Chained::chain` or `Chained::eval` on them.\n\nRust's Iterator map method, however, works on trait objects even if it requires `Self` to be `Sized`. This is made possible by re-implementing the Iterator trait on `Box\u003cI\u003e` and `\u0026mut I` where `I: Iterator + ?Sized`.\nThis works because the Iterator's most important method `next()` is object safe, as it takes `\u0026mut self` and returns `Option\u003cSelf::Item\u003e`.\n*Chained*, on the other hand, takes ownership of 'self' in both its methods which stops us from using such workarounds.\n\nMaking *Chained* object safe would require significant API changes, and I'm not sure if it's worth it. But I'm very much open to suggestions if the users of this library (if there will be any) deem that trait safety is important. Feel free to open an issue if you have a suggestion or create a PR if you'd like to help solve this directly through collaboration.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvoltairenoir%2Fchained","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvoltairenoir%2Fchained","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvoltairenoir%2Fchained/lists"}