Bug 1490496 - implement XPCOM FFI for key-value storage r=nika,lina,mossop
authorMyk Melez <myk@mykzilla.org>
Thu, 07 Feb 2019 16:14:04 +0000
changeset 457637 466f9c24e749d7b3701b60c5ed424e586634a718
parent 457636 259ae52cb2aed0f17d5799b0f8170b7b13cb2aae
child 457638 c508599012ee655cccbab36e57eacbf20778965c
push id35516
push userrmaries@mozilla.com
push dateFri, 08 Feb 2019 04:23:26 +0000
treeherdermozilla-central@d599d1a73a3a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnika, lina, mossop
bugs1490496
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1490496 - implement XPCOM FFI for key-value storage r=nika,lina,mossop MozReview-Commit-ID: JnQzXG581DW Differential Revision: https://phabricator.services.mozilla.com/D6328
Cargo.lock
browser/base/content/test/static/browser_all_files_referenced.js
storage/Variant.cpp
storage/Variant.h
storage/moz.build
storage/mozStorageSQLFunctions.cpp
storage/variant/Cargo.toml
storage/variant/src/lib.rs
third_party/rust/crossbeam-utils-0.3.2/.cargo-checksum.json
third_party/rust/crossbeam-utils-0.3.2/CHANGELOG.md
third_party/rust/crossbeam-utils-0.3.2/Cargo.toml
third_party/rust/crossbeam-utils-0.3.2/LICENSE-APACHE
third_party/rust/crossbeam-utils-0.3.2/LICENSE-MIT
third_party/rust/crossbeam-utils-0.3.2/README.md
third_party/rust/crossbeam-utils-0.3.2/src/cache_padded.rs
third_party/rust/crossbeam-utils-0.3.2/src/consume.rs
third_party/rust/crossbeam-utils-0.3.2/src/lib.rs
third_party/rust/crossbeam-utils-0.3.2/src/scoped.rs
third_party/rust/crossbeam-utils/.cargo-checksum.json
third_party/rust/crossbeam-utils/CHANGELOG.md
third_party/rust/crossbeam-utils/Cargo.toml
third_party/rust/crossbeam-utils/LICENSE-MIT
third_party/rust/crossbeam-utils/README.md
third_party/rust/crossbeam-utils/benches/atomic_cell.rs
third_party/rust/crossbeam-utils/src/atomic/atomic_cell.rs
third_party/rust/crossbeam-utils/src/atomic/consume.rs
third_party/rust/crossbeam-utils/src/atomic/mod.rs
third_party/rust/crossbeam-utils/src/cache_padded.rs
third_party/rust/crossbeam-utils/src/consume.rs
third_party/rust/crossbeam-utils/src/lib.rs
third_party/rust/crossbeam-utils/src/scoped.rs
third_party/rust/crossbeam-utils/src/sync/mod.rs
third_party/rust/crossbeam-utils/src/sync/parker.rs
third_party/rust/crossbeam-utils/src/thread.rs
third_party/rust/crossbeam-utils/tests/atomic_cell.rs
third_party/rust/crossbeam-utils/tests/cache_padded.rs
third_party/rust/crossbeam-utils/tests/parker.rs
third_party/rust/crossbeam-utils/tests/thread.rs
third_party/rust/lmdb-rkv/.cargo-checksum.json
third_party/rust/lmdb-rkv/Cargo.toml
third_party/rust/lmdb-rkv/src/cursor.rs
third_party/rust/lmdb-rkv/src/environment.rs
third_party/rust/lmdb-rkv/src/lib.rs
third_party/rust/rkv/.cargo-checksum.json
third_party/rust/rkv/Cargo.toml
third_party/rust/rkv/examples/iterator.rs
third_party/rust/rkv/examples/simple-store.rs
third_party/rust/rkv/src/env.rs
third_party/rust/rkv/src/integer.rs
third_party/rust/rkv/src/lib.rs
third_party/rust/rkv/src/readwrite.rs
third_party/rust/rkv/src/value.rs
third_party/rust/threadbound/.cargo-checksum.json
third_party/rust/threadbound/Cargo.toml
third_party/rust/threadbound/LICENSE-APACHE
third_party/rust/threadbound/LICENSE-MIT
third_party/rust/threadbound/README.md
third_party/rust/threadbound/src/lib.rs
third_party/rust/uuid-0.6.5/.cargo-checksum.json
third_party/rust/uuid-0.6.5/CODEOWNERS
third_party/rust/uuid-0.6.5/CODE_OF_CONDUCT.md
third_party/rust/uuid-0.6.5/CONTRIBUTING.md
third_party/rust/uuid-0.6.5/COPYRIGHT
third_party/rust/uuid-0.6.5/Cargo.toml
third_party/rust/uuid-0.6.5/LICENSE-APACHE
third_party/rust/uuid-0.6.5/LICENSE-MIT
third_party/rust/uuid-0.6.5/README.md
third_party/rust/uuid-0.6.5/benches/parse_str.rs
third_party/rust/uuid-0.6.5/src/adapter.rs
third_party/rust/uuid-0.6.5/src/core_support.rs
third_party/rust/uuid-0.6.5/src/lib.rs
third_party/rust/uuid-0.6.5/src/prelude.rs
third_party/rust/uuid-0.6.5/src/serde_support.rs
third_party/rust/uuid-0.6.5/src/slog_support.rs
third_party/rust/uuid-0.6.5/src/std_support.rs
third_party/rust/uuid-0.6.5/src/test_util.rs
third_party/rust/uuid-0.6.5/src/u128_support.rs
third_party/rust/uuid/.cargo-checksum.json
third_party/rust/uuid/CODE_OF_CONDUCT.md
third_party/rust/uuid/Cargo.toml
third_party/rust/uuid/README.md
third_party/rust/uuid/benches/format_str.rs
third_party/rust/uuid/benches/invalid_parse_str.rs
third_party/rust/uuid/benches/mod.rs
third_party/rust/uuid/benches/parse_str.rs
third_party/rust/uuid/benches/serde_support.rs
third_party/rust/uuid/benches/slog_support/mod.rs
third_party/rust/uuid/benches/slog_support/parse_str.rs
third_party/rust/uuid/benches/valid_parse_str.rs
third_party/rust/uuid/src/adapter.rs
third_party/rust/uuid/src/adapter/core_support/mod.rs
third_party/rust/uuid/src/adapter/mod.rs
third_party/rust/uuid/src/core_support.rs
third_party/rust/uuid/src/lib.rs
third_party/rust/uuid/src/parser/core_support.rs
third_party/rust/uuid/src/parser/mod.rs
third_party/rust/uuid/src/parser/std_support.rs
third_party/rust/uuid/src/prelude.rs
third_party/rust/uuid/src/serde_support.rs
third_party/rust/uuid/src/slog_support.rs
third_party/rust/uuid/src/std_support.rs
third_party/rust/uuid/src/test_util.rs
third_party/rust/uuid/src/u128_support.rs
third_party/rust/uuid/src/v1.rs
third_party/rust/uuid/src/v3.rs
third_party/rust/uuid/src/v4.rs
third_party/rust/uuid/src/v5.rs
toolkit/components/build/nsToolkitCompsCID.h
toolkit/components/kvstore/.eslintrc.js
toolkit/components/kvstore/Cargo.toml
toolkit/components/kvstore/kvstore.jsm
toolkit/components/kvstore/moz.build
toolkit/components/kvstore/nsIKeyValue.idl
toolkit/components/kvstore/nsKeyValueModule.cpp
toolkit/components/kvstore/src/error.rs
toolkit/components/kvstore/src/lib.rs
toolkit/components/kvstore/src/owned_value.rs
toolkit/components/kvstore/src/task.rs
toolkit/components/kvstore/test/xpcshell/.eslintrc.js
toolkit/components/kvstore/test/xpcshell/test_kvstore.js
toolkit/components/kvstore/test/xpcshell/xpcshell.ini
toolkit/components/moz.build
toolkit/library/rust/shared/Cargo.toml
toolkit/library/rust/shared/lib.rs
tools/lint/eslint/modules.json
xpcom/rust/moz_task/Cargo.toml
xpcom/rust/moz_task/src/lib.rs
xpcom/rust/xpcom/Cargo.toml
xpcom/rust/xpcom/src/lib.rs
xpcom/rust/xpcom/src/method.rs
xpcom/rust/xpcom/src/refptr.rs
xpcom/threads/MainThreadUtils.h
xpcom/threads/nsThreadManager.cpp
xpcom/threads/nsThreadUtils.cpp
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -610,16 +610,24 @@ dependencies = [
 name = "crossbeam-utils"
 version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "crossbeam-utils"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "cssparser"
 version = "0.25.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cssparser-macros 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "dtoa-short 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1111,25 +1119,25 @@ dependencies = [
  "cose-c 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "cubeb-pulse 0.2.0",
  "cubeb-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "encoding_c 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "encoding_glue 0.1.0",
  "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "geckoservo 0.0.1",
  "jsrust_shared 0.1.0",
+ "kvstore 0.1.0",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "mozurl 0.0.1",
  "mp4parse_capi 0.11.2",
  "netwerk_helper 0.0.1",
  "nserror 0.1.0",
  "nsstring 0.1.0",
  "prefs_parser 0.0.1",
  "profiler_helper 0.1.0",
- "rkv 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rsdparsa_capi 0.1.0",
  "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "u2fhid 0.2.3",
  "webrender_bindings 0.1.0",
  "xpcom 0.1.0",
 ]
 
 [[package]]
@@ -1319,16 +1327,35 @@ dependencies = [
 ]
 
 [[package]]
 name = "khronos_api"
 version = "3.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "kvstore"
+version = "0.1.0"
+dependencies = [
+ "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lmdb-rkv 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "moz_task 0.1.0",
+ "nserror 0.1.0",
+ "nsstring 0.1.0",
+ "ordered-float 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rkv 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "storage_variant 0.1.0",
+ "xpcom 0.1.0",
+]
+
+[[package]]
 name = "lalrpop"
 version = "0.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "ascii-canvas 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "bit-set 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1433,17 +1460,17 @@ dependencies = [
 
 [[package]]
 name = "linked-hash-map"
 version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "lmdb-rkv"
-version = "0.8.2"
+version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "lmdb-sys 0.8.0 (git+https://github.com/mozilla/lmdb-rs?branch=lmdb-sys-0.8.0-android-fix)",
 ]
 
 [[package]]
@@ -1612,16 +1639,25 @@ dependencies = [
 ]
 
 [[package]]
 name = "moz_cbor"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "moz_task"
+version = "0.1.0"
+dependencies = [
+ "nserror 0.1.0",
+ "nsstring 0.1.0",
+ "xpcom 0.1.0",
+]
+
+[[package]]
 name = "mozilla-central-workspace-hack"
 version = "0.1.0"
 dependencies = [
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "proc-macro2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.80 (git+https://github.com/servo/serde?branch=deserialize_from_enums9)",
@@ -2134,28 +2170,28 @@ name = "regex-syntax"
 version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "rkv"
-version = "0.5.1"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "arrayref 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "lmdb-rkv 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lmdb-rkv 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "ordered-float 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "ron"
 version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2393,16 +2429,26 @@ dependencies = [
 ]
 
 [[package]]
 name = "stable_deref_trait"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "storage_variant"
+version = "0.1.0"
+dependencies = [
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
+ "nserror 0.1.0",
+ "nsstring 0.1.0",
+ "xpcom 0.1.0",
+]
+
+[[package]]
 name = "string"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "string_cache"
 version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2669,16 +2715,21 @@ dependencies = [
 ]
 
 [[package]]
 name = "thread_profiler"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "threadbound"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "time"
 version = "0.1.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "redox_syscall 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)",
 ]
