{"id":21986028,"url":"https://github.com/tamschi/pinus","last_synced_at":"2025-03-23T02:17:45.680Z","repository":{"id":37892729,"uuid":"404885421","full_name":"Tamschi/pinus","owner":"Tamschi","description":"A prickly BTreeMap.","archived":false,"fork":false,"pushed_at":"2023-01-17T22:17:57.000Z","size":132,"stargazers_count":0,"open_issues_count":17,"forks_count":1,"subscribers_count":3,"default_branch":"develop","last_synced_at":"2025-03-01T22:55:13.936Z","etag":null,"topics":["data-structures","hacktoberfest","pinning","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Tamschi.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE-APACHE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":"SECURITY.md","support":null},"funding":{"github":"Tamschi"}},"created_at":"2021-09-09T22:22:10.000Z","updated_at":"2024-12-13T20:22:25.000Z","dependencies_parsed_at":"2023-02-04T19:30:42.610Z","dependency_job_id":null,"html_url":"https://github.com/Tamschi/pinus","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":"Tamschi/rust-template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tamschi%2Fpinus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tamschi%2Fpinus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tamschi%2Fpinus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tamschi%2Fpinus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Tamschi","download_url":"https://codeload.github.com/Tamschi/pinus/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245044577,"owners_count":20551903,"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":["data-structures","hacktoberfest","pinning","rust"],"created_at":"2024-11-29T18:16:50.881Z","updated_at":"2025-03-23T02:17:45.655Z","avatar_url":"https://github.com/Tamschi.png","language":"Rust","funding_links":["https://github.com/sponsors/Tamschi"],"categories":[],"sub_categories":[],"readme":"# pinus\n\n[![Lib.rs](https://img.shields.io/badge/Lib.rs-*-84f)](https://lib.rs/crates/pinus)\n[![Crates.io](https://img.shields.io/crates/v/pinus)](https://crates.io/crates/pinus)\n[![Docs.rs](https://docs.rs/pinus/badge.svg)](https://docs.rs/pinus)\n\n![Rust 1.55](https://img.shields.io/static/v1?logo=Rust\u0026label=\u0026message=1.55\u0026color=grey)\n[![CI](https://github.com/Tamschi/pinus/workflows/CI/badge.svg?branch=develop)](https://github.com/Tamschi/pinus/actions?query=workflow%3ACI+branch%3Adevelop)\n![Crates.io - License](https://img.shields.io/crates/l/pinus/0.0.4)\n\n[![GitHub](https://img.shields.io/static/v1?logo=GitHub\u0026label=\u0026message=%20\u0026color=grey)](https://github.com/Tamschi/pinus)\n[![open issues](https://img.shields.io/github/issues-raw/Tamschi/pinus)](https://github.com/Tamschi/pinus/issues)\n[![open pull requests](https://img.shields.io/github/issues-pr-raw/Tamschi/pinus)](https://github.com/Tamschi/pinus/pulls)\n[![good first issues](https://img.shields.io/github/issues-raw/Tamschi/pinus/good%20first%20issue?label=good+first+issues)](https://github.com/Tamschi/pinus/contribute)\n\n[![crev reviews](https://web.crev.dev/rust-reviews/badge/crev_count/pinus.svg)](https://web.crev.dev/rust-reviews/crate/pinus/)\n\nA prickly BTreeMap.\n\n- You can insert through shared references and values are pin-projected.\n- You can remove keys and drop entries through exclusive references.\n- You can remove values through exclusive references until the `PineMap` is pinned.\n\n[This][this-is-fine] container API [is fine][this-is-fine] ☕🐕,\nbut it's still fully usable without directly referencing that crate.\n\n[this-is-fine]: https://crates.io/crates/this-is-fine\n\nThis crate goes together well with [fruit-salad](https://crates.io/crates/fruit-salad) 🥗\n\n\u003c!-- markdownlint-disable heading-increment no-trailing-punctuation --\u003e\n\n### Help wanted!\n\n\u003c!-- markdownlint-enable heading-increment no-trailing-punctuation --\u003e\n\nI need only a fairly barebones implementation and not necessarily optimized version of this data structure for my own project(s),\nbut am committed to maintaining it into shape if there's interest.\n\nFollow the \"good first issues\" badge above for starting points!\n\nNote that the crate uses unsafe code very frequently, so you should be at least somewhat comfortable with ensuring soundness manually. Code reviews are also highly appreciated, both within and outside of this regard.\n\n## Installation\n\nPlease use [cargo-edit](https://crates.io/crates/cargo-edit) to always add the latest version of this library:\n\n```cmd\ncargo add pinus\n```\n\n## Examples\n\n### Homogeneous Map\n\n```rust\nuse pinus::{prelude::*, sync::PineMap};\nuse std::{convert::Infallible, pin::Pin};\nuse this_is_fine::prelude::*;\n\n// `PineMap` is interior-mutable, so either is useful:\nlet map = PineMap::new();\nlet mut mut_map = PineMap::new();\n\n\n// Get parallel shared references by inserting like this:\nlet a: \u0026String = map.insert(\"Hello!\", \"Hello!\".to_string())\n  .unwrap(/* Your data back if the entry already existed. */);\nlet b: \u0026String = map.insert_with(\"Hello again!\", |k| k.to_string())\n  .map_err(|(key, _factory)| key).unwrap();\nlet c: \u0026String = map.try_insert_with::\u003c_, Infallible\u003e(\"Hello once again!\", |k| Ok(k.to_string()))\n  .unwrap(/* Error from factory. */)\n  .map_err(|(key, _factory)| key).unwrap();\n\nlet a2: \u0026String = map.get(\"Hello!\").unwrap();\n\nlet _ = (a, a2, b, c);\n\n\n// Get exclusive references like this (also with or without factory):\nlet mut_a: \u0026mut String = mut_map.insert_with_mut(\"Hi!\", |k| k.to_string())\n  .map_err(|(key, _factory)| key).unwrap();\n\nlet mut_a2: \u0026mut String = mut_map.get_mut(\"Hi!\").unwrap();\n\n// The `…_mut` methods are actually faster, but their results can't be held onto at once:\n// let _ = (mut_a, mut_a2); // \"error[E0499]: cannot borrow `mut_map` as mutable more than once at a time\"\n\n\n// Remove entries like this:\nmut_map.clear();\nlet _: Option\u003c(\u0026str, String)\u003e = mut_map.remove_pair(\"A\");\nlet _: Option\u003cString\u003e = mut_map.remove_value(\"B\");\nlet _: Option\u003c\u0026str\u003e = mut_map.remove_key(\"C\");\nlet _: bool = mut_map.drop_entry(\"D\");\n\n\n/////\n\n\n// Now on to part 2, value pinning:\nlet mut map: Pin\u003c_\u003e = map.pin();\nlet mut mut_map: Pin\u003c_\u003e = mut_map.pin();\n\n\n// Shared references to values are now pinned:\nlet a: Pin\u003c\u0026String\u003e = map.insert(\"Hello!!\", \"Hello!!\".to_string())\n  .unwrap();\nlet b: Pin\u003c\u0026String\u003e = map.insert_with(\"Hello again!!\", |k| k.to_string())\n  .ok().unwrap();\nlet c: Pin\u003c\u0026String\u003e = map.try_insert_with::\u003c_, Infallible\u003e(\"Hello once again!!\", |k| Ok(k.to_string()))\n  .unwrap().ok().unwrap();\n\nlet a2: Pin\u003c\u0026String\u003e = map.get(\"Hello!\").unwrap();\n\nlet _ = (a, a2, b, c);\n\n\n// Exclusive references to values are also pinned:\nlet mut mut_a: Pin\u003c\u0026mut String\u003e = mut_map.insert_with_mut(\"Hi!\", |k| k.to_string())\n  .map_err(|(key, _factory)| key).unwrap();\n\nlet mut mut_a2: Pin\u003c\u0026mut String\u003e = mut_map.get_mut(\"Hi!\").unwrap();\n\n// The `…_mut` methods are actually faster, but their results can't be held onto at once:\n// let _ = (mut_a, mut_a2); // \"error[E0499]: cannot borrow `mut_map` as mutable more than once at a time\"\n\n// Only keys can be removed now, but values must be dropped in place:\nmut_map.clear();\nlet _: Option\u003c\u0026str\u003e = mut_map.remove_key(\"C\");\nlet _: bool = mut_map.drop_entry(\"D\");\n```\n\n### Heterogeneous Map\n\n```rust\nuse pinus::{prelude::*, sync::PressedPineMap};\nuse std::{\n  any::Any,\n  borrow::{Borrow, BorrowMut},\n  convert::Infallible,\n  pin::Pin,\n};\nuse this_is_fine::prelude::*;\n\nlet map = PressedPineMap::\u003c_, dyn Any\u003e::new();\n\n// `dyn Any` is `!Sized`,\n// so it's necessary to use the loosely-typed emplacement methods:\nlet _: \u0026dyn Any = map\n  .emplace_with(1, |_key, slot| slot.write(()))\n  .ok(/* or key and factory */).unwrap();\nlet _: \u0026dyn Any = map\n  .try_emplace_with::\u003c_, Infallible\u003e(2, |_key, slot| Ok(slot.write(())))\n  .unwrap(/* or factory error */)\n  .ok(/* or key and factory */).unwrap();\n\n// There's also a by-value method,\n// but it has slightly steeper requirements:\n#[derive(Debug)]\nstruct MyAny;\nimpl std::borrow::Borrow\u003cdyn Any\u003e for MyAny { //…\n#   fn borrow(\u0026self) -\u003e \u0026dyn Any { self }\n# }\nimpl std::borrow::BorrowMut\u003cdyn Any\u003e for MyAny { //…\n#   fn borrow_mut(\u0026mut self) -\u003e \u0026mut dyn Any { self }\n# }\n\nlet _: \u0026dyn Any = map\n  .emplace(3, MyAny)\n  .unwrap(/* or key and value */);\n\n// As usual the map's values can be pinned:\nlet map: Pin\u003cPressedPineMap\u003c_, _\u003e\u003e = map.pin();\n\n// And then further value references are pinned:\nlet _: Pin\u003c\u0026dyn Any\u003e = map.emplace(4, MyAny).unwrap();\n\n// To immediately get an unpinned reference, just use `.as_unpinned()`:\nlet _: \u0026dyn Any = map.as_unpinned().emplace(5, MyAny).unwrap();\n```\n\n## License\n\nLicensed under either of\n\n- Apache License, Version 2.0\n   ([LICENSE-APACHE](LICENSE-APACHE) or \u003chttp://www.apache.org/licenses/LICENSE-2.0\u003e)\n- MIT license\n   ([LICENSE-MIT](LICENSE-MIT) or \u003chttp://opensource.org/licenses/MIT\u003e)\n\nat your option.\n\n## Contribution\n\nUnless you explicitly state otherwise, any contribution intentionally submitted\nfor inclusion in the work by you, as defined in the Apache-2.0 license, shall be\ndual licensed as above, without any additional terms or conditions.\n\nSee [CONTRIBUTING](CONTRIBUTING.md) for more information.\n\n## [Code of Conduct](CODE_OF_CONDUCT.md)\n\n## [Changelog](CHANGELOG.md)\n\n## Versioning\n\n`pinus` strictly follows [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html) with the following exceptions:\n\n- The minor version will not reset to 0 on major version changes (except for v1).  \nConsider it the global feature level.\n- The patch version will not reset to 0 on major or minor version changes (except for v0.1 and v1).  \nConsider it the global patch level.\n\nThis includes the Rust version requirement specified above.  \nEarlier Rust versions may be compatible, but this can change with minor or patch releases.\n\nWhich versions are affected by features and patches can be determined from the respective headings in [CHANGELOG.md](CHANGELOG.md).\n\nNote that dependencies of this crate may have a more lenient MSRV policy!\nPlease use `cargo +nightly update -Z minimal-versions` in your automation if you don't generate Cargo.lock manually (or as necessary) and require support for a compiler older than current stable.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftamschi%2Fpinus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftamschi%2Fpinus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftamschi%2Fpinus/lists"}