diff --git a/.evergreen/MSRV-Cargo.lock b/.evergreen/MSRV-Cargo.lock deleted file mode 100644 index 89501541b..000000000 --- a/.evergreen/MSRV-Cargo.lock +++ /dev/null @@ -1,2794 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "ahash" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7d5a2cecb58716e47d67d5703a249964b14c7be1ec3cad3affc295b2d1c35d" -dependencies = [ - "cfg-if", - "getrandom", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "aho-corasick" -version = "0.7.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" -dependencies = [ - "memchr", -] - -[[package]] -name = "anyhow" -version = "1.0.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" -dependencies = [ - "backtrace", -] - -[[package]] -name = "approx" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" -dependencies = [ - "num-traits", -] - -[[package]] -name = "array-init" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23589ecb866b460d3a0f1278834750268c607e8e28a1b982c907219f3178cd72" -dependencies = [ - "nodrop", -] - -[[package]] -name = "async-attributes" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" -dependencies = [ - "quote", - "syn 1.0.98", -] - -[[package]] -name = "async-channel" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" -dependencies = [ - "concurrent-queue 1.2.2", - "event-listener", - "futures-core", -] - -[[package]] -name = "async-executor" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fa3dc5f2a8564f07759c008b9109dc0d39de92a88d5588b8a5036d286383afb" -dependencies = [ - "async-lock", - "async-task", - "concurrent-queue 2.3.0", - "fastrand", - "futures-lite", - "slab", -] - -[[package]] -name = "async-global-executor" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5262ed948da60dd8956c6c5aca4d4163593dddb7b32d73267c93dab7b2e98940" -dependencies = [ - "async-channel", - "async-executor", - "async-io", - "async-lock", - "blocking", - "futures-lite", - "num_cpus", - "once_cell", -] - -[[package]] -name = "async-io" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5e18f61464ae81cde0a23e713ae8fd299580c54d697a35820cfd0625b8b0e07" -dependencies = [ - "concurrent-queue 1.2.2", - "futures-lite", - "libc", - "log", - "once_cell", - "parking", - "polling", - "slab", - "socket2", - "waker-fn", - "winapi", -] - -[[package]] -name = "async-lock" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" -dependencies = [ - "event-listener", -] - -[[package]] -name = "async-process" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2c06e30a24e8c78a3987d07f0930edf76ef35e027e7bdb063fccafdad1f60c" -dependencies = [ - "async-io", - "blocking", - "cfg-if", - "event-listener", - "futures-lite", - "libc", - "once_cell", - "signal-hook", - "winapi", -] - -[[package]] -name = "async-std" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" -dependencies = [ - "async-attributes", - "async-channel", - "async-global-executor", - "async-io", - "async-lock", - "async-process", - "crossbeam-utils", - "futures-channel", - "futures-core", - "futures-io", - "futures-lite", - "gloo-timers", - "kv-log-macro", - "log", - "memchr", - "once_cell", - "pin-project-lite", - "pin-utils", - "slab", - "wasm-bindgen-futures", -] - -[[package]] -name = "async-std-resolver" -version = "0.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f2f8a4a203be3325981310ab243a28e6e4ea55b6519bffce05d41ab60e09ad8" -dependencies = [ - "async-std", - "async-trait", - "futures-io", - "futures-util", - "pin-utils", - "socket2", - "trust-dns-resolver", -] - -[[package]] -name = "async-stream" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dad5c83079eae9969be7fadefe640a1c566901f05ff91ab221de4b6f68d9507e" -dependencies = [ - "async-stream-impl", - "futures-core", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.98", -] - -[[package]] -name = "async-task" -version = "4.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524" - -[[package]] -name = "async-trait" -version = "0.1.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.98", -] - -[[package]] -name = "atomic-waker" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "backtrace" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide 0.7.1", - "object", - "rustc-demangle", -] - -[[package]] -name = "base64" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[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 = "block-buffer" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" -dependencies = [ - "generic-array", -] - -[[package]] -name = "blocking" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6ccb65d468978a086b69884437ded69a90faab3bbe6e67f242173ea728acccc" -dependencies = [ - "async-channel", - "async-task", - "atomic-waker", - "fastrand", - "futures-lite", - "once_cell", -] - -[[package]] -name = "bson" -version = "2.6.0" -source = "git+https://github.com/mongodb/bson-rust?branch=main#b243db19b74745fcf52eacd9e4d34077186186d5" -dependencies = [ - "ahash", - "base64", - "bitvec", - "chrono", - "hex", - "indexmap", - "js-sys", - "once_cell", - "rand", - "serde", - "serde_bytes", - "serde_json", - "serde_with", - "time", - "uuid 0.8.2", - "uuid 1.1.2", -] - -[[package]] -name = "bumpalo" -version = "3.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" - -[[package]] -name = "bytes" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0b3de4a0c5e67e16066a0715723abd91edc2f9001d09c46e1dca929351e130e" - -[[package]] -name = "cache-padded" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" - -[[package]] -name = "cc" -version = "1.0.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" -dependencies = [ - "jobserver", -] - -[[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.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" -dependencies = [ - "libc", - "num-integer", - "num-traits", - "winapi", -] - -[[package]] -name = "concurrent-queue" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" -dependencies = [ - "cache-padded", -] - -[[package]] -name = "concurrent-queue" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f057a694a54f12365049b0958a1685bb52d567f5593b355fbf685838e873d400" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - -[[package]] -name = "cpufeatures" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" -dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f916dfc5d356b0ed9dae65f1db9fc9770aa2851d2662b988ccf4fe3516e86348" -dependencies = [ - "autocfg", - "cfg-if", - "crossbeam-utils", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "ctor" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" -dependencies = [ - "quote", - "syn 1.0.98", -] - -[[package]] -name = "ctrlc" -version = "3.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b37feaa84e6861e00a1f5e5aa8da3ee56d605c9992d33e082786754828e20865" -dependencies = [ - "nix", - "winapi", -] - -[[package]] -name = "darling" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[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.98", -] - -[[package]] -name = "darling_macro" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" -dependencies = [ - "darling_core", - "quote", - "syn 1.0.98", -] - -[[package]] -name = "data-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" - -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.98", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version 0.4.0", - "syn 1.0.98", -] - -[[package]] -name = "diff" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" - -[[package]] -name = "digest" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "either" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" - -[[package]] -name = "encoding_rs" -version = "0.8.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "enum-as-inner" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21cdad81446a7f7dc43f6a77409efeb9733d2fa65553efef6018ef257c959b73" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 1.0.98", -] - -[[package]] -name = "event-listener" -version = "2.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71" - -[[package]] -name = "fastrand" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" -dependencies = [ - "instant", -] - -[[package]] -name = "flate2" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" -dependencies = [ - "crc32fast", - "miniz_oxide 0.5.3", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" -dependencies = [ - "matches", - "percent-encoding", -] - -[[package]] -name = "function_name" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef632c665dc6e2b99ffa4d913f7160bd902c4d3e4cb732d81dc3d221f848512" -dependencies = [ - "function_name-proc-macro", -] - -[[package]] -name = "function_name-proc-macro" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "569d2238870f92cff64fc810013b61edaf446ebcfba36b649b96bc5b4078328a" -dependencies = [ - "proc-macro-crate", - "quote", - "syn 1.0.98", -] - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "futures" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" - -[[package]] -name = "futures-executor" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" - -[[package]] -name = "futures-lite" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - -[[package]] -name = "futures-macro" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.98", -] - -[[package]] -name = "futures-sink" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" - -[[package]] -name = "futures-task" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" - -[[package]] -name = "futures-util" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "gimli" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" - -[[package]] -name = "gloo-timers" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fb7d06c1c8cc2a29bee7ec961009a0b2caa0793ee4900c2ffb348734ba1c8f9" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "h2" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "heck" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" - -[[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 = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "home" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654" -dependencies = [ - "winapi", -] - -[[package]] -name = "hostname" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" -dependencies = [ - "libc", - "match_cfg", - "winapi", -] - -[[package]] -name = "http" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" - -[[package]] -name = "httpdate" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" - -[[package]] -name = "hyper" -version = "0.14.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" -dependencies = [ - "http", - "hyper", - "rustls 0.20.6", - "tokio", - "tokio-rustls 0.23.4", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "idna" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "indexmap" -version = "1.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "ipconfig" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "723519edce41262b05d4143ceb95050e4c614f483e78e9fd9e39a8275a84ad98" -dependencies = [ - "socket2", - "widestring", - "winapi", - "winreg 0.7.0", -] - -[[package]] -name = "ipnet" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" - -[[package]] -name = "itoa" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" - -[[package]] -name = "jobserver" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" -dependencies = [ - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "kv-log-macro" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" -dependencies = [ - "log", -] - -[[package]] -name = "lambda_runtime" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a81840726d481d20b99a9ce87430f644e9590cb77715e1e66c5f4432c9b586" -dependencies = [ - "async-stream", - "bytes", - "futures", - "http", - "hyper", - "lambda_runtime_api_client", - "serde", - "serde_json", - "tokio", - "tokio-stream", - "tower", - "tracing", -] - -[[package]] -name = "lambda_runtime_api_client" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b54698c666ffe503cb51fa66e4567e53e806128a10359de7095999d925a771ed" -dependencies = [ - "http", - "hyper", - "tokio", - "tower-service", -] - -[[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.149" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" - -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - -[[package]] -name = "lock_api" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" -dependencies = [ - "value-bag", -] - -[[package]] -name = "lru-cache" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" -dependencies = [ - "linked-hash-map", -] - -[[package]] -name = "match_cfg" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" - -[[package]] -name = "matches" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" - -[[package]] -name = "maybe-uninit" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" - -[[package]] -name = "md-5" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658646b21e0b72f7866c7038ab086d3d5e1cd6271f060fd37defb241949d0582" -dependencies = [ - "digest", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - -[[package]] -name = "mime" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" - -[[package]] -name = "miniz_oxide" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" -dependencies = [ - "adler", -] - -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" -dependencies = [ - "libc", - "log", - "wasi", - "windows-sys", -] - -[[package]] -name = "mongocrypt" -version = "0.1.2" -source = "git+https://github.com/mongodb/libmongocrypt-rust.git?branch=main" -dependencies = [ - "bson", - "mongocrypt-sys", - "once_cell", - "serde", -] - -[[package]] -name = "mongocrypt-sys" -version = "0.1.2+1.8.0-alpha1" -source = "git+https://github.com/mongodb/libmongocrypt-rust.git?branch=main#eee5a9817cdfb92204f6167ade5064f540e8b9e9" - -[[package]] -name = "mongodb" -version = "2.7.0" -dependencies = [ - "anyhow", - "approx", - "async-executor", - "async-std", - "async-std-resolver", - "async-trait", - "backtrace", - "base64", - "bitflags", - "bson", - "chrono", - "ctrlc", - "derivative", - "derive_more", - "flate2", - "function_name", - "futures", - "futures-core", - "futures-executor", - "futures-io", - "futures-util", - "hex", - "hmac", - "home", - "lambda_runtime", - "lazy_static", - "log", - "md-5", - "mongocrypt", - "num_cpus", - "openssl", - "openssl-probe", - "pbkdf2", - "percent-encoding", - "pretty_assertions", - "rand", - "rayon", - "regex", - "reqwest", - "rustc_version_runtime", - "rustls 0.21.7", - "rustls-pemfile", - "semver 1.0.12", - "serde", - "serde-hex", - "serde_bytes", - "serde_json", - "serde_with", - "sha-1", - "sha2", - "snap", - "socket2", - "stringprep", - "strsim", - "take_mut", - "thiserror", - "time", - "tokio", - "tokio-openssl", - "tokio-rustls 0.24.1", - "tokio-util", - "tracing", - "tracing-subscriber", - "trust-dns-proto", - "trust-dns-resolver", - "typed-builder", - "uuid 1.1.2", - "webpki-roots 0.25.2", - "zstd", -] - -[[package]] -name = "nix" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc" -dependencies = [ - "bitflags", - "cfg-if", - "libc", -] - -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "num_threads" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" -dependencies = [ - "libc", -] - -[[package]] -name = "object" -version = "0.32.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "openssl" -version = "0.10.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "618febf65336490dfcf20b73f885f5651a0c89c64c2d4a8c3662585a70bf5bd0" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.98", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5f9bd0c2710541a3cda73d6f9ac4f1b240de4ae261065d309dbe73d9dceb42f" -dependencies = [ - "autocfg", - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "output_vt100" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" -dependencies = [ - "winapi", -] - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "parking" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec 1.9.0", - "windows-sys", -] - -[[package]] -name = "pbkdf2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" -dependencies = [ - "digest", -] - -[[package]] -name = "percent-encoding" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" - -[[package]] -name = "pin-project" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.98", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" - -[[package]] -name = "polling" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685404d509889fade3e86fe3a5803bca2ec09b0c0778d5ada6ec8bf7a8de5259" -dependencies = [ - "cfg-if", - "libc", - "log", - "wepoll-ffi", - "winapi", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" - -[[package]] -name = "pretty_assertions" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755" -dependencies = [ - "ctor", - "diff", - "output_vt100", - "yansi", -] - -[[package]] -name = "proc-macro-crate" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" -dependencies = [ - "toml", -] - -[[package]] -name = "proc-macro2" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" -dependencies = [ - "unicode-ident", -] - -[[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.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -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.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rayon" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" -dependencies = [ - "autocfg", - "crossbeam-deque", - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-utils", - "num_cpus", -] - -[[package]] -name = "redox_syscall" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534cfe58d6a18cc17120fbf4635d53d14691c1fe4d951064df9bd326178d7d5a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "regex" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" - -[[package]] -name = "reqwest" -version = "0.11.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75aa69a3f06bbcc66ede33af2af253c6f7a86b1ca0033f60c580a27074fbf92" -dependencies = [ - "base64", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-rustls", - "ipnet", - "js-sys", - "lazy_static", - "log", - "mime", - "percent-encoding", - "pin-project-lite", - "rustls 0.20.6", - "rustls-pemfile", - "serde", - "serde_json", - "serde_urlencoded", - "tokio", - "tokio-rustls 0.23.4", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "webpki-roots 0.22.4", - "winreg 0.10.1", -] - -[[package]] -name = "resolv-conf" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" -dependencies = [ - "hostname", - "quick-error", -] - -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin", - "untrusted", - "web-sys", - "winapi", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver 0.9.0", -] - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver 1.0.12", -] - -[[package]] -name = "rustc_version_runtime" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d31b7153270ebf48bf91c65ae5b0c00e749c4cfad505f66530ac74950249582f" -dependencies = [ - "rustc_version 0.2.3", - "semver 0.9.0", -] - -[[package]] -name = "rustls" -version = "0.20.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033" -dependencies = [ - "log", - "ring", - "sct", - "webpki", -] - -[[package]] -name = "rustls" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" -dependencies = [ - "log", - "ring", - "rustls-webpki", - "sct", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" -dependencies = [ - "base64", -] - -[[package]] -name = "rustls-webpki" -version = "0.101.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c7d5dece342910d9ba34d259310cae3e0154b873b35408b787b59bce53d34fe" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "ryu" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "sct" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1" - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "serde" -version = "1.0.140" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde-hex" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca37e3e4d1b39afd7ff11ee4e947efae85adfddf4841787bfa47c470e96dc26d" -dependencies = [ - "array-init", - "serde", - "smallvec 0.6.14", -] - -[[package]] -name = "serde_bytes" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212e73464ebcde48d723aa02eb270ba62eff38a9b732df31f33f1b4e145f3a54" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_derive" -version = "1.0.140" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.98", -] - -[[package]] -name = "serde_json" -version = "1.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" -dependencies = [ - "indexmap", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "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", -] - -[[package]] -name = "serde_with_macros" -version = "1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 1.0.98", -] - -[[package]] -name = "sha-1" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha2" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "signal-hook" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" -dependencies = [ - "libc", -] - -[[package]] -name = "slab" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "0.6.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0" -dependencies = [ - "maybe-uninit", -] - -[[package]] -name = "smallvec" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" - -[[package]] -name = "snap" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45456094d1983e2ee2a18fdfebce3189fa451699d0502cb8e3b49dba5ba41451" - -[[package]] -name = "socket2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - -[[package]] -name = "stringprep" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" - -[[package]] -name = "syn" -version = "1.0.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "take_mut" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "thiserror" -version = "1.0.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.98", -] - -[[package]] -name = "thread_local" -version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "time" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" -dependencies = [ - "itoa", - "libc", - "num_threads", - "time-macros", -] - -[[package]] -name = "time-macros" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" - -[[package]] -name = "tokio" -version = "1.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a8325f63a7d4774dd041e363b2409ed1c5cbbd0f867795e661df066b2b0a581" -dependencies = [ - "autocfg", - "bytes", - "libc", - "memchr", - "mio", - "num_cpus", - "once_cell", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "winapi", -] - -[[package]] -name = "tokio-macros" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.98", -] - -[[package]] -name = "tokio-openssl" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08f9ffb7809f1b20c1b398d92acf4cc719874b3b2b2d9ea2f09b4a80350878a" -dependencies = [ - "futures-util", - "openssl", - "openssl-sys", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.23.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" -dependencies = [ - "rustls 0.20.6", - "tokio", - "webpki", -] - -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls 0.21.7", - "tokio", -] - -[[package]] -name = "tokio-stream" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6edf2d6bc038a43d31353570e27270603f4648d18f5ed10c0e179abe43255af" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" -dependencies = [ - "bytes", - "futures-core", - "futures-io", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - -[[package]] -name = "toml" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" -dependencies = [ - "serde", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "pin-project", - "pin-project-lite", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-layer" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" -dependencies = [ - "nu-ansi-term", - "sharded-slab", - "smallvec 1.9.0", - "thread_local", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "trust-dns-proto" -version = "0.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c31f240f59877c3d4bb3b3ea0ec5a6a0cff07323580ff8c7a605cd7d08b255d" -dependencies = [ - "async-trait", - "cfg-if", - "data-encoding", - "enum-as-inner", - "futures-channel", - "futures-io", - "futures-util", - "idna", - "ipnet", - "lazy_static", - "log", - "rand", - "smallvec 1.9.0", - "thiserror", - "tinyvec", - "tokio", - "url", -] - -[[package]] -name = "trust-dns-resolver" -version = "0.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ba72c2ea84515690c9fcef4c6c660bb9df3036ed1051686de84605b74fd558" -dependencies = [ - "cfg-if", - "futures-util", - "ipconfig", - "lazy_static", - "log", - "lru-cache", - "parking_lot", - "resolv-conf", - "smallvec 1.9.0", - "thiserror", - "tokio", - "trust-dns-proto", -] - -[[package]] -name = "try-lock" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" - -[[package]] -name = "typed-builder" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89851716b67b937e393b3daa8423e67ddfc4bbbf1654bcf05488e95e0828db0c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.98", -] - -[[package]] -name = "typenum" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" - -[[package]] -name = "unicode-bidi" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" - -[[package]] -name = "unicode-ident" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" - -[[package]] -name = "unicode-normalization" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - -[[package]] -name = "url" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" -dependencies = [ - "form_urlencoded", - "idna", - "matches", - "percent-encoding", -] - -[[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.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f" -dependencies = [ - "getrandom", - "serde", -] - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "value-bag" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a72e1902dde2bd6441347de2b70b7f5d59bf157c6c62f0c44572607a1d55bbe" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "waker-fn" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" - -[[package]] -name = "want" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" -dependencies = [ - "log", - "try-lock", -] - -[[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.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a" -dependencies = [ - "bumpalo", - "lazy_static", - "log", - "proc-macro2", - "quote", - "syn 1.0.98", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de9a9cec1733468a8c657e57fa2413d2ae2c0129b95e87c5b72b8ace4d13f31f" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.98", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be" - -[[package]] -name = "web-sys" -version = "0.3.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "webpki-roots" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1c760f0d366a6c24a02ed7816e23e691f5d92291f94d15e836006fd11b04daf" -dependencies = [ - "webpki", -] - -[[package]] -name = "webpki-roots" -version = "0.25.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" - -[[package]] -name = "wepoll-ffi" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" -dependencies = [ - "cc", -] - -[[package]] -name = "widestring" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983" - -[[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-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" -dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" - -[[package]] -name = "windows_i686_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" - -[[package]] -name = "windows_i686_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" - -[[package]] -name = "winreg" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" -dependencies = [ - "winapi", -] - -[[package]] -name = "winreg" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" -dependencies = [ - "winapi", -] - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - -[[package]] -name = "yansi" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" - -[[package]] -name = "zerocopy" -version = "0.7.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c19fae0c8a9efc6a8281f2e623db8af1db9e57852e04cde3e754dd2dc29340f" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc56589e9ddd1f1c28d4b4b5c773ce232910a6bb67a70133d61c9e347585efe9" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "zstd" -version = "0.11.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" -dependencies = [ - "libc", - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.1+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fd07cbbc53846d9145dbffdf6dd09a7a0aa52be46741825f5c97bdd4f73f12b" -dependencies = [ - "cc", - "libc", -] diff --git a/.evergreen/MSRV-Cargo.toml.diff b/.evergreen/MSRV-Cargo.toml.diff new file mode 100644 index 000000000..bafd77e6b --- /dev/null +++ b/.evergreen/MSRV-Cargo.toml.diff @@ -0,0 +1,18 @@ +95c95 +< bson = "2.8.0" +--- +> bson = "=2.8.0" +103a104 +> hashbrown = "=0.12.3" +166c167 +< version = "1.17.0" +--- +> version = "=1.18.0" +193c194 +< serde_json = "1.0.64" +--- +> serde_json = "=1.0.64" +195c196 +< time = "0.3.9" +--- +> time = "=0.3.9" diff --git a/.evergreen/compile-only.sh b/.evergreen/compile-only.sh index 6df711733..e48578c7b 100755 --- a/.evergreen/compile-only.sh +++ b/.evergreen/compile-only.sh @@ -9,7 +9,7 @@ source ./.evergreen/env.sh if [ "$RUST_VERSION" != "" ]; then rustup toolchain install $RUST_VERSION TOOLCHAIN="+${RUST_VERSION}" - cp .evergreen/MSRV-Cargo.lock Cargo.lock + patch Cargo.toml .evergreen/MSRV-Cargo.toml.diff fi source ./.evergreen/feature-combinations.sh diff --git a/src/bson_util.rs b/src/bson_util.rs index d5f4b5047..185b43018 100644 --- a/src/bson_util.rs +++ b/src/bson_util.rs @@ -5,12 +5,14 @@ use std::{ use crate::{ bson::{Bson, Document, RawArrayBuf, RawBson, RawBsonRef, RawDocumentBuf}, + checked::Checked, error::{ErrorKind, Result}, runtime::SyncLittleEndianRead, }; /// Coerce numeric types into an `i64` if it would be lossless to do so. If this Bson is not numeric /// or the conversion would be lossy (e.g. 1.5 -> 1), this returns `None`. +#[allow(clippy::cast_possible_truncation)] pub(crate) fn get_int(val: &Bson) -> Option { match *val { Bson::Int32(i) => Some(i64::from(i)), @@ -33,6 +35,7 @@ pub(crate) fn get_int_raw(val: RawBsonRef<'_>) -> Option { /// Coerce numeric types into an `u64` if it would be lossless to do so. If this Bson is not numeric /// or the conversion would be lossy (e.g. 1.5 -> 1), this returns `None`. +#[allow(clippy::cast_possible_truncation)] pub(crate) fn get_u64(val: &Bson) -> Option { match *val { Bson::Int32(i) => u64::try_from(i).ok(), @@ -89,18 +92,18 @@ pub(crate) fn update_document_check(update: &Document) -> Result<()> { } /// The size in bytes of the provided document's entry in a BSON array at the given index. -pub(crate) fn array_entry_size_bytes(index: usize, doc_len: usize) -> u64 { +pub(crate) fn array_entry_size_bytes(index: usize, doc_len: usize) -> Result { // * type (1 byte) // * number of decimal digits in key // * null terminator for the key (1 byte) // * size of value - 1 + num_decimal_digits(index) + 1 + doc_len as u64 + (Checked::new(1) + num_decimal_digits(index) + 1 + doc_len).get() } /// The number of digits in `n` in base 10. /// Useful for calculating the size of an array entry in BSON. -fn num_decimal_digits(mut n: usize) -> u64 { +fn num_decimal_digits(mut n: usize) -> usize { let mut digits = 0; loop { diff --git a/src/checked.rs b/src/checked.rs new file mode 100644 index 000000000..ece4d2a59 --- /dev/null +++ b/src/checked.rs @@ -0,0 +1,502 @@ +// Modified from https://github.com/zeta12ti/Checked/blob/master/src/num.rs +// Original license: +// MIT License +// +// Copyright (c) 2017 zeta12ti +// +// 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. + +use std::{cmp::Ordering, convert::TryFrom, fmt, ops::*}; + +/// The Checked type. See the [module level documentation for more.](index.html) +#[derive(PartialEq, Eq, Clone, Copy, Hash)] +pub struct Checked(pub Option); + +impl Checked { + /// Creates a new Checked instance from some sort of integer. + #[inline] + pub fn new(x: T) -> Checked { + Checked(Some(x)) + } + + pub fn try_from(value: F) -> crate::error::Result + where + T: TryFrom, + T::Error: std::fmt::Display, + { + value + .try_into() + .map(|v| Self(Some(v))) + .map_err(|e| crate::error::Error::invalid_argument(format! {"{}", e})) + } + + pub fn get(self) -> crate::error::Result { + self.0 + .ok_or_else(|| crate::error::Error::invalid_argument("checked arithmetic failure")) + } + + pub fn try_into(self) -> crate::error::Result + where + T: TryInto, + T::Error: std::fmt::Display, + { + self.get().and_then(|v| { + v.try_into() + .map_err(|e| crate::error::Error::invalid_argument(format!("{}", e))) + }) + } +} + +// The derived Default only works if T has Default +// Even though this is what it would be anyway +// May change this to T's default (if it has one) +impl Default for Checked { + #[inline] + fn default() -> Checked { + Checked(None) + } +} + +impl fmt::Debug for Checked { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match **self { + Some(ref x) => x.fmt(f), + None => "overflow".fmt(f), + } + } +} + +impl fmt::Display for Checked { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match **self { + Some(ref x) => x.fmt(f), + None => "overflow".fmt(f), + } + } +} + +// I'd like to do +// `impl From where T: From for Checked`` +// in the obvious way, but that "conflicts" with the default `impl From for T`. +// This would subsume both the below Froms since Option has the right From impl. +impl From for Checked { + #[inline] + fn from(x: T) -> Checked { + Checked(Some(x)) + } +} + +impl From> for Checked { + #[inline] + fn from(x: Option) -> Checked { + Checked(x) + } +} + +impl Deref for Checked { + type Target = Option; + + #[inline] + fn deref(&self) -> &Option { + &self.0 + } +} + +impl DerefMut for Checked { + #[inline] + fn deref_mut(&mut self) -> &mut Option { + &mut self.0 + } +} + +impl PartialOrd for Checked { + fn partial_cmp(&self, other: &Checked) -> Option { + // I'm not really sure why we can't match **self etc. here. + // Even with refs everywhere it complains + // Note what happens in this implementation: + // we take the reference self, and call deref (the method) on it + // By Deref coercion, self gets derefed to a Checked + // Now Checked's deref gets called, returning a &Option + // That's what gets matched + match (self.deref(), other.deref()) { + (Some(x), Some(y)) => PartialOrd::partial_cmp(x, y), + _ => None, + } + } +} + +// implements the unary operator `op &T` +// based on `op T` where `T` is expected to be `Copy`able +macro_rules! forward_ref_unop { + (impl $imp:ident, $method:ident for $t:ty {}) => { + impl<'a> $imp for &'a $t { + type Output = <$t as $imp>::Output; + + #[inline] + fn $method(self) -> <$t as $imp>::Output { + $imp::$method(*self) + } + } + }; +} + +// implements binary operators "&T op U", "T op &U", "&T op &U" +// based on "T op U" where T and U are expected to be `Copy`able +macro_rules! forward_ref_binop { + (impl $imp:ident, $method:ident for $t:ty, $u:ty {}) => { + impl<'a> $imp<$u> for &'a $t { + type Output = <$t as $imp<$u>>::Output; + + #[inline] + fn $method(self, other: $u) -> <$t as $imp<$u>>::Output { + $imp::$method(*self, other) + } + } + + impl<'a> $imp<&'a $u> for $t { + type Output = <$t as $imp<$u>>::Output; + + #[inline] + fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output { + $imp::$method(self, *other) + } + } + + impl<'a, 'b> $imp<&'a $u> for &'b $t { + type Output = <$t as $imp<$u>>::Output; + + #[inline] + fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output { + $imp::$method(*self, *other) + } + } + }; +} + +macro_rules! impl_sh { + ($t:ident, $f:ident) => { + impl Shl> for Checked<$t> { + type Output = Checked<$t>; + + fn shl(self, other: Checked<$f>) -> Checked<$t> { + match (*self, *other) { + (Some(x), Some(y)) => Checked(x.checked_shl(y)), + _ => Checked(None), + } + } + } + + impl Shl<$f> for Checked<$t> { + type Output = Checked<$t>; + + fn shl(self, other: $f) -> Checked<$t> { + match *self { + Some(x) => Checked(x.checked_shl(other)), + None => Checked(None), + } + } + } + + forward_ref_binop! { impl Shl, shl for Checked<$t>, Checked<$f> {} } + forward_ref_binop! { impl Shl, shl for Checked<$t>, $f {} } + + impl ShlAssign<$f> for Checked<$t> { + #[inline] + fn shl_assign(&mut self, other: $f) { + *self = *self << other; + } + } + + impl ShlAssign> for Checked<$t> { + #[inline] + fn shl_assign(&mut self, other: Checked<$f>) { + *self = *self << other; + } + } + + impl Shr> for Checked<$t> { + type Output = Checked<$t>; + + fn shr(self, other: Checked<$f>) -> Checked<$t> { + match (*self, *other) { + (Some(x), Some(y)) => Checked(x.checked_shr(y)), + _ => Checked(None), + } + } + } + + impl Shr<$f> for Checked<$t> { + type Output = Checked<$t>; + + fn shr(self, other: $f) -> Checked<$t> { + match *self { + Some(x) => Checked(x.checked_shr(other)), + None => Checked(None), + } + } + } + + forward_ref_binop! { impl Shr, shr for Checked<$t>, Checked<$f> {} } + forward_ref_binop! { impl Shr, shr for Checked<$t>, $f {} } + + impl ShrAssign<$f> for Checked<$t> { + #[inline] + fn shr_assign(&mut self, other: $f) { + *self = *self >> other; + } + } + + impl ShrAssign> for Checked<$t> { + #[inline] + fn shr_assign(&mut self, other: Checked<$f>) { + *self = *self >> other; + } + } + }; +} + +macro_rules! impl_sh_reverse { + ($t:ident, $f:ident) => { + impl Shl> for $f { + type Output = Checked<$f>; + + fn shl(self, other: Checked<$t>) -> Checked<$f> { + match *other { + Some(x) => Checked(self.checked_shl(x)), + None => Checked(None), + } + } + } + + forward_ref_binop! { impl Shl, shl for $f, Checked<$t> {} } + + impl Shr> for $f { + type Output = Checked<$f>; + + fn shr(self, other: Checked<$t>) -> Checked<$f> { + match *other { + Some(x) => Checked(self.checked_shr(x)), + None => Checked(None), + } + } + } + + forward_ref_binop! { impl Shr, shr for $f, Checked<$t> {} } + }; +} + +macro_rules! impl_sh_all { + ($($t:ident)*) => ($( + // When checked_shX is added for other shift sizes, uncomment some of these. + // impl_sh! { $t, u8 } + // impl_sh! { $t, u16 } + impl_sh! { $t, u32 } + //impl_sh! { $t, u64 } + //impl_sh! { $t, usize } + + //impl_sh! { $t, i8 } + //impl_sh! { $t, i16 } + //impl_sh! { $t, i32 } + //impl_sh! { $t, i64 } + //impl_sh! { $t, isize } + + // impl_sh_reverse! { u8, $t } + // impl_sh_reverse! { u16, $t } + impl_sh_reverse! { u32, $t } + //impl_sh_reverse! { u64, $t } + //impl_sh_reverse! { usize, $t } + + //impl_sh_reverse! { i8, $t } + //impl_sh_reverse! { i16, $t } + //impl_sh_reverse! { i32, $t } + //impl_sh_reverse! { i64, $t } + //impl_sh_reverse! { isize, $t } + )*) +} + +impl_sh_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } + +// implements unary operators for checked types +macro_rules! impl_unop { + (impl $imp:ident, $method:ident, $checked_method:ident for $t:ty {}) => { + impl $imp for Checked<$t> { + type Output = Checked<$t>; + + fn $method(self) -> Checked<$t> { + match *self { + Some(x) => Checked(x.$checked_method()), + None => Checked(None), + } + } + } + + forward_ref_unop! { impl $imp, $method for Checked<$t> {} } + }; +} + +// implements unary operators for checked types (with no checked method) +macro_rules! impl_unop_unchecked { + (impl $imp:ident, $method:ident for $t:ty {$op:tt}) => { + impl $imp for Checked<$t> { + type Output = Checked<$t>; + + fn $method(self) -> Checked<$t> { + match *self { + Some(x) => Checked(Some($op x)), + None => Checked(None) + } + } + } + + forward_ref_unop! { impl $imp, $method for Checked<$t> {} } + } +} + +// implements binary operators for checked types +macro_rules! impl_binop { + (impl $imp:ident, $method:ident, $checked_method:ident for $t:ty {}) => { + impl $imp for Checked<$t> { + type Output = Checked<$t>; + + fn $method(self, other: Checked<$t>) -> Checked<$t> { + match (*self, *other) { + (Some(x), Some(y)) => Checked(x.$checked_method(y)), + _ => Checked(None), + } + } + } + + impl $imp<$t> for Checked<$t> { + type Output = Checked<$t>; + + fn $method(self, other: $t) -> Checked<$t> { + match *self { + Some(x) => Checked(x.$checked_method(other)), + _ => Checked(None), + } + } + } + + impl $imp> for $t { + type Output = Checked<$t>; + + fn $method(self, other: Checked<$t>) -> Checked<$t> { + match *other { + Some(x) => Checked(self.$checked_method(x)), + None => Checked(None), + } + } + } + + forward_ref_binop! { impl $imp, $method for Checked<$t>, Checked<$t> {} } + forward_ref_binop! { impl $imp, $method for Checked<$t>, $t {} } + forward_ref_binop! { impl $imp, $method for $t, Checked<$t> {} } + }; +} + +// implements binary operators for checked types (no checked method) +macro_rules! impl_binop_unchecked { + (impl $imp:ident, $method:ident for $t:ty {$op:tt}) => { + impl $imp for Checked<$t> { + type Output = Checked<$t>; + + fn $method(self, other: Checked<$t>) -> Checked<$t> { + match (*self, *other) { + (Some(x), Some(y)) => Checked(Some(x $op y)), + _ => Checked(None), + } + } + } + + impl $imp<$t> for Checked<$t> { + type Output = Checked<$t>; + + fn $method(self, other: $t) -> Checked<$t> { + match *self { + Some(x) => Checked(Some(x $op other)), + _ => Checked(None), + } + } + } + + impl $imp> for $t { + type Output = Checked<$t>; + + fn $method(self, other: Checked<$t>) -> Checked<$t> { + match *other { + Some(x) => Checked(Some(self $op x)), + None => Checked(None), + } + } + } + + forward_ref_binop! { impl $imp, $method for Checked<$t>, Checked<$t> {} } + forward_ref_binop! { impl $imp, $method for Checked<$t>, $t {} } + forward_ref_binop! { impl $imp, $method for $t, Checked<$t> {} } + } +} + +// implements assignment operators for checked types +macro_rules! impl_binop_assign { + (impl $imp:ident, $method:ident for $t:ty {$op:tt}) => { + impl $imp for Checked<$t> { + #[inline] + fn $method(&mut self, other: Checked<$t>) { + *self = *self $op other; + } + } + + impl $imp<$t> for Checked<$t> { + #[inline] + fn $method(&mut self, other: $t) { + *self = *self $op other; + } + } + }; +} + +macro_rules! checked_impl { + ($($t:ty)*) => { + $( + impl_binop! { impl Add, add, checked_add for $t {} } + impl_binop_assign! { impl AddAssign, add_assign for $t {+} } + impl_binop! { impl Sub, sub, checked_sub for $t {} } + impl_binop_assign! { impl SubAssign, sub_assign for $t {-} } + impl_binop! { impl Mul, mul, checked_mul for $t {} } + impl_binop_assign! { impl MulAssign, mul_assign for $t {*} } + impl_binop! { impl Div, div, checked_div for $t {} } + impl_binop_assign! { impl DivAssign, div_assign for $t {/} } + impl_binop! { impl Rem, rem, checked_rem for $t {} } + impl_binop_assign! { impl RemAssign, rem_assign for $t {%} } + impl_unop_unchecked! { impl Not, not for $t {!} } + impl_binop_unchecked! { impl BitXor, bitxor for $t {^} } + impl_binop_assign! { impl BitXorAssign, bitxor_assign for $t {^} } + impl_binop_unchecked! { impl BitOr, bitor for $t {|} } + impl_binop_assign! { impl BitOrAssign, bitor_assign for $t {|} } + impl_binop_unchecked! { impl BitAnd, bitand for $t {&} } + impl_binop_assign! { impl BitAndAssign, bitand_assign for $t {&} } + impl_unop! { impl Neg, neg, checked_neg for $t {} } + + )* + }; +} + +checked_impl! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } diff --git a/src/client/auth/sasl.rs b/src/client/auth/sasl.rs index 1d66099a5..444038834 100644 --- a/src/client/auth/sasl.rs +++ b/src/client/auth/sasl.rs @@ -42,7 +42,7 @@ impl SaslStart { body.insert("options", doc! { "skipEmptyExchange": true }); } - let mut command = Command::new("saslStart".into(), self.source, body); + let mut command = Command::new("saslStart", self.source, body); if let Some(server_api) = self.server_api { command.set_server_api(&server_api); } @@ -81,7 +81,7 @@ impl SaslContinue { "payload": Binary { subtype: BinarySubtype::Generic, bytes: self.payload }, }; - let mut command = Command::new("saslContinue".into(), self.source, body); + let mut command = Command::new("saslContinue", self.source, body); if let Some(server_api) = self.server_api { command.set_server_api(&server_api); } diff --git a/src/client/auth/x509.rs b/src/client/auth/x509.rs index e7cbdfb5f..a7e58a052 100644 --- a/src/client/auth/x509.rs +++ b/src/client/auth/x509.rs @@ -25,7 +25,7 @@ pub(crate) fn build_client_first( auth_command_doc.insert("username", username); } - let mut command = Command::new("authenticate".into(), "$external".into(), auth_command_doc); + let mut command = Command::new("authenticate", "$external", auth_command_doc); if let Some(server_api) = server_api { command.set_server_api(server_api); } diff --git a/src/client/executor.rs b/src/client/executor.rs index 15eae93d3..171452a50 100644 --- a/src/client/executor.rs +++ b/src/client/executor.rs @@ -23,10 +23,12 @@ use crate::{ WatchArgs, }, cmap::{ - conn::PinnedConnectionHandle, + conn::{ + wire::{next_request_id, Message}, + PinnedConnectionHandle, + }, Connection, ConnectionPool, - RawCommand, RawCommandResponse, }, cursor::{session::SessionCursor, Cursor, CursorSpecification}, @@ -573,51 +575,43 @@ impl Client { let connection_info = connection.info(); let service_id = connection.service_id(); - let request_id = crate::cmap::conn::next_request_id(); + let request_id = next_request_id(); if let Some(ref server_api) = self.inner.options.server_api { cmd.set_server_api(server_api); } let should_redact = cmd.should_redact(); + let should_compress = cmd.should_compress(); let cmd_name = cmd.name.clone(); let target_db = cmd.target_db.clone(); - let serialized = op.serialize_command(cmd)?; + #[allow(unused_mut)] + let mut message = Message::from_command(cmd, Some(request_id))?; #[cfg(feature = "in-use-encryption-unstable")] - let serialized = { + { let guard = self.inner.csfle.read().await; if let Some(ref csfle) = *guard { if csfle.opts().bypass_auto_encryption != Some(true) { - self.auto_encrypt(csfle, RawDocument::from_bytes(&serialized)?, &target_db) - .await? - .into_bytes() - } else { - serialized + let encrypted_payload = self + .auto_encrypt(csfle, &message.document_payload, &target_db) + .await?; + message.document_payload = encrypted_payload; } - } else { - serialized } - }; - let raw_cmd = RawCommand { - name: cmd_name.clone(), - target_db, - exhaust_allowed: false, - bytes: serialized, - }; + } self.emit_command_event(|| { let command_body = if should_redact { Document::new() } else { - Document::from_reader(raw_cmd.bytes.as_slice()) - .unwrap_or_else(|e| doc! { "serialization error": e.to_string() }) + message.get_command_document() }; CommandEvent::Started(CommandStartedEvent { command: command_body, - db: raw_cmd.target_db.clone(), - command_name: raw_cmd.name.clone(), + db: target_db.clone(), + command_name: cmd_name.clone(), request_id, connection: connection_info.clone(), service_id, @@ -626,7 +620,7 @@ impl Client { .await; let start_time = Instant::now(); - let command_result = match connection.send_raw_command(raw_cmd, request_id).await { + let command_result = match connection.send_message(message, should_compress).await { Ok(response) => { async fn handle_response( client: &Client, diff --git a/src/client/options.rs b/src/client/options.rs index f4bef3193..7e1519161 100644 --- a/src/client/options.rs +++ b/src/client/options.rs @@ -738,7 +738,11 @@ impl Serialize for ClientOptions { writeconcern: &self.write_concern, loadbalanced: &self.load_balanced, zlibcompressionlevel: &None, - srvmaxhosts: self.srv_max_hosts.map(|v| v as i32), + srvmaxhosts: self + .srv_max_hosts + .map(|v| v.try_into()) + .transpose() + .map_err(serde::ser::Error::custom)?, }; client_options.serialize(serializer) diff --git a/src/cmap.rs b/src/cmap.rs index dd4ca5d1c..c3f981352 100644 --- a/src/cmap.rs +++ b/src/cmap.rs @@ -15,7 +15,7 @@ use derivative::Derivative; pub use self::conn::ConnectionInfo; pub(crate) use self::{ - conn::{Command, Connection, RawCommand, RawCommandResponse, StreamDescription}, + conn::{Command, Connection, RawCommandResponse, StreamDescription}, status::PoolGenerationSubscriber, worker::PoolGeneration, }; diff --git a/src/cmap/conn.rs b/src/cmap/conn.rs index f42a9f7f4..8c358ffe3 100644 --- a/src/cmap/conn.rs +++ b/src/cmap/conn.rs @@ -1,6 +1,6 @@ mod command; mod stream_description; -mod wire; +pub(crate) mod wire; use std::{ sync::Arc, @@ -33,9 +33,8 @@ use crate::{ options::ServerAddress, runtime::AsyncStream, }; -pub(crate) use command::{Command, RawCommand, RawCommandResponse}; +pub(crate) use command::{Command, RawCommandResponse}; pub(crate) use stream_description::StreamDescription; -pub(crate) use wire::next_request_id; /// User-facing information about a connection to the database. #[derive(Clone, Debug, Serialize)] @@ -181,6 +180,7 @@ impl Connection { ) } + #[allow(clippy::cast_possible_truncation)] pub(crate) fn info(&self) -> ConnectionInfo { ConnectionInfo { id: self.id, @@ -273,7 +273,7 @@ impl Connection { } } - async fn send_message( + pub(crate) async fn send_message( &mut self, message: Message, to_compress: bool, @@ -318,7 +318,10 @@ impl Connection { let response_message = response_message_result?; self.more_to_come = response_message.flags.contains(MessageFlags::MORE_TO_COME); - RawCommandResponse::new(self.address.clone(), response_message) + Ok(RawCommandResponse::new( + self.address.clone(), + response_message, + )) } /// Executes a `Command` and returns a `CommandResponse` containing the result from the server. @@ -332,23 +335,7 @@ impl Connection { request_id: impl Into>, ) -> Result { let to_compress = command.should_compress(); - let message = Message::with_command(command, request_id.into())?; - self.send_message(message, to_compress).await - } - - /// Executes a `RawCommand` and returns a `CommandResponse` containing the result from the - /// server. - /// - /// An `Ok(...)` result simply means the server received the command and that the driver - /// received the response; it does not imply anything about the success of the command - /// itself. - pub(crate) async fn send_raw_command( - &mut self, - command: RawCommand, - request_id: impl Into>, - ) -> Result { - let to_compress = command.should_compress(); - let message = Message::with_raw_command(command, request_id.into()); + let message = Message::from_command(command, request_id.into())?; self.send_message(message, to_compress).await } @@ -379,7 +366,10 @@ impl Connection { let response_message = response_message_result?; self.more_to_come = response_message.flags.contains(MessageFlags::MORE_TO_COME); - RawCommandResponse::new(self.address.clone(), response_message) + Ok(RawCommandResponse::new( + self.address.clone(), + response_message, + )) } /// Gets the connection's StreamDescription. diff --git a/src/cmap/conn/command.rs b/src/cmap/conn/command.rs index 311d7d42c..933125156 100644 --- a/src/cmap/conn/command.rs +++ b/src/cmap/conn/command.rs @@ -1,11 +1,10 @@ use bson::{RawDocument, RawDocumentBuf}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use super::wire::Message; +use super::wire::{message::DocumentSequence, Message}; use crate::{ - bson::{rawdoc, Document}, - bson_util::extend_raw_document_buf, - client::{options::ServerApi, ClusterTime, HELLO_COMMAND_NAMES, REDACTED_COMMANDS}, + bson::Document, + client::{options::ServerApi, ClusterTime}, error::{Error, ErrorKind, Result}, hello::{HelloCommandResponse, HelloReply}, operation::{CommandErrorBody, CommandResponse}, @@ -14,28 +13,14 @@ use crate::{ ClientSession, }; -/// A command that has been serialized to BSON. -#[derive(Debug)] -pub(crate) struct RawCommand { - pub(crate) name: String, - pub(crate) target_db: String, - /// Whether or not the server may respond to this command multiple times via the moreToComeBit. - pub(crate) exhaust_allowed: bool, - pub(crate) bytes: Vec, -} - -impl RawCommand { - pub(crate) fn should_compress(&self) -> bool { - let name = self.name.to_lowercase(); - !REDACTED_COMMANDS.contains(name.as_str()) && !HELLO_COMMAND_NAMES.contains(name.as_str()) - } -} - /// Driver-side model of a database command. #[serde_with::skip_serializing_none] #[derive(Clone, Debug, Serialize, Default)] #[serde(rename_all = "camelCase")] -pub(crate) struct Command { +pub(crate) struct Command +where + T: Serialize, +{ #[serde(skip)] pub(crate) name: String, @@ -45,6 +30,9 @@ pub(crate) struct Command { #[serde(flatten)] pub(crate) body: T, + #[serde(skip)] + pub(crate) document_sequences: Vec, + #[serde(rename = "$db")] pub(crate) target_db: String, @@ -70,13 +58,17 @@ pub(crate) struct Command { recovery_token: Option, } -impl Command { - pub(crate) fn new(name: String, target_db: String, body: T) -> Self { +impl Command +where + T: Serialize, +{ + pub(crate) fn new(name: impl ToString, target_db: impl ToString, body: T) -> Self { Self { - name, - target_db, + name: name.to_string(), + target_db: target_db.to_string(), exhaust_allowed: false, body, + document_sequences: Vec::new(), lsid: None, cluster_time: None, server_api: None, @@ -100,6 +92,7 @@ impl Command { target_db, exhaust_allowed: false, body, + document_sequences: Vec::new(), lsid: None, cluster_time: None, server_api: None, @@ -112,6 +105,17 @@ impl Command { } } + pub(crate) fn add_document_sequence( + &mut self, + identifier: impl ToString, + documents: Vec, + ) { + self.document_sequences.push(DocumentSequence { + identifier: identifier.to_string(), + documents, + }); + } + pub(crate) fn set_session(&mut self, session: &ClientSession) { self.lsid = Some(session.id().clone()) } @@ -178,19 +182,6 @@ impl Command { } } -impl Command { - pub(crate) fn into_bson_bytes(mut self) -> Result> { - let mut command = self.body; - - // Clear the body of the command to avoid re-serializing. - self.body = rawdoc! {}; - let rest_of_command = bson::to_raw_document_buf(&self)?; - - extend_raw_document_buf(&mut command, rest_of_command)?; - Ok(command.into_bytes()) - } -} - #[derive(Debug, Clone)] pub(crate) struct RawCommandResponse { pub(crate) source: ServerAddress, @@ -220,9 +211,8 @@ impl RawCommandResponse { ) } - pub(crate) fn new(source: ServerAddress, message: Message) -> Result { - let raw = message.single_document_response()?; - Ok(Self::new_raw(source, RawDocumentBuf::from_bytes(raw)?)) + pub(crate) fn new(source: ServerAddress, message: Message) -> Self { + Self::new_raw(source, message.document_payload) } pub(crate) fn new_raw(source: ServerAddress, raw: RawDocumentBuf) -> Self { diff --git a/src/cmap/conn/stream_description.rs b/src/cmap/conn/stream_description.rs index 2ea6c7f99..b24164e26 100644 --- a/src/cmap/conn/stream_description.rs +++ b/src/cmap/conn/stream_description.rs @@ -99,7 +99,7 @@ impl StreamDescription { max_bson_object_size: 16 * 1024 * 1024, max_write_batch_size: 100_000, hello_ok: false, - max_message_size_bytes: Default::default(), + max_message_size_bytes: 48_000_000, service_id: None, } } diff --git a/src/cmap/conn/wire.rs b/src/cmap/conn/wire.rs index cfcaaaa04..76ef2cfab 100644 --- a/src/cmap/conn/wire.rs +++ b/src/cmap/conn/wire.rs @@ -1,5 +1,5 @@ mod header; -mod message; +pub(crate) mod message; mod util; pub(crate) use self::{ diff --git a/src/cmap/conn/wire/message.rs b/src/cmap/conn/wire/message.rs index 8b5d54bce..de5c9bb38 100644 --- a/src/cmap/conn/wire/message.rs +++ b/src/cmap/conn/wire/message.rs @@ -1,85 +1,87 @@ use std::io::Read; use bitflags::bitflags; +use bson::{doc, Array, Document}; +use serde::Serialize; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; -use super::header::{Header, OpCode}; +use super::{ + header::{Header, OpCode}, + next_request_id, +}; use crate::{ + bson::RawDocumentBuf, bson_util, - cmap::{ - conn::{command::RawCommand, wire::util::SyncCountReader}, - Command, - }, + checked::Checked, + cmap::{conn::wire::util::SyncCountReader, Command}, + compression::{Compressor, Decoder}, error::{Error, ErrorKind, Result}, runtime::SyncLittleEndianRead, }; -use crate::compression::{Compressor, Decoder}; - /// Represents an OP_MSG wire protocol operation. #[derive(Debug)] pub(crate) struct Message { + // OP_MSG payload type 0 + pub(crate) document_payload: RawDocumentBuf, + // OP_MSG payload type 1 + pub(crate) document_sequences: Vec, pub(crate) response_to: i32, pub(crate) flags: MessageFlags, - pub(crate) sections: Vec, pub(crate) checksum: Option, pub(crate) request_id: Option, } +#[derive(Clone, Debug)] +pub(crate) struct DocumentSequence { + pub(crate) identifier: String, + pub(crate) documents: Vec, +} + impl Message { - /// Creates a `Message` from a given `Command`. - /// - /// Note that `response_to` will need to be set manually. - pub(crate) fn with_command(command: Command, request_id: Option) -> Result { - let bytes = bson::to_vec(&command)?; - Ok(Self::with_raw_command( - RawCommand { - bytes, - target_db: command.target_db, - name: command.name, - exhaust_allowed: command.exhaust_allowed, - }, - request_id, - )) - } + /// Creates a `Message` from a given `Command`. Note that the `response_to` field must be set + /// manually. + pub(crate) fn from_command( + command: Command, + request_id: Option, + ) -> Result { + let document_payload = bson::to_raw_document_buf(&command)?; - /// Creates a `Message` from a given `Command`. - /// - /// Note that `response_to` will need to be set manually. - pub(crate) fn with_raw_command(command: RawCommand, request_id: Option) -> Self { let mut flags = MessageFlags::empty(); if command.exhaust_allowed { flags |= MessageFlags::EXHAUST_ALLOWED; } - Self { + Ok(Self { + document_payload, + document_sequences: command.document_sequences, response_to: 0, flags, - sections: vec![MessageSection::Document(command.bytes)], checksum: None, request_id, - } + }) } - /// Gets the first document contained in this Message. - pub(crate) fn single_document_response(self) -> Result> { - let section = self.sections.into_iter().next().ok_or_else(|| { - Error::new( - ErrorKind::InvalidResponse { - message: "no response received from server".into(), - }, - Option::>::None, - ) - })?; - match section { - MessageSection::Document(doc) => Some(doc), - MessageSection::Sequence { documents, .. } => documents.into_iter().next(), + /// Gets this message's command as a Document. If serialization fails, returns a document + /// containing the error. + pub(crate) fn get_command_document(&self) -> Document { + let mut command = match self.document_payload.to_document() { + Ok(document) => document, + Err(error) => return doc! { "serialization error": error.to_string() }, + }; + + for document_sequence in &self.document_sequences { + let mut documents = Array::new(); + for document in &document_sequence.documents { + match document.to_document() { + Ok(document) => documents.push(document.into()), + Err(error) => return doc! { "serialization error": error.to_string() }, + } + } + command.insert(document_sequence.identifier.clone(), documents); } - .ok_or_else(|| { - Error::from(ErrorKind::InvalidResponse { - message: "no message received from the server".to_string(), - }) - }) + + command } /// Reads bytes from `reader` and deserializes them into a Message. @@ -120,21 +122,22 @@ impl Message { mut reader: T, header: &Header, ) -> Result { - // TODO: RUST-616 ensure length is < maxMessageSizeBytes - let length_remaining = header.length - Header::LENGTH as i32; - let mut buf = vec![0u8; length_remaining as usize]; + let length = Checked::::try_from(header.length)?; + let length_remaining = length - Header::LENGTH; + let mut buf = vec![0u8; length_remaining.get()?]; reader.read_exact(&mut buf).await?; let reader = buf.as_slice(); - Self::read_op_common(reader, length_remaining, header) + Self::read_op_common(reader, length_remaining.get()?, header) } async fn read_from_op_compressed( mut reader: T, header: &Header, ) -> Result { - let length_remaining = header.length - Header::LENGTH as i32; - let mut buf = vec![0u8; length_remaining as usize]; + let length = Checked::::try_from(header.length)?; + let length_remaining = length - Header::LENGTH; + let mut buf = vec![0u8; length_remaining.get()?]; reader.read_exact(&mut buf).await?; let mut reader = buf.as_slice(); @@ -152,7 +155,7 @@ impl Message { } // Read uncompressed size - let uncompressed_size = reader.read_i32_sync()?; + let uncompressed_size = Checked::::try_from(reader.read_i32_sync()?)?; // Read compressor id let compressor_id: u8 = reader.read_u8_sync()?; @@ -164,7 +167,7 @@ impl Message { let decoded_message = decoder.decode(reader)?; // Check that claimed length matches original length - if decoded_message.len() as i32 != uncompressed_size { + if decoded_message.len() != uncompressed_size.get()? { return Err(ErrorKind::InvalidResponse { message: format!( "The server's message claims that the uncompressed length is {}, but was \ @@ -180,46 +183,61 @@ impl Message { let reader = decoded_message.as_slice(); let length_remaining = decoded_message.len(); - Self::read_op_common(reader, length_remaining as i32, header) + Self::read_op_common(reader, length_remaining, header) } - fn read_op_common( - mut reader: &[u8], - mut length_remaining: i32, - header: &Header, - ) -> Result { + fn read_op_common(mut reader: &[u8], length_remaining: usize, header: &Header) -> Result { + let mut length_remaining = Checked::new(length_remaining); let flags = MessageFlags::from_bits_truncate(reader.read_u32_sync()?); - length_remaining -= std::mem::size_of::() as i32; + length_remaining -= std::mem::size_of::(); let mut count_reader = SyncCountReader::new(&mut reader); - let mut sections = Vec::new(); - - while length_remaining - count_reader.bytes_read() as i32 > 4 { - sections.push(MessageSection::read(&mut count_reader)?); + let mut document_payload = None; + let mut document_sequences = Vec::new(); + while (length_remaining - count_reader.bytes_read()).get()? > 4 { + let next_section = MessageSection::read(&mut count_reader)?; + match next_section { + MessageSection::Document(document) => { + if document_payload.is_some() { + return Err(ErrorKind::InvalidResponse { + message: "an OP_MSG response must contain exactly one payload type 0 \ + section" + .into(), + } + .into()); + } else { + document_payload = Some(document); + } + } + MessageSection::Sequence(document_sequence) => { + document_sequences.push(document_sequence) + } + } } - length_remaining -= count_reader.bytes_read() as i32; + length_remaining -= count_reader.bytes_read(); let mut checksum = None; - if length_remaining == 4 && flags.contains(MessageFlags::CHECKSUM_PRESENT) { + if length_remaining.get()? == 4 && flags.contains(MessageFlags::CHECKSUM_PRESENT) { checksum = Some(reader.read_u32_sync()?); - } else if length_remaining != 0 { - return Err(ErrorKind::InvalidResponse { - message: format!( - "The server indicated that the reply would be {} bytes long, but it instead \ - was {}", - header.length, - header.length - length_remaining + count_reader.bytes_read() as i32, - ), - } - .into()); + } else if length_remaining.get()? != 0 { + let header_len = Checked::::try_from(header.length)?; + return Err(Error::invalid_response(format!( + "The server indicated that the reply would be {} bytes long, but it instead was {}", + header.length, + header_len - length_remaining + count_reader.bytes_read(), + ))); } Ok(Self { response_to: header.response_to, flags, - sections, + document_payload: document_payload.ok_or_else(|| ErrorKind::InvalidResponse { + message: "an OP_MSG response must contain exactly one payload type 0 section" + .into(), + })?, + document_sequences, checksum, request_id: None, }) @@ -227,15 +245,11 @@ impl Message { /// Serializes the Message to bytes and writes them to `writer`. pub(crate) async fn write_to(&self, mut writer: T) -> Result<()> { - let mut sections_bytes = Vec::new(); + let sections = self.get_sections_bytes()?; - for section in &self.sections { - section.write(&mut sections_bytes).await?; - } - - let total_length = Header::LENGTH + let total_length = Checked::new(Header::LENGTH) + std::mem::size_of::() - + sections_bytes.len() + + sections.len() + self .checksum .as_ref() @@ -243,15 +257,15 @@ impl Message { .unwrap_or(0); let header = Header { - length: total_length as i32, - request_id: self.request_id.unwrap_or_else(super::util::next_request_id), + length: total_length.try_into()?, + request_id: self.request_id.unwrap_or_else(next_request_id), response_to: self.response_to, op_code: OpCode::Message, }; header.write_to(&mut writer).await?; writer.write_u32_le(self.flags.bits()).await?; - writer.write_all(§ions_bytes).await?; + writer.write_all(§ions).await?; if let Some(checksum) = self.checksum { writer.write_u32_le(checksum).await?; @@ -263,7 +277,7 @@ impl Message { } /// Serializes message to bytes, compresses those bytes, and writes the bytes. - pub async fn write_compressed_to( + pub(crate) async fn write_compressed_to( &self, mut writer: T, compressor: &Compressor, @@ -271,28 +285,25 @@ impl Message { let mut encoder = compressor.to_encoder()?; let compressor_id = compressor.id() as u8; - let mut sections_bytes = Vec::new(); + let sections = self.get_sections_bytes()?; - for section in &self.sections { - section.write(&mut sections_bytes).await?; - } let flag_bytes = &self.flags.bits().to_le_bytes(); - let uncompressed_len = sections_bytes.len() + flag_bytes.len(); + let uncompressed_len = Checked::new(sections.len()) + flag_bytes.len(); // Compress the flags and sections. Depending on the handshake // this could use zlib, zstd or snappy encoder.write_all(flag_bytes)?; - encoder.write_all(sections_bytes.as_slice())?; + encoder.write_all(sections.as_slice())?; let compressed_bytes = encoder.finish()?; - let total_length = Header::LENGTH + let total_length = Checked::new(Header::LENGTH) + std::mem::size_of::() + std::mem::size_of::() + std::mem::size_of::() + compressed_bytes.len(); let header = Header { - length: total_length as i32, - request_id: self.request_id.unwrap_or_else(super::util::next_request_id), + length: total_length.try_into()?, + request_id: self.request_id.unwrap_or_else(next_request_id), response_to: self.response_to, op_code: OpCode::Compressed, }; @@ -302,7 +313,7 @@ impl Message { // Write original (pre-compressed) opcode (always OP_MSG) writer.write_i32_le(OpCode::Message as i32).await?; // Write uncompressed size - writer.write_i32_le(uncompressed_len as i32).await?; + writer.write_i32_le(uncompressed_len.try_into()?).await?; // Write compressor id writer.write_u8(compressor_id).await?; // Write compressed message @@ -312,6 +323,41 @@ impl Message { Ok(()) } + + fn get_sections_bytes(&self) -> Result> { + let mut sections = Vec::new(); + + // Payload type 0 + sections.push(0); + sections.extend(self.document_payload.as_bytes()); + + for document_sequence in &self.document_sequences { + // Payload type 1 + sections.push(1); + + let identifier_bytes = document_sequence.identifier.as_bytes(); + + let documents_size = document_sequence + .documents + .iter() + .fold(0, |running_size, document| { + running_size + document.as_bytes().len() + }); + + // Size bytes + identifier bytes + null-terminator byte + document bytes + let size = Checked::new(4) + identifier_bytes.len() + 1 + documents_size; + sections.extend(size.try_into::()?.to_le_bytes()); + + sections.extend(identifier_bytes); + sections.push(0); + + for document in &document_sequence.documents { + sections.extend(document.as_bytes()); + } + } + + Ok(sections) + } } const DEFAULT_MAX_MESSAGE_SIZE_BYTES: i32 = 48 * 1024 * 1024; @@ -327,13 +373,9 @@ bitflags! { /// Represents a section as defined by the OP_MSG spec. #[derive(Debug)] -pub(crate) enum MessageSection { - Document(Vec), - Sequence { - size: i32, - identifier: String, - documents: Vec>, - }, +enum MessageSection { + Document(RawDocumentBuf), + Sequence(DocumentSequence), } impl MessageSection { @@ -342,68 +384,41 @@ impl MessageSection { let payload_type = reader.read_u8_sync()?; if payload_type == 0 { - return Ok(MessageSection::Document(bson_util::read_document_bytes( - reader, - )?)); + let bytes = bson_util::read_document_bytes(reader)?; + let document = RawDocumentBuf::from_bytes(bytes)?; + return Ok(MessageSection::Document(document)); } - let size = reader.read_i32_sync()?; - let mut length_remaining = size - std::mem::size_of::() as i32; + let size = Checked::::try_from(reader.read_i32_sync()?)?; + let mut length_remaining = size - std::mem::size_of::(); let mut identifier = String::new(); - length_remaining -= reader.read_to_string(&mut identifier)? as i32; + length_remaining -= reader.read_to_string(&mut identifier)?; let mut documents = Vec::new(); let mut count_reader = SyncCountReader::new(reader); - while length_remaining > count_reader.bytes_read() as i32 { - documents.push(bson_util::read_document_bytes(&mut count_reader)?); + while length_remaining.get()? > count_reader.bytes_read() { + let bytes = bson_util::read_document_bytes(&mut count_reader)?; + let document = RawDocumentBuf::from_bytes(bytes)?; + documents.push(document); } - if length_remaining != count_reader.bytes_read() as i32 { + if length_remaining.get()? != count_reader.bytes_read() { return Err(ErrorKind::InvalidResponse { message: format!( "The server indicated that the reply would be {} bytes long, but it instead \ was {}", size, - length_remaining + count_reader.bytes_read() as i32, + length_remaining + count_reader.bytes_read(), ), } .into()); } - Ok(MessageSection::Sequence { - size, + Ok(MessageSection::Sequence(DocumentSequence { identifier, documents, - }) - } - - /// Serializes the MessageSection to bytes and writes them to `writer`. - async fn write(&self, writer: &mut W) -> Result<()> { - match self { - Self::Document(doc) => { - // Write payload type. - writer.write_u8(0).await?; - writer.write_all(doc.as_slice()).await?; - } - Self::Sequence { - size, - identifier, - documents, - } => { - // Write payload type. - writer.write_u8(1).await?; - - writer.write_i32_le(*size).await?; - super::util::write_cstring(writer, identifier).await?; - - for doc in documents { - writer.write_all(doc.as_slice()).await?; - } - } - } - - Ok(()) + })) } } diff --git a/src/cmap/conn/wire/util.rs b/src/cmap/conn/wire/util.rs index c39746bcb..a746ec273 100644 --- a/src/cmap/conn/wire/util.rs +++ b/src/cmap/conn/wire/util.rs @@ -4,9 +4,6 @@ use std::{ }; use lazy_static::lazy_static; -use tokio::io::{AsyncWrite, AsyncWriteExt}; - -use crate::error::Result; /// Closure to obtain a new, unique request ID. pub(crate) fn next_request_id() -> i32 { @@ -17,20 +14,6 @@ pub(crate) fn next_request_id() -> i32 { REQUEST_ID.fetch_add(1, Ordering::SeqCst) } -/// Serializes `string` to bytes and writes them to `writer` with a null terminator appended. -pub(super) async fn write_cstring( - writer: &mut W, - string: &str, -) -> Result<()> { - // Write the string's UTF-8 bytes. - writer.write_all(string.as_bytes()).await?; - - // Write the null terminator. - writer.write_all(&[0]).await?; - - Ok(()) -} - pub(super) struct SyncCountReader { reader: R, bytes_read: usize, diff --git a/src/coll.rs b/src/coll.rs index b8064fd74..0a6769628 100644 --- a/src/coll.rs +++ b/src/coll.rs @@ -1231,7 +1231,7 @@ where while n_attempted < ds.len() { let docs: Vec<&T> = ds.iter().skip(n_attempted).map(Borrow::borrow).collect(); - let insert = Insert::new_encrypted( + let insert = Insert::new( self.namespace(), docs, options.clone(), @@ -1360,10 +1360,16 @@ where let mut options = options.into(); resolve_write_concern_with_session!(self, options, session.as_ref())?; + #[cfg(feature = "in-use-encryption-unstable")] + let encrypted = self.client().auto_encryption_opts().await.is_some(); + #[cfg(not(feature = "in-use-encryption-unstable"))] + let encrypted = false; + let insert = Insert::new( self.namespace(), vec![doc], options.map(InsertManyOptions::from_insert_one_options), + encrypted, self.inner.human_readable_serialization, ); self.client() diff --git a/src/coll/options.rs b/src/coll/options.rs index eec2a4fab..658ed5b7c 100644 --- a/src/coll/options.rs +++ b/src/coll/options.rs @@ -10,7 +10,7 @@ use crate::{ error::Result, options::Collation, selection_criteria::SelectionCriteria, - serde_util, + serde_util::{self, write_concern_is_empty}, }; // Generated code for `Deserialize` or `TypedBuilder` causes a deprecation warning; annotating the @@ -151,7 +151,7 @@ pub struct InsertManyOptions { pub ordered: Option, /// The write concern for the operation. - #[serde(skip_deserializing)] + #[serde(skip_deserializing, skip_serializing_if = "write_concern_is_empty")] pub write_concern: Option, /// Tags the query with an arbitrary [`Bson`] value to help trace the operation through the diff --git a/src/collation.rs b/src/collation.rs index bae93d02b..b7fb2334d 100644 --- a/src/collation.rs +++ b/src/collation.rs @@ -128,7 +128,7 @@ impl Serialize for CollationStrength { S: serde::Serializer, { let level = u32::from(*self); - serializer.serialize_i32(level as i32) + serializer.serialize_i32(level.try_into().map_err(serde::ser::Error::custom)?) } } diff --git a/src/error.rs b/src/error.rs index fad317ced..70e8bd8c9 100644 --- a/src/error.rs +++ b/src/error.rs @@ -121,6 +121,13 @@ impl Error { .into() } + pub(crate) fn invalid_response(message: impl Into) -> Error { + ErrorKind::InvalidResponse { + message: message.into(), + } + .into() + } + /// Construct a generic network timeout error. pub(crate) fn network_timeout() -> Error { ErrorKind::Io(Arc::new(std::io::ErrorKind::TimedOut.into())).into() diff --git a/src/gridfs.rs b/src/gridfs.rs index 29c757581..86106fae5 100644 --- a/src/gridfs.rs +++ b/src/gridfs.rs @@ -11,6 +11,7 @@ use serde_with::skip_serializing_none; use crate::{ bson::{doc, oid::ObjectId, Bson, DateTime, Document, RawBinaryRef}, + checked::Checked, cursor::Cursor, error::{Error, ErrorKind, GridFsErrorKind, GridFsFileIdentifier, Result}, options::{CollectionOptions, FindOptions, ReadConcern, SelectionCriteria, WriteConcern}, @@ -76,8 +77,8 @@ impl FilesCollectionDocument { fn n_from_vals(length: u64, chunk_size_bytes: u32) -> u32 { let chunk_size_bytes = chunk_size_bytes as u64; - let n = length / chunk_size_bytes + u64::from(length % chunk_size_bytes != 0); - n as u32 + let n = Checked::new(length) / chunk_size_bytes + u64::from(length % chunk_size_bytes != 0); + n.try_into().unwrap() } /// Returns the expected length of a chunk given its index. @@ -88,7 +89,7 @@ impl FilesCollectionDocument { fn expected_chunk_length_from_vals(length: u64, chunk_size_bytes: u32, n: u32) -> u32 { let remainder = length % (chunk_size_bytes as u64); if n == Self::n_from_vals(length, chunk_size_bytes) - 1 && remainder != 0 { - remainder as u32 + Checked::new(remainder).try_into().unwrap() } else { chunk_size_bytes } diff --git a/src/gridfs/upload.rs b/src/gridfs/upload.rs index b283301c3..b0b806746 100644 --- a/src/gridfs/upload.rs +++ b/src/gridfs/upload.rs @@ -14,6 +14,7 @@ use super::{options::GridFsUploadOptions, Chunk, FilesCollectionDocument, GridFs use crate::{ bson::{doc, oid::ObjectId, spec::BinarySubtype, Bson, DateTime, Document, RawBinaryRef}, bson_util::get_int, + checked::Checked, client::AsyncDropToken, error::{Error, ErrorKind, GridFsErrorKind, Result}, index::IndexModel, @@ -501,21 +502,22 @@ async fn write_bytes( chunk_size_bytes: u32, files_id: Bson, ) -> Result<(u32, Vec)> { + let chunk_size_bytes: usize = Checked::new(chunk_size_bytes).try_into()?; bucket.create_indexes().await?; - let mut n = 0; + let mut n = Checked::new(0); let mut chunks = vec![]; - while buffer.len() as u32 - (n * chunk_size_bytes) >= chunk_size_bytes { + while (Checked::new(buffer.len()) - (n * chunk_size_bytes)).get()? >= chunk_size_bytes { let start = n * chunk_size_bytes; let end = (n + 1) * chunk_size_bytes; let chunk = Chunk { id: ObjectId::new(), files_id: files_id.clone(), - n: starting_n + n, + n: starting_n + n.try_into::()?, data: RawBinaryRef { subtype: BinarySubtype::Generic, - bytes: &buffer[(start as usize)..(end as usize)], + bytes: &buffer[start.get()?..end.get()?], }, }; n += 1; @@ -524,8 +526,8 @@ async fn write_bytes( match bucket.chunks().insert_many(chunks, None).await { Ok(_) => { - buffer.drain(..(n * chunk_size_bytes) as usize); - Ok((n, buffer)) + buffer.drain(..(n * chunk_size_bytes).get()?); + Ok((n.try_into()?, buffer)) } Err(error) => match clean_up_chunks(files_id, bucket.chunks().clone(), Some(error)).await { // clean_up_chunks will always return an error if one is passed in, so this case is diff --git a/src/hello.rs b/src/hello.rs index 1c1c14348..3925a3219 100644 --- a/src/hello.rs +++ b/src/hello.rs @@ -54,10 +54,16 @@ pub(crate) fn hello_command( if let Some(opts) = awaitable_options { command.insert("topologyVersion", opts.topology_version); - command.insert("maxAwaitTimeMS", opts.max_await_time.as_millis() as i64); + command.insert( + "maxAwaitTimeMS", + opts.max_await_time + .as_millis() + .try_into() + .unwrap_or(i64::MAX), + ); } - let mut command = Command::new(command_name.into(), "admin".into(), command); + let mut command = Command::new(command_name, "admin", command); if let Some(server_api) = server_api { command.set_server_api(server_api); } @@ -183,6 +189,7 @@ pub(crate) struct HelloCommandResponse { pub connection_id: Option, } +#[allow(clippy::cast_possible_truncation)] fn deserialize_connection_id<'de, D: serde::Deserializer<'de>>( de: D, ) -> std::result::Result, D::Error> { diff --git a/src/lib.rs b/src/lib.rs index 7f19df987..cf48784e7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -294,6 +294,8 @@ #![warn(missing_docs)] #![warn(rustdoc::missing_crate_level_docs)] +#![warn(clippy::cast_possible_truncation)] +#![warn(clippy::cast_possible_wrap)] #![cfg_attr( feature = "cargo-clippy", allow( @@ -320,6 +322,7 @@ pub use ::mongocrypt; mod bson_util; pub mod change_stream; +pub(crate) mod checked; mod client; mod cmap; mod coll; diff --git a/src/operation.rs b/src/operation.rs index 52f2e8392..2277456f1 100644 --- a/src/operation.rs +++ b/src/operation.rs @@ -79,6 +79,11 @@ pub(crate) use update::{Update, UpdateOrReplace}; const SERVER_4_2_0_WIRE_VERSION: i32 = 8; const SERVER_4_4_0_WIRE_VERSION: i32 = 9; +// The maximum number of bytes that may be included in a write payload when auto-encryption is +// enabled. +const MAX_ENCRYPTED_WRITE_SIZE: usize = 2_097_152; +// The amount of overhead bytes to account for when building a document sequence. +const COMMAND_OVERHEAD_SIZE: usize = 16_000; /// A trait modeling the behavior of a server side operation. /// @@ -98,10 +103,6 @@ pub(crate) trait Operation { /// The operation may store some additional state that is required for handling the response. fn build(&mut self, description: &StreamDescription) -> Result>; - /// Perform custom serialization of the built command. - /// By default, this will just call through to the `Serialize` implementation of the command. - fn serialize_command(&mut self, cmd: Command) -> Result>; - /// Parse the response for the atClusterTime field. /// Depending on the operation, this may be found in different locations. fn extract_at_cluster_time(&self, _response: &RawDocument) -> Result>; @@ -413,12 +414,6 @@ pub(crate) trait OperationWithDefaults { /// The operation may store some additional state that is required for handling the response. fn build(&mut self, description: &StreamDescription) -> Result>; - /// Perform custom serialization of the built command. - /// By default, this will just call through to the `Serialize` implementation of the command. - fn serialize_command(&mut self, cmd: Command) -> Result> { - Ok(bson::to_vec(&cmd)?) - } - /// Parse the response for the atClusterTime field. /// Depending on the operation, this may be found in different locations. fn extract_at_cluster_time(&self, _response: &RawDocument) -> Result> { @@ -489,9 +484,6 @@ impl Operation for T { fn build(&mut self, description: &StreamDescription) -> Result> { self.build(description) } - fn serialize_command(&mut self, cmd: Command) -> Result> { - self.serialize_command(cmd) - } fn extract_at_cluster_time(&self, response: &RawDocument) -> Result> { self.extract_at_cluster_time(response) } diff --git a/src/operation/aggregate/test.rs b/src/operation/aggregate/test.rs index 54c782a33..b2bda57f7 100644 --- a/src/operation/aggregate/test.rs +++ b/src/operation/aggregate/test.rs @@ -1,175 +1,16 @@ use std::time::Duration; -use super::AggregateTarget; use crate::{ - bson::{doc, Document}, - bson_util, - cmap::StreamDescription, - concern::{ReadConcern, ReadConcernLevel}, + bson::doc, error::{ErrorKind, WriteFailure}, operation::{ test::{self, handle_response_test}, Aggregate, - Operation, }, - options::{AggregateOptions, Hint}, + options::AggregateOptions, Namespace, }; -fn build_test( - target: impl Into, - pipeline: Vec, - options: Option, - mut expected_body: Document, -) { - let target = target.into(); - - let mut aggregate = Aggregate::new(target.clone(), pipeline, options); - - let cmd = aggregate.build(&StreamDescription::new_testing()).unwrap(); - - assert_eq!(cmd.name.as_str(), "aggregate"); - assert_eq!(cmd.target_db.as_str(), target.db_name()); - - let cmd_bytes = aggregate.serialize_command(cmd).unwrap(); - let mut cmd_doc = bson::from_slice(&cmd_bytes).unwrap(); - - bson_util::sort_document(&mut expected_body); - bson_util::sort_document(&mut cmd_doc); - - assert_eq!(cmd_doc, expected_body); -} - -#[test] -fn build() { - let ns = Namespace { - db: "test_db".to_string(), - coll: "test_coll".to_string(), - }; - - let pipeline = vec![doc! { "$match": { "x": 3 }}]; - - let options = AggregateOptions::builder() - .hint(Hint::Keys(doc! { "x": 1, "y": 2 })) - .bypass_document_validation(true) - .read_concern(ReadConcern::from(ReadConcernLevel::Available)) - .build(); - - let expected_body = doc! { - "aggregate": "test_coll", - "$db": "test_db", - "pipeline": bson_util::to_bson_array(&pipeline), - "cursor": {}, - "hint": { - "x": 1, - "y": 2, - }, - "bypassDocumentValidation": true, - "readConcern": { - "level": "available" - }, - }; - - build_test(ns, pipeline, Some(options), expected_body); -} - -#[test] -fn build_batch_size() { - let ns = Namespace { - db: "test_db".to_string(), - coll: "test_coll".to_string(), - }; - - let pipeline = Vec::new(); - - let mut expected_body = doc! { - "aggregate": "test_coll", - "$db": "test_db", - "pipeline": [], - "cursor": {}, - }; - - build_test(ns.clone(), pipeline.clone(), None, expected_body.clone()); - - build_test( - ns.clone(), - pipeline.clone(), - Some(AggregateOptions::default()), - expected_body.clone(), - ); - - let batch_size_options = AggregateOptions::builder().batch_size(5).build(); - expected_body.insert("cursor", doc! { "batchSize": 5 }); - build_test( - ns.clone(), - pipeline, - Some(batch_size_options.clone()), - expected_body.clone(), - ); - - let out_pipeline = vec![doc! { "$out": "cat" }]; - expected_body.insert("cursor", Document::new()); - expected_body.insert("pipeline", bson_util::to_bson_array(&out_pipeline)); - build_test( - ns.clone(), - out_pipeline, - Some(batch_size_options.clone()), - expected_body.clone(), - ); - - let merge_pipeline = vec![doc! { - "$merge": { - "into": "out", - } - }]; - expected_body.insert("pipeline", bson_util::to_bson_array(&merge_pipeline)); - build_test(ns, merge_pipeline, Some(batch_size_options), expected_body); -} - -#[test] -fn build_target() { - let pipeline = Vec::new(); - - let ns = Namespace { - db: "test_db".to_string(), - coll: "test_coll".to_string(), - }; - - let expected_body = doc! { - "aggregate": "test_coll", - "$db": "test_db", - "pipeline": [], - "cursor": {}, - }; - build_test(ns.clone(), pipeline.clone(), None, expected_body); - - let expected_body = doc! { - "aggregate": 1, - "$db": "test_db", - "pipeline": [], - "cursor": {} - }; - build_test(ns.db, pipeline, None, expected_body); -} - -#[test] -fn build_max_await_time() { - let options = AggregateOptions::builder() - .max_await_time(Duration::from_millis(5)) - .max_time(Duration::from_millis(10)) - .build(); - - let body = doc! { - "aggregate": 1, - "$db": "test_db", - "cursor": {}, - "maxTimeMS": 10i32, - "pipeline": [] - }; - - build_test("test_db".to_string(), Vec::new(), Some(options), body); -} - #[test] fn op_selection_criteria() { test::op_selection_criteria(|selection_criteria| { diff --git a/src/operation/count/test.rs b/src/operation/count/test.rs index 22bffd4bd..4102ce6d7 100644 --- a/src/operation/count/test.rs +++ b/src/operation/count/test.rs @@ -1,17 +1,15 @@ -use std::time::Duration; +#![allow(clippy::cast_possible_truncation)] +#![allow(clippy::cast_possible_wrap)] use crate::{ bson::doc, - bson_util, cmap::StreamDescription, coll::{options::EstimatedDocumentCountOptions, Namespace}, - concern::ReadConcern, operation::{ test::{self, handle_response_test}, Count, Operation, }, - options::ReadConcernLevel, }; #[test] @@ -33,41 +31,6 @@ fn build() { assert_eq!(count_command.target_db, "test_db"); } -#[test] -fn build_with_options() { - let read_concern: ReadConcern = ReadConcernLevel::Local.into(); - let max_time = Duration::from_millis(2_u64); - let options: EstimatedDocumentCountOptions = EstimatedDocumentCountOptions::builder() - .max_time(max_time) - .read_concern(read_concern.clone()) - .build(); - let ns = Namespace { - db: "test_db".to_string(), - coll: "test_coll".to_string(), - }; - let mut count_op = Count::new(ns, Some(options)); - let count_command = count_op - .build(&StreamDescription::new_testing()) - .expect("error on build"); - - assert_eq!(count_command.target_db, "test_db"); - - let mut expected_body = doc! { - "count": "test_coll", - "$db": "test_db", - "maxTimeMS": max_time.as_millis() as i32, - "readConcern": doc! {"level": read_concern.level.as_str().to_string() }, - }; - - let cmd_bytes = count_op.serialize_command(count_command).unwrap(); - let mut cmd_doc = bson::from_slice(&cmd_bytes).unwrap(); - - bson_util::sort_document(&mut cmd_doc); - bson_util::sort_document(&mut expected_body); - - assert_eq!(cmd_doc, expected_body); -} - #[test] fn op_selection_criteria() { test::op_selection_criteria(|selection_criteria| { diff --git a/src/operation/count_documents/test.rs b/src/operation/count_documents/test.rs index 42260199a..94d2e82cc 100644 --- a/src/operation/count_documents/test.rs +++ b/src/operation/count_documents/test.rs @@ -1,14 +1,12 @@ +#![allow(clippy::cast_possible_truncation)] +#![allow(clippy::cast_possible_wrap)] + use crate::{ bson::doc, bson_util, cmap::StreamDescription, coll::Namespace, - concern::ReadConcern, - operation::{ - test::{self, handle_response_test}, - Operation, - }, - options::{CountOptions, Hint}, + operation::{test::handle_response_test, Operation}, }; use super::CountDocuments; @@ -40,59 +38,6 @@ fn build() { assert_eq!(count_command.target_db, "test_db"); } -#[test] -fn build_with_options() { - let skip = 2; - let limit = 5; - let options = CountOptions::builder() - .skip(skip) - .limit(limit) - .hint(Hint::Name("_id_1".to_string())) - .read_concern(ReadConcern::available()) - .build(); - let ns = Namespace { - db: "test_db".to_string(), - coll: "test_coll".to_string(), - }; - let mut count_op = CountDocuments::new(ns, None, Some(options)).unwrap(); - let count_command = count_op - .build(&StreamDescription::new_testing()) - .expect("error on build"); - assert_eq!(count_command.target_db, "test_db"); - - let mut expected_body = doc! { - "aggregate": "test_coll", - "$db": "test_db", - "pipeline": [ - { "$match": {} }, - { "$skip": skip as i64 }, - { "$limit": limit as i64 }, - { "$group": { "_id": 1, "n": { "$sum": 1 } } }, - ], - "hint": "_id_1", - "cursor": { }, - "readConcern": { "level": "available" }, - }; - - bson_util::sort_document(&mut expected_body); - let serialized_command = count_op.serialize_command(count_command).unwrap(); - let mut cmd_doc = bson::from_slice(&serialized_command).unwrap(); - bson_util::sort_document(&mut cmd_doc); - - assert_eq!(cmd_doc, expected_body); -} - -#[test] -fn op_selection_criteria() { - test::op_selection_criteria(|selection_criteria| { - let options = CountOptions { - selection_criteria, - ..Default::default() - }; - CountDocuments::new(Namespace::empty(), None, Some(options)).unwrap() - }); -} - #[test] fn handle_success() { let ns = Namespace { diff --git a/src/operation/distinct/test.rs b/src/operation/distinct/test.rs index 955e725f1..5dfa0133f 100644 --- a/src/operation/distinct/test.rs +++ b/src/operation/distinct/test.rs @@ -1,3 +1,6 @@ +#![allow(clippy::cast_possible_truncation)] +#![allow(clippy::cast_possible_wrap)] + use std::time::Duration; use crate::{ diff --git a/src/operation/find/test.rs b/src/operation/find/test.rs index aafe7374a..57bb6dd28 100644 --- a/src/operation/find/test.rs +++ b/src/operation/find/test.rs @@ -1,195 +1,15 @@ use std::time::Duration; use crate::{ - bson::{doc, Document}, - bson_util, - cmap::StreamDescription, + bson::doc, operation::{ test::{self, handle_response_test}, Find, - Operation, }, - options::{CursorType, FindOptions, Hint, ReadConcern, ReadConcernLevel}, + options::{CursorType, FindOptions}, Namespace, }; -fn build_test( - ns: Namespace, - filter: Option, - options: Option, - mut expected_body: Document, -) { - let mut find = Find::new(ns.clone(), filter, options); - - let cmd = find.build(&StreamDescription::new_testing()).unwrap(); - - assert_eq!(cmd.name.as_str(), "find"); - assert_eq!(cmd.target_db.as_str(), ns.db.as_str()); - - let cmd_bytes = find.serialize_command(cmd).unwrap(); - let mut cmd_doc = bson::from_slice(&cmd_bytes).unwrap(); - - bson_util::sort_document(&mut expected_body); - bson_util::sort_document(&mut cmd_doc); - - assert_eq!(cmd_doc, expected_body); -} - -#[test] -fn build() { - let ns = Namespace { - db: "test_db".to_string(), - coll: "test_coll".to_string(), - }; - - let filter = doc! { - "x": 2, - "y": { "$gt": 1 }, - }; - - let options = FindOptions::builder() - .hint(Hint::Keys(doc! { "x": 1, "y": 2 })) - .projection(doc! { "x": 0 }) - .allow_partial_results(true) - .read_concern(ReadConcern::from(ReadConcernLevel::Available)) - .build(); - - let expected_body = doc! { - "find": "test_coll", - "$db": "test_db", - "filter": filter.clone(), - "hint": { - "x": 1, - "y": 2, - }, - "projection": { - "x": 0 - }, - "allowPartialResults": true, - "readConcern": { - "level": "available" - } - }; - - build_test(ns, Some(filter), Some(options), expected_body); -} - -#[test] -fn build_cursor_type() { - let ns = Namespace { - db: "test_db".to_string(), - coll: "test_coll".to_string(), - }; - - let non_tailable_options = FindOptions::builder() - .cursor_type(CursorType::NonTailable) - .build(); - - let non_tailable_body = doc! { - "find": "test_coll", - "$db": "test_db", - }; - - build_test( - ns.clone(), - None, - Some(non_tailable_options), - non_tailable_body, - ); - - let tailable_options = FindOptions::builder() - .cursor_type(CursorType::Tailable) - .build(); - - let tailable_body = doc! { - "find": "test_coll", - "tailable": true, - "$db": "test_db", - }; - - build_test(ns.clone(), None, Some(tailable_options), tailable_body); - - let tailable_await_options = FindOptions::builder() - .cursor_type(CursorType::TailableAwait) - .build(); - - let tailable_await_body = doc! { - "find": "test_coll", - "$db": "test_db", - "tailable": true, - "awaitData": true, - }; - - build_test(ns, None, Some(tailable_await_options), tailable_await_body); -} - -#[test] -fn build_max_await_time() { - let ns = Namespace { - db: "test_db".to_string(), - coll: "test_coll".to_string(), - }; - - let options = FindOptions::builder() - .max_await_time(Duration::from_millis(5)) - .max_time(Duration::from_millis(10)) - .build(); - - let body = doc! { - "find": "test_coll", - "$db": "test_db", - "maxTimeMS": 10i32 - }; - - build_test(ns, None, Some(options), body); -} - -#[test] -fn build_limit() { - let ns = Namespace { - db: "test_db".to_string(), - coll: "test_coll".to_string(), - }; - - let positive_options = FindOptions::builder().limit(5).build(); - - let positive_body = doc! { - "find": "test_coll", - "$db": "test_db", - "limit": 5_i64 - }; - - build_test(ns.clone(), None, Some(positive_options), positive_body); - - let negative_options = FindOptions::builder().limit(-5).build(); - - let negative_body = doc! { - "find": "test_coll", - "$db": "test_db", - "limit": 5_i64, - "singleBatch": true - }; - - build_test(ns, None, Some(negative_options), negative_body); -} - -#[test] -fn build_batch_size() { - let options = FindOptions::builder().batch_size(1).build(); - let body = doc! { - "find": "", - "$db": "", - "batchSize": 1 - }; - build_test(Namespace::empty(), None, Some(options), body); - - let options = FindOptions::builder() - .batch_size((std::i32::MAX as u32) + 1) - .build(); - let mut op = Find::new(Namespace::empty(), None, Some(options)); - assert!(op.build(&StreamDescription::new_testing()).is_err()) -} - #[test] fn op_selection_criteria() { test::op_selection_criteria(|selection_criteria| { diff --git a/src/operation/find_and_modify.rs b/src/operation/find_and_modify.rs index a065409ea..04e6a538d 100644 --- a/src/operation/find_and_modify.rs +++ b/src/operation/find_and_modify.rs @@ -138,10 +138,6 @@ impl<'a, R: Serialize, T: DeserializeOwned> OperationWithDefaults for FindAndMod )) } - fn serialize_command(&mut self, cmd: Command) -> Result> { - cmd.into_bson_bytes() - } - fn handle_response( &self, response: RawCommandResponse, diff --git a/src/operation/get_more.rs b/src/operation/get_more.rs index 2fb4f77a8..e486bbb49 100644 --- a/src/operation/get_more.rs +++ b/src/operation/get_more.rs @@ -70,7 +70,10 @@ impl<'conn> OperationWithDefaults for GetMore<'conn> { } if let Some(ref max_time) = self.max_time { - body.insert("maxTimeMS", max_time.as_millis() as i32); + body.insert( + "maxTimeMS", + max_time.as_millis().try_into().unwrap_or(i32::MAX), + ); } if let Some(ref comment) = self.comment { diff --git a/src/operation/insert.rs b/src/operation/insert.rs index 4c51b1c59..8ace66155 100644 --- a/src/operation/insert.rs +++ b/src/operation/insert.rs @@ -7,51 +7,43 @@ use bson::{oid::ObjectId, Bson, RawArrayBuf, RawDocumentBuf}; use serde::Serialize; use crate::{ - bson::doc, + bson::rawdoc, bson_util, + checked::Checked, cmap::{Command, RawCommandResponse, StreamDescription}, error::{BulkWriteFailure, Error, ErrorKind, Result}, - operation::{ - remove_empty_write_concern, - OperationWithDefaults, - Retryability, - WriteResponseBody, - }, + operation::{OperationWithDefaults, Retryability, WriteResponseBody}, options::{InsertManyOptions, WriteConcern}, results::InsertManyResult, serde_util, Namespace, }; -use super::CommandBody; +use super::{COMMAND_OVERHEAD_SIZE, MAX_ENCRYPTED_WRITE_SIZE}; #[derive(Debug)] pub(crate) struct Insert<'a, T> { ns: Namespace, documents: Vec<&'a T>, inserted_ids: Vec, - options: Option, + options: InsertManyOptions, encrypted: bool, human_readable_serialization: bool, } impl<'a, T> Insert<'a, T> { pub(crate) fn new( - ns: Namespace, - documents: Vec<&'a T>, - options: Option, - human_readable_serialization: bool, - ) -> Self { - Self::new_encrypted(ns, documents, options, false, human_readable_serialization) - } - - pub(crate) fn new_encrypted( ns: Namespace, documents: Vec<&'a T>, options: Option, encrypted: bool, human_readable_serialization: bool, ) -> Self { + let mut options = options.unwrap_or_default(); + if options.ordered.is_none() { + options.ordered = Some(true); + } + Self { ns, options, @@ -61,30 +53,26 @@ impl<'a, T> Insert<'a, T> { human_readable_serialization, } } - - fn is_ordered(&self) -> bool { - self.options - .as_ref() - .and_then(|o| o.ordered) - .unwrap_or(true) - } } impl<'a, T: Serialize> OperationWithDefaults for Insert<'a, T> { type O = InsertManyResult; - type Command = InsertCommand; + type Command = RawDocumentBuf; const NAME: &'static str = "insert"; - fn build(&mut self, description: &StreamDescription) -> Result> { - let mut docs = RawArrayBuf::new(); + fn build(&mut self, description: &StreamDescription) -> Result> { + let mut docs = Vec::new(); let mut size = 0; - let batch_size_limit = description.max_bson_object_size as u64; + + let max_doc_size = Checked::::try_from(description.max_bson_object_size)?; + let max_doc_sequence_size = + Checked::::try_from(description.max_message_size_bytes)? - COMMAND_OVERHEAD_SIZE; for (i, d) in self .documents .iter() - .take(description.max_write_batch_size as usize) + .take(Checked::new(description.max_write_batch_size).try_into()?) .enumerate() { let mut doc = @@ -105,7 +93,7 @@ impl<'a, T: Serialize> OperationWithDefaults for Insert<'a, T> { bytes.splice(4..4, oid_slice.iter().cloned()); // overwrite old length - let new_length = (bytes.len() as i32).to_le_bytes(); + let new_length = Checked::new(bytes.len()).try_into::()?.to_le_bytes(); bytes[0..4].copy_from_slice(&new_length); doc = RawDocumentBuf::from_bytes(bytes)?; @@ -113,47 +101,55 @@ impl<'a, T: Serialize> OperationWithDefaults for Insert<'a, T> { } }; - let doc_size = bson_util::array_entry_size_bytes(i, doc.as_bytes().len()); - - if self.encrypted && size > 0 && size + doc_size >= 2_097_152 { - break; + let doc_size = doc.as_bytes().len(); + if doc_size > max_doc_size.get()? { + return Err(ErrorKind::InvalidArgument { + message: format!( + "insert document must be within {} bytes, but document provided is {} \ + bytes", + max_doc_size, doc_size + ), + } + .into()); } - if size + doc_size <= batch_size_limit { - if self.inserted_ids.len() <= i { - self.inserted_ids.push(id); + + // From the spec: Drivers MUST not reduce the size limits for a single write before + // automatic encryption. I.e. if a single document has size larger than 2MiB (but less + // than `maxBsonObjectSize`) proceed with automatic encryption. + if self.encrypted && i != 0 { + let doc_entry_size = bson_util::array_entry_size_bytes(i, doc.as_bytes().len())?; + if (Checked::new(size) + doc_entry_size).get()? >= MAX_ENCRYPTED_WRITE_SIZE { + break; } - docs.push(doc); - size += doc_size; - } else { + } else if (Checked::new(size) + doc_size).get()? > max_doc_sequence_size.get()? { break; } - } - if docs.is_empty() { - return Err(ErrorKind::InvalidArgument { - message: "document exceeds maxBsonObjectSize".to_string(), - } - .into()); + self.inserted_ids.push(id); + docs.push(doc); + size += doc_size; } - let mut options = self.options.clone().unwrap_or_default(); - options.ordered = Some(self.is_ordered()); - remove_empty_write_concern!(Some(&mut options)); - let body = InsertCommand { - insert: self.ns.coll.clone(), - documents: docs, - options, + let mut body = rawdoc! { + Self::NAME: self.ns.coll.clone(), }; - Ok(Command::new("insert".to_string(), self.ns.db.clone(), body)) - } + let options_doc = bson::to_raw_document_buf(&self.options)?; + bson_util::extend_raw_document_buf(&mut body, options_doc)?; - fn serialize_command(&mut self, cmd: Command) -> Result> { - let mut doc = bson::to_raw_document_buf(&cmd)?; - // need to append documents separately because #[serde(flatten)] breaks the custom - // serialization logic. See https://github.com/serde-rs/serde/issues/2106. - doc.append("documents", cmd.body.documents); - Ok(doc.into_bytes()) + if self.encrypted { + // Auto-encryption does not support document sequences + let mut raw_array = RawArrayBuf::new(); + for doc in docs { + raw_array.push(doc); + } + body.append("documents", raw_array); + Ok(Command::new(Self::NAME, &self.ns.db, body)) + } else { + let mut command = Command::new(Self::NAME, &self.ns.db, body); + command.add_document_sequence("documents", docs); + Ok(command) + } } fn handle_response( @@ -162,16 +158,12 @@ impl<'a, T: Serialize> OperationWithDefaults for Insert<'a, T> { _description: &StreamDescription, ) -> Result { let response: WriteResponseBody = raw_response.body_utf8_lossy()?; + let response_n = Checked::::try_from(response.n)?; let mut map = HashMap::new(); - if self.is_ordered() { + if self.options.ordered == Some(true) { // in ordered inserts, only the first n were attempted. - for (i, id) in self - .inserted_ids - .iter() - .enumerate() - .take(response.n as usize) - { + for (i, id) in self.inserted_ids.iter().enumerate().take(response_n.get()?) { map.insert(i, id.clone()); } } else { @@ -203,24 +195,10 @@ impl<'a, T: Serialize> OperationWithDefaults for Insert<'a, T> { } fn write_concern(&self) -> Option<&WriteConcern> { - self.options.as_ref().and_then(|o| o.write_concern.as_ref()) + self.options.write_concern.as_ref() } fn retryability(&self) -> Retryability { Retryability::Write } } - -#[derive(Serialize)] -pub(crate) struct InsertCommand { - insert: String, - - /// will be serialized in `serialize_command` - #[serde(skip)] - documents: RawArrayBuf, - - #[serde(flatten)] - options: InsertManyOptions, -} - -impl CommandBody for InsertCommand {} diff --git a/src/operation/insert/test.rs b/src/operation/insert/test.rs index 97de1e9b1..6e221a5d2 100644 --- a/src/operation/insert/test.rs +++ b/src/operation/insert/test.rs @@ -1,17 +1,8 @@ -use bson::{ - oid::ObjectId, - spec::BinarySubtype, - Binary, - DateTime, - JavaScriptCodeWithScope, - Regex, - Timestamp, -}; use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; use crate::{ - bson::{doc, Bson, Document}, + bson::{doc, Document}, cmap::StreamDescription, concern::WriteConcern, error::{BulkWriteError, ErrorKind, WriteConcernError}, @@ -23,7 +14,6 @@ use crate::{ struct TestFixtures { op: Insert<'static, Document>, documents: Vec, - options: InsertManyOptions, } /// Get an Insert operation and the documents/options used to construct it. @@ -50,221 +40,20 @@ fn fixtures(opts: Option) -> TestFixtures { DOCUMENTS.iter().collect(), Some(options.clone()), false, + false, ); TestFixtures { op, documents: DOCUMENTS.clone(), - options, } } -#[test] -fn build() { - let mut fixtures = fixtures(None); - - let description = StreamDescription::new_testing(); - let cmd = fixtures.op.build(&description).unwrap(); - - assert_eq!(cmd.name.as_str(), "insert"); - assert_eq!(cmd.target_db.as_str(), "test_db"); - - assert_eq!(cmd.body.insert, "test_coll".to_string()); - - let mut cmd_docs: Vec = cmd - .body - .documents - .as_ref() - .into_iter() - .map(|b| Document::from_reader(b.unwrap().as_document().unwrap().as_bytes()).unwrap()) - .collect(); - assert_eq!(cmd_docs.len(), fixtures.documents.len()); - - for (original_doc, cmd_doc) in fixtures.documents.iter().zip(cmd_docs.iter_mut()) { - assert!(cmd_doc.get("_id").is_some()); - if original_doc.get("_id").is_none() { - cmd_doc.remove("_id"); - } - assert_eq!(original_doc, cmd_doc); - } - - let serialized = fixtures.op.serialize_command(cmd).unwrap(); - let cmd_doc = Document::from_reader(serialized.as_slice()).unwrap(); - - assert_eq!( - cmd_doc.get("ordered"), - fixtures.options.ordered.map(Bson::Boolean).as_ref() - ); - assert_eq!( - cmd_doc.get("bypassDocumentValidation"), - fixtures - .options - .bypass_document_validation - .map(Bson::Boolean) - .as_ref() - ); - assert_eq!( - cmd_doc.get("writeConcern"), - fixtures - .options - .write_concern - .as_ref() - .map(|wc| bson::to_bson(wc).unwrap()) - .as_ref() - ); -} - -#[test] -fn build_ordered() { - let docs = vec![Document::new()]; - let mut insert = Insert::new(Namespace::empty(), docs.iter().collect(), None, false); - let cmd = insert - .build(&StreamDescription::new_testing()) - .expect("should succeed"); - let serialized = insert.serialize_command(cmd).unwrap(); - let cmd_doc = Document::from_reader(serialized.as_slice()).unwrap(); - assert_eq!(cmd_doc.get("ordered"), Some(&Bson::Boolean(true))); - - let mut insert = Insert::new( - Namespace::empty(), - docs.iter().collect(), - Some(InsertManyOptions::builder().ordered(false).build()), - false, - ); - let cmd = insert - .build(&StreamDescription::new_testing()) - .expect("should succeed"); - let serialized = insert.serialize_command(cmd).unwrap(); - let cmd_doc = Document::from_reader(serialized.as_slice()).unwrap(); - assert_eq!(cmd_doc.get("ordered"), Some(&Bson::Boolean(false))); - - let mut insert = Insert::new( - Namespace::empty(), - docs.iter().collect(), - Some(InsertManyOptions::builder().ordered(true).build()), - false, - ); - let cmd = insert - .build(&StreamDescription::new_testing()) - .expect("should succeed"); - let serialized = insert.serialize_command(cmd).unwrap(); - let cmd_doc = Document::from_reader(serialized.as_slice()).unwrap(); - assert_eq!(cmd_doc.get("ordered"), Some(&Bson::Boolean(true))); - - let mut insert = Insert::new( - Namespace::empty(), - docs.iter().collect(), - Some(InsertManyOptions::builder().build()), - false, - ); - let cmd = insert - .build(&StreamDescription::new_testing()) - .expect("should succeed"); - let serialized = insert.serialize_command(cmd).unwrap(); - let cmd_doc = Document::from_reader(serialized.as_slice()).unwrap(); - assert_eq!(cmd_doc.get("ordered"), Some(&Bson::Boolean(true))); -} - #[derive(Debug, Serialize, Deserialize)] struct Documents { documents: Vec, } -#[test] -fn generate_ids() { - let docs = vec![doc! { "x": 1 }, doc! { "_id": 1_i32, "x": 2 }]; - - let mut insert = Insert::new(Namespace::empty(), docs.iter().collect(), None, false); - let cmd = insert.build(&StreamDescription::new_testing()).unwrap(); - let serialized = insert.serialize_command(cmd).unwrap(); - - #[derive(Debug, Serialize, Deserialize)] - struct D { - x: i32, - - #[serde(rename = "_id")] - id: Bson, - } - - let docs: Documents = bson::from_slice(serialized.as_slice()).unwrap(); - - assert_eq!(docs.documents.len(), 2); - let docs = docs.documents; - - docs[0].id.as_object_id().unwrap(); - assert_eq!(docs[0].x, 1); - - assert_eq!(docs[1].id, Bson::Int32(1)); - assert_eq!(docs[1].x, 2); - - // ensure the _id was prepended to the document - let docs: Documents = bson::from_slice(serialized.as_slice()).unwrap(); - assert_eq!(docs.documents[0].iter().next().unwrap().0, "_id") -} - -#[test] -fn serialize_all_types() { - let binary = Binary { - bytes: vec![36, 36, 36], - subtype: BinarySubtype::Generic, - }; - let date = DateTime::now(); - let regex = Regex { - pattern: "hello".to_string(), - options: "x".to_string(), - }; - let timestamp = Timestamp { - time: 123, - increment: 456, - }; - let code = Bson::JavaScriptCode("console.log(1)".to_string()); - let code_w_scope = JavaScriptCodeWithScope { - code: "console.log(a)".to_string(), - scope: doc! { "a": 1 }, - }; - let oid = ObjectId::new(); - let subdoc = doc! { "k": true, "b": { "hello": "world" } }; - - let decimal = { - let bytes = hex::decode("18000000136400D0070000000000000000000000003A3000").unwrap(); - let d = Document::from_reader(bytes.as_slice()).unwrap(); - d.get("d").unwrap().clone() - }; - - let docs = vec![doc! { - "x": 1_i32, - "y": 2_i64, - "s": "oke", - "array": [ true, "oke", { "12": 24 } ], - "bson": 1234.5, - "oid": oid, - "null": Bson::Null, - "subdoc": subdoc, - "b": true, - "d": 12.5, - "binary": binary, - "date": date, - "regex": regex, - "ts": timestamp, - "i": { "a": 300, "b": 12345 }, - "undefined": Bson::Undefined, - "code": code, - "code_w_scope": code_w_scope, - "decimal": decimal, - "symbol": Bson::Symbol("ok".to_string()), - "min_key": Bson::MinKey, - "max_key": Bson::MaxKey, - "_id": ObjectId::new(), - }]; - - let mut insert = Insert::new(Namespace::empty(), docs.iter().collect(), None, false); - let cmd = insert.build(&StreamDescription::new_testing()).unwrap(); - let serialized = insert.serialize_command(cmd).unwrap(); - let cmd: Documents = bson::from_slice(serialized.as_slice()).unwrap(); - - assert_eq!(cmd.documents, docs); -} - #[test] fn handle_success() { let mut fixtures = fixtures(None); diff --git a/src/operation/raw_output.rs b/src/operation/raw_output.rs index 151d7b3e7..254ea316b 100644 --- a/src/operation/raw_output.rs +++ b/src/operation/raw_output.rs @@ -19,10 +19,6 @@ impl Operation for RawOutput { self.0.build(description) } - fn serialize_command(&mut self, cmd: Command) -> Result> { - self.0.serialize_command(cmd) - } - fn extract_at_cluster_time( &self, response: &bson::RawDocument, diff --git a/src/operation/run_cursor_command.rs b/src/operation/run_cursor_command.rs index 88a6f4f66..766a2e1e5 100644 --- a/src/operation/run_cursor_command.rs +++ b/src/operation/run_cursor_command.rs @@ -38,10 +38,6 @@ impl<'conn> Operation for RunCursorCommand<'conn> { self.run_command.build(description) } - fn serialize_command(&mut self, cmd: Command) -> Result> { - self.run_command.serialize_command(cmd) - } - fn extract_at_cluster_time( &self, response: &bson::RawDocument, diff --git a/src/operation/update.rs b/src/operation/update.rs index 8c524f9e5..7ccfb8523 100644 --- a/src/operation/update.rs +++ b/src/operation/update.rs @@ -182,10 +182,6 @@ impl<'a, T: Serialize> OperationWithDefaults for Update<'a, T> { )) } - fn serialize_command(&mut self, cmd: Command) -> Result> { - cmd.into_bson_bytes() - } - fn handle_response( &self, raw_response: RawCommandResponse, diff --git a/src/sdam/description/topology.rs b/src/sdam/description/topology.rs index 7faa99231..b4540fad6 100644 --- a/src/sdam/description/topology.rs +++ b/src/sdam/description/topology.rs @@ -204,7 +204,7 @@ impl TopologyDescription { self.servers.get(address) } - pub(crate) fn update_command_with_read_pref( + pub(crate) fn update_command_with_read_pref( &self, address: &ServerAddress, command: &mut Command, @@ -252,7 +252,7 @@ impl TopologyDescription { } } - fn update_command_read_pref_for_mongos( + fn update_command_read_pref_for_mongos( &self, command: &mut Command, criteria: Option<&SelectionCriteria>, diff --git a/src/sdam/description/topology/server_selection.rs b/src/sdam/description/topology/server_selection.rs index d41ccade6..e1aa5c380 100644 --- a/src/sdam/description/topology/server_selection.rs +++ b/src/sdam/description/topology/server_selection.rs @@ -291,7 +291,7 @@ impl TopologyDescription { primary: &ServerDescription, max_staleness: Duration, ) { - let max_staleness_ms = max_staleness.as_millis() as i64; + let max_staleness_ms = max_staleness.as_millis().try_into().unwrap_or(i64::MAX); servers.retain(|server| { let server_staleness = self.calculate_secondary_staleness_with_primary(server, primary); @@ -307,7 +307,7 @@ impl TopologyDescription { servers: &mut Vec<&ServerDescription>, max_staleness: Duration, ) { - let max_staleness = max_staleness.as_millis() as i64; + let max_staleness = max_staleness.as_millis().try_into().unwrap_or(i64::MAX); let max_write_date = self .servers .values() @@ -347,7 +347,11 @@ impl TopologyDescription { let secondary_last_update = secondary.last_update_time?.timestamp_millis(); let secondary_last_write = secondary.last_write_date().ok()??.timestamp_millis(); - let heartbeat_frequency = self.heartbeat_frequency().as_millis() as i64; + let heartbeat_frequency = self + .heartbeat_frequency() + .as_millis() + .try_into() + .unwrap_or(i64::MAX); let staleness = (secondary_last_update - secondary_last_write) - (primary_last_update - primary_last_write) @@ -362,7 +366,11 @@ impl TopologyDescription { max_last_write_date: i64, ) -> Option { let secondary_last_write = secondary.last_write_date().ok()??.timestamp_millis(); - let heartbeat_frequency = self.heartbeat_frequency().as_millis() as i64; + let heartbeat_frequency = self + .heartbeat_frequency() + .as_millis() + .try_into() + .unwrap_or(i64::MAX); let staleness = max_last_write_date - secondary_last_write + heartbeat_frequency; Some(staleness) diff --git a/src/sdam/description/topology/server_selection/test/in_window.rs b/src/sdam/description/topology/server_selection/test/in_window.rs index d0a1f71cb..8d14ddd6f 100644 --- a/src/sdam/description/topology/server_selection/test/in_window.rs +++ b/src/sdam/description/topology/server_selection/test/in_window.rs @@ -200,18 +200,21 @@ async fn load_balancing_test() { counts.sort(); let share_of_selections = (*counts[0] as f64) / ((*counts[0] + *counts[1]) as f64); - assert!( - share_of_selections <= max_share, - "expected no more than {}% of selections, instead got {}%", - (max_share * 100.0) as u32, - (share_of_selections * 100.0) as u32 - ); - assert!( - share_of_selections >= min_share, - "expected at least {}% of selections, instead got {}%", - (min_share * 100.0) as u32, - (share_of_selections * 100.0) as u32 - ); + #[allow(clippy::cast_possible_truncation)] + { + assert!( + share_of_selections <= max_share, + "expected no more than {}% of selections, instead got {}%", + (max_share * 100.0) as u32, + (share_of_selections * 100.0) as u32 + ); + assert!( + share_of_selections >= min_share, + "expected at least {}% of selections, instead got {}%", + (min_share * 100.0) as u32, + (share_of_selections * 100.0) as u32 + ); + } } let mut handler = EventHandler::new(); diff --git a/src/sdam/description/topology/test.rs b/src/sdam/description/topology/test.rs index 235b79841..9a4109177 100644 --- a/src/sdam/description/topology/test.rs +++ b/src/sdam/description/topology/test.rs @@ -6,6 +6,7 @@ use std::time::Duration; pub use event::TestSdamEvent; +#[allow(clippy::cast_possible_truncation)] pub(crate) fn f64_ms_as_duration(f: f64) -> Duration { Duration::from_micros((f * 1000.0) as u64) } diff --git a/src/sdam/topology.rs b/src/sdam/topology.rs index ce44b0559..0bf9f1a6c 100644 --- a/src/sdam/topology.rs +++ b/src/sdam/topology.rs @@ -10,6 +10,7 @@ use futures_util::{ stream::{FuturesUnordered, StreamExt}, FutureExt, }; +use serde::Serialize; use tokio::sync::{ mpsc::{self, UnboundedReceiver, UnboundedSender}, watch::{self, Ref}, @@ -198,7 +199,7 @@ impl Topology { } /// Updates the given `command` as needed based on the `criteria`. - pub(crate) fn update_command_with_read_pref( + pub(crate) fn update_command_with_read_pref( &self, server_address: &ServerAddress, command: &mut Command, diff --git a/src/serde_util.rs b/src/serde_util.rs index a25443dbd..a19217449 100644 --- a/src/serde_util.rs +++ b/src/serde_util.rs @@ -7,6 +7,7 @@ use crate::{ bson::{doc, Bson, Document, RawDocumentBuf}, bson_util::get_u64, error::{Error, Result}, + options::WriteConcern, }; pub(crate) mod duration_option_as_int_seconds { @@ -17,9 +18,13 @@ pub(crate) mod duration_option_as_int_seconds { serializer: S, ) -> std::result::Result { match val { - Some(duration) if duration.as_secs() > i32::MAX as u64 => { - serializer.serialize_i64(duration.as_secs() as i64) - } + Some(duration) if duration.as_secs() > i32::MAX as u64 => serializer.serialize_i64( + duration + .as_secs() + .try_into() + .map_err(serde::ser::Error::custom)?, + ), + #[allow(clippy::cast_possible_truncation)] Some(duration) => serializer.serialize_i32(duration.as_secs() as i32), None => serializer.serialize_none(), } @@ -41,9 +46,13 @@ pub(crate) fn serialize_duration_option_as_int_millis( serializer: S, ) -> std::result::Result { match val { - Some(duration) if duration.as_millis() > i32::MAX as u128 => { - serializer.serialize_i64(duration.as_millis() as i64) - } + Some(duration) if duration.as_millis() > i32::MAX as u128 => serializer.serialize_i64( + duration + .as_millis() + .try_into() + .map_err(serde::ser::Error::custom)?, + ), + #[allow(clippy::cast_possible_truncation)] Some(duration) => serializer.serialize_i32(duration.as_millis() as i32), None => serializer.serialize_none(), } @@ -76,6 +85,7 @@ pub(crate) fn serialize_u32_option_as_batch_size( serializer: S, ) -> std::result::Result { match val { + #[allow(clippy::cast_possible_wrap)] Some(val) if *val <= std::i32::MAX as u32 => (doc! { "batchSize": (*val as i32) }) @@ -140,6 +150,7 @@ where } let date_time = match AwsDateTime::deserialize(deserializer)? { + #[allow(clippy::cast_possible_truncation)] AwsDateTime::Double(seconds) => { let millis = seconds * 1000.0; bson::DateTime::from_millis(millis as i64) @@ -167,6 +178,12 @@ pub(crate) fn to_raw_document_buf_with_options( Ok(raw_doc) } +pub(crate) fn write_concern_is_empty(write_concern: &Option) -> bool { + write_concern + .as_ref() + .map_or(true, |write_concern| write_concern.is_empty()) +} + #[cfg(test)] pub(crate) fn deserialize_nonempty_vec<'de, D, T>( deserializer: D, diff --git a/src/test.rs b/src/test.rs index dec6e3388..cee6466f6 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1,3 +1,6 @@ +#![allow(clippy::cast_possible_truncation)] +#![allow(clippy::cast_possible_wrap)] + #[cfg(all(not(feature = "sync"), not(feature = "tokio-sync")))] mod atlas_connectivity; mod atlas_planned_maintenance_testing; diff --git a/src/test/coll.rs b/src/test/coll.rs index 0b25194e2..e3852b561 100644 --- a/src/test/coll.rs +++ b/src/test/coll.rs @@ -1,6 +1,12 @@ -use std::{fmt::Debug, time::Duration}; +use std::{fmt::Debug, sync::Arc, time::Duration}; -use crate::Namespace; +use crate::{ + event::command::CommandEvent, + test::{Event, EventHandler}, + Client, + Namespace, +}; +use bson::{rawdoc, RawDocumentBuf}; use futures::stream::{StreamExt, TryStreamExt}; use lazy_static::lazy_static; use semver::VersionReq; @@ -1280,3 +1286,96 @@ async fn configure_human_readable_serialization() { .await .unwrap(); } + +#[cfg_attr(feature = "tokio-runtime", tokio::test)] +#[cfg_attr(feature = "async-std-runtime", async_std::test)] +async fn insert_many_document_sequences() { + if cfg!(feature = "in-use-encryption-unstable") { + log_uncaptured( + "skipping insert_many_document_sequences: auto-encryption does not support document \ + sequences", + ); + return; + } + + let handler = Arc::new(EventHandler::new()); + let client = Client::test_builder() + .event_handler(handler.clone()) + .build() + .await; + let mut subscriber = handler.subscribe(); + + let max_object_size = client.server_info.max_bson_object_size; + let max_message_size = client.server_info.max_message_size_bytes; + + let collection = client + .database("insert_many_document_sequences") + .collection::("insert_many_document_sequences"); + collection.drop(None).await.unwrap(); + + // A payload with > max_bson_object_size bytes but < max_message_size bytes should require only + // one round trip + let docs = vec![ + rawdoc! { "s": "a".repeat((max_object_size / 2) as usize) }, + rawdoc! { "s": "b".repeat((max_object_size / 2) as usize) }, + ]; + collection.insert_many(docs, None).await.unwrap(); + + let event = subscriber + .filter_map_event(Duration::from_millis(500), |e| match e { + Event::Command(command_event) => match command_event { + CommandEvent::Started(started) if started.command_name.as_str() == "insert" => { + Some(started) + } + _ => None, + }, + _ => None, + }) + .await + .expect("did not observe command started event for insert"); + let insert_documents = event.command.get_array("documents").unwrap(); + assert_eq!(insert_documents.len(), 2); + + // Build up a list of documents that exceeds max_message_size + let mut docs = Vec::new(); + let mut size = 0; + while size <= max_message_size { + // Leave some room for key/metadata bytes in document + let string_length = max_object_size - 500; + let doc = rawdoc! { "s": "a".repeat(string_length as usize) }; + size += doc.as_bytes().len() as i32; + docs.push(doc); + } + let total_docs = docs.len(); + collection.insert_many(docs, None).await.unwrap(); + + let first_event = subscriber + .filter_map_event(Duration::from_millis(500), |e| match e { + Event::Command(command_event) => match command_event { + CommandEvent::Started(started) if started.command_name.as_str() == "insert" => { + Some(started) + } + _ => None, + }, + _ => None, + }) + .await + .expect("did not observe command started event for insert"); + let first_batch_len = first_event.command.get_array("documents").unwrap().len(); + assert!(first_batch_len < total_docs); + + let second_event = subscriber + .filter_map_event(Duration::from_millis(500), |e| match e { + Event::Command(command_event) => match command_event { + CommandEvent::Started(started) if started.command_name.as_str() == "insert" => { + Some(started) + } + _ => None, + }, + _ => None, + }) + .await + .expect("did not observe command started event for insert"); + let second_batch_len = second_event.command.get_array("documents").unwrap().len(); + assert_eq!(first_batch_len + second_batch_len, total_docs); +}