env.rs
1 use crate::error::Error; 2 use crate::types::{Entry, KeyValuePair, Span}; 3 use std::borrow::Cow; 4 use std::collections::HashMap; 5 use std::hash::{BuildHasherDefault, Hasher}; 6 7 const FNV_OFFSET_BASIS: u64 = 0xcbf29ce484222325; 8 const FNV_PRIME: u64 = 0x100000001b3; 9 10 #[derive(Clone)] 11 pub(crate) struct Fnv1aHasher(u64); 12 13 impl Default for Fnv1aHasher { 14 #[inline] 15 fn default() -> Self { 16 Self(FNV_OFFSET_BASIS) 17 } 18 } 19 20 impl Hasher for Fnv1aHasher { 21 #[inline] 22 fn finish(&self) -> u64 { 23 self.0 24 } 25 26 #[inline] 27 fn write(&mut self, bytes: &[u8]) { 28 let mut hash = self.0; 29 for &b in bytes { 30 hash ^= b as u64; 31 hash = hash.wrapping_mul(FNV_PRIME); 32 } 33 self.0 = hash; 34 } 35 } 36 37 type FastMap<K, V> = HashMap<K, V, BuildHasherDefault<Fnv1aHasher>>; 38 39 /// Parsed environment with rich query API. 40 #[derive(Debug, Clone, Default)] 41 pub struct Environment<'a> { 42 pub(crate) pairs: FastMap<Cow<'a, str>, KeyValuePair<'a>>, 43 pub(crate) comments: Vec<Span>, 44 pub(crate) errors: Vec<Error>, 45 } 46 47 impl<'a> Environment<'a> { 48 pub fn new() -> Self { 49 Self::default() 50 } 51 52 pub fn from_entries(entries: Vec<Entry<'a>>) -> Self { 53 let mut env = Environment { 54 pairs: HashMap::with_capacity_and_hasher(entries.len(), BuildHasherDefault::default()), 55 comments: Vec::with_capacity(entries.len() / 4), 56 errors: Vec::new(), 57 }; 58 59 for entry in entries { 60 match entry { 61 Entry::Pair(kv) => { 62 env.pairs.insert(kv.key.clone(), *kv); 63 } 64 Entry::Comment(span) => { 65 env.comments.push(span); 66 } 67 Entry::Error(err) => { 68 env.errors.push(err); 69 } 70 } 71 } 72 env 73 } 74 75 pub fn get(&self, key: &str) -> Option<&str> { 76 self.pairs.get(key).map(|kv| kv.value.as_ref()) 77 } 78 79 pub fn get_or<'b>(&'b self, key: &str, default: &'b str) -> &'b str { 80 self.get(key).unwrap_or(default) 81 } 82 83 pub fn get_entry(&self, key: &str) -> Option<&KeyValuePair<'a>> { 84 self.pairs.get(key) 85 } 86 87 pub fn iter(&self) -> impl Iterator<Item = &KeyValuePair<'a>> { 88 self.pairs.values() 89 } 90 91 pub fn has_errors(&self) -> bool { 92 !self.errors.is_empty() 93 } 94 95 pub fn errors(&self) -> &[Error] { 96 &self.errors 97 } 98 99 pub fn to_map(&self) -> HashMap<String, String> { 100 self.pairs 101 .iter() 102 .map(|(k, v)| (k.to_string(), v.value.to_string())) 103 .collect() 104 } 105 106 pub fn into_owned(self) -> Environment<'static> { 107 Environment { 108 pairs: self 109 .pairs 110 .into_iter() 111 .map(|(k, v)| (Cow::Owned(k.into_owned()), v.into_owned())) 112 .collect(), 113 comments: self.comments, 114 errors: self.errors, 115 } 116 } 117 }