-
Notifications
You must be signed in to change notification settings - Fork 256
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Build out initial key values API (#324)
- Loading branch information
Showing
10 changed files
with
1,067 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
use std::fmt; | ||
|
||
/// An error encountered while working with structured data. | ||
#[derive(Clone, Debug)] | ||
pub struct Error { | ||
msg: &'static str, | ||
} | ||
|
||
impl Error { | ||
/// Create an error from the given message. | ||
pub fn msg(msg: &'static str) -> Self { | ||
Error { | ||
msg: msg, | ||
} | ||
} | ||
} | ||
|
||
impl fmt::Display for Error { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
self.msg.fmt(f) | ||
} | ||
} | ||
|
||
impl From<fmt::Error> for Error { | ||
fn from(_: fmt::Error) -> Self { | ||
Error::msg("formatting failed") | ||
} | ||
} | ||
|
||
impl From<Error> for fmt::Error { | ||
fn from(_: Error) -> Self { | ||
fmt::Error | ||
} | ||
} | ||
|
||
#[cfg(feature = "std")] | ||
mod std_support { | ||
use super::*; | ||
use std::error; | ||
|
||
impl error::Error for Error { | ||
fn description(&self) -> &str { | ||
"key values error" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 conversion. | ||
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 ToKey for 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<H>(&self, state: &mut H) | ||
where | ||
H: hash::Hasher, | ||
{ | ||
self.as_str().hash(state) | ||
} | ||
} | ||
|
||
impl<'k, 'ko> PartialEq<Key<'ko>> 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<Key<'ko>> for Key<'k> { | ||
fn partial_cmp(&self, other: &Key<'ko>) -> Option<cmp::Ordering> { | ||
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<str> for Key<'k> { | ||
fn as_ref(&self) -> &str { | ||
self.as_str() | ||
} | ||
} | ||
|
||
impl<'k> Borrow<str> 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()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
//! Structured key-value pairs. | ||
|
||
mod error; | ||
mod source; | ||
mod key; | ||
mod value; | ||
|
||
pub use self::error::Error; | ||
pub use self::source::{Source, Visitor}; | ||
pub use self::key::{Key, ToKey}; | ||
pub use self::value::{Value, ToValue}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
//! Sources for key-value pairs. | ||
|
||
use kv::{Error, Key, ToKey, 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<(), Error>; | ||
} | ||
|
||
impl<'a, T> Source for &'a T | ||
where | ||
T: Source + ?Sized, | ||
{ | ||
fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), Error> { | ||
(**self).visit(visitor) | ||
} | ||
} | ||
|
||
impl<K, V> Source for (K, V) | ||
where | ||
K: ToKey, | ||
V: ToValue, | ||
{ | ||
fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), Error> { | ||
visitor.visit_pair(self.0.to_key(), self.1.to_value()) | ||
} | ||
} | ||
|
||
impl<S> Source for [S] | ||
where | ||
S: Source, | ||
{ | ||
fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), Error> { | ||
for source in self { | ||
source.visit(visitor)?; | ||
} | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
impl<S> Source for Option<S> | ||
where | ||
S: Source, | ||
{ | ||
fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), Error> { | ||
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<(), 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<(), Error> { | ||
(**self).visit_pair(key, value) | ||
} | ||
} | ||
|
||
#[cfg(feature = "std")] | ||
mod std_support { | ||
use super::*; | ||
|
||
impl<S> Source for Box<S> | ||
where | ||
S: Source + ?Sized, | ||
{ | ||
fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), Error> { | ||
(**self).visit(visitor) | ||
} | ||
} | ||
|
||
impl<S> Source for Vec<S> | ||
where | ||
S: Source, | ||
{ | ||
fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), Error> { | ||
(**self).visit(visitor) | ||
} | ||
} | ||
|
||
impl<'kvs, V> Visitor<'kvs> for Box<V> | ||
where | ||
V: Visitor<'kvs> + ?Sized, | ||
{ | ||
fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { | ||
(**self).visit_pair(key, value) | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
#[test] | ||
fn source_is_object_safe() { | ||
fn _check(_: &Source) {} | ||
} | ||
|
||
#[test] | ||
fn visitor_is_object_safe() { | ||
fn _check(_: &Visitor) {} | ||
} | ||
} |
Oops, something went wrong.