Bug 1807981 - Audit winreg 0.10.1 as safe-to-run, and upgrade to it r=supply-chain-reviewers,webdriver-reviewers,whimboo

Upgrade winreg (currently used only by mozrunner) to 0.10.1.

As winreg 0.5.1 is currently listed as an exemption in `supply-chain`,
audit the new version as a blank slate, rather than performing an audit
of the diffs; this is both simpler and allows removing the exemption.

(There are some uses of `unsafe` that would be concerning in deployment
(more for reasons of stability than security), but the crate does
qualify as `safe-to-run`.)

winreg 0.5.1 is currently only used by mozrunner, which requires no
source changes for this upgrade.

Differential Revision: https://phabricator.services.mozilla.com/D165723
This commit is contained in:
Ray Kraesig
2023-01-03 06:25:38 +00:00
parent 05df12fcf8
commit db3d84fbf0
26 changed files with 2221 additions and 914 deletions

4
Cargo.lock generated
View File

@@ -6411,9 +6411,9 @@ dependencies = [
[[package]]
name = "winreg"
version = "0.5.1"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a27a759395c1195c4cc5cda607ef6f8f6498f64e78f7900f5de0a127a424704a"
checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
dependencies = [
"winapi",
]

View File

@@ -2458,6 +2458,18 @@ also contains a small C file compiled at build-time. I audited all of it and it
looks correct.
"""
[[audits.winreg]]
who = "Ray Kraesig <rkraesig@mozilla.com>"
criteria = "safe-to-run"
version = "0.10.1"
notes = """
This crate uses a lot of `unsafe`; not all of it is necessary, and not all of it
is correct. (In particular, the alignment of data buffers does not seem to be
correctly ensured at type-conversion time.) However, the code is not deceptive,
and any more subtle issues do not appear to be exploitable -- certainly not from
a test environment.
"""
[[audits.wpf-gpu-raster]]
who = "Lee Salzman <lsalzman@mozilla.com>"
criteria = "safe-to-deploy"

View File

@@ -1381,10 +1381,6 @@ criteria = "safe-to-deploy"
version = "0.4.0"
criteria = "safe-to-deploy"
[[exemptions.winreg]]
version = "0.5.1"
criteria = "safe-to-run"
[[exemptions.wio]]
version = "0.2.2"
criteria = "safe-to-deploy"

View File

@@ -18,7 +18,7 @@ mozprofile = { path = "../mozprofile", version = "0.9" }
plist = "1.0"
[target.'cfg(target_os = "windows")'.dependencies]
winreg = "0.5"
winreg = "0.10.1"
[target.'cfg(target_os = "macos")'.dependencies]
dirs = "4"

View File

@@ -1 +1 @@
{"files":{"Cargo.toml":"a1e8f0c4b5eab990649c6963190f190a033bca7035b85f88ea0836bfb10c9348","LICENSE":"ea021d8c6383c84d19c15ce90d3b1602cf448fdcc0bf3772c98e43c7bf1bf1d1","README.md":"137d72ca6c03e6876abb162733b305718591e28ab42f00689cb1bec7dbc38409","appveyor.yml":"986d99d18ffd511d6d4a357109d2b3ded4eea7449f49c339c6ca221064bb3bb0","examples/basic_usage.rs":"de70cb705ab3ccbf3681df106656b6398f9df27d0e7d21f7ef9a1ea51335b0cf","examples/enum.rs":"7e18a35960c824f88a122a4ae67020b44579379c0268fa7f37641b03aacb55cc","examples/installed_apps.rs":"0e210f33218649182276824f6cb461c2085ca9f8ca7c687318405b7896fd4d42","examples/serialization.rs":"b82553788bef12a9164c2a42d9ae99fceaef1e752286219ee8b24374cb5a8b19","examples/transactions.rs":"6fb7d7c7811aadab840b5ba36dfef9e8c19c0f874e02f54f90b73b16f455be70","src/decoder/mod.rs":"68064e7d0312be72152f008593377ac56bdad45fa5a007446a4358fbae17cfd0","src/decoder/serialization_serde.rs":"4fc46761f5139661bdc5fa2c490000701c5df71d1b4803ae41823acad0d0ded6","src/encoder/mod.rs":"2614013d7be54f5f39a21b8e75511e950d703e4571f9a63292ae51507a21c612","src/encoder/serialization_serde.rs":"a03fceb693761257a8bc4f72984e2a551f5a1d86e57fee6acdcc39934b8a9ee4","src/enums.rs":"8117cd8281018e092bb756836a1cc5d2bd826a87f20d9ead67a09c94296649f5","src/lib.rs":"ab3d8696a09a027a784b6baf7a3bbf852a6f029eb3914015c800f2761992f65c","src/transaction.rs":"e6c9d5ae895b3d397ce0436c7dd9562ad60405c8fedd6730e3801d69a9e84e74","src/types.rs":"c16db1ab91b1250ca1c510f20977d5046987764395c0f545a950c5a049428183"},"package":"a27a759395c1195c4cc5cda607ef6f8f6498f64e78f7900f5de0a127a424704a"}
{"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"}

350
third_party/rust/winreg/Cargo.lock generated vendored Normal file
View File

@@ -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",
]

View File

@@ -3,7 +3,7 @@
# 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
# 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
@@ -12,22 +12,29 @@
[package]
name = "winreg"
version = "0.5.1"
version = "0.10.1"
authors = ["Igor Shaula <gentoo90@gmail.com>"]
description = "Rust bindings to MS Windows Registry API"
documentation = "https://gentoo90.github.io/winreg-rs/v0.5.1/winreg"
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"]
@@ -36,11 +43,15 @@ required-features = ["transactions"]
name = "serialization"
required-features = ["serialization-serde"]
[[example]]
name = "map_key_serialization"
required-features = ["serialization-serde"]
[[example]]
name = "installed_apps"
required-features = ["serialization-serde"]
[dependencies.clippy]
version = "^0"
[dependencies.chrono]
version = "0.4.6"
optional = true
[dependencies.serde]
@@ -48,14 +59,17 @@ version = "1"
optional = true
[dependencies.winapi]
version = "0.3"
features = ["minwindef", "winerror", "winnt", "winreg", "handleapi"]
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"]

View File

@@ -1,20 +1,33 @@
winreg [![Crates.io](https://img.shields.io/crates/v/winreg.svg)](https://crates.io/crates/winreg) [![Build status](https://ci.appveyor.com/api/projects/status/f3lwrt67ghrf5omd?svg=true)](https://ci.appveyor.com/project/gentoo90/winreg-rs)
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` and `OsStr` => `REG_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 and structures for now)
* Transacted serialization of rust types into/from registry (only primitives, structures and maps for now)
## Usage
@@ -23,54 +36,75 @@ Current features:
```toml
# Cargo.toml
[dependencies]
winreg = "0.5"
winreg = "0.10"
```
```rust
extern crate winreg;
use std::path::Path;
use std::io;
use winreg::RegKey;
use std::path::Path;
use winreg::enums::*;
use winreg::RegKey;
fn main() {
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").unwrap();
let pf: String = cur_ver.get_value("ProgramFilesDir").unwrap();
let dp: String = cur_ver.get_value("DevicePath").unwrap();
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().unwrap();
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 = hkcu.create_subkey(&path).unwrap();
let (key, disp) = hkcu.create_subkey(&path)?;
key.set_value("TestSZ", &"written by Rust").unwrap();
let sz_val: String = key.get_value("TestSZ").unwrap();
key.delete_value("TestSZ").unwrap();
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("TestDWORD", &1234567890u32).unwrap();
let dword_val: u32 = key.get_value("TestDWORD").unwrap();
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).unwrap();
let qword_val: u64 = key.get_value("TestQWORD").unwrap();
key.set_value("TestQWORD", &1234567891011121314u64)?;
let qword_val: u64 = key.get_value("TestQWORD")?;
println!("TestQWORD = {}", qword_val);
key.create_subkey("sub\\key").unwrap();
hkcu.delete_subkey_all(&path).unwrap();
key.create_subkey("sub\\key")?;
hkcu.delete_subkey_all(&path)?;
println!("Trying to open nonexistent key...");
let key2 = hkcu.open_subkey(&path)
.unwrap_or_else(|e| match e.kind() {
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)
_ => panic!("{:?}", e),
});
Ok(())
}
```
@@ -78,10 +112,11 @@ fn main() {
```rust
extern crate winreg;
use std::io;
use winreg::RegKey;
use winreg::enums::*;
fn main() {
fn main() -> io::Result<()> {
println!("File extensions, registered in system:");
for i in RegKey::predef(HKEY_CLASSES_ROOT)
.enum_keys().map(|x| x.unwrap())
@@ -91,11 +126,12 @@ fn main() {
}
let system = RegKey::predef(HKEY_LOCAL_MACHINE)
.open_subkey("HARDWARE\\DESCRIPTION\\System")
.unwrap();
.open_subkey("HARDWARE\\DESCRIPTION\\System")?;
for (name, value) in system.enum_values().map(|x| x.unwrap()) {
println!("{} = {:?}", name, value);
}
Ok(())
}
```
@@ -104,7 +140,7 @@ fn main() {
```toml
# Cargo.toml
[dependencies]
winreg = { version = "0.5", features = ["transactions"] }
winreg = { version = "0.10", features = ["transactions"] }
```
```rust
@@ -114,28 +150,30 @@ use winreg::RegKey;
use winreg::enums::*;
use winreg::transaction::Transaction;
fn main() {
let t = Transaction::new().unwrap();
fn main() -> io::Result<()> {
let t = Transaction::new()?;
let hkcu = RegKey::predef(HKEY_CURRENT_USER);
let key = hkcu.create_subkey_transacted("Software\\RustTransaction", &t).unwrap();
key.set_value("TestQWORD", &1234567891011121314u64).unwrap();
key.set_value("TestDWORD", &1234567890u32).unwrap();
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).unwrap();
io::stdin().read_line(&mut input)?;
input = input.trim_right().to_owned();
if input == "y" || input == "Y" {
t.commit().unwrap();
t.commit()?;
println!("Transaction committed.");
}
else {
// this is optional, if transaction wasn't committed,
// it will be rolled back on disposal
t.rollback().unwrap();
t.rollback()?;
println!("Transaction wasn't committed, it will be rolled back.");
}
Ok(())
}
```
@@ -144,7 +182,7 @@ fn main() {
```toml
# Cargo.toml
[dependencies]
winreg = { version = "0.5", features = ["serialization-serde"] }
winreg = { version = "0.10", features = ["serialization-serde"] }
serde = "1"
serde_derive = "1"
```
@@ -152,18 +190,29 @@ serde_derive = "1"
```rust
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate winreg;
use std::collections::HashMap;
use std::error::Error;
use winreg::enums::*;
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct Rectangle{
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,
@@ -173,7 +222,10 @@ struct Test {
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,
@@ -183,44 +235,102 @@ struct Test {
t_f32: f32,
}
fn main() {
fn main() -> Result<(), Box<dyn Error>> {
let hkcu = winreg::RegKey::predef(HKEY_CURRENT_USER);
let key = hkcu.create_subkey("Software\\RustEncode").unwrap();
let v1 = Test{
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: 123456789,
t_u64: 123456789101112,
t_usize: 123456789101112,
t_struct: Rectangle{
x: 55,
y: 77,
w: 500,
h: 300,
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: -12345678910,
t_isize: -1234567890,
t_i64: -12_345_678_910,
t_isize: -1_234_567_890,
t_f64: -0.01,
t_f32: 3.14,
t_f32: 3.15,
};
key.encode(&v1).unwrap();
key.encode(&v1)?;
let v2: Test = key.decode().unwrap();
let v2: Test = key.decode()?;
println!("Decoded {:?}", v2);
// This shows `false` because f32 and f64 encoding/decoding is NOT precise
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)).
@@ -232,7 +342,7 @@ fn main() {
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`.
* `winreg` updated to `0.3`.
* `winapi` updated to `0.3`.
* Documentation fixes ([#14](https://github.com/gentoo90/winreg-rs/pull/14))
### 0.4.0

View File

@@ -1,11 +1,17 @@
version: 0.5.{build}
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
@@ -17,7 +23,7 @@ environment:
install:
- curl -sSf -o rustup-init.exe https://win.rustup.rs
- rustup-init.exe --default-host %TARGET% --default-toolchain %CHANNEL% -y
- 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
@@ -25,4 +31,7 @@ install:
build: false
test_script:
- cargo test --features=serialization-serde
- 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

11
third_party/rust/winreg/build.rs vendored Normal file
View File

@@ -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);
}
}

View File

@@ -4,47 +4,66 @@
// may not be copied, modified, or distributed
// except according to those terms.
extern crate winreg;
use std::path::Path;
use std::io;
use winreg::RegKey;
use std::path::Path;
use winreg::enums::*;
use winreg::RegKey;
fn main() {
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").unwrap();
let pf: String = cur_ver.get_value("ProgramFilesDir").unwrap();
let dp: String = cur_ver.get_value("DevicePath").unwrap();
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().unwrap();
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 = hkcu.create_subkey(&path).unwrap();
let (key, disp) = hkcu.create_subkey(&path)?;
key.set_value("TestSZ", &"written by Rust").unwrap();
let sz_val: String = key.get_value("TestSZ").unwrap();
key.delete_value("TestSZ").unwrap();
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("TestDWORD", &1234567890u32).unwrap();
let dword_val: u32 = key.get_value("TestDWORD").unwrap();
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", &1234567891011121314u64).unwrap();
let qword_val: u64 = key.get_value("TestQWORD").unwrap();
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").unwrap();
hkcu.delete_subkey_all(&path).unwrap();
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() {
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)
_ => panic!("{:?}", e),
});
Ok(())
}

View File

@@ -4,22 +4,24 @@
// may not be copied, modified, or distributed
// except according to those terms.
extern crate winreg;
use winreg::RegKey;
use std::io;
use winreg::enums::*;
use winreg::RegKey;
fn main() {
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("."))
.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")
.unwrap();
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(())
}

View File

@@ -6,38 +6,45 @@
#[macro_use]
extern crate serde_derive;
extern crate winreg;
use winreg::enums::*;
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>
UninstallString: Option<String>,
}
macro_rules! str_from_opt {
($s:expr) => { $s.as_ref().map(|x| &**x).unwrap_or("") }
($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, "{}-{}",
write!(
f,
"{}-{}",
str_from_opt!(self.DisplayName),
str_from_opt!(self.DisplayVersion))
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")
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");
let apps: HashMap<String, InstalledApp> =
uninstall_key.decode().expect("deserialization failed");
for (_k, v) in &apps {
for v in apps.values() {
println!("{}", v);
}
}

View File

@@ -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(())
}

View File

@@ -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(())
}

View File

@@ -6,6 +6,8 @@
#[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)]
@@ -35,7 +37,10 @@ struct Test {
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,
@@ -43,39 +48,46 @@ struct Test {
t_isize: isize,
t_f64: f64,
t_f32: f32,
// t_char: char,
}
fn main() {
fn main() -> Result<(), Box<dyn Error>> {
let hkcu = winreg::RegKey::predef(HKEY_CURRENT_USER);
let key = hkcu.create_subkey("Software\\RustEncode").unwrap();
let v1 = Test{
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: 123456789,
t_u64: 123456789101112,
t_usize: 1234567891,
t_struct: Rectangle{
coords: Coords{ x: 55, y: 77 },
size: Size{ w: 500, h: 300 },
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: -12345678910,
t_isize: -1234567890,
t_i64: -12_345_678_910,
t_isize: -1_234_567_890,
t_f64: -0.01,
t_f32: 3.14,
// t_char: 'a',
t_f32: 3.15,
};
key.encode(&v1).unwrap();
key.encode(&v1)?;
let v2: Test = key.decode().unwrap();
let v2: Test = key.decode()?;
println!("Decoded {:?}", v2);
// This shows `false` because f32 and f64 encoding/decoding is NOT precise
println!("Equal to encoded: {:?}", v1 == v2);
Ok(())
}

View File

@@ -5,30 +5,31 @@
// except according to those terms.
extern crate winreg;
use std::io;
use winreg::RegKey;
use winreg::enums::*;
use winreg::transaction::Transaction;
use winreg::RegKey;
fn main() {
let t = Transaction::new().unwrap();
fn main() -> io::Result<()> {
let t = Transaction::new()?;
let hkcu = RegKey::predef(HKEY_CURRENT_USER);
let key = hkcu.create_subkey_transacted("Software\\RustTransaction", &t).unwrap();
key.set_value("TestQWORD", &1234567891011121314u64).unwrap();
key.set_value("TestDWORD", &1234567890u32).unwrap();
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).unwrap();
input = input.trim_right().to_owned();
io::stdin().read_line(&mut input)?;
input = input.trim_end().to_owned();
if input == "y" || input == "Y" {
t.commit().unwrap();
println!("Transaction commited.");
}
else {
// this is optional, if transaction wasn't commited,
t.commit()?;
println!("Transaction committed.");
} else {
// this is optional, if transaction wasn't committed,
// it will be rolled back on disposal
t.rollback().unwrap();
t.rollback()?;
println!("Transaction wasn't commited, it will be rolled back.");
println!("Transaction wasn't committed, it will be rolled back.");
}
Ok(())
}

View File

@@ -3,42 +3,41 @@
// http://opensource.org/licenses/MIT>. This file
// may not be copied, modified, or distributed
// except according to those terms.
use std::io;
use std::fmt;
use std::error::Error;
use winapi::shared::minwindef::DWORD;
use super::{RegKey};
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) => (
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)
Some(ref s) => $s.key.get_value(s).map_err(DecoderError::IoError),
None => Err(DecoderError::NoFieldName),
}
)
};
}
macro_rules! parse_string{
($s:ident) => ({
macro_rules! parse_string {
($s:ident) => {{
let s: String = read_value!($s)?;
s.parse().map_err(|e| DecoderError::ParseError(format!("{:?}", e)))
})
s.parse()
.map_err(|e| DecoderError::ParseError(format!("{:?}", e)))
}};
}
macro_rules! no_impl {
($e:expr) => (
($e:expr) => {
Err(DecoderError::DecodeNotImplemented($e.to_owned()))
)
};
}
#[cfg(feature = "serialization-serde")] mod serialization_serde;
#[cfg(feature = "serialization-serde")]
mod serialization_serde;
#[derive(Debug)]
pub enum DecoderError{
pub enum DecoderError {
DecodeNotImplemented(String),
DeserializerError(String),
IoError(io::Error),
@@ -52,16 +51,7 @@ impl fmt::Display for DecoderError {
}
}
impl Error for DecoderError {
fn description(&self) -> &str {
use self::DecoderError::*;
match *self {
DecodeNotImplemented(ref s) | DeserializerError(ref s) | ParseError(ref s) => s,
IoError(ref e) => e.description(),
NoFieldName => "No field name"
}
}
}
impl Error for DecoderError {}
impl From<io::Error> for DecoderError {
fn from(err: io::Error) -> DecoderError {
@@ -101,11 +91,11 @@ impl Decoder {
}
fn new(key: RegKey) -> Decoder {
Decoder{
key: key,
Decoder {
key,
f_name: None,
reading_state: DecoderReadingState::WaitingForKey,
enumeration_state: DecoderEnumerationState::EnumeratingKeys(0)
enumeration_state: DecoderEnumerationState::EnumeratingKeys(0),
}
}
}

View File

@@ -3,11 +3,13 @@
// http://opensource.org/licenses/MIT>. This file
// may not be copied, modified, or distributed
// except according to those terms.
use std::mem;
use std::fmt;
use serde::de::*;
use super::{DecoderError, DecodeResult, DecoderReadingState, DecoderEnumerationState, Decoder, DECODER_SAM};
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 {
@@ -17,7 +19,10 @@ impl Error for DecoderError {
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> {
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"),
@@ -26,138 +31,245 @@ impl<'de, 'a> Deserializer<'de> for &'a mut Decoder {
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_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()))
_ => Err(DecoderError::DecodeNotImplemented(
"value type deserialization not implemented".to_owned(),
)),
}
}
}
}
fn deserialize_bool<V>(self, visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> {
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> {
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> {
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> {
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> {
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> {
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> {
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> {
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> {
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> {
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> {
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> {
no_impl!("deserialize_char")
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> {
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> {
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)?)
WaitingForValue => visitor.visit_string(read_value!(self)?),
}
}
fn deserialize_bytes<V>(self, _visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> {
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> {
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> {
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()
Err(..) => visitor.visit_none(),
}
}
fn deserialize_unit<V>(self, _visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> {
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> {
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> {
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> {
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> {
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> {
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> {
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> {
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> {
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> {
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> {
fn deserialize_ignored_any<V>(self, visitor: V) -> DecodeResult<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_any(visitor)
}
}
@@ -165,24 +277,23 @@ impl<'de, 'a> Deserializer<'de> for &'a mut Decoder {
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>
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)
}
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 {
@@ -198,7 +309,8 @@ impl<'de, 'a> MapAccess<'de> for Decoder {
}
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
where V: DeserializeSeed<'de>
where
V: DeserializeSeed<'de>,
{
self.reading_state = DecoderReadingState::WaitingForValue;
use self::DecoderEnumerationState::*;
@@ -212,10 +324,8 @@ impl<'de, 'a> MapAccess<'de> for Decoder {
}
Err(err) => Err(DecoderError::IoError(err)),
}
},
EnumeratingValues(..) => {
seed.deserialize(&mut *self)
}
EnumeratingValues(..) => seed.deserialize(&mut *self),
}
}
}

View File

@@ -3,41 +3,42 @@
// http://opensource.org/licenses/MIT>. This file
// may not be copied, modified, or distributed
// except according to those terms.
use std::io;
use std::fmt;
use std::error::Error;
use winapi::shared::minwindef::DWORD;
use super::RegKey;
use self::EncoderState::*;
use super::enums::*;
use super::transaction::Transaction;
use self::EncoderState::*;
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) => (
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)
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) => (
($e:expr) => {
Err(EncoderError::EncodeNotImplemented($e.to_owned()))
)
};
}
#[cfg(feature = "serialization-serde")] mod serialization_serde;
#[cfg(feature = "serialization-serde")]
mod serialization_serde;
#[derive(Debug)]
pub enum EncoderError{
pub enum EncoderError {
EncodeNotImplemented(String),
SerializerError(String),
IoError(io::Error),
NoFieldName,
KeyMustBeAString,
}
impl fmt::Display for EncoderError {
@@ -46,16 +47,7 @@ impl fmt::Display for EncoderError {
}
}
impl Error for EncoderError {
fn description(&self) -> &str {
use self::EncoderError::*;
match *self {
EncodeNotImplemented(ref s) | SerializerError(ref s) => s,
IoError(ref e) => e.description(),
NoFieldName => "No field name"
}
}
}
impl Error for EncoderError {}
pub type EncodeResult<T> = Result<T, EncoderError>;
@@ -79,11 +71,11 @@ pub struct Encoder {
state: EncoderState,
}
const ENCODER_SAM: DWORD = KEY_CREATE_SUB_KEY|KEY_SET_VALUE;
const ENCODER_SAM: DWORD = KEY_CREATE_SUB_KEY | KEY_SET_VALUE;
impl Encoder {
pub fn from_key(key: &RegKey) -> EncodeResult<Encoder> {
let tr = try!(Transaction::new());
let tr = Transaction::new()?;
key.open_subkey_transacted_with_flags("", &tr, ENCODER_SAM)
.map(|k| Encoder::new(k, tr))
.map_err(EncoderError::IoError)
@@ -92,9 +84,9 @@ impl Encoder {
fn new(key: RegKey, tr: Transaction) -> Encoder {
let mut keys = Vec::with_capacity(5);
keys.push(key);
Encoder{
keys: keys,
tr: tr,
Encoder {
keys,
tr,
state: Start,
}
}

View File

@@ -3,11 +3,11 @@
// 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;
use super::{Encoder, EncoderError, EncodeResult, ENCODER_SAM};
use super::EncoderState::*;
use serde::ser::*;
impl Error for EncoderError {
fn custom<T: fmt::Display>(msg: T) -> Self {
@@ -15,7 +15,6 @@ impl Error for EncoderError {
}
}
impl<'a> Serializer for &'a mut Encoder {
type Ok = ();
type Error = EncoderError;
@@ -24,8 +23,8 @@ impl<'a> Serializer for &'a mut Encoder {
type SerializeTuple = TupleEncoder;
type SerializeTupleStruct = TupleStructEncoder;
type SerializeTupleVariant = TupleVariantEncoder;
type SerializeMap = MapEncoder<'a>;
type SerializeStruct = StructEncoder<'a>;
type SerializeMap = StructMapEncoder<'a>;
type SerializeStruct = StructMapEncoder<'a>;
type SerializeStructVariant = StructVariantEncoder;
fn serialize_bool(self, value: bool) -> EncodeResult<Self::Ok> {
@@ -75,8 +74,10 @@ impl<'a> Serializer for &'a mut Encoder {
emit_value!(self, s)
}
fn serialize_char(self, _value: char) -> EncodeResult<Self::Ok> {
no_impl!("serialize_char")
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> {
@@ -103,27 +104,30 @@ impl<'a> Serializer for &'a mut Encoder {
no_impl!("serialize_unit_struct")
}
fn serialize_unit_variant(self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str)
-> EncodeResult<Self::Ok> {
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> {
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> {
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")
}
@@ -135,42 +139,47 @@ impl<'a> Serializer for &'a mut Encoder {
no_impl!("serialize_tuple")
}
fn serialize_tuple_struct(self,
_name: &'static str,
_len: usize)
-> EncodeResult<Self::SerializeTupleStruct> {
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> {
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> {
Ok(MapEncoder { _enc: self })
}
fn serialize_struct(self,
_name: &'static str,
_len: usize)
-> EncodeResult<Self::SerializeStruct> {
match mem::replace(&mut self.state, Start) {
// ---
Start => {
// root structure
Ok(StructEncoder { enc: self, is_root: true })
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) => {
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(StructEncoder { enc: self, is_root: true })
Ok(StructMapEncoder {
enc: self,
is_root: true,
})
}
Err(err) => Err(EncoderError::IoError(err)),
}
@@ -178,12 +187,21 @@ impl<'a> Serializer for &'a mut Encoder {
}
}
fn serialize_struct_variant(self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
_len: usize)
-> EncodeResult<Self::SerializeStructVariant> {
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")
}
}
@@ -246,41 +264,224 @@ impl SerializeTupleVariant for TupleVariantEncoder {
}
}
pub struct MapEncoder<'a> {
_enc: &'a mut Encoder,
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())
}
}
impl<'a> SerializeMap for MapEncoder<'a> {
pub struct StructMapEncoder<'a> {
enc: &'a mut Encoder,
is_root: bool,
}
impl<'a> SerializeStruct for StructMapEncoder<'a> {
type Ok = ();
type Error = EncoderError;
fn serialize_key<T: ?Sized + Serialize>(&mut self, _key: &T) -> EncodeResult<Self::Ok> {
no_impl!("SerializeMap::serialize_key")
}
fn serialize_value<T: ?Sized + Serialize>(&mut self, _value: &T) -> EncodeResult<Self::Ok> {
no_impl!("SerializeMap::serialize_value")
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> {
no_impl!("SerializeMap::end")
if self.is_root {
self.enc.keys.pop();
}
Ok(())
}
}
pub struct StructEncoder<'a> {
enc: &'a mut Encoder,
is_root: bool
}
impl<'a> SerializeStruct for StructEncoder<'a> {
impl<'a> SerializeMap 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));
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)
}
@@ -298,10 +499,11 @@ 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> {
fn serialize_field<T: ?Sized + Serialize>(
&mut self,
_key: &'static str,
_value: &T,
) -> EncodeResult<Self::Ok> {
no_impl!("SerializeStructVariant::serialize_field")
}
@@ -309,4 +511,3 @@ impl SerializeStructVariant for StructVariantEncoder {
no_impl!("SerializeStructVariant::end")
}
}

View File

@@ -6,29 +6,16 @@
//! `use winreg::enums::*;` to import all needed enumerations and constants
use super::winapi;
pub use winapi::um::winreg::{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};
pub use winapi::um::winnt::{KEY_QUERY_VALUE,
KEY_SET_VALUE,
KEY_CREATE_SUB_KEY,
KEY_ENUMERATE_SUB_KEYS,
KEY_NOTIFY,
KEY_CREATE_LINK,
KEY_WOW64_32KEY,
KEY_WOW64_64KEY,
KEY_WOW64_RES,
KEY_READ,
KEY_WRITE,
KEY_EXECUTE,
KEY_ALL_ACCESS};
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),*]) => (
@@ -56,3 +43,9 @@ 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::*;

File diff suppressed because it is too large Load Diff

View File

@@ -17,7 +17,7 @@
//!fn main() {
//! let t = Transaction::new().unwrap();
//! let hkcu = RegKey::predef(HKEY_CURRENT_USER);
//! let key = hkcu.create_subkey_transacted("Software\\RustTransaction", &t).unwrap();
//! let (key, _disp) = hkcu.create_subkey_transacted("Software\\RustTransaction", &t).unwrap();
//! key.set_value("TestQWORD", &1234567891011121314u64).unwrap();
//! key.set_value("TestDWORD", &1234567890u32).unwrap();
//!
@@ -39,11 +39,11 @@
//!}
//!```
#![cfg(feature = "transactions")]
use std::ptr;
use std::io;
use winapi::um::winnt;
use std::ptr;
use winapi::um::handleapi;
use winapi::um::ktmw32;
use winapi::um::winnt;
#[derive(Debug)]
pub struct Transaction {
@@ -64,9 +64,9 @@ impl Transaction {
ptr::null_mut(),
);
if handle == handleapi::INVALID_HANDLE_VALUE {
return Err(io::Error::last_os_error())
return Err(io::Error::last_os_error());
};
Ok(Transaction{ handle: handle })
Ok(Transaction { handle })
}
}
@@ -74,7 +74,7 @@ impl Transaction {
unsafe {
match ktmw32::CommitTransaction(self.handle) {
0 => Err(io::Error::last_os_error()),
_ => Ok(())
_ => Ok(()),
}
}
}
@@ -83,7 +83,7 @@ impl Transaction {
unsafe {
match ktmw32::RollbackTransaction(self.handle) {
0 => Err(io::Error::last_os_error()),
_ => Ok(())
_ => Ok(()),
}
}
}
@@ -92,7 +92,7 @@ impl Transaction {
unsafe {
match handleapi::CloseHandle(self.handle) {
0 => Err(io::Error::last_os_error()),
_ => Ok(())
_ => Ok(()),
}
}
}

View File

@@ -5,23 +5,24 @@
// except according to those terms.
//! Traits for loading/saving Registry values
use std::slice;
use std::io;
use std::ffi::{OsStr,OsString};
use std::os::windows::ffi::{OsStrExt,OsStringExt};
use super::winapi::shared::winerror;
use super::{RegValue};
use super::enums::*;
use super::{to_utf16,v16_to_v8};
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`, trailing `NULL` characters are trimmed
/// and line separating `NULL` characters in `REG_MULTI_SZ` are replaced by `\n`.
/// When converting to `OsString`, all `NULL` characters are left as is.
pub trait FromRegValue : Sized {
/// **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>;
}
@@ -30,16 +31,38 @@ impl FromRegValue for 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();}
while s.ends_with('\u{0}') {
s.pop();
}
if val.vtype == REG_MULTI_SZ {
return Ok(s.replace("\u{0}", "\n"))
return Ok(s.replace("\u{0}", "\n"));
}
Ok(s)
},
_ => werr!(winerror::ERROR_BAD_FILE_TYPE)
}
_ => 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),
}
}
}
@@ -48,13 +71,38 @@ 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 words = unsafe {
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)
}
_ => 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),
}
}
}
@@ -62,10 +110,9 @@ impl FromRegValue for OsString {
impl FromRegValue for u32 {
fn from_reg_value(val: &RegValue) -> io::Result<u32> {
match val.vtype {
REG_DWORD => {
Ok(unsafe{ *(val.bytes.as_ptr() as *const u32) })
},
_ => werr!(winerror::ERROR_BAD_FILE_TYPE)
#[allow(clippy::cast_ptr_alignment)]
REG_DWORD => Ok(unsafe { *(val.bytes.as_ptr() as *const u32) }),
_ => werr!(winerror::ERROR_BAD_FILE_TYPE),
}
}
}
@@ -73,69 +120,80 @@ impl FromRegValue for u32 {
impl FromRegValue for u64 {
fn from_reg_value(val: &RegValue) -> io::Result<u64> {
match val.vtype {
REG_QWORD => {
Ok(unsafe{ *(val.bytes.as_ptr() as *const u64) })
},
_ => werr!(winerror::ERROR_BAD_FILE_TYPE)
#[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` and `String` values
/// but **not** to `OsStr` values.
/// **NOTE:** Adds trailing `NULL` character to `str`, `String`, `OsStr` and `OsString` values
pub trait ToRegValue {
fn to_reg_value(&self) -> RegValue;
}
impl ToRegValue for String {
fn to_reg_value(&self) -> RegValue {
RegValue{
bytes: v16_to_v8(&to_utf16(self)),
vtype: REG_SZ
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,
}
}
}
}
}
impl<'a> ToRegValue for &'a str {
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,
}
}
}
}
}
impl<'a> ToRegValue for &'a OsStr {
fn to_reg_value(&self) -> RegValue {
RegValue{
bytes: v16_to_v8(&(self.encode_wide().collect::<Vec<_>>())),
vtype: REG_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: bytes,
vtype: REG_DWORD
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: bytes,
vtype: REG_QWORD
let bytes: Vec<u8> =
unsafe { slice::from_raw_parts((self as *const u64) as *const u8, 8).to_vec() };
RegValue {
bytes,
vtype: REG_QWORD,
}
}
}

364
third_party/rust/winreg/tests/reg_key.rs vendored Normal file
View File

@@ -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);
});
}