Skip to content

Commit d54317e

Browse files
authored
Merge pull request #379 from KodrAus/feat/value-coercion
Support coercing structured Values into primitive types
2 parents e876aec + 66af8f2 commit d54317e

File tree

11 files changed

+1221
-542
lines changed

11 files changed

+1221
-542
lines changed

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ kv_unstable_sval = ["kv_unstable", "sval/fmt"]
5151
[dependencies]
5252
cfg-if = "0.1.2"
5353
serde = { version = "1.0", optional = true, default-features = false }
54-
sval = { version = "0.4.2", optional = true, default-features = false }
54+
sval = { version = "0.5", optional = true, default-features = false }
5555

5656
[dev-dependencies]
5757
serde_test = "1.0"
58-
sval = { version = "0.4.2", features = ["test"] }
58+
sval = { version = "0.5", features = ["test"] }

src/kv/value/fill.rs

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
//! Lazy value initialization.
2+
3+
use std::fmt;
4+
5+
use super::internal::{Erased, Inner, Visitor};
6+
use super::{Error, Value};
7+
8+
impl<'v> Value<'v> {
9+
/// Get a value from a fillable slot.
10+
pub fn from_fill<T>(value: &'v T) -> Self
11+
where
12+
T: Fill + 'static,
13+
{
14+
Value {
15+
inner: Inner::Fill(unsafe { Erased::new_unchecked::<T>(value) }),
16+
}
17+
}
18+
}
19+
20+
/// A type that requires extra work to convert into a [`Value`](struct.Value.html).
21+
///
22+
/// This trait is a more advanced initialization API than [`ToValue`](trait.ToValue.html).
23+
/// It's intended for erased values coming from other logging frameworks that may need
24+
/// to perform extra work to determine the concrete type to use.
25+
pub trait Fill {
26+
/// Fill a value.
27+
fn fill(&self, slot: &mut Slot) -> Result<(), Error>;
28+
}
29+
30+
impl<'a, T> Fill for &'a T
31+
where
32+
T: Fill + ?Sized,
33+
{
34+
fn fill(&self, slot: &mut Slot) -> Result<(), Error> {
35+
(**self).fill(slot)
36+
}
37+
}
38+
39+
/// A value slot to fill using the [`Fill`](trait.Fill.html) trait.
40+
pub struct Slot<'s, 'f> {
41+
filled: bool,
42+
visitor: &'s mut dyn Visitor<'f>,
43+
}
44+
45+
impl<'s, 'f> fmt::Debug for Slot<'s, 'f> {
46+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
47+
f.debug_struct("Slot").finish()
48+
}
49+
}
50+
51+
impl<'s, 'f> Slot<'s, 'f> {
52+
pub(super) fn new(visitor: &'s mut dyn Visitor<'f>) -> Self {
53+
Slot {
54+
visitor,
55+
filled: false,
56+
}
57+
}
58+
59+
pub(super) fn fill<F>(&mut self, f: F) -> Result<(), Error>
60+
where
61+
F: FnOnce(&mut dyn Visitor<'f>) -> Result<(), Error>,
62+
{
63+
assert!(!self.filled, "the slot has already been filled");
64+
self.filled = true;
65+
66+
f(self.visitor)
67+
}
68+
69+
/// Fill the slot with a value.
70+
///
71+
/// The given value doesn't need to satisfy any particular lifetime constraints.
72+
///
73+
/// # Panics
74+
///
75+
/// Calling more than a single `fill` method on this slot will panic.
76+
pub fn fill_any<T>(&mut self, value: T) -> Result<(), Error>
77+
where
78+
T: Into<Value<'f>>,
79+
{
80+
self.fill(|visitor| value.into().inner.visit(visitor))
81+
}
82+
}
83+
84+
#[cfg(test)]
85+
mod tests {
86+
use super::*;
87+
88+
#[test]
89+
fn fill_value_borrowed() {
90+
struct TestFill;
91+
92+
impl Fill for TestFill {
93+
fn fill(&self, slot: &mut Slot) -> Result<(), Error> {
94+
let dbg: &dyn fmt::Debug = &1;
95+
96+
slot.fill_debug(&dbg)
97+
}
98+
}
99+
100+
assert_eq!("1", Value::from_fill(&TestFill).to_string());
101+
}
102+
103+
#[test]
104+
fn fill_value_owned() {
105+
struct TestFill;
106+
107+
impl Fill for TestFill {
108+
fn fill(&self, slot: &mut Slot) -> Result<(), Error> {
109+
slot.fill_any("a string")
110+
}
111+
}
112+
}
113+
114+
#[test]
115+
#[should_panic]
116+
fn fill_multiple_times_panics() {
117+
struct BadFill;
118+
119+
impl Fill for BadFill {
120+
fn fill(&self, slot: &mut Slot) -> Result<(), Error> {
121+
slot.fill_any(42)?;
122+
slot.fill_any(6789)?;
123+
124+
Ok(())
125+
}
126+
}
127+
128+
let _ = Value::from_fill(&BadFill).to_string();
129+
}
130+
131+
#[test]
132+
fn fill_cast() {
133+
struct TestFill;
134+
135+
impl Fill for TestFill {
136+
fn fill(&self, slot: &mut Slot) -> Result<(), Error> {
137+
slot.fill_any("a string")
138+
}
139+
}
140+
141+
assert_eq!(
142+
"a string",
143+
Value::from_fill(&TestFill)
144+
.to_borrowed_str()
145+
.expect("invalid value")
146+
);
147+
}
148+
}

0 commit comments

Comments
 (0)