use std::rc::Rc;
use super::recorded_inputs::BoundName;
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct InputTerms {
bound: Vec<BoundName>,
documented: Vec<Rc<str>>,
}
impl InputTerms {
pub fn binding(bound: Vec<BoundName>) -> Self {
Self::documenting(bound, Vec::new())
}
pub fn documenting(bound: Vec<BoundName>, documented: Vec<Rc<str>>) -> Self {
Self { bound, documented }
}
pub fn bound(&self) -> &[BoundName] {
&self.bound
}
pub fn rebound(&self, bound: Vec<BoundName>) -> Self {
Self::documenting(bound, self.documented.clone())
}
pub fn binds(&self, name: &BoundName) -> bool {
self.bound.iter().any(|bound| bound.names_the_same(name))
}
pub fn documented(&self) -> &[Rc<str>] {
&self.documented
}
pub fn shares_a_term_with(&self, other: &InputTerms) -> bool {
let shares_a_name = self.bound.iter().any(|name| other.binds(name));
let documents_a_term_again = self
.documented
.iter()
.any(|term| other.documented.contains(term));
shares_a_name || documents_a_term_again
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::Namespace;
use crate::source::{SourceId, Span};
struct TermsFixture;
impl TermsFixture {
fn name(name: &str) -> BoundName {
BoundName {
name: name.into(),
namespace: Namespace::Value,
span: Span::new(SourceId::new(0), 0..0),
}
}
fn binding(names: &[&str]) -> InputTerms {
InputTerms::binding(names.iter().map(|name| Self::name(name)).collect())
}
fn documenting(terms: &[&str]) -> InputTerms {
InputTerms::documenting(
Vec::new(),
terms.iter().map(|term| Rc::from(*term)).collect(),
)
}
}
#[test]
fn terms_bind_only_their_bound_names() {
let terms = TermsFixture::binding(&["a"]);
assert!(terms.binds(&TermsFixture::name("a")));
assert!(!terms.binds(&TermsFixture::name("b")));
assert_eq!(terms.bound(), [TermsFixture::name("a")]);
}
#[test]
fn terms_that_bind_a_shared_name_share_a_term() {
let earlier = TermsFixture::binding(&["a", "b"]);
assert!(earlier.shares_a_term_with(&TermsFixture::binding(&["b"])));
assert!(!earlier.shares_a_term_with(&TermsFixture::binding(&["c"])));
}
#[test]
fn terms_that_document_a_shared_term_share_a_term() {
let earlier = TermsFixture::documenting(&["g", "k"]);
assert!(earlier.shares_a_term_with(&TermsFixture::documenting(&["k"])));
assert!(!earlier.shares_a_term_with(&TermsFixture::documenting(&["h"])));
}
#[test]
fn a_name_bound_and_a_term_documented_are_not_shared() {
let binding = TermsFixture::binding(&["g"]);
let documenting = TermsFixture::documenting(&["g"]);
assert!(!binding.shares_a_term_with(&documenting));
assert!(!documenting.shares_a_term_with(&binding));
}
#[test]
fn documenting_terms_list_what_they_document() {
let terms = TermsFixture::documenting(&["g", "k"]);
assert_eq!(terms.documented(), [Rc::from("g"), Rc::from("k")]);
assert!(TermsFixture::binding(&["g"]).documented().is_empty());
}
#[test]
fn rebound_terms_keep_what_they_document() {
let rebound = TermsFixture::documenting(&["g"]).rebound(vec![TermsFixture::name("a")]);
assert_eq!(rebound.bound(), [TermsFixture::name("a")]);
assert!(rebound.shares_a_term_with(&TermsFixture::documenting(&["g"])));
}
}