Skip to content

Commit 58b19a3

Browse files
committed
build out innitial key values API
1 parent 74584a5 commit 58b19a3

11 files changed

Lines changed: 931 additions & 2 deletions

File tree

.travis.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ rust:
55
- stable
66
- beta
77
- nightly
8+
matrix:
9+
include:
10+
- rust: 1.21.0
11+
script:
12+
- cargo test --verbose --features kv_unstable
13+
- cargo test --verbose --features "kv_unstable std"
814
script:
915
- cargo build --verbose
1016
- cargo build --verbose --features serde

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ release_max_level_trace = []
3939

4040
std = []
4141

42+
# requires Rust `>= 1.21.0`
43+
kv_unstable = []
44+
4245
[badges]
4346
travis-ci = { repository = "rust-lang-nursery/log" }
4447
appveyor = { repository = "alexcrichton/log" }

src/key_values/error.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use std::fmt;
2+
3+
/// An error encountered while working with structured data.
4+
#[derive(Clone, Debug)]
5+
pub struct KeyValueError {
6+
msg: &'static str,
7+
}
8+
9+
impl KeyValueError {
10+
/// Create an error from the given message.
11+
pub fn msg(msg: &'static str) -> Self {
12+
KeyValueError {
13+
msg: msg,
14+
}
15+
}
16+
}
17+
18+
impl fmt::Display for KeyValueError {
19+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
20+
self.msg.fmt(f)
21+
}
22+
}
23+
24+
impl From<fmt::Error> for KeyValueError {
25+
fn from(_: fmt::Error) -> Self {
26+
KeyValueError::msg("formatting failed")
27+
}
28+
}
29+
30+
impl From<KeyValueError> for fmt::Error {
31+
fn from(_: KeyValueError) -> Self {
32+
fmt::Error
33+
}
34+
}
35+
36+
#[cfg(feature = "std")]
37+
mod std_support {
38+
use super::*;
39+
use std::error;
40+
41+
impl error::Error for KeyValueError {
42+
fn description(&self) -> &str {
43+
self.msg
44+
}
45+
46+
fn cause(&self) -> Option<&error::Error> {
47+
None
48+
}
49+
}
50+
}

src/key_values/key.rs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
//! Structured keys.
2+
3+
use std::fmt;
4+
use std::borrow::Borrow;
5+
6+
/// A type that can be converted into a [`Key`](struct.Key.html).
7+
pub trait ToKey {
8+
/// Perform the covnersion.
9+
fn to_key(&self) -> Key;
10+
}
11+
12+
impl<'a, T> ToKey for &'a T
13+
where
14+
T: ToKey + ?Sized,
15+
{
16+
fn to_key(&self) -> Key {
17+
(**self).to_key()
18+
}
19+
}
20+
21+
impl<'k> ToKey for Key<'k> {
22+
fn to_key(&self) -> Key {
23+
Key {
24+
key: self.key,
25+
}
26+
}
27+
}
28+
29+
impl<'k> ToKey for &'k str {
30+
fn to_key(&self) -> Key {
31+
Key::from_str(self)
32+
}
33+
}
34+
35+
/// A key in a structured key-value pair.
36+
pub struct Key<'k> {
37+
key: &'k str,
38+
}
39+
40+
impl<'k> Key<'k> {
41+
/// Get a key from a borrowed string.
42+
pub fn from_str(key: &'k str) -> Self {
43+
Key {
44+
key: key,
45+
}
46+
}
47+
48+
/// Get a borrowed string from this key.
49+
pub fn as_str(&self) -> &str {
50+
self.key
51+
}
52+
}
53+
54+
impl<'k> fmt::Debug for Key<'k> {
55+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
56+
self.key.fmt(f)
57+
}
58+
}
59+
60+
impl<'k> fmt::Display for Key<'k> {
61+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
62+
self.key.fmt(f)
63+
}
64+
}
65+
66+
impl<'k> AsRef<str> for Key<'k> {
67+
fn as_ref(&self) -> &str {
68+
self.as_str()
69+
}
70+
}
71+
72+
impl<'k> Borrow<str> for Key<'k> {
73+
fn borrow(&self) -> &str {
74+
self.as_str()
75+
}
76+
}
77+
78+
impl<'k> From<&'k str> for Key<'k> {
79+
fn from(s: &'k str) -> Self {
80+
Key::from_str(s)
81+
}
82+
}
83+
84+
#[cfg(feature = "std")]
85+
mod std_support {
86+
use super::*;
87+
88+
use std::borrow::Cow;
89+
90+
impl ToKey for String {
91+
fn to_key(&self) -> Key {
92+
Key::from_str(self)
93+
}
94+
}
95+
96+
impl<'a> ToKey for Cow<'a, str> {
97+
fn to_key(&self) -> Key {
98+
Key::from_str(self)
99+
}
100+
}
101+
}
102+
103+
#[cfg(test)]
104+
mod tests {
105+
use super::*;
106+
107+
#[test]
108+
fn key_from_string() {
109+
assert_eq!("a key", Key::from_str("a key").as_str());
110+
}
111+
}

