Skip to content

Instantly share code, notes, and snippets.

@fmonniot
Created January 28, 2021 06:08
Show Gist options
  • Save fmonniot/bb5a6795a3edef14c101b523d1063d9f to your computer and use it in GitHub Desktop.
Save fmonniot/bb5a6795a3edef14c101b523d1063d9f to your computer and use it in GitHub Desktop.
A trait offering a scoped hashmap using references
use std::{collections::HashMap};
fn main() {
println!("Hello, world!");
let words = ["hello", "my", "world"];
let mut env = new_env();
env.insert_value("my", "MY".to_string());
let result: Result<Vec<String>, ()> = words.iter().map(|word| {
do_something(&word, &env)
}).collect();
println!("{:?}", result)
}
fn do_something<'a, 'p: 'a, E: Environment<'p>>(e: &'static str, env: &'a E) -> Result<String, ()> {
if e.starts_with("w") {
let s2: ScopedEnvironment<'p, 'a> = env.new_scope();
let key: &'static str = e.split_at(1).1;
let result = do_something(key, &s2);
result
} else {
env.find_value(e).cloned().ok_or(())
}
}
// 'root must lives at least as long as 'parent
pub trait Environment<'parent> {
fn find_value<'a>(&'a self, name: &'static str) -> Option<&'a String>;
fn insert_value(&mut self, name: &'static str, value: String);
// 'parent must lives at least as long as 'a
fn new_scope<'a>(&'a self) -> ScopedEnvironment<'parent, 'a> where 'parent: 'a;
}
/// RootEnvironment represents the top level module and contains information accessible
/// from the entire module.
pub struct Root{
values: HashMap<&'static str, String>,
}
fn new_env() -> Root {
Root{values: HashMap::new()}
}
impl<'p> Environment<'p> for Root {
fn find_value(&self, name: &str) -> Option<&String> {
self.values.get(name)
}
// TODO Return error if name already exists
fn insert_value(&mut self, name: &'static str, value: String) {
self.values.insert(name, value);
}
fn new_scope<'a>(&'a self) -> ScopedEnvironment<'p, 'a> where 'p: 'a {
ScopedEnvironment { parent: self, values: HashMap::new() }
}
}
/// An Environment scoped to a module's sub expression (`let`, function, etc…)
pub struct ScopedEnvironment<'root, 'parent> {
parent: &'parent dyn Environment<'root>,
values: HashMap<&'static str, String>,
}
impl<'root, 'parent> Environment<'parent> for ScopedEnvironment<'root, 'parent> {
fn find_value(&self, name: &'static str) -> Option<&String> {
self.values.get(name).or_else(|| self.parent.find_value(name))
}
// TODO Return error if name already exists
fn insert_value(&mut self, name: &'static str, value: String) {
self.values.insert(name, value);
}
fn new_scope<'a>(&'a self) -> ScopedEnvironment<'parent, 'a> where 'parent: 'a{
let parent: &'a dyn Environment<'parent> = self;
ScopedEnvironment { parent, values: HashMap::new() }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment