| //! Sources for key-value pairs. | |
| use kv::{Error, Key, ToKey, ToValue, Value}; | |
| use std::fmt; | |
| /// 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`](trait.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 key-value pairs. | |
| /// If the given visitor returns an error then the source may early-return with it, | |
| /// even if there are more key-value pairs. | |
| /// | |
| /// # Implementation notes | |
| /// | |
| /// A source should yield the same key-value pairs to a subsequent visitor unless | |
| /// that visitor itself fails. | |
| fn visit<'kvs>(&'kvs self, visitor: &mut dyn Visitor<'kvs>) -> Result<(), Error>; | |
| /// Get the value for a given key. | |
| /// | |
| /// If the key appears multiple times in the source then which key is returned | |
| /// is implementation specific. | |
| /// | |
| /// # Implementation notes | |
| /// | |
| /// A source that can provide a more efficient implementation of this method | |
| /// should override it. | |
| fn get<'v>(&'v self, key: Key) -> Option<Value<'v>> { | |
| struct Get<'k, 'v> { | |
| key: Key<'k>, | |
| found: Option<Value<'v>>, | |
| } | |
| impl<'k, 'kvs> Visitor<'kvs> for Get<'k, 'kvs> { | |
| fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { | |
| if self.key == key { | |
| self.found = Some(value); | |
| } | |
| Ok(()) | |
| } | |
| } | |
| let mut get = Get { key, found: None }; | |
| let _ = self.visit(&mut get); | |
| get.found | |
| } | |
| /// Count the number of key-value pairs that can be visited. | |
| /// | |
| /// # Implementation notes | |
| /// | |
| /// A source that knows the number of key-value pairs upfront may provide a more | |
| /// efficient implementation. | |
| /// | |
| /// A subsequent call to `visit` should yield the same number of key-value pairs | |
| /// to the visitor, unless that visitor fails part way through. | |
| fn count(&self) -> usize { | |
| struct Count(usize); | |
| impl<'kvs> Visitor<'kvs> for Count { | |
| fn visit_pair(&mut self, _: Key<'kvs>, _: Value<'kvs>) -> Result<(), Error> { | |
| self.0 += 1; | |
| Ok(()) | |
| } | |
| } | |
| let mut count = Count(0); | |
| let _ = self.visit(&mut count); | |
| count.0 | |
| } | |
| } | |
| impl<'a, T> Source for &'a T | |
| where | |
| T: Source + ?Sized, | |
| { | |
| fn visit<'kvs>(&'kvs self, visitor: &mut dyn Visitor<'kvs>) -> Result<(), Error> { | |
| Source::visit(&**self, visitor) | |
| } | |
| fn get<'v>(&'v self, key: Key) -> Option<Value<'v>> { | |
| Source::get(&**self, key) | |
| } | |
| fn count(&self) -> usize { | |
| Source::count(&**self) | |
| } | |
| } | |
| impl<K, V> Source for (K, V) | |
| where | |
| K: ToKey, | |
| V: ToValue, | |
| { | |
| fn visit<'kvs>(&'kvs self, visitor: &mut dyn Visitor<'kvs>) -> Result<(), Error> { | |
| visitor.visit_pair(self.0.to_key(), self.1.to_value()) | |
| } | |
| fn get<'v>(&'v self, key: Key) -> Option<Value<'v>> { | |
| if self.0.to_key() == key { | |
| Some(self.1.to_value()) | |
| } else { | |
| None | |
| } | |
| } | |
| fn count(&self) -> usize { | |
| 1 | |
| } | |
| } | |
| impl<S> Source for [S] | |
| where | |
| S: Source, | |
| { | |
| fn visit<'kvs>(&'kvs self, visitor: &mut dyn Visitor<'kvs>) -> Result<(), Error> { | |
| for source in self { | |
| source.visit(visitor)?; | |
| } | |
| Ok(()) | |
| } | |
| fn count(&self) -> usize { | |
| self.len() | |
| } | |
| } | |
| impl<S> Source for Option<S> | |
| where | |
| S: Source, | |
| { | |
| fn visit<'kvs>(&'kvs self, visitor: &mut dyn Visitor<'kvs>) -> Result<(), Error> { | |
| if let Some(ref source) = *self { | |
| source.visit(visitor)?; | |
| } | |
| Ok(()) | |
| } | |
| fn count(&self) -> usize { | |
| self.as_ref().map(Source::count).unwrap_or(0) | |
| } | |
| } | |
| /// 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) | |
| } | |
| } | |
| impl<'a, 'b: 'a, 'kvs> Visitor<'kvs> for fmt::DebugMap<'a, 'b> { | |
| fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { | |
| self.entry(&key, &value); | |
| Ok(()) | |
| } | |
| } | |
| impl<'a, 'b: 'a, 'kvs> Visitor<'kvs> for fmt::DebugList<'a, 'b> { | |
| fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { | |
| self.entry(&(key, value)); | |
| Ok(()) | |
| } | |
| } | |
| impl<'a, 'b: 'a, 'kvs> Visitor<'kvs> for fmt::DebugSet<'a, 'b> { | |
| fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { | |
| self.entry(&(key, value)); | |
| Ok(()) | |
| } | |
| } | |
| impl<'a, 'b: 'a, 'kvs> Visitor<'kvs> for fmt::DebugTuple<'a, 'b> { | |
| fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { | |
| self.field(&key); | |
| self.field(&value); | |
| Ok(()) | |
| } | |
| } | |
| #[cfg(feature = "std")] | |
| mod std_support { | |
| use super::*; | |
| use std::borrow::Borrow; | |
| use std::collections::{BTreeMap, HashMap}; | |
| use std::hash::{BuildHasher, Hash}; | |
| impl<S> Source for Box<S> | |
| where | |
| S: Source + ?Sized, | |
| { | |
| fn visit<'kvs>(&'kvs self, visitor: &mut dyn Visitor<'kvs>) -> Result<(), Error> { | |
| Source::visit(&**self, visitor) | |
| } | |
| fn get<'v>(&'v self, key: Key) -> Option<Value<'v>> { | |
| Source::get(&**self, key) | |
| } | |
| fn count(&self) -> usize { | |
| Source::count(&**self) | |
| } | |
| } | |
| impl<S> Source for Vec<S> | |
| where | |
| S: Source, | |
| { | |
| fn visit<'kvs>(&'kvs self, visitor: &mut dyn Visitor<'kvs>) -> Result<(), Error> { | |
| Source::visit(&**self, visitor) | |
| } | |
| fn get<'v>(&'v self, key: Key) -> Option<Value<'v>> { | |
| Source::get(&**self, key) | |
| } | |
| fn count(&self) -> usize { | |
| Source::count(&**self) | |
| } | |
| } | |
| 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) | |
| } | |
| } | |
| impl<K, V, S> Source for HashMap<K, V, S> | |
| where | |
| K: ToKey + Borrow<str> + Eq + Hash, | |
| V: ToValue, | |
| S: BuildHasher, | |
| { | |
| fn visit<'kvs>(&'kvs self, visitor: &mut dyn Visitor<'kvs>) -> Result<(), Error> { | |
| for (key, value) in self { | |
| visitor.visit_pair(key.to_key(), value.to_value())?; | |
| } | |
| Ok(()) | |
| } | |
| fn get<'v>(&'v self, key: Key) -> Option<Value<'v>> { | |
| HashMap::get(self, key.as_str()).map(|v| v.to_value()) | |
| } | |
| fn count(&self) -> usize { | |
| self.len() | |
| } | |
| } | |
| impl<K, V> Source for BTreeMap<K, V> | |
| where | |
| K: ToKey + Borrow<str> + Ord, | |
| V: ToValue, | |
| { | |
| fn visit<'kvs>(&'kvs self, visitor: &mut dyn Visitor<'kvs>) -> Result<(), Error> { | |
| for (key, value) in self { | |
| visitor.visit_pair(key.to_key(), value.to_value())?; | |
| } | |
| Ok(()) | |
| } | |
| fn get<'v>(&'v self, key: Key) -> Option<Value<'v>> { | |
| BTreeMap::get(self, key.as_str()).map(|v| v.to_value()) | |
| } | |
| fn count(&self) -> usize { | |
| self.len() | |
| } | |
| } | |
| #[cfg(test)] | |
| mod tests { | |
| use super::*; | |
| use kv::value::test::Token; | |
| use std::collections::{BTreeMap, HashMap}; | |
| #[test] | |
| fn count() { | |
| assert_eq!(1, Source::count(&Box::new(("a", 1)))); | |
| assert_eq!(2, Source::count(&vec![("a", 1), ("b", 2)])); | |
| } | |
| #[test] | |
| fn get() { | |
| let source = vec![("a", 1), ("b", 2), ("a", 1)]; | |
| assert_eq!( | |
| Token::I64(1), | |
| Source::get(&source, Key::from_str("a")).unwrap().to_token() | |
| ); | |
| let source = Box::new(Option::None::<(&str, i32)>); | |
| assert!(Source::get(&source, Key::from_str("a")).is_none()); | |
| } | |
| #[test] | |
| fn hash_map() { | |
| let mut map = HashMap::new(); | |
| map.insert("a", 1); | |
| map.insert("b", 2); | |
| assert_eq!(2, Source::count(&map)); | |
| assert_eq!( | |
| Token::I64(1), | |
| Source::get(&map, Key::from_str("a")).unwrap().to_token() | |
| ); | |
| } | |
| #[test] | |
| fn btree_map() { | |
| let mut map = BTreeMap::new(); | |
| map.insert("a", 1); | |
| map.insert("b", 2); | |
| assert_eq!(2, Source::count(&map)); | |
| assert_eq!( | |
| Token::I64(1), | |
| Source::get(&map, Key::from_str("a")).unwrap().to_token() | |
| ); | |
| } | |
| } | |
| } | |
| #[cfg(test)] | |
| mod tests { | |
| use super::*; | |
| use kv::value::test::Token; | |
| #[test] | |
| fn source_is_object_safe() { | |
| fn _check(_: &dyn Source) {} | |
| } | |
| #[test] | |
| fn visitor_is_object_safe() { | |
| fn _check(_: &dyn Visitor) {} | |
| } | |
| #[test] | |
| fn count() { | |
| struct OnePair { | |
| key: &'static str, | |
| value: i32, | |
| } | |
| impl Source for OnePair { | |
| fn visit<'kvs>(&'kvs self, visitor: &mut dyn Visitor<'kvs>) -> Result<(), Error> { | |
| visitor.visit_pair(self.key.to_key(), self.value.to_value()) | |
| } | |
| } | |
| assert_eq!(1, Source::count(&("a", 1))); | |
| assert_eq!(2, Source::count(&[("a", 1), ("b", 2)] as &[_])); | |
| assert_eq!(0, Source::count(&Option::None::<(&str, i32)>)); | |
| assert_eq!(1, Source::count(&OnePair { key: "a", value: 1 })); | |
| } | |
| #[test] | |
| fn get() { | |
| let source = &[("a", 1), ("b", 2), ("a", 1)] as &[_]; | |
| assert_eq!( | |
| Token::I64(1), | |
| Source::get(source, Key::from_str("a")).unwrap().to_token() | |
| ); | |
| assert_eq!( | |
| Token::I64(2), | |
| Source::get(source, Key::from_str("b")).unwrap().to_token() | |
| ); | |
| assert!(Source::get(&source, Key::from_str("c")).is_none()); | |
| let source = Option::None::<(&str, i32)>; | |
| assert!(Source::get(&source, Key::from_str("a")).is_none()); | |
| } | |
| } |