use std::borrow::Cow;
use snowball::Among;
#[derive(Debug, Clone)]
pub struct SnowballEnv<'a> {
pub current: Cow<'a, str>,
pub cursor: i32,
pub limit: i32,
pub limit_backward: i32,
pub bra: i32,
pub ket: i32,
}
impl<'a> SnowballEnv<'a> {
pub fn create(value: &'a str) -> Self {
let len = value.len();
SnowballEnv {
current: Cow::from(value),
cursor: 0,
limit: len as i32,
limit_backward: 0,
bra: 0,
ket: len as i32,
}
}
pub fn get_current(self) -> Cow<'a, str> {
self.current
}
pub fn set_current(&mut self, current: &'a str) {
self.current = Cow::from(current);
}
pub fn set_current_s(&mut self, current: String) {
self.current = Cow::from(current);
}
fn replace_s(&mut self, bra: i32, ket: i32, s: &str) -> i32 {
let adjustment = s.len() as i32 - (ket - bra);
let mut result = String::with_capacity(self.current.len());
{
let (lhs, _) = self.current.split_at(bra as usize);
let (_, rhs) = self.current.split_at(ket as usize);
result.push_str(lhs);
result.push_str(s);
result.push_str(rhs);
}
let new_lim = self.limit + adjustment;
self.limit = new_lim;
if self.cursor >= ket {
let new_cur = self.cursor + adjustment;
self.cursor = new_cur;
} else if self.cursor > bra {
self.cursor = bra
}
self.current = Cow::from(result);
adjustment
}
pub fn eq_s(&mut self, s: &str) -> bool {
if self.cursor >= self.limit {
return false;
}
if self.current[(self.cursor as usize)..].starts_with(s) {
self.cursor += s.len() as i32;
while !self.current.is_char_boundary(self.cursor as usize) {
self.cursor += 1;
}
true
} else {
false
}
}
pub fn eq_s_b(&mut self, s: &str) -> bool {
if (self.cursor - self.limit_backward) < s.len() as i32 {
false
} else if !self.current.is_char_boundary(self.cursor as usize - s.len()) ||
!self.current[self.cursor as usize - s.len()..].starts_with(s) {
false
} else {
self.cursor -= s.len() as i32;
true
}
}
pub fn slice_from(&mut self, s: &str) {
let (bra, ket) = (self.bra, self.ket);
self.replace_s(bra, ket, s);
self.ket = bra + s.len() as i32;
}
pub fn next_char(&mut self) {
self.cursor += 1;
while !self.current.is_char_boundary(self.cursor as usize) {
self.cursor += 1;
}
}
pub fn previous_char(&mut self) {
self.cursor -= 1;
while !self.current.is_char_boundary(self.cursor as usize) {
self.cursor -= 1;
}
}
pub fn hop(&mut self, mut delta: i32) -> bool {
let mut res = self.cursor;
while delta > 0 {
delta -= 1;
if res >= self.limit {
return false;
}
res += 1;
while res < self.limit && !self.current.is_char_boundary(res as usize) {
res += 1;
}
}
self.cursor = res;
return true;
}
pub fn hop_checked(&mut self, delta: i32) -> bool {
return delta >= 0 && self.hop(delta);
}
pub fn hop_back(&mut self, mut delta: i32) -> bool {
let mut res = self.cursor;
while delta > 0 {
delta -= 1;
if res <= self.limit_backward {
return false;
}
res -= 1;
while res > self.limit_backward && !self.current.is_char_boundary(res as usize) {
res -= 1;
}
}
self.cursor = res;
return true;
}
pub fn hop_back_checked(&mut self, delta: i32) -> bool {
return delta >= 0 && self.hop_back(delta);
}
pub fn in_grouping(&mut self, chars: &[u8], min: u32, max: u32) -> bool {
if self.cursor >= self.limit {
return false;
}
if let Some(chr) = self.current[self.cursor as usize..].chars().next() {
let mut ch = chr as u32; if ch > max || ch < min {
return false;
}
ch -= min;
if (chars[(ch >> 3) as usize] & (0x1 << (ch & 0x7))) == 0 {
return false;
}
self.next_char();
return true;
}
return false;
}
pub fn go_in_grouping(&mut self, chars: &[u8], min: u32, max: u32) -> bool {
while self.cursor < self.limit {
if let Some(chr) = self.current[self.cursor as usize..].chars().next() {
let mut ch = chr as u32; if ch > max || ch < min {
return true;
}
ch -= min;
if (chars[(ch >> 3) as usize] & (0x1 << (ch & 0x7))) == 0 {
return true;
}
self.next_char();
} else {
return false;
}
}
return false;
}
pub fn in_grouping_b(&mut self, chars: &[u8], min: u32, max: u32) -> bool {
if self.cursor <= self.limit_backward {
return false;
}
let c = self.cursor;
self.previous_char();
if let Some(chr) = self.current[self.cursor as usize..].chars().next() {
let mut ch = chr as u32; if ch > max || ch < min {
self.cursor = c;
return false;
}
ch -= min;
if (chars[(ch >> 3) as usize] & (0x1 << (ch & 0x7))) == 0 {
self.cursor = c;
return false;
}
return true;
}
return false;
}
pub fn go_in_grouping_b(&mut self, chars: &[u8], min: u32, max: u32) -> bool {
while self.cursor > self.limit_backward {
let c = self.cursor;
self.previous_char();
if let Some(chr) = self.current[self.cursor as usize..].chars().next() {
let mut ch = chr as u32; if ch > max || ch < min {
self.cursor = c;
return true;
}
ch -= min;
if (chars[(ch >> 3) as usize] & (0x1 << (ch & 0x7))) == 0 {
self.cursor = c;
return true;
}
} else {
return false;
}
}
return false;
}
pub fn out_grouping(&mut self, chars: &[u8], min: u32, max: u32) -> bool {
if self.cursor >= self.limit {
return false;
}
if let Some(chr) = self.current[self.cursor as usize..].chars().next() {
let mut ch = chr as u32; if ch > max || ch < min {
self.next_char();
return true;
}
ch -= min;
if (chars[(ch >> 3) as usize] & (0x1 << (ch & 0x7))) == 0 {
self.next_char();
return true;
}
}
return false;
}
pub fn go_out_grouping(&mut self, chars: &[u8], min: u32, max: u32) -> bool {
while self.cursor < self.limit {
if let Some(chr) = self.current[self.cursor as usize..].chars().next() {
let mut ch = chr as u32; if ch <= max && ch >= min {
ch -= min;
if (chars[(ch >> 3) as usize] & (0x1 << (ch & 0x7))) != 0 {
return true;
}
}
self.next_char();
} else {
return false;
}
}
return false;
}
pub fn out_grouping_b(&mut self, chars: &[u8], min: u32, max: u32) -> bool {
if self.cursor <= self.limit_backward {
return false;
}
let c = self.cursor;
self.previous_char();
if let Some(chr) = self.current[self.cursor as usize..].chars().next() {
let mut ch = chr as u32; if ch > max || ch < min {
return true;
}
ch -= min;
if (chars[(ch >> 3) as usize] & (0x1 << (ch & 0x7))) == 0 {
return true;
}
self.cursor = c;
}
return false;
}
pub fn go_out_grouping_b(&mut self, chars: &[u8], min: u32, max: u32) -> bool {
while self.cursor > self.limit_backward {
let c = self.cursor;
self.previous_char();
if let Some(chr) = self.current[self.cursor as usize..].chars().next() {
let mut ch = chr as u32; if ch <= max && ch >= min {
ch -= min;
if (chars[(ch >> 3) as usize] & (0x1 << (ch & 0x7))) != 0 {
self.cursor = c;
return true;
}
}
} else {
return false;
}
}
return false;
}
pub fn slice_del(&mut self) {
self.slice_from("")
}
pub fn insert(&mut self, bra: i32, ket: i32, s: &str) {
let adjustment = self.replace_s(bra, ket, s);
if bra <= self.bra {
self.bra = self.bra + adjustment;
}
if bra <= self.ket {
self.ket = self.ket + adjustment;
}
}
pub fn assign_to(&mut self) -> String {
self.current[0..self.limit as usize].to_string()
}
pub fn slice_to(&mut self) -> String {
self.current[self.bra as usize..self.ket as usize].to_string()
}
pub fn find_among<T>(&mut self, amongs: &[Among<T>], context: &mut T) -> i32 {
use std::cmp::min;
let mut i: i32 = 0;
let mut j: i32 = amongs.len() as i32;
let c = self.cursor;
let l = self.limit;
let mut common_i = 0i32;
let mut common_j = 0i32;
let mut first_key_inspected = false;
loop {
let k = i + ((j - i) >> 1);
let mut diff: i32 = 0;
let mut common = min(common_i, common_j);
let w = &amongs[k as usize];
for lvar in common..w.0.len() as i32 {
if c + common == l {
diff = -1;
break;
}
diff = self.current.as_bytes()[(c + common) as usize] as i32 - w.0.as_bytes()[lvar as usize] as i32;
if diff != 0 {
break;
}
common += 1;
}
if diff < 0 {
j = k;
common_j = common;
} else {
i = k;
common_i = common;
}
if j - i <= 1 {
if i > 0 {
break;
}
if j == i {
break;
}
if first_key_inspected {
break;
}
first_key_inspected = true;
}
}
loop {
let w = &amongs[i as usize];
if common_i >= w.0.len() as i32{
self.cursor = c + w.0.len() as i32;
if let Some(ref method) = w.3 {
if method(self, context) {
self.cursor = c + w.0.len() as i32;
return w.2;
}
} else {
return w.2;
}
}
i = w.1;
if i < 0 {
return 0;
}
}
}
pub fn find_among_b<T>(&mut self, amongs: &[Among<T>], context: &mut T) -> i32 {
let mut i: i32 = 0;
let mut j: i32 = amongs.len() as i32;
let c = self.cursor;
let lb = self.limit_backward;
let mut common_i = 0i32;
let mut common_j = 0i32;
let mut first_key_inspected = false;
loop {
let k = i + ((j - i) >> 1);
let mut diff: i32 = 0;
let mut common = if common_i < common_j {
common_i
} else {
common_j
};
let w = &amongs[k as usize];
for lvar in (0..w.0.len() - common as usize).rev() {
if c - common == lb {
diff = -1;
break;
}
diff = self.current.as_bytes()[(c - common - 1) as usize] as i32 - w.0.as_bytes()[lvar] as i32;
if diff != 0 {
break;
}
common += 1;
}
if diff < 0 {
j = k;
common_j = common;
} else {
i = k;
common_i = common;
}
if j - i <= 1 {
if i > 0 {
break;
}
if j == i {
break;
}
if first_key_inspected {
break;
}
first_key_inspected = true;
}
}
loop {
let w = &amongs[i as usize];
if common_i >= w.0.len() as i32 {
self.cursor = c - w.0.len() as i32;
if let Some(ref method) = w.3 {
if method(self, context) {
self.cursor = c - w.0.len() as i32;
return w.2;
}
} else {
return w.2;
}
}
i = w.1;
if i < 0 {
return 0;
}
}
}
}