Upgrade rust/crates/log to 0.4.14

Test: make
Change-Id: I5abe243d26889b36f56963e9a9d22185dd5b9558
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index f8f6640..798cd7f 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
 {
   "git": {
-    "sha1": "aa4c0375cd94ed4d1b5de7ce0bb3369262dae7e2"
+    "sha1": "9d4206770dd93f07cb27c3e1f41dc21c45031302"
   }
 }
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index ed53c52..9a8f9aa 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -40,8 +40,9 @@
     - run: cargo test --verbose --features serde

     - run: cargo test --verbose --features std

     - run: cargo test --verbose --features kv_unstable

-    - run: cargo test --verbose --features "kv_unstable std"

-    - run: cargo test --verbose --features "kv_unstable_sval"

+    - run: cargo test --verbose --features kv_unstable_sval

+    - run: cargo test --verbose --features kv_unstable_serde

+    - run: cargo test --verbose --features "kv_unstable kv_unstable_std kv_unstable_sval kv_unstable_serde"

     - run: cargo run --verbose --manifest-path test_max_level_features/Cargo.toml

     - run: cargo run --verbose --manifest-path test_max_level_features/Cargo.toml --release

 

@@ -57,6 +58,22 @@
         rustup component add rustfmt

     - run: cargo fmt -- --check

 

+  features:

+    name: Feature check

+    runs-on: ubuntu-latest

+    steps:

+      - uses: actions/checkout@master

+      - name: Install Rust

+        run: |

+          rustup update nightly --no-self-update

+          rustup default nightly

+      - run: cargo build --verbose -Z avoid-dev-deps --features kv_unstable

+      - run: cargo build --verbose -Z avoid-dev-deps --features "kv_unstable std"

+      - run: cargo build --verbose -Z avoid-dev-deps --features "kv_unstable kv_unstable_sval"

+      - run: cargo build --verbose -Z avoid-dev-deps --features "kv_unstable kv_unstable_serde"

+      - run: cargo build --verbose -Z avoid-dev-deps --features "kv_unstable kv_unstable_std"

+      - run: cargo build --verbose -Z avoid-dev-deps --features "kv_unstable kv_unstable_sval kv_unstable_serde"

+

   msrv:

     name: MSRV

     runs-on: ubuntu-latest

@@ -69,6 +86,7 @@
       - run: cargo build --verbose

       - run: cargo build --verbose --features serde

       - run: cargo build --verbose --features std

+      - run: cargo test --verbose --manifest-path tests/Cargo.toml

 

   embedded:

     name: Embedded

@@ -79,5 +97,6 @@
         run: |

           rustup update stable --no-self-update

           rustup default stable

-      - run: rustup target add thumbv6m-none-eabi

+      - run: rustup target add thumbv6m-none-eabi riscv32imc-unknown-none-elf

       - run: cargo build --verbose --target=thumbv6m-none-eabi

+      - run: cargo build --verbose --target=riscv32imc-unknown-none-elf

diff --git a/Android.bp b/Android.bp
index 048de29..0b57b3c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,4 +1,5 @@
 // This file is generated by cargo2android.py --run --device --dependencies --features=std --patch=patches/Android.bp.diff.
+// Do not modify this file as changes will be overridden on upgrade.
 
 package {
     default_applicable_licenses: ["external_rust_crates_log_license"],
@@ -46,6 +47,7 @@
     features: ["std"],
     flags: [
         "--cfg atomic_cas",
+        "--cfg has_atomics",
     ],
     rustlibs: [
         "libcfg_if",
@@ -58,4 +60,4 @@
 }
 
 // dependent_library ["feature_list"]
-//   cfg-if-0.1.10
+//   cfg-if-1.0.0
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 296b49b..63c3ccd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,32 @@
 

 ## [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

@@ -170,7 +196,10 @@
 

 Look at the [release tags] for information about older releases.

 

-[Unreleased]: https://github.com/rust-lang-nursery/log/compare/0.4.11...HEAD

+[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

diff --git a/Cargo.toml b/Cargo.toml
index bd654d2..3cbe5e0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,7 +12,7 @@
 
 [package]
 name = "log"
-version = "0.4.11"
+version = "0.4.14"
 authors = ["The Rust Project Developers"]
 build = "build.rs"
 exclude = ["rfcs/**/*", "/.travis.yml", "/appveyor.yml"]
@@ -24,17 +24,19 @@
 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"
@@ -42,19 +44,34 @@
 default-features = false
 
 [dependencies.sval]
-version = "0.5.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.5.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 = []
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 447469e..0d31859 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,7 +1,7 @@
 [package]

 

 name = "log"

-version = "0.4.11" # remember to update html_root_url

+version = "0.4.14" # remember to update html_root_url

 authors = ["The Rust Project Developers"]

 license = "MIT OR Apache-2.0"

 readme = "README.md"

@@ -16,14 +16,16 @@
 build = "build.rs"

 

 [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

 

 [features]

@@ -45,14 +47,19 @@
 

 # requires the latest stable

 # this will have a tighter MSRV before stabilization

-kv_unstable = []

-kv_unstable_sval = ["kv_unstable", "sval/fmt"]

+kv_unstable = ["value-bag"]

+kv_unstable_sval = ["kv_unstable", "value-bag/sval", "sval"]

+kv_unstable_std = ["std", "kv_unstable", "value-bag/error"]

+kv_unstable_serde = ["kv_unstable_std", "value-bag/serde", "serde"]

 

 [dependencies]

-cfg-if = "0.1.2"

+cfg-if = "1.0"

 serde = { version = "1.0", optional = true, default-features = false }

-sval = { version = "0.5.2", optional = true, default-features = false }

+sval = { version = "1.0.0-alpha.5", optional = true, default-features = false }

+value-bag = { version = "1.0.0-alpha.6", optional = true, default-features = false }

 

 [dev-dependencies]

+serde = { version = "1.0", features = ["derive"] }

 serde_test = "1.0"

-sval = { version = "0.5.2", features = ["test"] }

+sval = { version = "1.0.0-alpha.5", features = ["derive"] }

+value-bag = { version = "1.0.0-alpha.6", features = ["test"] }

diff --git a/METADATA b/METADATA
index 281092f..86f9298 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@
   }
   url {
     type: ARCHIVE
-    value: "https://static.crates.io/crates/log/log-0.4.11.crate"
+    value: "https://static.crates.io/crates/log/log-0.4.14.crate"
   }
-  version: "0.4.11"
+  version: "0.4.14"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2020
-    month: 7
-    day: 15
+    year: 2021
+    month: 4
+    day: 2
   }
 }
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 32a5803..1b7b681 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -1,14 +1,56 @@
-// Generated by cargo2android.py for tests in Android.bp
+// Generated by update_crate_tests.py for tests that depend on this crate.
 {
   "presubmit": [
     {
-      "name": "env_logger_device_test_src_lib"
+      "name": "env_logger_device_test_tests_regexp_filter"
+    },
+    {
+      "name": "env_logger_device_test_tests_log-in-log"
+    },
+    {
+      "name": "tokio-test_device_test_tests_macros"
+    },
+    {
+      "name": "keystore2_test"
+    },
+    {
+      "name": "vpnprofilestore_test"
+    },
+    {
+      "name": "tokio-test_device_test_src_lib"
+    },
+    {
+      "name": "libsqlite3-sys_device_test_src_lib"
+    },
+    {
+      "name": "keystore2_selinux_test"
     },
     {
       "name": "android_logger_device_test_src_lib"
     },
     {
-      "name": "libsqlite3-sys_device_test_src_lib"
+      "name": "env_logger_device_test_tests_log_tls_dtors"
+    },
+    {
+      "name": "tokio-test_device_test_tests_block_on"
+    },
+    {
+      "name": "futures-util_device_test_src_lib"
+    },
+    {
+      "name": "tokio-test_device_test_tests_io"
+    },
+    {
+      "name": "keystore2_crypto_test_rust"
+    },
+    {
+      "name": "env_logger_device_test_src_lib"
+    },
+    {
+      "name": "quiche_device_test_src_lib"
+    },
+    {
+      "name": "env_logger_device_test_tests_init-twice-retains-filter"
     }
   ]
 }
diff --git a/benches/value.rs b/benches/value.rs
new file mode 100644
index 0000000..3dab3bf
--- /dev/null
+++ b/benches/value.rs
@@ -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))

+}

diff --git a/build.rs b/build.rs
index 65d2398..22cfa78 100644
--- a/build.rs
+++ b/build.rs
@@ -2,13 +2,42 @@
 //! atomics and sets `cfg` flags accordingly.

 

 use std::env;

