use std::collections::VecDeque; use crate::parse::lex::{Span, Tk}; use crate::parse::{Redir, RedirType}; use crate::prelude::*; pub trait VecDequeExt { fn to_vec(self) -> Vec; } pub trait CharDequeUtils { fn to_string(self) -> String; fn ends_with(&self, pat: &str) -> bool; fn starts_with(&self, pat: &str) -> bool; } pub trait TkVecUtils { fn get_span(&self) -> Option; fn debug_tokens(&self); } pub trait RedirVecUtils { /// Splits the vector of redirections into two vectors /// /// One vector contains input redirs, the other contains output redirs fn split_by_channel(self) -> (Vec, Vec); } impl VecDequeExt for VecDeque { fn to_vec(self) -> Vec { self.into_iter().collect::>() } } impl CharDequeUtils for VecDeque { fn to_string(mut self) -> String { let mut result = String::with_capacity(self.len()); while let Some(ch) = self.pop_front() { result.push(ch); } result } fn ends_with(&self, pat: &str) -> bool { let pat_chars = pat.chars(); let self_len = self.len(); // If pattern is longer than self, return false if pat_chars.clone().count() > self_len { return false; } // Compare from the back self .iter() .rev() .zip(pat_chars.rev()) .all(|(c1, c2)| c1 == &c2) } fn starts_with(&self, pat: &str) -> bool { let pat_chars = pat.chars(); let self_len = self.len(); // If pattern is longer than self, return false if pat_chars.clone().count() > self_len { return false; } // Compare from the front self.iter().zip(pat_chars).all(|(c1, c2)| c1 == &c2) } } impl TkVecUtils for Vec { fn get_span(&self) -> Option { if let Some(first_tk) = self.first() { self .last() .map(|last_tk| Span::new(first_tk.span.start..last_tk.span.end, first_tk.source())) } else { None } } fn debug_tokens(&self) { for token in self {} } } impl RedirVecUtils for Vec { fn split_by_channel(self) -> (Vec, Vec) { let mut input = vec![]; let mut output = vec![]; for redir in self { match redir.class { RedirType::Input => input.push(redir), RedirType::Pipe => match redir.io_mode.tgt_fd() { STDIN_FILENO => input.push(redir), STDOUT_FILENO | STDERR_FILENO => output.push(redir), _ => unreachable!(), }, _ => output.push(redir), } } (input, output) } }