{"id":33936772,"url":"https://github.com/nu11ptr/topo_sort","last_synced_at":"2026-04-10T10:02:33.804Z","repository":{"id":57670184,"uuid":"433824334","full_name":"nu11ptr/topo_sort","owner":"nu11ptr","description":"Cycle safe topological sort for a set of nodes and their dependencies","archived":false,"fork":false,"pushed_at":"2021-12-17T21:37:20.000Z","size":29,"stargazers_count":5,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-12-14T02:35:23.950Z","etag":null,"topics":["dependencies","dependency","rust","sort","sorting","sorting-algorithms","topological-sort"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nu11ptr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-12-01T12:48:14.000Z","updated_at":"2025-08-26T23:12:44.000Z","dependencies_parsed_at":"2022-09-26T20:40:51.495Z","dependency_job_id":null,"html_url":"https://github.com/nu11ptr/topo_sort","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/nu11ptr/topo_sort","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nu11ptr%2Ftopo_sort","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nu11ptr%2Ftopo_sort/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nu11ptr%2Ftopo_sort/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nu11ptr%2Ftopo_sort/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nu11ptr","download_url":"https://codeload.github.com/nu11ptr/topo_sort/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nu11ptr%2Ftopo_sort/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31637748,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-10T07:40:12.752Z","status":"ssl_error","status_checked_at":"2026-04-10T07:40:11.664Z","response_time":98,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["dependencies","dependency","rust","sort","sorting","sorting-algorithms","topological-sort"],"created_at":"2025-12-12T14:33:53.993Z","updated_at":"2026-04-10T10:02:33.796Z","avatar_url":"https://github.com/nu11ptr.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# topo_sort\n\n[![Crate](https://img.shields.io/crates/v/topo_sort?style=for-the-badge)](https://crates.io/crates/topo_sort)\n[![Docs](https://img.shields.io/docsrs/topo_sort?style=for-the-badge)](https://docs.rs/topo_sort)\n\nA \"cycle-safe\" topological sort for a set of nodes with dependencies in Rust.\nBasically, it allows sorting a list by its dependencies while checking for\ncycles in the graph. If a cycle is detected, a `CycleError` is returned from the\niterator (or `SortResults::Partial` is returned if using the `to/into_vec` APIs)\n.\n\nTopological sorts are used to sort the nodes of a unidirectional graph. Typical\napplications would include anything that requires dependency based sorting. For\nexample, it could be used to find the correct order of compilation dependencies,\nor it could be used to find module cycles in languages that don't allow cycles.\nThe applications are limitless.\n\n## Examples\n\n```toml\n[dependencies]\ntopo_sort = \"0.3\"\n```\n\nA basic example:\n\n```rust\nuse topo_sort::{SortResults, TopoSort};\n\nfn main() {\n    let mut topo_sort = TopoSort::with_capacity(5);\n    // read as \"C\" depends on \"A\" and \"B\"\n    topo_sort.insert(\"C\", vec![\"A\", \"B\"]);\n    topo_sort.insert(\"E\", vec![\"B\", \"C\"]);\n    topo_sort.insert(\"A\", vec![]);\n    topo_sort.insert(\"D\", vec![\"A\", \"C\", \"E\"]);\n    topo_sort.insert(\"B\", vec![\"A\"]);\n\n    match topo_sort.into_vec_nodes() {\n        SortResults::Full(nodes) =\u003e assert_eq!(vec![\"A\", \"B\", \"C\", \"E\", \"D\"], nodes),\n        SortResults::Partial(_) =\u003e panic!(\"unexpected cycle!\"),\n    }\n}\n```\n\n...or using iteration:\n\n```rust\nuse topo_sort::TopoSort;\n\nfn main() {\n    let mut topo_sort = TopoSort::with_capacity(5);\n    topo_sort.insert(\"C\", vec![\"A\", \"B\"]);\n    topo_sort.insert(\"E\", vec![\"B\", \"C\"]);\n    topo_sort.insert(\"A\", vec![]);\n    topo_sort.insert(\"D\", vec![\"A\", \"C\", \"E\"]);\n    topo_sort.insert(\"B\", vec![\"A\"]);\n\n    let mut nodes = Vec::with_capacity(5);\n    for node in \u0026topo_sort {\n        // We check for cycle errors before usage\n        match node {\n            Ok(node) =\u003e nodes.push(*node),\n            Err(_) =\u003e panic!(\"Unexpected cycle!\"),\n        }\n    }\n\n    assert_eq!(vec![\"A\", \"B\", \"C\", \"E\", \"D\"], nodes);\n}\n```\n\nCycle detection:\n\n```rust\nuse topo_sort::TopoSort;\n\nfn main() {\n    let mut topo_sort = TopoSort::with_capacity(3);\n    topo_sort.insert(1, vec![2, 3]);\n    topo_sort.insert(2, vec![3]);\n    assert_eq!(vec![2, 1], topo_sort.try_owned_vec_nodes().unwrap());\n\n    topo_sort.insert(3, vec![1]); // cycle\n    assert!(topo_sort.try_vec_nodes().is_err());\n}\n```\n\n## Features\n\n* Cycle detection - impossible to get data without handling cycle error\n    * Choose methods for retrieving \"all or nothing\" or partial data\n* Inserted nodes are never copied/cloned (unless explicitly requested\n  via `owned` methods)\n* Only requires `Eq` and `Hash` implemented on nodes\n    * There are a few optional `owned` methods that require `Clone`\n* Dependency free - only uses `std`\n* Choice of iteration or converting into `Vec`\n* Lazy sorting - sorting is initiated on iteration only\n\n## Usage\n\nUsing `TopoSort` is a basic two step process:\n\n1. Add in your nodes and dependencies to `TopoSort`\n2. Iterate over the results *OR* store them directly in a `Vec`\n\n* For step 2, there are three general ways to consume:\n    * Iteration - returns a `Result` so cycles can be detected every iteration\n    * `to/into_vec` functions - returns a `SortResults` enum with a `Vec` of\n      full (no cycle) or partial results (when cycle detected)\n    * `try_[into]_vec` functions - returns a `Vec` wrapped in a `Result` (full\n      or no results)\n\n## Algorithm\n\nThis is implemented\nusing [Kahn's algorithm](https://en.wikipedia.org/wiki/Topological_sorting).\nWhile basic caution was taken not to do anything too egregious performance-wise,\nthe author's use cases are not performance sensitive, and it has not been\noptimized. Still, the author tried to make reasonable trade offs and make it\nflexible for a variety of use cases, not just the author's.\n\n## Safety\n\nThe crate uses two tiny `unsafe` blocks which use the addresses of `HashMap`\nkeys in a new `HashMap`. This was necessary to avoid cloning inserted data on\nowned iteration by self referencing the struct. Since there is no removal in\nregular iteration (`iter()` or `for` loop using `\u0026`), this should be safe as\nthere is no chance of the data moving during borrowed iteration. During\nowned/consuming iteration (`into_iter()` or `for` without `\u0026`), we remove the\nentries as we go. If Rust's `HashMap` were to change and shrink during removals,\nthis iterator could break. If this makes you uncomfortable, simply don't use\nconsuming iteration.\n\nIt has been tested with [Miri](https://github.com/rust-lang/miri/) and passes\nall tests. (`MIRIFLAGS=-Zmiri-tag-raw-pointers cargo miri test`)\n\n## License\n\nThis project is licensed optionally under either:\n\n* Apache License, Version 2.0, (LICENSE-APACHE\n  or https://www.apache.org/licenses/LICENSE-2.0)\n* MIT license (LICENSE-MIT or https://opensource.org/licenses/MIT)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnu11ptr%2Ftopo_sort","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnu11ptr%2Ftopo_sort","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnu11ptr%2Ftopo_sort/lists"}