+use std::str;

 

 fn main() {

-    let target = env::var("TARGET").unwrap();

+    let target = match rustc_target() {

+        Some(target) => target,

+        None => return,

+    };

 

-    if !target.starts_with("thumbv6") {

+    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()

+}

diff --git a/patches/Android.bp.diff b/patches/Android.bp.diff
index f3cc736..f0de6f5 100644
--- a/patches/Android.bp.diff
+++ b/patches/Android.bp.diff
@@ -1,6 +1,6 @@
 --- Android.bp	2020-12-14 20:08:02.451621093 +0900
 +++ Android.bp.new	2020-12-14 20:05:44.460062409 +0900
-@@ -14,6 +14,11 @@ rust_library {
+@@ -50,6 +50,11 @@ rust_library {
      rustlibs: [
          "libcfg_if",
      ],
diff --git a/src/kv/key.rs b/src/kv/key.rs
index 367f6ed..0e688c1 100644
--- a/src/kv/key.rs
+++ b/src/kv/key.rs
@@ -128,6 +128,39 @@
     }

 }

 

+#[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::*;

diff --git a/src/kv/mod.rs b/src/kv/mod.rs
index f4c0866..f96b821 100644
--- a/src/kv/mod.rs
+++ b/src/kv/mod.rs
@@ -14,7 +14,7 @@
 

 mod error;

 mod key;

-mod source;

+pub mod source;

 

 pub mod value;

 

diff --git a/src/kv/source.rs b/src/kv/source.rs
index eeac1ec..e3ecde9 100644
--- a/src/kv/source.rs
+++ b/src/kv/source.rs
@@ -1,5 +1,11 @@
 //! Sources for key-value pairs.

 

+#[cfg(feature = "kv_unstable_sval")]

+extern crate sval;

+

+#[cfg(feature = "kv_unstable_serde")]

+extern crate serde;

+

 use kv::{Error, Key, ToKey, ToValue, Value};

 use std::fmt;

 

@@ -30,28 +36,14 @@
     ///

     /// A source that can provide a more efficient implementation of this method

     /// should override it.

+    #[cfg(not(test))]

     fn get<'v>(&'v self, key: Key) -> Option<Value<'v>> {

-        struct Get<'k, 'v> {

-            key: Key<'k>,

-            found: Option<Value<'v>>,

-        }

-

-        impl<'k, 'kvs> Visitor<'kvs> for Get<'k, 'kvs> {

-            fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> {

-                if self.key == key {

-                    self.found = Some(value);

-                }

-

-                Ok(())

-            }

-        }

-

-        let mut get = Get { key, found: None };

-

-        let _ = self.visit(&mut get);

-        get.found

+        get_default(self, key)

     }

 

+    #[cfg(test)]

+    fn get<'v>(&'v self, key: Key) -> Option<Value<'v>>;

+

     /// Count the number of key-value pairs that can be visited.

     ///

     /// # Implementation notes

@@ -61,21 +53,53 @@
     ///

     /// A subsequent call to `visit` should yield the same number of key-value pairs

     /// to the visitor, unless that visitor fails part way through.

+    #[cfg(not(test))]

     fn count(&self) -> usize {

-        struct Count(usize);

-

-        impl<'kvs> Visitor<'kvs> for Count {

-            fn visit_pair(&mut self, _: Key<'kvs>, _: Value<'kvs>) -> Result<(), Error> {

-                self.0 += 1;

-

-                Ok(())

-            }

-        }

-

-        let mut count = Count(0);

-        let _ = self.visit(&mut count);

-        count.0

+        count_default(self)

     }

+

+    #[cfg(test)]

+    fn count(&self) -> usize;

+}

+

+/// The default implemention of `Source::get`

+pub(crate) fn get_default<'v>(source: &'v (impl Source + ?Sized), key: Key) -> Option<Value<'v>> {

+    struct Get<'k, 'v> {

+        key: Key<'k>,

+        found: Option<Value<'v>>,

+    }

+

+    impl<'k, 'kvs> Visitor<'kvs> for Get<'k, 'kvs> {

+        fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> {

+            if self.key == key {

+                self.found = Some(value);

+            }

+

+            Ok(())

+        }

+    }

+

+    let mut get = Get { key, found: None };

+

+    let _ = source.visit(&mut get);

+    get.found

+}

+

+/// The default implementation of `Source::count`.

+pub(crate) fn count_default(source: impl Source) -> usize {

+    struct Count(usize);

+

+    impl<'kvs> Visitor<'kvs> for Count {

+        fn visit_pair(&mut self, _: Key<'kvs>, _: Value<'kvs>) -> Result<(), Error> {

+            self.0 += 1;

+

+            Ok(())

+        }

+    }

+

+    let mut count = Count(0);

+    let _ = source.visit(&mut count);

+    count.0

 }

 

 impl<'a, T> Source for &'a T

@@ -129,6 +153,16 @@
         Ok(())

     }

 

+    fn get<'v>(&'v self, key: Key) -> Option<Value<'v>> {

+        for source in self {

+            if let Some(found) = source.get(key.clone()) {

+                return Some(found);

+            }

+        }

+

+        None

+    }

+

     fn count(&self) -> usize {

         self.len()

     }

@@ -146,6 +180,10 @@
         Ok(())

     }

 

+    fn get<'v>(&'v self, key: Key) -> Option<Value<'v>> {

+        self.as_ref().and_then(|s| s.get(key))

+    }

+

     fn count(&self) -> usize {

         self.as_ref().map(Source::count).unwrap_or(0)

     }

@@ -291,7 +329,7 @@
     #[cfg(test)]

     mod tests {

         use super::*;

-        use kv::value::test::Token;

+        use kv::value::tests::Token;

         use std::collections::{BTreeMap, HashMap};

 

         #[test]

@@ -340,10 +378,313 @@
     }

 }

 

+/// The result of calling `Source::as_map`.

+pub struct AsMap<S>(S);

+

+/// Visit this source as a map.

+pub fn as_map<S>(source: S) -> AsMap<S>

+where

+    S: Source,

+{

+    AsMap(source)

+}

+

+impl<S> Source for AsMap<S>

+where

+    S: Source,

+{

+    fn visit<'kvs>(&'kvs self, visitor: &mut dyn Visitor<'kvs>) -> Result<(), Error> {

+        self.0.visit(visitor)

+    }

+

+    fn get<'v>(&'v self, key: Key) -> Option<Value<'v>> {

+        self.0.get(key)

+    }

+

+    fn count(&self) -> usize {

+        self.0.count()

+    }

+}

+

+impl<S> fmt::Debug for AsMap<S>

+where

+    S: Source,

+{

+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

+        let mut f = f.debug_map();

+        self.0.visit(&mut f).map_err(|_| fmt::Error)?;

+        f.finish()

+    }

+}

+

+/// The result of calling `Source::as_list`

+pub struct AsList<S>(S);

+

+/// Visit this source as a list.

+pub fn as_list<S>(source: S) -> AsList<S>

+where

+    S: Source,

+{

+    AsList(source)

+}

+

+impl<S> Source for AsList<S>

+where

+    S: Source,

+{

+    fn visit<'kvs>(&'kvs self, visitor: &mut dyn Visitor<'kvs>) -> Result<(), Error> {

+        self.0.visit(visitor)

+    }

+

+    fn get<'v>(&'v self, key: Key) -> Option<Value<'v>> {

+        self.0.get(key)

+    }

+

+    fn count(&self) -> usize {

+        self.0.count()

+    }

+}

+

+impl<S> fmt::Debug for AsList<S>

+where

+    S: Source,

+{

+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

+        let mut f = f.debug_list();

+        self.0.visit(&mut f).map_err(|_| fmt::Error)?;

+        f.finish()

+    }

+}

+

+#[cfg(feature = "kv_unstable_sval")]

+mod sval_support {

+    use super::*;

+

+    use self::sval::value;

+

+    impl<S> value::Value for AsMap<S>

+    where

+        S: Source,

+    {

+        fn stream(&self, stream: &mut value::Stream) -> value::Result {

+            struct StreamVisitor<'a, 'b>(&'a mut value::Stream<'b>);

+

+            impl<'a, 'b, 'kvs> Visitor<'kvs> for StreamVisitor<'a, 'b> {

+                fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> {

+                    self.0

+                        .map_key(key)

+                        .map_err(|_| Error::msg("failed to stream map key"))?;

+                    self.0

+                        .map_value(value)

+                        .map_err(|_| Error::msg("failed to stream map value"))?;

+                    Ok(())

+                }

+            }

+

+            stream

+                .map_begin(Some(self.count()))

+                .map_err(|_| self::sval::Error::msg("failed to begin map"))?;

+

+            self.visit(&mut StreamVisitor(stream))

+                .map_err(|_| self::sval::Error::msg("failed to visit key-values"))?;

+

+            stream

+                .map_end()

+                .map_err(|_| self::sval::Error::msg("failed to end map"))

+        }

+    }

+

+    impl<S> value::Value for AsList<S>

+    where

+        S: Source,

+    {

+        fn stream(&self, stream: &mut value::Stream) -> value::Result {

+            struct StreamVisitor<'a, 'b>(&'a mut value::Stream<'b>);

+

+            impl<'a, 'b, 'kvs> Visitor<'kvs> for StreamVisitor<'a, 'b> {

+                fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> {

+                    self.0

+                        .seq_elem((key, value))

+                        .map_err(|_| Error::msg("failed to stream seq entry"))?;

+                    Ok(())

+                }

+            }

+

+            stream

+                .seq_begin(Some(self.count()))

+                .map_err(|_| self::sval::Error::msg("failed to begin seq"))?;

+

+            self.visit(&mut StreamVisitor(stream))

+                .map_err(|_| self::sval::Error::msg("failed to visit key-values"))?;

+

+            stream

+                .seq_end()

+                .map_err(|_| self::sval::Error::msg("failed to end seq"))

+        }

+    }

+

+    #[cfg(test)]

+    mod tests {

+        use super::*;

+

+        use self::sval::Value;

+

+        use crate::kv::source;

+

+        #[test]

+        fn derive_stream() {

+            #[derive(Value)]

+            pub struct MyRecordAsMap<'a> {

+                msg: &'a str,

+                kvs: source::AsMap<&'a dyn Source>,

+            }

+

+            #[derive(Value)]

+            pub struct MyRecordAsList<'a> {

+                msg: &'a str,

+                kvs: source::AsList<&'a dyn Source>,

+            }

+        }