@@ -2937,16 +2988,21 @@ name = "uuid"
 version = "0.6.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "uuid"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "vcpkg"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "vec_map"
 version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3170,16 +3226,17 @@ source = "registry+https://github.com/ru
 
 [[package]]
 name = "xpcom"
 version = "0.1.0"
 dependencies = [
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "nserror 0.1.0",
  "nsstring 0.1.0",
+ "threadbound 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "xpcom_macros 0.1.0",
 ]
 
 [[package]]
 name = "xpcom-gtest"
 version = "0.1.0"
 dependencies = [
  "nserror 0.1.0",
@@ -3275,16 +3332,17 @@ dependencies = [
 "checksum cranelift-wasm 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7eccd196ecd01a2394ce05e2259afe5704874816b058541c7cce7794f0e835e"
 "checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7"
 "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3"
 "checksum crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fe8153ef04a7594ded05b427ffad46ddeaf22e63fd48d42b3e1e3bb4db07cae7"
 "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150"
 "checksum crossbeam-epoch 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2af0e75710d6181e234c8ecc79f14a97907850a541b13b0be1dd10992f2e4620"
 "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
 "checksum crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d636a8b3bcc1b409d7ffd3facef8f21dcb4009626adbd0c5e6c4305c07253c7b"
+"checksum crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "41ee4864f4797060e52044376f7d107429ce1fb43460021b126424b7180ee21a"
 "checksum cssparser 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)" = "730363a45c4e248d4f21d3e5c1156d1a9cdec0855056c0d9539e814bc59865c3"
 "checksum cssparser-macros 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f3a5383ae18dbfdeb569ed62019f5bddb2a95cd2d3833313c475a0d014777805"
 "checksum cstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b6557bdb1dc9647eae1cf7f5601b14cd45fc3c7ccf2df618387416fe542da6ea"
 "checksum cstr-macros 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0472c17c83d3ec1af32fb6ee2b3ad56ae0b6e69355d63d1d30602055c34324a8"
 "checksum cubeb 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8a3502aafa1bf95c524f65d2ba46d8741700c6a8a9543ea52c6da3d8b69a2896"
 "checksum cubeb-backend 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdcac95519416d9ec814db2dc40e6293e7da25b906023d93f48b87f0587ab138"
 "checksum cubeb-core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37f7b20f757a4e4b6aa28863236551bff77682dc6db192eba15af615492b5445"
 "checksum cubeb-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "653b9e245d35dbe2a2da7c4586275cee75ff656ddeb02d4a73b4afdfa6d67502"
@@ -3349,17 +3407,17 @@ dependencies = [
 "checksum lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e6412c5e2ad9584b0b8e979393122026cdd6d2a80b933f890dcd694ddbe73739"
 "checksum lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce12306c4739d86ee97c23139f3a34ddf0387bbf181bc7929d287025a8c3ef6b"
 "checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef"
 "checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
 "checksum libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3ad660d7cb8c5822cd83d10897b0f1f1526792737a179e73896152f85b88c2"
 "checksum libudev 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea626d3bdf40a1c5aee3bcd4f40826970cae8d80a8fec934c82a63840094dcfe"
 "checksum libz-sys 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "3fdd64ef8ee652185674455c1d450b83cbc8ad895625d543b5324d923f82e4d8"
 "checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e"
-"checksum lmdb-rkv 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "07d8d72d709440ac7a19b71e04fb66684ec7547b3831817872454b01fdaefe23"
+"checksum lmdb-rkv 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aba42e6d930590ce6625566f2d16300add86ef11335eedba0fcf29f9f4cbd8c5"
 "checksum lmdb-sys 0.8.0 (git+https://github.com/mozilla/lmdb-rs?branch=lmdb-sys-0.8.0-android-fix)" = "<none>"
 "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
 "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
 "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
 "checksum malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "35adee9ed962cf7d07d62cb58bc45029f3227f5b5b86246caa8632f06c187bc3"
 "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
 "checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a"
 "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
@@ -3415,17 +3473,17 @@ dependencies = [
 "checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8"
 "checksum redox_syscall 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "ab105df655884ede59d45b7070c8a65002d921461ee813a024558ca16030eea0"
 "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
 "checksum redox_users 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "214a97e49be64fd2c86f568dd0cb2c757d2cc53de95b273b6ad0a1c908482f26"
 "checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b"
 "checksum regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75ecf88252dce580404a22444fc7d626c01815debba56a7f4f536772a5ff19d3"
 "checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db"
 "checksum regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1ac0f60d675cc6cf13a20ec076568254472551051ad5dd050364d70671bf6b"
-"checksum rkv 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "663e50c3b2454387726a83b01629892824dcf113c0471841ea4bc9b5929eb75e"
+"checksum rkv 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "79504d734e64f3d9391fbcaf15ca247421da461b95b9cdebd9af5679a4cfd8c8"
 "checksum ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "da06feaa07f69125ab9ddc769b11de29090122170b402547f64b86fe16ebc399"
 "checksum runloop 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d79b4b604167921892e84afbbaad9d5ad74e091bf6c511d9dbfb0593f09fabd"
 "checksum rust-ini 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8a654c5bda722c699be6b0fe4c0d90de218928da5b724c3e467fc48865c37263"
 "checksum rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "76d7ba1feafada44f2d38eed812bd2489a03c0f5abb975799251518b68848649"
 "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
 "checksum ryu 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "fd0568787116e13c652377b6846f5931454a363a8fdf8ae50463ee40935b278b"
 "checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637"
 "checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d"
@@ -3465,16 +3523,17 @@ dependencies = [
 "checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209"
 "checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83"
 "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
 "checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693"
 "checksum thin-slice 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
 "checksum thin-vec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "73fdf4b84c65a85168477b7fb6c498e0716bc9487fba24623389ea7f51708044"
 "checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963"
 "checksum thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf947d192a9be60ef5131cc7a4648886ba89d712f16700ebbf80c8a69d05d48f"
+"checksum threadbound 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d23e87ee7a1ef5bd2d38cef24ff360f6e02beee13c6a7eb64dddde4a3da427a3"
 "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b"
 "checksum tokio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8ee337e5f4e501fc32966fec6fe0ca0cc1c237b0b1b14a335f8bfe3c5f06e286"
 "checksum tokio-codec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "881e9645b81c2ce95fcb799ded2c29ffb9f25ef5bef909089a420e5961dd8ccb"
 "checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71"
 "checksum tokio-executor 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "424f0c87ecd66b863045d84e384cb7ce0ae384d8b065b9f0363d29c0d1b30b2f"
 "checksum tokio-fs 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b5cbe4ca6e71cb0b62a66e4e6f53a8c06a6eefe46cc5f665ad6f274c9906f135"
 "checksum tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a5c9635ee806f26d302b8baa1e145689a280d8f5aa8d0552e7344808da54cc21"
 "checksum tokio-reactor 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8703a5762ff6913510dc64272c714c4389ffd8c4b3cf602879b8bd14ff06b604"
@@ -3492,16 +3551,17 @@ dependencies = [
 "checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f"
 "checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1"
 "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
 "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
 "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
 "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
 "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
 "checksum uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e1436e58182935dcd9ce0add9ea0b558e8a87befe01c1a301e6020aeb0876363"
+"checksum uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dab5c5526c5caa3d106653401a267fed923e7046f35895ffcb5ca42db64942e6"
 "checksum vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0a7d8bed3178a8fb112199d466eeca9ed09a14ba8ad67718179b4fd5487d0b"
 "checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
 "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
 "checksum walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63636bd0eb3d00ccb8b9036381b526efac53caf112b7783b730ab3f8e44da369"
 "checksum want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "797464475f30ddb8830cc529aaaae648d581f99e2036a928877dfde027ddf6b3"
 "checksum wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5e01c420bc7d36e778bd242e1167b079562ba8b34087122cc9057187026d060"
 "checksum webidl 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0f807f7488d680893f7188aa09d7672a3a0a8461975a098a2edf0a52e3fee29"
 "checksum which 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4be6cfa54dab45266e98b5d7be2f8ce959ddd49abd141a05d52dce4b07f803bb"
--- a/browser/base/content/test/static/browser_all_files_referenced.js
+++ b/browser/base/content/test/static/browser_all_files_referenced.js
@@ -176,16 +176,19 @@ var whitelist = [
    isFromDevTools: true},
   {file: "chrome://devtools/skin/images/aboutdebugging-firefox-release.svg",
    isFromDevTools: true},
   {file: "chrome://devtools/skin/images/next.svg", isFromDevTools: true},
   // Feature gates are available but not used yet - Bug 1479127
   {file: "resource://gre-resources/featuregates/FeatureGate.jsm"},
   {file: "resource://gre-resources/featuregates/FeatureGateImplementation.jsm"},
   {file: "resource://gre-resources/featuregates/feature_definitions.json"},
+  // kvstore.jsm wraps the API in nsIKeyValue.idl in a more ergonomic API
+  // It landed in bug 1490496, and we expect to start using it shortly.
+  {file: "resource://gre/modules/kvstore.jsm"},
 ];
 
 whitelist = new Set(whitelist.filter(item =>
   ("isFromDevTools" in item) == isDevtools &&
   (!item.skipUnofficial || !AppConstants.MOZILLA_OFFICIAL) &&
   (!item.platforms || item.platforms.includes(AppConstants.platform))
 ).map(item => item.file));
 
new file mode 100644
--- /dev/null
+++ b/storage/Variant.cpp
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "Variant.h"
+
+extern "C" {
+
+using namespace mozilla::storage;
+
+/**
+ * Return the data type of the given variant.  This method used to be exposed
+ * to XPCOM, but since bug 1507540 it's marked [notxpcom] in the interface
+ * definition, so we need this C function to access it from Rust.
+ */
+uint16_t NS_GetDataType(nsIVariant* aVariant) {
+  return aVariant->GetDataType();
+}
+
+// Convenience functions to create Storage variants from Rust.
+void NS_NewStorageNullVariant(nsIVariant** aVariant) {
+  nsCOMPtr<nsIVariant> variant = new NullVariant();
+  variant.forget(aVariant);
+}
+
+void NS_NewStorageBooleanVariant(bool aValue, nsIVariant** aVariant) {
+  nsCOMPtr<nsIVariant> variant = new BooleanVariant(aValue);
+  variant.forget(aVariant);
+}
+
+void NS_NewStorageIntegerVariant(int64_t aValue, nsIVariant** aVariant) {
+  nsCOMPtr<nsIVariant> variant = new IntegerVariant(aValue);
+  variant.forget(aVariant);
+}
+
+void NS_NewStorageFloatVariant(double aValue, nsIVariant** aVariant) {
+  nsCOMPtr<nsIVariant> variant = new FloatVariant(aValue);
+  variant.forget(aVariant);
+}
+
+void NS_NewStorageTextVariant(const nsAString& aValue, nsIVariant** aVariant) {
+  nsCOMPtr<nsIVariant> variant = new TextVariant(aValue);
+  variant.forget(aVariant);
+}
+
+void NS_NewStorageUTF8TextVariant(const nsACString& aValue,
+                                  nsIVariant** aVariant) {
+  nsCOMPtr<nsIVariant> variant = new UTF8TextVariant(aValue);
+  variant.forget(aVariant);
+}
+
+}  // extern "C"
--- a/storage/Variant.h
+++ b/storage/Variant.h
@@ -26,16 +26,23 @@
  * returned.  We provide traits for the basic sqlite types to make use easier.
  * The following types map to the indicated sqlite type:
  * int64_t   -> INTEGER (use IntegerVariant)
  * double    -> FLOAT (use FloatVariant)
  * nsString  -> TEXT (use TextVariant)
  * nsCString -> TEXT (use UTF8TextVariant)
  * uint8_t[] -> BLOB (use BlobVariant)
  * nullptr   -> NULL (use NullVariant)
+ *
+ * The kvstore component also reuses this class as a common implementation
+ * of a simple threadsafe variant for the storage of primitive values only.
+ * The BooleanVariant type has been introduced for kvstore use cases and should
+ * be enhanced to provide full boolean variant support for mozStorage.
+ *
+ * Bug 1494102 tracks that work.
  */
 
 namespace mozilla {
 namespace storage {
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Base Class
 
@@ -73,16 +80,23 @@ struct variant_storage_traits {
   }
 
   static inline void destroy(const StorageType &_storage) {}
 };
 
 #define NO_CONVERSION return NS_ERROR_CANNOT_CONVERT_DATA;
 
 template <typename DataType, bool Adopting = false>
+struct variant_boolean_traits {
+  typedef typename variant_storage_traits<DataType, Adopting>::StorageType
+      StorageType;
+  static inline nsresult asBool(const StorageType &, bool *) { NO_CONVERSION }
+};
+
+template <typename DataType, bool Adopting = false>
 struct variant_integer_traits {
   typedef typename variant_storage_traits<DataType, Adopting>::StorageType
       StorageType;
   static inline nsresult asInt32(const StorageType &, int32_t *) {
     NO_CONVERSION
   }
   static inline nsresult asInt64(const StorageType &, int64_t *) {
     NO_CONVERSION
@@ -118,16 +132,40 @@ struct variant_blob_traits {
                                  void **) {
     NO_CONVERSION
   }
 };
 
 #undef NO_CONVERSION
 
 /**
+ * BOOLEAN type
+ */
+
+template <>
+struct variant_traits<bool> {
+  static inline uint16_t type() { return nsIDataType::VTYPE_BOOL; }
+};
+template <>
+struct variant_boolean_traits<bool> {
+  static inline nsresult asBool(bool aValue, bool *_result) {
+    *_result = aValue;
+    return NS_OK;
+  }
+
+  // NB: It might be worth also providing conversions to int types.
+
+  // NB: It'd be nice to implement asBool conversions for 0 and 1, too.
+  // That would let us clean up some conversions in Places, such as:
+  // https://searchfox.org/mozilla-central/rev/0640ea80fbc8d48f8b197cd363e2535c95a15eb3/toolkit/components/places/SQLFunctions.cpp#564-565
+  // https://searchfox.org/mozilla-central/rev/0640ea80fbc8d48f8b197cd363e2535c95a15eb3/toolkit/components/places/SQLFunctions.cpp#1057
+  // https://searchfox.org/mozilla-central/rev/0640ea80fbc8d48f8b197cd363e2535c95a15eb3/toolkit/components/places/nsNavHistory.cpp#3189
+};
+
+/**
  * INTEGER types
  */
 
 template <>
 struct variant_traits<int64_t> {
   static inline uint16_t type() { return nsIDataType::VTYPE_INT64; }
 };
 template <>
@@ -342,16 +380,21 @@ class Variant final : public Variant_bas
   explicit Variant(
       const typename variant_storage_traits<DataType, Adopting>::ConstructorType
           aData) {
     variant_storage_traits<DataType, Adopting>::storage_conversion(aData,
                                                                    &mData);
   }
 
   uint16_t GetDataType() override { return variant_traits<DataType>::type(); }
+
+  NS_IMETHOD GetAsBool(bool *_boolean) override {
+    return variant_boolean_traits<DataType, Adopting>::asBool(mData, _boolean);
+  }
+
   NS_IMETHOD GetAsInt32(int32_t *_integer) override {
     return variant_integer_traits<DataType, Adopting>::asInt32(mData, _integer);
   }
 
   NS_IMETHOD GetAsInt64(int64_t *_integer) override {
     return variant_integer_traits<DataType, Adopting>::asInt64(mData, _integer);
   }
 
@@ -375,16 +418,20 @@ class Variant final : public Variant_bas
 
  private:
   typename variant_storage_traits<DataType, Adopting>::StorageType mData;
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Handy typedefs!  Use these for the right mapping.
 
+// Currently, BooleanVariant is only useful for kvstore.
+// Bug 1494102 tracks implementing full boolean variant support for mozStorage.
+typedef Variant<bool> BooleanVariant;
+
 typedef Variant<int64_t> IntegerVariant;
 typedef Variant<double> FloatVariant;
 typedef Variant<nsString> TextVariant;
 typedef Variant<nsCString> UTF8TextVariant;
 typedef Variant<uint8_t[], false> BlobVariant;
 typedef Variant<uint8_t[], true> AdoptedBlobVariant;
 
 }  // namespace storage
--- a/storage/moz.build
+++ b/storage/moz.build
@@ -72,16 +72,17 @@ UNIFIED_SOURCES += [
     'mozStorageStatement.cpp',
     'mozStorageStatementJSHelper.cpp',
     'mozStorageStatementParams.cpp',
     'mozStorageStatementRow.cpp',
     'SQLCollations.cpp',
     'StorageBaseStatementInternal.cpp',
     'TelemetryVFS.cpp',
     'VacuumManager.cpp',
+    'Variant.cpp',
 ]
 
 # These files need to be built separately because they #include variantToSQLiteT_impl.h.
 SOURCES += [
     'mozStorageBindingParams.cpp',
     'mozStorageConnection.cpp',
 ]
 
--- a/storage/mozStorageSQLFunctions.cpp
+++ b/storage/mozStorageSQLFunctions.cpp
@@ -2,16 +2,17 @@
  * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ArrayUtils.h"
 
 #include "mozStorageSQLFunctions.h"
+#include "nsTArray.h"
 #include "nsUnicharUtils.h"
 #include <algorithm>
 
 namespace mozilla {
 namespace storage {
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Local Helper Functions
new file mode 100644
--- /dev/null
+++ b/storage/variant/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "storage_variant"
+version = "0.1.0"
+authors = [
+    "Lina Cambridge <lina@yakshaving.ninja>",
+    "Myk Melez <myk@mykzilla.org>"
+]
+
+[dependencies]
+libc = "0.2"
+nserror = { path = "../../xpcom/rust/nserror" }
+nsstring = { path = "../../xpcom/rust/nsstring" }
+xpcom = { path = "../../xpcom/rust/xpcom" }
new file mode 100644
--- /dev/null
+++ b/storage/variant/src/lib.rs
@@ -0,0 +1,146 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+extern crate libc;
+extern crate nserror;
+extern crate nsstring;
+extern crate xpcom;
+
+use libc::{c_double, int64_t, uint16_t};
+use nserror::{nsresult, NsresultExt, NS_OK};
+use nsstring::{nsACString, nsAString, nsCString, nsString};
+use xpcom::{getter_addrefs, interfaces::nsIVariant, RefPtr};
+
+extern "C" {
+    fn NS_GetDataType(variant: *const nsIVariant) -> uint16_t;
+    fn NS_NewStorageNullVariant(result: *mut *const nsIVariant);
+    fn NS_NewStorageBooleanVariant(value: bool, result: *mut *const nsIVariant);
+    fn NS_NewStorageIntegerVariant(value: int64_t, result: *mut *const nsIVariant);
+    fn NS_NewStorageFloatVariant(value: c_double, result: *mut *const nsIVariant);
+    fn NS_NewStorageTextVariant(value: *const nsAString, result: *mut *const nsIVariant);
+    fn NS_NewStorageUTF8TextVariant(value: *const nsACString, result: *mut *const nsIVariant);
+}
+
+// These are the relevant parts of the nsXPTTypeTag enum in xptinfo.h,
+// which nsIVariant.idl reflects into the nsIDataType struct class and uses
+// to constrain the values of nsIVariant::dataType.
+#[repr(u16)]
+pub enum DataType {
+    INT32 = 2,
+    DOUBLE = 9,
+    BOOL = 10,
+    VOID = 13,
+    WSTRING = 21,
+    EMPTY = 255,
+}
+
+// Per https://github.com/rust-lang/rust/issues/44266, casts aren't allowed
+// in match arms, so it isn't possible to cast DataType variants to u16
+// in order to match them against the value of nsIVariant::dataType.
+// Instead we have to reflect each variant into a constant and then match
+// against the values of the constants.
+//
+// (Alternatively, we could use the enum_primitive crate to convert primitive
+// values of nsIVariant::dataType to their enum equivalents.  Or perhaps
+// bindgen would convert the nsXPTTypeTag enum in xptinfo.h into something else
+// we could use.  Since we currently only accept a small subset of values,
+// and since that enum is unlikely to change frequently, this workaround
+// seems sufficient.)
+//
+pub const DATA_TYPE_INT32: uint16_t = DataType::INT32 as u16;
+pub const DATA_TYPE_DOUBLE: uint16_t = DataType::DOUBLE as u16;
+pub const DATA_TYPE_BOOL: uint16_t = DataType::BOOL as u16;
+pub const DATA_TYPE_VOID: uint16_t = DataType::VOID as u16;
+pub const DATA_TYPE_WSTRING: uint16_t = DataType::WSTRING as u16;
+pub const DATA_TYPE_EMPTY: uint16_t = DataType::EMPTY as u16;
+
+pub trait GetDataType {
+    fn get_data_type(&self) -> uint16_t;
+}
+
+impl GetDataType for nsIVariant {
+    fn get_data_type(&self) -> uint16_t {
+        unsafe { NS_GetDataType(self) }
+    }
+}
+
+pub trait VariantType {
+    fn into_variant(self) -> RefPtr<nsIVariant>;
+    fn from_variant(variant: &nsIVariant) -> Result<Self, nsresult>
+    where
+        Self: Sized;
+}
+
+/// Implements traits to convert between variants and their types.
+macro_rules! variant {
+    ($typ:ident, $constructor:ident, $getter:ident) => {
+        impl VariantType for $typ {
+            fn into_variant(self) -> RefPtr<nsIVariant> {
+                // getter_addrefs returns a Result<RefPtr<T>, nsresult>,
+                // but we know that our $constructor is infallible, so we can
+                // safely unwrap and return the RefPtr.
+                getter_addrefs(|p| {
+                    unsafe { $constructor(self.into(), p) };
+                    NS_OK
+                }).unwrap()
+            }
+            fn from_variant(variant: &nsIVariant) -> Result<$typ, nsresult> {
+                let mut result = $typ::default();
+                let rv = unsafe { variant.$getter(&mut result) };
+                if rv.succeeded() {
+                    Ok(result)
+                } else {
+                    Err(rv)
+                }
+            }
+        }
+    };
+    (* $typ:ident, $constructor:ident, $getter:ident) => {
+        impl VariantType for $typ {
+            fn into_variant(self) -> RefPtr<nsIVariant> {
+                // getter_addrefs returns a Result<RefPtr<T>, nsresult>,
+                // but we know that our $constructor is infallible, so we can
+                // safely unwrap and return the RefPtr.
+                getter_addrefs(|p| {
+                    unsafe { $constructor(&*self, p) };
+                    NS_OK
+                }).unwrap()
+            }
+            fn from_variant(variant: &nsIVariant) -> Result<$typ, nsresult> {
+                let mut result = $typ::new();
+                let rv = unsafe { variant.$getter(&mut *result) };
+                if rv.succeeded() {
+                    Ok(result)
+                } else {
+                    Err(rv)
+                }
+            }
+        }
+    };
+}
+
+// The unit type (()) is a reasonable equivalation of the null variant.
+// The macro can't produce its implementations of VariantType, however,
+// so we implement them concretely.
+impl VariantType for () {
+    fn into_variant(self) -> RefPtr<nsIVariant> {
+        // getter_addrefs returns a Result<RefPtr<T>, nsresult>,
+        // but we know that NS_NewStorageNullVariant is infallible, so we can
+        // safely unwrap and return the RefPtr.
+        getter_addrefs(|p| {
+            unsafe { NS_NewStorageNullVariant(p) };
+            NS_OK
+        }).unwrap()
+    }
+    fn from_variant(_variant: &nsIVariant) -> Result<Self, nsresult> {
+        Ok(())
+    }
+}
+
+variant!(bool, NS_NewStorageBooleanVariant, GetAsBool);
+variant!(i32, NS_NewStorageIntegerVariant, GetAsInt32);
+variant!(i64, NS_NewStorageIntegerVariant, GetAsInt64);
+variant!(f64, NS_NewStorageFloatVariant, GetAsDouble);
+variant!(*nsString, NS_NewStorageTextVariant, GetAsAString);
+variant!(*nsCString, NS_NewStorageUTF8TextVariant, GetAsACString);
copy from third_party/rust/crossbeam-utils/.cargo-checksum.json
copy to third_party/rust/crossbeam-utils-0.3.2/.cargo-checksum.json
copy from third_party/rust/crossbeam-utils/CHANGELOG.md
copy to third_party/rust/crossbeam-utils-0.3.2/CHANGELOG.md
copy from third_party/rust/crossbeam-utils/Cargo.toml
copy to third_party/rust/crossbeam-utils-0.3.2/Cargo.toml
new file mode 100644
--- /dev/null
+++ b/third_party/rust/crossbeam-utils-0.3.2/LICENSE-APACHE
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
copy from third_party/rust/crossbeam-utils/LICENSE-MIT
copy to third_party/rust/crossbeam-utils-0.3.2/LICENSE-MIT
copy from third_party/rust/crossbeam-utils/README.md
copy to third_party/rust/crossbeam-utils-0.3.2/README.md
copy from third_party/rust/crossbeam-utils/src/cache_padded.rs
copy to third_party/rust/crossbeam-utils-0.3.2/src/cache_padded.rs
rename from third_party/rust/crossbeam-utils/src/consume.rs
rename to third_party/rust/crossbeam-utils-0.3.2/src/consume.rs
copy from third_party/rust/crossbeam-utils/src/lib.rs
copy to third_party/rust/crossbeam-utils-0.3.2/src/lib.rs
rename from third_party/rust/crossbeam-utils/src/scoped.rs
rename to third_party/rust/crossbeam-utils-0.3.2/src/scoped.rs
--- a/third_party/rust/crossbeam-utils/.cargo-checksum.json
+++ b/third_party/rust/crossbeam-utils/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"CHANGELOG.md":"6b764c44d2f0ddb3a10101f738673685992bbd894152c0fc354d571f5115f85a","Cargo.toml":"48f3a37f7267b76120aa309e4e2d4e13df6e2994b5b2b402177640957dbcb18b","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0621878e61f0d0fda054bcbe02df75192c28bde1ecc8289cbd86aeba2dd72720","README.md":"ef6edf8bcb3491d8453ca36008f9e3fa0895bb6c17db47b38867784ed7717983","src/cache_padded.rs":"47a99e571bf5c213395585ff001c7abd10388609f349a2e776d481e2ed0b32cb","src/consume.rs":"422c6006dca162a80d39f1abcf1fe26dae6d69772111b3e8824c7f9b335c3ec2","src/lib.rs":"81273b19bd30f6f20084ff01af1acedadcf9ac88db89137d59cb7ee24c226588","src/scoped.rs":"1b7eaaf1fd6033875e4e368e4318a93430bedeb6f68a11c10221ace0243cd83b"},"package":"d636a8b3bcc1b409d7ffd3facef8f21dcb4009626adbd0c5e6c4305c07253c7b"}
\ No newline at end of file
+{"files":{"CHANGELOG.md":"632777ff129c108f4b3a445f99604f98565345570f0688f68d0d906b6e62a713","Cargo.toml":"5a3bf61003b6175a0de19ad055afb9f99bd09af200910c5de9dcdfce8fd21fc2","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"fbf8251ad672babe9db82a62ef76d06854c96ee0195fd3d043be222a96b428ec","benches/atomic_cell.rs":"9e80d3c120df4e6e766ed4fa3df3ed1be5256f6e6cd96a1ced71bedab291bf7f","src/atomic/atomic_cell.rs":"bdb746cabb68eb12f1ddd531838e1732403d42f98f7bd5ce187a982e2bae051b","src/atomic/consume.rs":"bfdc7e2d8370a5a3bb1699b6214347c359d66fcc92a2d1345a513676ac91d821","src/atomic/mod.rs":"d37c5edec55b31dacf0f97f28cee8f91b06c551f04582e70aea6aea91390aa25","src/cache_padded.rs":"95b10657b4e50316d2213894e195c61602ff0c6655cc965301de1584fb7d61c7","src/lib.rs":"2459c04964ec61aff53201e941b3086c903bb3c651825efb4978ff5173478781","src/sync/mod.rs":"d37870028432ad0c3c7fa82d0ee99b3f4bdd9a8410a0a4255a80fe7cc8bdcf38","src/sync/parker.rs":"55324bbea5b7c6838a0f8467a5b8a5dbd5526c8e1c7fd4f6d64dad1ab19f9be9","src/thread.rs":"c01d49383e773fedac9abec3cfb008caec13f959a78f3ddcbf282f32ebecadd7","tests/atomic_cell.rs":"690f516c7e827b18adec5da1c3249ebb26ff674c5887d863ddc94fe1600b9c28","tests/cache_padded.rs":"02235757a554279dae5053d46314a765059ec036c63a05336353994c2aa344d1","tests/parker.rs":"996212c084286567638919c27d46a250a5d592d8e1a97c1e6a4d7e10c060e4dd","tests/thread.rs":"0d86998085a8aace79e5b3dae61aa8bd864492f44aafcce6ec85778954f55809"},"package":"41ee4864f4797060e52044376f7d107429ce1fb43460021b126424b7180ee21a"}
\ No newline at end of file
--- a/third_party/rust/crossbeam-utils/CHANGELOG.md
+++ b/third_party/rust/crossbeam-utils/CHANGELOG.md
@@ -1,59 +1,79 @@
-# Changelog
-All notable changes to this project will be documented in this file.
+# Version 0.6.3
+
+- Add `AtomicCell`.
+- Improve documentation.
+
+# Version 0.6.2
+
+- Add `Parker`.
+- Improve documentation.
+
+# Version 0.6.1
+
+- Fix a soundness bug in `Scope::spawn()`.
+- Remove the `T: 'scope` bound on `ScopedJoinHandle`.
+ 
+# Version 0.6.0
 
-The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
-and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+- Move `AtomicConsume` to `atomic` module.
+- `scope()` returns a `Result` of thread joins.
+- Remove `spawn_unchecked`.
+- Fix a soundness bug due to incorrect lifetimes.
+- Improve documentation.
+- Support nested scoped spawns.
+- Implement `Copy`, `Hash`, `PartialEq`, and `Eq` for `CachePadded`.
+- Add `CachePadded::into_inner()`.
+
+# Version 0.5.0
+
+- Reorganize sub-modules and rename functions.
 
-## [Unreleased]
+# Version 0.4.1
+
+- Fix a documentation link.
+
+# Version 0.4.0
 
-## [0.3.2] - 2018-03-12
-### Fixed
+- `CachePadded` supports types bigger than 64 bytes.
+- Fix a bug in scoped threads where unitialized memory was being dropped.
+- Minimum required Rust version is now 1.25.
+
+# Version 0.3.2
+
 - Mark `load_consume` with `#[inline]`.
 
-## [0.3.1] - 2018-03-12
-### Fixed
+# Version 0.3.1
+
 - `load_consume` on ARM and AArch64.
 
-## [0.3.0] - 2018-03-11
-### Added
-- `join` for scoped thread API.
-- `load_consume` for atomic load-consume memory ordering.
+# Version 0.3.0
 
-### Removed
-- `AtomicOption`.
+- Add `join` for scoped thread API.
+- Add `load_consume` for atomic load-consume memory ordering.
+- Remove `AtomicOption`.
 
-## [0.2.2] - 2018-01-14
-### Added
-- Support for Rust 1.12.1.
+# Version 0.2.2
 
-### Fixed
+- Support Rust 1.12.1.
 - Call `T::clone` when cloning a `CachePadded<T>`.
 
-## [0.2.1] - 2017-11-26
-### Added
+# Version 0.2.1
+
 - Add `use_std` feature.
 
-## [0.2.0] - 2017-11-17
-### Added
+# Version 0.2.0
+
 - Add `nightly` feature.
 - Use `repr(align(64))` on `CachePadded` with the `nightly` feature.
 - Implement `Drop` for `CachePadded<T>`.
 - Implement `Clone` for `CachePadded<T>`.
 - Implement `From<T>` for `CachePadded<T>`.
 - Implement better `Debug` for `CachePadded<T>`.
 - Write more tests.
 - Add this changelog.
-
-### Changed
 - Change cache line length to 64 bytes.
-
-### Removed
 - Remove `ZerosValid`.
 
-## 0.1.0 - 2017-08-27
-### Added
-- Old implementation of `CachePadded` from `crossbeam` version 0.3.0
+# Version 0.1.0
 
-[Unreleased]: https://github.com/crossbeam-rs/crossbeam-utils/compare/v0.2.1...HEAD
-[0.2.1]: https://github.com/crossbeam-rs/crossbeam-utils/compare/v0.2.0...v0.2.1
-[0.2.0]: https://github.com/crossbeam-rs/crossbeam-utils/compare/v0.1.0...v0.2.0
+- Old implementation of `CachePadded` from `crossbeam` version 0.3.0
--- a/third_party/rust/crossbeam-utils/Cargo.toml
+++ b/third_party/rust/crossbeam-utils/Cargo.toml
@@ -7,25 +7,25 @@
 #
 # If you believe there's an error in this file please file an
 # issue against the rust-lang/cargo repository. If you're
 # editing this file be aware that the upstream Cargo.toml
 # will likely look very different (and much more reasonable)
 
 [package]
 name = "crossbeam-utils"
-version = "0.3.2"
+version = "0.6.3"
 authors = ["The Crossbeam Project Developers"]
 description = "Utilities for concurrent programming"
-homepage = "https://github.com/crossbeam-rs/crossbeam-utils"
+homepage = "https://github.com/crossbeam-rs/crossbeam"
 documentation = "https://docs.rs/crossbeam-utils"
 readme = "README.md"
 keywords = ["scoped", "thread", "atomic", "cache"]
 categories = ["algorithms", "concurrency", "data-structures"]
 license = "MIT/Apache-2.0"
-repository = "https://github.com/crossbeam-rs/crossbeam-utils"
+repository = "https://github.com/crossbeam-rs/crossbeam"
 [dependencies.cfg-if]
 version = "0.1"
 
 [features]
-default = ["use_std"]
+default = ["std"]
 nightly = []
-use_std = []
+std = []
--- a/third_party/rust/crossbeam-utils/LICENSE-MIT
+++ b/third_party/rust/crossbeam-utils/LICENSE-MIT
@@ -1,10 +1,8 @@
-Copyright (c) 2010 The Rust Project Developers
-
 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
--- a/third_party/rust/crossbeam-utils/README.md
+++ b/third_party/rust/crossbeam-utils/README.md
@@ -1,29 +1,57 @@
-# Utilities for concurrent programming
+# Crossbeam Utils
 
-[![Build Status](https://travis-ci.org/crossbeam-rs/crossbeam-utils.svg?branch=master)](https://travis-ci.org/crossbeam-rs/crossbeam-utils)
-[![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)](https://github.com/crossbeam-rs/crossbeam-utils)
-[![Cargo](https://img.shields.io/crates/v/crossbeam-utils.svg)](https://crates.io/crates/crossbeam-utils)
-[![Documentation](https://docs.rs/crossbeam-utils/badge.svg)](https://docs.rs/crossbeam-utils)
+[![Build Status](https://travis-ci.org/crossbeam-rs/crossbeam.svg?branch=master)](
+https://travis-ci.org/crossbeam-rs/crossbeam)
+[![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)](
+https://github.com/crossbeam-rs/crossbeam-utils/tree/master/src)
+[![Cargo](https://img.shields.io/crates/v/crossbeam-utils.svg)](
+https://crates.io/crates/crossbeam-utils)
+[![Documentation](https://docs.rs/crossbeam-utils/badge.svg)](
+https://docs.rs/crossbeam-utils)
+[![Rust 1.26+](https://img.shields.io/badge/rust-1.26+-lightgray.svg)](
+https://www.rust-lang.org)
 
-This crate provides utilities for concurrent programming.
+This crate provides miscellaneous utilities for concurrent programming:
+
+* `AtomicConsume` allows reading from primitive atomic types with "consume" ordering.
+* `CachePadded<T>` pads and aligns a value to the length of a cache line.
+* `scope()` can spawn threads that borrow local variables from the stack. 
 
 ## Usage
 
 Add this to your `Cargo.toml`:
 
 ```toml
 [dependencies]
-crossbeam-utils = "0.2"
+crossbeam-utils = "0.6"
 ```
 
 Next, add this to your crate:
 
 ```rust
 extern crate crossbeam_utils;
 ```
 
+## Compatibility
+
+The minimum supported Rust version is 1.26.
+
+Features available in `no_std` environments:
+
+* `AtomicConsume`
+* `CachePadded<T>`
+
 ## License
 
-Licensed under the terms of MIT license and the Apache License (Version 2.0).
+Licensed under either of
+
+ * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
+ * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
 
-See [LICENSE-MIT](LICENSE-MIT) and [LICENSE-APACHE](LICENSE-APACHE) for details.
+at your option.
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
+dual licensed as above, without any additional terms or conditions.
new file mode 100755
--- /dev/null
+++ b/third_party/rust/crossbeam-utils/benches/atomic_cell.rs
@@ -0,0 +1,155 @@
+#![feature(test)]
+
+extern crate crossbeam_utils;
+extern crate test;
+
+use std::sync::Barrier;
+
+use crossbeam_utils::atomic::AtomicCell;
+use crossbeam_utils::thread;
+
+#[bench]
+fn load_u8(b: &mut test::Bencher) {
+    let a = AtomicCell::new(0u8);
+    let mut sum = 0;
+    b.iter(|| sum += a.load());
+    test::black_box(sum);
+}
+
+#[bench]
+fn store_u8(b: &mut test::Bencher) {
+    let a = AtomicCell::new(0u8);
+    b.iter(|| a.store(1));
+}
+
+#[bench]
+fn fetch_add_u8(b: &mut test::Bencher) {
+    let a = AtomicCell::new(0u8);
+    b.iter(|| a.fetch_add(1));
+}
+
+#[bench]
+fn compare_and_swap_u8(b: &mut test::Bencher) {
+    let a = AtomicCell::new(0u8);
+    let mut i = 0;
+    b.iter(|| {
+        a.compare_and_swap(i, i.wrapping_add(1));
+        i = i.wrapping_add(1);
+    });
+}
+
+#[bench]
+fn concurrent_load_u8(b: &mut test::Bencher) {
+    const THREADS: usize = 2;
+    const STEPS: usize = 1_000_000;
+
+    let start = Barrier::new(THREADS + 1);
+    let end = Barrier::new(THREADS + 1);
+    let exit = AtomicCell::new(false);
+
+    let a = AtomicCell::new(0u8);
+
+    thread::scope(|scope| {
+        for _ in 0..THREADS {
+            scope.spawn(|| loop {
+                start.wait();
+
+                let mut sum = 0;
+                for _ in 0..STEPS {
+                    sum += a.load();
+                }
+                test::black_box(sum);
+
+                end.wait();
+                if exit.load() {
+                    break;
+                }
+            });
+        }
+
+        start.wait();
+        end.wait();
+
+        b.iter(|| {
+            start.wait();
+            end.wait();
+        });
+
+        start.wait();
+        exit.store(true);
+        end.wait();
+    }).unwrap();
+}
+
+#[bench]
+fn load_usize(b: &mut test::Bencher) {
+    let a = AtomicCell::new(0usize);
+    let mut sum = 0;
+    b.iter(|| sum += a.load());
+    test::black_box(sum);
+}
+
+#[bench]
+fn store_usize(b: &mut test::Bencher) {
+    let a = AtomicCell::new(0usize);
+    b.iter(|| a.store(1));
+}
+
+#[bench]
+fn fetch_add_usize(b: &mut test::Bencher) {
+    let a = AtomicCell::new(0usize);
+    b.iter(|| a.fetch_add(1));
+}
+
+#[bench]
+fn compare_and_swap_usize(b: &mut test::Bencher) {
+    let a = AtomicCell::new(0usize);
+    let mut i = 0;
+    b.iter(|| {
+        a.compare_and_swap(i, i.wrapping_add(1));
+        i = i.wrapping_add(1);
+    });
+}
+
+#[bench]
+fn concurrent_load_usize(b: &mut test::Bencher) {
+    const THREADS: usize = 2;
+    const STEPS: usize = 1_000_000;
+
+    let start = Barrier::new(THREADS + 1);
+    let end = Barrier::new(THREADS + 1);
+    let exit = AtomicCell::new(false);
+
+    let a = AtomicCell::new(0usize);
+
+    thread::scope(|scope| {
+        for _ in 0..THREADS {
+            scope.spawn(|| loop {
+                start.wait();
+
+                let mut sum = 0;
+                for _ in 0..STEPS {
+                    sum += a.load();
+                }
+                test::black_box(sum);
+
+                end.wait();
+                if exit.load() {
+                    break;
+                }
+            });
+        }
+
+        start.wait();
+        end.wait();
+
+        b.iter(|| {
+            start.wait();
+            end.wait();
+        });
+
+        start.wait();
+        exit.store(true);
+        end.wait();
+    }).unwrap();
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/crossbeam-utils/src/atomic/atomic_cell.rs
@@ -0,0 +1,904 @@
+use core::cell::UnsafeCell;
+use core::fmt;
+use core::mem;
+use core::ptr;
+use core::slice;
+use core::sync::atomic::{self, AtomicBool, AtomicUsize, Ordering};
+
+/// A thread-safe mutable memory location.
+///
+/// This type is equivalent to [`Cell`], except it can also be shared among multiple threads.
+///
+/// Operations on `AtomicCell`s use atomic instructions whenever possible, and synchronize using
+/// global locks otherwise. You can call [`AtomicCell::<T>::is_lock_free()`] to check whether
+/// atomic instructions or locks will be used.
+///
+/// [`Cell`]: https://doc.rust-lang.org/std/cell/struct.Cell.html
+/// [`AtomicCell::<T>::is_lock_free()`]: struct.AtomicCell.html#method.is_lock_free
+pub struct AtomicCell<T> {
+    /// The inner value.
+    ///
+    /// If this value can be transmuted into a primitive atomic type, it will be treated as such.
+    /// Otherwise, all potentially concurrent operations on this data will be protected by a global
+    /// lock.
+    value: UnsafeCell<T>,
+}
+
+unsafe impl<T: Send> Send for AtomicCell<T> {}
+unsafe impl<T: Send> Sync for AtomicCell<T> {}
+
+impl<T> AtomicCell<T> {
+    /// Creates a new atomic cell initialized with `val`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use crossbeam_utils::atomic::AtomicCell;
+    ///
+    /// let a = AtomicCell::new(7);
+    /// ```
+    pub fn new(val: T) -> AtomicCell<T> {
+        AtomicCell {
+            value: UnsafeCell::new(val),
+        }
+    }
+
+    /// Returns a mutable reference to the inner value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use crossbeam_utils::atomic::AtomicCell;
+    ///
+    /// let mut a = AtomicCell::new(7);
+    /// *a.get_mut() += 1;
+    ///
+    /// assert_eq!(a.load(), 8);
+    /// ```
+    pub fn get_mut(&mut self) -> &mut T {
+        unsafe { &mut *self.value.get() }
+    }
+
+    /// Unwraps the atomic cell and returns its inner value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use crossbeam_utils::atomic::AtomicCell;
+    ///
+    /// let mut a = AtomicCell::new(7);
+    /// let v = a.into_inner();
+    ///
+    /// assert_eq!(v, 7);
+    /// ```
+    pub fn into_inner(self) -> T {
+        self.value.into_inner()
+    }
+
+    /// Returns `true` if operations on values of this type are lock-free.
+    ///
+    /// If the compiler or the platform doesn't support the necessary atomic instructions,
+    /// `AtomicCell<T>` will use global locks for every potentially concurrent atomic operation.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use crossbeam_utils::atomic::AtomicCell;
+    ///
+    /// // This type is internally represented as `AtomicUsize` so we can just use atomic
+    /// // operations provided by it.
+    /// assert_eq!(AtomicCell::<usize>::is_lock_free(), true);
+    ///
+    /// // A wrapper struct around `isize`.
+    /// struct Foo {
+    ///     bar: isize,
+    /// }
+    /// // `AtomicCell<Foo>` will be internally represented as `AtomicIsize`.
+    /// assert_eq!(AtomicCell::<Foo>::is_lock_free(), true);
+    ///
+    /// // Operations on zero-sized types are always lock-free.
+    /// assert_eq!(AtomicCell::<()>::is_lock_free(), true);
+    ///
+    /// // Very large types cannot be represented as any of the standard atomic types, so atomic
+    /// // operations on them will have to use global locks for synchronization.
+    /// assert_eq!(AtomicCell::<[u8; 1000]>::is_lock_free(), false);
+    /// ```
+    pub fn is_lock_free() -> bool {
+        atomic_is_lock_free::<T>()
+    }
+
+    /// Stores `val` into the atomic cell.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use crossbeam_utils::atomic::AtomicCell;
+    ///
+    /// let a = AtomicCell::new(7);
+    ///
+    /// assert_eq!(a.load(), 7);
+    /// a.store(8);
+    /// assert_eq!(a.load(), 8);
+    /// ```
+    pub fn store(&self, val: T) {
+        if mem::needs_drop::<T>() {
+            drop(self.swap(val));
+        } else {
+            unsafe {
+                atomic_store(self.value.get(), val);
+            }
+        }
+    }
+
+    /// Stores `val` into the atomic cell and returns the previous value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use crossbeam_utils::atomic::AtomicCell;
+    ///
+    /// let a = AtomicCell::new(7);
+    ///
+    /// assert_eq!(a.load(), 7);
+    /// assert_eq!(a.swap(8), 7);
+    /// assert_eq!(a.load(), 8);
+    /// ```
+    pub fn swap(&self, val: T) -> T {
+        unsafe { atomic_swap(self.value.get(), val) }
+    }
+}
+
+impl<T: Copy> AtomicCell<T> {
+    /// Loads a value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use crossbeam_utils::atomic::AtomicCell;
+    ///
+    /// let a = AtomicCell::new(7);
+    ///
+    /// assert_eq!(a.load(), 7);
+    /// ```
+    pub fn load(&self) -> T {
+        unsafe { atomic_load(self.value.get()) }
+    }
+}
+
+impl<T: Copy + Eq> AtomicCell<T> {
+    /// If the current value equals `current`, stores `new` into the atomic cell.
+    ///
+    /// The return value is always the previous value. If it is equal to `current`, then the value
+    /// was updated.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use crossbeam_utils::atomic::AtomicCell;
+    ///
+    /// let a = AtomicCell::new(1);
+    ///
+    /// assert_eq!(a.compare_exchange(2, 3), Err(1));
+    /// assert_eq!(a.load(), 1);
+    ///
+    /// assert_eq!(a.compare_exchange(1, 2), Ok(1));
+    /// assert_eq!(a.load(), 2);
+    /// ```
+    pub fn compare_and_swap(&self, current: T, new: T) -> T {
+        match self.compare_exchange(current, new) {
+            Ok(v) => v,
+            Err(v) => v,
+        }
+    }
+
+    /// If the current value equals `current`, stores `new` into the atomic cell.
+    ///
+    /// The return value is a result indicating whether the new value was written and containing
+    /// the previous value. On success this value is guaranteed to be equal to `current`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use crossbeam_utils::atomic::AtomicCell;
+    ///
+    /// let a = AtomicCell::new(1);
+    ///
+    /// assert_eq!(a.compare_exchange(2, 3), Err(1));
+    /// assert_eq!(a.load(), 1);
+    ///
+    /// assert_eq!(a.compare_exchange(1, 2), Ok(1));
+    /// assert_eq!(a.load(), 2);
+    /// ```
+    pub fn compare_exchange(&self, mut current: T, new: T) -> Result<T, T> {
+        loop {
+            match unsafe { atomic_compare_exchange_weak(self.value.get(), current, new) } {
+                Ok(_) => return Ok(current),
+                Err(previous) => {
+                    if previous != current {
+                        return Err(previous);
+                    }
+
+                    // The compare-exchange operation has failed and didn't store `new`. The
+                    // failure is either spurious, or `previous` was semantically equal to
+                    // `current` but not byte-equal. Let's retry with `previous` as the new
+                    // `current`.
+                    current = previous;
+                }
+            }
+        }
+    }
+}
+
+macro_rules! impl_arithmetic {
+    ($t:ty, $example:tt) => {
+        impl AtomicCell<$t> {
+            /// Increments the current value by `val` and returns the previous value.
+            ///
+            /// The addition wraps on overflow.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// use crossbeam_utils::atomic::AtomicCell;
+            ///
+            #[doc = $example]
+            ///
+            /// assert_eq!(a.fetch_add(3), 7);
+            /// assert_eq!(a.load(), 10);
+            /// ```
+            #[inline]
+            pub fn fetch_add(&self, val: $t) -> $t {
+                if can_transmute::<$t, atomic::AtomicUsize>() {
+                    let a = unsafe { &*(self.value.get() as *const atomic::AtomicUsize) };
+                    a.fetch_add(val as usize, Ordering::SeqCst) as $t
+                } else {
+                    let _guard = lock(self.value.get() as usize).write();
+                    let value = unsafe { &mut *(self.value.get()) };
+                    let old = *value;
+                    *value = value.wrapping_add(val);
+                    old
+                }
+            }
+
+            /// Decrements the current value by `val` and returns the previous value.
+            ///
+            /// The subtraction wraps on overflow.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// use crossbeam_utils::atomic::AtomicCell;
+            ///
+            #[doc = $example]
+            ///
+            /// assert_eq!(a.fetch_sub(3), 7);
+            /// assert_eq!(a.load(), 4);
+            /// ```
+            #[inline]
+            pub fn fetch_sub(&self, val: $t) -> $t {
+                if can_transmute::<$t, atomic::AtomicUsize>() {
+                    let a = unsafe { &*(self.value.get() as *const atomic::AtomicUsize) };
+                    a.fetch_sub(val as usize, Ordering::SeqCst) as $t
+                } else {
+                    let _guard = lock(self.value.get() as usize).write();
+                    let value = unsafe { &mut *(self.value.get()) };
+                    let old = *value;
+                    *value = value.wrapping_sub(val);
+                    old
+                }
+            }
+
+            /// Applies bitwise "and" to the current value and returns the previous value.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// use crossbeam_utils::atomic::AtomicCell;
+            ///
+            #[doc = $example]
+            ///
+            /// assert_eq!(a.fetch_and(3), 7);
+            /// assert_eq!(a.load(), 3);
+            /// ```
+            #[inline]
+            pub fn fetch_and(&self, val: $t) -> $t {
+                if can_transmute::<$t, atomic::AtomicUsize>() {
+                    let a = unsafe { &*(self.value.get() as *const atomic::AtomicUsize) };
+                    a.fetch_and(val as usize, Ordering::SeqCst) as $t
+                } else {
+                    let _guard = lock(self.value.get() as usize).write();
+                    let value = unsafe { &mut *(self.value.get()) };
+                    let old = *value;
+                    *value &= val;
+                    old
+                }
+            }
+
+            /// Applies bitwise "or" to the current value and returns the previous value.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// use crossbeam_utils::atomic::AtomicCell;
+            ///
+            #[doc = $example]
+            ///
+            /// assert_eq!(a.fetch_or(16), 7);
+            /// assert_eq!(a.load(), 23);
+            /// ```
+            #[inline]
+            pub fn fetch_or(&self, val: $t) -> $t {
+                if can_transmute::<$t, atomic::AtomicUsize>() {
+                    let a = unsafe { &*(self.value.get() as *const atomic::AtomicUsize) };
+                    a.fetch_or(val as usize, Ordering::SeqCst) as $t
+                } else {
+                    let _guard = lock(self.value.get() as usize).write();
+                    let value = unsafe { &mut *(self.value.get()) };
+                    let old = *value;
+                    *value |= val;
+                    old
+                }
+            }
+
+            /// Applies bitwise "xor" to the current value and returns the previous value.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// use crossbeam_utils::atomic::AtomicCell;
+            ///
+            #[doc = $example]
+            ///
+            /// assert_eq!(a.fetch_xor(2), 7);
+            /// assert_eq!(a.load(), 5);
+            /// ```
+            #[inline]
+            pub fn fetch_xor(&self, val: $t) -> $t {
+                if can_transmute::<$t, atomic::AtomicUsize>() {
+                    let a = unsafe { &*(self.value.get() as *const atomic::AtomicUsize) };
+                    a.fetch_xor(val as usize, Ordering::SeqCst) as $t
+                } else {
+                    let _guard = lock(self.value.get() as usize).write();
+                    let value = unsafe { &mut *(self.value.get()) };
+                    let old = *value;
+                    *value ^= val;
+                    old
+                }
+            }
+        }
+    };
+    ($t:ty, $atomic:ty, $example:tt) => {
+        impl AtomicCell<$t> {
+            /// Increments the current value by `val` and returns the previous value.
+            ///
+            /// The addition wraps on overflow.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// use crossbeam_utils::atomic::AtomicCell;
+            ///
+            #[doc = $example]
+            ///
+            /// assert_eq!(a.fetch_add(3), 7);
+            /// assert_eq!(a.load(), 10);
+            /// ```
+            #[inline]
+            pub fn fetch_add(&self, val: $t) -> $t {
+                let a = unsafe { &*(self.value.get() as *const $atomic) };
+                a.fetch_add(val, Ordering::SeqCst)
+            }
+
+            /// Decrements the current value by `val` and returns the previous value.
+            ///
+            /// The subtraction wraps on overflow.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// use crossbeam_utils::atomic::AtomicCell;
+            ///
+            #[doc = $example]
+            ///
+            /// assert_eq!(a.fetch_sub(3), 7);
+            /// assert_eq!(a.load(), 4);
+            /// ```
+            #[inline]
+            pub fn fetch_sub(&self, val: $t) -> $t {
+                let a = unsafe { &*(self.value.get() as *const $atomic) };
+                a.fetch_sub(val, Ordering::SeqCst)
+            }
+
+            /// Applies bitwise "and" to the current value and returns the previous value.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// use crossbeam_utils::atomic::AtomicCell;
+            ///
+            #[doc = $example]
+            ///
+            /// assert_eq!(a.fetch_and(3), 7);
+            /// assert_eq!(a.load(), 3);
+            /// ```
+            #[inline]
+            pub fn fetch_and(&self, val: $t) -> $t {
+                let a = unsafe { &*(self.value.get() as *const $atomic) };
+                a.fetch_and(val, Ordering::SeqCst)
+            }
+
+            /// Applies bitwise "or" to the current value and returns the previous value.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// use crossbeam_utils::atomic::AtomicCell;
+            ///
+            #[doc = $example]
+            ///
+            /// assert_eq!(a.fetch_or(16), 7);
+            /// assert_eq!(a.load(), 23);
+            /// ```
+            #[inline]
+            pub fn fetch_or(&self, val: $t) -> $t {
+                let a = unsafe { &*(self.value.get() as *const $atomic) };
+                a.fetch_or(val, Ordering::SeqCst)
+            }
+
+            /// Applies bitwise "xor" to the current value and returns the previous value.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// use crossbeam_utils::atomic::AtomicCell;
+            ///
+            #[doc = $example]
+            ///
+            /// assert_eq!(a.fetch_xor(2), 7);
+            /// assert_eq!(a.load(), 5);
+            /// ```
+            #[inline]
+            pub fn fetch_xor(&self, val: $t) -> $t {
+                let a = unsafe { &*(self.value.get() as *const $atomic) };
+                a.fetch_xor(val, Ordering::SeqCst)
+            }
+        }
+    };
+}
+
+cfg_if! {
+    if #[cfg(feature = "nightly")] {
+        impl_arithmetic!(u8, atomic::AtomicU8, "let a = AtomicCell::new(7u8);");
+        impl_arithmetic!(i8, atomic::AtomicI8, "let a = AtomicCell::new(7i8);");
+        impl_arithmetic!(u16, atomic::AtomicU16, "let a = AtomicCell::new(7u16);");
+        impl_arithmetic!(i16, atomic::AtomicI16, "let a = AtomicCell::new(7i16);");
+        impl_arithmetic!(u32, atomic::AtomicU32, "let a = AtomicCell::new(7u32);");
+        impl_arithmetic!(i32, atomic::AtomicI32, "let a = AtomicCell::new(7i32);");
+        impl_arithmetic!(u64, atomic::AtomicU64, "let a = AtomicCell::new(7u64);");
+        impl_arithmetic!(i64, atomic::AtomicI64, "let a = AtomicCell::new(7i64);");
+    } else {
+        impl_arithmetic!(u8, "let a = AtomicCell::new(7u8);");
+        impl_arithmetic!(i8, "let a = AtomicCell::new(7i8);");
+        impl_arithmetic!(u16, "let a = AtomicCell::new(7u16);");
+        impl_arithmetic!(i16, "let a = AtomicCell::new(7i16);");
+        impl_arithmetic!(u32, "let a = AtomicCell::new(7u32);");
+        impl_arithmetic!(i32, "let a = AtomicCell::new(7i32);");
+        impl_arithmetic!(u64, "let a = AtomicCell::new(7u64);");
+        impl_arithmetic!(i64, "let a = AtomicCell::new(7i64);");
+    }
+}
+
+impl_arithmetic!(
+    usize,
+    atomic::AtomicUsize,
+    "let a = AtomicCell::new(7usize);"
+);
+impl_arithmetic!(
+    isize,
+    atomic::AtomicIsize,
+    "let a = AtomicCell::new(7isize);"
+);
+
+impl AtomicCell<bool> {
+    /// Applies logical "and" to the current value and returns the previous value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use crossbeam_utils::atomic::AtomicCell;
+    ///
+    /// let a = AtomicCell::new(true);
+    ///
+    /// assert_eq!(a.fetch_and(true), true);
+    /// assert_eq!(a.load(), true);
+    ///
+    /// assert_eq!(a.fetch_and(false), true);
+    /// assert_eq!(a.load(), false);
+    /// ```
+    #[inline]
+    pub fn fetch_and(&self, val: bool) -> bool {
+        let a = unsafe { &*(self.value.get() as *const AtomicBool) };
+        a.fetch_and(val, Ordering::SeqCst)
+    }
+
+    /// Applies logical "or" to the current value and returns the previous value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use crossbeam_utils::atomic::AtomicCell;
+    ///
+    /// let a = AtomicCell::new(false);
+    ///
+    /// assert_eq!(a.fetch_or(false), false);
+    /// assert_eq!(a.load(), false);
+    ///
+    /// assert_eq!(a.fetch_or(true), false);
+    /// assert_eq!(a.load(), true);
+    /// ```
+    #[inline]
+    pub fn fetch_or(&self, val: bool) -> bool {
+        let a = unsafe { &*(self.value.get() as *const AtomicBool) };
+        a.fetch_or(val, Ordering::SeqCst)
+    }
+
+    /// Applies logical "xor" to the current value and returns the previous value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use crossbeam_utils::atomic::AtomicCell;
+    ///
+    /// let a = AtomicCell::new(true);
+    ///
+    /// assert_eq!(a.fetch_xor(false), true);
+    /// assert_eq!(a.load(), true);
+    ///
+    /// assert_eq!(a.fetch_xor(true), true);
+    /// assert_eq!(a.load(), false);
+    /// ```
+    #[inline]
+    pub fn fetch_xor(&self, val: bool) -> bool {
+        let a = unsafe { &*(self.value.get() as *const AtomicBool) };
+        a.fetch_xor(val, Ordering::SeqCst)
+    }
+}
+
+impl<T: Default> Default for AtomicCell<T> {
+    fn default() -> AtomicCell<T> {
+        AtomicCell::new(T::default())
+    }
+}
+
+impl<T: Copy + fmt::Debug> fmt::Debug for AtomicCell<T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("AtomicCell")
+            .field("value", &self.load())
+            .finish()
+    }
+}
+
+/// Returns `true` if the two values are equal byte-for-byte.
+fn byte_eq<T>(a: &T, b: &T) -> bool {
+    unsafe {
+        let a = slice::from_raw_parts(a as *const _ as *const u8, mem::size_of::<T>());
+        let b = slice::from_raw_parts(b as *const _ as *const u8, mem::size_of::<T>());
+        a == b
+    }
+}
+
+/// Returns `true` if values of type `A` can be transmuted into values of type `B`.
+fn can_transmute<A, B>() -> bool {
+    // Sizes must be equal, but alignment of `A` must be greater or equal than that of `B`.
+    mem::size_of::<A>() == mem::size_of::<B>() && mem::align_of::<A>() >= mem::align_of::<B>()
+}
+
+/// A simple stamped lock.
+struct Lock {
+    /// The current state of the lock.
+    ///
+    /// All bits except the least significant one hold the current stamp. When locked, the state
+    /// equals 1 and doesn't contain a valid stamp.
+    state: AtomicUsize,
+}
+
+impl Lock {
+    /// If not locked, returns the current stamp.
+    ///
+    /// This method should be called before optimistic reads.
+    #[inline]
+    fn optimistic_read(&self) -> Option<usize> {
+        let state = self.state.load(Ordering::Acquire);
+        if state == 1 {
+            None
+        } else {
+            Some(state)
+        }
+    }
+
+    /// Returns `true` if the current stamp is equal to `stamp`.
+    ///
+    /// This method should be called after optimistic reads to check whether they are valid. The
+    /// argument `stamp` should correspond to the one returned by method `optimistic_read`.
+    #[inline]
+    fn validate_read(&self, stamp: usize) -> bool {
+        atomic::fence(Ordering::Acquire);
+        self.state.load(Ordering::Relaxed) == stamp
+    }
+
+    /// Grabs the lock for writing.
+    #[inline]
+    fn write(&'static self) -> WriteGuard {
+        let mut step = 0usize;
+
+        loop {
+            let previous = self.state.swap(1, Ordering::Acquire);
+
+            if previous != 1 {
+                atomic::fence(Ordering::Release);
+
+                return WriteGuard {
+                    lock: self,
+                    state: previous,
+                };
+            }
+
+            if step < 10 {
+                atomic::spin_loop_hint();
+            } else {
+                #[cfg(not(feature = "std"))]
+                atomic::spin_loop_hint();
+
+                #[cfg(feature = "std")]
+                ::std::thread::yield_now();
+            }
+
+            step = step.wrapping_add(1);
+        }
+    }
+}
+
+/// A RAII guard that releases the lock and increments the stamp when dropped.
+struct WriteGuard {
+    /// The parent lock.
+    lock: &'static Lock,
+
+    /// The stamp before locking.
+    state: usize,
+}
+
+impl WriteGuard {
+    /// Releases the lock without incrementing the stamp.
+    #[inline]
+    fn abort(self) {
+        self.lock.state.store(self.state, Ordering::Release);
+    }
+}
+
+impl Drop for WriteGuard {
+    #[inline]
+    fn drop(&mut self) {
+        // Release the lock and increment the stamp.
+        self.lock
+            .state
+            .store(self.state.wrapping_add(2), Ordering::Release);
+    }
+}
+
+/// Returns a reference to the global lock associated with the `AtomicCell` at address `addr`.
+///
+/// This function is used to protect atomic data which doesn't fit into any of the primitive atomic
+/// types in `std::sync::atomic`. Operations on such atomics must therefore use a global lock.
+///
+/// However, there is not only one global lock but an array of many locks, and one of them is
+/// picked based on the given address. Having many locks reduces contention and improves
+/// scalability.
+#[inline]
+#[must_use]
+fn lock(addr: usize) -> &'static Lock {
+    // The number of locks is prime.
+    const LEN: usize = 97;
+
+    const L: Lock = Lock {
+        state: AtomicUsize::new(0),
+    };
+    static LOCKS: [Lock; LEN] = [
+        L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L,
+        L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L,
+        L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L,
+        L, L, L, L, L, L, L,
+    ];
+
+    // If the modulus is a constant number, the compiler will use crazy math to transform this into
+    // a sequence of cheap arithmetic operations rather than using the slow modulo instruction.
+    &LOCKS[addr % LEN]
+}
+
+/// An atomic `()`.
+///
+/// All operations are noops.
+struct AtomicUnit;
+
+impl AtomicUnit {
+    #[inline]
+    fn load(&self, _order: Ordering) {}
+
+    #[inline]
+    fn store(&self, _val: (), _order: Ordering) {}
+
+    #[inline]
+    fn swap(&self, _val: (), _order: Ordering) {}
+
+    #[inline]
+    fn compare_exchange_weak(
+        &self,
+        _current: (),
+        _new: (),
+        _success: Ordering,
+        _failure: Ordering,
+    ) -> Result<(), ()> {
+        Ok(())
+    }
+}
+
+macro_rules! atomic {
+    // If values of type `$t` can be transmuted into values of the primitive atomic type `$atomic`,
+    // declares variable `$a` of type `$atomic` and executes `$atomic_op`, breaking out of the loop.
+    (@check, $t:ty, $atomic:ty, $a:ident, $atomic_op:expr) => {
+        if can_transmute::<$t, $atomic>() {
+            let $a: &$atomic;
+            break $atomic_op;
+        }
+    };
+
+    // If values of type `$t` can be transmuted into values of a primitive atomic type, declares
+    // variable `$a` of that type and executes `$atomic_op`. Otherwise, just executes
+    // `$fallback_op`.
+    ($t:ty, $a:ident, $atomic_op:expr, $fallback_op:expr) => {
+        loop {
+            atomic!(@check, $t, AtomicUnit, $a, $atomic_op);
+            atomic!(@check, $t, atomic::AtomicUsize, $a, $atomic_op);
+
+            #[cfg(feature = "nightly")]
+            {
+                #[cfg(target_has_atomic = "8")]
+                atomic!(@check, $t, atomic::AtomicU8, $a, $atomic_op);
+                #[cfg(target_has_atomic = "16")]
+                atomic!(@check, $t, atomic::AtomicU16, $a, $atomic_op);
+                #[cfg(target_has_atomic = "32")]
+                atomic!(@check, $t, atomic::AtomicU32, $a, $atomic_op);
+                #[cfg(target_has_atomic = "64")]
+                atomic!(@check, $t, atomic::AtomicU64, $a, $atomic_op);
+            }
+
+            break $fallback_op;
+        }
+    };
+}
+
+/// Returns `true` if operations on `AtomicCell<T>` are lock-free.
+fn atomic_is_lock_free<T>() -> bool {
+    atomic! { T, _a, true, false }
+}
+
+/// Atomically reads data from `src`.
+///
+/// This operation uses the `SeqCst` ordering. If possible, an atomic instructions is used, and a
+/// global lock otherwise.
+unsafe fn atomic_load<T>(src: *mut T) -> T
+where
+    T: Copy,
+{
+    atomic! {
+        T, a,
+        {
+            a = &*(src as *const _ as *const _);
+            mem::transmute_copy(&a.load(Ordering::SeqCst))
+        },
+        {
+            let lock = lock(src as usize);
+
+            // Try doing an optimistic read first.
+            if let Some(stamp) = lock.optimistic_read() {
+                // We need a volatile read here because other threads might concurrently modify the
+                // value. In theory, data races are *always* UB, even if we use volatile reads and
+                // discard the data when a data race is detected. The proper solution would be to
+                // do atomic reads and atomic writes, but we can't atomically read and write all
+                // kinds of data since `AtomicU8` is not available on stable Rust yet.
+                let val = ptr::read_volatile(src);
+
+                if lock.validate_read(stamp) {
+                    return val;
+                }
+            }
+
+            // Grab a regular write lock so that writers don't starve this load.
+            let guard = lock.write();
+            let val = ptr::read(src);
+            // The value hasn't been changed. Drop the guard without incrementing the stamp.
+            guard.abort();
+            val
+        }
+    }
+}
+
+/// Atomically writes `val` to `dst`.
+///
+/// This operation uses the `SeqCst` ordering. If possible, an atomic instructions is used, and a
+/// global lock otherwise.
+unsafe fn atomic_store<T>(dst: *mut T, val: T) {
+    atomic! {
+        T, a,
+        {
+            a = &*(dst as *const _ as *const _);
+            let res = a.store(mem::transmute_copy(&val), Ordering::SeqCst);
+            mem::forget(val);
+            res
+        },
+        {
+            let _guard = lock(dst as usize).write();
+            ptr::write(dst, val)
+        }
+    }
+}
+
+/// Atomically swaps data at `dst` with `val`.
+///
+/// This operation uses the `SeqCst` ordering. If possible, an atomic instructions is used, and a
+/// global lock otherwise.
+unsafe fn atomic_swap<T>(dst: *mut T, val: T) -> T {
+    atomic! {
+        T, a,
+        {
+            a = &*(dst as *const _ as *const _);
+            let res = mem::transmute_copy(&a.swap(mem::transmute_copy(&val), Ordering::SeqCst));
+            mem::forget(val);
+            res
+        },
+        {
+            let _guard = lock(dst as usize).write();
+            ptr::replace(dst, val)
+        }
+    }
+}
+
+/// Atomically compares data at `dst` to `current` and, if equal byte-for-byte, exchanges data at
+/// `dst` with `new`.
+///
+/// Returns the old value on success, or the current value at `dst` on failure.
+///
+/// This operation uses the `SeqCst` ordering. If possible, an atomic instructions is used, and a
+/// global lock otherwise.
+unsafe fn atomic_compare_exchange_weak<T>(dst: *mut T, current: T, new: T) -> Result<T, T>
+where
+    T: Copy,
+{
+    atomic! {
+        T, a,
+        {
+            a = &*(dst as *const _ as *const _);
+            let res = a.compare_exchange_weak(
+                mem::transmute_copy(&current),
+                mem::transmute_copy(&new),
+                Ordering::SeqCst,
+                Ordering::SeqCst,
+            );
+            match res {
+                Ok(v) => Ok(mem::transmute_copy(&v)),
+                Err(v) => Err(mem::transmute_copy(&v)),
+            }
+        },
+        {
+            let guard = lock(dst as usize).write();
+
+            if byte_eq(&*dst, &current) {
+                Ok(ptr::replace(dst, new))
+            } else {
+                let val = ptr::read(dst);
+                // The value hasn't been changed. Drop the guard without incrementing the stamp.
+                guard.abort();
+                Err(val)
+            }
+        }
+    }
+}
copy from third_party/rust/crossbeam-utils/src/consume.rs
copy to third_party/rust/crossbeam-utils/src/atomic/consume.rs
--- a/third_party/rust/crossbeam-utils/src/consume.rs
+++ b/third_party/rust/crossbeam-utils/src/atomic/consume.rs
@@ -1,13 +1,13 @@
-use core::sync::atomic::Ordering;
 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
 use core::sync::atomic::compiler_fence;
+use core::sync::atomic::Ordering;
 
-/// Trait which allows reading from an atomic type with "consume" ordering.
+/// Trait which allows reading from primitive atomic types with "consume" ordering.
 pub trait AtomicConsume {
     /// Type returned by `load_consume`.
     type Val;
 
     /// Loads a value from the atomic using a "consume" memory ordering.
     ///
     /// This is similar to the "acquire" ordering, except that an ordering is
     /// only guaranteed with operations that "depend on" the result of the load.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/crossbeam-utils/src/atomic/mod.rs
@@ -0,0 +1,7 @@
+//! Additional utilities for atomics.
+
+mod atomic_cell;
+mod consume;
+
+pub use self::atomic_cell::AtomicCell;
+pub use self::consume::AtomicConsume;
--- a/third_party/rust/crossbeam-utils/src/cache_padded.rs
+++ b/third_party/rust/crossbeam-utils/src/cache_padded.rs
@@ -1,290 +1,116 @@
 use core::fmt;
-use core::mem;
 use core::ops::{Deref, DerefMut};
-use core::ptr;
-
-
-cfg_if! {
-    if #[cfg(feature = "nightly")] {
-        // This trick allows use to support rustc 1.12.1, which does not support the
-        // #[repr(align(n))] syntax. Using the attribute makes the parser fail over.
-        // It is, however, okay to use it within a macro, since it would be parsed
-        // in a later stage, but that never occurs due to the cfg_if.
-        // TODO(Vtec234): remove this crap when we drop support for 1.12.
-        macro_rules! nightly_inner {
-            () => (
-                #[derive(Clone)]
-                #[repr(align(64))]
-                pub(crate) struct Inner<T> {
-                    value: T,
-                }
-            )
-        }
-        nightly_inner!();
-
-        impl<T> Inner<T> {
-            pub(crate) fn new(t: T) -> Inner<T> {
-                Self {
-                    value: t
-                }
-            }
-        }
-
-        impl<T> Deref for Inner<T> {
-            type Target = T;
-
-            fn deref(&self) -> &T {
-                &self.value
-            }
-        }
-
-        impl<T> DerefMut for Inner<T> {
-            fn deref_mut(&mut self) -> &mut T {
-                &mut self.value
-            }
-        }
-    } else {
-        use core::marker::PhantomData;
-
-        struct Inner<T> {
-            bytes: [u8; 64],
 
-            /// `[T; 0]` ensures alignment is at least that of `T`.
-            /// `PhantomData<T>` signals that `CachePadded<T>` contains a `T`.
-            _marker: ([T; 0], PhantomData<T>),
-        }
-
-        impl<T> Inner<T> {
-            fn new(t: T) -> Inner<T> {
-                assert!(mem::size_of::<T>() <= mem::size_of::<Self>());
-                assert!(mem::align_of::<T>() <= mem::align_of::<Self>());
-
-                unsafe {
-                    let mut inner: Self = mem::uninitialized();
-                    let p: *mut T = &mut *inner;
-                    ptr::write(p, t);
-                    inner
-                }
-            }
-        }
-
-        impl<T> Deref for Inner<T> {
-            type Target = T;
-
-            fn deref(&self) -> &T {
-                unsafe { &*(self.bytes.as_ptr() as *const T) }
-            }
-        }
-
-        impl<T> DerefMut for Inner<T> {
-            fn deref_mut(&mut self) -> &mut T {
-                unsafe { &mut *(self.bytes.as_ptr() as *mut T) }
-            }
-        }
-
-        impl<T> Drop for CachePadded<T> {
-            fn drop(&mut self) {
-                let p: *mut T = self.deref_mut();
-                unsafe {
-                    ptr::drop_in_place(p);
-                }
-            }
-        }
-
-        impl<T: Clone> Clone for Inner<T> {
-            fn clone(&self) -> Inner<T> {
-                let val = self.deref().clone();
-                Self::new(val)
-            }
-        }
-    }
-}
-
-/// Pads `T` to the length of a cache line.
+/// Pads and aligns a value to the length of a cache line.
 ///
-/// Sometimes concurrent programming requires a piece of data to be padded out to the size of a
-/// cacheline to avoid "false sharing": cache lines being invalidated due to unrelated concurrent
-/// activity. Use this type when you want to *avoid* cache locality.
+/// In concurrent programming, sometimes it is desirable to make sure commonly accessed pieces of
+/// data are not placed into the same cache line. Updating an atomic value invalides the whole
+/// cache line it belongs to, which makes the next access to the same cache line slower for other
+/// CPU cores. Use `CachePadded` to ensure updating one piece of data doesn't invalidate other
+/// cached data.
 ///
-/// At the moment, cache lines are assumed to be 64 bytes on all architectures.
+/// Cache lines are assumed to be 64 bytes on all architectures.
 ///
 /// # Size and alignment
 ///
-/// By default, the size of `CachePadded<T>` is 64 bytes. If `T` is larger than that, then
-/// `CachePadded::<T>::new` will panic. Alignment of `CachePadded<T>` is the same as that of `T`.
+/// The size of `CachePadded<T>` is the smallest multiple of 64 bytes large enough to accommodate
+/// a value of type `T`.
+///
+/// The alignment of `CachePadded<T>` is the maximum of 64 bytes and the alignment of `T`.
+///
+/// # Examples
+///
+/// Alignment and padding:
+///
+/// ```
+/// use crossbeam_utils::CachePadded;
+///
+/// let array = [CachePadded::new(1i32), CachePadded::new(2i32)];
+/// let addr1 = &*array[0] as *const i32 as usize;
+/// let addr2 = &*array[1] as *const i32 as usize;
 ///
-/// However, if the `nightly` feature is enabled, arbitrarily large types `T` can be stored inside
-/// a `CachePadded<T>`. The size will then be a multiple of 64 at least the size of `T`, and the
-/// alignment will be the maximum of 64 and the alignment of `T`.
+/// assert_eq!(addr2 - addr1, 64);
+/// assert_eq!(addr1 % 64, 0);
+/// assert_eq!(addr2 % 64, 0);
+/// ```
+///
+/// When building a concurrent queue with a head and a tail index, it is wise to place them in
+/// different cache lines so that concurrent threads pushing and popping elements don't invalidate
+/// each other's cache lines:
+///
+/// ```
+/// use crossbeam_utils::CachePadded;
+/// use std::sync::atomic::AtomicUsize;
+///
+/// struct Queue<T> {
+///     head: CachePadded<AtomicUsize>,
+///     tail: CachePadded<AtomicUsize>,
+///     buffer: *mut T,
+/// }
+/// ```
+#[derive(Clone, Copy, Default, Hash, PartialEq, Eq)]
+#[repr(align(64))]
 pub struct CachePadded<T> {
-    inner: Inner<T>,
+    value: T,
 }
 
 unsafe impl<T: Send> Send for CachePadded<T> {}
 unsafe impl<T: Sync> Sync for CachePadded<T> {}
 
 impl<T> CachePadded<T> {
-    /// Pads a value to the length of a cache line.
+    /// Pads and aligns a value to the length of a cache line.
     ///
-    /// # Panics
+    /// # Examples
+    ///
+    /// ```
+    /// use crossbeam_utils::CachePadded;
     ///
-    /// If `nightly` is not enabled and `T` is larger than 64 bytes, this function will panic.
+    /// let padded_value = CachePadded::new(1);
+    /// ```
     pub fn new(t: T) -> CachePadded<T> {
-        CachePadded::<T> { inner: Inner::new(t) }
+        CachePadded::<T> { value: t }
+    }
+
+    /// Returns the value value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use crossbeam_utils::CachePadded;
+    ///
+    /// let padded_value = CachePadded::new(7);
+    /// let value = padded_value.into_inner();
+    /// assert_eq!(value, 7);
+    /// ```
+    pub fn into_inner(self) -> T {
+        self.value
     }
 }
 
 impl<T> Deref for CachePadded<T> {
     type Target = T;
 
     fn deref(&self) -> &T {
-        self.inner.deref()
+        &self.value
     }
 }
 
 impl<T> DerefMut for CachePadded<T> {
     fn deref_mut(&mut self) -> &mut T {
-        self.inner.deref_mut()
-    }
-}
-
-impl<T: Default> Default for CachePadded<T> {
-    fn default() -> Self {
-        Self::new(Default::default())
-    }
-}
-
-impl<T: Clone> Clone for CachePadded<T> {
-    fn clone(&self) -> Self {
-        CachePadded { inner: self.inner.clone() }
+        &mut self.value
     }
 }
 
 impl<T: fmt::Debug> fmt::Debug for CachePadded<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        let inner: &T = &*self;
-        write!(f, "CachePadded {{ {:?} }}", inner)
+        f.debug_struct("CachePadded")
+            .field("value", &self.value)
+            .finish()
     }
 }
 
 impl<T> From<T> for CachePadded<T> {
     fn from(t: T) -> Self {
         CachePadded::new(t)
     }
 }
-
-#[cfg(test)]
-mod test {
-    use super::*;
-    use std::cell::Cell;
-
-    #[test]
-    fn store_u64() {
-        let x: CachePadded<u64> = CachePadded::new(17);
-        assert_eq!(*x, 17);
-    }
-
-    #[test]
-    fn store_pair() {
-        let x: CachePadded<(u64, u64)> = CachePadded::new((17, 37));
-        assert_eq!(x.0, 17);
-        assert_eq!(x.1, 37);
-    }
-
-    #[test]
-    fn distance() {
-        let arr = [CachePadded::new(17u8), CachePadded::new(37u8)];
-        let a = &*arr[0] as *const u8;
-        let b = &*arr[1] as *const u8;
-        assert!(unsafe { a.offset(64) } <= b);
-    }
-
-    #[test]
-    fn different_sizes() {
-        CachePadded::new(17u8);
-        CachePadded::new(17u16);
-        CachePadded::new(17u32);
-        CachePadded::new([17u64; 0]);
-        CachePadded::new([17u64; 1]);
-        CachePadded::new([17u64; 2]);
-        CachePadded::new([17u64; 3]);
-        CachePadded::new([17u64; 4]);
-        CachePadded::new([17u64; 5]);
-        CachePadded::new([17u64; 6]);
-        CachePadded::new([17u64; 7]);
-        CachePadded::new([17u64; 8]);
-    }
-
-    cfg_if! {
-        if #[cfg(feature = "nightly")] {
-            #[test]
-            fn large() {
-                let a = [17u64; 9];
-                let b = CachePadded::new(a);
-                assert!(mem::size_of_val(&a) <= mem::size_of_val(&b));
-            }
-        } else {
-            #[test]
-            #[should_panic]
-            fn large() {
-                CachePadded::new([17u64; 9]);
-            }
-        }
-    }
-
-    #[test]
-    fn debug() {
-        assert_eq!(
-            format!("{:?}", CachePadded::new(17u64)),
-            "CachePadded { 17 }"
-        );
-    }
-
-    #[test]
-    fn drops() {
-        let count = Cell::new(0);
-
-        struct Foo<'a>(&'a Cell<usize>);
-
-        impl<'a> Drop for Foo<'a> {
-            fn drop(&mut self) {
-                self.0.set(self.0.get() + 1);
-            }
-        }
-
-        let a = CachePadded::new(Foo(&count));
-        let b = CachePadded::new(Foo(&count));
-
-        assert_eq!(count.get(), 0);
-        drop(a);
-        assert_eq!(count.get(), 1);
-        drop(b);
-        assert_eq!(count.get(), 2);
-    }
-
-    #[test]
-    fn clone() {
-        let a = CachePadded::new(17);
-        let b = a.clone();
-        assert_eq!(*a, *b);
-    }
-
-    #[test]
-    fn runs_custom_clone() {
-        let count = Cell::new(0);
-
-        struct Foo<'a>(&'a Cell<usize>);
-
-        impl<'a> Clone for Foo<'a> {
-            fn clone(&self) -> Foo<'a> {
-                self.0.set(self.0.get() + 1);
-                Foo::<'a>(self.0)
-            }
-        }
-
-        let a = CachePadded::new(Foo(&count));
-        a.clone();
-
-        assert_eq!(count.get(), 1);
-    }
-}
--- a/third_party/rust/crossbeam-utils/src/lib.rs
+++ b/third_party/rust/crossbeam-utils/src/lib.rs
@@ -1,14 +1,36 @@
-#![cfg_attr(feature = "nightly",
-            feature(attr_literals, repr_align, cfg_target_has_atomic, integer_atomics))]
-#![cfg_attr(not(feature = "use_std"), no_std)]
+//! Utilities for concurrent programming.
 
-#[cfg(feature = "use_std")]
-extern crate core;
+#![warn(missing_docs)]
+#![warn(missing_debug_implementations)]
+#![cfg_attr(not(feature = "std"), no_std)]
+#![cfg_attr(feature = "nightly", feature(alloc))]
+#![cfg_attr(feature = "nightly", feature(cfg_target_has_atomic))]
+#![cfg_attr(feature = "nightly", feature(integer_atomics))]
 
 #[macro_use]
 extern crate cfg_if;
+#[cfg(feature = "std")]
+extern crate core;
 
-pub mod cache_padded;
-#[cfg(feature = "use_std")]
-pub mod scoped;
-pub mod consume;
+cfg_if! {
+    if #[cfg(feature = "nightly")] {
+        extern crate alloc;
+    } else {
+        mod alloc {
+            extern crate std;
+            pub use self::std::*;
+        }
+    }
+}
+
+pub mod atomic;
+
+mod cache_padded;
+pub use cache_padded::CachePadded;
+
+cfg_if! {
+    if #[cfg(feature = "std")] {
+        pub mod sync;
+        pub mod thread;
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/crossbeam-utils/src/sync/mod.rs
@@ -0,0 +1,5 @@
+//! Synchronization tools.
+
+mod parker;
+
+pub use self::parker::{Parker, Unparker};
new file mode 100644
--- /dev/null
+++ b/third_party/rust/crossbeam-utils/src/sync/parker.rs
@@ -0,0 +1,311 @@
+use std::fmt;
+use std::marker::PhantomData;
+use std::sync::{Arc, Condvar, Mutex};
+use std::sync::atomic::AtomicUsize;
+use std::sync::atomic::Ordering::SeqCst;
+use std::time::Duration;
+
+/// A thread parking primitive.
+///
+/// Conceptually, each `Parker` has an associated token which is initially not present:
+///
+/// * The [`park`] method blocks the current thread unless or until the token is available, at
+///   which point it automatically consumes the token. It may also return *spuriously*, without
+///   consuming the token.
+///
+/// * The [`park_timeout`] method works the same as [`park`], but blocks for a specified maximum
+///   time.
+///
+/// * The [`unpark`] method atomically makes the token available if it wasn't already. Because the
+///   token is initially absent, [`unpark`] followed by [`park`] will result in the second call
+///   returning immediately.
+///
+/// In other words, each `Parker` acts a bit like a spinlock that can be locked and unlocked using
+/// [`park`] and [`unpark`].
+///
+/// # Examples
+///
+/// ```
+/// use std::thread;
+/// use std::time::Duration;
+/// use crossbeam_utils::sync::Parker;
+///
+/// let mut p = Parker::new();
+/// let u = p.unparker().clone();
+///
+/// // Make the token available.
+/// u.unpark();
+/// // Wakes up immediately and consumes the token.
+/// p.park();
+///
+/// thread::spawn(move || {
+///     thread::sleep(Duration::from_millis(500));
+///     u.unpark();
+/// });
+///
+/// // Wakes up when `u.unpark()` provides the token, but may also wake up
+/// // spuriously before that without consuming the token.
+/// p.park();
+/// ```
+///
+/// [`park`]: struct.Parker.html#method.park
+/// [`park_timeout`]: struct.Parker.html#method.park_timeout
+/// [`unpark`]: struct.Unparker.html#method.unpark
+pub struct Parker {
+    unparker: Unparker,
+    _marker: PhantomData<*const ()>,
+}
+
+unsafe impl Send for Parker {}
+
+impl Parker {
+    /// Creates a new `Parker`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use crossbeam_utils::sync::Parker;
+    ///
+    /// let p = Parker::new();
+    /// ```
+    ///
+    pub fn new() -> Parker {
+        Parker {
+            unparker: Unparker {
+                inner: Arc::new(Inner {
+                    state: AtomicUsize::new(EMPTY),
+                    lock: Mutex::new(()),
+                    cvar: Condvar::new(),
+                }),
+            },
+            _marker: PhantomData,
+        }
+    }
+
+    /// Blocks the current thread until the token is made available.
+    ///
+    /// A call to `park` may wake up spuriously without consuming the token, and callers should be
+    /// prepared for this possibility.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use crossbeam_utils::sync::Parker;
+    ///
+    /// let mut p = Parker::new();
+    /// let u = p.unparker().clone();
+    ///
+    /// // Make the token available.
+    /// u.unpark();
+    ///
+    /// // Wakes up immediately and consumes the token.
+    /// p.park();
+    /// ```
+    pub fn park(&self) {
+        self.unparker.inner.park(None);
+    }
+
+    /// Blocks the current thread until the token is made available, but only for a limited time.
+    ///
+    /// A call to `park_timeout` may wake up spuriously without consuming the token, and callers
+    /// should be prepared for this possibility.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::time::Duration;
+    /// use crossbeam_utils::sync::Parker;
+    ///
+    /// let mut p = Parker::new();
+    ///
+    /// // Waits for the token to become available, but will not wait longer than 500 ms.
+    /// p.park_timeout(Duration::from_millis(500));
+    /// ```
+    pub fn park_timeout(&self, timeout: Duration) {
+        self.unparker.inner.park(Some(timeout));
+    }
+
+    /// Returns a reference to an associated [`Unparker`].
+    ///
+    /// The returned [`Unparker`] doesn't have to be used by reference - it can also be cloned.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use crossbeam_utils::sync::Parker;
+    ///
+    /// let mut p = Parker::new();
+    /// let u = p.unparker().clone();
+    ///
+    /// // Make the token available.
+    /// u.unpark();
+    /// // Wakes up immediately and consumes the token.
+    /// p.park();
+    /// ```
+    ///
+    /// [`park`]: struct.Parker.html#method.park
+    /// [`park_timeout`]: struct.Parker.html#method.park_timeout
+    ///
+    /// [`Unparker`]: struct.Unparker.html
+    pub fn unparker(&self) -> &Unparker {
+        &self.unparker
+    }
+}
+
+impl fmt::Debug for Parker {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("Parker { .. }")
+    }
+}
+
+/// Unparks a thread parked by the associated [`Parker`].
+///
+/// [`Parker`]: struct.Parker.html
+pub struct Unparker {
+    inner: Arc<Inner>,
+}
+
+unsafe impl Send for Unparker {}
+unsafe impl Sync for Unparker {}
+
+impl Unparker {
+    /// Atomically makes the token available if it is not already.
+    ///
+    /// This method will wake up the thread blocked on [`park`] or [`park_timeout`], if there is
+    /// any.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::thread;
+    /// use std::time::Duration;
+    /// use crossbeam_utils::sync::Parker;
+    ///
+    /// let mut p = Parker::new();
+    /// let u = p.unparker().clone();
+    ///
+    /// thread::spawn(move || {
+    ///     thread::sleep(Duration::from_millis(500));
+    ///     u.unpark();
+    /// });
+    ///
+    /// // Wakes up when `u.unpark()` provides the token, but may also wake up
+    /// // spuriously before that without consuming the token.
+    /// p.park();
+    /// ```
+    ///
+    /// [`park`]: struct.Parker.html#method.park
+    /// [`park_timeout`]: struct.Parker.html#method.park_timeout
+    pub fn unpark(&self) {
+        self.inner.unpark()
+    }
+}
+
+impl fmt::Debug for Unparker {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("Unparker { .. }")
+    }
+}
+
+impl Clone for Unparker {
+    fn clone(&self) -> Unparker {
+        Unparker {
+            inner: self.inner.clone(),
+        }
+    }
+}
+
+const EMPTY: usize = 0;
+const PARKED: usize = 1;
+const NOTIFIED: usize = 2;
+
+struct Inner {
+    state: AtomicUsize,
+    lock: Mutex<()>,
+    cvar: Condvar,
+}
+
+impl Inner {
+    fn park(&self, timeout: Option<Duration>) {
+        // If we were previously notified then we consume this notification and return quickly.
+        if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
+            return;
+        }
+
+        // If the timeout is zero, then there is no need to actually block.
+        if let Some(ref dur) = timeout {
+            if *dur == Duration::from_millis(0) {
+                return;
+            }
+        }
+
+        // Otherwise we need to coordinate going to sleep.
+        let mut m = self.lock.lock().unwrap();
+
+        match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
+            Ok(_) => {}
+            // Consume this notification to avoid spurious wakeups in the next park.
+            Err(NOTIFIED) => {
+                // We must read `state` here, even though we know it will be `NOTIFIED`. This is
+                // because `unpark` may have been called again since we read `NOTIFIED` in the
+                // `compare_exchange` above. We must perform an acquire operation that synchronizes
+                // with that `unpark` to observe any writes it made before the call to `unpark`. To
+                // do that we must read from the write it made to `state`.
+                let old = self.state.swap(EMPTY, SeqCst);
+                assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
+                return;
+            }
+            Err(n) => panic!("inconsistent park_timeout state: {}", n),
+        }
+
+        match timeout {
+            None => {
+                loop {
+                    // Block the current thread on the conditional variable.
+                    m = self.cvar.wait(m).unwrap();
+
+                    match self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) {
+                        Ok(_) => return, // got a notification
+                        Err(_) => {} // spurious wakeup, go back to sleep
+                    }
+                }
+            }
+            Some(timeout) => {
+                // Wait with a timeout, and if we spuriously wake up or otherwise wake up from a
+                // notification we just want to unconditionally set `state` back to `EMPTY`, either
+                // consuming a notification or un-flagging ourselves as parked.
+                let (_m, _result) = self.cvar.wait_timeout(m, timeout).unwrap();
+
+                match self.state.swap(EMPTY, SeqCst) {
+                    NOTIFIED => {} // got a notification
+                    PARKED => {} // no notification
+                    n => panic!("inconsistent park_timeout state: {}", n),
+                }
+            }
+        }
+    }
+
+    pub fn unpark(&self) {
+        // To ensure the unparked thread will observe any writes we made before this call, we must
+        // perform a release operation that `park` can synchronize with. To do that we must write
+        // `NOTIFIED` even if `state` is already `NOTIFIED`. That is why this must be a swap rather
+        // than a compare-and-swap that returns if it reads `NOTIFIED` on failure.
+        match self.state.swap(NOTIFIED, SeqCst) {
+            EMPTY => return, // no one was waiting
+            NOTIFIED => return, // already unparked
+            PARKED => {} // gotta go wake someone up
+            _ => panic!("inconsistent state in unpark"),
+        }
+
+        // There is a period between when the parked thread sets `state` to `PARKED` (or last
+        // checked `state` in the case of a spurious wakeup) and when it actually waits on `cvar`.
+        // If we were to notify during this period it would be ignored and then when the parked
+        // thread went to sleep it would never wake up. Fortunately, it has `lock` locked at this
+        // stage so we can acquire `lock` to wait until it is ready to receive the notification.
+        //
+        // Releasing `lock` before the call to `notify_one` means that when the parked thread wakes
+        // it doesn't get woken only to have to wait for us to release `lock`.
+        drop(self.lock.lock().unwrap());
+        self.cvar.notify_one();
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/crossbeam-utils/src/thread.rs
@@ -0,0 +1,347 @@
+//! Threads that can borrow variables from the stack.
+//!
+//! Create a scope when spawned threads need to access variables on the stack:
+//!
+//! ```
+//! use crossbeam_utils::thread;
+//!
+//! let people = vec![
+//!     "Alice".to_string(),
+//!     "Bob".to_string(),
+//!     "Carol".to_string(),
+//! ];
+//!
+//! thread::scope(|scope| {
+//!     for person in &people {
+//!         scope.spawn(move |_| {
+//!             println!("Hello, {}!", person);
+//!         });
+//!     }
+//! }).unwrap();
+//! ```
+//!
+//! # Why scoped threads?
+//!
+//! Suppose we wanted to re-write the previous example using plain threads:
+//!
+//! ```ignore
+//! use std::thread;
+//!
+//! let people = vec![
+//!     "Alice".to_string(),
+//!     "Bob".to_string(),
+//!     "Carol".to_string(),
+//! ];
+//!
+//! let mut threads = Vec::new();
+//!
+//! for person in &people {
+//!     threads.push(thread::spawn(move |_| {
+//!         println!("Hello, {}!", person);
+//!     }));
+//! }
+//!
+//! for thread in threads {
+//!     thread.join().unwrap();
+//! }
+//! ```
+//!
+//! This doesn't work because the borrow checker complains about `people` not living long enough:
+//!
+//! ```text
+//! error[E0597]: `people` does not live long enough
+//!   --> src/main.rs:12:20
+//!    |
+//! 12 |     for person in &people {
+//!    |                    ^^^^^^ borrowed value does not live long enough
+//! ...
+//! 21 | }
+//!    | - borrowed value only lives until here
+//!    |
+//!    = note: borrowed value must be valid for the static lifetime...
+//! ```
+//!
+//! The problem here is that spawned threads are not allowed to borrow variables on stack because
+//! the compiler cannot prove they will be joined before `people` is destroyed.
+//!
+//! Scoped threads are a mechanism to guarantee to the compiler that spawned threads will be joined
+//! before the scope ends.
+//!
+//! # How scoped threads work
+//!
+//! If a variable is borrowed by a thread, the thread must complete before the variable is
+//! destroyed. Threads spawned using [`std::thread::spawn`] can only borrow variables with the
+//! `'static` lifetime because the borrow checker cannot be sure when the thread will complete.
+//!
+//! A scope creates a clear boundary between variables outside the scope and threads inside the
+//! scope. Whenever a scope spawns a thread, it promises to join the thread before the scope ends.
+//! This way we guarantee to the borrow checker that scoped threads only live within the scope and
+//! can safely access variables outside it.
+//!
+//! [`std::thread::spawn`]: https://doc.rust-lang.org/std/thread/fn.spawn.html
+
+use std::fmt;
+use std::io;
+use std::marker::PhantomData;
+use std::mem;
+use std::panic;
+use std::sync::{Arc, Mutex, mpsc};
+use std::thread;
+
+type SharedVec<T> = Arc<Mutex<Vec<T>>>;
+type SharedOption<T> = Arc<Mutex<Option<T>>>;
+
+/// Creates a new `Scope` for [*scoped thread spawning*](struct.Scope.html#method.spawn).
+///
+/// No matter what happens, before the `Scope` is dropped, it is guaranteed that all the unjoined
+/// spawned scoped threads are joined.
+///
+/// `thread::scope()` returns `Ok(())` if all the unjoined spawned threads did not panic. It returns
+/// `Err(e)` if one of them panics with `e`. If many of them panic, it is still guaranteed that all
+/// the threads are joined, and `thread::scope()` returns `Err(e)` with `e` from a panicking thread.
+///
+/// # Examples
+///
+/// Creating and using a scope:
+///
+/// ```
+/// crossbeam_utils::thread::scope(|scope| {
+///     scope.spawn(|_| println!("Exiting scope"));
+///     scope.spawn(|_| println!("Running child thread in scope"));
+/// }).unwrap();
+/// ```
+pub fn scope<'env, F, R>(f: F) -> thread::Result<R>
+where
+    F: FnOnce(&Scope<'env>) -> R,
+{
+    let (tx, rx) = mpsc::channel();
+    let scope = Scope::<'env> {
+        handles: SharedVec::default(),
+        chan: tx,
+        _marker: PhantomData,
+    };
+
+    // Execute the scoped function, but catch any panics.
+    let result = panic::catch_unwind(panic::AssertUnwindSafe(|| f(&scope)));
+
+    // Wait until all nested scopes are dropped.
+    drop(scope.chan);
+    let _ = rx.recv();
+
+    // Join all remaining spawned threads.
+    let panics: Vec<_> = {
+        let mut handles = scope.handles.lock().unwrap();
+
+        // Filter handles that haven't been joined, join them, and collect errors.
+        let panics = handles
+            .drain(..)
+            .filter_map(|handle| handle.lock().unwrap().take())
+            .filter_map(|handle| handle.join().err())
+            .collect();
+
+        panics
+    };
+
+    // If `f` has panicked, resume unwinding.
+    // If any of the child threads have panicked, return the panic errors.
+    // Otherwise, everything is OK and return the result of `f`.
+    match result {
+        Err(err) => panic::resume_unwind(err),
+        Ok(res) => {
+            if panics.is_empty() {
+                Ok(res)
+            } else {
+                Err(Box::new(panics))
+            }
+        }
+    }
+}
+
+/// A scope for spawning threads.
+pub struct Scope<'env> {
+    /// The list of the thread join handles.
+    handles: SharedVec<SharedOption<thread::JoinHandle<()>>>,
+
+    /// Used to wait until all subscopes all dropped.
+    chan: mpsc::Sender<()>,
+
+    /// Borrows data with invariant lifetime `'env`.
+    _marker: PhantomData<&'env mut &'env ()>,
+}
+
+unsafe impl<'env> Sync for Scope<'env> {}
+
+impl<'env> Scope<'env> {
+    /// Create a scoped thread.
+    ///
+    /// `spawn` is similar to the [`spawn`] function in Rust's standard library. The difference is
+    /// that this thread is scoped, meaning that it's guaranteed to terminate before the current
+    /// stack frame goes away, allowing you to reference the parent stack frame directly. This is
+    /// ensured by having the parent thread join on the child thread before the scope exits.
+    ///
+    /// [`spawn`]: https://doc.rust-lang.org/std/thread/fn.spawn.html
+    pub fn spawn<'scope, F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T>
+    where
+        F: FnOnce(&Scope<'env>) -> T,
+        F: Send + 'env,
+        T: Send + 'env,
+    {
+        self.builder().spawn(f).unwrap()
+    }
+
+    /// Generates the base configuration for spawning a scoped thread, from which configuration
+    /// methods can be chained.
+    pub fn builder<'scope>(&'scope self) -> ScopedThreadBuilder<'scope, 'env> {
+        ScopedThreadBuilder {
+            scope: self,
+            builder: thread::Builder::new(),
+        }
+    }
+}
+
+impl<'env> fmt::Debug for Scope<'env> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("Scope { .. }")
+    }
+}
+
+/// Scoped thread configuration. Provides detailed control over the properties and behavior of new
+/// scoped threads.
+#[derive(Debug)]
+pub struct ScopedThreadBuilder<'scope, 'env: 'scope> {
+    scope: &'scope Scope<'env>,
+    builder: thread::Builder,
+}
+
+impl<'scope, 'env> ScopedThreadBuilder<'scope, 'env> {
+    /// Names the thread-to-be. Currently the name is used for identification only in panic
+    /// messages.
+    pub fn name(mut self, name: String) -> ScopedThreadBuilder<'scope, 'env> {
+        self.builder = self.builder.name(name);
+        self
+    }
+
+    /// Sets the size of the stack for the new thread.
+    pub fn stack_size(mut self, size: usize) -> ScopedThreadBuilder<'scope, 'env> {
+        self.builder = self.builder.stack_size(size);
+        self
+    }
+
+    /// Spawns a new thread, and returns a join handle for it.
+    pub fn spawn<F, T>(self, f: F) -> io::Result<ScopedJoinHandle<'scope, T>>
+    where
+        F: FnOnce(&Scope<'env>) -> T,
+        F: Send + 'env,
+        T: Send + 'env,
+    {
+        // The result of `f` will be stored here.
+        let result = SharedOption::default();
+
+        // Spawn the thread and grab its join handle and thread handle.
+        let (handle, thread) = {
+            let result = Arc::clone(&result);
+
+            // A clone of the scope that will be moved into the new thread.
+            let scope = Scope::<'env> {
+                handles: Arc::clone(&self.scope.handles),
+                chan: self.scope.chan.clone(),
+                _marker: PhantomData,
+            };
+
+            // Spawn the thread.
+            let handle = {
+                let closure = move || {
+                    // Make sure the scope is inside the closure with the proper `'env` lifetime.
+                    let scope: Scope<'env> = scope;
+
+                    // Run the closure.
+                    let res = f(&scope);
+
+                    // Store the result if the closure didn't panic.
+                    *result.lock().unwrap() = Some(res);
+                };
+
+                // Change the type of `closure` from `FnOnce() -> T` to `FnMut() -> T`.
+                let mut closure = Some(closure);
+                let closure = move || closure.take().unwrap()();
+
+                // Allocate `clsoure` on the heap and erase the `'env` bound.
+                let closure: Box<FnMut() + Send + 'env> = Box::new(closure);
+                let closure: Box<FnMut() + Send + 'static> = unsafe { mem::transmute(closure) };
+
+                // Finally, spawn the closure.
+                let mut closure = closure;
+                self.builder.spawn(move || closure())?
+            };
+
+            let thread = handle.thread().clone();
+            let handle = Arc::new(Mutex::new(Some(handle)));
+            (handle, thread)
+        };
+
+        // Add the handle to the shared list of join handles.
+        self.scope.handles.lock().unwrap().push(Arc::clone(&handle));
+
+        Ok(ScopedJoinHandle {
+            handle,
+            result,
+            thread,
+            _marker: PhantomData,
+        })
+    }
+}
+
+unsafe impl<'scope, T> Send for ScopedJoinHandle<'scope, T> {}
+unsafe impl<'scope, T> Sync for ScopedJoinHandle<'scope, T> {}
+
+/// A handle to a scoped thread
+pub struct ScopedJoinHandle<'scope, T> {
+    /// A join handle to the spawned thread.
+    handle: SharedOption<thread::JoinHandle<()>>,
+
+    /// Holds the result of the inner closure.
+    result: SharedOption<T>,
+
+    /// A handle to the the spawned thread.
+    thread: thread::Thread,
+
+    /// Borrows the parent scope with lifetime `'scope`.
+    _marker: PhantomData<&'scope ()>,
+}
+
+impl<'scope, T> ScopedJoinHandle<'scope, T> {
+    /// Waits for the associated thread to finish.
+    ///
+    /// If the child thread panics, [`Err`] is returned with the parameter given to [`panic`].
+    ///
+    /// [`Err`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err
+    /// [`panic`]: https://doc.rust-lang.org/std/macro.panic.html
+    ///
+    /// # Panics
+    ///
+    /// This function may panic on some platforms if a thread attempts to join itself or otherwise
+    /// may create a deadlock with joining threads.
+    pub fn join(self) -> thread::Result<T> {
+        // Take out the handle. The handle will surely be available because the root scope waits
+        // for nested scopes before joining remaining threads.
+        let handle = self.handle.lock().unwrap().take().unwrap();
+
+        // Join the thread and then take the result out of its inner closure.
+        handle
+            .join()
+            .map(|()| self.result.lock().unwrap().take().unwrap())
+    }
+
+    /// Gets the underlying [`std::thread::Thread`] handle.
+    ///
+    /// [`std::thread::Thread`]: https://doc.rust-lang.org/std/thread/struct.Thread.html
+    pub fn thread(&self) -> &thread::Thread {
+        &self.thread
+    }
+}
+
+impl<'scope, T> fmt::Debug for ScopedJoinHandle<'scope, T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("ScopedJoinHandle { .. }")
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/crossbeam-utils/tests/atomic_cell.rs
@@ -0,0 +1,208 @@
+extern crate crossbeam_utils;
+
+use std::sync::atomic::AtomicUsize;
+use std::sync::atomic::Ordering::SeqCst;
+
+use crossbeam_utils::atomic::AtomicCell;
+
+#[test]
+fn is_lock_free() {
+    struct UsizeWrap(usize);
+    struct U8Wrap(bool);
+
+    assert_eq!(AtomicCell::<usize>::is_lock_free(), true);
+    assert_eq!(AtomicCell::<isize>::is_lock_free(), true);
+    assert_eq!(AtomicCell::<UsizeWrap>::is_lock_free(), true);
+
+    assert_eq!(AtomicCell::<u8>::is_lock_free(), cfg!(feature = "nightly"));
+    assert_eq!(
+        AtomicCell::<bool>::is_lock_free(),
+        cfg!(feature = "nightly")
+    );
+    assert_eq!(
+        AtomicCell::<U8Wrap>::is_lock_free(),
+        cfg!(feature = "nightly")
+    );
+}
+
+#[test]
+fn drops_unit() {
+    static CNT: AtomicUsize = AtomicUsize::new(0);
+    CNT.store(0, SeqCst);
+
+    #[derive(Debug, PartialEq, Eq)]
+    struct Foo();
+
+    impl Foo {
+        fn new() -> Foo {
+            CNT.fetch_add(1, SeqCst);
+            Foo()
+        }
+    }
+
+    impl Drop for Foo {
+        fn drop(&mut self) {
+            CNT.fetch_sub(1, SeqCst);
+        }
+    }
+
+    impl Default for Foo {
+        fn default() -> Foo {
+            Foo::new()
+        }
+    }
+
+    let a = AtomicCell::new(Foo::new());
+
+    assert_eq!(a.swap(Foo::new()), Foo::new());
+    assert_eq!(CNT.load(SeqCst), 1);
+
+    a.store(Foo::new());
+    assert_eq!(CNT.load(SeqCst), 1);
+
+    assert_eq!(a.swap(Foo::default()), Foo::new());
+    assert_eq!(CNT.load(SeqCst), 1);
+
+    drop(a);
+    assert_eq!(CNT.load(SeqCst), 0);
+}
+
+#[test]
+fn drops_u8() {
+    static CNT: AtomicUsize = AtomicUsize::new(0);
+    CNT.store(0, SeqCst);
+
+    #[derive(Debug, PartialEq, Eq)]
+    struct Foo(u8);
+
+    impl Foo {
+        fn new(val: u8) -> Foo {
+            CNT.fetch_add(1, SeqCst);
+            Foo(val)
+        }
+    }
+
+    impl Drop for Foo {
+        fn drop(&mut self) {
+            CNT.fetch_sub(1, SeqCst);
+        }
+    }
+
+    impl Default for Foo {
+        fn default() -> Foo {
+            Foo::new(0)
+        }
+    }
+
+    let a = AtomicCell::new(Foo::new(5));
+
+    assert_eq!(a.swap(Foo::new(6)), Foo::new(5));
+    assert_eq!(a.swap(Foo::new(1)), Foo::new(6));
+    assert_eq!(CNT.load(SeqCst), 1);
+
+    a.store(Foo::new(2));
+    assert_eq!(CNT.load(SeqCst), 1);
+
+    assert_eq!(a.swap(Foo::default()), Foo::new(2));
+    assert_eq!(CNT.load(SeqCst), 1);
+
+    assert_eq!(a.swap(Foo::default()), Foo::new(0));
+    assert_eq!(CNT.load(SeqCst), 1);
+
+    drop(a);
+    assert_eq!(CNT.load(SeqCst), 0);
+}
+
+#[test]
+fn drops_usize() {
+    static CNT: AtomicUsize = AtomicUsize::new(0);
+    CNT.store(0, SeqCst);
+
+    #[derive(Debug, PartialEq, Eq)]
+    struct Foo(usize);
+
+    impl Foo {
+        fn new(val: usize) -> Foo {
+            CNT.fetch_add(1, SeqCst);
+            Foo(val)
+        }
+    }
+
+    impl Drop for Foo {
+        fn drop(&mut self) {
+            CNT.fetch_sub(1, SeqCst);
+        }
+    }
+
+    impl Default for Foo {
+        fn default() -> Foo {
+            Foo::new(0)
+        }
+    }
+
+    let a = AtomicCell::new(Foo::new(5));
+
+    assert_eq!(a.swap(Foo::new(6)), Foo::new(5));
+    assert_eq!(a.swap(Foo::new(1)), Foo::new(6));
+    assert_eq!(CNT.load(SeqCst), 1);
+
+    a.store(Foo::new(2));
+    assert_eq!(CNT.load(SeqCst), 1);
+
+    assert_eq!(a.swap(Foo::default()), Foo::new(2));
+    assert_eq!(CNT.load(SeqCst), 1);
+
+    assert_eq!(a.swap(Foo::default()), Foo::new(0));
+    assert_eq!(CNT.load(SeqCst), 1);
+
+    drop(a);
+    assert_eq!(CNT.load(SeqCst), 0);
+}
+
+#[test]
+fn modular_u8() {
+    #[derive(Clone, Copy, Eq, Debug, Default)]
+    struct Foo(u8);
+
+    impl PartialEq for Foo {
+        fn eq(&self, other: &Foo) -> bool {
+            self.0 % 5 == other.0 % 5
+        }
+    }
+
+    let a = AtomicCell::new(Foo(1));
+
+    assert_eq!(a.load(), Foo(1));
+    assert_eq!(a.swap(Foo(2)), Foo(11));
+    assert_eq!(a.load(), Foo(52));
+
+    a.store(Foo(0));
+    assert_eq!(a.compare_exchange(Foo(0), Foo(5)), Ok(Foo(100)));
+    assert_eq!(a.load().0, 5);
+    assert_eq!(a.compare_exchange(Foo(10), Foo(15)), Ok(Foo(100)));
+    assert_eq!(a.load().0, 15);
+}
+
+#[test]
+fn modular_usize() {
+    #[derive(Clone, Copy, Eq, Debug, Default)]
+    struct Foo(usize);
+
+    impl PartialEq for Foo {
+        fn eq(&self, other: &Foo) -> bool {
+            self.0 % 5 == other.0 % 5
+        }
+    }
+
+    let a = AtomicCell::new(Foo(1));
+
+    assert_eq!(a.load(), Foo(1));
+    assert_eq!(a.swap(Foo(2)), Foo(11));
+    assert_eq!(a.load(), Foo(52));
+
+    a.store(Foo(0));
+    assert_eq!(a.compare_exchange(Foo(0), Foo(5)), Ok(Foo(100)));
+    assert_eq!(a.load().0, 5);
+    assert_eq!(a.compare_exchange(Foo(10), Foo(15)), Ok(Foo(100)));
+    assert_eq!(a.load().0, 15);
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/crossbeam-utils/tests/cache_padded.rs
@@ -0,0 +1,112 @@
+extern crate crossbeam_utils;
+
+use std::cell::Cell;
+use std::mem;
+
+use crossbeam_utils::CachePadded;
+
+#[test]
+fn default() {
+    let x: CachePadded<u64> = Default::default();
+    assert_eq!(*x, 0);
+}
+
+#[test]
+fn store_u64() {
+    let x: CachePadded<u64> = CachePadded::new(17);
+    assert_eq!(*x, 17);
+}
+
+#[test]
+fn store_pair() {
+    let x: CachePadded<(u64, u64)> = CachePadded::new((17, 37));
+    assert_eq!(x.0, 17);
+    assert_eq!(x.1, 37);
+}
+
+#[test]
+fn distance() {
+    let arr = [CachePadded::new(17u8), CachePadded::new(37u8)];
+    let a = &*arr[0] as *const u8;
+    let b = &*arr[1] as *const u8;
+    assert!(unsafe { a.offset(64) } <= b);
+}
+
+#[test]
+fn different_sizes() {
+    CachePadded::new(17u8);
+    CachePadded::new(17u16);
+    CachePadded::new(17u32);
+    CachePadded::new([17u64; 0]);
+    CachePadded::new([17u64; 1]);
+    CachePadded::new([17u64; 2]);
+    CachePadded::new([17u64; 3]);
+    CachePadded::new([17u64; 4]);
+    CachePadded::new([17u64; 5]);
+    CachePadded::new([17u64; 6]);
+    CachePadded::new([17u64; 7]);
+    CachePadded::new([17u64; 8]);
+}
+
+#[test]
+fn large() {
+    let a = [17u64; 9];
+    let b = CachePadded::new(a);
+    assert!(mem::size_of_val(&a) <= mem::size_of_val(&b));
+}
+
+#[test]
+fn debug() {
+    assert_eq!(
+        format!("{:?}", CachePadded::new(17u64)),
+        "CachePadded { value: 17 }"
+    );
+}
+
+#[test]
+fn drops() {
+    let count = Cell::new(0);
+
+    struct Foo<'a>(&'a Cell<usize>);
+
+    impl<'a> Drop for Foo<'a> {
+        fn drop(&mut self) {
+            self.0.set(self.0.get() + 1);
+        }
+    }
+
+    let a = CachePadded::new(Foo(&count));
+    let b = CachePadded::new(Foo(&count));
+
+    assert_eq!(count.get(), 0);
+    drop(a);
+    assert_eq!(count.get(), 1);
+    drop(b);
+    assert_eq!(count.get(), 2);
+}
+
+#[test]
+fn clone() {
+    let a = CachePadded::new(17);
+    let b = a.clone();
+    assert_eq!(*a, *b);
+}
+
+#[test]
+fn runs_custom_clone() {
+    let count = Cell::new(0);
+
+    struct Foo<'a>(&'a Cell<usize>);
+
+    impl<'a> Clone for Foo<'a> {
+        fn clone(&self) -> Foo<'a> {
+            self.0.set(self.0.get() + 1);
+            Foo::<'a>(self.0)
+        }
+    }
+
+    let a = CachePadded::new(Foo(&count));
+    let _ = a.clone();
+
+    assert_eq!(count.get(), 1);
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/crossbeam-utils/tests/parker.rs
@@ -0,0 +1,42 @@
+extern crate crossbeam_utils;
+
+use std::thread::sleep;
+use std::time::Duration;
+use std::u32;
+
+use crossbeam_utils::sync::Parker;
+use crossbeam_utils::thread;
+
+#[test]
+fn park_timeout_unpark_before() {
+    let p = Parker::new();
+    for _ in 0..10 {
+        p.unparker().unpark();
+        p.park_timeout(Duration::from_millis(u32::MAX as u64));
+    }
+}
+
+#[test]
+fn park_timeout_unpark_not_called() {
+    let p = Parker::new();
+    for _ in 0..10 {
+        p.park_timeout(Duration::from_millis(10));
+    }
+}
+
+#[test]
+fn park_timeout_unpark_called_other_thread() {
+    for _ in 0..10 {
+        let p = Parker::new();
+        let u = p.unparker().clone();
+
+        thread::scope(|scope| {
+            scope.spawn(move |_| {
+                sleep(Duration::from_millis(50));
+                u.unpark();
+            });
+
+            p.park_timeout(Duration::from_millis(u32::MAX as u64));
+        }).unwrap();
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/crossbeam-utils/tests/thread.rs
@@ -0,0 +1,175 @@
+extern crate crossbeam_utils;
+
+use std::any::Any;
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::thread::sleep;
+use std::time::Duration;
+
+use crossbeam_utils::thread;
+
+const THREADS: usize = 10;
+const SMALL_STACK_SIZE: usize = 20;
+
+#[test]
+fn join() {
+    let counter = AtomicUsize::new(0);
+    thread::scope(|scope| {
+        let handle = scope.spawn(|_| {
+            counter.store(1, Ordering::Relaxed);
+        });
+        assert!(handle.join().is_ok());
+
+        let panic_handle = scope.spawn(|_| {
+            panic!("\"My honey is running out!\", said Pooh.");
+        });
+        assert!(panic_handle.join().is_err());
+    }).unwrap();
+
+    // There should be sufficient synchronization.
+    assert_eq!(1, counter.load(Ordering::Relaxed));
+}
+
+#[test]
+fn counter() {
+    let counter = AtomicUsize::new(0);
+    thread::scope(|scope| {
+        for _ in 0..THREADS {
+            scope.spawn(|_| {
+                counter.fetch_add(1, Ordering::Relaxed);
+            });
+        }
+    }).unwrap();
+
+    assert_eq!(THREADS, counter.load(Ordering::Relaxed));
+}
+
+#[test]
+fn counter_builder() {
+    let counter = AtomicUsize::new(0);
+    thread::scope(|scope| {
+        for i in 0..THREADS {
+            scope
+                .builder()
+                .name(format!("child-{}", i))
+                .stack_size(SMALL_STACK_SIZE)
+                .spawn(|_| {
+                    counter.fetch_add(1, Ordering::Relaxed);
+                }).unwrap();
+        }
+    }).unwrap();
+
+    assert_eq!(THREADS, counter.load(Ordering::Relaxed));
+}
+
+#[test]
+fn counter_panic() {
+    let counter = AtomicUsize::new(0);
+    let result = thread::scope(|scope| {
+        scope.spawn(|_| {
+            panic!("\"My honey is running out!\", said Pooh.");
+        });
+        sleep(Duration::from_millis(100));
+
+        for _ in 0..THREADS {
+            scope.spawn(|_| {
+                counter.fetch_add(1, Ordering::Relaxed);
+            });
+        }
+    });
+
+    assert_eq!(THREADS, counter.load(Ordering::Relaxed));
+    assert!(result.is_err());
+}
+
+#[test]
+fn panic_twice() {
+    let result = thread::scope(|scope| {
+        scope.spawn(|_| {
+            sleep(Duration::from_millis(500));
+            panic!("thread #1");
+        });
+        scope.spawn(|_| {
+            panic!("thread #2");
+        });
+    });
+
+    let err = result.unwrap_err();
+    let vec = err
+        .downcast_ref::<Vec<Box<Any + Send + 'static>>>()
+        .unwrap();
+    assert_eq!(2, vec.len());
+
+    let first = vec[0].downcast_ref::<&str>().unwrap();
+    let second = vec[1].downcast_ref::<&str>().unwrap();
+    assert_eq!("thread #1", *first);
+    assert_eq!("thread #2", *second)
+}
+
+#[test]
+fn panic_many() {
+    let result = thread::scope(|scope| {
+        scope.spawn(|_| panic!("deliberate panic #1"));
+        scope.spawn(|_| panic!("deliberate panic #2"));
+        scope.spawn(|_| panic!("deliberate panic #3"));
+    });
+
+    let err = result.unwrap_err();
+    let vec = err
+        .downcast_ref::<Vec<Box<Any + Send + 'static>>>()
+        .unwrap();
+    assert_eq!(3, vec.len());
+
+    for panic in vec.iter() {
+        let panic = panic.downcast_ref::<&str>().unwrap();
+        assert!(
+            *panic == "deliberate panic #1"
+                || *panic == "deliberate panic #2"
+                || *panic == "deliberate panic #3"
+        );
+    }
+}
+
+#[test]
+fn nesting() {
+    let var = "foo".to_string();
+
+    struct Wrapper<'a> {
+        var: &'a String,
+    }
+
+    impl<'a> Wrapper<'a> {
+        fn recurse(&'a self, scope: &thread::Scope<'a>, depth: usize) {
+            assert_eq!(self.var, "foo");
+
+            if depth > 0 {
+                scope.spawn(move |scope| {
+                    self.recurse(scope, depth - 1);
+                });
+            }
+        }
+    }
+
+    let wrapper = Wrapper { var: &var };
+
+    thread::scope(|scope| {
+        scope.spawn(|scope| {
+            scope.spawn(|scope| {
+                wrapper.recurse(scope, 5);
+            });
+        });
+    }).unwrap();
+}
+
+#[test]
+fn join_nested() {
+    thread::scope(|scope| {
+        scope.spawn(|scope| {
+            let handle = scope.spawn(|_| 7);
+
+            sleep(Duration::from_millis(200));
+            handle.join().unwrap();
+        });
+
+        sleep(Duration::from_millis(100));
+    }).unwrap();
+}
--- a/third_party/rust/lmdb-rkv/.cargo-checksum.json
+++ b/third_party/rust/lmdb-rkv/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"7c3220dd808ac0d7d161eb289cffffbcd5d36fde28f4d352775296a9783716a3","LICENSE":"db6d163be642e3b568c5fb2104013da632316ecd4e75935df1613af8b0b37933","README.md":"97b61d73ff27afb03bde9ae960f12651093558214851303c8ae82f567abfe992","src/cursor.rs":"169e95f800425324dd71219b8e88d148c1c103983ff9ffc94821600af031a854","src/database.rs":"003a214f53acd632bc70f2f02d01dcb0bc5bf7e777e1781ef1ff19246f0157d0","src/environment.rs":"af4de52742e3f727f53b833ee66406870766b83d7621d3647b977d330b6fb937","src/error.rs":"0ea99c8bc1619f3789eff7734341efa7f48fcd8732dc9f3141804e0a802f5d71","src/flags.rs":"40fd3d4d72c8db8f9ecb893420300a3585e2ca4c49073065ec9ebf24fe23c064","src/lib.rs":"ae47ef9c92d425e1b8b9857899c747593984d87dfd318d2cf30e5f626904f215","src/transaction.rs":"e9e9485aafb19cab4688dc8a476eec033c21c8256717a89080cfb77d2dfe235c"},"package":"07d8d72d709440ac7a19b71e04fb66684ec7547b3831817872454b01fdaefe23"}
\ No newline at end of file
+{"files":{"Cargo.toml":"fec74a5e98cd6a19d96eb3fcb54504199035eed36b999fe50c874f8e12bbf28d","LICENSE":"db6d163be642e3b568c5fb2104013da632316ecd4e75935df1613af8b0b37933","README.md":"97b61d73ff27afb03bde9ae960f12651093558214851303c8ae82f567abfe992","src/cursor.rs":"1cf47e15c55e3df7db5293f81c7538b0139dd2c4414cdc3ee8799f8659a2af0d","src/database.rs":"003a214f53acd632bc70f2f02d01dcb0bc5bf7e777e1781ef1ff19246f0157d0","src/environment.rs":"be682d90b86aef52d68936d96325d9ce9579389c79ce7b3fc640a79a3836c34b","src/error.rs":"0ea99c8bc1619f3789eff7734341efa7f48fcd8732dc9f3141804e0a802f5d71","src/flags.rs":"40fd3d4d72c8db8f9ecb893420300a3585e2ca4c49073065ec9ebf24fe23c064","src/lib.rs":"1e070c161e33eb07ed3e992f827c4b86e6f682ad0a24442346afb4dbc6ab40dd","src/transaction.rs":"e9e9485aafb19cab4688dc8a476eec033c21c8256717a89080cfb77d2dfe235c"},"package":"aba42e6d930590ce6625566f2d16300add86ef11335eedba0fcf29f9f4cbd8c5"}
\ No newline at end of file
--- a/third_party/rust/lmdb-rkv/Cargo.toml
+++ b/third_party/rust/lmdb-rkv/Cargo.toml
@@ -7,17 +7,17 @@
 #
 # If you believe there's an error in this file please file an
 # issue against the rust-lang/cargo repository. If you're
 # editing this file be aware that the upstream Cargo.toml
 # will likely look very different (and much more reasonable)
 
 [package]
 name = "lmdb-rkv"
-version = "0.8.2"
+version = "0.9.0"
 authors = ["Dan Burkert <dan@danburkert.com>"]
 description = "Idiomatic and safe LMDB wrapper."
 documentation = "https://docs.rs/lmdb-rkv"
 readme = "README.md"
 keywords = ["LMDB", "database", "storage-engine", "bindings", "library"]
 categories = ["database"]
 license = "Apache-2.0"
 repository = "https://github.com/mozilla/lmdb-rs.git"
--- a/third_party/rust/lmdb-rkv/src/cursor.rs
+++ b/third_party/rust/lmdb-rkv/src/cursor.rs
@@ -1,11 +1,12 @@
-use libc::{c_void, size_t, c_uint};
-use std::{fmt, ptr, result, slice};
 use std::marker::PhantomData;
+use std::{fmt, mem, ptr, result, slice};
+
+use libc::{EINVAL, c_void, size_t, c_uint};
 
 use database::Database;
 use error::{Error, Result, lmdb_result};
 use ffi;
 use flags::WriteFlags;
 use transaction::Transaction;
 
 /// An LMDB cursor.
@@ -14,21 +15,17 @@ pub trait Cursor<'txn> {
     /// Returns a raw pointer to the underlying LMDB cursor.
     ///
     /// The caller **must** ensure that the pointer is not used after the
     /// lifetime of the cursor.
     fn cursor(&self) -> *mut ffi::MDB_cursor;
 
     /// Retrieves a key/data pair from the cursor. Depending on the cursor op,
     /// the current key may be returned.
-    fn get(&self,
-           key: Option<&[u8]>,
-           data: Option<&[u8]>,
-           op: c_uint)
-           -> Result<(Option<&'txn [u8]>, &'txn [u8])> {
+    fn get(&self, key: Option<&[u8]>, data: Option<&[u8]>, op: c_uint) -> Result<(Option<&'txn [u8]>, &'txn [u8])> {
         unsafe {
             let mut key_val = slice_to_val(key);
             let mut data_val = slice_to_val(data);
             let key_ptr = key_val.mv_data;
             lmdb_result(ffi::mdb_cursor_get(self.cursor(), &mut key_val, &mut data_val, op))?;
             let key_out = if key_ptr != key_val.mv_data { Some(val_to_slice(key_val)) } else { None };
             let data_out = val_to_slice(data_val);
             Ok((key_out, data_out))
@@ -47,65 +44,62 @@ pub trait Cursor<'txn> {
     }
 
     /// Iterate over database items starting from the beginning of the database.
     ///
     /// For databases with duplicate data items (`DatabaseFlags::DUP_SORT`), the
     /// duplicate data items of each key will be returned before moving on to
     /// the next key.
     fn iter_start(&mut self) -> Iter<'txn> {
-        self.get(None, None, ffi::MDB_FIRST).unwrap();
-        Iter::new(self.cursor(), ffi::MDB_GET_CURRENT, ffi::MDB_NEXT)
+        Iter::new(self.cursor(), ffi::MDB_FIRST, ffi::MDB_NEXT)
     }
 
     /// Iterate over database items starting from the given key.
     ///
     /// For databases with duplicate data items (`DatabaseFlags::DUP_SORT`), the
     /// duplicate data items of each key will be returned before moving on to
     /// the next key.
     fn iter_from<K>(&mut self, key: K) -> Iter<'txn> where K: AsRef<[u8]> {
         match self.get(Some(key.as_ref()), None, ffi::MDB_SET_RANGE) {
-            Err(Error::NotFound) => Ok(()),
-            Err(error) => Err(error),
-            Ok(_) => Ok(()),
-        }.unwrap();
+            Ok(_) | Err(Error::NotFound) => (),
+            Err(error) => panic!("mdb_cursor_get returned an unexpected error: {}", error),
+        };
         Iter::new(self.cursor(), ffi::MDB_GET_CURRENT, ffi::MDB_NEXT)
     }
 
     /// Iterate over duplicate database items. The iterator will begin with the
     /// item next after the cursor, and continue until the end of the database.
     /// Each item will be returned as an iterator of its duplicates.
     fn iter_dup(&mut self) -> IterDup<'txn> {
         IterDup::new(self.cursor(), ffi::MDB_NEXT)
     }
 
     /// Iterate over duplicate database items starting from the beginning of the
     /// database. Each item will be returned as an iterator of its duplicates.
     fn iter_dup_start(&mut self) -> IterDup<'txn> {
-        self.get(None, None, ffi::MDB_FIRST).unwrap();
-        IterDup::new(self.cursor(), ffi::MDB_GET_CURRENT)
+        IterDup::new(self.cursor(), ffi::MDB_FIRST)
     }
 
     /// Iterate over duplicate items in the database starting from the given
     /// key. Each item will be returned as an iterator of its duplicates.
     fn iter_dup_from<K>(&mut self, key: &K) -> IterDup<'txn> where K: AsRef<[u8]> {
         match self.get(Some(key.as_ref()), None, ffi::MDB_SET_RANGE) {
-            Err(Error::NotFound) => Ok(()),
-            Err(error) => Err(error),
-            Ok(_) => Ok(()),
-        }.unwrap();
+            Ok(_) | Err(Error::NotFound) => (),
+            Err(error) => panic!("mdb_cursor_get returned an unexpected error: {}", error),
+        };
         IterDup::new(self.cursor(), ffi::MDB_GET_CURRENT)
     }
 
