{"id":19389506,"url":"https://github.com/linksplatform/doublets-rs","last_synced_at":"2026-04-19T01:17:44.576Z","repository":{"id":50456774,"uuid":"519133554","full_name":"linksplatform/doublets-rs","owner":"linksplatform","description":null,"archived":false,"fork":false,"pushed_at":"2025-09-11T06:17:13.000Z","size":23286,"stargazers_count":6,"open_issues_count":29,"forks_count":2,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-09-11T08:46:39.952Z","etag":null,"topics":["associative","doublets","linksplatform","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/linksplatform.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":"2022-07-29T08:08:39.000Z","updated_at":"2025-03-03T18:48:38.000Z","dependencies_parsed_at":"2024-01-28T18:24:23.727Z","dependency_job_id":"0f3fb4f5-855d-4eb2-9923-7cee7e874b8b","html_url":"https://github.com/linksplatform/doublets-rs","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/linksplatform/doublets-rs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linksplatform%2Fdoublets-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linksplatform%2Fdoublets-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linksplatform%2Fdoublets-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linksplatform%2Fdoublets-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/linksplatform","download_url":"https://codeload.github.com/linksplatform/doublets-rs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linksplatform%2Fdoublets-rs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280761860,"owners_count":26386245,"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","status":"online","status_checked_at":"2025-10-24T02:00:06.418Z","response_time":73,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["associative","doublets","linksplatform","rust"],"created_at":"2024-11-10T10:16:25.684Z","updated_at":"2026-04-19T01:17:44.567Z","avatar_url":"https://github.com/linksplatform.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Doublets\n\n[![CI/CD Pipeline](https://github.com/linksplatform/doublets-rs/actions/workflows/release.yml/badge.svg?branch=main)](https://github.com/linksplatform/doublets-rs/actions/workflows/release.yml?query=branch%3Amain)\n[![Crates.io](https://img.shields.io/crates/v/doublets.svg)](https://crates.io/crates/doublets)\n[![License](https://img.shields.io/badge/license-Unlicense-blue.svg)](https://github.com/linksplatform/doublets-rs/blob/main/LICENSE)\n\nLinksPlatform's Rust implementation of Doublets (associative storage links).\n\nRust port of [Data.Doublets](https://github.com/linksplatform/Data.Doublets) library.\n\n## Overview\n\nDoublets is an associative data structure that represents a link store where each link consists of:\n- **Index** - unique identifier of the link\n- **Source** - the link's source (can reference itself or another link)\n- **Target** - the link's target (can reference itself or another link)\n\nThis simple yet powerful structure can represent any data model, from traditional key-value pairs to complex graph structures. Doublets provide a unified approach to data storage with constant-time lookup operations using size-balanced trees.\n\n### Key Features\n\n- **File-mapped storage** - data persists directly to disk using memory-mapped files\n- **Generic link types** - supports any unsigned integer type (`u8`, `u16`, `u32`, `u64`, `usize`)\n- **Two storage modes**:\n  - `unit::Store` - combined data and index storage in a single memory region\n  - `split::Store` - separated data and index storage for optimized memory layouts\n- **Thread-safe** - `Send` and `Sync` implementations for concurrent access\n- **Query system** - flexible pattern matching using `any` constants\n- **FFI bindings** - C-compatible foreign function interface for cross-language integration\n\n## Installation\n\nAdd to your `Cargo.toml`:\n\n```toml\n[dependencies]\ndoublets = \"0.1.0-pre\"\n```\n\n**Note:** This crate requires nightly Rust due to usage of experimental features.\n\n```bash\nrustup default nightly\n```\n\n## Example\n\nBasic CRUD operations with doublets:\n\n```rust\nuse doublets::{mem, unit, Doublets, DoubletsExt, Link, Links};\nuse data::Flow;\n\nfn main() -\u003e Result\u003c(), doublets::Error\u003cusize\u003e\u003e {\n    // Use file as persistent storage for doublets\n    let mem = mem::FileMapped::from_path(\"db.links\")?;\n    let mut store = unit::Store::\u003cusize, _\u003e::new(mem)?;\n\n    // Create a point link (a link that references itself as both source and target)\n    // Point: 1 -\u003e (1, 1)\n    let point = store.create_point()?;\n    println!(\"Created point: {}\", point);\n\n    // Create a regular link with explicit source and target\n    // Link: 2 -\u003e (1, 1)\n    let link = store.create_link(point, point)?;\n    println!(\"Created link: {}\", link);\n\n    // The `any` constant matches any link in queries\n    let any = store.constants().any;\n\n    // Count all links in the store\n    println!(\"Total links: {}\", store.count());\n\n    // Iterate over all links using pattern [any, any, any]\n    println!(\"All links:\");\n    store.each_iter([any, any, any]).for_each(|link| {\n        println!(\"  {}: {} -\u003e {}\", link.index, link.source, link.target);\n    });\n\n    // Query links by source: find all links where source = point\n    println!(\"Links with source = {}:\", point);\n    store.each_iter([any, point, any]).for_each(|link| {\n        println!(\"  {}: {} -\u003e {}\", link.index, link.source, link.target);\n    });\n\n    // Update a link: change the target\n    let updated = store.update(link, point, link)?;\n    println!(\"Updated link {} to target {}\", link, updated);\n\n    // Delete a link with a callback handler\n    store.delete_with(link, |before, after| {\n        println!(\"Deleted: {:?} =\u003e {:?}\", before, after);\n        Flow::Continue\n    })?;\n\n    // Clean up: delete all remaining links\n    store.delete_all()?;\n\n    Ok(())\n}\n```\n\n### Using In-Memory Storage\n\nFor testing or temporary data, you can use heap-allocated memory instead of file storage:\n\n```rust\nuse doublets::{mem, unit, Doublets, Links};\n\nfn main() -\u003e Result\u003c(), doublets::Error\u003cusize\u003e\u003e {\n    // Use global allocator for in-memory storage\n    let mem = mem::Global::new();\n    let mut store = unit::Store::\u003cusize, _\u003e::new(mem)?;\n\n    // Create some links\n    for i in 0..100 {\n        store.create_point()?;\n    }\n\n    println!(\"Created {} links\", store.count());\n    Ok(())\n}\n```\n\n### Using Split Storage\n\nSplit storage separates data and index trees for potentially better cache utilization:\n\n```rust\nuse doublets::{split::Store, Doublets, Links};\nuse mem::Global;\n\nfn main() -\u003e Result\u003c(), doublets::Error\u003cusize\u003e\u003e {\n    let mut store = Store::\u003cusize, _, _\u003e::new(Global::new(), Global::new())?;\n\n    // Create 1 million point links\n    for _ in 0..1_000_000 {\n        store.create_point()?;\n    }\n\n    println!(\"Total links: {}\", store.count());\n    Ok(())\n}\n```\n\n## API Overview\n\n### Core Traits\n\n| Trait | Description |\n|-------|-------------|\n| `Links\u003cT\u003e` | Low-level CRUD operations with handlers |\n| `Doublets\u003cT\u003e` | High-level operations with ergonomic API |\n| `DoubletsExt\u003cT\u003e` | Iterator extensions and parallel processing |\n\n### Main Types\n\n| Type | Description |\n|------|-------------|\n| `Link\u003cT\u003e` | A triplet of (index, source, target) |\n| `Doublet\u003cT\u003e` | A pair of (source, target) without index |\n| `unit::Store` | Combined memory layout storage |\n| `split::Store` | Separated memory layout storage |\n| `Error\u003cT\u003e` | Error type for link operations |\n\n### Key Operations\n\n```rust\n// Create operations\nstore.create()?;                      // Create empty link\nstore.create_point()?;                // Create self-referencing link\nstore.create_link(source, target)?;   // Create link with source and target\n\n// Read operations\nstore.count();                        // Count all links\nstore.count_by([any, source, any]);   // Count by pattern\nstore.get_link(index);                // Get link by index\nstore.search(source, target);         // Find link by source and target\nstore.iter();                         // Iterate all links\nstore.each_iter(query);               // Iterate by pattern\n\n// Update operations\nstore.update(index, source, target)?; // Update link\n\n// Delete operations\nstore.delete(index)?;                 // Delete link\nstore.delete_all()?;                  // Delete all links\n```\n\n## Architecture\n\n```\ndoublets-rs/\n├── doublets/           # Core library\n│   ├── src/\n│   │   ├── data/       # Core data structures (Link, Doublet, traits)\n│   │   └── mem/        # Memory management and storage\n│   │       ├── unit/   # Combined storage implementation\n│   │       └── split/  # Split storage implementation\n│   └── benches/        # Performance benchmarks\n├── doublets-ffi/       # C FFI bindings\n├── dev-deps/           # Platform dependencies\n│   ├── data-rs/        # Data primitives (LinkType, Flow, etc.)\n│   ├── mem-rs/         # Memory abstractions (RawMem, FileMapped)\n│   └── trees-rs/       # Tree structures (size-balanced trees)\n└── integration/        # Integration tests\n```\n\n## Features\n\n| Feature | Description |\n|---------|-------------|\n| `platform` (default) | Core platform types and traits |\n| `mem` | Memory management utilities |\n| `num` | Numeric utilities |\n| `data` | Re-exports from `platform-data` |\n| `rayon` | Parallel iteration support |\n| `small-search` | Stack-allocated buffers for small queries |\n| `full` | All features enabled |\n\n## Performance\n\nThe library is optimized for high-throughput operations:\n\n- **Size-balanced trees** for O(log n) search, insert, and delete operations\n- **Memory-mapped files** for efficient disk I/O\n- **Optional parallel iteration** with rayon feature\n- Benchmarks show creation of 1 million points in ~1 second on modern hardware\n\nRun benchmarks:\n\n```bash\ncargo bench --all-features\n```\n\n## Related Projects\n\n- [Data.Doublets](https://github.com/linksplatform/Data.Doublets) - C# implementation\n- [Comparisons.SQLiteVSDoublets](https://github.com/linksplatform/Comparisons.SQLiteVSDoublets) - Performance comparison with SQLite\n\n## Documentation\n\n- [API Documentation](https://docs.rs/doublets) (when published)\n- [LinksPlatform Overview](https://github.com/linksplatform)\n\n## Dependencies\n\n- [platform-data](https://github.com/linksplatform/data-rs) - Core data types\n- [platform-mem](https://github.com/linksplatform/mem-rs) - Memory abstractions\n- [platform-trees](https://github.com/linksplatform/trees-rs) - Tree implementations\n\n## Support\n\n- Ask questions at [stackoverflow.com/tags/links-platform](https://stackoverflow.com/tags/links-platform) (use tag `links-platform`)\n- Join our [Discord server](https://discord.gg/eEXJyjWv5e) for real-time support\n- Open issues on [GitHub](https://github.com/linksplatform/doublets-rs/issues)\n\n## License\n\nThis project is released into the public domain under the [Unlicense](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinksplatform%2Fdoublets-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flinksplatform%2Fdoublets-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinksplatform%2Fdoublets-rs/lists"}