+    }

+}

+

+#[cfg(feature = "kv_unstable_serde")]

+pub mod as_map {

+    //! `serde` adapters for serializing a `Source` as a map.

+

+    use super::*;

+

+    use self::serde::{Serialize, Serializer};

+

+    /// Serialize a `Source` as a map.

+    pub fn serialize<T, S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>

+    where

+        T: Source,

+        S: Serializer,

+    {

+        as_map(source).serialize(serializer)

+    }

+}

+

+#[cfg(feature = "kv_unstable_serde")]

+pub mod as_list {

+    //! `serde` adapters for serializing a `Source` as a list.

+

+    use super::*;

+

+    use self::serde::{Serialize, Serializer};

+

+    /// Serialize a `Source` as a list.

+    pub fn serialize<T, S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>

+    where

+        T: Source,

+        S: Serializer,

+    {

+        as_list(source).serialize(serializer)

+    }

+}

+

+#[cfg(feature = "kv_unstable_serde")]

+mod serde_support {

+    use super::*;

+

+    use self::serde::ser::{Error as SerError, Serialize, SerializeMap, SerializeSeq, Serializer};

+

+    impl<T> Serialize for AsMap<T>

+    where

+        T: Source,

+    {

+        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>

+        where

+            S: Serializer,

+        {

+            struct SerializerVisitor<'a, S>(&'a mut S);

+

+            impl<'a, 'kvs, S> Visitor<'kvs> for SerializerVisitor<'a, S>

+            where

+                S: SerializeMap,

+            {

+                fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> {

+                    self.0

+                        .serialize_entry(&key, &value)

+                        .map_err(|_| Error::msg("failed to serialize map entry"))?;

+                    Ok(())

+                }

+            }

+

+            let mut map = serializer.serialize_map(Some(self.count()))?;

+

+            self.visit(&mut SerializerVisitor(&mut map))

+                .map_err(|_| S::Error::custom("failed to visit key-values"))?;

+

+            map.end()

+        }

+    }

+

+    impl<T> Serialize for AsList<T>

+    where

+        T: Source,

+    {

+        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>

+        where

+            S: Serializer,

+        {

+            struct SerializerVisitor<'a, S>(&'a mut S);

+

+            impl<'a, 'kvs, S> Visitor<'kvs> for SerializerVisitor<'a, S>

+            where

+                S: SerializeSeq,

+            {

+                fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> {

+                    self.0

+                        .serialize_element(&(key, value))

+                        .map_err(|_| Error::msg("failed to serialize seq entry"))?;

+                    Ok(())

+                }

+            }

+

+            let mut seq = serializer.serialize_seq(Some(self.count()))?;

+

+            self.visit(&mut SerializerVisitor(&mut seq))

+                .map_err(|_| S::Error::custom("failed to visit seq"))?;

+

+            seq.end()

+        }

+    }

+

+    #[cfg(test)]

+    mod tests {

+        use super::*;

+

+        use self::serde::Serialize;

+

+        use crate::kv::source;

+

+        #[test]

+        fn derive_serialize() {

+            #[derive(Serialize)]

+            pub struct MyRecordAsMap<'a> {

+                msg: &'a str,

+                #[serde(flatten)]

+                #[serde(with = "source::as_map")]

+                kvs: &'a dyn Source,

+            }

+

+            #[derive(Serialize)]

+            pub struct MyRecordAsList<'a> {

+                msg: &'a str,

+                #[serde(flatten)]

+                #[serde(with = "source::as_list")]

+                kvs: &'a dyn Source,

+            }

+        }

+    }

+}

+

 #[cfg(test)]

 mod tests {

     use super::*;

-    use kv::value::test::Token;

+    use kv::value::tests::Token;

 

     #[test]

     fn source_is_object_safe() {

@@ -366,6 +707,14 @@
             fn visit<'kvs>(&'kvs self, visitor: &mut dyn Visitor<'kvs>) -> Result<(), Error> {

                 visitor.visit_pair(self.key.to_key(), self.value.to_value())

             }

+

+            fn get<'v>(&'v self, key: Key) -> Option<Value<'v>> {

+                get_default(self, key)

+            }

+

+            fn count(&self) -> usize {

+                count_default(self)

+            }

         }

 

         assert_eq!(1, Source::count(&("a", 1)));

@@ -390,4 +739,16 @@
         let source = Option::None::<(&str, i32)>;

         assert!(Source::get(&source, Key::from_str("a")).is_none());

     }

+

+    #[test]

+    fn as_map() {

+        let _ = crate::kv::source::as_map(("a", 1));

+        let _ = crate::kv::source::as_map(&("a", 1) as &dyn Source);

+    }

+

+    #[test]

+    fn as_list() {

+        let _ = crate::kv::source::as_list(("a", 1));

+        let _ = crate::kv::source::as_list(&("a", 1) as &dyn Source);

+    }

 }

diff --git a/src/kv/value.rs b/src/kv/value.rs
new file mode 100644
index 0000000..942d59e
--- /dev/null
+++ b/src/kv/value.rs
@@ -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);

+    }

+}

diff --git a/src/kv/value/fill.rs b/src/kv/value/fill.rs
deleted file mode 100644
index 2e74899..0000000
--- a/src/kv/value/fill.rs
+++ /dev/null
@@ -1,164 +0,0 @@
-//! Lazy value initialization.

-

-use std::fmt;

-

-use super::internal::{Erased, Inner, Visitor};

-use super::{Error, Value};

-

-impl<'v> Value<'v> {

-    /// Get a value from a fillable slot.

-    pub fn from_fill<T>(value: &'v T) -> Self

-    where

-        T: Fill + 'static,

-    {

-        Value {

-            inner: Inner::Fill(unsafe { Erased::new_unchecked::<T>(value) }),

-        }

-    }

-}

-

-/// 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<'s, 'f> {

-    filled: bool,

-    visitor: &'s mut dyn Visitor<'f>,

-}

-

-impl<'s, 'f> fmt::Debug for Slot<'s, 'f> {

-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

-        f.debug_struct("Slot").finish()

-    }

-}

-

-impl<'s, 'f> Slot<'s, 'f> {

-    pub(super) fn new(visitor: &'s mut dyn Visitor<'f>) -> Self {

-        Slot {

-            visitor,

-            filled: false,

-        }

-    }

-

-    pub(super) fn fill<F>(&mut self, f: F) -> Result<(), Error>

-    where

-        F: FnOnce(&mut dyn Visitor<'f>) -> Result<(), Error>,

-    {

-        assert!(!self.filled, "the slot has already been filled");

-        self.filled = true;

-

-        f(self.visitor)

-    }

-

-    /// Fill the slot with a value.

-    ///

-    /// The given value doesn't need to satisfy any particular lifetime constraints.

-    ///

-    /// # Panics

-    ///

-    /// Calling more than a single `fill` method on this slot will panic.

-    pub fn fill_any<T>(&mut self, value: T) -> Result<(), Error>

-    where

-        T: Into<Value<'f>>,

-    {

-        self.fill(|visitor| value.into().inner.visit(visitor))

-    }

-}

-

-#[cfg(test)]

-mod tests {

-    use super::*;

-

-    #[test]

-    fn fill_value_borrowed() {

-        struct TestFill;

-

-        impl Fill for TestFill {

-            fn fill(&self, slot: &mut Slot) -> Result<(), Error> {

-                let dbg: &dyn fmt::Debug = &1;

-

-                slot.fill_debug(&dbg)

-            }

-        }

-

-        assert_eq!("1", Value::from_fill(&TestFill).to_string());

-    }

-

-    #[test]

-    fn fill_value_owned() {

-        struct TestFill;

-

-        impl Fill for TestFill {

-            fn fill(&self, slot: &mut Slot) -> Result<(), Error> {

-                slot.fill_any("a 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_any(42)?;

-                slot.fill_any(6789)?;

-

-                Ok(())

-            }

-        }

-

-        let _ = Value::from_fill(&BadFill).to_string();

-    }

-

-    #[test]

-    fn fill_cast() {

-        struct TestFill;

-

-        impl Fill for TestFill {

-            fn fill(&self, slot: &mut Slot) -> Result<(), Error> {

-                slot.fill_any("a string")

-            }

-        }

-

-        assert_eq!(

-            "a string",

-            Value::from_fill(&TestFill)

-                .to_borrowed_str()

-                .expect("invalid value")

-        );

-    }

-

-    #[test]

-    fn fill_debug() {

-        struct TestFill;

-

-        impl Fill for TestFill {

-            fn fill(&self, slot: &mut Slot) -> Result<(), Error> {

-                slot.fill_any(42u64)

-            }

-        }

-

-        assert_eq!(

-            format!("{:04?}", 42u64),

-            format!("{:04?}", Value::from_fill(&TestFill)),

-        )

-    }

-}

diff --git a/src/kv/value/impls.rs b/src/kv/value/impls.rs
deleted file mode 100644
index 8752dbe..0000000
--- a/src/kv/value/impls.rs
+++ /dev/null
@@ -1,159 +0,0 @@
-//! Converting standard types into `Value`s.

-//!

-//! This module provides `ToValue` implementations for commonly

-//! logged types from the standard library.

-

-use std::fmt;

-

-use super::{Primitive, ToValue, Value};

-

-macro_rules! impl_into_owned {

-    ($($into_ty:ty => $convert:ident,)*) => {

-        $(

-            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_primitive(value as $convert)

-                }

-            }

-        )*

-    };

-}

-