-    /// Iterate over the duplicates of the item in the database with the given
-    /// key.
-    fn iter_dup_of<K>(&mut self, key: &K) -> Result<Iter<'txn>> where K:
-        AsRef<[u8]> {
-        self.get(Some(key.as_ref()), None, ffi::MDB_SET)?;
-        Ok(Iter::new(self.cursor(), ffi::MDB_GET_CURRENT, ffi::MDB_NEXT_DUP))
+    /// Iterate over the duplicates of the item in the database with the given key.
+    fn iter_dup_of<K>(&mut self, key: &K) -> Iter<'txn> where K: AsRef<[u8]> {
+        match self.get(Some(key.as_ref()), None, ffi::MDB_SET) {
+            Ok(_) | Err(Error::NotFound) => (),
+            Err(error) => panic!("mdb_cursor_get returned an unexpected error: {}", error),
+        };
+        Iter::new(self.cursor(), ffi::MDB_GET_CURRENT, ffi::MDB_NEXT_DUP)
     }
 }
 
 /// A read-only cursor for navigating the items within a database.
 pub struct RoCursor<'txn> {
     cursor: *mut ffi::MDB_cursor,
     _marker: PhantomData<fn() -> &'txn ()>,
 }
@@ -244,30 +238,24 @@ impl <'txn> fmt::Debug for Iter<'txn> {
 
 impl <'txn> Iterator for Iter<'txn> {
 
     type Item = (&'txn [u8], &'txn [u8]);
 
     fn next(&mut self) -> Option<(&'txn [u8], &'txn [u8])> {
         let mut key = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
         let mut data = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
-
+        let op = mem::replace(&mut self.op, self.next_op);
         unsafe {
-            let err_code = ffi::mdb_cursor_get(self.cursor, &mut key, &mut data, self.op);
-            // Set the operation for the next get
-            self.op = self.next_op;
-            if err_code == ffi::MDB_SUCCESS {
-                Some((val_to_slice(key), val_to_slice(data)))
-            } else {
-                // The documentation for mdb_cursor_get specifies that it may fail with MDB_NOTFOUND
-                // and MDB_EINVAL (and we shouldn't be passing in invalid parameters).
-                // TODO: validate that these are the only failures possible.
-                debug_assert!(err_code == ffi::MDB_NOTFOUND,
-                              "Unexpected LMDB error {:?}.", Error::from_err_code(err_code));
-                None
+            match ffi::mdb_cursor_get(self.cursor, &mut key, &mut data, op) {
+                ffi::MDB_SUCCESS => Some((val_to_slice(key), val_to_slice(data))),
+                // EINVAL can occur when the cursor was previously seeked to a non-existent value,
+                // e.g. iter_from with a key greater than all values in the database.
+                ffi::MDB_NOTFOUND | EINVAL => None,
+                error => panic!("mdb_cursor_get returned an unexpected error: {}", error),
             }
         }
     }
 }
 
 /// An iterator over the keys and duplicate values in an LMDB database.
 ///
 /// The yielded items of the iterator are themselves iterators over the duplicate values for a
@@ -294,22 +282,22 @@ impl <'txn> fmt::Debug for IterDup<'txn>
 
 impl <'txn> Iterator for IterDup<'txn> {
 
     type Item = Iter<'txn>;
 
     fn next(&mut self) -> Option<Iter<'txn>> {
         let mut key = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
         let mut data = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
+        let op = mem::replace(&mut self.op, ffi::MDB_NEXT_NODUP);
         let err_code = unsafe {
-            ffi::mdb_cursor_get(self.cursor, &mut key, &mut data, self.op)
+            ffi::mdb_cursor_get(self.cursor, &mut key, &mut data, op)
         };
 
         if err_code == ffi::MDB_SUCCESS {
-            self.op = ffi::MDB_NEXT;
             Some(Iter::new(self.cursor, ffi::MDB_GET_CURRENT, ffi::MDB_NEXT_DUP))
         } else {
             None
         }
     }
 }
 
 #[cfg(test)]
@@ -459,16 +447,46 @@ mod test {
         assert_eq!(items.clone().into_iter().skip(3).collect::<Vec<_>>(),
                    cursor.iter_from(b"key4").collect::<Vec<_>>());
 
         assert_eq!(vec!().into_iter().collect::<Vec<(&[u8], &[u8])>>(),
                    cursor.iter_from(b"key6").collect::<Vec<_>>());
     }
 
     #[test]
+    fn test_iter_empty_database() {
+        let dir = TempDir::new("test").unwrap();
+        let env = Environment::new().open(dir.path()).unwrap();
+        let db = env.open_db(None).unwrap();
+        let txn = env.begin_ro_txn().unwrap();
+        let mut cursor = txn.open_ro_cursor(db).unwrap();
+
+        assert_eq!(0, cursor.iter().count());
+        assert_eq!(0, cursor.iter_start().count());
+        assert_eq!(0, cursor.iter_from(b"foo").count());
+    }
+
+    #[test]
+    fn test_iter_empty_dup_database() {
+        let dir = TempDir::new("test").unwrap();
+        let env = Environment::new().open(dir.path()).unwrap();
+        let db = env.create_db(None, DatabaseFlags::DUP_SORT).unwrap();
+        let txn = env.begin_ro_txn().unwrap();
+        let mut cursor = txn.open_ro_cursor(db).unwrap();
+
+        assert_eq!(0, cursor.iter().count());
+        assert_eq!(0, cursor.iter_start().count());
+        assert_eq!(0, cursor.iter_from(b"foo").count());
+        assert_eq!(0, cursor.iter_dup().count());
+        assert_eq!(0, cursor.iter_dup_start().count());
+        assert_eq!(0, cursor.iter_dup_from(b"foo").count());
+        assert_eq!(0, cursor.iter_dup_of(b"foo").count());
+    }
+
+    #[test]
     fn test_iter_dup() {
         let dir = TempDir::new("test").unwrap();
         let env = Environment::new().open(dir.path()).unwrap();
         let db = env.create_db(None, DatabaseFlags::DUP_SORT).unwrap();
 
         let items: Vec<(&[u8], &[u8])> = vec!((b"a", b"1"),
                                               (b"a", b"2"),
                                               (b"a", b"3"),
@@ -509,19 +527,19 @@ mod test {
 
         assert_eq!(items.clone().into_iter().skip(9).collect::<Vec<(&[u8], &[u8])>>(),
                    cursor.iter_dup_from(b"d").flat_map(|x| x).collect::<Vec<_>>());
 
         assert_eq!(vec!().into_iter().collect::<Vec<(&[u8], &[u8])>>(),
                    cursor.iter_dup_from(b"f").flat_map(|x| x).collect::<Vec<_>>());
 
         assert_eq!(items.clone().into_iter().skip(3).take(3).collect::<Vec<(&[u8], &[u8])>>(),
-                   cursor.iter_dup_of(b"b").unwrap().collect::<Vec<_>>());
+                   cursor.iter_dup_of(b"b").collect::<Vec<_>>());
 
-        assert!(cursor.iter_dup_of(b"foo").is_err());
+        assert_eq!(0, cursor.iter_dup_of(b"foo").count());
     }
 
     #[test]
     fn test_put_del() {
         let dir = TempDir::new("test").unwrap();
         let env = Environment::new().open(dir.path()).unwrap();
         let db = env.open_db(None).unwrap();
 
--- a/third_party/rust/lmdb-rkv/src/environment.rs
+++ b/third_party/rust/lmdb-rkv/src/environment.rs
@@ -237,26 +237,28 @@ pub struct EnvironmentBuilder {
 }
 
 impl EnvironmentBuilder {
 
     /// Open an environment.
     ///
     /// On UNIX, the database files will be opened with 644 permissions.
     ///
-    /// The path may not contain the null character.
+    /// The path may not contain the null character, Windows UNC (Uniform Naming Convention)
+    /// paths are not supported either.
     pub fn open(&self, path: &Path) -> Result<Environment> {
         self.open_with_permissions(path, 0o644)
     }
 
     /// Open an environment with the provided UNIX permissions.
     ///
     /// On Windows, the permissions will be ignored.
     ///
-    /// The path may not contain the null character.
+    /// The path may not contain the null character, Windows UNC (Uniform Naming Convention)
+    /// paths are not supported either.
     pub fn open_with_permissions(&self, path: &Path, mode: ffi::mode_t) -> Result<Environment> {
         let mut env: *mut ffi::MDB_env = ptr::null_mut();
         unsafe {
             lmdb_try!(ffi::mdb_env_create(&mut env));
             if let Some(max_readers) = self.max_readers {
                 lmdb_try_with_cleanup!(ffi::mdb_env_set_maxreaders(env, max_readers),
                                        ffi::mdb_env_close(env))
             }
--- a/third_party/rust/lmdb-rkv/src/lib.rs
+++ b/third_party/rust/lmdb-rkv/src/lib.rs
@@ -1,14 +1,14 @@
 //! Idiomatic and safe APIs for interacting with the
 //! [Lightning Memory-mapped Database (LMDB)](https://symas.com/lmdb).
 
 #![cfg_attr(test, feature(test))]
 #![deny(missing_docs)]
-#![doc(html_root_url = "https://docs.rs/lmdb-rkv/0.8.1")]
+#![doc(html_root_url = "https://docs.rs/lmdb-rkv/0.9.0")]
 
 extern crate libc;
 extern crate lmdb_sys as ffi;
 
 #[cfg(test)] extern crate rand;
 #[cfg(test)] extern crate tempdir;
 #[cfg(test)] extern crate test;
 #[macro_use] extern crate bitflags;
--- a/third_party/rust/rkv/.cargo-checksum.json
+++ b/third_party/rust/rkv/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"d056c9e3d80dc0b35bba66382a80688612e4c49e6f1e261d024edb31093ed5fe","LICENSE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","README.md":"9dc24375b49fef42f35dec42e316e21827d7337622f9e7cf36243cd28808797a","examples/README.md":"143767fc145bf167ce269a65138cb3f7086cb715b8bc4f73626da82966e646f4","examples/iterator.rs":"112d21743156cc86292b7ee2e1fe230e2531a4b14b62dd57c6fbc8e56bea775f","examples/simple-store.rs":"d36887921364bc36fe925ea8209b71a88a9ccca4775d502134b6c68e81372e88","run-all-examples.sh":"7f9d11d01017f77e1c9d26e3e82dfca8c6930deaec85e864458e33a7fa267de0","src/env.rs":"bbbf8f09f2529f7953d3db96283a6b59bbe66e2f320b9aa768e97b7f1d20b4c5","src/error.rs":"495112ac06104c4f83e033604a6121cb2e12140cf6450d38d8a7c8d9f5fea874","src/integer.rs":"ba9a7958dc069a1af4348495a9803b73b8312213b0a09199f91ee6f1bce69832","src/lib.rs":"6394a6e752f6c43251533e1086530568d253299909a90c965ec69ac23fbb9cfa","src/manager.rs":"621cbb3eebcb21fa85368122ba0fa8c721dd399334ca66813b795b396899ee81","src/readwrite.rs":"c0eb9f5cb146583a0a9f96efceddcedbecb38b1e9254e2554e8e15a991065ba5","src/value.rs":"bb7f16f838d865559ea319165a167207ee94df501317ef7f3035146a1631cd71","tests/manager.rs":"ebc8a9d6e55b1bc0c0699341141de2ce13e1306386ce5677a0eb4eb749f21d54"},"package":"663e50c3b2454387726a83b01629892824dcf113c0471841ea4bc9b5929eb75e"}
\ No newline at end of file
+{"files":{"Cargo.toml":"a80cc710a906ed055c8d76679319d04e1825cbe95309cde92808a068c15bdca0","LICENSE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","README.md":"9dc24375b49fef42f35dec42e316e21827d7337622f9e7cf36243cd28808797a","examples/README.md":"143767fc145bf167ce269a65138cb3f7086cb715b8bc4f73626da82966e646f4","examples/iterator.rs":"a47bf9e90828e8ae3a1e5146f87efb5c48c7dbbd6e570e4eed4d6f07c8a2583d","examples/simple-store.rs":"f98feda8ec74f4dc6e06dd43d7708d42dc201a773673e10332d257251d536c41","run-all-examples.sh":"7f9d11d01017f77e1c9d26e3e82dfca8c6930deaec85e864458e33a7fa267de0","src/env.rs":"c501be4ea8e38b0127bf6a4706eae48995066ae0be057c08f36384233968455c","src/error.rs":"495112ac06104c4f83e033604a6121cb2e12140cf6450d38d8a7c8d9f5fea874","src/integer.rs":"3cf748279e4b1dd66c35c7e7989c1d3721d067ace097536756d2903683199680","src/lib.rs":"10d9e9fb91421f19667ee5869c64e26b87d2959813758bc081ce69ee0cb351e4","src/manager.rs":"621cbb3eebcb21fa85368122ba0fa8c721dd399334ca66813b795b396899ee81","src/readwrite.rs":"239115092dca693cea756e468879904fccaa7724b7df384eb2ec302ceda8881f","src/value.rs":"30e9784bb98110585fd1f06f263931a305a33bc457594006442c3352eb88f790","tests/manager.rs":"ebc8a9d6e55b1bc0c0699341141de2ce13e1306386ce5677a0eb4eb749f21d54"},"package":"79504d734e64f3d9391fbcaf15ca247421da461b95b9cdebd9af5679a4cfd8c8"}
\ No newline at end of file
--- a/third_party/rust/rkv/Cargo.toml
+++ b/third_party/rust/rkv/Cargo.toml
@@ -7,18 +7,18 @@
 #
 # If you believe there's an error in this file please file an
 # issue against the rust-lang/cargo repository. If you're
 # editing this file be aware that the upstream Cargo.toml
 # will likely look very different (and much more reasonable)
 
 [package]
 name = "rkv"
-version = "0.5.1"
-authors = ["Richard Newman <rnewman@twinql.com>"]
+version = "0.7.0"
+authors = ["Richard Newman <rnewman@twinql.com>", "Nan Jiang <najiang@mozilla.com>", "Myk Melez <myk@mykzilla.org>"]
 description = "a simple, humane, typed Rust interface to LMDB"
 homepage = "https://github.com/mozilla/rkv"
 readme = "README.md"
 keywords = ["lmdb", "database", "storage"]
 categories = ["database"]
 license = "Apache-2.0"
 repository = "https://github.com/mozilla/rkv"
 [dependencies.arrayref]
@@ -31,29 +31,29 @@ version = "1.0"
 version = "0.1.2"
 features = ["derive"]
 default_features = false
 
 [dependencies.lazy_static]
 version = "1.0"
 
 [dependencies.lmdb-rkv]
-version = "0.8"
+version = "0.9"
 
 [dependencies.ordered-float]
 version = "1.0"
 
 [dependencies.serde]
 version = "1.0"
 
 [dependencies.url]
 version = "1.7.0"
 
 [dependencies.uuid]
-version = "0.6"
+version = "0.7"
 [dev-dependencies.byteorder]
 version = "1"
 
 [dev-dependencies.tempfile]
 version = "3"
 
 [features]
 backtrace = ["failure/backtrace", "failure/std"]
--- a/third_party/rust/rkv/examples/iterator.rs
+++ b/third_party/rust/rkv/examples/iterator.rs
@@ -26,46 +26,46 @@ fn main() {
     let root = Builder::new().prefix("iterator").tempdir().unwrap();
     fs::create_dir_all(root.path()).unwrap();
     let p = root.path();
 
     let created_arc = Manager::singleton().write().unwrap().get_or_create(p, Rkv::new).unwrap();
     let k = created_arc.read().unwrap();
     let store = k.open_or_create("store").unwrap();
 
-    populate_store(&k, &store).unwrap();
+    populate_store(&k, store).unwrap();
 
     let reader = k.read().unwrap();
 
     println!("Iterating from the beginning...");
     // Reader::iter_start() iterates from the first item in the store, and
     // returns the (key, value) tuples in order.
-    let mut iter = reader.iter_start(&store).unwrap();
+    let mut iter = reader.iter_start(store).unwrap();
     while let Some((country, city)) = iter.next() {
         println!("{}, {:?}", str::from_utf8(country).unwrap(), city);
     }
 
     println!("");
     println!("Iterating from the given key...");
     // Reader::iter_from() iterates from the first key equal to or greater
     // than the given key.
-    let mut iter = reader.iter_from(&store, "Japan").unwrap();
+    let mut iter = reader.iter_from(store, "Japan").unwrap();
     while let Some((country, city)) = iter.next() {
         println!("{}, {:?}", str::from_utf8(country).unwrap(), city);
     }
 
     println!("");
     println!("Iterating from the given prefix...");
-    let mut iter = reader.iter_from(&store, "Un").unwrap();
+    let mut iter = reader.iter_from(store, "Un").unwrap();
     while let Some((country, city)) = iter.next() {
         println!("{}, {:?}", str::from_utf8(country).unwrap(), city);
     }
 }
 
-fn populate_store(k: &Rkv, store: &Store) -> Result<(), StoreError> {
+fn populate_store(k: &Rkv, store: Store) -> Result<(), StoreError> {
     let mut writer = k.write()?;
     for (country, city) in vec![
         ("Canada", Value::Str("Ottawa")),
         ("United States of America", Value::Str("Washington")),
         ("Germany", Value::Str("Berlin")),
         ("France", Value::Str("Paris")),
         ("Italy", Value::Str("Rome")),
         ("United Kingdom", Value::Str("London")),
--- a/third_party/rust/rkv/examples/simple-store.rs
+++ b/third_party/rust/rkv/examples/simple-store.rs
@@ -30,90 +30,90 @@ fn main() {
 
     // Creates a store called "store"
     let store = k.open_or_create("store").unwrap();
 
     println!("Inserting data...");
     {
         // Use a writer to mutate the store
         let mut writer = k.write().unwrap();
-        writer.put(&store, "int", &Value::I64(1234)).unwrap();
-        writer.put(&store, "uint", &Value::U64(1234_u64)).unwrap();
-        writer.put(&store, "float", &Value::F64(1234.0.into())).unwrap();
-        writer.put(&store, "instant", &Value::Instant(1528318073700)).unwrap();
-        writer.put(&store, "boolean", &Value::Bool(true)).unwrap();
-        writer.put(&store, "string", &Value::Str("héllo, yöu")).unwrap();
-        writer.put(&store, "json", &Value::Json(r#"{"foo":"bar", "number": 1}"#)).unwrap();
-        writer.put(&store, "blob", &Value::Blob(b"blob")).unwrap();
+        writer.put(store, "int", &Value::I64(1234)).unwrap();
+        writer.put(store, "uint", &Value::U64(1234_u64)).unwrap();
+        writer.put(store, "float", &Value::F64(1234.0.into())).unwrap();
+        writer.put(store, "instant", &Value::Instant(1528318073700)).unwrap();
+        writer.put(store, "boolean", &Value::Bool(true)).unwrap();
+        writer.put(store, "string", &Value::Str("héllo, yöu")).unwrap();
+        writer.put(store, "json", &Value::Json(r#"{"foo":"bar", "number": 1}"#)).unwrap();
+        writer.put(store, "blob", &Value::Blob(b"blob")).unwrap();
         writer.commit().unwrap();
     }
 
     println!("Looking up keys...");
     {
         // Use a reader to query the store
         let reader = k.read().unwrap();
-        println!("Get int {:?}", reader.get(&store, "int").unwrap());
-        println!("Get uint {:?}", reader.get(&store, "uint").unwrap());
-        println!("Get float {:?}", reader.get(&store, "float").unwrap());
-        println!("Get instant {:?}", reader.get(&store, "instant").unwrap());
-        println!("Get boolean {:?}", reader.get(&store, "boolean").unwrap());
-        println!("Get string {:?}", reader.get(&store, "string").unwrap());
-        println!("Get json {:?}", reader.get(&store, "json").unwrap());
-        println!("Get blob {:?}", reader.get(&store, "blob").unwrap());
-        println!("Get non-existent {:?}", reader.get(&store, "non-existent").unwrap());
+        println!("Get int {:?}", reader.get(store, "int").unwrap());
+        println!("Get uint {:?}", reader.get(store, "uint").unwrap());
+        println!("Get float {:?}", reader.get(store, "float").unwrap());
+        println!("Get instant {:?}", reader.get(store, "instant").unwrap());
+        println!("Get boolean {:?}", reader.get(store, "boolean").unwrap());
+        println!("Get string {:?}", reader.get(store, "string").unwrap());
+        println!("Get json {:?}", reader.get(store, "json").unwrap());
+        println!("Get blob {:?}", reader.get(store, "blob").unwrap());
+        println!("Get non-existent {:?}", reader.get(store, "non-existent").unwrap());
     }
 
     println!("Looking up keys via Writer.get()...");
     {
         let mut writer = k.write().unwrap();
-        writer.put(&store, "foo", &Value::Str("bar")).unwrap();
-        writer.put(&store, "bar", &Value::Str("baz")).unwrap();
-        writer.delete(&store, "foo").unwrap();
-        println!("It should be None! ({:?})", writer.get(&store, "foo").unwrap());
-        println!("Get bar ({:?})", writer.get(&store, "bar").unwrap());
+        writer.put(store, "foo", &Value::Str("bar")).unwrap();
+        writer.put(store, "bar", &Value::Str("baz")).unwrap();
+        writer.delete(store, "foo").unwrap();
+        println!("It should be None! ({:?})", writer.get(store, "foo").unwrap());
+        println!("Get bar ({:?})", writer.get(store, "bar").unwrap());
         writer.commit().unwrap();
         let reader = k.read().expect("reader");
-        println!("It should be None! ({:?})", reader.get(&store, "foo").unwrap());
-        println!("Get bar {:?}", reader.get(&store, "bar").unwrap());
+        println!("It should be None! ({:?})", reader.get(store, "foo").unwrap());
+        println!("Get bar {:?}", reader.get(store, "bar").unwrap());
     }
 
     println!("Aborting transaction...");
     {
         // Aborting a write transaction rollbacks the change(s)
         let mut writer = k.write().unwrap();
-        writer.put(&store, "foo", &Value::Str("bar")).unwrap();
+        writer.put(store, "foo", &Value::Str("bar")).unwrap();
         writer.abort();
 
         let reader = k.read().expect("reader");
-        println!("It should be None! ({:?})", reader.get(&store, "foo").unwrap());
+        println!("It should be None! ({:?})", reader.get(store, "foo").unwrap());
         // Explicitly aborting a transaction is not required unless an early
         // abort is desired, since both read and write transactions will
         // implicitly be aborted once they go out of scope.
     }
 
     println!("Deleting keys...");
     {
         // Deleting a key/value also requires a write transaction
         let mut writer = k.write().unwrap();
-        writer.put(&store, "foo", &Value::Str("bar")).unwrap();
-        writer.delete(&store, "foo").unwrap();
-        println!("It should be None! ({:?})", writer.get(&store, "foo").unwrap());
+        writer.put(store, "foo", &Value::Str("bar")).unwrap();
+        writer.delete(store, "foo").unwrap();
+        println!("It should be None! ({:?})", writer.get(store, "foo").unwrap());
         writer.commit().unwrap();
 
         // Committing a transaction consumes the writer, preventing you
         // from reusing it by failing and reporting a compile-time error.
         // This line would report error[E0382]: use of moved value: `writer`.
-        // writer.put(&store, "baz", &Value::Str("buz")).unwrap();
+        // writer.put(store, "baz", &Value::Str("buz")).unwrap();
     }
 
     println!("Write and read on multiple stores...");
     {
         let another_store = k.open_or_create("another_store").unwrap();
         let mut writer = k.write().unwrap();
-        writer.put(&store, "foo", &Value::Str("bar")).unwrap();
-        writer.put(&another_store, "foo", &Value::Str("baz")).unwrap();
+        writer.put(store, "foo", &Value::Str("bar")).unwrap();
+        writer.put(another_store, "foo", &Value::Str("baz")).unwrap();
         writer.commit().unwrap();
 
         let reader = k.read().unwrap();
-        println!("Get from store value: {:?}", reader.get(&store, "foo").unwrap());
-        println!("Get from another store value: {:?}", reader.get(&another_store, "foo").unwrap());
+        println!("Get from store value: {:?}", reader.get(store, "foo").unwrap());
+        println!("Get from another store value: {:?}", reader.get(another_store, "foo").unwrap());
     }
 }
--- a/third_party/rust/rkv/src/env.rs
+++ b/third_party/rust/rkv/src/env.rs
@@ -222,17 +222,17 @@ mod tests {
     }
 
     fn check_rkv(k: &Rkv) {
         let _ = k.open_or_create_default().expect("created default");
 
         let yyy = k.open_or_create("yyy").expect("opened");
         let reader = k.read().expect("reader");
 
-        let result = reader.get(&yyy, "foo");
+        let result = reader.get(yyy, "foo");
         assert_eq!(None, result.expect("success but no value"));
     }
 
     #[test]
     fn test_open() {
         let root = Builder::new().prefix("test_open").tempdir().expect("tempdir");
         println!("Root path: {:?}", root.path());
         fs::create_dir_all(root.path()).expect("dir created");
@@ -272,134 +272,188 @@ mod tests {
         // This panics with "opened: LmdbError(DbsFull)" because we specified
         // a capacity of one (database), and check_rkv already opened one
         // (plus the default database, which doesn't count against the limit).
         // This should really return an error rather than panicking, per
         // <https://github.com/mozilla/lmdb-rs/issues/6>.
         let _zzz = k.open_or_create("zzz").expect("opened");
     }
 
+    fn get_larger_than_default_map_size_value() -> usize {
+        // The LMDB C library and lmdb Rust crate docs for setting the map size
+        // <http://www.lmdb.tech/doc/group__mdb.html#gaa2506ec8dab3d969b0e609cd82e619e5>
+        // <https://docs.rs/lmdb/0.8.0/lmdb/struct.EnvironmentBuilder.html#method.set_map_size>
+        // both say that the default map size is 10,485,760 bytes, i.e. 10MiB.
+        //
+        // But the DEFAULT_MAPSIZE define in the LMDB code
+        // https://github.com/LMDB/lmdb/blob/26c7df88e44e31623d0802a564f24781acdefde3/libraries/liblmdb/mdb.c#L729
+        // sets the default map size to 1,048,576 bytes, i.e. 1MiB.
+        //
+        1024 * 1024 + 1 /* 1,048,576 + 1 bytes, i.e. 1MiB + 1 byte */
+    }
+
+    #[test]
+    #[should_panic(expected = "wrote: LmdbError(MapFull)")]
+    fn test_exceed_map_size() {
+        let root = Builder::new().prefix("test_exceed_map_size").tempdir().expect("tempdir");
+        println!("Root path: {:?}", root.path());
+        fs::create_dir_all(root.path()).expect("dir created");
+        assert!(root.path().is_dir());
+
+        let k = Rkv::new(root.path()).expect("new succeeded");
+        let sk: Store = k.open_or_create_default().expect("opened");
+
+        // Writing a large enough value should cause LMDB to fail on MapFull.
+        // We write a string that is larger than the default map size.
+        let val = "x".repeat(get_larger_than_default_map_size_value());
+        let mut writer = k.write().expect("writer");
+        writer.put(sk, "foo", &Value::Str(&val)).expect("wrote");
+    }
+
+    #[test]
+    fn test_increase_map_size() {
+        let root = Builder::new().prefix("test_open_with_map_size").tempdir().expect("tempdir");
+        println!("Root path: {:?}", root.path());
+        fs::create_dir_all(root.path()).expect("dir created");
+        assert!(root.path().is_dir());
+
+        let mut builder = Rkv::environment_builder();
+        // Set the map size to the size of the value we'll store in it + 100KiB,
+        // which ensures that there's enough space for the value and metadata.
+        builder.set_map_size(get_larger_than_default_map_size_value() + 100 * 1024 /* 100KiB */);
+        let k = Rkv::from_env(root.path(), builder).unwrap();
+        let sk: Store = k.open_or_create_default().expect("opened");
+        let val = "x".repeat(get_larger_than_default_map_size_value());
+
+        let mut writer = k.write().expect("writer");
+        writer.put(sk, "foo", &Value::Str(&val)).expect("wrote");
+        writer.commit().expect("committed");
+
+        let reader = k.read().unwrap();
+        assert_eq!(reader.get(sk, "foo").expect("read"), Some(Value::Str(&val)));
+    }
+
     #[test]
     fn test_round_trip_and_transactions() {
         let root = Builder::new().prefix("test_round_trip_and_transactions").tempdir().expect("tempdir");
         fs::create_dir_all(root.path()).expect("dir created");
         let k = Rkv::new(root.path()).expect("new succeeded");
 
         let sk: Store = k.open_or_create("sk").expect("opened");
 
         {
             let mut writer = k.write().expect("writer");
-            writer.put(&sk, "foo", &Value::I64(1234)).expect("wrote");
-            writer.put(&sk, "noo", &Value::F64(1234.0.into())).expect("wrote");
-            writer.put(&sk, "bar", &Value::Bool(true)).expect("wrote");
-            writer.put(&sk, "baz", &Value::Str("héllo, yöu")).expect("wrote");
-            assert_eq!(writer.get(&sk, "foo").expect("read"), Some(Value::I64(1234)));
-            assert_eq!(writer.get(&sk, "noo").expect("read"), Some(Value::F64(1234.0.into())));
-            assert_eq!(writer.get(&sk, "bar").expect("read"), Some(Value::Bool(true)));
-            assert_eq!(writer.get(&sk, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
+            writer.put(sk, "foo", &Value::I64(1234)).expect("wrote");
+            writer.put(sk, "noo", &Value::F64(1234.0.into())).expect("wrote");
+            writer.put(sk, "bar", &Value::Bool(true)).expect("wrote");
+            writer.put(sk, "baz", &Value::Str("héllo, yöu")).expect("wrote");
+            assert_eq!(writer.get(sk, "foo").expect("read"), Some(Value::I64(1234)));
+            assert_eq!(writer.get(sk, "noo").expect("read"), Some(Value::F64(1234.0.into())));
+            assert_eq!(writer.get(sk, "bar").expect("read"), Some(Value::Bool(true)));
+            assert_eq!(writer.get(sk, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
 
             // Isolation. Reads won't return values.
             let r = &k.read().unwrap();
-            assert_eq!(r.get(&sk, "foo").expect("read"), None);
-            assert_eq!(r.get(&sk, "bar").expect("read"), None);
-            assert_eq!(r.get(&sk, "baz").expect("read"), None);
+            assert_eq!(r.get(sk, "foo").expect("read"), None);
+            assert_eq!(r.get(sk, "bar").expect("read"), None);
+            assert_eq!(r.get(sk, "baz").expect("read"), None);
         }
 
         // Dropped: tx rollback. Reads will still return nothing.
 
         {
             let r = &k.read().unwrap();
-            assert_eq!(r.get(&sk, "foo").expect("read"), None);
-            assert_eq!(r.get(&sk, "bar").expect("read"), None);
-            assert_eq!(r.get(&sk, "baz").expect("read"), None);
+            assert_eq!(r.get(sk, "foo").expect("read"), None);
+            assert_eq!(r.get(sk, "bar").expect("read"), None);
+            assert_eq!(r.get(sk, "baz").expect("read"), None);
         }
 
         {
             let mut writer = k.write().expect("writer");
-            writer.put(&sk, "foo", &Value::I64(1234)).expect("wrote");
-            writer.put(&sk, "bar", &Value::Bool(true)).expect("wrote");
-            writer.put(&sk, "baz", &Value::Str("héllo, yöu")).expect("wrote");
-            assert_eq!(writer.get(&sk, "foo").expect("read"), Some(Value::I64(1234)));
-            assert_eq!(writer.get(&sk, "bar").expect("read"), Some(Value::Bool(true)));
-            assert_eq!(writer.get(&sk, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
+            writer.put(sk, "foo", &Value::I64(1234)).expect("wrote");
+            writer.put(sk, "bar", &Value::Bool(true)).expect("wrote");
+            writer.put(sk, "baz", &Value::Str("héllo, yöu")).expect("wrote");
+            assert_eq!(writer.get(sk, "foo").expect("read"), Some(Value::I64(1234)));
+            assert_eq!(writer.get(sk, "bar").expect("read"), Some(Value::Bool(true)));
+            assert_eq!(writer.get(sk, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
 
             writer.commit().expect("committed");
         }
 
         // Committed. Reads will succeed.
         {
             let r = k.read().unwrap();
-            assert_eq!(r.get(&sk, "foo").expect("read"), Some(Value::I64(1234)));
-            assert_eq!(r.get(&sk, "bar").expect("read"), Some(Value::Bool(true)));
-            assert_eq!(r.get(&sk, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
+            assert_eq!(r.get(sk, "foo").expect("read"), Some(Value::I64(1234)));
+            assert_eq!(r.get(sk, "bar").expect("read"), Some(Value::Bool(true)));
+            assert_eq!(r.get(sk, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
         }
 
         {
             let mut writer = k.write().expect("writer");
-            writer.delete(&sk, "foo").expect("deleted");
-            writer.delete(&sk, "bar").expect("deleted");
-            writer.delete(&sk, "baz").expect("deleted");
-            assert_eq!(writer.get(&sk, "foo").expect("read"), None);
-            assert_eq!(writer.get(&sk, "bar").expect("read"), None);
-            assert_eq!(writer.get(&sk, "baz").expect("read"), None);
+            writer.delete(sk, "foo").expect("deleted");
+            writer.delete(sk, "bar").expect("deleted");
+            writer.delete(sk, "baz").expect("deleted");
+            assert_eq!(writer.get(sk, "foo").expect("read"), None);
+            assert_eq!(writer.get(sk, "bar").expect("read"), None);
+            assert_eq!(writer.get(sk, "baz").expect("read"), None);
 
             // Isolation. Reads still return values.
             let r = k.read().unwrap();
-            assert_eq!(r.get(&sk, "foo").expect("read"), Some(Value::I64(1234)));
-            assert_eq!(r.get(&sk, "bar").expect("read"), Some(Value::Bool(true)));
-            assert_eq!(r.get(&sk, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
+            assert_eq!(r.get(sk, "foo").expect("read"), Some(Value::I64(1234)));
+            assert_eq!(r.get(sk, "bar").expect("read"), Some(Value::Bool(true)));
+            assert_eq!(r.get(sk, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
         }
 
         // Dropped: tx rollback. Reads will still return values.
 
         {
             let r = k.read().unwrap();
-            assert_eq!(r.get(&sk, "foo").expect("read"), Some(Value::I64(1234)));
-            assert_eq!(r.get(&sk, "bar").expect("read"), Some(Value::Bool(true)));
-            assert_eq!(r.get(&sk, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
+            assert_eq!(r.get(sk, "foo").expect("read"), Some(Value::I64(1234)));
+            assert_eq!(r.get(sk, "bar").expect("read"), Some(Value::Bool(true)));
+            assert_eq!(r.get(sk, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
         }
 
         {
             let mut writer = k.write().expect("writer");
-            writer.delete(&sk, "foo").expect("deleted");
-            writer.delete(&sk, "bar").expect("deleted");
-            writer.delete(&sk, "baz").expect("deleted");
-            assert_eq!(writer.get(&sk, "foo").expect("read"), None);
-            assert_eq!(writer.get(&sk, "bar").expect("read"), None);
-            assert_eq!(writer.get(&sk, "baz").expect("read"), None);
+            writer.delete(sk, "foo").expect("deleted");
+            writer.delete(sk, "bar").expect("deleted");
+            writer.delete(sk, "baz").expect("deleted");
+            assert_eq!(writer.get(sk, "foo").expect("read"), None);
+            assert_eq!(writer.get(sk, "bar").expect("read"), None);
+            assert_eq!(writer.get(sk, "baz").expect("read"), None);
 
             writer.commit().expect("committed");
         }
 
         // Committed. Reads will succeed but return None to indicate a missing value.
         {
             let r = k.read().unwrap();
-            assert_eq!(r.get(&sk, "foo").expect("read"), None);
-            assert_eq!(r.get(&sk, "bar").expect("read"), None);
-            assert_eq!(r.get(&sk, "baz").expect("read"), None);
+            assert_eq!(r.get(sk, "foo").expect("read"), None);
+            assert_eq!(r.get(sk, "bar").expect("read"), None);
+            assert_eq!(r.get(sk, "baz").expect("read"), None);
         }
     }
 
     #[test]
     fn test_open_store_for_read() {
         let root = Builder::new().prefix("test_open_store_for_read").tempdir().expect("tempdir");
         fs::create_dir_all(root.path()).expect("dir created");
         let k = Rkv::new(root.path()).expect("new succeeded");
         // First create the store, and start a write transaction on it.
         let sk = k.open_or_create("sk").expect("opened");
         let mut writer = k.write().expect("writer");
-        writer.put(&sk, "foo", &Value::Str("bar")).expect("write");
+        writer.put(sk, "foo", &Value::Str("bar")).expect("write");
 
         // Open the same store for read, note that the write transaction is still in progress,
         // it should not block the reader though.
         let sk_readonly = k.open("sk").expect("opened");
         writer.commit().expect("commit");
         // Now the write transaction is committed, any followed reads should see its change.
         let reader = k.read().expect("reader");
-        assert_eq!(reader.get(&sk_readonly, "foo").expect("read"), Some(Value::Str("bar")));
+        assert_eq!(reader.get(sk_readonly, "foo").expect("read"), Some(Value::Str("bar")));
     }
 
     #[test]
     #[should_panic(expected = "open a missing store")]
     fn test_open_a_missing_store() {
         let root = Builder::new().prefix("test_open_a_missing_store").tempdir().expect("tempdir");
         fs::create_dir_all(root.path()).expect("dir created");
         let k = Rkv::new(root.path()).expect("new succeeded");
@@ -430,29 +484,29 @@ mod tests {
         let k = Rkv::new(root.path()).expect("new succeeded");
         let sk: Store = k.open_or_create("sk").expect("opened");
 
         // Test reading a number, modifying it, and then writing it back.
         // We have to be done with the Value::I64 before calling Writer::put,
         // as the Value::I64 borrows an immutable reference to the Writer.
         // So we extract and copy its primitive value.
 
-        fn get_existing_foo(writer: &Writer<&str>, store: &Store) -> Option<i64> {
+        fn get_existing_foo(writer: &Writer<&str>, store: Store) -> Option<i64> {
             match writer.get(store, "foo").expect("read") {
                 Some(Value::I64(val)) => Some(val),
                 _ => None,
             }
         }
 
         let mut writer = k.write().expect("writer");
-        let mut existing = get_existing_foo(&writer, &sk).unwrap_or(99);
+        let mut existing = get_existing_foo(&writer, sk).unwrap_or(99);
         existing += 1;
-        writer.put(&sk, "foo", &Value::I64(existing)).expect("success");
+        writer.put(sk, "foo", &Value::I64(existing)).expect("success");
 
-        let updated = get_existing_foo(&writer, &sk).unwrap_or(99);
+        let updated = get_existing_foo(&writer, sk).unwrap_or(99);
         assert_eq!(updated, 100);
         writer.commit().expect("commit");
     }
 
     #[test]
     fn test_read_before_write_str() {
         let root = Builder::new().prefix("test_read_before_write_str").tempdir().expect("tempdir");
         fs::create_dir_all(root.path()).expect("dir created");
@@ -460,22 +514,22 @@ mod tests {
         let sk: Store = k.open_or_create("sk").expect("opened");
 
         // Test reading a string, modifying it, and then writing it back.
         // We have to be done with the Value::Str before calling Writer::put,
         // as the Value::Str (and its underlying &str) borrows an immutable
         // reference to the Writer.  So we copy it to a String.
 
         let mut writer = k.write().expect("writer");
-        let mut existing = match writer.get(&sk, "foo").expect("read") {
+        let mut existing = match writer.get(sk, "foo").expect("read") {
             Some(Value::Str(val)) => val,
             _ => "",
         }.to_string();
         existing.push('…');
-        writer.put(&sk, "foo", &Value::Str(&existing)).expect("write");
+        writer.put(sk, "foo", &Value::Str(&existing)).expect("write");
         writer.commit().expect("commit");
     }
 
     #[test]
     fn test_concurrent_read_transactions_prohibited() {
         let root = Builder::new().prefix("test_concurrent_reads_prohibited").tempdir().expect("tempdir");
         fs::create_dir_all(root.path()).expect("dir created");
         let k = Rkv::new(root.path()).expect("new succeeded");
@@ -498,59 +552,59 @@ mod tests {
         let root = Builder::new().prefix("test_isolation").tempdir().expect("tempdir");
         fs::create_dir_all(root.path()).expect("dir created");
         let k = Rkv::new(root.path()).expect("new succeeded");
         let s: Store = k.open_or_create("s").expect("opened");
 
         // Add one field.
         {
             let mut writer = k.write().expect("writer");
-            writer.put(&s, "foo", &Value::I64(1234)).expect("wrote");
+            writer.put(s, "foo", &Value::I64(1234)).expect("wrote");
             writer.commit().expect("committed");
         }
 
         {
             let reader = k.read().unwrap();
-            assert_eq!(reader.get(&s, "foo").expect("read"), Some(Value::I64(1234)));
+            assert_eq!(reader.get(s, "foo").expect("read"), Some(Value::I64(1234)));
         }
 
         // Establish a long-lived reader that outlasts a writer.
         let reader = k.read().expect("reader");
-        assert_eq!(reader.get(&s, "foo").expect("read"), Some(Value::I64(1234)));
+        assert_eq!(reader.get(s, "foo").expect("read"), Some(Value::I64(1234)));
 
         // Start a write transaction.
         let mut writer = k.write().expect("writer");
-        writer.put(&s, "foo", &Value::I64(999)).expect("wrote");
+        writer.put(s, "foo", &Value::I64(999)).expect("wrote");
 
         // The reader and writer are isolated.
-        assert_eq!(reader.get(&s, "foo").expect("read"), Some(Value::I64(1234)));
-        assert_eq!(writer.get(&s, "foo").expect("read"), Some(Value::I64(999)));
+        assert_eq!(reader.get(s, "foo").expect("read"), Some(Value::I64(1234)));
+        assert_eq!(writer.get(s, "foo").expect("read"), Some(Value::I64(999)));
 
         // If we commit the writer, we still have isolation.
         writer.commit().expect("committed");
-        assert_eq!(reader.get(&s, "foo").expect("read"), Some(Value::I64(1234)));
+        assert_eq!(reader.get(s, "foo").expect("read"), Some(Value::I64(1234)));
 
         // A new reader sees the committed value. Note that LMDB doesn't allow two
         // read transactions to exist in the same thread, so we abort the previous one.
         reader.abort();
         let reader = k.read().expect("reader");
-        assert_eq!(reader.get(&s, "foo").expect("read"), Some(Value::I64(999)));
+        assert_eq!(reader.get(s, "foo").expect("read"), Some(Value::I64(999)));
     }
 
     #[test]
     fn test_blob() {
         let root = Builder::new().prefix("test_round_trip_blob").tempdir().expect("tempdir");
         fs::create_dir_all(root.path()).expect("dir created");
         let k = Rkv::new(root.path()).expect("new succeeded");
         let sk: Store = k.open_or_create("sk").expect("opened");
         let mut writer = k.write().expect("writer");
 
-        assert_eq!(writer.get(&sk, "foo").expect("read"), None);
-        writer.put(&sk, "foo", &Value::Blob(&[1, 2, 3, 4])).expect("wrote");
-        assert_eq!(writer.get(&sk, "foo").expect("read"), Some(Value::Blob(&[1, 2, 3, 4])));
+        assert_eq!(writer.get(sk, "foo").expect("read"), None);
+        writer.put(sk, "foo", &Value::Blob(&[1, 2, 3, 4])).expect("wrote");
+        assert_eq!(writer.get(sk, "foo").expect("read"), Some(Value::Blob(&[1, 2, 3, 4])));
 
         fn u16_to_u8(src: &[u16]) -> Vec<u8> {
             let mut dst = vec![0; 2 * src.len()];
             LittleEndian::write_u16_into(src, &mut dst);
             dst
         }
 
         fn u8_to_u16(src: &[u8]) -> Vec<u16> {
@@ -558,66 +612,66 @@ mod tests {
             LittleEndian::read_u16_into(src, &mut dst);
             dst
         }
 
         // When storing UTF-16 strings as blobs, we'll need to convert
         // their [u16] backing storage to [u8].  Test that converting, writing,
         // reading, and converting back works as expected.
         let u16_array = [1000, 10000, 54321, 65535];
-        assert_eq!(writer.get(&sk, "bar").expect("read"), None);
-        writer.put(&sk, "bar", &Value::Blob(&u16_to_u8(&u16_array))).expect("wrote");
-        let u8_array = match writer.get(&sk, "bar").expect("read") {
+        assert_eq!(writer.get(sk, "bar").expect("read"), None);
+        writer.put(sk, "bar", &Value::Blob(&u16_to_u8(&u16_array))).expect("wrote");
+        let u8_array = match writer.get(sk, "bar").expect("read") {
             Some(Value::Blob(val)) => val,
             _ => &[],
         };
         assert_eq!(u8_to_u16(u8_array), u16_array);
     }
 
     #[test]
     #[should_panic(expected = "not yet implemented")]
     fn test_delete_value() {
         let root = Builder::new().prefix("test_delete_value").tempdir().expect("tempdir");
         fs::create_dir_all(root.path()).expect("dir created");
         let k = Rkv::new(root.path()).expect("new succeeded");
         let sk: Store = k.open_or_create_with_flags("sk", DatabaseFlags::DUP_SORT).expect("opened");
 
         let mut writer = k.write().expect("writer");
-        writer.put(&sk, "foo", &Value::I64(1234)).expect("wrote");
-        writer.put(&sk, "foo", &Value::I64(1235)).expect("wrote");
-        writer.delete_value(&sk, "foo", &Value::I64(1234)).expect("deleted");
+        writer.put(sk, "foo", &Value::I64(1234)).expect("wrote");
+        writer.put(sk, "foo", &Value::I64(1235)).expect("wrote");
+        writer.delete_value(sk, "foo", &Value::I64(1234)).expect("deleted");
     }
 
     #[test]
     fn test_iter() {
         let root = Builder::new().prefix("test_iter").tempdir().expect("tempdir");
         fs::create_dir_all(root.path()).expect("dir created");
         let k = Rkv::new(root.path()).expect("new succeeded");
         let sk: Store = k.open_or_create("sk").expect("opened");
 
         // An iterator over an empty store returns no values.
         {
             let reader = k.read::<&str>().unwrap();
-            let mut iter = reader.iter_start(&sk).unwrap();
+            let mut iter = reader.iter_start(sk).unwrap();
             assert!(iter.next().is_none());
         }
 
         let mut writer = k.write().expect("writer");
-        writer.put(&sk, "foo", &Value::I64(1234)).expect("wrote");
-        writer.put(&sk, "noo", &Value::F64(1234.0.into())).expect("wrote");
-        writer.put(&sk, "bar", &Value::Bool(true)).expect("wrote");
-        writer.put(&sk, "baz", &Value::Str("héllo, yöu")).expect("wrote");
-        writer.put(&sk, "héllò, töűrîst", &Value::Str("Emil.RuleZ!")).expect("wrote");
-        writer.put(&sk, "你好,遊客", &Value::Str("米克規則")).expect("wrote");
+        writer.put(sk, "foo", &Value::I64(1234)).expect("wrote");
+        writer.put(sk, "noo", &Value::F64(1234.0.into())).expect("wrote");
+        writer.put(sk, "bar", &Value::Bool(true)).expect("wrote");
+        writer.put(sk, "baz", &Value::Str("héllo, yöu")).expect("wrote");
+        writer.put(sk, "héllò, töűrîst", &Value::Str("Emil.RuleZ!")).expect("wrote");
+        writer.put(sk, "你好,遊客", &Value::Str("米克規則")).expect("wrote");
         writer.commit().expect("committed");
 
         let reader = k.read().unwrap();
 
         // Reader.iter() returns (key, value) tuples ordered by key.
-        let mut iter = reader.iter_start(&sk).unwrap();
+        let mut iter = reader.iter_start(sk).unwrap();
         let (key, val) = iter.next().unwrap();
         assert_eq!(str::from_utf8(key).expect("key"), "bar");
         assert_eq!(val.expect("value"), Some(Value::Bool(true)));
         let (key, val) = iter.next().unwrap();
         assert_eq!(str::from_utf8(key).expect("key"), "baz");
         assert_eq!(val.expect("value"), Some(Value::Str("héllo, yöu")));
         let (key, val) = iter.next().unwrap();
         assert_eq!(str::from_utf8(key).expect("key"), "foo");
@@ -634,28 +688,28 @@ mod tests {
         assert!(iter.next().is_none());
 
         // Iterators don't loop.  Once one returns None, additional calls
         // to its next() method will always return None.
         assert!(iter.next().is_none());
 
         // Reader.iter_from() begins iteration at the first key equal to
         // or greater than the given key.
-        let mut iter = reader.iter_from(&sk, "moo").unwrap();
+        let mut iter = reader.iter_from(sk, "moo").unwrap();
         let (key, val) = iter.next().unwrap();
         assert_eq!(str::from_utf8(key).expect("key"), "noo");
         assert_eq!(val.expect("value"), Some(Value::F64(1234.0.into())));
         let (key, val) = iter.next().unwrap();
         assert_eq!(str::from_utf8(key).expect("key"), "你好,遊客");
         assert_eq!(val.expect("value"), Some(Value::Str("米克規則")));
         assert!(iter.next().is_none());
 
         // Reader.iter_from() works as expected when the given key is a prefix
         // of a key in the store.
-        let mut iter = reader.iter_from(&sk, "no").unwrap();
+        let mut iter = reader.iter_from(sk, "no").unwrap();
         let (key, val) = iter.next().unwrap();
         assert_eq!(str::from_utf8(key).expect("key"), "noo");
         assert_eq!(val.expect("value"), Some(Value::F64(1234.0.into())));
         let (key, val) = iter.next().unwrap();
         assert_eq!(str::from_utf8(key).expect("key"), "你好,遊客");
         assert_eq!(val.expect("value"), Some(Value::Str("米克規則")));
         assert!(iter.next().is_none());
     }
@@ -663,96 +717,96 @@ mod tests {
     #[test]
     fn test_iter_from_key_greater_than_existing() {
         let root = Builder::new().prefix("test_iter_from_key_greater_than_existing").tempdir().expect("tempdir");
         fs::create_dir_all(root.path()).expect("dir created");
         let k = Rkv::new(root.path()).expect("new succeeded");
         let sk: Store = k.open_or_create("sk").expect("opened");
 
         let mut writer = k.write().expect("writer");
-        writer.put(&sk, "foo", &Value::I64(1234)).expect("wrote");
-        writer.put(&sk, "noo", &Value::F64(1234.0.into())).expect("wrote");
-        writer.put(&sk, "bar", &Value::Bool(true)).expect("wrote");
-        writer.put(&sk, "baz", &Value::Str("héllo, yöu")).expect("wrote");
+        writer.put(sk, "foo", &Value::I64(1234)).expect("wrote");
+        writer.put(sk, "noo", &Value::F64(1234.0.into())).expect("wrote");
+        writer.put(sk, "bar", &Value::Bool(true)).expect("wrote");
+        writer.put(sk, "baz", &Value::Str("héllo, yöu")).expect("wrote");
         writer.commit().expect("committed");
 
         let reader = k.read().unwrap();
-        let mut iter = reader.iter_from(&sk, "nuu").unwrap();
+        let mut iter = reader.iter_from(sk, "nuu").unwrap();
         assert!(iter.next().is_none());
     }
 
     #[test]
     fn test_multiple_store_read_write() {
         let root = Builder::new().prefix("test_multiple_store_read_write").tempdir().expect("tempdir");
         fs::create_dir_all(root.path()).expect("dir created");
         let k = Rkv::new(root.path()).expect("new succeeded");
 
         let s1: Store = k.open_or_create("store_1").expect("opened");
         let s2: Store = k.open_or_create("store_2").expect("opened");
         let s3: Store = k.open_or_create("store_3").expect("opened");
 
         let mut writer = k.write().expect("writer");
-        writer.put(&s1, "foo", &Value::Str("bar")).expect("wrote");
-        writer.put(&s2, "foo", &Value::I64(123)).expect("wrote");
-        writer.put(&s3, "foo", &Value::Bool(true)).expect("wrote");
+        writer.put(s1, "foo", &Value::Str("bar")).expect("wrote");
+        writer.put(s2, "foo", &Value::I64(123)).expect("wrote");
+        writer.put(s3, "foo", &Value::Bool(true)).expect("wrote");
 
-        assert_eq!(writer.get(&s1, "foo").expect("read"), Some(Value::Str("bar")));
-        assert_eq!(writer.get(&s2, "foo").expect("read"), Some(Value::I64(123)));
-        assert_eq!(writer.get(&s3, "foo").expect("read"), Some(Value::Bool(true)));
+        assert_eq!(writer.get(s1, "foo").expect("read"), Some(Value::Str("bar")));
+        assert_eq!(writer.get(s2, "foo").expect("read"), Some(Value::I64(123)));
+        assert_eq!(writer.get(s3, "foo").expect("read"), Some(Value::Bool(true)));
 
         writer.commit().expect("committed");
 
         let reader = k.read().expect("unbound_reader");
-        assert_eq!(reader.get(&s1, "foo").expect("read"), Some(Value::Str("bar")));
-        assert_eq!(reader.get(&s2, "foo").expect("read"), Some(Value::I64(123)));
-        assert_eq!(reader.get(&s3, "foo").expect("read"), Some(Value::Bool(true)));
+        assert_eq!(reader.get(s1, "foo").expect("read"), Some(Value::Str("bar")));
+        assert_eq!(reader.get(s2, "foo").expect("read"), Some(Value::I64(123)));
+        assert_eq!(reader.get(s3, "foo").expect("read"), Some(Value::Bool(true)));
         reader.abort();
 
         // test delete across multiple stores
         let mut writer = k.write().expect("writer");
-        writer.delete(&s1, "foo").expect("deleted");
-        writer.delete(&s2, "foo").expect("deleted");
-        writer.delete(&s3, "foo").expect("deleted");
+        writer.delete(s1, "foo").expect("deleted");
+        writer.delete(s2, "foo").expect("deleted");
+        writer.delete(s3, "foo").expect("deleted");
         writer.commit().expect("committed");
 
         let reader = k.read().expect("reader");
-        assert_eq!(reader.get(&s1, "key").expect("value"), None);
-        assert_eq!(reader.get(&s2, "key").expect("value"), None);
-        assert_eq!(reader.get(&s3, "key").expect("value"), None);
+        assert_eq!(reader.get(s1, "key").expect("value"), None);
+        assert_eq!(reader.get(s2, "key").expect("value"), None);
+        assert_eq!(reader.get(s3, "key").expect("value"), None);
     }
 
     #[test]
     fn test_multiple_store_iter() {
         let root = Builder::new().prefix("test_multiple_store_iter").tempdir().expect("tempdir");
         fs::create_dir_all(root.path()).expect("dir created");
         let k = Rkv::new(root.path()).expect("new succeeded");
         let s1: Store = k.open_or_create("store_1").expect("opened");
         let s2: Store = k.open_or_create("store_2").expect("opened");
 
         let mut writer = k.write().expect("writer");
         // Write to "s1"
-        writer.put(&s1, "foo", &Value::I64(1234)).expect("wrote");
-        writer.put(&s1, "noo", &Value::F64(1234.0.into())).expect("wrote");
-        writer.put(&s1, "bar", &Value::Bool(true)).expect("wrote");
-        writer.put(&s1, "baz", &Value::Str("héllo, yöu")).expect("wrote");
-        writer.put(&s1, "héllò, töűrîst", &Value::Str("Emil.RuleZ!")).expect("wrote");
-        writer.put(&s1, "你好,遊客", &Value::Str("米克規則")).expect("wrote");
+        writer.put(s1, "foo", &Value::I64(1234)).expect("wrote");
+        writer.put(s1, "noo", &Value::F64(1234.0.into())).expect("wrote");
+        writer.put(s1, "bar", &Value::Bool(true)).expect("wrote");
+        writer.put(s1, "baz", &Value::Str("héllo, yöu")).expect("wrote");
+        writer.put(s1, "héllò, töűrîst", &Value::Str("Emil.RuleZ!")).expect("wrote");
+        writer.put(s1, "你好,遊客", &Value::Str("米克規則")).expect("wrote");
         // Writer to "s2"
-        writer.put(&s2, "foo", &Value::I64(1234)).expect("wrote");
-        writer.put(&s2, "noo", &Value::F64(1234.0.into())).expect("wrote");
-        writer.put(&s2, "bar", &Value::Bool(true)).expect("wrote");
-        writer.put(&s2, "baz", &Value::Str("héllo, yöu")).expect("wrote");
-        writer.put(&s2, "héllò, töűrîst", &Value::Str("Emil.RuleZ!")).expect("wrote");
-        writer.put(&s2, "你好,遊客", &Value::Str("米克規則")).expect("wrote");
+        writer.put(s2, "foo", &Value::I64(1234)).expect("wrote");
+        writer.put(s2, "noo", &Value::F64(1234.0.into())).expect("wrote");
+        writer.put(s2, "bar", &Value::Bool(true)).expect("wrote");
+        writer.put(s2, "baz", &Value::Str("héllo, yöu")).expect("wrote");
+        writer.put(s2, "héllò, töűrîst", &Value::Str("Emil.RuleZ!")).expect("wrote");
+        writer.put(s2, "你好,遊客", &Value::Str("米克規則")).expect("wrote");
         writer.commit().expect("committed");
 
         let reader = k.read().unwrap();
 
         // Iterate through the whole store in "s1"
-        let mut iter = reader.iter_start(&s1).unwrap();
+        let mut iter = reader.iter_start(s1).unwrap();
         let (key, val) = iter.next().unwrap();
         assert_eq!(str::from_utf8(key).expect("key"), "bar");
         assert_eq!(val.expect("value"), Some(Value::Bool(true)));
         let (key, val) = iter.next().unwrap();
         assert_eq!(str::from_utf8(key).expect("key"), "baz");
         assert_eq!(val.expect("value"), Some(Value::Str("héllo, yöu")));
         let (key, val) = iter.next().unwrap();
         assert_eq!(str::from_utf8(key).expect("key"), "foo");
@@ -764,17 +818,17 @@ mod tests {
         assert_eq!(str::from_utf8(key).expect("key"), "noo");
         assert_eq!(val.expect("value"), Some(Value::F64(1234.0.into())));
         let (key, val) = iter.next().unwrap();
         assert_eq!(str::from_utf8(key).expect("key"), "你好,遊客");
         assert_eq!(val.expect("value"), Some(Value::Str("米克規則")));
         assert!(iter.next().is_none());
 
         // Iterate through the whole store in "s2"
-        let mut iter = reader.iter_start(&s2).unwrap();
+        let mut iter = reader.iter_start(s2).unwrap();
         let (key, val) = iter.next().unwrap();
         assert_eq!(str::from_utf8(key).expect("key"), "bar");
         assert_eq!(val.expect("value"), Some(Value::Bool(true)));
         let (key, val) = iter.next().unwrap();
         assert_eq!(str::from_utf8(key).expect("key"), "baz");
         assert_eq!(val.expect("value"), Some(Value::Str("héllo, yöu")));
         let (key, val) = iter.next().unwrap();
         assert_eq!(str::from_utf8(key).expect("key"), "foo");
@@ -786,47 +840,47 @@ mod tests {
         assert_eq!(str::from_utf8(key).expect("key"), "noo");
         assert_eq!(val.expect("value"), Some(Value::F64(1234.0.into())));
         let (key, val) = iter.next().unwrap();
         assert_eq!(str::from_utf8(key).expect("key"), "你好,遊客");
         assert_eq!(val.expect("value"), Some(Value::Str("米克規則")));
         assert!(iter.next().is_none());
 
         // Iterate from a given key in "s1"
-        let mut iter = reader.iter_from(&s1, "moo").unwrap();
+        let mut iter = reader.iter_from(s1, "moo").unwrap();
         let (key, val) = iter.next().unwrap();
         assert_eq!(str::from_utf8(key).expect("key"), "noo");
         assert_eq!(val.expect("value"), Some(Value::F64(1234.0.into())));
         let (key, val) = iter.next().unwrap();
         assert_eq!(str::from_utf8(key).expect("key"), "你好,遊客");
         assert_eq!(val.expect("value"), Some(Value::Str("米克規則")));
         assert!(iter.next().is_none());
 
         // Iterate from a given key in "s2"
-        let mut iter = reader.iter_from(&s2, "moo").unwrap();
+        let mut iter = reader.iter_from(s2, "moo").unwrap();
         let (key, val) = iter.next().unwrap();
         assert_eq!(str::from_utf8(key).expect("key"), "noo");
         assert_eq!(val.expect("value"), Some(Value::F64(1234.0.into())));
         let (key, val) = iter.next().unwrap();
         assert_eq!(str::from_utf8(key).expect("key"), "你好,遊客");
         assert_eq!(val.expect("value"), Some(Value::Str("米克規則")));
         assert!(iter.next().is_none());
 
         // Iterate from a given prefix in "s1"
-        let mut iter = reader.iter_from(&s1, "no").unwrap();
+        let mut iter = reader.iter_from(s1, "no").unwrap();
         let (key, val) = iter.next().unwrap();
         assert_eq!(str::from_utf8(key).expect("key"), "noo");
         assert_eq!(val.expect("value"), Some(Value::F64(1234.0.into())));
         let (key, val) = iter.next().unwrap();
         assert_eq!(str::from_utf8(key).expect("key"), "你好,遊客");
         assert_eq!(val.expect("value"), Some(Value::Str("米克規則")));
         assert!(iter.next().is_none());
 
         // Iterate from a given prefix in "s2"
-        let mut iter = reader.iter_from(&s2, "no").unwrap();
+        let mut iter = reader.iter_from(s2, "no").unwrap();
         let (key, val) = iter.next().unwrap();
         assert_eq!(str::from_utf8(key).expect("key"), "noo");
         assert_eq!(val.expect("value"), Some(Value::F64(1234.0.into())));
         let (key, val) = iter.next().unwrap();
         assert_eq!(str::from_utf8(key).expect("key"), "你好,遊客");
         assert_eq!(val.expect("value"), Some(Value::Str("米克規則")));
         assert!(iter.next().is_none());
     }
@@ -848,32 +902,32 @@ mod tests {
         // is just to confirm that a store can be shared by multiple threads.
 
         // For each KV pair, spawn a thread that writes it to the store.
         for i in 0..num_threads {
             let rkv_arc = rkv_arc.clone();
             write_handles.push(thread::spawn(move || {
                 let rkv = rkv_arc.write().expect("rkv");
                 let mut writer = rkv.write().expect("writer");
-                writer.put(&store, i.to_string(), &Value::U64(i)).expect("written");
+                writer.put(store, i.to_string(), &Value::U64(i)).expect("written");
                 writer.commit().unwrap();
             }));
         }
         for handle in write_handles {
             handle.join().expect("joined");
         }
 
         // For each KV pair, spawn a thread that reads it from the store
         // and returns its value.
         for i in 0..num_threads {
             let rkv_arc = rkv_arc.clone();
             read_handles.push(thread::spawn(move || {
                 let rkv = rkv_arc.read().expect("rkv");
                 let reader = rkv.read().expect("reader");
-                let value = match reader.get(&store, i.to_string()) {
+                let value = match reader.get(store, i.to_string()) {
                     Ok(Some(Value::U64(value))) => value,
                     Ok(Some(_)) => panic!("value type unexpected"),
                     Ok(None) => panic!("value not found"),
                     Err(err) => panic!(err),
                 };
                 assert_eq!(value, i);
                 value
             }));
--- a/third_party/rust/rkv/src/integer.rs
+++ b/third_party/rust/rkv/src/integer.rs
@@ -85,18 +85,18 @@ where
     K: PrimitiveInt,
 {
     pub(crate) fn new(reader: Reader<Key<K>>) -> IntegerReader<K> {
         IntegerReader {
             inner: reader,
         }
     }
 
-    pub fn get<'s>(&'s self, store: &'s IntegerStore, k: K) -> Result<Option<Value<'s>>, StoreError> {
-        self.inner.get(&store.inner, Key::new(k)?)
+    pub fn get(&self, store: IntegerStore, k: K) -> Result<Option<Value>, StoreError> {
+        self.inner.get(store.0, Key::new(k)?)
     }
 
     pub fn abort(self) {
         self.inner.abort();
     }
 }
 
 pub struct IntegerWriter<'env, K>
@@ -111,42 +111,39 @@ where
     K: PrimitiveInt,
 {
     pub(crate) fn new(writer: Writer<Key<K>>) -> IntegerWriter<K> {
         IntegerWriter {
             inner: writer,
         }
     }
 
-    pub fn get<'s>(&'s self, store: &'s IntegerStore, k: K) -> Result<Option<Value<'s>>, StoreError> {
-        self.inner.get(&store.inner, Key::new(k)?)
+    pub fn get(&self, store: IntegerStore, k: K) -> Result<Option<Value>, StoreError> {
+        self.inner.get(store.0, Key::new(k)?)
     }
 
-    pub fn put<'s>(&'s mut self, store: &'s IntegerStore, k: K, v: &Value) -> Result<(), StoreError> {
-        self.inner.put(&store.inner, Key::new(k)?, v)
+    pub fn put(&mut self, store: IntegerStore, k: K, v: &Value) -> Result<(), StoreError> {
+        self.inner.put(store.0, Key::new(k)?, v)
     }
 
     fn abort(self) {
         self.inner.abort();
     }
 
     fn commit(self) -> Result<(), StoreError> {
         self.inner.commit()
     }
 }
 
-pub struct IntegerStore {
-    inner: Store,
-}
+#[derive(Copy, Clone)]
+pub struct IntegerStore(Store);
 
 impl IntegerStore {
     pub fn new(db: Database) -> IntegerStore {
-        IntegerStore {
-            inner: Store::new(db),
-        }
+        IntegerStore(Store::new(db))
     }
 }
 
 #[cfg(test)]
 mod tests {
     extern crate tempfile;
 
     use self::tempfile::Builder;
@@ -159,16 +156,16 @@ mod tests {
     fn test_integer_keys() {
         let root = Builder::new().prefix("test_integer_keys").tempdir().expect("tempdir");
         fs::create_dir_all(root.path()).expect("dir created");
         let k = Rkv::new(root.path()).expect("new succeeded");
         let s = k.open_or_create_integer("s").expect("open");
 
         let mut writer = k.write_int::<u32>().expect("writer");
 
-        writer.put(&s, 123, &Value::Str("hello!")).expect("write");
-        assert_eq!(writer.get(&s, 123).expect("read"), Some(Value::Str("hello!")));
+        writer.put(s, 123, &Value::Str("hello!")).expect("write");
+        assert_eq!(writer.get(s, 123).expect("read"), Some(Value::Str("hello!")));
         writer.commit().expect("committed");
 
         let reader = k.read_int::<u32>().expect("reader");
-        assert_eq!(reader.get(&s, 123).expect("read"), Some(Value::Str("hello!")));
+        assert_eq!(reader.get(s, 123).expect("read"), Some(Value::Str("hello!")));
     }
 }
--- a/third_party/rust/rkv/src/lib.rs
+++ b/third_party/rust/rkv/src/lib.rs
@@ -74,100 +74,100 @@
 //!     // `Rkv.write()` to create a `Writer`.  There can be only one
 //!     // writer for a given store; opening a second one will block
 //!     // until the first completes.
 //!     let mut writer = env.write().unwrap();
 //!
 //!     // Writer takes a `Store` reference as the first argument.
 //!     // Keys are `AsRef<[u8]>`, while values are `Value` enum instances.
 //!     // Use the `Blob` variant to store arbitrary collections of bytes.
-//!     writer.put(&store, "int", &Value::I64(1234)).unwrap();
-//!     writer.put(&store, "uint", &Value::U64(1234_u64)).unwrap();
-//!     writer.put(&store, "float", &Value::F64(1234.0.into())).unwrap();
-//!     writer.put(&store, "instant", &Value::Instant(1528318073700)).unwrap();
-//!     writer.put(&store, "boolean", &Value::Bool(true)).unwrap();
-//!     writer.put(&store, "string", &Value::Str("héllo, yöu")).unwrap();
-//!     writer.put(&store, "json", &Value::Json(r#"{"foo":"bar", "number": 1}"#)).unwrap();
-//!     writer.put(&store, "blob", &Value::Blob(b"blob")).unwrap();
+//!     writer.put(store, "int", &Value::I64(1234)).unwrap();
+//!     writer.put(store, "uint", &Value::U64(1234_u64)).unwrap();
+//!     writer.put(store, "float", &Value::F64(1234.0.into())).unwrap();
+//!     writer.put(store, "instant", &Value::Instant(1528318073700)).unwrap();
+//!     writer.put(store, "boolean", &Value::Bool(true)).unwrap();
+//!     writer.put(store, "string", &Value::Str("héllo, yöu")).unwrap();
+//!     writer.put(store, "json", &Value::Json(r#"{"foo":"bar", "number": 1}"#)).unwrap();
+//!     writer.put(store, "blob", &Value::Blob(b"blob")).unwrap();
 //!
 //!     // You must commit a write transaction before the writer goes out
 //!     // of scope, or the transaction will abort and the data won't persist.
 //!     writer.commit().unwrap();
 //! }
 //!
 //! {
 //!     // Use a read transaction to query the store by calling `Rkv.read()`
 //!     // to create a `Reader`.  There can be unlimited concurrent readers
 //!     // for a store, and readers never block on a writer nor other readers.
 //!     let reader = env.read().expect("reader");
 //!
 //!     // To retrieve data, call `Reader.get()`, passing it the target store
 //!     // and the key for the value to retrieve.
-//!     println!("Get int {:?}", reader.get(&store, "int").unwrap());
-//!     println!("Get uint {:?}", reader.get(&store, "uint").unwrap());
-//!     println!("Get float {:?}", reader.get(&store, "float").unwrap());
-//!     println!("Get instant {:?}", reader.get(&store, "instant").unwrap());
-//!     println!("Get boolean {:?}", reader.get(&store, "boolean").unwrap());
-//!     println!("Get string {:?}", reader.get(&store, "string").unwrap());
-//!     println!("Get json {:?}", reader.get(&store, "json").unwrap());
-//!     println!("Get blob {:?}", reader.get(&store, "blob").unwrap());
+//!     println!("Get int {:?}", reader.get(store, "int").unwrap());
+//!     println!("Get uint {:?}", reader.get(store, "uint").unwrap());
+//!     println!("Get float {:?}", reader.get(store, "float").unwrap());
+//!     println!("Get instant {:?}", reader.get(store, "instant").unwrap());
+//!     println!("Get boolean {:?}", reader.get(store, "boolean").unwrap());
+//!     println!("Get string {:?}", reader.get(store, "string").unwrap());
+//!     println!("Get json {:?}", reader.get(store, "json").unwrap());
+//!     println!("Get blob {:?}", reader.get(store, "blob").unwrap());
 //!
 //!     // Retrieving a non-existent value returns `Ok(None)`.
-//!     println!("Get non-existent value {:?}", reader.get(&store, "non-existent"));
+//!     println!("Get non-existent value {:?}", reader.get(store, "non-existent"));
 //!
 //!     // A read transaction will automatically close once the reader
 //!     // goes out of scope, so isn't necessary to close it explicitly,
 //!     // although you can do so by calling `Reader.abort()`.
 //! }
 //!
 //! {
 //!     // Aborting a write transaction rolls back the change(s).
 //!     let mut writer = env.write().unwrap();
-//!     writer.put(&store, "foo", &Value::Str("bar")).unwrap();
+//!     writer.put(store, "foo", &Value::Str("bar")).unwrap();
 //!     writer.abort();
 //!
 //!     let reader = env.read().expect("reader");
-//!     println!("It should be None! ({:?})", reader.get(&store, "foo").unwrap());
+//!     println!("It should be None! ({:?})", reader.get(store, "foo").unwrap());
 //! }
 //!
 //! {
 //!     // Explicitly aborting a transaction is not required unless an early
 //!     // abort is desired, since both read and write transactions will
 //!     // implicitly be aborted once they go out of scope.
 //!     {
 //!         let mut writer = env.write().unwrap();
-//!         writer.put(&store, "foo", &Value::Str("bar")).unwrap();
+//!         writer.put(store, "foo", &Value::Str("bar")).unwrap();
 //!     }
 //!     let reader = env.read().expect("reader");
-//!     println!("It should be None! ({:?})", reader.get(&store, "foo").unwrap());
+//!     println!("It should be None! ({:?})", reader.get(store, "foo").unwrap());
 //! }
 //!
 //! {
 //!     // Deleting a key/value pair also requires a write transaction.
 //!     let mut writer = env.write().unwrap();
-//!     writer.put(&store, "foo", &Value::Str("bar")).unwrap();
-//!     writer.put(&store, "bar", &Value::Str("baz")).unwrap();
-//!     writer.delete(&store, "foo").unwrap();
+//!     writer.put(store, "foo", &Value::Str("bar")).unwrap();
+//!     writer.put(store, "bar", &Value::Str("baz")).unwrap();
+//!     writer.delete(store, "foo").unwrap();
 //!
 //!     // A write transaction also supports reading, the version of the
 //!     // store that it reads includes changes it has made regardless of
 //!     // the commit state of that transaction.
 //!     // In the code above, "foo" and "bar" were put into the store,
 //!     // then "foo" was deleted so only "bar" will return a result.
-//!     println!("It should be None! ({:?})", writer.get(&store, "foo").unwrap());
-//!     println!("Get bar ({:?})", writer.get(&store, "bar").unwrap());
+//!     println!("It should be None! ({:?})", writer.get(store, "foo").unwrap());
+//!     println!("Get bar ({:?})", writer.get(store, "bar").unwrap());
 //!     writer.commit().unwrap();
 //!     let reader = env.read().expect("reader");
-//!     println!("It should be None! ({:?})", reader.get(&store, "foo").unwrap());
-//!     println!("Get bar {:?}", reader.get(&store, "bar").unwrap());
+//!     println!("It should be None! ({:?})", reader.get(store, "foo").unwrap());
+//!     println!("Get bar {:?}", reader.get(store, "bar").unwrap());
 //!
 //!     // Committing a transaction consumes the writer, preventing you
 //!     // from reusing it by failing at compile time with an error.
 //!     // This line would report error[E0382]: use of moved value: `writer`.
-//!     // writer.put(&store, "baz", &Value::Str("buz")).unwrap();
+//!     // writer.put(store, "baz", &Value::Str("buz")).unwrap();
 //! }
 //! ```
 
 #![allow(dead_code)]
 
 #[macro_use]
 extern crate arrayref;
 #[macro_use]
@@ -213,9 +213,12 @@ pub use integer::{
 pub use manager::Manager;
 
 pub use readwrite::{
     Reader,
     Store,
     Writer,
 };
 
-pub use value::Value;
+pub use value::{
+    OwnedValue,
+    Value,
+};
--- a/third_party/rust/rkv/src/readwrite.rs
+++ b/third_party/rust/rkv/src/readwrite.rs
@@ -23,17 +23,17 @@ use lmdb::{
 };
 
 use lmdb::WriteFlags;
 
 use error::StoreError;
 
 use value::Value;
 
-fn read_transform<'x>(val: Result<&'x [u8], lmdb::Error>) -> Result<Option<Value<'x>>, StoreError> {
+fn read_transform(val: Result<&[u8], lmdb::Error>) -> Result<Option<Value>, StoreError> {
     match val {
         Ok(bytes) => Value::from_tagged_slice(bytes).map(Some).map_err(StoreError::DataError),
         Err(lmdb::Error::NotFound) => Ok(None),
         Err(e) => Err(StoreError::LmdbError(e)),
     }
 }
 
 pub struct Writer<'env, K>
@@ -63,33 +63,33 @@ where
 {
     pub(crate) fn new(txn: RwTransaction) -> Writer<K> {
         Writer {
             tx: txn,
             phantom: PhantomData,
         }
     }
 
-    pub fn get<'s>(&'s self, store: &'s Store, k: K) -> Result<Option<Value<'s>>, StoreError> {
-        let bytes = self.tx.get(store.db, &k.as_ref());
+    pub fn get(&self, store: Store, k: K) -> Result<Option<Value>, StoreError> {
+        let bytes = self.tx.get(store.0, &k);
         read_transform(bytes)
     }
 
     // TODO: flags
-    pub fn put<'s>(&'s mut self, store: &'s Store, k: K, v: &Value) -> Result<(), StoreError> {
+    pub fn put(&mut self, store: Store, k: K, v: &Value) -> Result<(), StoreError> {
         // TODO: don't allocate twice.
         let bytes = v.to_bytes()?;
-        self.tx.put(store.db, &k.as_ref(), &bytes, WriteFlags::empty()).map_err(StoreError::LmdbError)
+        self.tx.put(store.0, &k, &bytes, WriteFlags::empty()).map_err(StoreError::LmdbError)
     }
 
-    pub fn delete<'s>(&'s mut self, store: &'s Store, k: K) -> Result<(), StoreError> {
-        self.tx.del(store.db, &k.as_ref(), None).map_err(StoreError::LmdbError)
+    pub fn delete(&mut self, store: Store, k: K) -> Result<(), StoreError> {
+        self.tx.del(store.0, &k, None).map_err(StoreError::LmdbError)
     }
 
-    pub fn delete_value<'s>(&'s mut self, _store: &'s Store, _k: K, _v: &Value) -> Result<(), StoreError> {
+    pub fn delete_value(&mut self, _store: Store, _k: K, _v: &Value) -> Result<(), StoreError> {
         // Even better would be to make this a method only on a dupsort store —
         // it would need a little bit of reorganizing of types and traits,
         // but when I see "If the database does not support sorted duplicate
         // data items (MDB_DUPSORT) the data parameter is ignored" in the docs,
         // I see a footgun that we can avoid by using the type system.
         unimplemented!();
     }
 
@@ -108,27 +108,27 @@ where
 {
     pub(crate) fn new(txn: RoTransaction) -> Reader<K> {
         Reader {
             tx: txn,
             phantom: PhantomData,
         }
     }
 
-    pub fn get<'s>(&'s self, store: &'s Store, k: K) -> Result<Option<Value<'s>>, StoreError> {
-        let bytes = self.tx.get(store.db, &k.as_ref());
+    pub fn get(&self, store: Store, k: K) -> Result<Option<Value>, StoreError> {
+        let bytes = self.tx.get(store.0, &k);
         read_transform(bytes)
     }
 
     pub fn abort(self) {
         self.tx.abort();
     }
 
-    pub fn iter_start<'s>(&'s self, store: &'s Store) -> Result<Iter<'s>, StoreError> {
-        let mut cursor = self.tx.open_ro_cursor(store.db).map_err(StoreError::LmdbError)?;
+    pub fn iter_start(&self, store: Store) -> Result<Iter, StoreError> {
+        let mut cursor = self.tx.open_ro_cursor(store.0).map_err(StoreError::LmdbError)?;
 
         // We call Cursor.iter() instead of Cursor.iter_start() because
         // the latter panics at "called `Result::unwrap()` on an `Err` value:
         // NotFound" when there are no items in the store, whereas the former
         // returns an iterator that yields no items.
         //
         // And since we create the Cursor and don't change its position, we can
         // be sure that a call to Cursor.iter() will start at the beginning.
@@ -136,43 +136,39 @@ where
         let iter = cursor.iter();
 
         Ok(Iter {
             iter,
             cursor,
         })
     }
 
-    pub fn iter_from<'s>(&'s self, store: &'s Store, k: K) -> Result<Iter<'s>, StoreError> {
-        let mut cursor = self.tx.open_ro_cursor(store.db).map_err(StoreError::LmdbError)?;
+    pub fn iter_from(&self, store: Store, k: K) -> Result<Iter, StoreError> {
+        let mut cursor = self.tx.open_ro_cursor(store.0).map_err(StoreError::LmdbError)?;
         let iter = cursor.iter_from(k);
         Ok(Iter {
             iter,
             cursor,
         })
     }
 }
 
 impl<'env> Iterator for Iter<'env> {
     type Item = (&'env [u8], Result<Option<Value<'env>>, StoreError>);
 
-    fn next(&mut self) -> Option<(&'env [u8], Result<Option<Value<'env>>, StoreError>)> {
+    fn next(&mut self) -> Option<Self::Item> {
         match self.iter.next() {
             None => None,
             Some((key, bytes)) => Some((key, read_transform(Ok(bytes)))),
         }
     }
 }
 
-/// Wrapper around an `lmdb::Database`.  At this time, the underlying LMDB
+/// New type around an `lmdb::Database`.  At this time, the underlying LMDB
 /// handle (within lmdb-rs::Database) is a C integer, so Copy is automatic.
 #[derive(Copy, Clone)]
-pub struct Store {
-    db: Database,
-}
+pub struct Store(Database);
 
 impl Store {
     pub fn new(db: Database) -> Store {
-        Store {
-            db,
-        }
+        Store(db)
     }
 }
--- a/third_party/rust/rkv/src/value.rs
+++ b/third_party/rust/rkv/src/value.rs
@@ -11,18 +11,18 @@
 use ordered_float::OrderedFloat;
 
 use bincode::{
     deserialize,
     serialize,
 };
 
 use uuid::{
+    Bytes,
     Uuid,
-    UuidBytes,
 };
 
 use error::DataError;
 
 /// We define a set of types, associated with simple integers, to annotate values
 /// stored in LMDB. This is to avoid an accidental 'cast' from a value of one type
 /// to another. For this reason we don't simply use `deserialize` from the `bincode`
 /// crate.
@@ -38,17 +38,17 @@ pub enum Type {
     Str = 7,
     Json = 8,
     Blob = 9,
 }
 
 /// We use manual tagging, because <https://github.com/serde-rs/serde/issues/610>.
 impl Type {
     pub fn from_tag(tag: u8) -> Result<Type, DataError> {
-        Type::from_primitive(tag).ok_or(DataError::UnknownType(tag))
+        Type::from_primitive(tag).ok_or_else(|| DataError::UnknownType(tag))
     }
 
     pub fn to_tag(self) -> u8 {
         self as u8
     }
 
     fn from_primitive(p: u8) -> Option<Type> {
         match p {
@@ -84,37 +84,36 @@ impl ::std::fmt::Display for Type {
 
 #[derive(Debug, Eq, PartialEq)]
 pub enum Value<'s> {
     Bool(bool),
     U64(u64),
     I64(i64),
     F64(OrderedFloat<f64>),
     Instant(i64), // Millisecond-precision timestamp.
-    Uuid(&'s UuidBytes),
+    Uuid(&'s Bytes),
     Str(&'s str),
     Json(&'s str),
     Blob(&'s [u8]),
 }
 
-// TODO: implement conversion between the two types of `Value` wrapper.
-// This might be unnecessary: we'll probably jump straight to primitives.
-enum OwnedValue {
+#[derive(Debug, PartialEq)]
+pub enum OwnedValue {
     Bool(bool),
     U64(u64),
     I64(i64),
     F64(f64),
     Instant(i64), // Millisecond-precision timestamp.
     Uuid(Uuid),
     Str(String),
     Json(String), // TODO
     Blob(Vec<u8>),
 }
 
-fn uuid<'s>(bytes: &'s [u8]) -> Result<Value<'s>, DataError> {
+fn uuid(bytes: &[u8]) -> Result<Value, DataError> {
     if bytes.len() == 16 {
         Ok(Value::Uuid(array_ref![bytes, 0, 16]))
     } else {
         Err(DataError::InvalidUuid)
     }
 }
 
 impl<'s> Value<'s> {
@@ -177,8 +176,24 @@ impl<'s> Value<'s> {
             Value::Blob(ref v) => serialize(&(Type::Blob.to_tag(), v)),
             Value::Uuid(ref v) => {
                 // Processed above to avoid verbose duplication of error transforms.
                 serialize(&(Type::Uuid.to_tag(), v))
             },
         }.map_err(DataError::EncodingError)
     }
 }
+
+impl<'s> From<&'s Value<'s>> for OwnedValue {
+    fn from(value: &Value) -> OwnedValue {
+        match value {
+            Value::Bool(ref v) => OwnedValue::Bool(*v),
+            Value::U64(ref v) => OwnedValue::U64(*v),
+            Value::I64(ref v) => OwnedValue::I64(*v),
+            Value::F64(ref v) => OwnedValue::F64(**v),
+            Value::Instant(ref v) => OwnedValue::Instant(*v),
+            Value::Uuid(ref v) => OwnedValue::Uuid(Uuid::from_bytes(**v)),
+            Value::Str(ref v) => OwnedValue::Str(v.to_string()),
+            Value::Json(ref v) => OwnedValue::Json(v.to_string()),
+            Value::Blob(ref v) => OwnedValue::Blob(v.to_vec()),
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/threadbound/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{"Cargo.toml":"8411cf3bdec6a0efe067bdf0931ff341f20eff1d504f1b26fe6c035afe42b37c","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7f697f191d6ffb32881a6bcf535e817ebbebaaa11b9aacf4f0b26fd32e2cc201","README.md":"122935e4acdb0eedc4c1cd2efa802525c72cd7a3afe1b35bce6e4642698fa33f","src/lib.rs":"8bda9c9899e76e3dd577ead8b5c73aa5c4fdbcc818b37af5051e2dbfdb32feab"},"package":"d23e87ee7a1ef5bd2d38cef24ff360f6e02beee13c6a7eb64dddde4a3da427a3"}
\ No newline at end of file
copy from third_party/rust/crossbeam-utils/Cargo.toml
copy to third_party/rust/threadbound/Cargo.toml
--- a/third_party/rust/crossbeam-utils/Cargo.toml
+++ b/third_party/rust/threadbound/Cargo.toml
@@ -6,26 +6,17 @@
 # to registry (e.g. crates.io) dependencies
 #
 # If you believe there's an error in this file please file an
 # issue against the rust-lang/cargo repository. If you're
 # editing this file be aware that the upstream Cargo.toml
 # will likely look very different (and much more reasonable)
 
 [package]
-name = "crossbeam-utils"
-version = "0.3.2"
-authors = ["The Crossbeam Project Developers"]
-description = "Utilities for concurrent programming"
-homepage = "https://github.com/crossbeam-rs/crossbeam-utils"
-documentation = "https://docs.rs/crossbeam-utils"
+name = "threadbound"
+version = "0.1.0"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+description = "Make any value Sync but only available on its original thread."
+documentation = "https://docs.rs/threadbound"
 readme = "README.md"
-keywords = ["scoped", "thread", "atomic", "cache"]
-categories = ["algorithms", "concurrency", "data-structures"]
+categories = ["rust-patterns"]
 license = "MIT/Apache-2.0"
-repository = "https://github.com/crossbeam-rs/crossbeam-utils"
-[dependencies.cfg-if]
-version = "0.1"
-
-[features]
-default = ["use_std"]
-nightly = []
-use_std = []
+repository = "https://github.com/dtolnay/threadbound"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/threadbound/LICENSE-APACHE
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
copy from third_party/rust/crossbeam-utils/LICENSE-MIT
copy to third_party/rust/threadbound/LICENSE-MIT
--- a/third_party/rust/crossbeam-utils/LICENSE-MIT
+++ b/third_party/rust/threadbound/LICENSE-MIT
@@ -1,9 +1,9 @@
-Copyright (c) 2010 The Rust Project Developers
+Copyright (c) 2018
 
 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
new file mode 100644
--- /dev/null
+++ b/third_party/rust/threadbound/README.md
@@ -0,0 +1,87 @@
+ThreadBound\<T\>
+================
+
+[![Build Status](https://api.travis-ci.org/dtolnay/threadbound.svg?branch=master)](https://travis-ci.org/dtolnay/threadbound)
+[![Latest Version](https://img.shields.io/crates/v/threadbound.svg)](https://crates.io/crates/threadbound)
+[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/threadbound)
+
+ThreadBound is a wrapper that binds a value to its original thread. The wrapper
+gets to be [`Sync`] and [`Send`] but only the original thread on which the
+ThreadBound was constructed can retrieve the underlying value.
+
+[`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
+[`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
+
+```toml
+[dependencies]
+threadbound = "0.1"
+```
+
+*Version requirement: rustc 1.19+*
+
+### Example
+
+```rust
+extern crate threadbound;
+
+use std::marker::PhantomData;
+use std::rc::Rc;
+use std::sync::Arc;
+use threadbound::ThreadBound;
+
+// Neither Send nor Sync. Maybe the index points into a
+// thread-local interner.
+#[derive(Copy, Clone)]
+struct Span {
+    index: u32,
+    marker: PhantomData<Rc<()>>,
+}
+
+// Error types are always supposed to be Send and Sync.
+// We can use ThreadBound to make it so.
+struct Error {
+    span: ThreadBound<Span>,
+    message: String,
+}
+
+fn main() {
+    let err = Error {
+        span: ThreadBound::new(Span {
+            index: 99,
+            marker: PhantomData,
+        }),
+        message: "fearless concurrency".to_owned(),
+    };
+
+    // Original thread can see the contents.
+    assert_eq!(err.span.get_ref().unwrap().index, 99);
+
+    let err = Arc::new(err);
+    let err2 = err.clone();
+    std::thread::spawn(move || {
+        // Other threads cannot get access. Maybe they use
+        // a default value or a different codepath.
+        assert!(err2.span.get_ref().is_none());
+    });
+
+    // Original thread can still see the contents.
+    assert_eq!(err.span.get_ref().unwrap().index, 99);
+}
+```
+
+<br>
+
+#### License
+
+<sup>
+Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
+2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.
+</sup>
+
+<br>
+
+<sub>
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in this crate by you, as defined in the Apache-2.0 license, shall
+be dual licensed as above, without any additional terms or conditions.
+</sub>
new file mode 100644
--- /dev/null
+++ b/third_party/rust/threadbound/src/lib.rs
@@ -0,0 +1,136 @@
+//! [`ThreadBound<T>`] is a wrapper that binds a value to its original thread.
+//! The wrapper gets to be [`Sync`] and [`Send`] but only the original thread on
+//! which the ThreadBound was constructed can retrieve the underlying value.
+//!
+//! [`ThreadBound<T>`]: struct.ThreadBound.html
+//! [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
+//! [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
+//!
+//! # Example
+//!
+//! ```rust
+//! extern crate threadbound;
+//!
+//! use std::marker::PhantomData;
+//! use std::rc::Rc;
+//! use std::sync::Arc;
+//! use threadbound::ThreadBound;
+//!
+//! // Neither Send nor Sync. Maybe the index points into a
+//! // thread-local interner.
+//! #[derive(Copy, Clone)]
+//! struct Span {
+//!     index: u32,
+//!     marker: PhantomData<Rc<()>>,
+//! }
+//!
+//! // Error types are always supposed to be Send and Sync.
+//! // We can use ThreadBound to make it so.
+//! struct Error {
+//!     span: ThreadBound<Span>,
+//!     message: String,
+//! }
+//!
+//! fn main() {
+//!     let err = Error {
+//!         span: ThreadBound::new(Span {
+//!             index: 99,
+//!             marker: PhantomData,
+//!         }),
+//!         message: "fearless concurrency".to_owned(),
+//!     };
+//!
+//!     // Original thread can see the contents.
+//!     assert_eq!(err.span.get_ref().unwrap().index, 99);
+//!
+//!     let err = Arc::new(err);
+//!     let err2 = err.clone();
+//!     std::thread::spawn(move || {
+//!         // Other threads cannot get access. Maybe they use
+//!         // a default value or a different codepath.
+//!         assert!(err2.span.get_ref().is_none());
+//!     });
+//!
+//!     // Original thread can still see the contents.
+//!     assert_eq!(err.span.get_ref().unwrap().index, 99);
+//! }
+//! ```
+
+#![doc(html_root_url = "https://docs.rs/threadbound/0.1.0")]
+
+use std::fmt::{self, Debug};
+use std::thread::{self, ThreadId};
+
+/// ThreadBound is a Sync-maker and Send-maker that allows accessing a value
+/// of type T only from the original thread on which the ThreadBound was
+/// constructed.
+///
+/// Refer to the [crate-level documentation] for a usage example.
+///
+/// [crate-level documentation]: index.html
+pub struct ThreadBound<T> {
+    value: T,
+    thread_id: ThreadId,
+}
+
+unsafe impl<T> Sync for ThreadBound<T> {}
+
+// Send bound requires Copy, as otherwise Drop could run in the wrong place.
+unsafe impl<T: Copy> Send for ThreadBound<T> {}
+
+impl<T> ThreadBound<T> {
+    /// Binds a value to the current thread. The wrapper can be sent around to
+    /// other threads, but no other threads will be able to access the
+    /// underlying value.
+    pub fn new(value: T) -> Self {
+        ThreadBound {
+            value,
+            thread_id: thread::current().id(),
+        }
+    }
+
+    /// Accesses a reference to the underlying value if this is its original
+    /// thread, otherwise `None`.
+    pub fn get_ref(&self) -> Option<&T> {
+        if thread::current().id() == self.thread_id {
+            Some(&self.value)
+        } else {
+            None
+        }
+    }
+
+    /// Accesses a mutable reference to the underlying value if this is its
+    /// original thread, otherwise `None`.
+    pub fn get_mut(&mut self) -> Option<&mut T> {
+        if thread::current().id() == self.thread_id {
+            Some(&mut self.value)
+        } else {
+            None
+        }
+    }
+
+    /// Extracts ownership of the underlying value if this is its original
+    /// thread, otherwise `None`.
+    pub fn into_inner(self) -> Option<T> {
+        if thread::current().id() == self.thread_id {
+            Some(self.value)
+        } else {
+            None
+        }
+    }
+}
+
+impl<T: Default> Default for ThreadBound<T> {
+    fn default() -> Self {
+        ThreadBound::new(Default::default())
+    }
+}
+
+impl<T: Debug> Debug for ThreadBound<T> {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        match self.get_ref() {
+            Some(value) => Debug::fmt(value, formatter),
+            None => formatter.write_str("unknown"),
+        }
+    }
+}
copy from third_party/rust/uuid/.cargo-checksum.json
copy to third_party/rust/uuid-0.6.5/.cargo-checksum.json
new file mode 100644
--- /dev/null
+++ b/third_party/rust/uuid-0.6.5/CODEOWNERS
@@ -0,0 +1,16 @@
+# CI
+.travis.yml     @kinggoesgaming @KodrAus @Dylan-DPC @radix
+appveyor.yml    @kinggoesgaming @KodrAus @Dylan-DPC @radix
+
+# Cargo.toml
+Cargo.toml      @kinggoesgaming @KodrAus @Dylan-DPC @radix
+
+# Rust
+*.rs            @kinggoesgaming @KodrAus @Dylan-DPC @radix
+
+# CODEOWNERS
+CODEOWNERS      @kinggoesgaming @KodrAus @Dylan-DPC @radix
+
+#>> Critical
+# bors.toml file
+bors.toml       @kinggoesgaming @KodrAus @Dylan-DPC @radix
copy from third_party/rust/uuid/CODE_OF_CONDUCT.md
copy to third_party/rust/uuid-0.6.5/CODE_OF_CONDUCT.md
new file mode 100644
--- /dev/null
+++ b/third_party/rust/uuid-0.6.5/CONTRIBUTING.md
@@ -0,0 +1,149 @@
+Contributing to Uuid
+---
+[Contributing to Uuid]: #contributing-to-uuid
+
+Thank you for your interest in contributing to the Uuid Project!
+
+* [Feature Requests](#feature-requests)
+* [Bug Reports](#bug-reports)
+* [Pull Requests](#pull-requests)
+* [Writing Documentation](#writing-documentation)
+* [Issue Triage](#issue-triage)
+* [Out-of-tree Contributions](#out-of-tree-contributions)
+* [Helpful Links](#helpful-links)
+
+For any questions, please make a post on [users.rust-lang.org][u-r-l-o], post
+on [uuid-rs mailing list] or join our [gitter] channel.
+
+> All contributors need to follow our [Code of Conduct].
+
+[Code of Conduct]: CODE_OF_CONDUCT.md
+
+# Feature Requests
+[Feature Requests]: #feature-requests
+
+The `uuid` crate is still in flux. All features desired may not be present. As
+such you are welcome to request for new features. Keep in mind that `uuid` is
+a general purpose library. We want to provide features that most users would
+find useful. As such not every feature may be accepted.
+
+If you have the chance, please [search existing issues], as there is a chance
+that someone has already requested your feature.
+
+File your feature request with a descriptive title, as this helps others find
+your request.
+
+You can request your feature by following [this link][Feature Request Link] and
+filling it in. 
+
+> We welcome pull requests for your own feature requests, provided they have
+been discussed.
+
+[Feature Request Link]: https://github.com/uuid-rs/uuid/issues/new?template=Feature_request.md
+
+# Bug Reports
+[Bug Reports]: #bug-reports
+
+While no one likes bugs, they are an unfortunate reality in software. Remember
+we can't fix bugs we don't know about, so don't be shy about reporting.
+
+If you have the chance, please [search existing issues], as there is a chance
+that someone has already reported your error. This isn't strictly needed, as
+sometimes you might not what exactly you are looking for.
+
+File your issue with a descriptive title, as this helps others find your issue.
+
+Reporting a bug is as easy as following [this link][Bug Report Link] and
+filling it in.
+
+Sometimes a backtrace may be needed. In that case, set `RUST_BACKTRACE`
+environment variable to `1`. For example:
+
+```bash
+$ RUST_BACKTRACE=1 cargo build
+```
+
+> We welcome pull requests for your own bug reports, provided they have been
+discussed.
+
+[Bug Report Link]: https://github.com/uuid-rs/uuid/issues/new?template=Bug_report.md
+
+# Pull Requests
+[Pull Requests]: #pull-requests
+
+Pull requests(PRs) are the primary mechanism we use to change Uuid. GitHub itself
+has some [great documentation] on using the Pull Request feature. We use the
+"fork and pull" model described [here][fnp], where contributors push changes to
+their personal fork and create pull requests to bring those changes into the
+source repository.
+
+Unless the changes are fairly minor (like documentation changes or tiny
+patches), we require PRs to relevant issues.
+
+Please open PRs against branch:
+* `master` when making non-breaking changes 
+* `breaking` when your changes alter the public API in a breaking manner
+
+If the pull request is still a work in progress, prepend`[WIP] ` in your 
+title. `WIP bot` will make sure that the PR doesn't accidentally get merged.
+
+> Uuid Project has a minimum rust version policy. Currently `uuid` should 
+compile with atleast `1.18.0`, and is enforced on our CI builds.
+
+When you feel that the PR is ready, please ping one of the maintainers so
+they can review your changes.
+
+[great documentation]: https://help.github.com/articles/about-pull-requests/
+[fnp]: https://help.github.com/articles/about-collaborative-development-models/
+
+# Writing Documentation
+[Writing Documentation]: #writing-documentation
+
+Documentation is an important part of Uuid. Lackluster or incorrect
+documentation can cause headaches for the users of `uuid`. Therefore,
+improvements to documentation are always welcome.
+
+We follow the documentation style guidelines as given by [RFC 1574].
+
+[RFC 1574]: https://github.com/rust-lang/rfcs/blob/master/text/1574-more-api-documentation-conventions.md#appendix-a-full-conventions-text
+
+# Issue Triage
+[Issue Triage]: #issue-triage
+
+Sometimes, an issue might stay open even after the relevant bug has been fixed.
+Other times, the bug report may become invalid. Or we may just forget about the
+bug.
+
+You can help to go through old bug reports and check if they are still valid.
+You can follow [this link][lrus] to look for issues like this.
+
+[lrus]: https://github.com/uuid-rs/uuid/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-asc
+
+# Out-of-tree Contributions
+[Out-of-tree Contributions]: #out-of-tree-contributions
+
+You can contribute to Uuid in other ways:
+
+* Answer questions on [users.rust-lang.org][u-r-l-o], [uuid-rs mailing list] and/or
+[gitter] channel.
+* Find the [crates depending on `uuid`][dependent] and sending PRs to them,
+helping them keep their version of `uuid` up-to-date.
+
+[dependent]: https://crates.io/crates/uuid/reverse_dependencies
+
+# Helpful Links
+[Helpful Links]: #helpful-links
+
+For people new to Uuid, and just starting to contribute, or even for more
+seasoned developers, some useful places to look for information are:
+
+* The Wikipedia entry on [Universally Unique Identifier][wiki-uuid].
+* [RFC 4122] which gives the specification of Uuids.
+
+[wiki-uuid]: https://en.wikipedia.org/wiki/Universally_unique_identifier
+[RFC 4122]: https://www.ietf.org/rfc/rfc4122.txt
+
+[u-r-l-o]: https://users.rust-lang.org
+[uuid-rs mailing list]: https://uuid-rs.groups.io
+[gitter]: https://gitter.im/uuid-rs/Lobby
+[search existing issues]: https://github.com/uuid-rs/uuid/search?q=&type=Issues&utf8=%E2%9C%93
new file mode 100644
--- /dev/null
+++ b/third_party/rust/uuid-0.6.5/COPYRIGHT
@@ -0,0 +1,8 @@
+The Uuid Project is copyright 2013-2014, The Rust Project Developers and
+copyright 2018, The Uuid Developers.
+
+Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+http://www.apache.org/licenses/LICENSE-2.0> or the MIT License <LICENSE-MIT or
+http://opensource.org/licenses/MIT>, at your option. All files in the project
+carrying such notice may not be copied, modified, or distributed except
+according to those terms.
copy from third_party/rust/uuid/Cargo.toml
copy to third_party/rust/uuid-0.6.5/Cargo.toml
new file mode 100644
--- /dev/null
+++ b/third_party/rust/uuid-0.6.5/LICENSE-APACHE
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
copy from third_party/rust/crossbeam-utils/LICENSE-MIT
copy to third_party/rust/uuid-0.6.5/LICENSE-MIT
--- a/third_party/rust/crossbeam-utils/LICENSE-MIT
+++ b/third_party/rust/uuid-0.6.5/LICENSE-MIT
@@ -1,9 +1,10 @@
-Copyright (c) 2010 The Rust Project Developers
+Copyright (c) 2014 The Rust Project Developers
+Copyright (c) 2018 Ashley Mannix, Christopher Armstrong, Dylan DPC, Hunar Roop Kahlon
 
 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
copy from third_party/rust/uuid/README.md
copy to third_party/rust/uuid-0.6.5/README.md
rename from third_party/rust/uuid/benches/parse_str.rs
rename to third_party/rust/uuid-0.6.5/benches/parse_str.rs
rename from third_party/rust/uuid/src/adapter.rs
rename to third_party/rust/uuid-0.6.5/src/adapter.rs
copy from third_party/rust/uuid/src/core_support.rs
copy to third_party/rust/uuid-0.6.5/src/core_support.rs
copy from third_party/rust/uuid/src/lib.rs
copy to third_party/rust/uuid-0.6.5/src/lib.rs
copy from third_party/rust/uuid/src/prelude.rs
copy to third_party/rust/uuid-0.6.5/src/prelude.rs
copy from third_party/rust/uuid/src/serde_support.rs
copy to third_party/rust/uuid-0.6.5/src/serde_support.rs
copy from third_party/rust/uuid/src/slog_support.rs
copy to third_party/rust/uuid-0.6.5/src/slog_support.rs
copy from third_party/rust/uuid/src/std_support.rs
copy to third_party/rust/uuid-0.6.5/src/std_support.rs
copy from third_party/rust/uuid/src/test_util.rs
copy to third_party/rust/uuid-0.6.5/src/test_util.rs
copy from third_party/rust/uuid/src/u128_support.rs
copy to third_party/rust/uuid-0.6.5/src/u128_support.rs
--- a/third_party/rust/uuid/.cargo-checksum.json
+++ b/third_party/rust/uuid/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"CODEOWNERS":"65d3fcb4156a2d5bce80d382a34044753e384d7f1eb71cdc646de400a0b969c8","CODE_OF_CONDUCT.md":"42634d0f6d922f49857175af991802822f7f920487aefa2ee250a50d12251a66","CONTRIBUTING.md":"cb8fa34c1d15542a318a7cbe3cd41d364f6100d49043825413f3ebb4c7471c99","COPYRIGHT":"b4b2c0de2a05de3372d5c828128413ce82bb7dba2272487b7729f09cc3d3519d","Cargo.toml":"99a1ba4a59e407dbdca4ae23a88c616e10fa359b1185444f6c28899de4db76fb","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"436bc5a105d8e57dcd8778730f3754f7bf39c14d2f530e4cde4bd2d17a83ec3d","README.md":"fde0b945e228892663a3484ba1fda02c697260275266761cd6cd4b4d5c9e0fa6","benches/parse_str.rs":"8917f4957576462f5e06300f512abadc905507dcd4e6eb9a98a4f316091484b8","src/adapter.rs":"e2cb0a591d4e707dd9106393f1610fa40cab706b1ce52b65c5f049448f4dd6d8","src/core_support.rs":"d795af374511e39e4eb386e1a3c5861c066b02331021be75b5dca6eb4375af5a","src/lib.rs":"0967888ee586e3715a41f7d468f6094d7c2cc275e289a16a1e54e64e34cce3c6","src/prelude.rs":"e00e2a0016a31354f5e7356049c5a7436369c7c67afc9bcd319f3c37bd86dd07","src/serde_support.rs":"77406f58c17f62ba5e363d45bdc845c62f819749635bf39365dd5d6092884681","src/slog_support.rs":"9d4507ce3d70362b43d95894c63ae7f25316891adbdc8a8785795a767766cc21","src/std_support.rs":"9176739d18e81788d020644bbd58fffeba7e45cb617af3bd80ab62223b46c779","src/test_util.rs":"802233b76197fd708d83af87c133cad6b472ed9b0041c6e354a7f1a03aea5b8d","src/u128_support.rs":"af33323fb2905fe4c50178b602d19e4eb54ed3984aede6d94d0f44ce0770f669"},"package":"e1436e58182935dcd9ce0add9ea0b558e8a87befe01c1a301e6020aeb0876363"}
\ No newline at end of file
+{"files":{"CODEOWNERS":"65d3fcb4156a2d5bce80d382a34044753e384d7f1eb71cdc646de400a0b969c8","CODE_OF_CONDUCT.md":"7d9c9062ee835c2dfd348cfddb938c563f3a7b1140dd090444a03ea1d73626b1","CONTRIBUTING.md":"cb8fa34c1d15542a318a7cbe3cd41d364f6100d49043825413f3ebb4c7471c99","COPYRIGHT":"b4b2c0de2a05de3372d5c828128413ce82bb7dba2272487b7729f09cc3d3519d","Cargo.toml":"71a942d30769089e36cbe32fade63a078961f3cab23d41ab87f5c8e8efcd9348","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"436bc5a105d8e57dcd8778730f3754f7bf39c14d2f530e4cde4bd2d17a83ec3d","README.md":"01e0a86cc2b9f29fbef04623e3f8e8ca46252fd8d5360b83780fa816f6012011","benches/format_str.rs":"2bcff80d8ab03c83ccc61c756f75a0c7aead821f68b29eeaf38f4ba6344bfc6e","benches/invalid_parse_str.rs":"7f44d2ebec6ee1368d179f12dd09a288d589b252434082b2de134a658b460812","benches/mod.rs":"4733d7aa62dafe3e85ab90dca518b57f350a5538ea5643c5313e63939e884a45","benches/serde_support.rs":"afc719718c9a5d705b60bc9cd39720b921d9ee63ccf11c4b2900f02beea70c1b","benches/slog_support/mod.rs":"1be626f0a6921f4e6bd333ce7ab4a6c4da1fb6f3ae1c503672b4ba168a70c01d","benches/slog_support/parse_str.rs":"9c63ee7047ac8b9d08f02b7081020dd7300f84f302068927c859bbe26cea66a3","benches/valid_parse_str.rs":"7db47c7d25b20c8da03f25107fbea2b5c97fc814ff226e8489eda374f477eeac","src/adapter/core_support/mod.rs":"65bebe5034e450782ec9b0942bd4d758795ee315095fcc3f54412630a987f938","src/adapter/mod.rs":"8f3acffda66148a7095286309f32b823c66826bfe35742fbc63bf1a1e07365a5","src/core_support.rs":"f5c83e3e16a32ae93c76e0e1699f3a07872788e782ce5ee4c2f8229a06a871c8","src/lib.rs":"1d0492819a93dc386e90659a21f6231a01dd172552a1221a298c089db7c671b1","src/parser/core_support.rs":"a8621aa837da2f4cd82f86539c2f3f153c52fcea21c223aa098e5873cbf36d0f","src/parser/mod.rs":"51526e211c95730c830512007da23dfc9f88d1feccc9ddf881c541c1d5e01e2a","src/parser/std_support.rs":"4398d708bd42e8d3cb31eed8ada92615fb1cbfc70bfb3c7cbe952f47c7fe1183","src/prelude.rs":"89553bb9a75e3801698f57fcc099235e5213452738cace4ab190d9444a1adfa4","src/serde_support.rs":"fdc5be309b9fc062832f3a2b114d7a06e8c8357f6569796ed1fc7848a5ebc155","src/slog_support.rs":"370f891a73f99436baecd21f5f2b7d7c89842336aad99167b07ca3f03c48a70c","src/std_support.rs":"50d2bdaaae64e4d22d9180404ac8600944683dcdc51d7de6587a6fdb29193a70","src/test_util.rs":"1dfc1ab68bb403dd6d696fafeb7c00be59c37b51155703f3033ebf1062dd629f","src/u128_support.rs":"97ca20af9117e44bad72f987488efb0173699a22e0c646b268e0fe3dd90355a7","src/v1.rs":"82654b0cadfa56fd0140d78db5ab2d9869ea3d8eaaede0b975d42904317e9da4","src/v3.rs":"d25899b070bd791bc2b784d828399f5bce25f77300765dfd96e76583f31047f3","src/v4.rs":"0cc02041d1215826e9fa2493fb4d97b1d15bc4925450db22eba86123680586ef","src/v5.rs":"11aeea13d38c5e3c5d7cc8bf571ac1ce57a0d46f363b90a991ed43dc1cc9caaa"},"package":"dab5c5526c5caa3d106653401a267fed923e7046f35895ffcb5ca42db64942e6"}
\ No newline at end of file
--- a/third_party/rust/uuid/CODE_OF_CONDUCT.md
+++ b/third_party/rust/uuid/CODE_OF_CONDUCT.md
@@ -1,10 +1,14 @@
 # Contributor Covenant Code of Conduct
 
+The latest version of the CODE OF CONDUCT can be found [here].
+
+[here]: https://github.com/uuid-rs/conduct
+
 ## Our Pledge
 
 In the interest of fostering an open and welcoming environment, we as
 contributors and maintainers pledge to making participation in our project and
 our community a harassment-free experience for everyone, regardless of age, body
 size, disability, ethnicity, gender identity and expression, level of experience,
 education, socio-economic status, nationality, personal appearance, race,
 religion, or sexual identity and orientation.
@@ -50,17 +54,17 @@ when an individual is representing the p
 representing a project or community include using an official project e-mail
 address, posting via an official social media account, or acting as an appointed
 representative at an online or offline event. Representation of a project may be
 further defined and clarified by project maintainers.
 
 ## Enforcement
 
 Instances of abusive, harassing, or otherwise unacceptable behavior may be
-reported by contacting the project team at coc@senaite.org. All
+reported by contacting the project team at report@uuid-rs.groups.io. All
 complaints will be reviewed and investigated and will result in a response that
 is deemed necessary and appropriate to the circumstances. The project team is
 obligated to maintain confidentiality with regard to the reporter of an incident.
 Further details of specific enforcement policies may be posted separately.
 
 Project maintainers who do not follow or enforce the Code of Conduct in good
 faith may face temporary or permanent repercussions as determined by other
 members of the project's leadership.
--- a/third_party/rust/uuid/Cargo.toml
+++ b/third_party/rust/uuid/Cargo.toml
@@ -7,17 +7,17 @@
 #
 # If you believe there's an error in this file please file an
 # issue against the rust-lang/cargo repository. If you're
 # editing this file be aware that the upstream Cargo.toml
 # will likely look very different (and much more reasonable)
 
 [package]
 name = "uuid"
-version = "0.6.5"
+version = "0.7.1"
 authors = ["Ashley Mannix<ashleymannix@live.com.au>", "Christopher Armstrong", "Dylan DPC<dylan.dpc@gmail.com>", "Hunar Roop Kahlon<hunar.roop@gmail.com>"]
 exclude = [".github/**", ".travis.yml", "appveyor.yml", "bors.toml"]
 description = "A library to generate and parse UUIDs."
 homepage = "https://github.com/uuid-rs/uuid"
 documentation = "https://docs.rs/uuid"
 readme = "README.md"
 license = "Apache-2.0 OR MIT"
 repository = "https://github.com/uuid-rs/uuid"
@@ -27,45 +27,47 @@ all-features = true
 [package.metadata.playground]
 features = ["serde", "u128", "v1", "v3", "v4", "v5"]
 [dependencies.byteorder]
 version = "1"
 features = ["i128"]
 optional = true
 default-features = false
 
-[dependencies.cfg-if]
-version = "0.1.2"
-
 [dependencies.md5]
 version = "0.3"
 optional = true
 
 [dependencies.rand]
-version = "0.4"
+version = "0.5"
 optional = true
 
 [dependencies.serde]
 version = "1.0.56"
 optional = true
 default-features = false
 
 [dependencies.sha1]
 version = "0.6"
 optional = true
 
 [dependencies.slog]
 version = "2"
 optional = true
+[dev-dependencies.bincode]
+version = "1.0"
+
+[dev-dependencies.serde_json]
+version = "1.0"
+
 [dev-dependencies.serde_test]
 version = "1.0.56"
 
 [features]
 const_fn = ["nightly"]
 default = ["std"]
 nightly = []
 std = []
 u128 = ["byteorder"]
-use_std = ["std"]
 v1 = []
 v3 = ["md5", "rand"]
 v4 = ["rand"]
 v5 = ["sha1", "rand"]
--- a/third_party/rust/uuid/README.md
+++ b/third_party/rust/uuid/README.md
@@ -1,15 +1,16 @@
 uuid
 ====
 
 [![Build Status](https://travis-ci.org/uuid-rs/uuid.svg?branch=master)](https://travis-ci.org/uuid-rs/uuid) 
 [![Appveyor Status](https://ci.appveyor.com/api/projects/status/github/uuid-rs/uuid?branch=master&svg=true)](https://ci.appveyor.com/project/KodrAus/uuid) 
 [![Latest Version](https://img.shields.io/crates/v/uuid.svg)](https://crates.io/crates/uuid) 
 [![Join the chat at https://gitter.im/uuid-rs/Lobby](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/uuid-rs/Lobby?utm_source=badge&utm_medium=badge&utm_content=badge)
+![Minimum rustc version](https://img.shields.io/badge/rustc-1.22.0+-yellow.svg)
 
 A Rust library to generate and parse UUIDs.
 
 Provides support for Universally Unique Identifiers (UUIDs). A UUID is a unique
 128-bit number, stored as 16 octets. UUIDs are used to assign unique identifiers
 to entities without requiring a central allocating authority.
 
 They are particularly useful in distributed systems, though can be used in
@@ -24,17 +25,17 @@ unlikely.
 [Documentation](https://docs.rs/uuid)
 
 ## Usage
 
 Add this to your `Cargo.toml`:
 
 ```toml
 [dependencies]
-uuid = "0.6"
+uuid = "0.7"
 ```
 
 and this to your crate root:
 
 ```rust
 extern crate uuid;
 ```
 
@@ -63,17 +64,17 @@ Md5      | Version 3: MD5 hash
 Random   | Version 4: Random
 Sha1     | Version 5: SHA-1 hash
 
 To create a new random (V4) UUID and print it out in hexadecimal form, first
 you'll need to change how you depend on `uuid`:
 
 ```toml
 [dependencies]
-uuid = { version = "0.6", features = ["v4"] }
+uuid = { version = "0.7", features = ["v4"] }
 ```
 
 Next, you'll write:
 
 ```rust
 extern crate uuid;
 use uuid::Uuid;
 
@@ -83,26 +84,26 @@ fn main() {
 }
 ```
 
 To create a new sha1-hash based (V5) UUID and print it out in hexadecimal form,
 you'll also need to change how you depend on `uuid`:
 
 ```toml
 [dependencies]
-uuid = { version = "0.6", features = ["v5"] }
+uuid = { version = "0.7", features = ["v5"] }
 ```
 
 Next, you'll write:
 
 ```rust
 extern crate uuid;
 use uuid::Uuid;
 
 fn main() {
-    let my_uuid = Uuid::new_v5(&uuid::NAMESPACE_DNS, "foo");
+    let my_uuid = Uuid::new_v5(&Uuid::NAMESPACE_DNS, "foo".as_bytes());
     println!("{}", my_uuid);
 }
 ```
 
 ## References
 
 [Wikipedia: Universally Unique Identifier](https://en.wikipedia.org/wiki/Universally_unique_identifier)
new file mode 100755
--- /dev/null
+++ b/third_party/rust/uuid/benches/format_str.rs
@@ -0,0 +1,67 @@
+#![feature(test)]
+extern crate test;
+extern crate uuid;
+
+use std::io::Write;
+use test::Bencher;
+use uuid::prelude::*;
+
+#[bench]
+fn bench_hyphen(b: &mut Bencher) {
+    let uuid = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4").unwrap();
+    b.iter(|| {
+        let mut buffer = [0_u8; 36];
+        write!(&mut buffer as &mut [_], "{:x}", uuid.to_hyphenated()).unwrap();
+        test::black_box(buffer);
+    });
+}
+
+#[bench]
+fn bench_simple(b: &mut Bencher) {
+    let uuid = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4").unwrap();
+    b.iter(|| {
+        let mut buffer = [0_u8; 32];
+        write!(&mut buffer as &mut [_], "{:x}", uuid.to_simple()).unwrap();
+        test::black_box(buffer);
+    })
+}
+
+#[bench]
+fn bench_urn(b: &mut Bencher) {
+    let uuid = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4").unwrap();
+    b.iter(|| {
+        let mut buffer = [0_u8; 36 + 9];
+        write!(&mut buffer as &mut [_], "{:x}", uuid.to_urn()).unwrap();
+        test::black_box(buffer);
+    })
+}
+
+#[bench]
+fn bench_encode_hyphen(b: &mut Bencher) {
+    let uuid = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4").unwrap();
+    b.iter(|| {
+        let mut buffer = [0_u8; 36];
+        // uuid.to_hyphenated().encode_lower(&mut buffer);
+        test::black_box(buffer);
+    });
+}
+
+#[bench]
+fn bench_encode_simple(b: &mut Bencher) {
+    let uuid = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4").unwrap();
+    b.iter(|| {
+        let mut buffer = [0_u8; 32];
+        // uuid.to_simple().encode_lower(&mut buffer);
+        test::black_box(buffer);
+    })
+}
+
+#[bench]
+fn bench_encode_urn(b: &mut Bencher) {
+    let uuid = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4").unwrap();
+    b.iter(|| {
+        let mut buffer = [0_u8; 36 + 9];
+        // uuid.to_urn().encode_lower(&mut buffer);
+        test::black_box(buffer);
+    })
+}
copy from third_party/rust/uuid/benches/parse_str.rs
copy to third_party/rust/uuid/benches/invalid_parse_str.rs
--- a/third_party/rust/uuid/benches/parse_str.rs
+++ b/third_party/rust/uuid/benches/invalid_parse_str.rs
@@ -1,49 +1,37 @@
 #![feature(test)]
 #[cfg(feature = "slog")]
 #[macro_use]
 extern crate slog;
 extern crate test;
 extern crate uuid;
+
 #[cfg(feature = "slog")]
 use slog::Drain;
 use test::Bencher;
-use uuid::Uuid;
+use uuid::prelude::*;
 
 #[bench]
-fn bench_parse(b: &mut Bencher) {
+fn bench_parse_invalid_strings(b: &mut Bencher) {
     b.iter(|| {
         let _ = Uuid::parse_str("");
         let _ = Uuid::parse_str("!");
         let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E45");
         let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4");
         let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4");
         let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4");
         let _ = Uuid::parse_str("F9168C5E-CEB2-4faa");
         let _ = Uuid::parse_str("F9168C5E-CEB2-4faaXB6BFF329BF39FA1E4");
         let _ = Uuid::parse_str("F9168C5E-CEB-24fa-eB6BFF32-BF39FA1E4");
         let _ = Uuid::parse_str("01020304-1112-2122-3132-41424344");
         let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c88");
         let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0cg8");
         let _ = Uuid::parse_str("67e5504410b1426%9247bb680e5fe0c8");
 
-        // Valid
-        let _ = Uuid::parse_str("00000000000000000000000000000000");
-        let _ = Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8");
-        let _ = Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8");
-        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4");
-        let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c8");
-        let _ = Uuid::parse_str("01020304-1112-2122-3132-414243444546");
-        let _ = Uuid::parse_str("urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8");
-
-        // Nil
-        let _ = Uuid::parse_str("00000000000000000000000000000000");
-        let _ = Uuid::parse_str("00000000-0000-0000-0000-000000000000");
-
         // Test error reporting
         let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c");
         let _ = Uuid::parse_str("67e550X410b1426f9247bb680e5fe0cd");
         let _ = Uuid::parse_str("67e550-4105b1426f9247bb680e5fe0c");
         let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF1-02BF39FA1E4");
     });
 }
 
@@ -69,32 +57,8 @@ fn bench_parse_invalid_group_len(b: &mut
 }
 
 #[bench]
 fn bench_parse_invalid_groups(b: &mut Bencher) {
     b.iter(|| {
         let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4");
     });
 }
-
-#[bench]
-fn bench_valid_hyphenated(b: &mut Bencher) {
-    b.iter(|| {
-        let _ = Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8");
-    });
-}
-
-#[bench]
-fn bench_valid_short(b: &mut Bencher) {
-    b.iter(|| {
-        let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c8");
-    });
-}
-
-#[cfg(feature = "slog")]
-#[bench]
-fn bench_log_discard_kv(b: &mut Bencher) {
-    let root = slog::Logger::root(slog::Discard.fuse(), o!());
-    let u1 = Uuid::parse_str("F9168C5E-CEB2-4FAB-B6BF-329BF39FA1E4").unwrap();
-    b.iter(|| {
-        crit!(root, "test"; "u1" => u1);
-    });
-}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/uuid/benches/mod.rs
@@ -0,0 +1,8 @@
+#![feature(test)]
+#[cfg(feature = "slog")]
+#[macro_use]
+extern crate slog;
+extern crate test;
+extern crate uuid;
+
+pub mod slog_support;
new file mode 100755
--- /dev/null
+++ b/third_party/rust/uuid/benches/serde_support.rs
@@ -0,0 +1,49 @@
+#![cfg(feature = "serde")]
+#![feature(test)]
+
+extern crate bincode;
+extern crate serde_json;
+extern crate test;
+extern crate uuid;
+
+use test::Bencher;
+use uuid::prelude::*;
+
+#[bench]
+fn bench_json_encode(b: &mut Bencher) {
+    let uuid = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4").unwrap();
+    let mut buffer = [0_u8; 38];
+    b.iter(|| {
+        serde_json::to_writer(&mut buffer as &mut [u8], &uuid).unwrap();
+        test::black_box(buffer);
+    });
+    b.bytes = buffer.len() as u64;
+}
+
+#[bench]
+fn bench_json_decode(b: &mut Bencher) {
+    let s = "\"F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4\"";
+    b.iter(|| serde_json::from_str::<Uuid>(s).unwrap());
+    b.bytes = s.len() as u64;
+}
+
+#[bench]
+fn bench_bincode_encode(b: &mut Bencher) {
+    let uuid = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4").unwrap();
+    let mut buffer = [0_u8; 24];
+    b.iter(|| {
+        bincode::serialize_into(&mut buffer as &mut [u8], &uuid).unwrap();
+        test::black_box(buffer);
+    });
+    b.bytes = buffer.len() as u64;
+}
+
+#[bench]
+fn bench_bincode_decode(b: &mut Bencher) {
+    let bytes = [
+        16, 0, 0, 0, 0, 0, 0, 0, 249, 22, 140, 94, 206, 178, 79, 170, 182, 191,
+        50, 155, 243, 159, 161, 228,
+    ];
+    b.iter(|| bincode::deserialize::<Uuid>(&bytes).unwrap());
+    b.bytes = bytes.len() as u64;
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/uuid/benches/slog_support/mod.rs
@@ -0,0 +1,7 @@
+#[cfg(feature = "slog")]
+// #[macro_use]
+// extern crate slog;
+// extern crate test;
+extern crate uuid;
+
+pub mod parse_str;
new file mode 100644
--- /dev/null
+++ b/third_party/rust/uuid/benches/slog_support/parse_str.rs
@@ -0,0 +1,15 @@
+use test::Bencher;
+use uuid::prelude::*;
+
+#[bench]
+#[cfg(feature = "slog")]
+pub fn bench_log_discard_kv(b: &mut Bencher) {
+    let u1 = Uuid::parse_str("F9168C5E-CEB2-4FAB-B6BF-329BF39FA1E4").unwrap();
+    let root = ::slog::Logger::root(::slog::Drain::fuse(::slog::Discard), o!());
+    // let root = ::slog::Logger::root(::slog::Discard.fuse(), o!());
+
+    b.iter(|| {
+        #[cfg(feature = "slog")]
+        crit!(root, "test"; "u1" => u1);
+    });
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/uuid/benches/valid_parse_str.rs
@@ -0,0 +1,44 @@
+#![feature(test)]
+#[cfg(feature = "slog")]
+#[macro_use]
+extern crate slog;
+extern crate test;
+extern crate uuid;
+
+#[cfg(feature = "slog")]
+use slog::Drain;
+use test::Bencher;
+use uuid::prelude::*;
+
+#[bench]
+fn bench_parse_valid_strings(b: &mut Bencher) {
+    b.iter(|| {
+        // Valid
+        let _ = Uuid::parse_str("00000000000000000000000000000000");
+        let _ = Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8");
+        let _ = Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8");
+        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4");
+        let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c8");
+        let _ = Uuid::parse_str("01020304-1112-2122-3132-414243444546");
+        let _ =
+            Uuid::parse_str("urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8");
+
+        // Nil
+        let _ = Uuid::parse_str("00000000000000000000000000000000");
+        let _ = Uuid::parse_str("00000000-0000-0000-0000-000000000000");
+    });
+}
+
+#[bench]
+fn bench_valid_hyphenated(b: &mut Bencher) {
+    b.iter(|| {
+        let _ = Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8");
+    });
+}
+
+#[bench]
+fn bench_valid_short(b: &mut Bencher) {
+    b.iter(|| {
+        let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c8");
+    });
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/uuid/src/adapter/core_support/mod.rs
@@ -0,0 +1,175 @@
+// Copyright 2013-2014 The Rust Project Developers.
+// Copyright 2018 The Uuid Project Developers.
+//
+// See the COPYRIGHT file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use core::fmt;
+use prelude::*;
+
+impl fmt::Display for super::Hyphenated {
+    #[inline]
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::LowerHex::fmt(self, f)
+    }
+}
+
+impl<'a> fmt::Display for super::HyphenatedRef<'a> {
+    #[inline]
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::LowerHex::fmt(self, f)
+    }
+}
+
+impl fmt::Display for super::Simple {
+    #[inline]
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::LowerHex::fmt(self, f)
+    }
+}
+
+impl<'a> fmt::Display for super::SimpleRef<'a> {
+    #[inline]
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::LowerHex::fmt(self, f)
+    }
+}
+
+impl fmt::Display for super::Urn {
+    #[inline]
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::LowerHex::fmt(self, f)
+    }
+}
+
+impl<'a> fmt::Display for super::UrnRef<'a> {
+    #[inline]
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::LowerHex::fmt(self, f)
+    }
+}
+
+impl fmt::LowerHex for super::Hyphenated {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str(self.encode_lower(&mut [0; Self::LENGTH]))
+    }
+}
+
+impl<'a> fmt::LowerHex for super::HyphenatedRef<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        // TODO: Self doesn't work https://github.com/rust-lang/rust/issues/52808
+        f.write_str(self.encode_lower(&mut [0; super::HyphenatedRef::LENGTH]))
+    }
+}
+
+impl fmt::LowerHex for super::Simple {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str(self.encode_lower(&mut [0; Self::LENGTH]))
+    }
+}
+
+impl<'a> fmt::LowerHex for super::SimpleRef<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        // TODO: Self doesn't work https://github.com/rust-lang/rust/issues/52808
+        f.write_str(self.encode_lower(&mut [0; super::SimpleRef::LENGTH]))
+    }
+}
+
+impl fmt::LowerHex for super::Urn {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str(self.encode_lower(&mut [0; Self::LENGTH]))
+    }
+}
+
+impl<'a> fmt::LowerHex for super::UrnRef<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        // TODO: Self doesn't work https://github.com/rust-lang/rust/issues/52808
+        f.write_str(self.encode_lower(&mut [0; super::UrnRef::LENGTH]))
+    }
+}
+
+impl fmt::UpperHex for super::Hyphenated {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str(self.encode_upper(&mut [0; Self::LENGTH]))
+    }
+}
+
+impl<'a> fmt::UpperHex for super::HyphenatedRef<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        // TODO: Self doesn't work https://github.com/rust-lang/rust/issues/52808
+        f.write_str(self.encode_upper(&mut [0; super::HyphenatedRef::LENGTH]))
+    }
+}
+
+impl fmt::UpperHex for super::Simple {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str(self.encode_upper(&mut [0; Self::LENGTH]))
+    }
+}
+
+impl<'a> fmt::UpperHex for super::SimpleRef<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        // TODO: Self doesn't work https://github.com/rust-lang/rust/issues/52808
+        f.write_str(self.encode_upper(&mut [0; super::SimpleRef::LENGTH]))
+    }
+}
+
+impl fmt::UpperHex for super::Urn {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str(self.encode_upper(&mut [0; Self::LENGTH]))
+    }
+}
+
+impl<'a> fmt::UpperHex for super::UrnRef<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        // TODO: Self doesn't work https://github.com/rust-lang/rust/issues/52808
+        f.write_str(self.encode_upper(&mut [0; super::UrnRef::LENGTH]))
+    }
+}
+
+impl From<Uuid> for super::Hyphenated {
+    #[inline]
+    fn from(f: Uuid) -> Self {
+        super::Hyphenated::from_uuid(f)
+    }
+}
+
+impl<'a> From<&'a Uuid> for super::HyphenatedRef<'a> {
+    #[inline]
+    fn from(f: &'a Uuid) -> Self {
+        super::HyphenatedRef::from_uuid_ref(f)
+    }
+}
+
+impl From<Uuid> for super::Simple {
+    #[inline]
+    fn from(f: Uuid) -> Self {
+        super::Simple::from_uuid(f)
+    }
+}
+
+impl<'a> From<&'a Uuid> for super::SimpleRef<'a> {
+    #[inline]
+    fn from(f: &'a Uuid) -> Self {
+        super::SimpleRef::from_uuid_ref(f)
+    }
+}
+
+impl From<Uuid> for super::Urn {
+    #[inline]
+    fn from(f: Uuid) -> Self {
+        super::Urn::from_uuid(f)
+    }
+}
+
+impl<'a> From<&'a Uuid> for super::UrnRef<'a> {
+    #[inline]
+    fn from(f: &'a Uuid) -> Self {
+        super::UrnRef::from_uuid_ref(f)
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/uuid/src/adapter/mod.rs
@@ -0,0 +1,1088 @@
+// Copyright 2013-2014 The Rust Project Developers.
+// Copyright 2018 The Uuid Project Developers.
+//
+// See the COPYRIGHT file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Adapters for various formats for [`Uuid`]s
+//!
+//! [`Uuid`]: ../struct.Uuid.html
+
+use core::str;
+use prelude::*;
+
+mod core_support;
+
+/// An adaptor for formatting an [`Uuid`] as a hyphenated string.
+///
+/// Takes an owned instance of the [`Uuid`].
+///
+/// [`Uuid`]: ../struct.Uuid.html
+#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct Hyphenated(Uuid);
+
+/// An adaptor for formatting an [`Uuid`] as a hyphenated string.
+///
+/// Takes a reference of the [`Uuid`].
+///
+/// [`Uuid`]: ../struct.Uuid.html
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct HyphenatedRef<'a>(&'a Uuid);
+
+/// An adaptor for formatting an [`Uuid`] as a simple string.
+///
+/// Takes an owned instance of the [`Uuid`].
+///
+/// [`Uuid`]: ../struct.Uuid.html
+#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct Simple(Uuid);
+
+/// An adaptor for formatting an [`Uuid`] as a simple string.
+///
+/// Takes a reference of the [`Uuid`].
+///
+/// [`Uuid`]: ../struct.Uuid.html
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct SimpleRef<'a>(&'a Uuid);
+
+/// An adaptor for formatting an [`Uuid`] as a URN string.
+///
+/// Takes an owned instance of the [`Uuid`].
+///
+/// [`Uuid`]: ../struct.Uuid.html
+#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct Urn(Uuid);
+
+/// An adaptor for formatting an [`Uuid`] as a URN string.
+///
+/// Takes a reference of the [`Uuid`].
+///
+/// [`Uuid`]: ../struct.Uuid.html
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct UrnRef<'a>(&'a Uuid);
+
+impl Uuid {
+    /// Creates a [`Hyphenated`] instance from a [`Uuid`].
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    /// [`Hyphenated`]: adapter/struct.Hyphenated.html
+    #[cfg(not(feature = "const_fn"))]
+    #[inline]
+    pub fn to_hyphenated(self) -> Hyphenated {
+        Hyphenated::from_uuid(self)
+    }
+
+    /// Creates a [`Hyphenated`] instance from a [`Uuid`].
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    /// [`Hyphenated`]: adapter/struct.Hyphenated.html
+    #[cfg(feature = "const_fn")]
+    #[inline]
+    pub const fn to_hyphenated(self) -> Hyphenated {
+        Hyphenated::from_uuid(self)
+    }
+
+    /// Creates a [`HyphenatedRef`] instance from a [`Uuid`] reference.
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    /// [`HyphenatedRef`]: adapter/struct.HyphenatedRef.html
+    #[cfg(not(feature = "const_fn"))]
+    #[inline]
+    pub fn to_hyphenated_ref(&self) -> HyphenatedRef {
+        HyphenatedRef::from_uuid_ref(self)
+    }
+
+    /// Creates a [`HyphenatedRef`] instance from a [`Uuid`] reference.
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    /// [`HyphenatedRef`]: adapter/struct.HyphenatedRef.html
+    #[cfg(feature = "const_fn")]
+    #[inline]
+    pub const fn to_hyphenated_ref(&self) -> HyphenatedRef {
+        HyphenatedRef::from_uuid_ref(self)
+    }
+
+    /// Creates a [`Simple`] instance from a [`Uuid`].
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    /// [`Simple`]: adapter/struct.Simple.html
+    #[cfg(not(feature = "const_fn"))]
+    #[inline]
+    pub fn to_simple(self) -> Simple {
+        Simple::from_uuid(self)
+    }
+
+    /// Creates a [`Simple`] instance from a [`Uuid`].
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    /// [`Simple`]: adapter/struct.Simple.html
+    #[cfg(feature = "const_fn")]
+    #[inline]
+    pub const fn to_simple(self) -> Simple {
+        Simple::from_uuid(self)
+    }
+
+    /// Creates a [`SimpleRef`] instance from a [`Uuid`] reference.
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    /// [`SimpleRef`]: adapter/struct.SimpleRef.html
+    #[cfg(not(feature = "const_fn"))]
+    #[inline]
+    pub fn to_simple_ref(&self) -> SimpleRef {
+        SimpleRef::from_uuid_ref(self)
+    }
+
+    /// Creates a [`SimpleRef`] instance from a [`Uuid`] reference.
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    /// [`SimpleRef`]: adapter/struct.SimpleRef.html
+    #[cfg(feature = "const_fn")]
+    #[inline]
+    pub const fn to_simple_ref(&self) -> SimpleRef {
+        SimpleRef::from_uuid_ref(self)
+    }
+
+    /// Creates a [`Urn`] instance from a [`Uuid`].
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    /// [`Urn`]: adapter/struct.Urn.html
+    #[cfg(not(feature = "const_fn"))]
+    #[inline]
+    pub fn to_urn(self) -> Urn {
+        Urn::from_uuid(self)
+    }
+
+    /// Creates a [`Urn`] instance from a [`Uuid`].
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    /// [`Urn`]: adapter/struct.Urn.html
+    #[cfg(feature = "const_fn")]
+    #[inline]
+    pub const fn to_urn(self) -> Urn {
+        Urn::from_uuid(self)
+    }
+
+    /// Creates a [`UrnRef`] instance from a [`Uuid`] reference.
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    /// [`UrnRef`]: adapter/struct.UrnRef.html
+    #[cfg(not(feature = "const_fn"))]
+    #[inline]
+    pub fn to_urn_ref(&self) -> UrnRef {
+        UrnRef::from_uuid_ref(self)
+    }
+
+    /// Creates a [`UrnRef`] instance from a [`Uuid`] reference.
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    /// [`UrnRef`]: adapter/struct.UrnRef.html
+    #[cfg(feature = "const_fn")]
+    #[inline]
+    pub const fn to_urn_ref(&self) -> UrnRef {
+        UrnRef::from_uuid_ref(self)
+    }
+}
+
+const UPPER: [u8; 16] = [
+    b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B',
+    b'C', b'D', b'E', b'F',
+];
+const LOWER: [u8; 16] = [
+    b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'a', b'b',
+    b'c', b'd', b'e', b'f',
+];
+/// The segments of a UUID's [u8; 16] corresponding to each group.
+const BYTE_POSITIONS: [usize; 6] = [0, 4, 6, 8, 10, 16];
+/// The locations that hyphens are written into the buffer, after each
+/// group.
+const HYPHEN_POSITIONS: [usize; 4] = [8, 13, 18, 23];
+
+/// Encodes the `uuid` possibly with hyphens, and possibly in upper
+/// case, to full_buffer[start..] and returns the str sliced from
+/// full_buffer[..start + encoded_length].
+///
+/// The `start` parameter allows writing a prefix (such as
+/// "urn:uuid:") to the buffer that's included in the final encoded
+/// UUID.
+fn encode<'a>(
+    full_buffer: &'a mut [u8],
+    start: usize,
+    uuid: &Uuid,
+    hyphens: bool,
+    upper: bool,
+) -> &'a mut str {
+    let len = if hyphens { 36 } else { 32 };
+
+    {
+        let buffer = &mut full_buffer[start..start + len];
+        let bytes = uuid.as_bytes();
+
+        let hex = if upper { &UPPER } else { &LOWER };
+
+        for group in 0..5 {
+            // If we're writing hyphens, we need to shift the output
+            // location along by how many of them have been written
+            // before this point. That's exactly the (0-indexed) group
+            // number.
+            let hyphens_before = if hyphens { group } else { 0 };
+
+            for idx in BYTE_POSITIONS[group]..BYTE_POSITIONS[group + 1] {
+                let b = bytes[idx];
+                let out_idx = hyphens_before + 2 * idx;
+
+                buffer[out_idx + 0] = hex[(b >> 4) as usize];
+                buffer[out_idx + 1] = hex[(b & 0b1111) as usize];
+            }
+
+            if group != 4 && hyphens {
+                buffer[HYPHEN_POSITIONS[group]] = b'-';
+            }
+        }
+    }
+
+    str::from_utf8_mut(&mut full_buffer[..start + len])
+        .expect("found non-ASCII output characters while encoding a UUID")
+}
+
+impl Hyphenated {
+    /// The length of a hyphenated [`Uuid`] string.
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    pub const LENGTH: usize = 36;
+
+    /// Creates a [`Hyphenated`] from a [`Uuid`].
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    /// [`Hyphenated`]: struct.Hyphenated.html
+    #[cfg(not(feature = "const_fn"))]
+    pub fn from_uuid(uuid: Uuid) -> Self {
+        Hyphenated(uuid)
+    }
+
+    /// Creates a [`Hyphenated`] from a [`Uuid`].
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    /// [`Hyphenated`]: struct.Hyphenated.html
+    #[cfg(feature = "const_fn")]
+    pub const fn from_uuid(uuid: Uuid) -> Self {
+        Hyphenated(uuid)
+    }
+
+    // Writes the [`Uuid`] as a lower-case hyphenated string to
+    // `buffer`, and returns the subslice of the buffer that contains the
+    // encoded UUID.
+    //
+    // This is slightly more efficient than using the formatting
+    // infrastructure as it avoids virtual calls, and may avoid
+    // double buffering.
+    //
+    // [`Uuid`]: ../struct.Uuid.html
+    //
+    // # Panics
+    //
+    // Panics if the buffer is not large enough: it must have length at least
+    // [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a
+    // sufficiently-large temporary buffer.
+    //
+    // [`LENGTH`]: #associatedconstant.LENGTH
+    // [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer
+    //
+    // # Examples
+    //
+    // ```rust
+    // use uuid::Uuid;
+    //
+    // let uuid = Uuid::parse_str("936DA01f9abd4d9d80c702af85c822a8").unwrap();
+    //
+    // // the encoded portion is returned
+    // assert_eq!(
+    //     uuid.to_hyphenated()
+    //         .encode_lower(&mut Uuid::encode_buffer()),
+    //     "936da01f-9abd-4d9d-80c7-02af85c822a8"
+    // );
+    //
+    // // the buffer is mutated directly, and trailing contents remains
+    // let mut buf = [b'!'; 40];
+    // uuid.to_hyphenated().encode_lower(&mut buf);
+    // assert_eq!(
+    //     &buf as &[_],
+    //     b"936da01f-9abd-4d9d-80c7-02af85c822a8!!!!" as &[_]
+    // );
+    // ```
+    // */
+    pub(crate) fn encode_lower<'buf>(
+        &self,
+        buffer: &'buf mut [u8],
+    ) -> &'buf mut str {
+        encode(buffer, 0, &self.0, true, false)
+    }
+
+    // Writes the [`Uuid`] as an upper-case hyphenated string to
+    // `buffer`, and returns the subslice of the buffer that contains the
+    // encoded UUID.
+    //
+    // This is slightly more efficient than using the formatting
+    // infrastructure as it avoids virtual calls, and may avoid
+    // double buffering.
+    //
+    // [`Uuid`]: ../struct.Uuid.html
+    //
+    // # Panics
+    //
+    // Panics if the buffer is not large enough: it must have length at least
+    // [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a
+    // sufficiently-large temporary buffer.
+    //
+    // [`LENGTH`]: #associatedconstant.LENGTH
+    // [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer
+    //
+    // # Examples
+    //
+    // ```rust
+    // use uuid::Uuid;
+    //
+    // let uuid = Uuid::parse_str("936da01f9abd4d9d80c702af85c822a8").unwrap();
+    //
+    // // the encoded portion is returned
+    // assert_eq!(
+    //     uuid.to_hyphenated()
+    //         .encode_upper(&mut Uuid::encode_buffer()),
+    //     "936DA01F-9ABD-4D9D-80C7-02AF85C822A8"
+    // );
+    //
+    // // the buffer is mutated directly, and trailing contents remains
+    // let mut buf = [b'!'; 40];
+    // uuid.to_hyphenated().encode_upper(&mut buf);
+    // assert_eq!(
+    //     &buf as &[_],
+    //     b"936DA01F-9ABD-4D9D-80C7-02AF85C822A8!!!!" as &[_]
+    // );
+    // ```
+    // */
+    pub(crate) fn encode_upper<'buf>(
+        &self,
+        buffer: &'buf mut [u8],
+    ) -> &'buf mut str {
+        encode(buffer, 0, &self.0, true, true)
+    }
+}
+
+impl<'a> HyphenatedRef<'a> {
+    /// The length of a hyphenated [`Uuid`] string.
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    pub const LENGTH: usize = 36;
+
+    /// Creates a [`HyphenatedRef`] from a [`Uuid`] reference.
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    /// [`HyphenatedRef`]: struct.HyphenatedRef.html
+    #[cfg(not(feature = "const_fn"))]
+    pub fn from_uuid_ref(uuid: &'a Uuid) -> Self {
+        HyphenatedRef(uuid)
+    }
+
+    /// Creates a [`HyphenatedRef`] from a [`Uuid`] reference.
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    /// [`HyphenatedRef`]: struct.HyphenatedRef.html
+    #[cfg(feature = "const_fn")]
+    pub const fn from_uuid_ref(uuid: &'a Uuid) -> Self {
+        HyphenatedRef(uuid)
+    }
+
+    // Writes the [`Uuid`] as a lower-case hyphenated string to
+    // `buffer`, and returns the subslice of the buffer that contains the
+    // encoded UUID.
+    //
+    // This is slightly more efficient than using the formatting
+    // infrastructure as it avoids virtual calls, and may avoid
+    // double buffering.
+    //
+    // [`Uuid`]: ../struct.Uuid.html
+    //
+    // # Panics
+    //
+    // Panics if the buffer is not large enough: it must have length at least
+    // [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a
+    // sufficiently-large temporary buffer.
+    //
+    // [`LENGTH`]: #associatedconstant.LENGTH
+    // [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer
+    //
+    // # Examples
+    //
+    // ```rust
+    // use uuid::Uuid;
+    //
+    // let uuid = Uuid::parse_str("936DA01f9abd4d9d80c702af85c822a8").unwrap();
+    //
+    // // the encoded portion is returned
+    // assert_eq!(
+    //     uuid.to_hyphenated()
+    //         .encode_lower(&mut Uuid::encode_buffer()),
+    //     "936da01f-9abd-4d9d-80c7-02af85c822a8"
+    // );
+    //
+    // // the buffer is mutated directly, and trailing contents remains
+    // let mut buf = [b'!'; 40];
+    // uuid.to_hyphenated().encode_lower(&mut buf);
+    // assert_eq!(
+    //     uuid.to_hyphenated().encode_lower(&mut buf),
+    //     "936da01f-9abd-4d9d-80c7-02af85c822a8"
+    // );
+    // assert_eq!(
+    //     &buf as &[_],
+    //     b"936da01f-9abd-4d9d-80c7-02af85c822a8!!!!" as &[_]
+    // );
+    // ```
+    // */
+    pub(crate) fn encode_lower<'buf>(
+        &self,
+        buffer: &'buf mut [u8],
+    ) -> &'buf mut str {
+        encode(buffer, 0, self.0, true, false)
+    }
+
+    // Writes the [`Uuid`] as an upper-case hyphenated string to
+    // `buffer`, and returns the subslice of the buffer that contains the
+    // encoded UUID.
+    //
+    // This is slightly more efficient than using the formatting
+    // infrastructure as it avoids virtual calls, and may avoid
+    // double buffering.
+    //
+    // [`Uuid`]: ../struct.Uuid.html
+    //
+    // # Panics
+    //
+    // Panics if the buffer is not large enough: it must have length at least
+    // [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a
+    // sufficiently-large temporary buffer.
+    //
+    // [`LENGTH`]: #associatedconstant.LENGTH
+    // [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer
+    //
+    // # Examples
+    //
+    // ```rust
+    // use uuid::Uuid;
+    //
+    // let uuid = Uuid::parse_str("936da01f9abd4d9d80c702af85c822a8").unwrap();
+    //
+    // // the encoded portion is returned
+    // assert_eq!(
+    //     uuid.to_hyphenated()
+    //         .encode_upper(&mut Uuid::encode_buffer()),
+    //     "936DA01F-9ABD-4D9D-80C7-02AF85C822A8"
+    // );
+    //
+    // // the buffer is mutated directly, and trailing contents remains
+    // let mut buf = [b'!'; 40];
+    // assert_eq!(
+    //     uuid.to_hyphenated().encode_upper(&mut buf),
+    //     "936DA01F-9ABD-4D9D-80C7-02AF85C822A8"
+    // );
+    // assert_eq!(
+    //     &buf as &[_],
+    //     b"936DA01F-9ABD-4D9D-80C7-02AF85C822A8!!!!" as &[_]
+    // );
+    // ```
+    // */
+    pub(crate) fn encode_upper<'buf>(
+        &self,
+        buffer: &'buf mut [u8],
+    ) -> &'buf mut str {
+        encode(buffer, 0, self.0, true, true)
+    }
+}
+
+impl Simple {
+    /// The length of a simple [`Uuid`] string.
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    pub const LENGTH: usize = 32;
+
+    /// Creates a [`Simple`] from a [`Uuid`].
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    /// [`Simple`]: struct.Simple.html
+    #[cfg(not(feature = "const_fn"))]
+    pub fn from_uuid(uuid: Uuid) -> Self {
+        Simple(uuid)
+    }
+
+    /// Creates a [`Simple`] from a [`Uuid`].
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    /// [`Simple`]: struct.Simple.html
+    #[cfg(feature = "const_fn")]
+    pub const fn from_uuid(uuid: Uuid) -> Self {
+        Simple(uuid)
+    }
+
+    // Writes the [`Uuid`] as a lower-case simple string to `buffer`,
+    // and returns the subslice of the buffer that contains the encoded UUID.
+    //
+    // This is slightly more efficient than using the formatting
+    // infrastructure as it avoids virtual calls, and may avoid
+    // double buffering.
+    //
+    // [`Uuid`]: ../struct.Uuid.html
+    //
+    // # Panics
+    //
+    // Panics if the buffer is not large enough: it must have length at least
+    // [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a
+    // sufficiently-large temporary buffer.
+    //
+    // [`LENGTH`]: #associatedconstant.LENGTH
+    // [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer
+    //
+    // # Examples
+    //
+    // ```rust
+    // use uuid::Uuid;
+    //
+    // let uuid = Uuid::parse_str("936DA01f9abd4d9d80c702af85c822a8").unwrap();
+    //
+    // // the encoded portion is returned
+    // assert_eq!(
+    //     uuid.to_simple().encode_lower(&mut Uuid::encode_buffer()),
+    //     "936da01f9abd4d9d80c702af85c822a8"
+    // );
+    //
+    // // the buffer is mutated directly, and trailing contents remains
+    // let mut buf = [b'!'; 36];
+    // assert_eq!(
+    //     uuid.to_simple().encode_lower(&mut buf),
+    //     "936da01f9abd4d9d80c702af85c822a8"
+    // );
+    // assert_eq!(
+    //     &buf as &[_],
+    //     b"936da01f9abd4d9d80c702af85c822a8!!!!" as &[_]
+    // );
+    // ```
+    // */
+    pub(crate) fn encode_lower<'buf>(
+        &self,
+        buffer: &'buf mut [u8],
+    ) -> &'buf mut str {
+        encode(buffer, 0, &self.0, false, false)
+    }
+
+    // Writes the [`Uuid`] as an upper-case simple string to `buffer`,
+    // and returns the subslice of the buffer that contains the encoded UUID.
+    //
+    // [`Uuid`]: ../struct.Uuid.html
+    //
+    // # Panics
+    //
+    // Panics if the buffer is not large enough: it must have length at least
+    // [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a
+    // sufficiently-large temporary buffer.
+    //
+    // [`LENGTH`]: #associatedconstant.LENGTH
+    // [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer
+    //
+    // # Examples
+    //
+    // ```rust
+    // use uuid::Uuid;
+    //
+    // let uuid = Uuid::parse_str("936da01f9abd4d9d80c702af85c822a8").unwrap();
+    //
+    // // the encoded portion is returned
+    // assert_eq!(
+    //     uuid.to_simple().encode_upper(&mut Uuid::encode_buffer()),
+    //     "936DA01F9ABD4D9D80C702AF85C822A8"
+    // );
+    //
+    // // the buffer is mutated directly, and trailing contents remains
+    // let mut buf = [b'!'; 36];
+    // assert_eq!(
+    //     uuid.to_simple().encode_upper(&mut buf),
+    //     "936DA01F9ABD4D9D80C702AF85C822A8"
+    // );
+    // assert_eq!(
+    //     &buf as &[_],
+    //     b"936DA01F9ABD4D9D80C702AF85C822A8!!!!" as &[_]
+    // );
+    // ```
+    // */
+    pub(crate) fn encode_upper<'buf>(
+        &self,
+        buffer: &'buf mut [u8],
+    ) -> &'buf mut str {
+        encode(buffer, 0, &self.0, false, true)
+    }
+}
+
+impl<'a> SimpleRef<'a> {
+    /// The length of a simple [`Uuid`] string.
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    pub const LENGTH: usize = 32;
+
+    /// Creates a [`SimpleRef`] from a [`Uuid`] reference.
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    /// [`SimpleRef`]: struct.SimpleRef.html
+    #[cfg(not(feature = "const_fn"))]
+    pub fn from_uuid_ref(uuid: &'a Uuid) -> Self {
+        SimpleRef(uuid)
+    }
+
+    /// Creates a [`SimpleRef`] from a [`Uuid`] reference.
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    /// [`SimpleRef`]: struct.SimpleRef.html
+    #[cfg(feature = "const_fn")]
+    pub const fn from_uuid_ref(uuid: &'a Uuid) -> Self {
+        SimpleRef(uuid)
+    }
+
+    // Writes the [`Uuid`] as a lower-case simple string to `buffer`,
+    // and returns the subslice of the buffer that contains the encoded UUID.
+    //
+    // This is slightly more efficient than using the formatting
+    // infrastructure as it avoids virtual calls, and may avoid
+    // double buffering.
+    //
+    // [`Uuid`]: ../struct.Uuid.html
+    //
+    // # Panics
+    //
+    // Panics if the buffer is not large enough: it must have length at least
+    // [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a
+    // sufficiently-large temporary buffer.
+    //
+    // [`LENGTH`]: #associatedconstant.LENGTH
+    // [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer
+    //
+    // # Examples
+    //
+    // ```rust
+    // use uuid::Uuid;
+    //
+    // let uuid = Uuid::parse_str("936DA01f9abd4d9d80c702af85c822a8").unwrap();
+    //
+    // // the encoded portion is returned
+    // assert_eq!(
+    //     uuid.to_simple().encode_lower(&mut Uuid::encode_buffer()),
+    //     "936da01f9abd4d9d80c702af85c822a8"
+    // );
+    //
+    // // the buffer is mutated directly, and trailing contents remains
+    // let mut buf = [b'!'; 36];
+    // assert_eq!(
+    //     uuid.to_simple().encode_lower(&mut buf),
+    //     "936da01f9abd4d9d80c702af85c822a8"
+    // );
+    // assert_eq!(
+    //     &buf as &[_],
+    //     b"936da01f9abd4d9d80c702af85c822a8!!!!" as &[_]
+    // );
+    // ```
+    // */
+    pub(crate) fn encode_lower<'buf>(
+        &self,
+        buffer: &'buf mut [u8],
+    ) -> &'buf mut str {
+        encode(buffer, 0, self.0, false, false)
+    }
+
+    // Writes the [`Uuid`] as an upper-case simple string to `buffer`,
+    // and returns the subslice of the buffer that contains the encoded UUID.
+    //
+    // [`Uuid`]: ../struct.Uuid.html
+    //
+    // # Panics
+    //
+    // Panics if the buffer is not large enough: it must have length at least
+    // [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a
+    // sufficiently-large temporary buffer.
+    //
+    // [`LENGTH`]: #associatedconstant.LENGTH
+    // [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer
+    //
+    // # Examples
+    //
+    // ```rust
+    // use uuid::Uuid;
+    //
+    // let uuid = Uuid::parse_str("936da01f9abd4d9d80c702af85c822a8").unwrap();
+    //
+    // // the encoded portion is returned
+    // assert_eq!(
+    //     uuid.to_simple().encode_upper(&mut Uuid::encode_buffer()),
+    //     "936DA01F9ABD4D9D80C702AF85C822A8"
+    // );
+    //
+    // // the buffer is mutated directly, and trailing contents remains
+    // let mut buf = [b'!'; 36];
+    // assert_eq!(
+    //     uuid.to_simple().encode_upper(&mut buf),
+    //     "936DA01F9ABD4D9D80C702AF85C822A8"
+    // );
+    // assert_eq!(
+    //     &buf as &[_],
+    //     b"936DA01F9ABD4D9D80C702AF85C822A8!!!!" as &[_]
+    // );
+    // ```
+    // */
+    pub(crate) fn encode_upper<'buf>(
+        &self,
+        buffer: &'buf mut [u8],
+    ) -> &'buf mut str {
+        encode(buffer, 0, self.0, false, true)
+    }
+}
+
+impl Urn {
+    /// The length of a URN [`Uuid`] string.
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    pub const LENGTH: usize = 45;
+
+    /// Creates a [`Urn`] from a [`Uuid`].
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    /// [`Urn`]: struct.Urn.html
+    #[cfg(not(feature = "const_fn"))]
+    pub fn from_uuid(uuid: Uuid) -> Self {
+        Urn(uuid)
+    }
+
+    /// Creates a [`Urn`] from a [`Uuid`].
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    /// [`Urn`]: struct.Urn.html
+    #[cfg(feature = "const_fn")]
+    pub const fn from_uuid(uuid: Uuid) -> Self {
+        Urn(uuid)
+    }
+
+    // Writes the [`Uuid`] as a lower-case URN string to
+    // `buffer`, and returns the subslice of the buffer that contains the
+    // encoded UUID.
+    //
+    // This is slightly more efficient than using the formatting
+    // infrastructure as it avoids virtual calls, and may avoid
+    // double buffering.
+    //
+    // [`Uuid`]: ../struct.Uuid.html
+    //
+    // # Panics
+    //
+    // Panics if the buffer is not large enough: it must have length at least
+    // [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a
+    // sufficiently-large temporary buffer.
+    //
+    // [`LENGTH`]: #associatedconstant.LENGTH
+    // [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer
+    //
+    // # Examples
+    //
+    // ```rust
+    // use uuid::Uuid;
+    //
+    // let uuid = Uuid::parse_str("936DA01f9abd4d9d80c702af85c822a8").unwrap();
+    //
+    // // the encoded portion is returned
+    // assert_eq!(
+    //     uuid.to_urn().encode_lower(&mut Uuid::encode_buffer()),
+    //     "urn:uuid:936da01f-9abd-4d9d-80c7-02af85c822a8"
+    // );
+    //
+    // // the buffer is mutated directly, and trailing contents remains
+    // let mut buf = [b'!'; 49];
+    // uuid.to_urn().encode_lower(&mut buf);
+    // assert_eq!(
+    //     uuid.to_urn().encode_lower(&mut buf),
+    //     "urn:uuid:936da01f-9abd-4d9d-80c7-02af85c822a8"
+    // );
+    // assert_eq!(
+    //     &buf as &[_],
+    //     b"urn:uuid:936da01f-9abd-4d9d-80c7-02af85c822a8!!!!" as &[_]
+    // );
+    // ```
+    // */
+    pub(crate) fn encode_lower<'buf>(
+        &self,
+        buffer: &'buf mut [u8],
+    ) -> &'buf mut str {
+        buffer[..9].copy_from_slice(b"urn:uuid:");
+        encode(buffer, 9, &self.0, true, false)
+    }
+
+    // Writes the [`Uuid`] as an upper-case URN string to
+    // `buffer`, and returns the subslice of the buffer that contains the
+    // encoded UUID.
+    //
+    // This is slightly more efficient than using the formatting
+    // infrastructure as it avoids virtual calls, and may avoid
+    // double buffering.
+    //
+    // [`Uuid`]: ../struct.Uuid.html
+    //
+    // # Panics
+    //
+    // Panics if the buffer is not large enough: it must have length at least
+    // [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a
+    // sufficiently-large temporary buffer.
+    //
+    // [`LENGTH`]: #associatedconstant.LENGTH
+    // [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer
+    //
+    // # Examples
+    //
+    // ```rust
+    // use uuid::Uuid;
+    //
+    // let uuid = Uuid::parse_str("936da01f9abd4d9d80c702af85c822a8").unwrap();
+    //
+    // // the encoded portion is returned
+    // assert_eq!(
+    //     uuid.to_urn().encode_upper(&mut Uuid::encode_buffer()),
+    //     "urn:uuid:936DA01F-9ABD-4D9D-80C7-02AF85C822A8"
+    // );
+    //
+    // // the buffer is mutated directly, and trailing contents remains
+    // let mut buf = [b'!'; 49];
+    // assert_eq!(
+    //     uuid.to_urn().encode_upper(&mut buf),
+    //     "urn:uuid:936DA01F-9ABD-4D9D-80C7-02AF85C822A8"
+    // );
+    // assert_eq!(
+    //     &buf as &[_],
+    //     b"urn:uuid:936DA01F-9ABD-4D9D-80C7-02AF85C822A8!!!!" as &[_]
+    // );
+    // ```
+    // */
+    pub(crate) fn encode_upper<'buf>(
+        &self,
+        buffer: &'buf mut [u8],
+    ) -> &'buf mut str {
+        buffer[..9].copy_from_slice(b"urn:uuid:");
+        encode(buffer, 9, &self.0, true, true)
+    }
+}
+
+impl<'a> UrnRef<'a> {
+    /// The length of a URN [`Uuid`] string.
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    pub const LENGTH: usize = 45;
+
+    /// Creates a [`UrnRef`] from a [`Uuid`] reference.
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    /// [`UrnRef`]: struct.UrnRef.html
+    #[cfg(not(feature = "const_fn"))]
+    pub fn from_uuid_ref(uuid: &'a Uuid) -> Self {
+        UrnRef(uuid)
+    }
+
+    /// Creates a [`UrnRef`] from a [`Uuid`] reference.
+    ///
+    /// [`Uuid`]: ../struct.Uuid.html
+    /// [`UrnRef`]: struct.UrnRef.html
+    #[cfg(feature = "const_fn")]
+    pub const fn from_uuid_ref(uuid: &'a Uuid) -> Self {
+        UrnRef(&uuid)
+    }
+
+    // Writes the [`Uuid`] as a lower-case URN string to
+    // `buffer`, and returns the subslice of the buffer that contains the
+    // encoded UUID.
+    //
+    // This is slightly more efficient than using the formatting
+    // infrastructure as it avoids virtual calls, and may avoid
+    // double buffering.
+    //
+    // [`Uuid`]: ../struct.Uuid.html
+    //
+    // # Panics
+    //
+    // Panics if the buffer is not large enough: it must have length at least
+    // [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a
+    // sufficiently-large temporary buffer.
+    //
+    // [`LENGTH`]: #associatedconstant.LENGTH
+    // [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer
+    //
+    // # Examples
+    //
+    // ```rust
+    // use uuid::Uuid;
+    //
+    // let uuid = Uuid::parse_str("936DA01f9abd4d9d80c702af85c822a8").unwrap();
+    //
+    // // the encoded portion is returned
+    // assert_eq!(
+    //     uuid.to_urn().encode_lower(&mut Uuid::encode_buffer()),
+    //     "urn:uuid:936da01f-9abd-4d9d-80c7-02af85c822a8"
+    // );
+    //
+    // // the buffer is mutated directly, and trailing contents remains
+    // let mut buf = [b'!'; 49];
+    // uuid.to_urn().encode_lower(&mut buf);
+    // assert_eq!(
+    //     uuid.to_urn().encode_lower(&mut buf),
+    //     "urn:uuid:936da01f-9abd-4d9d-80c7-02af85c822a8"
+    // );
+    // assert_eq!(
+    //     &buf as &[_],
+    //     b"urn:uuid:936da01f-9abd-4d9d-80c7-02af85c822a8!!!!" as &[_]
+    // );
+    // ```
+    // */
+    pub(crate) fn encode_lower<'buf>(
+        &self,
+        buffer: &'buf mut [u8],
+    ) -> &'buf mut str {
+        buffer[..9].copy_from_slice(b"urn:uuid:");
+        encode(buffer, 9, self.0, true, false)
+    }
+
+    // Writes the [`Uuid`] as an upper-case URN string to
+    // `buffer`, and returns the subslice of the buffer that contains the
+    // encoded UUID.
+    //
+    // This is slightly more efficient than using the formatting
+    // infrastructure as it avoids virtual calls, and may avoid
+    // double buffering.
+    //
+    // [`Uuid`]: ../struct.Uuid.html
+    //
+    // # Panics
+    //
+    // Panics if the buffer is not large enough: it must have length at least
+    // [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a
+    // sufficiently-large temporary buffer.
+    //
+    // [`LENGTH`]: #associatedconstant.LENGTH
+    // [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer
+    //
+    // # Examples
+    //
+    // ```rust
+    // use uuid::Uuid;
+    //
+    // let uuid = Uuid::parse_str("936da01f9abd4d9d80c702af85c822a8").unwrap();
+    //
+    // // the encoded portion is returned
+    // assert_eq!(
+    //     uuid.to_urn().encode_upper(&mut Uuid::encode_buffer()),
+    //     "urn:uuid:936DA01F-9ABD-4D9D-80C7-02AF85C822A8"
+    // );
+    //
+    // // the buffer is mutated directly, and trailing contents remains
+    // let mut buf = [b'!'; 49];
+    // assert_eq!(
+    //     uuid.to_urn().encode_upper(&mut buf),
+    //     "urn:uuid:936DA01F-9ABD-4D9D-80C7-02AF85C822A8"
+    // );
+    // assert_eq!(
+    //     &buf as &[_],
+    //     b"urn:uuid:936DA01F-9ABD-4D9D-80C7-02AF85C822A8!!!!" as &[_]
+    // );
+    // ```
+    // */
+    pub(crate) fn encode_upper<'buf>(
+        &self,
+        buffer: &'buf mut [u8],
+    ) -> &'buf mut str {
+        buffer[..9].copy_from_slice(b"urn:uuid:");
+        encode(buffer, 9, self.0, true, true)
+    }
+}
+
+// TODO: uncomment when we undo the pub(crate) change
+// #[cfg(test)]
+// mod tests {
+// use Uuid;
+//
+// #[test]
+// fn hyphenated_trailing() {
+// let mut buf = [b'x'; 100];
+// let len = Uuid::nil().to_hyphenated().encode_lower(&mut buf).len();
+// assert_eq!(len, super::Hyphenated::LENGTH);
+// assert!(buf[len..].iter().all(|x| *x == b'x'));
+// }
+// #[test]
+// fn hyphenated_ref_trailing() {
+// let mut buf = [b'x'; 100];
+// let len = Uuid::nil().to_hyphenated().encode_lower(&mut buf).len();
+// assert_eq!(len, super::HyphenatedRef::LENGTH);
+// assert!(buf[len..].iter().all(|x| *x == b'x'));
+// }
+//
+// #[test]
+// fn simple_trailing() {
+// let mut buf = [b'x'; 100];
+// let len = Uuid::nil().to_simple().encode_lower(&mut buf).len();
+// assert_eq!(len, super::Simple::LENGTH);
+// assert!(buf[len..].iter().all(|x| *x == b'x'));
+// }
+// #[test]
+// fn simple_ref_trailing() {
+// let mut buf = [b'x'; 100];
+// let len = Uuid::nil().to_simple().encode_lower(&mut buf).len();
+// assert_eq!(len, super::SimpleRef::LENGTH);
+// assert!(buf[len..].iter().all(|x| *x == b'x'));
+// }
+//
+// #[test]
+// fn urn_trailing() {
+// let mut buf = [b'x'; 100];
+// let len = Uuid::nil().to_urn().encode_lower(&mut buf).len();
+// assert_eq!(len, super::Urn::LENGTH);
+// assert!(buf[len..].iter().all(|x| *x == b'x'));
+// }
+// #[test]
+// fn urn_ref_trailing() {
+// let mut buf = [b'x'; 100];
+// let len = Uuid::nil().to_urn().encode_lower(&mut buf).len();
+// assert_eq!(len, super::UrnRef::LENGTH);
+// assert!(buf[len..].iter().all(|x| *x == b'x'));
+// }
+//
+// #[test]
+// #[should_panic]
+// fn hyphenated_too_small() {
+// Uuid::nil().to_hyphenated().encode_lower(&mut [0; 35]);
+// }
+// #[test]
+// #[should_panic]
+// fn hyphenated_ref_too_small() {
+// Uuid::nil().to_hyphenated_ref().encode_lower(&mut [0; 35]);
+// }
+//
+// #[test]
+// #[should_panic]
+// fn simple_too_small() {
+// Uuid::nil().to_simple().encode_lower(&mut [0; 31]);
+// }
+// #[test]
+// #[should_panic]
+// fn simple_ref_too_small() {
+// Uuid::nil().to_simple_ref().encode_lower(&mut [0; 31]);
+// }
+// #[test]
+// #[should_panic]
+// fn urn_too_small() {
+// Uuid::nil().to_urn().encode_lower(&mut [0; 44]);
+// }
+// #[test]
+// #[should_panic]
+// fn urn_ref_too_small() {
+// Uuid::nil().to_urn_ref().encode_lower(&mut [0; 44]);
+// }
+// }
--- a/third_party/rust/uuid/src/core_support.rs
+++ b/third_party/rust/uuid/src/core_support.rs
@@ -4,66 +4,71 @@
 // See the COPYRIGHT file at the top-level directory of this distribution.
 //
 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use core::{fmt, str};
+use parser;
 use prelude::*;
 
-cfg_if! {
-    if #[cfg(feature = "std")] {
-        use std::fmt;
-        use std::str;
-    } else {
-        use core::fmt;
-        use core::str;
-    }
-}
-
 impl fmt::Display for Uuid {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         fmt::LowerHex::fmt(self, f)
     }
 }
 
-impl fmt::Display for UuidVariant {
+impl fmt::Display for Variant {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
-            UuidVariant::NCS => write!(f, "NCS"),
-            UuidVariant::RFC4122 => write!(f, "RFC4122"),
-            UuidVariant::Microsoft => write!(f, "Microsoft"),
-            UuidVariant::Future => write!(f, "Future"),
+            Variant::NCS => write!(f, "NCS"),
+            Variant::RFC4122 => write!(f, "RFC4122"),
+            Variant::Microsoft => write!(f, "Microsoft"),
+            Variant::Future => write!(f, "Future"),
         }
     }
 }
 
+impl fmt::Display for ::BytesError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(
+            f,
+            "invalid bytes length: expected {}, found {}",
+            self.expected(),
+            self.found()
+        )
+    }
+}
+
 impl fmt::LowerHex for Uuid {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        <super::Hyphenated as fmt::LowerHex>::fmt(&self.hyphenated(), f)
+        fmt::LowerHex::fmt(&self.to_hyphenated_ref(), f)
     }
 }
 
 impl fmt::UpperHex for Uuid {
+    #[inline]
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        <super::Hyphenated as fmt::UpperHex>::fmt(&self.hyphenated(), f)
+        fmt::UpperHex::fmt(&self.to_hyphenated_ref(), f)
     }
 }
 
 impl str::FromStr for Uuid {
-    type Err = super::ParseError;
+    type Err = parser::ParseError;
 
-    fn from_str(uuid_str: &str) -> Result<Uuid, super::ParseError> {
+    fn from_str(uuid_str: &str) -> Result<Self, Self::Err> {
         Uuid::parse_str(uuid_str)
     }
 }
 
 impl Default for Uuid {
+    #[inline]
     fn default() -> Self {
         Uuid::nil()
     }
 }
 
 #[cfg(test)]
 mod tests {
     extern crate std;
@@ -104,17 +109,17 @@ mod tests {
     #[test]
     fn test_uuid_display() {
         use super::fmt::Write;
 
         let uuid = test_util::new();
         let s = uuid.to_string();
         let mut buffer = String::new();
 
-        assert_eq!(s, uuid.hyphenated().to_string());
+        assert_eq!(s, uuid.to_hyphenated().to_string());
 
         check!(buffer, "{}", uuid, 36, |c| c.is_lowercase()
             || c.is_digit(10)
             || c == '-');
     }