Bug 1716518 - Upgrade log to v0.4.14. r=emilio

Differential Revision: https://phabricator.services.mozilla.com/D117811
This commit is contained in:
Mike Hommey 2021-06-15 22:04:49 +00:00
parent 91338fb7f7
commit 99831e111a
23 changed files with 4736 additions and 4226 deletions

6
Cargo.lock generated
View File

@ -2828,11 +2828,11 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.8"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if 0.1.10",
"cfg-if 1.0.0",
]
[[package]]

View File

@ -1 +1 @@
{"files":{"CHANGELOG.md":"4a384a648f3c5f9deed5463bbcdb92cf95dfe86d755767c0c21140d0539c1243","Cargo.toml":"cde739d8e087cc2515bc06d8ce327648606575e6dd51b74fb0ffd6a329381ba1","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"0a6436eede658249802b63f1e693b28c9f80a2da2697bb80a2677e6c253c3a7d","build.rs":"16a49ad8a5b11a610382f904c72435ce3201b0807c584128c7e61fbb59c76b09","src/kv/error.rs":"296f6af53062a4526bb75eb4dbf955c75aed3b6332c260dc5bd7f0bc68c2d8c7","src/kv/key.rs":"68077f9ad149b28ccdeacd9e95c44c292b68d7fa0823aac5e022e2f3df6120e6","src/kv/mod.rs":"3397573933689b11ca5ad526193166c1e4f665e5692c38cd8fdb63a5aa61f7bf","src/kv/source.rs":"3783ac96b54e24fe6525f9e3cec91425800267f842704d947fea27ee344025a2","src/kv/value/impls.rs":"c8d4cb4e746e7b5a6e1f1993145c2b5309ac556f7ffc757fb80bb10b89bfa40d","src/kv/value/internal.rs":"b7e7d94d018d0207dfb30350a2ce916dc124c48c2e056e7637c159132c707a59","src/kv/value/mod.rs":"a4732af6fb9b3fad8ddf9dd5f9da90689eb9023984ff1f455f871ed32fde4aef","src/kv/value/test.rs":"99e0b87dd8822e7f148a3acfd1dd050718e2aee3ecd9314849076bf043a0a3e9","src/lib.rs":"c594c4a71bff2118e120c9c64e1e2e866dc76489af007965b6c67e57bf1a1797","src/macros.rs":"68cbe1a49a3ac846d6b80d291f427a70dbad0f57dac8beecac7449723293bd99","src/serde.rs":"4677851fba9d43adcddeb94c416af9e06eb70d4fb86e2840256e1edfc4638fef","tests/filters.rs":"90cae6653ba6dc3a462bab2a0b96cb66d5d21882492118bfd6999c0baff1b0e5"},"package":"14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"}
{"files":{"CHANGELOG.md":"5fa3f03a8dfa3934f5b1cfba9a41781700ed6e67afe0f10717cc16b6855ceb16","Cargo.toml":"2863cdd3382ede73ecc608ad22a4d8ee476abed3b0016f9724deba59e9317338","LICENSE-APACHE":"7cfd738c53d61c79f07e348f622bf7707c9084237054d37fbe07788a75f5881c","LICENSE-MIT":"705aaaaecefa087c187bd2eacdb01b8ac1c5ee95b1d5d04d8d7efe0363207df8","README.md":"ca758a44f4a226f21b3bc997d27a5356b5e77ee13a1daad24ee8bbbebb301c5d","benches/value.rs":"55bd5f795a524f0699b2858eb14cc456abebeb43d50c90d2bfc77cd7856e8050","build.rs":"2bfb7564209da7c4d10433d9639d33541a89d63fc52cbe47d479a967cf746769","src/kv/error.rs":"ba46a4bcac717e6dc58fc5101833c825d7b95777c1dd907be46c8fa573a27d2d","src/kv/key.rs":"e74b489cde28960f76d4038b02867b4cb724c206d31abd461abeaa04e73cf7ef","src/kv/mod.rs":"9d916f43fd9c2829991fcff6db32f23bb7864e1113a622d49e59f110e2f290cf","src/kv/source.rs":"3f7aadc5f30c0c821fd20d899d8529eba8088eeda0c8603814de689da25dd4e8","src/kv/value.rs":"4d46ced0adbe385701c1d80d03c0f2abde2e43acf16521a9d26f058462f43799","src/lib.rs":"320a18401e7f9edc812a52b5be029fb9ef8c6d7435ab7b52650878477d21103b","src/macros.rs":"b0174b17f5e06b6a7bafb7873c79c7f8e2c70a531686adf03c027739ee040a44","src/serde.rs":"d8190561ed64398fe45142b261000255ea1bcda8707e6f1b07ef4b805da6829b","triagebot.toml":"2d1d46d069bc4e3739069676707ca2801e0e0ba58a784a264392362ff9ac4a77"},"package":"51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"}

View File

@ -1,145 +1,215 @@
# Change Log
## [Unreleased]
## [0.4.8] - 2019-07-28
### New
* Support attempting to get `Record` fields as static strings.
## [0.4.7] - 2019-07-06
### New
* Support for embedded environments with thread-unsafe initialization.
* Initial unstable support for capturing structured data under the `kv_unstable`
feature gate. This new API doesn't affect existing users and may change in future
patches (so those changes may not appear in the changelog until it stabilizes).
### Improved
* Docs for using `log` with the 2018 edition.
* Error messages for macros missing arguments.
## [0.4.6] - 2018-10-27
### Improved
* Support 2018-style macro import for the `log_enabled!` macro.
## [0.4.5] - 2018-09-03
### Improved
* Make `log`'s internal helper macros less likely to conflict with user-defined
macros.
## [0.4.4] - 2018-08-17
### Improved
* Support 2018-style imports of the log macros.
## [0.4.3] - 2018-06-29
### Improved
* More code generation improvements.
## [0.4.2] - 2018-06-05
### Improved
* Log invocations now generate less code.
### Fixed
* Example Logger implementations now properly set the max log level.
## [0.4.1] - 2017-12-30
### Fixed
* Some doc links were fixed.
## [0.4.0] - 2017-12-24
The changes in this release include cleanup of some obscure functionality and a more robust public
API designed to support bridges to other logging systems, and provide more flexibility to new
features in the future.
### Compatibility
Vast portions of the Rust ecosystem use the 0.3.x release series of log, and we don't want to force
the community to go through the pain of upgrading every crate to 0.4.x at the exact same time. Along
with 0.4.0, we've published a new 0.3.9 release which acts as a "shim" over 0.4.0. This will allow
crates using either version to coexist without losing messages from one side or the other.
There is one caveat - a log message generated by a crate using 0.4.x but consumed by a logging
implementation using 0.3.x will not have a file name or module path. Applications affected by this
can upgrade their logging implementations to one using 0.4.x to avoid losing this information. The
other direction does not lose any information, fortunately!
**TL;DR** Libraries should feel comfortable upgrading to 0.4.0 without treating that as a breaking
change. Applications may need to update their logging implementation (e.g. env-logger) to a newer
version using log 0.4.x to avoid losing module and file information.
### New
* The crate is now `no_std` by default.
* `Level` and `LevelFilter` now implement `Serialize` and `Deserialize` when the `serde` feature is
enabled.
* The `Record` and `Metadata` types can now be constructed by third-party code via a builder API.
* The `logger` free function returns a reference to the logger implementation. This, along with the
ability to construct `Record`s, makes it possible to bridge from another logging framework to
this one without digging into the private internals of the crate. The standard `error!` `warn!`,
etc, macros now exclusively use the public API of the crate rather than "secret" internal APIs.
* `Log::flush` has been added to allow crates to tell the logging implementation to ensure that all
"in flight" log events have been persisted. This can be used, for example, just before an
application exits to ensure that asynchronous log sinks finish their work.
### Removed
* The `shutdown` and `shutdown_raw` functions have been removed. Supporting shutdown significantly
complicated the implementation and imposed a performance cost on each logging operation.
* The `log_panics` function and its associated `nightly` Cargo feature have been removed. Use the
[log-panics](https://crates.io/crates/log-panics) instead.
### Changed
* The `Log` prefix has been removed from type names. For example, `LogLevelFilter` is now
`LevelFilter`, and `LogRecord` is now `Record`.
* The `MaxLogLevelFilter` object has been removed in favor of a `set_max_level` free function.
* The `set_logger` free functions have been restructured. The logger is now directly passed to the
functions rather than a closure which returns the logger. `set_logger` now takes a `&'static
Log` and is usable in `no_std` contexts in place of the old `set_logger_raw`. `set_boxed_logger`
is a convenience function which takes a `Box<Log>` but otherwise acts like `set_logger`. It
requires the `std` feature.
* The `file` and `module_path` values in `Record` no longer have the `'static` lifetime to support
integration with other logging frameworks that don't provide a `'static` lifetime for the
equivalent values.
* The `file`, `line`, and `module_path` values in `Record` are now `Option`s to support integration
with other logging frameworks that don't provide those values.
### In the Future
* We're looking to add support for *structured* logging - the inclusion of extra key-value pairs of
information in a log event in addition to the normal string message. This should be able to be
added in a backwards compatible manner to the 0.4.x series when the design is worked out.
## Older
Look at the [release tags] for information about older releases.
[Unreleased]: https://github.com/rust-lang-nursery/log/compare/0.4.8...HEAD
[0.4.8]: https://github.com/rust-lang-nursery/log/compare/0.4.7...0.4.8
[0.4.7]: https://github.com/rust-lang-nursery/log/compare/0.4.6...0.4.7
[0.4.6]: https://github.com/rust-lang-nursery/log/compare/0.4.5...0.4.6
[0.4.5]: https://github.com/rust-lang-nursery/log/compare/0.4.4...0.4.5
[0.4.4]: https://github.com/rust-lang-nursery/log/compare/0.4.3...0.4.4
[0.4.3]: https://github.com/rust-lang-nursery/log/compare/0.4.2...0.4.3
[0.4.2]: https://github.com/rust-lang-nursery/log/compare/0.4.1...0.4.2
[0.4.1]: https://github.com/rust-lang-nursery/log/compare/0.4.0...0.4.1
[0.4.0]: https://github.com/rust-lang-nursery/log/compare/0.3.8...0.4.0
[release tags]: https://github.com/rust-lang-nursery/log/releases
# Change Log
## [Unreleased]
## [0.4.14] - 2021-01-27
* Remove the `__private_api_log_lit` special case.
* Fixed incorrect combination of `kv_unstable` and `std` features causing compile failures.
* Remove unstable `Value::to_*` conversions that were incorrectly using `as`.
* Rename unstable `Value::to_error` to `Value::to_borrowed_error`.
## [0.4.13] - 2021-01-11
* This is the same as `0.4.11`, except with a `kv_unstable_std` feature added to aid migrating current dependents to `0.4.14` (which was originally going to be `0.4.13` until it was decided to create a patch from `0.4.11` to minimize disruption).
## [0.4.12] - 2020-12-24
### New
* Support platforms without atomics by racing instead of failing to compile
* Implement `Log` for `Box<T: Log>`
* Update `cfg-if` to `1.0`
* Internal reworks of the structured logging API. Removed the `Fill` API
and added `source::as_map` and `source::as_list` to easily serialize a `Source`
as either a map of `{key: value, ..}` or as a list of `[(key, value), ..]`.
### Fixed
* Fixed deserialization of `LevelFilter` to use their `u64` index variants
## [0.4.11] - 2020-07-09
### New
* Support coercing structured values into concrete types.
* Reference the `win_dbg_logger` in the readme.
### Fixed
* Updates a few deprecated items used internally.
* Fixed issues in docs and expands sections.
* Show the correct build badge in the readme.
* Fix up a possible inference breakage with structured value errors.
* Respect formatting flags in structured value formatting.
## [0.4.10] - 2019-12-16 (yanked)
### Fixed
* Fixed the `log!` macros so they work in expression context (this regressed in `0.4.9`, which has been yanked).
## [0.4.9] - 2019-12-12 (yanked)
### Minimum Supported Rust Version
This release bumps the minimum compiler version to `1.31.0`. This was mainly needed for `cfg-if`,
but between `1.16.0` and `1.31.0` there are a lot of language and library improvements we now
take advantage of.
### New
* Unstable support for capturing key-value pairs in a record using the `log!` macros
### Improved
* Better documentation for max level filters.
* Internal updates to line up with bumped MSRV
## [0.4.8] - 2019-07-28
### New
* Support attempting to get `Record` fields as static strings.
## [0.4.7] - 2019-07-06
### New
* Support for embedded environments with thread-unsafe initialization.
* Initial unstable support for capturing structured data under the `kv_unstable`
feature gate. This new API doesn't affect existing users and may change in future
patches (so those changes may not appear in the changelog until it stabilizes).
### Improved
* Docs for using `log` with the 2018 edition.
* Error messages for macros missing arguments.
## [0.4.6] - 2018-10-27
### Improved
* Support 2018-style macro import for the `log_enabled!` macro.
## [0.4.5] - 2018-09-03
### Improved
* Make `log`'s internal helper macros less likely to conflict with user-defined
macros.
## [0.4.4] - 2018-08-17
### Improved
* Support 2018-style imports of the log macros.
## [0.4.3] - 2018-06-29
### Improved
* More code generation improvements.
## [0.4.2] - 2018-06-05
### Improved
* Log invocations now generate less code.
### Fixed
* Example Logger implementations now properly set the max log level.
## [0.4.1] - 2017-12-30
### Fixed
* Some doc links were fixed.
## [0.4.0] - 2017-12-24
The changes in this release include cleanup of some obscure functionality and a more robust public
API designed to support bridges to other logging systems, and provide more flexibility to new
features in the future.
### Compatibility
Vast portions of the Rust ecosystem use the 0.3.x release series of log, and we don't want to force
the community to go through the pain of upgrading every crate to 0.4.x at the exact same time. Along
with 0.4.0, we've published a new 0.3.9 release which acts as a "shim" over 0.4.0. This will allow
crates using either version to coexist without losing messages from one side or the other.
There is one caveat - a log message generated by a crate using 0.4.x but consumed by a logging
implementation using 0.3.x will not have a file name or module path. Applications affected by this
can upgrade their logging implementations to one using 0.4.x to avoid losing this information. The
other direction does not lose any information, fortunately!
**TL;DR** Libraries should feel comfortable upgrading to 0.4.0 without treating that as a breaking
change. Applications may need to update their logging implementation (e.g. env-logger) to a newer
version using log 0.4.x to avoid losing module and file information.
### New
* The crate is now `no_std` by default.
* `Level` and `LevelFilter` now implement `Serialize` and `Deserialize` when the `serde` feature is
enabled.
* The `Record` and `Metadata` types can now be constructed by third-party code via a builder API.
* The `logger` free function returns a reference to the logger implementation. This, along with the
ability to construct `Record`s, makes it possible to bridge from another logging framework to
this one without digging into the private internals of the crate. The standard `error!` `warn!`,
etc, macros now exclusively use the public API of the crate rather than "secret" internal APIs.
* `Log::flush` has been added to allow crates to tell the logging implementation to ensure that all
"in flight" log events have been persisted. This can be used, for example, just before an
application exits to ensure that asynchronous log sinks finish their work.
### Removed
* The `shutdown` and `shutdown_raw` functions have been removed. Supporting shutdown significantly
complicated the implementation and imposed a performance cost on each logging operation.
* The `log_panics` function and its associated `nightly` Cargo feature have been removed. Use the
[log-panics](https://crates.io/crates/log-panics) instead.
### Changed
* The `Log` prefix has been removed from type names. For example, `LogLevelFilter` is now
`LevelFilter`, and `LogRecord` is now `Record`.
* The `MaxLogLevelFilter` object has been removed in favor of a `set_max_level` free function.
* The `set_logger` free functions have been restructured. The logger is now directly passed to the
functions rather than a closure which returns the logger. `set_logger` now takes a `&'static
Log` and is usable in `no_std` contexts in place of the old `set_logger_raw`. `set_boxed_logger`
is a convenience function which takes a `Box<Log>` but otherwise acts like `set_logger`. It
requires the `std` feature.
* The `file` and `module_path` values in `Record` no longer have the `'static` lifetime to support
integration with other logging frameworks that don't provide a `'static` lifetime for the
equivalent values.
* The `file`, `line`, and `module_path` values in `Record` are now `Option`s to support integration
with other logging frameworks that don't provide those values.
### In the Future
* We're looking to add support for *structured* logging - the inclusion of extra key-value pairs of
information in a log event in addition to the normal string message. This should be able to be
added in a backwards compatible manner to the 0.4.x series when the design is worked out.
## Older
Look at the [release tags] for information about older releases.
[Unreleased]: https://github.com/rust-lang-nursery/log/compare/0.4.14...HEAD
[0.4.14]: https://github.com/rust-lang-nursery/log/compare/0.4.13...0.4.14
[0.4.13]: https://github.com/rust-lang-nursery/log/compare/0.4.11...0.4.13
[0.4.12]: https://github.com/rust-lang-nursery/log/compare/0.4.11...0.4.12
[0.4.11]: https://github.com/rust-lang-nursery/log/compare/0.4.10...0.4.11
[0.4.10]: https://github.com/rust-lang-nursery/log/compare/0.4.9...0.4.10
[0.4.9]: https://github.com/rust-lang-nursery/log/compare/0.4.8...0.4.9
[0.4.8]: https://github.com/rust-lang-nursery/log/compare/0.4.7...0.4.8
[0.4.7]: https://github.com/rust-lang-nursery/log/compare/0.4.6...0.4.7
[0.4.6]: https://github.com/rust-lang-nursery/log/compare/0.4.5...0.4.6
[0.4.5]: https://github.com/rust-lang-nursery/log/compare/0.4.4...0.4.5
[0.4.4]: https://github.com/rust-lang-nursery/log/compare/0.4.3...0.4.4
[0.4.3]: https://github.com/rust-lang-nursery/log/compare/0.4.2...0.4.3
[0.4.2]: https://github.com/rust-lang-nursery/log/compare/0.4.1...0.4.2
[0.4.1]: https://github.com/rust-lang-nursery/log/compare/0.4.0...0.4.1
[0.4.0]: https://github.com/rust-lang-nursery/log/compare/0.3.8...0.4.0
[release tags]: https://github.com/rust-lang-nursery/log/releases

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,7 +12,7 @@
[package]
name = "log"
version = "0.4.8"
version = "0.4.14"
authors = ["The Rust Project Developers"]
build = "build.rs"
exclude = ["rfcs/**/*", "/.travis.yml", "/appveyor.yml"]
@ -24,13 +24,19 @@ categories = ["development-tools::debugging"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-lang/log"
[package.metadata.docs.rs]
features = ["std", "serde", "kv_unstable_sval"]
features = ["std", "serde", "kv_unstable_std", "kv_unstable_sval", "kv_unstable_serde"]
[[test]]
name = "filters"
path = "tests/filters.rs"
harness = false
[[test]]
name = "macros"
path = "tests/macros.rs"
harness = true
[dependencies.cfg-if]
version = "0.1.2"
version = "1.0"
[dependencies.serde]
version = "1.0"
@ -38,19 +44,34 @@ optional = true
default-features = false
[dependencies.sval]
version = "0.4.2"
version = "1.0.0-alpha.5"
optional = true
default-features = false
[dependencies.value-bag]
version = "1.0.0-alpha.6"
optional = true
default-features = false
[dev-dependencies.serde]
version = "1.0"
features = ["derive"]
[dev-dependencies.serde_test]
version = "1.0"
[dev-dependencies.sval]
version = "0.4.2"
version = "1.0.0-alpha.5"
features = ["derive"]
[dev-dependencies.value-bag]
version = "1.0.0-alpha.6"
features = ["test"]
[features]
kv_unstable = []
kv_unstable_sval = ["kv_unstable", "sval/fmt"]
kv_unstable = ["value-bag"]
kv_unstable_serde = ["kv_unstable_std", "value-bag/serde", "serde"]
kv_unstable_std = ["std", "kv_unstable", "value-bag/error"]
kv_unstable_sval = ["kv_unstable", "value-bag/sval", "sval"]
max_level_debug = []
max_level_error = []
max_level_info = []
@ -64,8 +85,3 @@ release_max_level_off = []
release_max_level_trace = []
release_max_level_warn = []
std = []
[badges.appveyor]
repository = "alexcrichton/log"
[badges.travis-ci]
repository = "rust-lang-nursery/log"

View File

@ -1,201 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,25 +1,25 @@
Copyright (c) 2014 The Rust Project Developers
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
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.
Copyright (c) 2014 The Rust Project Developers
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
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.

View File

@ -1,86 +1,86 @@
log
===
A Rust library providing a lightweight logging *facade*.
[![Build Status](https://travis-ci.com/rust-lang-nursery/log.svg?branch=master)](https://travis-ci.com/rust-lang-nursery/log)
[![Build status](https://ci.appveyor.com/api/projects/status/nopdjmmjt45xcrki?svg=true)](https://ci.appveyor.com/project/alexcrichton/log)
[![Latest version](https://img.shields.io/crates/v/log.svg)](https://crates.io/crates/log)
[![Documentation](https://docs.rs/log/badge.svg)](https://docs.rs/log)
![License](https://img.shields.io/crates/l/log.svg)
* [`log` documentation](https://docs.rs/log)
A logging facade provides a single logging API that abstracts over the actual
logging implementation. Libraries can use the logging API provided by this
crate, and the consumer of those libraries can choose the logging
implementation that is most suitable for its use case.
## Minimum supported `rustc`
`1.16.0+`
This version is explicitly tested in CI and may be bumped in any release as needed. Maintaining compatibility with older compilers is a priority though, so the bar for bumping the minimum supported version is set very high. Any changes to the supported minimum version will be called out in the release notes.
## Usage
## In libraries
Libraries should link only to the `log` crate, and use the provided macros to
log whatever information will be useful to downstream consumers:
```toml
[dependencies]
log = "0.4"
```
```rust
use log::{info, trace, warn};
pub fn shave_the_yak(yak: &mut Yak) {
trace!("Commencing yak shaving");
loop {
match find_a_razor() {
Ok(razor) => {
info!("Razor located: {}", razor);
yak.shave(razor);
break;
}
Err(err) => {
warn!("Unable to locate a razor: {}, retrying", err);
}
}
}
}
```
## In executables
In order to produce log output, executables have to use a logger implementation compatible with the facade.
There are many available implementations to chose from, here are some of the most popular ones:
* Simple minimal loggers:
* [`env_logger`](https://docs.rs/env_logger/*/env_logger/)
* [`simple_logger`](https://github.com/borntyping/rust-simple_logger)
* [`simplelog`](https://github.com/drakulix/simplelog.rs)
* [`pretty_env_logger`](https://docs.rs/pretty_env_logger/*/pretty_env_logger/)
* [`stderrlog`](https://docs.rs/stderrlog/*/stderrlog/)
* [`flexi_logger`](https://docs.rs/flexi_logger/*/flexi_logger/)
* Complex configurable frameworks:
* [`log4rs`](https://docs.rs/log4rs/*/log4rs/)
* [`fern`](https://docs.rs/fern/*/fern/)
* Adaptors for other facilities:
* [`syslog`](https://docs.rs/syslog/*/syslog/)
* [`slog-stdlog`](https://docs.rs/slog-stdlog/*/slog_stdlog/)
* [`android_log`](https://docs.rs/android_log/*/android_log/)
* For WebAssembly binaries:
* [`console_log`](https://docs.rs/console_log/*/console_log/)
Executables should choose a logger implementation and initialize it early in the
runtime of the program. Logger implementations will typically include a
function to do this. Any log messages generated before the logger is
initialized will be ignored.
The executable itself may use the `log` crate to log as well.
log
===
A Rust library providing a lightweight logging *facade*.
[![Build status](https://img.shields.io/github/workflow/status/rust-lang/log/CI/master)](https://github.com/rust-lang/log/actions)
[![Latest version](https://img.shields.io/crates/v/log.svg)](https://crates.io/crates/log)
[![Documentation](https://docs.rs/log/badge.svg)](https://docs.rs/log)
![License](https://img.shields.io/crates/l/log.svg)
* [`log` documentation](https://docs.rs/log)
A logging facade provides a single logging API that abstracts over the actual
logging implementation. Libraries can use the logging API provided by this
crate, and the consumer of those libraries can choose the logging
implementation that is most suitable for its use case.
## Minimum supported `rustc`
`1.31.0+`
This version is explicitly tested in CI and may be bumped in any release as needed. Maintaining compatibility with older compilers is a priority though, so the bar for bumping the minimum supported version is set very high. Any changes to the supported minimum version will be called out in the release notes.
## Usage
## In libraries
Libraries should link only to the `log` crate, and use the provided macros to
log whatever information will be useful to downstream consumers:
```toml
[dependencies]
log = "0.4"
```
```rust
use log::{info, trace, warn};
pub fn shave_the_yak(yak: &mut Yak) {
trace!("Commencing yak shaving");
loop {
match find_a_razor() {
Ok(razor) => {
info!("Razor located: {}", razor);
yak.shave(razor);
break;
}
Err(err) => {
warn!("Unable to locate a razor: {}, retrying", err);
}
}
}
}
```
## In executables
In order to produce log output, executables have to use a logger implementation compatible with the facade.
There are many available implementations to choose from, here are some of the most popular ones:
* Simple minimal loggers:
* [`env_logger`](https://docs.rs/env_logger/*/env_logger/)
* [`simple_logger`](https://github.com/borntyping/rust-simple_logger)
* [`simplelog`](https://github.com/drakulix/simplelog.rs)
* [`pretty_env_logger`](https://docs.rs/pretty_env_logger/*/pretty_env_logger/)
* [`stderrlog`](https://docs.rs/stderrlog/*/stderrlog/)
* [`flexi_logger`](https://docs.rs/flexi_logger/*/flexi_logger/)
* Complex configurable frameworks:
* [`log4rs`](https://docs.rs/log4rs/*/log4rs/)
* [`fern`](https://docs.rs/fern/*/fern/)
* Adaptors for other facilities:
* [`syslog`](https://docs.rs/syslog/*/syslog/)
* [`slog-stdlog`](https://docs.rs/slog-stdlog/*/slog_stdlog/)
* [`android_log`](https://docs.rs/android_log/*/android_log/)
* [`win_dbg_logger`](https://docs.rs/win_dbg_logger/*/win_dbg_logger/)
* For WebAssembly binaries:
* [`console_log`](https://docs.rs/console_log/*/console_log/)
Executables should choose a logger implementation and initialize it early in the
runtime of the program. Logger implementations will typically include a
function to do this. Any log messages generated before the logger is
initialized will be ignored.
The executable itself may use the `log` crate to log as well.

30
third_party/rust/log/benches/value.rs vendored Normal file
View File

@ -0,0 +1,30 @@
#![cfg(feature = "kv_unstable")]
#![feature(test)]
extern crate log;
extern crate test;
use log::kv::Value;
#[bench]
fn u8_to_value(b: &mut test::Bencher) {
b.iter(|| Value::from(1u8))
}
#[bench]
fn u8_to_value_debug(b: &mut test::Bencher) {
b.iter(|| Value::from_debug(&1u8))
}
#[bench]
fn str_to_value_debug(b: &mut test::Bencher) {
b.iter(|| Value::from_debug(&"a string"))
}
#[bench]
fn custom_to_value_debug(b: &mut test::Bencher) {
#[derive(Debug)]
struct A;
b.iter(|| Value::from_debug(&A))
}

View File

@ -1,14 +1,43 @@
//! This build script detects target platforms that lack proper support for
//! atomics and sets `cfg` flags accordingly.
use std::env;
fn main() {
let target = env::var("TARGET").unwrap();
if !target.starts_with("thumbv6") {
println!("cargo:rustc-cfg=atomic_cas");
}
println!("cargo:rerun-if-changed=build.rs");
}
//! This build script detects target platforms that lack proper support for
//! atomics and sets `cfg` flags accordingly.
use std::env;
use std::str;
fn main() {
let target = match rustc_target() {
Some(target) => target,
None => return,
};
if target_has_atomic_cas(&target) {
println!("cargo:rustc-cfg=atomic_cas");
}
if target_has_atomics(&target) {
println!("cargo:rustc-cfg=has_atomics");
}
println!("cargo:rerun-if-changed=build.rs");
}
fn target_has_atomic_cas(target: &str) -> bool {
match &target[..] {
"thumbv6m-none-eabi"
| "msp430-none-elf"
| "riscv32i-unknown-none-elf"
| "riscv32imc-unknown-none-elf" => false,
_ => true,
}
}
fn target_has_atomics(target: &str) -> bool {
match &target[..] {
"msp430-none-elf" | "riscv32i-unknown-none-elf" | "riscv32imc-unknown-none-elf" => false,
_ => true,
}
}
fn rustc_target() -> Option<String> {
env::var("TARGET").ok()
}

View File

@ -1,88 +1,70 @@
use std::fmt;
/// An error encountered while working with structured data.
#[derive(Debug)]
pub struct Error {
inner: Inner
}
#[derive(Debug)]
enum Inner {
#[cfg(feature = "std")]
Boxed(std_support::BoxedError),
Msg(&'static str),
Fmt,
}
impl Error {
/// Create an error from a message.
pub fn msg(msg: &'static str) -> Self {
Error {
inner: Inner::Msg(msg),
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::Inner::*;
match &self.inner {
#[cfg(feature = "std")]
&Boxed(ref err) => err.fmt(f),
&Msg(ref msg) => msg.fmt(f),
&Fmt => fmt::Error.fmt(f),
}
}
}
impl From<fmt::Error> for Error {
fn from(_: fmt::Error) -> Self {
Error {
inner: Inner::Fmt,
}
}
}
impl From<Error> for fmt::Error {
fn from(_: Error) -> Self {
fmt::Error
}
}
#[cfg(feature = "std")]
mod std_support {
use super::*;
use std::{error, io};
pub(super) type BoxedError = Box<error::Error + Send + Sync>;
impl Error {
/// Create an error from a standard error type.
pub fn boxed<E>(err: E) -> Self
where
E: Into<BoxedError>,
{
Error {
inner: Inner::Boxed(err.into())
}
}
}
impl error::Error for Error {
fn description(&self) -> &str {
"key values error"
}
}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Self {
Error::boxed(err)
}
}
impl From<Error> for io::Error {
fn from(err: Error) -> Self {
io::Error::new(io::ErrorKind::Other, err)
}
}
}
use std::fmt;
/// An error encountered while working with structured data.
#[derive(Debug)]
pub struct Error {
inner: Inner,
}
#[derive(Debug)]
enum Inner {
#[cfg(feature = "std")]
Boxed(std_support::BoxedError),
Msg(&'static str),
Fmt,
}
impl Error {
/// Create an error from a message.
pub fn msg(msg: &'static str) -> Self {
Error {
inner: Inner::Msg(msg),
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::Inner::*;
match &self.inner {
#[cfg(feature = "std")]
&Boxed(ref err) => err.fmt(f),
&Msg(ref msg) => msg.fmt(f),
&Fmt => fmt::Error.fmt(f),
}
}
}
impl From<fmt::Error> for Error {
fn from(_: fmt::Error) -> Self {
Error { inner: Inner::Fmt }
}
}
#[cfg(feature = "std")]
mod std_support {
use super::*;
use std::{error, io};
pub(super) type BoxedError = Box<dyn error::Error + Send + Sync>;
impl Error {
/// Create an error from a standard error type.
pub fn boxed<E>(err: E) -> Self
where
E: Into<BoxedError>,
{
Error {
inner: Inner::Boxed(err.into()),
}
}
}
impl error::Error for Error {}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Self {
Error::boxed(err)
}
}
}

View File

@ -1,143 +1,172 @@
//! Structured keys.
use std::fmt;
use std::cmp;
use std::hash;
use std::borrow::Borrow;
/// A type that can be converted into a [`Key`](struct.Key.html).
pub trait ToKey {
/// Perform the conversion.
fn to_key(&self) -> Key;
}
impl<'a, T> ToKey for &'a T
where
T: ToKey + ?Sized,
{
fn to_key(&self) -> Key {
(**self).to_key()
}
}
impl<'k> ToKey for Key<'k> {
fn to_key(&self) -> Key {
Key {
key: self.key,
}
}
}
impl ToKey for str {
fn to_key(&self) -> Key {
Key::from_str(self)
}
}
/// A key in a structured key-value pair.
#[derive(Clone)]
pub struct Key<'k> {
key: &'k str,
}
impl<'k> Key<'k> {
/// Get a key from a borrowed string.
pub fn from_str(key: &'k str) -> Self {
Key {
key: key,
}
}
/// Get a borrowed string from this key.
pub fn as_str(&self) -> &str {
self.key
}
}
impl<'k> fmt::Debug for Key<'k> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.key.fmt(f)
}
}
impl<'k> fmt::Display for Key<'k> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.key.fmt(f)
}
}
impl<'k> hash::Hash for Key<'k> {
fn hash<H>(&self, state: &mut H)
where
H: hash::Hasher,
{
self.as_str().hash(state)
}
}
impl<'k, 'ko> PartialEq<Key<'ko>> for Key<'k> {
fn eq(&self, other: &Key<'ko>) -> bool {
self.as_str().eq(other.as_str())
}
}
impl<'k> Eq for Key<'k> {}
impl<'k, 'ko> PartialOrd<Key<'ko>> for Key<'k> {
fn partial_cmp(&self, other: &Key<'ko>) -> Option<cmp::Ordering> {
self.as_str().partial_cmp(other.as_str())
}
}
impl<'k> Ord for Key<'k> {
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.as_str().cmp(other.as_str())
}
}
impl<'k> AsRef<str> for Key<'k> {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl<'k> Borrow<str> for Key<'k> {
fn borrow(&self) -> &str {
self.as_str()
}
}
impl<'k> From<&'k str> for Key<'k> {
fn from(s: &'k str) -> Self {
Key::from_str(s)
}
}
#[cfg(feature = "std")]
mod std_support {
use super::*;
use std::borrow::Cow;
impl ToKey for String {
fn to_key(&self) -> Key {
Key::from_str(self)
}
}
impl<'a> ToKey for Cow<'a, str> {
fn to_key(&self) -> Key {
Key::from_str(self)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn key_from_string() {
assert_eq!("a key", Key::from_str("a key").as_str());
}
}
//! Structured keys.
use std::borrow::Borrow;
use std::cmp;
use std::fmt;
use std::hash;
/// A type that can be converted into a [`Key`](struct.Key.html).
pub trait ToKey {
/// Perform the conversion.
fn to_key(&self) -> Key;
}
impl<'a, T> ToKey for &'a T
where
T: ToKey + ?Sized,
{
fn to_key(&self) -> Key {
(**self).to_key()
}
}
impl<'k> ToKey for Key<'k> {
fn to_key(&self) -> Key {
Key { key: self.key }
}
}
impl ToKey for str {
fn to_key(&self) -> Key {
Key::from_str(self)
}
}
/// A key in a structured key-value pair.
#[derive(Clone)]
pub struct Key<'k> {
key: &'k str,
}
impl<'k> Key<'k> {
/// Get a key from a borrowed string.
pub fn from_str(key: &'k str) -> Self {
Key { key: key }
}
/// Get a borrowed string from this key.
pub fn as_str(&self) -> &str {
self.key
}
}
impl<'k> fmt::Debug for Key<'k> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.key.fmt(f)
}
}
impl<'k> fmt::Display for Key<'k> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.key.fmt(f)
}
}
impl<'k> hash::Hash for Key<'k> {
fn hash<H>(&self, state: &mut H)
where
H: hash::Hasher,
{
self.as_str().hash(state)
}
}
impl<'k, 'ko> PartialEq<Key<'ko>> for Key<'k> {
fn eq(&self, other: &Key<'ko>) -> bool {
self.as_str().eq(other.as_str())
}
}
impl<'k> Eq for Key<'k> {}
impl<'k, 'ko> PartialOrd<Key<'ko>> for Key<'k> {
fn partial_cmp(&self, other: &Key<'ko>) -> Option<cmp::Ordering> {
self.as_str().partial_cmp(other.as_str())
}
}
impl<'k> Ord for Key<'k> {
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.as_str().cmp(other.as_str())
}
}
impl<'k> AsRef<str> for Key<'k> {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl<'k> Borrow<str> for Key<'k> {
fn borrow(&self) -> &str {
self.as_str()
}
}
impl<'k> From<&'k str> for Key<'k> {
fn from(s: &'k str) -> Self {
Key::from_str(s)
}
}
#[cfg(feature = "std")]
mod std_support {
use super::*;
use std::borrow::Cow;
impl ToKey for String {
fn to_key(&self) -> Key {
Key::from_str(self)
}
}
impl<'a> ToKey for Cow<'a, str> {
fn to_key(&self) -> Key {
Key::from_str(self)
}
}
}
#[cfg(feature = "kv_unstable_sval")]
mod sval_support {
use super::*;
extern crate sval;
use self::sval::value::{self, Value};
impl<'a> Value for Key<'a> {
fn stream(&self, stream: &mut value::Stream) -> value::Result {
self.key.stream(stream)
}
}
}
#[cfg(feature = "kv_unstable_serde")]
mod serde_support {
use super::*;
extern crate serde;
use self::serde::{Serialize, Serializer};
impl<'a> Serialize for Key<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.key.serialize(serializer)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn key_from_string() {
assert_eq!("a key", Key::from_str("a key").as_str());
}
}

View File

@ -1,23 +1,26 @@
//! **UNSTABLE:** Structured key-value pairs.
//!
//! This module is unstable and breaking changes may be made
//! at any time. See [the tracking issue](https://github.com/rust-lang-nursery/log/issues/328)
//! for more details.
//!
//! Add the `kv_unstable` feature to your `Cargo.toml` to enable
//! this module:
//!
//! ```toml
//! [dependencies.log]
//! features = ["kv_unstable"]
//! ```
mod error;
mod source;
mod key;
pub mod value;
pub use self::error::Error;
pub use self::source::{Source, Visitor};
pub use self::key::{Key, ToKey};
pub use self::value::{Value, ToValue};
//! **UNSTABLE:** Structured key-value pairs.
//!
//! This module is unstable and breaking changes may be made
//! at any time. See [the tracking issue](https://github.com/rust-lang-nursery/log/issues/328)
//! for more details.
//!
//! Add the `kv_unstable` feature to your `Cargo.toml` to enable
//! this module:
//!
//! ```toml
//! [dependencies.log]
//! features = ["kv_unstable"]
//! ```
mod error;
mod key;
pub mod source;
pub mod value;
pub use self::error::Error;
pub use self::key::{Key, ToKey};
pub use self::source::{Source, Visitor};
#[doc(inline)]
pub use self::value::{ToValue, Value};

File diff suppressed because it is too large Load Diff

655
third_party/rust/log/src/kv/value.rs vendored Normal file
View File

@ -0,0 +1,655 @@
//! Structured values.
use std::fmt;
extern crate value_bag;
#[cfg(feature = "kv_unstable_sval")]
extern crate sval;
#[cfg(feature = "kv_unstable_serde")]
extern crate serde;
use self::value_bag::ValueBag;
pub use kv::Error;
/// A type that can be converted into a [`Value`](struct.Value.html).
pub trait ToValue {
/// Perform the conversion.
fn to_value(&self) -> Value;
}
impl<'a, T> ToValue for &'a T
where
T: ToValue + ?Sized,
{
fn to_value(&self) -> Value {
(**self).to_value()
}
}
impl<'v> ToValue for Value<'v> {
fn to_value(&self) -> Value {
Value {
inner: self.inner.clone(),
}
}
}
/// A value in a structured key-value pair.
///
/// # Capturing values
///
/// There are a few ways to capture a value:
///
/// - Using the `Value::capture_*` methods.
/// - Using the `Value::from_*` methods.
/// - Using the `ToValue` trait.
/// - Using the standard `From` trait.
///
/// ## Using the `Value::capture_*` methods
///
/// `Value` offers a few constructor methods that capture values of different kinds.
/// These methods require a `T: 'static` to support downcasting.
///
/// ```
/// use log::kv::Value;
///
/// let value = Value::capture_debug(&42i32);
///
/// assert_eq!(Some(42), value.to_i64());
/// ```
///
/// ## Using the `Value::from_*` methods
///
/// `Value` offers a few constructor methods that capture values of different kinds.
/// These methods don't require `T: 'static`, but can't support downcasting.
///
/// ```
/// use log::kv::Value;
///
/// let value = Value::from_debug(&42i32);
///
/// assert_eq!(None, value.to_i64());
/// ```
///
/// ## Using the `ToValue` trait
///
/// The `ToValue` trait can be used to capture values generically.
/// It's the bound used by `Source`.
///
/// ```
/// # use log::kv::ToValue;
/// let value = 42i32.to_value();
///
/// assert_eq!(Some(42), value.to_i64());
/// ```
///
/// ```
/// # use std::fmt::Debug;
/// use log::kv::ToValue;
///
/// let value = (&42i32 as &dyn Debug).to_value();
///
/// assert_eq!(None, value.to_i64());
/// ```
///
/// ## Using the standard `From` trait
///
/// Standard types that implement `ToValue` also implement `From`.
///
/// ```
/// use log::kv::Value;
///
/// let value = Value::from(42i32);
///
/// assert_eq!(Some(42), value.to_i64());
/// ```
pub struct Value<'v> {
inner: ValueBag<'v>,
}
impl<'v> Value<'v> {
/// Get a value from a type implementing `ToValue`.
pub fn from_any<T>(value: &'v T) -> Self
where
T: ToValue,
{
value.to_value()
}
/// Get a value from a type implementing `std::fmt::Debug`.
pub fn capture_debug<T>(value: &'v T) -> Self
where
T: fmt::Debug + 'static,
{
Value {
inner: ValueBag::capture_debug(value),
}
}
/// Get a value from a type implementing `std::fmt::Display`.
pub fn capture_display<T>(value: &'v T) -> Self
where
T: fmt::Display + 'static,
{
Value {
inner: ValueBag::capture_display(value),
}
}
/// Get a value from an error.
#[cfg(feature = "kv_unstable_std")]
pub fn capture_error<T>(err: &'v T) -> Self
where
T: std::error::Error + 'static,
{
Value {
inner: ValueBag::capture_error(err),
}
}
#[cfg(feature = "kv_unstable_serde")]
/// Get a value from a type implementing `serde::Serialize`.
pub fn capture_serde<T>(value: &'v T) -> Self
where
T: self::serde::Serialize + 'static,
{
Value {
inner: ValueBag::capture_serde1(value),
}
}
/// Get a value from a type implementing `sval::value::Value`.
#[cfg(feature = "kv_unstable_sval")]
pub fn capture_sval<T>(value: &'v T) -> Self
where
T: self::sval::value::Value + 'static,
{
Value {
inner: ValueBag::capture_sval1(value),
}
}
/// Get a value from a type implementing `std::fmt::Debug`.
pub fn from_debug<T>(value: &'v T) -> Self
where
T: fmt::Debug,
{
Value {
inner: ValueBag::from_debug(value),
}
}
/// Get a value from a type implementing `std::fmt::Display`.
pub fn from_display<T>(value: &'v T) -> Self
where
T: fmt::Display,
{
Value {
inner: ValueBag::from_display(value),
}
}
/// Get a value from a type implementing `serde::Serialize`.
#[cfg(feature = "kv_unstable_serde")]
pub fn from_serde<T>(value: &'v T) -> Self
where
T: self::serde::Serialize,
{
Value {
inner: ValueBag::from_serde1(value),
}
}
/// Get a value from a type implementing `sval::value::Value`.
#[cfg(feature = "kv_unstable_sval")]
pub fn from_sval<T>(value: &'v T) -> Self
where
T: self::sval::value::Value,
{
Value {
inner: ValueBag::from_sval1(value),
}
}
/// Get a value from a dynamic `std::fmt::Debug`.
pub fn from_dyn_debug(value: &'v dyn fmt::Debug) -> Self {
Value {
inner: ValueBag::from_dyn_debug(value),
}
}
/// Get a value from a dynamic `std::fmt::Display`.
pub fn from_dyn_display(value: &'v dyn fmt::Display) -> Self {
Value {
inner: ValueBag::from_dyn_display(value),
}
}
/// Get a value from a dynamic error.
#[cfg(feature = "kv_unstable_std")]
pub fn from_dyn_error(err: &'v (dyn std::error::Error + 'static)) -> Self {
Value {
inner: ValueBag::from_dyn_error(err),
}
}
/// Get a value from a type implementing `sval::value::Value`.
#[cfg(feature = "kv_unstable_sval")]
pub fn from_dyn_sval(value: &'v dyn self::sval::value::Value) -> Self {
Value {
inner: ValueBag::from_dyn_sval1(value),
}
}
/// Get a value from an internal primitive.
fn from_value_bag<T>(value: T) -> Self
where
T: Into<ValueBag<'v>>,
{
Value {
inner: value.into(),
}
}
/// Check whether this value can be downcast to `T`.
pub fn is<T: 'static>(&self) -> bool {
self.inner.is::<T>()
}
/// Try downcast this value to `T`.
pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
self.inner.downcast_ref::<T>()
}
}
impl<'v> fmt::Debug for Value<'v> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.inner, f)
}
}
impl<'v> fmt::Display for Value<'v> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.inner, f)
}
}
impl ToValue for dyn fmt::Debug {
fn to_value(&self) -> Value {
Value::from_dyn_debug(self)
}
}
impl ToValue for dyn fmt::Display {
fn to_value(&self) -> Value {
Value::from_dyn_display(self)
}
}
#[cfg(feature = "kv_unstable_std")]
impl ToValue for dyn std::error::Error + 'static {
fn to_value(&self) -> Value {
Value::from_dyn_error(self)
}
}
#[cfg(feature = "kv_unstable_serde")]
impl<'v> self::serde::Serialize for Value<'v> {
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
where
S: self::serde::Serializer,
{
self.inner.serialize(s)
}
}
#[cfg(feature = "kv_unstable_sval")]
impl<'v> self::sval::value::Value for Value<'v> {
fn stream(&self, stream: &mut self::sval::value::Stream) -> self::sval::value::Result {
self::sval::value::Value::stream(&self.inner, stream)
}
}
#[cfg(feature = "kv_unstable_sval")]
impl ToValue for dyn self::sval::value::Value {
fn to_value(&self) -> Value {
Value::from_dyn_sval(self)
}
}
impl ToValue for str {
fn to_value(&self) -> Value {
Value::from(self)
}
}
impl<'v> From<&'v str> for Value<'v> {
fn from(value: &'v str) -> Self {
Value::from_value_bag(value)
}
}
impl ToValue for () {
fn to_value(&self) -> Value {
Value::from_value_bag(())
}
}
impl<T> ToValue for Option<T>
where
T: ToValue,
{
fn to_value(&self) -> Value {
match *self {
Some(ref value) => value.to_value(),
None => Value::from_value_bag(()),
}
}
}
macro_rules! impl_to_value_primitive {
($($into_ty:ty,)*) => {
$(
impl ToValue for $into_ty {
fn to_value(&self) -> Value {
Value::from(*self)
}
}
impl<'v> From<$into_ty> for Value<'v> {
fn from(value: $into_ty) -> Self {
Value::from_value_bag(value)
}
}
)*
};
}
macro_rules! impl_value_to_primitive {
($(#[doc = $doc:tt] $into_name:ident -> $into_ty:ty,)*) => {
impl<'v> Value<'v> {
$(
#[doc = $doc]
pub fn $into_name(&self) -> Option<$into_ty> {
self.inner.$into_name()
}
)*
}
}
}
impl_to_value_primitive![
usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, f32, f64, char, bool,
];
impl_value_to_primitive![
#[doc = "Try convert this value into a `u64`."]
to_u64 -> u64,
#[doc = "Try convert this value into a `i64`."]
to_i64 -> i64,
#[doc = "Try convert this value into a `u128`."]
to_u128 -> u128,
#[doc = "Try convert this value into a `i128`."]
to_i128 -> i128,
#[doc = "Try convert this value into a `f64`."]
to_f64 -> f64,
#[doc = "Try convert this value into a `char`."]
to_char -> char,
#[doc = "Try convert this value into a `bool`."]
to_bool -> bool,
];
impl<'v> Value<'v> {
/// Try convert this value into an error.
#[cfg(feature = "kv_unstable_std")]
pub fn to_borrowed_error(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.inner.to_borrowed_error()
}
/// Try convert this value into a borrowed string.
pub fn to_borrowed_str(&self) -> Option<&str> {
self.inner.to_borrowed_str()
}
}
#[cfg(feature = "kv_unstable_std")]
mod std_support {
use super::*;
use std::borrow::Cow;
impl<T> ToValue for Box<T>
where
T: ToValue + ?Sized,
{
fn to_value(&self) -> Value {
(**self).to_value()
}
}
impl ToValue for String {
fn to_value(&self) -> Value {
Value::from(&**self)
}
}
impl<'v> ToValue for Cow<'v, str> {
fn to_value(&self) -> Value {
Value::from(&**self)
}
}
impl<'v> Value<'v> {
/// Try convert this value into a string.
pub fn to_str(&self) -> Option<Cow<str>> {
self.inner.to_str()
}
}
}
#[cfg(test)]
pub(crate) mod tests {
use super::*;
pub(crate) use super::value_bag::test::Token;
impl<'v> Value<'v> {
pub(crate) fn to_token(&self) -> Token {
self.inner.to_token()
}
}
fn unsigned() -> impl Iterator<Item = Value<'static>> {
vec![
Value::from(8u8),
Value::from(16u16),
Value::from(32u32),
Value::from(64u64),
Value::from(1usize),
]
.into_iter()
}
fn signed() -> impl Iterator<Item = Value<'static>> {
vec![
Value::from(-8i8),
Value::from(-16i16),
Value::from(-32i32),
Value::from(-64i64),
Value::from(-1isize),
]
.into_iter()
}
fn float() -> impl Iterator<Item = Value<'static>> {
vec![Value::from(32.32f32), Value::from(64.64f64)].into_iter()
}
fn bool() -> impl Iterator<Item = Value<'static>> {
vec![Value::from(true), Value::from(false)].into_iter()
}
fn str() -> impl Iterator<Item = Value<'static>> {
vec![Value::from("a string"), Value::from("a loong string")].into_iter()
}
fn char() -> impl Iterator<Item = Value<'static>> {
vec![Value::from('a'), Value::from('⛰')].into_iter()
}
#[test]
fn test_capture_fmt() {
assert_eq!(Some(42u64), Value::capture_display(&42).to_u64());
assert_eq!(Some(42u64), Value::capture_debug(&42).to_u64());
assert!(Value::from_display(&42).to_u64().is_none());
assert!(Value::from_debug(&42).to_u64().is_none());
}
#[cfg(feature = "kv_unstable_std")]
#[test]
fn test_capture_error() {
let err = std::io::Error::from(std::io::ErrorKind::Other);
assert!(Value::capture_error(&err).to_borrowed_error().is_some());
assert!(Value::from_dyn_error(&err).to_borrowed_error().is_some());
}
#[cfg(feature = "kv_unstable_serde")]
#[test]
fn test_capture_serde() {
assert_eq!(Some(42u64), Value::capture_serde(&42).to_u64());
assert_eq!(Some(42u64), Value::from_serde(&42).to_u64());
}
#[cfg(feature = "kv_unstable_sval")]
#[test]
fn test_capture_sval() {
assert_eq!(Some(42u64), Value::capture_sval(&42).to_u64());
assert_eq!(Some(42u64), Value::from_sval(&42).to_u64());
}
#[test]
fn test_to_value_display() {
assert_eq!(42u64.to_value().to_string(), "42");
assert_eq!(42i64.to_value().to_string(), "42");
assert_eq!(42.01f64.to_value().to_string(), "42.01");
assert_eq!(true.to_value().to_string(), "true");
assert_eq!('a'.to_value().to_string(), "a");
assert_eq!("a loong string".to_value().to_string(), "a loong string");
assert_eq!(Some(true).to_value().to_string(), "true");
assert_eq!(().to_value().to_string(), "None");
assert_eq!(Option::None::<bool>.to_value().to_string(), "None");
}
#[test]
fn test_to_value_structured() {
assert_eq!(42u64.to_value().to_token(), Token::U64(42));
assert_eq!(42i64.to_value().to_token(), Token::I64(42));
assert_eq!(42.01f64.to_value().to_token(), Token::F64(42.01));
assert_eq!(true.to_value().to_token(), Token::Bool(true));
assert_eq!('a'.to_value().to_token(), Token::Char('a'));
assert_eq!(
"a loong string".to_value().to_token(),
Token::Str("a loong string".into())
);
assert_eq!(Some(true).to_value().to_token(), Token::Bool(true));
assert_eq!(().to_value().to_token(), Token::None);
assert_eq!(Option::None::<bool>.to_value().to_token(), Token::None);
}
#[test]
fn test_to_number() {
for v in unsigned() {
assert!(v.to_u64().is_some());
assert!(v.to_i64().is_some());
}
for v in signed() {
assert!(v.to_i64().is_some());
}
for v in unsigned().chain(signed()).chain(float()) {
assert!(v.to_f64().is_some());
}
for v in bool().chain(str()).chain(char()) {
assert!(v.to_u64().is_none());
assert!(v.to_i64().is_none());
assert!(v.to_f64().is_none());
}
}
#[test]
fn test_to_str() {
for v in str() {
assert!(v.to_borrowed_str().is_some());
#[cfg(feature = "kv_unstable_std")]
assert!(v.to_str().is_some());
}
let short_lived = String::from("short lived");
let v = Value::from(&*short_lived);
assert!(v.to_borrowed_str().is_some());
#[cfg(feature = "kv_unstable_std")]
assert!(v.to_str().is_some());
for v in unsigned().chain(signed()).chain(float()).chain(bool()) {
assert!(v.to_borrowed_str().is_none());
#[cfg(feature = "kv_unstable_std")]
assert!(v.to_str().is_none());
}
}
#[test]
fn test_to_bool() {
for v in bool() {
assert!(v.to_bool().is_some());
}
for v in unsigned()
.chain(signed())
.chain(float())
.chain(str())
.chain(char())
{
assert!(v.to_bool().is_none());
}
}
#[test]
fn test_to_char() {
for v in char() {
assert!(v.to_char().is_some());
}
for v in unsigned()
.chain(signed())
.chain(float())
.chain(str())
.chain(bool())
{
assert!(v.to_char().is_none());
}
}
#[test]
fn test_downcast_ref() {
#[derive(Debug)]
struct Foo(u64);
let v = Value::capture_debug(&Foo(42));
assert!(v.is::<Foo>());
assert_eq!(42u64, v.downcast_ref::<Foo>().expect("invalid downcast").0);
}
}

