/ src / env.rs
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  }