-
Notifications
You must be signed in to change notification settings - Fork 259
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
970 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,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<fmt::Error> for KeyValueError { | ||
fn from(_: fmt::Error) -> Self { | ||
KeyValueError::msg("formatting failed") | ||
} | ||
} | ||
|
||
impl From<KeyValueError> 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 | ||
} | ||
} | ||
} |
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 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<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; | ||
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; |
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,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<K, V> 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<S> 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<S> Source for Option<S> | ||
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<S> Source for Box<S> | ||
where | ||
S: Source + ?Sized, | ||
{ | ||
fn visit<'kvs>(&'kvs self, visitor: &mut Visitor<'kvs>) -> Result<(), KeyValueError> { | ||
(**self).visit(visitor) | ||
} | ||
} | ||
|
||
impl<S> Source for Vec<S> | ||
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) {} | ||
} | ||
} |
Oops, something went wrong.