| //! Sources for key-value pairs. | |
| #[cfg(feature = "kv_unstable_sval")] | |
| extern crate sval; | |
| #[cfg(feature = "kv_unstable_serde")] | |
| extern crate serde; | |
| 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. | |
| #[cfg(not(test))] | |
| fn get<'v>(&'v self, key: Key) -> Option<Value<'v>> { | |
| get_default(self, key) | |
| } | |
| #[cfg(test)] | |
| fn get<'v>(&'v self, key: Key) -> Option<Value<'v>>; | |
| /// 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. | |
| #[cfg(not(test))] | |
| fn count(&self) -> usize { | |
| count_default(self) | |
| } | |
| #[cfg(test)] | |
| fn count(&self) -> usize; | |
| } | |
| /// The default implemention of `Source::get` | |
| pub(crate) fn get_default<'v>(source: &'v (impl Source + ?Sized), 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 _ = source.visit(&mut get); | |
| get.found | |
| } | |
| /// The default implementation of `Source::count`. | |
| pub(crate) fn count_default(source: impl Source) -> 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 _ = source.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 get<'v>(&'v self, key: Key) -> Option<Value<'v>> { | |
| for source in self { | |
| if let Some(found) = source.get(key.clone()) { | |
| return Some(found); | |
| } | |
| } | |
| None | |
| } | |
| 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 get<'v>(&'v self, key: Key) -> Option<Value<'v>> { | |
| self.as_ref().and_then(|s| s.get(key)) | |
| } | |
| 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::tests::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() | |
| ); | |
| } | |
| } | |
| } | |
| /// The result of calling `Source::as_map`. | |
| pub struct AsMap<S>(S); | |
| /// Visit this source as a map. | |
| pub fn as_map<S>(source: S) -> AsMap<S> | |
| where | |
| S: Source, | |
| { | |
| AsMap(source) | |
| } | |
| impl<S> Source for AsMap<S> | |
| where | |
| S: Source, | |
| { | |
| fn visit<'kvs>(&'kvs self, visitor: &mut dyn Visitor<'kvs>) -> Result<(), Error> { | |
| self.0.visit(visitor) | |
| } | |
| fn get<'v>(&'v self, key: Key) -> Option<Value<'v>> { | |
| self.0.get(key) | |
| } | |
| fn count(&self) -> usize { | |
| self.0.count() | |
| } | |
| } | |
| impl<S> fmt::Debug for AsMap<S> | |
| where | |
| S: Source, | |
| { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| let mut f = f.debug_map(); | |
| self.0.visit(&mut f).map_err(|_| fmt::Error)?; | |
| f.finish() | |
| } | |
| } | |
| /// The result of calling `Source::as_list` | |
| pub struct AsList<S>(S); | |
| /// Visit this source as a list. | |
| pub fn as_list<S>(source: S) -> AsList<S> | |
| where | |
| S: Source, | |
| { | |
| AsList(source) | |
| } | |
| impl<S> Source for AsList<S> | |
| where | |
| S: Source, | |
| { | |
| fn visit<'kvs>(&'kvs self, visitor: &mut dyn Visitor<'kvs>) -> Result<(), Error> { | |
| self.0.visit(visitor) | |
| } | |
| fn get<'v>(&'v self, key: Key) -> Option<Value<'v>> { | |
| self.0.get(key) | |
| } | |
| fn count(&self) -> usize { | |
| self.0.count() | |
| } | |
| } | |
| impl<S> fmt::Debug for AsList<S> | |
| where | |
| S: Source, | |
| { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| let mut f = f.debug_list(); | |
| self.0.visit(&mut f).map_err(|_| fmt::Error)?; | |
| f.finish() | |
| } | |
| } | |
| #[cfg(feature = "kv_unstable_sval")] | |
| mod sval_support { | |
| use super::*; | |
| use self::sval::value; | |
| impl<S> value::Value for AsMap<S> | |
| where | |
| S: Source, | |
| { | |
| fn stream(&self, stream: &mut value::Stream) -> value::Result { | |
| struct StreamVisitor<'a, 'b>(&'a mut value::Stream<'b>); | |
| impl<'a, 'b, 'kvs> Visitor<'kvs> for StreamVisitor<'a, 'b> { | |
| fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { | |
| self.0 | |
| .map_key(key) | |
| .map_err(|_| Error::msg("failed to stream map key"))?; | |
| self.0 | |
| .map_value(value) | |
| .map_err(|_| Error::msg("failed to stream map value"))?; | |
| Ok(()) | |
| } | |
| } | |
| stream | |
| .map_begin(Some(self.count())) | |
| .map_err(|_| self::sval::Error::msg("failed to begin map"))?; | |
| self.visit(&mut StreamVisitor(stream)) | |
| .map_err(|_| self::sval::Error::msg("failed to visit key-values"))?; | |
| stream | |
| .map_end() | |
| .map_err(|_| self::sval::Error::msg("failed to end map")) | |
| } | |
| } | |
| impl<S> value::Value for AsList<S> | |
| where | |
| S: Source, | |
| { | |
| fn stream(&self, stream: &mut value::Stream) -> value::Result { | |
| struct StreamVisitor<'a, 'b>(&'a mut value::Stream<'b>); | |
| impl<'a, 'b, 'kvs> Visitor<'kvs> for StreamVisitor<'a, 'b> { | |
| fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { | |
| self.0 | |
| .seq_elem((key, value)) | |
| .map_err(|_| Error::msg("failed to stream seq entry"))?; | |
| Ok(()) | |
| } | |
| } | |
| stream | |
| .seq_begin(Some(self.count())) | |
| .map_err(|_| self::sval::Error::msg("failed to begin seq"))?; | |
| self.visit(&mut StreamVisitor(stream)) | |
| .map_err(|_| self::sval::Error::msg("failed to visit key-values"))?; | |
| stream | |
| .seq_end() | |
| .map_err(|_| self::sval::Error::msg("failed to end seq")) | |
| } | |
| } | |
| #[cfg(test)] | |
| mod tests { | |
| use super::*; | |
| use self::sval::Value; | |
| use crate::kv::source; | |
| #[test] | |
| fn derive_stream() { | |
| #[derive(Value)] | |
| pub struct MyRecordAsMap<'a> { | |
| msg: &'a str, | |
| kvs: source::AsMap<&'a dyn Source>, | |
| } | |
| #[derive(Value)] | |
| pub struct MyRecordAsList<'a> { | |
| msg: &'a str, | |
| kvs: source::AsList<&'a dyn Source>, | |
| } | |
| } | |
| } | |
| } | |
| #[cfg(feature = "kv_unstable_serde")] | |
| pub mod as_map { | |
| //! `serde` adapters for serializing a `Source` as a map. | |
| use super::*; | |
| use self::serde::{Serialize, Serializer}; | |
| /// Serialize a `Source` as a map. | |
| pub fn serialize<T, S>(source: &T, serializer: S) -> Result<S::Ok, S::Error> | |
| where | |
| T: Source, | |
| S: Serializer, | |
| { | |
| as_map(source).serialize(serializer) | |
| } | |
| } | |
| #[cfg(feature = "kv_unstable_serde")] | |
| pub mod as_list { | |
| //! `serde` adapters for serializing a `Source` as a list. | |
| use super::*; | |
| use self::serde::{Serialize, Serializer}; | |
| /// Serialize a `Source` as a list. | |
| pub fn serialize<T, S>(source: &T, serializer: S) -> Result<S::Ok, S::Error> | |
| where | |
| T: Source, | |
| S: Serializer, | |
| { | |
| as_list(source).serialize(serializer) | |
| } | |
| } | |
| #[cfg(feature = "kv_unstable_serde")] | |
| mod serde_support { | |
| use super::*; | |
| use self::serde::ser::{Error as SerError, Serialize, SerializeMap, SerializeSeq, Serializer}; | |
| impl<T> Serialize for AsMap<T> | |
| where | |
| T: Source, | |
| { | |
| fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | |
| where | |
| S: Serializer, | |
| { | |
| struct SerializerVisitor<'a, S>(&'a mut S); | |
| impl<'a, 'kvs, S> Visitor<'kvs> for SerializerVisitor<'a, S> | |
| where | |
| S: SerializeMap, | |
| { | |
| fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { | |
| self.0 | |
| .serialize_entry(&key, &value) | |
| .map_err(|_| Error::msg("failed to serialize map entry"))?; | |
| Ok(()) | |
| } | |
| } | |
| let mut map = serializer.serialize_map(Some(self.count()))?; | |
| self.visit(&mut SerializerVisitor(&mut map)) | |
| .map_err(|_| S::Error::custom("failed to visit key-values"))?; | |
| map.end() | |
| } | |
| } | |
| impl<T> Serialize for AsList<T> | |
| where | |
| T: Source, | |
| { | |
| fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | |
| where | |
| S: Serializer, | |
| { | |
| struct SerializerVisitor<'a, S>(&'a mut S); | |
| impl<'a, 'kvs, S> Visitor<'kvs> for SerializerVisitor<'a, S> | |
| where | |
| S: SerializeSeq, | |
| { | |
| fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { | |
| self.0 | |
| .serialize_element(&(key, value)) | |
| .map_err(|_| Error::msg("failed to serialize seq entry"))?; | |
| Ok(()) | |
| } | |
| } | |
| let mut seq = serializer.serialize_seq(Some(self.count()))?; | |
| self.visit(&mut SerializerVisitor(&mut seq)) | |
| .map_err(|_| S::Error::custom("failed to visit seq"))?; | |
| seq.end() | |
| } | |
| } | |
| #[cfg(test)] | |
| mod tests { | |
| use super::*; | |
| use self::serde::Serialize; | |
| use crate::kv::source; | |
| #[test] | |
| fn derive_serialize() { | |
| #[derive(Serialize)] | |
| pub struct MyRecordAsMap<'a> { | |
| msg: &'a str, | |
| #[serde(flatten)] | |
| #[serde(with = "source::as_map")] | |
| kvs: &'a dyn Source, | |
| } | |
| #[derive(Serialize)] | |
| pub struct MyRecordAsList<'a> { | |
| msg: &'a str, | |
| #[serde(flatten)] | |
| #[serde(with = "source::as_list")] | |
| kvs: &'a dyn Source, | |
| } | |
| } | |
| } | |
| } | |
| #[cfg(test)] | |
| mod tests { | |
| use super::*; | |
| use kv::value::tests::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()) | |
| } | |
| fn get<'v>(&'v self, key: Key) -> Option<Value<'v>> { | |
| get_default(self, key) | |
| } | |
| fn count(&self) -> usize { | |
| count_default(self) | |
| } | |
| } | |
| 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()); | |
| } | |
| #[test] | |
| fn as_map() { | |
| let _ = crate::kv::source::as_map(("a", 1)); | |
| let _ = crate::kv::source::as_map(&("a", 1) as &dyn Source); | |
| } | |
| #[test] | |
| fn as_list() { | |
| let _ = crate::kv::source::as_list(("a", 1)); | |
| let _ = crate::kv::source::as_list(&("a", 1) as &dyn Source); | |
| } | |
| } |