bson-2.10.0/.cargo_vcs_info.json0000644000000001360000000000100120550ustar { "git": { "sha1": "12eb662e783bdbfc7252e3b3f0f56b8895132dba" }, "path_in_vcs": "" }bson-2.10.0/.github/ISSUE_TEMPLATE/bug_report.md000064400000000000000000000025501046102023000170640ustar 00000000000000--- name: Bug report about: Create a report to help us improve title: '' labels: '' assignees: '' --- ## Versions/Environment 1. What version of Rust are you using? 2. What operating system are you using? 3. What versions of the driver and its dependencies are you using? (Run `cargo pkgid mongodb` & `cargo pkgid bson`) 4. What version of MongoDB are you using? (Check with the MongoDB shell using `db.version()`) 5. What is your MongoDB topology (standalone, replica set, sharded cluster, serverless)? ## Describe the bug A clear and concise description of what the bug is. **BE SPECIFIC**: * What is the _expected_ behavior and what is _actually_ happening? * Do you have any particular output that demonstrates this problem? * Do you have any ideas on _why_ this may be happening that could give us a clue in the right direction? * Did this issue arise out of nowhere, or after an update (of the driver, server, and/or Rust)? * Are there multiple ways of triggering this bug (perhaps more than one function produce a crash)? * If you know how to reproduce this bug, please include a code snippet here: ``` ``` **To Reproduce** Steps to reproduce the behavior: 1. First, do this. 2. Then do this. 3. After doing that, do this. 4. And then, finally, do this. 5. Bug occurs. bson-2.10.0/.github/workflows/close_stale_issues.yml000064400000000000000000000014121046102023000206530ustar 00000000000000--- name: 'Close stale issues' on: schedule: - cron: '30 1 * * *' permissions: issues: write jobs: stale: runs-on: ubuntu-latest steps: - uses: actions/stale@v4 with: stale-issue-message: 'There has not been any recent activity on this ticket, so we are marking it as stale. If we do not hear anything further from you, this issue will be automatically closed in one week.' days-before-issue-stale: 7 days-before-pr-stale: -1 days-before-close: 7 close-issue-message: 'There has not been any recent activity on this ticket, so we are closing it. Thanks for reaching out and please feel free to file a new issue if you have further questions.' only-issue-labels: 'waiting-for-reporter' bson-2.10.0/.github/workflows/issue_assignment.yml000064400000000000000000000010321046102023000203410ustar 00000000000000--- name: Issue assignment on: issues: types: [opened] jobs: auto-assign: runs-on: ubuntu-latest steps: - name: 'Auto-assign issue' uses: pozil/auto-assign-issue@v1.1.0 with: assignees: abr-egn,isabelatkinson numOfAssignee: 1 add-labels: runs-on: ubuntu-latest steps: - name: initial labeling uses: andymckay/labeler@master with: add-labels: "triage" bson-2.10.0/.github/workflows/remove_labels.yml000064400000000000000000000006541046102023000176110ustar 00000000000000--- name: Remove Labels on: issue_comment: types: [created, edited] jobs: remove-labels: if: ${{ github.actor != 'Tom Selander' && github.actor != 'patrickfreed' && github.actor != 'abr-egn' && github.actor != 'isabelatkinson'}} runs-on: ubuntu-latest steps: - name: initial labeling uses: andymckay/labeler@master with: remove-labels: "waiting-for-reporter, Stale" bson-2.10.0/Cargo.lock0000644000001020450000000000100100320ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "ahash" version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "getrandom", "once_cell", "version_check", "zerocopy", ] [[package]] name = "aho-corasick" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "android-tzdata" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" [[package]] name = "android_system_properties" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" dependencies = [ "libc", ] [[package]] name = "ansi_term" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" dependencies = [ "winapi", ] [[package]] name = "assert_matches" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", "winapi", ] [[package]] name = "autocfg" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "base64" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "bit-set" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" dependencies = [ "bit-vec", ] [[package]] name = "bit-vec" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "bitvec" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ "funty", "radium", "tap", "wyz", ] [[package]] name = "bson" version = "2.10.0" dependencies = [ "ahash", "assert_matches", "base64 0.13.1", "bitvec", "chrono", "criterion", "getrandom", "hex", "indexmap 2.2.6", "js-sys", "once_cell", "pretty_assertions", "proptest", "rand", "serde", "serde_bytes", "serde_json", "serde_with 1.14.0", "serde_with 3.7.0", "time", "uuid 0.8.2", "uuid 1.8.0", ] [[package]] name = "bumpalo" version = "3.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" [[package]] name = "cast" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", "serde", "windows-targets", ] [[package]] name = "clap" version = "2.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "bitflags 1.3.2", "textwrap", "unicode-width", ] [[package]] name = "core-foundation-sys" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "criterion" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" dependencies = [ "atty", "cast", "clap", "criterion-plot", "csv", "itertools", "lazy_static", "num-traits", "oorandom", "plotters", "rayon", "regex", "serde", "serde_cbor", "serde_derive", "serde_json", "tinytemplate", "walkdir", ] [[package]] name = "criterion-plot" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" dependencies = [ "cast", "itertools", ] [[package]] name = "crossbeam-deque" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "csv" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" dependencies = [ "csv-core", "itoa", "ryu", "serde", ] [[package]] name = "csv-core" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" dependencies = [ "memchr", ] [[package]] name = "ctor" version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" dependencies = [ "quote", "syn 1.0.109", ] [[package]] name = "darling" version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" dependencies = [ "darling_core 0.13.4", "darling_macro 0.13.4", ] [[package]] name = "darling" version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" dependencies = [ "darling_core 0.20.8", "darling_macro 0.20.8", ] [[package]] name = "darling_core" version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", "syn 1.0.109", ] [[package]] name = "darling_core" version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", "syn 2.0.57", ] [[package]] name = "darling_macro" version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ "darling_core 0.13.4", "quote", "syn 1.0.109", ] [[package]] name = "darling_macro" version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ "darling_core 0.20.8", "quote", "syn 2.0.57", ] [[package]] name = "deranged" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", "serde", ] [[package]] name = "difference" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" [[package]] name = "either" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ "libc", "windows-sys", ] [[package]] name = "fastrand" version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "funty" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "getrandom" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "js-sys", "libc", "wasi", "wasm-bindgen", ] [[package]] name = "half" version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "hermit-abi" version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "iana-time-zone" version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", "windows-core", ] [[package]] name = "iana-time-zone-haiku" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ "cc", ] [[package]] name = "ident_case" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "indexmap" version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", "serde", ] [[package]] name = "indexmap" version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown 0.14.3", "serde", ] [[package]] name = "itertools" version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] [[package]] name = "itoa" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libm" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "linux-raw-sys" version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "log" version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "memchr" version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-traits" version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", "libm", ] [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oorandom" version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" [[package]] name = "output_vt100" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" dependencies = [ "winapi", ] [[package]] name = "plotters" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" dependencies = [ "num-traits", "plotters-backend", "plotters-svg", "wasm-bindgen", "web-sys", ] [[package]] name = "plotters-backend" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" [[package]] name = "plotters-svg" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" dependencies = [ "plotters-backend", ] [[package]] name = "powerfmt" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "pretty_assertions" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427" dependencies = [ "ansi_term", "ctor", "difference", "output_vt100", ] [[package]] name = "proc-macro2" version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" dependencies = [ "bit-set", "bit-vec", "bitflags 2.5.0", "lazy_static", "num-traits", "rand", "rand_chacha", "rand_xorshift", "regex-syntax", "rusty-fork", "tempfile", "unarray", ] [[package]] name = "quick-error" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] [[package]] name = "radium" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", ] [[package]] name = "rand_chacha" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core", ] [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] [[package]] name = "rand_xorshift" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ "rand_core", ] [[package]] name = "rayon" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", ] [[package]] name = "rayon-core" version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils", ] [[package]] name = "regex" version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "rustix" version = "0.38.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" dependencies = [ "bitflags 2.5.0", "errno", "libc", "linux-raw-sys", "windows-sys", ] [[package]] name = "rusty-fork" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" dependencies = [ "fnv", "quick-error", "tempfile", "wait-timeout", ] [[package]] name = "ryu" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "same-file" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ "winapi-util", ] [[package]] name = "serde" version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" dependencies = [ "serde", ] [[package]] name = "serde_cbor" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" dependencies = [ "half", "serde", ] [[package]] name = "serde_derive" version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", "syn 2.0.57", ] [[package]] name = "serde_json" version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" dependencies = [ "indexmap 2.2.6", "itoa", "ryu", "serde", ] [[package]] name = "serde_with" version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" dependencies = [ "serde", "serde_with_macros 1.5.2", ] [[package]] name = "serde_with" version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee80b0e361bbf88fd2f6e242ccd19cfda072cb0faa6ae694ecee08199938569a" dependencies = [ "base64 0.21.7", "chrono", "hex", "indexmap 1.9.3", "indexmap 2.2.6", "serde", "serde_derive", "serde_json", "serde_with_macros 3.7.0", "time", ] [[package]] name = "serde_with_macros" version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" dependencies = [ "darling 0.13.4", "proc-macro2", "quote", "syn 1.0.109", ] [[package]] name = "serde_with_macros" version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6561dc161a9224638a31d876ccdfefbc1df91d3f3a8342eddb35f055d48c7655" dependencies = [ "darling 0.20.8", "proc-macro2", "quote", "syn 2.0.57", ] [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "syn" version = "2.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11a6ae1e52eb25aab8f3fb9fca13be982a373b8f1157ca14b897a825ba4a2d35" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "tap" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", "rustix", "windows-sys", ] [[package]] name = "textwrap" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" dependencies = [ "unicode-width", ] [[package]] name = "time" version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", "serde", "time-core", "time-macros", ] [[package]] name = "time-core" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" dependencies = [ "num-conv", "time-core", ] [[package]] name = "tinytemplate" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" dependencies = [ "serde", "serde_json", ] [[package]] name = "unarray" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-width" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "uuid" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ "getrandom", "serde", ] [[package]] name = "uuid" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ "getrandom", "serde", ] [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wait-timeout" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" dependencies = [ "libc", ] [[package]] name = "walkdir" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", ] [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", "syn 2.0.57", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", "syn 2.0.57", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "web-sys" version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ "windows-targets", ] [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" [[package]] name = "windows_x86_64_msvc" version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" [[package]] name = "wyz" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" dependencies = [ "tap", ] [[package]] name = "zerocopy" version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", "syn 2.0.57", ] bson-2.10.0/Cargo.toml0000644000000060340000000000100100560ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "bson" version = "2.10.0" authors = [ "Y. T. Chung ", "Kevin Yeh ", "Saghm Rossi ", "Patrick Freed ", "Isabel Atkinson ", "Abraham Egnor ", ] exclude = [ "etc/**", "examples/**", "fuzz/**", "serde-tests/**", "src/tests/**", "rustfmt.toml", ".travis.yml", ".evergreen/**", ".gitignore", ] description = "Encoding and decoding support for BSON in Rust" readme = "README.md" keywords = [ "bson", "mongodb", "serde", "serialization", "deserialization", ] categories = ["encoding"] license = "MIT" repository = "https://github.com/mongodb/bson-rust" [package.metadata.docs.rs] all-features = true rustdoc-args = [ "--cfg", "docsrs", ] [lib] name = "bson" [dependencies.ahash] version = "0.8.0" [dependencies.base64] version = "0.13.0" [dependencies.bitvec] version = "1.0.1" [dependencies.chrono] version = "0.4.15" features = ["std"] optional = true default-features = false [dependencies.hex] version = "0.4.2" [dependencies.indexmap] version = "2.1.0" [dependencies.once_cell] version = "1.5.1" [dependencies.rand] version = "0.8" [dependencies.serde] version = "1.0" features = ["derive"] [dependencies.serde_bytes] version = "0.11.5" [dependencies.serde_json] version = "1.0" features = ["preserve_order"] [dependencies.serde_with] version = "1.3.1" optional = true [dependencies.serde_with-3] version = "3.1.0" optional = true package = "serde_with" [dependencies.time] version = "0.3.9" features = [ "formatting", "parsing", "macros", "large-dates", ] [dependencies.uuid] version = "1.1.2" features = [ "serde", "v4", ] [dependencies.uuid-0_8] version = "0.8.1" features = [ "serde", "v4", ] optional = true package = "uuid" [dev-dependencies.assert_matches] version = "1.2" [dev-dependencies.chrono] version = "0.4" features = [ "serde", "clock", "std", ] default-features = false [dev-dependencies.criterion] version = "0.3.0" [dev-dependencies.pretty_assertions] version = "0.6.1" [dev-dependencies.proptest] version = "1.0.0" [dev-dependencies.serde_bytes] version = "0.11" [features] chrono-0_4 = ["chrono"] default = [] time-0_3 = [] uuid-1 = [] [target."cfg(all(target_arch = \"wasm32\", target_os = \"unknown\"))".dependencies.js-sys] version = "0.3" [target."cfg(all(target_arch = \"wasm32\", target_os = \"unknown\"))".dev-dependencies.getrandom] version = "0.2" features = ["js"] bson-2.10.0/Cargo.toml.orig000064400000000000000000000054241046102023000135410ustar 00000000000000[package] name = "bson" version = "2.10.0" authors = [ "Y. T. Chung ", "Kevin Yeh ", "Saghm Rossi ", "Patrick Freed ", "Isabel Atkinson ", "Abraham Egnor ", ] description = "Encoding and decoding support for BSON in Rust" license = "MIT" readme = "README.md" repository = "https://github.com/mongodb/bson-rust" edition = "2018" keywords = ["bson", "mongodb", "serde", "serialization", "deserialization"] categories = ["encoding"] # By default cargo include everything git include # cargo diet can help to manage what's not useful. exclude = [ "etc/**", "examples/**", "fuzz/**", "serde-tests/**", "src/tests/**", "rustfmt.toml", ".travis.yml", ".evergreen/**", ".gitignore" ] [features] default = [] # if enabled, include API for interfacing with chrono 0.4 chrono-0_4 = ["chrono"] # if enabled, include API for interfacing with uuid 0.8 # This is commented out because Cargo implicitly adds this feature since # uuid-0_8 is also an optional dependency. # uuid-0_8 = [] # if enabled, include API for interfacing with uuid 1.x uuid-1 = [] # if enabled, include API for interfacing with time 0.3 time-0_3 = [] # if enabled, include serde_with interop. # should be used in conjunction with chrono-0_4 or uuid-0_8. # it's commented out here because Cargo implicitly adds a feature flag for # all optional dependencies. # serde_with [lib] name = "bson" [dependencies] ahash = "0.8.0" chrono = { version = "0.4.15", features = ["std"], default-features = false, optional = true } rand = "0.8" serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", features = ["preserve_order"] } indexmap = "2.1.0" hex = "0.4.2" base64 = "0.13.0" once_cell = "1.5.1" uuid-0_8 = { package = "uuid", version = "0.8.1", features = ["serde", "v4"], optional = true } uuid = { version = "1.1.2", features = ["serde", "v4"] } serde_bytes = "0.11.5" serde_with = { version = "1.3.1", optional = true } serde_with-3 = { package = "serde_with", version = "3.1.0", optional = true } time = { version = "0.3.9", features = ["formatting", "parsing", "macros", "large-dates"] } bitvec = "1.0.1" [target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies] js-sys = "0.3" [dev-dependencies] assert_matches = "1.2" criterion = "0.3.0" pretty_assertions = "0.6.1" proptest = "1.0.0" serde_bytes = "0.11" chrono = { version = "0.4", features = ["serde", "clock", "std"], default-features = false } [target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dev-dependencies] getrandom = { version = "0.2", features = ["js"] } [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] bson-2.10.0/LICENSE000064400000000000000000000021141046102023000116500ustar 00000000000000The MIT License (MIT) Copyright (c) 2015 Y. T. CHUNG Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. bson-2.10.0/README.md000064400000000000000000000305111046102023000121240ustar 00000000000000# bson [![crates.io](https://img.shields.io/crates/v/bson.svg)](https://crates.io/crates/bson) [![docs.rs](https://docs.rs/mongodb/badge.svg)](https://docs.rs/bson) [![crates.io](https://img.shields.io/crates/l/bson.svg)](https://crates.io/crates/bson) Encoding and decoding support for BSON in Rust ## Index - [Installation](#installation) - [Requirements](#requirements) - [Importing](#importing) - [Feature flags](#feature-flags) - [Useful links](#useful-links) - [Overview of BSON Format](#overview-of-the-bson-format) - [Usage](#usage) - [BSON Values](#bson-values) - [BSON Documents](#bson-documents) - [Modeling BSON with strongly typed data structures](#modeling-bson-with-strongly-typed-data-structures) - [Working with datetimes](#working-with-datetimes) - [Working with UUIDs](#working-with-uuids) - [WASM support](#wasm-support) - [Contributing](#contributing) - [Running the Tests](#running-the-tests) - [Continuous Integration](#continuous-integration) ## Useful links - [API Documentation](https://docs.rs/bson/) - [Serde Documentation](https://serde.rs/) ## Installation ### Requirements - Rust 1.48+ ### Importing This crate is available on [crates.io](https://crates.io/crates/bson). To use it in your application, simply add it to your project's `Cargo.toml`. ```toml [dependencies] bson = "2.10.0" ``` Note that if you are using `bson` through the `mongodb` crate, you do not need to specify it in your `Cargo.toml`, since the `mongodb` crate already re-exports it. #### Feature Flags | Feature | Description | Extra dependencies | Default | | :----------- | :---------------------------------------------------------------------------------------------------------- | :----------------- | :------ | | `chrono-0_4` | Enable support for v0.4 of the [`chrono`](https://docs.rs/chrono/0.4) crate in the public API. | n/a | no | | `uuid-0_8` | Enable support for v0.8 of the [`uuid`](https://docs.rs/uuid/0.8) crate in the public API. | n/a | no | | `uuid-1` | Enable support for v1.x of the [`uuid`](https://docs.rs/uuid/1.0) crate in the public API. | n/a | no | | `serde_with` | Enable [`serde_with`](https://docs.rs/serde_with/1.x) 1.x integrations for `bson::DateTime` and `bson::Uuid`.| serde_with | no | | `serde_with-3` | Enable [`serde_with`](https://docs.rs/serde_with/3.x) 3.x integrations for `bson::DateTime` and `bson::Uuid`.| serde_with | no | ## Overview of the BSON Format BSON, short for Binary JSON, is a binary-encoded serialization of JSON-like documents. Like JSON, BSON supports the embedding of documents and arrays within other documents and arrays. BSON also contains extensions that allow representation of data types that are not part of the JSON spec. For example, BSON has a datetime type and a binary data type. ```text // JSON equivalent {"hello": "world"} // BSON encoding \x16\x00\x00\x00 // total document size \x02 // 0x02 = type String hello\x00 // field name \x06\x00\x00\x00world\x00 // field value \x00 // 0x00 = type EOO ('end of object') ``` BSON is the primary data representation for [MongoDB](https://www.mongodb.com/), and this crate is used in the [`mongodb`](https://docs.rs/mongodb/latest/mongodb/) driver crate in its API and implementation. For more information about BSON itself, see [bsonspec.org](http://bsonspec.org). ## Usage ### BSON values Many different types can be represented as a BSON value, including 32-bit and 64-bit signed integers, 64 bit floating point numbers, strings, datetimes, embedded documents, and more. To see a full list of possible BSON values, see the [BSON specification](http://bsonspec.org/spec.html). The various possible BSON values are modeled in this crate by the [`Bson`](https://docs.rs/bson/latest/bson/enum.Bson.html) enum. #### Creating [`Bson`](https://docs.rs/bson/latest/bson/enum.Bson.html) instances [`Bson`](https://docs.rs/bson/latest/bson/enum.Bson.html) values can be instantiated directly or via the [`bson!`](https://docs.rs/bson/latest/bson/macro.bson.html) macro: ```rust let string = Bson::String("hello world".to_string()); let int = Bson::Int32(5); let array = Bson::Array(vec![Bson::Int32(5), Bson::Boolean(false)]); let string: Bson = "hello world".into(); let int: Bson = 5i32.into(); let string = bson!("hello world"); let int = bson!(5); let array = bson!([5, false]); ``` [`bson!`](https://docs.rs/bson/latest/bson/macro.bson.html) supports both array and object literals, and it automatically converts any values specified to [`Bson`](https://docs.rs/bson/latest/bson/enum.Bson.html), provided they are `Into`. #### [`Bson`](https://docs.rs/bson/latest/bson/enum.Bson.html) value unwrapping [`Bson`](https://docs.rs/bson/latest/bson/enum.Bson.html) has a number of helper methods for accessing the underlying native Rust types. These helpers can be useful in circumstances in which the specific type of a BSON value is known ahead of time. e.g.: ```rust let value = Bson::Int32(5); let int = value.as_i32(); // Some(5) let bool = value.as_bool(); // None let value = bson!([true]); let array = value.as_array(); // Some(&Vec) ``` ### BSON documents BSON documents are ordered maps of UTF-8 encoded strings to BSON values. They are logically similar to JSON objects in that they can contain subdocuments, arrays, and values of several different types. This crate models BSON documents via the [`Document`](https://docs.rs/bson/latest/bson/document/struct.Document.html) struct. #### Creating [`Document`](https://docs.rs/bson/latest/bson/document/struct.Document.html)s [`Document`](https://docs.rs/bson/latest/bson/document/struct.Document.html)s can be created directly either from a byte reader containing BSON data or via the `doc!` macro: ```rust let mut bytes = hex::decode("0C0000001069000100000000").unwrap(); let doc = Document::from_reader(&mut bytes.as_slice()).unwrap(); // { "i": 1 } let doc = doc! { "hello": "world", "int": 5, "subdoc": { "cat": true }, }; ``` [`doc!`](https://docs.rs/bson/latest/bson/macro.doc.html) works similarly to [`bson!`](https://docs.rs/bson/latest/bson/macro.bson.html), except that it always returns a [`Document`](https://docs.rs/bson/latest/bson/document/struct.Document.html) rather than a [`Bson`](https://docs.rs/bson/latest/bson/enum.Bson.html). #### [`Document`](https://docs.rs/bson/latest/bson/document/struct.Document.html) member access [`Document`](https://docs.rs/bson/latest/bson/document/struct.Document.html) has a number of methods on it to facilitate member access: ```rust let doc = doc! { "string": "string", "bool": true, "i32": 5, "doc": { "x": true }, }; // attempt get values as untyped Bson let none = doc.get("asdfadsf"); // None let value = doc.get("string"); // Some(&Bson::String("string")) // attempt to get values with explicit typing let string = doc.get_str("string"); // Ok("string") let subdoc = doc.get_document("doc"); // Some(Document({ "x": true })) let error = doc.get_i64("i32"); // Err(...) ``` ### Modeling BSON with strongly typed data structures While it is possible to work with documents and BSON values directly, it will often introduce a lot of boilerplate for verifying the necessary keys are present and their values are the correct types. [`serde`](https://serde.rs/) provides a powerful way of mapping BSON data into Rust data structures largely automatically, removing the need for all that boilerplate. e.g.: ```rust #[derive(Serialize, Deserialize)] struct Person { name: String, age: i32, phones: Vec, } // Some BSON input data as a `Bson`. let bson_data: Bson = bson!({ "name": "John Doe", "age": 43, "phones": [ "+44 1234567", "+44 2345678" ] }); // Deserialize the Person struct from the BSON data, automatically // verifying that the necessary keys are present and that they are of // the correct types. let mut person: Person = bson::from_bson(bson_data).unwrap(); // Do things just like with any other Rust data structure. println!("Redacting {}'s record.", person.name); person.name = "REDACTED".to_string(); // Get a serialized version of the input data as a `Bson`. let redacted_bson = bson::to_bson(&person).unwrap(); ``` Any types that implement `Serialize` and `Deserialize` can be used in this way. Doing so helps separate the "business logic" that operates over the data from the (de)serialization logic that translates the data to/from its serialized form. This can lead to more clear and concise code that is also less error prone. ### Working with datetimes The BSON format includes a datetime type, which is modeled in this crate by the [`bson::DateTime`](https://docs.rs/bson/latest/bson/struct.DateTime.html) struct, and the `Serialize` and `Deserialize` implementations for this struct produce and parse BSON datetimes when serializing to or deserializing from BSON. The popular crate [`chrono`](https://docs.rs/chrono) also provides a `DateTime` type, but its `Serialize` and `Deserialize` implementations operate on strings instead, so when using it with BSON, the BSON datetime type is not used. To work around this, the `chrono-0_4` feature flag can be enabled. This flag exposes a number of convenient conversions between `bson::DateTime` and `chrono::DateTime`, including the [`chrono_datetime_as_bson_datetime`](https://docs.rs/bson/latest/bson/serde_helpers/chrono_datetime_as_bson_datetime/index.html) serde helper, which can be used to (de)serialize `chrono::DateTime`s to/from BSON datetimes, and the `From` implementation for `Bson`, which allows `chrono::DateTime` values to be used in the `doc!` and `bson!` macros. e.g. ``` rust use serde::{Serialize, Deserialize}; #[derive(Serialize, Deserialize)] struct Foo { // serializes as a BSON datetime. date_time: bson::DateTime, // serializes as an RFC 3339 / ISO-8601 string. chrono_datetime: chrono::DateTime, // serializes as a BSON datetime. // this requires the "chrono-0_4" feature flag #[serde(with = "bson::serde_helpers::chrono_datetime_as_bson_datetime")] chrono_as_bson: chrono::DateTime, } // this automatic conversion also requires the "chrono-0_4" feature flag let query = doc! { "created_at": chrono::Utc::now(), }; ``` ### Working with UUIDs See the module-level documentation for the [`bson::uuid` module](https://docs.rs/bson/latest/bson/uuid). ### WASM support This crate compiles to the `wasm32-unknown-unknown` target; when doing so, the `js-sys` crate is used for the current timestamp component of `ObjectId` generation. ## Minimum supported Rust version (MSRV) The MSRV for this crate is currently 1.64.0. This will be rarely be increased, and if it ever is, it will only happen in a minor or major version release. ## Contributing We encourage and would happily accept contributions in the form of GitHub pull requests. Before opening one, be sure to run the tests locally; check out the [testing section](#running-the-tests) for information on how to do that. Once you open a pull request, your branch will be run against the same testing matrix that we use for our [continuous integration](#continuous-integration) system, so it is usually sufficient to only run the integration tests locally against a standalone. Remember to always run the linter tests before opening a pull request. ## Running the tests ### Integration and unit tests To actually run the tests, you can use `cargo` like you would in any other crate: ```bash cargo test --verbose # runs against localhost:27017 ``` ### Linter Tests Our linter tests use the nightly version of `rustfmt` to verify that the source is formatted properly and the stable version of `clippy` to statically detect any common mistakes. You can use `rustup` to install them both: ```bash rustup component add clippy --toolchain stable rustup component add rustfmt --toolchain nightly ``` To run the linter tests, run the `check-clippy.sh` and `check-rustfmt.sh` scripts in the `.evergreen` directory: ```bash bash .evergreen/check-clippy.sh && bash .evergreen/check-rustfmt.sh ``` ## Continuous Integration Commits to main are run automatically on [evergreen](https://evergreen.mongodb.com/waterfall/rust-bson). bson-2.10.0/clippy.toml000064400000000000000000000000171046102023000130400ustar 00000000000000msrv = "1.64.0"bson-2.10.0/src/binary.rs000064400000000000000000000064721046102023000132770ustar 00000000000000use crate::{spec::BinarySubtype, Document, RawBinaryRef}; use std::{ convert::TryFrom, error, fmt::{self, Display}, }; /// Represents a BSON binary value. #[derive(Debug, Clone, PartialEq)] pub struct Binary { /// The subtype of the bytes. pub subtype: BinarySubtype, /// The binary bytes. pub bytes: Vec, } impl Display for Binary { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!( fmt, "Binary({:#x}, {})", u8::from(self.subtype), base64::encode(&self.bytes) ) } } impl Binary { /// Creates a [`Binary`] from a base64 string and optional [`BinarySubtype`]. If the /// `subtype` argument is [`None`], the [`Binary`] constructed will default to /// [`BinarySubtype::Generic`]. /// /// ```rust /// # use bson::{Binary, binary::Result}; /// # fn example() -> Result<()> { /// let input = base64::encode("hello"); /// let binary = Binary::from_base64(input, None)?; /// println!("{:?}", binary); /// // binary: Binary { subtype: Generic, bytes: [104, 101, 108, 108, 111] } /// # Ok(()) /// # } /// ``` pub fn from_base64( input: impl AsRef, subtype: impl Into>, ) -> Result { let bytes = base64::decode(input.as_ref()).map_err(|e| Error::DecodingError { message: e.to_string(), })?; let subtype = match subtype.into() { Some(s) => s, None => BinarySubtype::Generic, }; Ok(Binary { subtype, bytes }) } pub(crate) fn from_extended_doc(doc: &Document) -> Option { let binary_doc = doc.get_document("$binary").ok()?; if let Ok(bytes) = binary_doc.get_str("base64") { let bytes = base64::decode(bytes).ok()?; let subtype = binary_doc.get_str("subType").ok()?; let subtype = hex::decode(subtype).ok()?; if subtype.len() == 1 { Some(Self { bytes, subtype: subtype[0].into(), }) } else { None } } else { // in non-human-readable mode, RawBinary will serialize as // { "$binary": { "bytes": , "subType": } }; let binary = binary_doc.get_binary_generic("bytes").ok()?; let subtype = binary_doc.get_i32("subType").ok()?; Some(Self { bytes: binary.clone(), subtype: u8::try_from(subtype).ok()?.into(), }) } } /// Borrow the contents as a [`RawBinaryRef`]. pub fn as_raw_binary(&self) -> RawBinaryRef<'_> { RawBinaryRef { bytes: self.bytes.as_slice(), subtype: self.subtype, } } } /// Possible errors that can arise during [`Binary`] construction. #[derive(Clone, Debug)] #[non_exhaustive] pub enum Error { /// While trying to decode from base64, an error was returned. DecodingError { message: String }, } impl error::Error for Error {} impl std::fmt::Display for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { Error::DecodingError { message: m } => fmt.write_str(m), } } } pub type Result = std::result::Result; bson-2.10.0/src/bson.rs000064400000000000000000001057351046102023000127560ustar 00000000000000// The MIT License (MIT) // Copyright (c) 2015 Y. T. Chung // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in // the Software without restriction, including without limitation the rights to // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of // the Software, and to permit persons to whom the Software is furnished to do so, // subject to the following conditions: // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. //! BSON definition use std::{ convert::{TryFrom, TryInto}, fmt::{self, Debug, Display, Formatter}, }; use serde_json::{json, Value}; pub use crate::document::Document; use crate::{ oid::{self, ObjectId}, spec::{BinarySubtype, ElementType}, Binary, Decimal128, }; /// Possible BSON value types. #[derive(Clone, Default, PartialEq)] pub enum Bson { /// 64-bit binary floating point Double(f64), /// UTF-8 string String(String), /// Array Array(Array), /// Embedded document Document(Document), /// Boolean value Boolean(bool), /// Null value #[default] Null, /// Regular expression RegularExpression(Regex), /// JavaScript code JavaScriptCode(String), /// JavaScript code w/ scope JavaScriptCodeWithScope(JavaScriptCodeWithScope), /// 32-bit signed integer Int32(i32), /// 64-bit signed integer Int64(i64), /// Timestamp Timestamp(Timestamp), /// Binary data Binary(Binary), /// [ObjectId](http://dochub.mongodb.org/core/objectids) ObjectId(oid::ObjectId), /// UTC datetime DateTime(crate::DateTime), /// Symbol (Deprecated) Symbol(String), /// [128-bit decimal floating point](https://github.com/mongodb/specifications/blob/master/source/bson-decimal128/decimal128.rst) Decimal128(Decimal128), /// Undefined value (Deprecated) Undefined, /// Max key MaxKey, /// Min key MinKey, /// DBPointer (Deprecated) DbPointer(DbPointer), } /// Alias for `Vec`. pub type Array = Vec; impl Display for Bson { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match *self { Bson::Double(f) => write!(fmt, "{}", f), Bson::String(ref s) => write!(fmt, "\"{}\"", s), Bson::Array(ref vec) => { fmt.write_str("[")?; let mut first = true; for bson in vec { if !first { fmt.write_str(", ")?; } write!(fmt, "{}", bson)?; first = false; } fmt.write_str("]") } Bson::Document(ref doc) => write!(fmt, "{}", doc), Bson::Boolean(b) => write!(fmt, "{}", b), Bson::Null => write!(fmt, "null"), Bson::RegularExpression(ref x) => write!(fmt, "{}", x), Bson::JavaScriptCode(ref code) | Bson::JavaScriptCodeWithScope(JavaScriptCodeWithScope { ref code, .. }) => { fmt.write_str(code) } Bson::Int32(i) => write!(fmt, "{}", i), Bson::Int64(i) => write!(fmt, "{}", i), Bson::Timestamp(ref x) => write!(fmt, "{}", x), Bson::Binary(ref x) => write!(fmt, "{}", x), Bson::ObjectId(ref id) => write!(fmt, "ObjectId(\"{}\")", id), Bson::DateTime(date_time) => write!(fmt, "DateTime(\"{}\")", date_time), Bson::Symbol(ref sym) => write!(fmt, "Symbol(\"{}\")", sym), Bson::Decimal128(ref d) => write!(fmt, "{}", d), Bson::Undefined => write!(fmt, "undefined"), Bson::MinKey => write!(fmt, "MinKey"), Bson::MaxKey => write!(fmt, "MaxKey"), Bson::DbPointer(DbPointer { ref namespace, ref id, }) => write!(fmt, "DbPointer({}, {})", namespace, id), } } } impl Debug for Bson { fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { match *self { Bson::Double(f) => fmt.debug_tuple("Double").field(&f).finish(), Bson::String(ref s) => fmt.debug_tuple("String").field(s).finish(), Bson::Array(ref vec) => { write!(fmt, "Array(")?; Debug::fmt(vec, fmt)?; write!(fmt, ")") } Bson::Document(ref doc) => Debug::fmt(doc, fmt), Bson::Boolean(b) => fmt.debug_tuple("Boolean").field(&b).finish(), Bson::Null => write!(fmt, "Null"), Bson::RegularExpression(ref regex) => Debug::fmt(regex, fmt), Bson::JavaScriptCode(ref code) => { fmt.debug_tuple("JavaScriptCode").field(code).finish() } Bson::JavaScriptCodeWithScope(ref code) => Debug::fmt(code, fmt), Bson::Int32(i) => fmt.debug_tuple("Int32").field(&i).finish(), Bson::Int64(i) => fmt.debug_tuple("Int64").field(&i).finish(), Bson::Timestamp(ref t) => Debug::fmt(t, fmt), Bson::Binary(ref b) => Debug::fmt(b, fmt), Bson::ObjectId(ref id) => Debug::fmt(id, fmt), Bson::DateTime(ref date_time) => Debug::fmt(date_time, fmt), Bson::Symbol(ref sym) => fmt.debug_tuple("Symbol").field(sym).finish(), Bson::Decimal128(ref d) => Debug::fmt(d, fmt), Bson::Undefined => write!(fmt, "Undefined"), Bson::MinKey => write!(fmt, "MinKey"), Bson::MaxKey => write!(fmt, "MaxKey"), Bson::DbPointer(ref pointer) => Debug::fmt(pointer, fmt), } } } impl From for Bson { fn from(a: f32) -> Bson { Bson::Double(a.into()) } } impl From for Bson { fn from(a: f64) -> Bson { Bson::Double(a) } } impl From<&str> for Bson { fn from(s: &str) -> Bson { Bson::String(s.to_owned()) } } impl From for Bson { fn from(a: String) -> Bson { Bson::String(a) } } impl From for Bson { fn from(a: Document) -> Bson { Bson::Document(a) } } impl From for Bson { fn from(a: bool) -> Bson { Bson::Boolean(a) } } impl From for Bson { fn from(regex: Regex) -> Bson { Bson::RegularExpression(regex) } } impl From for Bson { fn from(code_with_scope: JavaScriptCodeWithScope) -> Bson { Bson::JavaScriptCodeWithScope(code_with_scope) } } impl From for Bson { fn from(binary: Binary) -> Bson { Bson::Binary(binary) } } impl From for Bson { fn from(ts: Timestamp) -> Bson { Bson::Timestamp(ts) } } impl From<&T> for Bson where T: Clone + Into, { fn from(t: &T) -> Bson { t.clone().into() } } impl From<&mut T> for Bson where for<'a> &'a T: Into, { fn from(t: &mut T) -> Bson { (&*t).into() } } impl From> for Bson where T: Into, { fn from(v: Vec) -> Bson { Bson::Array(v.into_iter().map(|val| val.into()).collect()) } } impl From<&[T]> for Bson where T: Clone + Into, { fn from(s: &[T]) -> Bson { Bson::Array(s.iter().cloned().map(|val| val.into()).collect()) } } impl> ::std::iter::FromIterator for Bson { /// # Examples /// /// ``` /// use std::iter::FromIterator; /// use bson::Bson; /// /// let x: Bson = Bson::from_iter(vec!["lorem", "ipsum", "dolor"]); /// // or /// let x: Bson = vec!["lorem", "ipsum", "dolor"].into_iter().collect(); /// ``` fn from_iter>(iter: I) -> Self { Bson::Array(iter.into_iter().map(Into::into).collect()) } } impl From for Bson { fn from(a: i32) -> Bson { Bson::Int32(a) } } impl From for Bson { fn from(a: i64) -> Bson { Bson::Int64(a) } } impl From for Bson { fn from(a: u32) -> Bson { if let Ok(i) = i32::try_from(a) { Bson::Int32(i) } else { Bson::Int64(a.into()) } } } impl From<[u8; 12]> for Bson { fn from(a: [u8; 12]) -> Bson { Bson::ObjectId(oid::ObjectId::from_bytes(a)) } } impl From for Bson { fn from(a: oid::ObjectId) -> Bson { Bson::ObjectId(a) } } #[cfg(feature = "time-0_3")] #[cfg_attr(docsrs, doc(cfg(feature = "time-0_3")))] impl From for Bson { fn from(a: time::OffsetDateTime) -> Bson { Bson::DateTime(crate::DateTime::from(a)) } } #[cfg(feature = "chrono-0_4")] #[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))] impl From> for Bson { fn from(a: chrono::DateTime) -> Bson { Bson::DateTime(crate::DateTime::from(a)) } } #[cfg(feature = "uuid-0_8")] #[cfg_attr(docsrs, doc(cfg(feature = "uuid-0_8")))] impl From for Bson { fn from(uuid: uuid_0_8::Uuid) -> Self { Bson::Binary(uuid.into()) } } #[cfg(feature = "uuid-1")] #[cfg_attr(docsrs, doc(cfg(feature = "uuid-1")))] impl From for Bson { fn from(uuid: uuid::Uuid) -> Self { Bson::Binary(uuid.into()) } } impl From for Bson { fn from(dt: crate::DateTime) -> Self { Bson::DateTime(dt) } } impl From for Bson { fn from(a: DbPointer) -> Bson { Bson::DbPointer(a) } } impl From for Bson { fn from(d: Decimal128) -> Self { Bson::Decimal128(d) } } impl From> for Bson where T: Into, { fn from(a: Option) -> Bson { match a { None => Bson::Null, Some(t) => t.into(), } } } /// This will create the [relaxed Extended JSON v2](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/) representation of the provided [`Bson`](../enum.Bson.html). impl From for Value { fn from(bson: Bson) -> Self { bson.into_relaxed_extjson() } } impl Bson { /// Converts the Bson value into its [relaxed extended JSON representation](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/). /// /// Note: If this method is called on a case which contains a `Decimal128` value, it will panic. pub fn into_relaxed_extjson(self) -> Value { match self { Bson::Double(v) if v.is_nan() => { let s = if v.is_sign_negative() { "-NaN" } else { "NaN" }; json!({ "$numberDouble": s }) } Bson::Double(v) if v.is_infinite() => { let s = if v.is_sign_negative() { "-Infinity" } else { "Infinity" }; json!({ "$numberDouble": s }) } Bson::Double(v) => json!(v), Bson::String(v) => json!(v), Bson::Array(v) => Value::Array(v.into_iter().map(Bson::into_relaxed_extjson).collect()), Bson::Document(v) => Value::Object( v.into_iter() .map(|(k, v)| (k, v.into_relaxed_extjson())) .collect(), ), Bson::Boolean(v) => json!(v), Bson::Null => Value::Null, Bson::RegularExpression(Regex { pattern, options }) => { let mut chars: Vec<_> = options.chars().collect(); chars.sort_unstable(); let options: String = chars.into_iter().collect(); json!({ "$regularExpression": { "pattern": pattern, "options": options, } }) } Bson::JavaScriptCode(code) => json!({ "$code": code }), Bson::JavaScriptCodeWithScope(JavaScriptCodeWithScope { code, scope }) => json!({ "$code": code, "$scope": scope, }), Bson::Int32(v) => v.into(), Bson::Int64(v) => v.into(), Bson::Timestamp(Timestamp { time, increment }) => json!({ "$timestamp": { "t": time, "i": increment, } }), Bson::Binary(Binary { subtype, ref bytes }) => { let tval: u8 = From::from(subtype); json!({ "$binary": { "base64": base64::encode(bytes), "subType": hex::encode([tval]), } }) } Bson::ObjectId(v) => json!({"$oid": v.to_hex()}), Bson::DateTime(v) if v.timestamp_millis() >= 0 && v.to_time_0_3().year() <= 9999 => { json!({ // Unwrap safety: timestamps in the guarded range can always be formatted. "$date": v.try_to_rfc3339_string().unwrap(), }) } Bson::DateTime(v) => json!({ "$date": { "$numberLong": v.timestamp_millis().to_string() }, }), Bson::Symbol(v) => json!({ "$symbol": v }), Bson::Decimal128(v) => json!({ "$numberDecimal": v.to_string() }), Bson::Undefined => json!({ "$undefined": true }), Bson::MinKey => json!({ "$minKey": 1 }), Bson::MaxKey => json!({ "$maxKey": 1 }), Bson::DbPointer(DbPointer { ref namespace, ref id, }) => json!({ "$dbPointer": { "$ref": namespace, "$id": { "$oid": id.to_hex() } } }), } } /// Converts the Bson value into its [canonical extended JSON representation](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/). pub fn into_canonical_extjson(self) -> Value { match self { Bson::Int32(i) => json!({ "$numberInt": i.to_string() }), Bson::Int64(i) => json!({ "$numberLong": i.to_string() }), Bson::Double(f) if f.is_normal() => { let mut s = f.to_string(); if f.fract() == 0.0 { s.push_str(".0"); } json!({ "$numberDouble": s }) } Bson::Double(f) if f == 0.0 => { let s = if f.is_sign_negative() { "-0.0" } else { "0.0" }; json!({ "$numberDouble": s }) } Bson::DateTime(date) => { json!({ "$date": { "$numberLong": date.timestamp_millis().to_string() } }) } Bson::Array(arr) => { Value::Array(arr.into_iter().map(Bson::into_canonical_extjson).collect()) } Bson::Document(arr) => Value::Object( arr.into_iter() .map(|(k, v)| (k, v.into_canonical_extjson())) .collect(), ), Bson::JavaScriptCodeWithScope(JavaScriptCodeWithScope { code, scope }) => json!({ "$code": code, "$scope": Bson::Document(scope).into_canonical_extjson(), }), other => other.into_relaxed_extjson(), } } /// Get the [`ElementType`] of this value. pub fn element_type(&self) -> ElementType { match *self { Bson::Double(..) => ElementType::Double, Bson::String(..) => ElementType::String, Bson::Array(..) => ElementType::Array, Bson::Document(..) => ElementType::EmbeddedDocument, Bson::Boolean(..) => ElementType::Boolean, Bson::Null => ElementType::Null, Bson::RegularExpression(..) => ElementType::RegularExpression, Bson::JavaScriptCode(..) => ElementType::JavaScriptCode, Bson::JavaScriptCodeWithScope(..) => ElementType::JavaScriptCodeWithScope, Bson::Int32(..) => ElementType::Int32, Bson::Int64(..) => ElementType::Int64, Bson::Timestamp(..) => ElementType::Timestamp, Bson::Binary(..) => ElementType::Binary, Bson::ObjectId(..) => ElementType::ObjectId, Bson::DateTime(..) => ElementType::DateTime, Bson::Symbol(..) => ElementType::Symbol, Bson::Decimal128(..) => ElementType::Decimal128, Bson::Undefined => ElementType::Undefined, Bson::MaxKey => ElementType::MaxKey, Bson::MinKey => ElementType::MinKey, Bson::DbPointer(..) => ElementType::DbPointer, } } /// Converts to extended format. /// This function mainly used for [extended JSON format](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/). // TODO RUST-426: Investigate either removing this from the serde implementation or unifying // with the extended JSON implementation. pub(crate) fn into_extended_document(self, rawbson: bool) -> Document { match self { Bson::RegularExpression(Regex { ref pattern, ref options, }) => { let mut chars: Vec<_> = options.chars().collect(); chars.sort_unstable(); let options: String = chars.into_iter().collect(); doc! { "$regularExpression": { "pattern": pattern, "options": options, } } } Bson::JavaScriptCode(ref code) => { doc! { "$code": code, } } Bson::JavaScriptCodeWithScope(JavaScriptCodeWithScope { code, scope }) => { doc! { "$code": code, "$scope": scope, } } Bson::Timestamp(Timestamp { time, increment }) => { doc! { "$timestamp": { "t": time, "i": increment, } } } Bson::Binary(Binary { subtype, bytes }) => { let tval: u8 = From::from(subtype); if rawbson { doc! { "$binary": { "bytes": Binary { subtype: BinarySubtype::Generic, bytes }, "subType": Bson::Int32(tval.into()) } } } else { doc! { "$binary": { "base64": base64::encode(bytes), "subType": hex::encode([tval]), } } } } Bson::ObjectId(ref v) => { doc! { "$oid": v.to_string(), } } Bson::DateTime(v) if rawbson => doc! { "$date": v.timestamp_millis(), }, Bson::DateTime(v) if v.timestamp_millis() >= 0 && v.to_time_0_3().year() <= 9999 => { doc! { // Unwrap safety: timestamps in the guarded range can always be formatted. "$date": v.try_to_rfc3339_string().unwrap(), } } Bson::DateTime(v) => doc! { "$date": { "$numberLong": v.timestamp_millis().to_string() }, }, Bson::Symbol(ref v) => { doc! { "$symbol": v.to_owned(), } } Bson::Undefined => { doc! { "$undefined": true, } } Bson::MinKey => { doc! { "$minKey": 1, } } Bson::MaxKey => { doc! { "$maxKey": 1, } } Bson::DbPointer(DbPointer { ref namespace, ref id, }) => { doc! { "$dbPointer": { "$ref": namespace, "$id": { "$oid": id.to_string() } } } } _ => panic!("Attempted conversion of invalid data type: {}", self), } } pub(crate) fn from_extended_document(doc: Document) -> Bson { if doc.len() > 2 { return Bson::Document(doc); } let mut keys: Vec<_> = doc.keys().map(|s| s.as_str()).collect(); keys.sort_unstable(); match keys.as_slice() { ["$oid"] => { if let Ok(oid) = doc.get_str("$oid") { if let Ok(oid) = ObjectId::parse_str(oid) { return Bson::ObjectId(oid); } } } ["$symbol"] => { if let Ok(symbol) = doc.get_str("$symbol") { return Bson::Symbol(symbol.into()); } } ["$numberInt"] => { if let Ok(i) = doc.get_str("$numberInt") { if let Ok(i) = i.parse() { return Bson::Int32(i); } } } ["$numberLong"] => { if let Ok(i) = doc.get_str("$numberLong") { if let Ok(i) = i.parse() { return Bson::Int64(i); } } } ["$numberDouble"] => match doc.get_str("$numberDouble") { Ok("Infinity") => return Bson::Double(std::f64::INFINITY), Ok("-Infinity") => return Bson::Double(std::f64::NEG_INFINITY), Ok("NaN") => return Bson::Double(std::f64::NAN), Ok(other) => { if let Ok(d) = other.parse() { return Bson::Double(d); } } _ => {} }, ["$numberDecimal"] => { if let Ok(d) = doc.get_str("$numberDecimal") { if let Ok(d) = d.parse() { return Bson::Decimal128(d); } } } ["$numberDecimalBytes"] => { if let Ok(bytes) = doc.get_binary_generic("$numberDecimalBytes") { if let Ok(b) = bytes.clone().try_into() { return Bson::Decimal128(Decimal128 { bytes: b }); } } } ["$binary"] => { if let Some(binary) = Binary::from_extended_doc(&doc) { return Bson::Binary(binary); } } ["$code"] => { if let Ok(code) = doc.get_str("$code") { return Bson::JavaScriptCode(code.into()); } } ["$code", "$scope"] => { if let Ok(code) = doc.get_str("$code") { if let Ok(scope) = doc.get_document("$scope") { return Bson::JavaScriptCodeWithScope(JavaScriptCodeWithScope { code: code.into(), scope: scope.clone(), }); } } } ["$timestamp"] => { if let Ok(timestamp) = doc.get_document("$timestamp") { if let Ok(t) = timestamp.get_i32("t") { if let Ok(i) = timestamp.get_i32("i") { return Bson::Timestamp(Timestamp { time: t as u32, increment: i as u32, }); } } if let Ok(t) = timestamp.get_i64("t") { if let Ok(i) = timestamp.get_i64("i") { if t >= 0 && i >= 0 && t <= (std::u32::MAX as i64) && i <= (std::u32::MAX as i64) { return Bson::Timestamp(Timestamp { time: t as u32, increment: i as u32, }); } } } } } ["$regularExpression"] => { if let Ok(regex) = doc.get_document("$regularExpression") { if let Ok(pattern) = regex.get_str("pattern") { if let Ok(options) = regex.get_str("options") { return Bson::RegularExpression(Regex::new(pattern, options)); } } } } ["$dbPointer"] => { if let Ok(db_pointer) = doc.get_document("$dbPointer") { if let Ok(ns) = db_pointer.get_str("$ref") { if let Ok(id) = db_pointer.get_object_id("$id") { return Bson::DbPointer(DbPointer { namespace: ns.into(), id, }); } } } } ["$date"] => { if let Ok(date) = doc.get_i64("$date") { return Bson::DateTime(crate::DateTime::from_millis(date)); } if let Ok(date) = doc.get_str("$date") { if let Ok(dt) = crate::DateTime::parse_rfc3339_str(date) { return Bson::DateTime(dt); } } } ["$minKey"] => { let min_key = doc.get("$minKey"); if min_key == Some(&Bson::Int32(1)) || min_key == Some(&Bson::Int64(1)) { return Bson::MinKey; } } ["$maxKey"] => { let max_key = doc.get("$maxKey"); if max_key == Some(&Bson::Int32(1)) || max_key == Some(&Bson::Int64(1)) { return Bson::MaxKey; } } ["$undefined"] => { if doc.get("$undefined") == Some(&Bson::Boolean(true)) { return Bson::Undefined; } } _ => {} }; Bson::Document( doc.into_iter() .map(|(k, v)| { let v = match v { Bson::Document(v) => Bson::from_extended_document(v), other => other, }; (k, v) }) .collect(), ) } } /// Value helpers impl Bson { /// If `self` is [`Double`](Bson::Double), return its value as an `f64`. Returns [`None`] /// otherwise. pub fn as_f64(&self) -> Option { match *self { Bson::Double(v) => Some(v), _ => None, } } /// If `self` is [`String`](Bson::String), return its value as a `&str`. Returns [`None`] /// otherwise. pub fn as_str(&self) -> Option<&str> { match *self { Bson::String(ref s) => Some(s), _ => None, } } /// If `self` is [`String`](Bson::String), return a mutable reference to its value as a [`str`]. /// Returns [`None`] otherwise. pub fn as_str_mut(&mut self) -> Option<&mut str> { match *self { Bson::String(ref mut s) => Some(s), _ => None, } } /// If `self` is [`Array`](Bson::Array), return its value. Returns [`None`] otherwise. pub fn as_array(&self) -> Option<&Array> { match *self { Bson::Array(ref v) => Some(v), _ => None, } } /// If `self` is [`Array`](Bson::Array), return a mutable reference to its value. Returns /// [`None`] otherwise. pub fn as_array_mut(&mut self) -> Option<&mut Array> { match *self { Bson::Array(ref mut v) => Some(v), _ => None, } } /// If `self` is [`Document`](Bson::Document), return its value. Returns [`None`] otherwise. pub fn as_document(&self) -> Option<&Document> { match *self { Bson::Document(ref v) => Some(v), _ => None, } } /// If `self` is [`Document`](Bson::Document), return a mutable reference to its value. Returns /// [`None`] otherwise. pub fn as_document_mut(&mut self) -> Option<&mut Document> { match *self { Bson::Document(ref mut v) => Some(v), _ => None, } } /// If `self` is [`Boolean`](Bson::Boolean), return its value. Returns [`None`] otherwise. pub fn as_bool(&self) -> Option { match *self { Bson::Boolean(v) => Some(v), _ => None, } } /// If `self` is [`Int32`](Bson::Int32), return its value. Returns [`None`] otherwise. pub fn as_i32(&self) -> Option { match *self { Bson::Int32(v) => Some(v), _ => None, } } /// If `self` is [`Int64`](Bson::Int64), return its value. Returns [`None`] otherwise. pub fn as_i64(&self) -> Option { match *self { Bson::Int64(v) => Some(v), _ => None, } } /// If `self` is [`ObjectId`](Bson::ObjectId), return its value. Returns [`None`] otherwise. pub fn as_object_id(&self) -> Option { match *self { Bson::ObjectId(v) => Some(v), _ => None, } } /// If `self` is [`ObjectId`](Bson::ObjectId), return a mutable reference to its value. Returns /// [`None`] otherwise. pub fn as_object_id_mut(&mut self) -> Option<&mut oid::ObjectId> { match *self { Bson::ObjectId(ref mut v) => Some(v), _ => None, } } /// If `self` is [`DateTime`](Bson::DateTime), return its value. Returns [`None`] otherwise. pub fn as_datetime(&self) -> Option<&crate::DateTime> { match *self { Bson::DateTime(ref v) => Some(v), _ => None, } } /// If `self` is [`DateTime`](Bson::DateTime), return a mutable reference to its value. Returns /// [`None`] otherwise. pub fn as_datetime_mut(&mut self) -> Option<&mut crate::DateTime> { match *self { Bson::DateTime(ref mut v) => Some(v), _ => None, } } /// If `self` is [`Symbol`](Bson::Symbol), return its value. Returns [`None`] otherwise. pub fn as_symbol(&self) -> Option<&str> { match *self { Bson::Symbol(ref v) => Some(v), _ => None, } } /// If `self` is [`Symbol`](Bson::Symbol), return a mutable reference to its value. Returns /// [`None`] otherwise. pub fn as_symbol_mut(&mut self) -> Option<&mut str> { match *self { Bson::Symbol(ref mut v) => Some(v), _ => None, } } /// If `self` is [`Timestamp`](Bson::Timestamp), return its value. Returns [`None`] otherwise. pub fn as_timestamp(&self) -> Option { match *self { Bson::Timestamp(timestamp) => Some(timestamp), _ => None, } } /// If `self` is [`Null`](Bson::Null), return `()`. Returns [`None`] otherwise. pub fn as_null(&self) -> Option<()> { match *self { Bson::Null => Some(()), _ => None, } } /// If `self` is [`DbPointer`](Bson::DbPointer), return its value. Returns [`None`] otherwise. pub fn as_db_pointer(&self) -> Option<&DbPointer> { match self { Bson::DbPointer(ref db_pointer) => Some(db_pointer), _ => None, } } } /// Represents a BSON timestamp value. #[derive(Debug, Eq, Ord, PartialEq, PartialOrd, Clone, Copy, Hash)] pub struct Timestamp { /// The number of seconds since the Unix epoch. pub time: u32, /// An incrementing value to order timestamps with the same number of seconds in the `time` /// field. pub increment: u32, } impl Display for Timestamp { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "Timestamp({}, {})", self.time, self.increment) } } impl Timestamp { pub(crate) fn to_le_bytes(self) -> [u8; 8] { let mut out = [0; 8]; out[0..4].copy_from_slice(&self.increment.to_le_bytes()); out[4..8].copy_from_slice(&self.time.to_le_bytes()); out } pub(crate) fn from_le_bytes(bytes: [u8; 8]) -> Self { let mut inc_bytes = [0; 4]; inc_bytes.copy_from_slice(&bytes[0..4]); let mut time_bytes = [0; 4]; time_bytes.copy_from_slice(&bytes[4..8]); Self { increment: u32::from_le_bytes(inc_bytes), time: u32::from_le_bytes(time_bytes), } } } /// Represents a BSON regular expression value. #[derive(Debug, Clone, PartialEq)] pub struct Regex { /// The regex pattern to match. pub pattern: String, /// The options for the regex. /// /// Options are identified by characters, which must be stored in /// alphabetical order. Valid options are 'i' for case insensitive matching, 'm' for /// multiline matching, 'x' for verbose mode, 'l' to make \w, \W, etc. locale dependent, /// 's' for dotall mode ('.' matches everything), and 'u' to make \w, \W, etc. match /// unicode. pub options: String, } impl Regex { pub(crate) fn new(pattern: impl AsRef, options: impl AsRef) -> Self { let mut chars: Vec<_> = options.as_ref().chars().collect(); chars.sort_unstable(); let options: String = chars.into_iter().collect(); Self { pattern: pattern.as_ref().to_string(), options, } } } impl Display for Regex { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "/{}/{}", self.pattern, self.options) } } /// Represents a BSON code with scope value. #[derive(Debug, Clone, PartialEq)] pub struct JavaScriptCodeWithScope { /// The JavaScript code. pub code: String, /// The scope document containing variable bindings. pub scope: Document, } impl Display for JavaScriptCodeWithScope { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.write_str(&self.code) } } /// Represents a DBPointer. (Deprecated) #[derive(Debug, Clone, PartialEq)] pub struct DbPointer { pub(crate) namespace: String, pub(crate) id: oid::ObjectId, } bson-2.10.0/src/datetime/builder.rs000064400000000000000000000134111046102023000152240ustar 00000000000000use super::*; use std::convert::TryFrom; use time::Date; /// Builder for constructing a BSON [`DateTime`] pub struct DateTimeBuilder { pub(crate) year: Y, pub(crate) month: M, pub(crate) day: D, pub(crate) hour: Option, pub(crate) minute: Option, pub(crate) second: Option, pub(crate) millisecond: Option, } impl Default for DateTimeBuilder { fn default() -> Self { Self { year: NoYear, month: NoMonth, day: NoDay, hour: None, minute: None, second: None, millisecond: None, } } } pub struct Year(i32); pub struct NoYear; pub struct Month(u8); pub struct NoMonth; pub struct Day(u8); pub struct NoDay; impl DateTimeBuilder { /// Sets the year for the builder instance. Years between ±9999 inclusive are valid. /// If the specified value is out of range, calling the `build()` method will return /// an error. /// /// Note: This is a required method. You will not be able to call `build()` before calling /// this method. pub fn year(self, y: i32) -> DateTimeBuilder { let Self { year: _, month, day, hour, minute, second, millisecond, } = self; DateTimeBuilder { year: Year(y), month, day, hour, minute, second, millisecond, } } } impl DateTimeBuilder { /// Sets the month for the builder instance. Maps months as 1-January to 12-December. /// If the specified value is out of range, calling the `build()` method will return /// an error. /// /// Note: This is a required method. You will not be able to call `build()` before calling /// this method. pub fn month(self, m: u8) -> DateTimeBuilder { let Self { year, month: _, day, hour, minute, second, millisecond, } = self; DateTimeBuilder { year, month: Month(m), day, hour, minute, second, millisecond, } } } impl DateTimeBuilder { /// Sets the day for the builder instance. Values in the range `1..=31` are valid. /// If the specified value does not exist for the provided month/year or is out of range, /// calling the `build()` method will return an error. /// /// Note: This is a required method. You will not be able to call `build()` before calling /// this method. pub fn day(self, d: u8) -> DateTimeBuilder { let Self { year, month, day: _, hour, minute, second, millisecond, } = self; DateTimeBuilder { year, month, day: Day(d), hour, minute, second, millisecond, } } } impl DateTimeBuilder { /// Sets the hour (24-hour format) for the builder instance. Values must be in the range /// `0..=23`. If the specified value is out of range, calling the `build()` method will /// return an error. /// /// Note: This is an optional method. The hour will default to 0 if not explicitly set. pub fn hour(mut self, hour: u8) -> DateTimeBuilder { self.hour = Some(hour); self } /// Sets the minute for the builder instance. Values must be in the range `0..=59`. /// If the specified value is out of range, calling the `build()` method will return an error. /// /// Note: This is an optional method. The minute will default to 0 if not explicitly set. pub fn minute(mut self, minute: u8) -> DateTimeBuilder { self.minute = Some(minute); self } /// Sets the second for the builder instance. Values must be in range `0..=59`. /// If the specified value is out of range, calling the `build()` method will return an error. /// /// Note: This is an optional method. The second will default to 0 if not explicitly set. pub fn second(mut self, second: u8) -> DateTimeBuilder { self.second = Some(second); self } /// Sets the millisecond for the builder instance. Values must be in the range `0..=999`. /// If the specified value is out of range, calling the `build()` method will return an error. /// /// Note: This is an optional method. The millisecond will default to 0 if not explicitly set. pub fn millisecond(mut self, millisecond: u16) -> DateTimeBuilder { self.millisecond = Some(millisecond); self } } impl DateTimeBuilder { /// Convert a builder with a specified year, month, day, and optionally, an hour, minute, second /// and millisecond to a [`DateTime`]. /// /// Note: You cannot call `build()` before setting at least the year, month and day. pub fn build(self) -> Result { let err = |e: time::error::ComponentRange| Error::InvalidTimestamp { message: e.to_string(), }; let month = time::Month::try_from(self.month.0).map_err(err)?; let dt = Date::from_calendar_date(self.year.0, month, self.day.0) .map_err(err)? .with_hms_milli( self.hour.unwrap_or(0), self.minute.unwrap_or(0), self.second.unwrap_or(0), self.millisecond.unwrap_or(0), ) .map_err(err)?; Ok(DateTime::from_time_private(dt.assume_utc())) } } bson-2.10.0/src/datetime.rs000064400000000000000000000513541046102023000136060ustar 00000000000000//! Module containing functionality related to BSON DateTimes. //! For more information, see the documentation for the [`DateTime`] type. use std::{ convert::TryInto, error, fmt::{self, Display}, result, time::{Duration, SystemTime}, }; pub(crate) mod builder; pub use crate::datetime::builder::DateTimeBuilder; use time::format_description::well_known::Rfc3339; #[cfg(feature = "chrono-0_4")] use chrono::{LocalResult, TimeZone, Utc}; #[cfg(all( any(feature = "serde_with", feature = "serde_with-3"), any(feature = "chrono-0_4", feature = "time-0_3") ))] use serde::{Deserialize, Deserializer, Serialize}; #[cfg(all( feature = "serde_with", any(feature = "chrono-0_4", feature = "time-0_3") ))] use serde_with::{DeserializeAs, SerializeAs}; /// Struct representing a BSON datetime. /// Note: BSON datetimes have millisecond precision. /// /// To enable conversions between this type and [`chrono::DateTime`], enable the `"chrono-0_4"` /// feature flag in your `Cargo.toml`. /// ``` /// use chrono::prelude::*; /// # fn main() -> std::result::Result<(), Box> { /// # #[cfg(feature = "chrono-0_4")] /// # { /// let chrono_dt: chrono::DateTime = "2014-11-28T12:00:09Z".parse()?; /// let bson_dt: bson::DateTime = chrono_dt.into(); /// let bson_dt = bson::DateTime::from_chrono(chrono_dt); /// let back_to_chrono: chrono::DateTime = bson_dt.into(); /// let back_to_chrono = bson_dt.to_chrono(); /// # } /// # Ok(()) /// # } /// ``` /// /// You may also construct this type from a given `year`, `month`, `day`, and optionally, /// an `hour`, `minute`, `second` and `millisecond`, which default to 0 if not explicitly set. /// /// ``` /// # fn main() -> Result<(), Box> { /// let dt = bson::DateTime::builder().year(1998).month(2).day(12).minute(1).millisecond(23).build()?; /// let expected = bson::DateTime::parse_rfc3339_str("1998-02-12T00:01:00.023Z")?; /// assert_eq!(dt, expected); /// # Ok(()) /// # } /// ``` /// /// ## Serde integration /// /// This type differs from [`chrono::DateTime`] in that it serializes to and deserializes from a /// BSON datetime rather than an RFC 3339 formatted string. /// /// e.g. /// ```rust /// use serde::{Serialize, Deserialize}; /// /// #[derive(Serialize, Deserialize)] /// struct Foo { /// // serializes as a BSON datetime. /// date_time: bson::DateTime, /// /// // serializes as an RFC 3339 / ISO-8601 string. /// chrono_datetime: chrono::DateTime, /// } /// /// # fn main() -> bson::ser::Result<()> { /// let f = Foo { date_time: bson::DateTime::now(), chrono_datetime: chrono::Utc::now() }; /// println!("{:?}", bson::to_document(&f)?); /// # Ok(()) /// # } /// ``` /// Produces the following output: /// ```js /// { "date_time": DateTime("2023-01-23 20:11:47.316 +00:00:00"), "chrono_datetime": "2023-01-23T20:11:47.316114543Z" } /// ``` /// /// Additionally, in non-BSON formats, it will serialize to and deserialize from that format's /// equivalent of the [extended JSON representation](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/) of a datetime. /// /// e.g. /// ```rust /// # use serde::Serialize; /// # #[derive(Serialize)] /// # struct Foo { /// # // serializes as a BSON datetime. /// # date_time: bson::DateTime, /// # /// # // serializes as an RFC 3339 / ISO-8601 string. /// # chrono_datetime: chrono::DateTime, /// # } /// # fn main() -> Result<(), Box> { /// let f = Foo { date_time: bson::DateTime::now(), chrono_datetime: chrono::Utc::now() }; /// println!("{}", serde_json::to_string(&f)?); /// # Ok(()) /// # } /// ``` /// Produces the following output: /// ```js /// {"date_time":{"$date":{"$numberLong":"1674504029491"}},"chrono_datetime":"2023-01-23T20:00:29.491791120Z"} /// ``` /// /// ### `serde_helpers` /// The `bson` crate provides a number of useful helpers for serializing and deserializing /// various datetime types to and from different formats. For example, to serialize a /// [`chrono::DateTime`] as a BSON datetime, you can use /// [`crate::serde_helpers::chrono_datetime_as_bson_datetime`]. Similarly, to serialize a BSON /// [`DateTime`] to a string, you can use [`crate::serde_helpers::bson_datetime_as_rfc3339_string`]. /// Check out the [`crate::serde_helpers`] module documentation for a list of all of the helpers /// offered by the crate. /// /// ```rust /// # #[cfg(feature = "chrono-0_4")] /// # { /// use serde::{Serialize, Deserialize}; /// /// #[derive(Serialize, Deserialize)] /// struct Foo { /// // serializes as a BSON datetime. /// date_time: bson::DateTime, /// /// // serializes as an RFC 3339 / ISO-8601 string. /// chrono_datetime: chrono::DateTime, /// /// // serializes as a BSON datetime. /// // this requires the "chrono-0_4" feature flag /// #[serde(with = "bson::serde_helpers::chrono_datetime_as_bson_datetime")] /// chrono_as_bson: chrono::DateTime, /// /// // serializes as an RFC 3339 / ISO-8601 string. /// #[serde(with = "bson::serde_helpers::bson_datetime_as_rfc3339_string")] /// bson_as_string: bson::DateTime, /// } /// # } /// ``` /// ### The `serde_with-3` feature flag /// /// The `serde_with-3` feature can be enabled to support more ergonomic serde attributes for /// (de)serializing [`chrono::DateTime`] from/to BSON via the [`serde_with`](https://docs.rs/serde_with/1.11.0/serde_with/) /// crate. The main benefit of this compared to the regular `serde_helpers` is that `serde_with-3` /// can handle nested [`chrono::DateTime`] values (e.g. in [`Option`]), whereas the former only /// works on fields that are exactly [`chrono::DateTime`]. /// ``` /// # #[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))] /// # { /// use serde::{Deserialize, Serialize}; /// use bson::doc; /// /// #[serde_with_3::serde_as] /// #[derive(Deserialize, Serialize, PartialEq, Debug)] /// struct Foo { /// /// Serializes as a BSON datetime rather than using [`chrono::DateTime`]'s serialization /// #[serde_as(as = "Option")] /// as_bson: Option>, /// } /// /// let dt = chrono::Utc::now(); /// let foo = Foo { /// as_bson: Some(dt), /// }; /// /// let expected = doc! { /// "as_bson": bson::DateTime::from_chrono(dt), /// }; /// /// assert_eq!(bson::to_document(&foo)?, expected); /// # } /// # Ok::<(), Box>(()) /// ``` #[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Copy, Clone)] pub struct DateTime(i64); impl crate::DateTime { /// The latest possible date that can be represented in BSON. pub const MAX: Self = Self::from_millis(i64::MAX); /// The earliest possible date that can be represented in BSON. pub const MIN: Self = Self::from_millis(i64::MIN); /// Makes a new [`DateTime`] from the number of non-leap milliseconds since /// January 1, 1970 0:00:00 UTC (aka "UNIX timestamp"). pub const fn from_millis(date: i64) -> Self { Self(date) } /// Returns a [`DateTime`] which corresponds to the current date and time. pub fn now() -> DateTime { Self::from_system_time(SystemTime::now()) } /// Convert the given [`chrono::DateTime`] into a [`bson::DateTime`](DateTime), truncating it to /// millisecond precision. #[cfg(feature = "chrono-0_4")] #[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))] pub fn from_chrono(dt: chrono::DateTime) -> Self { Self::from_millis(dt.timestamp_millis()) } /// Returns a builder used to construct a [`DateTime`] from a given year, month, /// day, and optionally, an hour, minute, second and millisecond, which default to /// 0 if not explicitly set. /// /// Note: You cannot call `build()` before setting at least the year, month and day. pub fn builder() -> DateTimeBuilder { DateTimeBuilder::default() } /// Convert this [`DateTime`] to a [`chrono::DateTime`]. /// /// Note: Not every BSON datetime can be represented as a [`chrono::DateTime`]. For such dates, /// [`chrono::DateTime::MIN_UTC`] or [`chrono::DateTime::MAX_UTC`] will be returned, whichever /// is closer. /// /// ``` /// let bson_dt = bson::DateTime::now(); /// let chrono_dt = bson_dt.to_chrono(); /// assert_eq!(bson_dt.timestamp_millis(), chrono_dt.timestamp_millis()); /// /// let big = bson::DateTime::from_millis(i64::MAX); /// let chrono_big = big.to_chrono(); /// assert_eq!(chrono_big, chrono::DateTime::::MAX_UTC) /// ``` #[cfg(feature = "chrono-0_4")] #[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))] pub fn to_chrono(self) -> chrono::DateTime { match Utc.timestamp_millis_opt(self.0) { LocalResult::Single(dt) => dt, _ => { if self.0 < 0 { chrono::DateTime::::MIN_UTC } else { chrono::DateTime::::MAX_UTC } } } } fn from_time_private(dt: time::OffsetDateTime) -> Self { let millis = dt.unix_timestamp_nanos() / 1_000_000; match millis.try_into() { Ok(ts) => Self::from_millis(ts), _ => { if millis > 0 { Self::MAX } else { Self::MIN } } } } #[cfg(not(feature = "time-0_3"))] #[allow(unused)] pub(crate) fn from_time_0_3(dt: time::OffsetDateTime) -> Self { Self::from_time_private(dt) } /// Convert the given [`time::OffsetDateTime`] into a [`bson::DateTime`](DateTime), truncating /// it to millisecond precision. /// /// If the provided time is too far in the future or too far in the past to be represented /// by a BSON datetime, either [`DateTime::MAX`] or [`DateTime::MIN`] will be /// returned, whichever is closer. #[cfg(feature = "time-0_3")] pub fn from_time_0_3(dt: time::OffsetDateTime) -> Self { Self::from_time_private(dt) } fn to_time_private(self) -> time::OffsetDateTime { match self.to_time_opt() { Some(dt) => dt, None => if self.0 < 0 { time::PrimitiveDateTime::MIN } else { time::PrimitiveDateTime::MAX } .assume_utc(), } } pub(crate) fn to_time_opt(self) -> Option { time::OffsetDateTime::UNIX_EPOCH.checked_add(time::Duration::milliseconds(self.0)) } #[cfg(not(feature = "time-0_3"))] #[allow(unused)] pub(crate) fn to_time_0_3(self) -> time::OffsetDateTime { self.to_time_private() } /// Convert this [`DateTime`] to a [`time::OffsetDateTime`]. /// /// Note: Not every BSON datetime can be represented as a [`time::OffsetDateTime`]. For such /// dates, [`time::PrimitiveDateTime::MIN`] or [`time::PrimitiveDateTime::MAX`] will be /// returned, whichever is closer. /// /// ``` /// let bson_dt = bson::DateTime::now(); /// let time_dt = bson_dt.to_time_0_3(); /// assert_eq!(bson_dt.timestamp_millis() / 1000, time_dt.unix_timestamp()); /// /// let big = bson::DateTime::from_millis(i64::MIN); /// let time_big = big.to_time_0_3(); /// assert_eq!(time_big, time::PrimitiveDateTime::MIN.assume_utc()) /// ``` #[cfg(feature = "time-0_3")] #[cfg_attr(docsrs, doc(cfg(feature = "time-0_3")))] pub fn to_time_0_3(self) -> time::OffsetDateTime { self.to_time_private() } /// Convert the given [`std::time::SystemTime`] to a [`DateTime`]. /// /// If the provided time is too far in the future or too far in the past to be represented /// by a BSON datetime, either [`DateTime::MAX`] or [`DateTime::MIN`] will be /// returned, whichever is closer. pub fn from_system_time(st: SystemTime) -> Self { match st.duration_since(SystemTime::UNIX_EPOCH) { Ok(d) => { if d.as_millis() <= i64::MAX as u128 { Self::from_millis(d.as_millis() as i64) } else { Self::MAX } } // handle SystemTime from before the Unix Epoch Err(e) => { let millis = e.duration().as_millis(); if millis > i64::MAX as u128 { Self::MIN } else { Self::from_millis(-(millis as i64)) } } } } /// Convert this [`DateTime`] to a [`std::time::SystemTime`]. pub fn to_system_time(self) -> SystemTime { if self.0 >= 0 { SystemTime::UNIX_EPOCH + Duration::from_millis(self.0 as u64) } else { // need to convert to i128 before calculating absolute value since i64::MIN.abs() // overflows and panics. SystemTime::UNIX_EPOCH - Duration::from_millis((self.0 as i128).unsigned_abs() as u64) } } /// Returns the number of non-leap-milliseconds since January 1, 1970 UTC. pub const fn timestamp_millis(self) -> i64 { self.0 } #[deprecated(since = "2.3.0", note = "Use try_to_rfc3339_string instead.")] /// Convert this [`DateTime`] to an RFC 3339 formatted string. Panics if it could not be /// represented in that format. pub fn to_rfc3339_string(self) -> String { self.try_to_rfc3339_string().unwrap() } /// Convert this [`DateTime`] to an RFC 3339 formatted string. pub fn try_to_rfc3339_string(self) -> Result { self.to_time_0_3() .format(&Rfc3339) .map_err(|e| Error::CannotFormat { message: e.to_string(), }) } /// Convert the given RFC 3339 formatted string to a [`DateTime`], truncating it to millisecond /// precision. pub fn parse_rfc3339_str(s: impl AsRef) -> Result { let odt = time::OffsetDateTime::parse(s.as_ref(), &Rfc3339).map_err(|e| { Error::InvalidTimestamp { message: e.to_string(), } })?; Ok(Self::from_time_0_3(odt)) } /// Returns the time elapsed since `earlier`, or `None` if the given `DateTime` is later than /// this one. pub fn checked_duration_since(self, earlier: Self) -> Option { if earlier.0 > self.0 { return None; } Some(Duration::from_millis((self.0 - earlier.0) as u64)) } /// Returns the time elapsed since `earlier`, or a [`Duration`] of zero if the given `DateTime` /// is later than this one. pub fn saturating_duration_since(self, earlier: Self) -> Duration { self.checked_duration_since(earlier) .unwrap_or(Duration::ZERO) } } impl fmt::Debug for crate::DateTime { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut tup = f.debug_tuple("DateTime"); match self.to_time_opt() { Some(dt) => tup.field(&dt), _ => tup.field(&self.0), }; tup.finish() } } impl Display for crate::DateTime { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.to_time_opt() { Some(dt) => Display::fmt(&dt, f), _ => Display::fmt(&self.0, f), } } } impl From for crate::DateTime { fn from(st: SystemTime) -> Self { Self::from_system_time(st) } } impl From for SystemTime { fn from(dt: crate::DateTime) -> Self { dt.to_system_time() } } #[cfg(feature = "chrono-0_4")] #[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))] impl From for chrono::DateTime { fn from(bson_dt: DateTime) -> Self { bson_dt.to_chrono() } } #[cfg(feature = "chrono-0_4")] #[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))] impl From> for crate::DateTime { fn from(x: chrono::DateTime) -> Self { Self::from_chrono(x) } } #[cfg(all(feature = "chrono-0_4", feature = "serde_with"))] #[cfg_attr(docsrs, doc(cfg(all(feature = "chrono-0_4", feature = "serde_with"))))] impl<'de> DeserializeAs<'de, chrono::DateTime> for crate::DateTime { fn deserialize_as(deserializer: D) -> std::result::Result, D::Error> where D: Deserializer<'de>, { let dt = DateTime::deserialize(deserializer)?; Ok(dt.to_chrono()) } } #[cfg(all(feature = "chrono-0_4", feature = "serde_with"))] #[cfg_attr(docsrs, doc(cfg(all(feature = "chrono-0_4", feature = "chrono-0_4"))))] impl SerializeAs> for crate::DateTime { fn serialize_as( source: &chrono::DateTime, serializer: S, ) -> std::result::Result where S: serde::Serializer, { let dt = DateTime::from_chrono(*source); dt.serialize(serializer) } } #[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))] #[cfg_attr( docsrs, doc(cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))) )] impl<'de> serde_with_3::DeserializeAs<'de, chrono::DateTime> for crate::DateTime { fn deserialize_as(deserializer: D) -> std::result::Result, D::Error> where D: Deserializer<'de>, { let dt = DateTime::deserialize(deserializer)?; Ok(dt.to_chrono()) } } #[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))] #[cfg_attr(docsrs, doc(cfg(all(feature = "chrono-0_4", feature = "chrono-0_4"))))] impl serde_with_3::SerializeAs> for crate::DateTime { fn serialize_as( source: &chrono::DateTime, serializer: S, ) -> std::result::Result where S: serde::Serializer, { let dt = DateTime::from_chrono(*source); dt.serialize(serializer) } } #[cfg(feature = "time-0_3")] #[cfg_attr(docsrs, doc(cfg(feature = "time-0_3")))] impl From for time::OffsetDateTime { fn from(bson_dt: DateTime) -> Self { bson_dt.to_time_0_3() } } #[cfg(feature = "time-0_3")] #[cfg_attr(docsrs, doc(cfg(feature = "time-0_3")))] impl From for crate::DateTime { fn from(x: time::OffsetDateTime) -> Self { Self::from_time_0_3(x) } } #[cfg(all(feature = "time-0_3", feature = "serde_with"))] #[cfg_attr(docsrs, doc(cfg(all(feature = "time-0_3", feature = "serde_with"))))] impl<'de> DeserializeAs<'de, time::OffsetDateTime> for crate::DateTime { fn deserialize_as(deserializer: D) -> std::result::Result where D: Deserializer<'de>, { let dt = DateTime::deserialize(deserializer)?; Ok(dt.to_time_0_3()) } } #[cfg(all(feature = "time-0_3", feature = "serde_with"))] #[cfg_attr(docsrs, doc(cfg(all(feature = "time-0_3", feature = "chrono-0_4"))))] impl SerializeAs for crate::DateTime { fn serialize_as( source: &time::OffsetDateTime, serializer: S, ) -> std::result::Result where S: serde::Serializer, { let dt = DateTime::from_time_0_3(*source); dt.serialize(serializer) } } #[cfg(all(feature = "time-0_3", feature = "serde_with-3"))] #[cfg_attr(docsrs, doc(cfg(all(feature = "time-0_3", feature = "serde_with-3"))))] impl<'de> serde_with_3::DeserializeAs<'de, time::OffsetDateTime> for crate::DateTime { fn deserialize_as(deserializer: D) -> std::result::Result where D: Deserializer<'de>, { let dt = DateTime::deserialize(deserializer)?; Ok(dt.to_time_0_3()) } } #[cfg(all(feature = "time-0_3", feature = "serde_with-3"))] #[cfg_attr(docsrs, doc(cfg(all(feature = "time-0_3", feature = "chrono-0_4"))))] impl serde_with_3::SerializeAs for crate::DateTime { fn serialize_as( source: &time::OffsetDateTime, serializer: S, ) -> std::result::Result where S: serde::Serializer, { let dt = DateTime::from_time_0_3(*source); dt.serialize(serializer) } } /// Errors that can occur during [`DateTime`] construction and generation. #[derive(Clone, Debug)] #[non_exhaustive] pub enum Error { /// Error returned when an invalid datetime format is provided to a conversion method. #[non_exhaustive] InvalidTimestamp { message: String }, /// Error returned when a [`DateTime`] cannot be represented in a particular format. #[non_exhaustive] CannotFormat { message: String }, } /// Alias for `Result` pub type Result = result::Result; impl fmt::Display for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { Error::InvalidTimestamp { message } | Error::CannotFormat { message } => { write!(fmt, "{}", message) } } } } impl error::Error for Error {} bson-2.10.0/src/de/error.rs000064400000000000000000000102551046102023000135260ustar 00000000000000use std::{error, fmt, fmt::Display, io, string, sync::Arc}; use serde::de::{self, Unexpected}; use crate::Bson; /// Possible errors that can arise during decoding. #[derive(Clone, Debug)] #[non_exhaustive] pub enum Error { /// A [`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html) encountered while deserializing. Io(Arc), /// A [`std::string::FromUtf8Error`](https://doc.rust-lang.org/std/string/struct.FromUtf8Error.html) encountered /// while decoding a UTF-8 String from the input data. InvalidUtf8String(string::FromUtf8Error), /// While decoding a [`Document`](crate::Document) from bytes, an unexpected or unsupported /// element type was encountered. #[non_exhaustive] UnrecognizedDocumentElementType { /// The key at which an unexpected/unsupported element type was encountered. key: String, /// The encountered element type. element_type: u8, }, /// The end of the BSON input was reached too soon. EndOfStream, /// A general error encountered during deserialization. /// See: #[non_exhaustive] DeserializationError { /// A message describing the error. message: String, }, } impl From for Error { fn from(err: io::Error) -> Error { Error::Io(Arc::new(err)) } } impl From for Error { fn from(err: string::FromUtf8Error) -> Error { Error::InvalidUtf8String(err) } } impl fmt::Display for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match *self { Error::Io(ref inner) => inner.fmt(fmt), Error::InvalidUtf8String(ref inner) => inner.fmt(fmt), Error::UnrecognizedDocumentElementType { ref key, element_type, } => write!( fmt, "unrecognized element type for key \"{}\": `{:#x}`", key, element_type ), Error::EndOfStream => fmt.write_str("end of stream"), Error::DeserializationError { ref message } => message.fmt(fmt), } } } impl error::Error for Error { fn source(&self) -> Option<&(dyn error::Error + 'static)> { match *self { Error::Io(ref inner) => Some(inner.as_ref()), Error::InvalidUtf8String(ref inner) => Some(inner), _ => None, } } } impl de::Error for Error { fn custom(msg: T) -> Error { Error::DeserializationError { message: msg.to_string(), } } } /// Alias for `Result`. pub type Result = std::result::Result; impl Bson { /// Method for converting a given [`Bson`] value to a [`serde::de::Unexpected`] for error /// reporting. pub(crate) fn as_unexpected(&self) -> Unexpected { match self { Bson::Array(_) => Unexpected::Seq, Bson::Binary(b) => Unexpected::Bytes(b.bytes.as_slice()), Bson::Boolean(b) => Unexpected::Bool(*b), Bson::DbPointer(_) => Unexpected::Other("dbpointer"), Bson::Document(_) => Unexpected::Map, Bson::Double(f) => Unexpected::Float(*f), Bson::Int32(i) => Unexpected::Signed(*i as i64), Bson::Int64(i) => Unexpected::Signed(*i), Bson::JavaScriptCode(_) => Unexpected::Other("javascript code"), Bson::JavaScriptCodeWithScope(_) => Unexpected::Other("javascript code with scope"), Bson::MaxKey => Unexpected::Other("maxkey"), Bson::MinKey => Unexpected::Other("minkey"), Bson::Null => Unexpected::Unit, Bson::Undefined => Unexpected::Other("undefined"), Bson::ObjectId(_) => Unexpected::Other("objectid"), Bson::RegularExpression(_) => Unexpected::Other("regex"), Bson::String(s) => Unexpected::Str(s.as_str()), Bson::Symbol(_) => Unexpected::Other("symbol"), Bson::Timestamp(_) => Unexpected::Other("timestamp"), Bson::DateTime(_) => Unexpected::Other("datetime"), Bson::Decimal128(_) => Unexpected::Other("decimal128"), } } } bson-2.10.0/src/de/mod.rs000064400000000000000000000271501046102023000131560ustar 00000000000000// The MIT License (MIT) // Copyright (c) 2015 Y. T. Chung // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in // the Software without restriction, including without limitation the rights to // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of // the Software, and to permit persons to whom the Software is furnished to do so, // subject to the following conditions: // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. //! Deserializer mod error; mod raw; mod serde; pub use self::{ error::{Error, Result}, serde::{Deserializer, DeserializerOptions}, }; use std::io::Read; use crate::{ bson::{Bson, Document, Timestamp}, oid::ObjectId, raw::RawBinaryRef, ser::write_i32, spec::BinarySubtype, Decimal128, }; use ::serde::{ de::{DeserializeOwned, Error as _, Unexpected}, Deserialize, }; pub(crate) use self::serde::{convert_unsigned_to_signed_raw, BsonVisitor}; pub(crate) use self::raw::Deserializer as RawDeserializer; pub(crate) const MAX_BSON_SIZE: i32 = 16 * 1024 * 1024; pub(crate) const MIN_BSON_DOCUMENT_SIZE: i32 = 4 + 1; // 4 bytes for length, one byte for null terminator pub(crate) const MIN_BSON_STRING_SIZE: i32 = 4 + 1; // 4 bytes for length, one byte for null terminator pub(crate) const MIN_CODE_WITH_SCOPE_SIZE: i32 = 4 + MIN_BSON_STRING_SIZE + MIN_BSON_DOCUMENT_SIZE; /// Hint provided to the deserializer via `deserialize_newtype_struct` as to the type of thing /// being deserialized. #[derive(Debug, Clone, Copy)] enum DeserializerHint { /// No hint provided, deserialize normally. None, /// The type being deserialized expects the BSON to contain a binary value with the provided /// subtype. This is currently used to deserialize [`bson::Uuid`] values. BinarySubtype(BinarySubtype), /// The type being deserialized is raw BSON, meaning no allocations should occur as part of /// deserializing and everything should be visited via borrowing or [`Copy`] if possible. RawBson, } pub(crate) fn read_string(reader: &mut R, utf8_lossy: bool) -> Result { let len = read_i32(reader)?; // UTF-8 String must have at least 1 byte (the last 0x00). if len < 1 { return Err(Error::invalid_length( len as usize, &"UTF-8 string must have at least 1 byte", )); } let s = if utf8_lossy { let mut buf = Vec::with_capacity(len as usize - 1); reader.take(len as u64 - 1).read_to_end(&mut buf)?; String::from_utf8_lossy(&buf).to_string() } else { let mut s = String::with_capacity(len as usize - 1); reader.take(len as u64 - 1).read_to_string(&mut s)?; s }; // read the null terminator if read_u8(reader)? != 0 { return Err(Error::invalid_length( len as usize, &"contents of string longer than provided length", )); } Ok(s) } pub(crate) fn read_bool(mut reader: R) -> Result { let val = read_u8(&mut reader)?; if val > 1 { return Err(Error::invalid_value( Unexpected::Unsigned(val as u64), &"boolean must be stored as 0 or 1", )); } Ok(val != 0) } #[inline] pub(crate) fn read_u8(reader: &mut R) -> Result { let mut buf = [0; 1]; reader.read_exact(&mut buf)?; Ok(u8::from_le_bytes(buf)) } #[inline] pub(crate) fn read_i32(reader: &mut R) -> Result { let mut buf = [0; 4]; reader.read_exact(&mut buf)?; Ok(i32::from_le_bytes(buf)) } #[inline] pub(crate) fn read_i64(reader: &mut R) -> Result { let mut buf = [0; 8]; reader.read_exact(&mut buf)?; Ok(i64::from_le_bytes(buf)) } #[inline] fn read_f64(reader: &mut R) -> Result { let mut buf = [0; 8]; reader.read_exact(&mut buf)?; Ok(f64::from_le_bytes(buf)) } /// Placeholder decoder for `Decimal128`. Reads 128 bits and just stores them, does no validation or /// parsing. #[inline] fn read_f128(reader: &mut R) -> Result { let mut buf = [0u8; 128 / 8]; reader.read_exact(&mut buf)?; Ok(Decimal128 { bytes: buf }) } impl<'a> RawBinaryRef<'a> { pub(crate) fn from_slice_with_len_and_payload( mut bytes: &'a [u8], mut len: i32, subtype: BinarySubtype, ) -> Result { if !(0..=MAX_BSON_SIZE).contains(&len) { return Err(Error::invalid_length( len as usize, &format!("binary length must be between 0 and {}", MAX_BSON_SIZE).as_str(), )); } else if len as usize > bytes.len() { return Err(Error::invalid_length( len as usize, &format!( "binary length {} exceeds buffer length {}", len, bytes.len() ) .as_str(), )); } // Skip length data in old binary. if let BinarySubtype::BinaryOld = subtype { let data_len = read_i32(&mut bytes)?; if data_len + 4 != len { return Err(Error::invalid_length( data_len as usize, &"0x02 length did not match top level binary length", )); } len -= 4; } Ok(Self { bytes: &bytes[0..len as usize], subtype, }) } } impl Timestamp { pub(crate) fn from_reader(mut reader: R) -> Result { let mut bytes = [0; 8]; reader.read_exact(&mut bytes)?; Ok(Timestamp::from_le_bytes(bytes)) } } impl ObjectId { pub(crate) fn from_reader(mut reader: R) -> Result { let mut buf = [0u8; 12]; reader.read_exact(&mut buf)?; Ok(Self::from_bytes(buf)) } } /// Deserialize a `T` from the provided [`Bson`] value. /// /// The [`Deserializer`] used by this function presents itself as human readable, whereas the /// one used in [`from_slice`] does not. This means that this function may deserialize differently /// than [`from_slice`] for types that change their deserialization logic depending on whether /// the format is human readable or not. To deserialize from [`Bson`] with a deserializer that /// presents itself as not human readable, use [`from_bson_with_options`] with /// [`DeserializerOptions::human_readable`] set to false. pub fn from_bson(bson: Bson) -> Result where T: DeserializeOwned, { let de = Deserializer::new(bson); Deserialize::deserialize(de) } /// Deserialize a `T` from the provided [`Bson`] value, configuring the underlying /// deserializer with the provided options. /// ``` /// # use serde::Deserialize; /// # use bson::{bson, DeserializerOptions}; /// #[derive(Debug, Deserialize, PartialEq)] /// struct MyData { /// a: String, /// } /// /// let bson = bson!({ "a": "hello" }); /// let options = DeserializerOptions::builder().human_readable(false).build(); /// let data: MyData = bson::from_bson_with_options(bson, options)?; /// assert_eq!(data, MyData { a: "hello".to_string() }); /// # Ok::<(), Box>(()) /// ``` pub fn from_bson_with_options(bson: Bson, options: DeserializerOptions) -> Result where T: DeserializeOwned, { let de = Deserializer::new_with_options(bson, options); Deserialize::deserialize(de) } /// Deserialize a `T` from the provided [`Document`]. /// /// The [`Deserializer`] used by this function presents itself as human readable, whereas the /// one used in [`from_slice`] does not. This means that this function may deserialize differently /// than [`from_slice`] for types that change their deserialization logic depending on whether /// the format is human readable or not. To deserialize from [`Document`] with a deserializer that /// presents itself as not human readable, use [`from_document_with_options`] with /// [`DeserializerOptions::human_readable`] set to false. pub fn from_document(doc: Document) -> Result where T: DeserializeOwned, { from_bson(Bson::Document(doc)) } /// Deserialize a `T` from the provided [`Document`], configuring the underlying /// deserializer with the provided options. /// ``` /// # use serde::Deserialize; /// # use bson::{doc, DeserializerOptions}; /// #[derive(Debug, Deserialize, PartialEq)] /// struct MyData { /// a: String, /// } /// /// let doc = doc! { "a": "hello" }; /// let options = DeserializerOptions::builder().human_readable(false).build(); /// let data: MyData = bson::from_document_with_options(doc, options)?; /// assert_eq!(data, MyData { a: "hello".to_string() }); /// # Ok::<(), Box>(()) /// ``` pub fn from_document_with_options(doc: Document, options: DeserializerOptions) -> Result where T: DeserializeOwned, { let de = Deserializer::new_with_options(Bson::Document(doc), options); Deserialize::deserialize(de) } fn reader_to_vec(mut reader: R) -> Result> { let length = read_i32(&mut reader)?; if length < MIN_BSON_DOCUMENT_SIZE { return Err(Error::custom("document size too small")); } let mut bytes = Vec::with_capacity(length as usize); write_i32(&mut bytes, length).map_err(Error::custom)?; reader.take(length as u64 - 4).read_to_end(&mut bytes)?; Ok(bytes) } /// Deserialize an instance of type `T` from an I/O stream of BSON. pub fn from_reader(reader: R) -> Result where T: DeserializeOwned, R: Read, { let bytes = reader_to_vec(reader)?; from_slice(bytes.as_slice()) } /// Deserialize an instance of type `T` from an I/O stream of BSON, replacing any invalid UTF-8 /// sequences with the Unicode replacement character. /// /// This is mainly useful when reading raw BSON returned from a MongoDB server, which /// in rare cases can contain invalidly truncated strings (). /// For most use cases, [`crate::from_reader`] can be used instead. pub fn from_reader_utf8_lossy(reader: R) -> Result where T: DeserializeOwned, R: Read, { let bytes = reader_to_vec(reader)?; from_slice_utf8_lossy(bytes.as_slice()) } /// Deserialize an instance of type `T` from a slice of BSON bytes. pub fn from_slice<'de, T>(bytes: &'de [u8]) -> Result where T: Deserialize<'de>, { let mut deserializer = raw::Deserializer::new(bytes, false); T::deserialize(&mut deserializer) } /// Deserialize an instance of type `T` from a slice of BSON bytes, replacing any invalid UTF-8 /// sequences with the Unicode replacement character. /// /// This is mainly useful when reading raw BSON returned from a MongoDB server, which /// in rare cases can contain invalidly truncated strings (). /// For most use cases, [`crate::from_slice`] can be used instead. pub fn from_slice_utf8_lossy<'de, T>(bytes: &'de [u8]) -> Result where T: Deserialize<'de>, { let mut deserializer = raw::Deserializer::new(bytes, true); T::deserialize(&mut deserializer) } bson-2.10.0/src/de/raw.rs000064400000000000000000001623071046102023000131740ustar 00000000000000use std::{ borrow::Cow, convert::TryInto, io::{ErrorKind, Read}, sync::Arc, }; use serde::{ de::{EnumAccess, Error as SerdeError, IntoDeserializer, MapAccess, VariantAccess}, forward_to_deserialize_any, Deserializer as SerdeDeserializer, }; use crate::{ oid::ObjectId, raw::{RawBinaryRef, RAW_ARRAY_NEWTYPE, RAW_BSON_NEWTYPE, RAW_DOCUMENT_NEWTYPE}, spec::{BinarySubtype, ElementType}, uuid::UUID_NEWTYPE_NAME, Bson, DateTime, Decimal128, DeserializerOptions, RawDocument, Timestamp, }; use super::{ read_bool, read_f128, read_f64, read_i32, read_i64, read_string, read_u8, DeserializerHint, Error, Result, MAX_BSON_SIZE, MIN_CODE_WITH_SCOPE_SIZE, }; use crate::de::serde::MapDeserializer; /// Deserializer used to parse and deserialize raw BSON bytes. pub(crate) struct Deserializer<'de> { bytes: BsonBuf<'de>, /// The type of the element currently being deserialized. /// /// When the Deserializer is initialized, this will be `ElementType::EmbeddedDocument`, as the /// only top level type is a document. The "embedded" portion is incorrect in this context, /// but given that there's no difference between deserializing an embedded document and a /// top level one, the distinction isn't necessary. current_type: ElementType, } /// Enum used to determine what the type of document being deserialized is in /// `Deserializer::deserialize_document`. enum DocumentType { Array, EmbeddedDocument, } impl<'de> Deserializer<'de> { pub(crate) fn new(buf: &'de [u8], utf8_lossy: bool) -> Self { Self { bytes: BsonBuf::new(buf, utf8_lossy), current_type: ElementType::EmbeddedDocument, } } /// Ensure the entire document was visited, returning an error if not. /// Will read the trailing null byte if necessary (i.e. the visitor stopped after visiting /// exactly the number of elements in the document). fn end_document(&mut self, length_remaining: i32) -> Result<()> { match length_remaining.cmp(&1) { std::cmp::Ordering::Equal => { let nullbyte = read_u8(&mut self.bytes)?; if nullbyte != 0 { return Err(Error::custom(format!( "expected null byte at end of document, got {:#x} instead", nullbyte ))); } } std::cmp::Ordering::Greater => { return Err(Error::custom(format!( "document has bytes remaining that were not visited: {}", length_remaining ))); } std::cmp::Ordering::Less => { if length_remaining < 0 { return Err(Error::custom("length of document was too short")); } } } Ok(()) } /// Read a string from the BSON. /// /// If utf8_lossy, this will be an owned string if invalid UTF-8 is encountered in the string, /// otherwise it will be borrowed. fn deserialize_str(&mut self) -> Result> { self.bytes.read_str() } /// Read a null-terminated C style string from the underling BSON. /// /// If utf8_lossy, this will be an owned string if invalid UTF-8 is encountered in the string, /// otherwise it will be borrowed. fn deserialize_cstr(&mut self) -> Result> { self.bytes.read_cstr() } /// Read an ObjectId from the underling BSON. /// /// If hinted to use raw BSON, the bytes of the ObjectId will be visited. /// Otherwise, a map in the shape of the extended JSON format of an ObjectId will be. fn deserialize_objectid(&mut self, visitor: V, hint: DeserializerHint) -> Result where V: serde::de::Visitor<'de>, { let oid = ObjectId::from_reader(&mut self.bytes)?; visitor.visit_map(ObjectIdAccess::new(oid, hint)) } /// Read a document from the underling BSON, whether it's an array or an actual document. /// /// If hinted to use raw BSON, the bytes themselves will be visited using a special newtype /// name. Otherwise, the key-value pairs will be accessed in order, either as part of a /// [`MapAccess`] for documents or a [`SeqAccess`] for arrays. fn deserialize_document( &mut self, visitor: V, hint: DeserializerHint, document_type: DocumentType, ) -> Result where V: serde::de::Visitor<'de>, { let is_array = match document_type { DocumentType::Array => true, DocumentType::EmbeddedDocument => false, }; match hint { DeserializerHint::RawBson => { let mut len = self.bytes.slice(4)?; let len = read_i32(&mut len)?; let doc = RawDocument::from_bytes(self.bytes.read_slice(len as usize)?) .map_err(Error::custom)?; let access = if is_array { RawDocumentAccess::for_array(doc) } else { RawDocumentAccess::new(doc) }; visitor.visit_map(access) } _ if is_array => self.access_document(|access| visitor.visit_seq(access)), _ => self.access_document(|access| visitor.visit_map(access)), } } /// Construct a [`DocumentAccess`] and pass it into the provided closure, returning the /// result of the closure if no other errors are encountered. fn access_document(&mut self, f: F) -> Result where F: FnOnce(DocumentAccess<'_, 'de>) -> Result, { let mut length_remaining = read_i32(&mut self.bytes)?; if length_remaining < 4 { return Err(Error::custom("invalid length, less than min document size")); } length_remaining -= 4; let out = f(DocumentAccess { root_deserializer: self, length_remaining: &mut length_remaining, }); if out.is_ok() { self.end_document(length_remaining)?; } out } /// Deserialize the next element type and update `current_type` accordingly. /// Returns [`None`] if a null byte is read. fn deserialize_next_type(&mut self) -> Result> { let tag = read_u8(&mut self.bytes)?; if tag == 0 { return Ok(None); } let element_type = ElementType::from(tag) .ok_or_else(|| Error::custom(format!("invalid element type: {}", tag)))?; self.current_type = element_type; Ok(Some(element_type)) } /// Deserialize the next element in the BSON, using the type of the element along with the /// provided hint to determine how to visit the data. fn deserialize_next(&mut self, visitor: V, hint: DeserializerHint) -> Result where V: serde::de::Visitor<'de>, { match self.current_type { ElementType::Int32 => visitor.visit_i32(read_i32(&mut self.bytes)?), ElementType::Int64 => visitor.visit_i64(read_i64(&mut self.bytes)?), ElementType::Double => visitor.visit_f64(read_f64(&mut self.bytes)?), ElementType::String => match self.deserialize_str()? { Cow::Borrowed(s) => visitor.visit_borrowed_str(s), Cow::Owned(string) => visitor.visit_string(string), }, ElementType::Boolean => visitor.visit_bool(read_bool(&mut self.bytes)?), ElementType::Null => visitor.visit_unit(), ElementType::ObjectId => self.deserialize_objectid(visitor, hint), ElementType::EmbeddedDocument => { self.deserialize_document(visitor, hint, DocumentType::EmbeddedDocument) } ElementType::Array => self.deserialize_document(visitor, hint, DocumentType::Array), ElementType::Binary => { let len = read_i32(&mut self.bytes)?; if !(0..=MAX_BSON_SIZE).contains(&len) { return Err(Error::invalid_length( len as usize, &format!("binary length must be between 0 and {}", MAX_BSON_SIZE).as_str(), )); } let subtype = BinarySubtype::from(read_u8(&mut self.bytes)?); if let DeserializerHint::BinarySubtype(expected_subtype) = hint { if subtype != expected_subtype { return Err(Error::custom(format!( "expected binary subtype {:?} instead got {:?}", expected_subtype, subtype ))); } } match subtype { BinarySubtype::Generic => { visitor.visit_borrowed_bytes(self.bytes.read_slice(len as usize)?) } _ => { let binary = RawBinaryRef::from_slice_with_len_and_payload( self.bytes.read_slice(len as usize)?, len, subtype, )?; let mut d = BinaryDeserializer::new(binary, hint); visitor.visit_map(BinaryAccess { deserializer: &mut d, }) } } } ElementType::Undefined => { visitor.visit_map(RawBsonAccess::new("$undefined", BsonContent::Boolean(true))) } ElementType::DateTime => { let dti = read_i64(&mut self.bytes)?; let dt = DateTime::from_millis(dti); let mut d = DateTimeDeserializer::new(dt, hint); visitor.visit_map(DateTimeAccess { deserializer: &mut d, }) } ElementType::RegularExpression => { let mut de = RegexDeserializer::new(&mut *self); visitor.visit_map(RegexAccess::new(&mut de)) } ElementType::DbPointer => { let mut de = DbPointerDeserializer::new(&mut *self, hint); visitor.visit_map(DbPointerAccess::new(&mut de)) } ElementType::JavaScriptCode => { let utf8_lossy = self.bytes.utf8_lossy; match hint { DeserializerHint::RawBson => visitor.visit_map(RawBsonAccess::new( "$code", BsonContent::Str(self.bytes.read_borrowed_str()?), )), _ => { let code = read_string(&mut self.bytes, utf8_lossy)?; let doc = Bson::JavaScriptCode(code).into_extended_document(false); visitor.visit_map(MapDeserializer::new( doc, DeserializerOptions::builder().human_readable(false).build(), )) } } } ElementType::JavaScriptCodeWithScope => { let len = read_i32(&mut self.bytes)?; if len < MIN_CODE_WITH_SCOPE_SIZE { return Err(SerdeError::invalid_length( len.try_into().unwrap_or(0), &format!( "CodeWithScope to be at least {} bytes", MIN_CODE_WITH_SCOPE_SIZE ) .as_str(), )); } else if (self.bytes.bytes_remaining() as i32) < len - 4 { return Err(SerdeError::invalid_length( len.try_into().unwrap_or(0), &format!( "CodeWithScope to be at most {} bytes", self.bytes.bytes_remaining() ) .as_str(), )); } let mut de = CodeWithScopeDeserializer::new(&mut *self, hint, len - 4); let out = visitor.visit_map(CodeWithScopeAccess::new(&mut de)); if de.length_remaining != 0 { return Err(SerdeError::invalid_length( len.try_into().unwrap_or(0), &format!( "CodeWithScope length {} bytes greater than actual length", de.length_remaining ) .as_str(), )); } out } ElementType::Symbol => { let utf8_lossy = self.bytes.utf8_lossy; match hint { DeserializerHint::RawBson => visitor.visit_map(RawBsonAccess::new( "$symbol", BsonContent::Str(self.bytes.read_borrowed_str()?), )), _ => { let symbol = read_string(&mut self.bytes, utf8_lossy)?; let doc = Bson::Symbol(symbol).into_extended_document(false); visitor.visit_map(MapDeserializer::new( doc, DeserializerOptions::builder().human_readable(false).build(), )) } } } ElementType::Timestamp => { let ts = Timestamp::from_reader(&mut self.bytes)?; let mut d = TimestampDeserializer::new(ts); visitor.visit_map(TimestampAccess { deserializer: &mut d, }) } ElementType::Decimal128 => { let d128 = read_f128(&mut self.bytes)?; visitor.visit_map(Decimal128Access::new(d128)) } ElementType::MaxKey => { visitor.visit_map(RawBsonAccess::new("$maxKey", BsonContent::Int32(1))) } ElementType::MinKey => { visitor.visit_map(RawBsonAccess::new("$minKey", BsonContent::Int32(1))) } } } } impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut Deserializer<'de> { type Error = Error; #[inline] fn deserialize_any(self, visitor: V) -> Result where V: serde::de::Visitor<'de>, { self.deserialize_next(visitor, DeserializerHint::None) } #[inline] fn deserialize_option(self, visitor: V) -> Result where V: serde::de::Visitor<'de>, { match self.current_type { ElementType::Null => visitor.visit_none(), _ => visitor.visit_some(self), } } fn deserialize_enum( self, _name: &str, _variants: &'static [&'static str], visitor: V, ) -> Result where V: serde::de::Visitor<'de>, { match self.current_type { ElementType::String => visitor.visit_enum(self.deserialize_str()?.into_deserializer()), ElementType::EmbeddedDocument => { self.access_document(|access| visitor.visit_enum(access)) } t => Err(Error::custom(format!("expected enum, instead got {:?}", t))), } } fn deserialize_bytes(self, visitor: V) -> Result where V: serde::de::Visitor<'de>, { match self.current_type { ElementType::ObjectId => visitor.visit_borrowed_bytes(self.bytes.read_slice(12)?), _ => self.deserialize_any(visitor), } } fn deserialize_newtype_struct(self, name: &'static str, visitor: V) -> Result where V: serde::de::Visitor<'de>, { match name { UUID_NEWTYPE_NAME => self.deserialize_next( visitor, DeserializerHint::BinarySubtype(BinarySubtype::Uuid), ), RAW_BSON_NEWTYPE => self.deserialize_next(visitor, DeserializerHint::RawBson), RAW_DOCUMENT_NEWTYPE => { if self.current_type != ElementType::EmbeddedDocument { return Err(serde::de::Error::custom(format!( "expected raw document, instead got {:?}", self.current_type ))); } self.deserialize_next(visitor, DeserializerHint::RawBson) } RAW_ARRAY_NEWTYPE => { if self.current_type != ElementType::Array { return Err(serde::de::Error::custom(format!( "expected raw array, instead got {:?}", self.current_type ))); } self.deserialize_next(visitor, DeserializerHint::RawBson) } _ => visitor.visit_newtype_struct(self), } } fn is_human_readable(&self) -> bool { false } forward_to_deserialize_any! { bool char str byte_buf unit unit_struct string identifier seq tuple tuple_struct struct map ignored_any i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 } } /// Struct for accessing documents for deserialization purposes. /// This is used to deserialize maps, structs, sequences, and enums. struct DocumentAccess<'d, 'de> { root_deserializer: &'d mut Deserializer<'de>, length_remaining: &'d mut i32, } impl<'d, 'de> DocumentAccess<'d, 'de> { /// Read the next element type and update the root deserializer with it. /// /// Returns `Ok(None)` if the document has been fully read and has no more elements. fn read_next_type(&mut self) -> Result> { let t = self.read(|s| s.root_deserializer.deserialize_next_type())?; if t.is_none() && *self.length_remaining != 0 { return Err(Error::custom(format!( "got null byte but still have length {} remaining", self.length_remaining ))); } Ok(t) } /// Executes a closure that reads from the BSON bytes and returns an error if the number of /// bytes read exceeds length_remaining. /// /// A mutable reference to this [`DocumentAccess`] is passed into the closure. fn read(&mut self, f: F) -> Result where F: FnOnce(&mut Self) -> Result, { let start_bytes = self.root_deserializer.bytes.bytes_read(); let out = f(self)?; let bytes_read = self.root_deserializer.bytes.bytes_read() - start_bytes; let bytes_read: i32 = bytes_read .try_into() .map_err(|_| Error::custom("overflow in read size"))?; if bytes_read > *self.length_remaining { return Err(Error::custom("length of document too short")); } *self.length_remaining -= bytes_read; Ok(out) } /// Read the next value from the document. fn read_next_value(&mut self, seed: V) -> Result where V: serde::de::DeserializeSeed<'de>, { self.read(|s| seed.deserialize(&mut *s.root_deserializer)) } } impl<'d, 'de> serde::de::MapAccess<'de> for DocumentAccess<'d, 'de> { type Error = crate::de::Error; fn next_key_seed(&mut self, seed: K) -> Result> where K: serde::de::DeserializeSeed<'de>, { if self.read_next_type()?.is_none() { return Ok(None); } self.read(|s| { seed.deserialize(DocumentKeyDeserializer { root_deserializer: &mut *s.root_deserializer, }) }) .map(Some) } fn next_value_seed(&mut self, seed: V) -> Result where V: serde::de::DeserializeSeed<'de>, { self.read_next_value(seed) } } impl<'d, 'de> serde::de::SeqAccess<'de> for DocumentAccess<'d, 'de> { type Error = Error; fn next_element_seed(&mut self, seed: S) -> Result> where S: serde::de::DeserializeSeed<'de>, { if self.read_next_type()?.is_none() { return Ok(None); } let _index = self.read(|s| s.root_deserializer.deserialize_cstr())?; self.read_next_value(seed).map(Some) } } impl<'d, 'de> EnumAccess<'de> for DocumentAccess<'d, 'de> { type Error = Error; type Variant = Self; fn variant_seed(mut self, seed: V) -> Result<(V::Value, Self::Variant)> where V: serde::de::DeserializeSeed<'de>, { if self.read_next_type()?.is_none() { return Err(Error::EndOfStream); } let key = self.read(|s| { seed.deserialize(DocumentKeyDeserializer { root_deserializer: &mut *s.root_deserializer, }) })?; Ok((key, self)) } } impl<'d, 'de> VariantAccess<'de> for DocumentAccess<'d, 'de> { type Error = Error; fn unit_variant(self) -> Result<()> { Err(Error::custom( "expected a string enum, got a document instead", )) } fn newtype_variant_seed(mut self, seed: S) -> Result where S: serde::de::DeserializeSeed<'de>, { self.read_next_value(seed) } fn tuple_variant(mut self, _len: usize, visitor: V) -> Result where V: serde::de::Visitor<'de>, { self.read(|s| s.root_deserializer.deserialize_seq(visitor)) } fn struct_variant(mut self, _fields: &'static [&'static str], visitor: V) -> Result where V: serde::de::Visitor<'de>, { self.read(|s| s.root_deserializer.deserialize_map(visitor)) } } /// Deserializer used specifically for deserializing a document's cstring keys. struct DocumentKeyDeserializer<'d, 'de> { root_deserializer: &'d mut Deserializer<'de>, } impl<'d, 'de> serde::de::Deserializer<'de> for DocumentKeyDeserializer<'d, 'de> { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: serde::de::Visitor<'de>, { let s = self.root_deserializer.deserialize_cstr()?; match s { Cow::Borrowed(b) => visitor.visit_borrowed_str(b), Cow::Owned(string) => visitor.visit_string(string), } } fn deserialize_enum( self, _name: &str, _variants: &'static [&'static str], visitor: V, ) -> Result where V: serde::de::Visitor<'de>, { visitor.visit_enum( self.root_deserializer .deserialize_cstr()? .into_deserializer(), ) } fn deserialize_newtype_struct(self, _name: &'static str, visitor: V) -> Result where V: serde::de::Visitor<'de>, { visitor.visit_newtype_struct(self) } fn is_human_readable(&self) -> bool { false } forward_to_deserialize_any! { bool char str bytes byte_buf option unit unit_struct string identifier seq tuple tuple_struct struct map ignored_any i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 } } /// Deserializer used to deserialize the given field name without any copies. struct FieldDeserializer { field_name: &'static str, } impl<'de> serde::de::Deserializer<'de> for FieldDeserializer { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: serde::de::Visitor<'de>, { visitor.visit_borrowed_str(self.field_name) } fn deserialize_newtype_struct(self, _name: &'static str, visitor: V) -> Result where V: serde::de::Visitor<'de>, { visitor.visit_newtype_struct(self) } fn is_human_readable(&self) -> bool { false } serde::forward_to_deserialize_any! { bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq bytes byte_buf map struct option unit ignored_any unit_struct tuple_struct tuple enum identifier } } /// A [`MapAccess`] used to deserialize entire documents as chunks of bytes without deserializing /// the individual key/value pairs. struct RawDocumentAccess<'d> { deserializer: RawDocumentDeserializer<'d>, /// Whether the first key has been deserialized yet or not. deserialized_first: bool, /// Whether or not this document being deserialized is for an array or not. array: bool, } impl<'de> RawDocumentAccess<'de> { fn new(doc: &'de RawDocument) -> Self { Self { deserializer: RawDocumentDeserializer { raw_doc: doc }, deserialized_first: false, array: false, } } fn for_array(doc: &'de RawDocument) -> Self { Self { deserializer: RawDocumentDeserializer { raw_doc: doc }, deserialized_first: false, array: true, } } } impl<'de> serde::de::MapAccess<'de> for RawDocumentAccess<'de> { type Error = Error; fn next_key_seed(&mut self, seed: K) -> Result> where K: serde::de::DeserializeSeed<'de>, { if !self.deserialized_first { self.deserialized_first = true; // the newtype name will indicate to the [`RawBson`] enum that the incoming // bytes are meant to be treated as a document or array instead of a binary value. seed.deserialize(FieldDeserializer { field_name: if self.array { RAW_ARRAY_NEWTYPE } else { RAW_DOCUMENT_NEWTYPE }, }) .map(Some) } else { Ok(None) } } fn next_value_seed(&mut self, seed: V) -> Result where V: serde::de::DeserializeSeed<'de>, { seed.deserialize(self.deserializer) } } #[derive(Clone, Copy)] struct RawDocumentDeserializer<'a> { raw_doc: &'a RawDocument, } impl<'de> serde::de::Deserializer<'de> for RawDocumentDeserializer<'de> { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: serde::de::Visitor<'de>, { visitor.visit_borrowed_bytes(self.raw_doc.as_bytes()) } fn is_human_readable(&self) -> bool { false } serde::forward_to_deserialize_any! { bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq bytes byte_buf map struct option unit newtype_struct ignored_any unit_struct tuple_struct tuple enum identifier } } struct ObjectIdAccess { oid: ObjectId, visited: bool, hint: DeserializerHint, } impl ObjectIdAccess { fn new(oid: ObjectId, hint: DeserializerHint) -> Self { Self { oid, visited: false, hint, } } } impl<'de> serde::de::MapAccess<'de> for ObjectIdAccess { type Error = Error; fn next_key_seed(&mut self, seed: K) -> Result> where K: serde::de::DeserializeSeed<'de>, { if self.visited { return Ok(None); } self.visited = true; seed.deserialize(FieldDeserializer { field_name: "$oid" }) .map(Some) } fn next_value_seed(&mut self, seed: V) -> Result where V: serde::de::DeserializeSeed<'de>, { seed.deserialize(ObjectIdDeserializer { oid: self.oid, hint: self.hint, }) } } struct ObjectIdDeserializer { oid: ObjectId, hint: DeserializerHint, } impl<'de> serde::de::Deserializer<'de> for ObjectIdDeserializer { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: serde::de::Visitor<'de>, { // save an allocation when deserializing to raw bson match self.hint { DeserializerHint::RawBson => visitor.visit_bytes(&self.oid.bytes()), _ => visitor.visit_string(self.oid.to_hex()), } } fn is_human_readable(&self) -> bool { false } serde::forward_to_deserialize_any! { bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq bytes byte_buf map struct option unit newtype_struct ignored_any unit_struct tuple_struct tuple enum identifier } } pub(crate) struct Decimal128Access { decimal: Decimal128, visited: bool, } impl Decimal128Access { pub(crate) fn new(decimal: Decimal128) -> Self { Self { decimal, visited: false, } } } impl<'de> serde::de::MapAccess<'de> for Decimal128Access { type Error = Error; fn next_key_seed(&mut self, seed: K) -> Result> where K: serde::de::DeserializeSeed<'de>, { if self.visited { return Ok(None); } self.visited = true; seed.deserialize(FieldDeserializer { field_name: "$numberDecimalBytes", }) .map(Some) } fn next_value_seed(&mut self, seed: V) -> Result where V: serde::de::DeserializeSeed<'de>, { seed.deserialize(Decimal128Deserializer(self.decimal)) } } struct Decimal128Deserializer(Decimal128); impl<'de> serde::de::Deserializer<'de> for Decimal128Deserializer { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: serde::de::Visitor<'de>, { visitor.visit_bytes(&self.0.bytes) } fn is_human_readable(&self) -> bool { false } serde::forward_to_deserialize_any! { bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq bytes byte_buf map struct option unit newtype_struct ignored_any unit_struct tuple_struct tuple enum identifier } } enum TimestampDeserializationStage { TopLevel, Time, Increment, Done, } struct TimestampAccess<'d> { deserializer: &'d mut TimestampDeserializer, } impl<'de, 'd> serde::de::MapAccess<'de> for TimestampAccess<'d> { type Error = Error; fn next_key_seed(&mut self, seed: K) -> Result> where K: serde::de::DeserializeSeed<'de>, { match self.deserializer.stage { TimestampDeserializationStage::TopLevel => seed .deserialize(FieldDeserializer { field_name: "$timestamp", }) .map(Some), TimestampDeserializationStage::Time => seed .deserialize(FieldDeserializer { field_name: "t" }) .map(Some), TimestampDeserializationStage::Increment => seed .deserialize(FieldDeserializer { field_name: "i" }) .map(Some), TimestampDeserializationStage::Done => Ok(None), } } fn next_value_seed(&mut self, seed: V) -> Result where V: serde::de::DeserializeSeed<'de>, { seed.deserialize(&mut *self.deserializer) } } struct TimestampDeserializer { ts: Timestamp, stage: TimestampDeserializationStage, } impl TimestampDeserializer { fn new(ts: Timestamp) -> Self { Self { ts, stage: TimestampDeserializationStage::TopLevel, } } } impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut TimestampDeserializer { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: serde::de::Visitor<'de>, { match self.stage { TimestampDeserializationStage::TopLevel => { self.stage = TimestampDeserializationStage::Time; visitor.visit_map(TimestampAccess { deserializer: self }) } TimestampDeserializationStage::Time => { self.stage = TimestampDeserializationStage::Increment; visitor.visit_u32(self.ts.time) } TimestampDeserializationStage::Increment => { self.stage = TimestampDeserializationStage::Done; visitor.visit_u32(self.ts.increment) } TimestampDeserializationStage::Done => { Err(Error::custom("timestamp fully deserialized already")) } } } fn is_human_readable(&self) -> bool { false } serde::forward_to_deserialize_any! { bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq bytes byte_buf map struct option unit newtype_struct ignored_any unit_struct tuple_struct tuple enum identifier } } /// A [`MapAccess`] providing access to a BSON datetime being deserialized. /// /// If hinted to be raw BSON, this deserializes the serde data model equivalent /// of { "$date": }. /// /// Otherwise, this deserializes the serde data model equivalent of /// { "$date": { "$numberLong": } }. struct DateTimeAccess<'d> { deserializer: &'d mut DateTimeDeserializer, } impl<'de, 'd> serde::de::MapAccess<'de> for DateTimeAccess<'d> { type Error = Error; fn next_key_seed(&mut self, seed: K) -> Result> where K: serde::de::DeserializeSeed<'de>, { match self.deserializer.stage { DateTimeDeserializationStage::TopLevel => seed .deserialize(FieldDeserializer { field_name: "$date", }) .map(Some), DateTimeDeserializationStage::NumberLong => seed .deserialize(FieldDeserializer { field_name: "$numberLong", }) .map(Some), DateTimeDeserializationStage::Done => Ok(None), } } fn next_value_seed(&mut self, seed: V) -> Result where V: serde::de::DeserializeSeed<'de>, { seed.deserialize(&mut *self.deserializer) } } struct DateTimeDeserializer { dt: DateTime, stage: DateTimeDeserializationStage, hint: DeserializerHint, } enum DateTimeDeserializationStage { TopLevel, NumberLong, Done, } impl DateTimeDeserializer { fn new(dt: DateTime, hint: DeserializerHint) -> Self { Self { dt, stage: DateTimeDeserializationStage::TopLevel, hint, } } } impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut DateTimeDeserializer { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: serde::de::Visitor<'de>, { match self.stage { DateTimeDeserializationStage::TopLevel => match self.hint { DeserializerHint::RawBson => { self.stage = DateTimeDeserializationStage::Done; visitor.visit_i64(self.dt.timestamp_millis()) } _ => { self.stage = DateTimeDeserializationStage::NumberLong; visitor.visit_map(DateTimeAccess { deserializer: self }) } }, DateTimeDeserializationStage::NumberLong => { self.stage = DateTimeDeserializationStage::Done; visitor.visit_string(self.dt.timestamp_millis().to_string()) } DateTimeDeserializationStage::Done => { Err(Error::custom("DateTime fully deserialized already")) } } } fn deserialize_newtype_struct(self, _name: &'static str, visitor: V) -> Result where V: serde::de::Visitor<'de>, { visitor.visit_newtype_struct(self) } fn is_human_readable(&self) -> bool { false } serde::forward_to_deserialize_any! { bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq bytes byte_buf map struct option unit ignored_any unit_struct tuple_struct tuple enum identifier } } /// A [`MapAccess`] providing access to a BSON binary being deserialized. /// /// If hinted to be raw BSON, this deserializes the serde data model equivalent /// of { "$binary": { "subType": , "bytes": } }. /// /// Otherwise, this deserializes the serde data model equivalent of /// { "$binary": { "subType": , "base64": } }. struct BinaryAccess<'d, 'de> { deserializer: &'d mut BinaryDeserializer<'de>, } impl<'de, 'd> serde::de::MapAccess<'de> for BinaryAccess<'d, 'de> { type Error = Error; fn next_key_seed(&mut self, seed: K) -> Result> where K: serde::de::DeserializeSeed<'de>, { let field_name = match self.deserializer.stage { BinaryDeserializationStage::TopLevel => "$binary", BinaryDeserializationStage::Subtype => "subType", BinaryDeserializationStage::Bytes => match self.deserializer.hint { DeserializerHint::RawBson => "bytes", _ => "base64", }, BinaryDeserializationStage::Done => return Ok(None), }; seed.deserialize(FieldDeserializer { field_name }).map(Some) } fn next_value_seed(&mut self, seed: V) -> Result where V: serde::de::DeserializeSeed<'de>, { seed.deserialize(&mut *self.deserializer) } } struct BinaryDeserializer<'a> { binary: RawBinaryRef<'a>, hint: DeserializerHint, stage: BinaryDeserializationStage, } impl<'a> BinaryDeserializer<'a> { fn new(binary: RawBinaryRef<'a>, hint: DeserializerHint) -> Self { Self { binary, hint, stage: BinaryDeserializationStage::TopLevel, } } } impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut BinaryDeserializer<'de> { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: serde::de::Visitor<'de>, { match self.stage { BinaryDeserializationStage::TopLevel => { self.stage = BinaryDeserializationStage::Subtype; visitor.visit_map(BinaryAccess { deserializer: self }) } BinaryDeserializationStage::Subtype => { self.stage = BinaryDeserializationStage::Bytes; match self.hint { DeserializerHint::RawBson => visitor.visit_u8(self.binary.subtype.into()), _ => visitor.visit_string(hex::encode([u8::from(self.binary.subtype)])), } } BinaryDeserializationStage::Bytes => { self.stage = BinaryDeserializationStage::Done; match self.hint { DeserializerHint::RawBson => visitor.visit_borrowed_bytes(self.binary.bytes), _ => visitor.visit_string(base64::encode(self.binary.bytes)), } } BinaryDeserializationStage::Done => { Err(Error::custom("Binary fully deserialized already")) } } } fn is_human_readable(&self) -> bool { false } serde::forward_to_deserialize_any! { bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq bytes byte_buf map struct option unit newtype_struct ignored_any unit_struct tuple_struct tuple enum identifier } } enum BinaryDeserializationStage { TopLevel, Subtype, Bytes, Done, } /// A [`MapAccess`] providing access to a BSON code with scope being deserialized. /// /// If hinted to be raw BSON, this deserializes the serde data model equivalent /// of { "$code": , "$scope": <&RawDocument> } }. /// /// Otherwise, this deserializes the serde data model equivalent of /// { "$code": "$scope": }. struct CodeWithScopeAccess<'de, 'd, 'a> { deserializer: &'a mut CodeWithScopeDeserializer<'de, 'd>, } impl<'de, 'd, 'a> CodeWithScopeAccess<'de, 'd, 'a> { fn new(deserializer: &'a mut CodeWithScopeDeserializer<'de, 'd>) -> Self { Self { deserializer } } } impl<'de, 'd, 'a> serde::de::MapAccess<'de> for CodeWithScopeAccess<'de, 'd, 'a> { type Error = Error; fn next_key_seed(&mut self, seed: K) -> Result> where K: serde::de::DeserializeSeed<'de>, { match self.deserializer.stage { CodeWithScopeDeserializationStage::Code => seed .deserialize(FieldDeserializer { field_name: "$code", }) .map(Some), CodeWithScopeDeserializationStage::Scope => seed .deserialize(FieldDeserializer { field_name: "$scope", }) .map(Some), CodeWithScopeDeserializationStage::Done => Ok(None), } } fn next_value_seed(&mut self, seed: V) -> Result where V: serde::de::DeserializeSeed<'de>, { seed.deserialize(&mut *self.deserializer) } } struct CodeWithScopeDeserializer<'de, 'a> { root_deserializer: &'a mut Deserializer<'de>, stage: CodeWithScopeDeserializationStage, hint: DeserializerHint, length_remaining: i32, } impl<'de, 'a> CodeWithScopeDeserializer<'de, 'a> { fn new(root_deserializer: &'a mut Deserializer<'de>, hint: DeserializerHint, len: i32) -> Self { Self { root_deserializer, stage: CodeWithScopeDeserializationStage::Code, hint, length_remaining: len, } } /// Executes a closure that reads from the BSON bytes and returns an error if the number of /// bytes read exceeds length_remaining. /// /// A mutable reference to this [`CodeWithScopeDeserializer`] is passed into the closure. fn read(&mut self, f: F) -> Result where F: FnOnce(&mut Self) -> Result, { let start_bytes = self.root_deserializer.bytes.bytes_read(); let out = f(self)?; let bytes_read = self.root_deserializer.bytes.bytes_read() - start_bytes; self.length_remaining -= bytes_read as i32; if self.length_remaining < 0 { return Err(Error::custom("length of CodeWithScope too short")); } Ok(out) } } impl<'de, 'a, 'b> serde::de::Deserializer<'de> for &'b mut CodeWithScopeDeserializer<'de, 'a> { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: serde::de::Visitor<'de>, { match self.stage { CodeWithScopeDeserializationStage::Code => { self.stage = CodeWithScopeDeserializationStage::Scope; match self.read(|s| s.root_deserializer.deserialize_str())? { Cow::Borrowed(s) => visitor.visit_borrowed_str(s), Cow::Owned(s) => visitor.visit_string(s), } } CodeWithScopeDeserializationStage::Scope => { self.stage = CodeWithScopeDeserializationStage::Done; self.read(|s| { s.root_deserializer.deserialize_document( visitor, s.hint, DocumentType::EmbeddedDocument, ) }) } CodeWithScopeDeserializationStage::Done => Err(Error::custom( "JavaScriptCodeWithScope fully deserialized already", )), } } fn deserialize_newtype_struct(self, _name: &'static str, visitor: V) -> Result where V: serde::de::Visitor<'de>, { visitor.visit_newtype_struct(self) } fn is_human_readable(&self) -> bool { false } serde::forward_to_deserialize_any! { bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq bytes byte_buf map struct option unit ignored_any unit_struct tuple_struct tuple enum identifier } } #[derive(Debug)] enum CodeWithScopeDeserializationStage { Code, Scope, Done, } /// A [`MapAccess`] providing access to a BSON DB pointer being deserialized. /// /// Regardless of the hint, this deserializes the serde data model equivalent /// of { "$dbPointer": { "$ref": , "$id": } }. struct DbPointerAccess<'de, 'd, 'a> { deserializer: &'a mut DbPointerDeserializer<'de, 'd>, } impl<'de, 'd, 'a> DbPointerAccess<'de, 'd, 'a> { fn new(deserializer: &'a mut DbPointerDeserializer<'de, 'd>) -> Self { Self { deserializer } } } impl<'de, 'd, 'a> serde::de::MapAccess<'de> for DbPointerAccess<'de, 'd, 'a> { type Error = Error; fn next_key_seed(&mut self, seed: K) -> Result> where K: serde::de::DeserializeSeed<'de>, { match self.deserializer.stage { DbPointerDeserializationStage::TopLevel => seed .deserialize(FieldDeserializer { field_name: "$dbPointer", }) .map(Some), DbPointerDeserializationStage::Namespace => seed .deserialize(FieldDeserializer { field_name: "$ref" }) .map(Some), DbPointerDeserializationStage::Id => seed .deserialize(FieldDeserializer { field_name: "$id" }) .map(Some), DbPointerDeserializationStage::Done => Ok(None), } } fn next_value_seed(&mut self, seed: V) -> Result where V: serde::de::DeserializeSeed<'de>, { seed.deserialize(&mut *self.deserializer) } } struct DbPointerDeserializer<'de, 'a> { root_deserializer: &'a mut Deserializer<'de>, stage: DbPointerDeserializationStage, hint: DeserializerHint, } impl<'de, 'a> DbPointerDeserializer<'de, 'a> { fn new(root_deserializer: &'a mut Deserializer<'de>, hint: DeserializerHint) -> Self { Self { root_deserializer, stage: DbPointerDeserializationStage::TopLevel, hint, } } } impl<'de, 'a, 'b> serde::de::Deserializer<'de> for &'b mut DbPointerDeserializer<'de, 'a> { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: serde::de::Visitor<'de>, { match self.stage { DbPointerDeserializationStage::TopLevel => { self.stage = DbPointerDeserializationStage::Namespace; visitor.visit_map(DbPointerAccess::new(self)) } DbPointerDeserializationStage::Namespace => { self.stage = DbPointerDeserializationStage::Id; match self.root_deserializer.deserialize_str()? { Cow::Borrowed(s) => visitor.visit_borrowed_str(s), Cow::Owned(s) => visitor.visit_string(s), } } DbPointerDeserializationStage::Id => { self.stage = DbPointerDeserializationStage::Done; self.root_deserializer .deserialize_objectid(visitor, self.hint) } DbPointerDeserializationStage::Done => { Err(Error::custom("DbPointer fully deserialized already")) } } } fn deserialize_newtype_struct(self, _name: &'static str, visitor: V) -> Result where V: serde::de::Visitor<'de>, { visitor.visit_newtype_struct(self) } fn is_human_readable(&self) -> bool { false } serde::forward_to_deserialize_any! { bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq bytes byte_buf map struct option unit ignored_any unit_struct tuple_struct tuple enum identifier } } #[derive(Debug)] enum DbPointerDeserializationStage { TopLevel, Namespace, Id, Done, } /// A [`MapAccess`] providing access to a BSON regular expression being deserialized. /// /// Regardless of the hint, this deserializes the serde data model equivalent /// of { "$regularExpression": { "pattern": , "options": } }. struct RegexAccess<'de, 'd, 'a> { deserializer: &'a mut RegexDeserializer<'de, 'd>, } impl<'de, 'd, 'a> RegexAccess<'de, 'd, 'a> { fn new(deserializer: &'a mut RegexDeserializer<'de, 'd>) -> Self { Self { deserializer } } } impl<'de, 'd, 'a> serde::de::MapAccess<'de> for RegexAccess<'de, 'd, 'a> { type Error = Error; fn next_key_seed(&mut self, seed: K) -> Result> where K: serde::de::DeserializeSeed<'de>, { match self.deserializer.stage { RegexDeserializationStage::TopLevel => seed .deserialize(FieldDeserializer { field_name: "$regularExpression", }) .map(Some), RegexDeserializationStage::Pattern => seed .deserialize(FieldDeserializer { field_name: "pattern", }) .map(Some), RegexDeserializationStage::Options => seed .deserialize(FieldDeserializer { field_name: "options", }) .map(Some), RegexDeserializationStage::Done => Ok(None), } } fn next_value_seed(&mut self, seed: V) -> Result where V: serde::de::DeserializeSeed<'de>, { seed.deserialize(&mut *self.deserializer) } } struct RegexDeserializer<'de, 'a> { root_deserializer: &'a mut Deserializer<'de>, stage: RegexDeserializationStage, } impl<'de, 'a> RegexDeserializer<'de, 'a> { fn new(root_deserializer: &'a mut Deserializer<'de>) -> Self { Self { root_deserializer, stage: RegexDeserializationStage::TopLevel, } } } impl<'de, 'a, 'b> serde::de::Deserializer<'de> for &'b mut RegexDeserializer<'de, 'a> { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: serde::de::Visitor<'de>, { match self.stage { RegexDeserializationStage::TopLevel => { self.stage.advance(); visitor.visit_map(RegexAccess::new(self)) } RegexDeserializationStage::Pattern | RegexDeserializationStage::Options => { self.stage.advance(); match self.root_deserializer.deserialize_cstr()? { Cow::Borrowed(s) => visitor.visit_borrowed_str(s), Cow::Owned(s) => visitor.visit_string(s), } } RegexDeserializationStage::Done => { Err(Error::custom("DbPointer fully deserialized already")) } } } fn is_human_readable(&self) -> bool { false } serde::forward_to_deserialize_any! { bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq bytes byte_buf map struct option unit newtype_struct ignored_any unit_struct tuple_struct tuple enum identifier } } #[derive(Debug)] enum RegexDeserializationStage { TopLevel, Pattern, Options, Done, } impl RegexDeserializationStage { fn advance(&mut self) { *self = match self { RegexDeserializationStage::TopLevel => RegexDeserializationStage::Pattern, RegexDeserializationStage::Pattern => RegexDeserializationStage::Options, RegexDeserializationStage::Options => RegexDeserializationStage::Done, RegexDeserializationStage::Done => RegexDeserializationStage::Done, } } } /// Helper access struct for visiting the extended JSON model of simple BSON types. /// e.g. Symbol, Timestamp, etc. struct RawBsonAccess<'a> { key: &'static str, value: BsonContent<'a>, first: bool, } /// Enum value representing some cached BSON data needed to represent a given /// BSON type's extended JSON model. #[derive(Debug, Clone, Copy)] enum BsonContent<'a> { Str(&'a str), Int32(i32), Boolean(bool), } impl<'a> RawBsonAccess<'a> { fn new(key: &'static str, value: BsonContent<'a>) -> Self { Self { key, value, first: true, } } } impl<'de> MapAccess<'de> for RawBsonAccess<'de> { type Error = Error; fn next_key_seed(&mut self, seed: K) -> Result> where K: serde::de::DeserializeSeed<'de>, { if self.first { self.first = false; seed.deserialize(FieldDeserializer { field_name: self.key, }) .map(Some) } else { Ok(None) } } fn next_value_seed(&mut self, seed: V) -> Result where V: serde::de::DeserializeSeed<'de>, { seed.deserialize(RawBsonDeserializer { value: self.value }) } } struct RawBsonDeserializer<'a> { value: BsonContent<'a>, } impl<'de> serde::de::Deserializer<'de> for RawBsonDeserializer<'de> { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: serde::de::Visitor<'de>, { match self.value { BsonContent::Boolean(b) => visitor.visit_bool(b), BsonContent::Str(s) => visitor.visit_borrowed_str(s), BsonContent::Int32(i) => visitor.visit_i32(i), } } fn deserialize_newtype_struct(self, _name: &'static str, visitor: V) -> Result where V: serde::de::Visitor<'de>, { visitor.visit_newtype_struct(self) } fn is_human_readable(&self) -> bool { false } serde::forward_to_deserialize_any! { bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq bytes byte_buf map struct option unit ignored_any unit_struct tuple_struct tuple enum identifier } } /// Struct wrapping a slice of BSON bytes. struct BsonBuf<'a> { bytes: &'a [u8], index: usize, /// Whether or not to insert replacement characters in place of invalid UTF-8 sequences when /// deserializing strings. utf8_lossy: bool, } impl<'a> Read for BsonBuf<'a> { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { self.index_check()?; let bytes_read = self.bytes[self.index..].as_ref().read(buf)?; self.index += bytes_read; Ok(bytes_read) } } impl<'a> BsonBuf<'a> { fn new(bytes: &'a [u8], utf8_lossy: bool) -> Self { Self { bytes, index: 0, utf8_lossy, } } fn bytes_read(&self) -> usize { self.index } fn bytes_remaining(&self) -> usize { self.bytes.len() - self.bytes_read() } /// Verify the index has not run out of bounds. fn index_check(&self) -> std::io::Result<()> { if self.index >= self.bytes.len() { return Err(ErrorKind::UnexpectedEof.into()); } Ok(()) } /// Get the string starting at the provided index and ending at the buffer's current index. /// /// Can optionally override the global UTF-8 lossy setting to ensure bytes are not allocated. fn str(&mut self, start: usize, utf8_lossy_override: Option) -> Result> { let bytes = &self.bytes[start..self.index]; let s = if utf8_lossy_override.unwrap_or(self.utf8_lossy) { String::from_utf8_lossy(bytes) } else { Cow::Borrowed(std::str::from_utf8(bytes).map_err(Error::custom)?) }; // consume the null byte if self.bytes[self.index] != 0 { return Err(Error::custom("string was not null-terminated")); } self.index += 1; self.index_check()?; Ok(s) } /// Attempts to read a null-terminated UTF-8 cstring from the data. /// /// If utf8_lossy and invalid UTF-8 is encountered, the unicode replacement character will be /// inserted in place of the offending data, resulting in an owned [`String`]. Otherwise, the /// data will be borrowed as-is. fn read_cstr(&mut self) -> Result> { let start = self.index; while self.index < self.bytes.len() && self.bytes[self.index] != 0 { self.index += 1 } self.index_check()?; self.str(start, None) } fn _advance_to_len_encoded_str(&mut self) -> Result { let len = read_i32(self)?; let start = self.index; // UTF-8 String must have at least 1 byte (the last 0x00). if len < 1 { return Err(Error::invalid_length( len as usize, &"UTF-8 string must have at least 1 byte", )); } self.index += (len - 1) as usize; self.index_check()?; Ok(start) } /// Attempts to read a null-terminated UTF-8 string from the data. /// /// If invalid UTF-8 is encountered, the unicode replacement character will be inserted in place /// of the offending data, resulting in an owned [`String`]. Otherwise, the data will be /// borrowed as-is. fn read_str(&mut self) -> Result> { let start = self._advance_to_len_encoded_str()?; self.str(start, None) } /// Attempts to read a null-terminated UTF-8 string from the data. fn read_borrowed_str(&mut self) -> Result<&'a str> { let start = self._advance_to_len_encoded_str()?; match self.str(start, Some(false))? { Cow::Borrowed(s) => Ok(s), Cow::Owned(_) => panic!("should have errored when encountering invalid UTF-8"), } } fn slice(&self, length: usize) -> Result<&'a [u8]> { if self.index + length > self.bytes.len() { return Err(Error::Io(Arc::new( std::io::ErrorKind::UnexpectedEof.into(), ))); } Ok(&self.bytes[self.index..(self.index + length)]) } fn read_slice(&mut self, length: usize) -> Result<&'a [u8]> { let slice = self.slice(length)?; self.index += length; Ok(slice) } } bson-2.10.0/src/de/serde.rs000064400000000000000000001111501046102023000134730ustar 00000000000000use std::{ borrow::Cow, convert::{TryFrom, TryInto}, fmt, vec, }; use serde::de::{ self, Deserialize, DeserializeSeed, Deserializer as _, EnumAccess, Error, MapAccess, SeqAccess, Unexpected, VariantAccess, Visitor, }; use serde_bytes::ByteBuf; use crate::{ bson::{Bson, DbPointer, JavaScriptCodeWithScope, Regex, Timestamp}, datetime::DateTime, document::{Document, IntoIter}, oid::ObjectId, raw::{RawBsonRef, RAW_ARRAY_NEWTYPE, RAW_BSON_NEWTYPE, RAW_DOCUMENT_NEWTYPE}, spec::BinarySubtype, uuid::UUID_NEWTYPE_NAME, Binary, Decimal128, }; use super::{raw::Decimal128Access, DeserializerHint}; pub(crate) struct BsonVisitor; struct ObjectIdVisitor; impl<'de> Visitor<'de> for ObjectIdVisitor { type Value = ObjectId; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("expecting an ObjectId") } #[inline] fn visit_str(self, value: &str) -> std::result::Result where E: serde::de::Error, { ObjectId::parse_str(value).map_err(|_| { E::invalid_value( Unexpected::Str(value), &"24-character, big-endian hex string", ) }) } #[inline] fn visit_bytes(self, v: &[u8]) -> std::result::Result where E: serde::de::Error, { let bytes: [u8; 12] = v .try_into() .map_err(|_| E::invalid_length(v.len(), &"12 bytes"))?; Ok(ObjectId::from_bytes(bytes)) } #[inline] fn visit_map(self, mut visitor: V) -> Result where V: MapAccess<'de>, { match BsonVisitor.visit_map(&mut visitor)? { Bson::ObjectId(oid) => Ok(oid), bson => { let err = format!( "expected map containing extended-JSON formatted ObjectId, instead found {}", bson ); Err(de::Error::custom(err)) } } } } impl<'de> Deserialize<'de> for ObjectId { fn deserialize(deserializer: D) -> std::result::Result where D: serde::Deserializer<'de>, { if !deserializer.is_human_readable() { deserializer.deserialize_bytes(ObjectIdVisitor) } else { deserializer.deserialize_any(ObjectIdVisitor) } } } impl<'de> Deserialize<'de> for Document { /// Deserialize this value given this [`Deserializer`]. fn deserialize(deserializer: D) -> Result where D: de::Deserializer<'de>, { deserializer.deserialize_map(BsonVisitor).and_then(|bson| { if let Bson::Document(doc) = bson { Ok(doc) } else { let err = format!("expected document, found extended JSON data type: {}", bson); Err(de::Error::invalid_type(Unexpected::Map, &&err[..])) } }) } } impl<'de> Deserialize<'de> for Bson { #[inline] fn deserialize(deserializer: D) -> Result where D: de::Deserializer<'de>, { deserializer.deserialize_any(BsonVisitor) } } impl<'de> Visitor<'de> for BsonVisitor { type Value = Bson; fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("a Bson") } #[inline] fn visit_bool(self, value: bool) -> Result where E: Error, { Ok(Bson::Boolean(value)) } #[inline] fn visit_i8(self, value: i8) -> Result where E: Error, { Ok(Bson::Int32(value as i32)) } #[inline] fn visit_u8(self, value: u8) -> Result where E: Error, { convert_unsigned_to_signed(value as u64) } #[inline] fn visit_i16(self, value: i16) -> Result where E: Error, { Ok(Bson::Int32(value as i32)) } #[inline] fn visit_u16(self, value: u16) -> Result where E: Error, { convert_unsigned_to_signed(value as u64) } #[inline] fn visit_i32(self, value: i32) -> Result where E: Error, { Ok(Bson::Int32(value)) } #[inline] fn visit_u32(self, value: u32) -> Result where E: Error, { convert_unsigned_to_signed(value as u64) } #[inline] fn visit_i64(self, value: i64) -> Result where E: Error, { Ok(Bson::Int64(value)) } #[inline] fn visit_u64(self, value: u64) -> Result where E: Error, { convert_unsigned_to_signed(value) } #[inline] fn visit_f64(self, value: f64) -> Result { Ok(Bson::Double(value)) } #[inline] fn visit_str(self, value: &str) -> Result where E: de::Error, { self.visit_string(String::from(value)) } #[inline] fn visit_string(self, value: String) -> Result { Ok(Bson::String(value)) } #[inline] fn visit_none(self) -> Result { Ok(Bson::Null) } #[inline] fn visit_some(self, deserializer: D) -> Result where D: de::Deserializer<'de>, { deserializer.deserialize_any(self) } #[inline] fn visit_unit(self) -> Result { Ok(Bson::Null) } #[inline] fn visit_seq(self, mut visitor: V) -> Result where V: SeqAccess<'de>, { let mut values = Vec::new(); while let Some(elem) = visitor.next_element()? { values.push(elem); } Ok(Bson::Array(values)) } fn visit_map(self, mut visitor: V) -> Result where V: MapAccess<'de>, { use crate::extjson; let mut doc = Document::new(); while let Some(k) = visitor.next_key::()? { match k.as_str() { "$oid" => { enum BytesOrHex<'a> { Bytes([u8; 12]), Hex(Cow<'a, str>), } impl<'a, 'de: 'a> Deserialize<'de> for BytesOrHex<'a> { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { struct BytesOrHexVisitor; impl<'de> Visitor<'de> for BytesOrHexVisitor { type Value = BytesOrHex<'de>; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!(formatter, "hexstring or byte array") } fn visit_str(self, v: &str) -> Result where E: Error, { Ok(BytesOrHex::Hex(Cow::Owned(v.to_string()))) } fn visit_borrowed_str( self, v: &'de str, ) -> Result where E: Error, { Ok(BytesOrHex::Hex(Cow::Borrowed(v))) } fn visit_bytes(self, v: &[u8]) -> Result where E: Error, { Ok(BytesOrHex::Bytes(v.try_into().map_err(Error::custom)?)) } } deserializer.deserialize_any(BytesOrHexVisitor) } } let bytes_or_hex: BytesOrHex = visitor.next_value()?; match bytes_or_hex { BytesOrHex::Bytes(b) => return Ok(Bson::ObjectId(ObjectId::from_bytes(b))), BytesOrHex::Hex(hex) => { return Ok(Bson::ObjectId(ObjectId::parse_str(&hex).map_err( |_| { V::Error::invalid_value( Unexpected::Str(&hex), &"24-character, big-endian hex string", ) }, )?)); } } } "$symbol" => { let string: String = visitor.next_value()?; return Ok(Bson::Symbol(string)); } "$numberInt" => { let string: String = visitor.next_value()?; return Ok(Bson::Int32(string.parse().map_err(|_| { V::Error::invalid_value( Unexpected::Str(&string), &"32-bit signed integer as a string", ) })?)); } "$numberLong" => { let string: String = visitor.next_value()?; return Ok(Bson::Int64(string.parse().map_err(|_| { V::Error::invalid_value( Unexpected::Str(&string), &"64-bit signed integer as a string", ) })?)); } "$numberDouble" => { let string: String = visitor.next_value()?; let val = match string.as_str() { "Infinity" => Bson::Double(std::f64::INFINITY), "-Infinity" => Bson::Double(std::f64::NEG_INFINITY), "NaN" => Bson::Double(std::f64::NAN), _ => Bson::Double(string.parse().map_err(|_| { V::Error::invalid_value( Unexpected::Str(&string), &"64-bit signed integer as a string", ) })?), }; return Ok(val); } "$binary" => { let v = visitor.next_value::()?; return Ok(Bson::Binary( extjson::models::Binary { body: v } .parse() .map_err(Error::custom)?, )); } "$code" => { let code = visitor.next_value::()?; if let Some(key) = visitor.next_key::()? { if key.as_str() == "$scope" { let scope = visitor.next_value::()?; return Ok(Bson::JavaScriptCodeWithScope(JavaScriptCodeWithScope { code, scope, })); } else { return Err(Error::unknown_field(key.as_str(), &["$scope"])); } } else { return Ok(Bson::JavaScriptCode(code)); } } "$scope" => { let scope = visitor.next_value::()?; if let Some(key) = visitor.next_key::()? { if key.as_str() == "$code" { let code = visitor.next_value::()?; return Ok(Bson::JavaScriptCodeWithScope(JavaScriptCodeWithScope { code, scope, })); } else { return Err(Error::unknown_field(key.as_str(), &["$code"])); } } else { return Err(Error::missing_field("$code")); } } "$timestamp" => { let ts = visitor.next_value::()?; return Ok(Bson::Timestamp(Timestamp { time: ts.t, increment: ts.i, })); } "$regularExpression" => { let re = visitor.next_value::()?; return Ok(Bson::RegularExpression(Regex::new(re.pattern, re.options))); } "$dbPointer" => { let dbp = visitor.next_value::()?; return Ok(Bson::DbPointer(DbPointer { id: dbp.id.parse().map_err(Error::custom)?, namespace: dbp.ref_ns, })); } "$date" => { let dt = visitor.next_value::()?; return Ok(Bson::DateTime( extjson::models::DateTime { body: dt } .parse() .map_err(Error::custom)?, )); } "$maxKey" => { let i = visitor.next_value::()?; return extjson::models::MaxKey { value: i } .parse() .map_err(Error::custom); } "$minKey" => { let i = visitor.next_value::()?; return extjson::models::MinKey { value: i } .parse() .map_err(Error::custom); } "$undefined" => { let b = visitor.next_value::()?; return extjson::models::Undefined { value: b } .parse() .map_err(Error::custom); } "$numberDecimal" => { let string: String = visitor.next_value()?; return Ok(Bson::Decimal128(string.parse::().map_err( |_| { V::Error::invalid_value( Unexpected::Str(&string), &"decimal128 as a string", ) }, )?)); } "$numberDecimalBytes" => { let bytes = visitor.next_value::()?; return Ok(Bson::Decimal128(Decimal128::deserialize_from_slice( &bytes, )?)); } k => { let v = visitor.next_value::()?; doc.insert(k, v); } } } Ok(Bson::Document(doc)) } #[inline] fn visit_bytes(self, v: &[u8]) -> Result where E: Error, { Ok(Bson::Binary(Binary { subtype: BinarySubtype::Generic, bytes: v.to_vec(), })) } #[inline] fn visit_byte_buf(self, v: Vec) -> Result where E: Error, { Ok(Bson::Binary(Binary { subtype: BinarySubtype::Generic, bytes: v, })) } #[inline] fn visit_newtype_struct(self, deserializer: D) -> Result where D: serde::Deserializer<'de>, { deserializer.deserialize_any(self) } } enum BsonInteger { Int32(i32), Int64(i64), } fn _convert_unsigned(value: u64) -> Result { if let Ok(int32) = i32::try_from(value) { Ok(BsonInteger::Int32(int32)) } else if let Ok(int64) = i64::try_from(value) { Ok(BsonInteger::Int64(int64)) } else { Err(Error::custom(format!( "cannot represent {} as a signed number", value ))) } } fn convert_unsigned_to_signed(value: u64) -> Result where E: Error, { let bi = _convert_unsigned(value)?; match bi { BsonInteger::Int32(i) => Ok(Bson::Int32(i)), BsonInteger::Int64(i) => Ok(Bson::Int64(i)), } } pub(crate) fn convert_unsigned_to_signed_raw<'a, E>(value: u64) -> Result, E> where E: Error, { let bi = _convert_unsigned(value)?; match bi { BsonInteger::Int32(i) => Ok(RawBsonRef::Int32(i)), BsonInteger::Int64(i) => Ok(RawBsonRef::Int64(i)), } } /// Serde Deserializer pub struct Deserializer { value: Option, options: DeserializerOptions, } /// Options used to configure a [`Deserializer`]. These can also be passed into /// [`crate::from_bson_with_options`] and [`crate::from_document_with_options`]. #[derive(Debug, Clone, Default)] #[non_exhaustive] pub struct DeserializerOptions { /// Whether the [`Deserializer`] should present itself as human readable or not. /// The default is true. pub human_readable: Option, } impl DeserializerOptions { /// Create a builder struct used to construct a [`DeserializerOptions`]. pub fn builder() -> DeserializerOptionsBuilder { DeserializerOptionsBuilder { options: Default::default(), } } } /// Builder used to construct a [`DeserializerOptions`]. pub struct DeserializerOptionsBuilder { options: DeserializerOptions, } impl DeserializerOptionsBuilder { /// Set the value for [`DeserializerOptions::human_readable`]. pub fn human_readable(mut self, val: impl Into>) -> Self { self.options.human_readable = val.into(); self } /// Consume this builder and produce a [`DeserializerOptions`]. pub fn build(self) -> DeserializerOptions { self.options } } impl Deserializer { /// Construct a new [`Deserializer`] using the default options. pub fn new(value: Bson) -> Deserializer { Deserializer::new_with_options(value, Default::default()) } /// Create a new [`Deserializer`] using the provided options. pub fn new_with_options(value: Bson, options: DeserializerOptions) -> Self { Deserializer { value: Some(value), options, } } fn deserialize_next<'de, V>( mut self, visitor: V, hint: DeserializerHint, ) -> Result where V: serde::de::Visitor<'de>, { let value = match self.value.take() { Some(value) => value, None => return Err(crate::de::Error::EndOfStream), }; let is_rawbson = matches!(hint, DeserializerHint::RawBson); if let DeserializerHint::BinarySubtype(expected_subtype) = hint { if let Bson::Binary(ref binary) = value { if binary.subtype != expected_subtype { return Err(Error::custom(format!( "expected Binary with subtype {:?}, instead got subtype {:?}", expected_subtype, binary.subtype ))); } } }; match value { Bson::Double(v) => visitor.visit_f64(v), Bson::String(v) => visitor.visit_string(v), Bson::Array(v) => { let len = v.len(); visitor.visit_seq(SeqDeserializer { iter: v.into_iter(), options: self.options, len, }) } Bson::Document(v) => visitor.visit_map(MapDeserializer::new(v, self.options)), Bson::Boolean(v) => visitor.visit_bool(v), Bson::Null => visitor.visit_unit(), Bson::Int32(v) => visitor.visit_i32(v), Bson::Int64(v) => visitor.visit_i64(v), Bson::Binary(b) if b.subtype == BinarySubtype::Generic => { visitor.visit_byte_buf(b.bytes) } Bson::Decimal128(d) => visitor.visit_map(Decimal128Access::new(d)), _ => { let doc = value.into_extended_document(is_rawbson); visitor.visit_map(MapDeserializer::new(doc, self.options)) } } } } macro_rules! forward_to_deserialize { ($( $name:ident ( $( $arg:ident : $ty:ty ),* ); )*) => { $( forward_to_deserialize!{ func: $name ( $( $arg: $ty ),* ); } )* }; (func: deserialize_enum ( $( $arg:ident : $ty:ty ),* );) => { fn deserialize_enum( self, $(_: $ty,)* _visitor: V, ) -> ::std::result::Result where V: ::serde::de::Visitor<'de> { Err(::serde::de::Error::custom("unexpected Enum")) } }; (func: $name:ident ( $( $arg:ident : $ty:ty ),* );) => { #[inline] fn $name( self, $(_: $ty,)* visitor: V, ) -> ::std::result::Result where V: ::serde::de::Visitor<'de> { self.deserialize_any(visitor) } }; } impl<'de> de::Deserializer<'de> for Deserializer { type Error = crate::de::Error; fn is_human_readable(&self) -> bool { self.options.human_readable.unwrap_or(true) } #[inline] fn deserialize_any(self, visitor: V) -> crate::de::Result where V: Visitor<'de>, { self.deserialize_next(visitor, DeserializerHint::None) } #[inline] fn deserialize_bytes(self, visitor: V) -> Result where V: Visitor<'de>, { match self.value { Some(Bson::ObjectId(oid)) if !self.is_human_readable() => { visitor.visit_bytes(&oid.bytes()) } _ => self.deserialize_any(visitor), } } #[inline] fn deserialize_option(self, visitor: V) -> crate::de::Result where V: Visitor<'de>, { match self.value { Some(Bson::Null) => visitor.visit_none(), Some(_) => visitor.visit_some(self), None => Err(crate::de::Error::EndOfStream), } } #[inline] fn deserialize_enum( mut self, _name: &str, _variants: &'static [&'static str], visitor: V, ) -> crate::de::Result where V: Visitor<'de>, { let value = match self.value.take() { Some(Bson::Document(value)) => value, Some(Bson::String(variant)) => { return visitor.visit_enum(EnumDeserializer { val: Bson::String(variant), deserializer: VariantDeserializer { val: None, options: self.options, }, }); } Some(v) => { return Err(crate::de::Error::invalid_type( v.as_unexpected(), &"expected an enum", )); } None => { return Err(crate::de::Error::EndOfStream); } }; let mut iter = value.into_iter(); let (variant, value) = match iter.next() { Some(v) => v, None => { return Err(crate::de::Error::invalid_value( Unexpected::Other("empty document"), &"variant name", )) } }; // enums are encoded in json as maps with a single key:value pair match iter.next() { Some((k, _)) => Err(crate::de::Error::invalid_value( Unexpected::Map, &format!("expected map with a single key, got extra key \"{}\"", k).as_str(), )), None => visitor.visit_enum(EnumDeserializer { val: Bson::String(variant), deserializer: VariantDeserializer { val: Some(value), options: self.options, }, }), } } #[inline] fn deserialize_newtype_struct( self, name: &'static str, visitor: V, ) -> crate::de::Result where V: Visitor<'de>, { match name { UUID_NEWTYPE_NAME => self.deserialize_next( visitor, DeserializerHint::BinarySubtype(BinarySubtype::Uuid), ), RAW_BSON_NEWTYPE => self.deserialize_next(visitor, DeserializerHint::RawBson), RAW_DOCUMENT_NEWTYPE => { if !matches!(self.value, Some(Bson::Document(_))) { return Err(serde::de::Error::custom(format!( "expected raw document, instead got {:?}", self.value ))); } self.deserialize_next(visitor, DeserializerHint::RawBson) } RAW_ARRAY_NEWTYPE => { if !matches!(self.value, Some(Bson::Array(_))) { return Err(serde::de::Error::custom(format!( "expected raw array, instead got {:?}", self.value ))); } self.deserialize_next(visitor, DeserializerHint::RawBson) } _ => visitor.visit_newtype_struct(self), } } forward_to_deserialize! { deserialize_bool(); deserialize_u8(); deserialize_u16(); deserialize_u32(); deserialize_u64(); deserialize_i8(); deserialize_i16(); deserialize_i32(); deserialize_i64(); deserialize_f32(); deserialize_f64(); deserialize_char(); deserialize_str(); deserialize_string(); deserialize_unit(); deserialize_seq(); deserialize_map(); deserialize_unit_struct(name: &'static str); deserialize_tuple_struct(name: &'static str, len: usize); deserialize_struct(name: &'static str, fields: &'static [&'static str]); deserialize_tuple(len: usize); deserialize_identifier(); deserialize_ignored_any(); deserialize_byte_buf(); } } struct EnumDeserializer { val: Bson, deserializer: VariantDeserializer, } impl<'de> EnumAccess<'de> for EnumDeserializer { type Error = crate::de::Error; type Variant = VariantDeserializer; fn variant_seed(self, seed: V) -> crate::de::Result<(V::Value, Self::Variant)> where V: DeserializeSeed<'de>, { let dec = Deserializer::new_with_options(self.val, self.deserializer.options.clone()); let value = seed.deserialize(dec)?; Ok((value, self.deserializer)) } } struct VariantDeserializer { val: Option, options: DeserializerOptions, } impl<'de> VariantAccess<'de> for VariantDeserializer { type Error = crate::de::Error; fn unit_variant(mut self) -> crate::de::Result<()> { match self.val.take() { None => Ok(()), Some(val) => { Bson::deserialize(Deserializer::new_with_options(val, self.options)).map(|_| ()) } } } fn newtype_variant_seed(mut self, seed: T) -> crate::de::Result where T: DeserializeSeed<'de>, { let dec = Deserializer::new_with_options( self.val.take().ok_or(crate::de::Error::EndOfStream)?, self.options, ); seed.deserialize(dec) } fn tuple_variant(mut self, _len: usize, visitor: V) -> crate::de::Result where V: Visitor<'de>, { match self.val.take().ok_or(crate::de::Error::EndOfStream)? { Bson::Array(fields) => { let de = SeqDeserializer { len: fields.len(), iter: fields.into_iter(), options: self.options, }; de.deserialize_any(visitor) } other => Err(crate::de::Error::invalid_type( other.as_unexpected(), &"expected a tuple", )), } } fn struct_variant( mut self, _fields: &'static [&'static str], visitor: V, ) -> crate::de::Result where V: Visitor<'de>, { match self.val.take().ok_or(crate::de::Error::EndOfStream)? { Bson::Document(fields) => { let de = MapDeserializer { len: fields.len(), iter: fields.into_iter(), value: None, options: self.options, }; de.deserialize_any(visitor) } ref other => Err(crate::de::Error::invalid_type( other.as_unexpected(), &"expected a struct", )), } } } struct SeqDeserializer { iter: vec::IntoIter, len: usize, options: DeserializerOptions, } impl<'de> de::Deserializer<'de> for SeqDeserializer { type Error = crate::de::Error; #[inline] fn deserialize_any(self, visitor: V) -> crate::de::Result where V: Visitor<'de>, { if self.len == 0 { visitor.visit_unit() } else { visitor.visit_seq(self) } } forward_to_deserialize! { deserialize_bool(); deserialize_u8(); deserialize_u16(); deserialize_u32(); deserialize_u64(); deserialize_i8(); deserialize_i16(); deserialize_i32(); deserialize_i64(); deserialize_f32(); deserialize_f64(); deserialize_char(); deserialize_str(); deserialize_string(); deserialize_unit(); deserialize_option(); deserialize_seq(); deserialize_bytes(); deserialize_map(); deserialize_unit_struct(name: &'static str); deserialize_newtype_struct(name: &'static str); deserialize_tuple_struct(name: &'static str, len: usize); deserialize_struct(name: &'static str, fields: &'static [&'static str]); deserialize_tuple(len: usize); deserialize_enum(name: &'static str, variants: &'static [&'static str]); deserialize_identifier(); deserialize_ignored_any(); deserialize_byte_buf(); } } impl<'de> SeqAccess<'de> for SeqDeserializer { type Error = crate::de::Error; fn next_element_seed(&mut self, seed: T) -> crate::de::Result> where T: DeserializeSeed<'de>, { match self.iter.next() { None => Ok(None), Some(value) => { self.len -= 1; let de = Deserializer::new_with_options(value, self.options.clone()); match seed.deserialize(de) { Ok(value) => Ok(Some(value)), Err(err) => Err(err), } } } } fn size_hint(&self) -> Option { Some(self.len) } } pub(crate) struct MapDeserializer { pub(crate) iter: IntoIter, pub(crate) value: Option, pub(crate) len: usize, pub(crate) options: DeserializerOptions, } impl MapDeserializer { pub(crate) fn new(doc: Document, options: impl Into>) -> Self { let len = doc.len(); MapDeserializer { iter: doc.into_iter(), len, value: None, options: options.into().unwrap_or_default(), } } } impl<'de> MapAccess<'de> for MapDeserializer { type Error = crate::de::Error; fn next_key_seed(&mut self, seed: K) -> crate::de::Result> where K: DeserializeSeed<'de>, { match self.iter.next() { Some((key, value)) => { self.len -= 1; self.value = Some(value); let de = Deserializer::new_with_options(Bson::String(key), self.options.clone()); match seed.deserialize(de) { Ok(val) => Ok(Some(val)), Err(e) => Err(e), } } None => Ok(None), } } fn next_value_seed(&mut self, seed: V) -> crate::de::Result where V: DeserializeSeed<'de>, { let value = self.value.take().ok_or(crate::de::Error::EndOfStream)?; let de = Deserializer::new_with_options(value, self.options.clone()); seed.deserialize(de) } fn size_hint(&self) -> Option { Some(self.len) } } impl<'de> de::Deserializer<'de> for MapDeserializer { type Error = crate::de::Error; #[inline] fn deserialize_any(self, visitor: V) -> crate::de::Result where V: Visitor<'de>, { visitor.visit_map(self) } forward_to_deserialize! { deserialize_bool(); deserialize_u8(); deserialize_u16(); deserialize_u32(); deserialize_u64(); deserialize_i8(); deserialize_i16(); deserialize_i32(); deserialize_i64(); deserialize_f32(); deserialize_f64(); deserialize_char(); deserialize_str(); deserialize_string(); deserialize_unit(); deserialize_option(); deserialize_seq(); deserialize_bytes(); deserialize_map(); deserialize_unit_struct(name: &'static str); deserialize_newtype_struct(name: &'static str); deserialize_tuple_struct(name: &'static str, len: usize); deserialize_struct(name: &'static str, fields: &'static [&'static str]); deserialize_tuple(len: usize); deserialize_enum(name: &'static str, variants: &'static [&'static str]); deserialize_identifier(); deserialize_ignored_any(); deserialize_byte_buf(); } } impl<'de> Deserialize<'de> for Timestamp { fn deserialize(deserializer: D) -> Result where D: de::Deserializer<'de>, { match Bson::deserialize(deserializer)? { Bson::Timestamp(timestamp) => Ok(timestamp), _ => Err(D::Error::custom("expecting Timestamp")), } } } impl<'de> Deserialize<'de> for Regex { fn deserialize(deserializer: D) -> Result where D: de::Deserializer<'de>, { match Bson::deserialize(deserializer)? { Bson::RegularExpression(regex) => Ok(regex), _ => Err(D::Error::custom("expecting Regex")), } } } impl<'de> Deserialize<'de> for JavaScriptCodeWithScope { fn deserialize(deserializer: D) -> Result where D: de::Deserializer<'de>, { match Bson::deserialize(deserializer)? { Bson::JavaScriptCodeWithScope(code_with_scope) => Ok(code_with_scope), _ => Err(D::Error::custom("expecting JavaScriptCodeWithScope")), } } } impl<'de> Deserialize<'de> for Binary { fn deserialize(deserializer: D) -> Result where D: de::Deserializer<'de>, { match Bson::deserialize(deserializer)? { Bson::Binary(binary) => Ok(binary), d => Err(D::Error::custom(format!( "expecting Binary but got {:?} instead", d ))), } } } impl<'de> Deserialize<'de> for Decimal128 { fn deserialize(deserializer: D) -> Result where D: de::Deserializer<'de>, { match Bson::deserialize(deserializer)? { Bson::Decimal128(d128) => Ok(d128), o => Err(D::Error::custom(format!( "expecting Decimal128, got {:?}", o ))), } } } impl<'de> Deserialize<'de> for DateTime { fn deserialize(deserializer: D) -> Result where D: de::Deserializer<'de>, { match Bson::deserialize(deserializer)? { Bson::DateTime(dt) => Ok(dt), _ => Err(D::Error::custom("expecting DateTime")), } } } impl<'de> Deserialize<'de> for DbPointer { fn deserialize(deserializer: D) -> Result where D: de::Deserializer<'de>, { match Bson::deserialize(deserializer)? { Bson::DbPointer(db_pointer) => Ok(db_pointer), _ => Err(D::Error::custom("expecting DbPointer")), } } } bson-2.10.0/src/decimal128.rs000064400000000000000000000404671046102023000136460ustar 00000000000000//! [BSON Decimal128](https://github.com/mongodb/specifications/blob/master/source/bson-decimal128/decimal128.rst) data type representation use std::{convert::TryInto, fmt}; use bitvec::prelude::*; /// Struct representing a BSON Decimal128 type. /// /// This type supports conversion to and from human-readable strings via the [std::fmt::Display] and /// [std::str::FromStr] traits: /// /// ```rust /// # use std::str::FromStr; /// # use bson::Decimal128; /// # fn example() -> std::result::Result<(), Box> { /// let value: Decimal128 = "3.14159".parse()?; /// assert_eq!("3.14159", format!("{}", value)); /// let scientific = Decimal128::from_str("1.05E+3")?; /// assert_eq!("1.05E+3", scientific.to_string()); /// # Ok(()) /// # } /// # example().unwrap() /// ``` #[derive(Copy, Clone, PartialEq)] pub struct Decimal128 { /// BSON bytes containing the decimal128. Stored for round tripping. pub(crate) bytes: [u8; 16], } impl Decimal128 { /// Constructs a new `Decimal128` from the provided raw byte representation. pub fn from_bytes(bytes: [u8; 128 / 8]) -> Self { Self { bytes } } /// Returns the raw byte representation of this `Decimal128`. pub fn bytes(&self) -> [u8; 128 / 8] { self.bytes } pub(crate) fn deserialize_from_slice( bytes: &[u8], ) -> std::result::Result { let arr: [u8; 128 / 8] = bytes.try_into().map_err(E::custom)?; Ok(Decimal128 { bytes: arr }) } } impl fmt::Debug for Decimal128 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Decimal128(...)") } } impl fmt::Display for Decimal128 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", ParsedDecimal128::new(self)) } } impl std::str::FromStr for Decimal128 { type Err = ParseError; fn from_str(s: &str) -> Result { Ok(s.parse::()?.pack()) } } #[derive(Debug, Clone, PartialEq)] struct ParsedDecimal128 { sign: bool, kind: Decimal128Kind, } #[derive(Debug, Clone, PartialEq)] enum Decimal128Kind { NaN { signalling: bool, }, Infinity, Finite { exponent: Exponent, coefficient: Coefficient, }, } #[derive(Debug, Clone, PartialEq)] struct Exponent([u8; 2]); impl Exponent { /// The exponent is stored as an unsigned value; `BIAS` is subtracted to get the actual value. const BIAS: i16 = 6176; /// The minimum representable exponent. This is distinct from the specifications "min" value, /// which marks the point at which exponents are considered subnormal. const TINY: i16 = -6176; /// The maximum representable exponent. const MAX: i16 = 6111; /// The number of unused bits in the parsed representation. const UNUSED_BITS: usize = 2; /// The total number of bits in the packed representation. const PACKED_WIDTH: usize = 14; fn from_bits(src_bits: &BitSlice) -> Self { let mut bytes = [0u8; 2]; bytes.view_bits_mut::()[Self::UNUSED_BITS..].copy_from_bitslice(src_bits); Self(bytes) } fn from_native(value: i16) -> Self { let mut bytes = [0u8; 2]; bytes.view_bits_mut::().store_be(value + Self::BIAS); Self(bytes) } fn bits(&self) -> &BitSlice { &self.0.view_bits::()[Self::UNUSED_BITS..] } fn raw(&self) -> u16 { self.0.view_bits::().load_be::() } fn value(&self) -> i16 { (self.raw() as i16) - Self::BIAS } } #[derive(Debug, Clone, PartialEq)] struct Coefficient([u8; 16]); impl Coefficient { /// The number of unused bits in the parsed representation. const UNUSED_BITS: usize = 14; /// The maximum number of digits allowed in a base-10 string representation of the coefficient. const MAX_DIGITS: usize = 34; /// The maximum allowable value of a coefficient. const MAX_VALUE: u128 = 9_999_999_999_999_999_999_999_999_999_999_999; fn from_bits( src_prefix: &BitSlice, src_suffix: &BitSlice, ) -> Result { let mut bytes = [0u8; 16]; let bits = &mut bytes.view_bits_mut::()[Self::UNUSED_BITS..]; let prefix_len = src_prefix.len(); bits[0..prefix_len].copy_from_bitslice(src_prefix); bits[prefix_len..].copy_from_bitslice(src_suffix); let out = Self(bytes); if out.value() > Self::MAX_VALUE { Err(ParseError::Overflow) } else { Ok(out) } } fn from_native(value: u128) -> Self { let mut bytes = [0u8; 16]; bytes.view_bits_mut::().store_be(value); Self(bytes) } fn bits(&self) -> &BitSlice { &self.0.view_bits::()[Self::UNUSED_BITS..] } fn value(&self) -> u128 { self.0.view_bits::().load_be::() } } impl ParsedDecimal128 { fn new(source: &Decimal128) -> Self { // BSON byte order is the opposite of the decimal128 spec byte order, so flip 'em. The rest // of this method could be rewritten to not need this, but readability is helped by // keeping the implementation congruent with the spec. let tmp: [u8; 16] = { let mut tmp = [0u8; 16]; tmp.view_bits_mut::() .store_be(source.bytes.view_bits::().load_le::()); tmp }; let src_bits = tmp.view_bits::(); let sign = src_bits[0]; let kind = if src_bits[1..5].all() { // Special value if src_bits[5] { Decimal128Kind::NaN { signalling: src_bits[6], } } else { Decimal128Kind::Infinity } } else { // Finite value let exponent_offset; let coeff_prefix; if src_bits[1..3].all() { exponent_offset = 3; coeff_prefix = bits![static u8, Msb0; 1, 0, 0]; } else { exponent_offset = 1; coeff_prefix = bits![static u8, Msb0; 0]; } let coeff_offset = exponent_offset + Exponent::PACKED_WIDTH; let exponent = Exponent::from_bits(&src_bits[exponent_offset..coeff_offset]); let coefficient = match Coefficient::from_bits(coeff_prefix, &src_bits[coeff_offset..]) { Ok(c) => c, // Invalid coefficients get silently replaced with zero. Err(_) => Coefficient([0u8; 16]), }; Decimal128Kind::Finite { exponent, coefficient, } }; ParsedDecimal128 { sign, kind } } fn pack(&self) -> Decimal128 { let mut tmp = [0u8; 16]; let dest_bits = tmp.view_bits_mut::(); dest_bits.set(0, self.sign); match &self.kind { Decimal128Kind::NaN { signalling } => { dest_bits[1..6].copy_from_bitslice(bits![u8, Msb0; 1, 1, 1, 1, 1]); dest_bits.set(6, *signalling); } Decimal128Kind::Infinity => { dest_bits[1..6].copy_from_bitslice(bits![u8, Msb0; 1, 1, 1, 1, 0]); } Decimal128Kind::Finite { exponent, coefficient, } => { let mut coeff_bits = coefficient.bits(); let exponent_offset; if coeff_bits[0] { dest_bits.set(1, true); dest_bits.set(2, true); coeff_bits = &coeff_bits[3..]; exponent_offset = 3; } else { coeff_bits = &coeff_bits[1..]; exponent_offset = 1; }; let coeff_offset = exponent_offset + Exponent::PACKED_WIDTH; dest_bits[exponent_offset..coeff_offset].copy_from_bitslice(exponent.bits()); dest_bits[coeff_offset..].copy_from_bitslice(coeff_bits); } } let mut bytes = [0u8; 16]; bytes .view_bits_mut::() .store_le(tmp.view_bits::().load_be::()); Decimal128 { bytes } } } impl fmt::Display for ParsedDecimal128 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // MongoDB diverges from the IEEE spec and requires no sign for NaN if self.sign && !matches!(&self.kind, Decimal128Kind::NaN { .. }) { write!(f, "-")?; } match &self.kind { Decimal128Kind::NaN { signalling: _signalling, } => { /* Likewise, MongoDB requires no 's' prefix for signalling. if *signalling { write!(f, "s")?; } */ write!(f, "NaN")?; } Decimal128Kind::Infinity => write!(f, "Infinity")?, Decimal128Kind::Finite { exponent, coefficient, } => { let coeff_str = format!("{}", coefficient.value()); let exp_val = exponent.value(); let adj_exp = exp_val + (coeff_str.len() as i16) - 1; if exp_val <= 0 && adj_exp >= -6 { // Plain notation if exp_val == 0 { write!(f, "{}", coeff_str)?; } else { let dec_charlen = exp_val.unsigned_abs() as usize; if dec_charlen >= coeff_str.len() { write!(f, "0.")?; write!(f, "{}", "0".repeat(dec_charlen - coeff_str.len()))?; write!(f, "{}", coeff_str)?; } else { let (pre, post) = coeff_str.split_at(coeff_str.len() - dec_charlen); write!(f, "{}", pre)?; write!(f, ".")?; write!(f, "{}", post)?; } } } else { // Exponential notation let (pre, post) = coeff_str.split_at(1); write!(f, "{}", pre)?; if !post.is_empty() { write!(f, ".{}", post)?; } write!(f, "E")?; if adj_exp > 0 { write!(f, "+")?; } write!(f, "{}", adj_exp)?; } } } Ok(()) } } #[derive(Debug)] #[non_exhaustive] pub enum ParseError { EmptyExponent, InvalidExponent(std::num::ParseIntError), InvalidCoefficient(std::num::ParseIntError), Overflow, Underflow, InexactRounding, } impl fmt::Display for ParseError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { ParseError::EmptyExponent => write!(f, "empty exponent"), ParseError::InvalidExponent(e) => write!(f, "invalid exponent: {}", e), ParseError::InvalidCoefficient(e) => write!(f, "invalid coefficient: {}", e), ParseError::Overflow => write!(f, "overflow"), ParseError::Underflow => write!(f, "underflow"), ParseError::InexactRounding => write!(f, "inexact rounding"), } } } impl std::error::Error for ParseError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { ParseError::InvalidExponent(e) => Some(e), ParseError::InvalidCoefficient(e) => Some(e), _ => None, } } } impl std::str::FromStr for ParsedDecimal128 { type Err = ParseError; fn from_str(mut s: &str) -> Result { let sign; if let Some(rest) = s.strip_prefix(&['-', '+'][..]) { sign = s.starts_with('-'); s = rest; } else { sign = false; } let kind = match s.to_ascii_lowercase().as_str() { "nan" => Decimal128Kind::NaN { signalling: false }, "snan" => Decimal128Kind::NaN { signalling: true }, "infinity" | "inf" => Decimal128Kind::Infinity, finite_str => { // Split into parts let mut decimal_str; let exp_str; match finite_str.split_once('e') { None => { decimal_str = finite_str; exp_str = "0"; } Some((_, "")) => return Err(ParseError::EmptyExponent), Some((pre, post)) => { decimal_str = pre; exp_str = post; } } let mut exp = exp_str .parse::() .map_err(ParseError::InvalidExponent)?; // Remove decimal point and adjust exponent let joined_str; if let Some((pre, post)) = decimal_str.split_once('.') { let exp_adj = post.len().try_into().map_err(|_| ParseError::Underflow)?; exp = exp.checked_sub(exp_adj).ok_or(ParseError::Underflow)?; joined_str = format!("{}{}", pre, post); decimal_str = &joined_str; } // Strip leading zeros let rest = decimal_str.trim_start_matches('0'); decimal_str = if rest.is_empty() { "0" } else { rest }; // Check decimal precision { let len = decimal_str.len(); if len > Coefficient::MAX_DIGITS { decimal_str = round_decimal_str(decimal_str, Coefficient::MAX_DIGITS)?; let exp_adj = (len - decimal_str.len()) .try_into() .map_err(|_| ParseError::Overflow)?; exp = exp.checked_add(exp_adj).ok_or(ParseError::Overflow)?; } } // Check exponent limits if exp < Exponent::TINY { if decimal_str != "0" { let delta = (Exponent::TINY - exp) .try_into() .map_err(|_| ParseError::Overflow)?; let new_precision = decimal_str .len() .checked_sub(delta) .ok_or(ParseError::Underflow)?; decimal_str = round_decimal_str(decimal_str, new_precision)?; } exp = Exponent::TINY; } let padded_str; if exp > Exponent::MAX { if decimal_str != "0" { let delta = (exp - Exponent::MAX) .try_into() .map_err(|_| ParseError::Overflow)?; if decimal_str .len() .checked_add(delta) .ok_or(ParseError::Overflow)? > Coefficient::MAX_DIGITS { return Err(ParseError::Overflow); } padded_str = format!("{}{}", decimal_str, "0".repeat(delta)); decimal_str = &padded_str; } exp = Exponent::MAX; } // Assemble the final value let exponent = Exponent::from_native(exp); let coeff: u128 = decimal_str .parse() .map_err(ParseError::InvalidCoefficient)?; let coefficient = Coefficient::from_native(coeff); Decimal128Kind::Finite { exponent, coefficient, } } }; Ok(Self { sign, kind }) } } fn round_decimal_str(s: &str, precision: usize) -> Result<&str, ParseError> { let (pre, post) = s.split_at(precision); // Any nonzero trimmed digits mean it would be an imprecise round. if post.chars().any(|c| c != '0') { return Err(ParseError::InexactRounding); } Ok(pre) } bson-2.10.0/src/document.rs000064400000000000000000000546341046102023000136340ustar 00000000000000//! A BSON document represented as an associative HashMap with insertion ordering. use std::{ convert::TryInto, error, fmt::{self, Debug, Display, Formatter}, io::{Read, Write}, iter::{Extend, FromIterator, IntoIterator}, }; use ahash::RandomState; use indexmap::IndexMap; use serde::{de::Error, Deserialize}; use crate::{ bson::{Array, Bson, Timestamp}, de::{read_i32, MIN_BSON_DOCUMENT_SIZE}, oid::ObjectId, spec::BinarySubtype, Binary, Decimal128, }; /// Error to indicate that either a value was empty or it contained an unexpected /// type, for use with the direct getters. #[derive(PartialEq, Clone)] #[non_exhaustive] pub enum ValueAccessError { /// Cannot find the expected field with the specified key NotPresent, /// Found a Bson value with the specified key, but not with the expected type UnexpectedType, } /// Result of accessing Bson value pub type ValueAccessResult = Result; impl Debug for ValueAccessError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match *self { ValueAccessError::NotPresent => write!(f, "ValueAccessError: field is not present"), ValueAccessError::UnexpectedType => { write!(f, "ValueAccessError: field does not have the expected type") } } } } impl Display for ValueAccessError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match *self { ValueAccessError::NotPresent => write!(f, "field is not present"), ValueAccessError::UnexpectedType => write!(f, "field does not have the expected type"), } } } impl error::Error for ValueAccessError {} /// A BSON document represented as an associative HashMap with insertion ordering. #[derive(Clone, PartialEq)] pub struct Document { inner: IndexMap, } impl Default for Document { fn default() -> Self { Document::new() } } impl Display for Document { fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { fmt.write_str("{")?; let mut first = true; for (k, v) in self { if first { first = false; fmt.write_str(" ")?; } else { fmt.write_str(", ")?; } write!(fmt, "\"{}\": {}", k, v)?; } write!(fmt, "{}}}", if !first { " " } else { "" }) } } impl Debug for Document { fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { write!(fmt, "Document(")?; Debug::fmt(&self.inner, fmt)?; write!(fmt, ")") } } /// An iterator over Document entries. pub struct IntoIter { inner: indexmap::map::IntoIter, } /// An owning iterator over Document entries. pub struct Iter<'a> { inner: indexmap::map::Iter<'a, String, Bson>, } /// An iterator over an Document's keys. pub struct Keys<'a> { inner: indexmap::map::Keys<'a, String, Bson>, } /// An iterator over an Document's values. pub struct Values<'a> { inner: indexmap::map::Values<'a, String, Bson>, } /// An iterator over a [`Document`]'s keys and mutable values. pub struct IterMut<'a> { inner: indexmap::map::IterMut<'a, String, Bson>, } impl<'a> Iterator for Keys<'a> { type Item = &'a String; fn next(&mut self) -> Option<&'a String> { self.inner.next() } } impl<'a> Iterator for Values<'a> { type Item = &'a Bson; fn next(&mut self) -> Option<&'a Bson> { self.inner.next() } } impl IntoIterator for Document { type Item = (String, Bson); type IntoIter = IntoIter; fn into_iter(self) -> Self::IntoIter { IntoIter { inner: self.inner.into_iter(), } } } impl<'a> IntoIterator for &'a Document { type Item = (&'a String, &'a Bson); type IntoIter = Iter<'a>; fn into_iter(self) -> Self::IntoIter { Iter { inner: self.inner.iter(), } } } impl FromIterator<(String, Bson)> for Document { fn from_iter>(iter: T) -> Self { let mut doc = Document::new(); for (k, v) in iter { doc.insert(k, v); } doc } } impl Iterator for IntoIter { type Item = (String, Bson); fn next(&mut self) -> Option<(String, Bson)> { self.inner.next() } } impl<'a> Iterator for Iter<'a> { type Item = (&'a String, &'a Bson); fn next(&mut self) -> Option<(&'a String, &'a Bson)> { self.inner.next() } } impl<'a> Iterator for IterMut<'a> { type Item = (&'a String, &'a mut Bson); fn next(&mut self) -> Option<(&'a String, &'a mut Bson)> { self.inner.next() } } impl Document { /// Creates a new empty Document. pub fn new() -> Document { Document { inner: IndexMap::default(), } } /// Gets an iterator over the entries of the map. pub fn iter(&self) -> Iter { self.into_iter() } /// Gets an iterator over pairs of keys and mutable values. pub fn iter_mut(&mut self) -> IterMut { IterMut { inner: self.inner.iter_mut(), } } /// Clears the document, removing all values. pub fn clear(&mut self) { self.inner.clear(); } /// Returns a reference to the Bson corresponding to the key. pub fn get(&self, key: impl AsRef) -> Option<&Bson> { self.inner.get(key.as_ref()) } /// Gets a mutable reference to the Bson corresponding to the key pub fn get_mut(&mut self, key: impl AsRef) -> Option<&mut Bson> { self.inner.get_mut(key.as_ref()) } /// Get a floating point value for this key if it exists and has /// the correct type. pub fn get_f64(&self, key: impl AsRef) -> ValueAccessResult { match self.get(key) { Some(&Bson::Double(v)) => Ok(v), Some(_) => Err(ValueAccessError::UnexpectedType), None => Err(ValueAccessError::NotPresent), } } /// Get a mutable reference to a floating point value for this key if it exists and has /// the correct type. pub fn get_f64_mut(&mut self, key: impl AsRef) -> ValueAccessResult<&mut f64> { match self.get_mut(key) { Some(&mut Bson::Double(ref mut v)) => Ok(v), Some(_) => Err(ValueAccessError::UnexpectedType), None => Err(ValueAccessError::NotPresent), } } /// Get a reference to a Decimal128 value for key, if it exists. pub fn get_decimal128(&self, key: impl AsRef) -> ValueAccessResult<&Decimal128> { match self.get(key) { Some(Bson::Decimal128(v)) => Ok(v), Some(_) => Err(ValueAccessError::UnexpectedType), None => Err(ValueAccessError::NotPresent), } } /// Get a mutable reference to a Decimal128 value for key, if it exists. pub fn get_decimal128_mut( &mut self, key: impl AsRef, ) -> ValueAccessResult<&mut Decimal128> { match self.get_mut(key) { Some(&mut Bson::Decimal128(ref mut v)) => Ok(v), Some(_) => Err(ValueAccessError::UnexpectedType), None => Err(ValueAccessError::NotPresent), } } /// Get a string slice this key if it exists and has the correct type. pub fn get_str(&self, key: impl AsRef) -> ValueAccessResult<&str> { match self.get(key) { Some(Bson::String(v)) => Ok(v), Some(_) => Err(ValueAccessError::UnexpectedType), None => Err(ValueAccessError::NotPresent), } } /// Get a mutable string slice this key if it exists and has the correct type. pub fn get_str_mut(&mut self, key: impl AsRef) -> ValueAccessResult<&mut str> { match self.get_mut(key) { Some(&mut Bson::String(ref mut v)) => Ok(v), Some(_) => Err(ValueAccessError::UnexpectedType), None => Err(ValueAccessError::NotPresent), } } /// Get a reference to an array for this key if it exists and has /// the correct type. pub fn get_array(&self, key: impl AsRef) -> ValueAccessResult<&Array> { match self.get(key) { Some(Bson::Array(v)) => Ok(v), Some(_) => Err(ValueAccessError::UnexpectedType), None => Err(ValueAccessError::NotPresent), } } /// Get a mutable reference to an array for this key if it exists and has /// the correct type. pub fn get_array_mut(&mut self, key: impl AsRef) -> ValueAccessResult<&mut Array> { match self.get_mut(key) { Some(&mut Bson::Array(ref mut v)) => Ok(v), Some(_) => Err(ValueAccessError::UnexpectedType), None => Err(ValueAccessError::NotPresent), } } /// Get a reference to a document for this key if it exists and has /// the correct type. pub fn get_document(&self, key: impl AsRef) -> ValueAccessResult<&Document> { match self.get(key) { Some(Bson::Document(v)) => Ok(v), Some(_) => Err(ValueAccessError::UnexpectedType), None => Err(ValueAccessError::NotPresent), } } /// Get a mutable reference to a document for this key if it exists and has /// the correct type. pub fn get_document_mut(&mut self, key: impl AsRef) -> ValueAccessResult<&mut Document> { match self.get_mut(key) { Some(&mut Bson::Document(ref mut v)) => Ok(v), Some(_) => Err(ValueAccessError::UnexpectedType), None => Err(ValueAccessError::NotPresent), } } /// Get a bool value for this key if it exists and has the correct type. pub fn get_bool(&self, key: impl AsRef) -> ValueAccessResult { match self.get(key) { Some(&Bson::Boolean(v)) => Ok(v), Some(_) => Err(ValueAccessError::UnexpectedType), None => Err(ValueAccessError::NotPresent), } } /// Get a mutable reference to a bool value for this key if it exists and has the correct type. pub fn get_bool_mut(&mut self, key: impl AsRef) -> ValueAccessResult<&mut bool> { match self.get_mut(key) { Some(&mut Bson::Boolean(ref mut v)) => Ok(v), Some(_) => Err(ValueAccessError::UnexpectedType), None => Err(ValueAccessError::NotPresent), } } /// Returns wether this key has a null value pub fn is_null(&self, key: impl AsRef) -> bool { self.get(key) == Some(&Bson::Null) } /// Get an i32 value for this key if it exists and has the correct type. pub fn get_i32(&self, key: impl AsRef) -> ValueAccessResult { match self.get(key) { Some(&Bson::Int32(v)) => Ok(v), Some(_) => Err(ValueAccessError::UnexpectedType), None => Err(ValueAccessError::NotPresent), } } /// Get a mutable reference to an i32 value for this key if it exists and has the correct type. pub fn get_i32_mut(&mut self, key: impl AsRef) -> ValueAccessResult<&mut i32> { match self.get_mut(key) { Some(&mut Bson::Int32(ref mut v)) => Ok(v), Some(_) => Err(ValueAccessError::UnexpectedType), None => Err(ValueAccessError::NotPresent), } } /// Get an i64 value for this key if it exists and has the correct type. pub fn get_i64(&self, key: impl AsRef) -> ValueAccessResult { match self.get(key) { Some(&Bson::Int64(v)) => Ok(v), Some(_) => Err(ValueAccessError::UnexpectedType), None => Err(ValueAccessError::NotPresent), } } /// Get a mutable reference to an i64 value for this key if it exists and has the correct type. pub fn get_i64_mut(&mut self, key: impl AsRef) -> ValueAccessResult<&mut i64> { match self.get_mut(key) { Some(&mut Bson::Int64(ref mut v)) => Ok(v), Some(_) => Err(ValueAccessError::UnexpectedType), None => Err(ValueAccessError::NotPresent), } } /// Get a time stamp value for this key if it exists and has the correct type. pub fn get_timestamp(&self, key: impl AsRef) -> ValueAccessResult { match self.get(key) { Some(&Bson::Timestamp(timestamp)) => Ok(timestamp), Some(_) => Err(ValueAccessError::UnexpectedType), None => Err(ValueAccessError::NotPresent), } } /// Get a mutable reference to a time stamp value for this key if it exists and has the correct /// type. pub fn get_timestamp_mut(&mut self, key: impl AsRef) -> ValueAccessResult<&mut Timestamp> { match self.get_mut(key) { Some(&mut Bson::Timestamp(ref mut timestamp)) => Ok(timestamp), Some(_) => Err(ValueAccessError::UnexpectedType), None => Err(ValueAccessError::NotPresent), } } /// Get a reference to a generic binary value for this key if it exists and has the correct /// type. pub fn get_binary_generic(&self, key: impl AsRef) -> ValueAccessResult<&Vec> { match self.get(key) { Some(&Bson::Binary(Binary { subtype: BinarySubtype::Generic, ref bytes, })) => Ok(bytes), Some(_) => Err(ValueAccessError::UnexpectedType), None => Err(ValueAccessError::NotPresent), } } /// Get a mutable reference generic binary value for this key if it exists and has the correct /// type. pub fn get_binary_generic_mut( &mut self, key: impl AsRef, ) -> ValueAccessResult<&mut Vec> { match self.get_mut(key) { Some(&mut Bson::Binary(Binary { subtype: BinarySubtype::Generic, ref mut bytes, })) => Ok(bytes), Some(_) => Err(ValueAccessError::UnexpectedType), None => Err(ValueAccessError::NotPresent), } } /// Get an object id value for this key if it exists and has the correct type. pub fn get_object_id(&self, key: impl AsRef) -> ValueAccessResult { match self.get(key) { Some(&Bson::ObjectId(v)) => Ok(v), Some(_) => Err(ValueAccessError::UnexpectedType), None => Err(ValueAccessError::NotPresent), } } /// Get a mutable reference to an object id value for this key if it exists and has the correct /// type. pub fn get_object_id_mut(&mut self, key: impl AsRef) -> ValueAccessResult<&mut ObjectId> { match self.get_mut(key) { Some(&mut Bson::ObjectId(ref mut v)) => Ok(v), Some(_) => Err(ValueAccessError::UnexpectedType), None => Err(ValueAccessError::NotPresent), } } /// Get a reference to a UTC datetime value for this key if it exists and has the correct type. pub fn get_datetime(&self, key: impl AsRef) -> ValueAccessResult<&crate::DateTime> { match self.get(key) { Some(Bson::DateTime(v)) => Ok(v), Some(_) => Err(ValueAccessError::UnexpectedType), None => Err(ValueAccessError::NotPresent), } } /// Get a mutable reference to a UTC datetime value for this key if it exists and has the /// correct type. pub fn get_datetime_mut( &mut self, key: impl AsRef, ) -> ValueAccessResult<&mut crate::DateTime> { match self.get_mut(key) { Some(&mut Bson::DateTime(ref mut v)) => Ok(v), Some(_) => Err(ValueAccessError::UnexpectedType), None => Err(ValueAccessError::NotPresent), } } /// Returns true if the map contains a value for the specified key. pub fn contains_key(&self, key: impl AsRef) -> bool { self.inner.contains_key(key.as_ref()) } /// Gets a collection of all keys in the document. pub fn keys(&self) -> Keys { Keys { inner: self.inner.keys(), } } /// Gets a collection of all values in the document. pub fn values(&self) -> Values { Values { inner: self.inner.values(), } } /// Returns the number of elements in the document. pub fn len(&self) -> usize { self.inner.len() } /// Returns true if the document contains no elements pub fn is_empty(&self) -> bool { self.inner.is_empty() } /// Sets the value of the entry with the OccupiedEntry's key, /// and returns the entry's old value. Accepts any type that /// can be converted into Bson. pub fn insert, BT: Into>(&mut self, key: KT, val: BT) -> Option { self.inner.insert(key.into(), val.into()) } /// Takes the value of the entry out of the document, and returns it. /// Computes in **O(n)** time (average). pub fn remove(&mut self, key: impl AsRef) -> Option { self.inner.shift_remove(key.as_ref()) } pub fn entry(&mut self, k: String) -> Entry { match self.inner.entry(k) { indexmap::map::Entry::Occupied(o) => Entry::Occupied(OccupiedEntry { inner: o }), indexmap::map::Entry::Vacant(v) => Entry::Vacant(VacantEntry { inner: v }), } } /// Attempts to serialize the [`Document`] into a byte stream. /// /// While the method signature indicates an owned writer must be passed in, a mutable reference /// may also be passed in due to blanket implementations of [`Write`] provided in the standard /// library. /// /// ``` /// # fn main() -> bson::ser::Result<()> { /// use bson::doc; /// /// let mut v: Vec = Vec::new(); /// let doc = doc! { "x" : 1 }; /// doc.to_writer(&mut v)?; /// # Ok(()) /// # } /// ``` pub fn to_writer(&self, mut writer: W) -> crate::ser::Result<()> { let buf = crate::to_vec(self)?; writer.write_all(&buf)?; Ok(()) } fn decode(reader: &mut R, utf_lossy: bool) -> crate::de::Result { let length = read_i32(reader)?; if length < MIN_BSON_DOCUMENT_SIZE { return Err(crate::de::Error::invalid_length( length as usize, &"document length must be at least 5", )); } let ulen: usize = length .try_into() .map_err(|e| crate::de::Error::DeserializationError { message: format!("invalid document length: {}", e), })?; let mut buf = vec![0u8; ulen]; buf[0..4].copy_from_slice(&length.to_le_bytes()); reader.read_exact(&mut buf[4..])?; let mut deserializer = crate::de::RawDeserializer::new(&buf, utf_lossy); Document::deserialize(&mut deserializer) } /// Attempts to deserialize a [`Document`] from a byte stream. /// /// While the method signature indicates an owned reader must be passed in, a mutable reference /// may also be passed in due to blanket implementations of [`Read`] provided in the standard /// library. /// /// ``` /// # use std::error::Error; /// # fn main() -> std::result::Result<(), Box> { /// use bson::{doc, Document}; /// use std::io::Cursor; /// /// let mut v: Vec = Vec::new(); /// let doc = doc! { "x" : 1 }; /// doc.to_writer(&mut v)?; /// /// // read from mutable reference /// let mut reader = Cursor::new(v.clone()); /// let doc1 = Document::from_reader(&mut reader)?; /// /// // read from owned value /// let doc2 = Document::from_reader(Cursor::new(v))?; /// /// assert_eq!(doc, doc1); /// assert_eq!(doc, doc2); /// # Ok(()) /// # } /// ``` pub fn from_reader(mut reader: R) -> crate::de::Result { Self::decode(&mut reader, false) } /// Attempt to deserialize a [`Document`] that may contain invalid UTF-8 strings from a byte /// stream. /// /// This is mainly useful when reading raw BSON returned from a MongoDB server, which /// in rare cases can contain invalidly truncated strings (). /// For most use cases, `Document::from_reader` can be used instead. pub fn from_reader_utf8_lossy(mut reader: R) -> crate::de::Result { Self::decode(&mut reader, true) } } /// A view into a single entry in a map, which may either be vacant or occupied. /// /// This enum is constructed from the entry method on HashMap. pub enum Entry<'a> { /// An occupied entry. Occupied(OccupiedEntry<'a>), /// A vacant entry. Vacant(VacantEntry<'a>), } impl<'a> Entry<'a> { /// Returns a reference to this entry's key. pub fn key(&self) -> &str { match self { Self::Vacant(v) => v.key(), Self::Occupied(o) => o.key(), } } fn into_indexmap_entry(self) -> indexmap::map::Entry<'a, String, Bson> { match self { Self::Occupied(o) => indexmap::map::Entry::Occupied(o.inner), Self::Vacant(v) => indexmap::map::Entry::Vacant(v.inner), } } /// Inserts the given default value in the entry if it is vacant and returns a mutable reference /// to it. Otherwise a mutable reference to an already existent value is returned. pub fn or_insert(self, default: Bson) -> &'a mut Bson { self.into_indexmap_entry().or_insert(default) } /// Inserts the result of the `default` function in the entry if it is vacant and returns a /// mutable reference to it. Otherwise a mutable reference to an already existent value is /// returned. pub fn or_insert_with Bson>(self, default: F) -> &'a mut Bson { self.into_indexmap_entry().or_insert_with(default) } } /// A view into a vacant entry in a [Document]. It is part of the [Entry] enum. pub struct VacantEntry<'a> { inner: indexmap::map::VacantEntry<'a, String, Bson>, } impl<'a> VacantEntry<'a> { /// Gets a reference to the key that would be used when inserting a value through the /// [VacantEntry]. fn key(&self) -> &str { self.inner.key() } } /// A view into an occupied entry in a [Document]. It is part of the [Entry] enum. pub struct OccupiedEntry<'a> { inner: indexmap::map::OccupiedEntry<'a, String, Bson>, } impl<'a> OccupiedEntry<'a> { /// Gets a reference to the key in the entry. pub fn key(&self) -> &str { self.inner.key() } } impl Extend<(String, Bson)> for Document { fn extend>(&mut self, iter: T) { for (k, v) in iter { self.insert(k, v); } } } bson-2.10.0/src/extjson/de.rs000064400000000000000000000177041046102023000140750ustar 00000000000000//! Deserializing [MongoDB Extended JSON v2](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/) //! //! ## Usage //! //! Extended JSON can be deserialized using [`Bson`](../../enum.Bson.html)'s //! `TryFrom` implementation. This implementation accepts both canonical and //! relaxed extJSON, and the two modes can even be mixed within a single representation. //! //! e.g. //! ```rust //! # use bson::Bson; //! # use serde_json::json; //! # use std::convert::{TryFrom, TryInto}; //! let json_doc = json!({ "x": 5i32, "y": { "$numberInt": "5" }, "z": { "subdoc": "hello" } }); //! let bson: Bson = json_doc.try_into().unwrap(); // Bson::Document(...) //! //! let json_date = json!({ "$date": { "$numberLong": "1590972160292" } }); //! let bson_date: Bson = json_date.try_into().unwrap(); // Bson::DateTime(...) //! //! let invalid_ext_json = json!({ "$numberLong": 5 }); //! Bson::try_from(invalid_ext_json).expect_err("5 should be a string"); //! ``` use std::convert::{TryFrom, TryInto}; use serde::de::{Error as _, Unexpected}; use crate::{extjson::models, oid, Bson, Document}; #[derive(Clone, Debug)] #[non_exhaustive] /// Error cases that can occur during deserialization from [extended JSON](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/). pub enum Error { /// Errors that can occur during OID construction and generation from the input data. InvalidObjectId(oid::Error), /// A general error encountered during deserialization. /// See: DeserializationError { message: String }, } impl std::fmt::Display for Error { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { match *self { Self::InvalidObjectId(ref err) => err.fmt(fmt), Self::DeserializationError { ref message } => message.fmt(fmt), } } } impl std::error::Error for Error {} impl serde::de::Error for Error { fn custom(msg: T) -> Self where T: std::fmt::Display, { Self::DeserializationError { message: format!("{}", msg), } } } impl From for Error { fn from(err: serde_json::Error) -> Self { Self::DeserializationError { message: err.to_string(), } } } impl From for Error { fn from(err: oid::Error) -> Self { Self::InvalidObjectId(err) } } pub type Result = std::result::Result; /// This converts from the input JSON object as if it were [MongoDB Extended JSON v2](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/). impl TryFrom> for Bson { type Error = Error; fn try_from(obj: serde_json::Map) -> Result { if obj.contains_key("$oid") { let oid: models::ObjectId = serde_json::from_value(obj.into())?; return Ok(Bson::ObjectId(oid.parse()?)); } if obj.contains_key("$symbol") { let symbol: models::Symbol = serde_json::from_value(obj.into())?; return Ok(Bson::Symbol(symbol.value)); } if obj.contains_key("$regularExpression") { let regex: models::Regex = serde_json::from_value(obj.into())?; return Ok(regex.parse().into()); } if obj.contains_key("$numberInt") { let int: models::Int32 = serde_json::from_value(obj.into())?; return Ok(Bson::Int32(int.parse()?)); } if obj.contains_key("$numberLong") { let int: models::Int64 = serde_json::from_value(obj.into())?; return Ok(Bson::Int64(int.parse()?)); } if obj.contains_key("$numberDouble") { let double: models::Double = serde_json::from_value(obj.into())?; return Ok(Bson::Double(double.parse()?)); } if obj.contains_key("$numberDecimal") { let decimal: models::Decimal128 = serde_json::from_value(obj.into())?; return Ok(Bson::Decimal128(decimal.parse()?)); } if obj.contains_key("$binary") { let binary: models::Binary = serde_json::from_value(obj.into())?; return Ok(Bson::Binary(binary.parse()?)); } if obj.contains_key("$uuid") { let uuid: models::Uuid = serde_json::from_value(obj.into())?; return Ok(Bson::Binary(uuid.parse()?)); } if obj.contains_key("$code") { let code_w_scope: models::JavaScriptCodeWithScope = serde_json::from_value(obj.into())?; return match code_w_scope.scope { Some(scope) => Ok(crate::JavaScriptCodeWithScope { code: code_w_scope.code, scope: scope.try_into()?, } .into()), None => Ok(Bson::JavaScriptCode(code_w_scope.code)), }; } if obj.contains_key("$timestamp") { let ts: models::Timestamp = serde_json::from_value(obj.into())?; return Ok(ts.parse().into()); } if obj.contains_key("$date") { let extjson_datetime: models::DateTime = serde_json::from_value(obj.into())?; return Ok(Bson::DateTime(extjson_datetime.parse()?)); } if obj.contains_key("$minKey") { let min_key: models::MinKey = serde_json::from_value(obj.into())?; return min_key.parse(); } if obj.contains_key("$maxKey") { let max_key: models::MaxKey = serde_json::from_value(obj.into())?; return max_key.parse(); } if obj.contains_key("$dbPointer") { let db_ptr: models::DbPointer = serde_json::from_value(obj.into())?; return Ok(db_ptr.parse()?.into()); } if obj.contains_key("$undefined") { let undefined: models::Undefined = serde_json::from_value(obj.into())?; return undefined.parse(); } Ok(Bson::Document(obj.try_into()?)) } } /// This converts from the input JSON as if it were [MongoDB Extended JSON v2](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/). impl TryFrom for Bson { type Error = Error; fn try_from(value: serde_json::Value) -> Result { match value { serde_json::Value::Number(x) => x .as_i64() .map(|i| { if i >= std::i32::MIN as i64 && i <= std::i32::MAX as i64 { Bson::Int32(i as i32) } else { Bson::Int64(i) } }) .or_else(|| x.as_f64().map(Bson::from)) .ok_or_else(|| { Error::invalid_value( Unexpected::Other(format!("{}", x).as_str()), &"a number that could fit in i32, i64, or f64", ) }), serde_json::Value::String(x) => Ok(x.into()), serde_json::Value::Bool(x) => Ok(x.into()), serde_json::Value::Array(x) => Ok(Bson::Array( x.into_iter() .map(Bson::try_from) .collect::>>()?, )), serde_json::Value::Null => Ok(Bson::Null), serde_json::Value::Object(map) => map.try_into(), } } } /// This converts from the input JSON as if it were [MongoDB Extended JSON v2](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/). impl TryFrom> for Document { type Error = Error; fn try_from(obj: serde_json::Map) -> Result { Ok(obj .into_iter() .map(|(k, v)| -> Result<(String, Bson)> { let value: Bson = v.try_into()?; Ok((k, value)) }) .collect::>>()? .into_iter() .collect()) } } bson-2.10.0/src/extjson/mod.rs000064400000000000000000000100051046102023000142470ustar 00000000000000//! Deserialization and serialization of [MongoDB Extended JSON v2](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/) //! //! ## Overview of Extended JSON //! //! MongoDB Extended JSON (abbreviated extJSON) is format of JSON that allows for the encoding of //! BSON type information. Normal JSON cannot unambiguously represent all BSON types losslessly, so //! an extension was designed to include conventions for representing those types. //! //! For example, a BSON binary is represented by the following format: //! ```text //! { //! "$binary": { //! "base64": , //! "subType": , //! } //! } //! ``` //! For more information on extJSON and the complete list of translations, see the [official MongoDB documentation](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/). //! //! All MongoDB drivers and BSON libraries interpret and produce extJSON, so it can serve as a //! useful tool for communicating between applications where raw BSON bytes cannot be used (e.g. via //! JSON REST APIs). It's also useful for representing BSON data as a string. //! //! ### Canonical and Relaxed Modes //! //! There are two modes of extJSON: "Canonical" and "Relaxed". They are the same except for the //! following differences: //! - In relaxed mode, all BSON numbers are represented by the JSON number type, rather than the //! object //! notation. //! - In relaxed mode, the string in the datetime object notation is RFC 3339 (ISO-8601) formatted //! (if the date is after 1970). //! //! e.g. //! ```rust //! # use bson::bson; //! let doc = bson!({ "x": 5, "d": bson::DateTime::now() }); //! //! println!("relaxed: {}", doc.clone().into_relaxed_extjson()); //! // relaxed: "{"x":5,"d":{"$date":"2020-06-01T22:19:13.075Z"}}" //! //! println!("canonical: {}", doc.into_canonical_extjson()); //! // canonical: {"x":{"$numberInt":"5"},"d":{"$date":{"$numberLong":"1591050020711"}}} //! ``` //! //! Canonical mode is useful when BSON values need to be round tripped without losing any type //! information. Relaxed mode is more useful when debugging or logging BSON data. //! //! ## Deserializing Extended JSON //! //! Extended JSON can be deserialized using [`Bson`](../enum.Bson.html)'s //! `TryFrom` implementation. This implementation accepts both canonical and //! relaxed extJSON, and the two modes can even be mixed within a single representation. //! //! e.g. //! ```rust //! # use bson::Bson; //! # use serde_json::json; //! # use std::convert::{TryFrom, TryInto}; //! let json_doc = json!({ "x": 5i32, "y": { "$numberInt": "5" }, "z": { "subdoc": "hello" } }); //! let bson: Bson = json_doc.try_into().unwrap(); // Bson::Document(...) //! //! let json_date = json!({ "$date": { "$numberLong": "1590972160292" } }); //! let bson_date: Bson = json_date.try_into().unwrap(); // Bson::DateTime(...) //! //! let invalid_ext_json = json!({ "$numberLong": 5 }); //! Bson::try_from(invalid_ext_json).expect_err("5 should be a string"); //! ``` //! //! ## Serializing to Extended JSON //! //! Extended JSON can be created via [`Bson`](../enum.Bson.html)'s `Into` //! implementation (which will create relaxed extJSON), //! [`Bson::into_relaxed_extjson`](../enum.Bson.html#method.into_relaxed_extjson), and //! [`Bson::into_canonical_extjson`](../enum.Bson.html#method.into_canonical_extjson). //! //! e.g. //! ```rust //! # use bson::{bson, oid}; //! let doc = bson!({ "x": 5i32, "_id": oid::ObjectId::new() }); //! //! let relaxed_extjson: serde_json::Value = doc.clone().into(); //! println!("{}", relaxed_extjson); // { "x": 5, "_id": { "$oid": } } //! //! let relaxed_extjson = doc.clone().into_relaxed_extjson(); //! println!("{}", relaxed_extjson); // { "x": 5, "_id": { "$oid": } } //! //! let canonical_extjson = doc.into_canonical_extjson(); //! println!("{}", canonical_extjson); // { "x": { "$numberInt": "5" }, "_id": { "$oid": } } //! ``` pub mod de; pub(crate) mod models; bson-2.10.0/src/extjson/models.rs000064400000000000000000000234751046102023000147720ustar 00000000000000//! A module defining serde models for the extended JSON representations of the various BSON types. use serde::{ de::{Error, Unexpected}, Deserialize, Serialize, }; use std::borrow::Cow; use crate::{extjson, oid, raw::serde::CowStr, spec::BinarySubtype, Bson}; #[derive(Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct Int32 { #[serde(rename = "$numberInt")] value: String, } impl Int32 { pub(crate) fn parse(self) -> extjson::de::Result { let i: i32 = self.value.parse().map_err(|_| { extjson::de::Error::invalid_value( Unexpected::Str(self.value.as_str()), &"i32 as a string", ) })?; Ok(i) } } #[derive(Deserialize, Serialize)] #[serde(deny_unknown_fields)] pub(crate) struct Int64 { #[serde(rename = "$numberLong")] value: String, } impl Int64 { pub(crate) fn parse(self) -> extjson::de::Result { let i: i64 = self.value.parse().map_err(|_| { extjson::de::Error::invalid_value( Unexpected::Str(self.value.as_str()), &"i64 as a string", ) })?; Ok(i) } } #[derive(Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct Double { #[serde(rename = "$numberDouble")] value: String, } impl Double { pub(crate) fn parse(self) -> extjson::de::Result { match self.value.as_str() { "Infinity" => Ok(std::f64::INFINITY), "-Infinity" => Ok(std::f64::NEG_INFINITY), "NaN" => Ok(std::f64::NAN), other => { let d: f64 = other.parse().map_err(|_| { extjson::de::Error::invalid_value( Unexpected::Str(other), &"bson double as string", ) })?; Ok(d) } } } } #[derive(Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct Decimal128 { #[serde(rename = "$numberDecimal")] value: String, } impl Decimal128 { pub(crate) fn parse(self) -> extjson::de::Result { self.value.parse().map_err(|_| { extjson::de::Error::invalid_value( Unexpected::Str(&self.value), &"bson decimal128 as string", ) }) } } #[derive(Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct ObjectId { #[serde(rename = "$oid")] oid: String, } impl ObjectId { pub(crate) fn parse(self) -> extjson::de::Result { let oid = oid::ObjectId::parse_str(self.oid.as_str())?; Ok(oid) } } impl From for ObjectId { fn from(id: crate::oid::ObjectId) -> Self { Self { oid: id.to_hex() } } } #[derive(Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct Symbol { #[serde(rename = "$symbol")] pub(crate) value: String, } #[derive(Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct Regex { #[serde(rename = "$regularExpression")] body: RegexBody, } #[derive(Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct RegexBody { pub(crate) pattern: String, pub(crate) options: String, } impl Regex { pub(crate) fn parse(self) -> crate::Regex { crate::Regex::new(self.body.pattern, self.body.options) } } #[derive(Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct Binary { #[serde(rename = "$binary")] pub(crate) body: BinaryBody, } #[derive(Deserialize, Serialize)] #[serde(deny_unknown_fields)] pub(crate) struct BinaryBody { pub(crate) base64: String, #[serde(rename = "subType")] pub(crate) subtype: String, } impl Binary { pub(crate) fn parse(self) -> extjson::de::Result { let bytes = base64::decode(self.body.base64.as_str()).map_err(|_| { extjson::de::Error::invalid_value( Unexpected::Str(self.body.base64.as_str()), &"base64 encoded bytes", ) })?; let subtype = hex::decode(self.body.subtype.as_str()).map_err(|_| { extjson::de::Error::invalid_value( Unexpected::Str(self.body.subtype.as_str()), &"hexadecimal number as a string", ) })?; if subtype.len() == 1 { Ok(crate::Binary { bytes, subtype: subtype[0].into(), }) } else { Err(extjson::de::Error::invalid_value( Unexpected::Bytes(subtype.as_slice()), &"one byte subtype", )) } } } #[derive(Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct Uuid { #[serde(rename = "$uuid")] value: String, } impl Uuid { pub(crate) fn parse(self) -> extjson::de::Result { let uuid = uuid::Uuid::parse_str(&self.value).map_err(|_| { extjson::de::Error::invalid_value( Unexpected::Str(&self.value), &"$uuid value does not follow RFC 4122 format regarding length and hyphens", ) })?; Ok(crate::Binary { subtype: BinarySubtype::Uuid, bytes: uuid.as_bytes().to_vec(), }) } } #[derive(Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct JavaScriptCodeWithScope { #[serde(rename = "$code")] pub(crate) code: String, #[serde(rename = "$scope")] #[serde(default)] pub(crate) scope: Option>, } #[derive(Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct Timestamp { #[serde(rename = "$timestamp")] body: TimestampBody, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub(crate) struct TimestampBody { #[serde(serialize_with = "crate::serde_helpers::serialize_u32_as_i64")] pub(crate) t: u32, #[serde(serialize_with = "crate::serde_helpers::serialize_u32_as_i64")] pub(crate) i: u32, } impl Timestamp { pub(crate) fn parse(self) -> crate::Timestamp { crate::Timestamp { time: self.body.t, increment: self.body.i, } } } #[derive(Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct DateTime { #[serde(rename = "$date")] pub(crate) body: DateTimeBody, } #[derive(Deserialize, Serialize)] #[serde(untagged)] pub(crate) enum DateTimeBody { Canonical(Int64), Relaxed(String), } impl DateTimeBody { pub(crate) fn from_millis(m: i64) -> Self { DateTimeBody::Canonical(Int64 { value: m.to_string(), }) } } impl DateTime { pub(crate) fn parse(self) -> extjson::de::Result { match self.body { DateTimeBody::Canonical(date) => { let date = date.parse()?; Ok(crate::DateTime::from_millis(date)) } DateTimeBody::Relaxed(date) => { let datetime = crate::DateTime::parse_rfc3339_str(date.as_str()).map_err(|_| { extjson::de::Error::invalid_value( Unexpected::Str(date.as_str()), &"rfc3339 formatted utc datetime", ) })?; Ok(datetime) } } } } #[derive(Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct MinKey { #[serde(rename = "$minKey")] pub(crate) value: u8, } impl MinKey { pub(crate) fn parse(self) -> extjson::de::Result { if self.value == 1 { Ok(Bson::MinKey) } else { Err(extjson::de::Error::invalid_value( Unexpected::Unsigned(self.value as u64), &"value of $minKey should always be 1", )) } } } #[derive(Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct MaxKey { #[serde(rename = "$maxKey")] pub(crate) value: u8, } impl MaxKey { pub(crate) fn parse(self) -> extjson::de::Result { if self.value == 1 { Ok(Bson::MaxKey) } else { Err(extjson::de::Error::invalid_value( Unexpected::Unsigned(self.value as u64), &"value of $maxKey should always be 1", )) } } } #[derive(Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct DbPointer { #[serde(rename = "$dbPointer")] body: DbPointerBody, } #[derive(Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct DbPointerBody { #[serde(rename = "$ref")] pub(crate) ref_ns: String, #[serde(rename = "$id")] pub(crate) id: ObjectId, } impl DbPointer { pub(crate) fn parse(self) -> extjson::de::Result { Ok(crate::DbPointer { namespace: self.body.ref_ns, id: self.body.id.parse()?, }) } } #[derive(Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct Undefined { #[serde(rename = "$undefined")] pub(crate) value: bool, } impl Undefined { pub(crate) fn parse(self) -> extjson::de::Result { if self.value { Ok(Bson::Undefined) } else { Err(extjson::de::Error::invalid_value( Unexpected::Bool(false), &"$undefined should always be true", )) } } } #[derive(Debug, Deserialize)] pub(crate) struct BorrowedRegexBody<'a> { #[serde(borrow)] pub(crate) pattern: Cow<'a, str>, #[serde(borrow)] pub(crate) options: Cow<'a, str>, } #[derive(Debug, Deserialize)] pub(crate) struct BorrowedBinaryBody<'a> { #[serde(borrow)] pub(crate) bytes: Cow<'a, [u8]>, #[serde(rename = "subType")] pub(crate) subtype: u8, } #[derive(Deserialize)] pub(crate) struct BorrowedDbPointerBody<'a> { #[serde(rename = "$ref")] #[serde(borrow)] pub(crate) ns: CowStr<'a>, #[serde(rename = "$id")] pub(crate) id: oid::ObjectId, } bson-2.10.0/src/lib.rs000064400000000000000000000312541046102023000125550ustar 00000000000000// The MIT License (MIT) // Copyright (c) 2015 Y. T. Chung // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in // the Software without restriction, including without limitation the rights to // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of // the Software, and to permit persons to whom the Software is furnished to do so, // subject to the following conditions: // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. //! BSON, short for Binary JSON, is a binary-encoded serialization of JSON-like documents. //! Like JSON, BSON supports the embedding of documents and arrays within other documents //! and arrays. BSON also contains extensions that allow representation of data types that //! are not part of the JSON spec. For example, BSON has a datetime type and a binary data type. //! //! ```text //! // JSON equivalent //! {"hello": "world"} //! //! // BSON encoding //! \x16\x00\x00\x00 // total document size //! \x02 // 0x02 = type String //! hello\x00 // field name //! \x06\x00\x00\x00world\x00 // field value //! \x00 // 0x00 = type EOO ('end of object') //! ``` //! //! BSON is the primary data representation for [MongoDB](https://www.mongodb.com/), and this crate is used in the //! [`mongodb`](https://docs.rs/mongodb/latest/mongodb/) driver crate in its API and implementation. //! //! For more information about BSON itself, see [bsonspec.org](http://bsonspec.org). //! //! ## Installation //! ### Requirements //! - Rust 1.64+ //! //! ### Importing //! This crate is available on [crates.io](https://crates.io/crates/bson). To use it in your application, //! simply add it to your project's `Cargo.toml`. //! //! ```toml //! [dependencies] //! bson = "2.10.0" //! ``` //! //! Note that if you are using `bson` through the `mongodb` crate, you do not need to specify it in //! your `Cargo.toml`, since the `mongodb` crate already re-exports it. //! //! #### Feature Flags //! //! | Feature | Description | Default | //! |:-------------|:-----------------------------------------------------------------------------------------------------|:--------| //! | `chrono-0_4` | Enable support for v0.4 of the [`chrono`](https://docs.rs/chrono/0.4) crate in the public API. | no | //! | `uuid-0_8` | Enable support for v0.8 of the [`uuid`](https://docs.rs/uuid/0.8) crate in the public API. | no | //! | `uuid-1` | Enable support for v1.x of the [`uuid`](https://docs.rs/uuid/1.x) crate in the public API. | no | //! | `time-0_3` | Enable support for v0.3 of the [`time`](https://docs.rs/time/0.3) crate in the public API. | no | //! | `serde_with` | Enable [`serde_with`](https://docs.rs/serde_with/latest) integrations for [`DateTime`] and [`Uuid`]. | no | //! //! ## BSON values //! //! Many different types can be represented as a BSON value, including 32-bit and 64-bit signed //! integers, 64 bit floating point numbers, strings, datetimes, embedded documents, and more. To //! see a full list of possible BSON values, see the [BSON specification](http://bsonspec.org/spec.html). The various //! possible BSON values are modeled in this crate by the [`Bson`](enum.Bson.html) enum. //! //! ### Creating [`Bson`](enum.Bson.html) instances //! //! [`Bson`](enum.Bson.html) values can be instantiated directly or via the //! [`bson!`](macro.bson.html) macro: //! //! ```rust //! use bson::{bson, Bson}; //! //! let string = Bson::String("hello world".to_string()); //! let int = Bson::Int32(5); //! let array = Bson::Array(vec![Bson::Int32(5), Bson::Boolean(false)]); //! //! let string: Bson = "hello world".into(); //! let int: Bson = 5i32.into(); //! //! let string = bson!("hello world"); //! let int = bson!(5); //! let array = bson!([5, false]); //! ``` //! [`bson!`](macro.bson.html) has supports both array and object literals, and it automatically //! converts any values specified to [`Bson`](enum.Bson.html), provided they are `Into`. //! //! ### [`Bson`](enum.Bson.html) value unwrapping //! //! [`Bson`](enum.Bson.html) has a number of helper methods for accessing the underlying native Rust //! types. These helpers can be useful in circumstances in which the specific type of a BSON value //! is known ahead of time. //! //! e.g.: //! ```rust //! use bson::{bson, Bson}; //! //! let value = Bson::Int32(5); //! let int = value.as_i32(); // Some(5) //! let bool = value.as_bool(); // None //! //! let value = bson!([true]); //! let array = value.as_array(); // Some(&Vec) //! ``` //! //! ## BSON documents //! //! BSON documents are ordered maps of UTF-8 encoded strings to BSON values. They are logically //! similar to JSON objects in that they can contain subdocuments, arrays, and values of several //! different types. This crate models BSON documents via the //! [`Document`](document/struct.Document.html) struct. //! //! ### Creating [`Document`](document/struct.Document.html)s //! //! [`Document`](document/struct.Document.html)s can be created directly either from a byte //! reader containing BSON data or via the `doc!` macro: //! ```rust //! use bson::{doc, Document}; //! use std::io::Read; //! //! let mut bytes = hex::decode("0C0000001069000100000000").unwrap(); //! let doc = Document::from_reader(&mut bytes.as_slice()).unwrap(); // { "i": 1 } //! //! let doc = doc! { //! "hello": "world", //! "int": 5, //! "subdoc": { "cat": true }, //! }; //! ``` //! [`doc!`](macro.doc.html) works similarly to [`bson!`](macro.bson.html), except that it always //! returns a [`Document`](document/struct.Document.html) rather than a [`Bson`](enum.Bson.html). //! //! ### [`Document`](document/struct.Document.html) member access //! //! [`Document`](document/struct.Document.html) has a number of methods on it to facilitate member //! access: //! //! ```rust //! use bson::doc; //! //! let doc = doc! { //! "string": "string", //! "bool": true, //! "i32": 5, //! "doc": { "x": true }, //! }; //! //! // attempt get values as untyped Bson //! let none = doc.get("asdfadsf"); // None //! let value = doc.get("string"); // Some(&Bson::String("string")) //! //! // attempt to get values with explicit typing //! let string = doc.get_str("string"); // Ok("string") //! let subdoc = doc.get_document("doc"); // Some(Document({ "x": true })) //! let error = doc.get_i64("i32"); // Err(...) //! ``` //! //! ## Modeling BSON with strongly typed data structures //! //! While it is possible to work with documents and BSON values directly, it will often introduce a //! lot of boilerplate for verifying the necessary keys are present and their values are the correct //! types. [`serde`](https://serde.rs/) provides a powerful way of mapping BSON data into Rust data structures largely //! automatically, removing the need for all that boilerplate. //! //! e.g.: //! ```rust //! use serde::{Deserialize, Serialize}; //! use bson::{bson, Bson}; //! //! #[derive(Serialize, Deserialize)] //! struct Person { //! name: String, //! age: i32, //! phones: Vec, //! } //! //! // Some BSON input data as a [`Bson`]. //! let bson_data: Bson = bson!({ //! "name": "John Doe", //! "age": 43, //! "phones": [ //! "+44 1234567", //! "+44 2345678" //! ] //! }); //! //! // Deserialize the Person struct from the BSON data, automatically //! // verifying that the necessary keys are present and that they are of //! // the correct types. //! let mut person: Person = bson::from_bson(bson_data).unwrap(); //! //! // Do things just like with any other Rust data structure. //! println!("Redacting {}'s record.", person.name); //! person.name = "REDACTED".to_string(); //! //! // Get a serialized version of the input data as a [`Bson`]. //! let redacted_bson = bson::to_bson(&person).unwrap(); //! ``` //! //! Any types that implement [`Serialize`](serde::Serialize) and [`Deserialize`](serde::Deserialize) //! can be used in this way. Doing so helps separate the "business logic" that operates over the //! data from the (de)serialization logic that translates the data to/from its serialized form. This //! can lead to more clear and concise code that is also less error prone. //! //! ## Working with datetimes //! //! The BSON format includes a datetime type, which is modeled in this crate by the //! [`DateTime`] struct, and the //! [`Serialize`](serde::Serialize) and [`Deserialize`](serde::Deserialize) implementations for this //! struct produce and parse BSON datetimes when serializing to or deserializing from BSON. The //! popular crate [`chrono`](docs.rs/chrono) also provides a [`DateTime`] type, but its //! [`Serialize`](serde::Serialize) and [`Deserialize`](serde::Deserialize) implementations operate //! on strings instead, so when using it with BSON, the BSON datetime type is not used. To work //! around this, the `chrono-0_4` feature flag can be enabled. This flag exposes a number of //! convenient conversions between [`bson::DateTime`](crate::DateTime) and [`chrono::DateTime`], //! including the [`serde_helpers::chrono_datetime_as_bson_datetime`] //! serde helper, which can be used to (de)serialize [`chrono::DateTime`]s to/from BSON datetimes, //! and the `From` implementation for [`Bson`], which allows [`chrono::DateTime`] //! values to be used in the `doc!` and `bson!` macros. //! //! e.g. //! ``` rust //! # #[cfg(feature = "chrono-0_4")] //! # { //! use serde::{Serialize, Deserialize}; //! use bson::doc; //! //! #[derive(Serialize, Deserialize)] //! struct Foo { //! // serializes as a BSON datetime. //! date_time: bson::DateTime, //! //! // serializes as an RFC 3339 / ISO-8601 string. //! chrono_datetime: chrono::DateTime, //! //! // serializes as a BSON datetime. //! // this requires the "chrono-0_4" feature flag //! #[serde(with = "bson::serde_helpers::chrono_datetime_as_bson_datetime")] //! chrono_as_bson: chrono::DateTime, //! } //! //! // this automatic conversion also requires the "chrono-0_4" feature flag //! let query = doc! { //! "created_at": chrono::Utc::now(), //! }; //! # } //! ``` //! //! ## Working with UUIDs //! //! See the module level documentation for the [`uuid`] module. //! //! ## WASM support //! //! This crate compiles to the `wasm32-unknown-unknown` target; when doing so, the `js-sys` crate is //! used for the current timestamp component of `ObjectId` generation. //! //! ## Minimum supported Rust version (MSRV) //! //! The MSRV for this crate is currently 1.64.0. This will be rarely be increased, and if it ever //! is, it will only happen in a minor or major version release. #![allow(clippy::cognitive_complexity, clippy::derive_partial_eq_without_eq)] #![doc(html_root_url = "https://docs.rs/bson/2.6.0")] #![cfg_attr(docsrs, feature(doc_cfg))] #[doc(inline)] pub use self::{ binary::Binary, bson::{Array, Bson, DbPointer, Document, JavaScriptCodeWithScope, Regex, Timestamp}, datetime::DateTime, de::{ from_bson, from_bson_with_options, from_document, from_document_with_options, from_reader, from_reader_utf8_lossy, from_slice, from_slice_utf8_lossy, Deserializer, DeserializerOptions, }, decimal128::Decimal128, raw::{ RawArray, RawArrayBuf, RawBinaryRef, RawBson, RawBsonRef, RawDbPointerRef, RawDocument, RawDocumentBuf, RawJavaScriptCodeWithScope, RawJavaScriptCodeWithScopeRef, RawRegexRef, }, ser::{ to_bson, to_bson_with_options, to_document, to_document_with_options, to_raw_document_buf, to_vec, Serializer, SerializerOptions, }, uuid::{Uuid, UuidRepresentation}, }; #[macro_use] mod macros; pub mod binary; mod bson; pub mod datetime; pub mod de; pub mod decimal128; pub mod document; pub mod extjson; pub mod oid; pub mod raw; pub mod ser; pub mod serde_helpers; pub mod spec; pub mod uuid; #[cfg(test)] mod tests; bson-2.10.0/src/macros.rs000064400000000000000000000333561046102023000133000ustar 00000000000000// BSON macro based on the serde_json json! implementation. /// Construct a bson::BSON value from a literal. /// /// ```rust /// # use bson::bson; /// # /// # fn main() { /// let value = bson!({ /// "code": 200, /// "success": true, /// "payload": { /// "some": [ /// "pay", /// "loads", /// ] /// } /// }); /// # } /// ``` #[macro_export] macro_rules! bson { ////////////////////////////////////////////////////////////////////////// // TT muncher for parsing the inside of an array [...]. Produces a vec![...] // of the elements. // // Must be invoked as: bson!(@array [] $($tt)*) ////////////////////////////////////////////////////////////////////////// // Finished with trailing comma. (@array [$($elems:expr,)*]) => { vec![$($elems,)*] }; // Finished without trailing comma. (@array [$($elems:expr),*]) => { vec![$($elems),*] }; // Next element is `null`. (@array [$($elems:expr,)*] null $($rest:tt)*) => { $crate::bson!(@array [$($elems,)* $crate::bson!(null)] $($rest)*) }; // Next element is an array. (@array [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => { $crate::bson!(@array [$($elems,)* $crate::bson!([$($array)*])] $($rest)*) }; // Next element is a map. (@array [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => { $crate::bson!(@array [$($elems,)* $crate::bson!({$($map)*})] $($rest)*) }; // Next element is an expression followed by comma. (@array [$($elems:expr,)*] $next:expr, $($rest:tt)*) => { $crate::bson!(@array [$($elems,)* $crate::bson!($next),] $($rest)*) }; // Last element is an expression with no trailing comma. (@array [$($elems:expr,)*] $last:expr) => { $crate::bson!(@array [$($elems,)* $crate::bson!($last)]) }; // Comma after the most recent element. (@array [$($elems:expr),*] , $($rest:tt)*) => { $crate::bson!(@array [$($elems,)*] $($rest)*) }; ////////////////////////////////////////////////////////////////////////// // TT muncher for parsing the inside of an object {...}. Each entry is // inserted into the given map variable. // // Must be invoked as: bson!(@object $map () ($($tt)*) ($($tt)*)) // // We require two copies of the input tokens so that we can match on one // copy and trigger errors on the other copy. ////////////////////////////////////////////////////////////////////////// // Finished. (@object $object:ident () () ()) => {}; // Insert the current entry followed by trailing comma. (@object $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => { $object.insert::<_, $crate::Bson>(($($key)+), $value); $crate::bson!(@object $object () ($($rest)*) ($($rest)*)); }; // Insert the last entry without trailing comma. (@object $object:ident [$($key:tt)+] ($value:expr)) => { $object.insert::<_, $crate::Bson>(($($key)+), $value); }; // Next value is `null`. (@object $object:ident ($($key:tt)+) (: null $($rest:tt)*) $copy:tt) => { $crate::bson!(@object $object [$($key)+] ($crate::bson!(null)) $($rest)*); }; // Next value is an array. (@object $object:ident ($($key:tt)+) (: [$($array:tt)*] $($rest:tt)*) $copy:tt) => { $crate::bson!(@object $object [$($key)+] ($crate::bson!([$($array)*])) $($rest)*); }; // Next value is a map. (@object $object:ident ($($key:tt)+) (: {$($map:tt)*} $($rest:tt)*) $copy:tt) => { $crate::bson!(@object $object [$($key)+] ($crate::bson!({$($map)*})) $($rest)*); }; // Next value is an expression followed by comma. (@object $object:ident ($($key:tt)+) (: $value:expr , $($rest:tt)*) $copy:tt) => { $crate::bson!(@object $object [$($key)+] ($crate::bson!($value)) , $($rest)*); }; // Last value is an expression with no trailing comma. (@object $object:ident ($($key:tt)+) (: $value:expr) $copy:tt) => { $crate::bson!(@object $object [$($key)+] ($crate::bson!($value))); }; // Missing value for last entry. Trigger a reasonable error message. (@object $object:ident ($($key:tt)+) (:) $copy:tt) => { // "unexpected end of macro invocation" $crate::bson!(); }; // Missing key-value separator and value for last entry. // Trigger a reasonable error message. (@object $object:ident ($($key:tt)+) () $copy:tt) => { // "unexpected end of macro invocation" $crate::bson!(); }; // Misplaced key-value separator. Trigger a reasonable error message. (@object $object:ident () (: $($rest:tt)*) ($kv_separator:tt $($copy:tt)*)) => { // Takes no arguments so "no rules expected the token `:`". unimplemented!($kv_separator); }; // Found a comma inside a key. Trigger a reasonable error message. (@object $object:ident ($($key:tt)*) (, $($rest:tt)*) ($comma:tt $($copy:tt)*)) => { // Takes no arguments so "no rules expected the token `,`". unimplemented!($comma); }; // Key is fully parenthesized. This avoids clippy double_parens false // positives because the parenthesization may be necessary here. (@object $object:ident () (($key:expr) : $($rest:tt)*) $copy:tt) => { $crate::bson!(@object $object ($key) (: $($rest)*) (: $($rest)*)); }; // Munch a token into the current key. (@object $object:ident ($($key:tt)*) ($tt:tt $($rest:tt)*) $copy:tt) => { $crate::bson!(@object $object ($($key)* $tt) ($($rest)*) ($($rest)*)); }; ////////////////////////////////////////////////////////////////////////// // The main implementation. // // Must be invoked as: bson!($($bson)+) ////////////////////////////////////////////////////////////////////////// (null) => { $crate::Bson::Null }; ([]) => { $crate::Bson::Array(vec![]) }; ([ $($tt:tt)+ ]) => { $crate::Bson::Array($crate::bson!(@array [] $($tt)+)) }; ({}) => { $crate::Bson::Document($crate::doc!{}) }; ({$($tt:tt)+}) => { $crate::Bson::Document($crate::doc!{$($tt)+}) }; // Any Into type. // Must be below every other rule. ($other:expr) => { <_ as ::std::convert::Into<$crate::Bson>>::into($other) }; } /// Construct a bson::Document value. /// /// ```rust /// # use bson::doc; /// # /// # fn main() { /// let value = doc! { /// "code": 200, /// "success": true, /// "payload": { /// "some": [ /// "pay", /// "loads", /// ] /// } /// }; /// # } /// ``` #[macro_export] macro_rules! doc { () => {{ $crate::Document::new() }}; ( $($tt:tt)+ ) => {{ let mut object = $crate::Document::new(); $crate::bson!(@object object () ($($tt)+) ($($tt)+)); object }}; } /// Construct a [`crate::RawBson`] value from a literal. /// /// ```rust /// use bson::rawbson; /// /// let value = rawbson!({ /// "code": 200, /// "success": true, /// "payload": { /// "some": [ /// "pay", /// "loads", /// ] /// } /// }); /// ``` #[macro_export] macro_rules! rawbson { ////////////////////////////////////////////////////////////////////////// // TT muncher for parsing the inside of an array [...]. Produces a // RawArrayBuf containing the elements. // // Must be invoked as: bson!(@array [] $($tt)*) ////////////////////////////////////////////////////////////////////////// // Finished with trailing comma. (@array [$($elems:expr,)*]) => { <$crate::RawArrayBuf as std::iter::FromIterator::<$crate::RawBson>>::from_iter(vec![$($elems,)*]) }; // Finished without trailing comma. (@array [$($elems:expr),*]) => { <$crate::RawArrayBuf as std::iter::FromIterator::<$crate::RawBson>>::from_iter(vec![$($elems),*]) }; // Next element is `null`. (@array [$($elems:expr,)*] null $($rest:tt)*) => { $crate::rawbson!(@array [$($elems,)* $crate::rawbson!(null)] $($rest)*) }; // Next element is an array. (@array [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => { $crate::rawbson!(@array [$($elems,)* $crate::rawbson!([$($array)*])] $($rest)*) }; // Next element is a map. (@array [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => { $crate::rawbson!(@array [$($elems,)* $crate::rawbson!({$($map)*})] $($rest)*) }; // Next element is an expression followed by comma. (@array [$($elems:expr,)*] $next:expr, $($rest:tt)*) => { $crate::rawbson!(@array [$($elems,)* $crate::rawbson!($next),] $($rest)*) }; // Last element is an expression with no trailing comma. (@array [$($elems:expr,)*] $last:expr) => { $crate::rawbson!(@array [$($elems,)* $crate::rawbson!($last)]) }; // Comma after the most recent element. (@array [$($elems:expr),*] , $($rest:tt)*) => { $crate::rawbson!(@array [$($elems,)*] $($rest)*) }; ////////////////////////////////////////////////////////////////////////// // TT muncher for parsing the inside of an object {...}. Each entry is // inserted into the given map variable. // // Must be invoked as: rawbson!(@object $map () ($($tt)*) ($($tt)*)) // // We require two copies of the input tokens so that we can match on one // copy and trigger errors on the other copy. ////////////////////////////////////////////////////////////////////////// // Finished. (@object $object:ident () () ()) => {}; // Insert the current entry followed by trailing comma. (@object $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => { $object.append(($($key)+), $value); $crate::rawbson!(@object $object () ($($rest)*) ($($rest)*)); }; // Insert the last entry without trailing comma. (@object $object:ident [$($key:tt)+] ($value:expr)) => { $object.append(($($key)+), $value); }; // Next value is `null`. (@object $object:ident ($($key:tt)+) (: null $($rest:tt)*) $copy:tt) => { $crate::rawbson!(@object $object [$($key)+] ($crate::rawbson!(null)) $($rest)*); }; // Next value is an array. (@object $object:ident ($($key:tt)+) (: [$($array:tt)*] $($rest:tt)*) $copy:tt) => { $crate::rawbson!(@object $object [$($key)+] ($crate::rawbson!([$($array)*])) $($rest)*); }; // Next value is a map. (@object $object:ident ($($key:tt)+) (: {$($map:tt)*} $($rest:tt)*) $copy:tt) => { $crate::rawbson!(@object $object [$($key)+] ($crate::rawbson!({$($map)*})) $($rest)*); }; // Next value is an expression followed by comma. (@object $object:ident ($($key:tt)+) (: $value:expr , $($rest:tt)*) $copy:tt) => { $crate::rawbson!(@object $object [$($key)+] ($crate::rawbson!($value)) , $($rest)*); }; // Last value is an expression with no trailing comma. (@object $object:ident ($($key:tt)+) (: $value:expr) $copy:tt) => { $crate::rawbson!(@object $object [$($key)+] ($crate::rawbson!($value))); }; // Missing value for last entry. Trigger a reasonable error message. (@object $object:ident ($($key:tt)+) (:) $copy:tt) => { // "unexpected end of macro invocation" $crate::rawbson!(); }; // Missing key-value separator and value for last entry. // Trigger a reasonable error message. (@object $object:ident ($($key:tt)+) () $copy:tt) => { // "unexpected end of macro invocation" $crate::rawbson!(); }; // Misplaced key-value separator. Trigger a reasonable error message. (@object $object:ident () (: $($rest:tt)*) ($kv_separator:tt $($copy:tt)*)) => { // Takes no arguments so "no rules expected the token `:`". unimplemented!($kv_separator); }; // Found a comma inside a key. Trigger a reasonable error message. (@object $object:ident ($($key:tt)*) (, $($rest:tt)*) ($comma:tt $($copy:tt)*)) => { // Takes no arguments so "no rules expected the token `,`". unimplemented!($comma); }; // Key is fully parenthesized. This avoids clippy double_parens false // positives because the parenthesization may be necessary here. (@object $object:ident () (($key:expr) : $($rest:tt)*) $copy:tt) => { $crate::rawbson!(@object $object ($key) (: $($rest)*) (: $($rest)*)); }; // Munch a token into the current key. (@object $object:ident ($($key:tt)*) ($tt:tt $($rest:tt)*) $copy:tt) => { $crate::rawbson!(@object $object ($($key)* $tt) ($($rest)*) ($($rest)*)); }; ////////////////////////////////////////////////////////////////////////// // The main implementation. // // Must be invoked as: rawbson!($($bson)+) ////////////////////////////////////////////////////////////////////////// (null) => { $crate::RawBson::Null }; ([]) => { $crate::RawBson::Array($crate::RawArrayBuf::new()) }; ([ $($tt:tt)+ ]) => { $crate::RawBson::Array($crate::rawbson!(@array [] $($tt)+)) }; ({}) => { $crate::RawBson::Document($crate::rawdoc!{}) }; ({$($tt:tt)+}) => { $crate::RawBson::Document($crate::rawdoc!{$($tt)+}) }; // Any Into type. // Must be below every other rule. ($other:expr) => { <_ as ::std::convert::Into<$crate::RawBson>>::into($other) }; } /// Construct a [`crate::RawDocumentBuf`] value. /// /// ```rust /// use bson::rawdoc; /// /// let value = rawdoc! { /// "code": 200, /// "success": true, /// "payload": { /// "some": [ /// "pay", /// "loads", /// ] /// } /// }; /// ``` #[macro_export] macro_rules! rawdoc { () => {{ $crate::RawDocumentBuf::new() }}; ( $($tt:tt)+ ) => {{ let mut object = $crate::RawDocumentBuf::new(); $crate::rawbson!(@object object () ($($tt)+) ($($tt)+)); object }}; } bson-2.10.0/src/oid.rs000064400000000000000000000316341046102023000125640ustar 00000000000000//! Module containing functionality related to BSON ObjectIds. //! For more information, see the documentation for the [`ObjectId`] type. use std::{ error, fmt, result, str::FromStr, sync::atomic::{AtomicUsize, Ordering}, }; #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] use std::{convert::TryInto, time::SystemTime}; use hex::{self, FromHexError}; use once_cell::sync::Lazy; use rand::{random, thread_rng, Rng}; const TIMESTAMP_SIZE: usize = 4; const PROCESS_ID_SIZE: usize = 5; const COUNTER_SIZE: usize = 3; const TIMESTAMP_OFFSET: usize = 0; const PROCESS_ID_OFFSET: usize = TIMESTAMP_OFFSET + TIMESTAMP_SIZE; const COUNTER_OFFSET: usize = PROCESS_ID_OFFSET + PROCESS_ID_SIZE; const MAX_U24: usize = 0xFF_FFFF; static OID_COUNTER: Lazy = Lazy::new(|| AtomicUsize::new(thread_rng().gen_range(0..=MAX_U24))); /// Errors that can occur during [`ObjectId`] construction and generation. #[derive(Clone, Debug)] #[non_exhaustive] pub enum Error { /// An invalid character was found in the provided hex string. Valid characters are: `0...9`, /// `a...f`, or `A...F`. #[non_exhaustive] InvalidHexStringCharacter { c: char, index: usize, hex: String }, /// An [`ObjectId`]'s hex string representation must be an exactly 12-byte (24-char) /// hexadecimal string. #[non_exhaustive] InvalidHexStringLength { length: usize, hex: String }, } /// Alias for Result. pub type Result = result::Result; impl fmt::Display for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { Error::InvalidHexStringCharacter { c, index, hex } => { write!( fmt, "invalid character '{}' was found at index {} in the provided hex string: \ \"{}\"", c, index, hex ) } Error::InvalidHexStringLength { length, hex } => { write!( fmt, "provided hex string representation must be exactly 12 bytes, instead got: \ \"{}\", length {}", hex, length ) } } } } impl error::Error for Error {} /// A wrapper around a raw 12-byte ObjectId. /// /// ## `serde` integration /// When serialized to BSON via `serde`, this type produces a BSON ObjectId. In non-BSON formats, it /// will serialize to and deserialize from that format's equivalent of the [extended JSON representation](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/) of a BSON ObjectId. /// /// [`ObjectId`]s can be deserialized from hex strings in all formats. /// /// e.g. /// ```rust /// use serde::{Serialize, Deserialize}; /// use bson::oid::ObjectId; /// /// #[derive(Serialize, Deserialize)] /// struct Foo { /// oid: ObjectId, /// } /// /// # fn main() -> std::result::Result<(), Box> { /// let f = Foo { oid: ObjectId::new() }; /// println!("bson: {}", bson::to_document(&f)?); /// println!("json: {}", serde_json::to_string(&f)?); /// # Ok(()) /// # } /// ``` /// Produces the following output: /// ```text /// bson: { "oid": ObjectId("63ceed18f71dda7d8cf21e8e") } /// json: {"oid":{"$oid":"63ceed18f71dda7d8cf21e8e"}} /// ``` /// /// ### `serde_helpers` /// The `bson` crate provides a number of useful helpers for serializing and deserializing /// various types to and from different formats. For example, to serialize an /// [`ObjectId`] as a hex string, you can use /// [`crate::serde_helpers::serialize_object_id_as_hex_string`]. /// Check out the [`crate::serde_helpers`] module documentation for a list of all of the helpers /// offered by the crate. /// /// e.g. /// ```rust /// use serde::{Serialize, Deserialize}; /// use bson::oid::ObjectId; /// /// #[derive(Serialize, Deserialize)] /// struct Foo { /// // Serializes as a BSON ObjectId or extJSON in non-BSON formats /// oid: ObjectId, /// /// // Serializes as a hex string in all formats /// #[serde(serialize_with = "bson::serde_helpers::serialize_object_id_as_hex_string")] /// oid_as_hex: ObjectId, /// } /// # fn main() -> std::result::Result<(), Box> { /// let f = Foo { oid: ObjectId::new(), oid_as_hex: ObjectId::new() }; /// println!("bson: {}", bson::to_document(&f)?); /// println!("json: {}", serde_json::to_string(&f)?); /// # Ok(()) /// # } /// ``` /// Produces the following output: /// ```text /// bson: { "oid": ObjectId("63ceeffd37518221cdc6cda2"), "oid_as_hex": "63ceeffd37518221cdc6cda3" } /// json: {"oid":{"$oid":"63ceeffd37518221cdc6cda2"},"oid_as_hex":"63ceeffd37518221cdc6cda3"} /// ``` #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)] pub struct ObjectId { id: [u8; 12], } impl Default for ObjectId { fn default() -> Self { Self::new() } } impl FromStr for ObjectId { type Err = Error; fn from_str(s: &str) -> std::result::Result { Self::parse_str(s) } } impl From<[u8; 12]> for ObjectId { fn from(bytes: [u8; 12]) -> Self { Self { id: bytes } } } impl ObjectId { /// Generates a new [`ObjectId`], represented in bytes. /// See the [docs](http://www.mongodb.com/docs/manual/reference/object-id/) /// for more information. pub fn new() -> ObjectId { let timestamp = ObjectId::gen_timestamp(); let process_id = ObjectId::gen_process_id(); let counter = ObjectId::gen_count(); let mut buf: [u8; 12] = [0; 12]; buf[TIMESTAMP_OFFSET..(TIMESTAMP_SIZE + TIMESTAMP_OFFSET)] .clone_from_slice(×tamp[..TIMESTAMP_SIZE]); buf[PROCESS_ID_OFFSET..(PROCESS_ID_SIZE + PROCESS_ID_OFFSET)] .clone_from_slice(&process_id[..PROCESS_ID_SIZE]); buf[COUNTER_OFFSET..(COUNTER_SIZE + COUNTER_OFFSET)] .clone_from_slice(&counter[..COUNTER_SIZE]); ObjectId::from_bytes(buf) } /// Constructs a new ObjectId wrapper around the raw byte representation. pub const fn from_bytes(bytes: [u8; 12]) -> ObjectId { ObjectId { id: bytes } } /// Creates an ObjectID using a 12-byte (24-char) hexadecimal string. pub fn parse_str(s: impl AsRef) -> Result { let s = s.as_ref(); let bytes: Vec = hex::decode(s.as_bytes()).map_err(|e| match e { FromHexError::InvalidHexCharacter { c, index } => Error::InvalidHexStringCharacter { c, index, hex: s.to_string(), }, FromHexError::InvalidStringLength | FromHexError::OddLength => { Error::InvalidHexStringLength { length: s.len(), hex: s.to_string(), } } })?; if bytes.len() != 12 { Err(Error::InvalidHexStringLength { length: s.len(), hex: s.to_string(), }) } else { let mut byte_array: [u8; 12] = [0; 12]; byte_array[..].copy_from_slice(&bytes[..]); Ok(ObjectId::from_bytes(byte_array)) } } /// Retrieves the timestamp from an [`ObjectId`]. pub fn timestamp(&self) -> crate::DateTime { let mut buf = [0; 4]; buf.copy_from_slice(&self.id[0..4]); let seconds_since_epoch = u32::from_be_bytes(buf); // This doesn't overflow since u32::MAX * 1000 < i64::MAX crate::DateTime::from_millis(seconds_since_epoch as i64 * 1000) } /// Returns the raw byte representation of an ObjectId. pub const fn bytes(&self) -> [u8; 12] { self.id } /// Convert this [`ObjectId`] to its hex string representation. pub fn to_hex(self) -> String { hex::encode(self.id) } /// Generates a new timestamp representing the current seconds since epoch. /// Represented in Big Endian. fn gen_timestamp() -> [u8; 4] { #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] let timestamp: u32 = (js_sys::Date::now() / 1000.0) as u32; #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] let timestamp: u32 = SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) .expect("system clock is before 1970") .as_secs() .try_into() .unwrap(); // will succeed until 2106 since timestamp is unsigned timestamp.to_be_bytes() } /// Generate a random 5-byte array. fn gen_process_id() -> [u8; 5] { static BUF: Lazy<[u8; 5]> = Lazy::new(random); *BUF } /// Gets an incremental 3-byte count. /// Represented in Big Endian. fn gen_count() -> [u8; 3] { let u_counter = OID_COUNTER.fetch_add(1, Ordering::SeqCst); // Mod result instead of OID_COUNTER to prevent threading issues. let u = u_counter % (MAX_U24 + 1); // Convert usize to writable u64, then extract the first three bytes. let u_int = u as u64; let buf = u_int.to_be_bytes(); let buf_u24: [u8; 3] = [buf[5], buf[6], buf[7]]; buf_u24 } } impl fmt::Display for ObjectId { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(&self.to_hex()) } } impl fmt::Debug for ObjectId { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("ObjectId").field(&self.to_hex()).finish() } } #[cfg(test)] use crate::tests::LOCK; #[test] fn count_generated_is_big_endian() { let _guard = LOCK.run_exclusively(); let start = 1_122_866; OID_COUNTER.store(start, Ordering::SeqCst); // Test count generates correct value 1122866 let count_bytes = ObjectId::gen_count(); let mut buf: [u8; 4] = [0; 4]; buf[1..=COUNTER_SIZE].clone_from_slice(&count_bytes[..COUNTER_SIZE]); let count = u32::from_be_bytes(buf); assert_eq!(start as u32, count); // Test OID formats count correctly as big endian let oid = ObjectId::new(); assert_eq!(0x11u8, oid.bytes()[COUNTER_OFFSET]); assert_eq!(0x22u8, oid.bytes()[COUNTER_OFFSET + 1]); assert_eq!(0x33u8, oid.bytes()[COUNTER_OFFSET + 2]); } #[test] fn test_counter_overflow_u24_max() { let _guard = LOCK.run_exclusively(); let start = MAX_U24; OID_COUNTER.store(start, Ordering::SeqCst); let oid = ObjectId::new(); assert_eq!(0xFFu8, oid.bytes()[COUNTER_OFFSET]); assert_eq!(0xFFu8, oid.bytes()[COUNTER_OFFSET + 1]); assert_eq!(0xFFu8, oid.bytes()[COUNTER_OFFSET + 2]); // Test counter overflows to 0 when set to MAX_24 + 1 let oid_new = ObjectId::new(); assert_eq!(0x00u8, oid_new.bytes()[COUNTER_OFFSET]); assert_eq!(0x00u8, oid_new.bytes()[COUNTER_OFFSET + 1]); assert_eq!(0x00u8, oid_new.bytes()[COUNTER_OFFSET + 2]); } #[test] fn test_counter_overflow_usize_max() { let _guard = LOCK.run_exclusively(); let start = usize::max_value(); OID_COUNTER.store(start, Ordering::SeqCst); // Test counter overflows to u24_max when set to usize_max let oid = ObjectId::new(); assert_eq!(0xFFu8, oid.bytes()[COUNTER_OFFSET]); assert_eq!(0xFFu8, oid.bytes()[COUNTER_OFFSET + 1]); assert_eq!(0xFFu8, oid.bytes()[COUNTER_OFFSET + 2]); // Test counter overflows to 0 when set to usize_max + 1 let oid_new = ObjectId::new(); assert_eq!(0x00u8, oid_new.bytes()[COUNTER_OFFSET]); assert_eq!(0x00u8, oid_new.bytes()[COUNTER_OFFSET + 1]); assert_eq!(0x00u8, oid_new.bytes()[COUNTER_OFFSET + 2]); } #[cfg(test)] mod test { use time::macros::datetime; #[test] fn test_display() { let id = super::ObjectId::parse_str("53e37d08776f724e42000000").unwrap(); assert_eq!(format!("{}", id), "53e37d08776f724e42000000") } #[test] fn test_debug() { let id = super::ObjectId::parse_str("53e37d08776f724e42000000").unwrap(); assert_eq!( format!("{:?}", id), "ObjectId(\"53e37d08776f724e42000000\")" ); assert_eq!( format!("{:#?}", id), "ObjectId(\n \"53e37d08776f724e42000000\",\n)" ); } #[test] fn test_timestamp() { let id = super::ObjectId::parse_str("000000000000000000000000").unwrap(); // "Jan 1st, 1970 00:00:00 UTC" assert_eq!(datetime!(1970-01-01 0:00 UTC), id.timestamp().to_time_0_3()); let id = super::ObjectId::parse_str("7FFFFFFF0000000000000000").unwrap(); // "Jan 19th, 2038 03:14:07 UTC" assert_eq!( datetime!(2038-01-19 3:14:07 UTC), id.timestamp().to_time_0_3() ); let id = super::ObjectId::parse_str("800000000000000000000000").unwrap(); // "Jan 19th, 2038 03:14:08 UTC" assert_eq!( datetime!(2038-01-19 3:14:08 UTC), id.timestamp().to_time_0_3() ); let id = super::ObjectId::parse_str("FFFFFFFF0000000000000000").unwrap(); // "Feb 7th, 2106 06:28:15 UTC" assert_eq!( datetime!(2106-02-07 6:28:15 UTC), id.timestamp().to_time_0_3() ); } } bson-2.10.0/src/raw/array.rs000064400000000000000000000257771046102023000137330ustar 00000000000000use std::{borrow::Cow, convert::TryFrom}; use serde::{ser::SerializeSeq, Deserialize, Serialize}; use super::{ error::{ValueAccessError, ValueAccessErrorKind, ValueAccessResult}, serde::OwnedOrBorrowedRawArray, Error, RawBinaryRef, RawBsonRef, RawDocument, RawIter, RawRegexRef, Result, }; use crate::{ oid::ObjectId, raw::RAW_ARRAY_NEWTYPE, spec::ElementType, Bson, DateTime, RawArrayBuf, Timestamp, }; /// A slice of a BSON document containing a BSON array value (akin to [`std::str`]). This can be /// retrieved from a [`RawDocument`] via [`RawDocument::get`]. /// /// This is an _unsized_ type, meaning that it must always be used behind a pointer like `&`. /// /// Accessing elements within a [`RawArray`] is similar to element access in [`crate::Document`], /// but because the contents are parsed during iteration instead of at creation time, format errors /// can happen at any time during use. /// /// Iterating over a [`RawArray`] yields either an error or a value that borrows from the /// original document without making any additional allocations. /// /// ``` /// use bson::{doc, raw::RawDocument}; /// /// let doc = doc! { /// "x": [1, true, "two", 5.5] /// }; /// let bytes = bson::to_vec(&doc)?; /// /// let rawdoc = RawDocument::from_bytes(bytes.as_slice())?; /// let rawarray = rawdoc.get_array("x")?; /// /// for v in rawarray { /// println!("{:?}", v?); /// } /// # Ok::<(), Box>(()) /// ``` /// /// Individual elements can be accessed using [`RawArray::get`] or any of /// the type-specific getters, such as [`RawArray::get_object_id`] or /// [`RawArray::get_str`]. Note that accessing elements is an O(N) operation, as it /// requires iterating through the array from the beginning to find the requested index. /// /// ``` /// # use bson::raw::{ValueAccessError}; /// use bson::{doc, raw::RawDocument}; /// /// let doc = doc! { /// "x": [1, true, "two", 5.5] /// }; /// let bytes = bson::to_vec(&doc)?; /// /// let rawdoc = RawDocument::from_bytes(bytes.as_slice())?; /// let rawarray = rawdoc.get_array("x")?; /// /// assert_eq!(rawarray.get_bool(1)?, true); /// # Ok::<(), Box>(()) /// ``` #[derive(PartialEq)] #[repr(transparent)] pub struct RawArray { pub(crate) doc: RawDocument, } impl RawArray { pub(crate) fn from_doc(doc: &RawDocument) -> &RawArray { // SAFETY: // // Dereferencing a raw pointer requires unsafe due to the potential that the pointer is // null, dangling, or misaligned. We know the pointer is not null or dangling due to the // fact that it's created by a safe reference. Converting &RawDocument to *const // RawDocument will be properly aligned due to them being references to the same type, // and converting *const RawDocument to *const RawArray is aligned due to the fact that // the only field in a RawArray is a RawDocument, meaning the structs are represented // identically at the byte level. unsafe { &*(doc as *const RawDocument as *const RawArray) } } /// Convert this borrowed [`RawArray`] into an owned [`RawArrayBuf`]. /// /// This involves a traversal of the array to count the values. pub fn to_raw_array_buf(&self) -> RawArrayBuf { RawArrayBuf::from_raw_document_buf(self.doc.to_raw_document_buf()) } /// Gets a reference to the value at the given index. pub fn get(&self, index: usize) -> Result>> { self.into_iter().nth(index).transpose() } fn get_with<'a, T>( &'a self, index: usize, expected_type: ElementType, f: impl FnOnce(RawBsonRef<'a>) -> Option, ) -> ValueAccessResult { let bson = self .get(index) .map_err(|e| ValueAccessError { key: index.to_string(), kind: ValueAccessErrorKind::InvalidBson(e), })? .ok_or(ValueAccessError { key: index.to_string(), kind: ValueAccessErrorKind::NotPresent, })?; match f(bson) { Some(t) => Ok(t), None => Err(ValueAccessError { key: index.to_string(), kind: ValueAccessErrorKind::UnexpectedType { expected: expected_type, actual: bson.element_type(), }, }), } } /// Gets the BSON double at the given index or returns an error if the value at that index isn't /// a double. pub fn get_f64(&self, index: usize) -> ValueAccessResult { self.get_with(index, ElementType::Double, RawBsonRef::as_f64) } /// Gets a reference to the string at the given index or returns an error if the /// value at that index isn't a string. pub fn get_str(&self, index: usize) -> ValueAccessResult<&str> { self.get_with(index, ElementType::String, RawBsonRef::as_str) } /// Gets a reference to the document at the given index or returns an error if the /// value at that index isn't a document. pub fn get_document(&self, index: usize) -> ValueAccessResult<&RawDocument> { self.get_with( index, ElementType::EmbeddedDocument, RawBsonRef::as_document, ) } /// Gets a reference to the array at the given index or returns an error if the /// value at that index isn't a array. pub fn get_array(&self, index: usize) -> ValueAccessResult<&RawArray> { self.get_with(index, ElementType::Array, RawBsonRef::as_array) } /// Gets a reference to the BSON binary value at the given index or returns an error if the /// value at that index isn't a binary. pub fn get_binary(&self, index: usize) -> ValueAccessResult> { self.get_with(index, ElementType::Binary, RawBsonRef::as_binary) } /// Gets the ObjectId at the given index or returns an error if the value at that index isn't an /// ObjectId. pub fn get_object_id(&self, index: usize) -> ValueAccessResult { self.get_with(index, ElementType::ObjectId, RawBsonRef::as_object_id) } /// Gets the boolean at the given index or returns an error if the value at that index isn't a /// boolean. pub fn get_bool(&self, index: usize) -> ValueAccessResult { self.get_with(index, ElementType::Boolean, RawBsonRef::as_bool) } /// Gets the DateTime at the given index or returns an error if the value at that index isn't a /// DateTime. pub fn get_datetime(&self, index: usize) -> ValueAccessResult { self.get_with(index, ElementType::DateTime, RawBsonRef::as_datetime) } /// Gets a reference to the BSON regex at the given index or returns an error if the /// value at that index isn't a regex. pub fn get_regex(&self, index: usize) -> ValueAccessResult> { self.get_with(index, ElementType::RegularExpression, RawBsonRef::as_regex) } /// Gets a reference to the BSON timestamp at the given index or returns an error if the /// value at that index isn't a timestamp. pub fn get_timestamp(&self, index: usize) -> ValueAccessResult { self.get_with(index, ElementType::Timestamp, RawBsonRef::as_timestamp) } /// Gets the BSON int32 at the given index or returns an error if the value at that index isn't /// a 32-bit integer. pub fn get_i32(&self, index: usize) -> ValueAccessResult { self.get_with(index, ElementType::Int32, RawBsonRef::as_i32) } /// Gets BSON int64 at the given index or returns an error if the value at that index isn't a /// 64-bit integer. pub fn get_i64(&self, index: usize) -> ValueAccessResult { self.get_with(index, ElementType::Int64, RawBsonRef::as_i64) } /// Gets a reference to the raw bytes of the [`RawArray`]. pub fn as_bytes(&self) -> &[u8] { self.doc.as_bytes() } /// Whether this array contains any elements or not. pub fn is_empty(&self) -> bool { self.doc.is_empty() } } impl std::fmt::Debug for RawArray { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("RawArray") .field("data", &hex::encode(self.doc.as_bytes())) .finish() } } impl TryFrom<&RawArray> for Vec { type Error = Error; fn try_from(arr: &RawArray) -> Result> { arr.into_iter() .map(|result| { let rawbson = result?; Bson::try_from(rawbson) }) .collect() } } impl ToOwned for RawArray { type Owned = RawArrayBuf; fn to_owned(&self) -> Self::Owned { self.to_raw_array_buf() } } impl<'a> From<&'a RawArray> for Cow<'a, RawArray> { fn from(rdr: &'a RawArray) -> Self { Cow::Borrowed(rdr) } } impl<'a> IntoIterator for &'a RawArray { type IntoIter = RawArrayIter<'a>; type Item = Result>; fn into_iter(self) -> RawArrayIter<'a> { RawArrayIter { inner: RawIter::new(&self.doc), } } } /// An iterator over borrowed raw BSON array values. pub struct RawArrayIter<'a> { inner: RawIter<'a>, } impl<'a> Iterator for RawArrayIter<'a> { type Item = Result>; fn next(&mut self) -> Option>> { match self.inner.next() { Some(Ok(elem)) => match elem.value() { Ok(value) => Some(Ok(value)), Err(e) => Some(Err(e)), }, Some(Err(e)) => Some(Err(e)), None => None, } } } impl<'de: 'a, 'a> Deserialize<'de> for &'a RawArray { fn deserialize(deserializer: D) -> std::result::Result where D: serde::Deserializer<'de>, { match OwnedOrBorrowedRawArray::deserialize(deserializer)? { OwnedOrBorrowedRawArray::Borrowed(b) => Ok(b), o => Err(serde::de::Error::custom(format!( "expected borrowed raw array, instead got owned {:?}", o ))), } } } impl<'a> Serialize for &'a RawArray { fn serialize(&self, serializer: S) -> std::result::Result where S: serde::Serializer, { struct SeqSerializer<'a>(&'a RawArray); impl<'a> Serialize for SeqSerializer<'a> { fn serialize(&self, serializer: S) -> std::result::Result where S: serde::Serializer, { if serializer.is_human_readable() { let mut seq = serializer.serialize_seq(None)?; for v in self.0 { let v = v.map_err(serde::ser::Error::custom)?; seq.serialize_element(&v)?; } seq.end() } else { serializer.serialize_bytes(self.0.as_bytes()) } } } serializer.serialize_newtype_struct(RAW_ARRAY_NEWTYPE, &SeqSerializer(self)) } } bson-2.10.0/src/raw/array_buf.rs000064400000000000000000000120051046102023000145430ustar 00000000000000use std::{ borrow::{Borrow, Cow}, fmt::Debug, iter::FromIterator, }; use serde::{Deserialize, Serialize}; use crate::{RawArray, RawBsonRef, RawDocumentBuf}; use super::{bson::RawBson, serde::OwnedOrBorrowedRawArray, RawArrayIter}; /// An owned BSON array value (akin to [`std::path::PathBuf`]), backed by a buffer of raw BSON /// bytes. This type can be used to construct owned array values, which can be used to append to /// [`RawDocumentBuf`] or as a field in a [`Deserialize`] struct. /// /// Iterating over a [`RawArrayBuf`] yields either an error or a [`RawBson`] value that borrows from /// the original document without making any additional allocations. /// ``` /// # use bson::raw::Error; /// use bson::raw::RawArrayBuf; /// /// let mut array = RawArrayBuf::new(); /// array.push("a string"); /// array.push(12_i32); /// /// let mut iter = array.into_iter(); /// /// let value = iter.next().unwrap()?; /// assert_eq!(value.as_str(), Some("a string")); /// /// let value = iter.next().unwrap()?; /// assert_eq!(value.as_i32(), Some(12)); /// /// assert!(iter.next().is_none()); /// # Ok::<(), Error>(()) /// ``` /// /// This type implements [`Deref`](std::ops::Deref) to [`RawArray`], meaning that all methods on /// [`RawArray`] are available on [`RawArrayBuf`] values as well. This includes [`RawArray::get`] or /// any of the type-specific getters, such as [`RawArray::get_object_id`] or [`RawArray::get_str`]. /// Note that accessing elements is an O(N) operation, as it requires iterating through the document /// from the beginning to find the requested key. #[derive(Clone, PartialEq)] pub struct RawArrayBuf { inner: RawDocumentBuf, len: usize, } impl RawArrayBuf { /// Construct a new, empty [`RawArrayBuf`]. pub fn new() -> RawArrayBuf { Self { inner: RawDocumentBuf::new(), len: 0, } } /// Construct a new [`RawArrayBuf`] from the provided [`Vec`] of bytes. /// /// This involves a traversal of the array to count the values. pub(crate) fn from_raw_document_buf(doc: RawDocumentBuf) -> Self { let len = doc.iter().count(); Self { inner: doc, len } } /// Append a value to the end of the array. /// /// ``` /// # use bson::raw::Error; /// use bson::raw::{RawArrayBuf, RawDocumentBuf}; /// /// let mut array = RawArrayBuf::new(); /// array.push("a string"); /// array.push(12_i32); /// /// let mut doc = RawDocumentBuf::new(); /// doc.append("a key", "a value"); /// array.push(doc.clone()); /// /// let mut iter = array.into_iter(); /// /// let value = iter.next().unwrap()?; /// assert_eq!(value.as_str(), Some("a string")); /// /// let value = iter.next().unwrap()?; /// assert_eq!(value.as_i32(), Some(12)); /// /// let value = iter.next().unwrap()?; /// assert_eq!(value.as_document(), Some(doc.as_ref())); /// /// assert!(iter.next().is_none()); /// # Ok::<(), Error>(()) /// ``` pub fn push(&mut self, value: impl Into) { self.inner.append(self.len.to_string(), value); self.len += 1; } } impl Debug for RawArrayBuf { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("RawArrayBuf") .field("data", &hex::encode(self.as_bytes())) .field("len", &self.len) .finish() } } impl std::ops::Deref for RawArrayBuf { type Target = RawArray; fn deref(&self) -> &Self::Target { RawArray::from_doc(&self.inner) } } impl AsRef for RawArrayBuf { fn as_ref(&self) -> &RawArray { RawArray::from_doc(&self.inner) } } impl Borrow for RawArrayBuf { fn borrow(&self) -> &RawArray { self.as_ref() } } impl<'a> IntoIterator for &'a RawArrayBuf { type IntoIter = RawArrayIter<'a>; type Item = super::Result>; fn into_iter(self) -> RawArrayIter<'a> { self.as_ref().into_iter() } } impl<'a> From for Cow<'a, RawArray> { fn from(rd: RawArrayBuf) -> Self { Cow::Owned(rd) } } impl<'a> From<&'a RawArrayBuf> for Cow<'a, RawArray> { fn from(rd: &'a RawArrayBuf) -> Self { Cow::Borrowed(rd.as_ref()) } } impl> FromIterator for RawArrayBuf { fn from_iter>(iter: I) -> Self { let mut array_buf = RawArrayBuf::new(); for item in iter { array_buf.push(item); } array_buf } } impl<'de> Deserialize<'de> for RawArrayBuf { fn deserialize(deserializer: D) -> std::result::Result where D: serde::Deserializer<'de>, { Ok(OwnedOrBorrowedRawArray::deserialize(deserializer)?.into_owned()) } } impl Serialize for RawArrayBuf { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { self.as_ref().serialize(serializer) } } impl Default for RawArrayBuf { fn default() -> Self { Self::new() } } bson-2.10.0/src/raw/bson.rs000064400000000000000000000432531046102023000135430ustar 00000000000000use std::convert::{TryFrom, TryInto}; use serde::{Deserialize, Serialize}; use crate::{ oid::{self, ObjectId}, raw::RAW_BSON_NEWTYPE, spec::ElementType, Binary, Bson, DbPointer, Decimal128, RawArray, RawArrayBuf, RawBinaryRef, RawBsonRef, RawDbPointerRef, RawDocument, RawDocumentBuf, RawJavaScriptCodeWithScopeRef, RawRegexRef, Regex, Timestamp, }; use super::{ serde::{bson_visitor::OwnedOrBorrowedRawBsonVisitor, OwnedOrBorrowedRawBson}, Error, Result, }; /// A BSON value backed by owned raw BSON bytes. #[derive(Debug, Clone, PartialEq)] pub enum RawBson { /// 64-bit binary floating point Double(f64), /// UTF-8 string String(String), /// Array Array(RawArrayBuf), /// Embedded document Document(RawDocumentBuf), /// Boolean value Boolean(bool), /// Null value Null, /// Regular expression RegularExpression(Regex), /// JavaScript code JavaScriptCode(String), /// JavaScript code w/ scope JavaScriptCodeWithScope(RawJavaScriptCodeWithScope), /// 32-bit signed integer Int32(i32), /// 64-bit signed integer Int64(i64), /// Timestamp Timestamp(Timestamp), /// Binary data Binary(Binary), /// [ObjectId](http://dochub.mongodb.org/core/objectids) ObjectId(oid::ObjectId), /// UTC datetime DateTime(crate::DateTime), /// Symbol (Deprecated) Symbol(String), /// [128-bit decimal floating point](https://github.com/mongodb/specifications/blob/master/source/bson-decimal128/decimal128.rst) Decimal128(Decimal128), /// Undefined value (Deprecated) Undefined, /// Max key MaxKey, /// Min key MinKey, /// DBPointer (Deprecated) DbPointer(DbPointer), } impl RawBson { /// Get the [`ElementType`] of this value. pub fn element_type(&self) -> ElementType { match *self { RawBson::Double(..) => ElementType::Double, RawBson::String(..) => ElementType::String, RawBson::Array(..) => ElementType::Array, RawBson::Document(..) => ElementType::EmbeddedDocument, RawBson::Boolean(..) => ElementType::Boolean, RawBson::Null => ElementType::Null, RawBson::RegularExpression(..) => ElementType::RegularExpression, RawBson::JavaScriptCode(..) => ElementType::JavaScriptCode, RawBson::JavaScriptCodeWithScope(..) => ElementType::JavaScriptCodeWithScope, RawBson::Int32(..) => ElementType::Int32, RawBson::Int64(..) => ElementType::Int64, RawBson::Timestamp(..) => ElementType::Timestamp, RawBson::Binary(..) => ElementType::Binary, RawBson::ObjectId(..) => ElementType::ObjectId, RawBson::DateTime(..) => ElementType::DateTime, RawBson::Symbol(..) => ElementType::Symbol, RawBson::Decimal128(..) => ElementType::Decimal128, RawBson::Undefined => ElementType::Undefined, RawBson::MaxKey => ElementType::MaxKey, RawBson::MinKey => ElementType::MinKey, RawBson::DbPointer(..) => ElementType::DbPointer, } } /// Gets the wrapped `f64` value or returns [`None`] if the value isn't a BSON /// double. pub fn as_f64(&self) -> Option { match self { RawBson::Double(d) => Some(*d), _ => None, } } /// Gets a reference to the [`String`] that's wrapped or returns [`None`] if the wrapped value /// isn't a BSON String. pub fn as_str(&self) -> Option<&'_ str> { match self { RawBson::String(s) => Some(s), _ => None, } } /// Gets a reference to the [`RawArrayBuf`] that's wrapped or returns [`None`] if the wrapped /// value isn't a BSON array. pub fn as_array(&self) -> Option<&'_ RawArray> { match self { RawBson::Array(v) => Some(v), _ => None, } } /// Gets a mutable reference to the [`RawArrayBuf`] that's wrapped or returns [`None`] if the /// wrapped value isn't a BSON array. pub fn as_array_mut(&mut self) -> Option<&mut RawArrayBuf> { match self { RawBson::Array(ref mut v) => Some(v), _ => None, } } /// Gets a reference to the [`RawDocumentBuf`] that's wrapped or returns [`None`] if the wrapped /// value isn't a BSON document. pub fn as_document(&self) -> Option<&'_ RawDocument> { match self { RawBson::Document(v) => Some(v), _ => None, } } /// Gets a mutable reference to the [`RawDocumentBuf`] that's wrapped or returns [`None`] if the /// wrapped value isn't a BSON document. pub fn as_document_mut(&mut self) -> Option<&mut RawDocumentBuf> { match self { RawBson::Document(ref mut v) => Some(v), _ => None, } } /// Gets the wrapped `bool` value or returns [`None`] if the wrapped value isn't a BSON /// boolean. pub fn as_bool(&self) -> Option { match self { RawBson::Boolean(v) => Some(*v), _ => None, } } /// Gets the wrapped `i32` value or returns [`None`] if the wrapped value isn't a BSON /// Int32. pub fn as_i32(&self) -> Option { match self { RawBson::Int32(v) => Some(*v), _ => None, } } /// Gets the wrapped `i64` value or returns [`None`] if the wrapped value isn't a BSON /// Int64. pub fn as_i64(&self) -> Option { match self { RawBson::Int64(v) => Some(*v), _ => None, } } /// Gets the wrapped [`crate::oid::ObjectId`] value or returns [`None`] if the wrapped value /// isn't a BSON ObjectID. pub fn as_object_id(&self) -> Option { match self { RawBson::ObjectId(v) => Some(*v), _ => None, } } /// Gets a reference to the [`Binary`] that's wrapped or returns [`None`] if the wrapped value /// isn't a BSON binary. pub fn as_binary(&self) -> Option> { match self { RawBson::Binary(v) => Some(RawBinaryRef { bytes: v.bytes.as_slice(), subtype: v.subtype, }), _ => None, } } /// Gets a reference to the [`Regex`] that's wrapped or returns [`None`] if the wrapped value /// isn't a BSON regular expression. pub fn as_regex(&self) -> Option> { match self { RawBson::RegularExpression(v) => Some(RawRegexRef { pattern: v.pattern.as_str(), options: v.options.as_str(), }), _ => None, } } /// Gets the wrapped [`crate::DateTime`] value or returns [`None`] if the wrapped value isn't a /// BSON datetime. pub fn as_datetime(&self) -> Option { match self { RawBson::DateTime(v) => Some(*v), _ => None, } } /// Gets a reference to the symbol that's wrapped or returns [`None`] if the wrapped value isn't /// a BSON Symbol. pub fn as_symbol(&self) -> Option<&'_ str> { match self { RawBson::Symbol(v) => Some(v), _ => None, } } /// Gets the wrapped [`crate::Timestamp`] value or returns [`None`] if the wrapped value isn't a /// BSON datetime. pub fn as_timestamp(&self) -> Option { match self { RawBson::Timestamp(timestamp) => Some(*timestamp), _ => None, } } /// Returns `Some(())` if this value is null, otherwise returns [`None`]. pub fn as_null(&self) -> Option<()> { match self { RawBson::Null => Some(()), _ => None, } } /// Gets a reference to the [`crate::DbPointer`] that's wrapped or returns [`None`] if the /// wrapped value isn't a BSON DbPointer. pub fn as_db_pointer(&self) -> Option> { match self { RawBson::DbPointer(d) => Some(RawDbPointerRef { namespace: d.namespace.as_str(), id: d.id, }), _ => None, } } /// Gets a reference to the code that's wrapped or returns [`None`] if the wrapped value isn't a /// BSON JavaScript code. pub fn as_javascript(&self) -> Option<&'_ str> { match self { RawBson::JavaScriptCode(s) => Some(s), _ => None, } } /// Gets a reference to the [`RawJavaScriptCodeWithScope`] that's wrapped or returns [`None`] /// if the wrapped value isn't a BSON JavaScript code with scope value. pub fn as_javascript_with_scope(&self) -> Option> { match self { RawBson::JavaScriptCodeWithScope(s) => Some(RawJavaScriptCodeWithScopeRef { code: s.code.as_str(), scope: &s.scope, }), _ => None, } } /// Gets a [`RawBsonRef`] value referencing this owned raw BSON value. pub fn as_raw_bson_ref(&self) -> RawBsonRef<'_> { match self { RawBson::Double(d) => RawBsonRef::Double(*d), RawBson::String(s) => RawBsonRef::String(s.as_str()), RawBson::Array(a) => RawBsonRef::Array(a), RawBson::Document(d) => RawBsonRef::Document(d), RawBson::Boolean(b) => RawBsonRef::Boolean(*b), RawBson::Null => RawBsonRef::Null, RawBson::RegularExpression(re) => RawBsonRef::RegularExpression(RawRegexRef { options: re.options.as_str(), pattern: re.pattern.as_str(), }), RawBson::JavaScriptCode(c) => RawBsonRef::JavaScriptCode(c.as_str()), RawBson::JavaScriptCodeWithScope(code_w_scope) => { RawBsonRef::JavaScriptCodeWithScope(RawJavaScriptCodeWithScopeRef { code: code_w_scope.code.as_str(), scope: code_w_scope.scope.as_ref(), }) } RawBson::Int32(i) => RawBsonRef::Int32(*i), RawBson::Int64(i) => RawBsonRef::Int64(*i), RawBson::Timestamp(ts) => RawBsonRef::Timestamp(*ts), RawBson::Binary(b) => RawBsonRef::Binary(RawBinaryRef { bytes: b.bytes.as_slice(), subtype: b.subtype, }), RawBson::ObjectId(oid) => RawBsonRef::ObjectId(*oid), RawBson::DateTime(dt) => RawBsonRef::DateTime(*dt), RawBson::Symbol(s) => RawBsonRef::Symbol(s.as_str()), RawBson::Decimal128(d) => RawBsonRef::Decimal128(*d), RawBson::Undefined => RawBsonRef::Undefined, RawBson::MaxKey => RawBsonRef::MaxKey, RawBson::MinKey => RawBsonRef::MinKey, RawBson::DbPointer(dbp) => RawBsonRef::DbPointer(RawDbPointerRef { namespace: dbp.namespace.as_str(), id: dbp.id, }), } } } impl From for RawBson { fn from(i: i32) -> Self { RawBson::Int32(i) } } impl From for RawBson { fn from(i: i64) -> Self { RawBson::Int64(i) } } impl From for RawBson { fn from(s: String) -> Self { RawBson::String(s) } } impl From<&str> for RawBson { fn from(s: &str) -> Self { RawBson::String(s.to_owned()) } } impl From for RawBson { fn from(f: f64) -> Self { RawBson::Double(f) } } impl From for RawBson { fn from(b: bool) -> Self { RawBson::Boolean(b) } } impl From for RawBson { fn from(d: RawDocumentBuf) -> Self { RawBson::Document(d) } } impl From for RawBson { fn from(a: RawArrayBuf) -> Self { RawBson::Array(a) } } impl From for RawBson { fn from(dt: crate::DateTime) -> Self { RawBson::DateTime(dt) } } impl From for RawBson { fn from(ts: Timestamp) -> Self { RawBson::Timestamp(ts) } } impl From for RawBson { fn from(oid: ObjectId) -> Self { RawBson::ObjectId(oid) } } impl From for RawBson { fn from(d: Decimal128) -> Self { RawBson::Decimal128(d) } } impl From for RawBson { fn from(code_w_scope: RawJavaScriptCodeWithScope) -> Self { RawBson::JavaScriptCodeWithScope(code_w_scope) } } impl From for RawBson { fn from(b: Binary) -> Self { RawBson::Binary(b) } } impl From for RawBson { fn from(re: Regex) -> Self { RawBson::RegularExpression(re) } } impl From for RawBson { fn from(d: DbPointer) -> Self { RawBson::DbPointer(d) } } impl<'de> Deserialize<'de> for RawBson { fn deserialize(deserializer: D) -> std::result::Result where D: serde::Deserializer<'de>, { match deserializer .deserialize_newtype_struct(RAW_BSON_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? { OwnedOrBorrowedRawBson::Owned(o) => Ok(o), OwnedOrBorrowedRawBson::Borrowed(b) => Ok(b.to_raw_bson()), } } } impl Serialize for RawBson { fn serialize(&self, serializer: S) -> std::result::Result where S: serde::Serializer, { self.as_raw_bson_ref().serialize(serializer) } } impl TryFrom for Bson { type Error = Error; fn try_from(rawbson: RawBson) -> Result { Ok(match rawbson { RawBson::Double(d) => Bson::Double(d), RawBson::String(s) => Bson::String(s), RawBson::Document(rawdoc) => Bson::Document(rawdoc.as_ref().try_into()?), RawBson::Array(rawarray) => Bson::Array(rawarray.as_ref().try_into()?), RawBson::Binary(rawbson) => Bson::Binary(rawbson), RawBson::ObjectId(rawbson) => Bson::ObjectId(rawbson), RawBson::Boolean(rawbson) => Bson::Boolean(rawbson), RawBson::DateTime(rawbson) => Bson::DateTime(rawbson), RawBson::Null => Bson::Null, RawBson::RegularExpression(rawregex) => Bson::RegularExpression(rawregex), RawBson::JavaScriptCode(rawbson) => Bson::JavaScriptCode(rawbson), RawBson::Int32(rawbson) => Bson::Int32(rawbson), RawBson::Timestamp(rawbson) => Bson::Timestamp(rawbson), RawBson::Int64(rawbson) => Bson::Int64(rawbson), RawBson::Undefined => Bson::Undefined, RawBson::DbPointer(rawbson) => Bson::DbPointer(rawbson), RawBson::Symbol(rawbson) => Bson::Symbol(rawbson), RawBson::JavaScriptCodeWithScope(rawbson) => { Bson::JavaScriptCodeWithScope(crate::JavaScriptCodeWithScope { code: rawbson.code, scope: rawbson.scope.try_into()?, }) } RawBson::Decimal128(rawbson) => Bson::Decimal128(rawbson), RawBson::MaxKey => Bson::MaxKey, RawBson::MinKey => Bson::MinKey, }) } } impl TryFrom for RawBson { type Error = Error; fn try_from(bson: Bson) -> Result { Ok(match bson { Bson::Double(d) => RawBson::Double(d), Bson::String(s) => RawBson::String(s), Bson::Document(doc) => RawBson::Document((&doc).try_into()?), Bson::Array(arr) => RawBson::Array( arr.into_iter() .map(|b| -> Result { b.try_into() }) .collect::>()?, ), Bson::Binary(bin) => RawBson::Binary(bin), Bson::ObjectId(id) => RawBson::ObjectId(id), Bson::Boolean(b) => RawBson::Boolean(b), Bson::DateTime(dt) => RawBson::DateTime(dt), Bson::Null => RawBson::Null, Bson::RegularExpression(regex) => RawBson::RegularExpression(regex), Bson::JavaScriptCode(s) => RawBson::JavaScriptCode(s), Bson::Int32(i) => RawBson::Int32(i), Bson::Timestamp(ts) => RawBson::Timestamp(ts), Bson::Int64(i) => RawBson::Int64(i), Bson::Undefined => RawBson::Undefined, Bson::DbPointer(p) => RawBson::DbPointer(p), Bson::Symbol(s) => RawBson::Symbol(s), Bson::JavaScriptCodeWithScope(jcws) => { RawBson::JavaScriptCodeWithScope(crate::RawJavaScriptCodeWithScope { code: jcws.code, scope: (&jcws.scope).try_into()?, }) } Bson::Decimal128(d) => RawBson::Decimal128(d), Bson::MaxKey => RawBson::MaxKey, Bson::MinKey => RawBson::MinKey, }) } } /// A BSON "code with scope" value backed by owned raw BSON. #[derive(Debug, Clone, PartialEq)] pub struct RawJavaScriptCodeWithScope { /// The code value. pub code: String, /// The scope document. pub scope: RawDocumentBuf, } impl<'de> Deserialize<'de> for RawJavaScriptCodeWithScope { fn deserialize(deserializer: D) -> std::result::Result where D: serde::Deserializer<'de>, { match RawBson::deserialize(deserializer)? { RawBson::JavaScriptCodeWithScope(b) => Ok(b), c => Err(serde::de::Error::custom(format!( "expected CodeWithScope, but got {:?} instead", c ))), } } } impl Serialize for RawJavaScriptCodeWithScope { fn serialize(&self, serializer: S) -> std::result::Result where S: serde::Serializer, { let raw = RawJavaScriptCodeWithScopeRef { code: self.code.as_str(), scope: self.scope.as_ref(), }; raw.serialize(serializer) } } bson-2.10.0/src/raw/bson_ref.rs000064400000000000000000000533371046102023000144030ustar 00000000000000use std::convert::{TryFrom, TryInto}; use serde::{ser::SerializeStruct, Deserialize, Serialize}; use serde_bytes::Bytes; use super::{ bson::RawBson, serde::{bson_visitor::OwnedOrBorrowedRawBsonVisitor, OwnedOrBorrowedRawBson}, Error, RawArray, RawDocument, Result, }; use crate::{ extjson, oid::{self, ObjectId}, raw::{RawJavaScriptCodeWithScope, RAW_BSON_NEWTYPE}, spec::{BinarySubtype, ElementType}, Binary, Bson, DbPointer, Decimal128, RawArrayBuf, RawDocumentBuf, Regex, Timestamp, }; /// A BSON value referencing raw bytes stored elsewhere. #[derive(Debug, Clone, Copy, PartialEq)] pub enum RawBsonRef<'a> { /// 64-bit binary floating point Double(f64), /// UTF-8 string String(&'a str), /// Array Array(&'a RawArray), /// Embedded document Document(&'a RawDocument), /// Boolean value Boolean(bool), /// Null value Null, /// Regular expression RegularExpression(RawRegexRef<'a>), /// JavaScript code JavaScriptCode(&'a str), /// JavaScript code w/ scope JavaScriptCodeWithScope(RawJavaScriptCodeWithScopeRef<'a>), /// 32-bit signed integer Int32(i32), /// 64-bit signed integer Int64(i64), /// Timestamp Timestamp(Timestamp), /// Binary data Binary(RawBinaryRef<'a>), /// [ObjectId](http://dochub.mongodb.org/core/objectids) ObjectId(oid::ObjectId), /// UTC datetime DateTime(crate::DateTime), /// Symbol (Deprecated) Symbol(&'a str), /// [128-bit decimal floating point](https://github.com/mongodb/specifications/blob/master/source/bson-decimal128/decimal128.rst) Decimal128(Decimal128), /// Undefined value (Deprecated) Undefined, /// Max key MaxKey, /// Min key MinKey, /// DBPointer (Deprecated) DbPointer(RawDbPointerRef<'a>), } impl<'a> RawBsonRef<'a> { /// Get the [`ElementType`] of this value. pub fn element_type(&self) -> ElementType { match *self { RawBsonRef::Double(..) => ElementType::Double, RawBsonRef::String(..) => ElementType::String, RawBsonRef::Array(..) => ElementType::Array, RawBsonRef::Document(..) => ElementType::EmbeddedDocument, RawBsonRef::Boolean(..) => ElementType::Boolean, RawBsonRef::Null => ElementType::Null, RawBsonRef::RegularExpression(..) => ElementType::RegularExpression, RawBsonRef::JavaScriptCode(..) => ElementType::JavaScriptCode, RawBsonRef::JavaScriptCodeWithScope(..) => ElementType::JavaScriptCodeWithScope, RawBsonRef::Int32(..) => ElementType::Int32, RawBsonRef::Int64(..) => ElementType::Int64, RawBsonRef::Timestamp(..) => ElementType::Timestamp, RawBsonRef::Binary(..) => ElementType::Binary, RawBsonRef::ObjectId(..) => ElementType::ObjectId, RawBsonRef::DateTime(..) => ElementType::DateTime, RawBsonRef::Symbol(..) => ElementType::Symbol, RawBsonRef::Decimal128(..) => ElementType::Decimal128, RawBsonRef::Undefined => ElementType::Undefined, RawBsonRef::MaxKey => ElementType::MaxKey, RawBsonRef::MinKey => ElementType::MinKey, RawBsonRef::DbPointer(..) => ElementType::DbPointer, } } /// Gets the `f64` that's referenced or returns [`None`] if the referenced value isn't a BSON /// double. pub fn as_f64(self) -> Option { match self { RawBsonRef::Double(d) => Some(d), _ => None, } } /// Gets the `&str` that's referenced or returns [`None`] if the referenced value isn't a BSON /// String. pub fn as_str(self) -> Option<&'a str> { match self { RawBsonRef::String(s) => Some(s), _ => None, } } /// Gets the [`RawArray`] that's referenced or returns [`None`] if the referenced value /// isn't a BSON array. pub fn as_array(self) -> Option<&'a RawArray> { match self { RawBsonRef::Array(v) => Some(v), _ => None, } } /// Gets the [`RawDocument`] that's referenced or returns [`None`] if the referenced value /// isn't a BSON document. pub fn as_document(self) -> Option<&'a RawDocument> { match self { RawBsonRef::Document(v) => Some(v), _ => None, } } /// Gets the `bool` that's referenced or returns [`None`] if the referenced value isn't a BSON /// boolean. pub fn as_bool(self) -> Option { match self { RawBsonRef::Boolean(v) => Some(v), _ => None, } } /// Gets the `i32` that's referenced or returns [`None`] if the referenced value isn't a BSON /// Int32. pub fn as_i32(self) -> Option { match self { RawBsonRef::Int32(v) => Some(v), _ => None, } } /// Gets the `i64` that's referenced or returns [`None`] if the referenced value isn't a BSON /// Int64. pub fn as_i64(self) -> Option { match self { RawBsonRef::Int64(v) => Some(v), _ => None, } } /// Gets the [`crate::oid::ObjectId`] that's referenced or returns [`None`] if the referenced /// value isn't a BSON ObjectID. pub fn as_object_id(self) -> Option { match self { RawBsonRef::ObjectId(v) => Some(v), _ => None, } } /// Gets the [`RawBinaryRef`] that's referenced or returns [`None`] if the referenced value /// isn't a BSON binary. pub fn as_binary(self) -> Option> { match self { RawBsonRef::Binary(v) => Some(v), _ => None, } } /// Gets the [`RawRegexRef`] that's referenced or returns [`None`] if the referenced value isn't /// a BSON regular expression. pub fn as_regex(self) -> Option> { match self { RawBsonRef::RegularExpression(v) => Some(v), _ => None, } } /// Gets the [`crate::DateTime`] that's referenced or returns [`None`] if the referenced value /// isn't a BSON datetime. pub fn as_datetime(self) -> Option { match self { RawBsonRef::DateTime(v) => Some(v), _ => None, } } /// Gets the symbol that's referenced or returns [`None`] if the referenced value isn't a BSON /// symbol. pub fn as_symbol(self) -> Option<&'a str> { match self { RawBsonRef::Symbol(v) => Some(v), _ => None, } } /// Gets the [`crate::Timestamp`] that's referenced or returns [`None`] if the referenced value /// isn't a BSON timestamp. pub fn as_timestamp(self) -> Option { match self { RawBsonRef::Timestamp(timestamp) => Some(timestamp), _ => None, } } /// Gets the null value that's referenced or returns [`None`] if the referenced value isn't a /// BSON null. pub fn as_null(self) -> Option<()> { match self { RawBsonRef::Null => Some(()), _ => None, } } /// Gets the [`RawDbPointerRef`] that's referenced or returns [`None`] if the referenced value /// isn't a BSON DB pointer. pub fn as_db_pointer(self) -> Option> { match self { RawBsonRef::DbPointer(d) => Some(d), _ => None, } } /// Gets the code that's referenced or returns [`None`] if the referenced value isn't a BSON /// JavaScript. pub fn as_javascript(self) -> Option<&'a str> { match self { RawBsonRef::JavaScriptCode(s) => Some(s), _ => None, } } /// Gets the [`RawJavaScriptCodeWithScope`] that's referenced or returns [`None`] if the /// referenced value isn't a BSON JavaScript with scope. pub fn as_javascript_with_scope(self) -> Option> { match self { RawBsonRef::JavaScriptCodeWithScope(s) => Some(s), _ => None, } } /// Convert this [`RawBsonRef`] to the equivalent [`RawBson`]. pub fn to_raw_bson(self) -> RawBson { match self { RawBsonRef::Double(d) => RawBson::Double(d), RawBsonRef::String(s) => RawBson::String(s.to_string()), RawBsonRef::Array(a) => RawBson::Array(a.to_owned()), RawBsonRef::Document(d) => RawBson::Document(d.to_owned()), RawBsonRef::Boolean(b) => RawBson::Boolean(b), RawBsonRef::Null => RawBson::Null, RawBsonRef::RegularExpression(re) => { RawBson::RegularExpression(Regex::new(re.pattern, re.options)) } RawBsonRef::JavaScriptCode(c) => RawBson::JavaScriptCode(c.to_owned()), RawBsonRef::JavaScriptCodeWithScope(c_w_s) => { RawBson::JavaScriptCodeWithScope(RawJavaScriptCodeWithScope { code: c_w_s.code.to_string(), scope: c_w_s.scope.to_owned(), }) } RawBsonRef::Int32(i) => RawBson::Int32(i), RawBsonRef::Int64(i) => RawBson::Int64(i), RawBsonRef::Timestamp(t) => RawBson::Timestamp(t), RawBsonRef::Binary(b) => RawBson::Binary(Binary { bytes: b.bytes.to_vec(), subtype: b.subtype, }), RawBsonRef::ObjectId(o) => RawBson::ObjectId(o), RawBsonRef::DateTime(dt) => RawBson::DateTime(dt), RawBsonRef::Symbol(s) => RawBson::Symbol(s.to_string()), RawBsonRef::Decimal128(d) => RawBson::Decimal128(d), RawBsonRef::Undefined => RawBson::Undefined, RawBsonRef::MaxKey => RawBson::MaxKey, RawBsonRef::MinKey => RawBson::MinKey, RawBsonRef::DbPointer(d) => RawBson::DbPointer(DbPointer { namespace: d.namespace.to_string(), id: d.id, }), } } } impl<'de: 'a, 'a> Deserialize<'de> for RawBsonRef<'a> { fn deserialize(deserializer: D) -> std::result::Result where D: serde::Deserializer<'de>, { match deserializer .deserialize_newtype_struct(RAW_BSON_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? { OwnedOrBorrowedRawBson::Borrowed(b) => Ok(b), o => Err(serde::de::Error::custom(format!( "RawBson must be deserialized from borrowed content, instead got {:?}", o ))), } } } impl<'a> Serialize for RawBsonRef<'a> { fn serialize(&self, serializer: S) -> std::result::Result where S: serde::Serializer, { match self { RawBsonRef::Double(v) => serializer.serialize_f64(*v), RawBsonRef::String(v) => serializer.serialize_str(v), RawBsonRef::Array(v) => v.serialize(serializer), RawBsonRef::Document(v) => v.serialize(serializer), RawBsonRef::Boolean(v) => serializer.serialize_bool(*v), RawBsonRef::Null => serializer.serialize_unit(), RawBsonRef::Int32(v) => serializer.serialize_i32(*v), RawBsonRef::Int64(v) => serializer.serialize_i64(*v), RawBsonRef::ObjectId(oid) => oid.serialize(serializer), RawBsonRef::DateTime(dt) => dt.serialize(serializer), RawBsonRef::Binary(b) => b.serialize(serializer), RawBsonRef::JavaScriptCode(c) => { let mut state = serializer.serialize_struct("$code", 1)?; state.serialize_field("$code", c)?; state.end() } RawBsonRef::JavaScriptCodeWithScope(code_w_scope) => code_w_scope.serialize(serializer), RawBsonRef::DbPointer(dbp) => dbp.serialize(serializer), RawBsonRef::Symbol(s) => { let mut state = serializer.serialize_struct("$symbol", 1)?; state.serialize_field("$symbol", s)?; state.end() } RawBsonRef::RegularExpression(re) => re.serialize(serializer), RawBsonRef::Timestamp(t) => t.serialize(serializer), RawBsonRef::Decimal128(d) => d.serialize(serializer), RawBsonRef::Undefined => { let mut state = serializer.serialize_struct("$undefined", 1)?; state.serialize_field("$undefined", &true)?; state.end() } RawBsonRef::MaxKey => { let mut state = serializer.serialize_struct("$maxKey", 1)?; state.serialize_field("$maxKey", &1)?; state.end() } RawBsonRef::MinKey => { let mut state = serializer.serialize_struct("$minKey", 1)?; state.serialize_field("$minKey", &1)?; state.end() } } } } impl<'a> TryFrom> for Bson { type Error = Error; fn try_from(rawbson: RawBsonRef<'a>) -> Result { rawbson.to_raw_bson().try_into() } } impl<'a> From for RawBsonRef<'a> { fn from(i: i32) -> Self { RawBsonRef::Int32(i) } } impl<'a> From for RawBsonRef<'a> { fn from(i: i64) -> Self { RawBsonRef::Int64(i) } } impl<'a> From<&'a str> for RawBsonRef<'a> { fn from(s: &'a str) -> Self { RawBsonRef::String(s) } } impl<'a> From for RawBsonRef<'a> { fn from(f: f64) -> Self { RawBsonRef::Double(f) } } impl<'a> From for RawBsonRef<'a> { fn from(b: bool) -> Self { RawBsonRef::Boolean(b) } } impl<'a> From<&'a RawDocumentBuf> for RawBsonRef<'a> { fn from(d: &'a RawDocumentBuf) -> Self { RawBsonRef::Document(d.as_ref()) } } impl<'a> From<&'a RawDocument> for RawBsonRef<'a> { fn from(d: &'a RawDocument) -> Self { RawBsonRef::Document(d) } } impl<'a> From<&'a RawArray> for RawBsonRef<'a> { fn from(a: &'a RawArray) -> Self { RawBsonRef::Array(a) } } impl<'a> From<&'a RawArrayBuf> for RawBsonRef<'a> { fn from(a: &'a RawArrayBuf) -> Self { RawBsonRef::Array(a) } } impl<'a> From for RawBsonRef<'a> { fn from(dt: crate::DateTime) -> Self { RawBsonRef::DateTime(dt) } } impl<'a> From for RawBsonRef<'a> { fn from(ts: Timestamp) -> Self { RawBsonRef::Timestamp(ts) } } impl<'a> From for RawBsonRef<'a> { fn from(oid: ObjectId) -> Self { RawBsonRef::ObjectId(oid) } } impl<'a> From for RawBsonRef<'a> { fn from(d: Decimal128) -> Self { RawBsonRef::Decimal128(d) } } /// A BSON binary value referencing raw bytes stored elsewhere. #[derive(Clone, Copy, Debug, PartialEq)] pub struct RawBinaryRef<'a> { /// The subtype of the binary value. pub subtype: BinarySubtype, /// The binary bytes. pub bytes: &'a [u8], } impl<'a> RawBinaryRef<'a> { /// Copy the contents into a [`Binary`]. pub fn to_binary(&self) -> Binary { Binary { subtype: self.subtype, bytes: self.bytes.to_owned(), } } pub(crate) fn len(&self) -> i32 { match self.subtype { BinarySubtype::BinaryOld => self.bytes.len() as i32 + 4, _ => self.bytes.len() as i32, } } } impl<'de: 'a, 'a> Deserialize<'de> for RawBinaryRef<'a> { fn deserialize(deserializer: D) -> std::result::Result where D: serde::Deserializer<'de>, { match RawBsonRef::deserialize(deserializer)? { RawBsonRef::Binary(b) => Ok(b), c => Err(serde::de::Error::custom(format!( "expected binary, but got {:?} instead", c ))), } } } impl<'a> Serialize for RawBinaryRef<'a> { fn serialize(&self, serializer: S) -> std::result::Result where S: serde::Serializer, { if let BinarySubtype::Generic = self.subtype { serializer.serialize_bytes(self.bytes) } else if !serializer.is_human_readable() { #[derive(Serialize)] struct BorrowedBinary<'a> { bytes: &'a Bytes, #[serde(rename = "subType")] subtype: u8, } let mut state = serializer.serialize_struct("$binary", 1)?; let body = BorrowedBinary { bytes: Bytes::new(self.bytes), subtype: self.subtype.into(), }; state.serialize_field("$binary", &body)?; state.end() } else { let mut state = serializer.serialize_struct("$binary", 1)?; let body = extjson::models::BinaryBody { base64: base64::encode(self.bytes), subtype: hex::encode([self.subtype.into()]), }; state.serialize_field("$binary", &body)?; state.end() } } } impl<'a> From> for RawBsonRef<'a> { fn from(b: RawBinaryRef<'a>) -> Self { RawBsonRef::Binary(b) } } impl<'a> From<&'a Binary> for RawBsonRef<'a> { fn from(bin: &'a Binary) -> Self { bin.as_raw_binary().into() } } /// A BSON regex referencing raw bytes stored elsewhere. #[derive(Clone, Copy, Debug, PartialEq)] pub struct RawRegexRef<'a> { /// The regex pattern to match. pub pattern: &'a str, /// The options for the regex. /// /// Options are identified by characters, which must be stored in /// alphabetical order. Valid options are 'i' for case insensitive matching, 'm' for /// multiline matching, 'x' for verbose mode, 'l' to make \w, \W, etc. locale dependent, /// 's' for dotall mode ('.' matches everything), and 'u' to make \w, \W, etc. match /// unicode. pub options: &'a str, } impl<'de: 'a, 'a> Deserialize<'de> for RawRegexRef<'a> { fn deserialize(deserializer: D) -> std::result::Result where D: serde::Deserializer<'de>, { match RawBsonRef::deserialize(deserializer)? { RawBsonRef::RegularExpression(b) => Ok(b), c => Err(serde::de::Error::custom(format!( "expected Regex, but got {:?} instead", c ))), } } } impl<'a> Serialize for RawRegexRef<'a> { fn serialize(&self, serializer: S) -> std::result::Result where S: serde::Serializer, { #[derive(Serialize)] struct BorrowedRegexBody<'a> { pattern: &'a str, options: &'a str, } let mut state = serializer.serialize_struct("$regularExpression", 1)?; let body = BorrowedRegexBody { pattern: self.pattern, options: self.options, }; state.serialize_field("$regularExpression", &body)?; state.end() } } impl<'a> From> for RawBsonRef<'a> { fn from(re: RawRegexRef<'a>) -> Self { RawBsonRef::RegularExpression(re) } } /// A BSON "code with scope" value referencing raw bytes stored elsewhere. #[derive(Clone, Copy, Debug, PartialEq)] pub struct RawJavaScriptCodeWithScopeRef<'a> { /// The JavaScript code. pub code: &'a str, /// The scope document containing variable bindings. pub scope: &'a RawDocument, } impl<'a> RawJavaScriptCodeWithScopeRef<'a> { pub(crate) fn len(self) -> i32 { 4 + 4 + self.code.len() as i32 + 1 + self.scope.as_bytes().len() as i32 } } impl<'de: 'a, 'a> Deserialize<'de> for RawJavaScriptCodeWithScopeRef<'a> { fn deserialize(deserializer: D) -> std::result::Result where D: serde::Deserializer<'de>, { match RawBsonRef::deserialize(deserializer)? { RawBsonRef::JavaScriptCodeWithScope(b) => Ok(b), c => Err(serde::de::Error::custom(format!( "expected CodeWithScope, but got {:?} instead", c ))), } } } impl<'a> Serialize for RawJavaScriptCodeWithScopeRef<'a> { fn serialize(&self, serializer: S) -> std::result::Result where S: serde::Serializer, { let mut state = serializer.serialize_struct("$codeWithScope", 2)?; state.serialize_field("$code", &self.code)?; state.serialize_field("$scope", &self.scope)?; state.end() } } impl<'a> From> for RawBsonRef<'a> { fn from(code_w_scope: RawJavaScriptCodeWithScopeRef<'a>) -> Self { RawBsonRef::JavaScriptCodeWithScope(code_w_scope) } } /// A BSON DB pointer value referencing raw bytes stored elesewhere. #[derive(Debug, Clone, Copy, PartialEq)] pub struct RawDbPointerRef<'a> { pub(crate) namespace: &'a str, pub(crate) id: ObjectId, } impl<'de: 'a, 'a> Deserialize<'de> for RawDbPointerRef<'a> { fn deserialize(deserializer: D) -> std::result::Result where D: serde::Deserializer<'de>, { match RawBsonRef::deserialize(deserializer)? { RawBsonRef::DbPointer(b) => Ok(b), c => Err(serde::de::Error::custom(format!( "expected DbPointer, but got {:?} instead", c ))), } } } impl<'a> Serialize for RawDbPointerRef<'a> { fn serialize(&self, serializer: S) -> std::result::Result where S: serde::Serializer, { #[derive(Serialize)] struct BorrowedDbPointerBody<'a> { #[serde(rename = "$ref")] ref_ns: &'a str, #[serde(rename = "$id")] id: ObjectId, } let mut state = serializer.serialize_struct("$dbPointer", 1)?; let body = BorrowedDbPointerBody { ref_ns: self.namespace, id: self.id, }; state.serialize_field("$dbPointer", &body)?; state.end() } } bson-2.10.0/src/raw/document.rs000064400000000000000000000551641046102023000144240ustar 00000000000000use std::{ borrow::Cow, convert::{TryFrom, TryInto}, }; use serde::{ser::SerializeMap, Deserialize, Serialize}; use crate::{ de::MIN_BSON_DOCUMENT_SIZE, raw::{error::ErrorKind, serde::OwnedOrBorrowedRawDocument, RAW_DOCUMENT_NEWTYPE}, DateTime, Timestamp, }; use super::{ error::{ValueAccessError, ValueAccessErrorKind, ValueAccessResult}, i32_from_slice, iter::Iter, try_to_str, Error, RawArray, RawBinaryRef, RawBsonRef, RawDocumentBuf, RawIter, RawRegexRef, Result, }; use crate::{oid::ObjectId, spec::ElementType, Document}; /// A slice of a BSON document (akin to [`std::str`]). This can be created from a /// [`RawDocumentBuf`] or any type that contains valid BSON data, including static binary literals, /// [`Vec`](std::vec::Vec), or arrays. /// /// This is an _unsized_ type, meaning that it must always be used behind a pointer like `&`. For an /// owned version of this type, see [`RawDocumentBuf`]. /// /// Accessing elements within a [`RawDocument`] is similar to element access in [`crate::Document`], /// but because the contents are parsed during iteration instead of at creation time, format errors /// can happen at any time during use. /// /// Iterating over a [`RawDocument`] yields either an error or a key-value pair that borrows from /// the original document without making any additional allocations. /// ``` /// # use bson::raw::{Error}; /// use bson::raw::RawDocument; /// /// let doc = RawDocument::from_bytes(b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00")?; /// let mut iter = doc.into_iter(); /// let (key, value) = iter.next().unwrap()?; /// assert_eq!(key, "hi"); /// assert_eq!(value.as_str(), Some("y'all")); /// assert!(iter.next().is_none()); /// # Ok::<(), Error>(()) /// ``` /// /// Individual elements can be accessed using [`RawDocument::get`] or any of /// the type-specific getters, such as [`RawDocument::get_object_id`] or /// [`RawDocument::get_str`]. Note that accessing elements is an O(N) operation, as it /// requires iterating through the document from the beginning to find the requested key. /// /// ``` /// use bson::raw::RawDocument; /// /// let doc = RawDocument::from_bytes(b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00")?; /// assert_eq!(doc.get_str("hi")?, "y'all"); /// # Ok::<(), Box>(()) /// ``` #[derive(PartialEq)] #[repr(transparent)] pub struct RawDocument { data: [u8], } impl RawDocument { /// Constructs a new [`RawDocument`], validating _only_ the /// following invariants: /// * `data` is at least five bytes long (the minimum for a valid BSON document) /// * the initial four bytes of `data` accurately represent the length of the bytes as /// required by the BSON spec. /// * the last byte of `data` is a 0 /// /// Note that the internal structure of the bytes representing the /// BSON elements is _not_ validated at all by this method. If the /// bytes do not conform to the BSON spec, then method calls on /// the [`RawDocument`] will return Errors where appropriate. /// /// ``` /// use bson::raw::RawDocument; /// /// let doc = RawDocument::from_bytes(b"\x05\0\0\0\0")?; /// # Ok::<(), bson::raw::Error>(()) /// ``` pub fn from_bytes + ?Sized>(data: &D) -> Result<&RawDocument> { let data = data.as_ref(); if data.len() < 5 { return Err(Error { key: None, kind: ErrorKind::MalformedValue { message: "document too short".into(), }, }); } let length = i32_from_slice(data)?; if data.len() as i32 != length { return Err(Error { key: None, kind: ErrorKind::MalformedValue { message: "document length incorrect".into(), }, }); } if data[data.len() - 1] != 0 { return Err(Error { key: None, kind: ErrorKind::MalformedValue { message: "document not null-terminated".into(), }, }); } Ok(RawDocument::new_unchecked(data)) } /// Creates a new [`RawDocument`] referencing the provided data slice. pub(crate) fn new_unchecked + ?Sized>(data: &D) -> &RawDocument { // SAFETY: // // Dereferencing a raw pointer requires unsafe due to the potential that the pointer is // null, dangling, or misaligned. We know the pointer is not null or dangling due to the // fact that it's created by a safe reference. Converting &[u8] to *const [u8] will be // properly aligned due to them being references to the same type, and converting *const // [u8] to *const RawDocument is aligned due to the fact that the only field in a // RawDocument is a [u8] and it is #[repr(transparent), meaning the structs are represented // identically at the byte level. unsafe { &*(data.as_ref() as *const [u8] as *const RawDocument) } } /// Creates a new [`RawDocumentBuf`] with an owned copy of the BSON bytes. /// /// ``` /// use bson::raw::{RawDocument, RawDocumentBuf, Error}; /// /// let data = b"\x05\0\0\0\0"; /// let doc_ref = RawDocument::from_bytes(data)?; /// let doc: RawDocumentBuf = doc_ref.to_raw_document_buf(); /// # Ok::<(), Error>(()) pub fn to_raw_document_buf(&self) -> RawDocumentBuf { // unwrap is ok here because we already verified the bytes in `RawDocumentRef::new` RawDocumentBuf::from_bytes(self.data.to_owned()).unwrap() } /// Gets a reference to the value corresponding to the given key by iterating until the key is /// found. /// /// ``` /// # use bson::raw::Error; /// use bson::{rawdoc, oid::ObjectId}; /// /// let doc = rawdoc! { /// "_id": ObjectId::new(), /// "f64": 2.5, /// }; /// /// let element = doc.get("f64")?.expect("finding key f64"); /// assert_eq!(element.as_f64(), Some(2.5)); /// assert!(doc.get("unknown")?.is_none()); /// # Ok::<(), Error>(()) /// ``` pub fn get(&self, key: impl AsRef) -> Result>> { for elem in RawIter::new(self) { let elem = elem?; if key.as_ref() == elem.key() { return Ok(Some(elem.try_into()?)); } } Ok(None) } /// Gets an iterator over the elements in the [`RawDocument`] that yields /// `Result<(&str, RawBson<'_>)>`. pub fn iter(&self) -> Iter<'_> { Iter::new(self) } /// Gets an iterator over the elements in the [`RawDocument`], /// which yields `Result>` values. These hold a /// reference to the underlying document but do not explicitly /// resolve the values. /// /// This iterator, which underpins the implementation of the /// default iterator, produces `RawElement` objects that hold a /// view onto the document but do not parse out or construct /// values until the `.value()` or `.try_into()` methods are /// called. pub fn iter_elements(&self) -> RawIter<'_> { RawIter::new(self) } fn get_with<'a, T>( &'a self, key: impl AsRef, expected_type: ElementType, f: impl FnOnce(RawBsonRef<'a>) -> Option, ) -> ValueAccessResult { let key = key.as_ref(); let bson = self .get(key) .map_err(|e| ValueAccessError { key: key.to_string(), kind: ValueAccessErrorKind::InvalidBson(e), })? .ok_or(ValueAccessError { key: key.to_string(), kind: ValueAccessErrorKind::NotPresent, })?; match f(bson) { Some(t) => Ok(t), None => Err(ValueAccessError { key: key.to_string(), kind: ValueAccessErrorKind::UnexpectedType { expected: expected_type, actual: bson.element_type(), }, }), } } /// Gets a reference to the BSON double value corresponding to a given key or returns an error /// if the key corresponds to a value which isn't a double. /// /// ``` /// # use bson::raw::Error; /// use bson::raw::ValueAccessErrorKind; /// use bson::rawdoc; /// /// let doc = rawdoc! { /// "bool": true, /// "f64": 2.5, /// }; /// /// assert_eq!(doc.get_f64("f64")?, 2.5); /// assert!(matches!(doc.get_f64("bool").unwrap_err().kind, ValueAccessErrorKind::UnexpectedType { .. })); /// assert!(matches!(doc.get_f64("unknown").unwrap_err().kind, ValueAccessErrorKind::NotPresent)); /// # Ok::<(), Box>(()) /// ``` pub fn get_f64(&self, key: impl AsRef) -> ValueAccessResult { self.get_with(key, ElementType::Double, RawBsonRef::as_f64) } /// Gets a reference to the string value corresponding to a given key or returns an error if the /// key corresponds to a value which isn't a string. /// /// ``` /// use bson::{rawdoc, raw::ValueAccessErrorKind}; /// /// let doc = rawdoc! { /// "string": "hello", /// "bool": true, /// }; /// /// assert_eq!(doc.get_str("string")?, "hello"); /// assert!(matches!(doc.get_str("bool").unwrap_err().kind, ValueAccessErrorKind::UnexpectedType { .. })); /// assert!(matches!(doc.get_str("unknown").unwrap_err().kind, ValueAccessErrorKind::NotPresent)); /// # Ok::<(), Box>(()) /// ``` pub fn get_str(&self, key: impl AsRef) -> ValueAccessResult<&'_ str> { self.get_with(key, ElementType::String, RawBsonRef::as_str) } /// Gets a reference to the document value corresponding to a given key or returns an error if /// the key corresponds to a value which isn't a document. /// /// ``` /// # use bson::raw::Error; /// use bson::{rawdoc, raw::ValueAccessErrorKind}; /// /// let doc = rawdoc! { /// "doc": { "key": "value"}, /// "bool": true, /// }; /// /// assert_eq!(doc.get_document("doc")?.get_str("key")?, "value"); /// assert!(matches!(doc.get_document("bool").unwrap_err().kind, ValueAccessErrorKind::UnexpectedType { .. })); /// assert!(matches!(doc.get_document("unknown").unwrap_err().kind, ValueAccessErrorKind::NotPresent)); /// # Ok::<(), Box>(()) /// ``` pub fn get_document(&self, key: impl AsRef) -> ValueAccessResult<&'_ RawDocument> { self.get_with(key, ElementType::EmbeddedDocument, RawBsonRef::as_document) } /// Gets a reference to the array value corresponding to a given key or returns an error if /// the key corresponds to a value which isn't an array. /// /// ``` /// use bson::{rawdoc, raw::ValueAccessErrorKind}; /// /// let doc = rawdoc! { /// "array": [true, 3], /// "bool": true, /// }; /// /// let mut arr_iter = doc.get_array("array")?.into_iter(); /// let _: bool = arr_iter.next().unwrap()?.as_bool().unwrap(); /// let _: i32 = arr_iter.next().unwrap()?.as_i32().unwrap(); /// /// assert!(arr_iter.next().is_none()); /// assert!(doc.get_array("bool").is_err()); /// assert!(matches!(doc.get_array("unknown").unwrap_err().kind, ValueAccessErrorKind::NotPresent)); /// # Ok::<(), Box>(()) /// ``` pub fn get_array(&self, key: impl AsRef) -> ValueAccessResult<&'_ RawArray> { self.get_with(key, ElementType::Array, RawBsonRef::as_array) } /// Gets a reference to the BSON binary value corresponding to a given key or returns an error /// if the key corresponds to a value which isn't a binary value. /// /// ``` /// use bson::{ /// rawdoc, /// raw::ValueAccessErrorKind, /// spec::BinarySubtype, /// Binary, /// }; /// /// let doc = rawdoc! { /// "binary": Binary { subtype: BinarySubtype::Generic, bytes: vec![1, 2, 3] }, /// "bool": true, /// }; /// /// assert_eq!(&doc.get_binary("binary")?.bytes, &[1, 2, 3]); /// assert!(matches!(doc.get_binary("bool").unwrap_err().kind, ValueAccessErrorKind::UnexpectedType { .. })); /// assert!(matches!(doc.get_binary("unknown").unwrap_err().kind, ValueAccessErrorKind::NotPresent)); /// # Ok::<(), Box>(()) /// ``` pub fn get_binary(&self, key: impl AsRef) -> ValueAccessResult> { self.get_with(key, ElementType::Binary, RawBsonRef::as_binary) } /// Gets a reference to the ObjectId value corresponding to a given key or returns an error if /// the key corresponds to a value which isn't an ObjectId. /// /// ``` /// # use bson::raw::Error; /// use bson::{rawdoc, oid::ObjectId, raw::ValueAccessErrorKind}; /// /// let doc = rawdoc! { /// "_id": ObjectId::new(), /// "bool": true, /// }; /// /// let oid = doc.get_object_id("_id")?; /// assert!(matches!(doc.get_object_id("bool").unwrap_err().kind, ValueAccessErrorKind::UnexpectedType { .. })); /// assert!(matches!(doc.get_object_id("unknown").unwrap_err().kind, ValueAccessErrorKind::NotPresent)); /// # Ok::<(), Box>(()) /// ``` pub fn get_object_id(&self, key: impl AsRef) -> ValueAccessResult { self.get_with(key, ElementType::ObjectId, RawBsonRef::as_object_id) } /// Gets a reference to the boolean value corresponding to a given key or returns an error if /// the key corresponds to a value which isn't a boolean. /// /// ``` /// # use bson::raw::Error; /// use bson::{rawdoc, oid::ObjectId, raw::ValueAccessErrorKind}; /// /// let doc = rawdoc! { /// "_id": ObjectId::new(), /// "bool": true, /// }; /// /// assert!(doc.get_bool("bool")?); /// assert!(matches!(doc.get_bool("_id").unwrap_err().kind, ValueAccessErrorKind::UnexpectedType { .. })); /// assert!(matches!(doc.get_bool("unknown").unwrap_err().kind, ValueAccessErrorKind::NotPresent)); /// # Ok::<(), Box>(()) /// ``` pub fn get_bool(&self, key: impl AsRef) -> ValueAccessResult { self.get_with(key, ElementType::Boolean, RawBsonRef::as_bool) } /// Gets a reference to the BSON DateTime value corresponding to a given key or returns an /// error if the key corresponds to a value which isn't a DateTime. /// /// ``` /// # use bson::raw::Error; /// use bson::{rawdoc, raw::ValueAccessErrorKind, DateTime}; /// /// let dt = DateTime::now(); /// let doc = rawdoc! { /// "created_at": dt, /// "bool": true, /// }; /// /// assert_eq!(doc.get_datetime("created_at")?, dt); /// assert!(matches!(doc.get_datetime("bool").unwrap_err().kind, ValueAccessErrorKind::UnexpectedType { .. })); /// assert!(matches!(doc.get_datetime("unknown").unwrap_err().kind, ValueAccessErrorKind::NotPresent)); /// # Ok::<(), Box>(()) /// ``` pub fn get_datetime(&self, key: impl AsRef) -> ValueAccessResult { self.get_with(key, ElementType::DateTime, RawBsonRef::as_datetime) } /// Gets a reference to the BSON regex value corresponding to a given key or returns an error if /// the key corresponds to a value which isn't a regex. /// /// ``` /// use bson::{rawdoc, Regex, raw::ValueAccessErrorKind}; /// /// let doc = rawdoc! { /// "regex": Regex { /// pattern: r"end\s*$".into(), /// options: "i".into(), /// }, /// "bool": true, /// }; /// /// assert_eq!(doc.get_regex("regex")?.pattern, r"end\s*$"); /// assert_eq!(doc.get_regex("regex")?.options, "i"); /// assert!(matches!(doc.get_regex("bool").unwrap_err().kind, ValueAccessErrorKind::UnexpectedType { .. })); /// assert!(matches!(doc.get_regex("unknown").unwrap_err().kind, ValueAccessErrorKind::NotPresent)); /// # Ok::<(), Box>(()) /// ``` pub fn get_regex(&self, key: impl AsRef) -> ValueAccessResult> { self.get_with(key, ElementType::RegularExpression, RawBsonRef::as_regex) } /// Gets a reference to the BSON timestamp value corresponding to a given key or returns an /// error if the key corresponds to a value which isn't a timestamp. /// /// ``` /// # use bson::raw::Error; /// use bson::{rawdoc, Timestamp, raw::ValueAccessErrorKind}; /// /// let doc = rawdoc! { /// "bool": true, /// "ts": Timestamp { time: 649876543, increment: 9 }, /// }; /// /// let timestamp = doc.get_timestamp("ts")?; /// /// assert_eq!(timestamp.time, 649876543); /// assert_eq!(timestamp.increment, 9); /// assert!(matches!(doc.get_timestamp("bool").unwrap_err().kind, ValueAccessErrorKind::UnexpectedType { .. })); /// assert!(matches!(doc.get_timestamp("unknown").unwrap_err().kind, ValueAccessErrorKind::NotPresent)); /// # Ok::<(), Box>(()) /// ``` pub fn get_timestamp(&self, key: impl AsRef) -> ValueAccessResult { self.get_with(key, ElementType::Timestamp, RawBsonRef::as_timestamp) } /// Gets a reference to the BSON int32 value corresponding to a given key or returns an error if /// the key corresponds to a value which isn't a 32-bit integer. /// /// ``` /// # use bson::raw::Error; /// use bson::{rawdoc, raw::ValueAccessErrorKind}; /// /// let doc = rawdoc! { /// "bool": true, /// "i32": 1_000_000, /// }; /// /// assert_eq!(doc.get_i32("i32")?, 1_000_000); /// assert!(matches!(doc.get_i32("bool").unwrap_err().kind, ValueAccessErrorKind::UnexpectedType { ..})); /// assert!(matches!(doc.get_i32("unknown").unwrap_err().kind, ValueAccessErrorKind::NotPresent)); /// # Ok::<(), Box>(()) /// ``` pub fn get_i32(&self, key: impl AsRef) -> ValueAccessResult { self.get_with(key, ElementType::Int32, RawBsonRef::as_i32) } /// Gets a reference to the BSON int64 value corresponding to a given key or returns an error if /// the key corresponds to a value which isn't a 64-bit integer. /// /// ``` /// # use bson::raw::Error; /// use bson::{rawdoc, raw::ValueAccessErrorKind}; /// /// let doc = rawdoc! { /// "bool": true, /// "i64": 9223372036854775807_i64, /// }; /// /// assert_eq!(doc.get_i64("i64")?, 9223372036854775807); /// assert!(matches!(doc.get_i64("bool").unwrap_err().kind, ValueAccessErrorKind::UnexpectedType { .. })); /// assert!(matches!(doc.get_i64("unknown").unwrap_err().kind, ValueAccessErrorKind::NotPresent)); /// # Ok::<(), Box>(()) /// ``` pub fn get_i64(&self, key: impl AsRef) -> ValueAccessResult { self.get_with(key, ElementType::Int64, RawBsonRef::as_i64) } /// Return a reference to the contained data as a `&[u8]` /// /// ``` /// # use bson::raw::Error; /// use bson::rawdoc; /// let docbuf = rawdoc! {}; /// assert_eq!(docbuf.as_bytes(), b"\x05\x00\x00\x00\x00"); /// # Ok::<(), Error>(()) /// ``` pub fn as_bytes(&self) -> &[u8] { &self.data } /// Returns whether this document contains any elements or not. pub fn is_empty(&self) -> bool { self.as_bytes().len() == MIN_BSON_DOCUMENT_SIZE as usize } pub(crate) fn read_cstring_at(&self, start_at: usize) -> Result<&str> { let buf = &self.as_bytes()[start_at..]; let mut splits = buf.splitn(2, |x| *x == 0); let value = splits .next() .ok_or_else(|| Error::new_without_key(ErrorKind::new_malformed("no value")))?; if splits.next().is_some() { Ok(try_to_str(value)?) } else { Err(Error::new_without_key(ErrorKind::new_malformed( "expected null terminator", ))) } } } impl<'de: 'a, 'a> Deserialize<'de> for &'a RawDocument { fn deserialize(deserializer: D) -> std::result::Result where D: serde::Deserializer<'de>, { match OwnedOrBorrowedRawDocument::deserialize(deserializer)? { OwnedOrBorrowedRawDocument::Borrowed(b) => Ok(b), OwnedOrBorrowedRawDocument::Owned(d) => Err(serde::de::Error::custom(format!( "expected borrowed raw document, instead got owned {:?}", d ))), } } } impl<'a> Serialize for &'a RawDocument { fn serialize(&self, serializer: S) -> std::result::Result where S: serde::Serializer, { struct KvpSerializer<'a>(&'a RawDocument); impl<'a> Serialize for KvpSerializer<'a> { fn serialize(&self, serializer: S) -> std::result::Result where S: serde::Serializer, { if serializer.is_human_readable() { let mut map = serializer.serialize_map(None)?; for kvp in self.0 { let (k, v) = kvp.map_err(serde::ser::Error::custom)?; map.serialize_entry(k, &v)?; } map.end() } else { serializer.serialize_bytes(self.0.as_bytes()) } } } serializer.serialize_newtype_struct(RAW_DOCUMENT_NEWTYPE, &KvpSerializer(self)) } } impl std::fmt::Debug for RawDocument { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("RawDocument") .field("data", &hex::encode(&self.data)) .finish() } } impl AsRef for RawDocument { fn as_ref(&self) -> &RawDocument { self } } impl ToOwned for RawDocument { type Owned = RawDocumentBuf; fn to_owned(&self) -> Self::Owned { self.to_raw_document_buf() } } impl<'a> From<&'a RawDocument> for Cow<'a, RawDocument> { fn from(rdr: &'a RawDocument) -> Self { Cow::Borrowed(rdr) } } impl TryFrom<&RawDocument> for crate::Document { type Error = Error; fn try_from(rawdoc: &RawDocument) -> Result { rawdoc .into_iter() .map(|res| res.and_then(|(k, v)| Ok((k.to_owned(), v.try_into()?)))) .collect() } } impl<'a> IntoIterator for &'a RawDocument { type IntoIter = Iter<'a>; type Item = Result<(&'a str, RawBsonRef<'a>)>; fn into_iter(self) -> Iter<'a> { self.iter() } } bson-2.10.0/src/raw/document_buf.rs000064400000000000000000000334571046102023000152610ustar 00000000000000use std::{ borrow::{Borrow, Cow}, convert::{TryFrom, TryInto}, iter::FromIterator, ops::Deref, }; use serde::{Deserialize, Serialize}; use crate::{de::MIN_BSON_DOCUMENT_SIZE, spec::BinarySubtype, Document}; use super::{ bson::RawBson, iter::Iter, serde::OwnedOrBorrowedRawDocument, Error, ErrorKind, RawBsonRef, RawDocument, RawIter, Result, }; /// An owned BSON document (akin to [`std::path::PathBuf`]), backed by a buffer of raw BSON bytes. /// This can be created from a `Vec` or a [`crate::Document`]. /// /// Accessing elements within a [`RawDocumentBuf`] is similar to element access in /// [`crate::Document`], but because the contents are parsed during iteration instead of at creation /// time, format errors can happen at any time during use. /// /// Iterating over a [`RawDocumentBuf`] yields either an error or a key-value pair that borrows from /// the original document without making any additional allocations. /// /// ``` /// # use bson::raw::Error; /// use bson::raw::RawDocumentBuf; /// /// let doc = RawDocumentBuf::from_bytes(b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00".to_vec())?; /// let mut iter = doc.iter(); /// let (key, value) = iter.next().unwrap()?; /// assert_eq!(key, "hi"); /// assert_eq!(value.as_str(), Some("y'all")); /// assert!(iter.next().is_none()); /// # Ok::<(), Error>(()) /// ``` /// /// This type implements [`Deref`] to [`RawDocument`], meaning that all methods on [`RawDocument`] /// are available on [`RawDocumentBuf`] values as well. This includes [`RawDocument::get`] or any of /// the type-specific getters, such as [`RawDocument::get_object_id`] or [`RawDocument::get_str`]. /// Note that accessing elements is an O(N) operation, as it requires iterating through the document /// from the beginning to find the requested key. /// /// ``` /// use bson::raw::RawDocumentBuf; /// /// let doc = RawDocumentBuf::from_bytes(b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00".to_vec())?; /// assert_eq!(doc.get_str("hi")?, "y'all"); /// # Ok::<(), Box>(()) /// ``` #[derive(Clone, PartialEq)] pub struct RawDocumentBuf { data: Vec, } impl RawDocumentBuf { /// Creates a new, empty [`RawDocumentBuf`]. pub fn new() -> RawDocumentBuf { let mut data = Vec::new(); data.extend(MIN_BSON_DOCUMENT_SIZE.to_le_bytes()); data.push(0); Self { data } } /// Constructs a new [`RawDocumentBuf`], validating _only_ the /// following invariants: /// * `data` is at least five bytes long (the minimum for a valid BSON document) /// * the initial four bytes of `data` accurately represent the length of the bytes as /// required by the BSON spec. /// * the last byte of `data` is a 0 /// /// Note that the internal structure of the bytes representing the /// BSON elements is _not_ validated at all by this method. If the /// bytes do not conform to the BSON spec, then method calls on /// the RawDocument will return Errors where appropriate. /// /// ``` /// # use bson::raw::{RawDocumentBuf, Error}; /// let doc = RawDocumentBuf::from_bytes(b"\x05\0\0\0\0".to_vec())?; /// # Ok::<(), Error>(()) /// ``` pub fn from_bytes(data: Vec) -> Result { let _ = RawDocument::from_bytes(data.as_slice())?; Ok(Self { data }) } /// Create a [`RawDocumentBuf`] from a [`Document`]. /// /// ``` /// # use bson::raw::Error; /// use bson::{doc, oid::ObjectId, raw::RawDocumentBuf}; /// /// let document = doc! { /// "_id": ObjectId::new(), /// "name": "Herman Melville", /// "title": "Moby-Dick", /// }; /// let doc = RawDocumentBuf::from_document(&document)?; /// # Ok::<(), Error>(()) /// ``` pub fn from_document(doc: &Document) -> Result { let mut data = Vec::new(); doc.to_writer(&mut data).map_err(|e| Error { key: None, kind: ErrorKind::MalformedValue { message: e.to_string(), }, })?; Ok(Self { data }) } /// Gets an iterator over the elements in the [`RawDocumentBuf`], which yields /// `Result<(&str, RawBson<'_>)>`. /// /// ``` /// # use bson::raw::Error; /// use bson::{doc, raw::RawDocumentBuf}; /// /// let doc = RawDocumentBuf::from_document(&doc! { "ferris": true })?; /// /// for element in doc.iter() { /// let (key, value) = element?; /// assert_eq!(key, "ferris"); /// assert_eq!(value.as_bool(), Some(true)); /// } /// # Ok::<(), Error>(()) /// ``` /// /// # Note: /// /// There is no owning iterator for [`RawDocumentBuf`]. If you need ownership over /// elements that might need to allocate, you must explicitly convert /// them to owned types yourself. pub fn iter(&self) -> Iter<'_> { Iter::new(self) } /// Gets an iterator over the elements in the [`RawDocumentBuf`], /// which yields `Result>` values. These hold a /// reference to the underlying document but do not explicitly /// resolve the values. /// /// This iterator, which underpins the implementation of the /// default iterator, produces `RawElement` objects that hold a /// view onto the document but do not parse out or construct /// values until the `.value()` or `.try_into()` methods are /// called. /// /// # Note: /// /// There is no owning iterator for [`RawDocumentBuf`]. If you /// need ownership over elements that might need to allocate, you /// must explicitly convert them to owned types yourself. pub fn iter_elements(&self) -> RawIter<'_> { RawIter::new(self) } /// Return the contained data as a `Vec` /// /// ``` /// # use bson::raw::Error; /// use bson::{doc, raw::RawDocumentBuf}; /// /// let doc = RawDocumentBuf::from_document(&doc!{})?; /// assert_eq!(doc.into_bytes(), b"\x05\x00\x00\x00\x00".to_vec()); /// # Ok::<(), Error>(()) /// ``` pub fn into_bytes(self) -> Vec { self.data } /// Append a key value pair to the end of the document without checking to see if /// the key already exists. /// /// It is a user error to append the same key more than once to the same document, and it may /// result in errors when communicating with MongoDB. /// /// If the provided key contains an interior null byte, this method will panic. /// /// ``` /// # use bson::raw::Error; /// use bson::{doc, raw::RawDocumentBuf}; /// /// let mut doc = RawDocumentBuf::new(); /// doc.append("a string", "some string"); /// doc.append("an integer", 12_i32); /// /// let mut subdoc = RawDocumentBuf::new(); /// subdoc.append("a key", true); /// doc.append("a document", subdoc); /// /// let expected = doc! { /// "a string": "some string", /// "an integer": 12_i32, /// "a document": { "a key": true }, /// }; /// /// assert_eq!(doc.to_document()?, expected); /// # Ok::<(), Error>(()) /// ``` pub fn append(&mut self, key: impl AsRef, value: impl Into) { let value = value.into(); self.append_ref(key, value.as_raw_bson_ref()) } /// Append a key value pair to the end of the document without checking to see if /// the key already exists. /// /// It is a user error to append the same key more than once to the same document, and it may /// result in errors when communicating with MongoDB. /// /// If the provided key contains an interior null byte, this method will panic. pub fn append_ref<'a>(&mut self, key: impl AsRef, value: impl Into>) { fn append_string(doc: &mut RawDocumentBuf, value: &str) { doc.data .extend(((value.as_bytes().len() + 1) as i32).to_le_bytes()); doc.data.extend(value.as_bytes()); doc.data.push(0); } fn append_cstring(doc: &mut RawDocumentBuf, value: &str) { if value.contains('\0') { panic!("cstr includes interior null byte: {}", value) } doc.data.extend(value.as_bytes()); doc.data.push(0); } let original_len = self.data.len(); // write the key for the next value to the end // the element type will replace the previous null byte terminator of the document append_cstring(self, key.as_ref()); let value = value.into(); let element_type = value.element_type(); match value { RawBsonRef::Int32(i) => { self.data.extend(i.to_le_bytes()); } RawBsonRef::String(s) => { append_string(self, s); } RawBsonRef::Document(d) => { self.data.extend(d.as_bytes()); } RawBsonRef::Array(a) => { self.data.extend(a.as_bytes()); } RawBsonRef::Binary(b) => { let len = b.len(); self.data.extend(len.to_le_bytes()); self.data.push(b.subtype.into()); if let BinarySubtype::BinaryOld = b.subtype { self.data.extend((len - 4).to_le_bytes()) } self.data.extend(b.bytes); } RawBsonRef::Boolean(b) => { self.data.push(b as u8); } RawBsonRef::DateTime(dt) => { self.data.extend(dt.timestamp_millis().to_le_bytes()); } RawBsonRef::DbPointer(dbp) => { append_string(self, dbp.namespace); self.data.extend(dbp.id.bytes()); } RawBsonRef::Decimal128(d) => { self.data.extend(d.bytes()); } RawBsonRef::Double(d) => { self.data.extend(d.to_le_bytes()); } RawBsonRef::Int64(i) => { self.data.extend(i.to_le_bytes()); } RawBsonRef::RegularExpression(re) => { append_cstring(self, re.pattern); append_cstring(self, re.options); } RawBsonRef::JavaScriptCode(js) => { append_string(self, js); } RawBsonRef::JavaScriptCodeWithScope(code_w_scope) => { let len = code_w_scope.len(); self.data.extend(len.to_le_bytes()); append_string(self, code_w_scope.code); self.data.extend(code_w_scope.scope.as_bytes()); } RawBsonRef::Timestamp(ts) => { self.data.extend(ts.to_le_bytes()); } RawBsonRef::ObjectId(oid) => { self.data.extend(oid.bytes()); } RawBsonRef::Symbol(s) => { append_string(self, s); } RawBsonRef::Null | RawBsonRef::Undefined | RawBsonRef::MinKey | RawBsonRef::MaxKey => {} } // update element type self.data[original_len - 1] = element_type as u8; // append trailing null byte self.data.push(0); // update length let new_len = (self.data.len() as i32).to_le_bytes(); self.data[0..4].copy_from_slice(&new_len); } /// Convert this [`RawDocumentBuf`] to a [`Document`], returning an error /// if invalid BSON is encountered. pub fn to_document(&self) -> Result { self.as_ref().try_into() } } impl Default for RawDocumentBuf { fn default() -> Self { Self::new() } } impl<'de> Deserialize<'de> for RawDocumentBuf { fn deserialize(deserializer: D) -> std::result::Result where D: serde::Deserializer<'de>, { Ok(OwnedOrBorrowedRawDocument::deserialize(deserializer)?.into_owned()) } } impl Serialize for RawDocumentBuf { fn serialize(&self, serializer: S) -> std::result::Result where S: serde::Serializer, { let doc: &RawDocument = self.deref(); doc.serialize(serializer) } } impl std::fmt::Debug for RawDocumentBuf { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("RawDocumentBuf") .field("data", &hex::encode(&self.data)) .finish() } } impl<'a> From for Cow<'a, RawDocument> { fn from(rd: RawDocumentBuf) -> Self { Cow::Owned(rd) } } impl<'a> From<&'a RawDocumentBuf> for Cow<'a, RawDocument> { fn from(rd: &'a RawDocumentBuf) -> Self { Cow::Borrowed(rd.as_ref()) } } impl TryFrom for Document { type Error = Error; fn try_from(raw: RawDocumentBuf) -> Result { Document::try_from(raw.as_ref()) } } impl TryFrom<&Document> for RawDocumentBuf { type Error = Error; fn try_from(doc: &Document) -> Result { RawDocumentBuf::from_document(doc) } } impl<'a> IntoIterator for &'a RawDocumentBuf { type IntoIter = Iter<'a>; type Item = Result<(&'a str, RawBsonRef<'a>)>; fn into_iter(self) -> Iter<'a> { self.iter() } } impl AsRef for RawDocumentBuf { fn as_ref(&self) -> &RawDocument { RawDocument::new_unchecked(&self.data) } } impl Deref for RawDocumentBuf { type Target = RawDocument; fn deref(&self) -> &Self::Target { RawDocument::new_unchecked(&self.data) } } impl Borrow for RawDocumentBuf { fn borrow(&self) -> &RawDocument { self.deref() } } impl, T: Into> FromIterator<(S, T)> for RawDocumentBuf { fn from_iter>(iter: I) -> Self { let mut buf = RawDocumentBuf::new(); for (k, v) in iter { buf.append(k, v); } buf } } bson-2.10.0/src/raw/error.rs000064400000000000000000000104241046102023000137250ustar 00000000000000use std::str::Utf8Error; use crate::spec::ElementType; /// An error that occurs when attempting to parse raw BSON bytes. #[derive(Debug, PartialEq, Clone)] #[non_exhaustive] pub struct Error { /// The type of error that was encountered. pub kind: ErrorKind, /// They key associated with the error, if any. pub(crate) key: Option, } impl Error { pub(crate) fn new_with_key(key: impl Into, kind: ErrorKind) -> Self { Self { kind, key: Some(key.into()), } } pub(crate) fn new_without_key(kind: ErrorKind) -> Self { Self { key: None, kind } } pub(crate) fn with_key(mut self, key: impl AsRef) -> Self { self.key = Some(key.as_ref().to_string()); self } /// The key at which the error was encountered, if any. pub fn key(&self) -> Option<&str> { self.key.as_deref() } } /// The different categories of errors that can be returned when reading from raw BSON. #[derive(Clone, Debug, PartialEq)] #[non_exhaustive] pub enum ErrorKind { /// A BSON value did not fit the proper format. #[non_exhaustive] MalformedValue { message: String }, /// Improper UTF-8 bytes were found when proper UTF-8 was expected. Utf8EncodingError(Utf8Error), } impl ErrorKind { pub(crate) fn new_malformed(e: impl ToString) -> Self { ErrorKind::MalformedValue { message: e.to_string(), } } } impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let p = self .key .as_ref() .map(|k| format!("error at key \"{}\": ", k)); let prefix = p.as_ref().map_or("", |p| p.as_str()); match &self.kind { ErrorKind::MalformedValue { message } => { write!(f, "{}malformed value: {:?}", prefix, message) } ErrorKind::Utf8EncodingError(e) => write!(f, "{}utf-8 encoding error: {}", prefix, e), } } } impl std::error::Error for Error {} pub type Result = std::result::Result; /// Execute the provided closure, mapping the key of the returned error (if any) to the provided /// key. pub(crate) fn try_with_key Result>(key: impl AsRef, f: F) -> Result { f().map_err(|e| e.with_key(key)) } pub type ValueAccessResult = std::result::Result; /// Error to indicate that either a value was empty or it contained an unexpected /// type, for use with the direct getters (e.g. [`crate::RawDocument::get_str`]). #[derive(Debug, PartialEq, Clone)] #[non_exhaustive] pub struct ValueAccessError { /// The type of error that was encountered. pub kind: ValueAccessErrorKind, /// The key at which the error was encountered. pub(crate) key: String, } impl ValueAccessError { /// The key at which the error was encountered. pub fn key(&self) -> &str { self.key.as_str() } } /// The type of error encountered when using a direct getter (e.g. [`crate::RawDocument::get_str`]). #[derive(Debug, PartialEq, Clone)] #[non_exhaustive] pub enum ValueAccessErrorKind { /// Cannot find the expected field with the specified key NotPresent, /// Found a Bson value with the specified key, but not with the expected type #[non_exhaustive] UnexpectedType { /// The type that was expected. expected: ElementType, /// The actual type that was encountered. actual: ElementType, }, /// An error was encountered attempting to decode the document. InvalidBson(super::Error), } impl std::fmt::Display for ValueAccessError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let prefix = format!("error at key: \"{}\": ", self.key); match &self.kind { ValueAccessErrorKind::UnexpectedType { actual, expected } => write!( f, "{} unexpected element type: {:?}, expected: {:?}", prefix, actual, expected ), ValueAccessErrorKind::InvalidBson(error) => { write!(f, "{}: {}", prefix, error) } ValueAccessErrorKind::NotPresent => write!(f, "{}value not present", prefix), } } } impl std::error::Error for ValueAccessError {} bson-2.10.0/src/raw/iter.rs000064400000000000000000000321711046102023000135420ustar 00000000000000use std::convert::TryInto; use crate::{ de::{read_bool, MIN_BSON_DOCUMENT_SIZE, MIN_CODE_WITH_SCOPE_SIZE}, oid::ObjectId, raw::{Error, ErrorKind, Result}, spec::{BinarySubtype, ElementType}, Bson, DateTime, Decimal128, RawArray, RawBinaryRef, RawBson, RawDbPointerRef, RawJavaScriptCodeWithScopeRef, RawRegexRef, Timestamp, }; use super::{ checked_add, error::try_with_key, f64_from_slice, i32_from_slice, i64_from_slice, read_len, read_lenencode, try_to_str, RawBsonRef, RawDocument, }; /// An iterator over the document's entries. pub struct Iter<'a> { inner: RawIter<'a>, } impl<'a> Iter<'a> { pub(crate) fn new(doc: &'a RawDocument) -> Self { Iter { inner: RawIter::new(doc), } } } impl<'a> Iterator for Iter<'a> { type Item = Result<(&'a str, RawBsonRef<'a>)>; fn next(&mut self) -> Option)>> { match self.inner.next() { Some(Ok(elem)) => match elem.value() { Err(e) => Some(Err(e)), Ok(value) => Some(Ok((elem.key, value))), }, Some(Err(e)) => Some(Err(e)), None => None, } } } /// An iterator over the document's elements. pub struct RawIter<'a> { doc: &'a RawDocument, offset: usize, /// Whether the underlying doc is assumed to be valid or if an error has been encountered. /// After an error, all subsequent iterations will return None. valid: bool, } impl<'a> RawIter<'a> { pub(crate) fn new(doc: &'a RawDocument) -> Self { Self { doc, offset: 4, valid: true, } } fn verify_enough_bytes(&self, start: usize, num_bytes: usize) -> Result<()> { let end = checked_add(start, num_bytes)?; if self.doc.as_bytes().get(start..end).is_none() { return Err(Error::new_without_key(ErrorKind::new_malformed(format!( "length exceeds remaining length of buffer: {} vs {}", num_bytes, self.doc.as_bytes().len() - start )))); } Ok(()) } fn next_document_len(&self, starting_at: usize) -> Result { self.verify_enough_bytes(starting_at, MIN_BSON_DOCUMENT_SIZE as usize)?; let size = i32_from_slice(&self.doc.as_bytes()[starting_at..])? as usize; if size < MIN_BSON_DOCUMENT_SIZE as usize { return Err(Error::new_without_key(ErrorKind::new_malformed(format!( "document too small: {} bytes", size )))); } self.verify_enough_bytes(starting_at, size)?; if self.doc.as_bytes()[starting_at + size - 1] != 0 { return Err(Error::new_without_key(ErrorKind::new_malformed( "not null terminated", ))); } Ok(size) } } #[derive(Clone)] pub struct RawElement<'a> { key: &'a str, kind: ElementType, doc: &'a RawDocument, start_at: usize, size: usize, } impl<'a> TryInto> for RawElement<'a> { type Error = Error; fn try_into(self) -> Result> { self.value() } } impl<'a> TryInto for RawElement<'a> { type Error = Error; fn try_into(self) -> Result { Ok(self.value()?.to_raw_bson()) } } impl<'a> TryInto for RawElement<'a> { type Error = Error; fn try_into(self) -> Result { self.value()?.to_raw_bson().try_into() } } #[allow(clippy::len_without_is_empty)] impl<'a> RawElement<'a> { pub fn len(&self) -> usize { self.size } pub fn key(&self) -> &str { self.key } pub fn element_type(&self) -> ElementType { self.kind } pub fn value(&self) -> Result> { Ok(match self.kind { ElementType::Null => RawBsonRef::Null, ElementType::Undefined => RawBsonRef::Undefined, ElementType::MinKey => RawBsonRef::MinKey, ElementType::MaxKey => RawBsonRef::MaxKey, ElementType::ObjectId => RawBsonRef::ObjectId(self.get_oid_at(self.start_at)?), ElementType::Int32 => RawBsonRef::Int32(i32_from_slice(self.slice())?), ElementType::Int64 => RawBsonRef::Int64(i64_from_slice(self.slice())?), ElementType::Double => RawBsonRef::Double(f64_from_slice(self.slice())?), ElementType::String => RawBsonRef::String(self.read_str()?), ElementType::EmbeddedDocument => { RawBsonRef::Document(RawDocument::from_bytes(self.slice())?) } ElementType::Array => { RawBsonRef::Array(RawArray::from_doc(RawDocument::from_bytes(self.slice())?)) } ElementType::Boolean => { RawBsonRef::Boolean(read_bool(self.slice()).map_err(|e| self.malformed_error(e))?) } ElementType::DateTime => { RawBsonRef::DateTime(DateTime::from_millis(i64_from_slice(self.slice())?)) } ElementType::Decimal128 => RawBsonRef::Decimal128(Decimal128::from_bytes( self.slice() .try_into() .map_err(|e| self.malformed_error(e))?, )), ElementType::JavaScriptCode => RawBsonRef::JavaScriptCode(self.read_str()?), ElementType::Symbol => RawBsonRef::Symbol(self.read_str()?), ElementType::DbPointer => RawBsonRef::DbPointer(RawDbPointerRef { namespace: read_lenencode(self.slice())?, id: self.get_oid_at(self.start_at + (self.size - 12))?, }), ElementType::RegularExpression => { let pattern = self.doc.read_cstring_at(self.start_at)?; RawBsonRef::RegularExpression(RawRegexRef { pattern, options: self .doc .read_cstring_at(self.start_at + pattern.len() + 1)?, }) } ElementType::Timestamp => RawBsonRef::Timestamp( Timestamp::from_reader(self.slice()).map_err(|e| self.malformed_error(e))?, ), ElementType::Binary => { let len = self.size.checked_sub(4 + 1).ok_or_else(|| { self.malformed_error(format!("length exceeds maximum: {}", self.size)) })?; let data_start = self.start_at + 4 + 1; if self.size >= i32::MAX as usize { return Err( self.malformed_error(format!("binary length exceeds maximum: {}", len)) ); } let subtype = BinarySubtype::from(self.doc.as_bytes()[self.start_at + 4]); let data = match subtype { BinarySubtype::BinaryOld => { if len < 4 { return Err(self.malformed_error( "old binary subtype has no inner declared length", )); } let oldlength = i32_from_slice(&self.doc.as_bytes()[data_start..])? as usize; if checked_add(oldlength, 4)? != len { return Err(self.malformed_error( "old binary subtype has wrong inner declared length", )); } self.slice_bounds(data_start + 4, len - 4) } _ => self.slice_bounds(data_start, len), }; RawBsonRef::Binary(RawBinaryRef { subtype, bytes: data, }) } ElementType::JavaScriptCodeWithScope => { if self.size < MIN_CODE_WITH_SCOPE_SIZE as usize { return Err(self.malformed_error("code with scope length too small")); } let slice = self.slice(); let code = read_lenencode(&slice[4..])?; let scope_start = 4 + 4 + code.len() + 1; let scope = RawDocument::from_bytes(&slice[scope_start..])?; RawBsonRef::JavaScriptCodeWithScope(RawJavaScriptCodeWithScopeRef { code, scope }) } }) } fn malformed_error(&self, e: impl ToString) -> Error { Error::new_with_key(self.key, ErrorKind::new_malformed(e)) } fn slice(&self) -> &'a [u8] { self.slice_bounds(self.start_at, self.size) } fn slice_bounds(&self, start_at: usize, size: usize) -> &'a [u8] { &self.doc.as_bytes()[start_at..(start_at + size)] } fn read_str(&self) -> Result<&'a str> { try_to_str(self.slice_bounds(self.start_at + 4, self.size - 4 - 1)) } fn get_oid_at(&self, start_at: usize) -> Result { Ok(ObjectId::from_bytes( self.doc.as_bytes()[start_at..(start_at + 12)] .try_into() .map_err(|e| Error::new_with_key(self.key, ErrorKind::new_malformed(e)))?, )) } } impl<'a> RawIter<'a> { fn get_next_length_at(&self, start_at: usize) -> Result { let len = i32_from_slice(&self.doc.as_bytes()[start_at..])?; if len < 0 { Err(Error::new_without_key(ErrorKind::new_malformed( "lengths can't be negative", ))) } else { Ok(len as usize) } } } impl<'a> Iterator for RawIter<'a> { type Item = Result>; fn next(&mut self) -> Option>> { if !self.valid { return None; } else if self.offset == self.doc.as_bytes().len() - 1 { if self.doc.as_bytes()[self.offset] == 0 { // end of document marker return None; } else { self.valid = false; return Some(Err(Error::new_without_key(ErrorKind::new_malformed( "document not null terminated", )))); } } else if self.offset >= self.doc.as_bytes().len() { self.valid = false; return Some(Err(Error::new_without_key(ErrorKind::new_malformed( "iteration overflowed document", )))); } let key = match self.doc.read_cstring_at(self.offset + 1) { Ok(k) => k, Err(e) => { self.valid = false; return Some(Err(e)); } }; let offset = self.offset + 1 + key.len() + 1; // type specifier + key + \0 let kvp_result = try_with_key(key, || { let element_type = match ElementType::from(self.doc.as_bytes()[self.offset]) { Some(et) => et, None => { return Err(Error::new_with_key( key, ErrorKind::new_malformed(format!( "invalid tag: {}", self.doc.as_bytes()[self.offset] )), )) } }; let element_size = match element_type { ElementType::Boolean => 1, ElementType::Int32 => 4, ElementType::Int64 => 8, ElementType::Double => 8, ElementType::DateTime => 8, ElementType::Timestamp => 8, ElementType::ObjectId => 12, ElementType::Decimal128 => 16, ElementType::Null => 0, ElementType::Undefined => 0, ElementType::MinKey => 0, ElementType::MaxKey => 0, ElementType::String => read_len(&self.doc.as_bytes()[offset..])?, ElementType::EmbeddedDocument => self.next_document_len(offset)?, ElementType::Array => self.next_document_len(offset)?, ElementType::Binary => self.get_next_length_at(offset)? + 4 + 1, ElementType::RegularExpression => { let pattern = self.doc.read_cstring_at(offset)?; let options = self.doc.read_cstring_at(offset + pattern.len() + 1)?; pattern.len() + 1 + options.len() + 1 } ElementType::DbPointer => read_len(&self.doc.as_bytes()[offset..])? + 12, ElementType::Symbol => read_len(&self.doc.as_bytes()[offset..])?, ElementType::JavaScriptCode => read_len(&self.doc.as_bytes()[offset..])?, ElementType::JavaScriptCodeWithScope => self.get_next_length_at(offset)?, }; self.verify_enough_bytes(offset, element_size)?; self.offset = offset + element_size; Ok((element_type, element_size)) }); if kvp_result.is_err() { self.valid = false; } Some(match kvp_result { Ok((kind, size)) => Ok(RawElement { key, kind, doc: self.doc, start_at: offset, size, }), Err(e) => Err(e), }) } } bson-2.10.0/src/raw/mod.rs000064400000000000000000000204501046102023000133530ustar 00000000000000//! An API for interacting with raw BSON bytes. //! //! This module provides two document types, [`RawDocumentBuf`] and [`RawDocument`] (akin to //! [`std::string::String`] and [`str`]), for working with raw BSON documents. These types differ //! from the regular [`crate::Document`] type in that their storage is BSON bytes rather than a //! hash-map like Rust type. In certain circumstances, these types can be leveraged for increased //! performance. //! //! This module also provides a [`RawBson`] type for modeling any borrowed BSON element and a //! [`RawArray`] type for modeling a borrowed slice of a document containing a BSON array element. //! //! A [`RawDocumentBuf`] can be created from a `Vec` containing raw BSON data. A //! [`RawDocument`] can be created from anything that can be borrowed as a `&[u8]`. Both types //! can access elements via methods similar to those available on the [`crate::Document`] type. //! Note that [`RawDocument::get`] (which [`RawDocument`] calls through to via its //! [`Deref`](std::ops::Deref) implementation) returns a [`Result`], since the bytes contained in //! the document are not fully validated until trying to access the contained data. //! //! ```rust //! use bson::raw::{ //! RawBson, //! RawDocumentBuf, //! }; //! //! // See http://bsonspec.org/spec.html for details on the binary encoding of BSON. //! let doc = RawDocumentBuf::from_bytes(b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00".to_vec())?; //! let elem = doc.get("hi")?.unwrap(); //! //! assert_eq!( //! elem.as_str(), //! Some("y'all"), //! ); //! # Ok::<(), bson::raw::Error>(()) //! ``` //! //! ### [`crate::Document`] interop //! //! A [`RawDocument`] can be created from a [`crate::Document`]. Internally, this //! serializes the [`crate::Document`] to a `Vec`, and then includes those bytes in the //! [`RawDocument`]. //! //! ```rust //! use bson::{ //! raw::RawDocumentBuf, //! doc, //! }; //! //! let document = doc! { //! "goodbye": { //! "cruel": "world" //! } //! }; //! //! let raw = RawDocumentBuf::from_document(&document)?; //! let value = raw //! .get_document("goodbye")? //! .get_str("cruel")?; //! //! assert_eq!( //! value, //! "world", //! ); //! # Ok::<(), Box>(()) //! ``` //! //! ### Reference type ([`RawDocument`]) //! //! A BSON document can also be accessed with the [`RawDocument`] type, which is an //! unsized type that represents the BSON payload as a `[u8]`. This allows accessing nested //! documents without reallocation. [`RawDocument`] must always be accessed via a pointer type, //! similar to `[T]` and `str`. //! //! The below example constructs a bson document in a stack-based array, //! and extracts a `&str` from it, performing no heap allocation. //! ```rust //! use bson::raw::RawDocument; //! //! let bytes = b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00"; //! assert_eq!(RawDocument::from_bytes(bytes)?.get_str("hi")?, "y'all"); //! # Ok::<(), Box>(()) //! ``` //! //! ### Iteration //! //! [`RawDocument`] implements [`IntoIterator`], which can also be //! accessed via [`RawDocumentBuf::iter`]. //! ```rust //! use bson::{ //! raw::{ //! RawBsonRef, //! RawDocumentBuf, //! }, //! doc, //! }; //! //! let original_doc = doc! { //! "crate": "bson", //! "year": "2021", //! }; //! //! let doc = RawDocumentBuf::from_document(&original_doc)?; //! let mut doc_iter = doc.iter(); //! //! let (key, value): (&str, RawBsonRef) = doc_iter.next().unwrap()?; //! assert_eq!(key, "crate"); //! assert_eq!(value.as_str(), Some("bson")); //! //! let (key, value): (&str, RawBsonRef) = doc_iter.next().unwrap()?; //! assert_eq!(key, "year"); //! assert_eq!(value.as_str(), Some("2021")); //! # Ok::<(), bson::raw::Error>(()) //! ``` mod array; mod array_buf; mod bson; mod bson_ref; mod document; mod document_buf; mod error; mod iter; pub(crate) mod serde; #[cfg(test)] mod test; use std::convert::{TryFrom, TryInto}; use crate::de::MIN_BSON_STRING_SIZE; pub use self::{ array::{RawArray, RawArrayIter}, array_buf::RawArrayBuf, bson::{RawBson, RawJavaScriptCodeWithScope}, bson_ref::{ RawBinaryRef, RawBsonRef, RawDbPointerRef, RawJavaScriptCodeWithScopeRef, RawRegexRef, }, document::RawDocument, document_buf::RawDocumentBuf, error::{Error, ErrorKind, Result, ValueAccessError, ValueAccessErrorKind, ValueAccessResult}, iter::{RawElement, RawIter}, }; /// Special newtype name indicating that the type being (de)serialized is a raw BSON document. pub(crate) const RAW_DOCUMENT_NEWTYPE: &str = "$__private__bson_RawDocument"; /// Special newtype name indicating that the type being (de)serialized is a raw BSON array. pub(crate) const RAW_ARRAY_NEWTYPE: &str = "$__private__bson_RawArray"; /// Special newtype name indicating that the type being (de)serialized is a raw BSON value. pub(crate) const RAW_BSON_NEWTYPE: &str = "$__private__bson_RawBson"; /// Given a u8 slice, return an i32 calculated from the first four bytes in /// little endian order. fn f64_from_slice(val: &[u8]) -> Result { let arr = val .get(0..8) .and_then(|s| s.try_into().ok()) .ok_or_else(|| { Error::new_without_key(ErrorKind::MalformedValue { message: format!("expected 8 bytes to read double, instead got {}", val.len()), }) })?; Ok(f64::from_le_bytes(arr)) } /// Given a u8 slice, return an i32 calculated from the first four bytes in /// little endian order. fn i32_from_slice(val: &[u8]) -> Result { let arr: [u8; 4] = val .get(0..4) .and_then(|s| s.try_into().ok()) .ok_or_else(|| { Error::new_without_key(ErrorKind::MalformedValue { message: format!("expected 4 bytes to read i32, instead got {}", val.len()), }) })?; Ok(i32::from_le_bytes(arr)) } /// Given an u8 slice, return an i64 calculated from the first 8 bytes in /// little endian order. fn i64_from_slice(val: &[u8]) -> Result { let arr = val .get(0..8) .and_then(|s| s.try_into().ok()) .ok_or_else(|| { Error::new_without_key(ErrorKind::MalformedValue { message: format!("expected 8 bytes to read i64, instead got {}", val.len()), }) })?; Ok(i64::from_le_bytes(arr)) } fn read_len(buf: &[u8]) -> Result { if buf.len() < 4 { return Err(Error::new_without_key(ErrorKind::MalformedValue { message: format!( "expected buffer with string to contain at least 4 bytes, but it only has {}", buf.len() ), })); } let length = i32_from_slice(&buf[..4])?; let end = checked_add(usize_try_from_i32(length)?, 4)?; if end < MIN_BSON_STRING_SIZE as usize { return Err(Error::new_without_key(ErrorKind::MalformedValue { message: format!( "BSON length encoded string needs to be at least {} bytes, instead got {}", MIN_BSON_STRING_SIZE, end ), })); } if buf.len() < end { return Err(Error::new_without_key(ErrorKind::MalformedValue { message: format!( "expected buffer to contain at least {} bytes, but it only has {}", end, buf.len() ), })); } if buf[end - 1] != 0 { return Err(Error::new_without_key(ErrorKind::MalformedValue { message: "expected string to be null-terminated".to_string(), })); } Ok(length as usize + 4) } fn read_lenencode(buf: &[u8]) -> Result<&str> { let end = read_len(buf)?; // exclude length-prefix and null byte suffix try_to_str(&buf[4..(end - 1)]) } fn try_to_str(data: &[u8]) -> Result<&str> { std::str::from_utf8(data).map_err(|e| Error::new_without_key(ErrorKind::Utf8EncodingError(e))) } fn usize_try_from_i32(i: i32) -> Result { usize::try_from(i).map_err(|e| { Error::new_without_key(ErrorKind::MalformedValue { message: e.to_string(), }) }) } fn checked_add(lhs: usize, rhs: usize) -> Result { lhs.checked_add(rhs).ok_or_else(|| { Error::new_without_key(ErrorKind::MalformedValue { message: "attempted to add with overflow".to_string(), }) }) } bson-2.10.0/src/raw/serde/bson_visitor.rs000064400000000000000000000262431046102023000164240ustar 00000000000000use std::{borrow::Cow, convert::TryFrom}; use serde::de::{Error as SerdeError, Visitor}; use serde_bytes::ByteBuf; use crate::{ de::convert_unsigned_to_signed_raw, extjson::models::{ BorrowedBinaryBody, BorrowedDbPointerBody, BorrowedRegexBody, TimestampBody, }, oid::ObjectId, raw::{RAW_ARRAY_NEWTYPE, RAW_DOCUMENT_NEWTYPE}, spec::BinarySubtype, Binary, DateTime, DbPointer, Decimal128, RawArray, RawArrayBuf, RawBinaryRef, RawBson, RawBsonRef, RawDbPointerRef, RawDocument, RawDocumentBuf, RawJavaScriptCodeWithScope, RawJavaScriptCodeWithScopeRef, RawRegexRef, Regex, Timestamp, }; use super::{ CowByteBuffer, CowStr, OwnedOrBorrowedRawBson, OwnedOrBorrowedRawDocument, SeededVisitor, }; /// A visitor used to deserialize types backed by raw BSON. pub(crate) struct OwnedOrBorrowedRawBsonVisitor; impl<'de> Visitor<'de> for OwnedOrBorrowedRawBsonVisitor { type Value = OwnedOrBorrowedRawBson<'de>; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { write!(formatter, "a raw BSON value") } fn visit_borrowed_str(self, v: &'de str) -> Result where E: SerdeError, { Ok(RawBsonRef::String(v).into()) } fn visit_str(self, v: &str) -> Result where E: SerdeError, { Ok(RawBson::String(v.to_string()).into()) } fn visit_string(self, v: String) -> Result where E: SerdeError, { Ok(RawBson::String(v).into()) } fn visit_borrowed_bytes(self, bytes: &'de [u8]) -> Result where E: SerdeError, { Ok(RawBsonRef::Binary(RawBinaryRef { bytes, subtype: BinarySubtype::Generic, }) .into()) } fn visit_i8(self, v: i8) -> Result where E: SerdeError, { Ok(RawBsonRef::Int32(v.into()).into()) } fn visit_i16(self, v: i16) -> Result where E: SerdeError, { Ok(RawBsonRef::Int32(v.into()).into()) } fn visit_i32(self, v: i32) -> Result where E: SerdeError, { Ok(RawBsonRef::Int32(v).into()) } fn visit_i64(self, v: i64) -> Result where E: SerdeError, { Ok(RawBsonRef::Int64(v).into()) } fn visit_u8(self, value: u8) -> Result where E: SerdeError, { Ok(convert_unsigned_to_signed_raw(value.into())?.into()) } fn visit_u16(self, value: u16) -> Result where E: SerdeError, { Ok(convert_unsigned_to_signed_raw(value.into())?.into()) } fn visit_u32(self, value: u32) -> Result where E: SerdeError, { Ok(convert_unsigned_to_signed_raw(value.into())?.into()) } fn visit_u64(self, value: u64) -> Result where E: SerdeError, { Ok(convert_unsigned_to_signed_raw(value)?.into()) } fn visit_bool(self, v: bool) -> Result where E: SerdeError, { Ok(RawBsonRef::Boolean(v).into()) } fn visit_f64(self, v: f64) -> Result where E: SerdeError, { Ok(RawBsonRef::Double(v).into()) } fn visit_none(self) -> Result where E: SerdeError, { Ok(RawBsonRef::Null.into()) } fn visit_unit(self) -> Result where E: SerdeError, { Ok(RawBsonRef::Null.into()) } fn visit_newtype_struct(self, deserializer: D) -> Result where D: serde::Deserializer<'de>, { deserializer.deserialize_any(self) } fn visit_byte_buf(self, v: Vec) -> Result where E: SerdeError, { Ok(RawBson::Binary(Binary { bytes: v, subtype: BinarySubtype::Generic, }) .into()) } fn visit_seq(self, seq: A) -> Result where A: serde::de::SeqAccess<'de>, { let mut buffer = CowByteBuffer::new(); let seeded_visitor = SeededVisitor::new(&mut buffer); seeded_visitor.visit_seq(seq)?; match OwnedOrBorrowedRawDocument::try_from(buffer).map_err(SerdeError::custom)? { OwnedOrBorrowedRawDocument::Borrowed(borrowed) => { let raw_array = RawArray::from_doc(borrowed); Ok(RawBsonRef::Array(raw_array).into()) } OwnedOrBorrowedRawDocument::Owned(owned) => { let raw_array = RawArrayBuf::from_raw_document_buf(owned); Ok(RawBson::Array(raw_array).into()) } } } fn visit_map(self, mut map: A) -> Result where A: serde::de::MapAccess<'de>, { let first_key = match map.next_key::()? { Some(k) => k, None => return Ok(RawBson::Document(RawDocumentBuf::new()).into()), }; match first_key.0.as_ref() { "$oid" => { let oid: ObjectId = map.next_value()?; Ok(RawBsonRef::ObjectId(oid).into()) } "$symbol" => { let s: CowStr = map.next_value()?; match s.0 { Cow::Borrowed(s) => Ok(RawBsonRef::Symbol(s).into()), Cow::Owned(s) => Ok(RawBson::Symbol(s).into()), } } "$numberDecimalBytes" => { let bytes: ByteBuf = map.next_value()?; return Ok(RawBsonRef::Decimal128(Decimal128::deserialize_from_slice( bytes.as_ref(), )?) .into()); } "$regularExpression" => { let body: BorrowedRegexBody = map.next_value()?; match (body.pattern, body.options) { (Cow::Borrowed(p), Cow::Borrowed(o)) => { Ok(RawBsonRef::RegularExpression(RawRegexRef { pattern: p, options: o, }) .into()) } (p, o) => Ok(RawBson::RegularExpression(Regex { pattern: p.into_owned(), options: o.into_owned(), }) .into()), } } "$undefined" => { let _: bool = map.next_value()?; Ok(RawBsonRef::Undefined.into()) } "$binary" => { let v: BorrowedBinaryBody = map.next_value()?; if let Cow::Borrowed(bytes) = v.bytes { Ok(RawBsonRef::Binary(RawBinaryRef { bytes, subtype: v.subtype.into(), }) .into()) } else { Ok(RawBson::Binary(Binary { bytes: v.bytes.into_owned(), subtype: v.subtype.into(), }) .into()) } } "$date" => { let date: i64 = map.next_value()?; Ok(RawBsonRef::DateTime(DateTime::from_millis(date)).into()) } "$timestamp" => { let timestamp: TimestampBody = map.next_value()?; Ok(RawBsonRef::Timestamp(Timestamp { time: timestamp.t, increment: timestamp.i, }) .into()) } "$minKey" => { let _ = map.next_value::()?; Ok(RawBsonRef::MinKey.into()) } "$maxKey" => { let _ = map.next_value::()?; Ok(RawBsonRef::MaxKey.into()) } "$code" => { let code = map.next_value::()?; if let Some(key) = map.next_key::()? { if key.0.as_ref() == "$scope" { let scope = map.next_value::()?; match (code.0, scope) { (Cow::Borrowed(code), OwnedOrBorrowedRawDocument::Borrowed(scope)) => { Ok(RawBsonRef::JavaScriptCodeWithScope( RawJavaScriptCodeWithScopeRef { code, scope }, ) .into()) } (code, scope) => Ok(RawBson::JavaScriptCodeWithScope( RawJavaScriptCodeWithScope { code: code.into_owned(), scope: scope.into_owned(), }, ) .into()), } } else { Err(SerdeError::unknown_field(&key.0, &["$scope"])) } } else if let Cow::Borrowed(code) = code.0 { Ok(RawBsonRef::JavaScriptCode(code).into()) } else { Ok(RawBson::JavaScriptCode(code.0.into_owned()).into()) } } "$dbPointer" => { let db_pointer: BorrowedDbPointerBody = map.next_value()?; if let Cow::Borrowed(ns) = db_pointer.ns.0 { Ok(RawBsonRef::DbPointer(RawDbPointerRef { namespace: ns, id: db_pointer.id, }) .into()) } else { Ok(RawBson::DbPointer(DbPointer { namespace: db_pointer.ns.0.into_owned(), id: db_pointer.id, }) .into()) } } RAW_DOCUMENT_NEWTYPE => { let bson = map.next_value::<&[u8]>()?; let doc = RawDocument::from_bytes(bson).map_err(SerdeError::custom)?; Ok(RawBsonRef::Document(doc).into()) } RAW_ARRAY_NEWTYPE => { let bson = map.next_value::<&[u8]>()?; let doc = RawDocument::from_bytes(bson).map_err(SerdeError::custom)?; Ok(RawBsonRef::Array(RawArray::from_doc(doc)).into()) } _ => { let mut buffer = CowByteBuffer::new(); let seeded_visitor = SeededVisitor::new(&mut buffer); seeded_visitor.iterate_map(first_key, map)?; match OwnedOrBorrowedRawDocument::try_from(buffer).map_err(SerdeError::custom)? { OwnedOrBorrowedRawDocument::Borrowed(borrowed) => { Ok(RawBsonRef::Document(borrowed).into()) } OwnedOrBorrowedRawDocument::Owned(owned) => Ok(RawBson::Document(owned).into()), } } } } } bson-2.10.0/src/raw/serde/seeded_visitor.rs000064400000000000000000000454271046102023000167210ustar 00000000000000use std::{borrow::Cow, convert::TryFrom, fmt::Formatter, ops::Range}; use serde::{ de::{DeserializeSeed, Error as SerdeError, MapAccess, SeqAccess, Visitor}, Deserializer, }; use serde_bytes::ByteBuf; use crate::{ de::MIN_BSON_DOCUMENT_SIZE, extjson::models::{ BorrowedBinaryBody, BorrowedDbPointerBody, BorrowedRegexBody, TimestampBody, }, oid::ObjectId, raw::{RAW_ARRAY_NEWTYPE, RAW_BSON_NEWTYPE, RAW_DOCUMENT_NEWTYPE}, spec::{BinarySubtype, ElementType}, RawDocumentBuf, }; use super::CowStr; /// A copy-on-write byte buffer containing raw BSON bytes. The inner value starts as `None` and /// transitions to either `Cow::Borrowed` or `Cow::Owned` depending upon the data visited. pub(crate) struct CowByteBuffer<'de>(pub(crate) Option>); impl<'de> CowByteBuffer<'de> { /// Creates an new empty buffer. pub(crate) fn new() -> Self { Self(None) } /// The length of the buffer. fn len(&self) -> usize { match &self.0 { Some(buffer) => buffer.len(), None => 0, } } /// Gets a mutable reference to the inner buffer, allocating a `Vec` and transitioning the /// buffer's state as necessary. fn get_owned_buffer(&mut self) -> &mut Vec { self.0 .get_or_insert_with(|| Cow::Owned(Vec::new())) .to_mut() } /// Appends a single byte to the buffer. fn push_byte(&mut self, byte: u8) { let buffer = self.get_owned_buffer(); buffer.push(byte); } /// Appends a slice of bytes to the buffer. fn append_bytes(&mut self, bytes: &[u8]) { let buffer = self.get_owned_buffer(); buffer.extend_from_slice(bytes); } /// Appends a slice of borrowed bytes to the buffer. If the buffer is currently `None`, it will /// store a reference to the borrowed bytes; otherwise, it will copy the bytes to the /// existing buffer. fn append_borrowed_bytes(&mut self, bytes: &'de [u8]) { match &mut self.0 { Some(buffer) => buffer.to_mut().extend_from_slice(bytes), None => self.0 = Some(Cow::Borrowed(bytes)), } } /// Copies a slice of bytes into the given range. This method will panic if the range is out of /// bounds. fn copy_from_slice(&mut self, range: Range, slice: &[u8]) { let buffer = self.get_owned_buffer(); buffer[range].copy_from_slice(slice); } /// Removes the bytes in the given range from the buffer. This method will panic if the range is /// out of bounds. fn drain(&mut self, range: Range) { let buffer = self.get_owned_buffer(); buffer.drain(range); } } pub(crate) struct SeededVisitor<'a, 'de> { buffer: &'a mut CowByteBuffer<'de>, } impl<'a, 'de> DeserializeSeed<'de> for SeededVisitor<'a, 'de> { type Value = ElementType; fn deserialize(self, deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_newtype_struct(RAW_BSON_NEWTYPE, self) } } impl<'a, 'de> DeserializeSeed<'de> for &mut SeededVisitor<'a, 'de> { type Value = ElementType; fn deserialize(self, deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_newtype_struct( RAW_BSON_NEWTYPE, SeededVisitor { buffer: self.buffer, }, ) } } /// A visitor that builds up a raw BSON value in a single buffer. This visitor will only produce /// valid BSON if the value being deserialized is a byte buffer, slice of bytes, map, or sequence. /// Implementations using this visitor should check the `ElementType` returned from `deserialize` to /// validate that a valid BSON type was visited. impl<'a, 'de> SeededVisitor<'a, 'de> { pub(crate) fn new(buffer: &'a mut CowByteBuffer<'de>) -> Self { Self { buffer } } /// Appends a cstring to the buffer. Returns an error if the given string contains a null byte. fn append_cstring(&mut self, key: &str) -> Result<(), String> { let key_bytes = key.as_bytes(); if key_bytes.contains(&0) { return Err(format!("key contains interior null byte: {}", key)); } self.buffer.append_bytes(key_bytes); self.buffer.push_byte(0); Ok(()) } /// Appends a string and its length to the buffer. fn append_string(&mut self, s: &str) { let bytes = s.as_bytes(); // Add 1 to account for null byte. self.append_length_bytes((bytes.len() + 1) as i32); self.buffer.append_bytes(bytes); self.buffer.push_byte(0); } /// Converts the given length into little-endian bytes and appends the bytes to the buffer. fn append_length_bytes(&mut self, length: i32) { self.buffer.append_bytes(&length.to_le_bytes()); } /// Appends an owned byte buffer to the buffer. If the buffer is currently empty (i.e. the byte /// buffer was the top-level value provided to the deserializer), the buffer will be updated to /// contain an owned copy of the bytes provided. Otherwise (i.e. when the value is embedded), /// the bytes and their corresponding length and subtype bytes will be appended to the /// buffer. fn append_owned_binary(&mut self, bytes: Vec, subtype: u8) { match &mut self.buffer.0 { Some(_) => self.append_embedded_binary(&bytes, subtype), None => self.buffer.0 = Some(Cow::Owned(bytes)), } } /// Appends a slice of bytes to the buffer. If the buffer is currently empty (i.e. the byte /// buffer was the top-level value provided to the deserializer), the buffer will be updated to /// contain a reference to the slice of bytes. Otherwise (i.e. when the value is embedded), /// the bytes and their corresponding length and subtype will be appended to the buffer. fn append_borrowed_binary(&mut self, bytes: &'de [u8], subtype: u8) { match &self.buffer.0 { Some(_) => self.append_embedded_binary(bytes, subtype), None => self.buffer.0 = Some(Cow::Borrowed(bytes)), } } /// Appends the given bytes and their corresponding length and subtype to the buffer. fn append_embedded_binary(&mut self, bytes: &[u8], subtype: impl Into) { self.append_length_bytes(bytes.len() as i32); self.buffer.push_byte(subtype.into()); self.buffer.append_bytes(bytes); } /// Appends 1 byte to the buffer as a placeholder for an element type. This byte should be /// overwritten by a call to append_element after the element has been written to the buffer. fn pad_element_type(&mut self) -> usize { let index = self.buffer.len(); self.buffer.push_byte(0); index } /// Writes the given element_type at the given index, which should be obtained from /// pad_element_type. fn write_element_type(&mut self, element_type: ElementType, index: usize) { self.buffer .copy_from_slice(index..index + 1, &[element_type as u8]); } /// Appends 4 bytes to the buffer as a placeholder for the length of a document. These bytes /// should be overwritten by a call to finish_document after the data in the document has been /// written. fn pad_document_length(&mut self) -> usize { let index = self.buffer.len(); self.buffer.append_bytes(&[0; 4]); index } /// Writes the length of a document at the given index, which should be obtained from /// pad_document_length, and appends the final null byte of the document. Returns an error if /// the size does not fit into an i32. fn finish_document(&mut self, length_index: usize) -> Result<(), String> { self.buffer.push_byte(0); let length_bytes = match i32::try_from(self.buffer.len() - length_index) { Ok(length) => length.to_le_bytes(), Err(_) => return Err("value exceeds maximum length".to_string()), }; self.buffer .copy_from_slice(length_index..length_index + 4, &length_bytes); Ok(()) } /// Iterates the given `MapAccess` and appends its keys and values to the buffer. The given map /// must have had `next_key` called exactly once, and the value returned from that call must be /// provided as `first_key`. `next_value` must not have been called on the map. pub(crate) fn iterate_map(mut self, first_key: CowStr, mut map: A) -> Result<(), A::Error> where A: MapAccess<'de>, { let length_index = self.pad_document_length(); let mut current_key = first_key; loop { let element_type_index = self.pad_element_type(); self.append_cstring(current_key.0.as_ref()) .map_err(SerdeError::custom)?; let element_type = map.next_value_seed(&mut self)?; self.write_element_type(element_type, element_type_index); match map.next_key::()? { Some(next_key) => current_key = next_key, None => break, } } self.finish_document(length_index) .map_err(SerdeError::custom)?; Ok(()) } } impl<'a, 'de> Visitor<'de> for SeededVisitor<'a, 'de> { type Value = ElementType; fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { formatter.write_str("a raw BSON value") } fn visit_newtype_struct(self, deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_any(self) } fn visit_map(mut self, mut map: A) -> Result where A: MapAccess<'de>, { let first_key = match map.next_key::()? { Some(key) => key, None => { self.buffer .append_bytes(&MIN_BSON_DOCUMENT_SIZE.to_le_bytes()); self.buffer.push_byte(0); return Ok(ElementType::EmbeddedDocument); } }; match first_key.0.as_ref() { "$oid" => { let oid: ObjectId = map.next_value()?; self.buffer.append_bytes(&oid.bytes()); Ok(ElementType::ObjectId) } "$symbol" => { let s: &str = map.next_value()?; self.append_string(s); Ok(ElementType::Symbol) } "$numberDecimalBytes" => { let bytes: ByteBuf = map.next_value()?; self.buffer.append_bytes(&bytes.into_vec()); Ok(ElementType::Decimal128) } "$regularExpression" => { let regex: BorrowedRegexBody = map.next_value()?; let pattern = regex.pattern.as_ref(); let options = regex.options.as_ref(); self.append_cstring(pattern).map_err(SerdeError::custom)?; self.append_cstring(options).map_err(SerdeError::custom)?; Ok(ElementType::RegularExpression) } "$undefined" => { let _: bool = map.next_value()?; Ok(ElementType::Undefined) } "$binary" => { let binary: BorrowedBinaryBody = map.next_value()?; match binary.bytes { Cow::Borrowed(borrowed_bytes) => { self.append_borrowed_binary(borrowed_bytes, binary.subtype); } Cow::Owned(owned_bytes) => { self.append_owned_binary(owned_bytes, binary.subtype); } } Ok(ElementType::Binary) } "$date" => { let date: i64 = map.next_value()?; self.buffer.append_bytes(&date.to_le_bytes()); Ok(ElementType::DateTime) } "$timestamp" => { let timestamp: TimestampBody = map.next_value()?; self.buffer.append_bytes(×tamp.i.to_le_bytes()); self.buffer.append_bytes(×tamp.t.to_le_bytes()); Ok(ElementType::Timestamp) } "$minKey" => { let _: i32 = map.next_value()?; Ok(ElementType::MinKey) } "$maxKey" => { let _: i32 = map.next_value()?; Ok(ElementType::MaxKey) } "$code" => { let code: CowStr = map.next_value()?; if let Some(key) = map.next_key::()? { let key = key.0.as_ref(); if key == "$scope" { let length_index = self.pad_document_length(); self.append_string(code.0.as_ref()); let scope: RawDocumentBuf = map.next_value()?; self.buffer.append_bytes(scope.as_bytes()); let length_bytes = ((self.buffer.len() - length_index) as i32).to_le_bytes(); self.buffer .copy_from_slice(length_index..length_index + 4, &length_bytes); Ok(ElementType::JavaScriptCodeWithScope) } else { Err(SerdeError::unknown_field(key, &["$scope"])) } } else { self.append_string(code.0.as_ref()); Ok(ElementType::JavaScriptCode) } } "$dbPointer" => { let db_pointer: BorrowedDbPointerBody = map.next_value()?; self.append_string(db_pointer.ns.0.as_ref()); self.buffer.append_bytes(&db_pointer.id.bytes()); Ok(ElementType::DbPointer) } RAW_DOCUMENT_NEWTYPE => { let document_bytes: &[u8] = map.next_value()?; self.buffer.append_borrowed_bytes(document_bytes); Ok(ElementType::EmbeddedDocument) } RAW_ARRAY_NEWTYPE => { let array_bytes: &[u8] = map.next_value()?; self.buffer.append_borrowed_bytes(array_bytes); Ok(ElementType::Array) } _ => { self.iterate_map(first_key, map)?; Ok(ElementType::EmbeddedDocument) } } } fn visit_seq(mut self, mut seq: A) -> Result where A: SeqAccess<'de>, { let length_index = self.pad_document_length(); let mut i = 0u32; loop { let element_type_index = self.pad_element_type(); let key = i.to_string(); self.append_cstring(&key).map_err(SerdeError::custom)?; let element_type = match seq.next_element_seed(&mut self)? { Some(element_type) => element_type, None => { // Remove the additional key and padding for the element that was not present. self.buffer.drain(element_type_index..self.buffer.len()); break; } }; self.write_element_type(element_type, element_type_index); i += 1; } self.finish_document(length_index) .map_err(SerdeError::custom)?; Ok(ElementType::Array) } // visit_string and visit_borrowed_str will forward to this method. fn visit_str(mut self, s: &str) -> Result where E: SerdeError, { self.append_string(s); Ok(ElementType::String) } fn visit_bool(self, b: bool) -> Result where E: SerdeError, { self.buffer.push_byte(b as u8); Ok(ElementType::Boolean) } fn visit_i8(self, n: i8) -> Result where E: SerdeError, { self.buffer.append_bytes(&(n as i32).to_le_bytes()); Ok(ElementType::Int32) } fn visit_i16(self, n: i16) -> Result where E: SerdeError, { self.buffer.append_bytes(&(n as i32).to_le_bytes()); Ok(ElementType::Int32) } fn visit_i32(self, n: i32) -> Result where E: SerdeError, { self.buffer.append_bytes(&n.to_le_bytes()); Ok(ElementType::Int32) } fn visit_i64(self, n: i64) -> Result where E: SerdeError, { self.buffer.append_bytes(&n.to_le_bytes()); Ok(ElementType::Int64) } fn visit_u8(self, n: u8) -> Result where E: SerdeError, { self.buffer.append_bytes(&(n as i32).to_le_bytes()); Ok(ElementType::Int32) } fn visit_u16(self, n: u16) -> Result where E: SerdeError, { self.buffer.append_bytes(&(n as i32).to_le_bytes()); Ok(ElementType::Int32) } fn visit_u32(self, n: u32) -> Result where E: SerdeError, { match i32::try_from(n) { Ok(n) => { self.buffer.append_bytes(&n.to_le_bytes()); Ok(ElementType::Int32) } Err(_) => { self.buffer.append_bytes(&(n as i64).to_le_bytes()); Ok(ElementType::Int64) } } } fn visit_u64(self, n: u64) -> Result where E: SerdeError, { if let Ok(n) = i32::try_from(n) { self.buffer.append_bytes(&n.to_le_bytes()); Ok(ElementType::Int32) } else if let Ok(n) = i64::try_from(n) { self.buffer.append_bytes(&n.to_le_bytes()); Ok(ElementType::Int64) } else { Err(SerdeError::custom(format!( "number is too large for BSON: {}", n ))) } } fn visit_f64(self, n: f64) -> Result where E: SerdeError, { self.buffer.append_bytes(&n.to_le_bytes()); Ok(ElementType::Double) } fn visit_none(self) -> Result where E: SerdeError, { Ok(ElementType::Null) } fn visit_unit(self) -> Result where E: SerdeError, { Ok(ElementType::Null) } // visit_byte_buf will forward to this method. fn visit_bytes(mut self, bytes: &[u8]) -> Result where E: SerdeError, { self.append_owned_binary(bytes.to_owned(), BinarySubtype::Generic.into()); Ok(ElementType::Binary) } fn visit_borrowed_bytes(mut self, bytes: &'de [u8]) -> Result where E: SerdeError, { self.append_borrowed_binary(bytes, BinarySubtype::Generic.into()); Ok(ElementType::Binary) } } bson-2.10.0/src/raw/serde.rs000064400000000000000000000145111046102023000136770ustar 00000000000000pub(crate) mod bson_visitor; pub(crate) mod seeded_visitor; use std::{borrow::Cow, convert::TryFrom, fmt::Debug}; use serde::{de::Error as SerdeError, Deserialize}; use crate::{ raw::{RAW_ARRAY_NEWTYPE, RAW_DOCUMENT_NEWTYPE}, spec::BinarySubtype, RawArray, RawArrayBuf, RawBsonRef, RawDocument, RawDocumentBuf, }; use super::{bson::RawBson, RAW_BSON_NEWTYPE}; use bson_visitor::*; use seeded_visitor::*; /// Wrapper around a `Cow` to enable borrowed deserialization. /// The default [`Deserialize`] impl for [`Cow`] always uses the owned version. #[derive(Debug, Deserialize)] pub(crate) struct CowStr<'a>(#[serde(borrow)] Cow<'a, str>); /// A raw BSON value that may either be borrowed or owned. /// /// This is used to consolidate the [`Serialize`] and [`Deserialize`] implementations for /// [`RawBson`] and [`OwnedRawBson`]. pub(crate) enum OwnedOrBorrowedRawBson<'a> { Owned(RawBson), Borrowed(RawBsonRef<'a>), } impl<'a, 'de: 'a> Deserialize<'de> for OwnedOrBorrowedRawBson<'a> { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { deserializer.deserialize_newtype_struct(RAW_BSON_NEWTYPE, OwnedOrBorrowedRawBsonVisitor) } } impl<'a> Debug for OwnedOrBorrowedRawBson<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Owned(o) => o.fmt(f), Self::Borrowed(b) => b.fmt(f), } } } impl<'a> From> for OwnedOrBorrowedRawBson<'a> { fn from(b: RawBsonRef<'a>) -> Self { OwnedOrBorrowedRawBson::Borrowed(b) } } impl<'a> From for OwnedOrBorrowedRawBson<'a> { fn from(b: RawBson) -> Self { OwnedOrBorrowedRawBson::Owned(b) } } /// Wrapper type that can deserialize either an owned or a borrowed raw BSON document. #[derive(Debug)] pub(crate) enum OwnedOrBorrowedRawDocument<'a> { Owned(RawDocumentBuf), Borrowed(&'a RawDocument), } impl<'a> OwnedOrBorrowedRawDocument<'a> { pub(crate) fn into_owned(self) -> RawDocumentBuf { match self { Self::Owned(o) => o, Self::Borrowed(b) => b.to_owned(), } } } impl<'a> From for OwnedOrBorrowedRawDocument<'a> { fn from(doc: RawDocumentBuf) -> Self { Self::Owned(doc) } } impl<'a> From<&'a RawDocument> for OwnedOrBorrowedRawDocument<'a> { fn from(doc: &'a RawDocument) -> Self { Self::Borrowed(doc) } } impl<'a, 'de: 'a> TryFrom> for OwnedOrBorrowedRawDocument<'a> { type Error = crate::raw::Error; fn try_from(buffer: CowByteBuffer<'de>) -> Result { let doc = match buffer.0 { Some(Cow::Borrowed(borrowed)) => RawDocument::from_bytes(borrowed)?.into(), Some(Cow::Owned(owned)) => RawDocumentBuf::from_bytes(owned)?.into(), None => RawDocumentBuf::new().into(), }; Ok(doc) } } impl<'a, 'de: 'a> Deserialize<'de> for OwnedOrBorrowedRawDocument<'a> { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { match deserializer .deserialize_newtype_struct(RAW_DOCUMENT_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? { OwnedOrBorrowedRawBson::Borrowed(RawBsonRef::Document(d)) => Ok(Self::Borrowed(d)), OwnedOrBorrowedRawBson::Owned(RawBson::Document(d)) => Ok(Self::Owned(d)), // For non-BSON formats, RawDocument gets serialized as bytes, so we need to deserialize // from them here too. For BSON, the deserializer will return an error if it // sees the RAW_DOCUMENT_NEWTYPE but the next type isn't a document. OwnedOrBorrowedRawBson::Borrowed(RawBsonRef::Binary(b)) if b.subtype == BinarySubtype::Generic => { Ok(Self::Borrowed( RawDocument::from_bytes(b.bytes).map_err(SerdeError::custom)?, )) } OwnedOrBorrowedRawBson::Owned(RawBson::Binary(b)) if b.subtype == BinarySubtype::Generic => { Ok(Self::Owned( RawDocumentBuf::from_bytes(b.bytes).map_err(SerdeError::custom)?, )) } o => Err(SerdeError::custom(format!( "expected raw document, instead got {:?}", o ))), } } } /// Wrapper type that can deserialize either an owned or a borrowed raw BSON array. #[derive(Debug)] pub(crate) enum OwnedOrBorrowedRawArray<'a> { Owned(RawArrayBuf), Borrowed(&'a RawArray), } impl<'a> OwnedOrBorrowedRawArray<'a> { pub(crate) fn into_owned(self) -> RawArrayBuf { match self { Self::Owned(o) => o, Self::Borrowed(b) => b.to_owned(), } } } impl<'a, 'de: 'a> Deserialize<'de> for OwnedOrBorrowedRawArray<'a> { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { match deserializer .deserialize_newtype_struct(RAW_ARRAY_NEWTYPE, OwnedOrBorrowedRawBsonVisitor)? { OwnedOrBorrowedRawBson::Borrowed(RawBsonRef::Array(d)) => Ok(Self::Borrowed(d)), OwnedOrBorrowedRawBson::Owned(RawBson::Array(d)) => Ok(Self::Owned(d)), // For non-BSON formats, RawArray gets serialized as bytes, so we need to deserialize // from them here too. For BSON, the deserializer will return an error if it // sees the RAW_DOCUMENT_NEWTYPE but the next type isn't a document. OwnedOrBorrowedRawBson::Borrowed(RawBsonRef::Binary(b)) if b.subtype == BinarySubtype::Generic => { let doc = RawDocument::from_bytes(b.bytes).map_err(SerdeError::custom)?; Ok(Self::Borrowed(RawArray::from_doc(doc))) } OwnedOrBorrowedRawBson::Owned(RawBson::Binary(b)) if b.subtype == BinarySubtype::Generic => { let doc = RawDocumentBuf::from_bytes(b.bytes).map_err(SerdeError::custom)?; Ok(Self::Owned(RawArrayBuf::from_raw_document_buf(doc))) } o => Err(SerdeError::custom(format!( "expected raw array, instead got {:?}", o ))), } } } bson-2.10.0/src/raw/test/append.rs000064400000000000000000000222431046102023000150240ustar 00000000000000use std::iter::FromIterator; use crate::{ oid::ObjectId, raw::RawJavaScriptCodeWithScope, spec::BinarySubtype, tests::LOCK, Binary, Bson, DateTime, DbPointer, Decimal128, Document, JavaScriptCodeWithScope, RawArrayBuf, RawBson, RawDocumentBuf, Regex, Timestamp, }; use pretty_assertions::assert_eq; fn append_test(expected: Document, append: impl FnOnce(&mut RawDocumentBuf)) { let bytes = crate::to_vec(&expected).unwrap(); let mut buf = RawDocumentBuf::new(); append(&mut buf); assert_eq!(buf.as_bytes(), bytes); } #[test] fn i32() { let expected = doc! { "a": -1_i32, "b": 123_i32, "c": 0_i32 }; append_test(expected, |doc| { doc.append("a", -1_i32); doc.append("b", 123_i32); doc.append("c", 0_i32); }); } #[test] fn i64() { let expected = doc! { "a": -1_i64, "b": 123_i64, "c": 0_i64 }; append_test(expected, |doc| { doc.append("a", -1_i64); doc.append("b", 123_i64); doc.append("c", 0_i64); }); } #[test] fn str() { let expected = doc! { "first": "the quick", "second": "brown fox", "third": "jumped over", "last": "the lazy sheep dog", }; append_test(expected, |doc| { doc.append("first", "the quick"); doc.append("second", "brown fox"); doc.append("third", "jumped over"); doc.append("last", "the lazy sheep dog"); }); } #[test] fn double() { let expected = doc! { "positive": 12.5, "0": 0.0, "negative": -123.24, "nan": f64::NAN, "inf": f64::INFINITY, }; append_test(expected, |doc| { doc.append("positive", 12.5); doc.append("0", 0.0); doc.append("negative", -123.24); doc.append("nan", f64::NAN); doc.append("inf", f64::INFINITY); }); } #[test] fn boolean() { let expected = doc! { "true": true, "false": false, }; append_test(expected, |doc| { doc.append("true", true); doc.append("false", false); }); } #[test] fn null() { let expected = doc! { "null": null, }; append_test(expected, |doc| { doc.append("null", RawBson::Null); }); } #[test] fn document() { let expected = doc! { "empty": {}, "subdoc": { "a": 1_i32, "b": true, } }; append_test(expected, |doc| { doc.append("empty", RawDocumentBuf::new()); let mut buf = RawDocumentBuf::new(); buf.append("a", 1_i32); buf.append("b", true); doc.append("subdoc", buf); }); } #[test] fn array() { let expected = doc! { "empty": [], "array": [ true, "string", { "a": "subdoc" }, 123_i32 ] }; append_test(expected, |doc| { doc.append("empty", RawArrayBuf::new()); let mut buf = RawArrayBuf::new(); buf.push(true); buf.push("string"); let mut subdoc = RawDocumentBuf::new(); subdoc.append("a", "subdoc"); buf.push(subdoc); buf.push(123_i32); doc.append("array", buf); }); } #[test] fn oid() { let _guard = LOCK.run_concurrently(); let oid = ObjectId::new(); let expected = doc! { "oid": oid, }; append_test(expected, |doc| doc.append("oid", oid)); } #[test] fn datetime() { let dt = DateTime::now(); let old = DateTime::from_millis(-1); let expected = doc! { "now": dt, "old": old }; append_test(expected, |doc| { doc.append("now", dt); doc.append("old", old); }); } #[test] fn timestamp() { let ts = Timestamp { time: 123, increment: 2, }; let expected = doc! { "ts": ts, }; append_test(expected, |doc| { doc.append("ts", ts); }); } #[test] fn binary() { let bytes = vec![1, 2, 3, 4]; let bin = Binary { bytes: bytes.clone(), subtype: BinarySubtype::Generic, }; let old = Binary { bytes, subtype: BinarySubtype::BinaryOld, }; let expected = doc! { "generic": bin.clone(), "binary_old": old.clone(), }; append_test(expected, |doc| { doc.append("generic", bin); doc.append("binary_old", old); }); } #[test] fn min_max_key() { let expected = doc! { "min": Bson::MinKey, "max": Bson::MaxKey }; append_test(expected, |doc| { doc.append("min", RawBson::MinKey); doc.append("max", RawBson::MaxKey); }); } #[test] fn undefined() { let expected = doc! { "undefined": Bson::Undefined, }; append_test(expected, |doc| { doc.append("undefined", RawBson::Undefined); }); } #[test] fn regex() { let expected = doc! { "regex": Regex::new("some pattern", "abc"), }; append_test(expected, |doc| { doc.append("regex", Regex::new("some pattern", "abc")); }); } #[test] fn code() { let code_w_scope = JavaScriptCodeWithScope { code: "some code".to_string(), scope: doc! { "a": 1_i32, "b": true }, }; let expected = doc! { "code": Bson::JavaScriptCode("some code".to_string()), "code_w_scope": code_w_scope, }; append_test(expected, |doc| { doc.append("code", RawBson::JavaScriptCode("some code".to_string())); let mut scope = RawDocumentBuf::new(); scope.append("a", 1_i32); scope.append("b", true); doc.append( "code_w_scope", RawJavaScriptCodeWithScope { code: "some code".to_string(), scope, }, ); }); } #[test] fn symbol() { let expected = doc! { "symbol": Bson::Symbol("symbol".to_string()) }; append_test(expected, |doc| { doc.append("symbol", RawBson::Symbol("symbol".to_string())); }); } #[test] fn dbpointer() { let _guard = LOCK.run_concurrently(); let id = ObjectId::new(); let expected = doc! { "symbol": Bson::DbPointer(DbPointer { namespace: "ns".to_string(), id }) }; append_test(expected, |doc| { doc.append( "symbol", RawBson::DbPointer(DbPointer { namespace: "ns".to_string(), id, }), ); }); } #[test] fn decimal128() { let decimal = Decimal128 { bytes: [1; 16] }; let expected = doc! { "decimal": decimal }; append_test(expected, |doc| { doc.append("decimal", decimal); }); } #[test] fn general() { let dt = DateTime::now(); let expected = doc! { "a": true, "second key": 123.4, "third": 15_i64, "32": -100101_i32, "subdoc": { "a": "subkey", "another": { "subdoc": dt } }, "array": [1_i64, true, { "doc": 23_i64 }, ["another", "array"]], }; append_test(expected, |doc| { doc.append("a", true); doc.append("second key", 123.4); doc.append("third", 15_i64); doc.append("32", -100101_i32); let mut subdoc = RawDocumentBuf::new(); subdoc.append("a", "subkey"); let mut subsubdoc = RawDocumentBuf::new(); subsubdoc.append("subdoc", dt); subdoc.append("another", subsubdoc); doc.append("subdoc", subdoc); let mut array = RawArrayBuf::new(); array.push(1_i64); array.push(true); let mut array_subdoc = RawDocumentBuf::new(); array_subdoc.append("doc", 23_i64); array.push(array_subdoc); let mut sub_array = RawArrayBuf::new(); sub_array.push("another"); sub_array.push("array"); array.push(sub_array); doc.append("array", array); }); } #[test] fn from_iter() { let doc_buf = RawDocumentBuf::from_iter([ ( "array", RawBson::Array(RawArrayBuf::from_iter([ RawBson::Boolean(true), RawBson::Document(RawDocumentBuf::from_iter([ ("ok", RawBson::Boolean(false)), ("other", RawBson::String("hello".to_string())), ])), ])), ), ("bool", RawBson::Boolean(true)), ("string", RawBson::String("some string".to_string())), ]); let doc = doc! { "array": [ true, { "ok": false, "other": "hello" } ], "bool": true, "string": "some string" }; let expected = doc! { "expected": doc }; append_test(expected, |doc| { doc.append("expected", doc_buf); }); } #[test] fn array_buf() { let mut arr_buf = RawArrayBuf::new(); arr_buf.push(true); let mut doc_buf = RawDocumentBuf::new(); doc_buf.append("x", 3_i32); doc_buf.append("string", "string"); arr_buf.push(doc_buf); let mut sub_arr = RawArrayBuf::new(); sub_arr.push("a string"); arr_buf.push(sub_arr); let arr = rawbson!([ true, { "x": 3_i32, "string": "string" }, [ "a string" ] ]); assert_eq!(arr_buf.as_ref(), arr.as_array().unwrap()); } bson-2.10.0/src/raw/test/mod.rs000064400000000000000000000325101046102023000143320ustar 00000000000000mod append; mod props; use super::*; use crate::{ doc, oid::ObjectId, raw::error::ValueAccessErrorKind, spec::BinarySubtype, Binary, Bson, DateTime, Regex, Timestamp, }; #[test] fn string_from_document() { let rawdoc = rawdoc! { "this": "first", "that": "second", "something": "else", }; assert_eq!( rawdoc.get("that").unwrap().unwrap().as_str().unwrap(), "second", ); } #[test] fn nested_document() { let rawdoc = rawdoc! { "outer": { "inner": "surprise", "i64": 6_i64 } }; let subdoc = rawdoc .get("outer") .expect("get doc result") .expect("get doc option") .as_document() .expect("as doc"); assert_eq!( subdoc .get("inner") .expect("get str result") .expect("get str option") .as_str() .expect("as str"), "surprise", ); assert_eq!( subdoc .get("i64") .expect("get i64 result") .expect("get i64 option") .as_i64() .expect("as i64 result"), 6 ); } #[test] fn iterate() { let rawdoc = rawdoc! { "apples": "oranges", "peanut butter": "chocolate", "easy as": {"do": 1, "re": 2, "mi": 3}, }; let mut dociter = rawdoc.into_iter(); let next = dociter.next().expect("no result").expect("invalid bson"); assert_eq!(next.0, "apples"); assert_eq!(next.1.as_str().expect("result was not a str"), "oranges"); let next = dociter.next().expect("no result").expect("invalid bson"); assert_eq!(next.0, "peanut butter"); assert_eq!(next.1.as_str().expect("result was not a str"), "chocolate"); let next = dociter.next().expect("no result").expect("invalid bson"); assert_eq!(next.0, "easy as"); let _doc = next.1.as_document().expect("result was a not a document"); let next = dociter.next(); assert!(next.is_none()); } #[test] fn rawdoc_to_doc() { let rawdoc = rawdoc! { "f64": 2.5, "string": "hello", "document": {}, "array": ["binary", "serialized", "object", "notation"], "binary": Binary { subtype: BinarySubtype::Generic, bytes: vec![1, 2, 3] }, "object_id": ObjectId::from_bytes([1, 2, 3, 4, 5,6,7,8,9,10, 11,12]), "boolean": true, "datetime": DateTime::now(), "null": RawBson::Null, "regex": Regex { pattern: String::from(r"end\s*$"), options: String::from("i")}, "javascript": RawBson::JavaScriptCode(String::from("console.log(console);")), "symbol": RawBson::Symbol(String::from("artist-formerly-known-as")), "javascript_with_scope": RawJavaScriptCodeWithScope { code: String::from("console.log(msg);"), scope: rawdoc! { "ok": true } }, "int32": 23i32, "timestamp": Timestamp { time: 3542578, increment: 0 }, "int64": 46i64, "end": "END", }; let doc: crate::Document = rawdoc.clone().try_into().expect("invalid bson"); let round_tripped_bytes = crate::to_vec(&doc).expect("serialize should work"); assert_eq!(round_tripped_bytes.as_slice(), rawdoc.as_bytes()); let mut vec_writer_bytes = vec![]; doc.to_writer(&mut vec_writer_bytes) .expect("to writer should work"); assert_eq!(vec_writer_bytes, rawdoc.into_bytes()); } #[test] fn f64() { #![allow(clippy::float_cmp)] let rawdoc = rawdoc! { "f64": 2.5 }; assert_eq!( rawdoc .get("f64") .expect("error finding key f64") .expect("no key f64") .as_f64() .expect("result was not a f64"), 2.5, ); } #[test] fn string() { let rawdoc = rawdoc! { "string": "hello" }; assert_eq!( rawdoc .get("string") .expect("error finding key string") .expect("no key string") .as_str() .expect("result was not a string"), "hello", ); } #[test] fn document() { let rawdoc = rawdoc! {"document": {}}; let doc = rawdoc .get("document") .expect("error finding key document") .expect("no key document") .as_document() .expect("result was not a document"); assert_eq!(doc.as_bytes(), [5u8, 0, 0, 0, 0].as_ref()); // Empty document } #[test] fn array() { let rawdoc = rawdoc! { "array": ["binary", "serialized", "object", "notation"] }; let array = rawdoc .get("array") .expect("error finding key array") .expect("no key array") .as_array() .expect("result was not an array"); assert_eq!(array.get_str(0), Ok("binary")); assert_eq!(array.get_str(3), Ok("notation")); assert_eq!( array.get_str(4).unwrap_err().kind, ValueAccessErrorKind::NotPresent ); } #[test] fn binary() { let rawdoc = rawdoc! { "binary": Binary { subtype: BinarySubtype::Generic, bytes: vec![1u8, 2, 3] } }; let binary: bson_ref::RawBinaryRef<'_> = rawdoc .get("binary") .expect("error finding key binary") .expect("no key binary") .as_binary() .expect("result was not a binary object"); assert_eq!(binary.subtype, BinarySubtype::Generic); assert_eq!(binary.bytes, &[1, 2, 3]); } #[test] fn object_id() { let rawdoc = rawdoc! { "object_id": ObjectId::from_bytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]), }; let oid = rawdoc .get("object_id") .expect("error finding key object_id") .expect("no key object_id") .as_object_id() .expect("result was not an object id"); assert_eq!(oid.to_hex(), "0102030405060708090a0b0c"); } #[test] fn boolean() { let rawdoc = rawdoc! { "boolean": true, }; let boolean = rawdoc .get("boolean") .expect("error finding key boolean") .expect("no key boolean") .as_bool() .expect("result was not boolean"); assert!(boolean); } #[test] fn datetime() { use time::macros::datetime; let rawdoc = rawdoc! { "boolean": true, "datetime": DateTime::from_time_0_3(datetime!(2000-10-31 12:30:45 UTC)), }; let datetime = rawdoc .get("datetime") .expect("error finding key datetime") .expect("no key datetime") .as_datetime() .expect("result was not datetime"); assert_eq!( datetime.try_to_rfc3339_string().unwrap(), "2000-10-31T12:30:45Z" ); } #[test] fn null() { let rawdoc = rawdoc! { "null": null, }; rawdoc .get("null") .expect("error finding key null") .expect("no key null") .as_null() .expect("was not null"); } #[test] fn regex() { let rawdoc = rawdoc! { "regex": Regex { pattern: String::from(r"end\s*$"), options: String::from("i")}, }; let regex = rawdoc .get("regex") .expect("error finding key regex") .expect("no key regex") .as_regex() .expect("was not regex"); assert_eq!(regex.pattern, r"end\s*$"); assert_eq!(regex.options, "i"); } #[test] fn javascript() { let rawdoc = rawdoc! { "javascript": RawBson::JavaScriptCode(String::from("console.log(console);")), }; let js = rawdoc .get("javascript") .expect("error finding key javascript") .expect("no key javascript") .as_javascript() .expect("was not javascript"); assert_eq!(js, "console.log(console);"); } #[test] fn symbol() { let rawdoc = rawdoc! { "symbol": RawBson::Symbol(String::from("artist-formerly-known-as")), }; let symbol = rawdoc .get("symbol") .expect("error finding key symbol") .expect("no key symbol") .as_symbol() .expect("was not symbol"); assert_eq!(symbol, "artist-formerly-known-as"); } #[test] fn javascript_with_scope() { let rawdoc = rawdoc! { "javascript_with_scope": RawJavaScriptCodeWithScope { code: String::from("console.log(msg);"), scope: rawdoc! { "ok": true } }, }; let js_with_scope = rawdoc .get("javascript_with_scope") .expect("error finding key javascript_with_scope") .expect("no key javascript_with_scope") .as_javascript_with_scope() .expect("was not javascript with scope"); assert_eq!(js_with_scope.code, "console.log(msg);"); let (scope_key, scope_value_bson) = js_with_scope .scope .into_iter() .next() .expect("no next value in scope") .expect("invalid element"); assert_eq!(scope_key, "ok"); let scope_value = scope_value_bson.as_bool().expect("not a boolean"); assert!(scope_value); } #[test] fn int32() { let rawdoc = rawdoc! { "int32": 23i32, }; let int32 = rawdoc .get("int32") .expect("error finding key int32") .expect("no key int32") .as_i32() .expect("was not int32"); assert_eq!(int32, 23i32); } #[test] fn timestamp() { let rawdoc = rawdoc! { "timestamp": Timestamp { time: 3542578, increment: 7 }, }; let ts = rawdoc .get("timestamp") .expect("error finding key timestamp") .expect("no key timestamp") .as_timestamp() .expect("was not a timestamp"); assert_eq!(ts.increment, 7); assert_eq!(ts.time, 3542578); } #[test] fn int64() { let rawdoc = rawdoc! { "int64": 46i64, }; let int64 = rawdoc .get("int64") .expect("error finding key int64") .expect("no key int64") .as_i64() .expect("was not int64"); assert_eq!(int64, 46i64); } #[test] fn document_iteration() { let rawdoc = rawdoc! { "f64": 2.5, "string": "hello", "document": {}, "array": ["binary", "serialized", "object", "notation"], "binary": Binary { subtype: BinarySubtype::Generic, bytes: vec![1u8, 2, 3] }, "object_id": ObjectId::from_bytes([1, 2, 3, 4, 5,6,7,8,9,10, 11,12]), "boolean": true, "datetime": DateTime::now(), "null": RawBson::Null, "regex": Regex { pattern: String::from(r"end\s*$"), options: String::from("i") }, "javascript": RawBson::JavaScriptCode(String::from("console.log(console);")), "symbol": RawBson::Symbol(String::from("artist-formerly-known-as")), "javascript_with_scope": RawJavaScriptCodeWithScope { code: String::from("console.log(msg);"), scope: rawdoc! { "ok": true } }, "int32": 23i32, "timestamp": Timestamp { time: 3542578, increment: 0 }, "int64": 46i64, "end": "END", }; assert_eq!( rawdoc .into_iter() .collect::>>() .expect("collecting iterated doc") .len(), 17 ); let end = rawdoc .get("end") .expect("error finding key end") .expect("no key end") .as_str() .expect("was not str"); assert_eq!(end, "END"); } #[test] fn into_bson_conversion() { let rawdoc = rawdoc! { "f64": 2.5, "string": "hello", "document": {}, "array": ["binary", "serialized", "object", "notation"], "object_id": ObjectId::from_bytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]), "binary": Binary { subtype: BinarySubtype::Generic, bytes: vec![1u8, 2, 3] }, "boolean": false, }; let rawbson = RawBsonRef::Document(RawDocument::from_bytes(rawdoc.as_bytes()).unwrap()); let b: Bson = rawbson.try_into().expect("invalid bson"); let doc = b.as_document().expect("not a document"); assert_eq!(*doc.get("f64").expect("f64 not found"), Bson::Double(2.5)); assert_eq!( *doc.get("string").expect("string not found"), Bson::String(String::from("hello")) ); assert_eq!( *doc.get("document").expect("document not found"), Bson::Document(doc! {}) ); assert_eq!( *doc.get("array").expect("array not found"), Bson::Array( vec!["binary", "serialized", "object", "notation"] .into_iter() .map(|s| Bson::String(String::from(s))) .collect() ) ); assert_eq!( *doc.get("object_id").expect("object_id not found"), Bson::ObjectId(ObjectId::from_bytes([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ])) ); assert_eq!( *doc.get("binary").expect("binary not found"), Bson::Binary(Binary { subtype: BinarySubtype::Generic, bytes: vec![1, 2, 3] }) ); assert_eq!( *doc.get("boolean").expect("boolean not found"), Bson::Boolean(false) ); } use props::arbitrary_bson; use proptest::prelude::*; use std::convert::TryInto; proptest! { #[test] fn no_crashes(s: Vec) { let _ = RawDocumentBuf::from_bytes(s); } #[test] fn roundtrip_bson(bson in arbitrary_bson()) { let doc = doc! { "bson": bson }; let raw = crate::to_vec(&doc); prop_assert!(raw.is_ok()); let raw = RawDocumentBuf::from_bytes(raw.unwrap()); prop_assert!(raw.is_ok()); let raw = raw.unwrap(); let roundtrip: Result = raw.try_into(); prop_assert!(roundtrip.is_ok()); let roundtrip = roundtrip.unwrap(); prop_assert_eq!(doc, roundtrip); } } bson-2.10.0/src/raw/test/props.rs000064400000000000000000000045531046102023000147240ustar 00000000000000use crate::{spec::BinarySubtype, Binary, Bson, Document, JavaScriptCodeWithScope, Regex}; use proptest::prelude::*; fn arbitrary_binary_subtype() -> impl Strategy { prop_oneof![ Just(BinarySubtype::Generic), Just(BinarySubtype::Function), Just(BinarySubtype::BinaryOld), Just(BinarySubtype::UuidOld), Just(BinarySubtype::Uuid), Just(BinarySubtype::Md5), ] } pub(crate) fn arbitrary_bson() -> impl Strategy { let leaf = prop_oneof![ Just(Bson::Null), any::().prop_map(Bson::String), any::().prop_map(Bson::Boolean), any::().prop_map(Bson::Double), any::().prop_map(Bson::Int32), any::().prop_map(Bson::Int64), any::<(String, String)>().prop_map(|(pattern, options)| { Bson::RegularExpression(Regex::new(pattern, options)) }), any::<[u8; 12]>().prop_map(|bytes| Bson::ObjectId(crate::oid::ObjectId::from_bytes(bytes))), (arbitrary_binary_subtype(), any::>()).prop_map(|(subtype, bytes)| { let bytes = if let BinarySubtype::BinaryOld = subtype { // BinarySubtype::BinaryOld expects a four byte prefix, which the bson::Bson type // leaves up to the caller. let mut newbytes = Vec::with_capacity(bytes.len() + 4); newbytes.extend_from_slice(&(bytes.len() as i32).to_le_bytes()); newbytes.extend_from_slice(&bytes); newbytes } else { bytes }; Bson::Binary(Binary { subtype, bytes }) }), any::().prop_map(Bson::JavaScriptCode), ]; leaf.prop_recursive(4, 256, 10, |inner| { prop_oneof![ prop::collection::hash_map("[^\0]*", inner.clone(), 0..12) .prop_map(|map| Bson::Document(map.into_iter().collect())), prop::collection::vec(inner.clone(), 0..12).prop_map(Bson::Array), ( prop::collection::hash_map("[^\0]*", inner, 0..12) .prop_map(|map| map.into_iter().collect::()), any::() ) .prop_map(|(scope, code)| Bson::JavaScriptCodeWithScope( JavaScriptCodeWithScope { code, scope } )), ] }) } bson-2.10.0/src/ser/error.rs000064400000000000000000000043301046102023000137240ustar 00000000000000use std::{error, fmt, fmt::Display, io, sync::Arc}; use serde::ser; use crate::bson::Bson; /// Possible errors that can arise during encoding. #[derive(Clone, Debug)] #[non_exhaustive] pub enum Error { /// A [`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html) encountered while serializing. Io(Arc), /// A key could not be serialized to a BSON string. InvalidDocumentKey(Bson), /// An invalid string was specified. InvalidCString(String), /// A general error that occurred during serialization. /// See: #[non_exhaustive] SerializationError { /// A message describing the error. message: String, }, /// An unsigned integer type could not fit into a signed integer type. UnsignedIntegerExceededRange(u64), } impl From for Error { fn from(err: io::Error) -> Error { Error::Io(Arc::new(err)) } } impl fmt::Display for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match *self { Error::Io(ref inner) => inner.fmt(fmt), Error::InvalidDocumentKey(ref key) => write!(fmt, "Invalid map key type: {}", key), Error::InvalidCString(ref string) => { write!(fmt, "cstrings cannot contain null bytes: {:?}", string) } Error::SerializationError { ref message } => message.fmt(fmt), Error::UnsignedIntegerExceededRange(value) => write!( fmt, "BSON does not support unsigned integers. An attempt to serialize the value: {} in a signed type failed due to the value's \ size.", value ), } } } impl error::Error for Error { fn cause(&self) -> Option<&dyn error::Error> { match *self { Error::Io(ref inner) => Some(inner.as_ref()), _ => None, } } } impl ser::Error for Error { fn custom(msg: T) -> Error { Error::SerializationError { message: msg.to_string(), } } } /// Alias for `Result`. pub type Result = std::result::Result; bson-2.10.0/src/ser/mod.rs000064400000000000000000000160331046102023000133550ustar 00000000000000// The MIT License (MIT) // Copyright (c) 2015 Y. T. Chung // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in // the Software without restriction, including without limitation the rights to // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of // the Software, and to permit persons to whom the Software is furnished to do so, // subject to the following conditions: // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. //! Serializer mod error; mod raw; mod serde; pub use self::{ error::{Error, Result}, serde::{Serializer, SerializerOptions}, }; use std::io::Write; use crate::{ bson::{Bson, Document}, de::MAX_BSON_SIZE, spec::BinarySubtype, RawDocumentBuf, }; use ::serde::{ser::Error as SerdeError, Serialize}; fn write_string(writer: &mut W, s: &str) -> Result<()> { writer.write_all(&(s.len() as i32 + 1).to_le_bytes())?; writer.write_all(s.as_bytes())?; writer.write_all(b"\0")?; Ok(()) } fn write_cstring(writer: &mut W, s: &str) -> Result<()> { if s.contains('\0') { return Err(Error::InvalidCString(s.into())); } writer.write_all(s.as_bytes())?; writer.write_all(b"\0")?; Ok(()) } #[inline] pub(crate) fn write_i32(writer: &mut W, val: i32) -> Result<()> { writer .write_all(&val.to_le_bytes()) .map(|_| ()) .map_err(From::from) } #[inline] fn write_i64(writer: &mut W, val: i64) -> Result<()> { writer .write_all(&val.to_le_bytes()) .map(|_| ()) .map_err(From::from) } #[inline] fn write_f64(writer: &mut W, val: f64) -> Result<()> { writer .write_all(&val.to_le_bytes()) .map(|_| ()) .map_err(From::from) } #[inline] fn write_binary(mut writer: W, bytes: &[u8], subtype: BinarySubtype) -> Result<()> { let len = if let BinarySubtype::BinaryOld = subtype { bytes.len() + 4 } else { bytes.len() }; if len > MAX_BSON_SIZE as usize { return Err(Error::custom(format!( "binary length {} exceeded maximum size", bytes.len() ))); } write_i32(&mut writer, len as i32)?; writer.write_all(&[subtype.into()])?; if let BinarySubtype::BinaryOld = subtype { write_i32(&mut writer, len as i32 - 4)?; }; writer.write_all(bytes).map_err(From::from) } /// Encode a `T` Serializable into a [`Bson`] value. /// /// The [`Serializer`] used by this function presents itself as human readable, whereas the /// one used in [`to_vec`] does not. This means that this function will produce different BSON than /// [`to_vec`] for types that change their serialization output depending on whether /// the format is human readable or not. To serialize to a [`Document`] with a serializer that /// presents itself as not human readable, use [`to_bson_with_options`] with /// [`SerializerOptions::human_readable`] set to false. pub fn to_bson(value: &T) -> Result where T: Serialize, { let ser = Serializer::new(); value.serialize(ser) } /// Encode a `T` into a [`Bson`] value, configuring the underlying serializer with the provided /// options. /// ``` /// # use serde::Serialize; /// # use bson::{bson, SerializerOptions}; /// #[derive(Debug, Serialize)] /// struct MyData { /// a: String, /// } /// /// let data = MyData { a: "ok".to_string() }; /// let options = SerializerOptions::builder().human_readable(false).build(); /// let bson = bson::to_bson_with_options(&data, options)?; /// assert_eq!(bson, bson!({ "a": "ok" })); /// # Ok::<(), Box>(()) /// ``` pub fn to_bson_with_options(value: &T, options: SerializerOptions) -> Result where T: Serialize, { let ser = Serializer::new_with_options(options); value.serialize(ser) } /// Encode a `T` Serializable into a BSON [`Document`]. /// /// The [`Serializer`] used by this function presents itself as human readable, whereas the /// one used in [`to_vec`] does not. This means that this function will produce different BSON than /// [`to_vec`] for types that change their serialization output depending on whether /// the format is human readable or not. To serialize to a [`Document`] with a serializer that /// presents itself as not human readable, use [`to_document_with_options`] with /// [`SerializerOptions::human_readable`] set to false. pub fn to_document(value: &T) -> Result where T: Serialize, { to_document_with_options(value, Default::default()) } /// Encode a `T` into a [`Document`], configuring the underlying serializer with the provided /// options. /// ``` /// # use serde::Serialize; /// # use bson::{doc, SerializerOptions}; /// #[derive(Debug, Serialize)] /// struct MyData { /// a: String, /// } /// /// let data = MyData { a: "ok".to_string() }; /// let options = SerializerOptions::builder().human_readable(false).build(); /// let doc = bson::to_document_with_options(&data, options)?; /// assert_eq!(doc, doc! { "a": "ok" }); /// # Ok::<(), Box>(()) /// ``` pub fn to_document_with_options( value: &T, options: SerializerOptions, ) -> Result where T: Serialize, { match to_bson_with_options(value, options)? { Bson::Document(doc) => Ok(doc), bson => Err(Error::SerializationError { message: format!( "Could not be serialized to Document, got {:?} instead", bson.element_type() ), }), } } /// Serialize the given `T` as a BSON byte vector. #[inline] pub fn to_vec(value: &T) -> Result> where T: Serialize, { let mut serializer = raw::Serializer::new(); value.serialize(&mut serializer)?; Ok(serializer.into_vec()) } /// Serialize the given `T` as a [`RawDocumentBuf`]. /// /// ```rust /// use serde::Serialize; /// use bson::rawdoc; /// /// #[derive(Serialize)] /// struct Cat { /// name: String, /// age: i32 /// } /// /// let cat = Cat { name: "Garfield".to_string(), age: 43 }; /// let doc = bson::to_raw_document_buf(&cat)?; /// assert_eq!(doc, rawdoc! { "name": "Garfield", "age": 43 }); /// # Ok::<(), Box>(()) /// ``` #[inline] pub fn to_raw_document_buf(value: &T) -> Result where T: Serialize, { RawDocumentBuf::from_bytes(to_vec(value)?).map_err(Error::custom) } bson-2.10.0/src/ser/raw/document_serializer.rs000064400000000000000000000225501046102023000174370ustar 00000000000000use serde::{ser::Impossible, Serialize}; use crate::{ ser::{write_cstring, write_i32, Error, Result}, to_bson, Bson, }; use super::Serializer; pub(crate) struct DocumentSerializationResult<'a> { pub(crate) root_serializer: &'a mut Serializer, } /// Serializer used to serialize document or array bodies. pub(crate) struct DocumentSerializer<'a> { root_serializer: &'a mut Serializer, num_keys_serialized: usize, start: usize, } impl<'a> DocumentSerializer<'a> { pub(crate) fn start(rs: &'a mut Serializer) -> crate::ser::Result { let start = rs.bytes.len(); write_i32(&mut rs.bytes, 0)?; Ok(Self { root_serializer: rs, num_keys_serialized: 0, start, }) } /// Serialize a document key using the provided closure. fn serialize_doc_key_custom Result<()>>( &mut self, f: F, ) -> Result<()> { // push a dummy element type for now, will update this once we serialize the value self.root_serializer.reserve_element_type(); f(self.root_serializer)?; self.num_keys_serialized += 1; Ok(()) } /// Serialize a document key to string using [`KeySerializer`]. fn serialize_doc_key(&mut self, key: &T) -> Result<()> where T: serde::Serialize + ?Sized, { self.serialize_doc_key_custom(|rs| { key.serialize(KeySerializer { root_serializer: rs, })?; Ok(()) })?; Ok(()) } pub(crate) fn end_doc(self) -> crate::ser::Result> { self.root_serializer.bytes.push(0); let length = (self.root_serializer.bytes.len() - self.start) as i32; self.root_serializer.replace_i32(self.start, length); Ok(DocumentSerializationResult { root_serializer: self.root_serializer, }) } } impl<'a> serde::ser::SerializeSeq for DocumentSerializer<'a> { type Ok = (); type Error = Error; #[inline] fn serialize_element(&mut self, value: &T) -> Result<()> where T: serde::Serialize, { let index = self.num_keys_serialized; self.serialize_doc_key_custom(|rs| { use std::io::Write; write!(&mut rs.bytes, "{}", index)?; rs.bytes.push(0); Ok(()) })?; value.serialize(&mut *self.root_serializer) } #[inline] fn end(self) -> Result { self.end_doc().map(|_| ()) } } impl<'a> serde::ser::SerializeMap for DocumentSerializer<'a> { type Ok = (); type Error = Error; #[inline] fn serialize_key(&mut self, key: &T) -> Result<()> where T: serde::Serialize, { self.serialize_doc_key(key) } #[inline] fn serialize_value(&mut self, value: &T) -> Result<()> where T: serde::Serialize, { value.serialize(&mut *self.root_serializer) } fn end(self) -> Result { self.end_doc().map(|_| ()) } } impl<'a> serde::ser::SerializeStruct for DocumentSerializer<'a> { type Ok = (); type Error = Error; #[inline] fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> where T: serde::Serialize, { self.serialize_doc_key(key)?; value.serialize(&mut *self.root_serializer) } #[inline] fn end(self) -> Result { self.end_doc().map(|_| ()) } } impl<'a> serde::ser::SerializeTuple for DocumentSerializer<'a> { type Ok = (); type Error = Error; #[inline] fn serialize_element(&mut self, value: &T) -> Result<()> where T: serde::Serialize, { self.serialize_doc_key(&self.num_keys_serialized.to_string())?; value.serialize(&mut *self.root_serializer) } #[inline] fn end(self) -> Result { self.end_doc().map(|_| ()) } } impl<'a> serde::ser::SerializeTupleStruct for DocumentSerializer<'a> { type Ok = (); type Error = Error; #[inline] fn serialize_field(&mut self, value: &T) -> Result<()> where T: serde::Serialize, { self.serialize_doc_key(&self.num_keys_serialized.to_string())?; value.serialize(&mut *self.root_serializer) } #[inline] fn end(self) -> Result { self.end_doc().map(|_| ()) } } /// Serializer used specifically for serializing document keys. /// Only keys that serialize to strings will be accepted. struct KeySerializer<'a> { root_serializer: &'a mut Serializer, } impl<'a> KeySerializer<'a> { fn invalid_key(v: T) -> Error { Error::InvalidDocumentKey(to_bson(&v).unwrap_or(Bson::Null)) } } impl<'a> serde::Serializer for KeySerializer<'a> { type Ok = (); type Error = Error; type SerializeSeq = Impossible<(), Error>; type SerializeTuple = Impossible<(), Error>; type SerializeTupleStruct = Impossible<(), Error>; type SerializeTupleVariant = Impossible<(), Error>; type SerializeMap = Impossible<(), Error>; type SerializeStruct = Impossible<(), Error>; type SerializeStructVariant = Impossible<(), Error>; #[inline] fn serialize_bool(self, v: bool) -> Result { Err(Self::invalid_key(v)) } #[inline] fn serialize_i8(self, v: i8) -> Result { Err(Self::invalid_key(v)) } #[inline] fn serialize_i16(self, v: i16) -> Result { Err(Self::invalid_key(v)) } #[inline] fn serialize_i32(self, v: i32) -> Result { Err(Self::invalid_key(v)) } #[inline] fn serialize_i64(self, v: i64) -> Result { Err(Self::invalid_key(v)) } #[inline] fn serialize_u8(self, v: u8) -> Result { Err(Self::invalid_key(v)) } #[inline] fn serialize_u16(self, v: u16) -> Result { Err(Self::invalid_key(v)) } #[inline] fn serialize_u32(self, v: u32) -> Result { Err(Self::invalid_key(v)) } #[inline] fn serialize_u64(self, v: u64) -> Result { Err(Self::invalid_key(v)) } #[inline] fn serialize_f32(self, v: f32) -> Result { Err(Self::invalid_key(v)) } #[inline] fn serialize_f64(self, v: f64) -> Result { Err(Self::invalid_key(v)) } #[inline] fn serialize_char(self, v: char) -> Result { Err(Self::invalid_key(v)) } #[inline] fn serialize_str(self, v: &str) -> Result { write_cstring(&mut self.root_serializer.bytes, v) } #[inline] fn serialize_bytes(self, v: &[u8]) -> Result { Err(Self::invalid_key(v)) } #[inline] fn serialize_none(self) -> Result { Err(Self::invalid_key(Bson::Null)) } #[inline] fn serialize_some(self, value: &T) -> Result where T: Serialize, { value.serialize(self) } #[inline] fn serialize_unit(self) -> Result { Err(Self::invalid_key(Bson::Null)) } #[inline] fn serialize_unit_struct(self, _name: &'static str) -> Result { Err(Self::invalid_key(Bson::Null)) } #[inline] fn serialize_unit_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, ) -> Result { self.serialize_str(variant) } #[inline] fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result where T: Serialize, { value.serialize(self) } #[inline] fn serialize_newtype_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, value: &T, ) -> Result where T: Serialize, { Err(Self::invalid_key(value)) } #[inline] fn serialize_seq(self, _len: Option) -> Result { Err(Self::invalid_key(Bson::Array(vec![]))) } #[inline] fn serialize_tuple(self, _len: usize) -> Result { Err(Self::invalid_key(Bson::Array(vec![]))) } #[inline] fn serialize_tuple_struct( self, _name: &'static str, _len: usize, ) -> Result { Err(Self::invalid_key(Bson::Document(doc! {}))) } #[inline] fn serialize_tuple_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { Err(Self::invalid_key(Bson::Array(vec![]))) } #[inline] fn serialize_map(self, _len: Option) -> Result { Err(Self::invalid_key(Bson::Document(doc! {}))) } #[inline] fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { Err(Self::invalid_key(Bson::Document(doc! {}))) } #[inline] fn serialize_struct_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { Err(Self::invalid_key(Bson::Document(doc! {}))) } } bson-2.10.0/src/ser/raw/mod.rs000064400000000000000000000356571046102023000141630ustar 00000000000000mod document_serializer; mod value_serializer; use std::io::Write; use serde::{ ser::{Error as SerdeError, SerializeMap, SerializeStruct}, Serialize, }; use self::value_serializer::{ValueSerializer, ValueType}; use super::{write_binary, write_cstring, write_f64, write_i32, write_i64, write_string}; use crate::{ raw::{RAW_ARRAY_NEWTYPE, RAW_DOCUMENT_NEWTYPE}, ser::{Error, Result}, spec::{BinarySubtype, ElementType}, uuid::UUID_NEWTYPE_NAME, }; use document_serializer::DocumentSerializer; /// Serializer used to convert a type `T` into raw BSON bytes. pub(crate) struct Serializer { bytes: Vec, /// The index into `bytes` where the current element type will need to be stored. /// This needs to be set retroactively because in BSON, the element type comes before the key, /// but in serde, the serializer learns of the type after serializing the key. type_index: usize, /// Hint provided by the type being serialized. hint: SerializerHint, } /// Various bits of information that the serialized type can provide to the serializer to /// inform the purpose of the next serialization step. #[derive(Debug, Clone, Copy)] enum SerializerHint { None, /// The next call to `serialize_bytes` is for the purposes of serializing a UUID. Uuid, /// The next call to `serialize_bytes` is for the purposes of serializing a raw document. RawDocument, /// The next call to `serialize_bytes` is for the purposes of serializing a raw array. RawArray, } impl SerializerHint { fn take(&mut self) -> SerializerHint { std::mem::replace(self, SerializerHint::None) } } impl Serializer { pub(crate) fn new() -> Self { Self { bytes: Vec::new(), type_index: 0, hint: SerializerHint::None, } } /// Convert this serializer into the vec of the serialized bytes. pub(crate) fn into_vec(self) -> Vec { self.bytes } /// Reserve a spot for the element type to be set retroactively via `update_element_type`. #[inline] fn reserve_element_type(&mut self) { self.type_index = self.bytes.len(); // record index self.bytes.push(0); // push temporary placeholder } /// Retroactively set the element type of the most recently serialized element. #[inline] fn update_element_type(&mut self, t: ElementType) -> Result<()> { if self.type_index == 0 { if matches!(t, ElementType::EmbeddedDocument) { // don't need to set the element type for the top level document return Ok(()); } else { return Err(Error::custom(format!( "attempted to encode a non-document type at the top level: {:?}", t ))); } } self.bytes[self.type_index] = t as u8; Ok(()) } /// Replace an i32 value at the given index with the given value. #[inline] fn replace_i32(&mut self, at: usize, with: i32) { let portion = &mut self.bytes[at..at + 4]; portion.copy_from_slice(&with.to_le_bytes()); } } impl<'a> serde::Serializer for &'a mut Serializer { type Ok = (); type Error = Error; type SerializeSeq = DocumentSerializer<'a>; type SerializeTuple = DocumentSerializer<'a>; type SerializeTupleStruct = DocumentSerializer<'a>; type SerializeTupleVariant = VariantSerializer<'a>; type SerializeMap = DocumentSerializer<'a>; type SerializeStruct = StructSerializer<'a>; type SerializeStructVariant = VariantSerializer<'a>; fn is_human_readable(&self) -> bool { false } #[inline] fn serialize_bool(self, v: bool) -> Result { self.update_element_type(ElementType::Boolean)?; self.bytes.push(v as u8); Ok(()) } #[inline] fn serialize_i8(self, v: i8) -> Result { self.serialize_i32(v.into()) } #[inline] fn serialize_i16(self, v: i16) -> Result { self.serialize_i32(v.into()) } #[inline] fn serialize_i32(self, v: i32) -> Result { self.update_element_type(ElementType::Int32)?; write_i32(&mut self.bytes, v)?; Ok(()) } #[inline] fn serialize_i64(self, v: i64) -> Result { self.update_element_type(ElementType::Int64)?; write_i64(&mut self.bytes, v)?; Ok(()) } #[inline] fn serialize_u8(self, v: u8) -> Result { self.serialize_i32(v.into()) } #[inline] fn serialize_u16(self, v: u16) -> Result { self.serialize_i32(v.into()) } #[inline] fn serialize_u32(self, v: u32) -> Result { self.serialize_i64(v.into()) } #[inline] fn serialize_u64(self, v: u64) -> Result { use std::convert::TryFrom; match i64::try_from(v) { Ok(ivalue) => self.serialize_i64(ivalue), Err(_) => Err(Error::UnsignedIntegerExceededRange(v)), } } #[inline] fn serialize_f32(self, v: f32) -> Result { self.serialize_f64(v.into()) } #[inline] fn serialize_f64(self, v: f64) -> Result { self.update_element_type(ElementType::Double)?; write_f64(&mut self.bytes, v) } #[inline] fn serialize_char(self, v: char) -> Result { let mut s = String::new(); s.push(v); self.serialize_str(&s) } #[inline] fn serialize_str(self, v: &str) -> Result { self.update_element_type(ElementType::String)?; write_string(&mut self.bytes, v) } #[inline] fn serialize_bytes(self, v: &[u8]) -> Result { match self.hint.take() { SerializerHint::RawDocument => { self.update_element_type(ElementType::EmbeddedDocument)?; self.bytes.write_all(v)?; } SerializerHint::RawArray => { self.update_element_type(ElementType::Array)?; self.bytes.write_all(v)?; } hint => { self.update_element_type(ElementType::Binary)?; let subtype = if matches!(hint, SerializerHint::Uuid) { BinarySubtype::Uuid } else { BinarySubtype::Generic }; write_binary(&mut self.bytes, v, subtype)?; } }; Ok(()) } #[inline] fn serialize_none(self) -> Result { self.update_element_type(ElementType::Null)?; Ok(()) } #[inline] fn serialize_some(self, value: &T) -> Result where T: serde::Serialize, { value.serialize(self) } #[inline] fn serialize_unit(self) -> Result { self.serialize_none() } #[inline] fn serialize_unit_struct(self, _name: &'static str) -> Result { self.serialize_unit() } #[inline] fn serialize_unit_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, ) -> Result { self.serialize_str(variant) } #[inline] fn serialize_newtype_struct(self, name: &'static str, value: &T) -> Result where T: serde::Serialize, { match name { UUID_NEWTYPE_NAME => self.hint = SerializerHint::Uuid, RAW_DOCUMENT_NEWTYPE => self.hint = SerializerHint::RawDocument, RAW_ARRAY_NEWTYPE => self.hint = SerializerHint::RawArray, _ => {} } value.serialize(self) } #[inline] fn serialize_newtype_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, value: &T, ) -> Result where T: serde::Serialize, { self.update_element_type(ElementType::EmbeddedDocument)?; let mut d = DocumentSerializer::start(&mut *self)?; d.serialize_entry(variant, value)?; d.end_doc()?; Ok(()) } #[inline] fn serialize_seq(self, _len: Option) -> Result { self.update_element_type(ElementType::Array)?; DocumentSerializer::start(&mut *self) } #[inline] fn serialize_tuple(self, len: usize) -> Result { self.serialize_seq(Some(len)) } #[inline] fn serialize_tuple_struct( self, _name: &'static str, len: usize, ) -> Result { self.serialize_seq(Some(len)) } #[inline] fn serialize_tuple_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, _len: usize, ) -> Result { self.update_element_type(ElementType::EmbeddedDocument)?; VariantSerializer::start(&mut *self, variant, VariantInnerType::Tuple) } #[inline] fn serialize_map(self, _len: Option) -> Result { self.update_element_type(ElementType::EmbeddedDocument)?; DocumentSerializer::start(&mut *self) } #[inline] fn serialize_struct(self, name: &'static str, _len: usize) -> Result { let value_type = match name { "$oid" => Some(ValueType::ObjectId), "$date" => Some(ValueType::DateTime), "$binary" => Some(ValueType::Binary), "$timestamp" => Some(ValueType::Timestamp), "$minKey" => Some(ValueType::MinKey), "$maxKey" => Some(ValueType::MaxKey), "$code" => Some(ValueType::JavaScriptCode), "$codeWithScope" => Some(ValueType::JavaScriptCodeWithScope), "$symbol" => Some(ValueType::Symbol), "$undefined" => Some(ValueType::Undefined), "$regularExpression" => Some(ValueType::RegularExpression), "$dbPointer" => Some(ValueType::DbPointer), "$numberDecimal" => Some(ValueType::Decimal128), _ => None, }; self.update_element_type( value_type .map(Into::into) .unwrap_or(ElementType::EmbeddedDocument), )?; match value_type { Some(vt) => Ok(StructSerializer::Value(ValueSerializer::new(self, vt))), None => Ok(StructSerializer::Document(DocumentSerializer::start(self)?)), } } #[inline] fn serialize_struct_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, _len: usize, ) -> Result { self.update_element_type(ElementType::EmbeddedDocument)?; VariantSerializer::start(&mut *self, variant, VariantInnerType::Struct) } } pub(crate) enum StructSerializer<'a> { /// Serialize a BSON value currently represented in serde as a struct (e.g. ObjectId) Value(ValueSerializer<'a>), /// Serialize the struct as a document. Document(DocumentSerializer<'a>), } impl<'a> SerializeStruct for StructSerializer<'a> { type Ok = (); type Error = Error; #[inline] fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> where T: Serialize, { match self { StructSerializer::Value(ref mut v) => (&mut *v).serialize_field(key, value), StructSerializer::Document(d) => d.serialize_field(key, value), } } #[inline] fn end(self) -> Result { match self { StructSerializer::Document(d) => SerializeStruct::end(d), StructSerializer::Value(mut v) => v.end(), } } } enum VariantInnerType { Tuple, Struct, } /// Serializer used for enum variants, including both tuple (e.g. Foo::Bar(1, 2, 3)) and /// struct (e.g. Foo::Bar { a: 1 }). pub(crate) struct VariantSerializer<'a> { root_serializer: &'a mut Serializer, /// Variants are serialized as documents of the form `{ : }`, /// and `doc_start` indicates the index at which the outer document begins. doc_start: usize, /// `inner_start` indicates the index at which the inner document or array begins. inner_start: usize, /// How many elements have been serialized in the inner document / array so far. num_elements_serialized: usize, } impl<'a> VariantSerializer<'a> { fn start( rs: &'a mut Serializer, variant: &'static str, inner_type: VariantInnerType, ) -> Result { let doc_start = rs.bytes.len(); // write placeholder length for document, will be updated at end write_i32(&mut rs.bytes, 0)?; let inner = match inner_type { VariantInnerType::Struct => ElementType::EmbeddedDocument, VariantInnerType::Tuple => ElementType::Array, }; rs.bytes.push(inner as u8); write_cstring(&mut rs.bytes, variant)?; let inner_start = rs.bytes.len(); // write placeholder length for inner, will be updated at end write_i32(&mut rs.bytes, 0)?; Ok(Self { root_serializer: rs, num_elements_serialized: 0, doc_start, inner_start, }) } #[inline] fn serialize_element(&mut self, k: &str, v: &T) -> Result<()> where T: Serialize + ?Sized, { self.root_serializer.reserve_element_type(); write_cstring(&mut self.root_serializer.bytes, k)?; v.serialize(&mut *self.root_serializer)?; self.num_elements_serialized += 1; Ok(()) } #[inline] fn end_both(self) -> Result<()> { // null byte for the inner self.root_serializer.bytes.push(0); let arr_length = (self.root_serializer.bytes.len() - self.inner_start) as i32; self.root_serializer .replace_i32(self.inner_start, arr_length); // null byte for document self.root_serializer.bytes.push(0); let doc_length = (self.root_serializer.bytes.len() - self.doc_start) as i32; self.root_serializer.replace_i32(self.doc_start, doc_length); Ok(()) } } impl<'a> serde::ser::SerializeTupleVariant for VariantSerializer<'a> { type Ok = (); type Error = Error; #[inline] fn serialize_field(&mut self, value: &T) -> Result<()> where T: Serialize, { self.serialize_element(format!("{}", self.num_elements_serialized).as_str(), value) } #[inline] fn end(self) -> Result { self.end_both() } } impl<'a> serde::ser::SerializeStructVariant for VariantSerializer<'a> { type Ok = (); type Error = Error; #[inline] fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> where T: Serialize, { self.serialize_element(key, value) } #[inline] fn end(self) -> Result { self.end_both() } } bson-2.10.0/src/ser/raw/value_serializer.rs000064400000000000000000000466061046102023000167450ustar 00000000000000use std::{convert::TryFrom, io::Write}; use serde::{ ser::{Error as SerdeError, Impossible, SerializeMap, SerializeStruct}, Serialize, }; use crate::{ oid::ObjectId, raw::RAW_DOCUMENT_NEWTYPE, ser::{write_binary, write_cstring, write_i32, write_i64, write_string, Error, Result}, spec::{BinarySubtype, ElementType}, RawDocument, RawJavaScriptCodeWithScopeRef, }; use super::{document_serializer::DocumentSerializer, Serializer}; /// A serializer used specifically for serializing the serde-data-model form of a BSON type (e.g. /// [`Binary`]) to raw bytes. pub(crate) struct ValueSerializer<'a> { root_serializer: &'a mut Serializer, state: SerializationStep, } /// State machine used to track which step in the serialization of a given type the serializer is /// currently on. #[derive(Debug)] enum SerializationStep { Oid, DateTime, DateTimeNumberLong, Binary, /// This step can either transition to the raw or base64 steps depending /// on whether a string or bytes are serialized. BinaryBytes, BinarySubType { base64: String, }, RawBinarySubType { bytes: Vec, }, Symbol, RegEx, RegExPattern, RegExOptions, Timestamp, TimestampTime, TimestampIncrement { time: i64, }, DbPointer, DbPointerRef, DbPointerId, Code, CodeWithScopeCode, CodeWithScopeScope { code: String, raw: bool, }, MinKey, MaxKey, Undefined, Decimal128, Decimal128Value, Done, } /// Enum of BSON "value" types that this serializer can serialize. #[derive(Debug, Clone, Copy)] pub(super) enum ValueType { DateTime, Binary, ObjectId, Symbol, RegularExpression, Timestamp, DbPointer, JavaScriptCode, JavaScriptCodeWithScope, MinKey, MaxKey, Decimal128, Undefined, } impl From for ElementType { fn from(vt: ValueType) -> Self { match vt { ValueType::Binary => ElementType::Binary, ValueType::DateTime => ElementType::DateTime, ValueType::DbPointer => ElementType::DbPointer, ValueType::Decimal128 => ElementType::Decimal128, ValueType::Symbol => ElementType::Symbol, ValueType::RegularExpression => ElementType::RegularExpression, ValueType::Timestamp => ElementType::Timestamp, ValueType::JavaScriptCode => ElementType::JavaScriptCode, ValueType::JavaScriptCodeWithScope => ElementType::JavaScriptCodeWithScope, ValueType::MaxKey => ElementType::MaxKey, ValueType::MinKey => ElementType::MinKey, ValueType::Undefined => ElementType::Undefined, ValueType::ObjectId => ElementType::ObjectId, } } } impl<'a> ValueSerializer<'a> { pub(super) fn new(rs: &'a mut Serializer, value_type: ValueType) -> Self { let state = match value_type { ValueType::DateTime => SerializationStep::DateTime, ValueType::Binary => SerializationStep::Binary, ValueType::ObjectId => SerializationStep::Oid, ValueType::Symbol => SerializationStep::Symbol, ValueType::RegularExpression => SerializationStep::RegEx, ValueType::Timestamp => SerializationStep::Timestamp, ValueType::DbPointer => SerializationStep::DbPointer, ValueType::JavaScriptCode => SerializationStep::Code, ValueType::JavaScriptCodeWithScope => SerializationStep::CodeWithScopeCode, ValueType::MinKey => SerializationStep::MinKey, ValueType::MaxKey => SerializationStep::MaxKey, ValueType::Decimal128 => SerializationStep::Decimal128, ValueType::Undefined => SerializationStep::Undefined, }; Self { root_serializer: rs, state, } } fn invalid_step(&self, primitive_type: &'static str) -> Error { Error::custom(format!( "cannot serialize {} at step {:?}", primitive_type, self.state )) } } impl<'a, 'b> serde::Serializer for &'b mut ValueSerializer<'a> { type Ok = (); type Error = Error; type SerializeSeq = Impossible<(), Error>; type SerializeTuple = Impossible<(), Error>; type SerializeTupleStruct = Impossible<(), Error>; type SerializeTupleVariant = Impossible<(), Error>; type SerializeMap = CodeWithScopeSerializer<'b>; type SerializeStruct = Self; type SerializeStructVariant = Impossible<(), Error>; #[inline] fn serialize_bool(self, _v: bool) -> Result { Err(self.invalid_step("bool")) } #[inline] fn serialize_i8(self, _v: i8) -> Result { Err(self.invalid_step("i8")) } #[inline] fn serialize_i16(self, _v: i16) -> Result { Err(self.invalid_step("i16")) } #[inline] fn serialize_i32(self, _v: i32) -> Result { Err(self.invalid_step("i32")) } #[inline] fn serialize_i64(self, v: i64) -> Result { match self.state { SerializationStep::TimestampTime => { self.state = SerializationStep::TimestampIncrement { time: v }; Ok(()) } SerializationStep::TimestampIncrement { time } => { let t = u32::try_from(time).map_err(Error::custom)?; let i = u32::try_from(v).map_err(Error::custom)?; write_i32(&mut self.root_serializer.bytes, i as i32)?; write_i32(&mut self.root_serializer.bytes, t as i32)?; Ok(()) } _ => Err(self.invalid_step("i64")), } } #[inline] fn serialize_u8(self, v: u8) -> Result { match self.state { SerializationStep::RawBinarySubType { ref bytes } => { write_binary(&mut self.root_serializer.bytes, bytes.as_slice(), v.into())?; self.state = SerializationStep::Done; Ok(()) } _ => Err(self.invalid_step("u8")), } } #[inline] fn serialize_u16(self, _v: u16) -> Result { Err(self.invalid_step("u16")) } #[inline] fn serialize_u32(self, _v: u32) -> Result { Err(self.invalid_step("u32")) } #[inline] fn serialize_u64(self, _v: u64) -> Result { Err(self.invalid_step("u64")) } #[inline] fn serialize_f32(self, _v: f32) -> Result { Err(self.invalid_step("f32")) } #[inline] fn serialize_f64(self, _v: f64) -> Result { Err(self.invalid_step("f64")) } #[inline] fn serialize_char(self, _v: char) -> Result { Err(self.invalid_step("char")) } fn serialize_str(self, v: &str) -> Result { match &self.state { SerializationStep::DateTimeNumberLong => { let millis: i64 = v.parse().map_err(Error::custom)?; write_i64(&mut self.root_serializer.bytes, millis)?; } SerializationStep::Oid => { let oid = ObjectId::parse_str(v).map_err(Error::custom)?; self.root_serializer.bytes.write_all(&oid.bytes())?; } SerializationStep::BinaryBytes => { self.state = SerializationStep::BinarySubType { base64: v.to_string(), }; } SerializationStep::BinarySubType { base64 } => { let subtype_byte = hex::decode(v).map_err(Error::custom)?; let subtype: BinarySubtype = subtype_byte[0].into(); let bytes = base64::decode(base64.as_str()).map_err(Error::custom)?; write_binary(&mut self.root_serializer.bytes, bytes.as_slice(), subtype)?; } SerializationStep::Symbol | SerializationStep::DbPointerRef => { write_string(&mut self.root_serializer.bytes, v)?; } SerializationStep::RegExPattern => { write_cstring(&mut self.root_serializer.bytes, v)?; } SerializationStep::RegExOptions => { let mut chars: Vec<_> = v.chars().collect(); chars.sort_unstable(); let sorted = chars.into_iter().collect::(); write_cstring(&mut self.root_serializer.bytes, sorted.as_str())?; } SerializationStep::Code => { write_string(&mut self.root_serializer.bytes, v)?; } SerializationStep::CodeWithScopeCode => { self.state = SerializationStep::CodeWithScopeScope { code: v.to_string(), raw: false, }; } s => { return Err(Error::custom(format!( "can't serialize string for step {:?}", s ))) } } Ok(()) } #[inline] fn serialize_bytes(self, v: &[u8]) -> Result { match self.state { SerializationStep::Decimal128Value => { self.root_serializer.bytes.write_all(v)?; Ok(()) } SerializationStep::BinaryBytes => { self.state = SerializationStep::RawBinarySubType { bytes: v.to_vec() }; Ok(()) } SerializationStep::CodeWithScopeScope { ref code, raw } if raw => { let raw = RawJavaScriptCodeWithScopeRef { code, scope: RawDocument::from_bytes(v).map_err(Error::custom)?, }; write_i32(&mut self.root_serializer.bytes, raw.len())?; write_string(&mut self.root_serializer.bytes, code)?; self.root_serializer.bytes.write_all(v)?; self.state = SerializationStep::Done; Ok(()) } _ => Err(self.invalid_step("&[u8]")), } } #[inline] fn serialize_none(self) -> Result { Err(self.invalid_step("none")) } #[inline] fn serialize_some(self, _value: &T) -> Result where T: Serialize, { Err(self.invalid_step("some")) } #[inline] fn serialize_unit(self) -> Result { Err(self.invalid_step("unit")) } #[inline] fn serialize_unit_struct(self, _name: &'static str) -> Result { Err(self.invalid_step("unit_struct")) } #[inline] fn serialize_unit_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, ) -> Result { Err(self.invalid_step("unit_variant")) } #[inline] fn serialize_newtype_struct(self, name: &'static str, value: &T) -> Result where T: Serialize, { match (&mut self.state, name) { ( SerializationStep::CodeWithScopeScope { code: _, ref mut raw, }, RAW_DOCUMENT_NEWTYPE, ) => { *raw = true; value.serialize(self) } _ => Err(self.invalid_step("newtype_struct")), } } #[inline] fn serialize_newtype_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _value: &T, ) -> Result where T: Serialize, { Err(self.invalid_step("newtype_variant")) } #[inline] fn serialize_seq(self, _len: Option) -> Result { Err(self.invalid_step("seq")) } #[inline] fn serialize_tuple(self, _len: usize) -> Result { Err(self.invalid_step("newtype_tuple")) } #[inline] fn serialize_tuple_struct( self, _name: &'static str, _len: usize, ) -> Result { Err(self.invalid_step("tuple_struct")) } #[inline] fn serialize_tuple_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { Err(self.invalid_step("tuple_variant")) } #[inline] fn serialize_map(self, _len: Option) -> Result { match self.state { SerializationStep::CodeWithScopeScope { ref code, raw } if !raw => { CodeWithScopeSerializer::start(code.as_str(), self.root_serializer) } _ => Err(self.invalid_step("map")), } } #[inline] fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { Ok(self) } #[inline] fn serialize_struct_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { Err(self.invalid_step("struct_variant")) } fn is_human_readable(&self) -> bool { false } } impl<'a, 'b> SerializeStruct for &'b mut ValueSerializer<'a> { type Ok = (); type Error = Error; fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> where T: Serialize, { match (&self.state, key) { (SerializationStep::DateTime, "$date") => { self.state = SerializationStep::DateTimeNumberLong; value.serialize(&mut **self)?; } (SerializationStep::DateTimeNumberLong, "$numberLong") => { value.serialize(&mut **self)?; self.state = SerializationStep::Done; } (SerializationStep::Oid, "$oid") => { value.serialize(&mut **self)?; self.state = SerializationStep::Done; } (SerializationStep::Binary, "$binary") => { self.state = SerializationStep::BinaryBytes; value.serialize(&mut **self)?; } (SerializationStep::BinaryBytes, key) if key == "bytes" || key == "base64" => { // state is updated in serialize value.serialize(&mut **self)?; } (SerializationStep::RawBinarySubType { .. }, "subType") => { value.serialize(&mut **self)?; self.state = SerializationStep::Done; } (SerializationStep::BinarySubType { .. }, "subType") => { value.serialize(&mut **self)?; self.state = SerializationStep::Done; } (SerializationStep::Symbol, "$symbol") => { value.serialize(&mut **self)?; self.state = SerializationStep::Done; } (SerializationStep::RegEx, "$regularExpression") => { self.state = SerializationStep::RegExPattern; value.serialize(&mut **self)?; } (SerializationStep::RegExPattern, "pattern") => { value.serialize(&mut **self)?; self.state = SerializationStep::RegExOptions; } (SerializationStep::RegExOptions, "options") => { value.serialize(&mut **self)?; self.state = SerializationStep::Done; } (SerializationStep::Timestamp, "$timestamp") => { self.state = SerializationStep::TimestampTime; value.serialize(&mut **self)?; } (SerializationStep::TimestampTime, "t") => { // state is updated in serialize value.serialize(&mut **self)?; } (SerializationStep::TimestampIncrement { .. }, "i") => { value.serialize(&mut **self)?; self.state = SerializationStep::Done; } (SerializationStep::DbPointer, "$dbPointer") => { self.state = SerializationStep::DbPointerRef; value.serialize(&mut **self)?; } (SerializationStep::DbPointerRef, "$ref") => { value.serialize(&mut **self)?; self.state = SerializationStep::DbPointerId; } (SerializationStep::DbPointerId, "$id") => { self.state = SerializationStep::Oid; value.serialize(&mut **self)?; } (SerializationStep::Code, "$code") => { value.serialize(&mut **self)?; self.state = SerializationStep::Done; } (SerializationStep::CodeWithScopeCode, "$code") => { // state is updated in serialize value.serialize(&mut **self)?; } (SerializationStep::CodeWithScopeScope { .. }, "$scope") => { value.serialize(&mut **self)?; self.state = SerializationStep::Done; } (SerializationStep::MinKey, "$minKey") => { self.state = SerializationStep::Done; } (SerializationStep::MaxKey, "$maxKey") => { self.state = SerializationStep::Done; } (SerializationStep::Undefined, "$undefined") => { self.state = SerializationStep::Done; } (SerializationStep::Decimal128, "$numberDecimal") | (SerializationStep::Decimal128, "$numberDecimalBytes") => { self.state = SerializationStep::Decimal128Value; value.serialize(&mut **self)?; } (SerializationStep::Decimal128Value, "$numberDecimal") => { value.serialize(&mut **self)?; self.state = SerializationStep::Done; } (SerializationStep::Done, k) => { return Err(Error::custom(format!( "expected to end serialization of type, got extra key \"{}\"", k ))); } (state, k) => { return Err(Error::custom(format!( "mismatched serialization step and next key: {:?} + \"{}\"", state, k ))); } } Ok(()) } #[inline] fn end(self) -> Result { Ok(()) } } pub(crate) struct CodeWithScopeSerializer<'a> { start: usize, doc: DocumentSerializer<'a>, } impl<'a> CodeWithScopeSerializer<'a> { #[inline] fn start(code: &str, rs: &'a mut Serializer) -> Result { let start = rs.bytes.len(); write_i32(&mut rs.bytes, 0)?; // placeholder length write_string(&mut rs.bytes, code)?; let doc = DocumentSerializer::start(rs)?; Ok(Self { start, doc }) } } impl<'a> SerializeMap for CodeWithScopeSerializer<'a> { type Ok = (); type Error = Error; #[inline] fn serialize_key(&mut self, key: &T) -> Result<()> where T: Serialize, { self.doc.serialize_key(key) } #[inline] fn serialize_value(&mut self, value: &T) -> Result<()> where T: Serialize, { self.doc.serialize_value(value) } #[inline] fn end(self) -> Result { let result = self.doc.end_doc()?; let total_len = (result.root_serializer.bytes.len() - self.start) as i32; result.root_serializer.replace_i32(self.start, total_len); Ok(()) } } bson-2.10.0/src/ser/serde.rs000064400000000000000000000510771046102023000137070ustar 00000000000000use serde::ser::{ self, Error as SerdeError, Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple, SerializeTupleStruct, SerializeTupleVariant, }; use serde_bytes::Bytes; use crate::{ bson::{Array, Bson, DbPointer, Document, JavaScriptCodeWithScope, Regex, Timestamp}, datetime::DateTime, extjson, oid::ObjectId, raw::{RawDbPointerRef, RawRegexRef, RAW_ARRAY_NEWTYPE, RAW_DOCUMENT_NEWTYPE}, spec::BinarySubtype, uuid::UUID_NEWTYPE_NAME, Binary, Decimal128, }; use super::{to_bson_with_options, Error}; impl Serialize for ObjectId { #[inline] fn serialize(&self, serializer: S) -> Result where S: serde::ser::Serializer, { let mut ser = serializer.serialize_struct("$oid", 1)?; ser.serialize_field("$oid", &self.to_string())?; ser.end() } } impl Serialize for Document { #[inline] fn serialize(&self, serializer: S) -> Result where S: ser::Serializer, { let mut state = serializer.serialize_map(Some(self.len()))?; for (k, v) in self { state.serialize_entry(k, v)?; } state.end() } } impl Serialize for Bson { #[inline] fn serialize(&self, serializer: S) -> Result where S: ser::Serializer, { match self { Bson::Double(v) => serializer.serialize_f64(*v), Bson::String(v) => serializer.serialize_str(v), Bson::Array(v) => v.serialize(serializer), Bson::Document(v) => v.serialize(serializer), Bson::Boolean(v) => serializer.serialize_bool(*v), Bson::Null => serializer.serialize_unit(), Bson::Int32(v) => serializer.serialize_i32(*v), Bson::Int64(v) => serializer.serialize_i64(*v), Bson::ObjectId(oid) => oid.serialize(serializer), Bson::DateTime(dt) => dt.serialize(serializer), Bson::Binary(b) => b.serialize(serializer), Bson::JavaScriptCode(c) => { let mut state = serializer.serialize_struct("$code", 1)?; state.serialize_field("$code", c)?; state.end() } Bson::JavaScriptCodeWithScope(code_w_scope) => code_w_scope.serialize(serializer), Bson::DbPointer(dbp) => dbp.serialize(serializer), Bson::Symbol(s) => { let mut state = serializer.serialize_struct("$symbol", 1)?; state.serialize_field("$symbol", s)?; state.end() } Bson::RegularExpression(re) => re.serialize(serializer), Bson::Timestamp(t) => t.serialize(serializer), Bson::Decimal128(d) => { let mut state = serializer.serialize_struct("$numberDecimal", 1)?; state.serialize_field("$numberDecimalBytes", Bytes::new(&d.bytes))?; state.end() } Bson::Undefined => { let mut state = serializer.serialize_struct("$undefined", 1)?; state.serialize_field("$undefined", &true)?; state.end() } Bson::MaxKey => { let mut state = serializer.serialize_struct("$maxKey", 1)?; state.serialize_field("$maxKey", &1)?; state.end() } Bson::MinKey => { let mut state = serializer.serialize_struct("$minKey", 1)?; state.serialize_field("$minKey", &1)?; state.end() } } } } /// Serde Serializer #[non_exhaustive] pub struct Serializer { options: SerializerOptions, } /// Options used to configure a [`Serializer`]. #[derive(Debug, Clone, Default)] #[non_exhaustive] pub struct SerializerOptions { /// Whether the [`Serializer`] should present itself as human readable or not. /// The default value is true. pub human_readable: Option, } impl SerializerOptions { /// Create a builder used to construct a new [`SerializerOptions`]. pub fn builder() -> SerializerOptionsBuilder { SerializerOptionsBuilder { options: Default::default(), } } } /// A builder used to construct new [`SerializerOptions`] structs. pub struct SerializerOptionsBuilder { options: SerializerOptions, } impl SerializerOptionsBuilder { /// Set the value for [`SerializerOptions::is_human_readable`]. pub fn human_readable(mut self, value: impl Into>) -> Self { self.options.human_readable = value.into(); self } /// Consume this builder and produce a [`SerializerOptions`]. pub fn build(self) -> SerializerOptions { self.options } } impl Serializer { /// Construct a new [`Serializer`]. #[allow(clippy::new_without_default)] pub fn new() -> Serializer { Serializer { options: Default::default(), } } /// Construct a new [`Serializer`] configured with the provided [`SerializerOptions`]. pub fn new_with_options(options: SerializerOptions) -> Self { Serializer { options } } } impl ser::Serializer for Serializer { type Ok = Bson; type Error = Error; type SerializeSeq = ArraySerializer; type SerializeTuple = TupleSerializer; type SerializeTupleStruct = TupleStructSerializer; type SerializeTupleVariant = TupleVariantSerializer; type SerializeMap = MapSerializer; type SerializeStruct = StructSerializer; type SerializeStructVariant = StructVariantSerializer; #[inline] fn serialize_bool(self, value: bool) -> crate::ser::Result { Ok(Bson::Boolean(value)) } #[inline] fn serialize_i8(self, value: i8) -> crate::ser::Result { self.serialize_i32(value as i32) } #[inline] fn serialize_u8(self, value: u8) -> crate::ser::Result { Ok(Bson::Int32(value as i32)) } #[inline] fn serialize_i16(self, value: i16) -> crate::ser::Result { self.serialize_i32(value as i32) } #[inline] fn serialize_u16(self, value: u16) -> crate::ser::Result { Ok(Bson::Int32(value as i32)) } #[inline] fn serialize_i32(self, value: i32) -> crate::ser::Result { Ok(Bson::Int32(value)) } #[inline] fn serialize_u32(self, value: u32) -> crate::ser::Result { Ok(Bson::Int64(value as i64)) } #[inline] fn serialize_i64(self, value: i64) -> crate::ser::Result { Ok(Bson::Int64(value)) } #[inline] fn serialize_u64(self, value: u64) -> crate::ser::Result { use std::convert::TryFrom; match i64::try_from(value) { Ok(ivalue) => Ok(Bson::Int64(ivalue)), Err(_) => Err(Error::UnsignedIntegerExceededRange(value)), } } #[inline] fn serialize_f32(self, value: f32) -> crate::ser::Result { self.serialize_f64(value as f64) } #[inline] fn serialize_f64(self, value: f64) -> crate::ser::Result { Ok(Bson::Double(value)) } #[inline] fn serialize_char(self, value: char) -> crate::ser::Result { let mut s = String::new(); s.push(value); self.serialize_str(&s) } #[inline] fn serialize_str(self, value: &str) -> crate::ser::Result { Ok(Bson::String(value.to_string())) } fn serialize_bytes(self, value: &[u8]) -> crate::ser::Result { // let mut state = self.serialize_seq(Some(value.len()))?; // for byte in value { // state.serialize_element(byte)?; // } // state.end() Ok(Bson::Binary(Binary { subtype: BinarySubtype::Generic, bytes: value.to_vec(), })) } #[inline] fn serialize_none(self) -> crate::ser::Result { self.serialize_unit() } #[inline] fn serialize_some(self, value: &V) -> crate::ser::Result where V: Serialize, { value.serialize(self) } #[inline] fn serialize_unit(self) -> crate::ser::Result { Ok(Bson::Null) } #[inline] fn serialize_unit_struct(self, _name: &'static str) -> crate::ser::Result { self.serialize_unit() } #[inline] fn serialize_unit_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, ) -> crate::ser::Result { Ok(Bson::String(variant.to_string())) } #[inline] fn serialize_newtype_struct( self, name: &'static str, value: &T, ) -> crate::ser::Result where T: Serialize, { match name { UUID_NEWTYPE_NAME => { let is_human_readable = self.is_human_readable(); match value.serialize(self)? { Bson::String(s) if is_human_readable => { // the serializer reports itself as human readable, so [`Uuid`] will // serialize itself as a string. let uuid = crate::Uuid::parse_str(s).map_err(Error::custom)?; Ok(Bson::Binary(uuid.into())) } Bson::Binary(b) if !is_human_readable => Ok(Bson::Binary(Binary { bytes: b.bytes, subtype: BinarySubtype::Uuid, })), b => { let expectation = if is_human_readable { "a string" } else { "bytes" }; Err(Error::custom(format!( "expected UUID to be serialized as {} but got {:?} instead", expectation, b ))) } } } // when in non-human-readable mode, raw document / raw array will serialize as bytes. RAW_DOCUMENT_NEWTYPE | RAW_ARRAY_NEWTYPE if !self.is_human_readable() => match value .serialize(self)? { Bson::Binary(b) => { let doc = Document::from_reader(b.bytes.as_slice()).map_err(Error::custom)?; if name == RAW_DOCUMENT_NEWTYPE { Ok(Bson::Document(doc)) } else { Ok(Bson::Array(doc.into_iter().map(|kvp| kvp.1).collect())) } } b => Err(Error::custom(format!( "expected raw document or array to be serialized as bytes but got {:?} instead", b ))), }, _ => value.serialize(self), } } #[inline] fn serialize_newtype_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, value: &T, ) -> crate::ser::Result where T: Serialize, { let mut newtype_variant = Document::new(); newtype_variant.insert(variant, to_bson_with_options(value, self.options)?); Ok(newtype_variant.into()) } #[inline] fn serialize_seq(self, len: Option) -> crate::ser::Result { Ok(ArraySerializer { inner: Array::with_capacity(len.unwrap_or(0)), options: self.options, }) } #[inline] fn serialize_tuple(self, len: usize) -> crate::ser::Result { Ok(TupleSerializer { inner: Array::with_capacity(len), options: self.options, }) } #[inline] fn serialize_tuple_struct( self, _name: &'static str, len: usize, ) -> crate::ser::Result { Ok(TupleStructSerializer { inner: Array::with_capacity(len), options: self.options, }) } #[inline] fn serialize_tuple_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, len: usize, ) -> crate::ser::Result { Ok(TupleVariantSerializer { inner: Array::with_capacity(len), name: variant, options: self.options, }) } #[inline] fn serialize_map(self, _len: Option) -> crate::ser::Result { Ok(MapSerializer { inner: Document::new(), next_key: None, options: self.options, }) } #[inline] fn serialize_struct( self, _name: &'static str, _len: usize, ) -> crate::ser::Result { Ok(StructSerializer { inner: Document::new(), options: self.options, }) } #[inline] fn serialize_struct_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, _len: usize, ) -> crate::ser::Result { Ok(StructVariantSerializer { name: variant, inner: Document::new(), options: self.options, }) } fn is_human_readable(&self) -> bool { self.options.human_readable.unwrap_or(true) } } #[doc(hidden)] pub struct ArraySerializer { inner: Array, options: SerializerOptions, } impl SerializeSeq for ArraySerializer { type Ok = Bson; type Error = Error; fn serialize_element(&mut self, value: &T) -> crate::ser::Result<()> { self.inner .push(to_bson_with_options(value, self.options.clone())?); Ok(()) } fn end(self) -> crate::ser::Result { Ok(Bson::Array(self.inner)) } } #[doc(hidden)] pub struct TupleSerializer { inner: Array, options: SerializerOptions, } impl SerializeTuple for TupleSerializer { type Ok = Bson; type Error = Error; fn serialize_element(&mut self, value: &T) -> crate::ser::Result<()> { self.inner .push(to_bson_with_options(value, self.options.clone())?); Ok(()) } fn end(self) -> crate::ser::Result { Ok(Bson::Array(self.inner)) } } #[doc(hidden)] pub struct TupleStructSerializer { inner: Array, options: SerializerOptions, } impl SerializeTupleStruct for TupleStructSerializer { type Ok = Bson; type Error = Error; fn serialize_field(&mut self, value: &T) -> crate::ser::Result<()> { self.inner .push(to_bson_with_options(value, self.options.clone())?); Ok(()) } fn end(self) -> crate::ser::Result { Ok(Bson::Array(self.inner)) } } #[doc(hidden)] pub struct TupleVariantSerializer { inner: Array, name: &'static str, options: SerializerOptions, } impl SerializeTupleVariant for TupleVariantSerializer { type Ok = Bson; type Error = Error; fn serialize_field(&mut self, value: &T) -> crate::ser::Result<()> { self.inner .push(to_bson_with_options(value, self.options.clone())?); Ok(()) } fn end(self) -> crate::ser::Result { let mut tuple_variant = Document::new(); tuple_variant.insert(self.name, self.inner); Ok(tuple_variant.into()) } } #[doc(hidden)] pub struct MapSerializer { inner: Document, next_key: Option, options: SerializerOptions, } impl SerializeMap for MapSerializer { type Ok = Bson; type Error = Error; fn serialize_key(&mut self, key: &T) -> crate::ser::Result<()> { self.next_key = match to_bson_with_options(&key, self.options.clone())? { Bson::String(s) => Some(s), other => return Err(Error::InvalidDocumentKey(other)), }; Ok(()) } fn serialize_value(&mut self, value: &T) -> crate::ser::Result<()> { let key = self.next_key.take().unwrap_or_default(); self.inner .insert(key, to_bson_with_options(&value, self.options.clone())?); Ok(()) } fn end(self) -> crate::ser::Result { Ok(Bson::from_extended_document(self.inner)) } } #[doc(hidden)] pub struct StructSerializer { inner: Document, options: SerializerOptions, } impl SerializeStruct for StructSerializer { type Ok = Bson; type Error = Error; fn serialize_field( &mut self, key: &'static str, value: &T, ) -> crate::ser::Result<()> { self.inner .insert(key, to_bson_with_options(value, self.options.clone())?); Ok(()) } fn end(self) -> crate::ser::Result { Ok(Bson::from_extended_document(self.inner)) } } #[doc(hidden)] pub struct StructVariantSerializer { inner: Document, name: &'static str, options: SerializerOptions, } impl SerializeStructVariant for StructVariantSerializer { type Ok = Bson; type Error = Error; fn serialize_field( &mut self, key: &'static str, value: &T, ) -> crate::ser::Result<()> { self.inner .insert(key, to_bson_with_options(value, self.options.clone())?); Ok(()) } fn end(self) -> crate::ser::Result { let var = Bson::from_extended_document(self.inner); let mut struct_variant = Document::new(); struct_variant.insert(self.name, var); Ok(Bson::Document(struct_variant)) } } impl Serialize for Timestamp { #[inline] fn serialize(&self, serializer: S) -> Result where S: ser::Serializer, { let mut state = serializer.serialize_struct("$timestamp", 1)?; let body = extjson::models::TimestampBody { t: self.time, i: self.increment, }; state.serialize_field("$timestamp", &body)?; state.end() } } impl Serialize for Regex { #[inline] fn serialize(&self, serializer: S) -> Result where S: ser::Serializer, { let raw = RawRegexRef { pattern: self.pattern.as_str(), options: self.options.as_str(), }; raw.serialize(serializer) } } impl Serialize for JavaScriptCodeWithScope { #[inline] fn serialize(&self, serializer: S) -> Result where S: ser::Serializer, { let mut state = serializer.serialize_struct("$codeWithScope", 2)?; state.serialize_field("$code", &self.code)?; state.serialize_field("$scope", &self.scope)?; state.end() } } impl Serialize for Binary { #[inline] fn serialize(&self, serializer: S) -> Result where S: ser::Serializer, { if let BinarySubtype::Generic = self.subtype { serializer.serialize_bytes(self.bytes.as_slice()) } else { let mut state = serializer.serialize_struct("$binary", 1)?; let body = extjson::models::BinaryBody { base64: base64::encode(self.bytes.as_slice()), subtype: hex::encode([self.subtype.into()]), }; state.serialize_field("$binary", &body)?; state.end() } } } impl Serialize for Decimal128 { #[inline] fn serialize(&self, serializer: S) -> Result where S: ser::Serializer, { if serializer.is_human_readable() { let mut state = serializer.serialize_map(Some(1))?; state.serialize_entry("$numberDecimal", &self.to_string())?; state.end() } else { let mut state = serializer.serialize_struct("$numberDecimal", 1)?; state.serialize_field("$numberDecimalBytes", serde_bytes::Bytes::new(&self.bytes))?; state.end() } } } impl Serialize for DateTime { #[inline] fn serialize(&self, serializer: S) -> Result where S: ser::Serializer, { let mut state = serializer.serialize_struct("$date", 1)?; let body = extjson::models::DateTimeBody::from_millis(self.timestamp_millis()); state.serialize_field("$date", &body)?; state.end() } } impl Serialize for DbPointer { #[inline] fn serialize(&self, serializer: S) -> Result where S: ser::Serializer, { let raw = RawDbPointerRef { namespace: self.namespace.as_str(), id: self.id, }; raw.serialize(serializer) } } bson-2.10.0/src/serde_helpers.rs000064400000000000000000000634061046102023000146370ustar 00000000000000//! Collection of helper functions for serializing to and deserializing from BSON using Serde use std::{convert::TryFrom, result::Result}; use serde::{ser, Serialize, Serializer}; use crate::oid::ObjectId; #[doc(inline)] pub use bson_datetime_as_rfc3339_string::{ deserialize as deserialize_bson_datetime_from_rfc3339_string, serialize as serialize_bson_datetime_as_rfc3339_string, }; #[cfg(feature = "chrono-0_4")] #[doc(inline)] pub use chrono_datetime_as_bson_datetime::{ deserialize as deserialize_chrono_datetime_from_bson_datetime, serialize as serialize_chrono_datetime_as_bson_datetime, }; #[doc(inline)] pub use hex_string_as_object_id::{ deserialize as deserialize_hex_string_from_object_id, serialize as serialize_hex_string_as_object_id, }; #[doc(inline)] pub use i64_as_bson_datetime::{ deserialize as deserialize_i64_from_bson_datetime, serialize as serialize_i64_as_bson_datetime, }; #[doc(inline)] pub use rfc3339_string_as_bson_datetime::{ deserialize as deserialize_rfc3339_string_from_bson_datetime, serialize as serialize_rfc3339_string_as_bson_datetime, }; #[cfg(feature = "time-0_3")] #[doc(inline)] pub use time_0_3_offsetdatetime_as_bson_datetime::{ deserialize as deserialize_time_0_3_offsetdatetime_from_bson_datetime, serialize as serialize_time_0_3_offsetdatetime_as_bson_datetime, }; #[doc(inline)] pub use timestamp_as_u32::{ deserialize as deserialize_timestamp_from_u32, serialize as serialize_timestamp_as_u32, }; #[doc(inline)] pub use u32_as_f64::{deserialize as deserialize_u32_from_f64, serialize as serialize_u32_as_f64}; #[doc(inline)] pub use u32_as_timestamp::{ deserialize as deserialize_u32_from_timestamp, serialize as serialize_u32_as_timestamp, }; #[doc(inline)] pub use u64_as_f64::{deserialize as deserialize_u64_from_f64, serialize as serialize_u64_as_f64}; #[cfg(feature = "uuid-1")] #[doc(inline)] pub use uuid_1_as_binary::{ deserialize as deserialize_uuid_1_from_binary, serialize as serialize_uuid_1_as_binary, }; #[cfg(feature = "uuid-1")] #[doc(inline)] pub use uuid_1_as_c_sharp_legacy_binary::{ deserialize as deserialize_uuid_1_from_c_sharp_legacy_binary, serialize as serialize_uuid_1_as_c_sharp_legacy_binary, }; #[cfg(feature = "uuid-1")] #[doc(inline)] pub use uuid_1_as_java_legacy_binary::{ deserialize as deserialize_uuid_1_from_java_legacy_binary, serialize as serialize_uuid_1_as_java_legacy_binary, }; #[cfg(feature = "uuid-1")] #[doc(inline)] pub use uuid_1_as_python_legacy_binary::{ deserialize as deserialize_uuid_1_from_python_legacy_binary, serialize as serialize_uuid_1_as_python_legacy_binary, }; #[cfg(feature = "uuid-0_8")] #[doc(inline)] pub use uuid_as_binary::{ deserialize as deserialize_uuid_from_binary, serialize as serialize_uuid_as_binary, }; #[cfg(feature = "uuid-0_8")] #[doc(inline)] pub use uuid_as_c_sharp_legacy_binary::{ deserialize as deserialize_uuid_from_c_sharp_legacy_binary, serialize as serialize_uuid_as_c_sharp_legacy_binary, }; #[cfg(feature = "uuid-0_8")] #[doc(inline)] pub use uuid_as_java_legacy_binary::{ deserialize as deserialize_uuid_from_java_legacy_binary, serialize as serialize_uuid_as_java_legacy_binary, }; #[cfg(feature = "uuid-0_8")] #[doc(inline)] pub use uuid_as_python_legacy_binary::{ deserialize as deserialize_uuid_from_python_legacy_binary, serialize as serialize_uuid_as_python_legacy_binary, }; /// Attempts to serialize a u32 as an i32. Errors if an exact conversion is not possible. pub fn serialize_u32_as_i32(val: &u32, serializer: S) -> Result { match i32::try_from(*val) { Ok(val) => serializer.serialize_i32(val), Err(_) => Err(ser::Error::custom(format!("cannot convert {} to i32", val))), } } /// Serializes a u32 as an i64. pub fn serialize_u32_as_i64(val: &u32, serializer: S) -> Result { serializer.serialize_i64(*val as i64) } /// Attempts to serialize a u64 as an i32. Errors if an exact conversion is not possible. pub fn serialize_u64_as_i32(val: &u64, serializer: S) -> Result { match i32::try_from(*val) { Ok(val) => serializer.serialize_i32(val), Err(_) => Err(ser::Error::custom(format!("cannot convert {} to i32", val))), } } /// Attempts to serialize a u64 as an i64. Errors if an exact conversion is not possible. pub fn serialize_u64_as_i64(val: &u64, serializer: S) -> Result { match i64::try_from(*val) { Ok(val) => serializer.serialize_i64(val), Err(_) => Err(ser::Error::custom(format!("cannot convert {} to i64", val))), } } /// Serializes an [`ObjectId`] as a hex string. pub fn serialize_object_id_as_hex_string( val: &ObjectId, serializer: S, ) -> Result { val.to_hex().serialize(serializer) } /// Contains functions to serialize a u32 as an f64 (BSON double) and deserialize a /// u32 from an f64 (BSON double). /// /// ```rust /// # use serde::{Serialize, Deserialize}; /// # use bson::serde_helpers::u32_as_f64; /// #[derive(Serialize, Deserialize)] /// struct FileInfo { /// #[serde(with = "u32_as_f64")] /// pub size_bytes: u32, /// } /// ``` pub mod u32_as_f64 { use serde::{de, Deserialize, Deserializer, Serializer}; /// Deserializes a u32 from an f64 (BSON double). Errors if an exact conversion is not possible. pub fn deserialize<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { let f = f64::deserialize(deserializer)?; if (f - f as u32 as f64).abs() <= f64::EPSILON { Ok(f as u32) } else { Err(de::Error::custom(format!( "cannot convert f64 (BSON double) {} to u32", f ))) } } /// Serializes a u32 as an f64 (BSON double). pub fn serialize(val: &u32, serializer: S) -> Result { serializer.serialize_f64(*val as f64) } } /// Contains functions to serialize a u64 as an f64 (BSON double) and deserialize a /// u64 from an f64 (BSON double). /// /// ```rust /// # use serde::{Serialize, Deserialize}; /// # use bson::serde_helpers::u64_as_f64; /// #[derive(Serialize, Deserialize)] /// struct FileInfo { /// #[serde(with = "u64_as_f64")] /// pub size_bytes: u64, /// } /// ``` pub mod u64_as_f64 { use serde::{de, ser, Deserialize, Deserializer, Serializer}; /// Deserializes a u64 from an f64 (BSON double). Errors if an exact conversion is not possible. pub fn deserialize<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { let f = f64::deserialize(deserializer)?; if (f - f as u64 as f64).abs() <= f64::EPSILON { Ok(f as u64) } else { Err(de::Error::custom(format!( "cannot convert f64 (BSON double) {} to u64", f ))) } } /// Serializes a u64 as an f64 (BSON double). Errors if an exact conversion is not possible. pub fn serialize(val: &u64, serializer: S) -> Result { if val < &u64::MAX && *val == *val as f64 as u64 { serializer.serialize_f64(*val as f64) } else { Err(ser::Error::custom(format!( "cannot convert u64 {} to f64 (BSON double)", val ))) } } } /// Contains functions to serialize a [`time::OffsetDateTime`] as a [`crate::DateTime`] and /// deserialize a [`time::OffsetDateTime`] from a [`crate::DateTime`]. /// /// ```rust /// # #[cfg(feature = "time-0_3")] /// # { /// # use serde::{Serialize, Deserialize}; /// # use bson::serde_helpers::time_0_3_offsetdatetime_as_bson_datetime; /// #[derive(Serialize, Deserialize)] /// struct Event { /// #[serde(with = "time_0_3_offsetdatetime_as_bson_datetime")] /// pub date: time::OffsetDateTime, /// } /// # } /// ``` #[cfg(feature = "time-0_3")] #[cfg_attr(docsrs, doc(cfg(feature = "time-0_3")))] pub mod time_0_3_offsetdatetime_as_bson_datetime { use crate::DateTime; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::result::Result; /// Deserializes a [`time::OffsetDateTime`] from a [`crate::DateTime`]. #[cfg_attr(docsrs, doc(cfg(feature = "time-0_3")))] pub fn deserialize<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { let datetime = DateTime::deserialize(deserializer)?; Ok(datetime.to_time_0_3()) } /// Serializes a [`time::OffsetDateTime`] as a [`crate::DateTime`]. #[cfg_attr(docsrs, doc(cfg(feature = "time-0_3")))] pub fn serialize( val: &time::OffsetDateTime, serializer: S, ) -> Result { let datetime = DateTime::from_time_0_3(val.to_owned()); datetime.serialize(serializer) } } /// Contains functions to serialize a [`chrono::DateTime`] as a [`crate::DateTime`] and deserialize /// a [`chrono::DateTime`] from a [`crate::DateTime`]. /// /// ```rust /// # #[cfg(feature = "chrono-0_4")] /// # { /// # use serde::{Serialize, Deserialize}; /// # use bson::serde_helpers::chrono_datetime_as_bson_datetime; /// #[derive(Serialize, Deserialize)] /// struct Event { /// #[serde(with = "chrono_datetime_as_bson_datetime")] /// pub date: chrono::DateTime, /// } /// # } /// ``` #[cfg(feature = "chrono-0_4")] #[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))] pub mod chrono_datetime_as_bson_datetime { use crate::DateTime; use chrono::Utc; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::result::Result; /// Deserializes a [`chrono::DateTime`] from a [`crate::DateTime`]. #[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))] pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { let datetime = DateTime::deserialize(deserializer)?; Ok(datetime.to_chrono()) } /// Serializes a [`chrono::DateTime`] as a [`crate::DateTime`]. #[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))] pub fn serialize( val: &chrono::DateTime, serializer: S, ) -> Result { let datetime = DateTime::from_chrono(val.to_owned()); datetime.serialize(serializer) } } /// Contains functions to serialize an RFC 3339 (ISO 8601) formatted string as a [`crate::DateTime`] /// and deserialize an RFC 3339 (ISO 8601) formatted string from a [`crate::DateTime`]. /// /// ```rust /// # use serde::{Serialize, Deserialize}; /// # use bson::serde_helpers::rfc3339_string_as_bson_datetime; /// #[derive(Serialize, Deserialize)] /// struct Event { /// #[serde(with = "rfc3339_string_as_bson_datetime")] /// pub date: String, /// } /// ``` pub mod rfc3339_string_as_bson_datetime { use crate::{Bson, DateTime}; use serde::{de, ser, Deserialize, Deserializer, Serialize, Serializer}; use std::result::Result; /// Deserializes an ISO string from a DateTime. pub fn deserialize<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { let date = DateTime::deserialize(deserializer)?; date.try_to_rfc3339_string() .map_err(|e| de::Error::custom(format!("cannot format {} as RFC 3339: {}", date, e))) } /// Serializes an ISO string as a DateTime. pub fn serialize(val: &str, serializer: S) -> Result { let date = crate::DateTime::parse_rfc3339_str(val) .map_err(|_| ser::Error::custom(format!("cannot convert {} to DateTime", val)))?; Bson::DateTime(date).serialize(serializer) } } /// Contains functions to serialize a [`crate::DateTime`] as an RFC 3339 (ISO 8601) formatted string /// and deserialize a [`crate::DateTime`] from an RFC 3339 (ISO 8601) formatted string. /// /// ```rust /// # use serde::{Serialize, Deserialize}; /// # use bson::serde_helpers::bson_datetime_as_rfc3339_string; /// #[derive(Serialize, Deserialize)] /// struct Event { /// #[serde(with = "bson_datetime_as_rfc3339_string")] /// pub date: bson::DateTime, /// } /// ``` pub mod bson_datetime_as_rfc3339_string { use crate::DateTime; use serde::{de, ser, Deserialize, Deserializer, Serializer}; use std::result::Result; /// Deserializes a [`crate::DateTime`] from an RFC 3339 formatted string. pub fn deserialize<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { let iso = String::deserialize(deserializer)?; let date = crate::DateTime::parse_rfc3339_str(&iso).map_err(|_| { de::Error::custom(format!("cannot parse RFC 3339 datetime from \"{}\"", iso)) })?; Ok(date) } /// Serializes a [`crate::DateTime`] as an RFC 3339 (ISO 8601) formatted string. pub fn serialize(val: &DateTime, serializer: S) -> Result { let formatted = val .try_to_rfc3339_string() .map_err(|e| ser::Error::custom(format!("cannot format {} as RFC 3339: {}", val, e)))?; serializer.serialize_str(&formatted) } } /// Contains functions to serialize a hex string as an ObjectId and deserialize a /// hex string from an ObjectId /// /// ```rust /// # use serde::{Serialize, Deserialize}; /// # use bson::serde_helpers::hex_string_as_object_id; /// #[derive(Serialize, Deserialize)] /// struct Item { /// #[serde(with = "hex_string_as_object_id")] /// pub id: String, /// } /// ``` pub mod hex_string_as_object_id { use crate::oid::ObjectId; use serde::{ser, Deserialize, Deserializer, Serialize, Serializer}; /// Deserializes a hex string from an ObjectId. pub fn deserialize<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { let object_id = ObjectId::deserialize(deserializer)?; Ok(object_id.to_hex()) } /// Serializes a hex string as an ObjectId. pub fn serialize(val: &str, serializer: S) -> Result { match ObjectId::parse_str(val) { Ok(oid) => oid.serialize(serializer), Err(_) => Err(ser::Error::custom(format!( "cannot convert {} to ObjectId", val ))), } } } /// Contains functions to `serialize` a `i64` integer as [`DateTime`](crate::DateTime) and /// `deserialize` a `i64` integer from [`DateTime`](crate::DateTime). /// /// ### The i64 should represent seconds `(DateTime::timestamp_millis(..))`. /// /// ```rust /// # use serde::{Serialize, Deserialize}; /// # use bson::serde_helpers::i64_as_bson_datetime; /// #[derive(Serialize, Deserialize)] /// struct Item { /// #[serde(with = "i64_as_bson_datetime")] /// pub now: i64, /// } /// ``` pub mod i64_as_bson_datetime { use crate::DateTime; use serde::{Deserialize, Deserializer, Serialize, Serializer}; /// Deserializes a i64 integer from a DateTime. pub fn deserialize<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { let date: DateTime = DateTime::deserialize(deserializer)?; Ok(date.timestamp_millis()) } /// Serializes a i64 integer as a DateTime. pub fn serialize(val: &i64, serializer: S) -> Result { let date_time = DateTime::from_millis(*val); date_time.serialize(serializer) } } #[allow(unused_macros)] macro_rules! as_binary_mod { ($feat:meta, $uu:path) => { use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::result::Result; use $uu; /// Serializes a Uuid as a Binary. #[cfg_attr(docsrs, doc($feat))] pub fn serialize(val: &Uuid, serializer: S) -> Result { crate::uuid::Uuid::from(*val).serialize(serializer) } /// Deserializes a Uuid from a Binary. #[cfg_attr(docsrs, doc($feat))] pub fn deserialize<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { let bson_uuid = crate::uuid::Uuid::deserialize(deserializer)?; Ok(bson_uuid.into()) } }; } /// Contains functions to serialize a [`uuid_0_8::Uuid`] as a [`crate::Binary`] and deserialize a /// [`uuid_0_8::Uuid`] from a [`crate::Binary`]. /// /// ```rust /// # #[cfg(feature = "uuid-0_8")] /// # { /// use serde::{Serialize, Deserialize}; /// use uuid_0_8::Uuid; /// use bson::serde_helpers::uuid_as_binary; /// /// #[derive(Serialize, Deserialize)] /// struct Item { /// #[serde(with = "uuid_as_binary")] /// pub id: Uuid, /// } /// # } /// ``` #[cfg(feature = "uuid-0_8")] #[cfg_attr(docsrs, doc(cfg(feature = "uuid-0_8")))] pub mod uuid_as_binary { as_binary_mod!(cfg(feature = "uuid-0_8"), uuid_0_8::Uuid); } /// Contains functions to serialize a [`uuid::Uuid`] as a [`crate::Binary`] and deserialize a /// [`uuid::Uuid`] from a [`crate::Binary`]. /// /// ```rust /// # #[cfg(feature = "uuid-1")] /// # { /// use serde::{Serialize, Deserialize}; /// use uuid::Uuid; /// use bson::serde_helpers::uuid_1_as_binary; /// /// #[derive(Serialize, Deserialize)] /// struct Item { /// #[serde(with = "uuid_1_as_binary")] /// pub id: Uuid, /// } /// # } /// ``` #[cfg(feature = "uuid-1")] #[cfg_attr(docsrs, doc(cfg(feature = "uuid-1")))] pub mod uuid_1_as_binary { as_binary_mod!(cfg(feature = "uuid-1"), uuid::Uuid); } #[allow(unused_macros)] macro_rules! as_legacy_binary_mod { ($feat:meta, $uu:path, $rep:path) => { use crate::{uuid::UuidRepresentation, Binary}; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use std::result::Result; use $uu; /// Serializes a Uuid as a Binary in the legacy UUID format. #[cfg_attr(docsrs, doc($feat))] pub fn serialize(val: &Uuid, serializer: S) -> Result { let binary = Binary::from_uuid_with_representation(crate::uuid::Uuid::from(*val), $rep); binary.serialize(serializer) } /// Deserializes a Uuid from a Binary in the legacy UUID format. #[cfg_attr(docsrs, doc($feat))] pub fn deserialize<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { let binary = Binary::deserialize(deserializer)?; let uuid = binary .to_uuid_with_representation($rep) .map_err(de::Error::custom)?; Ok(uuid.into()) } }; } /// Contains functions to serialize a [`uuid_0_8::Uuid`] to a [`crate::Binary`] in the legacy /// Java driver UUID format and deserialize [`uuid_0_8::Uuid`] from a [`crate::Binary`] in the /// legacy Java driver format. /// /// ```rust /// #[cfg(feature = "uuid-0_8")] /// # { /// use serde::{Serialize, Deserialize}; /// use uuid_0_8::Uuid; /// use bson::serde_helpers::uuid_as_java_legacy_binary; /// /// #[derive(Serialize, Deserialize)] /// struct Item { /// #[serde(with = "uuid_as_java_legacy_binary")] /// pub id: Uuid, /// } /// # } /// ``` #[cfg(feature = "uuid-0_8")] #[cfg_attr(docsrs, doc(cfg(feature = "uuid-0_8")))] pub mod uuid_as_java_legacy_binary { as_legacy_binary_mod!( cfg(feature = "uuid-0_8"), uuid_0_8::Uuid, UuidRepresentation::JavaLegacy ); } /// Contains functions to serialize a [`uuid::Uuid`] to a [`crate::Binary`] in the legacy /// Java driver UUID format and deserialize [`uuid::Uuid`] from a [`crate::Binary`] in the legacy /// Java driver format. /// /// ```rust /// #[cfg(feature = "uuid-1")] /// # { /// use serde::{Serialize, Deserialize}; /// use uuid::Uuid; /// use bson::serde_helpers::uuid_1_as_java_legacy_binary; /// /// #[derive(Serialize, Deserialize)] /// struct Item { /// #[serde(with = "uuid_1_as_java_legacy_binary")] /// pub id: Uuid, /// } /// # } /// ``` #[cfg(feature = "uuid-1")] #[cfg_attr(docsrs, doc(cfg(feature = "uuid-1")))] pub mod uuid_1_as_java_legacy_binary { as_legacy_binary_mod!( cfg(feature = "uuid-1"), uuid::Uuid, UuidRepresentation::JavaLegacy ); } /// Contains functions to serialize a [`uuid_0_8::Uuid`] to a [`crate::Binary`] in the legacy Python /// driver UUID format and deserialize [`uuid_0_8::Uuid`] from a [`crate::Binary`] in the legacy /// Python driver format. /// /// ```rust /// # #[cfg(feature = "uuid-0_8")] /// # { /// use serde::{Serialize, Deserialize}; /// use uuid_0_8::Uuid; /// use bson::serde_helpers::uuid_as_python_legacy_binary; /// /// #[derive(Serialize, Deserialize)] /// struct Item { /// #[serde(with = "uuid_as_python_legacy_binary")] /// pub id: Uuid, /// } /// # } /// ``` #[cfg(feature = "uuid-0_8")] #[cfg_attr(docsrs, doc(cfg(feature = "uuid-0_8")))] pub mod uuid_as_python_legacy_binary { as_legacy_binary_mod!( cfg(feature = "uuid-0_8"), uuid_0_8::Uuid, UuidRepresentation::PythonLegacy ); } /// Contains functions to serialize a [`uuid::Uuid`] to a [`crate::Binary`] in the legacy Python /// driver UUID format and deserialize [`uuid::Uuid`] from a [`crate::Binary`] in the legacy Python /// driver format. /// /// ```rust /// # #[cfg(feature = "uuid-1")] /// # { /// use serde::{Serialize, Deserialize}; /// use uuid::Uuid; /// use bson::serde_helpers::uuid_1_as_python_legacy_binary; /// /// #[derive(Serialize, Deserialize)] /// struct Item { /// #[serde(with = "uuid_1_as_python_legacy_binary")] /// pub id: Uuid, /// } /// # } /// ``` #[cfg(feature = "uuid-1")] #[cfg_attr(docsrs, doc(cfg(feature = "uuid-1")))] pub mod uuid_1_as_python_legacy_binary { as_legacy_binary_mod!( cfg(feature = "uuid-1"), uuid::Uuid, UuidRepresentation::PythonLegacy ); } /// Contains functions to serialize a [`uuid_0_8::Uuid`] to a [`crate::Binary`] in the legacy C# /// driver UUID format and deserialize [`uuid_0_8::Uuid`] from a [`crate::Binary`] in the legacy C# /// driver format. /// /// ```rust /// # #[cfg(feature = "uuid-0_8")] /// # { /// use serde::{Serialize, Deserialize}; /// use uuid_0_8::Uuid; /// use bson::serde_helpers::uuid_as_c_sharp_legacy_binary; /// /// #[derive(Serialize, Deserialize)] /// struct Item { /// #[serde(with = "uuid_as_c_sharp_legacy_binary")] /// pub id: Uuid, /// } /// # } /// ``` #[cfg(feature = "uuid-0_8")] #[cfg_attr(docsrs, doc(cfg(feature = "uuid-0_8")))] pub mod uuid_as_c_sharp_legacy_binary { as_legacy_binary_mod!( cfg(feature = "uuid-0_8"), uuid_0_8::Uuid, UuidRepresentation::CSharpLegacy ); } /// Contains functions to serialize a [`uuid::Uuid`] to a [`crate::Binary`] in the legacy C# driver /// UUID format and deserialize [`uuid::Uuid`] from a [`crate::Binary`] in the legacy C# driver /// format. /// /// ```rust /// # #[cfg(feature = "uuid-1")] /// # { /// use serde::{Serialize, Deserialize}; /// use uuid::Uuid; /// use bson::serde_helpers::uuid_1_as_c_sharp_legacy_binary; /// /// #[derive(Serialize, Deserialize)] /// struct Item { /// #[serde(with = "uuid_1_as_c_sharp_legacy_binary")] /// pub id: Uuid, /// } /// # } /// ``` #[cfg(feature = "uuid-1")] #[cfg_attr(docsrs, doc(cfg(feature = "uuid-1")))] pub mod uuid_1_as_c_sharp_legacy_binary { as_legacy_binary_mod!( cfg(feature = "uuid-1"), uuid::Uuid, UuidRepresentation::CSharpLegacy ); } /// Contains functions to serialize a u32 as a bson::Timestamp and deserialize a u32 from a /// bson::Timestamp. The u32 should represent seconds since the Unix epoch. /// /// ```rust /// # use serde::{Serialize, Deserialize}; /// # use bson::serde_helpers::u32_as_timestamp; /// #[derive(Serialize, Deserialize)] /// struct Event { /// #[serde(with = "u32_as_timestamp")] /// pub time: u32, /// } /// ``` pub mod u32_as_timestamp { use crate::{Bson, Timestamp}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::result::Result; /// Serializes a u32 as a bson::Timestamp. pub fn serialize(val: &u32, serializer: S) -> Result { let timestamp = Bson::Timestamp(Timestamp { time: *val, increment: 0, }); timestamp.serialize(serializer) } /// Deserializes a u32 from a bson::Timestamp. pub fn deserialize<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { let timestamp = Timestamp::deserialize(deserializer)?; Ok(timestamp.time) } } /// Contains functions to serialize a bson::Timestamp as a u32 and deserialize a bson::Timestamp /// from a u32. The u32 should represent seconds since the Unix epoch. Serialization will return an /// error if the Timestamp has a non-zero increment. /// /// ```rust /// # use serde::{Serialize, Deserialize}; /// # use bson::{serde_helpers::timestamp_as_u32, Timestamp}; /// #[derive(Serialize, Deserialize)] /// struct Item { /// #[serde(with = "timestamp_as_u32")] /// pub timestamp: Timestamp, /// } /// ``` pub mod timestamp_as_u32 { use crate::Timestamp; use serde::{ser, Deserialize, Deserializer, Serializer}; use std::result::Result; /// Serializes a bson::Timestamp as a u32. Returns an error if the conversion is lossy (i.e. the /// Timestamp has a non-zero increment). pub fn serialize(val: &Timestamp, serializer: S) -> Result { if val.increment != 0 { return Err(ser::Error::custom( "Cannot convert Timestamp with a non-zero increment to u32", )); } serializer.serialize_u32(val.time) } /// Deserializes a bson::Timestamp from a u32. pub fn deserialize<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { let time = u32::deserialize(deserializer)?; Ok(Timestamp { time, increment: 0 }) } } bson-2.10.0/src/spec.rs000064400000000000000000000175001046102023000127370ustar 00000000000000// The MIT License (MIT) // Copyright (c) 2015 Y. T. Chung // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in // the Software without restriction, including without limitation the rights to // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of // the Software, and to permit persons to whom the Software is furnished to do so, // subject to the following conditions: // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. //! Constants derived from the [BSON Specification Version 1.1](http://bsonspec.org/spec.html). use std::convert::From; const ELEMENT_TYPE_FLOATING_POINT: u8 = 0x01; const ELEMENT_TYPE_UTF8_STRING: u8 = 0x02; const ELEMENT_TYPE_EMBEDDED_DOCUMENT: u8 = 0x03; const ELEMENT_TYPE_ARRAY: u8 = 0x04; const ELEMENT_TYPE_BINARY: u8 = 0x05; const ELEMENT_TYPE_UNDEFINED: u8 = 0x06; // Deprecated const ELEMENT_TYPE_OBJECT_ID: u8 = 0x07; const ELEMENT_TYPE_BOOLEAN: u8 = 0x08; const ELEMENT_TYPE_UTC_DATETIME: u8 = 0x09; const ELEMENT_TYPE_NULL_VALUE: u8 = 0x0A; const ELEMENT_TYPE_REGULAR_EXPRESSION: u8 = 0x0B; const ELEMENT_TYPE_DBPOINTER: u8 = 0x0C; // Deprecated const ELEMENT_TYPE_JAVASCRIPT_CODE: u8 = 0x0D; const ELEMENT_TYPE_SYMBOL: u8 = 0x0E; // Deprecated const ELEMENT_TYPE_JAVASCRIPT_CODE_WITH_SCOPE: u8 = 0x0F; const ELEMENT_TYPE_32BIT_INTEGER: u8 = 0x10; const ELEMENT_TYPE_TIMESTAMP: u8 = 0x11; const ELEMENT_TYPE_64BIT_INTEGER: u8 = 0x12; #[allow(unused)] const ELEMENT_TYPE_128BIT_DECIMAL: u8 = 0x13; const ELEMENT_TYPE_MINKEY: u8 = 0xFF; const ELEMENT_TYPE_MAXKEY: u8 = 0x7F; const BINARY_SUBTYPE_GENERIC: u8 = 0x00; const BINARY_SUBTYPE_FUNCTION: u8 = 0x01; const BINARY_SUBTYPE_BINARY_OLD: u8 = 0x02; const BINARY_SUBTYPE_UUID_OLD: u8 = 0x03; const BINARY_SUBTYPE_UUID: u8 = 0x04; const BINARY_SUBTYPE_MD5: u8 = 0x05; const BINARY_SUBTYPE_ENCRYPTED: u8 = 0x06; const BINARY_SUBTYPE_COLUMN: u8 = 0x07; const BINARY_SUBTYPE_SENSITIVE: u8 = 0x08; const BINARY_SUBTYPE_USER_DEFINED: u8 = 0x80; /// All available BSON element types. /// /// Not all element types are representable by the [`Bson`](crate::Bson) type. #[repr(u8)] #[derive(Debug, Eq, PartialEq, Clone, Copy)] pub enum ElementType { /// 64-bit binary floating point Double = ELEMENT_TYPE_FLOATING_POINT, /// UTF-8 string String = ELEMENT_TYPE_UTF8_STRING, /// Embedded document EmbeddedDocument = ELEMENT_TYPE_EMBEDDED_DOCUMENT, /// Array Array = ELEMENT_TYPE_ARRAY, /// Binary data Binary = ELEMENT_TYPE_BINARY, /// Deprecated. Undefined (value) Undefined = ELEMENT_TYPE_UNDEFINED, /// [ObjectId](http://dochub.mongodb.org/core/objectids) ObjectId = ELEMENT_TYPE_OBJECT_ID, /// Bool value Boolean = ELEMENT_TYPE_BOOLEAN, /// UTC datetime DateTime = ELEMENT_TYPE_UTC_DATETIME, /// Null value Null = ELEMENT_TYPE_NULL_VALUE, /// Regular expression - The first cstring is the regex pattern, the second is the regex /// options string. Options are identified by characters, which must be stored in /// alphabetical order. Valid options are 'i' for case insensitive matching, 'm' for /// multiline matching, 'x' for verbose mode, 'l' to make \w, \W, etc. locale dependent, /// 's' for dotall mode ('.' matches everything), and 'u' to make \w, \W, etc. match /// unicode. RegularExpression = ELEMENT_TYPE_REGULAR_EXPRESSION, /// Deprecated. DbPointer = ELEMENT_TYPE_DBPOINTER, /// JavaScript code JavaScriptCode = ELEMENT_TYPE_JAVASCRIPT_CODE, /// Deprecated. Symbol = ELEMENT_TYPE_SYMBOL, /// JavaScript code w/ scope JavaScriptCodeWithScope = ELEMENT_TYPE_JAVASCRIPT_CODE_WITH_SCOPE, /// 32-bit integer Int32 = ELEMENT_TYPE_32BIT_INTEGER, /// Timestamp Timestamp = ELEMENT_TYPE_TIMESTAMP, /// 64-bit integer Int64 = ELEMENT_TYPE_64BIT_INTEGER, /// [128-bit decimal floating point](https://github.com/mongodb/specifications/blob/master/source/bson-decimal128/decimal128.rst) Decimal128 = ELEMENT_TYPE_128BIT_DECIMAL, MaxKey = ELEMENT_TYPE_MAXKEY, MinKey = ELEMENT_TYPE_MINKEY, } impl ElementType { /// Attempt to convert from a `u8`. #[inline] pub fn from(tag: u8) -> Option { use self::ElementType::*; Some(match tag { ELEMENT_TYPE_FLOATING_POINT => Self::Double, ELEMENT_TYPE_UTF8_STRING => Self::String, ELEMENT_TYPE_EMBEDDED_DOCUMENT => EmbeddedDocument, ELEMENT_TYPE_ARRAY => Array, ELEMENT_TYPE_BINARY => Binary, ELEMENT_TYPE_UNDEFINED => Undefined, ELEMENT_TYPE_OBJECT_ID => ObjectId, ELEMENT_TYPE_BOOLEAN => Boolean, ELEMENT_TYPE_UTC_DATETIME => Self::DateTime, ELEMENT_TYPE_NULL_VALUE => Self::Null, ELEMENT_TYPE_REGULAR_EXPRESSION => RegularExpression, ELEMENT_TYPE_DBPOINTER => DbPointer, ELEMENT_TYPE_JAVASCRIPT_CODE => JavaScriptCode, ELEMENT_TYPE_SYMBOL => Symbol, ELEMENT_TYPE_JAVASCRIPT_CODE_WITH_SCOPE => JavaScriptCodeWithScope, ELEMENT_TYPE_32BIT_INTEGER => Int32, ELEMENT_TYPE_TIMESTAMP => Timestamp, ELEMENT_TYPE_64BIT_INTEGER => Int64, ELEMENT_TYPE_128BIT_DECIMAL => Decimal128, ELEMENT_TYPE_MAXKEY => MaxKey, ELEMENT_TYPE_MINKEY => MinKey, _ => return None, }) } } /// The available binary subtypes, plus a user-defined slot. #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] #[non_exhaustive] pub enum BinarySubtype { Generic, Function, BinaryOld, UuidOld, Uuid, Md5, Encrypted, Column, Sensitive, UserDefined(u8), Reserved(u8), } impl From for u8 { #[inline] fn from(t: BinarySubtype) -> u8 { match t { BinarySubtype::Generic => BINARY_SUBTYPE_GENERIC, BinarySubtype::Function => BINARY_SUBTYPE_FUNCTION, BinarySubtype::BinaryOld => BINARY_SUBTYPE_BINARY_OLD, BinarySubtype::UuidOld => BINARY_SUBTYPE_UUID_OLD, BinarySubtype::Uuid => BINARY_SUBTYPE_UUID, BinarySubtype::Md5 => BINARY_SUBTYPE_MD5, BinarySubtype::Encrypted => BINARY_SUBTYPE_ENCRYPTED, BinarySubtype::Column => BINARY_SUBTYPE_COLUMN, BinarySubtype::Sensitive => BINARY_SUBTYPE_SENSITIVE, BinarySubtype::UserDefined(x) => x, BinarySubtype::Reserved(x) => x, } } } impl From for BinarySubtype { #[inline] fn from(t: u8) -> BinarySubtype { match t { BINARY_SUBTYPE_GENERIC => BinarySubtype::Generic, BINARY_SUBTYPE_FUNCTION => BinarySubtype::Function, BINARY_SUBTYPE_BINARY_OLD => BinarySubtype::BinaryOld, BINARY_SUBTYPE_UUID_OLD => BinarySubtype::UuidOld, BINARY_SUBTYPE_UUID => BinarySubtype::Uuid, BINARY_SUBTYPE_MD5 => BinarySubtype::Md5, BINARY_SUBTYPE_ENCRYPTED => BinarySubtype::Encrypted, BINARY_SUBTYPE_COLUMN => BinarySubtype::Column, BINARY_SUBTYPE_SENSITIVE => BinarySubtype::Sensitive, _ if t < BINARY_SUBTYPE_USER_DEFINED => BinarySubtype::Reserved(t), _ => BinarySubtype::UserDefined(t), } } } bson-2.10.0/src/uuid/mod.rs000064400000000000000000000520261046102023000135340ustar 00000000000000//! UUID support for BSON. //! //! ## The [`crate::Uuid`] type //! //! The BSON format supports UUIDs via the "binary" type with the UUID subtype (4). //! To facilitate working with these UUID-subtyped binary values, this crate provides a //! [`crate::Uuid`] type, whose `serde` implementation automatically serializes to and deserializes //! from binary values with subtype 4. //! //! The popular [`uuid`](https://docs.rs/uuid) crate also provides a //! [UUID type](https://docs.rs/uuid/latest/uuid/struct.Uuid.html), //! though its `serde` implementation does not produce or parse subtype 4 //! binary values. Instead, when serialized with `bson::to_bson`, it produces as a string, and when //! serialized with `bson::to_vec`, it produces a binary value with subtype _0_ rather than 4. //! Because of this, it is highly recommended to use the [`crate::Uuid`] type when working with BSON //! instead of the `uuid` crate's [`Uuid`], since [`crate::Uuid`] correctly produces subtype 4 //! binary values via either serialization function. //! //! e.g. //! //! ``` rust //! # #[cfg(feature = "uuid-1")] //! # { //! # use uuid as uuid; //! use serde::{Serialize, Deserialize}; //! use bson::doc; //! //! #[derive(Serialize, Deserialize)] //! struct Foo { //! /// serializes as a String or subtype 0 BSON binary, depending //! /// on whether `bson::to_bson` or `bson::to_vec` is used. //! uuid: uuid::Uuid, //! //! /// serializes as a BSON binary with subtype 4 when either is used. //! bson_uuid: bson::Uuid, //! //! /// serializes as a BSON binary with subtype 4 when either is used. //! /// this requires the "uuid-1" feature flag //! #[serde(with = "bson::serde_helpers::uuid_1_as_binary")] //! uuid_as_bson: uuid::Uuid, //! } //! # }; //! ``` //! //! ## The `uuid-1` feature flag //! //! To facilitate the conversion between [`crate::Uuid`] values and the `uuid` crate's [`Uuid`] //! values, the `uuid-1` feature flag can be enabled. This flag exposes a number of convenient //! conversions, including the `crate::Uuid::to_uuid_1` method and the `From` //! implementation for [`Bson`], which allows the `uuid` crate's [`Uuid`] values to be used in the //! `doc!` and `bson!` macros. //! //! ``` //! # #[cfg(feature = "uuid-1")] //! # { //! # use uuid as uuid; //! use bson::doc; //! //! // this automatic conversion does not require any feature flags //! let query = doc! { //! "uuid": bson::Uuid::new(), //! }; //! //! // but this automatic conversion requires the "uuid-1" feature flag //! let query = doc! { //! "uuid": uuid::Uuid::new_v4(), //! }; //! //! // this also requires the "uuid-1" feature flag. //! let uuid = bson::Uuid::new().to_uuid_1(); //! # }; //! ``` //! //! For backwards compatibility, a `uuid-0_8` feature flag can be enabled, which provides the same //! API for interoperation with version 0.8 of the `uuid` crate. //! //! ## The `serde_with-3` feature flag //! //! The `serde_with-3` feature can be enabled to support more ergonomic serde attributes for //! (de)serializing [`uuid::Uuid`] from/to BSON via the [`serde_with`](https://docs.rs/serde_with/1.11.0/serde_with/) //! crate. The main benefit of this compared to the regular `serde_helpers` is that `serde_with-3` //! can handle nested [`uuid::Uuid`] values (e.g. in [`Option`]), whereas the former only works on //! fields that are exactly [`uuid::Uuid`]. //! ``` //! # #[cfg(all(feature = "uuid-1", feature = "serde_with-3"))] //! # { //! # use uuid as uuid; //! use serde::{Deserialize, Serialize}; //! use bson::doc; //! //! #[serde_with_3::serde_as] //! #[derive(Deserialize, Serialize, PartialEq, Debug)] //! struct Foo { //! /// Serializes as a BSON binary rather than using [`uuid::Uuid`]'s serialization //! #[serde_as(as = "Option")] //! as_bson: Option, //! } //! //! let foo = Foo { //! as_bson: Some(uuid::Uuid::new_v4()), //! }; //! //! let expected = doc! { //! "as_bson": bson::Uuid::from(foo.as_bson.unwrap()), //! }; //! //! assert_eq!(bson::to_document(&foo)?, expected); //! # } //! # Ok::<(), Box>(()) //! ``` //! //! ## Using [`crate::Uuid`] with non-BSON formats //! //! [`crate::Uuid`]'s `serde` implementation is the same as [`uuid::Uuid`]'s //! for non-BSON formats such as JSON: //! //! ``` rust //! # #[cfg(feature = "uuid-1")] //! # { //! # use uuid as uuid; //! # use serde::{Serialize, Deserialize}; //! # #[derive(Serialize, Deserialize)] //! # struct Foo { //! # uuid: uuid::Uuid, //! # bson_uuid: bson::Uuid, //! # } //! use serde_json::json; //! //! let uuid = uuid::Uuid::new_v4(); //! let bson_uuid: bson::Uuid = uuid.into(); //! let foo = Foo { uuid, bson_uuid, }; //! //! let json = serde_json::to_value(&foo)?; //! assert_eq!(json, json!({ "uuid": uuid.to_string(), "bson_uuid": uuid.to_string() })); //! # } //! # Ok::<(), Box::>(()) //! ``` #[cfg(test)] mod test; use std::{ fmt::{self, Display}, str::FromStr, }; use serde::{Deserialize, Serialize}; use crate::{de::BsonVisitor, spec::BinarySubtype, Binary, Bson}; /// Special type name used in the [`Uuid`] serialization implementation to indicate a BSON /// UUID is being serialized or deserialized. The BSON serializers/deserializers will handle this /// name specially, but other serializers/deserializers will just ignore it and use [`uuid::Uuid`]'s /// serde integration. pub(crate) const UUID_NEWTYPE_NAME: &str = "$__bson_private_uuid"; /// A struct modeling a BSON UUID value (i.e. a Binary value with subtype 4). /// /// This type should be used instead of [`uuid::Uuid`](https://docs.rs/uuid/latest/uuid/struct.Uuid.html) /// when serializing to or deserializing from BSON, since /// [`uuid::Uuid`](https://docs.rs/uuid/latest/uuid/struct.Uuid.html)'s `serde` implementation doesn't /// produce or parse BSON UUIDs. /// /// To enable interop with the [`Uuid`] type from the `uuid` crate, enable the `uuid-0_8` feature /// flag. /// /// For more information on the usage of this type, see the [`uuid`] module-level documentation. /// /// Note: due to an issue in serde (see [here](https://github.com/serde-rs/serde/issues/2106)), this type /// will also allow deserialization from 16 byte + subtype 0 Binary values in BSON if part of a /// `#[serde(flatten)]` chain. This behavior shouldn't be relied upon as it may be fixed at some /// point in the future. #[derive(Clone, Copy, PartialEq, Hash, Eq, PartialOrd, Ord)] pub struct Uuid { uuid: uuid::Uuid, } impl Uuid { /// Creates a random UUID. /// /// This uses the operating system's RNG as the source of random numbers. If you'd like to use a /// custom generator, generate random bytes and pass them to [`Uuid::from_bytes`] instead. pub fn new() -> Self { Self { uuid: uuid::Uuid::new_v4(), } } /// Creates a [`Uuid`] using the supplied big-endian bytes. pub const fn from_bytes(bytes: [u8; 16]) -> Self { Self::from_external_uuid(uuid::Uuid::from_bytes(bytes)) } /// Creates a [`Uuid`] from the provided hex string. pub fn parse_str(input: impl AsRef) -> Result { let uuid = uuid::Uuid::parse_str(input.as_ref()).map_err(|e| Error::InvalidUuidString { message: e.to_string(), })?; Ok(Self::from_external_uuid(uuid)) } pub(crate) const fn from_external_uuid(uuid: uuid::Uuid) -> Self { Self { uuid } } /// Returns an array of 16 bytes containing the [`Uuid`]'s data. pub const fn bytes(self) -> [u8; 16] { *self.uuid.as_bytes() } } impl Default for Uuid { fn default() -> Self { Self::new() } } #[cfg(feature = "uuid-0_8")] #[cfg_attr(docsrs, doc(cfg(feature = "uuid-0_8")))] impl Uuid { /// Create a [`Uuid`] from a [`uuid::Uuid`](https://docs.rs/uuid/0.8/uuid/struct.Uuid.html) from /// the [`uuid`](https://docs.rs/uuid/0.8) crate. pub fn from_uuid_0_8(uuid: uuid_0_8::Uuid) -> Self { Self::from_external_uuid(uuid::Uuid::from_u128(uuid.as_u128())) } /// Convert this [`Uuid`] to a [`uuid::Uuid`](https://docs.rs/uuid/0.8/uuid/struct.Uuid.html) from /// the [`uuid`](https://docs.rs/uuid/0.8) crate. pub fn to_uuid_0_8(self) -> uuid_0_8::Uuid { uuid_0_8::Uuid::from_bytes(self.uuid.into_bytes()) } } #[cfg(feature = "uuid-1")] #[cfg_attr(docsrs, doc(cfg(feature = "uuid-1")))] impl Uuid { /// Create a [`Uuid`] from a [`uuid::Uuid`](https://docs.rs/uuid/0.8/uuid/struct.Uuid.html) from /// the [`uuid`](https://docs.rs/uuid/0.8) crate. pub fn from_uuid_1(uuid: uuid::Uuid) -> Self { Self::from_external_uuid(uuid) } /// Convert this [`Uuid`] to a [`uuid::Uuid`](https://docs.rs/uuid/0.8/uuid/struct.Uuid.html) from /// the [`uuid`](https://docs.rs/uuid/0.8) crate. pub fn to_uuid_1(self) -> uuid::Uuid { self.uuid } } impl Serialize for Uuid { fn serialize(&self, serializer: S) -> std::result::Result where S: serde::Serializer, { serializer.serialize_newtype_struct(UUID_NEWTYPE_NAME, &self.uuid) } } impl<'de> Deserialize<'de> for Uuid { fn deserialize(deserializer: D) -> std::result::Result where D: serde::Deserializer<'de>, { match deserializer.deserialize_newtype_struct(UUID_NEWTYPE_NAME, BsonVisitor)? { // Need to support deserializing from generic subtypes for non-BSON formats. // When using the BSON deserializer, the newtype name will ensure the subtype is only // ever BinarySubtype::Uuid. Bson::Binary(b) if matches!(b.subtype, BinarySubtype::Uuid | BinarySubtype::Generic) => { let uuid = uuid::Uuid::from_slice(b.bytes.as_slice()).map_err(serde::de::Error::custom)?; Ok(Self::from_external_uuid(uuid)) } Bson::Binary(b) if b.subtype == BinarySubtype::UuidOld => { Err(serde::de::Error::custom( "received legacy UUID (subtype 3) but expected regular UUID (subtype 4)", )) } Bson::String(s) => { let uuid = uuid::Uuid::from_str(s.as_str()).map_err(serde::de::Error::custom)?; Ok(Self::from_external_uuid(uuid)) } b => Err(serde::de::Error::invalid_type(b.as_unexpected(), &"a UUID")), } } } impl Display for Uuid { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.uuid.fmt(f) } } impl std::fmt::Debug for Uuid { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { std::fmt::Debug::fmt(&self.uuid, f) } } impl From for Binary { fn from(uuid: Uuid) -> Self { Binary { subtype: BinarySubtype::Uuid, bytes: uuid.bytes().to_vec(), } } } impl From for Bson { fn from(u: Uuid) -> Self { Bson::Binary(u.into()) } } #[cfg(feature = "uuid-0_8")] impl From for Uuid { fn from(u: uuid_0_8::Uuid) -> Self { Self::from_uuid_0_8(u) } } #[cfg(feature = "uuid-0_8")] impl From for uuid_0_8::Uuid { fn from(s: Uuid) -> Self { s.to_uuid_0_8() } } #[cfg(feature = "uuid-1")] impl From for Uuid { fn from(u: uuid::Uuid) -> Self { Self::from_uuid_1(u) } } #[cfg(feature = "uuid-1")] impl From for uuid::Uuid { fn from(s: Uuid) -> Self { s.to_uuid_1() } } /// Enum of the possible representations to use when converting between [`Uuid`] and [`Binary`]. /// This enum is necessary because the different drivers used to have different ways of encoding /// UUIDs, with the BSON subtype: 0x03 (UUID old). /// If a UUID has been serialized with a particular representation, it MUST /// be deserialized with the same representation. /// /// Example: /// ``` /// use bson::{Binary, uuid::{Uuid, UuidRepresentation}}; /// /// let uuid = Uuid::parse_str("00112233445566778899AABBCCDDEEFF")?; /// let bin = Binary::from_uuid_with_representation(uuid, UuidRepresentation::PythonLegacy); /// /// // This conversion fails, since the binary holds a PythonLegacy UUID, so we're required to specify /// // that. /// assert!(bin.to_uuid().is_err()); /// /// // This conversion succeeds, since we specified the correct representation. /// let new_uuid = bin.to_uuid_with_representation(UuidRepresentation::PythonLegacy)?; /// assert_eq!(new_uuid, uuid); /// /// # Ok::<(), Box::>(()) /// ``` #[non_exhaustive] #[derive(PartialEq, Clone, Copy, Debug)] pub enum UuidRepresentation { /// The canonical representation of UUIDs in BSON (binary with subtype 0x04) Standard, /// The legacy representation of UUIDs in BSON used by the C# driver (binary subtype 0x03) CSharpLegacy, /// The legacy representation of UUIDs in BSON used by the Java driver (binary subtype 0x03) JavaLegacy, /// The legacy representation of UUIDs in BSON used by the Python driver, which is the same /// format as STANDARD, but has binary subtype 0x03 PythonLegacy, } impl Binary { /// Serializes a [`Uuid`] into BSON [`Binary`] type pub fn from_uuid(uuid: Uuid) -> Self { Binary::from(uuid) } /// Serializes a [`Uuid`] into BSON binary type and takes the desired representation as a /// parameter. `Binary::from_uuid_with_representation(uuid, UuidRepresentation::Standard)` is /// equivalent to `Binary::from_uuid(uuid)`. /// /// See the documentation for [`UuidRepresentation`] for more information on the possible /// representations. pub fn from_uuid_with_representation(uuid: Uuid, rep: UuidRepresentation) -> Self { match rep { UuidRepresentation::Standard => Binary::from_uuid(uuid), UuidRepresentation::CSharpLegacy => { let mut bytes = uuid.bytes().to_vec(); bytes[0..4].reverse(); bytes[4..6].reverse(); bytes[6..8].reverse(); Binary { subtype: BinarySubtype::UuidOld, bytes, } } UuidRepresentation::PythonLegacy => Binary { subtype: BinarySubtype::UuidOld, bytes: uuid.bytes().to_vec(), }, UuidRepresentation::JavaLegacy => { let mut bytes = uuid.bytes().to_vec(); bytes[0..8].reverse(); bytes[8..16].reverse(); Binary { subtype: BinarySubtype::UuidOld, bytes, } } } } /// Deserializes a BSON [`Binary`] type into a [`Uuid`] according to the provided /// representation. If the representation does not match the [`Binary`], an error will be /// returned. /// /// See the documentation for [`UuidRepresentation`] for more information on the possible /// representations. pub fn to_uuid_with_representation(&self, rep: UuidRepresentation) -> Result { // If representation is non-standard, then its subtype must be UuidOld if rep != UuidRepresentation::Standard && self.subtype != BinarySubtype::UuidOld { return Err(Error::RepresentationMismatch { requested_representation: rep, actual_binary_subtype: self.subtype, expected_binary_subtype: BinarySubtype::UuidOld, }); } // If representation is standard, then its subtype must be Uuid if rep == UuidRepresentation::Standard && self.subtype != BinarySubtype::Uuid { return Err(Error::RepresentationMismatch { requested_representation: rep, actual_binary_subtype: self.subtype, expected_binary_subtype: BinarySubtype::Uuid, }); } // Must be 16 bytes long if self.bytes.len() != 16 { return Err(Error::InvalidLength { length: self.bytes.len(), }); } let mut buf = [0u8; 16]; buf.copy_from_slice(&self.bytes); Ok(match rep { UuidRepresentation::Standard => Uuid::from_bytes(buf), UuidRepresentation::CSharpLegacy => { buf[0..4].reverse(); buf[4..6].reverse(); buf[6..8].reverse(); Uuid::from_bytes(buf) } UuidRepresentation::PythonLegacy => Uuid::from_bytes(buf), UuidRepresentation::JavaLegacy => { buf[0..8].reverse(); buf[8..16].reverse(); Uuid::from_bytes(buf) } }) } /// Deserializes a BSON [`Binary`] type into a [`Uuid`] using the standard /// representation. pub fn to_uuid(&self) -> Result { self.to_uuid_with_representation(UuidRepresentation::Standard) } } macro_rules! trait_impls { ($feat:meta, $u:ty) => { #[cfg($feat)] #[cfg_attr(docsrs, doc(cfg($feat)))] impl From<$u> for Binary { fn from(uuid: $u) -> Self { Binary { subtype: BinarySubtype::Uuid, bytes: uuid.as_bytes().to_vec(), } } } #[cfg(all($feat, feature = "serde_with"))] #[cfg_attr(docsrs, doc(cfg(all($feat, feature = "serde_with"))))] impl<'de> serde_with::DeserializeAs<'de, $u> for crate::Uuid { fn deserialize_as(deserializer: D) -> std::result::Result<$u, D::Error> where D: serde::Deserializer<'de>, { let uuid = Uuid::deserialize(deserializer)?; Ok(uuid.into()) } } #[cfg(all($feat, feature = "serde_with"))] #[cfg_attr(docsrs, doc(cfg(all($feat, feature = "serde_with"))))] impl serde_with::SerializeAs<$u> for crate::Uuid { fn serialize_as(source: &$u, serializer: S) -> std::result::Result where S: serde::Serializer, { let uuid = Uuid::from(*source); uuid.serialize(serializer) } } #[cfg(all($feat, feature = "serde_with-3"))] #[cfg_attr(docsrs, doc(cfg(all($feat, feature = "serde_with-3"))))] impl<'de> serde_with_3::DeserializeAs<'de, $u> for crate::Uuid { fn deserialize_as(deserializer: D) -> std::result::Result<$u, D::Error> where D: serde::Deserializer<'de>, { let uuid = Uuid::deserialize(deserializer)?; Ok(uuid.into()) } } #[cfg(all($feat, feature = "serde_with-3"))] #[cfg_attr(docsrs, doc(cfg(all($feat, feature = "serde_with-3"))))] impl serde_with_3::SerializeAs<$u> for crate::Uuid { fn serialize_as(source: &$u, serializer: S) -> std::result::Result where S: serde::Serializer, { let uuid = Uuid::from(*source); uuid.serialize(serializer) } } }; } trait_impls!(feature = "uuid-0_8", uuid_0_8::Uuid); trait_impls!(feature = "uuid-1", uuid::Uuid); /// Errors that can occur during [`Uuid`] construction and generation. #[derive(Clone, Debug)] #[non_exhaustive] pub enum Error { /// Error returned when an invalid string is provided to [`Uuid::parse_str`]. #[non_exhaustive] InvalidUuidString { message: String }, /// Error returned when the representation specified does not match the underlying /// [`crate::Binary`] value in [`crate::Binary::to_uuid_with_representation`]. #[non_exhaustive] RepresentationMismatch { /// The subtype that was expected given the requested representation. expected_binary_subtype: BinarySubtype, /// The actual subtype of the binary value. actual_binary_subtype: BinarySubtype, /// The requested representation. requested_representation: UuidRepresentation, }, /// Error returned from [`crate::Binary::to_uuid`] if the underling data is not 16 bytes long. #[non_exhaustive] InvalidLength { /// The actual length of the data. length: usize, }, } /// Alias for `Result`. pub type Result = std::result::Result; impl fmt::Display for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { Error::InvalidUuidString { message } => { write!(fmt, "{}", message) } Error::RepresentationMismatch { expected_binary_subtype, actual_binary_subtype, requested_representation, } => { write!( fmt, "expected {:?} when converting to UUID with {:?}, isntead got {:?}", expected_binary_subtype, requested_representation, actual_binary_subtype ) } Error::InvalidLength { length } => { write!( fmt, "expected UUID to contain 16 bytes, instead got {}", length ) } } } } impl std::error::Error for Error {} bson-2.10.0/src/uuid/test.rs000064400000000000000000000201711046102023000137300ustar 00000000000000use crate::{ from_document, from_slice, spec::BinarySubtype, uuid::{Uuid, UuidRepresentation}, Binary, Bson, Document, }; use serde::{Deserialize, Serialize}; use serde_json::json; #[derive(Debug, Serialize, Deserialize, PartialEq)] struct U { uuid: Uuid, } #[test] fn into_bson() { let uuid = Uuid::new(); let bson: Bson = uuid.into(); let binary = Binary { bytes: uuid.bytes().to_vec(), subtype: BinarySubtype::Uuid, }; assert_eq!(bson, Bson::Binary(binary)); } #[test] fn raw_serialization() { let u = U { uuid: Uuid::new() }; let bytes = crate::to_vec(&u).unwrap(); let doc: Document = crate::from_slice(bytes.as_slice()).unwrap(); assert_eq!(doc, doc! { "uuid": u.uuid }); let u_roundtrip: U = crate::from_slice(bytes.as_slice()).unwrap(); assert_eq!(u_roundtrip, u); } #[test] fn bson_serialization() { let u = U { uuid: Uuid::new() }; let correct = doc! { "uuid": Binary { bytes: u.uuid.bytes().to_vec(), subtype: BinarySubtype::Uuid } }; assert_eq!(doc! { "uuid": u.uuid }, correct); let doc = crate::to_document(&u).unwrap(); assert_eq!(doc, correct); let u_roundtrip: U = crate::from_document(doc).unwrap(); assert_eq!(u_roundtrip, u); } #[test] fn json() { let u = U { uuid: Uuid::new() }; let json = serde_json::to_value(&u).unwrap(); assert_eq!(json, json!({ "uuid": u.uuid.to_string() })); let u_roundtrip_json: U = serde_json::from_value(json).unwrap(); assert_eq!(u_roundtrip_json, u); } #[test] fn wrong_subtype() { let generic = doc! { "uuid": Binary { bytes: Uuid::new().bytes().to_vec(), subtype: BinarySubtype::Generic } }; crate::from_document::(generic.clone()).unwrap_err(); let generic_bytes = crate::to_vec(&generic).unwrap(); crate::from_slice::(&generic_bytes).unwrap_err(); let old = doc! { "uuid": Binary { bytes: Uuid::new().bytes().to_vec(), subtype: BinarySubtype::UuidOld } }; crate::from_document::(old.clone()).unwrap_err(); let old_bytes = crate::to_vec(&old).unwrap(); crate::from_slice::(&old_bytes).unwrap_err(); let other = doc! { "uuid": Binary { bytes: Uuid::new().bytes().to_vec(), subtype: BinarySubtype::UserDefined(100) } }; crate::from_document::(other.clone()).unwrap_err(); let other_bytes = crate::to_vec(&other).unwrap(); crate::from_slice::(&other_bytes).unwrap_err(); } #[test] fn test_binary_constructors() { let uuid = crate::Uuid::parse_str("00112233445566778899AABBCCDDEEFF").unwrap(); let bin = Binary::from_uuid(uuid); assert_eq!(bin.bytes, uuid.bytes()); assert_eq!(bin.subtype, BinarySubtype::Uuid); let bin = Binary::from_uuid_with_representation(uuid, UuidRepresentation::Standard); assert_eq!(bin.bytes, uuid.bytes()); assert_eq!(bin.subtype, BinarySubtype::Uuid); let bin = Binary::from_uuid_with_representation(uuid, UuidRepresentation::JavaLegacy); assert_eq!( bin.bytes, Uuid::parse_str("7766554433221100FFEEDDCCBBAA9988") .unwrap() .bytes() ); assert_eq!(bin.subtype, BinarySubtype::UuidOld); let bin = Binary::from_uuid_with_representation(uuid, UuidRepresentation::CSharpLegacy); assert_eq!( bin.bytes, Uuid::parse_str("33221100554477668899AABBCCDDEEFF") .unwrap() .bytes() ); assert_eq!(bin.subtype, BinarySubtype::UuidOld); // Same byte ordering as standard representation let bin = Binary::from_uuid_with_representation(uuid, UuidRepresentation::PythonLegacy); assert_eq!( bin.bytes, Uuid::parse_str("00112233445566778899AABBCCDDEEFF") .unwrap() .bytes() ); assert_eq!(bin.subtype, BinarySubtype::UuidOld); } #[test] fn test_binary_to_uuid_standard_rep() { let uuid = crate::Uuid::parse_str("00112233445566778899AABBCCDDEEFF").unwrap(); let bin = Binary::from_uuid(uuid); assert_eq!(bin.to_uuid().unwrap(), uuid); assert_eq!( bin.to_uuid_with_representation(UuidRepresentation::Standard) .unwrap(), uuid ); assert!(bin .to_uuid_with_representation(UuidRepresentation::CSharpLegacy) .is_err()); assert!(bin .to_uuid_with_representation(UuidRepresentation::PythonLegacy) .is_err()); assert!(bin .to_uuid_with_representation(UuidRepresentation::PythonLegacy) .is_err()); } #[test] fn test_binary_to_uuid_explicitly_standard_rep() { let uuid = crate::Uuid::parse_str("00112233445566778899AABBCCDDEEFF").unwrap(); let bin = Binary::from_uuid_with_representation(uuid, UuidRepresentation::Standard); assert_eq!(bin.to_uuid().unwrap(), uuid); assert_eq!( bin.to_uuid_with_representation(UuidRepresentation::Standard) .unwrap(), uuid ); assert!(bin .to_uuid_with_representation(UuidRepresentation::CSharpLegacy) .is_err()); assert!(bin .to_uuid_with_representation(UuidRepresentation::PythonLegacy) .is_err()); assert!(bin .to_uuid_with_representation(UuidRepresentation::PythonLegacy) .is_err()); } #[test] fn test_binary_to_uuid_java_rep() { let uuid = crate::Uuid::parse_str("00112233445566778899AABBCCDDEEFF").unwrap(); let bin = Binary::from_uuid_with_representation(uuid, UuidRepresentation::JavaLegacy); assert!(bin.to_uuid().is_err()); assert!(bin .to_uuid_with_representation(UuidRepresentation::Standard) .is_err()); assert_eq!( bin.to_uuid_with_representation(UuidRepresentation::JavaLegacy) .unwrap(), uuid ); } #[test] fn test_binary_to_uuid_csharp_legacy_rep() { let uuid = crate::Uuid::parse_str("00112233445566778899AABBCCDDEEFF").unwrap(); let bin = Binary::from_uuid_with_representation(uuid, UuidRepresentation::CSharpLegacy); assert!(bin.to_uuid().is_err()); assert!(bin .to_uuid_with_representation(UuidRepresentation::Standard) .is_err()); assert_eq!( bin.to_uuid_with_representation(UuidRepresentation::CSharpLegacy) .unwrap(), uuid ); } #[test] fn test_binary_to_uuid_python_legacy_rep() { let uuid = crate::Uuid::parse_str("00112233445566778899AABBCCDDEEFF").unwrap(); let bin = Binary::from_uuid_with_representation(uuid, UuidRepresentation::PythonLegacy); assert!(bin.to_uuid().is_err()); assert!(bin .to_uuid_with_representation(UuidRepresentation::Standard) .is_err()); assert_eq!( bin.to_uuid_with_representation(UuidRepresentation::PythonLegacy) .unwrap(), uuid ); } #[cfg(feature = "uuid-0_8")] #[test] fn interop_0_8() { let uuid = crate::Uuid::new(); let uuid_uuid = uuid.to_uuid_0_8(); assert_eq!(uuid.to_string(), uuid_uuid.to_string()); assert_eq!(&uuid.bytes(), uuid_uuid.as_bytes()); let back: crate::Uuid = uuid_uuid.into(); assert_eq!(back, uuid); let d_bson = doc! { "uuid": uuid }; let d_uuid = doc! { "uuid": uuid_uuid }; assert_eq!(d_bson, d_uuid); } #[cfg(feature = "uuid-1")] #[test] fn interop_1() { let uuid = crate::Uuid::new(); let uuid_uuid = uuid.to_uuid_1(); assert_eq!(uuid.to_string(), uuid_uuid.to_string()); assert_eq!(&uuid.bytes(), uuid_uuid.as_bytes()); let back: crate::Uuid = uuid_uuid.into(); assert_eq!(back, uuid); let d_bson = doc! { "uuid": uuid }; let d_uuid = doc! { "uuid": uuid_uuid }; assert_eq!(d_bson, d_uuid); } #[test] fn deserialize_uuid_from_string() { #[derive(Deserialize)] struct UuidWrapper { uuid: Uuid, } let uuid = Uuid::new(); let doc = doc! { "uuid": uuid.to_string() }; let wrapper: UuidWrapper = from_document(doc).expect("failed to deserialize document"); assert_eq!(wrapper.uuid, uuid); let raw_doc = rawdoc! { "uuid": uuid.to_string() }; let wrapper: UuidWrapper = from_slice(raw_doc.as_bytes()).expect("failed to deserialize raw document"); assert_eq!(wrapper.uuid, uuid); }