Created
January 28, 2021 06:08
-
-
Save fmonniot/bb5a6795a3edef14c101b523d1063d9f to your computer and use it in GitHub Desktop.
A trait offering a scoped hashmap using references
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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