-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(value)

-    }

-}

-

-impl<'v> ToValue for fmt::Arguments<'v> {

-    fn to_value(&self) -> Value {

-        Value::from(*self)

-    }

-}

-

-impl<'v> From<fmt::Arguments<'v>> for Value<'v> {

-    fn from(value: fmt::Arguments<'v>) -> Self {

-        Value::from_primitive(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_into_owned! [

-    usize => u64,

-    u8 => u64,

-    u16 => u64,

-    u32 => u64,

-    u64 => u64,

-

-    isize => i64,

-    i8 => i64,

-    i16 => i64,

-    i32 => i64,

-    i64 => i64,

-

-    f32 => f64,

-    f64 => f64,

-

-    char => char,

-    bool => bool,

-];

-

-#[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);

-    }

-}

diff --git a/src/kv/value/internal/cast.rs b/src/kv/value/internal/cast.rs
deleted file mode 100644
index aaa4b07..0000000
--- a/src/kv/value/internal/cast.rs
+++ /dev/null
@@ -1,475 +0,0 @@
-//! Coerce a `Value` into some concrete types.

-//!

-//! These operations are cheap when the captured value is a simple primitive,

-//! but may end up executing arbitrary caller code if the value is complex.

-//! They will also attempt to downcast erased types into a primitive where possible.

-

-use std::any::TypeId;

-use std::fmt;

-

-use super::{Erased, Inner, Primitive, Visitor};

-use crate::kv::value::{Error, Value};

-

-impl<'v> Value<'v> {

-    /// Try get a `usize` from this value.

-    ///

-    /// This method is cheap for primitive types, but may call arbitrary

-    /// serialization implementations for complex ones.

-    pub fn to_usize(&self) -> Option<usize> {

-        self.inner

-            .cast()

-            .into_primitive()

-            .into_u64()

-            .map(|v| v as usize)

-    }

-

-    /// Try get a `u8` from this value.

-    ///

-    /// This method is cheap for primitive types, but may call arbitrary

-    /// serialization implementations for complex ones.

-    pub fn to_u8(&self) -> Option<u8> {

-        self.inner

-            .cast()

-            .into_primitive()

-            .into_u64()

-            .map(|v| v as u8)

-    }

-

-    /// Try get a `u16` from this value.

-    ///

-    /// This method is cheap for primitive types, but may call arbitrary

-    /// serialization implementations for complex ones.

-    pub fn to_u16(&self) -> Option<u16> {

-        self.inner

-            .cast()

-            .into_primitive()

-            .into_u64()

-            .map(|v| v as u16)

-    }

-

-    /// Try get a `u32` from this value.

-    ///

-    /// This method is cheap for primitive types, but may call arbitrary

-    /// serialization implementations for complex ones.

-    pub fn to_u32(&self) -> Option<u32> {

-        self.inner

-            .cast()

-            .into_primitive()

-            .into_u64()

-            .map(|v| v as u32)

-    }

-

-    /// Try get a `u64` from this value.

-    ///

-    /// This method is cheap for primitive types, but may call arbitrary

-    /// serialization implementations for complex ones.

-    pub fn to_u64(&self) -> Option<u64> {

-        self.inner.cast().into_primitive().into_u64()

-    }

-

-    /// Try get a `isize` from this value.

-    ///

-    /// This method is cheap for primitive types, but may call arbitrary

-    /// serialization implementations for complex ones.

-    pub fn to_isize(&self) -> Option<isize> {

-        self.inner

-            .cast()

-            .into_primitive()

-            .into_i64()

-            .map(|v| v as isize)

-    }

-

-    /// Try get a `i8` from this value.

-    ///

-    /// This method is cheap for primitive types, but may call arbitrary

-    /// serialization implementations for complex ones.

-    pub fn to_i8(&self) -> Option<i8> {

-        self.inner

-            .cast()

-            .into_primitive()

-            .into_i64()

-            .map(|v| v as i8)

-    }

-

-    /// Try get a `i16` from this value.

-    ///

-    /// This method is cheap for primitive types, but may call arbitrary

-    /// serialization implementations for complex ones.

-    pub fn to_i16(&self) -> Option<i16> {

-        self.inner

-            .cast()

-            .into_primitive()

-            .into_i64()

-            .map(|v| v as i16)

-    }

-

-    /// Try get a `i32` from this value.

-    ///

-    /// This method is cheap for primitive types, but may call arbitrary

-    /// serialization implementations for complex ones.

-    pub fn to_i32(&self) -> Option<i32> {

-        self.inner

-            .cast()

-            .into_primitive()

-            .into_i64()

-            .map(|v| v as i32)

-    }

-

-    /// Try get a `i64` from this value.

-    ///

-    /// This method is cheap for primitive types, but may call arbitrary

-    /// serialization implementations for complex ones.

-    pub fn to_i64(&self) -> Option<i64> {

-        self.inner.cast().into_primitive().into_i64()

-    }

-

-    /// Try get a `f32` from this value.

-    ///

-    /// This method is cheap for primitive types, but may call arbitrary

-    /// serialization implementations for complex ones.

-    pub fn to_f32(&self) -> Option<f32> {

-        self.inner

-            .cast()

-            .into_primitive()

-            .into_f64()

-            .map(|v| v as f32)

-    }

-

-    /// Try get a `f64` from this value.

-    ///

-    /// This method is cheap for primitive types, but may call arbitrary

-    /// serialization implementations for complex ones.

-    pub fn to_f64(&self) -> Option<f64> {

-        self.inner.cast().into_primitive().into_f64()

-    }

-

-    /// Try get a `bool` from this value.

-    ///

-    /// This method is cheap for primitive types, but may call arbitrary

-    /// serialization implementations for complex ones.

-    pub fn to_bool(&self) -> Option<bool> {

-        self.inner.cast().into_primitive().into_bool()

-    }

-

-    /// Try get a `char` from this value.

-    ///

-    /// This method is cheap for primitive types, but may call arbitrary

-    /// serialization implementations for complex ones.

-    pub fn to_char(&self) -> Option<char> {

-        self.inner.cast().into_primitive().into_char()

-    }

-

-    /// Try get a `str` from this value.

-    ///

-    /// This method is cheap for primitive types. It won't allocate an owned

-    /// `String` if the value is a complex type.

-    pub fn to_borrowed_str(&self) -> Option<&str> {

-        self.inner.cast().into_primitive().into_borrowed_str()

-    }

-}

-

-impl<'v> Inner<'v> {

-    /// Cast the inner value to another type.

-    fn cast(self) -> Cast<'v> {

-        struct CastVisitor<'v>(Cast<'v>);

-

-        impl<'v> Visitor<'v> for CastVisitor<'v> {

-            fn debug(&mut self, _: &dyn fmt::Debug) -> Result<(), Error> {

-                Ok(())

-            }

-

-            fn u64(&mut self, v: u64) -> Result<(), Error> {

-                self.0 = Cast::Primitive(Primitive::Unsigned(v));

-                Ok(())

-            }

-

-            fn i64(&mut self, v: i64) -> Result<(), Error> {

-                self.0 = Cast::Primitive(Primitive::Signed(v));

-                Ok(())

-            }

-

-            fn f64(&mut self, v: f64) -> Result<(), Error> {

-                self.0 = Cast::Primitive(Primitive::Float(v));

-                Ok(())

-            }

-

-            fn bool(&mut self, v: bool) -> Result<(), Error> {

-                self.0 = Cast::Primitive(Primitive::Bool(v));

-                Ok(())

-            }

-

-            fn char(&mut self, v: char) -> Result<(), Error> {

-                self.0 = Cast::Primitive(Primitive::Char(v));

-                Ok(())

-            }

-

-            fn borrowed_str(&mut self, v: &'v str) -> Result<(), Error> {

-                self.0 = Cast::Primitive(Primitive::Str(v));

-                Ok(())

-            }

-

-            #[cfg(not(feature = "std"))]

-            fn str(&mut self, _: &str) -> Result<(), Error> {

-                Ok(())

-            }

-

-            #[cfg(feature = "std")]

-            fn str(&mut self, v: &str) -> Result<(), Error> {

-                self.0 = Cast::String(v.into());

-                Ok(())

-            }

-

-            fn none(&mut self) -> Result<(), Error> {

-                self.0 = Cast::Primitive(Primitive::None);

-                Ok(())

-            }

-

-            #[cfg(feature = "kv_unstable_sval")]

-            fn sval(&mut self, v: &dyn super::sval::Value) -> Result<(), Error> {

-                self.0 = super::sval::cast(v);

-                Ok(())

-            }

-        }

-

-        // Try downcast an erased value first

-        // It also lets us avoid the Visitor infrastructure for simple primitives

-        let primitive = match self {

-            Inner::Primitive(value) => Some(value),

-            Inner::Fill(value) => value.downcast_primitive(),

-            Inner::Debug(value) => value.downcast_primitive(),

-            Inner::Display(value) => value.downcast_primitive(),

-

-            #[cfg(feature = "sval")]

-            Inner::Sval(value) => value.downcast_primitive(),

-        };

-

-        primitive.map(Cast::Primitive).unwrap_or_else(|| {

-            // If the erased value isn't a primitive then we visit it

-            let mut cast = CastVisitor(Cast::Primitive(Primitive::None));

-            let _ = self.visit(&mut cast);

-            cast.0

-        })

-    }

-}

-

-pub(super) enum Cast<'v> {

-    Primitive(Primitive<'v>),

-    #[cfg(feature = "std")]

-    String(String),

-}

-

