{"id":18560961,"url":"https://github.com/artichoke/cactusref","last_synced_at":"2025-05-16T11:06:57.344Z","repository":{"id":35531746,"uuid":"197692124","full_name":"artichoke/cactusref","owner":"artichoke","description":"🌵 Cycle-Aware Reference Counting in Rust","archived":false,"fork":false,"pushed_at":"2025-05-13T00:03:29.000Z","size":3033,"stargazers_count":148,"open_issues_count":9,"forks_count":4,"subscribers_count":5,"default_branch":"trunk","last_synced_at":"2025-05-13T01:19:51.093Z","etag":null,"topics":["artichoke","garbage-collection","garbage-collector","memory-management","reference-counting","rust","rust-crate"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/cactusref","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/artichoke.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,"zenodo":null}},"created_at":"2019-07-19T03:02:01.000Z","updated_at":"2025-05-05T16:10:39.000Z","dependencies_parsed_at":"2023-12-24T04:30:04.102Z","dependency_job_id":"fafb79b8-56ce-4b19-9749-898a95a1ac9c","html_url":"https://github.com/artichoke/cactusref","commit_stats":{"total_commits":424,"total_committers":3,"mean_commits":"141.33333333333334","dds":0.2264150943396226,"last_synced_commit":"3d7df4b3f3132ff0b4853e60aadf5595ad813561"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artichoke%2Fcactusref","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artichoke%2Fcactusref/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artichoke%2Fcactusref/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artichoke%2Fcactusref/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/artichoke","download_url":"https://codeload.github.com/artichoke/cactusref/tar.gz/refs/heads/trunk","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254518383,"owners_count":22084374,"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":["artichoke","garbage-collection","garbage-collector","memory-management","reference-counting","rust","rust-crate"],"created_at":"2024-11-06T22:05:18.380Z","updated_at":"2025-05-16T11:06:52.329Z","avatar_url":"https://github.com/artichoke.png","language":"Rust","readme":"# CactusRef\n\n[![GitHub Actions](https://github.com/artichoke/cactusref/workflows/CI/badge.svg)](https://github.com/artichoke/cactusref/actions)\n[![Discord](https://img.shields.io/discord/607683947496734760)](https://discord.gg/QCe2tp2)\n[![Twitter](https://img.shields.io/twitter/follow/artichokeruby?label=Follow\u0026style=social)](https://twitter.com/artichokeruby)\n\u003cbr\u003e\n[![Crate](https://img.shields.io/crates/v/cactusref.svg)](https://crates.io/crates/cactusref)\n[![API](https://docs.rs/cactusref/badge.svg)](https://docs.rs/cactusref)\n[![API trunk](https://img.shields.io/badge/docs-trunk-blue.svg)](https://artichoke.github.io/cactusref/cactusref/)\n\nSingle-threaded, cycle-aware, reference-counting pointers. 'Rc' stands for\n'Reference Counted'.\n\n\u003e What if, hear me out, we put a hash map in a smart pointer?\n\nCactusRef is a single-threaded, reference-counted smart pointer that can\ndeallocate cycles without having to resort to weak pointers. [`Rc`][std-rc] from\n`std` can be difficult to work with because creating a cycle of `Rc`s will\nresult in a memory leak.\n\n[std-rc]: https://doc.rust-lang.org/stable/std/rc/struct.Rc.html\n\nCactusRef is a near drop-in replacement for `std::rc::Rc` which introduces\nadditional APIs for bookkeeping ownership relationships in a graph of `Rc`s.\n\nCombining CactusRef's [adoption APIs] for tracking links in the object graph and\ndriving garbage collection with Rust's [drop glue] implements a kind of tracing\ngarbage collector. Graphs of CactusRefs detect cycles local to the graph of\nconnected CactusRefs and do not need to scan the whole heap as is [typically\nrequired][rust-tour-tracing-gc] in a tracing garbage collector.\n\nCycles of CactusRefs are deterministically collected and deallocated when they\nare no longer reachable from outside of the cycle.\n\n[adoption apis]:\n  https://artichoke.github.io/cactusref/cactusref/trait.Adopt.html\n[drop glue]: https://doc.rust-lang.org/nightly/reference/destructors.html\n[rust-tour-tracing-gc]:\n  https://manishearth.github.io/blog/2021/04/05/a-tour-of-safe-tracing-gc-designs-in-rust/\n\n## Self-referential Data Structures\n\nCactusRef can be used to implement [self-referential data structures] such as a\ndoubly-linked list without using weak references.\n\n[self-referential data structures]:\n  https://artichoke.github.io/cactusref/cactusref/implementing_self_referential_data_structures/index.html\n\n## Usage\n\nAdd this to your `Cargo.toml`:\n\n```toml\n[dependencies]\ncactusref = \"0.5.0\"\n```\n\nCactusRef is mostly a drop-in replacement for `std::rc::Rc`, which can be used\nlike:\n\n```rust\nuse cactusref::Rc;\n\nlet node = Rc::new(123_i32);\nlet another = Rc::clone(\u0026node);\nassert_eq!(Rc::strong_count(\u0026another), 2);\n\nlet weak = Rc::downgrade(\u0026node);\nassert!(weak.upgrade().is_some());\n```\n\nOr start making self-referential data structures like:\n\n```rust\nuse std::cell::RefCell;\nuse cactusref::{Adopt, Rc};\n\nstruct Node {\n    next: Option\u003cRc\u003cRefCell\u003cNode\u003e\u003e\u003e,\n    data: i32,\n}\n\nlet left = Node { next: None, data: 123 };\nlet left = Rc::new(RefCell::new(left));\n\nlet right = Node { next: Some(Rc::clone(\u0026left)), data: 456 };\nlet right = Rc::new(RefCell::new(right));\n\nunsafe {\n    // bookkeep that `right` has added an owning ref to `left`.\n    Rc::adopt_unchecked(\u0026right, \u0026left);\n}\n\nleft.borrow_mut().next = Some(Rc::clone(\u0026right));\n\nunsafe {\n    // bookkeep that `left` has added an owning ref to `right`.\n    Rc::adopt_unchecked(\u0026left, \u0026right);\n}\n\nlet mut node = Rc::clone(\u0026left);\n// this loop will print:\n//\n// \u003e traversing ring and found node with data = 123\n// \u003e traversing ring and found node with data = 456\n// \u003e traversing ring and found node with data = 123\n// \u003e traversing ring and found node with data = 456\n// \u003e traversing ring and found node with data = 123\nfor _ in 0..5 {\n    println!(\"traversing ring and found node with data = {}\", node.borrow().data);\n    let next = if let Some(ref next) = node.borrow().next {\n        Rc::clone(next)\n    } else {\n        break;\n    };\n    node = next;\n}\nassert_eq!(Rc::strong_count(\u0026node), 3);\ndrop(node);\n\ndrop(left);\ndrop(right);\n// All members of the ring are garbage collected and deallocated.\n```\n\n## Maturity\n\nCactusRef is experimental. This crate has several limitations:\n\n- CactusRef is nightly only.\n- Cycle detection requires [unsafe code][adopt-api] to use.\n\nCactusRef is a non-trivial extension to `std::rc::Rc` and has not been proven to\nbe safe. Although CactusRef makes a best effort to abort the program if it\ndetects a dangling `Rc`, this crate may be unsound.\n\n[adopt-api]: https://docs.rs/cactusref/*/cactusref/trait.Adopt.html\n\n## `no_std`\n\nCactusRef is `no_std` compatible with an optional and enabled by default\ndependency on `std`. CactusRef depends on the [`alloc`] crate.\n\n[`alloc`]: https://doc.rust-lang.org/alloc/\n\n## Crate features\n\nAll features are enabled by default.\n\n- **std** - Enable linking to the [Rust Standard Library]. Enabling this feature\n  adds [`Error`] implementations to error types in this crate.\n\n[rust standard library]: https://doc.rust-lang.org/nightly/std/\n[`error`]: https://doc.rust-lang.org/nightly/std/error/trait.Error.html\n\n## License\n\nCactusRef is licensed with the [MIT License](LICENSE) (c) Ryan Lopopolo.\n\nCactusRef is derived from `Rc` in the Rust standard library @\n[`f586d79d`][alloc-rc-snapshot] which is dual licensed with the [MIT\nLicense][rust-mit-license] and [Apache 2.0 License][rust-apache2-license].\n\n[alloc-rc-snapshot]:\n  https://github.com/rust-lang/rust/blob/f586d79d183d144e0cbf519e29247f36670e2076/library/alloc/src/rc.rs\n[rust-mit-license]:\n  https://github.com/rust-lang/rust/blob/f586d79d183d144e0cbf519e29247f36670e2076/LICENSE-MIT\n[rust-apache2-license]:\n  https://github.com/rust-lang/rust/blob/f586d79d183d144e0cbf519e29247f36670e2076/LICENSE-APACHE\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fartichoke%2Fcactusref","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fartichoke%2Fcactusref","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fartichoke%2Fcactusref/lists"}