{"id":50897802,"url":"https://github.com/rmw-link/sdb","last_synced_at":"2026-07-22T07:01:13.417Z","repository":{"id":57666428,"uuid":"375547948","full_name":"rmw-link/sdb","owner":"rmw-link","description":"a user-friendly wrapper for sanakirja database","archived":false,"fork":false,"pushed_at":"2021-07-10T18:18:30.000Z","size":391,"stargazers_count":7,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-06-08T00:10:42.062Z","etag":null,"topics":["database","rust","sled"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rmw-link.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-06-10T02:38:03.000Z","updated_at":"2026-05-07T04:12:15.000Z","dependencies_parsed_at":"2022-09-26T20:31:47.585Z","dependency_job_id":null,"html_url":"https://github.com/rmw-link/sdb","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/rmw-link/sdb","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmw-link%2Fsdb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmw-link%2Fsdb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmw-link%2Fsdb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmw-link%2Fsdb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rmw-link","download_url":"https://codeload.github.com/rmw-link/sdb/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmw-link%2Fsdb/sbom","scorecard":{"id":779233,"data":{"date":"2025-08-11","repo":{"name":"github.com/rmw-link/sdb","commit":"daddcc5ae2802c6d41ebdd5f0772607d77e0d2b6"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.3,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":8,"reason":"2 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: RUSTSEC-2024-0384","Warn: Project is vulnerable to: RUSTSEC-2020-0077"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-23T04:29:28.602Z","repository_id":57666428,"created_at":"2025-08-23T04:29:28.603Z","updated_at":"2025-08-23T04:29:28.603Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35751644,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-22T02:00:06.236Z","response_time":124,"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":["database","rust","sled"],"created_at":"2026-06-16T01:31:30.080Z","updated_at":"2026-07-22T07:01:13.409Z","avatar_url":"https://github.com/rmw-link.png","language":"Rust","funding_links":[],"categories":["database"],"sub_categories":[],"readme":"\u003c!-- 本文件由 ./readme.make.md 自动生成，请不要直接修改此文件 --\u003e\n\n# sdb\n\na user-friendly wrapper for [sanakirja](https://docs.rs/sanakirja/latest/sanakirja/) database\n\nsanakirja a key can have multiple values , this is different from the other k-v databases .\n\n## about\n\nsanakirja author is [Pierre-Étienne Meunier](https://twitter.com/pijul_org) .\n\nsee [Sanakirja 1.0 (pure Rust transactional on-disk key-value store) released!](https://www.reddit.com/r/rust/comments/lp5jez/sanakirja_10_pure_rust_transactional_ondisk/)\n\n\u003e Sanakirja is at least 10 times faster than Sled in my (sequential) benchmarks, and even 20%-50% faster than LMDB (the fastest C equivalent) in the same benchmarks. Also, I started it when there was no real alternative (Sled didn't exist at the time).\n\n[I](https://github.com/rmw-link/sdb) wrapper it for easy use .\n\nFirst step : static define db , see [tests/db.rs](./tests/db.rs)\n\nI use `static_init = {git=\"https://gitlab.com/vkahl/static_init.git\"}` for static init ( use git version because of [bug](https://gitlab.com/okannen/static_init/-/issues/7) ) .  You can use [lazy_static](https://docs.rs/crate/lazy_static) instead .\n\n```rust\nuse desse::{Desse, DesseSized};\nuse sdb::{desse, Db, DbEv, DbU, Encode, Sdb, Storable, Tx, UnsizedStorable};\nuse static_init::dynamic;\nuse std::env;\nuse std::path::Path;\n\n#[dynamic]\npub static DIR: String = env::current_exe()\n  .unwrap()\n  .parent()\n  .unwrap()\n  .parent()\n  .unwrap()\n  .display()\n  .to_string();\n\n#[dynamic]\npub static TX: Tx = {\n  let dir = Path::new(\u0026*DIR).join(\"db\");\n\n  println!(\"DATABASE DIR {}\", dir.display().to_string());\n\n  //use sdb::TxArgs::{InitSize, MaxTx, Filename};\n\n  Tx::new(\n    \u0026dir,\n    \u0026[\n      //MaxTx(3),\n      //Filename(\"sdb\"),\n      //InitSize(1\u003c\u003c21),\n    ],\n  )\n};\n\n#[dynamic]\npub static DB0: Db\u003c'static, u64, u64\u003e = TX.db(0);\n\n#[derive(Sdb, Default, Eq, PartialEq, PartialOrd, Ord, Hash, Clone, Copy, Debug)]\npub struct Hash(pub [u8; 2]);\n\n#[dynamic]\npub static DB1: Db\u003c'static, u64, Hash\u003e = TX.db(1);\n\n#[dynamic] // DbU = Db \u0026 btree::page_unsized::Page\npub static DB2: DbU\u003c'static, u64, [u8]\u003e = TX.db(2);\n\n#[dynamic]\npub static DB3: DbU\u003c'static, [u8], [u8]\u003e = TX.db(3);\n\n#[derive(Sdb, Default, Eq, PartialEq, PartialOrd, Ord, Hash, Clone, Copy, Debug)]\npub struct Data {\n  pub hash: [u8; 3],\n  pub id: u64,\n}\n\n#[dynamic]\npub static DB4: Db\u003c'static, u64, Data\u003e = TX.db(4);\n\n#[derive(DesseSized, Desse, Debug)]\npub struct Data2 {\n  pub hash: [u8; 3],\n  pub id: u64,\n}\n\ndesse!(Data2, Data2Desse); // the same as below\n\n/*\n#[derive(\n  Default, Eq, PartialEq, PartialOrd, Ord, Hash, Clone, Copy, Debug, DesseSized, Desse,\n)]\npub struct Data2Desse([u8; Data2::SIZE]);\n\nuse sdb::direct_repr;\ndirect_repr!(Data2Desse);\n\n#[dynamic]\npub static DB5: DbEv\u003c'static, u64, Data2Desse, Data2\u003e = TX.db(5);\n\nimpl Encode\u003cData2Desse\u003e for Data2 {\n  #[inline]\n  fn encode\u003cR: Sized\u003e(\u0026self, next: \u0026mut dyn FnMut(\u0026Data2Desse) -\u003e R) -\u003e R {\n    next(\u0026Data2Desse(self.serialize()))\n  }\n}\n\nimpl From\u003c\u0026Data2Desse\u003e for Data2 {\n  fn from(v: \u0026Data2Desse) -\u003e Self {\n    Data2::deserialize_from(\u0026v.0)\n  }\n}\n*/\n\n#[dynamic]\npub static DB5: DbEv\u003c'static, u64, Data2Desse, Data2\u003e = TX.db(5);\n\n```\n\nSecond step : use it , see [tests/main.rs](./tests/main.rs)\n\n```rust\nmod db;\nuse anyhow::Result;\nuse db::{Data, Data2, Hash, DB0, DB1, DB2, DB3, DB4, DB5, TX};\nuse sdb::UnsizedStorable;\n\n#[test]\nfn main() -\u003e Result\u003c()\u003e {\n  println!(\"direct put\");\n  DB0.put(\u00260, \u00260)?;\n  DB0.put(\u00260, \u00261)?;\n  DB0.put(\u00266, \u00261)?;\n  DB0.put(\u00266, \u00262)?;\n  DB0.put(\u00266, \u00263)?;\n  println!(\"- print val where key = 6\");\n  for entry in DB0.key_iter(\u00266)? {\n    let (k, v) = entry?;\n    println!(\"\u003e {:?} {:?}\", k, v)\n  }\n  DB0.rm1(\u00266, None)?;\n\n  {\n    println!(\"# write transaction\");\n    let tx = TX.w()?;\n    let mut db0 = tx.db(\u0026DB0);\n\n    db0.put(\u00261, \u00265)?;\n    db0.put(\u00261, \u00263)?;\n    db0.put(\u00262, \u00262)?;\n    db0.put(\u00262, \u00261)?;\n    db0.put(\u00263, \u00267)?;\n    db0.put(\u00263, \u00269)?;\n    db0.put(\u00265, \u00261)?;\n    db0.put(\u00265, \u00269)?;\n\n    println!(\"- print all key db0\");\n    for entry in db0.iter(None, None)? {\n      let (k, v) = entry?;\n      println!(\"\u003e {:?} {:?}\", k, v)\n    }\n\n    println!(\"- print db1 where key is 2\");\n    for entry in db0.key_iter(\u00264)? {\n      let (k, v) = entry?;\n      println!(\"\u003e {:?} {:?}\", k, v)\n    }\n\n    println!(\"- delete key 2 the first value : {}\", db0.rm1(\u00262, None)?);\n    println!(\"- delete key=2 and value=5 : {}\", db0.rm1(\u00262, \u00265)?);\n    println!(\"- delete key 3 all value : delete number = {}\", db0.rm(\u00263)?);\n    println!(\"- delete key 5 the first value : {}\", db0.rm1(\u00265, None)?);\n\n    println!(\"- print all key\");\n    for entry in db0.iter(None, None)? {\n      let (k, v) = entry?;\n      println!(\"\u003e {:?} {:?}\", k, v)\n    }\n\n    let mut db1 = tx.db(\u0026DB1);\n    db1.put(\u00261, \u0026Hash([1, 2]))?;\n    println!(\"- print all key db1\");\n    for entry in db1.iter(None, None)? {\n      let (k, v) = entry?;\n      println!(\"\u003e {:?} {:?}\", k, v)\n    }\n\n    let mut db2 = tx.db(\u0026DB2);\n    db2.put(\u00261, \u0026[1, 2, 3][..])?;\n    db2.put(\u00262, \u0026[4, 6][..])?;\n\n    println!(\"- print all key db2\");\n    for entry in db2.iter(None, None)? {\n      let (k, v) = entry?;\n      println!(\"\u003e {:?} {:?}\", k, v)\n    }\n\n    let mut db3 = tx.db(\u0026DB3);\n    db3.put(\u0026[1, 2][..], \u0026[1, 2, 3][..])?;\n\n    println!(\"- print all key db3\");\n    for entry in db3.iter(None, None)? {\n      let (k, v) = entry?;\n      println!(\"\u003e {:?} {:?}\", k, v)\n    }\n\n    let mut db4 = tx.db(\u0026DB4);\n    let data = Data {\n      id: 1234,\n      hash: [3, 2, 1],\n    };\n    println!(\"data size : {}\", data.size());\n    db4.put(\u00261, \u0026data)?;\n    println!(\"- print all key db4\");\n    for entry in db4.iter(None, None)? {\n      let (k, v) = entry?;\n      println!(\"\u003e {:?} {:?}\", k, v)\n    }\n\n    let mut db5 = tx.db(\u0026DB5);\n    let data = Data2 {\n      id: 1234,\n      hash: [3, 2, 1],\n    };\n    db5.put(\u00261, \u0026data)?;\n    println!(\"- print all key db5\");\n    for entry in db5.iter(None, None)? {\n      let (k, v) = entry?;\n      println!(\"\u003e {:?} {:?}\", k, Data2::from(v))\n    }\n    //write tx will auto commit when drop\n  }\n\n  {\n    println!(\"# read transaction\");\n\n    let tx = TX.r()?; //\n    let db0 = tx.db(\u0026DB0);\n\n    dbg!(db0.exist(\u00262, \u00261)?);\n    for i in [1, 2, 5] {\n      dbg!(i, db0.one(\u0026i)?);\n    }\n\n    println!(\"- print all key\");\n    for entry in db0.iter(None, None)? {\n      let (k, v) = entry?;\n      println!(\"\u003e {:?} {:?}\", k, v)\n    }\n    println!(\"- print key greater or equal 2\");\n    for entry in db0.iter(\u00262, None)? {\n      let (k, v) = entry?;\n      println!(\"\u003e {:?} {:?}\", k, v)\n    }\n\n    println!(\"- print key greater or equal 2 and value greater or equal 1\");\n    for entry in db0.iter(\u00262, \u00261)? {\n      let (k, v) = entry?;\n      println!(\"\u003e {:?} {:?}\", k, v)\n    }\n\n    println!(\"- print key greater or equal 2 and value greater or equal 1\");\n    for entry in db0.iter(\u00262, \u00261)? {\n      let (k, v) = entry?;\n      println!(\"\u003e {:?} {:?}\", k, v)\n    }\n\n    println!(\"- print key in revese order\");\n    for entry in db0.riter(None, None)? {\n      let (k, v) = entry?;\n      println!(\"\u003e {:?} {:?}\", k, v);\n    }\n\n    let db4 = tx.db(\u0026DB4);\n    println!(\"- db4 : print key in revese order\");\n    for entry in db4.riter(None, None)? {\n      let (k, v) = entry?;\n      println!(\"\u003e {:?} {:?}\", k, v);\n    }\n  }\n\n  Ok(())\n}\n\n```\n\ndb method you can see [src/dbpage.rs](./src/dbpage.rs)\n\n```rust\nuse crate::tx::{Tx, TxnEnv};\npub use sanakirja::btree::page::Page;\nuse sanakirja::btree::{BTreeMutPage, BTreePage, Iter, RevIter};\nuse sanakirja::{Error, LoadPage, Storable};\nuse std::marker::PhantomData;\n\nmacro_rules! db_page_r {\n  ($self:ident, $db:ident, $fn:expr) =\u003e {{\n    let tx = $self.tx.r()?;\n    let $db = tx.db($self);\n    $fn\n  }};\n}\n\nmacro_rules! db_page_w {\n  ($self:ident, $db:ident, $fn:expr) =\u003e {{\n    let tx = $self.tx.w()?;\n    let mut $db = tx.db($self);\n    $fn\n  }};\n}\n\nimpl\u003c\n    'a,\n    K: ?Sized + Storable + PartialEq,\n    V: ?Sized + Storable + PartialEq,\n    P: BTreeMutPage\u003cK, V\u003e + BTreePage\u003cK, V\u003e,\n    RK: ?Sized + Encode\u003cK\u003e,\n    RV: ?Sized + Encode\u003cV\u003e,\n  \u003e DbPage\u003c'a, K, V, P, RK, RV\u003e\n{\n  pub fn upsert(\u0026self, k: \u0026RK, v: \u0026RV) -\u003e std::result::Result\u003cbool, Error\u003e {\n    db_page_w!(self, db, db.upsert(k, v))\n  }\n\n  pub fn put(\u0026self, k: \u0026RK, v: \u0026RV) -\u003e Result\u003cbool, Error\u003e {\n    db_page_w!(self, db, db.put(k, v))\n  }\n\n  pub fn rm(\u0026self, k: \u0026RK) -\u003e Result\u003cusize, Error\u003e {\n    db_page_w!(self, db, db.rm(k))\n  }\n\n  pub fn one(\u0026self, k: \u0026'a RK) -\u003e Result\u003cOption\u003c\u0026'a V\u003e, \u003cTxnEnv as LoadPage\u003e::Error\u003e {\n    db_page_r!(self, db, db.one(k))\n  }\n\n  pub fn exist(\u0026self, k: \u0026RK, v: \u0026RV) -\u003e Result\u003cbool, \u003cTxnEnv as LoadPage\u003e::Error\u003e {\n    db_page_r!(self, db, db.exist(k, v))\n  }\n\n  pub fn rm1\u003cIntoV: Into\u003cOption\u003c\u0026'a RV\u003e\u003e\u003e(\u0026self, k: \u0026RK, v: IntoV) -\u003e Result\u003cbool, Error\u003e {\n    db_page_w!(self, db, db.rm1(k, v.into()))\n  }\n\n  pub fn key_iter(\n    \u0026self,\n    k: \u0026'a RK,\n  ) -\u003e Result\u003c\n    Box\u003cdyn Iterator\u003cItem = Result\u003c(\u0026'a K, \u0026'a V), \u003cTxnEnv as LoadPage\u003e::Error\u003e\u003e + 'a\u003e,\n    \u003cTxnEnv as LoadPage\u003e::Error,\n  \u003e {\n    db_page_r!(self, db, db.key_iter(k))\n  }\n\n  pub fn iter\u003cOptionK: Into\u003cOption\u003c\u0026'a RK\u003e\u003e, OptionV: Into\u003cOption\u003c\u0026'a RV\u003e\u003e\u003e(\n    \u0026self,\n    k: OptionK,\n    v: OptionV,\n  ) -\u003e Result\u003cIter\u003cTxnEnv, K, V, P\u003e, \u003cTxnEnv as LoadPage\u003e::Error\u003e {\n    db_page_r!(self, db, db.iter(k.into(), v.into()))\n  }\n\n  pub fn riter\u003cOptionK: Into\u003cOption\u003c\u0026'a RK\u003e\u003e, OptionV: Into\u003cOption\u003c\u0026'a RV\u003e\u003e\u003e(\n    \u0026self,\n    k: OptionK,\n    v: OptionV,\n  ) -\u003e Result\u003cRevIter\u003cTxnEnv, K, V, P\u003e, \u003cTxnEnv as LoadPage\u003e::Error\u003e {\n    db_page_r!(self, db, db.riter(k.into(), v.into()))\n  }\n}\n\npub struct DbPage\u003c\n  'a,\n  K: ?Sized + Storable + PartialEq,\n  V: ?Sized + Storable + PartialEq,\n  P: BTreeMutPage\u003cK, V\u003e + BTreePage\u003cK, V\u003e,\n  RK: ?Sized + Encode\u003cK\u003e,\n  RV: ?Sized + Encode\u003cV\u003e,\n\u003e {\n  pub(crate) tx: \u0026'a Tx,\n  pub id: usize,\n  pub(crate) _kvp: PhantomData\u003c(\u0026'a K, \u0026'a V, \u0026'a P, \u0026'a RK, \u0026'a RV)\u003e,\n}\n\npub trait Encode\u003cT: ?Sized\u003e {\n  fn encode\u003cR: Sized\u003e(\u0026self, next: \u0026mut dyn FnMut(\u0026T) -\u003e R) -\u003e R;\n}\n\n#[macro_export]\nmacro_rules! encode {\n  ($cls:ty, $t:ty) =\u003e {\n    impl $crate::Encode\u003c$t\u003e for $cls {\n      #[inline]\n      fn encode\u003cR: Sized\u003e(\u0026self, next: \u0026mut dyn FnMut(\u0026$t) -\u003e R) -\u003e R {\n        next(self)\n      }\n    }\n  };\n  ($cls:ty) =\u003e {\n    encode!($cls, $cls);\n  };\n}\n\n#[macro_export]\nmacro_rules! encode_li {\n  ( $( $x:ty ),* ) =\u003e {\n    $(encode!($x);)*\n  };\n}\n\nencode_li!(\n  [u8],\n  bool,\n  i8,\n  u8,\n  i16,\n  u16,\n  i32,\n  u32,\n  i64,\n  u64,\n  i128,\n  u128,\n  isize,\n  usize,\n  f32,\n  f64\n);\n\n```\n\n\n## sanakirja\n\nCopy-on-write datastructures, storable on disk (or elsewhere) with a stable format.\n\n* [Rethinking Sanakirja, a Rust database engine with fast clones (first released in 2015)](https://www.reddit.com/r/rust/comments/ld6k2h/rethinking_sanakirja_a_rust_database_engine_with/)\n* [Implementing cross-process Sanakirja locks](https://pijul.org/posts/2021-01-15-sanakirja-locks/)\n* [Sanakirja gets its full concurrency model](https://pijul.org/posts/2019-03-20-sanakirja-0.10/)\n* [News of Sanakirja](https://pijul.org/2017/03/16/sanakirja/)\n* [Sanakirja 0.2](https://pijul.org/2016/03/24/sanakirja-0.2/)\n* [Functional semantics in Sanakirja](https://pijul.org/2016/03/03/functional-database/)\n\n\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frmw-link%2Fsdb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frmw-link%2Fsdb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frmw-link%2Fsdb/lists"}