-impl<'v> Cast<'v> {

-    fn into_primitive(self) -> Primitive<'v> {

-        match self {

-            Cast::Primitive(value) => value,

-            #[cfg(feature = "std")]

-            _ => Primitive::None,

-        }

-    }

-}

-

-impl<'v> Primitive<'v> {

-    fn into_borrowed_str(self) -> Option<&'v str> {

-        if let Primitive::Str(value) = self {

-            Some(value)

-        } else {

-            None

-        }

-    }

-

-    fn into_u64(self) -> Option<u64> {

-        match self {

-            Primitive::Unsigned(value) => Some(value),

-            Primitive::Signed(value) => Some(value as u64),

-            Primitive::Float(value) => Some(value as u64),

-            _ => None,

-        }

-    }

-

-    fn into_i64(self) -> Option<i64> {

-        match self {

-            Primitive::Signed(value) => Some(value),

-            Primitive::Unsigned(value) => Some(value as i64),

-            Primitive::Float(value) => Some(value as i64),

-            _ => None,

-        }

-    }

-

-    fn into_f64(self) -> Option<f64> {

-        match self {

-            Primitive::Float(value) => Some(value),

-            Primitive::Unsigned(value) => Some(value as f64),

-            Primitive::Signed(value) => Some(value as f64),

-            _ => None,

-        }

-    }

-

-    fn into_char(self) -> Option<char> {

-        if let Primitive::Char(value) = self {

-            Some(value)

-        } else {

-            None

-        }

-    }

-

-    fn into_bool(self) -> Option<bool> {

-        if let Primitive::Bool(value) = self {

-            Some(value)

-        } else {

-            None

-        }

-    }

-}

-

-impl<'v, T: ?Sized + 'static> Erased<'v, T> {

-    // NOTE: This function is a perfect candidate for memoization

-    // The outcome could be stored in a `Cell<Primitive>`

-    fn downcast_primitive(self) -> Option<Primitive<'v>> {

-        macro_rules! type_ids {

-            ($($value:ident : $ty:ty => $cast:expr,)*) => {{

-                struct TypeIds;

-

-                impl TypeIds {

-                    fn downcast_primitive<'v, T: ?Sized>(&self, value: Erased<'v, T>) -> Option<Primitive<'v>> {

-                        $(

-                            if TypeId::of::<$ty>() == value.type_id {

-                                let $value = unsafe { value.downcast_unchecked::<$ty>() };

-                                return Some(Primitive::from($cast));

-                            }

-                        )*

-

-                        None

-                    }

-                }

-

-                TypeIds

-            }};

-        }

-

-        let type_ids = type_ids![

-            value: usize => *value as u64,

-            value: u8 => *value as u64,

-            value: u16 => *value as u64,

-            value: u32 => *value as u64,

-            value: u64 => *value,

-

-            value: isize => *value as i64,

-            value: i8 => *value as i64,

-            value: i16 => *value as i64,

-            value: i32 => *value as i64,

-            value: i64 => *value,

-

-            value: f32 => *value as f64,

-            value: f64 => *value,

-

-            value: char => *value,

-            value: bool => *value,

-

-            value: &str => *value,

-        ];

-

-        type_ids.downcast_primitive(self)

-    }

-}

-

-#[cfg(feature = "std")]

-mod std_support {

-    use super::*;

-

-    use std::borrow::Cow;

-

-    impl<'v> Value<'v> {

-        /// Try get a `usize` from this value.

-        ///

-        /// This method is cheap for primitive types, but may call arbitrary

-        /// serialization implementations for complex ones. If the serialization

-        /// implementation produces a short lived string it will be allocated.

-        pub fn to_str(&self) -> Option<Cow<str>> {

-            self.inner.cast().into_str()

-        }

-    }

-

-    impl<'v> Cast<'v> {

-        pub(super) fn into_str(self) -> Option<Cow<'v, str>> {

-            match self {

-                Cast::Primitive(Primitive::Str(value)) => Some(value.into()),

-                Cast::String(value) => Some(value.into()),

-                _ => None,

-            }

-        }

-    }

-

-    #[cfg(test)]

-    mod tests {

-        use crate::kv::ToValue;

-

-        #[test]

-        fn primitive_cast() {

-            assert_eq!(

-                "a string",

-                "a string"

-                    .to_owned()

-                    .to_value()

-                    .to_borrowed_str()

-                    .expect("invalid value")

-            );

-            assert_eq!(

-                "a string",

-                &*"a string".to_value().to_str().expect("invalid value")

-            );

-            assert_eq!(

-                "a string",

-                &*"a string"

-                    .to_owned()

-                    .to_value()

-                    .to_str()

-                    .expect("invalid value")

-            );

-        }

-    }

-}

-

-#[cfg(test)]

-mod tests {

-    use crate::kv::ToValue;

-

-    #[test]

-    fn primitive_cast() {

-        assert_eq!(

-            "a string",

-            "a string"

-                .to_value()

-                .to_borrowed_str()

-                .expect("invalid value")

-        );

-        assert_eq!(

-            "a string",

-            Some("a string")

-                .to_value()

-                .to_borrowed_str()

-                .expect("invalid value")

-        );

-

-        assert_eq!(1u8, 1u64.to_value().to_u8().expect("invalid value"));

-        assert_eq!(1u16, 1u64.to_value().to_u16().expect("invalid value"));

-        assert_eq!(1u32, 1u64.to_value().to_u32().expect("invalid value"));

-        assert_eq!(1u64, 1u64.to_value().to_u64().expect("invalid value"));

-        assert_eq!(1usize, 1u64.to_value().to_usize().expect("invalid value"));

-

-        assert_eq!(-1i8, -1i64.to_value().to_i8().expect("invalid value"));

-        assert_eq!(-1i16, -1i64.to_value().to_i16().expect("invalid value"));

-        assert_eq!(-1i32, -1i64.to_value().to_i32().expect("invalid value"));

-        assert_eq!(-1i64, -1i64.to_value().to_i64().expect("invalid value"));

-        assert_eq!(-1isize, -1i64.to_value().to_isize().expect("invalid value"));

-

-        assert!(1f32.to_value().to_f32().is_some(), "invalid value");

-        assert!(1f64.to_value().to_f64().is_some(), "invalid value");

-

-        assert_eq!(1u32, 1i64.to_value().to_u32().expect("invalid value"));

-        assert_eq!(1i32, 1u64.to_value().to_i32().expect("invalid value"));

-        assert!(1f32.to_value().to_i32().is_some(), "invalid value");

-

-        assert_eq!('a', 'a'.to_value().to_char().expect("invalid value"));

-        assert_eq!(true, true.to_value().to_bool().expect("invalid value"));

-    }

-}

diff --git a/src/kv/value/internal/fmt.rs b/src/kv/value/internal/fmt.rs
deleted file mode 100644
index 66817d4..0000000
--- a/src/kv/value/internal/fmt.rs
+++ /dev/null
@@ -1,249 +0,0 @@
-//! Integration between `Value` and `std::fmt`.

-//!

-//! This module allows any `Value` to implement the `fmt::Debug` and `fmt::Display` traits,

-//! and for any `fmt::Debug` or `fmt::Display` to be captured as a `Value`.

-

-use std::fmt;

-

-use super::{Erased, Inner, Visitor};

-use crate::kv;

-use crate::kv::value::{Error, Slot};

-

-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 + 'static,

-    {

-        kv::Value {

-            inner: Inner::Debug(unsafe { Erased::new_unchecked::<T>(value) }),

-        }

-    }

-

-    /// Get a value from a displayable type.

-    pub fn from_display<T>(value: &'v T) -> Self

-    where

-        T: fmt::Display + 'static,

-    {

-        kv::Value {

-            inner: Inner::Display(unsafe { Erased::new_unchecked::<T>(value) }),

-        }

-    }

-}

-

-impl<'s, 'f> Slot<'s, 'f> {

-    /// Fill the slot with a debuggable value.

-    ///

-    /// The given value doesn't need to satisfy any particular lifetime constraints.

-    ///

-    /// # Panics

-    ///

-    /// Calling more than a single `fill` method on this slot will panic.

-    pub fn fill_debug<T>(&mut self, value: T) -> Result<(), Error>

-    where

-        T: fmt::Debug,

-    {

-        self.fill(|visitor| visitor.debug(&value))

-    }

-

-    /// Fill the slot with a displayable value.

-    ///

-    /// The given value doesn't need to satisfy any particular lifetime constraints.

-    ///

-    /// # Panics

-    ///

-    /// Calling more than a single `fill` method on this slot will panic.

-    pub fn fill_display<T>(&mut self, value: T) -> Result<(), Error>

-    where

-        T: fmt::Display,

-    {

-        self.fill(|visitor| visitor.display(&value))

-    }

-}

-

-pub(in kv::value) use self::fmt::{Arguments, Debug, Display};

-