View File

@ -1,269 +0,0 @@
use std::fmt;
use super::{ToValue, Value, Primitive};
impl ToValue for usize {
fn to_value(&self) -> Value {
Value::from(*self)
}
}
impl<'v> From<usize> for Value<'v> {
fn from(value: usize) -> Self {
Value::from_primitive(Primitive::Unsigned(value as u64))
}
}
impl ToValue for isize {
fn to_value(&self) -> Value {
Value::from(*self)
}
}
impl<'v> From<isize> for Value<'v> {
fn from(value: isize) -> Self {
Value::from_primitive(Primitive::Signed(value as i64))
}
}
impl ToValue for u8 {
fn to_value(&self) -> Value {
Value::from(*self)
}
}
impl<'v> From<u8> for Value<'v> {
fn from(value: u8) -> Self {
Value::from_primitive(Primitive::Unsigned(value as u64))
}
}
impl ToValue for u16 {
fn to_value(&self) -> Value {
Value::from(*self)
}
}
impl<'v> From<u16> for Value<'v> {
fn from(value: u16) -> Self {
Value::from_primitive(Primitive::Unsigned(value as u64))
}
}
impl ToValue for u32 {
fn to_value(&self) -> Value {
Value::from(*self)
}
}
impl<'v> From<u32> for Value<'v> {
fn from(value: u32) -> Self {
Value::from_primitive(Primitive::Unsigned(value as u64))
}
}
impl ToValue for u64 {
fn to_value(&self) -> Value {
Value::from(*self)
}
}
impl<'v> From<u64> for Value<'v> {
fn from(value: u64) -> Self {
Value::from_primitive(Primitive::Unsigned(value))
}
}
impl ToValue for i8 {
fn to_value(&self) -> Value {
Value::from(*self)
}
}
impl<'v> From<i8> for Value<'v> {
fn from(value: i8) -> Self {
Value::from_primitive(Primitive::Signed(value as i64))
}
}
impl ToValue for i16 {
fn to_value(&self) -> Value {
Value::from(*self)
}
}
impl<'v> From<i16> for Value<'v> {
fn from(value: i16) -> Self {
Value::from_primitive(Primitive::Signed(value as i64))
}
}
impl ToValue for i32 {
fn to_value(&self) -> Value {
Value::from(*self)
}
}
impl<'v> From<i32> for Value<'v> {
fn from(value: i32) -> Self {
Value::from_primitive(Primitive::Signed(value as i64))
}
}
impl ToValue for i64 {
fn to_value(&self) -> Value {
Value::from(*self)
}
}
impl<'v> From<i64> for Value<'v> {
fn from(value: i64) -> Self {
Value::from_primitive(Primitive::Signed(value))
}
}
impl ToValue for f32 {
fn to_value(&self) -> Value {
Value::from(*self)
}
}
impl<'v> From<f32> for Value<'v> {
fn from(value: f32) -> Self {
Value::from_primitive(Primitive::Float(value as f64))
}
}
impl ToValue for f64 {
fn to_value(&self) -> Value {
Value::from(*self)
}
}
impl<'v> From<f64> for Value<'v> {
fn from(value: f64) -> Self {
Value::from_primitive(Primitive::Float(value))
}
}
impl ToValue for bool {
fn to_value(&self) -> Value {
Value::from(*self)
}
}
impl<'v> From<bool> for Value<'v> {
fn from(value: bool) -> Self {
Value::from_primitive(Primitive::Bool(value))
}
}
impl ToValue for char {
fn to_value(&self) -> Value {
Value::from(*self)
}
}
impl<'v> From<char> for Value<'v> {
fn from(value: char) -> Self {
Value::from_primitive(Primitive::Char(value))
}
}
impl<'v> ToValue for &'v str {
fn to_value(&self) -> Value {
Value::from(*self)
}
}
impl<'v> From<&'v str> for Value<'v> {
fn from(value: &'v str) -> Self {
Value::from_primitive(Primitive::Str(value))
}
}
impl ToValue for () {
fn to_value(&self) -> Value {
Value::from_primitive(Primitive::None)
}
}
impl<T> ToValue for Option<T>
where
T: ToValue,
{
fn to_value(&self) -> Value {
match *self {
Some(ref value) => value.to_value(),
None => Value::from_primitive(Primitive::None),
}
}
}
impl<'v> ToValue for fmt::Arguments<'v> {
fn to_value(&self) -> Value {
Value::from_debug(self)
}
}
#[cfg(feature = "std")]
mod std_support {
use super::*;
use std::borrow::Cow;
impl<T> ToValue for Box<T>
where
T: ToValue + ?Sized,
{
fn to_value(&self) -> Value {
(**self).to_value()
}
}
impl ToValue for String {
fn to_value(&self) -> Value {
Value::from_primitive(Primitive::Str(&*self))
}
}
impl<'v> ToValue for Cow<'v, str> {
fn to_value(&self) -> Value {
Value::from_primitive(Primitive::Str(&*self))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use kv::value::test::Token;
#[test]
fn test_to_value_display() {
assert_eq!(42u64.to_value().to_string(), "42");
assert_eq!(42i64.to_value().to_string(), "42");
assert_eq!(42.01f64.to_value().to_string(), "42.01");
assert_eq!(true.to_value().to_string(), "true");
assert_eq!('a'.to_value().to_string(), "'a'");
assert_eq!(format_args!("a {}", "value").to_value().to_string(), "a value");
assert_eq!("a loong string".to_value().to_string(), "\"a loong string\"");
assert_eq!(Some(true).to_value().to_string(), "true");
assert_eq!(().to_value().to_string(), "None");
assert_eq!(Option::None::<bool>.to_value().to_string(), "None");
}
#[test]
fn test_to_value_structured() {
assert_eq!(42u64.to_value().to_token(), Token::U64(42));
assert_eq!(42i64.to_value().to_token(), Token::I64(42));
assert_eq!(42.01f64.to_value().to_token(), Token::F64(42.01));
assert_eq!(true.to_value().to_token(), Token::Bool(true));
assert_eq!('a'.to_value().to_token(), Token::Char('a'));
assert_eq!(format_args!("a {}", "value").to_value().to_token(), Token::Str("a value".into()));
assert_eq!("a loong string".to_value().to_token(), Token::Str("a loong string".into()));
assert_eq!(Some(true).to_value().to_token(), Token::Bool(true));
assert_eq!(().to_value().to_token(), Token::None);
assert_eq!(Option::None::<bool>.to_value().to_token(), Token::None);
}
}

View File

@ -1,264 +0,0 @@
use std::fmt;
use super::{Fill, Slot, Error};
use kv;
// `Visitor` is an internal API for visiting the structure of a value.
// It's not intended to be public (at this stage).
/// A container for a structured value for a specific kind of visitor.
#[derive(Clone, Copy)]
pub(super) enum Inner<'v> {
/// A simple primitive value that can be copied without allocating.
Primitive(Primitive<'v>),
/// A value that can be filled.
Fill(&'v Fill),
/// A debuggable value.
Debug(&'v fmt::Debug),
/// A displayable value.
Display(&'v fmt::Display),
#[cfg(feature = "kv_unstable_sval")]
/// A structured value from `sval`.
Sval(&'v sval_support::Value),
}
impl<'v> Inner<'v> {
pub(super) fn visit(&self, visitor: &mut Visitor) -> Result<(), Error> {
match *self {
Inner::Primitive(value) => match value {
Primitive::Signed(value) => visitor.i64(value),
Primitive::Unsigned(value) => visitor.u64(value),
Primitive::Float(value) => visitor.f64(value),
Primitive::Bool(value) => visitor.bool(value),
Primitive::Char(value) => visitor.char(value),
Primitive::Str(value) => visitor.str(value),
Primitive::None => visitor.none(),
},
Inner::Fill(value) => value.fill(&mut Slot::new(visitor)),
Inner::Debug(value) => visitor.debug(value),
Inner::Display(value) => visitor.display(value),
#[cfg(feature = "kv_unstable_sval")]
Inner::Sval(value) => visitor.sval(value),
}
}
}
/// The internal serialization contract.
pub(super) trait Visitor {
fn debug(&mut self, v: &fmt::Debug) -> Result<(), Error>;
fn display(&mut self, v: &fmt::Display) -> Result<(), Error> {
self.debug(&format_args!("{}", v))
}
fn u64(&mut self, v: u64) -> Result<(), Error>;
fn i64(&mut self, v: i64) -> Result<(), Error>;
fn f64(&mut self, v: f64) -> Result<(), Error>;
fn bool(&mut self, v: bool) -> Result<(), Error>;
fn char(&mut self, v: char) -> Result<(), Error>;
fn str(&mut self, v: &str) -> Result<(), Error>;
fn none(&mut self) -> Result<(), Error>;
#[cfg(feature = "kv_unstable_sval")]
fn sval(&mut self, v: &sval_support::Value) -> Result<(), Error>;
}
#[derive(Clone, Copy)]
pub(super) enum Primitive<'v> {
Signed(i64),
Unsigned(u64),
Float(f64),
Bool(bool),
Char(char),
Str(&'v str),
None,
}
mod fmt_support {
use super::*;
impl<'v> kv::Value<'v> {
/// Get a value from a debuggable type.
pub fn from_debug<T>(value: &'v T) -> Self
where
T: fmt::Debug,
{
kv::Value {
inner: Inner::Debug(value),
}
}
/// Get a value from a displayable type.
pub fn from_display<T>(value: &'v T) -> Self
where
T: fmt::Display,
{
kv::Value {
inner: Inner::Display(value),
}
}
}
impl<'v> fmt::Debug for kv::Value<'v> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.visit(&mut FmtVisitor(f))?;
Ok(())
}
}
impl<'v> fmt::Display for kv::Value<'v> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.visit(&mut FmtVisitor(f))?;
Ok(())
}
}
struct FmtVisitor<'a, 'b: 'a>(&'a mut fmt::Formatter<'b>);
impl<'a, 'b: 'a> Visitor for FmtVisitor<'a, 'b> {
fn debug(&mut self, v: &fmt::Debug) -> Result<(), Error> {
v.fmt(self.0)?;
Ok(())
}
fn u64(&mut self, v: u64) -> Result<(), Error> {
self.debug(&format_args!("{:?}", v))
}
fn i64(&mut self, v: i64) -> Result<(), Error> {
self.debug(&format_args!("{:?}", v))
}
fn f64(&mut self, v: f64) -> Result<(), Error> {
self.debug(&format_args!("{:?}", v))
}
fn bool(&mut self, v: bool) -> Result<(), Error> {
self.debug(&format_args!("{:?}", v))
}
fn char(&mut self, v: char) -> Result<(), Error> {
self.debug(&format_args!("{:?}", v))
}
fn str(&mut self, v: &str) -> Result<(), Error> {
self.debug(&format_args!("{:?}", v))
}
fn none(&mut self) -> Result<(), Error> {
self.debug(&format_args!("None"))
}
#[cfg(feature = "kv_unstable_sval")]
fn sval(&mut self, v: &sval_support::Value) -> Result<(), Error> {
sval_support::fmt(self.0, v)
}
}
}
#[cfg(feature = "kv_unstable_sval")]
pub(super) mod sval_support {
use super::*;
extern crate sval;
impl<'v> kv::Value<'v> {
/// Get a value from a structured type.
pub fn from_sval<T>(value: &'v T) -> Self
where
T: sval::Value,
{
kv::Value {
inner: Inner::Sval(value),
}
}
}
impl<'v> sval::Value for kv::Value<'v> {
fn stream(&self, s: &mut sval::value::Stream) -> sval::value::Result {
self.visit(&mut SvalVisitor(s)).map_err(Error::into_sval)?;
Ok(())
}
}
pub(in kv::value) use self::sval::Value;
pub(super) fn fmt(f: &mut fmt::Formatter, v: &sval::Value) -> Result<(), Error> {
sval::fmt::debug(f, v)?;
Ok(())
}
impl Error {
fn from_sval(_: sval::value::Error) -> Self {
Error::msg("`sval` serialization failed")
}
fn into_sval(self) -> sval::value::Error {
sval::value::Error::msg("`sval` serialization failed")
}
}
struct SvalVisitor<'a, 'b: 'a>(&'a mut sval::value::Stream<'b>);
impl<'a, 'b: 'a> Visitor for SvalVisitor<'a, 'b> {
fn debug(&mut self, v: &fmt::Debug) -> Result<(), Error> {
self.0.fmt(format_args!("{:?}", v)).map_err(Error::from_sval)
}
fn u64(&mut self, v: u64) -> Result<(), Error> {
self.0.u64(v).map_err(Error::from_sval)
}
fn i64(&mut self, v: i64) -> Result<(), Error> {
self.0.i64(v).map_err(Error::from_sval)
}
fn f64(&mut self, v: f64) -> Result<(), Error> {
self.0.f64(v).map_err(Error::from_sval)
}
fn bool(&mut self, v: bool) -> Result<(), Error> {
self.0.bool(v).map_err(Error::from_sval)
}
fn char(&mut self, v: char) -> Result<(), Error> {
self.0.char(v).map_err(Error::from_sval)
}
fn str(&mut self, v: &str) -> Result<(), Error> {
self.0.str(v).map_err(Error::from_sval)
}
fn none(&mut self) -> Result<(), Error> {
self.0.none().map_err(Error::from_sval)
}
fn sval(&mut self, v: &sval::Value) -> Result<(), Error> {
self.0.any(v).map_err(Error::from_sval)
}
}
#[cfg(test)]
mod tests {
use super::*;
use kv::value::test::Token;
#[test]
fn test_from_sval() {
assert_eq!(kv::Value::from_sval(&42u64).to_token(), Token::Sval);
}
#[test]
fn test_sval_structured() {
let value = kv::Value::from(42u64);
let expected = vec![sval::test::Token::Unsigned(42)];
assert_eq!(sval::test::tokens(value), expected);
}
}
}

View File

@ -1,155 +0,0 @@
//! Structured values.
use std::fmt;
mod internal;
mod impls;
#[cfg(test)]
pub(in kv) mod test;
pub use kv::Error;
use self::internal::{Inner, Visitor, Primitive};
/// A type that can be converted into a [`Value`](struct.Value.html).
pub trait ToValue {
/// Perform the conversion.
fn to_value(&self) -> Value;
}
impl<'a, T> ToValue for &'a T
where
T: ToValue + ?Sized,
{
fn to_value(&self) -> Value {
(**self).to_value()
}
}
impl<'v> ToValue for Value<'v> {
fn to_value(&self) -> Value {
Value {
inner: self.inner,
}
}
}
/// A type that requires extra work to convert into a [`Value`](struct.Value.html).
///
/// This trait is a more advanced initialization API than [`ToValue`](trait.ToValue.html).
/// It's intended for erased values coming from other logging frameworks that may need
/// to perform extra work to determine the concrete type to use.
pub trait Fill {
/// Fill a value.
fn fill(&self, slot: &mut Slot) -> Result<(), Error>;
}
impl<'a, T> Fill for &'a T
where
T: Fill + ?Sized,
{
fn fill(&self, slot: &mut Slot) -> Result<(), Error> {
(**self).fill(slot)
}
}
/// A value slot to fill using the [`Fill`](trait.Fill.html) trait.
pub struct Slot<'a> {
filled: bool,
visitor: &'a mut Visitor,
}
impl<'a> fmt::Debug for Slot<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Slot").finish()
}
}
impl<'a> Slot<'a> {
fn new(visitor: &'a mut Visitor) -> Self {
Slot {
visitor,
filled: false,
}
}
/// Fill the slot with a value.
///
/// The given value doesn't need to satisfy any particular lifetime constraints.
///
/// # Panics
///
/// Calling `fill` more than once will panic.
pub fn fill(&mut self, value: Value) -> Result<(), Error> {
assert!(!self.filled, "the slot has already been filled");
self.filled = true;
value.visit(self.visitor)
}
}
/// A value in a structured key-value pair.
pub struct Value<'v> {
inner: Inner<'v>,
}
impl<'v> Value<'v> {
/// Get a value from an internal `Visit`.
fn from_primitive(value: Primitive<'v>) -> Self {
Value {
inner: Inner::Primitive(value),
}
}
/// Get a value from a fillable slot.
pub fn from_fill<T>(value: &'v T) -> Self
where
T: Fill,
{
Value {
inner: Inner::Fill(value),
}
}
fn visit(&self, visitor: &mut Visitor) -> Result<(), Error> {
self.inner.visit(visitor)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fill_value() {
struct TestFill;
impl Fill for TestFill {
fn fill(&self, slot: &mut Slot) -> Result<(), Error> {
let dbg: &fmt::Debug = &1;
slot.fill(Value::from_debug(&dbg))
}
}
assert_eq!("1", Value::from_fill(&TestFill).to_string());
}
#[test]
#[should_panic]
fn fill_multiple_times_panics() {
struct BadFill;
impl Fill for BadFill {
fn fill(&self, slot: &mut Slot) -> Result<(), Error> {
slot.fill(42.into())?;
slot.fill(6789.into())?;
Ok(())
}
}
let _ = Value::from_fill(&BadFill).to_string();
}
}

View File

@ -1,81 +0,0 @@
// Test support for inspecting Values
use std::fmt;
use std::str;
use super::{Value, Error};
use super::internal;
#[derive(Debug, PartialEq)]
pub(in kv) enum Token {
U64(u64),
I64(i64),
F64(f64),
Char(char),
Bool(bool),
Str(String),
None,
#[cfg(feature = "kv_unstable_sval")]
Sval,
}
#[cfg(test)]
impl<'v> Value<'v> {
pub(in kv) fn to_token(&self) -> Token {
struct TestVisitor(Option<Token>);
impl internal::Visitor for TestVisitor {
fn debug(&mut self, v: &fmt::Debug) -> Result<(), Error> {
self.0 = Some(Token::Str(format!("{:?}", v)));
Ok(())
}
fn u64(&mut self, v: u64) -> Result<(), Error> {
self.0 = Some(Token::U64(v));
Ok(())
}
fn i64(&mut self, v: i64) -> Result<(), Error> {
self.0 = Some(Token::I64(v));
Ok(())
}
fn f64(&mut self, v: f64) -> Result<(), Error> {
self.0 = Some(Token::F64(v));
Ok(())
}
fn bool(&mut self, v: bool) -> Result<(), Error> {
self.0 = Some(Token::Bool(v));
Ok(())
}
fn char(&mut self, v: char) -> Result<(), Error> {
self.0 = Some(Token::Char(v));
Ok(())
}
fn str(&mut self, v: &str) -> Result<(), Error> {
self.0 = Some(Token::Str(v.into()));
Ok(())
}
fn none(&mut self) -> Result<(), Error> {
self.0 = Some(Token::None);
Ok(())
}
#[cfg(feature = "kv_unstable_sval")]
fn sval(&mut self, _: &internal::sval_support::Value) -> Result<(), Error> {
self.0 = Some(Token::Sval);
Ok(())
}
}
let mut visitor = TestVisitor(None);
self.visit(&mut visitor).unwrap();
visitor.0.unwrap()
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,250 +1,250 @@
// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/// The standard logging macro.
///
/// This macro will generically log with the specified `Level` and `format!`
/// based argument list.
///
/// # Examples
///
/// ```edition2018
/// use log::{log, Level};
///
/// # fn main() {
/// let data = (42, "Forty-two");
/// let private_data = "private";
///
/// log!(Level::Error, "Received errors: {}, {}", data.0, data.1);
/// log!(target: "app_events", Level::Warn, "App warning: {}, {}, {}",
/// data.0, data.1, private_data);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! log {
(target: $target:expr, $lvl:expr, $($arg:tt)+) => ({
let lvl = $lvl;
if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() {
$crate::__private_api_log(
__log_format_args!($($arg)+),
lvl,
&($target, __log_module_path!(), __log_file!(), __log_line!()),
);
}
});
($lvl:expr, $($arg:tt)+) => (log!(target: __log_module_path!(), $lvl, $($arg)+))
}
/// Logs a message at the error level.
///
/// # Examples
///
/// ```edition2018
/// use log::error;
///
/// # fn main() {
/// let (err_info, port) = ("No connection", 22);
///
/// error!("Error: {} on port {}", err_info, port);
/// error!(target: "app_events", "App Error: {}, Port: {}", err_info, 22);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! error {
(target: $target:expr, $($arg:tt)+) => (
log!(target: $target, $crate::Level::Error, $($arg)+);
);
($($arg:tt)+) => (
log!($crate::Level::Error, $($arg)+);
)
}
/// Logs a message at the warn level.
///
/// # Examples
///
/// ```edition2018
/// use log::warn;
///
/// # fn main() {
/// let warn_description = "Invalid Input";
///
/// warn!("Warning! {}!", warn_description);
/// warn!(target: "input_events", "App received warning: {}", warn_description);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! warn {
(target: $target:expr, $($arg:tt)+) => (
log!(target: $target, $crate::Level::Warn, $($arg)+);
);
($($arg:tt)+) => (
log!($crate::Level::Warn, $($arg)+);
)
}
/// Logs a message at the info level.
///
/// # Examples
///
/// ```edition2018
/// use log::info;
///
/// # fn main() {
/// # struct Connection { port: u32, speed: f32 }
/// let conn_info = Connection { port: 40, speed: 3.20 };
///
/// info!("Connected to port {} at {} Mb/s", conn_info.port, conn_info.speed);
/// info!(target: "connection_events", "Successfull connection, port: {}, speed: {}",
/// conn_info.port, conn_info.speed);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! info {
(target: $target:expr, $($arg:tt)+) => (
log!(target: $target, $crate::Level::Info, $($arg)+);
);
($($arg:tt)+) => (
log!($crate::Level::Info, $($arg)+);
)
}
/// Logs a message at the debug level.
///
/// # Examples
///
/// ```edition2018
/// use log::debug;
///
/// # fn main() {
/// # struct Position { x: f32, y: f32 }
/// let pos = Position { x: 3.234, y: -1.223 };
///
/// debug!("New position: x: {}, y: {}", pos.x, pos.y);
/// debug!(target: "app_events", "New position: x: {}, y: {}", pos.x, pos.y);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! debug {
(target: $target:expr, $($arg:tt)+) => (
log!(target: $target, $crate::Level::Debug, $($arg)+);
);
($($arg:tt)+) => (
log!($crate::Level::Debug, $($arg)+);
)
}
/// Logs a message at the trace level.
///
/// # Examples
///
/// ```edition2018
/// use log::trace;
///
/// # fn main() {
/// # struct Position { x: f32, y: f32 }
/// let pos = Position { x: 3.234, y: -1.223 };
///
/// trace!("Position is: x: {}, y: {}", pos.x, pos.y);
/// trace!(target: "app_events", "x is {} and y is {}",
/// if pos.x >= 0.0 { "positive" } else { "negative" },
/// if pos.y >= 0.0 { "positive" } else { "negative" });
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! trace {
(target: $target:expr, $($arg:tt)+) => (
log!(target: $target, $crate::Level::Trace, $($arg)+);
);
($($arg:tt)+) => (
log!($crate::Level::Trace, $($arg)+);
)
}
/// Determines if a message logged at the specified level in that module will
/// be logged.
///
/// This can be used to avoid expensive computation of log message arguments if
/// the message would be ignored anyway.
///
/// # Examples
///
/// ```edition2018
/// use log::Level::Debug;
/// use log::{debug, log_enabled};
///
/// # fn foo() {
/// if log_enabled!(Debug) {
/// let data = expensive_call();
/// debug!("expensive debug data: {} {}", data.x, data.y);
/// }
/// if log_enabled!(target: "Global", Debug) {
/// let data = expensive_call();
/// debug!(target: "Global", "expensive debug data: {} {}", data.x, data.y);
/// }
/// # }
/// # struct Data { x: u32, y: u32 }
/// # fn expensive_call() -> Data { Data { x: 0, y: 0 } }
/// # fn main() {}
/// ```
#[macro_export(local_inner_macros)]
macro_rules! log_enabled {
(target: $target:expr, $lvl:expr) => {{
let lvl = $lvl;
lvl <= $crate::STATIC_MAX_LEVEL
&& lvl <= $crate::max_level()
&& $crate::__private_api_enabled(lvl, $target)
}};
($lvl:expr) => {
log_enabled!(target: __log_module_path!(), $lvl)
};
}
// The log macro above cannot invoke format_args directly because it uses
// local_inner_macros. A format_args invocation there would resolve to
// $crate::format_args which does not exist. Instead invoke format_args here
// outside of local_inner_macros so that it resolves (probably) to
// core::format_args or std::format_args. Same for the several macros that
// follow.
//
// This is a workaround until we drop support for pre-1.30 compilers. At that
// point we can remove use of local_inner_macros, use $crate:: when invoking
// local macros, and invoke format_args directly.
#[doc(hidden)]
#[macro_export]
macro_rules! __log_format_args {
($($args:tt)*) => {
format_args!($($args)*)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __log_module_path {
() => {
module_path!()
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __log_file {
() => {
file!()
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __log_line {
() => {
line!()
};
}
// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/// The standard logging macro.
///
/// This macro will generically log with the specified `Level` and `format!`
/// based argument list.
///
/// # Examples
///
/// ```edition2018
/// use log::{log, Level};
///
/// # fn main() {
/// let data = (42, "Forty-two");
/// let private_data = "private";
///
/// log!(Level::Error, "Received errors: {}, {}", data.0, data.1);
/// log!(target: "app_events", Level::Warn, "App warning: {}, {}, {}",
/// data.0, data.1, private_data);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! log {
(target: $target:expr, $lvl:expr, $($arg:tt)+) => ({
let lvl = $lvl;
if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() {
$crate::__private_api_log(
__log_format_args!($($arg)+),
lvl,
&($target, __log_module_path!(), __log_file!(), __log_line!()),
);
}
});
($lvl:expr, $($arg:tt)+) => (log!(target: __log_module_path!(), $lvl, $($arg)+))
}
/// Logs a message at the error level.
///
/// # Examples
///
/// ```edition2018
/// use log::error;
///
/// # fn main() {
/// let (err_info, port) = ("No connection", 22);
///
/// error!("Error: {} on port {}", err_info, port);
/// error!(target: "app_events", "App Error: {}, Port: {}", err_info, 22);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! error {
(target: $target:expr, $($arg:tt)+) => (
log!(target: $target, $crate::Level::Error, $($arg)+)
);
($($arg:tt)+) => (
log!($crate::Level::Error, $($arg)+)
)
}
/// Logs a message at the warn level.
///
/// # Examples
///
/// ```edition2018
/// use log::warn;
///
/// # fn main() {
/// let warn_description = "Invalid Input";
///
/// warn!("Warning! {}!", warn_description);
/// warn!(target: "input_events", "App received warning: {}", warn_description);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! warn {
(target: $target:expr, $($arg:tt)+) => (
log!(target: $target, $crate::Level::Warn, $($arg)+)
);
($($arg:tt)+) => (
log!($crate::Level::Warn, $($arg)+)
)
}
/// Logs a message at the info level.
///
/// # Examples
///
/// ```edition2018
/// use log::info;
///
/// # fn main() {
/// # struct Connection { port: u32, speed: f32 }
/// let conn_info = Connection { port: 40, speed: 3.20 };
///
/// info!("Connected to port {} at {} Mb/s", conn_info.port, conn_info.speed);
/// info!(target: "connection_events", "Successfull connection, port: {}, speed: {}",
/// conn_info.port, conn_info.speed);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! info {
(target: $target:expr, $($arg:tt)+) => (
log!(target: $target, $crate::Level::Info, $($arg)+)
);
($($arg:tt)+) => (
log!($crate::Level::Info, $($arg)+)
)
}
/// Logs a message at the debug level.
///
/// # Examples
///
/// ```edition2018
/// use log::debug;
///
/// # fn main() {
/// # struct Position { x: f32, y: f32 }
/// let pos = Position { x: 3.234, y: -1.223 };
///
/// debug!("New position: x: {}, y: {}", pos.x, pos.y);
/// debug!(target: "app_events", "New position: x: {}, y: {}", pos.x, pos.y);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! debug {
(target: $target:expr, $($arg:tt)+) => (
log!(target: $target, $crate::Level::Debug, $($arg)+)
);
($($arg:tt)+) => (
log!($crate::Level::Debug, $($arg)+)
)
}
/// Logs a message at the trace level.
///
/// # Examples
///
/// ```edition2018
/// use log::trace;
///
/// # fn main() {
/// # struct Position { x: f32, y: f32 }
/// let pos = Position { x: 3.234, y: -1.223 };
///
/// trace!("Position is: x: {}, y: {}", pos.x, pos.y);
/// trace!(target: "app_events", "x is {} and y is {}",
/// if pos.x >= 0.0 { "positive" } else { "negative" },
/// if pos.y >= 0.0 { "positive" } else { "negative" });
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! trace {
(target: $target:expr, $($arg:tt)+) => (
log!(target: $target, $crate::Level::Trace, $($arg)+)
);
($($arg:tt)+) => (
log!($crate::Level::Trace, $($arg)+)
)
}
/// Determines if a message logged at the specified level in that module will
/// be logged.
///
/// This can be used to avoid expensive computation of log message arguments if
/// the message would be ignored anyway.
///
/// # Examples
///
/// ```edition2018
/// use log::Level::Debug;
/// use log::{debug, log_enabled};
///
/// # fn foo() {
/// if log_enabled!(Debug) {
/// let data = expensive_call();
/// debug!("expensive debug data: {} {}", data.x, data.y);
/// }
/// if log_enabled!(target: "Global", Debug) {
/// let data = expensive_call();
/// debug!(target: "Global", "expensive debug data: {} {}", data.x, data.y);
/// }
/// # }
/// # struct Data { x: u32, y: u32 }
/// # fn expensive_call() -> Data { Data { x: 0, y: 0 } }
/// # fn main() {}
/// ```
#[macro_export(local_inner_macros)]
macro_rules! log_enabled {
(target: $target:expr, $lvl:expr) => {{
let lvl = $lvl;
lvl <= $crate::STATIC_MAX_LEVEL
&& lvl <= $crate::max_level()
&& $crate::__private_api_enabled(lvl, $target)
}};
($lvl:expr) => {
log_enabled!(target: __log_module_path!(), $lvl)
};
}
// The log macro above cannot invoke format_args directly because it uses
// local_inner_macros. A format_args invocation there would resolve to
// $crate::format_args which does not exist. Instead invoke format_args here
// outside of local_inner_macros so that it resolves (probably) to
// core::format_args or std::format_args. Same for the several macros that
// follow.
//
// This is a workaround until we drop support for pre-1.30 compilers. At that
// point we can remove use of local_inner_macros, use $crate:: when invoking
// local macros, and invoke format_args directly.
#[doc(hidden)]
#[macro_export]
macro_rules! __log_format_args {
($($args:tt)*) => {
format_args!($($args)*)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __log_module_path {
() => {
module_path!()
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __log_file {
() => {
file!()
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __log_line {
() => {
line!()
};
}

View File

@ -1,329 +1,400 @@
#![cfg(feature = "serde")]
extern crate serde;
use self::serde::de::{
Deserialize, DeserializeSeed, Deserializer, EnumAccess, Error, Unexpected, VariantAccess,
Visitor,
};
use self::serde::ser::{Serialize, Serializer};
use {Level, LevelFilter, LOG_LEVEL_NAMES};
use std::fmt;
use std::str::{self, FromStr};
// The Deserialize impls are handwritten to be case insensitive using FromStr.
impl Serialize for Level {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
Level::Error => serializer.serialize_unit_variant("Level", 0, "ERROR"),
Level::Warn => serializer.serialize_unit_variant("Level", 1, "WARN"),
Level::Info => serializer.serialize_unit_variant("Level", 2, "INFO"),
Level::Debug => serializer.serialize_unit_variant("Level", 3, "DEBUG"),
Level::Trace => serializer.serialize_unit_variant("Level", 4, "TRACE"),
}
}
}
impl<'de> Deserialize<'de> for Level {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct LevelIdentifier;
impl<'de> Visitor<'de> for LevelIdentifier {
type Value = Level;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("log level")
}
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
where
E: Error,
{
// Case insensitive.
FromStr::from_str(s).map_err(|_| Error::unknown_variant(s, &LOG_LEVEL_NAMES[1..]))
}
fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
where
E: Error,
{
let variant = str::from_utf8(value)
.map_err(|_| Error::invalid_value(Unexpected::Bytes(value), &self))?;
self.visit_str(variant)
}
}
impl<'de> DeserializeSeed<'de> for LevelIdentifier {
type Value = Level;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_identifier(LevelIdentifier)
}
}
struct LevelEnum;
impl<'de> Visitor<'de> for LevelEnum {
type Value = Level;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("log level")
}
fn visit_enum<A>(self, value: A) -> Result<Self::Value, A::Error>
where
A: EnumAccess<'de>,
{
let (level, variant) = value.variant_seed(LevelIdentifier)?;
// Every variant is a unit variant.
variant.unit_variant()?;
Ok(level)
}
}
deserializer.deserialize_enum("Level", &LOG_LEVEL_NAMES[1..], LevelEnum)
}
}
impl Serialize for LevelFilter {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
LevelFilter::Off => serializer.serialize_unit_variant("LevelFilter", 0, "OFF"),
LevelFilter::Error => serializer.serialize_unit_variant("LevelFilter", 1, "ERROR"),
LevelFilter::Warn => serializer.serialize_unit_variant("LevelFilter", 2, "WARN"),
LevelFilter::Info => serializer.serialize_unit_variant("LevelFilter", 3, "INFO"),
LevelFilter::Debug => serializer.serialize_unit_variant("LevelFilter", 4, "DEBUG"),
LevelFilter::Trace => serializer.serialize_unit_variant("LevelFilter", 5, "TRACE"),
}
}
}
impl<'de> Deserialize<'de> for LevelFilter {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct LevelFilterIdentifier;
impl<'de> Visitor<'de> for LevelFilterIdentifier {
type Value = LevelFilter;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("log level filter")
}
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
where
E: Error,
{
// Case insensitive.
FromStr::from_str(s).map_err(|_| Error::unknown_variant(s, &LOG_LEVEL_NAMES))
}
fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
where
E: Error,
{
let variant = str::from_utf8(value)
.map_err(|_| Error::invalid_value(Unexpected::Bytes(value), &self))?;
self.visit_str(variant)
}
}
impl<'de> DeserializeSeed<'de> for LevelFilterIdentifier {
type Value = LevelFilter;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_identifier(LevelFilterIdentifier)
}
}
struct LevelFilterEnum;
impl<'de> Visitor<'de> for LevelFilterEnum {
type Value = LevelFilter;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("log level filter")
}
fn visit_enum<A>(self, value: A) -> Result<Self::Value, A::Error>
where
A: EnumAccess<'de>,
{
let (level_filter, variant) = value.variant_seed(LevelFilterIdentifier)?;
// Every variant is a unit variant.
variant.unit_variant()?;
Ok(level_filter)
}
}
deserializer.deserialize_enum("LevelFilter", &LOG_LEVEL_NAMES, LevelFilterEnum)
}
}
#[cfg(test)]
mod tests {
extern crate serde_test;
use self::serde_test::{assert_de_tokens, assert_de_tokens_error, assert_tokens, Token};
use {Level, LevelFilter};
fn level_token(variant: &'static str) -> Token {
Token::UnitVariant {
name: "Level",
variant: variant,
}
}
fn level_bytes_tokens(variant: &'static [u8]) -> [Token; 3] {
[
Token::Enum { name: "Level" },
Token::Bytes(variant),
Token::Unit,
]
}
fn level_filter_token(variant: &'static str) -> Token {
Token::UnitVariant {
name: "LevelFilter",
variant: variant,
}
}
fn level_filter_bytes_tokens(variant: &'static [u8]) -> [Token; 3] {
[
Token::Enum {
name: "LevelFilter",
},
Token::Bytes(variant),
Token::Unit,
]
}
#[test]
fn test_level_ser_de() {
let cases = [
(Level::Error, [level_token("ERROR")]),
(Level::Warn, [level_token("WARN")]),
(Level::Info, [level_token("INFO")]),
(Level::Debug, [level_token("DEBUG")]),
(Level::Trace, [level_token("TRACE")]),
];
for &(s, expected) in &cases {
assert_tokens(&s, &expected);
}
}
#[test]
fn test_level_case_insensitive() {
let cases = [
(Level::Error, [level_token("error")]),
(Level::Warn, [level_token("warn")]),
(Level::Info, [level_token("info")]),
(Level::Debug, [level_token("debug")]),
(Level::Trace, [level_token("trace")]),
];
for &(s, expected) in &cases {
assert_de_tokens(&s, &expected);
}
}
#[test]
fn test_level_de_bytes() {
let cases = [
(Level::Error, level_bytes_tokens(b"ERROR")),
(Level::Warn, level_bytes_tokens(b"WARN")),
(Level::Info, level_bytes_tokens(b"INFO")),
(Level::Debug, level_bytes_tokens(b"DEBUG")),
(Level::Trace, level_bytes_tokens(b"TRACE")),
];
for &(value, tokens) in &cases {
assert_de_tokens(&value, &tokens);
}
}
#[test]
fn test_level_de_error() {
let msg = "unknown variant `errorx`, expected one of \
`ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE`";
assert_de_tokens_error::<Level>(&[level_token("errorx")], msg);
}
#[test]
fn test_level_filter_ser_de() {
let cases = [
(LevelFilter::Off, [level_filter_token("OFF")]),
(LevelFilter::Error, [level_filter_token("ERROR")]),
(LevelFilter::Warn, [level_filter_token("WARN")]),
(LevelFilter::Info, [level_filter_token("INFO")]),
(LevelFilter::Debug, [level_filter_token("DEBUG")]),
(LevelFilter::Trace, [level_filter_token("TRACE")]),
];
for &(s, expected) in &cases {
assert_tokens(&s, &expected);
}
}
#[test]
fn test_level_filter_case_insensitive() {
let cases = [
(LevelFilter::Off, [level_filter_token("off")]),
(LevelFilter::Error, [level_filter_token("error")]),
(LevelFilter::Warn, [level_filter_token("warn")]),
(LevelFilter::Info, [level_filter_token("info")]),
(LevelFilter::Debug, [level_filter_token("debug")]),
(LevelFilter::Trace, [level_filter_token("trace")]),
];
for &(s, expected) in &cases {
assert_de_tokens(&s, &expected);
}
}
#[test]
fn test_level_filter_de_bytes() {
let cases = [
(LevelFilter::Off, level_filter_bytes_tokens(b"OFF")),
(LevelFilter::Error, level_filter_bytes_tokens(b"ERROR")),
(LevelFilter::Warn, level_filter_bytes_tokens(b"WARN")),
(LevelFilter::Info, level_filter_bytes_tokens(b"INFO")),
(LevelFilter::Debug, level_filter_bytes_tokens(b"DEBUG")),
(LevelFilter::Trace, level_filter_bytes_tokens(b"TRACE")),
];
for &(value, tokens) in &cases {
assert_de_tokens(&value, &tokens);
}
}
#[test]
fn test_level_filter_de_error() {
let msg = "unknown variant `errorx`, expected one of \
`OFF`, `ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE`";
assert_de_tokens_error::<LevelFilter>(&[level_filter_token("errorx")], msg);
}
}
#![cfg(feature = "serde")]
extern crate serde;
use self::serde::de::{
Deserialize, DeserializeSeed, Deserializer, EnumAccess, Error, Unexpected, VariantAccess,
Visitor,
};
use self::serde::ser::{Serialize, Serializer};
use {Level, LevelFilter, LOG_LEVEL_NAMES};
use std::fmt;
use std::str::{self, FromStr};
// The Deserialize impls are handwritten to be case insensitive using FromStr.
impl Serialize for Level {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
Level::Error => serializer.serialize_unit_variant("Level", 0, "ERROR"),
Level::Warn => serializer.serialize_unit_variant("Level", 1, "WARN"),
Level::Info => serializer.serialize_unit_variant("Level", 2, "INFO"),
Level::Debug => serializer.serialize_unit_variant("Level", 3, "DEBUG"),
Level::Trace => serializer.serialize_unit_variant("Level", 4, "TRACE"),
}
}
}
impl<'de> Deserialize<'de> for Level {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct LevelIdentifier;
impl<'de> Visitor<'de> for LevelIdentifier {
type Value = Level;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("log level")
}
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
where
E: Error,
{
// Case insensitive.
FromStr::from_str(s).map_err(|_| Error::unknown_variant(s, &LOG_LEVEL_NAMES[1..]))
}
fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
where
E: Error,
{
let variant = str::from_utf8(value)
.map_err(|_| Error::invalid_value(Unexpected::Bytes(value), &self))?;
self.visit_str(variant)
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where
E: Error,
{
let variant = LOG_LEVEL_NAMES[1..]
.get(v as usize)
.ok_or_else(|| Error::invalid_value(Unexpected::Unsigned(v), &self))?;
self.visit_str(variant)
}
}
impl<'de> DeserializeSeed<'de> for LevelIdentifier {
type Value = Level;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_identifier(LevelIdentifier)
}
}
struct LevelEnum;
impl<'de> Visitor<'de> for LevelEnum {
type Value = Level;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("log level")
}
fn visit_enum<A>(self, value: A) -> Result<Self::Value, A::Error>
where
A: EnumAccess<'de>,
{
let (level, variant) = value.variant_seed(LevelIdentifier)?;
// Every variant is a unit variant.
variant.unit_variant()?;
Ok(level)
}
}
deserializer.deserialize_enum("Level", &LOG_LEVEL_NAMES[1..], LevelEnum)
}
}
impl Serialize for LevelFilter {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
LevelFilter::Off => serializer.serialize_unit_variant("LevelFilter", 0, "OFF"),
LevelFilter::Error => serializer.serialize_unit_variant("LevelFilter", 1, "ERROR"),
LevelFilter::Warn => serializer.serialize_unit_variant("LevelFilter", 2, "WARN"),
LevelFilter::Info => serializer.serialize_unit_variant("LevelFilter", 3, "INFO"),
LevelFilter::Debug => serializer.serialize_unit_variant("LevelFilter", 4, "DEBUG"),
LevelFilter::Trace => serializer.serialize_unit_variant("LevelFilter", 5, "TRACE"),
}
}
}
impl<'de> Deserialize<'de> for LevelFilter {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct LevelFilterIdentifier;
impl<'de> Visitor<'de> for LevelFilterIdentifier {
type Value = LevelFilter;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("log level filter")
}
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
where
E: Error,
{
// Case insensitive.
FromStr::from_str(s).map_err(|_| Error::unknown_variant(s, &LOG_LEVEL_NAMES))
}
fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
where
E: Error,
{
let variant = str::from_utf8(value)
.map_err(|_| Error::invalid_value(Unexpected::Bytes(value), &self))?;
self.visit_str(variant)
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where
E: Error,
{
let variant = LOG_LEVEL_NAMES
.get(v as usize)
.ok_or_else(|| Error::invalid_value(Unexpected::Unsigned(v), &self))?;
self.visit_str(variant)
}
}
impl<'de> DeserializeSeed<'de> for LevelFilterIdentifier {
type Value = LevelFilter;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_identifier(LevelFilterIdentifier)
}
}
struct LevelFilterEnum;
impl<'de> Visitor<'de> for LevelFilterEnum {
type Value = LevelFilter;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("log level filter")
}
fn visit_enum<A>(self, value: A) -> Result<Self::Value, A::Error>
where
A: EnumAccess<'de>,
{
let (level_filter, variant) = value.variant_seed(LevelFilterIdentifier)?;
// Every variant is a unit variant.
variant.unit_variant()?;
Ok(level_filter)
}
}
deserializer.deserialize_enum("LevelFilter", &LOG_LEVEL_NAMES, LevelFilterEnum)
}
}
#[cfg(test)]
mod tests {
extern crate serde_test;
use self::serde_test::{assert_de_tokens, assert_de_tokens_error, assert_tokens, Token};
use {Level, LevelFilter};
fn level_token(variant: &'static str) -> Token {
Token::UnitVariant {
name: "Level",
variant: variant,
}
}
fn level_bytes_tokens(variant: &'static [u8]) -> [Token; 3] {
[
Token::Enum { name: "Level" },
Token::Bytes(variant),
Token::Unit,
]
}
fn level_variant_tokens(variant: u32) -> [Token; 3] {
[
Token::Enum { name: "Level" },
Token::U32(variant),
Token::Unit,
]
}
fn level_filter_token(variant: &'static str) -> Token {
Token::UnitVariant {
name: "LevelFilter",
variant: variant,
}
}
fn level_filter_bytes_tokens(variant: &'static [u8]) -> [Token; 3] {
[
Token::Enum {
name: "LevelFilter",
},
Token::Bytes(variant),
Token::Unit,
]
}
fn level_filter_variant_tokens(variant: u32) -> [Token; 3] {
[
Token::Enum {
name: "LevelFilter",
},
Token::U32(variant),
Token::Unit,
]
}
#[test]
fn test_level_ser_de() {
let cases = [
(Level::Error, [level_token("ERROR")]),
(Level::Warn, [level_token("WARN")]),
(Level::Info, [level_token("INFO")]),
(Level::Debug, [level_token("DEBUG")]),
(Level::Trace, [level_token("TRACE")]),
];
for &(s, expected) in &cases {
assert_tokens(&s, &expected);
}
}
#[test]
fn test_level_case_insensitive() {
let cases = [
(Level::Error, [level_token("error")]),
(Level::Warn, [level_token("warn")]),
(Level::Info, [level_token("info")]),
(Level::Debug, [level_token("debug")]),
(Level::Trace, [level_token("trace")]),
];
for &(s, expected) in &cases {
assert_de_tokens(&s, &expected);
}
}
#[test]
fn test_level_de_bytes() {
let cases = [
(Level::Error, level_bytes_tokens(b"ERROR")),
(Level::Warn, level_bytes_tokens(b"WARN")),
(Level::Info, level_bytes_tokens(b"INFO")),
(Level::Debug, level_bytes_tokens(b"DEBUG")),
(Level::Trace, level_bytes_tokens(b"TRACE")),
];
for &(value, tokens) in &cases {
assert_de_tokens(&value, &tokens);
}
}
#[test]
fn test_level_de_variant_index() {
let cases = [
(Level::Error, level_variant_tokens(0)),
(Level::Warn, level_variant_tokens(1)),
(Level::Info, level_variant_tokens(2)),
(Level::Debug, level_variant_tokens(3)),
(Level::Trace, level_variant_tokens(4)),
];
for &(value, tokens) in &cases {
assert_de_tokens(&value, &tokens);
}
}
#[test]
fn test_level_de_error() {
let msg = "unknown variant `errorx`, expected one of \
`ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE`";
assert_de_tokens_error::<Level>(&[level_token("errorx")], msg);
}
#[test]
fn test_level_filter_ser_de() {
let cases = [
(LevelFilter::Off, [level_filter_token("OFF")]),
(LevelFilter::Error, [level_filter_token("ERROR")]),
(LevelFilter::Warn, [level_filter_token("WARN")]),
(LevelFilter::Info, [level_filter_token("INFO")]),
(LevelFilter::Debug, [level_filter_token("DEBUG")]),
(LevelFilter::Trace, [level_filter_token("TRACE")]),
];
for &(s, expected) in &cases {
assert_tokens(&s, &expected);
}
}
#[test]
fn test_level_filter_case_insensitive() {
let cases = [
(LevelFilter::Off, [level_filter_token("off")]),
(LevelFilter::Error, [level_filter_token("error")]),
(LevelFilter::Warn, [level_filter_token("warn")]),
(LevelFilter::Info, [level_filter_token("info")]),
(LevelFilter::Debug, [level_filter_token("debug")]),
(LevelFilter::Trace, [level_filter_token("trace")]),
];
for &(s, expected) in &cases {
assert_de_tokens(&s, &expected);
}
}
#[test]
fn test_level_filter_de_bytes() {
let cases = [
(LevelFilter::Off, level_filter_bytes_tokens(b"OFF")),
(LevelFilter::Error, level_filter_bytes_tokens(b"ERROR")),
(LevelFilter::Warn, level_filter_bytes_tokens(b"WARN")),
(LevelFilter::Info, level_filter_bytes_tokens(b"INFO")),
(LevelFilter::Debug, level_filter_bytes_tokens(b"DEBUG")),
(LevelFilter::Trace, level_filter_bytes_tokens(b"TRACE")),
];
for &(value, tokens) in &cases {
assert_de_tokens(&value, &tokens);
}
}
#[test]
fn test_level_filter_de_variant_index() {
let cases = [
(LevelFilter::Off, level_filter_variant_tokens(0)),
(LevelFilter::Error, level_filter_variant_tokens(1)),
(LevelFilter::Warn, level_filter_variant_tokens(2)),
(LevelFilter::Info, level_filter_variant_tokens(3)),
(LevelFilter::Debug, level_filter_variant_tokens(4)),
(LevelFilter::Trace, level_filter_variant_tokens(5)),
];
for &(value, tokens) in &cases {
assert_de_tokens(&value, &tokens);
}
}
#[test]
fn test_level_filter_de_error() {
let msg = "unknown variant `errorx`, expected one of \
`OFF`, `ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE`";
assert_de_tokens_error::<LevelFilter>(&[level_filter_token("errorx")], msg);
}
}