src/key_values/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//! Structured key-value pairs.
2+
3+
mod error;
4+
pub mod source;
5+
pub mod key;
6+
pub mod value;
7+
8+
pub use self::error::KeyValueError;
9+
pub use self::source::Source;
10+
pub use self::key::Key;
11+
pub use self::value::Value;

src/key_values/source.rs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
//! Sources for key-value pairs.
2+
3+
pub use key_values::{KeyValueError, Key, Value};
4+
5+
use key_values::key::ToKey;
6+
use key_values::value::ToValue;
7+
8+
/// A source of key-value pairs.
9+
///
10+
/// The source may be a single pair, a set of pairs, or a filter over a set of pairs.
11+
/// Use the [`Visitor`](struct.Visitor.html) trait to inspect the structured data
12+
/// in a source.
13+
pub trait Source {
14+
/// Visit key-value pairs.
15+
///
16+
/// A source doesn't have to guarantee any ordering or uniqueness of pairs.
17+
fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), KeyValueError>;
18+
}
19+
20+
impl<'a, T> Source for &'a T
21+
where
22+
T: Source + ?Sized,
23+
{
24+
fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), KeyValueError> {
25+
(**self).visit(visitor)
26+
}
27+
}
28+
29+
impl<K, V> Source for (K, V)
30+
where
31+
K: ToKey,
32+
V: ToValue,
33+
{
34+
fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), KeyValueError> {
35+
visitor.visit_pair(self.0.to_key(), self.1.to_value())
36+
}
37+
}
38+
39+
impl<S> Source for [S]
40+
where
41+
S: Source,
42+
{
43+
fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), KeyValueError> {
44+
for source in self {
45+
source.visit(visitor)?;
46+
}
47+
48+
Ok(())
49+
}
50+
}
51+
52+
impl<S> Source for Option<S>
53+
where
54+
S: Source,
55+
{
56+
fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), KeyValueError> {
57+
if let Some(ref source) = *self {
58+
source.visit(visitor)?;
59+
}
60+
61+
Ok(())
62+
}
63+
}
64+
65+
/// A visitor for the key-value pairs in a [`Source`](trait.Source.html).
66+
pub trait Visitor<'kvs> {
67+
/// Visit a key-value pair.
68+
fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), KeyValueError>;
69+
}
70+
71+
impl<'a, 'kvs, T> Visitor<'kvs> for &'a mut T
72+
where
73+
T: Visitor<'kvs> + ?Sized,
74+
{
75+
fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), KeyValueError> {
76+
(**self).visit_pair(key, value)
77+
}
78+
}
79+
80+
#[cfg(feature = "std")]
81+
mod std_support {
82+
use super::*;
83+
84+
impl<S> Source for Box<S>
85+
where
86+
S: Source + ?Sized,
87+
{
88+
fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), KeyValueError> {
89+
(**self).visit(visitor)
90+
}
91+
}
92+
93+
impl<S> Source for Vec<S>
94+
where
95+
S: Source,
96+
{
97+
fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), KeyValueError> {
98+
(**self).visit(visitor)
99+
}
100+
}
101+
}
102+
103+
#[cfg(test)]
104+
mod tests {
105+
use super::*;
106+
107+
#[test]
108+
fn source_is_object_safe() {
109+
fn _check(_: &Source) {}
110+
}
111+
112+
#[test]
113+
fn visitor_is_object_safe() {
114+
fn _check(_: &Visitor) {}
115+
}
116+
}

0 commit comments

Comments
 (0)