-impl<'v> fmt::Debug for kv::Value<'v> {

-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

-        struct DebugVisitor<'a, 'b: 'a>(&'a mut fmt::Formatter<'b>);

-

-        impl<'a, 'b: 'a, 'v> Visitor<'v> for DebugVisitor<'a, 'b> {

-            fn debug(&mut self, v: &dyn fmt::Debug) -> Result<(), Error> {

-                fmt::Debug::fmt(v, self.0)?;

-

-                Ok(())

-            }

-

-            fn display(&mut self, v: &dyn fmt::Display) -> Result<(), Error> {

-                fmt::Display::fmt(v, self.0)?;

-

-                Ok(())

-            }

-

-            fn u64(&mut self, v: u64) -> Result<(), Error> {

-                fmt::Debug::fmt(&v, self.0)?;

-

-                Ok(())

-            }

-

-            fn i64(&mut self, v: i64) -> Result<(), Error> {

-                fmt::Debug::fmt(&v, self.0)?;

-

-                Ok(())

-            }

-

-            fn f64(&mut self, v: f64) -> Result<(), Error> {

-                fmt::Debug::fmt(&v, self.0)?;

-

-                Ok(())

-            }

-

-            fn bool(&mut self, v: bool) -> Result<(), Error> {

-                fmt::Debug::fmt(&v, self.0)?;

-

-                Ok(())

-            }

-

-            fn char(&mut self, v: char) -> Result<(), Error> {

-                fmt::Debug::fmt(&v, self.0)?;

-

-                Ok(())

-            }

-

-            fn str(&mut self, v: &str) -> Result<(), Error> {

-                fmt::Debug::fmt(&v, self.0)?;

-

-                Ok(())

-            }

-

-            fn none(&mut self) -> Result<(), Error> {

-                self.debug(&format_args!("None"))

-            }

-

-            #[cfg(feature = "kv_unstable_sval")]

-            fn sval(&mut self, v: &dyn super::sval::Value) -> Result<(), Error> {

-                super::sval::fmt(self.0, v)

-            }

-        }

-

-        self.visit(&mut DebugVisitor(f)).map_err(|_| fmt::Error)?;

-

-        Ok(())

-    }

-}

-

-impl<'v> fmt::Display for kv::Value<'v> {

-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

-        struct DisplayVisitor<'a, 'b: 'a>(&'a mut fmt::Formatter<'b>);

-

-        impl<'a, 'b: 'a, 'v> Visitor<'v> for DisplayVisitor<'a, 'b> {

-            fn debug(&mut self, v: &dyn fmt::Debug) -> Result<(), Error> {

-                fmt::Debug::fmt(v, self.0)?;

-

-                Ok(())

-            }

-

-            fn display(&mut self, v: &dyn fmt::Display) -> Result<(), Error> {

-                fmt::Display::fmt(v, self.0)?;

-

-                Ok(())

-            }

-

-            fn u64(&mut self, v: u64) -> Result<(), Error> {

-                fmt::Display::fmt(&v, self.0)?;

-

-                Ok(())

-            }

-

-            fn i64(&mut self, v: i64) -> Result<(), Error> {

-                fmt::Display::fmt(&v, self.0)?;

-

-                Ok(())

-            }

-

-            fn f64(&mut self, v: f64) -> Result<(), Error> {

-                fmt::Display::fmt(&v, self.0)?;

-

-                Ok(())

-            }

-

-            fn bool(&mut self, v: bool) -> Result<(), Error> {

-                fmt::Display::fmt(&v, self.0)?;

-

-                Ok(())

-            }

-

-            fn char(&mut self, v: char) -> Result<(), Error> {

-                fmt::Display::fmt(&v, self.0)?;

-

-                Ok(())

-            }

-

-            fn str(&mut self, v: &str) -> Result<(), Error> {

-                fmt::Display::fmt(&v, self.0)?;

-

-                Ok(())

-            }

-

-            fn none(&mut self) -> Result<(), Error> {

-                self.debug(&format_args!("None"))

-            }

-

-            #[cfg(feature = "kv_unstable_sval")]

-            fn sval(&mut self, v: &dyn super::sval::Value) -> Result<(), Error> {

-                super::sval::fmt(self.0, v)

-            }

-        }

-

-        self.visit(&mut DisplayVisitor(f)).map_err(|_| fmt::Error)?;

-

-        Ok(())

-    }

-}

-

-#[cfg(test)]

-mod tests {

-    use super::*;

-

-    use crate::kv::value::ToValue;

-

-    #[test]

-    fn fmt_cast() {

-        assert_eq!(

-            42u32,

-            kv::Value::from_debug(&42u64)

-                .to_u32()

-                .expect("invalid value")

-        );

-

-        assert_eq!(

-            "a string",

-            kv::Value::from_display(&"a string")

-                .to_borrowed_str()

-                .expect("invalid value")

-        );

-    }

-

-    #[test]

-    fn fmt_debug() {

-        assert_eq!(

-            format!("{:?}", "a string"),

-            format!("{:?}", "a string".to_value()),

-        );

-

-        assert_eq!(

-            format!("{:04?}", 42u64),

-            format!("{:04?}", 42u64.to_value()),

-        );

-    }

-

-    #[test]

-    fn fmt_display() {

-        assert_eq!(

-            format!("{}", "a string"),

-            format!("{}", "a string".to_value()),

-        );

-

-        assert_eq!(format!("{:04}", 42u64), format!("{:04}", 42u64.to_value()),);

-    }

-}

diff --git a/src/kv/value/internal/mod.rs b/src/kv/value/internal/mod.rs
deleted file mode 100644
index 01b72a7..0000000
--- a/src/kv/value/internal/mod.rs
+++ /dev/null
@@ -1,181 +0,0 @@
-//! The internal `Value` serialization API.

-//!

-//! This implementation isn't intended to be public. It may need to change

-//! for optimizations or to support new external serialization frameworks.

-

-use std::any::TypeId;

-

-use super::{Error, Fill, Slot};

-

-pub(super) mod cast;

-pub(super) mod fmt;

-#[cfg(feature = "kv_unstable_sval")]

-pub(super) mod sval;

-

-/// 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(Erased<'v, dyn Fill + 'static>),

-    /// A debuggable value.

-    Debug(Erased<'v, dyn fmt::Debug + 'static>),

-    /// A displayable value.

-    Display(Erased<'v, dyn fmt::Display + 'static>),

-

-    #[cfg(feature = "kv_unstable_sval")]

-    /// A structured value from `sval`.

-    Sval(Erased<'v, dyn sval::Value + 'static>),

-}

-

-impl<'v> Inner<'v> {

-    pub(super) fn visit(self, visitor: &mut dyn Visitor<'v>) -> Result<(), Error> {

-        match self {

-            Inner::Primitive(value) => value.visit(visitor),

-            Inner::Fill(value) => value.get().fill(&mut Slot::new(visitor)),

-            Inner::Debug(value) => visitor.debug(value.get()),

-            Inner::Display(value) => visitor.display(value.get()),

-

-            #[cfg(feature = "kv_unstable_sval")]

-            Inner::Sval(value) => visitor.sval(value.get()),

-        }

-    }

-}

-

-/// The internal serialization contract.

-pub(super) trait Visitor<'v> {

-    fn debug(&mut self, v: &dyn fmt::Debug) -> Result<(), Error>;

-    fn display(&mut self, v: &dyn 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 borrowed_str(&mut self, v: &'v str) -> Result<(), Error> {

-        self.str(v)

-    }

-

-    fn none(&mut self) -> Result<(), Error>;

-

-    #[cfg(feature = "kv_unstable_sval")]

-    fn sval(&mut self, v: &dyn sval::Value) -> Result<(), Error>;

-}

-

-/// A captured primitive value.

-///

-/// These values are common and cheap to copy around.

-#[derive(Clone, Copy)]

-pub(super) enum Primitive<'v> {

-    Signed(i64),

-    Unsigned(u64),

-    Float(f64),

-    Bool(bool),

-    Char(char),

-    Str(&'v str),

-    Fmt(fmt::Arguments<'v>),

-    None,

-}

-

-impl<'v> Primitive<'v> {

-    fn visit(self, visitor: &mut dyn Visitor<'v>) -> Result<(), Error> {

-        match self {

-            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.borrowed_str(value),

-            Primitive::Fmt(value) => visitor.debug(&value),

-            Primitive::None => visitor.none(),

-        }

-    }

-}

-

-impl<'v> From<u64> for Primitive<'v> {

-    fn from(v: u64) -> Self {

-        Primitive::Unsigned(v)

-    }

-}

-

-impl<'v> From<i64> for Primitive<'v> {

-    fn from(v: i64) -> Self {

-        Primitive::Signed(v)

-    }

-}

-

-impl<'v> From<f64> for Primitive<'v> {

-    fn from(v: f64) -> Self {

-        Primitive::Float(v)

-    }

-}

-

-impl<'v> From<bool> for Primitive<'v> {

-    fn from(v: bool) -> Self {

-        Primitive::Bool(v)

-    }

-}

-

-impl<'v> From<char> for Primitive<'v> {

-    fn from(v: char) -> Self {

-        Primitive::Char(v)

-    }

-}

-

-impl<'v> From<&'v str> for Primitive<'v> {

-    fn from(v: &'v str) -> Self {

-        Primitive::Str(v)

-    }

-}

-

-impl<'v> From<fmt::Arguments<'v>> for Primitive<'v> {

-    fn from(v: fmt::Arguments<'v>) -> Self {

-        Primitive::Fmt(v)

-    }

-}

-

-/// A downcastable dynamic type.

-pub(super) struct Erased<'v, T: ?Sized> {

-    type_id: TypeId,

-    inner: &'v T,

-}

-

-impl<'v, T: ?Sized> Clone for Erased<'v, T> {

-    fn clone(&self) -> Self {

-        Erased {

-            type_id: self.type_id,

-            inner: self.inner,

-        }

-    }

-}

-

-impl<'v, T: ?Sized> Copy for Erased<'v, T> {}

-

