summaryrefslogtreecommitdiffstats
path: root/third_party/rust/winreg
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/winreg')
-rw-r--r--third_party/rust/winreg/.cargo-checksum.json1
-rw-r--r--third_party/rust/winreg/Cargo.lock350
-rw-r--r--third_party/rust/winreg/Cargo.toml75
-rw-r--r--third_party/rust/winreg/LICENSE19
-rw-r--r--third_party/rust/winreg/README.md381
-rw-r--r--third_party/rust/winreg/appveyor.yml37
-rw-r--r--third_party/rust/winreg/build.rs11
-rw-r--r--third_party/rust/winreg/examples/basic_usage.rs69
-rw-r--r--third_party/rust/winreg/examples/enum.rs27
-rw-r--r--third_party/rust/winreg/examples/installed_apps.rs50
-rw-r--r--third_party/rust/winreg/examples/load_app_key.rs26
-rw-r--r--third_party/rust/winreg/examples/map_key_serialization.rs57
-rw-r--r--third_party/rust/winreg/examples/serialization.rs93
-rw-r--r--third_party/rust/winreg/examples/transactions.rs35
-rw-r--r--third_party/rust/winreg/src/decoder/mod.rs101
-rw-r--r--third_party/rust/winreg/src/decoder/serialization_serde.rs331
-rw-r--r--third_party/rust/winreg/src/encoder/mod.rs97
-rw-r--r--third_party/rust/winreg/src/encoder/serialization_serde.rs513
-rw-r--r--third_party/rust/winreg/src/enums.rs51
-rw-r--r--third_party/rust/winreg/src/lib.rs1143
-rw-r--r--third_party/rust/winreg/src/transaction.rs105
-rw-r--r--third_party/rust/winreg/src/types.rs199
-rw-r--r--third_party/rust/winreg/tests/reg_key.rs364
23 files changed, 4135 insertions, 0 deletions
diff --git a/third_party/rust/winreg/.cargo-checksum.json b/third_party/rust/winreg/.cargo-checksum.json
new file mode 100644
index 0000000000..c0feadd1a0
--- /dev/null
+++ b/third_party/rust/winreg/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.lock":"818308f83f82333925a5c79a33070576296820a9ca6f619b3be3b89918916f22","Cargo.toml":"7462003029eaddf0220e48731744d83b9e91b40a71c33ee13543b65995c4fb52","LICENSE":"ea021d8c6383c84d19c15ce90d3b1602cf448fdcc0bf3772c98e43c7bf1bf1d1","README.md":"37ad193ded0a105eecea15743a76249c6ec735b82a06b78312052648564eccb5","appveyor.yml":"92f6bab3b9609448c48983d6c418fb9061dbd851a9d804ccd923f7e34ab742f1","build.rs":"3d34e0c23f6c21e6da11fb0fc3aff792b8f30f3ecfbb6b4f536d0a70394e13e7","examples/basic_usage.rs":"e7dd3af233d3aca6a92676eab2ac55414af1477d4214e7c1c2cdbdf583c83fa1","examples/enum.rs":"9be94d7dde12fc49a3fbe5c7810a6a9ad28eaac9319271e1cabda121301e08f3","examples/installed_apps.rs":"595709b6453b1efb5c613e69795d6f6576d45762867de1ee7247f2c3e988edbb","examples/load_app_key.rs":"16275c44efa22519101c199903c53e0cdca5ad4ebdcb39939c5a285de2fa006c","examples/map_key_serialization.rs":"82b102a36c91f99e8eeb2d1cfde13131f087457de1c84db3af31097fdb4541b0","examples/serialization.rs":"7f5c0e7e50872c9655cf4e54b4efb54a8bc19113dc645279496b8e3d20109295","examples/transactions.rs":"8094aa5dcecedae3acef58ece3ed264a44e908c12cfd4a65ff8c90254dbc7225","src/decoder/mod.rs":"75318907ca32ff0aa3af9bf63be9d728a76d7a75f7d1fdb88bcb3a9df4abeb01","src/decoder/serialization_serde.rs":"3f7cc4249dbff8255ed40cd4a3b4416779ddbad4bd476032094259a8668d0cd2","src/encoder/mod.rs":"a5331802cbe374e0c511aa1335fa32d7bbb3aa972cb136df3fc585b3f3855cf5","src/encoder/serialization_serde.rs":"d63037eb017fd2ece03ed4a140baf2a75516a3ef0315bf10a3eb16d5455880d6","src/enums.rs":"d69acf7106672a1cf2b43091faa12de98d5cf400872e1fcbe6e1891ba5d185ae","src/lib.rs":"130872ae9e213c8705592f3e1eac3245029f93e2c22c8f2337e3ecea25152d49","src/transaction.rs":"adaeecac01dc5886b90ab4ef03889ddd136ce26206dfa8f8da7410f0db80a742","src/types.rs":"d0c3ebc2aaab2f0fac426e60701acefa435c91812540d52dba1532664a0301ee","tests/reg_key.rs":"8a59b554230545e15a3affa82fb6d9061b45ac15e777df6cc383b725b8f4ad93"},"package":"80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"} \ No newline at end of file
diff --git a/third_party/rust/winreg/Cargo.lock b/third_party/rust/winreg/Cargo.lock
new file mode 100644
index 0000000000..e021632fd1
--- /dev/null
+++ b/third_party/rust/winreg/Cargo.lock
@@ -0,0 +1,350 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "autocfg"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
+
+[[package]]
+name = "autocfg"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "cfg-if"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
+
+[[package]]
+name = "chrono"
+version = "0.4.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
+dependencies = [
+ "libc",
+ "num-integer",
+ "num-traits",
+ "time",
+ "winapi",
+]
+
+[[package]]
+name = "cloudabi"
+version = "0.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "fuchsia-cprng"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
+
+[[package]]
+name = "libc"
+version = "0.2.101"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21"
+
+[[package]]
+name = "num-integer"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
+dependencies = [
+ "autocfg 1.0.1",
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
+dependencies = [
+ "autocfg 1.0.1",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rand"
+version = "0.3.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c"
+dependencies = [
+ "libc",
+ "rand 0.4.6",
+]
+
+[[package]]
+name = "rand"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
+dependencies = [
+ "fuchsia-cprng",
+ "libc",
+ "rand_core 0.3.1",
+ "rdrand",
+ "winapi",
+]
+
+[[package]]
+name = "rand"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
+dependencies = [
+ "autocfg 0.1.7",
+ "libc",
+ "rand_chacha",
+ "rand_core 0.4.2",
+ "rand_hc",
+ "rand_isaac",
+ "rand_jitter",
+ "rand_os",
+ "rand_pcg",
+ "rand_xorshift",
+ "winapi",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
+dependencies = [
+ "autocfg 0.1.7",
+ "rand_core 0.3.1",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
+dependencies = [
+ "rand_core 0.4.2",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
+
+[[package]]
+name = "rand_hc"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
+dependencies = [
+ "rand_core 0.3.1",
+]
+
+[[package]]
+name = "rand_isaac"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
+dependencies = [
+ "rand_core 0.3.1",
+]
+
+[[package]]
+name = "rand_jitter"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
+dependencies = [
+ "libc",
+ "rand_core 0.4.2",
+ "winapi",
+]
+
+[[package]]
+name = "rand_os"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
+dependencies = [
+ "cloudabi",
+ "fuchsia-cprng",
+ "libc",
+ "rand_core 0.4.2",
+ "rdrand",
+ "winapi",
+]
+
+[[package]]
+name = "rand_pcg"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
+dependencies = [
+ "autocfg 0.1.7",
+ "rand_core 0.4.2",
+]
+
+[[package]]
+name = "rand_xorshift"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
+dependencies = [
+ "rand_core 0.3.1",
+]
+
+[[package]]
+name = "rdrand"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
+dependencies = [
+ "rand_core 0.3.1",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.1.57"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
+
+[[package]]
+name = "remove_dir_all"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.130"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
+
+[[package]]
+name = "serde_derive"
+version = "1.0.130"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.76"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7dc4738f2e68ed2855de5ac9cdbe05c9216773ecde4739b2f095002ab03a13ef"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "rand 0.6.5",
+ "redox_syscall",
+ "remove_dir_all",
+ "winapi",
+]
+
+[[package]]
+name = "time"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
+dependencies = [
+ "libc",
+ "wasi",
+ "winapi",
+]
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
+
+[[package]]
+name = "wasi"
+version = "0.10.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "winreg"
+version = "0.10.1"
+dependencies = [
+ "chrono",
+ "rand 0.3.23",
+ "serde",
+ "serde_derive",
+ "tempfile",
+ "winapi",
+]
diff --git a/third_party/rust/winreg/Cargo.toml b/third_party/rust/winreg/Cargo.toml
new file mode 100644
index 0000000000..adb2e88655
--- /dev/null
+++ b/third_party/rust/winreg/Cargo.toml
@@ -0,0 +1,75 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies
+#
+# If you 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 = "winreg"
+version = "0.10.1"
+authors = ["Igor Shaula <gentoo90@gmail.com>"]
+description = "Rust bindings to MS Windows Registry API"
+documentation = "https://docs.rs/winreg"
+readme = "README.md"
+keywords = ["Windows", "WinSDK", "Registry"]
+categories = ["api-bindings", "os::windows-apis"]
+license = "MIT"
+repository = "https://github.com/gentoo90/winreg-rs"
+[package.metadata.docs.rs]
+all-features = true
+targets = ["x86_64-pc-windows-msvc", "i686-pc-windows-msvc"]
+
+[[example]]
+name = "basic_usage"
+required-features = ["chrono"]
+
+[[example]]
+name = "enum"
+
+[[example]]
+name = "load_app_key"
+
+[[example]]
+name = "transactions"
+required-features = ["transactions"]
+
+[[example]]
+name = "serialization"
+required-features = ["serialization-serde"]
+
+[[example]]
+name = "map_key_serialization"
+required-features = ["serialization-serde"]
+
+[[example]]
+name = "installed_apps"
+required-features = ["serialization-serde"]
+[dependencies.chrono]
+version = "0.4.6"
+optional = true
+
+[dependencies.serde]
+version = "1"
+optional = true
+
+[dependencies.winapi]
+version = "0.3.9"
+features = ["impl-default", "impl-debug", "minwindef", "minwinbase", "timezoneapi", "winerror", "winnt", "winreg", "handleapi"]
+[dev-dependencies.rand]
+version = "0.3"
+
+[dev-dependencies.serde_derive]
+version = "1"
+
+[dev-dependencies.tempfile]
+version = "~3.0"
+
+[features]
+serialization-serde = ["transactions", "serde"]
+transactions = ["winapi/ktmw32"]
diff --git a/third_party/rust/winreg/LICENSE b/third_party/rust/winreg/LICENSE
new file mode 100644
index 0000000000..b9d358e3e7
--- /dev/null
+++ b/third_party/rust/winreg/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2015 Igor Shaula
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/third_party/rust/winreg/README.md b/third_party/rust/winreg/README.md
new file mode 100644
index 0000000000..2683a0619f
--- /dev/null
+++ b/third_party/rust/winreg/README.md
@@ -0,0 +1,381 @@
+winreg
+[![Winreg on Appveyor][appveyor-image]][appveyor]
+[![Winreg on crates.io][cratesio-image]][cratesio]
+[![Winreg on docs.rs][docsrs-image]][docsrs]
+======
+
+[appveyor-image]: https://ci.appveyor.com/api/projects/status/f3lwrt67ghrf5omd?svg=true
+[appveyor]: https://ci.appveyor.com/project/gentoo90/winreg-rs
+[cratesio-image]: https://img.shields.io/crates/v/winreg.svg
+[cratesio]: https://crates.io/crates/winreg
+[docsrs-image]: https://docs.rs/winreg/badge.svg
+[docsrs]: https://docs.rs/winreg
+
+Rust bindings to MS Windows Registry API. Work in progress.
+
+Current features:
+* Basic registry operations:
+ * open/create/delete keys
+ * load application hive from a file
+ * read and write values
+ * seamless conversion between `REG_*` types and rust primitives
+ * `String` and `OsString` <= `REG_SZ`, `REG_EXPAND_SZ` or `REG_MULTI_SZ`
+ * `String`, `&str`, `OsString`, `&OsStr` => `REG_SZ`
+ * `Vec<String>`, `Vec<OsString>` <= `REG_MULTI_SZ`
+ * `Vec<String>`, `Vec<&str>`, `Vec<OsString>`, `Vec<&OsStr>` => `REG_MULTI_SZ`
+ * `u32` <=> `REG_DWORD`
+ * `u64` <=> `REG_QWORD`
+* Iteration through key names and through values
+* Transactions
+* Transacted serialization of rust types into/from registry (only primitives, structures and maps for now)
+
+## Usage
+
+### Basic usage
+
+```toml
+# Cargo.toml
+[dependencies]
+winreg = "0.10"
+```
+
+```rust
+extern crate winreg;
+use std::io;
+use std::path::Path;
+use winreg::enums::*;
+use winreg::RegKey;
+
+fn main() -> io::Result<()> {
+ println!("Reading some system info...");
+ let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
+ let cur_ver = hklm.open_subkey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion")?;
+ let pf: String = cur_ver.get_value("ProgramFilesDir")?;
+ let dp: String = cur_ver.get_value("DevicePath")?;
+ println!("ProgramFiles = {}\nDevicePath = {}", pf, dp);
+ let info = cur_ver.query_info()?;
+ println!("info = {:?}", info);
+ let mt = info.get_last_write_time_system();
+ println!(
+ "last_write_time as winapi::um::minwinbase::SYSTEMTIME = {}-{:02}-{:02} {:02}:{:02}:{:02}",
+ mt.wYear, mt.wMonth, mt.wDay, mt.wHour, mt.wMinute, mt.wSecond
+ );
+
+ // enable `chrono` feature on `winreg` to make this work
+ // println!(
+ // "last_write_time as chrono::NaiveDateTime = {}",
+ // info.get_last_write_time_chrono()
+ // );
+
+ println!("And now lets write something...");
+ let hkcu = RegKey::predef(HKEY_CURRENT_USER);
+ let path = Path::new("Software").join("WinregRsExample1");
+ let (key, disp) = hkcu.create_subkey(&path)?;
+
+ match disp {
+ REG_CREATED_NEW_KEY => println!("A new key has been created"),
+ REG_OPENED_EXISTING_KEY => println!("An existing key has been opened"),
+ }
+
+ key.set_value("TestSZ", &"written by Rust")?;
+ let sz_val: String = key.get_value("TestSZ")?;
+ key.delete_value("TestSZ")?;
+ println!("TestSZ = {}", sz_val);
+
+ key.set_value("TestMultiSZ", &vec!["written", "by", "Rust"])?;
+ let multi_sz_val: Vec<String> = key.get_value("TestMultiSZ")?;
+ key.delete_value("TestMultiSZ")?;
+ println!("TestMultiSZ = {:?}", multi_sz_val);
+
+ key.set_value("TestDWORD", &1234567890u32)?;
+ let dword_val: u32 = key.get_value("TestDWORD")?;
+ println!("TestDWORD = {}", dword_val);
+
+ key.set_value("TestQWORD", &1234567891011121314u64)?;
+ let qword_val: u64 = key.get_value("TestQWORD")?;
+ println!("TestQWORD = {}", qword_val);
+
+ key.create_subkey("sub\\key")?;
+ hkcu.delete_subkey_all(&path)?;
+
+ println!("Trying to open nonexistent key...");
+ hkcu.open_subkey(&path).unwrap_or_else(|e| match e.kind() {
+ io::ErrorKind::NotFound => panic!("Key doesn't exist"),
+ io::ErrorKind::PermissionDenied => panic!("Access denied"),
+ _ => panic!("{:?}", e),
+ });
+ Ok(())
+}
+```
+
+### Iterators
+
+```rust
+extern crate winreg;
+use std::io;
+use winreg::RegKey;
+use winreg::enums::*;
+
+fn main() -> io::Result<()> {
+ println!("File extensions, registered in system:");
+ for i in RegKey::predef(HKEY_CLASSES_ROOT)
+ .enum_keys().map(|x| x.unwrap())
+ .filter(|x| x.starts_with("."))
+ {
+ println!("{}", i);
+ }
+
+ let system = RegKey::predef(HKEY_LOCAL_MACHINE)
+ .open_subkey("HARDWARE\\DESCRIPTION\\System")?;
+ for (name, value) in system.enum_values().map(|x| x.unwrap()) {
+ println!("{} = {:?}", name, value);
+ }
+
+ Ok(())
+}
+```
+
+### Transactions
+
+```toml
+# Cargo.toml
+[dependencies]
+winreg = { version = "0.10", features = ["transactions"] }
+```
+
+```rust
+extern crate winreg;
+use std::io;
+use winreg::RegKey;
+use winreg::enums::*;
+use winreg::transaction::Transaction;
+
+fn main() -> io::Result<()> {
+ let t = Transaction::new()?;
+ let hkcu = RegKey::predef(HKEY_CURRENT_USER);
+ let (key, _disp) = hkcu.create_subkey_transacted("Software\\RustTransaction", &t)?;
+ key.set_value("TestQWORD", &1234567891011121314u64)?;
+ key.set_value("TestDWORD", &1234567890u32)?;
+
+ println!("Commit transaction? [y/N]:");
+ let mut input = String::new();
+ io::stdin().read_line(&mut input)?;
+ input = input.trim_right().to_owned();
+ if input == "y" || input == "Y" {
+ t.commit()?;
+ println!("Transaction committed.");
+ }
+ else {
+ // this is optional, if transaction wasn't committed,
+ // it will be rolled back on disposal
+ t.rollback()?;
+
+ println!("Transaction wasn't committed, it will be rolled back.");
+ }
+
+ Ok(())
+}
+```
+
+### Serialization
+
+```toml
+# Cargo.toml
+[dependencies]
+winreg = { version = "0.10", features = ["serialization-serde"] }
+serde = "1"
+serde_derive = "1"
+```
+
+```rust
+#[macro_use]
+extern crate serde_derive;
+extern crate winreg;
+use std::collections::HashMap;
+use std::error::Error;
+use winreg::enums::*;
+
+#[derive(Debug, Serialize, Deserialize, PartialEq)]
+struct Coords {
+ x: u32,
+ y: u32,
+}
+
+#[derive(Debug, Serialize, Deserialize, PartialEq)]
+struct Size {
+ w: u32,
+ h: u32,
+}
+
+#[derive(Debug, Serialize, Deserialize, PartialEq)]
+struct Rectangle {
+ coords: Coords,
+ size: Size,
+}
+
+#[derive(Debug, Serialize, Deserialize, PartialEq)]
+struct Test {
+ t_bool: bool,
+ t_u8: u8,
+ t_u16: u16,
+ t_u32: u32,
+ t_u64: u64,
+ t_usize: usize,
+ t_struct: Rectangle,
+ t_map: HashMap<String, u32>,
+ t_string: String,
+ #[serde(rename = "")] // empty name becomes the (Default) value in the registry
+ t_char: char,
+ t_i8: i8,
+ t_i16: i16,
+ t_i32: i32,
+ t_i64: i64,
+ t_isize: isize,
+ t_f64: f64,
+ t_f32: f32,
+}
+
+fn main() -> Result<(), Box<dyn Error>> {
+ let hkcu = winreg::RegKey::predef(HKEY_CURRENT_USER);
+ let (key, _disp) = hkcu.create_subkey("Software\\RustEncode")?;
+
+ let mut map = HashMap::new();
+ map.insert("".to_owned(), 0); // empty name becomes the (Default) value in the registry
+ map.insert("v1".to_owned(), 1);
+ map.insert("v2".to_owned(), 2);
+ map.insert("v3".to_owned(), 3);
+
+ let v1 = Test {
+ t_bool: false,
+ t_u8: 127,
+ t_u16: 32768,
+ t_u32: 123_456_789,
+ t_u64: 123_456_789_101_112,
+ t_usize: 1_234_567_891,
+ t_struct: Rectangle {
+ coords: Coords { x: 55, y: 77 },
+ size: Size { w: 500, h: 300 },
+ },
+ t_map: map,
+ t_string: "test 123!".to_owned(),
+ t_char: 'a',
+ t_i8: -123,
+ t_i16: -2049,
+ t_i32: 20100,
+ t_i64: -12_345_678_910,
+ t_isize: -1_234_567_890,
+ t_f64: -0.01,
+ t_f32: 3.15,
+ };
+
+ key.encode(&v1)?;
+
+ let v2: Test = key.decode()?;
+ println!("Decoded {:?}", v2);
+
+ println!("Equal to encoded: {:?}", v1 == v2);
+ Ok(())
+}
+```
+
+## Changelog
+
+### 0.10.1
+
+* Bump minimal required version of `winapi` to `0.3.9` (required for `load_app_key`)
+* Reexport `REG_PROCESS_APPKEY` and use it in the `load_app_key` example
+
+### 0.10.0
+
+* Add `RegKey::load_app_key()` and `RegKey::load_app_key_with_flags()` ([#30](https://github.com/gentoo90/winreg-rs/issues/30))
+* Update dev dependency `rand` to `0.8`
+* Add Github actions
+* Fix some clippy warnings
+
+### 0.9.0
+
+* Breaking change: `OsStr` and `OsString` registry values are not `NULL`-terminated any more ([#34](https://github.com/gentoo90/winreg-rs/issues/34), [#42](https://github.com/gentoo90/winreg-rs/issues/42))
+* Refactoring: use macros for `ToRegValue` impls and tests for string values
+* Fix `bare_trait_objects` warning in the doctests
+* Add `impl ToRegValue for OsString`
+* Add conversion between `REG_MULTI_SZ` and vectors of strings ([#16](https://github.com/gentoo90/winreg-rs/issues/16))
+* Fix: set minimal `winapi` version to 0.3.7 (earlier versions don't have `impl-default` and `impl-debug` features which we use)
+* Appveyor now checks the crate against `rust-1.31.1` too
+
+### 0.8.0
+
+* Implement serialization of `char` and maps
+* Implement `std::fmt::Display` for `RegValue`
+* Make `RegKey::{predef,raw_handle,enum_keys,enum_values}` functions `const`
+* Give a better error message when compiling on platforms other than Windows ([#38](https://github.com/gentoo90/winreg-rs/pull/38))
+* Tests are moved from `src/lib.rs` to `tests/reg_key.rs`
+
+### 0.7.0
+
+* Breaking change: remove deprecated `Error::description` ([#28](https://github.com/gentoo90/winreg-rs/pull/28))
+* Optimize `Iterator::nth()` for the `Enum*` iterators ([#29](https://github.com/gentoo90/winreg-rs/pull/29))
+
+### 0.6.2
+
+* Add `RegKey::delete_subkey_with_flags()` ([#27](https://github.com/gentoo90/winreg-rs/pull/27))
+
+### 0.6.1
+
+* Add `last_write_time` field to `RegKeyMetadata` (returned by `RegKey::query_info()`) ([#25](https://github.com/gentoo90/winreg-rs/pull/25)).
+* Add `get_last_write_time_system()` and `get_last_write_time_chrono()` (under `chrono` feature) methods to `RegKeyMetadata`.
+
+### 0.6.0
+
+* Breaking change: `create_subkey`, `create_subkey_with_flags`, `create_subkey_transacted` and
+`create_subkey_transacted_with_flags` now return a tuple which contains the subkey and its disposition
+which can be `REG_CREATED_NEW_KEY` or `REG_OPENED_EXISTING_KEY` ([#21](https://github.com/gentoo90/winreg-rs/issues/21)).
+* Examples fixed to not use `unwrap` according to [Rust API guidelines](https://rust-lang-nursery.github.io/api-guidelines/documentation.html#examples-use--not-try-not-unwrap-c-question-mark).
+
+### 0.5.1
+
+* Reexport `HKEY` ([#15](https://github.com/gentoo90/winreg-rs/issues/15)).
+* Add `raw_handle` method ([#18](https://github.com/gentoo90/winreg-rs/pull/18)).
+
+### 0.5.0
+
+* Breaking change: `open_subkey` now opens a key with readonly permissions.
+Use `create_subkey` or `open_subkey_with_flags` to open with read-write permissins.
+* Breaking change: features `transactions` and `serialization-serde` are now disabled by default.
+* Breaking change: serialization now uses `serde` instead of `rustc-serialize`.
+* `winapi` updated to `0.3`.
+* Documentation fixes ([#14](https://github.com/gentoo90/winreg-rs/pull/14))
+
+### 0.4.0
+
+* Make transactions and serialization otional features
+* Update dependensies + minor fixes ([#12](https://github.com/gentoo90/winreg-rs/pull/12))
+
+### 0.3.5
+
+* Implement `FromRegValue` for `OsString` and `ToRegValue` for `OsStr` ([#8](https://github.com/gentoo90/winreg-rs/issues/8))
+* Minor fixes
+
+### 0.3.4
+
+* Add `copy_tree` method to `RegKey`
+* Now checked with [rust-clippy](https://github.com/Manishearth/rust-clippy)
+ * no more `unwrap`s
+ * replaced `to_string` with `to_owned`
+* Fix: reading strings longer than 2048 characters ([#6](https://github.com/gentoo90/winreg-rs/pull/6))
+
+### 0.3.3
+
+* Fix: now able to read values longer than 2048 bytes ([#3](https://github.com/gentoo90/winreg-rs/pull/3))
+
+### 0.3.2
+
+* Fix: `FromRegValue` trait now requires `Sized` (fixes build with rust 1.4)
+
+### 0.3.1
+
+* Fix: bump `winapi` version to fix build
+
+### 0.3.0
+
+* Add transactions support and make serialization transacted
+* Breaking change: use `std::io::{Error,Result}` instead of own `RegError` and `RegResult`
diff --git a/third_party/rust/winreg/appveyor.yml b/third_party/rust/winreg/appveyor.yml
new file mode 100644
index 0000000000..b690b6a0cb
--- /dev/null
+++ b/third_party/rust/winreg/appveyor.yml
@@ -0,0 +1,37 @@
+version: 0.10.{build}
+pull_requests:
+ do_not_increment_build_number: true
+
+branches:
+ except:
+ - github-actions
+
+os: Visual Studio 2015
+
+environment:
+ matrix:
+ - TARGET: x86_64-pc-windows-msvc
+ CHANNEL: 1.31.1
+ - TARGET: x86_64-pc-windows-gnu
+ CHANNEL: stable
+ - TARGET: x86_64-pc-windows-msvc
+ CHANNEL: stable
+ - TARGET: i686-pc-windows-gnu
+ CHANNEL: stable
+ - TARGET: i686-pc-windows-msvc
+ CHANNEL: stable
+
+install:
+ - curl -sSf -o rustup-init.exe https://win.rustup.rs
+ - rustup-init.exe --profile=minimal --component rustfmt,clippy --default-host %TARGET% --default-toolchain %CHANNEL% -y
+ - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
+ - rustc -Vv
+ - cargo -V
+
+build: false
+
+test_script:
+ - if not "%CHANNEL%"=="1.31.1" cargo fmt --all -- --check
+ - if not "%CHANNEL%"=="1.31.1" cargo clippy --all-features --all-targets
+ - cargo test --release --no-default-features
+ - cargo test --release --all-features
diff --git a/third_party/rust/winreg/build.rs b/third_party/rust/winreg/build.rs
new file mode 100644
index 0000000000..7acab76640
--- /dev/null
+++ b/third_party/rust/winreg/build.rs
@@ -0,0 +1,11 @@
+fn main() {
+ if std::env::var("CARGO_CFG_WINDOWS").is_err() {
+ eprintln!("error: winreg is only supported on Windows platforms");
+ eprintln!(
+ "help: if your application is multi-platform, use \
+ `[target.'cfg(windows)'.dependencies] winreg = \"...\"`"
+ );
+ eprintln!("help: if your application is only supported on Windows, use `--target x86_64-pc-windows-gnu` or some other windows platform");
+ std::process::exit(1);
+ }
+}
diff --git a/third_party/rust/winreg/examples/basic_usage.rs b/third_party/rust/winreg/examples/basic_usage.rs
new file mode 100644
index 0000000000..6422e9eeb2
--- /dev/null
+++ b/third_party/rust/winreg/examples/basic_usage.rs
@@ -0,0 +1,69 @@
+// Copyright 2015, Igor Shaula
+// Licensed under the MIT License <LICENSE or
+// http://opensource.org/licenses/MIT>. This file
+// may not be copied, modified, or distributed
+// except according to those terms.
+extern crate winreg;
+use std::io;
+use std::path::Path;
+use winreg::enums::*;
+use winreg::RegKey;
+
+fn main() -> io::Result<()> {
+ println!("Reading some system info...");
+ let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
+ let cur_ver = hklm.open_subkey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion")?;
+ let pf: String = cur_ver.get_value("ProgramFilesDir")?;
+ let dp: String = cur_ver.get_value("DevicePath")?;
+ println!("ProgramFiles = {}\nDevicePath = {}", pf, dp);
+ let info = cur_ver.query_info()?;
+ println!("info = {:?}", info);
+ let mt = info.get_last_write_time_system();
+ println!(
+ "last_write_time as winapi::um::minwinbase::SYSTEMTIME = {}-{:02}-{:02} {:02}:{:02}:{:02}",
+ mt.wYear, mt.wMonth, mt.wDay, mt.wHour, mt.wMinute, mt.wSecond
+ );
+ println!(
+ "last_write_time as chrono::NaiveDateTime = {}",
+ info.get_last_write_time_chrono()
+ );
+
+ println!("And now lets write something...");
+ let hkcu = RegKey::predef(HKEY_CURRENT_USER);
+ let path = Path::new("Software").join("WinregRsExample1");
+ let (key, disp) = hkcu.create_subkey(&path)?;
+
+ match disp {
+ REG_CREATED_NEW_KEY => println!("A new key has been created"),
+ REG_OPENED_EXISTING_KEY => println!("An existing key has been opened"),
+ }
+
+ key.set_value("TestSZ", &"written by Rust")?;
+ let sz_val: String = key.get_value("TestSZ")?;
+ key.delete_value("TestSZ")?;
+ println!("TestSZ = {}", sz_val);
+
+ key.set_value("TestMultiSZ", &vec!["written", "by", "Rust"])?;
+ let multi_sz_val: Vec<String> = key.get_value("TestMultiSZ")?;
+ key.delete_value("TestMultiSZ")?;
+ println!("TestMultiSZ = {:?}", multi_sz_val);
+
+ key.set_value("TestDWORD", &1_234_567_890u32)?;
+ let dword_val: u32 = key.get_value("TestDWORD")?;
+ println!("TestDWORD = {}", dword_val);
+
+ key.set_value("TestQWORD", &1_234_567_891_011_121_314u64)?;
+ let qword_val: u64 = key.get_value("TestQWORD")?;
+ println!("TestQWORD = {}", qword_val);
+
+ key.create_subkey("sub\\key")?;
+ hkcu.delete_subkey_all(&path)?;
+
+ println!("Trying to open nonexistent key...");
+ hkcu.open_subkey(&path).unwrap_or_else(|e| match e.kind() {
+ io::ErrorKind::NotFound => panic!("Key doesn't exist"),
+ io::ErrorKind::PermissionDenied => panic!("Access denied"),
+ _ => panic!("{:?}", e),
+ });
+ Ok(())
+}
diff --git a/third_party/rust/winreg/examples/enum.rs b/third_party/rust/winreg/examples/enum.rs
new file mode 100644
index 0000000000..dd1a78d870
--- /dev/null
+++ b/third_party/rust/winreg/examples/enum.rs
@@ -0,0 +1,27 @@
+// Copyright 2015, Igor Shaula
+// Licensed under the MIT License <LICENSE or
+// http://opensource.org/licenses/MIT>. This file
+// may not be copied, modified, or distributed
+// except according to those terms.
+extern crate winreg;
+use std::io;
+use winreg::enums::*;
+use winreg::RegKey;
+
+fn main() -> io::Result<()> {
+ println!("File extensions, registered in system:");
+ for i in RegKey::predef(HKEY_CLASSES_ROOT)
+ .enum_keys()
+ .map(|x| x.unwrap())
+ .filter(|x| x.starts_with('.'))
+ {
+ println!("{}", i);
+ }
+
+ let system = RegKey::predef(HKEY_LOCAL_MACHINE).open_subkey("HARDWARE\\DESCRIPTION\\System")?;
+ for (name, value) in system.enum_values().map(|x| x.unwrap()) {
+ println!("{} = {:?}", name, value);
+ }
+
+ Ok(())
+}
diff --git a/third_party/rust/winreg/examples/installed_apps.rs b/third_party/rust/winreg/examples/installed_apps.rs
new file mode 100644
index 0000000000..a7546847db
--- /dev/null
+++ b/third_party/rust/winreg/examples/installed_apps.rs
@@ -0,0 +1,50 @@
+// Copyright 2017, Igor Shaula
+// Licensed under the MIT License <LICENSE or
+// http://opensource.org/licenses/MIT>. This file
+// may not be copied, modified, or distributed
+// except according to those terms.
+#[macro_use]
+extern crate serde_derive;
+extern crate winreg;
+use std::collections::HashMap;
+use std::fmt;
+use winreg::enums::*;
+
+#[allow(non_snake_case)]
+#[derive(Debug, Serialize, Deserialize)]
+struct InstalledApp {
+ DisplayName: Option<String>,
+ DisplayVersion: Option<String>,
+ UninstallString: Option<String>,
+}
+
+macro_rules! str_from_opt {
+ ($s:expr) => {
+ $s.as_ref().map(|x| &**x).unwrap_or("")
+ };
+}
+
+impl fmt::Display for InstalledApp {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(
+ f,
+ "{}-{}",
+ str_from_opt!(self.DisplayName),
+ str_from_opt!(self.DisplayVersion)
+ )
+ }
+}
+
+fn main() {
+ let hklm = winreg::RegKey::predef(HKEY_LOCAL_MACHINE);
+ let uninstall_key = hklm
+ .open_subkey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall")
+ .expect("key is missing");
+
+ let apps: HashMap<String, InstalledApp> =
+ uninstall_key.decode().expect("deserialization failed");
+
+ for v in apps.values() {
+ println!("{}", v);
+ }
+}
diff --git a/third_party/rust/winreg/examples/load_app_key.rs b/third_party/rust/winreg/examples/load_app_key.rs
new file mode 100644
index 0000000000..2340c82b59
--- /dev/null
+++ b/third_party/rust/winreg/examples/load_app_key.rs
@@ -0,0 +1,26 @@
+// Copyright 2021, Igor Shaula
+// Licensed under the MIT License <LICENSE or
+// http://opensource.org/licenses/MIT>. This file
+// may not be copied, modified, or distributed
+// except according to those terms.
+extern crate winreg;
+use std::io;
+use winreg::enums::*;
+use winreg::RegKey;
+
+fn main() -> io::Result<()> {
+ {
+ // put this in a block so app_key_1 gets out of scope and doesn't prevent us
+ // from loading the key again later
+ let app_key_1 = RegKey::load_app_key("myhive.dat", true)?;
+ app_key_1.set_value("answer", &42u32)?;
+ }
+ let answer: u32 = {
+ // NOTE: on Windows 7 this fails with ERROR_ALREADY_EXISTS
+ let app_key_2 =
+ RegKey::load_app_key_with_flags("myhive.dat", KEY_READ, REG_PROCESS_APPKEY)?;
+ app_key_2.get_value("answer")?
+ };
+ println!("The Answer is {}", answer);
+ Ok(())
+}
diff --git a/third_party/rust/winreg/examples/map_key_serialization.rs b/third_party/rust/winreg/examples/map_key_serialization.rs
new file mode 100644
index 0000000000..c0be704913
--- /dev/null
+++ b/third_party/rust/winreg/examples/map_key_serialization.rs
@@ -0,0 +1,57 @@
+// Copyright 2020, Igor Shaula
+// Licensed under the MIT License <LICENSE or
+// http://opensource.org/licenses/MIT>. This file
+// may not be copied, modified, or distributed
+// except according to those terms.
+#[macro_use]
+extern crate serde_derive;
+extern crate winreg;
+use std::collections::HashMap;
+use std::error::Error;
+use winreg::enums::*;
+
+#[derive(Debug, Serialize, Deserialize, PartialEq)]
+struct Coords {
+ x: u32,
+ y: u32,
+}
+
+#[derive(Debug, Serialize, Deserialize, PartialEq)]
+struct Size {
+ w: u32,
+ h: u32,
+}
+
+#[derive(Debug, Serialize, Deserialize, PartialEq)]
+struct Rectangle {
+ coords: Coords,
+ size: Size,
+}
+
+fn main() -> Result<(), Box<dyn Error>> {
+ let hkcu = winreg::RegKey::predef(HKEY_CURRENT_USER);
+ let (key, _disp) = hkcu.create_subkey("Software\\RustEncodeMapKey")?;
+ let mut v1 = HashMap::new();
+ v1.insert(
+ "first".to_owned(),
+ Rectangle {
+ coords: Coords { x: 55, y: 77 },
+ size: Size { w: 500, h: 300 },
+ },
+ );
+ v1.insert(
+ "second".to_owned(),
+ Rectangle {
+ coords: Coords { x: 11, y: 22 },
+ size: Size { w: 1000, h: 600 },
+ },
+ );
+
+ key.encode(&v1)?;
+
+ let v2: HashMap<String, Rectangle> = key.decode()?;
+ println!("Decoded {:?}", v2);
+
+ println!("Equal to encoded: {:?}", v1 == v2);
+ Ok(())
+}
diff --git a/third_party/rust/winreg/examples/serialization.rs b/third_party/rust/winreg/examples/serialization.rs
new file mode 100644
index 0000000000..462813291a
--- /dev/null
+++ b/third_party/rust/winreg/examples/serialization.rs
@@ -0,0 +1,93 @@
+// Copyright 2015, Igor Shaula
+// Licensed under the MIT License <LICENSE or
+// http://opensource.org/licenses/MIT>. This file
+// may not be copied, modified, or distributed
+// except according to those terms.
+#[macro_use]
+extern crate serde_derive;
+extern crate winreg;
+use std::collections::HashMap;
+use std::error::Error;
+use winreg::enums::*;
+
+#[derive(Debug, Serialize, Deserialize, PartialEq)]
+struct Coords {
+ x: u32,
+ y: u32,
+}
+
+#[derive(Debug, Serialize, Deserialize, PartialEq)]
+struct Size {
+ w: u32,
+ h: u32,
+}
+
+#[derive(Debug, Serialize, Deserialize, PartialEq)]
+struct Rectangle {
+ coords: Coords,
+ size: Size,
+}
+
+#[derive(Debug, Serialize, Deserialize, PartialEq)]
+struct Test {
+ t_bool: bool,
+ t_u8: u8,
+ t_u16: u16,
+ t_u32: u32,
+ t_u64: u64,
+ t_usize: usize,
+ t_struct: Rectangle,
+ t_map: HashMap<String, u32>,
+ t_string: String,
+ #[serde(rename = "")] // empty name becomes the (Default) value in the registry
+ t_char: char,
+ t_i8: i8,
+ t_i16: i16,
+ t_i32: i32,
+ t_i64: i64,
+ t_isize: isize,
+ t_f64: f64,
+ t_f32: f32,
+}
+
+fn main() -> Result<(), Box<dyn Error>> {
+ let hkcu = winreg::RegKey::predef(HKEY_CURRENT_USER);
+ let (key, _disp) = hkcu.create_subkey("Software\\RustEncode")?;
+
+ let mut map = HashMap::new();
+ map.insert("".to_owned(), 0); // empty name becomes the (Default) value in the registry
+ map.insert("v1".to_owned(), 1);
+ map.insert("v2".to_owned(), 2);
+ map.insert("v3".to_owned(), 3);
+
+ let v1 = Test {
+ t_bool: false,
+ t_u8: 127,
+ t_u16: 32768,
+ t_u32: 123_456_789,
+ t_u64: 123_456_789_101_112,
+ t_usize: 1_234_567_891,
+ t_struct: Rectangle {
+ coords: Coords { x: 55, y: 77 },
+ size: Size { w: 500, h: 300 },
+ },
+ t_map: map,
+ t_string: "test 123!".to_owned(),
+ t_char: 'a',
+ t_i8: -123,
+ t_i16: -2049,
+ t_i32: 20100,
+ t_i64: -12_345_678_910,
+ t_isize: -1_234_567_890,
+ t_f64: -0.01,
+ t_f32: 3.15,
+ };
+
+ key.encode(&v1)?;
+
+ let v2: Test = key.decode()?;
+ println!("Decoded {:?}", v2);
+
+ println!("Equal to encoded: {:?}", v1 == v2);
+ Ok(())
+}
diff --git a/third_party/rust/winreg/examples/transactions.rs b/third_party/rust/winreg/examples/transactions.rs
new file mode 100644
index 0000000000..4cc91b7c9f
--- /dev/null
+++ b/third_party/rust/winreg/examples/transactions.rs
@@ -0,0 +1,35 @@
+// Copyright 2015, Igor Shaula
+// Licensed under the MIT License <LICENSE or
+// http://opensource.org/licenses/MIT>. This file
+// may not be copied, modified, or distributed
+// except according to those terms.
+extern crate winreg;
+use std::io;
+use winreg::enums::*;
+use winreg::transaction::Transaction;
+use winreg::RegKey;
+
+fn main() -> io::Result<()> {
+ let t = Transaction::new()?;
+ let hkcu = RegKey::predef(HKEY_CURRENT_USER);
+ let (key, _disp) = hkcu.create_subkey_transacted("Software\\RustTransaction", &t)?;
+ key.set_value("TestQWORD", &1_234_567_891_011_121_314u64)?;
+ key.set_value("TestDWORD", &1_234_567_890u32)?;
+
+ println!("Commit transaction? [y/N]:");
+ let mut input = String::new();
+ io::stdin().read_line(&mut input)?;
+ input = input.trim_end().to_owned();
+ if input == "y" || input == "Y" {
+ t.commit()?;
+ println!("Transaction committed.");
+ } else {
+ // this is optional, if transaction wasn't committed,
+ // it will be rolled back on disposal
+ t.rollback()?;
+
+ println!("Transaction wasn't committed, it will be rolled back.");
+ }
+
+ Ok(())
+}
diff --git a/third_party/rust/winreg/src/decoder/mod.rs b/third_party/rust/winreg/src/decoder/mod.rs
new file mode 100644
index 0000000000..82493b846d
--- /dev/null
+++ b/third_party/rust/winreg/src/decoder/mod.rs
@@ -0,0 +1,101 @@
+// Copyright 2017, Igor Shaula
+// Licensed under the MIT License <LICENSE or
+// http://opensource.org/licenses/MIT>. This file
+// may not be copied, modified, or distributed
+// except according to those terms.
+use super::enums::*;
+use super::RegKey;
+use std::error::Error;
+use std::fmt;
+use std::io;
+use winapi::shared::minwindef::DWORD;
+
+macro_rules! read_value {
+ ($s:ident) => {
+ match mem::replace(&mut $s.f_name, None) {
+ Some(ref s) => $s.key.get_value(s).map_err(DecoderError::IoError),
+ None => Err(DecoderError::NoFieldName),
+ }
+ };
+}
+
+macro_rules! parse_string {
+ ($s:ident) => {{
+ let s: String = read_value!($s)?;
+ s.parse()
+ .map_err(|e| DecoderError::ParseError(format!("{:?}", e)))
+ }};
+}
+
+macro_rules! no_impl {
+ ($e:expr) => {
+ Err(DecoderError::DecodeNotImplemented($e.to_owned()))
+ };
+}
+
+#[cfg(feature = "serialization-serde")]
+mod serialization_serde;
+
+#[derive(Debug)]
+pub enum DecoderError {
+ DecodeNotImplemented(String),
+ DeserializerError(String),
+ IoError(io::Error),
+ ParseError(String),
+ NoFieldName,
+}
+
+impl fmt::Display for DecoderError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{:?}", self)
+ }
+}
+
+impl Error for DecoderError {}
+
+impl From<io::Error> for DecoderError {
+ fn from(err: io::Error) -> DecoderError {
+ DecoderError::IoError(err)
+ }
+}
+
+pub type DecodeResult<T> = Result<T, DecoderError>;
+
+#[derive(Debug)]
+enum DecoderReadingState {
+ WaitingForKey,
+ WaitingForValue,
+}
+
+#[derive(Debug)]
+enum DecoderEnumerationState {
+ EnumeratingKeys(DWORD),
+ EnumeratingValues(DWORD),
+}
+
+#[derive(Debug)]
+pub struct Decoder {
+ key: RegKey,
+ f_name: Option<String>,
+ reading_state: DecoderReadingState,
+ enumeration_state: DecoderEnumerationState,
+}
+
+const DECODER_SAM: DWORD = KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS;
+
+impl Decoder {
+ pub fn from_key(key: &RegKey) -> DecodeResult<Decoder> {
+ key.open_subkey_with_flags("", DECODER_SAM)
+ .map(Decoder::new)
+ .map_err(DecoderError::IoError)
+ }
+
+ fn new(key: RegKey) -> Decoder {
+ Decoder {
+ key,
+ f_name: None,
+ reading_state: DecoderReadingState::WaitingForKey,
+ enumeration_state: DecoderEnumerationState::EnumeratingKeys(0),
+ }
+ }
+}
diff --git a/third_party/rust/winreg/src/decoder/serialization_serde.rs b/third_party/rust/winreg/src/decoder/serialization_serde.rs
new file mode 100644
index 0000000000..1287540448
--- /dev/null
+++ b/third_party/rust/winreg/src/decoder/serialization_serde.rs
@@ -0,0 +1,331 @@
+// Copyright 2017, Igor Shaula
+// Licensed under the MIT License <LICENSE or
+// http://opensource.org/licenses/MIT>. This file
+// may not be copied, modified, or distributed
+// except according to those terms.
+use super::super::FromRegValue;
+use super::{
+ DecodeResult, Decoder, DecoderEnumerationState, DecoderError, DecoderReadingState, DECODER_SAM,
+};
+use serde::de::*;
+use std::fmt;
+use std::mem;
+
+impl Error for DecoderError {
+ fn custom<T: fmt::Display>(msg: T) -> Self {
+ DecoderError::DeserializerError(format!("{}", msg))
+ }
+}
+
+impl<'de, 'a> Deserializer<'de> for &'a mut Decoder {
+ type Error = DecoderError;
+ fn deserialize_any<V>(self, visitor: V) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ use self::DecoderEnumerationState::*;
+ match self.enumeration_state {
+ EnumeratingKeys(..) => no_impl!("deserialize_any for keys"),
+ EnumeratingValues(..) => {
+ let s = self.f_name.as_ref().ok_or(DecoderError::NoFieldName)?;
+ let v = self.key.get_raw_value(s)?;
+ use RegType::*;
+ match v.vtype {
+ REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => {
+ visitor.visit_string(String::from_reg_value(&v)?)
+ }
+ REG_DWORD => visitor.visit_u32(u32::from_reg_value(&v)?),
+ REG_QWORD => visitor.visit_u64(u64::from_reg_value(&v)?),
+ _ => Err(DecoderError::DecodeNotImplemented(
+ "value type deserialization not implemented".to_owned(),
+ )),
+ }
+ }
+ }
+ }
+
+ fn deserialize_bool<V>(self, visitor: V) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_bool(read_value!(self).map(|v: u32| v > 0)?)
+ }
+
+ fn deserialize_u8<V>(self, visitor: V) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_u32(visitor)
+ }
+
+ fn deserialize_u16<V>(self, visitor: V) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_u32(visitor)
+ }
+
+ fn deserialize_u32<V>(self, visitor: V) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_u32(read_value!(self)?)
+ }
+
+ fn deserialize_u64<V>(self, visitor: V) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_u64(read_value!(self)?)
+ }
+
+ fn deserialize_i8<V>(self, visitor: V) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_i8(parse_string!(self)?)
+ }
+
+ fn deserialize_i16<V>(self, visitor: V) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_i16(parse_string!(self)?)
+ }
+
+ fn deserialize_i32<V>(self, visitor: V) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_i32(parse_string!(self)?)
+ }
+
+ fn deserialize_i64<V>(self, visitor: V) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_i64(parse_string!(self)?)
+ }
+
+ fn deserialize_f32<V>(self, visitor: V) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_f32(parse_string!(self)?)
+ }
+
+ fn deserialize_f64<V>(self, visitor: V) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_f64(parse_string!(self)?)
+ }
+
+ fn deserialize_char<V>(self, visitor: V) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_string(visitor)
+ }
+
+ fn deserialize_str<V>(self, _visitor: V) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ no_impl!("deserialize_str")
+ }
+
+ fn deserialize_string<V>(self, visitor: V) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ use self::DecoderReadingState::*;
+ match self.reading_state {
+ WaitingForKey => {
+ let s = self.f_name.as_ref().ok_or(DecoderError::NoFieldName)?;
+ visitor.visit_string(s.clone())
+ }
+ WaitingForValue => visitor.visit_string(read_value!(self)?),
+ }
+ }
+
+ fn deserialize_bytes<V>(self, _visitor: V) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ no_impl!("deserialize_bytes")
+ }
+
+ fn deserialize_byte_buf<V>(self, _visitor: V) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ no_impl!("deserialize_byte_buf")
+ }
+
+ fn deserialize_option<V>(self, visitor: V) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ let v = {
+ let s = self.f_name.as_ref().ok_or(DecoderError::NoFieldName)?;
+ self.key.get_raw_value(s)
+ };
+ match v {
+ Ok(..) => visitor.visit_some(&mut *self),
+ Err(..) => visitor.visit_none(),
+ }
+ }
+
+ fn deserialize_unit<V>(self, _visitor: V) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ no_impl!("deserialize_unit")
+ }
+
+ fn deserialize_unit_struct<V>(self, _name: &'static str, _visitor: V) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ no_impl!("deserialize_unit_struct")
+ }
+
+ fn deserialize_newtype_struct<V>(
+ self,
+ _name: &'static str,
+ _visitor: V,
+ ) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ no_impl!("deserialize_newtype_struct")
+ }
+
+ fn deserialize_seq<V>(self, _visitor: V) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ no_impl!("deserialize_seq")
+ }
+
+ fn deserialize_tuple<V>(self, _len: usize, _visitor: V) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ no_impl!("deserialize_tuple")
+ }
+
+ fn deserialize_tuple_struct<V>(
+ self,
+ _name: &'static str,
+ _len: usize,
+ _visitor: V,
+ ) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ no_impl!("deserialize_tuple_struct")
+ }
+
+ fn deserialize_map<V>(self, visitor: V) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_map(self)
+ }
+
+ fn deserialize_struct<V>(
+ self,
+ _name: &'static str,
+ _fields: &'static [&'static str],
+ visitor: V,
+ ) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_map(self)
+ }
+
+ fn deserialize_identifier<V>(self, visitor: V) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_string(visitor)
+ }
+
+ fn deserialize_enum<V>(
+ self,
+ _name: &'static str,
+ _variants: &'static [&'static str],
+ _visitor: V,
+ ) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ no_impl!("deserialize_enum")
+ }
+
+ fn deserialize_ignored_any<V>(self, visitor: V) -> DecodeResult<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_any(visitor)
+ }
+}
+
+impl<'de, 'a> MapAccess<'de> for Decoder {
+ type Error = DecoderError;
+ fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
+ where
+ K: DeserializeSeed<'de>,
+ {
+ self.reading_state = DecoderReadingState::WaitingForKey;
+ use self::DecoderEnumerationState::*;
+ match self.enumeration_state {
+ EnumeratingKeys(index) => match self.key.enum_key(index) {
+ Some(res) => {
+ self.f_name = Some(res?);
+ self.enumeration_state = EnumeratingKeys(index + 1);
+ seed.deserialize(&mut *self).map(Some)
+ }
+ None => {
+ self.enumeration_state = EnumeratingValues(0);
+ self.next_key_seed(seed)
+ }
+ },
+ EnumeratingValues(index) => {
+ let next_value = self.key.enum_value(index);
+ match next_value {
+ Some(res) => {
+ self.f_name = Some(res?.0);
+ self.enumeration_state = EnumeratingValues(index + 1);
+ seed.deserialize(&mut *self).map(Some)
+ }
+ None => Ok(None),
+ }
+ }
+ }
+ }
+
+ fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
+ where
+ V: DeserializeSeed<'de>,
+ {
+ self.reading_state = DecoderReadingState::WaitingForValue;
+ use self::DecoderEnumerationState::*;
+ match self.enumeration_state {
+ EnumeratingKeys(..) => {
+ let f_name = self.f_name.as_ref().ok_or(DecoderError::NoFieldName)?;
+ match self.key.open_subkey_with_flags(f_name, DECODER_SAM) {
+ Ok(subkey) => {
+ let mut nested = Decoder::new(subkey);
+ seed.deserialize(&mut nested)
+ }
+ Err(err) => Err(DecoderError::IoError(err)),
+ }
+ }
+ EnumeratingValues(..) => seed.deserialize(&mut *self),
+ }
+ }
+}
diff --git a/third_party/rust/winreg/src/encoder/mod.rs b/third_party/rust/winreg/src/encoder/mod.rs
new file mode 100644
index 0000000000..f552dc05df
--- /dev/null
+++ b/third_party/rust/winreg/src/encoder/mod.rs
@@ -0,0 +1,97 @@
+// Copyright 2017, Igor Shaula
+// Licensed under the MIT License <LICENSE or
+// http://opensource.org/licenses/MIT>. This file
+// may not be copied, modified, or distributed
+// except according to those terms.
+use self::EncoderState::*;
+use super::enums::*;
+use super::transaction::Transaction;
+use super::RegKey;
+use std::error::Error;
+use std::fmt;
+use std::io;
+use winapi::shared::minwindef::DWORD;
+
+macro_rules! emit_value {
+ ($s:ident, $v:ident) => {
+ match mem::replace(&mut $s.state, Start) {
+ NextKey(ref s) => $s.keys[$s.keys.len() - 1]
+ .set_value(s, &$v)
+ .map_err(EncoderError::IoError),
+ Start => Err(EncoderError::NoFieldName),
+ }
+ };
+}
+
+macro_rules! no_impl {
+ ($e:expr) => {
+ Err(EncoderError::EncodeNotImplemented($e.to_owned()))
+ };
+}
+
+#[cfg(feature = "serialization-serde")]
+mod serialization_serde;
+
+#[derive(Debug)]
+pub enum EncoderError {
+ EncodeNotImplemented(String),
+ SerializerError(String),
+ IoError(io::Error),
+ NoFieldName,
+ KeyMustBeAString,
+}
+
+impl fmt::Display for EncoderError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{:?}", self)
+ }
+}
+
+impl Error for EncoderError {}
+
+pub type EncodeResult<T> = Result<T, EncoderError>;
+
+impl From<io::Error> for EncoderError {
+ fn from(err: io::Error) -> EncoderError {
+ EncoderError::IoError(err)
+ }
+}
+
+#[derive(Debug)]
+enum EncoderState {
+ Start,
+ NextKey(String),
+ // NextMapKey,
+}
+
+#[derive(Debug)]
+pub struct Encoder {
+ keys: Vec<RegKey>,
+ tr: Transaction,
+ state: EncoderState,
+}
+
+const ENCODER_SAM: DWORD = KEY_CREATE_SUB_KEY | KEY_SET_VALUE;
+
+impl Encoder {
+ pub fn from_key(key: &RegKey) -> EncodeResult<Encoder> {
+ let tr = Transaction::new()?;
+ key.open_subkey_transacted_with_flags("", &tr, ENCODER_SAM)
+ .map(|k| Encoder::new(k, tr))
+ .map_err(EncoderError::IoError)
+ }
+
+ fn new(key: RegKey, tr: Transaction) -> Encoder {
+ let mut keys = Vec::with_capacity(5);
+ keys.push(key);
+ Encoder {
+ keys,
+ tr,
+ state: Start,
+ }
+ }
+
+ pub fn commit(&mut self) -> EncodeResult<()> {
+ self.tr.commit().map_err(EncoderError::IoError)
+ }
+}
diff --git a/third_party/rust/winreg/src/encoder/serialization_serde.rs b/third_party/rust/winreg/src/encoder/serialization_serde.rs
new file mode 100644
index 0000000000..f764cce6ec
--- /dev/null
+++ b/third_party/rust/winreg/src/encoder/serialization_serde.rs
@@ -0,0 +1,513 @@
+// Copyright 2017, Igor Shaula
+// Licensed under the MIT License <LICENSE or
+// http://opensource.org/licenses/MIT>. This file
+// may not be copied, modified, or distributed
+// except according to those terms.
+use super::EncoderState::*;
+use super::{EncodeResult, Encoder, EncoderError, ENCODER_SAM};
+use serde::ser::*;
+use std::fmt;
+use std::mem;
+
+impl Error for EncoderError {
+ fn custom<T: fmt::Display>(msg: T) -> Self {
+ EncoderError::SerializerError(format!("{}", msg))
+ }
+}
+
+impl<'a> Serializer for &'a mut Encoder {
+ type Ok = ();
+ type Error = EncoderError;
+
+ type SerializeSeq = SeqEncoder;
+ type SerializeTuple = TupleEncoder;
+ type SerializeTupleStruct = TupleStructEncoder;
+ type SerializeTupleVariant = TupleVariantEncoder;
+ type SerializeMap = StructMapEncoder<'a>;
+ type SerializeStruct = StructMapEncoder<'a>;
+ type SerializeStructVariant = StructVariantEncoder;
+
+ fn serialize_bool(self, value: bool) -> EncodeResult<Self::Ok> {
+ self.serialize_u32(value as u32)
+ }
+
+ fn serialize_i8(self, value: i8) -> EncodeResult<Self::Ok> {
+ self.serialize_i64(value as i64)
+ }
+
+ fn serialize_i16(self, value: i16) -> EncodeResult<Self::Ok> {
+ self.serialize_i64(value as i64)
+ }
+
+ fn serialize_i32(self, value: i32) -> EncodeResult<Self::Ok> {
+ self.serialize_i64(value as i64)
+ }
+
+ fn serialize_i64(self, value: i64) -> EncodeResult<Self::Ok> {
+ let s = value.to_string();
+ emit_value!(self, s)
+ }
+
+ fn serialize_u8(self, value: u8) -> EncodeResult<Self::Ok> {
+ self.serialize_u32(value as u32)
+ }
+
+ fn serialize_u16(self, value: u16) -> EncodeResult<Self::Ok> {
+ self.serialize_u32(value as u32)
+ }
+
+ fn serialize_u32(self, value: u32) -> EncodeResult<Self::Ok> {
+ emit_value!(self, value)
+ }
+
+ fn serialize_u64(self, value: u64) -> EncodeResult<Self::Ok> {
+ emit_value!(self, value)
+ }
+
+ fn serialize_f32(self, value: f32) -> EncodeResult<Self::Ok> {
+ let s = value.to_string();
+ emit_value!(self, s)
+ }
+
+ fn serialize_f64(self, value: f64) -> EncodeResult<Self::Ok> {
+ let s = value.to_string();
+ emit_value!(self, s)
+ }
+
+ fn serialize_char(self, value: char) -> EncodeResult<Self::Ok> {
+ let mut s = String::new();
+ s.push(value);
+ emit_value!(self, s)
+ }
+
+ fn serialize_str(self, value: &str) -> EncodeResult<Self::Ok> {
+ emit_value!(self, value)
+ }
+
+ fn serialize_bytes(self, _value: &[u8]) -> EncodeResult<Self::Ok> {
+ no_impl!("serialize_bytes")
+ }
+
+ fn serialize_none(self) -> EncodeResult<Self::Ok> {
+ no_impl!("serialize_none")
+ }
+
+ fn serialize_some<T: ?Sized + Serialize>(self, _value: &T) -> EncodeResult<Self::Ok> {
+ no_impl!("serialize_some")
+ }
+
+ fn serialize_unit(self) -> EncodeResult<Self::Ok> {
+ no_impl!("serialize_unit")
+ }
+
+ fn serialize_unit_struct(self, _name: &'static str) -> EncodeResult<Self::Ok> {
+ no_impl!("serialize_unit_struct")
+ }
+
+ fn serialize_unit_variant(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ ) -> EncodeResult<Self::Ok> {
+ no_impl!("serialize_unit_variant")
+ }
+
+ fn serialize_newtype_struct<T: ?Sized + Serialize>(
+ self,
+ _name: &'static str,
+ _value: &T,
+ ) -> EncodeResult<Self::Ok> {
+ no_impl!("serialize_newtype_struct")
+ }
+
+ fn serialize_newtype_variant<T: ?Sized + Serialize>(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ _value: &T,
+ ) -> EncodeResult<Self::Ok> {
+ no_impl!("serialize_newtype_variant")
+ }
+
+ fn serialize_seq(self, _len: Option<usize>) -> EncodeResult<Self::SerializeSeq> {
+ no_impl!("serialize_seq")
+ }
+
+ fn serialize_tuple(self, _len: usize) -> EncodeResult<Self::SerializeTuple> {
+ no_impl!("serialize_tuple")
+ }
+
+ fn serialize_tuple_struct(
+ self,
+ _name: &'static str,
+ _len: usize,
+ ) -> EncodeResult<Self::SerializeTupleStruct> {
+ no_impl!("serialize_tuple_struct")
+ }
+
+ fn serialize_tuple_variant(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ _len: usize,
+ ) -> EncodeResult<Self::SerializeTupleVariant> {
+ no_impl!("serialize_tuple_variant")
+ }
+
+ fn serialize_map(self, _len: Option<usize>) -> EncodeResult<Self::SerializeMap> {
+ match mem::replace(&mut self.state, Start) {
+ // ---
+ Start => {
+ // root structure
+ Ok(StructMapEncoder {
+ enc: self,
+ is_root: true,
+ })
+ }
+ NextKey(ref s) => {
+ // nested structure
+ match self.keys[self.keys.len() - 1].create_subkey_transacted_with_flags(
+ &s,
+ &self.tr,
+ ENCODER_SAM,
+ ) {
+ Ok((subkey, _disp)) => {
+ self.keys.push(subkey);
+ Ok(StructMapEncoder {
+ enc: self,
+ is_root: true,
+ })
+ }
+ Err(err) => Err(EncoderError::IoError(err)),
+ }
+ }
+ }
+ }
+
+ fn serialize_struct(
+ self,
+ _name: &'static str,
+ _len: usize,
+ ) -> EncodeResult<Self::SerializeStruct> {
+ self.serialize_map(Some(_len))
+ }
+
+ fn serialize_struct_variant(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ _len: usize,
+ ) -> EncodeResult<Self::SerializeStructVariant> {
+ no_impl!("serialize_struct_variant")
+ }
+}
+
+pub struct SeqEncoder {}
+
+impl SerializeSeq for SeqEncoder {
+ type Ok = ();
+ type Error = EncoderError;
+ fn serialize_element<T: ?Sized + Serialize>(&mut self, _value: &T) -> EncodeResult<Self::Ok> {
+ no_impl!("SerializeSeq::serialize_element")
+ }
+ fn end(self) -> EncodeResult<Self::Ok> {
+ no_impl!("SerializeSeq::end")
+ }
+}
+
+pub struct TupleEncoder {}
+
+impl SerializeTuple for TupleEncoder {
+ type Ok = ();
+ type Error = EncoderError;
+
+ fn serialize_element<T: ?Sized + Serialize>(&mut self, _value: &T) -> EncodeResult<Self::Ok> {
+ no_impl!("SerializeTuple::serialize_element")
+ }
+
+ fn end(self) -> EncodeResult<Self::Ok> {
+ no_impl!("SerializeTuple::end")
+ }
+}
+
+pub struct TupleStructEncoder {}
+
+impl SerializeTupleStruct for TupleStructEncoder {
+ type Ok = ();
+ type Error = EncoderError;
+
+ fn serialize_field<T: ?Sized + Serialize>(&mut self, _value: &T) -> EncodeResult<Self::Ok> {
+ no_impl!("SerializeTupleStruct::serialize_field")
+ }
+
+ fn end(self) -> EncodeResult<Self::Ok> {
+ no_impl!("SerializeTupleStruct::end")
+ }
+}
+
+pub struct TupleVariantEncoder {}
+
+impl SerializeTupleVariant for TupleVariantEncoder {
+ type Ok = ();
+ type Error = EncoderError;
+
+ fn serialize_field<T: ?Sized + Serialize>(&mut self, _value: &T) -> EncodeResult<Self::Ok> {
+ no_impl!("SerializeTupleVariant::serialize_field")
+ }
+
+ fn end(self) -> EncodeResult<Self::Ok> {
+ no_impl!("SerializeTupleVariant::end")
+ }
+}
+
+struct MapKeySerializer;
+
+impl serde::Serializer for MapKeySerializer {
+ type Ok = String;
+ type Error = EncoderError;
+
+ type SerializeSeq = Impossible<String, EncoderError>;
+ type SerializeTuple = Impossible<String, EncoderError>;
+ type SerializeTupleStruct = Impossible<String, EncoderError>;
+ type SerializeTupleVariant = Impossible<String, EncoderError>;
+ type SerializeMap = Impossible<String, EncoderError>;
+ type SerializeStruct = Impossible<String, EncoderError>;
+ type SerializeStructVariant = Impossible<String, EncoderError>;
+
+ #[inline]
+ fn serialize_unit_variant(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ variant: &'static str,
+ ) -> EncodeResult<Self::Ok> {
+ Ok(variant.to_owned())
+ }
+
+ #[inline]
+ fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> EncodeResult<Self::Ok>
+ where
+ T: ?Sized + Serialize,
+ {
+ value.serialize(self)
+ }
+
+ fn serialize_bool(self, _value: bool) -> EncodeResult<Self::Ok> {
+ Err(EncoderError::KeyMustBeAString)
+ }
+
+ fn serialize_i8(self, value: i8) -> EncodeResult<Self::Ok> {
+ Ok(value.to_string())
+ }
+
+ fn serialize_i16(self, value: i16) -> EncodeResult<Self::Ok> {
+ Ok(value.to_string())
+ }
+
+ fn serialize_i32(self, value: i32) -> EncodeResult<Self::Ok> {
+ Ok(value.to_string())
+ }
+
+ fn serialize_i64(self, value: i64) -> EncodeResult<Self::Ok> {
+ Ok(value.to_string())
+ }
+
+ fn serialize_u8(self, value: u8) -> EncodeResult<Self::Ok> {
+ Ok(value.to_string())
+ }
+
+ fn serialize_u16(self, value: u16) -> EncodeResult<Self::Ok> {
+ Ok(value.to_string())
+ }
+
+ fn serialize_u32(self, value: u32) -> EncodeResult<Self::Ok> {
+ Ok(value.to_string())
+ }
+
+ fn serialize_u64(self, value: u64) -> EncodeResult<Self::Ok> {
+ Ok(value.to_string())
+ }
+
+ fn serialize_f32(self, _value: f32) -> EncodeResult<Self::Ok> {
+ Err(EncoderError::KeyMustBeAString)
+ }
+
+ fn serialize_f64(self, _value: f64) -> EncodeResult<Self::Ok> {
+ Err(EncoderError::KeyMustBeAString)
+ }
+
+ #[inline]
+ fn serialize_char(self, value: char) -> EncodeResult<Self::Ok> {
+ Ok({
+ let mut s = String::new();
+ s.push(value);
+ s
+ })
+ }
+
+ #[inline]
+ fn serialize_str(self, value: &str) -> EncodeResult<Self::Ok> {
+ Ok(value.to_owned())
+ }
+
+ fn serialize_bytes(self, _value: &[u8]) -> EncodeResult<Self::Ok> {
+ Err(EncoderError::KeyMustBeAString)
+ }
+
+ fn serialize_unit(self) -> EncodeResult<Self::Ok> {
+ Err(EncoderError::KeyMustBeAString)
+ }
+
+ fn serialize_unit_struct(self, _name: &'static str) -> EncodeResult<Self::Ok> {
+ Err(EncoderError::KeyMustBeAString)
+ }
+
+ fn serialize_newtype_variant<T>(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ _value: &T,
+ ) -> EncodeResult<Self::Ok>
+ where
+ T: ?Sized + Serialize,
+ {
+ Err(EncoderError::KeyMustBeAString)
+ }
+
+ fn serialize_none(self) -> EncodeResult<Self::Ok> {
+ Err(EncoderError::KeyMustBeAString)
+ }
+
+ fn serialize_some<T>(self, _value: &T) -> EncodeResult<Self::Ok>
+ where
+ T: ?Sized + Serialize,
+ {
+ Err(EncoderError::KeyMustBeAString)
+ }
+
+ fn serialize_seq(self, _len: Option<usize>) -> EncodeResult<Self::SerializeSeq> {
+ Err(EncoderError::KeyMustBeAString)
+ }
+
+ fn serialize_tuple(self, _len: usize) -> EncodeResult<Self::SerializeTuple> {
+ Err(EncoderError::KeyMustBeAString)
+ }
+
+ fn serialize_tuple_struct(
+ self,
+ _name: &'static str,
+ _len: usize,
+ ) -> EncodeResult<Self::SerializeTupleStruct> {
+ Err(EncoderError::KeyMustBeAString)
+ }
+
+ fn serialize_tuple_variant(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ _len: usize,
+ ) -> EncodeResult<Self::SerializeTupleVariant> {
+ Err(EncoderError::KeyMustBeAString)
+ }
+
+ fn serialize_map(self, _len: Option<usize>) -> EncodeResult<Self::SerializeMap> {
+ Err(EncoderError::KeyMustBeAString)
+ }
+
+ fn serialize_struct(
+ self,
+ _name: &'static str,
+ _len: usize,
+ ) -> EncodeResult<Self::SerializeStruct> {
+ Err(EncoderError::KeyMustBeAString)
+ }
+
+ fn serialize_struct_variant(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ _len: usize,
+ ) -> EncodeResult<Self::SerializeStructVariant> {
+ Err(EncoderError::KeyMustBeAString)
+ }
+
+ fn collect_str<T: ?Sized>(self, value: &T) -> EncodeResult<String>
+ where
+ T: fmt::Display,
+ {
+ Ok(value.to_string())
+ }
+}
+
+pub struct StructMapEncoder<'a> {
+ enc: &'a mut Encoder,
+ is_root: bool,
+}
+
+impl<'a> SerializeStruct for StructMapEncoder<'a> {
+ type Ok = ();
+ type Error = EncoderError;
+
+ fn serialize_field<T: ?Sized + Serialize>(
+ &mut self,
+ key: &'static str,
+ value: &T,
+ ) -> EncodeResult<Self::Ok> {
+ self.enc.state = NextKey(String::from(key));
+ value.serialize(&mut *self.enc)
+ }
+
+ fn end(self) -> EncodeResult<Self::Ok> {
+ if self.is_root {
+ self.enc.keys.pop();
+ }
+ Ok(())
+ }
+}
+
+impl<'a> SerializeMap for StructMapEncoder<'a> {
+ type Ok = ();
+ type Error = EncoderError;
+
+ fn serialize_key<T: ?Sized + Serialize>(&mut self, key: &T) -> EncodeResult<Self::Ok> {
+ self.enc.state = NextKey(key.serialize(MapKeySerializer)?);
+ Ok(())
+ }
+
+ fn serialize_value<T: ?Sized + Serialize>(&mut self, value: &T) -> EncodeResult<Self::Ok> {
+ value.serialize(&mut *self.enc)
+ }
+
+ fn end(self) -> EncodeResult<Self::Ok> {
+ if self.is_root {
+ self.enc.keys.pop();
+ }
+ Ok(())
+ }
+}
+
+pub struct StructVariantEncoder {}
+
+impl SerializeStructVariant for StructVariantEncoder {
+ type Ok = ();
+ type Error = EncoderError;
+
+ fn serialize_field<T: ?Sized + Serialize>(
+ &mut self,
+ _key: &'static str,
+ _value: &T,
+ ) -> EncodeResult<Self::Ok> {
+ no_impl!("SerializeStructVariant::serialize_field")
+ }
+
+ fn end(self) -> EncodeResult<Self::Ok> {
+ no_impl!("SerializeStructVariant::end")
+ }
+}
diff --git a/third_party/rust/winreg/src/enums.rs b/third_party/rust/winreg/src/enums.rs
new file mode 100644
index 0000000000..b537b287c2
--- /dev/null
+++ b/third_party/rust/winreg/src/enums.rs
@@ -0,0 +1,51 @@
+// Copyright 2015, Igor Shaula
+// Licensed under the MIT License <LICENSE or
+// http://opensource.org/licenses/MIT>. This file
+// may not be copied, modified, or distributed
+// except according to those terms.
+
+//! `use winreg::enums::*;` to import all needed enumerations and constants
+use super::winapi;
+pub use winapi::um::winnt::{
+ KEY_ALL_ACCESS, KEY_CREATE_LINK, KEY_CREATE_SUB_KEY, KEY_ENUMERATE_SUB_KEYS, KEY_EXECUTE,
+ KEY_NOTIFY, KEY_QUERY_VALUE, KEY_READ, KEY_SET_VALUE, KEY_WOW64_32KEY, KEY_WOW64_64KEY,
+ KEY_WOW64_RES, KEY_WRITE,
+};
+pub use winapi::um::winreg::{
+ HKEY_CLASSES_ROOT, HKEY_CURRENT_CONFIG, HKEY_CURRENT_USER, HKEY_CURRENT_USER_LOCAL_SETTINGS,
+ HKEY_DYN_DATA, HKEY_LOCAL_MACHINE, HKEY_PERFORMANCE_DATA, HKEY_PERFORMANCE_NLSTEXT,
+ HKEY_PERFORMANCE_TEXT, HKEY_USERS, REG_PROCESS_APPKEY,
+};
+
+macro_rules! winapi_enum{
+ ($t:ident, $doc:expr => [$($v:ident),*]) => (
+ #[doc=$doc]
+ #[allow(non_camel_case_types)]
+ #[derive(Debug,Clone,PartialEq)]
+ pub enum $t {
+ $( $v = winapi::um::winnt::$v as isize ),*
+ }
+ )
+}
+
+winapi_enum!(RegType, "Enumeration of possible registry value types" => [
+REG_NONE,
+REG_SZ,
+REG_EXPAND_SZ,
+REG_BINARY,
+REG_DWORD,
+REG_DWORD_BIG_ENDIAN,
+REG_LINK,
+REG_MULTI_SZ,
+REG_RESOURCE_LIST,
+REG_FULL_RESOURCE_DESCRIPTOR,
+REG_RESOURCE_REQUIREMENTS_LIST,
+REG_QWORD
+]);
+pub use self::RegType::*;
+
+winapi_enum!(RegDisposition, "Enumeration of possible disposition values" => [
+REG_CREATED_NEW_KEY,
+REG_OPENED_EXISTING_KEY
+]);
+pub use self::RegDisposition::*;
diff --git a/third_party/rust/winreg/src/lib.rs b/third_party/rust/winreg/src/lib.rs
new file mode 100644
index 0000000000..784976c5c8
--- /dev/null
+++ b/third_party/rust/winreg/src/lib.rs
@@ -0,0 +1,1143 @@
+// Copyright 2015, Igor Shaula
+// Licensed under the MIT License <LICENSE or
+// http://opensource.org/licenses/MIT>. This file
+// may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Crate for accessing MS Windows registry
+//!
+//!## Usage
+//!
+//!### Basic usage
+//!
+//!```toml,ignore
+//!# Cargo.toml
+//![dependencies]
+//!winreg = "0.10"
+//!```
+//!
+//!```no_run
+//!extern crate winreg;
+//!use std::io;
+//!use std::path::Path;
+//!use winreg::enums::*;
+//!use winreg::RegKey;
+//!
+//!fn main() -> io::Result<()> {
+//! println!("Reading some system info...");
+//! let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
+//! let cur_ver = hklm.open_subkey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion")?;
+//! let pf: String = cur_ver.get_value("ProgramFilesDir")?;
+//! let dp: String = cur_ver.get_value("DevicePath")?;
+//! println!("ProgramFiles = {}\nDevicePath = {}", pf, dp);
+//! let info = cur_ver.query_info()?;
+//! println!("info = {:?}", info);
+//! let mt = info.get_last_write_time_system();
+//! println!(
+//! "last_write_time as winapi::um::minwinbase::SYSTEMTIME = {}-{:02}-{:02} {:02}:{:02}:{:02}",
+//! mt.wYear, mt.wMonth, mt.wDay, mt.wHour, mt.wMinute, mt.wSecond
+//! );
+//!
+//! // enable `chrono` feature on `winreg` to make this work
+//! // println!(
+//! // "last_write_time as chrono::NaiveDateTime = {}",
+//! // info.get_last_write_time_chrono()
+//! // );
+//!
+//! println!("And now lets write something...");
+//! let hkcu = RegKey::predef(HKEY_CURRENT_USER);
+//! let path = Path::new("Software").join("WinregRsExample1");
+//! let (key, disp) = hkcu.create_subkey(&path)?;
+//!
+//! match disp {
+//! REG_CREATED_NEW_KEY => println!("A new key has been created"),
+//! REG_OPENED_EXISTING_KEY => println!("An existing key has been opened"),
+//! }
+//!
+//! key.set_value("TestSZ", &"written by Rust")?;
+//! let sz_val: String = key.get_value("TestSZ")?;
+//! key.delete_value("TestSZ")?;
+//! println!("TestSZ = {}", sz_val);
+//!
+//! key.set_value("TestMultiSZ", &vec!["written", "by", "Rust"])?;
+//! let multi_sz_val: Vec<String> = key.get_value("TestMultiSZ")?;
+//! key.delete_value("TestMultiSZ")?;
+//! println!("TestMultiSZ = {:?}", multi_sz_val);
+//!
+//! key.set_value("TestDWORD", &1234567890u32)?;
+//! let dword_val: u32 = key.get_value("TestDWORD")?;
+//! println!("TestDWORD = {}", dword_val);
+//!
+//! key.set_value("TestQWORD", &1234567891011121314u64)?;
+//! let qword_val: u64 = key.get_value("TestQWORD")?;
+//! println!("TestQWORD = {}", qword_val);
+//!
+//! key.create_subkey("sub\\key")?;
+//! hkcu.delete_subkey_all(&path)?;
+//!
+//! println!("Trying to open nonexistent key...");
+//! hkcu.open_subkey(&path).unwrap_or_else(|e| match e.kind() {
+//! io::ErrorKind::NotFound => panic!("Key doesn't exist"),
+//! io::ErrorKind::PermissionDenied => panic!("Access denied"),
+//! _ => panic!("{:?}", e),
+//! });
+//! Ok(())
+//!}
+//!```
+//!
+//!### Iterators
+//!
+//!```no_run
+//!extern crate winreg;
+//!use std::io;
+//!use winreg::RegKey;
+//!use winreg::enums::*;
+//!
+//!fn main() -> io::Result<()> {
+//! println!("File extensions, registered in system:");
+//! for i in RegKey::predef(HKEY_CLASSES_ROOT)
+//! .enum_keys().map(|x| x.unwrap())
+//! .filter(|x| x.starts_with("."))
+//! {
+//! println!("{}", i);
+//! }
+//!
+//! let system = RegKey::predef(HKEY_LOCAL_MACHINE)
+//! .open_subkey("HARDWARE\\DESCRIPTION\\System")?;
+//! for (name, value) in system.enum_values().map(|x| x.unwrap()) {
+//! println!("{} = {:?}", name, value);
+//! }
+//!
+//! Ok(())
+//!}
+//!```
+//!
+#[cfg(feature = "chrono")]
+extern crate chrono;
+#[cfg(feature = "serialization-serde")]
+extern crate serde;
+extern crate winapi;
+use enums::*;
+use std::default::Default;
+use std::ffi::OsStr;
+use std::fmt;
+use std::io;
+use std::mem::transmute;
+use std::os::windows::ffi::OsStrExt;
+use std::ptr;
+use std::slice;
+#[cfg(feature = "transactions")]
+use transaction::Transaction;
+use types::{FromRegValue, ToRegValue};
+pub use winapi::shared::minwindef::HKEY;
+use winapi::shared::minwindef::{BYTE, DWORD, FILETIME, LPBYTE};
+use winapi::shared::winerror;
+use winapi::um::minwinbase::SYSTEMTIME;
+use winapi::um::timezoneapi::FileTimeToSystemTime;
+use winapi::um::winnt::{self, WCHAR};
+use winapi::um::winreg as winapi_reg;
+
+macro_rules! werr {
+ ($e:expr) => {
+ Err(io::Error::from_raw_os_error($e as i32))
+ };
+}
+
+#[cfg(feature = "serialization-serde")]
+mod decoder;
+#[cfg(feature = "serialization-serde")]
+mod encoder;
+pub mod enums;
+#[cfg(feature = "transactions")]
+pub mod transaction;
+pub mod types;
+
+/// Metadata returned by `RegKey::query_info`
+#[derive(Debug, Default)]
+pub struct RegKeyMetadata {
+ // pub Class: winapi::LPWSTR,
+ // pub ClassLen: DWORD,
+ pub sub_keys: DWORD,
+ pub max_sub_key_len: DWORD,
+ pub max_class_len: DWORD,
+ pub values: DWORD,
+ pub max_value_name_len: DWORD,
+ pub max_value_len: DWORD,
+ // pub SecurityDescriptor: DWORD,
+ pub last_write_time: FILETIME,
+}
+
+impl RegKeyMetadata {
+ /// Returns `last_write_time` field as `winapi::um::minwinbase::SYSTEMTIME`
+ pub fn get_last_write_time_system(&self) -> SYSTEMTIME {
+ let mut st: SYSTEMTIME = unsafe { ::std::mem::zeroed() };
+ unsafe {
+ FileTimeToSystemTime(&self.last_write_time, &mut st);
+ }
+ st
+ }
+
+ /// Returns `last_write_time` field as `chrono::NaiveDateTime`.
+ /// Part of `chrono` feature.
+ #[cfg(feature = "chrono")]
+ pub fn get_last_write_time_chrono(&self) -> chrono::NaiveDateTime {
+ let st = self.get_last_write_time_system();
+
+ chrono::NaiveDate::from_ymd(st.wYear.into(), st.wMonth.into(), st.wDay.into()).and_hms(
+ st.wHour.into(),
+ st.wMinute.into(),
+ st.wSecond.into(),
+ )
+ }
+}
+
+/// Raw registry value
+#[derive(PartialEq)]
+pub struct RegValue {
+ pub bytes: Vec<u8>,
+ pub vtype: RegType,
+}
+
+macro_rules! format_reg_value {
+ ($e:expr => $t:ident) => {
+ match $t::from_reg_value($e) {
+ Ok(val) => format!("{:?}", val),
+ Err(_) => return Err(fmt::Error),
+ }
+ };
+}
+
+impl fmt::Display for RegValue {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let f_val = match self.vtype {
+ REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => format_reg_value!(self => String),
+ REG_DWORD => format_reg_value!(self => u32),
+ REG_QWORD => format_reg_value!(self => u64),
+ _ => format!("{:?}", self.bytes), //TODO: implement more types
+ };
+ write!(f, "{}", f_val)
+ }
+}
+
+impl fmt::Debug for RegValue {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "RegValue({:?}: {})", self.vtype, self)
+ }
+}
+
+/// Handle of opened registry key
+#[derive(Debug)]
+pub struct RegKey {
+ hkey: HKEY,
+}
+
+unsafe impl Send for RegKey {}
+
+impl RegKey {
+ /// Open one of predefined keys:
+ ///
+ /// * `HKEY_CLASSES_ROOT`
+ /// * `HKEY_CURRENT_USER`
+ /// * `HKEY_LOCAL_MACHINE`
+ /// * `HKEY_USERS`
+ /// * `HKEY_PERFORMANCE_DATA`
+ /// * `HKEY_PERFORMANCE_TEXT`
+ /// * `HKEY_PERFORMANCE_NLSTEXT`
+ /// * `HKEY_CURRENT_CONFIG`
+ /// * `HKEY_DYN_DATA`
+ /// * `HKEY_CURRENT_USER_LOCAL_SETTINGS`
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use winreg::RegKey;
+ /// # use winreg::enums::*;
+ /// let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
+ /// ```
+ pub const fn predef(hkey: HKEY) -> RegKey {
+ RegKey { hkey }
+ }
+
+ /// Load a registry hive from a file as an application hive.
+ /// If `lock` is set to `true`, then the hive cannot be loaded again until
+ /// it's unloaded (i.e. all keys from it go out of scope).
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use std::error::Error;
+ /// # use winreg::RegKey;
+ /// # use winreg::enums::*;
+ /// # fn main() -> Result<(), Box<dyn Error>> {
+ /// let handle = RegKey::load_app_key("C:\\myhive.dat", false)?;
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn load_app_key<N: AsRef<OsStr>>(filename: N, lock: bool) -> io::Result<RegKey> {
+ let options = if lock {
+ winapi_reg::REG_PROCESS_APPKEY
+ } else {
+ 0
+ };
+ RegKey::load_app_key_with_flags(filename, enums::KEY_ALL_ACCESS, options)
+ }
+
+ /// Load a registry hive from a file as an application hive with desired
+ /// permissions and options. If `options` is set to `REG_PROCESS_APPKEY`,
+ /// then the hive cannot be loaded again until it's unloaded (i.e. all keys
+ /// from it go out of scope).
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use std::error::Error;
+ /// # use winreg::RegKey;
+ /// # use winreg::enums::*;
+ /// # fn main() -> Result<(), Box<dyn Error>> {
+ /// let handle = RegKey::load_app_key_with_flags("C:\\myhive.dat", KEY_READ, 0)?;
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn load_app_key_with_flags<N: AsRef<OsStr>>(
+ filename: N,
+ perms: winapi_reg::REGSAM,
+ options: DWORD,
+ ) -> io::Result<RegKey> {
+ let c_filename = to_utf16(filename);
+ let mut new_hkey: HKEY = ptr::null_mut();
+ match unsafe {
+ winapi_reg::RegLoadAppKeyW(c_filename.as_ptr(), &mut new_hkey, perms, options, 0)
+ as DWORD
+ } {
+ 0 => Ok(RegKey { hkey: new_hkey }),
+ err => werr!(err),
+ }
+ }
+
+ /// Return inner winapi HKEY of a key:
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use std::error::Error;
+ /// # use winreg::RegKey;
+ /// # use winreg::enums::*;
+ /// # fn main() -> Result<(), Box<dyn Error>> {
+ /// let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
+ /// let soft = hklm.open_subkey("SOFTWARE")?;
+ /// let handle = soft.raw_handle();
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub const fn raw_handle(&self) -> HKEY {
+ self.hkey
+ }
+
+ /// Open subkey with `KEY_READ` permissions.
+ /// Will open another handle to itself if `path` is an empty string.
+ /// To open with different permissions use `open_subkey_with_flags`.
+ /// You can also use `create_subkey` to open with `KEY_ALL_ACCESS` permissions.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use std::error::Error;
+ /// # use winreg::RegKey;
+ /// # use winreg::enums::*;
+ /// # fn main() -> Result<(), Box<dyn Error>> {
+ /// let soft = RegKey::predef(HKEY_CURRENT_USER)
+ /// .open_subkey("Software")?;
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn open_subkey<P: AsRef<OsStr>>(&self, path: P) -> io::Result<RegKey> {
+ self.open_subkey_with_flags(path, enums::KEY_READ)
+ }
+
+ /// Open subkey with desired permissions.
+ /// Will open another handle to itself if `path` is an empty string.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use std::error::Error;
+ /// # use winreg::RegKey;
+ /// # use winreg::enums::*;
+ /// # fn main() -> Result<(), Box<dyn Error>> {
+ /// let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
+ /// hklm.open_subkey_with_flags("SOFTWARE\\Microsoft", KEY_READ)?;
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn open_subkey_with_flags<P: AsRef<OsStr>>(
+ &self,
+ path: P,
+ perms: winapi_reg::REGSAM,
+ ) -> io::Result<RegKey> {
+ let c_path = to_utf16(path);
+ let mut new_hkey: HKEY = ptr::null_mut();
+ match unsafe {
+ winapi_reg::RegOpenKeyExW(self.hkey, c_path.as_ptr(), 0, perms, &mut new_hkey) as DWORD
+ } {
+ 0 => Ok(RegKey { hkey: new_hkey }),
+ err => werr!(err),
+ }
+ }
+
+ /// Part of `transactions` feature.
+ #[cfg(feature = "transactions")]
+ pub fn open_subkey_transacted<P: AsRef<OsStr>>(
+ &self,
+ path: P,
+ t: &Transaction,
+ ) -> io::Result<RegKey> {
+ self.open_subkey_transacted_with_flags(path, t, winnt::KEY_READ)
+ }
+
+ /// Part of `transactions` feature.
+ #[cfg(feature = "transactions")]
+ pub fn open_subkey_transacted_with_flags<P: AsRef<OsStr>>(
+ &self,
+ path: P,
+ t: &Transaction,
+ perms: winapi_reg::REGSAM,
+ ) -> io::Result<RegKey> {
+ let c_path = to_utf16(path);
+ let mut new_hkey: HKEY = ptr::null_mut();
+ match unsafe {
+ winapi_reg::RegOpenKeyTransactedW(
+ self.hkey,
+ c_path.as_ptr(),
+ 0,
+ perms,
+ &mut new_hkey,
+ t.handle,
+ ptr::null_mut(),
+ ) as DWORD
+ } {
+ 0 => Ok(RegKey { hkey: new_hkey }),
+ err => werr!(err),
+ }
+ }
+
+ /// Create subkey (and all missing parent keys)
+ /// and open it with `KEY_ALL_ACCESS` permissions.
+ /// Will just open key if it already exists.
+ /// If succeeds returns a tuple with the created subkey and its disposition,
+ /// which can be `REG_CREATED_NEW_KEY` or `REG_OPENED_EXISTING_KEY`.
+ /// Will open another handle to itself if `path` is an empty string.
+ /// To create with different permissions use `create_subkey_with_flags`.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use std::error::Error;
+ /// # use winreg::RegKey;
+ /// use winreg::enums::*;
+ /// # fn main() -> Result<(), Box<dyn Error>> {
+ /// let hkcu = RegKey::predef(HKEY_CURRENT_USER);
+ /// let (settings, disp) = hkcu.create_subkey("Software\\MyProduct\\Settings")?;
+ ///
+ /// match disp {
+ /// REG_CREATED_NEW_KEY => println!("A new key has been created"),
+ /// REG_OPENED_EXISTING_KEY => println!("An existing key has been opened")
+ /// }
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn create_subkey<P: AsRef<OsStr>>(&self, path: P) -> io::Result<(RegKey, RegDisposition)> {
+ self.create_subkey_with_flags(path, enums::KEY_ALL_ACCESS)
+ }
+
+ pub fn create_subkey_with_flags<P: AsRef<OsStr>>(
+ &self,
+ path: P,
+ perms: winapi_reg::REGSAM,
+ ) -> io::Result<(RegKey, RegDisposition)> {
+ let c_path = to_utf16(path);
+ let mut new_hkey: HKEY = ptr::null_mut();
+ let mut disp_buf: DWORD = 0;
+ match unsafe {
+ winapi_reg::RegCreateKeyExW(
+ self.hkey,
+ c_path.as_ptr(),
+ 0,
+ ptr::null_mut(),
+ winnt::REG_OPTION_NON_VOLATILE,
+ perms,
+ ptr::null_mut(),
+ &mut new_hkey,
+ &mut disp_buf,
+ )
+ } {
+ 0 => {
+ let disp: RegDisposition = unsafe { transmute(disp_buf as u8) };
+ Ok((RegKey { hkey: new_hkey }, disp))
+ }
+ err => werr!(err),
+ }
+ }
+
+ /// Part of `transactions` feature.
+ #[cfg(feature = "transactions")]
+ pub fn create_subkey_transacted<P: AsRef<OsStr>>(
+ &self,
+ path: P,
+ t: &Transaction,
+ ) -> io::Result<(RegKey, RegDisposition)> {
+ self.create_subkey_transacted_with_flags(path, t, winnt::KEY_ALL_ACCESS)
+ }
+
+ /// Part of `transactions` feature.
+ #[cfg(feature = "transactions")]
+ pub fn create_subkey_transacted_with_flags<P: AsRef<OsStr>>(
+ &self,
+ path: P,
+ t: &Transaction,
+ perms: winapi_reg::REGSAM,
+ ) -> io::Result<(RegKey, RegDisposition)> {
+ let c_path = to_utf16(path);
+ let mut new_hkey: HKEY = ptr::null_mut();
+ let mut disp_buf: DWORD = 0;
+ match unsafe {
+ winapi_reg::RegCreateKeyTransactedW(
+ self.hkey,
+ c_path.as_ptr(),
+ 0,
+ ptr::null_mut(),
+ winnt::REG_OPTION_NON_VOLATILE,
+ perms,
+ ptr::null_mut(),
+ &mut new_hkey,
+ &mut disp_buf,
+ t.handle,
+ ptr::null_mut(),
+ ) as DWORD
+ } {
+ 0 => {
+ let disp: RegDisposition = unsafe { transmute(disp_buf as u8) };
+ Ok((RegKey { hkey: new_hkey }, disp))
+ }
+ err => werr!(err),
+ }
+ }
+
+ /// Copy all the values and subkeys from `path` to `dest` key.
+ /// WIll copy the content of `self` if `path` is an empty string.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use std::error::Error;
+ /// # use winreg::RegKey;
+ /// # use winreg::enums::*;
+ /// # fn main() -> Result<(), Box<dyn Error>> {
+ /// let hkcu = RegKey::predef(HKEY_CURRENT_USER);
+ /// let src = hkcu.open_subkey_with_flags("Software\\MyProduct", KEY_READ)?;
+ /// let (dst, dst_disp) = hkcu.create_subkey("Software\\MyProduct\\Section2")?;
+ /// src.copy_tree("Section1", &dst)?;
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn copy_tree<P: AsRef<OsStr>>(&self, path: P, dest: &RegKey) -> io::Result<()> {
+ let c_path = to_utf16(path);
+ match unsafe { winapi_reg::RegCopyTreeW(self.hkey, c_path.as_ptr(), dest.hkey) } {
+ 0 => Ok(()),
+ err => werr!(err),
+ }
+ }
+
+ pub fn query_info(&self) -> io::Result<RegKeyMetadata> {
+ let mut info: RegKeyMetadata = Default::default();
+ match unsafe {
+ winapi_reg::RegQueryInfoKeyW(
+ self.hkey,
+ ptr::null_mut(), // Class: winapi::LPWSTR,
+ ptr::null_mut(), // ClassLen: DWORD,
+ ptr::null_mut(), // Reserved
+ &mut info.sub_keys,
+ &mut info.max_sub_key_len,
+ &mut info.max_class_len,
+ &mut info.values,
+ &mut info.max_value_name_len,
+ &mut info.max_value_len,
+ ptr::null_mut(), // lpcbSecurityDescriptor: winapi::LPDWORD,
+ &mut info.last_write_time,
+ ) as DWORD
+ } {
+ 0 => Ok(info),
+ err => werr!(err),
+ }
+ }
+
+ /// Return an iterator over subkeys names.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use winreg::RegKey;
+ /// # use winreg::enums::*;
+ /// println!("File extensions, registered in this system:");
+ /// for i in RegKey::predef(HKEY_CLASSES_ROOT)
+ /// .enum_keys().map(|x| x.unwrap())
+ /// .filter(|x| x.starts_with("."))
+ /// {
+ /// println!("{}", i);
+ /// }
+ /// ```
+ pub const fn enum_keys(&self) -> EnumKeys {
+ EnumKeys {
+ key: self,
+ index: 0,
+ }
+ }
+
+ /// Return an iterator over values.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use std::error::Error;
+ /// # use winreg::RegKey;
+ /// # use winreg::enums::*;
+ /// # fn main() -> Result<(), Box<dyn Error>> {
+ /// let system = RegKey::predef(HKEY_LOCAL_MACHINE)
+ /// .open_subkey_with_flags("HARDWARE\\DESCRIPTION\\System", KEY_READ)?;
+ /// for (name, value) in system.enum_values().map(|x| x.unwrap()) {
+ /// println!("{} = {:?}", name, value);
+ /// }
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub const fn enum_values(&self) -> EnumValues {
+ EnumValues {
+ key: self,
+ index: 0,
+ }
+ }
+
+ /// Delete key. Key names are not case sensitive.
+ /// Cannot delete if it has subkeys.
+ /// Use `delete_subkey_all` for that.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use std::error::Error;
+ /// # use winreg::RegKey;
+ /// # use winreg::enums::*;
+ /// # fn main() -> Result<(), Box<dyn Error>> {
+ /// RegKey::predef(HKEY_CURRENT_USER)
+ /// .delete_subkey(r"Software\MyProduct\History")?;
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn delete_subkey<P: AsRef<OsStr>>(&self, path: P) -> io::Result<()> {
+ self.delete_subkey_with_flags(path, 0)
+ }
+
+ /// Delete key from the desired platform-specific view of the registry.
+ /// Key names are not case sensitive.
+ ///
+ /// # Examples
+ /// ```no_run
+ /// # use std::error::Error;
+ /// # use winreg::RegKey;
+ /// # use winreg::enums::*;
+ /// # fn main() -> Result<(), Box<dyn Error>> {
+ /// // delete the key from the 32-bit registry view
+ /// RegKey::predef(HKEY_LOCAL_MACHINE)
+ /// .delete_subkey_with_flags(r"Software\MyProduct\History", KEY_WOW64_32KEY)?;
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn delete_subkey_with_flags<P: AsRef<OsStr>>(
+ &self,
+ path: P,
+ perms: winapi_reg::REGSAM,
+ ) -> io::Result<()> {
+ let c_path = to_utf16(path);
+ match unsafe {
+ winapi_reg::RegDeleteKeyExW(
+ self.hkey,
+ c_path.as_ptr(), // This parameter cannot be NULL.
+ perms,
+ 0,
+ )
+ } {
+ 0 => Ok(()),
+ err => werr!(err),
+ }
+ }
+
+ /// Part of `transactions` feature.
+ #[cfg(feature = "transactions")]
+ pub fn delete_subkey_transacted<P: AsRef<OsStr>>(
+ &self,
+ path: P,
+ t: &Transaction,
+ ) -> io::Result<()> {
+ self.delete_subkey_transacted_with_flags(path, t, 0)
+ }
+
+ /// Part of `transactions` feature.
+ #[cfg(feature = "transactions")]
+ pub fn delete_subkey_transacted_with_flags<P: AsRef<OsStr>>(
+ &self,
+ path: P,
+ t: &Transaction,
+ perms: winapi_reg::REGSAM,
+ ) -> io::Result<()> {
+ let c_path = to_utf16(path);
+ match unsafe {
+ winapi_reg::RegDeleteKeyTransactedW(
+ self.hkey,
+ c_path.as_ptr(), // This parameter cannot be NULL.
+ perms,
+ 0,
+ t.handle,
+ ptr::null_mut(),
+ )
+ } {
+ 0 => Ok(()),
+ err => werr!(err),
+ }
+ }
+
+ /// Recursively delete subkey with all its subkeys and values.
+ /// If `path` is an empty string, the subkeys and values of this key are deleted.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use std::error::Error;
+ /// # use winreg::RegKey;
+ /// # use winreg::enums::*;
+ /// # fn main() -> Result<(), Box<dyn Error>> {
+ /// RegKey::predef(HKEY_CURRENT_USER)
+ /// .delete_subkey_all("Software\\MyProduct")?;
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn delete_subkey_all<P: AsRef<OsStr>>(&self, path: P) -> io::Result<()> {
+ let c_path;
+ let path_ptr = if path.as_ref().is_empty() {
+ ptr::null()
+ } else {
+ c_path = to_utf16(path);
+ c_path.as_ptr()
+ };
+ match unsafe {
+ winapi_reg::RegDeleteTreeW(
+ self.hkey,
+ path_ptr, //If this parameter is NULL, the subkeys and values of this key are deleted.
+ ) as DWORD
+ } {
+ 0 => Ok(()),
+ err => werr!(err),
+ }
+ }
+
+ /// Get a value from registry and seamlessly convert it to the specified rust type
+ /// with `FromRegValue` implemented (currently `String`, `u32` and `u64`).
+ /// Will get the `Default` value if `name` is an empty string.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use std::error::Error;
+ /// # use winreg::RegKey;
+ /// # use winreg::enums::*;
+ /// # fn main() -> Result<(), Box<dyn Error>> {
+ /// let hkcu = RegKey::predef(HKEY_CURRENT_USER);
+ /// let settings = hkcu.open_subkey("Software\\MyProduct\\Settings")?;
+ /// let server: String = settings.get_value("server")?;
+ /// let port: u32 = settings.get_value("port")?;
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn get_value<T: FromRegValue, N: AsRef<OsStr>>(&self, name: N) -> io::Result<T> {
+ match self.get_raw_value(name) {
+ Ok(ref val) => FromRegValue::from_reg_value(val),
+ Err(err) => Err(err),
+ }
+ }
+
+ /// Get raw bytes from registry value.
+ /// Will get the `Default` value if `name` is an empty string.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use std::error::Error;
+ /// # use winreg::RegKey;
+ /// # use winreg::enums::*;
+ /// # fn main() -> Result<(), Box<dyn Error>> {
+ /// let hkcu = RegKey::predef(HKEY_CURRENT_USER);
+ /// let settings = hkcu.open_subkey("Software\\MyProduct\\Settings")?;
+ /// let data = settings.get_raw_value("data")?;
+ /// println!("Bytes: {:?}", data.bytes);
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn get_raw_value<N: AsRef<OsStr>>(&self, name: N) -> io::Result<RegValue> {
+ let c_name = to_utf16(name);
+ let mut buf_len: DWORD = 2048;
+ let mut buf_type: DWORD = 0;
+ let mut buf: Vec<u8> = Vec::with_capacity(buf_len as usize);
+ loop {
+ match unsafe {
+ winapi_reg::RegQueryValueExW(
+ self.hkey,
+ c_name.as_ptr() as *const u16,
+ ptr::null_mut(),
+ &mut buf_type,
+ buf.as_mut_ptr() as LPBYTE,
+ &mut buf_len,
+ ) as DWORD
+ } {
+ 0 => {
+ unsafe {
+ buf.set_len(buf_len as usize);
+ }
+ // minimal check before transmute to RegType
+ if buf_type > winnt::REG_QWORD {
+ return werr!(winerror::ERROR_BAD_FILE_TYPE);
+ }
+ let t: RegType = unsafe { transmute(buf_type as u8) };
+ return Ok(RegValue {
+ bytes: buf,
+ vtype: t,
+ });
+ }
+ winerror::ERROR_MORE_DATA => {
+ buf.reserve(buf_len as usize);
+ }
+ err => return werr!(err),
+ }
+ }
+ }
+
+ /// Seamlessly convert a value from a rust type and write it to the registry value
+ /// with `ToRegValue` trait implemented (currently `String`, `&str`, `u32` and `u64`).
+ /// Will set the `Default` value if `name` is an empty string.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use std::error::Error;
+ /// # use winreg::RegKey;
+ /// # use winreg::enums::*;
+ /// # fn main() -> Result<(), Box<dyn Error>> {
+ /// let hkcu = RegKey::predef(HKEY_CURRENT_USER);
+ /// let (settings, disp) = hkcu.create_subkey("Software\\MyProduct\\Settings")?;
+ /// settings.set_value("server", &"www.example.com")?;
+ /// settings.set_value("port", &8080u32)?;
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn set_value<T: ToRegValue, N: AsRef<OsStr>>(&self, name: N, value: &T) -> io::Result<()> {
+ self.set_raw_value(name, &value.to_reg_value())
+ }
+
+ /// Write raw bytes from `RegValue` struct to a registry value.
+ /// Will set the `Default` value if `name` is an empty string.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use std::error::Error;
+ /// use winreg::{RegKey, RegValue};
+ /// use winreg::enums::*;
+ /// # fn main() -> Result<(), Box<dyn Error>> {
+ /// let hkcu = RegKey::predef(HKEY_CURRENT_USER);
+ /// let settings = hkcu.open_subkey("Software\\MyProduct\\Settings")?;
+ /// let bytes: Vec<u8> = vec![1, 2, 3, 5, 8, 13, 21, 34, 55, 89];
+ /// let data = RegValue{ vtype: REG_BINARY, bytes: bytes};
+ /// settings.set_raw_value("data", &data)?;
+ /// println!("Bytes: {:?}", data.bytes);
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn set_raw_value<N: AsRef<OsStr>>(&self, name: N, value: &RegValue) -> io::Result<()> {
+ let c_name = to_utf16(name);
+ let t = value.vtype.clone() as DWORD;
+ match unsafe {
+ winapi_reg::RegSetValueExW(
+ self.hkey,
+ c_name.as_ptr(),
+ 0,
+ t,
+ value.bytes.as_ptr() as *const BYTE,
+ value.bytes.len() as u32,
+ ) as DWORD
+ } {
+ 0 => Ok(()),
+ err => werr!(err),
+ }
+ }
+
+ /// Delete specified value from registry.
+ /// Will delete the `Default` value if `name` is an empty string.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use std::error::Error;
+ /// # use winreg::RegKey;
+ /// # use winreg::enums::*;
+ /// # fn main() -> Result<(), Box<dyn Error>> {
+ /// let hkcu = RegKey::predef(HKEY_CURRENT_USER);
+ /// let settings = hkcu.open_subkey("Software\\MyProduct\\Settings")?;
+ /// settings.delete_value("data")?;
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn delete_value<N: AsRef<OsStr>>(&self, name: N) -> io::Result<()> {
+ let c_name = to_utf16(name);
+ match unsafe { winapi_reg::RegDeleteValueW(self.hkey, c_name.as_ptr()) as DWORD } {
+ 0 => Ok(()),
+ err => werr!(err),
+ }
+ }
+
+ /// Save `Encodable` type to a registry key.
+ /// Part of `serialization-serde` feature.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use std::error::Error;
+ /// #[macro_use]
+ /// extern crate serde_derive;
+ /// extern crate winreg;
+ /// use winreg::RegKey;
+ /// use winreg::enums::*;
+ ///
+ /// #[derive(Serialize)]
+ /// struct Rectangle{
+ /// x: u32,
+ /// y: u32,
+ /// w: u32,
+ /// h: u32,
+ /// }
+ ///
+ /// #[derive(Serialize)]
+ /// struct Settings{
+ /// current_dir: String,
+ /// window_pos: Rectangle,
+ /// show_in_tray: bool,
+ /// }
+ ///
+ /// # fn main() -> Result<(), Box<dyn Error>> {
+ /// let s: Settings = Settings{
+ /// current_dir: "C:\\".to_owned(),
+ /// window_pos: Rectangle{ x:200, y: 100, w: 800, h: 500 },
+ /// show_in_tray: false,
+ /// };
+ /// let s_key = RegKey::predef(HKEY_CURRENT_USER)
+ /// .open_subkey("Software\\MyProduct\\Settings")?;
+ /// s_key.encode(&s)?;
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[cfg(feature = "serialization-serde")]
+ pub fn encode<T: serde::Serialize>(&self, value: &T) -> encoder::EncodeResult<()> {
+ let mut encoder = encoder::Encoder::from_key(self)?;
+ value.serialize(&mut encoder)?;
+ encoder.commit()
+ }
+
+ /// Load `Decodable` type from a registry key.
+ /// Part of `serialization-serde` feature.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use std::error::Error;
+ /// #[macro_use]
+ /// extern crate serde_derive;
+ /// extern crate winreg;
+ /// use winreg::RegKey;
+ /// use winreg::enums::*;
+ ///
+ /// #[derive(Deserialize)]
+ /// struct Rectangle{
+ /// x: u32,
+ /// y: u32,
+ /// w: u32,
+ /// h: u32,
+ /// }
+ ///
+ /// #[derive(Deserialize)]
+ /// struct Settings{
+ /// current_dir: String,
+ /// window_pos: Rectangle,
+ /// show_in_tray: bool,
+ /// }
+ ///
+ /// # fn main() -> Result<(), Box<dyn Error>> {
+ /// let s_key = RegKey::predef(HKEY_CURRENT_USER)
+ /// .open_subkey("Software\\MyProduct\\Settings")?;
+ /// let s: Settings = s_key.decode()?;
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[cfg(feature = "serialization-serde")]
+ pub fn decode<'de, T: serde::Deserialize<'de>>(&self) -> decoder::DecodeResult<T> {
+ let mut decoder = decoder::Decoder::from_key(self)?;
+ T::deserialize(&mut decoder)
+ }
+
+ fn close_(&mut self) -> io::Result<()> {
+ // don't try to close predefined keys
+ if self.hkey >= enums::HKEY_CLASSES_ROOT {
+ return Ok(());
+ };
+ match unsafe { winapi_reg::RegCloseKey(self.hkey) as DWORD } {
+ 0 => Ok(()),
+ err => werr!(err),
+ }
+ }
+
+ fn enum_key(&self, index: DWORD) -> Option<io::Result<String>> {
+ let mut name_len = 2048;
+ #[allow(clippy::unnecessary_cast)]
+ let mut name = [0 as WCHAR; 2048];
+ match unsafe {
+ winapi_reg::RegEnumKeyExW(
+ self.hkey,
+ index,
+ name.as_mut_ptr(),
+ &mut name_len,
+ ptr::null_mut(), // reserved
+ ptr::null_mut(), // lpClass: LPWSTR,
+ ptr::null_mut(), // lpcClass: LPDWORD,
+ ptr::null_mut(), // lpftLastWriteTime: PFILETIME,
+ ) as DWORD
+ } {
+ 0 => match String::from_utf16(&name[..name_len as usize]) {
+ Ok(s) => Some(Ok(s)),
+ Err(_) => Some(werr!(winerror::ERROR_INVALID_BLOCK)),
+ },
+ winerror::ERROR_NO_MORE_ITEMS => None,
+ err => Some(werr!(err)),
+ }
+ }
+
+ fn enum_value(&self, index: DWORD) -> Option<io::Result<(String, RegValue)>> {
+ let mut name_len = 2048;
+ #[allow(clippy::unnecessary_cast)]
+ let mut name = [0 as WCHAR; 2048];
+
+ let mut buf_len: DWORD = 2048;
+ let mut buf_type: DWORD = 0;
+ let mut buf: Vec<u8> = Vec::with_capacity(buf_len as usize);
+ loop {
+ match unsafe {
+ winapi_reg::RegEnumValueW(
+ self.hkey,
+ index,
+ name.as_mut_ptr(),
+ &mut name_len,
+ ptr::null_mut(), // reserved
+ &mut buf_type,
+ buf.as_mut_ptr() as LPBYTE,
+ &mut buf_len,
+ ) as DWORD
+ } {
+ 0 => {
+ let name = match String::from_utf16(&name[..name_len as usize]) {
+ Ok(s) => s,
+ Err(_) => return Some(werr!(winerror::ERROR_INVALID_DATA)),
+ };
+ unsafe {
+ buf.set_len(buf_len as usize);
+ }
+ // minimal check before transmute to RegType
+ if buf_type > winnt::REG_QWORD {
+ return Some(werr!(winerror::ERROR_BAD_FILE_TYPE));
+ }
+ let t: RegType = unsafe { transmute(buf_type as u8) };
+ let value = RegValue {
+ bytes: buf,
+ vtype: t,
+ };
+ return Some(Ok((name, value)));
+ }
+ winerror::ERROR_MORE_DATA => {
+ name_len += 1; //for NULL char
+ buf.reserve(buf_len as usize);
+ }
+ winerror::ERROR_NO_MORE_ITEMS => return None,
+ err => return Some(werr!(err)),
+ }
+ }
+ }
+}
+
+impl Drop for RegKey {
+ fn drop(&mut self) {
+ self.close_().unwrap_or(());
+ }
+}
+
+/// Iterator over subkeys names
+pub struct EnumKeys<'key> {
+ key: &'key RegKey,
+ index: DWORD,
+}
+
+impl<'key> Iterator for EnumKeys<'key> {
+ type Item = io::Result<String>;
+
+ fn next(&mut self) -> Option<io::Result<String>> {
+ match self.key.enum_key(self.index) {
+ v @ Some(_) => {
+ self.index += 1;
+ v
+ }
+ e @ None => e,
+ }
+ }
+
+ fn nth(&mut self, n: usize) -> Option<Self::Item> {
+ self.index += n as DWORD;
+ self.next()
+ }
+}
+
+/// Iterator over values
+pub struct EnumValues<'key> {
+ key: &'key RegKey,
+ index: DWORD,
+}
+
+impl<'key> Iterator for EnumValues<'key> {
+ type Item = io::Result<(String, RegValue)>;
+
+ fn next(&mut self) -> Option<io::Result<(String, RegValue)>> {
+ match self.key.enum_value(self.index) {
+ v @ Some(_) => {
+ self.index += 1;
+ v
+ }
+ e @ None => e,
+ }
+ }
+
+ fn nth(&mut self, n: usize) -> Option<Self::Item> {
+ self.index += n as DWORD;
+ self.next()
+ }
+}
+
+fn to_utf16<P: AsRef<OsStr>>(s: P) -> Vec<u16> {
+ s.as_ref()
+ .encode_wide()
+ .chain(Some(0).into_iter())
+ .collect()
+}
+
+fn v16_to_v8(v: &[u16]) -> Vec<u8> {
+ unsafe { slice::from_raw_parts(v.as_ptr() as *const u8, v.len() * 2).to_vec() }
+}
diff --git a/third_party/rust/winreg/src/transaction.rs b/third_party/rust/winreg/src/transaction.rs
new file mode 100644
index 0000000000..e63e3ea17c
--- /dev/null
+++ b/third_party/rust/winreg/src/transaction.rs
@@ -0,0 +1,105 @@
+// Copyright 2015, Igor Shaula
+// Licensed under the MIT License <LICENSE or
+// http://opensource.org/licenses/MIT>. This file
+// may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Structure for a registry transaction.
+//! Part of `transactions` feature.
+//!
+//!```no_run
+//!extern crate winreg;
+//!use std::io;
+//!use winreg::RegKey;
+//!use winreg::enums::*;
+//!use winreg::transaction::Transaction;
+//!
+//!fn main() {
+//! let t = Transaction::new().unwrap();
+//! let hkcu = RegKey::predef(HKEY_CURRENT_USER);
+//! let (key, _disp) = hkcu.create_subkey_transacted("Software\\RustTransaction", &t).unwrap();
+//! key.set_value("TestQWORD", &1234567891011121314u64).unwrap();
+//! key.set_value("TestDWORD", &1234567890u32).unwrap();
+//!
+//! println!("Commit transaction? [y/N]:");
+//! let mut input = String::new();
+//! io::stdin().read_line(&mut input).unwrap();
+//! input = input.trim_right().to_owned();
+//! if input == "y" || input == "Y" {
+//! t.commit().unwrap();
+//! println!("Transaction committed.");
+//! }
+//! else {
+//! // this is optional, if transaction wasn't committed,
+//! // it will be rolled back on disposal
+//! t.rollback().unwrap();
+//!
+//! println!("Transaction wasn't committed, it will be rolled back.");
+//! }
+//!}
+//!```
+#![cfg(feature = "transactions")]
+use std::io;
+use std::ptr;
+use winapi::um::handleapi;
+use winapi::um::ktmw32;
+use winapi::um::winnt;
+
+#[derive(Debug)]
+pub struct Transaction {
+ pub handle: winnt::HANDLE,
+}
+
+impl Transaction {
+ //TODO: add arguments
+ pub fn new() -> io::Result<Transaction> {
+ unsafe {
+ let handle = ktmw32::CreateTransaction(
+ ptr::null_mut(),
+ ptr::null_mut(),
+ 0,
+ 0,
+ 0,
+ 0,
+ ptr::null_mut(),
+ );
+ if handle == handleapi::INVALID_HANDLE_VALUE {
+ return Err(io::Error::last_os_error());
+ };
+ Ok(Transaction { handle })
+ }
+ }
+
+ pub fn commit(&self) -> io::Result<()> {
+ unsafe {
+ match ktmw32::CommitTransaction(self.handle) {
+ 0 => Err(io::Error::last_os_error()),
+ _ => Ok(()),
+ }
+ }
+ }
+
+ pub fn rollback(&self) -> io::Result<()> {
+ unsafe {
+ match ktmw32::RollbackTransaction(self.handle) {
+ 0 => Err(io::Error::last_os_error()),
+ _ => Ok(()),
+ }
+ }
+ }
+
+ fn close_(&mut self) -> io::Result<()> {
+ unsafe {
+ match handleapi::CloseHandle(self.handle) {
+ 0 => Err(io::Error::last_os_error()),
+ _ => Ok(()),
+ }
+ }
+ }
+}
+
+impl Drop for Transaction {
+ fn drop(&mut self) {
+ self.close_().unwrap_or(());
+ }
+}
diff --git a/third_party/rust/winreg/src/types.rs b/third_party/rust/winreg/src/types.rs
new file mode 100644
index 0000000000..37439354eb
--- /dev/null
+++ b/third_party/rust/winreg/src/types.rs
@@ -0,0 +1,199 @@
+// Copyright 2015, Igor Shaula
+// Licensed under the MIT License <LICENSE or
+// http://opensource.org/licenses/MIT>. This file
+// may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Traits for loading/saving Registry values
+use super::enums::*;
+use super::winapi::shared::winerror;
+use super::RegValue;
+use super::{to_utf16, v16_to_v8};
+use std::ffi::{OsStr, OsString};
+use std::io;
+use std::os::windows::ffi::OsStringExt;
+use std::slice;
+
+/// A trait for types that can be loaded from registry values.
+///
+/// **NOTE:** Uses `from_utf16_lossy` when converting to `String`.
+///
+/// **NOTE:** When converting to `String` or `OsString`, trailing `NULL` characters are trimmed
+/// and line separating `NULL` characters in `REG_MULTI_SZ` are replaced by `\n`
+/// effectively representing the value as a multiline string.
+/// When converting to `Vec<String>` or `Vec<OsString>` `NULL` is used as a strings separator.
+pub trait FromRegValue: Sized {
+ fn from_reg_value(val: &RegValue) -> io::Result<Self>;
+}
+
+impl FromRegValue for String {
+ fn from_reg_value(val: &RegValue) -> io::Result<String> {
+ match val.vtype {
+ REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => {
+ let words = unsafe {
+ #[allow(clippy::cast_ptr_alignment)]
+ slice::from_raw_parts(val.bytes.as_ptr() as *const u16, val.bytes.len() / 2)
+ };
+ let mut s = String::from_utf16_lossy(words);
+ while s.ends_with('\u{0}') {
+ s.pop();
+ }
+ if val.vtype == REG_MULTI_SZ {
+ return Ok(s.replace("\u{0}", "\n"));
+ }
+ Ok(s)
+ }
+ _ => werr!(winerror::ERROR_BAD_FILE_TYPE),
+ }
+ }
+}
+
+impl FromRegValue for Vec<String> {
+ fn from_reg_value(val: &RegValue) -> io::Result<Vec<String>> {
+ match val.vtype {
+ REG_MULTI_SZ => {
+ let words = unsafe {
+ slice::from_raw_parts(val.bytes.as_ptr() as *const u16, val.bytes.len() / 2)
+ };
+ let mut s = String::from_utf16_lossy(words);
+ while s.ends_with('\u{0}') {
+ s.pop();
+ }
+ let v: Vec<String> = s.split('\u{0}').map(|x| x.to_owned()).collect();
+ Ok(v)
+ }
+ _ => werr!(winerror::ERROR_BAD_FILE_TYPE),
+ }
+ }
+}
+
+impl FromRegValue for OsString {
+ fn from_reg_value(val: &RegValue) -> io::Result<OsString> {
+ match val.vtype {
+ REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => {
+ let mut words = unsafe {
+ #[allow(clippy::cast_ptr_alignment)]
+ slice::from_raw_parts(val.bytes.as_ptr() as *const u16, val.bytes.len() / 2)
+ };
+ while let Some(0) = words.last() {
+ words = &words[0..words.len() - 1];
+ }
+ let s = OsString::from_wide(words);
+ Ok(s)
+ }
+ _ => werr!(winerror::ERROR_BAD_FILE_TYPE),
+ }
+ }
+}
+
+impl FromRegValue for Vec<OsString> {
+ fn from_reg_value(val: &RegValue) -> io::Result<Vec<OsString>> {
+ match val.vtype {
+ REG_MULTI_SZ => {
+ let mut words = unsafe {
+ slice::from_raw_parts(val.bytes.as_ptr() as *const u16, val.bytes.len() / 2)
+ };
+ while let Some(0) = words.last() {
+ words = &words[0..words.len() - 1];
+ }
+ let v: Vec<OsString> = words
+ .split(|ch| *ch == 0u16)
+ .map(|x| OsString::from_wide(x))
+ .collect();
+ Ok(v)
+ }
+ _ => werr!(winerror::ERROR_BAD_FILE_TYPE),
+ }
+ }
+}
+
+impl FromRegValue for u32 {
+ fn from_reg_value(val: &RegValue) -> io::Result<u32> {
+ match val.vtype {
+ #[allow(clippy::cast_ptr_alignment)]
+ REG_DWORD => Ok(unsafe { *(val.bytes.as_ptr() as *const u32) }),
+ _ => werr!(winerror::ERROR_BAD_FILE_TYPE),
+ }
+ }
+}
+
+impl FromRegValue for u64 {
+ fn from_reg_value(val: &RegValue) -> io::Result<u64> {
+ match val.vtype {
+ #[allow(clippy::cast_ptr_alignment)]
+ REG_QWORD => Ok(unsafe { *(val.bytes.as_ptr() as *const u64) }),
+ _ => werr!(winerror::ERROR_BAD_FILE_TYPE),
+ }
+ }
+}
+
+/// A trait for types that can be written into registry values.
+///
+/// **NOTE:** Adds trailing `NULL` character to `str`, `String`, `OsStr` and `OsString` values
+pub trait ToRegValue {
+ fn to_reg_value(&self) -> RegValue;
+}
+
+macro_rules! to_reg_value_sz {
+ ($t:ty$(, $l:lifetime)*) => {
+ impl<$($l,)*> ToRegValue for $t {
+ fn to_reg_value(&self) -> RegValue {
+ RegValue {
+ bytes: v16_to_v8(&to_utf16(self)),
+ vtype: REG_SZ,
+ }
+ }
+ }
+ }
+}
+
+to_reg_value_sz!(String);
+to_reg_value_sz!(&'a str, 'a);
+to_reg_value_sz!(OsString);
+to_reg_value_sz!(&'a OsStr, 'a);
+
+macro_rules! to_reg_value_multi_sz {
+ ($t:ty$(, $l:lifetime)*) => {
+ impl<$($l,)*> ToRegValue for Vec<$t> {
+ fn to_reg_value(&self) -> RegValue {
+ let mut os_strings = self
+ .into_iter()
+ .map(to_utf16)
+ .collect::<Vec<_>>()
+ .concat();
+ os_strings.push(0);
+ RegValue {
+ bytes: v16_to_v8(&os_strings),
+ vtype: REG_MULTI_SZ,
+ }
+ }
+ }
+ }
+}
+
+to_reg_value_multi_sz!(String);
+to_reg_value_multi_sz!(&'a str, 'a);
+to_reg_value_multi_sz!(OsString);
+to_reg_value_multi_sz!(&'a OsStr, 'a);
+
+impl ToRegValue for u32 {
+ fn to_reg_value(&self) -> RegValue {
+ let bytes: Vec<u8> =
+ unsafe { slice::from_raw_parts((self as *const u32) as *const u8, 4).to_vec() };
+ RegValue {
+ bytes,
+ vtype: REG_DWORD,
+ }
+ }
+}
+
+impl ToRegValue for u64 {
+ fn to_reg_value(&self) -> RegValue {
+ let bytes: Vec<u8> =
+ unsafe { slice::from_raw_parts((self as *const u64) as *const u8, 8).to_vec() };
+ RegValue {
+ bytes,
+ vtype: REG_QWORD,
+ }
+ }
+}
diff --git a/third_party/rust/winreg/tests/reg_key.rs b/third_party/rust/winreg/tests/reg_key.rs
new file mode 100644
index 0000000000..0a79300424
--- /dev/null
+++ b/third_party/rust/winreg/tests/reg_key.rs
@@ -0,0 +1,364 @@
+extern crate rand;
+extern crate tempfile;
+extern crate winapi;
+extern crate winreg;
+#[cfg(feature = "serialization-serde")]
+#[macro_use]
+extern crate serde_derive;
+use self::rand::Rng;
+use std::collections::HashMap;
+use std::ffi::{OsStr, OsString};
+use tempfile::tempdir;
+use winapi::shared::winerror;
+use winreg::enums::*;
+use winreg::types::FromRegValue;
+use winreg::{RegKey, RegValue};
+
+#[test]
+fn test_raw_handle() {
+ let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
+ let handle = hklm.raw_handle();
+ assert_eq!(HKEY_LOCAL_MACHINE, handle);
+}
+
+#[test]
+fn test_load_appkey() {
+ let val_name = "LoadKeyTest";
+ let dir = tempdir().unwrap();
+ let file_path = dir.path().join("RustLoadAppkeyTest.dat");
+ let val1 = "Test123".to_owned();
+ {
+ let key1 = RegKey::load_app_key(&file_path, true).unwrap();
+ key1.set_value(val_name, &val1).unwrap();
+ // this fails on Windows 7 with ERROR_ALREADY_EXISTS
+ let key_err = RegKey::load_app_key_with_flags(&file_path, KEY_READ, 0).unwrap_err();
+ assert_eq!(
+ key_err.raw_os_error(),
+ Some(winerror::ERROR_SHARING_VIOLATION as i32)
+ );
+ }
+ let val2: String = {
+ // this fails on Windows 7 with ERROR_ALREADY_EXISTS
+ let key2 = RegKey::load_app_key_with_flags(&file_path, KEY_READ, 1).unwrap();
+ key2.get_value(val_name).unwrap()
+ };
+ assert_eq!(val1, val2);
+}
+
+#[test]
+fn test_open_subkey_with_flags_query_info() {
+ let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
+ let win = hklm
+ .open_subkey_with_flags("Software\\Microsoft\\Windows", KEY_READ)
+ .unwrap();
+
+ let info = win.query_info().unwrap();
+ info.get_last_write_time_system();
+ #[cfg(feature = "chrono")]
+ info.get_last_write_time_chrono();
+
+ assert!(win
+ .open_subkey_with_flags("CurrentVersion\\", KEY_READ)
+ .is_ok());
+ assert!(hklm
+ .open_subkey_with_flags("i\\just\\hope\\nobody\\created\\that\\key", KEY_READ)
+ .is_err());
+}
+
+#[test]
+fn test_create_subkey_disposition() {
+ let hkcu = RegKey::predef(HKEY_CURRENT_USER);
+ let path = "Software\\WinRegRsTestCreateSubkey";
+ let (_subkey, disp) = hkcu.create_subkey(path).unwrap();
+ assert_eq!(disp, REG_CREATED_NEW_KEY);
+ let (_subkey2, disp2) = hkcu.create_subkey(path).unwrap();
+ assert_eq!(disp2, REG_OPENED_EXISTING_KEY);
+ hkcu.delete_subkey_all(&path).unwrap();
+}
+
+macro_rules! with_key {
+ ($k:ident, $path:expr => $b:block) => {{
+ let mut path = "Software\\WinRegRsTest".to_owned();
+ path.push_str($path);
+ let ($k, _disp) = RegKey::predef(HKEY_CURRENT_USER)
+ .create_subkey(&path).unwrap();
+ $b
+ RegKey::predef(HKEY_CURRENT_USER)
+ .delete_subkey_all(path).unwrap();
+ }}
+}
+
+#[test]
+fn test_delete_subkey() {
+ let path = "Software\\WinRegRsTestDeleteSubkey";
+ RegKey::predef(HKEY_CURRENT_USER)
+ .create_subkey(path)
+ .unwrap();
+ assert!(RegKey::predef(HKEY_CURRENT_USER)
+ .delete_subkey(path)
+ .is_ok());
+}
+
+#[test]
+fn test_delete_subkey_with_flags() {
+ let path = "Software\\Classes\\WinRegRsTestDeleteSubkeyWithFlags";
+ RegKey::predef(HKEY_CURRENT_USER)
+ .create_subkey_with_flags(path, KEY_WOW64_32KEY)
+ .unwrap();
+ assert!(RegKey::predef(HKEY_CURRENT_USER)
+ .delete_subkey_with_flags(path, KEY_WOW64_32KEY)
+ .is_ok());
+}
+
+#[test]
+fn test_copy_tree() {
+ with_key!(key, "CopyTree" => {
+ let (sub_tree, _sub_tree_disp) = key.create_subkey("Src\\Sub\\Tree").unwrap();
+ for v in &["one", "two", "three"] {
+ sub_tree.set_value(v, v).unwrap();
+ }
+ let (dst, _dst_disp) = key.create_subkey("Dst").unwrap();
+ assert!(key.copy_tree("Src", &dst).is_ok());
+ });
+}
+
+#[test]
+fn test_long_value() {
+ with_key!(key, "LongValue" => {
+ let name = "RustLongVal";
+ let val1 = RegValue { vtype: REG_BINARY, bytes: (0..6000).map(|_| rand::random::<u8>()).collect() };
+ key.set_raw_value(name, &val1).unwrap();
+ let val2 = key.get_raw_value(name).unwrap();
+ assert_eq!(val1, val2);
+ });
+}
+
+macro_rules! test_value_sz {
+ ($fname:ident, $kname:expr, $conv:expr => $tout:ty) => {
+ #[test]
+ fn $fname() {
+ with_key!(key, $kname => {
+ let name = "RustSzVal";
+ let val1 = $conv("Test123 \n$%^&|+-*/\\()");
+ key.set_value(name, &val1).unwrap();
+ let val2: $tout = key.get_value(name).unwrap();
+ assert_eq!(val1, val2);
+ });
+ }
+ }
+}
+
+test_value_sz!(test_string_value, "StringValue", str::to_owned => String);
+test_value_sz!(test_str_value, "StrValue", |x|x => String);
+test_value_sz!(test_os_string_value, "OsStringValue", OsString::from => OsString);
+test_value_sz!(test_os_str_value, "OsStrValue", OsStr::new => OsString);
+
+#[test]
+fn test_long_string_value() {
+ with_key!(key, "LongStringValue" => {
+ let name = "RustLongStringVal";
+ let val1 : String = rand::thread_rng().gen_ascii_chars().take(7000).collect();
+ key.set_value(name, &val1).unwrap();
+ let val2: String = key.get_value(name).unwrap();
+ assert_eq!(val1, val2);
+ });
+}
+
+#[test]
+fn test_long_os_string_value() {
+ with_key!(key, "LongOsStringValue" => {
+ let name = "RustLongOsStringVal";
+ let val1 = rand::thread_rng().gen_ascii_chars().take(7000).collect::<String>();
+ let val1 = OsStr::new(&val1);
+ key.set_value(name, &val1).unwrap();
+ let val2: OsString = key.get_value(name).unwrap();
+ assert_eq!(val1, val2);
+ });
+}
+
+macro_rules! test_value_multi_sz {
+ ($fname:ident, $kname:expr, $conv:expr => $tout:ty) => {
+ #[test]
+ fn $fname() {
+ with_key!(key, $kname => {
+ let name = "RustMultiSzVal";
+
+ let val1 = vec![
+ $conv("lorem ipsum\ndolor"),
+ $conv("sit amet")
+ ];
+ key.set_value(name, &val1).unwrap();
+ let val2: Vec<$tout> = key.get_value(name).unwrap();
+
+ assert_eq!(val1, val2);
+ });
+ }
+ }
+}
+
+test_value_multi_sz!(test_vec_string_value, "StringVectorValue", str::to_owned => String);
+test_value_multi_sz!(test_vec_str_value, "StrVectorValue", |x|x => String);
+test_value_multi_sz!(test_vec_os_string_value, "OsStringVectorValue", OsString::from => OsString);
+test_value_multi_sz!(test_vec_os_str_value, "OsStrVectorValue", OsStr::new => OsString);
+
+#[test]
+fn test_u32_value() {
+ with_key!(key, "U32Value" => {
+ let name = "RustU32Val";
+ let val1 = 1_234_567_890u32;
+ key.set_value(name, &val1).unwrap();
+ let val2: u32 = key.get_value(name).unwrap();
+ assert_eq!(val1, val2);
+ });
+}
+
+#[test]
+fn test_u64_value() {
+ with_key!(key, "U64Value" => {
+ let name = "RustU64Val";
+ let val1 = 1_234_567_891_011_121_314u64;
+ key.set_value(name, &val1).unwrap();
+ let val2: u64 = key.get_value(name).unwrap();
+ assert_eq!(val1, val2);
+ });
+}
+
+#[test]
+fn test_delete_value() {
+ with_key!(key, "DeleteValue" => {
+ let name = "WinregRsTestVal";
+ key.set_value(name, &"Qwerty123").unwrap();
+ assert!(key.delete_value(name).is_ok());
+ });
+}
+
+#[test]
+fn test_enum_keys() {
+ with_key!(key, "EnumKeys" => {
+ let mut keys1 = vec!("qwerty", "asdf", "1", "2", "3", "5", "8", "йцукен");
+ keys1.sort_unstable();
+ for i in &keys1 {
+ key.create_subkey(i).unwrap();
+ }
+ let keys2: Vec<_> = key.enum_keys().map(|x| x.unwrap()).collect();
+ assert_eq!(keys1, keys2);
+ });
+}
+
+#[test]
+fn test_enum_values() {
+ with_key!(key, "EnumValues" => {
+ let mut vals1 = vec!("qwerty", "asdf", "1", "2", "3", "5", "8", "йцукен");
+ vals1.sort_unstable();
+ for i in &vals1 {
+ key.set_value(i,i).unwrap();
+ }
+ let mut vals2: Vec<String> = Vec::with_capacity(vals1.len());
+ let mut vals3: Vec<String> = Vec::with_capacity(vals1.len());
+ for (name, val) in key.enum_values()
+ .map(|x| x.unwrap())
+ {
+ vals2.push(name);
+ vals3.push(String::from_reg_value(&val).unwrap());
+ }
+ assert_eq!(vals1, vals2);
+ assert_eq!(vals1, vals3);
+ });
+}
+
+#[test]
+fn test_enum_long_values() {
+ with_key!(key, "EnumLongValues" => {
+ let mut vals = HashMap::with_capacity(3);
+
+ for i in &[5500, 9500, 15000] {
+ let name: String = format!("val{}", i);
+ let val = RegValue { vtype: REG_BINARY, bytes: (0..*i).map(|_| rand::random::<u8>()).collect() };
+ vals.insert(name, val);
+ }
+
+ for (name, val) in key.enum_values()
+ .map(|x| x.unwrap())
+ {
+ assert_eq!(val.bytes, vals[&name].bytes);
+ }
+ });
+}
+
+#[cfg(feature = "serialization-serde")]
+#[test]
+fn test_serialization() {
+ #[derive(Debug, PartialEq, Serialize, Deserialize)]
+ struct Rectangle {
+ x: u32,
+ y: u32,
+ w: u32,
+ h: u32,
+ }
+
+ #[derive(Debug, PartialEq, Serialize, Deserialize)]
+ struct Test {
+ t_bool: bool,
+ t_u8: u8,
+ t_u16: u16,
+ t_u32: u32,
+ t_u64: u64,
+ t_usize: usize,
+ t_struct: Rectangle,
+ t_string: String,
+ t_map: HashMap<String, HashMap<String, u32>>,
+ t_i8: i8,
+ t_i16: i16,
+ t_i32: i32,
+ t_i64: i64,
+ t_isize: isize,
+ t_f64: f64,
+ t_f32: f32,
+ t_char: char,
+ }
+
+ let mut k1 = HashMap::new();
+ k1.insert("val1".to_owned(), 32);
+ k1.insert("val2".to_owned(), 64);
+ k1.insert("val3".to_owned(), 128);
+
+ let mut k2 = HashMap::new();
+ k2.insert("val1".to_owned(), 256);
+ k2.insert("val2".to_owned(), 512);
+ k2.insert("val3".to_owned(), 1024);
+
+ let mut map = HashMap::new();
+ map.insert("key1".to_owned(), k1);
+ map.insert("key2".to_owned(), k2);
+
+ let v1 = Test {
+ t_bool: false,
+ t_u8: 127,
+ t_u16: 32768,
+ t_u32: 123_456_789,
+ t_u64: 123_456_789_101_112,
+ t_usize: 1_234_567_891,
+ t_struct: Rectangle {
+ x: 55,
+ y: 77,
+ w: 500,
+ h: 300,
+ },
+ t_map: map,
+ t_string: "Test123 \n$%^&|+-*/\\()".to_owned(),
+ t_i8: -123,
+ t_i16: -2049,
+ t_i32: 20100,
+ t_i64: -12_345_678_910,
+ t_isize: -1_234_567_890,
+ t_f64: -0.01,
+ t_f32: 3.15,
+ t_char: 'a',
+ };
+
+ with_key!(key, "Serialization" => {
+ key.encode(&v1).unwrap();
+ let v2: Test = key.decode().unwrap();
+ assert_eq!(v1, v2);
+ });
+}