use std::collections::HashMap;
use bc_envelope::prelude::*;
use crate::{
Pattern,
pattern::{Matcher, Path, compile_as_atomic, leaf::LeafPattern, vm::Instr},
};
#[derive(Debug, Clone)]
pub struct BoolPattern(dcbor_pattern::BoolPattern);
impl BoolPattern {
pub fn any() -> Self { Self(dcbor_pattern::BoolPattern::any()) }
pub fn value(value: bool) -> Self {
Self(dcbor_pattern::BoolPattern::value(value))
}
pub fn from_dcbor_pattern(
dcbor_pattern: dcbor_pattern::BoolPattern,
) -> Self {
Self(dcbor_pattern)
}
}
impl PartialEq for BoolPattern {
fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
}
impl Eq for BoolPattern {}
impl std::hash::Hash for BoolPattern {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { self.0.hash(state); }
}
impl Matcher for BoolPattern {
fn paths_with_captures(
&self,
haystack: &Envelope,
) -> (Vec<Path>, HashMap<String, Vec<Path>>) {
if let Some(cbor) = haystack.subject().as_leaf() {
let dcbor_paths = dcbor_pattern::Matcher::paths(&self.0, &cbor);
if !dcbor_paths.is_empty() {
let envelope_paths = vec![vec![haystack.clone()]];
let envelope_captures = HashMap::new(); (envelope_paths, envelope_captures)
} else {
(vec![], HashMap::new())
}
} else {
(vec![], HashMap::new())
}
}
fn compile(
&self,
code: &mut Vec<Instr>,
literals: &mut Vec<Pattern>,
captures: &mut Vec<String>,
) {
compile_as_atomic(
&Pattern::Leaf(LeafPattern::Bool(self.clone())),
code,
literals,
captures,
);
}
}
impl std::fmt::Display for BoolPattern {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[cfg(test)]
mod tests {
use dcbor_parse::parse_dcbor_item;
use super::*;
#[test]
fn test_bool_pattern_display() {
assert_eq!(BoolPattern::any().to_string(), "bool");
assert_eq!(BoolPattern::value(true).to_string(), "true");
assert_eq!(BoolPattern::value(false).to_string(), "false");
}
#[test]
fn test_bool_pattern_dcbor_integration() {
let true_envelope = Envelope::new(true);
let false_envelope = Envelope::new(false);
let number_envelope = Envelope::new(42);
let text_envelope = Envelope::new("hello");
let any_pattern = BoolPattern::any();
assert!(any_pattern.matches(&true_envelope));
assert!(any_pattern.matches(&false_envelope));
assert!(!any_pattern.matches(&number_envelope)); assert!(!any_pattern.matches(&text_envelope));
let true_pattern = BoolPattern::value(true);
assert!(true_pattern.matches(&true_envelope));
assert!(!true_pattern.matches(&false_envelope));
assert!(!true_pattern.matches(&number_envelope));
assert!(!true_pattern.matches(&text_envelope));
let false_pattern = BoolPattern::value(false);
assert!(!false_pattern.matches(&true_envelope));
assert!(false_pattern.matches(&false_envelope));
assert!(!false_pattern.matches(&number_envelope));
assert!(!false_pattern.matches(&text_envelope));
let paths = true_pattern.paths(&true_envelope);
assert_eq!(paths.len(), 1);
assert_eq!(paths[0], vec![true_envelope.clone()]);
let no_paths = true_pattern.paths(&false_envelope);
assert_eq!(no_paths.len(), 0);
}
#[test]
fn test_bool_pattern_paths_with_captures() {
let bool_envelope = Envelope::new(true);
let pattern = BoolPattern::value(true);
let (paths, captures) = pattern.paths_with_captures(&bool_envelope);
assert_eq!(paths.len(), 1);
assert_eq!(paths[0], vec![bool_envelope.clone()]);
assert_eq!(captures.len(), 0); }
#[test]
fn test_bool_pattern_with_non_bool_envelope() {
let envelope = Envelope::new_assertion("key", "value");
let pattern = BoolPattern::any();
let paths = pattern.paths(&envelope);
assert_eq!(paths.len(), 0); }
#[test]
fn test_bool_pattern_with_direct_cbor_values() {
let true_cbor = parse_dcbor_item("true").unwrap();
let false_cbor = parse_dcbor_item("false").unwrap();
let true_envelope = Envelope::new(true_cbor);
let false_envelope = Envelope::new(false_cbor);
let any_pattern = BoolPattern::any();
assert!(any_pattern.matches(&true_envelope));
assert!(any_pattern.matches(&false_envelope));
let true_pattern = BoolPattern::value(true);
assert!(true_pattern.matches(&true_envelope));
assert!(!true_pattern.matches(&false_envelope));
let false_pattern = BoolPattern::value(false);
assert!(!false_pattern.matches(&true_envelope));
assert!(false_pattern.matches(&false_envelope));
}
}