#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Scope {
Object,
Call,
}
pub fn resolve<S: AsRef<str>>(
name: &str,
local_qualified: bool,
restriction: Option<&[S]>,
object_declares: bool,
) -> Scope {
if local_qualified {
return Scope::Call;
}
if let Some(list) = restriction
&& !list.is_empty()
&& !list.iter().any(|n| n.as_ref() == name)
{
return Scope::Call;
}
if object_declares {
Scope::Object
} else {
Scope::Call
}
}
#[cfg(test)]
mod tests {
use super::*;
const NONE: Option<&[&str]> = None;
#[test]
fn unrestricted_block_searches_the_object_first() {
assert_eq!(resolve("x", false, NONE, true), Scope::Object);
assert_eq!(resolve("y", false, NONE, false), Scope::Call);
assert_eq!(resolve("z", false, NONE, false), Scope::Call);
}
#[test]
fn restricted_block_lets_only_listed_names_into_the_object() {
let list = Some(&["x"][..]);
assert_eq!(resolve("x", false, list, true), Scope::Object);
assert_eq!(resolve("y", false, list, false), Scope::Call);
assert_eq!(resolve("y", false, list, true), Scope::Call);
}
#[test]
fn a_listed_name_the_object_lacks_resolves_in_the_call_scope() {
let list = Some(&["x"][..]);
assert_eq!(resolve("x", false, list, false), Scope::Call);
}
#[test]
fn empty_restriction_list_is_unrestricted() {
let list = Some(&[] as &[&str]);
assert_eq!(resolve("x", false, list, true), Scope::Object);
assert_eq!(resolve("y", false, list, false), Scope::Call);
}
#[test]
fn local_qualifier_bypasses_the_object() {
assert_eq!(resolve("x", false, NONE, true), Scope::Object);
assert_eq!(resolve("x", true, NONE, true), Scope::Call);
}
#[test]
fn local_qualifier_wins_over_a_restriction_list() {
let list = Some(&["x"][..]);
assert_eq!(resolve("x", true, list, true), Scope::Call);
assert_eq!(resolve("x", false, list, true), Scope::Object);
}
}