{"id":21655197,"url":"https://github.com/pseitz/serde_json_borrow","last_synced_at":"2025-04-12T21:19:48.590Z","repository":{"id":64813932,"uuid":"558374870","full_name":"PSeitz/serde_json_borrow","owner":"PSeitz","description":"Fast JSON deserialization on borrowed data","archived":false,"fork":false,"pushed_at":"2025-01-30T16:55:54.000Z","size":3552,"stargazers_count":85,"open_issues_count":0,"forks_count":13,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-12T21:19:34.256Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","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/PSeitz.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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}},"created_at":"2022-10-27T12:28:57.000Z","updated_at":"2025-02-20T06:09:17.000Z","dependencies_parsed_at":"2024-05-28T09:38:23.661Z","dependency_job_id":"d278f441-cf42-4beb-b1d3-71fb3595d685","html_url":"https://github.com/PSeitz/serde_json_borrow","commit_stats":{"total_commits":26,"total_committers":3,"mean_commits":8.666666666666666,"dds":0.2692307692307693,"last_synced_commit":"3582902211777c63554dcdb8b77bfb50753322c8"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PSeitz%2Fserde_json_borrow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PSeitz%2Fserde_json_borrow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PSeitz%2Fserde_json_borrow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PSeitz%2Fserde_json_borrow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PSeitz","download_url":"https://codeload.github.com/PSeitz/serde_json_borrow/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248632120,"owners_count":21136629,"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":[],"created_at":"2024-11-25T08:30:36.549Z","updated_at":"2025-04-12T21:19:48.569Z","avatar_url":"https://github.com/PSeitz.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Crates.io](https://img.shields.io/crates/v/serde_json_borrow.svg)](https://crates.io/crates/serde_json_borrow)\n [![Docs](https://docs.rs/serde_json_borrow/badge.svg)](https://docs.rs/crate/serde_json_borrow/)\n \n# Serde JSON Borrow\n\nUp to 2x faster JSON parsing for NDJSON (Newline Delimited JSON format) type use cases.\n\n`serde_json_borrow` deserializes JSON from `\u0026'ctx str` into `serde_json_borrow::Value\u003c'ctx\u003e` DOM, by trying to reference the original bytes, instead of copying them into `Strings`.\n\nIn contrast the default [serde_json](https://github.com/serde-rs/json) parses into an owned `serde_json::Value`. Every `String` encountered is getting copied and \ntherefore allocated. That's great for ergonomonics, but not great for performance.\nEspecially in cases where the DOM representation is just an intermediate struct.\n\nTo get a little bit more performance, `serde_json_borrow` pushes the (key,values) for JSON objects into a `Vec` instead of using a `BTreeMap`. Access works via\nan iterator, which has the same API when iterating the `BTreeMap`.\n\n## OwnedValue\nYou can take advantage of `OwnedValue` to parse a `String` containing unparsed `JSON` into a `Value` without having to worry about lifetimes,\nas `OwnedValue` will take ownership of the `String` and reference slices of it, rather than making copies.\n\nNote: `OwnedValue` does not implement `Deserialize`.\n\n# Limitations\nThe feature flag `cowkeys` uses `Cow\u003cstr\u003e` instead of `\u0026str` as keys in objects. This enables support for escaped data in keys.\nWithout the `cowkeys` feature flag `\u0026str` is used, which does not allow any JSON escaping characters in keys.\n\nList of _unsupported_ characters (https://www.json.org/json-en.html) in keys without `cowkeys` feature flag.\n\n```\n\\\" represents the quotation mark character (U+0022).\n\\\\ represents the reverse solidus character (U+005C).\n\\/ represents the solidus character (U+002F).\n\\b represents the backspace character (U+0008).\n\\f represents the form feed character (U+000C).\n\\n represents the line feed character (U+000A).\n\\r represents the carriage return character (U+000D).\n\\t represents the character tabulation character (U+0009).\n```\n\n# Benchmark\n\n`cargo bench`\n\n* simple_json -\u003e flat object with some keys\n* hdfs -\u003e log\n* wiki -\u003e few keys with large text body \n* gh-archive -\u003e highly nested object\n```\nsimple_json\nserde_json               Avg: 139.29 MiB/s    Median: 139.53 MiB/s    [134.51 MiB/s .. 140.45 MiB/s]    \nserde_json_borrow        Avg: 210.33 MiB/s    Median: 209.66 MiB/s    [204.08 MiB/s .. 214.28 MiB/s]    \nSIMD_json_borrow         Avg: 140.36 MiB/s    Median: 140.44 MiB/s    [138.96 MiB/s .. 141.75 MiB/s]    \nhdfs\nserde_json               Avg: 284.64 MiB/s    Median: 284.60 MiB/s    [280.98 MiB/s .. 286.46 MiB/s]    \nserde_json_borrow        Avg: 372.99 MiB/s    Median: 371.75 MiB/s    [365.97 MiB/s .. 379.96 MiB/s]    \nSIMD_json_borrow         Avg: 294.41 MiB/s    Median: 294.96 MiB/s    [287.76 MiB/s .. 296.96 MiB/s]    \nhdfs_with_array\nserde_json               Avg: 194.50 MiB/s    Median: 200.41 MiB/s    [155.44 MiB/s .. 211.49 MiB/s]    \nserde_json_borrow        Avg: 275.01 MiB/s    Median: 282.74 MiB/s    [208.35 MiB/s .. 289.78 MiB/s]    \nSIMD_json_borrow         Avg: 206.34 MiB/s    Median: 210.52 MiB/s    [180.99 MiB/s .. 220.30 MiB/s]    \nwiki\nserde_json               Avg: 439.95 MiB/s    Median: 441.28 MiB/s    [429.97 MiB/s .. 444.82 MiB/s]    \nserde_json_borrow        Avg: 484.74 MiB/s    Median: 485.29 MiB/s    [471.38 MiB/s .. 489.16 MiB/s]    \nSIMD_json_borrow         Avg: 576.57 MiB/s    Median: 578.11 MiB/s    [554.03 MiB/s .. 586.18 MiB/s]    \ngh-archive\nserde_json               Avg: 176.21 MiB/s    Median: 176.37 MiB/s    [172.52 MiB/s .. 177.78 MiB/s]    \nserde_json_borrow        Avg: 363.58 MiB/s    Median: 364.02 MiB/s    [355.28 MiB/s .. 374.10 MiB/s]    \nSIMD_json_borrow         Avg: 383.66 MiB/s    Median: 386.94 MiB/s    [363.80 MiB/s .. 400.25 MiB/s]    \n\n```\n\n# TODO \nInstead of parsing a JSON object into a `Vec`, a `BTreeMap` could be enabled via a feature flag.\n\n# Mutability\n`OwnedValue` is immutable by design.\nIf you need to mutate the `Value` you can convert it to `serde_json::Value`.\n\nHere is an example why mutability won't work:\n\nhttps://play.rust-lang.org/?version=stable\u0026mode=debug\u0026edition=2021\u0026gist=bb0b919acc8930e71bdefdfc6a6d5240\n```rust\nuse std::io;\n\nuse std::borrow::Cow;\n\n\n/// Parses a `String` into `Value`, by taking ownership of `String` and reference slices from it in\n/// contrast to copying the contents.\n///\n/// This is done to mitigate lifetime issues.\npub struct OwnedValue {\n    /// Keep owned data, to be able to safely reference it from Value\u003c'static\u003e\n    _data: String,\n    value: Vec\u003cCow\u003c'static, str\u003e\u003e,\n}\n\nimpl OwnedValue {\n    /// Takes ownership of a `String` and parses it into a DOM.\n    pub fn parse_from(data: String) -\u003e io::Result\u003cSelf\u003e {\n        let value = vec![Cow::from(data.as_str())];\n        let value = unsafe { extend_lifetime(value) };\n        Ok(Self { _data: data, value })\n    }\n\n    /// Returns the `Value` reference.\n    pub fn get_value\u003c'a\u003e(\u0026'a self) -\u003e \u0026'a Vec\u003cCow\u003c'a, str\u003e\u003e {\n        \u0026self.value\n    }\n    /// This cast will break the borrow checker\n    pub fn get_value_mut\u003c'a\u003e(\u0026'a mut self) -\u003e \u0026'a mut Vec\u003cCow\u003c'a, str\u003e\u003e {\n        unsafe{std::mem::transmute::\u003c\u0026mut Vec\u003cCow\u003c'static, str\u003e\u003e, \u0026mut Vec\u003cCow\u003c'a, str\u003e\u003e\u003e(\u0026mut self.value)}\n    }\n}\n\nunsafe fn extend_lifetime\u003c'b\u003e(r: Vec\u003cCow\u003c'b, str\u003e\u003e) -\u003e Vec\u003cCow\u003c'static, str\u003e\u003e {\n    std::mem::transmute::\u003cVec\u003cCow\u003c'b, str\u003e\u003e, Vec\u003cCow\u003c'static, str\u003e\u003e\u003e(r)\n}\n\nfn main() {\n    let mut v1 = OwnedValue::parse_from(String::from(\"oop\")).unwrap();\n    let mut v2 = OwnedValue::parse_from(String::from(\"oop\")).unwrap();\n    let oop = v1.get_value().last().unwrap().clone();\n    v2.get_value_mut().push(oop);\n    drop(v1);\n    let oop = v2.get_value_mut().pop().unwrap();\n    println!(\"oop: '{oop}'\");\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpseitz%2Fserde_json_borrow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpseitz%2Fserde_json_borrow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpseitz%2Fserde_json_borrow/lists"}