View File

@ -1,72 +0,0 @@
#[macro_use]
extern crate log;
use log::{Level, LevelFilter, Log, Metadata, Record};
use std::sync::{Arc, Mutex};
#[cfg(feature = "std")]
use log::set_boxed_logger;
#[cfg(not(feature = "std"))]
fn set_boxed_logger(logger: Box<Log>) -> Result<(), log::SetLoggerError> {
log::set_logger(unsafe { &*Box::into_raw(logger) })
}
struct State {
last_log: Mutex<Option<Level>>,
}
struct Logger(Arc<State>);
impl Log for Logger {
fn enabled(&self, _: &Metadata) -> bool {
true
}
fn log(&self, record: &Record) {
*self.0.last_log.lock().unwrap() = Some(record.level());
}
fn flush(&self) {}
}
fn main() {
let me = Arc::new(State {
last_log: Mutex::new(None),
});
let a = me.clone();
set_boxed_logger(Box::new(Logger(me))).unwrap();
test(&a, LevelFilter::Off);
test(&a, LevelFilter::Error);
test(&a, LevelFilter::Warn);
test(&a, LevelFilter::Info);
test(&a, LevelFilter::Debug);
test(&a, LevelFilter::Trace);
}
fn test(a: &State, filter: LevelFilter) {
log::set_max_level(filter);
error!("");
last(&a, t(Level::Error, filter));
warn!("");
last(&a, t(Level::Warn, filter));
info!("");
last(&a, t(Level::Info, filter));
debug!("");
last(&a, t(Level::Debug, filter));
trace!("");
last(&a, t(Level::Trace, filter));
fn t(lvl: Level, filter: LevelFilter) -> Option<Level> {
if lvl <= filter {
Some(lvl)
} else {
None
}
}
}
fn last(state: &State, expected: Option<Level>) {
let lvl = state.last_log.lock().unwrap().take();
assert_eq!(lvl, expected);
}

1
third_party/rust/log/triagebot.toml vendored Normal file
View File

@ -0,0 +1 @@
[assign]