use dcbor::prelude::*;
use crate::pattern::{Matcher, Path, Pattern, vm::Instr};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SequencePattern(Vec<Pattern>);
impl SequencePattern {
pub fn new(patterns: Vec<Pattern>) -> Self { Self(patterns) }
pub fn patterns(&self) -> &[Pattern] { &self.0 }
pub fn is_empty(&self) -> bool { self.patterns().is_empty() }
pub fn len(&self) -> usize { self.patterns().len() }
}
impl Matcher for SequencePattern {
fn paths(&self, _haystack: &CBOR) -> Vec<Path> {
vec![]
}
fn compile(
&self,
code: &mut Vec<Instr>,
literals: &mut Vec<Pattern>,
captures: &mut Vec<String>,
) {
if self.patterns().is_empty() {
return;
}
if self.patterns().len() == 1 {
self.patterns()[0].compile(code, literals, captures);
return;
}
for (i, pattern) in self.patterns().iter().enumerate() {
if i > 0 {
code.push(Instr::ExtendSequence);
}
pattern.compile(code, literals, captures);
if i > 0 {
code.push(Instr::CombineSequence);
}
}
}
fn collect_capture_names(&self, names: &mut Vec<String>) {
for pattern in self.patterns() {
pattern.collect_capture_names(names);
}
}
fn is_complex(&self) -> bool {
self.patterns().len() > 1
|| self.patterns().iter().any(|p| p.is_complex())
}
fn paths_with_captures(
&self,
cbor: &CBOR,
) -> (Vec<Path>, std::collections::HashMap<String, Vec<Path>>) {
(self.paths(cbor), std::collections::HashMap::new())
}
}
impl std::fmt::Display for SequencePattern {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.patterns().is_empty() {
write!(f, "()")
} else {
let patterns_str: Vec<String> =
self.patterns().iter().map(|p| p.to_string()).collect();
write!(f, "{}", patterns_str.join(", "))
}
}
}
#[cfg(test)]
mod tests {
use dcbor_parse::parse_dcbor_item;
use super::*;
#[test]
fn test_sequence_pattern_new() {
let patterns = vec![Pattern::text("first"), Pattern::text("second")];
let sequence = SequencePattern::new(patterns.clone());
assert_eq!(sequence.patterns(), &patterns);
}
#[test]
fn test_sequence_pattern_empty() {
let sequence = SequencePattern::new(vec![]);
assert!(sequence.is_empty());
assert_eq!(sequence.len(), 0);
}
#[test]
fn test_sequence_pattern_len() {
let patterns =
vec![Pattern::text("a"), Pattern::text("b"), Pattern::text("c")];
let sequence = SequencePattern::new(patterns);
assert!(!sequence.is_empty());
assert_eq!(sequence.len(), 3);
}
#[test]
fn test_sequence_pattern_display() {
let patterns = vec![
Pattern::text("first"),
Pattern::text("second"),
Pattern::text("third"),
];
let sequence = SequencePattern::new(patterns);
let display = sequence.to_string();
assert!(display.contains("first"));
assert!(display.contains("second"));
assert!(display.contains("third"));
assert!(display.contains(", "));
}
#[test]
fn test_sequence_pattern_display_empty() {
let sequence = SequencePattern::new(vec![]);
assert_eq!(sequence.to_string(), "()");
}
#[test]
fn test_sequence_pattern_is_complex() {
let empty_sequence = SequencePattern::new(vec![]);
assert!(!empty_sequence.is_complex());
let single_sequence = SequencePattern::new(vec![Pattern::text("test")]);
assert!(!single_sequence.is_complex());
let multi_sequence = SequencePattern::new(vec![
Pattern::text("first"),
Pattern::text("second"),
]);
assert!(multi_sequence.is_complex());
}
#[test]
fn test_sequence_pattern_compile() {
let patterns = vec![Pattern::text("first"), Pattern::text("second")];
let sequence = SequencePattern::new(patterns);
let mut code = Vec::new();
let mut literals = Vec::new();
let mut captures = Vec::new();
sequence.compile(&mut code, &mut literals, &mut captures);
assert!(!code.is_empty());
assert_eq!(literals.len(), 2);
}
#[test]
fn test_sequence_pattern_compile_empty() {
let sequence = SequencePattern::new(vec![]);
let mut code = Vec::new();
let mut literals = Vec::new();
let mut captures = Vec::new();
sequence.compile(&mut code, &mut literals, &mut captures);
assert!(code.is_empty());
}
#[test]
fn test_sequence_pattern_collect_capture_names() {
let patterns = vec![
Pattern::capture("first", Pattern::text("a")),
Pattern::text("b"),
Pattern::capture("third", Pattern::text("c")),
];
let sequence = SequencePattern::new(patterns);
let mut names = Vec::new();
sequence.collect_capture_names(&mut names);
assert_eq!(names.len(), 2);
assert!(names.contains(&"first".to_string()));
assert!(names.contains(&"third".to_string()));
}
#[test]
fn test_sequence_pattern_paths() {
let patterns = vec![Pattern::text("a"), Pattern::text("b")];
let sequence = SequencePattern::new(patterns);
let cbor = "test".to_cbor();
let paths = sequence.paths(&cbor);
assert!(paths.is_empty());
}
#[test]
fn test_sequence_pattern_with_array() {
let _array_cbor =
parse_dcbor_item(r#"["first", "second", "third"]"#).unwrap();
let sequence = SequencePattern::new(vec![
Pattern::text("first"),
Pattern::text("second"),
Pattern::text("third"),
]);
assert_eq!(sequence.len(), 3);
assert!(!sequence.is_empty());
assert!(sequence.is_complex());
let display = sequence.to_string();
assert!(display.contains("first"));
assert!(display.contains("second"));
assert!(display.contains("third"));
assert!(display.contains(", "));
}
#[test]
fn test_sequence_pattern_with_mixed_types() {
let _mixed_array =
parse_dcbor_item(r#"[42, "hello", true, null]"#).unwrap();
let sequence = SequencePattern::new(vec![
Pattern::number(42),
Pattern::text("hello"),
Pattern::bool(true),
Pattern::null(),
]);
assert_eq!(sequence.len(), 4);
assert!(sequence.is_complex());
let mut code = Vec::new();
let mut literals = Vec::new();
let mut captures = Vec::new();
sequence.compile(&mut code, &mut literals, &mut captures);
assert!(!code.is_empty());
assert_eq!(literals.len(), 4); }
#[test]
fn test_sequence_pattern_partial_match() {
let _large_array =
parse_dcbor_item(r#"["start", "middle1", "middle2", "end"]"#)
.unwrap();
let sequence = SequencePattern::new(vec![
Pattern::text("middle1"),
Pattern::text("middle2"),
]);
assert_eq!(sequence.len(), 2);
assert!(!sequence.is_empty());
assert!(sequence.is_complex());
let display = sequence.to_string();
assert!(display.contains("middle1"));
assert!(display.contains("middle2"));
assert!(display.contains(", "));
}
#[test]
fn test_sequence_pattern_with_captures() {
let sequence = SequencePattern::new(vec![
Pattern::capture("first_value", Pattern::text("hello")),
Pattern::capture("second_value", Pattern::number(42)),
Pattern::text("world"),
]);
let mut names = Vec::new();
sequence.collect_capture_names(&mut names);
assert_eq!(names.len(), 2);
assert!(names.contains(&"first_value".to_string()));
assert!(names.contains(&"second_value".to_string()));
let display = sequence.to_string();
assert!(display.contains("@first_value"));
assert!(display.contains("@second_value"));
assert!(display.contains(", "));
}
#[test]
fn test_sequence_pattern_with_simple_types() {
let _simple_array = parse_dcbor_item(r#"["text", 123, true]"#).unwrap();
let sequence = SequencePattern::new(vec![
Pattern::text("text"),
Pattern::number(123),
Pattern::bool(true),
]);
assert_eq!(sequence.len(), 3);
assert!(sequence.is_complex());
let mut code = Vec::new();
let mut literals = Vec::new();
let mut captures = Vec::new();
sequence.compile(&mut code, &mut literals, &mut captures);
assert!(!code.is_empty());
assert_eq!(literals.len(), 3); }
#[test]
fn test_sequence_pattern_with_byte_strings() {
let _bytes_array =
parse_dcbor_item(r#"[h'deadbeef', h'cafebabe', "text"]"#).unwrap();
let sequence = SequencePattern::new(vec![
Pattern::byte_string(hex::decode("deadbeef").unwrap()),
Pattern::byte_string(hex::decode("cafebabe").unwrap()),
Pattern::text("text"),
]);
assert_eq!(sequence.len(), 3);
assert!(sequence.is_complex());
let patterns = sequence.patterns();
assert_eq!(patterns.len(), 3);
let display = sequence.to_string();
assert!(display.contains(", "));
}
}