From 32d080a92ea40b3b4405e63af2a9b364167e5979 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Wed, 13 Mar 2019 15:16:31 +1100 Subject: [PATCH 1/8] build out initial key values API --- .travis.yml | 13 +- Cargo.toml | 3 + src/key_values/error.rs | 50 ++++++ src/key_values/key.rs | 143 ++++++++++++++++ src/key_values/mod.rs | 11 ++ src/key_values/source.rs | 116 +++++++++++++ src/key_values/value/any.rs | 97 +++++++++++ src/key_values/value/backend.rs | 62 +++++++ src/key_values/value/impls.rs | 287 ++++++++++++++++++++++++++++++++ src/key_values/value/mod.rs | 73 ++++++++ src/lib.rs | 120 ++++++++++++- 11 files changed, 970 insertions(+), 5 deletions(-) create mode 100644 src/key_values/error.rs create mode 100644 src/key_values/key.rs create mode 100644 src/key_values/mod.rs create mode 100644 src/key_values/source.rs create mode 100644 src/key_values/value/any.rs create mode 100644 src/key_values/value/backend.rs create mode 100644 src/key_values/value/impls.rs create mode 100644 src/key_values/value/mod.rs diff --git a/.travis.yml b/.travis.yml index edcc10b4f..a87b92b19 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,13 +5,20 @@ rust: - stable - beta - nightly -install: - - '[ "$TRAVIS_RUST_VERSION" == "1.16.0" ] || rustup target add thumbv6m-none-eabi' +matrix: + include: + - rust: 1.21.0 + script: + - cargo test --verbose --features kv_unstable + - cargo test --verbose --features "kv_unstable std" + - rust: stable + script: + - rustup target add thumbv6m-none-eabi + - cargo build --verbose --target=thumbv6m-none-eabi script: - cargo build --verbose - cargo build --verbose --features serde - cargo build --verbose --features std - - '[ "$TRAVIS_RUST_VERSION" == "1.16.0" ] || cargo build --verbose --target=thumbv6m-none-eabi' - cargo test --verbose - cargo test --verbose --features serde - cargo test --verbose --features std diff --git a/Cargo.toml b/Cargo.toml index 8d8093e0a..4477b0dd8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,9 @@ release_max_level_trace = [] std = [] +# requires Rust `>= 1.21.0` +kv_unstable = [] + [badges] travis-ci = { repository = "rust-lang-nursery/log" } appveyor = { repository = "alexcrichton/log" } diff --git a/src/key_values/error.rs b/src/key_values/error.rs new file mode 100644 index 000000000..e45a7a82e --- /dev/null +++ b/src/key_values/error.rs @@ -0,0 +1,50 @@ +use std::fmt; + +/// An error encountered while working with structured data. +#[derive(Clone, Debug)] +pub struct KeyValueError { + msg: &'static str, +} + +impl KeyValueError { + /// Create an error from the given message. + pub fn msg(msg: &'static str) -> Self { + KeyValueError { + msg: msg, + } + } +} + +impl fmt::Display for KeyValueError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.msg.fmt(f) + } +} + +impl From for KeyValueError { + fn from(_: fmt::Error) -> Self { + KeyValueError::msg("formatting failed") + } +} + +impl From for fmt::Error { + fn from(_: KeyValueError) -> Self { + fmt::Error + } +} + +#[cfg(feature = "std")] +mod std_support { + use super::*; + use std::error; + + impl error::Error for KeyValueError { + fn description(&self) -> &str { + self.msg + } + + fn cause(&self) -> Option<&error::Error> { + None + } + } +} \ No newline at end of file diff --git a/src/key_values/key.rs b/src/key_values/key.rs new file mode 100644 index 000000000..33ccd1f51 --- /dev/null +++ b/src/key_values/key.rs @@ -0,0 +1,143 @@ +//! Structured keys. + +use std::fmt; +use std::cmp; +use std::hash; +use std::borrow::Borrow; + +/// A type that can be converted into a [`Key`](struct.Key.html). +pub trait ToKey { + /// Perform the covnersion. + fn to_key(&self) -> Key; +} + +impl<'a, T> ToKey for &'a T +where + T: ToKey + ?Sized, +{ + fn to_key(&self) -> Key { + (**self).to_key() + } +} + +impl<'k> ToKey for Key<'k> { + fn to_key(&self) -> Key { + Key { + key: self.key, + } + } +} + +impl<'k> ToKey for &'k str { + fn to_key(&self) -> Key { + Key::from_str(self) + } +} + +/// A key in a structured key-value pair. +#[derive(Clone)] +pub struct Key<'k> { + key: &'k str, +} + +impl<'k> Key<'k> { + /// Get a key from a borrowed string. + pub fn from_str(key: &'k str) -> Self { + Key { + key: key, + } + } + + /// Get a borrowed string from this key. + pub fn as_str(&self) -> &str { + self.key + } +} + +impl<'k> fmt::Debug for Key<'k> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.key.fmt(f) + } +} + +impl<'k> fmt::Display for Key<'k> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.key.fmt(f) + } +} + +impl<'k> hash::Hash for Key<'k> { + fn hash(&self, state: &mut H) + where + H: hash::Hasher, + { + self.as_str().hash(state) + } +} + +impl<'k, 'ko> PartialEq> for Key<'k> { + fn eq(&self, other: &Key<'ko>) -> bool { + self.as_str().eq(other.as_str()) + } +} + +impl<'k> Eq for Key<'k> {} + +impl<'k, 'ko> PartialOrd> for Key<'k> { + fn partial_cmp(&self, other: &Key<'ko>) -> Option { + self.as_str().partial_cmp(other.as_str()) + } +} + +impl<'k> Ord for Key<'k> { + fn cmp(&self, other: &Self) -> cmp::Ordering { + self.as_str().cmp(other.as_str()) + } +} + +impl<'k> AsRef for Key<'k> { + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl<'k> Borrow for Key<'k> { + fn borrow(&self) -> &str { + self.as_str() + } +} + +impl<'k> From<&'k str> for Key<'k> { + fn from(s: &'k str) -> Self { + Key::from_str(s) + } +} + +#[cfg(feature = "std")] +mod std_support { + use super::*; + + use std::borrow::Cow; + + impl ToKey for String { + fn to_key(&self) -> Key { + Key::from_str(self) + } + } + + impl<'a> ToKey for Cow<'a, str> { + fn to_key(&self) -> Key { + Key::from_str(self) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn key_from_string() { + assert_eq!("a key", Key::from_str("a key").as_str()); + } +} \ No newline at end of file diff --git a/src/key_values/mod.rs b/src/key_values/mod.rs new file mode 100644 index 000000000..da8505776 --- /dev/null +++ b/src/key_values/mod.rs @@ -0,0 +1,11 @@ +//! Structured key-value pairs. + +mod error; +pub mod source; +pub mod key; +pub mod value; + +pub use self::error::KeyValueError; +pub use self::source::Source; +pub use self::key::Key; +pub use self::value::Value; diff --git a/src/key_values/source.rs b/src/key_values/source.rs new file mode 100644 index 000000000..b0a49ac28 --- /dev/null +++ b/src/key_values/source.rs @@ -0,0 +1,116 @@ +//! Sources for key-value pairs. + +pub use key_values::{KeyValueError, Key, Value}; + +use key_values::key::ToKey; +use key_values::value::ToValue; + +/// A source of key-value pairs. +/// +/// The source may be a single pair, a set of pairs, or a filter over a set of pairs. +/// Use the [`Visitor`](struct.Visitor.html) trait to inspect the structured data +/// in a source. +pub trait Source { + /// Visit key-value pairs. + /// + /// A source doesn't have to guarantee any ordering or uniqueness of pairs. + fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), KeyValueError>; +} + +impl<'a, T> Source for &'a T +where + T: Source + ?Sized, +{ + fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), KeyValueError> { + (**self).visit(visitor) + } +} + +impl Source for (K, V) +where + K: ToKey, + V: ToValue, +{ + fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), KeyValueError> { + visitor.visit_pair(self.0.to_key(), self.1.to_value()) + } +} + +impl Source for [S] +where + S: Source, +{ + fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), KeyValueError> { + for source in self { + source.visit(visitor)?; + } + + Ok(()) + } +} + +impl Source for Option +where + S: Source, +{ + fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), KeyValueError> { + if let Some(ref source) = *self { + source.visit(visitor)?; + } + + Ok(()) + } +} + +/// A visitor for the key-value pairs in a [`Source`](trait.Source.html). +pub trait Visitor<'kvs> { + /// Visit a key-value pair. + fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), KeyValueError>; +} + +impl<'a, 'kvs, T> Visitor<'kvs> for &'a mut T +where + T: Visitor<'kvs> + ?Sized, +{ + fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), KeyValueError> { + (**self).visit_pair(key, value) + } +} + +#[cfg(feature = "std")] +mod std_support { + use super::*; + + impl Source for Box + where + S: Source + ?Sized, + { + fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), KeyValueError> { + (**self).visit(visitor) + } + } + + impl Source for Vec + where + S: Source, + { + fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), KeyValueError> { + (**self).visit(visitor) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn source_is_object_safe() { + fn _check(_: &Source) {} + } + + #[test] + fn visitor_is_object_safe() { + fn _check(_: &Visitor) {} + } +} \ No newline at end of file diff --git a/src/key_values/value/any.rs b/src/key_values/value/any.rs new file mode 100644 index 000000000..04baf4844 --- /dev/null +++ b/src/key_values/value/any.rs @@ -0,0 +1,97 @@ +use std::{fmt, mem}; +use std::marker::PhantomData; + +use super::{ToValue, KeyValueError}; +use super::backend::Backend; + +/// A function for converting some type `T` into a [`Value`](struct.Value.html). +pub type FromAnyFn = fn(FromAny, &T) -> Result<(), KeyValueError>; + +/// A helper for converting any type into a [`Value`](struct.Value.html). +pub struct FromAny<'a>(&'a mut Backend); + +impl<'a> FromAny<'a> { + pub(super) fn value(self, v: T) -> Result<(), KeyValueError> + where + T: ToValue, + { + v.to_value().inner.visit(self.0) + } + + /// Convert a formattable type into a value. + pub fn debug(self, v: T) -> Result<(), KeyValueError> + where + T: fmt::Debug + { + self.0.fmt(format_args!("{:?}", v)) + } + + /// Convert a `u64` into a value. + pub fn u64(self, v: u64) -> Result<(), KeyValueError> { + self.0.u64(v) + } + + /// Convert a `i64` into a value. + pub fn i64(self, v: i64) -> Result<(), KeyValueError> { + self.0.i64(v) + } + + /// Convert a `f64` into a value. + pub fn f64(self, v: f64) -> Result<(), KeyValueError> { + self.0.f64(v) + } + + /// Convert a `bool` into a value. + pub fn bool(self, v: bool) -> Result<(), KeyValueError> { + self.0.bool(v) + } + + /// Convert a `char` into a value. + pub fn char(self, v: char) -> Result<(), KeyValueError> { + self.0.char(v) + } + + /// Convert an empty type into a value. + pub fn none(self) -> Result<(), KeyValueError> { + self.0.none() + } + + /// Convert a string into a value. + pub fn str(self, v: &str) -> Result<(), KeyValueError> { + self.0.str(v) + } +} + +// `Any<'a>` is very similar to `std::fmt::Arguments<'a>` +// It takes a &T and fn pointer and stores them in an erased structure. +// It's a bit like an ad-hoc trait object that can accept any arbitrary +// value without those values needing to implement any traits. + +#[derive(Clone, Copy)] +pub(super) struct Any<'a> { + data: &'a Void, + from: FromAnyFn, +} + +// FIXME: This would be more correct as an extern type +// Replace once the `extern_types` feature is stable +// and available +struct Void { + _priv: (), + _oibit_remover: PhantomData<*mut Fn()>, +} + +impl<'a> Any<'a> { + pub(super) fn new(data: &'a T, from: FromAnyFn) -> Self { + unsafe { + Any { + data: mem::transmute::<&'a T, &'a Void>(data), + from: mem::transmute::, FromAnyFn>(from), + } + } + } + + pub(super) fn visit(&self, backend: &mut Backend) -> Result<(), KeyValueError> { + (self.from)(FromAny(backend), self.data) + } +} diff --git a/src/key_values/value/backend.rs b/src/key_values/value/backend.rs new file mode 100644 index 000000000..a378581dd --- /dev/null +++ b/src/key_values/value/backend.rs @@ -0,0 +1,62 @@ +use std::fmt; + +use super::KeyValueError; + +// `Backend` is an internal visitor for the structure of a value. +// Right now we only have an implementation for `std::fmt`, but +// this trait makes it possible to add more structured backends like +// `serde` that can retain some of that original structure. +// +// `Backend` isn't expected to be public, so that `log` can hide its +// internal serialization contract. This keeps its public API small +// and gives us room to move while the API is still evolving. +// For a public API, see the `FromAny` type. + +pub(super) trait Backend { + fn fmt(&mut self, v: fmt::Arguments) -> Result<(), KeyValueError>; + fn u64(&mut self, v: u64) -> Result<(), KeyValueError>; + fn i64(&mut self, v: i64) -> Result<(), KeyValueError>; + fn f64(&mut self, v: f64) -> Result<(), KeyValueError>; + fn bool(&mut self, v: bool) -> Result<(), KeyValueError>; + fn char(&mut self, v: char) -> Result<(), KeyValueError>; + fn str(&mut self, v: &str) -> Result<(), KeyValueError>; + fn none(&mut self) -> Result<(), KeyValueError>; +} + +pub(super) struct FmtBackend<'a, 'b: 'a>(pub(super) &'a mut fmt::Formatter<'b>); + +impl<'a, 'b: 'a> Backend for FmtBackend<'a, 'b> { + fn fmt(&mut self, v: fmt::Arguments) -> Result<(), KeyValueError> { + fmt::Debug::fmt(&v, self.0)?; + + Ok(()) + } + + fn u64(&mut self, v: u64) -> Result<(), KeyValueError> { + self.fmt(format_args!("{:?}", v)) + } + + fn i64(&mut self, v: i64) -> Result<(), KeyValueError> { + self.fmt(format_args!("{:?}", v)) + } + + fn f64(&mut self, v: f64) -> Result<(), KeyValueError> { + self.fmt(format_args!("{:?}", v)) + } + + fn bool(&mut self, v: bool) -> Result<(), KeyValueError> { + self.fmt(format_args!("{:?}", v)) + } + + fn char(&mut self, v: char) -> Result<(), KeyValueError> { + self.fmt(format_args!("{:?}", v)) + } + + fn str(&mut self, v: &str) -> Result<(), KeyValueError> { + self.fmt(format_args!("{:?}", v)) + } + + fn none(&mut self) -> Result<(), KeyValueError> { + self.fmt(format_args!("{:?}", Option::None::<()>)) + } +} diff --git a/src/key_values/value/impls.rs b/src/key_values/value/impls.rs new file mode 100644 index 000000000..c63b2346b --- /dev/null +++ b/src/key_values/value/impls.rs @@ -0,0 +1,287 @@ +use std::fmt; + +use super::{ToValue, Value}; + +impl ToValue for u8 { + fn to_value(&self) -> Value { + Value::from_any(self, |from, value| from.u64(*value as u64)) + } +} + +impl ToValue for u16 { + fn to_value(&self) -> Value { + Value::from_any(self, |from, value| from.u64(*value as u64)) + } +} + +impl ToValue for u32 { + fn to_value(&self) -> Value { + Value::from_any(self, |from, value| from.u64(*value as u64)) + } +} + +impl ToValue for u64 { + fn to_value(&self) -> Value { + Value::from_any(self, |from, value| from.u64(*value)) + } +} + +impl ToValue for i8 { + fn to_value(&self) -> Value { + Value::from_any(self, |from, value| from.i64(*value as i64)) + } +} + +impl ToValue for i16 { + fn to_value(&self) -> Value { + Value::from_any(self, |from, value| from.i64(*value as i64)) + } +} + +impl ToValue for i32 { + fn to_value(&self) -> Value { + Value::from_any(self, |from, value| from.i64(*value as i64)) + } +} + +impl ToValue for i64 { + fn to_value(&self) -> Value { + Value::from_any(self, |from, value| from.i64(*value)) + } +} + +impl ToValue for f32 { + fn to_value(&self) -> Value { + Value::from_any(self, |from, value| from.f64(*value as f64)) + } +} + +impl ToValue for f64 { + fn to_value(&self) -> Value { + Value::from_any(self, |from, value| from.f64(*value)) + } +} + +impl ToValue for bool { + fn to_value(&self) -> Value { + Value::from_any(self, |from, value| from.bool(*value)) + } +} + +impl ToValue for char { + fn to_value(&self) -> Value { + Value::from_any(self, |from, value| from.char(*value)) + } +} + +impl<'v> ToValue for &'v str { + fn to_value(&self) -> Value { + Value::from_any(self, |from, value| from.str(value)) + } +} + +impl ToValue for () { + fn to_value(&self) -> Value { + Value::from_any(self, |from, _| from.none()) + } +} + +impl ToValue for Option +where + T: ToValue, +{ + fn to_value(&self) -> Value { + Value::from_any(self, |from, value| { + match *value { + Some(ref value) => from.value(value), + None => from.none(), + } + }) + } +} + +impl<'v> ToValue for fmt::Arguments<'v> { + fn to_value(&self) -> Value { + Value::from_any(self, |from, value| from.debug(value)) + } +} + +#[cfg(feature = "std")] +mod std_support { + use super::*; + + use std::borrow::Cow; + + impl ToValue for Box + where + T: ToValue + ?Sized, + { + fn to_value(&self) -> Value { + (**self).to_value() + } + } + + impl ToValue for String { + fn to_value(&self) -> Value { + Value::from_any(self, |from, value| from.str(&*value)) + } + } + + impl<'a> ToValue for Cow<'a, str> { + fn to_value(&self) -> Value { + Value::from_any(self, |from, value| from.str(&*value)) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use key_values::value::KeyValueError; + use key_values::value::backend::Backend; + + use std::fmt::Write; + use std::str::{self, Utf8Error}; + + // A quick-and-dirty no-std buffer + // to write strings into + struct Buffer { + buf: [u8; 16], + len: usize, + } + + impl Buffer { + fn new() -> Self { + Buffer { + buf: [0; 16], + len: 0, + } + } + + fn as_str(&self) -> Result<&str, Utf8Error> { + str::from_utf8(&self.buf[0..self.len]) + } + } + + impl Write for Buffer { + fn write_str(&mut self, s: &str) -> fmt::Result { + let bytes = s.as_bytes(); + + let end = self.len + bytes.len(); + + if end > 16 { + panic!("`{}` would overflow", s); + } + + let buf = &mut self.buf[self.len..end]; + buf.copy_from_slice(bytes); + self.len = end; + + Ok(()) + } + } + + #[test] + fn test_to_value_display() { + // Write a value into our buffer using `::fmt` + fn check(value: Value, expected: &str) { + let mut buf = Buffer::new(); + write!(&mut buf, "{}", value).unwrap(); + + assert_eq!(expected, buf.as_str().unwrap()); + } + + check(42u64.to_value(), "42"); + check(42i64.to_value(), "42"); + check(42.01f64.to_value(), "42.01"); + check(true.to_value(), "true"); + check('a'.to_value(), "'a'"); + check(format_args!("a {}", "value").to_value(), "a value"); + check("a loong string".to_value(), "\"a loong string\""); + check(Some(true).to_value(), "true"); + check(().to_value(), "None"); + check(Option::None::.to_value(), "None"); + } + + #[test] + fn test_to_value_structured() { + #[derive(Debug, PartialEq)] + enum Token<'a> { + U64(u64), + I64(i64), + F64(f64), + Char(char), + Bool(bool), + Str(&'a str), + None, + } + + struct TestBackend(F); + + impl Backend for TestBackend + where + F: Fn(Token), + { + fn fmt(&mut self, v: fmt::Arguments) -> Result<(), KeyValueError> { + let mut buf = Buffer::new(); + write!(&mut buf, "{}", v)?; + + let s = buf.as_str().map_err(|_| KeyValueError::msg("invalid UTF8"))?; + (self.0)(Token::Str(s)); + Ok(()) + } + + fn u64(&mut self, v: u64) -> Result<(), KeyValueError> { + (self.0)(Token::U64(v)); + Ok(()) + } + + fn i64(&mut self, v: i64) -> Result<(), KeyValueError> { + (self.0)(Token::I64(v)); + Ok(()) + } + + fn f64(&mut self, v: f64) -> Result<(), KeyValueError> { + (self.0)(Token::F64(v)); + Ok(()) + } + + fn bool(&mut self, v: bool) -> Result<(), KeyValueError> { + (self.0)(Token::Bool(v)); + Ok(()) + } + + fn char(&mut self, v: char) -> Result<(), KeyValueError> { + (self.0)(Token::Char(v)); + Ok(()) + } + + fn str(&mut self, v: &str) -> Result<(), KeyValueError> { + (self.0)(Token::Str(v)); + Ok(()) + } + + fn none(&mut self) -> Result<(), KeyValueError> { + (self.0)(Token::None); + Ok(()) + } + } + + // Check that a value retains the right structure + fn check(value: Value, expected: Token) { + let mut backend = TestBackend(|token: Token| assert_eq!(expected, token)); + value.inner.visit(&mut backend).unwrap(); + } + + check(42u64.to_value(), Token::U64(42)); + check(42i64.to_value(), Token::I64(42)); + check(42.01f64.to_value(), Token::F64(42.01)); + check(true.to_value(), Token::Bool(true)); + check('a'.to_value(), Token::Char('a')); + check(format_args!("a {}", "value").to_value(), Token::Str("a value")); + check("a loong string".to_value(), Token::Str("a loong string")); + check(Some(true).to_value(), Token::Bool(true)); + check(().to_value(), Token::None); + check(Option::None::.to_value(), Token::None); + } +} \ No newline at end of file diff --git a/src/key_values/value/mod.rs b/src/key_values/value/mod.rs new file mode 100644 index 000000000..9298f8989 --- /dev/null +++ b/src/key_values/value/mod.rs @@ -0,0 +1,73 @@ +//! Structured values. + +use std::fmt; + +mod any; +mod backend; +mod impls; + +pub use key_values::KeyValueError; + +use self::any::{Any, FromAnyFn}; + +/// 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: Any<'v>, +} + +impl<'v> Value<'v> { + // FIXME: The `from_any` API is intended to be public. + // Its implications need discussion first though. + fn from_any(v: &'v T, from: FromAnyFn) -> Self { + Value { + inner: Any::new(v, from) + } + } + + /// Get a value from a formattable type. + pub fn from_debug(value: &'v T) -> Self + where + T: fmt::Debug, + { + Self::from_any(value, |from, value| from.debug(value)) + } +} + +impl<'v> fmt::Debug for Value<'v> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.visit(&mut self::backend::FmtBackend(f))?; + + Ok(()) + } +} + +impl<'v> fmt::Display for Value<'v> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.visit(&mut self::backend::FmtBackend(f))?; + + Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 42e579561..17f61ba44 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -307,6 +307,9 @@ use std::sync::atomic::ATOMIC_USIZE_INIT; mod macros; mod serde; +#[cfg(feature = "kv_unstable")] +pub mod key_values; + // 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: &'static Log = &NopLogger; @@ -725,6 +728,19 @@ pub struct Record<'a> { module_path: Option<&'a str>, file: Option<&'a str>, line: Option, + #[cfg(feature = "kv_unstable")] + key_values: KeyValues<'a>, +} + +#[cfg(feature = "kv_unstable")] +#[derive(Clone)] +struct KeyValues<'a>(&'a key_values::Source); + +#[cfg(feature = "kv_unstable")] +impl<'a> fmt::Debug for KeyValues<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("KeyValues").finish() + } } impl<'a> Record<'a> { @@ -775,6 +791,47 @@ impl<'a> Record<'a> { pub fn line(&self) -> Option { self.line } + + /// The structued key-value pairs associated with the message. + #[cfg(feature = "kv_unstable")] + #[inline] + pub fn key_values(&self) -> &key_values::Source { + self.key_values.0 + } + + /// Create a new [`Builder`](struct.Builder.html) based on this record. + #[cfg(feature = "kv_unstable")] + #[inline] + pub fn to_builder(&self) -> RecordBuilder { + #[cfg(feature = "kv_unstable")] + return RecordBuilder { + record: Record { + metadata: Metadata { + level: self.metadata.level, + target: self.metadata.target, + }, + args: self.args, + module_path: self.module_path, + file: self.file, + line: self.line, + key_values: self.key_values.clone(), + } + }; + + #[cfg(not(feature = "kv_unstable"))] + return RecordBuilder { + record: Record { + metadata: Metadata { + level: self.metadata.level, + target: self.metadata.target, + }, + args: self.args, + module_path: self.module_path, + file: self.file, + line: self.line, + } + }; + } } /// Builder for [`Record`](struct.Record.html). @@ -837,15 +894,28 @@ impl<'a> RecordBuilder<'a> { /// [`Metadata::builder().build()`]: struct.MetadataBuilder.html#method.build #[inline] pub fn new() -> RecordBuilder<'a> { - RecordBuilder { + #[cfg(feature = "kv_unstable")] + return RecordBuilder { record: Record { args: format_args!(""), metadata: Metadata::builder().build(), module_path: None, file: None, line: None, + key_values: KeyValues(&Option::None::<(key_values::Key, key_values::Value)>), }, - } + }; + + #[cfg(not(feature = "kv_unstable"))] + return RecordBuilder { + record: Record { + args: format_args!(""), + metadata: Metadata::builder().build(), + module_path: None, + file: None, + line: None, + }, + }; } /// Set [`args`](struct.Record.html#method.args). @@ -897,6 +967,14 @@ impl<'a> RecordBuilder<'a> { self } + /// Set [`key_values`](struct.Record.html#method.key_values) + #[cfg(feature = "kv_unstable")] + #[inline] + pub fn key_values(&mut self, kvs: &'a key_values::Source) -> &mut RecordBuilder<'a> { + self.record.key_values = KeyValues(kvs); + self + } + /// Invoke the builder and return a `Record` #[inline] pub fn build(&self) -> Record<'a> { @@ -1523,4 +1601,42 @@ mod tests { assert_eq!(record_test.file(), Some("bar")); assert_eq!(record_test.line(), Some(30)); } + + #[test] + #[cfg(feature = "kv_unstable")] + fn test_record_key_values_builder() { + use super::Record; + use key_values::source::{self, Visitor}; + + struct TestVisitor { + seen_pairs: usize, + } + + impl<'kvs> Visitor<'kvs> for TestVisitor { + fn visit_pair( + &mut self, + _: source::Key<'kvs>, + _: source::Value<'kvs> + ) -> Result<(), source::KeyValueError> { + self.seen_pairs += 1; + Ok(()) + } + } + + let kvs: &[(&str, i32)] = &[ + ("a", 1), + ("b", 2) + ]; + let record_test = Record::builder() + .key_values(&kvs) + .build(); + + let mut visitor = TestVisitor { + seen_pairs: 0, + }; + + record_test.key_values().visit(&mut visitor).unwrap(); + + assert_eq!(2, visitor.seen_pairs); + } } From 6faac8af1efcf3fba873930aa05e78e1766904c9 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Thu, 18 Apr 2019 10:02:29 +1000 Subject: [PATCH 2/8] address initial PR feedback - fix trailing file newlines - tweak KeyValuesError type not to rely on deprecated Error APIs - change ToKey impl from &str to str - hide the sub-modules under key_values - add a Visitor impl for Box --- src/key_values/error.rs | 8 ++------ src/key_values/key.rs | 6 +++--- src/key_values/mod.rs | 12 ++++++------ src/key_values/source.rs | 16 +++++++++++----- src/key_values/value/impls.rs | 2 +- src/key_values/value/mod.rs | 2 +- src/lib.rs | 2 ++ 7 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/key_values/error.rs b/src/key_values/error.rs index e45a7a82e..ad9ccc684 100644 --- a/src/key_values/error.rs +++ b/src/key_values/error.rs @@ -40,11 +40,7 @@ mod std_support { impl error::Error for KeyValueError { fn description(&self) -> &str { - self.msg - } - - fn cause(&self) -> Option<&error::Error> { - None + "key_values error" } } -} \ No newline at end of file +} diff --git a/src/key_values/key.rs b/src/key_values/key.rs index 33ccd1f51..82f1e85e6 100644 --- a/src/key_values/key.rs +++ b/src/key_values/key.rs @@ -7,7 +7,7 @@ use std::borrow::Borrow; /// A type that can be converted into a [`Key`](struct.Key.html). pub trait ToKey { - /// Perform the covnersion. + /// Perform the conversion. fn to_key(&self) -> Key; } @@ -28,7 +28,7 @@ impl<'k> ToKey for Key<'k> { } } -impl<'k> ToKey for &'k str { +impl ToKey for str { fn to_key(&self) -> Key { Key::from_str(self) } @@ -140,4 +140,4 @@ mod tests { fn key_from_string() { assert_eq!("a key", Key::from_str("a key").as_str()); } -} \ No newline at end of file +} diff --git a/src/key_values/mod.rs b/src/key_values/mod.rs index da8505776..35c88f0b6 100644 --- a/src/key_values/mod.rs +++ b/src/key_values/mod.rs @@ -1,11 +1,11 @@ //! Structured key-value pairs. mod error; -pub mod source; -pub mod key; -pub mod value; +mod source; +mod key; +mod value; pub use self::error::KeyValueError; -pub use self::source::Source; -pub use self::key::Key; -pub use self::value::Value; +pub use self::source::{Source, Visitor}; +pub use self::key::{Key, ToKey}; +pub use self::value::{Value, ToValue}; diff --git a/src/key_values/source.rs b/src/key_values/source.rs index b0a49ac28..29ed3146a 100644 --- a/src/key_values/source.rs +++ b/src/key_values/source.rs @@ -1,9 +1,6 @@ //! Sources for key-value pairs. -pub use key_values::{KeyValueError, Key, Value}; - -use key_values::key::ToKey; -use key_values::value::ToValue; +use key_values::{KeyValueError, Key, ToKey, Value, ToValue}; /// A source of key-value pairs. /// @@ -98,6 +95,15 @@ mod std_support { (**self).visit(visitor) } } + + impl<'kvs, V> Visitor<'kvs> for Box + where + V: Visitor<'kvs> + ?Sized, + { + fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), KeyValueError> { + (**self).visit_pair(key, value) + } + } } #[cfg(test)] @@ -113,4 +119,4 @@ mod tests { fn visitor_is_object_safe() { fn _check(_: &Visitor) {} } -} \ No newline at end of file +} diff --git a/src/key_values/value/impls.rs b/src/key_values/value/impls.rs index c63b2346b..d854fc65c 100644 --- a/src/key_values/value/impls.rs +++ b/src/key_values/value/impls.rs @@ -284,4 +284,4 @@ mod tests { check(().to_value(), Token::None); check(Option::None::.to_value(), Token::None); } -} \ No newline at end of file +} diff --git a/src/key_values/value/mod.rs b/src/key_values/value/mod.rs index 9298f8989..f988f4e7b 100644 --- a/src/key_values/value/mod.rs +++ b/src/key_values/value/mod.rs @@ -6,7 +6,7 @@ mod any; mod backend; mod impls; -pub use key_values::KeyValueError; +use key_values::KeyValueError; use self::any::{Any, FromAnyFn}; diff --git a/src/lib.rs b/src/lib.rs index 17f61ba44..f5bc15719 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -732,6 +732,8 @@ pub struct Record<'a> { key_values: KeyValues<'a>, } +// This wrapper type is only needed so we can +// `#[derive(Debug)]` on `Record`. #[cfg(feature = "kv_unstable")] #[derive(Clone)] struct KeyValues<'a>(&'a key_values::Source); From 53f0eaca7242fc665c36ef57f856d93d26d93d65 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Thu, 18 Apr 2019 15:11:58 +1000 Subject: [PATCH 3/8] rename key_values module to kv --- src/{key_values => kv}/error.rs | 0 src/{key_values => kv}/key.rs | 0 src/{key_values => kv}/mod.rs | 0 src/{key_values => kv}/source.rs | 2 +- src/{key_values => kv}/value/any.rs | 0 src/{key_values => kv}/value/backend.rs | 0 src/{key_values => kv}/value/impls.rs | 4 ++-- src/{key_values => kv}/value/mod.rs | 2 +- src/lib.rs | 18 +++++++++--------- 9 files changed, 13 insertions(+), 13 deletions(-) rename src/{key_values => kv}/error.rs (100%) rename src/{key_values => kv}/key.rs (100%) rename src/{key_values => kv}/mod.rs (100%) rename src/{key_values => kv}/source.rs (97%) rename src/{key_values => kv}/value/any.rs (100%) rename src/{key_values => kv}/value/backend.rs (100%) rename src/{key_values => kv}/value/impls.rs (98%) rename src/{key_values => kv}/value/mod.rs (97%) diff --git a/src/key_values/error.rs b/src/kv/error.rs similarity index 100% rename from src/key_values/error.rs rename to src/kv/error.rs diff --git a/src/key_values/key.rs b/src/kv/key.rs similarity index 100% rename from src/key_values/key.rs rename to src/kv/key.rs diff --git a/src/key_values/mod.rs b/src/kv/mod.rs similarity index 100% rename from src/key_values/mod.rs rename to src/kv/mod.rs diff --git a/src/key_values/source.rs b/src/kv/source.rs similarity index 97% rename from src/key_values/source.rs rename to src/kv/source.rs index 29ed3146a..9861afcb2 100644 --- a/src/key_values/source.rs +++ b/src/kv/source.rs @@ -1,6 +1,6 @@ //! Sources for key-value pairs. -use key_values::{KeyValueError, Key, ToKey, Value, ToValue}; +use kv::{KeyValueError, Key, ToKey, Value, ToValue}; /// A source of key-value pairs. /// diff --git a/src/key_values/value/any.rs b/src/kv/value/any.rs similarity index 100% rename from src/key_values/value/any.rs rename to src/kv/value/any.rs diff --git a/src/key_values/value/backend.rs b/src/kv/value/backend.rs similarity index 100% rename from src/key_values/value/backend.rs rename to src/kv/value/backend.rs diff --git a/src/key_values/value/impls.rs b/src/kv/value/impls.rs similarity index 98% rename from src/key_values/value/impls.rs rename to src/kv/value/impls.rs index d854fc65c..ece0f6e72 100644 --- a/src/key_values/value/impls.rs +++ b/src/kv/value/impls.rs @@ -137,8 +137,8 @@ mod std_support { #[cfg(test)] mod tests { use super::*; - use key_values::value::KeyValueError; - use key_values::value::backend::Backend; + use kv::value::KeyValueError; + use kv::value::backend::Backend; use std::fmt::Write; use std::str::{self, Utf8Error}; diff --git a/src/key_values/value/mod.rs b/src/kv/value/mod.rs similarity index 97% rename from src/key_values/value/mod.rs rename to src/kv/value/mod.rs index f988f4e7b..0450d3152 100644 --- a/src/key_values/value/mod.rs +++ b/src/kv/value/mod.rs @@ -6,7 +6,7 @@ mod any; mod backend; mod impls; -use key_values::KeyValueError; +use kv::KeyValueError; use self::any::{Any, FromAnyFn}; diff --git a/src/lib.rs b/src/lib.rs index f5bc15719..7575a6c42 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -308,7 +308,7 @@ mod macros; mod serde; #[cfg(feature = "kv_unstable")] -pub mod key_values; +pub mod kv; // 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. @@ -736,7 +736,7 @@ pub struct Record<'a> { // `#[derive(Debug)]` on `Record`. #[cfg(feature = "kv_unstable")] #[derive(Clone)] -struct KeyValues<'a>(&'a key_values::Source); +struct KeyValues<'a>(&'a kv::Source); #[cfg(feature = "kv_unstable")] impl<'a> fmt::Debug for KeyValues<'a> { @@ -797,7 +797,7 @@ impl<'a> Record<'a> { /// The structued key-value pairs associated with the message. #[cfg(feature = "kv_unstable")] #[inline] - pub fn key_values(&self) -> &key_values::Source { + pub fn key_values(&self) -> &kv::Source { self.key_values.0 } @@ -904,7 +904,7 @@ impl<'a> RecordBuilder<'a> { module_path: None, file: None, line: None, - key_values: KeyValues(&Option::None::<(key_values::Key, key_values::Value)>), + key_values: KeyValues(&Option::None::<(kv::Key, kv::Value)>), }, }; @@ -972,7 +972,7 @@ impl<'a> RecordBuilder<'a> { /// Set [`key_values`](struct.Record.html#method.key_values) #[cfg(feature = "kv_unstable")] #[inline] - pub fn key_values(&mut self, kvs: &'a key_values::Source) -> &mut RecordBuilder<'a> { + pub fn key_values(&mut self, kvs: &'a kv::Source) -> &mut RecordBuilder<'a> { self.record.key_values = KeyValues(kvs); self } @@ -1608,7 +1608,7 @@ mod tests { #[cfg(feature = "kv_unstable")] fn test_record_key_values_builder() { use super::Record; - use key_values::source::{self, Visitor}; + use kv::{self, Visitor}; struct TestVisitor { seen_pairs: usize, @@ -1617,9 +1617,9 @@ mod tests { impl<'kvs> Visitor<'kvs> for TestVisitor { fn visit_pair( &mut self, - _: source::Key<'kvs>, - _: source::Value<'kvs> - ) -> Result<(), source::KeyValueError> { + _: kv::Key<'kvs>, + _: kv::Value<'kvs> + ) -> Result<(), kv::KeyValueError> { self.seen_pairs += 1; Ok(()) } From ee05032759cf2fd6c04b6501b8c35b8e2e3942a7 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Thu, 18 Apr 2019 16:00:36 +1000 Subject: [PATCH 4/8] refactor Value internals to use trait objects --- src/kv/value/any.rs | 97 ----------------------- src/kv/value/backend.rs | 62 --------------- src/kv/value/impls.rs | 165 +++++++++++++++++++++++++++++++-------- src/kv/value/internal.rs | 86 ++++++++++++++++++++ src/kv/value/mod.rs | 29 ++++--- 5 files changed, 238 insertions(+), 201 deletions(-) delete mode 100644 src/kv/value/any.rs delete mode 100644 src/kv/value/backend.rs create mode 100644 src/kv/value/internal.rs diff --git a/src/kv/value/any.rs b/src/kv/value/any.rs deleted file mode 100644 index 04baf4844..000000000 --- a/src/kv/value/any.rs +++ /dev/null @@ -1,97 +0,0 @@ -use std::{fmt, mem}; -use std::marker::PhantomData; - -use super::{ToValue, KeyValueError}; -use super::backend::Backend; - -/// A function for converting some type `T` into a [`Value`](struct.Value.html). -pub type FromAnyFn = fn(FromAny, &T) -> Result<(), KeyValueError>; - -/// A helper for converting any type into a [`Value`](struct.Value.html). -pub struct FromAny<'a>(&'a mut Backend); - -impl<'a> FromAny<'a> { - pub(super) fn value(self, v: T) -> Result<(), KeyValueError> - where - T: ToValue, - { - v.to_value().inner.visit(self.0) - } - - /// Convert a formattable type into a value. - pub fn debug(self, v: T) -> Result<(), KeyValueError> - where - T: fmt::Debug - { - self.0.fmt(format_args!("{:?}", v)) - } - - /// Convert a `u64` into a value. - pub fn u64(self, v: u64) -> Result<(), KeyValueError> { - self.0.u64(v) - } - - /// Convert a `i64` into a value. - pub fn i64(self, v: i64) -> Result<(), KeyValueError> { - self.0.i64(v) - } - - /// Convert a `f64` into a value. - pub fn f64(self, v: f64) -> Result<(), KeyValueError> { - self.0.f64(v) - } - - /// Convert a `bool` into a value. - pub fn bool(self, v: bool) -> Result<(), KeyValueError> { - self.0.bool(v) - } - - /// Convert a `char` into a value. - pub fn char(self, v: char) -> Result<(), KeyValueError> { - self.0.char(v) - } - - /// Convert an empty type into a value. - pub fn none(self) -> Result<(), KeyValueError> { - self.0.none() - } - - /// Convert a string into a value. - pub fn str(self, v: &str) -> Result<(), KeyValueError> { - self.0.str(v) - } -} - -// `Any<'a>` is very similar to `std::fmt::Arguments<'a>` -// It takes a &T and fn pointer and stores them in an erased structure. -// It's a bit like an ad-hoc trait object that can accept any arbitrary -// value without those values needing to implement any traits. - -#[derive(Clone, Copy)] -pub(super) struct Any<'a> { - data: &'a Void, - from: FromAnyFn, -} - -// FIXME: This would be more correct as an extern type -// Replace once the `extern_types` feature is stable -// and available -struct Void { - _priv: (), - _oibit_remover: PhantomData<*mut Fn()>, -} - -impl<'a> Any<'a> { - pub(super) fn new(data: &'a T, from: FromAnyFn) -> Self { - unsafe { - Any { - data: mem::transmute::<&'a T, &'a Void>(data), - from: mem::transmute::, FromAnyFn>(from), - } - } - } - - pub(super) fn visit(&self, backend: &mut Backend) -> Result<(), KeyValueError> { - (self.from)(FromAny(backend), self.data) - } -} diff --git a/src/kv/value/backend.rs b/src/kv/value/backend.rs deleted file mode 100644 index a378581dd..000000000 --- a/src/kv/value/backend.rs +++ /dev/null @@ -1,62 +0,0 @@ -use std::fmt; - -use super::KeyValueError; - -// `Backend` is an internal visitor for the structure of a value. -// Right now we only have an implementation for `std::fmt`, but -// this trait makes it possible to add more structured backends like -// `serde` that can retain some of that original structure. -// -// `Backend` isn't expected to be public, so that `log` can hide its -// internal serialization contract. This keeps its public API small -// and gives us room to move while the API is still evolving. -// For a public API, see the `FromAny` type. - -pub(super) trait Backend { - fn fmt(&mut self, v: fmt::Arguments) -> Result<(), KeyValueError>; - fn u64(&mut self, v: u64) -> Result<(), KeyValueError>; - fn i64(&mut self, v: i64) -> Result<(), KeyValueError>; - fn f64(&mut self, v: f64) -> Result<(), KeyValueError>; - fn bool(&mut self, v: bool) -> Result<(), KeyValueError>; - fn char(&mut self, v: char) -> Result<(), KeyValueError>; - fn str(&mut self, v: &str) -> Result<(), KeyValueError>; - fn none(&mut self) -> Result<(), KeyValueError>; -} - -pub(super) struct FmtBackend<'a, 'b: 'a>(pub(super) &'a mut fmt::Formatter<'b>); - -impl<'a, 'b: 'a> Backend for FmtBackend<'a, 'b> { - fn fmt(&mut self, v: fmt::Arguments) -> Result<(), KeyValueError> { - fmt::Debug::fmt(&v, self.0)?; - - Ok(()) - } - - fn u64(&mut self, v: u64) -> Result<(), KeyValueError> { - self.fmt(format_args!("{:?}", v)) - } - - fn i64(&mut self, v: i64) -> Result<(), KeyValueError> { - self.fmt(format_args!("{:?}", v)) - } - - fn f64(&mut self, v: f64) -> Result<(), KeyValueError> { - self.fmt(format_args!("{:?}", v)) - } - - fn bool(&mut self, v: bool) -> Result<(), KeyValueError> { - self.fmt(format_args!("{:?}", v)) - } - - fn char(&mut self, v: char) -> Result<(), KeyValueError> { - self.fmt(format_args!("{:?}", v)) - } - - fn str(&mut self, v: &str) -> Result<(), KeyValueError> { - self.fmt(format_args!("{:?}", v)) - } - - fn none(&mut self) -> Result<(), KeyValueError> { - self.fmt(format_args!("{:?}", Option::None::<()>)) - } -} diff --git a/src/kv/value/impls.rs b/src/kv/value/impls.rs index ece0f6e72..a78498541 100644 --- a/src/kv/value/impls.rs +++ b/src/kv/value/impls.rs @@ -1,88 +1,172 @@ use std::fmt; -use super::{ToValue, Value}; +use super::{KeyValueError, ToValue, Value, Visit, Visitor}; impl ToValue for u8 { fn to_value(&self) -> Value { - Value::from_any(self, |from, value| from.u64(*value as u64)) + Value::from_internal(self) + } +} + +impl Visit for u8 { + fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + visitor.u64(*self as u64) } } impl ToValue for u16 { fn to_value(&self) -> Value { - Value::from_any(self, |from, value| from.u64(*value as u64)) + Value::from_internal(self) + } +} + +impl Visit for u16 { + fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + visitor.u64(*self as u64) } } impl ToValue for u32 { fn to_value(&self) -> Value { - Value::from_any(self, |from, value| from.u64(*value as u64)) + Value::from_internal(self) + } +} + +impl Visit for u32 { + fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + visitor.u64(*self as u64) } } impl ToValue for u64 { fn to_value(&self) -> Value { - Value::from_any(self, |from, value| from.u64(*value)) + Value::from_internal(self) + } +} + +impl Visit for u64 { + fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + visitor.u64(*self) } } impl ToValue for i8 { fn to_value(&self) -> Value { - Value::from_any(self, |from, value| from.i64(*value as i64)) + Value::from_internal(self) + } +} + +impl Visit for i8 { + fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + visitor.i64(*self as i64) } } impl ToValue for i16 { fn to_value(&self) -> Value { - Value::from_any(self, |from, value| from.i64(*value as i64)) + Value::from_internal(self) + } +} + +impl Visit for i16 { + fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + visitor.i64(*self as i64) } } impl ToValue for i32 { fn to_value(&self) -> Value { - Value::from_any(self, |from, value| from.i64(*value as i64)) + Value::from_internal(self) + } +} + +impl Visit for i32 { + fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + visitor.i64(*self as i64) } } impl ToValue for i64 { fn to_value(&self) -> Value { - Value::from_any(self, |from, value| from.i64(*value)) + Value::from_internal(self) + } +} + +impl Visit for i64 { + fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + visitor.i64(*self) } } impl ToValue for f32 { fn to_value(&self) -> Value { - Value::from_any(self, |from, value| from.f64(*value as f64)) + Value::from_internal(self) + } +} + +impl Visit for f32 { + fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + visitor.f64(*self as f64) } } impl ToValue for f64 { fn to_value(&self) -> Value { - Value::from_any(self, |from, value| from.f64(*value)) + Value::from_internal(self) + } +} + +impl Visit for f64 { + fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + visitor.f64(*self) } } impl ToValue for bool { fn to_value(&self) -> Value { - Value::from_any(self, |from, value| from.bool(*value)) + Value::from_internal(self) + } +} + +impl Visit for bool { + fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + visitor.bool(*self) } } impl ToValue for char { fn to_value(&self) -> Value { - Value::from_any(self, |from, value| from.char(*value)) + Value::from_internal(self) + } +} + +impl Visit for char { + fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + visitor.char(*self) } } impl<'v> ToValue for &'v str { fn to_value(&self) -> Value { - Value::from_any(self, |from, value| from.str(value)) + Value::from_internal(self) + } +} + +impl<'v> Visit for &'v str { + fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + visitor.str(*self) } } impl ToValue for () { fn to_value(&self) -> Value { - Value::from_any(self, |from, _| from.none()) + Value::from_internal(self) + } +} + +impl Visit for () { + fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + visitor.none() } } @@ -91,18 +175,25 @@ where T: ToValue, { fn to_value(&self) -> Value { - Value::from_any(self, |from, value| { - match *value { - Some(ref value) => from.value(value), - None => from.none(), - } - }) + Value::from_internal(self) + } +} + +impl Visit for Option +where + T: ToValue, +{ + fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + match *self { + Some(ref value) => value.to_value().visit(visitor), + None => visitor.none(), + } } } impl<'v> ToValue for fmt::Arguments<'v> { fn to_value(&self) -> Value { - Value::from_any(self, |from, value| from.debug(value)) + Value::from_debug(self) } } @@ -123,13 +214,25 @@ mod std_support { impl ToValue for String { fn to_value(&self) -> Value { - Value::from_any(self, |from, value| from.str(&*value)) + Value::from_internal(self) + } + } + + impl Visit for String { + fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + visitor.str(&*self) } } impl<'a> ToValue for Cow<'a, str> { fn to_value(&self) -> Value { - Value::from_any(self, |from, value| from.str(&*value)) + Value::from_internal(self) + } + } + + impl<'a> Visit for Cow<'a, str> { + fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + visitor.str(&*self) } } } @@ -138,7 +241,7 @@ mod std_support { mod tests { use super::*; use kv::value::KeyValueError; - use kv::value::backend::Backend; + use kv::value::internal::Visitor; use std::fmt::Write; use std::str::{self, Utf8Error}; @@ -216,15 +319,15 @@ mod tests { None, } - struct TestBackend(F); + struct TestVisitor(F); - impl Backend for TestBackend + impl Visitor for TestVisitor where F: Fn(Token), { - fn fmt(&mut self, v: fmt::Arguments) -> Result<(), KeyValueError> { + fn debug(&mut self, v: &fmt::Debug) -> Result<(), KeyValueError> { let mut buf = Buffer::new(); - write!(&mut buf, "{}", v)?; + write!(&mut buf, "{:?}", v)?; let s = buf.as_str().map_err(|_| KeyValueError::msg("invalid UTF8"))?; (self.0)(Token::Str(s)); @@ -269,8 +372,8 @@ mod tests { // Check that a value retains the right structure fn check(value: Value, expected: Token) { - let mut backend = TestBackend(|token: Token| assert_eq!(expected, token)); - value.inner.visit(&mut backend).unwrap(); + let mut visitor = TestVisitor(|token: Token| assert_eq!(expected, token)); + value.visit(&mut visitor).unwrap(); } check(42u64.to_value(), Token::U64(42)); diff --git a/src/kv/value/internal.rs b/src/kv/value/internal.rs new file mode 100644 index 000000000..4b1d91b73 --- /dev/null +++ b/src/kv/value/internal.rs @@ -0,0 +1,86 @@ +use std::fmt; + +use super::KeyValueError; + +// `Visit` and `Visitor` is an internal API for visiting the structure of a value. +// It's not intended to be public (at this stage). +// +// Right now we only have an implementation for `std::fmt`, but +// this trait makes it possible to add more structured backends like +// `serde` that can retain that original structure. + +/// A container for a structured value for a specific kind of visitor. +#[derive(Clone, Copy)] +pub(super) enum Inner<'v> { + /// An internal `Visit`. It'll be an internal structure-preserving + /// type from the standard library that's implemented in this crate. + Internal(&'v Visit), + /// A formattable value. + Debug(&'v fmt::Debug), +} + +impl<'v> Inner<'v> { + pub(super) fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + match *self { + Inner::Internal(ref value) => value.visit(visitor), + Inner::Debug(ref value) => visitor.debug(value), + } + } +} + +/// An internal structure-preserving value. +pub(super) trait Visit { + fn visit(&self, backend: &mut Visitor) -> Result<(), KeyValueError>; +} + +/// The internal serialization contract. +pub(super) trait Visitor { + fn debug(&mut self, v: &fmt::Debug) -> Result<(), KeyValueError>; + + fn u64(&mut self, v: u64) -> Result<(), KeyValueError>; + fn i64(&mut self, v: i64) -> Result<(), KeyValueError>; + fn f64(&mut self, v: f64) -> Result<(), KeyValueError>; + fn bool(&mut self, v: bool) -> Result<(), KeyValueError>; + fn char(&mut self, v: char) -> Result<(), KeyValueError>; + fn str(&mut self, v: &str) -> Result<(), KeyValueError>; + fn none(&mut self) -> Result<(), KeyValueError>; +} + +/// A visitor for `std::fmt`. +pub(super) struct FmtVisitor<'a, 'b: 'a>(pub(super) &'a mut fmt::Formatter<'b>); + +impl<'a, 'b: 'a> Visitor for FmtVisitor<'a, 'b> { + fn debug(&mut self, v: &fmt::Debug) -> Result<(), KeyValueError> { + v.fmt(self.0)?; + + Ok(()) + } + + fn u64(&mut self, v: u64) -> Result<(), KeyValueError> { + self.debug(&format_args!("{:?}", v)) + } + + fn i64(&mut self, v: i64) -> Result<(), KeyValueError> { + self.debug(&format_args!("{:?}", v)) + } + + fn f64(&mut self, v: f64) -> Result<(), KeyValueError> { + self.debug(&format_args!("{:?}", v)) + } + + fn bool(&mut self, v: bool) -> Result<(), KeyValueError> { + self.debug(&format_args!("{:?}", v)) + } + + fn char(&mut self, v: char) -> Result<(), KeyValueError> { + self.debug(&format_args!("{:?}", v)) + } + + fn str(&mut self, v: &str) -> Result<(), KeyValueError> { + self.debug(&format_args!("{:?}", v)) + } + + fn none(&mut self) -> Result<(), KeyValueError> { + self.debug(&format_args!("None")) + } +} diff --git a/src/kv/value/mod.rs b/src/kv/value/mod.rs index 0450d3152..727e89ef5 100644 --- a/src/kv/value/mod.rs +++ b/src/kv/value/mod.rs @@ -2,13 +2,12 @@ use std::fmt; -mod any; -mod backend; +mod internal; mod impls; use kv::KeyValueError; -use self::any::{Any, FromAnyFn}; +use self::internal::{Inner, Visit, Visitor}; /// A type that can be converted into a [`Value`](struct.Value.html). pub trait ToValue { @@ -35,15 +34,17 @@ impl<'v> ToValue for Value<'v> { /// A value in a structured key-value pair. pub struct Value<'v> { - inner: Any<'v>, + inner: Inner<'v>, } impl<'v> Value<'v> { - // FIXME: The `from_any` API is intended to be public. - // Its implications need discussion first though. - fn from_any(v: &'v T, from: FromAnyFn) -> Self { + /// Get a value from an internal `Visit`. + fn from_internal(value: &'v T) -> Self + where + T: Visit, + { Value { - inner: Any::new(v, from) + inner: Inner::Internal(value), } } @@ -52,13 +53,19 @@ impl<'v> Value<'v> { where T: fmt::Debug, { - Self::from_any(value, |from, value| from.debug(value)) + Value { + inner: Inner::Debug(value), + } + } + + fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + self.inner.visit(visitor) } } impl<'v> fmt::Debug for Value<'v> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.inner.visit(&mut self::backend::FmtBackend(f))?; + self.visit(&mut self::internal::FmtVisitor(f))?; Ok(()) } @@ -66,7 +73,7 @@ impl<'v> fmt::Debug for Value<'v> { impl<'v> fmt::Display for Value<'v> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.inner.visit(&mut self::backend::FmtBackend(f))?; + self.visit(&mut self::internal::FmtVisitor(f))?; Ok(()) } From 383d80bffe0aef0f625cbf766033f7a060510ffb Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Thu, 18 Apr 2019 16:56:34 +1000 Subject: [PATCH 5/8] provide a reasonable Debug impl for KeyValues on a Record --- src/lib.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7575a6c42..5a3606047 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -733,7 +733,9 @@ pub struct Record<'a> { } // This wrapper type is only needed so we can -// `#[derive(Debug)]` on `Record`. +// `#[derive(Debug)]` on `Record`. It also +// provides a useful `Debug` implementation for +// the underlying `Source`. #[cfg(feature = "kv_unstable")] #[derive(Clone)] struct KeyValues<'a>(&'a kv::Source); @@ -741,7 +743,21 @@ struct KeyValues<'a>(&'a kv::Source); #[cfg(feature = "kv_unstable")] impl<'a> fmt::Debug for KeyValues<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("KeyValues").finish() + use self::kv::{Key, Value, Visitor, KeyValueError}; + + struct FmtVisitor<'a, 'b: 'a>(fmt::DebugMap<'a, 'b>); + + impl<'a, 'b: 'a, 'kvs> Visitor<'kvs> for FmtVisitor<'a, 'b> { + fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), KeyValueError> { + self.0.entry(&key, &value); + + Ok(()) + } + } + + let mut visitor = FmtVisitor(f.debug_map()); + self.0.visit(&mut visitor)?; + visitor.0.finish() } } From b5ccd514a9a123f93e50d80465ed20f36280300a Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Fri, 26 Apr 2019 14:02:29 +1000 Subject: [PATCH 6/8] add from_display to value and some more impls --- src/kv/value/impls.rs | 24 ++++++++++++++++++++++++ src/kv/value/internal.rs | 8 +++++++- src/kv/value/mod.rs | 12 +++++++++++- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/kv/value/impls.rs b/src/kv/value/impls.rs index a78498541..999ed8c81 100644 --- a/src/kv/value/impls.rs +++ b/src/kv/value/impls.rs @@ -2,6 +2,30 @@ use std::fmt; use super::{KeyValueError, ToValue, Value, Visit, Visitor}; +impl ToValue for usize { + fn to_value(&self) -> Value { + Value::from_internal(self) + } +} + +impl Visit for usize { + fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + visitor.u64(*self as u64) + } +} + +impl ToValue for isize { + fn to_value(&self) -> Value { + Value::from_internal(self) + } +} + +impl Visit for isize { + fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + visitor.i64(*self as i64) + } +} + impl ToValue for u8 { fn to_value(&self) -> Value { Value::from_internal(self) diff --git a/src/kv/value/internal.rs b/src/kv/value/internal.rs index 4b1d91b73..a4aee79dc 100644 --- a/src/kv/value/internal.rs +++ b/src/kv/value/internal.rs @@ -15,8 +15,10 @@ pub(super) enum Inner<'v> { /// An internal `Visit`. It'll be an internal structure-preserving /// type from the standard library that's implemented in this crate. Internal(&'v Visit), - /// A formattable value. + /// A debuggable value. Debug(&'v fmt::Debug), + /// A displayable value. + Display(&'v fmt::Display), } impl<'v> Inner<'v> { @@ -24,6 +26,7 @@ impl<'v> Inner<'v> { match *self { Inner::Internal(ref value) => value.visit(visitor), Inner::Debug(ref value) => visitor.debug(value), + Inner::Display(ref value) => visitor.display(value), } } } @@ -36,6 +39,9 @@ pub(super) trait Visit { /// The internal serialization contract. pub(super) trait Visitor { fn debug(&mut self, v: &fmt::Debug) -> Result<(), KeyValueError>; + fn display(&mut self, v: &fmt::Display) -> Result<(), KeyValueError> { + self.debug(&format_args!("{}", v)) + } fn u64(&mut self, v: u64) -> Result<(), KeyValueError>; fn i64(&mut self, v: i64) -> Result<(), KeyValueError>; diff --git a/src/kv/value/mod.rs b/src/kv/value/mod.rs index 727e89ef5..87ad180f7 100644 --- a/src/kv/value/mod.rs +++ b/src/kv/value/mod.rs @@ -48,7 +48,7 @@ impl<'v> Value<'v> { } } - /// Get a value from a formattable type. + /// Get a value from a debuggable type. pub fn from_debug(value: &'v T) -> Self where T: fmt::Debug, @@ -58,6 +58,16 @@ impl<'v> Value<'v> { } } + /// Get a value from a displayable type. + pub fn from_display(value: &'v T) -> Self + where + T: fmt::Display, + { + Value { + inner: Inner::Display(value), + } + } + fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { self.inner.visit(visitor) } From d69a8f8f5c2c7d3807d89b21a10839a544e0b0c7 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Sat, 27 Apr 2019 11:48:32 +1000 Subject: [PATCH 7/8] rename KeyValueError to kv::Error --- src/kv/error.rs | 18 ++++++------ src/kv/mod.rs | 2 +- src/kv/source.rs | 22 +++++++-------- src/kv/value/impls.rs | 60 ++++++++++++++++++++-------------------- src/kv/value/internal.rs | 40 +++++++++++++-------------- src/kv/value/mod.rs | 4 +-- src/lib.rs | 6 ++-- 7 files changed, 76 insertions(+), 76 deletions(-) diff --git a/src/kv/error.rs b/src/kv/error.rs index ad9ccc684..8abaf2fac 100644 --- a/src/kv/error.rs +++ b/src/kv/error.rs @@ -2,33 +2,33 @@ use std::fmt; /// An error encountered while working with structured data. #[derive(Clone, Debug)] -pub struct KeyValueError { +pub struct Error { msg: &'static str, } -impl KeyValueError { +impl Error { /// Create an error from the given message. pub fn msg(msg: &'static str) -> Self { - KeyValueError { + Error { msg: msg, } } } -impl fmt::Display for KeyValueError { +impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.msg.fmt(f) } } -impl From for KeyValueError { +impl From for Error { fn from(_: fmt::Error) -> Self { - KeyValueError::msg("formatting failed") + Error::msg("formatting failed") } } -impl From for fmt::Error { - fn from(_: KeyValueError) -> Self { +impl From for fmt::Error { + fn from(_: Error) -> Self { fmt::Error } } @@ -38,7 +38,7 @@ mod std_support { use super::*; use std::error; - impl error::Error for KeyValueError { + impl error::Error for Error { fn description(&self) -> &str { "key_values error" } diff --git a/src/kv/mod.rs b/src/kv/mod.rs index 35c88f0b6..f10441254 100644 --- a/src/kv/mod.rs +++ b/src/kv/mod.rs @@ -5,7 +5,7 @@ mod source; mod key; mod value; -pub use self::error::KeyValueError; +pub use self::error::Error; pub use self::source::{Source, Visitor}; pub use self::key::{Key, ToKey}; pub use self::value::{Value, ToValue}; diff --git a/src/kv/source.rs b/src/kv/source.rs index 9861afcb2..5218d184a 100644 --- a/src/kv/source.rs +++ b/src/kv/source.rs @@ -1,6 +1,6 @@ //! Sources for key-value pairs. -use kv::{KeyValueError, Key, ToKey, Value, ToValue}; +use kv::{Error, Key, ToKey, Value, ToValue}; /// A source of key-value pairs. /// @@ -11,14 +11,14 @@ pub trait Source { /// Visit key-value pairs. /// /// A source doesn't have to guarantee any ordering or uniqueness of pairs. - fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), KeyValueError>; + fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), Error>; } impl<'a, T> Source for &'a T where T: Source + ?Sized, { - fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), KeyValueError> { + fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), Error> { (**self).visit(visitor) } } @@ -28,7 +28,7 @@ where K: ToKey, V: ToValue, { - fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), KeyValueError> { + fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), Error> { visitor.visit_pair(self.0.to_key(), self.1.to_value()) } } @@ -37,7 +37,7 @@ impl Source for [S] where S: Source, { - fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), KeyValueError> { + fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), Error> { for source in self { source.visit(visitor)?; } @@ -50,7 +50,7 @@ impl Source for Option where S: Source, { - fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), KeyValueError> { + fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), Error> { if let Some(ref source) = *self { source.visit(visitor)?; } @@ -62,14 +62,14 @@ where /// A visitor for the key-value pairs in a [`Source`](trait.Source.html). pub trait Visitor<'kvs> { /// Visit a key-value pair. - fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), KeyValueError>; + fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error>; } impl<'a, 'kvs, T> Visitor<'kvs> for &'a mut T where T: Visitor<'kvs> + ?Sized, { - fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), KeyValueError> { + fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { (**self).visit_pair(key, value) } } @@ -82,7 +82,7 @@ mod std_support { where S: Source + ?Sized, { - fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), KeyValueError> { + fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), Error> { (**self).visit(visitor) } } @@ -91,7 +91,7 @@ mod std_support { where S: Source, { - fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), KeyValueError> { + fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), Error> { (**self).visit(visitor) } } @@ -100,7 +100,7 @@ mod std_support { where V: Visitor<'kvs> + ?Sized, { - fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), KeyValueError> { + fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { (**self).visit_pair(key, value) } } diff --git a/src/kv/value/impls.rs b/src/kv/value/impls.rs index 999ed8c81..f4c01d72f 100644 --- a/src/kv/value/impls.rs +++ b/src/kv/value/impls.rs @@ -1,6 +1,6 @@ use std::fmt; -use super::{KeyValueError, ToValue, Value, Visit, Visitor}; +use super::{Error, ToValue, Value, Visit, Visitor}; impl ToValue for usize { fn to_value(&self) -> Value { @@ -9,7 +9,7 @@ impl ToValue for usize { } impl Visit for usize { - fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + fn visit(&self, visitor: &mut Visitor) -> Result<(), Error> { visitor.u64(*self as u64) } } @@ -21,7 +21,7 @@ impl ToValue for isize { } impl Visit for isize { - fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + fn visit(&self, visitor: &mut Visitor) -> Result<(), Error> { visitor.i64(*self as i64) } } @@ -33,7 +33,7 @@ impl ToValue for u8 { } impl Visit for u8 { - fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + fn visit(&self, visitor: &mut Visitor) -> Result<(), Error> { visitor.u64(*self as u64) } } @@ -45,7 +45,7 @@ impl ToValue for u16 { } impl Visit for u16 { - fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + fn visit(&self, visitor: &mut Visitor) -> Result<(), Error> { visitor.u64(*self as u64) } } @@ -57,7 +57,7 @@ impl ToValue for u32 { } impl Visit for u32 { - fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + fn visit(&self, visitor: &mut Visitor) -> Result<(), Error> { visitor.u64(*self as u64) } } @@ -69,7 +69,7 @@ impl ToValue for u64 { } impl Visit for u64 { - fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + fn visit(&self, visitor: &mut Visitor) -> Result<(), Error> { visitor.u64(*self) } } @@ -81,7 +81,7 @@ impl ToValue for i8 { } impl Visit for i8 { - fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + fn visit(&self, visitor: &mut Visitor) -> Result<(), Error> { visitor.i64(*self as i64) } } @@ -93,7 +93,7 @@ impl ToValue for i16 { } impl Visit for i16 { - fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + fn visit(&self, visitor: &mut Visitor) -> Result<(), Error> { visitor.i64(*self as i64) } } @@ -105,7 +105,7 @@ impl ToValue for i32 { } impl Visit for i32 { - fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + fn visit(&self, visitor: &mut Visitor) -> Result<(), Error> { visitor.i64(*self as i64) } } @@ -117,7 +117,7 @@ impl ToValue for i64 { } impl Visit for i64 { - fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + fn visit(&self, visitor: &mut Visitor) -> Result<(), Error> { visitor.i64(*self) } } @@ -129,7 +129,7 @@ impl ToValue for f32 { } impl Visit for f32 { - fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + fn visit(&self, visitor: &mut Visitor) -> Result<(), Error> { visitor.f64(*self as f64) } } @@ -141,7 +141,7 @@ impl ToValue for f64 { } impl Visit for f64 { - fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + fn visit(&self, visitor: &mut Visitor) -> Result<(), Error> { visitor.f64(*self) } } @@ -153,7 +153,7 @@ impl ToValue for bool { } impl Visit for bool { - fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + fn visit(&self, visitor: &mut Visitor) -> Result<(), Error> { visitor.bool(*self) } } @@ -165,7 +165,7 @@ impl ToValue for char { } impl Visit for char { - fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + fn visit(&self, visitor: &mut Visitor) -> Result<(), Error> { visitor.char(*self) } } @@ -177,7 +177,7 @@ impl<'v> ToValue for &'v str { } impl<'v> Visit for &'v str { - fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + fn visit(&self, visitor: &mut Visitor) -> Result<(), Error> { visitor.str(*self) } } @@ -189,7 +189,7 @@ impl ToValue for () { } impl Visit for () { - fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + fn visit(&self, visitor: &mut Visitor) -> Result<(), Error> { visitor.none() } } @@ -207,7 +207,7 @@ impl Visit for Option where T: ToValue, { - fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + fn visit(&self, visitor: &mut Visitor) -> Result<(), Error> { match *self { Some(ref value) => value.to_value().visit(visitor), None => visitor.none(), @@ -243,7 +243,7 @@ mod std_support { } impl Visit for String { - fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + fn visit(&self, visitor: &mut Visitor) -> Result<(), Error> { visitor.str(&*self) } } @@ -255,7 +255,7 @@ mod std_support { } impl<'a> Visit for Cow<'a, str> { - fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + fn visit(&self, visitor: &mut Visitor) -> Result<(), Error> { visitor.str(&*self) } } @@ -264,7 +264,7 @@ mod std_support { #[cfg(test)] mod tests { use super::*; - use kv::value::KeyValueError; + use kv::value::Error; use kv::value::internal::Visitor; use std::fmt::Write; @@ -349,46 +349,46 @@ mod tests { where F: Fn(Token), { - fn debug(&mut self, v: &fmt::Debug) -> Result<(), KeyValueError> { + fn debug(&mut self, v: &fmt::Debug) -> Result<(), Error> { let mut buf = Buffer::new(); write!(&mut buf, "{:?}", v)?; - let s = buf.as_str().map_err(|_| KeyValueError::msg("invalid UTF8"))?; + let s = buf.as_str().map_err(|_| Error::msg("invalid UTF8"))?; (self.0)(Token::Str(s)); Ok(()) } - fn u64(&mut self, v: u64) -> Result<(), KeyValueError> { + fn u64(&mut self, v: u64) -> Result<(), Error> { (self.0)(Token::U64(v)); Ok(()) } - fn i64(&mut self, v: i64) -> Result<(), KeyValueError> { + fn i64(&mut self, v: i64) -> Result<(), Error> { (self.0)(Token::I64(v)); Ok(()) } - fn f64(&mut self, v: f64) -> Result<(), KeyValueError> { + fn f64(&mut self, v: f64) -> Result<(), Error> { (self.0)(Token::F64(v)); Ok(()) } - fn bool(&mut self, v: bool) -> Result<(), KeyValueError> { + fn bool(&mut self, v: bool) -> Result<(), Error> { (self.0)(Token::Bool(v)); Ok(()) } - fn char(&mut self, v: char) -> Result<(), KeyValueError> { + fn char(&mut self, v: char) -> Result<(), Error> { (self.0)(Token::Char(v)); Ok(()) } - fn str(&mut self, v: &str) -> Result<(), KeyValueError> { + fn str(&mut self, v: &str) -> Result<(), Error> { (self.0)(Token::Str(v)); Ok(()) } - fn none(&mut self) -> Result<(), KeyValueError> { + fn none(&mut self) -> Result<(), Error> { (self.0)(Token::None); Ok(()) } diff --git a/src/kv/value/internal.rs b/src/kv/value/internal.rs index a4aee79dc..d03c1a8b8 100644 --- a/src/kv/value/internal.rs +++ b/src/kv/value/internal.rs @@ -1,6 +1,6 @@ use std::fmt; -use super::KeyValueError; +use super::Error; // `Visit` and `Visitor` is an internal API for visiting the structure of a value. // It's not intended to be public (at this stage). @@ -22,7 +22,7 @@ pub(super) enum Inner<'v> { } impl<'v> Inner<'v> { - pub(super) fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + pub(super) fn visit(&self, visitor: &mut Visitor) -> Result<(), Error> { match *self { Inner::Internal(ref value) => value.visit(visitor), Inner::Debug(ref value) => visitor.debug(value), @@ -33,60 +33,60 @@ impl<'v> Inner<'v> { /// An internal structure-preserving value. pub(super) trait Visit { - fn visit(&self, backend: &mut Visitor) -> Result<(), KeyValueError>; + fn visit(&self, backend: &mut Visitor) -> Result<(), Error>; } /// The internal serialization contract. pub(super) trait Visitor { - fn debug(&mut self, v: &fmt::Debug) -> Result<(), KeyValueError>; - fn display(&mut self, v: &fmt::Display) -> Result<(), KeyValueError> { + fn debug(&mut self, v: &fmt::Debug) -> Result<(), Error>; + fn display(&mut self, v: &fmt::Display) -> Result<(), Error> { self.debug(&format_args!("{}", v)) } - fn u64(&mut self, v: u64) -> Result<(), KeyValueError>; - fn i64(&mut self, v: i64) -> Result<(), KeyValueError>; - fn f64(&mut self, v: f64) -> Result<(), KeyValueError>; - fn bool(&mut self, v: bool) -> Result<(), KeyValueError>; - fn char(&mut self, v: char) -> Result<(), KeyValueError>; - fn str(&mut self, v: &str) -> Result<(), KeyValueError>; - fn none(&mut self) -> Result<(), KeyValueError>; + fn u64(&mut self, v: u64) -> Result<(), Error>; + fn i64(&mut self, v: i64) -> Result<(), Error>; + fn f64(&mut self, v: f64) -> Result<(), Error>; + fn bool(&mut self, v: bool) -> Result<(), Error>; + fn char(&mut self, v: char) -> Result<(), Error>; + fn str(&mut self, v: &str) -> Result<(), Error>; + fn none(&mut self) -> Result<(), Error>; } /// A visitor for `std::fmt`. pub(super) struct FmtVisitor<'a, 'b: 'a>(pub(super) &'a mut fmt::Formatter<'b>); impl<'a, 'b: 'a> Visitor for FmtVisitor<'a, 'b> { - fn debug(&mut self, v: &fmt::Debug) -> Result<(), KeyValueError> { + fn debug(&mut self, v: &fmt::Debug) -> Result<(), Error> { v.fmt(self.0)?; Ok(()) } - fn u64(&mut self, v: u64) -> Result<(), KeyValueError> { + fn u64(&mut self, v: u64) -> Result<(), Error> { self.debug(&format_args!("{:?}", v)) } - fn i64(&mut self, v: i64) -> Result<(), KeyValueError> { + fn i64(&mut self, v: i64) -> Result<(), Error> { self.debug(&format_args!("{:?}", v)) } - fn f64(&mut self, v: f64) -> Result<(), KeyValueError> { + fn f64(&mut self, v: f64) -> Result<(), Error> { self.debug(&format_args!("{:?}", v)) } - fn bool(&mut self, v: bool) -> Result<(), KeyValueError> { + fn bool(&mut self, v: bool) -> Result<(), Error> { self.debug(&format_args!("{:?}", v)) } - fn char(&mut self, v: char) -> Result<(), KeyValueError> { + fn char(&mut self, v: char) -> Result<(), Error> { self.debug(&format_args!("{:?}", v)) } - fn str(&mut self, v: &str) -> Result<(), KeyValueError> { + fn str(&mut self, v: &str) -> Result<(), Error> { self.debug(&format_args!("{:?}", v)) } - fn none(&mut self) -> Result<(), KeyValueError> { + fn none(&mut self) -> Result<(), Error> { self.debug(&format_args!("None")) } } diff --git a/src/kv/value/mod.rs b/src/kv/value/mod.rs index 87ad180f7..ff0db6c63 100644 --- a/src/kv/value/mod.rs +++ b/src/kv/value/mod.rs @@ -5,7 +5,7 @@ use std::fmt; mod internal; mod impls; -use kv::KeyValueError; +use kv::Error; use self::internal::{Inner, Visit, Visitor}; @@ -68,7 +68,7 @@ impl<'v> Value<'v> { } } - fn visit(&self, visitor: &mut Visitor) -> Result<(), KeyValueError> { + fn visit(&self, visitor: &mut Visitor) -> Result<(), Error> { self.inner.visit(visitor) } } diff --git a/src/lib.rs b/src/lib.rs index 5a3606047..855ddc835 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -743,12 +743,12 @@ struct KeyValues<'a>(&'a kv::Source); #[cfg(feature = "kv_unstable")] impl<'a> fmt::Debug for KeyValues<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use self::kv::{Key, Value, Visitor, KeyValueError}; + use self::kv::{Key, Value, Visitor, Error}; struct FmtVisitor<'a, 'b: 'a>(fmt::DebugMap<'a, 'b>); impl<'a, 'b: 'a, 'kvs> Visitor<'kvs> for FmtVisitor<'a, 'b> { - fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), KeyValueError> { + fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { self.0.entry(&key, &value); Ok(()) @@ -1635,7 +1635,7 @@ mod tests { &mut self, _: kv::Key<'kvs>, _: kv::Value<'kvs> - ) -> Result<(), kv::KeyValueError> { + ) -> Result<(), kv::Error> { self.seen_pairs += 1; Ok(()) } From 7dea857cc0058ae9f890710a7ce77b1019163c80 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Sat, 27 Apr 2019 11:51:53 +1000 Subject: [PATCH 8/8] make deprecated description just a little more semantic --- src/kv/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kv/error.rs b/src/kv/error.rs index 8abaf2fac..8e91f04f8 100644 --- a/src/kv/error.rs +++ b/src/kv/error.rs @@ -40,7 +40,7 @@ mod std_support { impl error::Error for Error { fn description(&self) -> &str { - "key_values error" + "key values error" } } }