-impl<'v, T: ?Sized> Erased<'v, T> {

-    // SAFETY: `U: Unsize<T>` and the underlying value `T` must not change

-    // We could add a safe variant of this method with the `Unsize` trait

-    pub(super) unsafe fn new_unchecked<U>(inner: &'v T) -> Self

-    where

-        U: 'static,

-        T: 'static,

-    {

-        Erased {

-            type_id: TypeId::of::<U>(),

-            inner,

-        }

-    }

-

-    pub(super) fn get(self) -> &'v T {

-        self.inner

-    }

-

-    // SAFETY: The underlying type of `T` is `U`

-    pub(super) unsafe fn downcast_unchecked<U>(self) -> &'v U {

-        &*(self.inner as *const T as *const U)

-    }

-}

diff --git a/src/kv/value/internal/sval.rs b/src/kv/value/internal/sval.rs
deleted file mode 100644
index 618a036..0000000
--- a/src/kv/value/internal/sval.rs
+++ /dev/null
@@ -1,210 +0,0 @@
-//! Integration between `Value` and `sval`.

-//!

-//! This module allows any `Value` to implement the `sval::Value` trait,

-//! and for any `sval::Value` to be captured as a `Value`.

-

-extern crate sval;

-

-use std::fmt;

-

-use super::cast::Cast;

-use super::{Erased, Inner, Primitive, Visitor};

-use crate::kv;

-use crate::kv::value::{Error, Slot};

-

-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 + 'static,

-    {

-        kv::Value {

-            inner: Inner::Sval(unsafe { Erased::new_unchecked::<T>(value) }),

-        }

-    }

-}

-

-impl<'s, 'f> Slot<'s, 'f> {

-    /// Fill the slot with a structured value.

-    ///

-    /// The given value doesn't need to satisfy any particular lifetime constraints.

-    ///

-    /// # Panics

-    ///

-    /// Calling more than a single `fill` method on this slot will panic.

-    pub fn fill_sval<T>(&mut self, value: T) -> Result<(), Error>

-    where

-        T: sval::Value,

-    {

-        self.fill(|visitor| visitor.sval(&value))

-    }

-}

-

-impl<'v> sval::Value for kv::Value<'v> {

-    fn stream(&self, s: &mut sval::value::Stream) -> sval::value::Result {

-        struct SvalVisitor<'a, 'b: 'a>(&'a mut sval::value::Stream<'b>);

-

-        impl<'a, 'b: 'a, 'v> Visitor<'v> for SvalVisitor<'a, 'b> {

-            fn debug(&mut self, v: &dyn 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: &dyn sval::Value) -> Result<(), Error> {

-                self.0.any(v).map_err(Error::from_sval)

-            }

-        }

-

-        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: &dyn sval::Value) -> Result<(), Error> {

-    sval::fmt::debug(f, v)?;

-    Ok(())

-}

-

-pub(super) fn cast<'v>(v: &dyn sval::Value) -> Cast<'v> {

-    struct CastStream<'v>(Cast<'v>);

-

-    impl<'v> sval::Stream for CastStream<'v> {

-        fn u64(&mut self, v: u64) -> sval::stream::Result {

-            self.0 = Cast::Primitive(Primitive::Unsigned(v));

-            Ok(())

-        }

-

-        fn i64(&mut self, v: i64) -> sval::stream::Result {

-            self.0 = Cast::Primitive(Primitive::Signed(v));

-            Ok(())

-        }

-

-        fn f64(&mut self, v: f64) -> sval::stream::Result {

-            self.0 = Cast::Primitive(Primitive::Float(v));

-            Ok(())

-        }

-

-        fn char(&mut self, v: char) -> sval::stream::Result {

-            self.0 = Cast::Primitive(Primitive::Char(v));

-            Ok(())

-        }

-

-        fn bool(&mut self, v: bool) -> sval::stream::Result {

-            self.0 = Cast::Primitive(Primitive::Bool(v));

-            Ok(())

-        }

-

-        #[cfg(feature = "std")]

-        fn str(&mut self, s: &str) -> sval::stream::Result {

-            self.0 = Cast::String(s.into());

-            Ok(())

-        }

-    }

-

-    let mut cast = CastStream(Cast::Primitive(Primitive::None));

-    let _ = sval::stream(&mut cast, v);

-

-    cast.0

-}

-

-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")

-    }

-}

-

-#[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);

-    }

-

-    #[test]

-    fn sval_cast() {

-        assert_eq!(

-            42u32,

-            kv::Value::from_sval(&42u64)

-                .to_u32()

-                .expect("invalid value")

-        );

-

-        assert_eq!(

-            "a string",

-            kv::Value::from_sval(&"a string")

-                .to_borrowed_str()

-                .expect("invalid value")

-        );

-

-        #[cfg(feature = "std")]

-        assert_eq!(

-            "a string",

-            kv::Value::from_sval(&"a string")

-                .to_str()

-                .expect("invalid value")

-        );

-    }

-

-    #[test]

-    fn sval_debug() {

-        struct TestSval;

-

-        impl sval::Value for TestSval {

-            fn stream(&self, stream: &mut sval::value::Stream) -> sval::value::Result {

-                stream.u64(42)

-            }

-        }

-

-        assert_eq!(

-            format!("{:04?}", 42u64),

-            format!("{:04?}", kv::Value::from_sval(&TestSval)),

-        );

-    }

-}

diff --git a/src/kv/value/mod.rs b/src/kv/value/mod.rs
deleted file mode 100644
index 1d59dbf..0000000
--- a/src/kv/value/mod.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-//! Structured values.

-

-mod fill;

-mod impls;

-mod internal;

-

-#[cfg(test)]

-pub(in kv) mod test;

-

-pub use self::fill::{Fill, Slot};

-pub use kv::Error;

-

-use self::internal::{Inner, Primitive, Visitor};

-

-/// 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 value in a structured key-value pair.

-pub struct Value<'v> {

-    inner: Inner<'v>,

-}

-

-impl<'v> Value<'v> {

-    /// Get a value from an internal primitive.

-    fn from_primitive<T>(value: T) -> Self

-    where

-        T: Into<Primitive<'v>>,

-    {

-        Value {

-            inner: Inner::Primitive(value.into()),

-        }

-    }

-

-    /// Visit the value using an internal visitor.

-    fn visit<'a>(&'a self, visitor: &mut dyn Visitor<'a>) -> Result<(), Error> {

-        self.inner.visit(visitor)

-    }

-}

diff --git a/src/kv/value/test.rs b/src/kv/value/test.rs
deleted file mode 100644
index c8d6d5c..0000000
--- a/src/kv/value/test.rs
+++ /dev/null
@@ -1,81 +0,0 @@
-// Test support for inspecting Values

-

-use std::fmt;

-use std::str;

-

-use super::internal;

-use super::{Error, Value};

-

-#[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<'v> internal::Visitor<'v> for TestVisitor {

-            fn debug(&mut self, v: &dyn 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, _: &dyn internal::sval::Value) -> Result<(), Error> {

-                self.0 = Some(Token::Sval);

-                Ok(())

-            }

-        }

-

-        let mut visitor = TestVisitor(None);

-        self.visit(&mut visitor).unwrap();

-

-        visitor.0.unwrap()

-    }

-}

diff --git a/src/lib.rs b/src/lib.rs
index 83b78d0..e754268 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -266,7 +266,7 @@
 #![doc(

     html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",

     html_favicon_url = "https://www.rust-lang.org/favicon.ico",

-    html_root_url = "https://docs.rs/log/0.4.11"

+    html_root_url = "https://docs.rs/log/0.4.14"

 )]

 #![warn(missing_docs)]

 #![deny(missing_debug_implementations)]

@@ -288,7 +288,6 @@
 use std::fmt;

 use std::mem;

 use std::str::FromStr;

-use std::sync::atomic::{AtomicUsize, Ordering};

 

 #[macro_use]

 mod macros;

@@ -297,6 +296,54 @@
 #[cfg(feature = "kv_unstable")]

 pub mod kv;

 

+#[cfg(has_atomics)]

+use std::sync::atomic::{AtomicUsize, Ordering};

+

+#[cfg(not(has_atomics))]

+use std::cell::Cell;

+#[cfg(not(has_atomics))]

+use std::sync::atomic::Ordering;

+

+#[cfg(not(has_atomics))]

+struct AtomicUsize {

+    v: Cell<usize>,

+}

+

+#[cfg(not(has_atomics))]

+impl AtomicUsize {

+    const fn new(v: usize) -> AtomicUsize {

+        AtomicUsize { v: Cell::new(v) }

+    }

+

+    fn load(&self, _order: Ordering) -> usize {

+        self.v.get()

+    }

+

+    fn store(&self, val: usize, _order: Ordering) {

+        self.v.set(val)

+    }

+

+    #[cfg(atomic_cas)]

+    fn compare_exchange(

+        &self,

+        current: usize,

+        new: usize,

+        _success: Ordering,

+        _failure: Ordering,

+    ) -> Result<usize, usize> {

+        let prev = self.v.get();

+        if current == prev {

+            self.v.set(new);

+        }

+        Ok(prev)

+    }

+}

+

+// Any platform without atomics is unlikely to have multiple cores, so

+// writing via Cell will not be a race condition.

+#[cfg(not(has_atomics))]

+unsafe impl Sync for AtomicUsize {}

+

 // The LOGGER static holds a pointer to the global logger. It is protected by

 // the STATE static which determines whether LOGGER has been initialized yet.

 static mut LOGGER: &dyn Log = &NopLogger;

@@ -479,7 +526,7 @@
 

 impl fmt::Display for Level {

     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {

-        fmt.pad(LOG_LEVEL_NAMES[*self as usize])

+        fmt.pad(self.as_str())

     }

 }

 

