Skip to content

Commit 32d080a

Browse files
committed
build out initial key values API
1 parent 75043f9 commit 32d080a

11 files changed

Lines changed: 970 additions & 5 deletions

File tree

.travis.yml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,20 @@ rust:
55
- stable
66
- beta
77
- nightly
8-
install:
9-
- '[ "$TRAVIS_RUST_VERSION" == "1.16.0" ] || rustup target add thumbv6m-none-eabi'
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"
14+
- rust: stable
15+
script:
16+
- rustup target add thumbv6m-none-eabi
17+
- cargo build --verbose --target=thumbv6m-none-eabi
1018
script:
1119
- cargo build --verbose
1220
- cargo build --verbose --features serde
1321
- cargo build --verbose --features std
14-
- '[ "$TRAVIS_RUST_VERSION" == "1.16.0" ] || cargo build --verbose --target=thumbv6m-none-eabi'
1522
- cargo test --verbose
1623
- cargo test --verbose --features serde
1724
- cargo test --verbose --features std

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: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
//! Structured keys.
2+
3+
use std::fmt;
4+
use std::cmp;
5+
use std::hash;
6+
use std::borrow::Borrow;
7+
8+
/// A type that can be converted into a [`Key`](struct.Key.html).
9+
pub trait ToKey {
10+
/// Perform the covnersion.
11+
fn to_key(&self) -> Key;
12+
}
13+
14+
impl<'a, T> ToKey for &'a T
15+
where
16+
T: ToKey + ?Sized,
17+
{
18+
fn to_key(&self) -> Key {
19+
(**self).to_key()
20+
}
21+
}
22+
23+
impl<'k> ToKey for Key<'k> {
24+
fn to_key(&self) -> Key {
25+
Key {
26+
key: self.key,
27+
}
28+
}
29+
}
30+
31+
impl<'k> ToKey for &'k str {
32+
fn to_key(&self) -> Key {
33+
Key::from_str(self)
34+
}
35+
}
36+
37+
/// A key in a structured key-value pair.
38+
#[derive(Clone)]
39+
pub struct Key<'k> {
40+
key: &'k str,
41+
}
42+
43+
impl<'k> Key<'k> {
44+
/// Get a key from a borrowed string.
45+
pub fn from_str(key: &'k str) -> Self {
46+
Key {
47+
key: key,
48+
}
49+
}
50+
51+
/// Get a borrowed string from this key.
52+
pub fn as_str(&self) -> &str {
53+
self.key
54+
}
55+
}
56+
57+
impl<'k> fmt::Debug for Key<'k> {
58+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
59+
self.key.fmt(f)
60+
}
61+
}
62+
63+
impl<'k> fmt::Display for Key<'k> {
64+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
65+
self.key.fmt(f)
66+
}
67+
}
68+
69+
impl<'k> hash::Hash for Key<'k> {
70+
fn hash<H>(&self, state: &mut H)
71+
where
72+
H: hash::Hasher,
73+
{
74+
self.as_str().hash(state)
75+
}
76+
}
77+
78+
impl<'k, 'ko> PartialEq<Key<'ko>> for Key<'k> {
79+
fn eq(&self, other: &Key<'ko>) -> bool {
80+
self.as_str().eq(other.as_str())
81+
}
82+
}
83+
84+
impl<'k> Eq for Key<'k> {}
85+
86+
impl<'k, 'ko> PartialOrd<Key<'ko>> for Key<'k> {
87+
fn partial_cmp(&self, other: &Key<'ko>) -> Option<cmp::Ordering> {
88+
self.as_str().partial_cmp(other.as_str())
89+
}
90+
}
91+
92+
impl<'k> Ord for Key<'k> {
93+
fn cmp(&self, other: &Self) -> cmp::Ordering {
94+
self.as_str().cmp(other.as_str())
95+
}
96+
}
97+
98+
impl<'k> AsRef<str> for Key<'k> {
99+
fn as_ref(&self) -> &str {
100+
self.as_str()
101+
}
102+
}
103+
104+
impl<'k> Borrow<str> for Key<'k> {
105+
fn borrow(&self) -> &str {
106+
self.as_str()
107+
}
108+
}
109+
110+
impl<'k> From<&'k str> for Key<'k> {
111+
fn from(s: &'k str) -> Self {
112+
Key::from_str(s)
113+
}
114+
}
115+
116+
#[cfg(feature = "std")]
117+
mod std_support {
118+
use super::*;
119+
120+
use std::borrow::Cow;
121+
122+
impl ToKey for String {
123+
fn to_key(&self) -> Key {
124+
Key::from_str(self)
125+
}
126+
}
127+
128+
impl<'a> ToKey for Cow<'a, str> {
129+
fn to_key(&self) -> Key {
130+
Key::from_str(self)
131+
}
132+
}
133+
}
134+
135+
#[cfg(test)]
136+
mod tests {
137+
use super::*;
138+
139+
#[test]
140+
fn key_from_string() {
141+
assert_eq!("a key", Key::from_str("a key").as_str());
142+
}
143+
}

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)