@@ -506,6 +553,13 @@
     pub fn to_level_filter(&self) -> LevelFilter {

         LevelFilter::from_usize(*self as usize).unwrap()

     }

+

+    /// Returns the string representation of the `Level`.

+    ///

+    /// This returns the same string as the `fmt::Display` implementation.

+    pub fn as_str(&self) -> &'static str {

+        LOG_LEVEL_NAMES[*self as usize]

+    }

 }

 

 /// An enum representing the available verbosity level filters of the logger.

@@ -632,7 +686,7 @@
 

 impl fmt::Display for LevelFilter {

     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {

-        fmt.pad(LOG_LEVEL_NAMES[*self as usize])

+        fmt.pad(self.as_str())

     }

 }

 

@@ -661,6 +715,13 @@
     pub fn to_level(&self) -> Option<Level> {

         Level::from_usize(*self as usize)

     }

+

+    /// Returns the string representation of the `LevelFilter`.

+    ///

+    /// This returns the same string as the `fmt::Display` implementation.

+    pub fn as_str(&self) -> &'static str {

+        LOG_LEVEL_NAMES[*self as usize]

+    }

 }

 

 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]

@@ -1153,6 +1214,23 @@
     fn flush(&self) {}

 }

 

+#[cfg(feature = "std")]

+impl<T> Log for std::boxed::Box<T>

+where

+    T: ?Sized + Log,

+{

+    fn enabled(&self, metadata: &Metadata) -> bool {

+        self.as_ref().enabled(metadata)

+    }

+

+    fn log(&self, record: &Record) {

+        self.as_ref().log(record)

+    }

+    fn flush(&self) {

+        self.as_ref().flush()

+    }

+}

+

 /// Sets the global maximum log level.

 ///

 /// Generally, this should only be called by the active logging implementation.

@@ -1266,7 +1344,15 @@
 where

     F: FnOnce() -> &'static dyn Log,

 {

-    match STATE.compare_and_swap(UNINITIALIZED, INITIALIZING, Ordering::SeqCst) {

+    let old_state = match STATE.compare_exchange(

+        UNINITIALIZED,

+        INITIALIZING,

+        Ordering::SeqCst,

+        Ordering::SeqCst,

+    ) {

+        Ok(s) | Err(s) => s,

+    };

+    match old_state {

         UNINITIALIZED => {

             unsafe {

                 LOGGER = make_logger();

@@ -1385,25 +1471,6 @@
 

 // WARNING: this is not part of the crate's public API and is subject to change at any time

 #[doc(hidden)]

-pub fn __private_api_log_lit(

-    message: &str,

-    level: Level,

-    &(target, module_path, file, line): &(&str, &'static str, &'static str, u32),

-) {

-    logger().log(

-        &Record::builder()

-            .args(format_args!("{}", message))

-            .level(level)

-            .target(target)

-            .module_path_static(Some(module_path))

-            .file_static(Some(file))

-            .line(Some(line))

-            .build(),

-    );

-}

-

-// WARNING: this is not part of the crate's public API and is subject to change at any time

-#[doc(hidden)]

 pub fn __private_api_enabled(level: Level, target: &str) -> bool {

     logger().enabled(&Metadata::builder().level(level).target(target).build())

 }

@@ -1497,6 +1564,20 @@
     }

 

     #[test]

+    fn test_level_as_str() {

+        let tests = &[

+            (Level::Error, "ERROR"),

+            (Level::Warn, "WARN"),

+            (Level::Info, "INFO"),

+            (Level::Debug, "DEBUG"),

+            (Level::Trace, "TRACE"),

+        ];

+        for (input, expected) in tests {

+            assert_eq!(*expected, input.as_str());

+        }

+    }

+

+    #[test]

     fn test_level_show() {

         assert_eq!("INFO", Level::Info.to_string());

         assert_eq!("ERROR", Level::Error.to_string());

@@ -1536,6 +1617,21 @@
     }

 

     #[test]

+    fn test_level_filter_as_str() {

+        let tests = &[

+            (LevelFilter::Off, "OFF"),

+            (LevelFilter::Error, "ERROR"),

+            (LevelFilter::Warn, "WARN"),

+            (LevelFilter::Info, "INFO"),

+            (LevelFilter::Debug, "DEBUG"),

+            (LevelFilter::Trace, "TRACE"),

+        ];

+        for (input, expected) in tests {

+            assert_eq!(*expected, input.as_str());

+        }

+    }

+

+    #[test]

     #[cfg(feature = "std")]

     fn test_error_trait() {

         use super::SetLoggerError;

diff --git a/src/macros.rs b/src/macros.rs
index 48de437..a234e04 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -29,18 +29,6 @@
 /// ```

 #[macro_export(local_inner_macros)]

 macro_rules! log {

-    (target: $target:expr, $lvl:expr, $message:expr) => ({

-        let lvl = $lvl;

-        if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() {

-            // ensure that $message is a valid format string literal

-            let _ = __log_format_args!($message);

-            $crate::__private_api_log_lit(

-                $message,

-                lvl,

-                &($target, __log_module_path!(), __log_file!(), __log_line!()),

-            );

-        }

-    });

     (target: $target:expr, $lvl:expr, $($arg:tt)+) => ({

         let lvl = $lvl;

         if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() {

@@ -71,10 +59,10 @@
 #[macro_export(local_inner_macros)]

 macro_rules! error {

     (target: $target:expr, $($arg:tt)+) => (

-        log!(target: $target, $crate::Level::Error, $($arg)+);

+        log!(target: $target, $crate::Level::Error, $($arg)+)

     );

     ($($arg:tt)+) => (

-        log!($crate::Level::Error, $($arg)+);

+        log!($crate::Level::Error, $($arg)+)

     )

 }

 

@@ -95,10 +83,10 @@
 #[macro_export(local_inner_macros)]

 macro_rules! warn {

     (target: $target:expr, $($arg:tt)+) => (

-        log!(target: $target, $crate::Level::Warn, $($arg)+);

+        log!(target: $target, $crate::Level::Warn, $($arg)+)

     );

     ($($arg:tt)+) => (

-        log!($crate::Level::Warn, $($arg)+);

+        log!($crate::Level::Warn, $($arg)+)

     )

 }

 

@@ -121,10 +109,10 @@
 #[macro_export(local_inner_macros)]

 macro_rules! info {

     (target: $target:expr, $($arg:tt)+) => (

-        log!(target: $target, $crate::Level::Info, $($arg)+);

+        log!(target: $target, $crate::Level::Info, $($arg)+)

     );

     ($($arg:tt)+) => (

-        log!($crate::Level::Info, $($arg)+);

+        log!($crate::Level::Info, $($arg)+)

     )

 }

 

@@ -146,10 +134,10 @@
 #[macro_export(local_inner_macros)]

 macro_rules! debug {

     (target: $target:expr, $($arg:tt)+) => (

-        log!(target: $target, $crate::Level::Debug, $($arg)+);

+        log!(target: $target, $crate::Level::Debug, $($arg)+)

     );

     ($($arg:tt)+) => (

-        log!($crate::Level::Debug, $($arg)+);

+        log!($crate::Level::Debug, $($arg)+)

     )

 }

 

@@ -173,10 +161,10 @@
 #[macro_export(local_inner_macros)]

 macro_rules! trace {

     (target: $target:expr, $($arg:tt)+) => (

-        log!(target: $target, $crate::Level::Trace, $($arg)+);

+        log!(target: $target, $crate::Level::Trace, $($arg)+)

     );

     ($($arg:tt)+) => (

-        log!($crate::Level::Trace, $($arg)+);

+        log!($crate::Level::Trace, $($arg)+)

     )

 }

 

diff --git a/src/serde.rs b/src/serde.rs
index 8320ce1..e691321 100644
--- a/src/serde.rs
+++ b/src/serde.rs
@@ -60,6 +60,17 @@
 

                 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 {

@@ -144,6 +155,17 @@
 

                 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 {

@@ -203,6 +225,14 @@
         ]

     }

 

+    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",

@@ -220,6 +250,16 @@
         ]

     }

 

+    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 = [

@@ -266,6 +306,21 @@
     }

 

     #[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`";

@@ -321,6 +376,22 @@
     }

 

     #[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`";

diff --git a/tests/filters.rs b/tests/filters.rs
deleted file mode 100644
index 661c034..0000000
--- a/tests/filters.rs
+++ /dev/null
@@ -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<dyn Log>) -> Result<(), log::SetLoggerError> {

-    log::set_logger(Box::leak(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);

-}

diff --git a/tests/macros.rs b/tests/macros.rs
deleted file mode 100644
index e9dc133..0000000
--- a/tests/macros.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-#[macro_use]

-extern crate log;

-

-#[test]

-fn base() {

-    info!("hello");

-    info!("hello",);

-}

-

-#[test]

-fn base_expr_context() {

-    let _ = info!("hello");

-}

-

-#[test]

-fn with_args() {

-    info!("hello {}", "cats");

-    info!("hello {}", "cats",);

-    info!("hello {}", "cats",);

-}

-

-#[test]

-fn with_args_expr_context() {

-    match "cats" {

-        cats => info!("hello {}", cats),

-    };

-}

-

-#[test]

-fn with_named_args() {

-    let cats = "cats";

-

-    info!("hello {cats}", cats = cats);

-    info!("hello {cats}", cats = cats,);

-    info!("hello {cats}", cats = cats,);

-}