#[cfg(doc)]
use super::{check_entropy_heuristic, mask_bounded, normalized_hex_credential_span};
use super::{
is_assignment_label_gap, is_lookup_key_label, strip_delimiters, tokenize_entropy_tokens,
MAX_BRIDGE_FRAGMENTS, MAX_BRIDGE_GLUE_TOKENS, MIN_BRIDGE_FRAGMENT_LEN,
};
fn adjacent_gap_is_bridgeable(text: &str, gap_start: usize, gap_end: usize) -> bool {
gap_end >= gap_start && !text[gap_start..gap_end].contains(|c: char| c.is_ascii_alphanumeric())
}
pub(super) fn is_bridge_fragment_shape(s: &str) -> bool {
s.len() >= MIN_BRIDGE_FRAGMENT_LEN && s.bytes().all(|b| b.is_ascii_alphanumeric())
}
fn is_delimiter_only_token(s: &str) -> bool {
!s.bytes().any(|b| b.is_ascii_alphanumeric())
}
fn probe_bridge_fragment(
tokens: &[(usize, &str)],
text: &str,
edge: usize,
dir: isize,
) -> Option<usize> {
let mut i = edge;
let mut glue_skipped = 0usize;
loop {
let next_i = i.checked_add_signed(dir)?;
if next_i >= tokens.len() {
return None;
}
let (lo, hi) = if dir < 0 { (next_i, i) } else { (i, next_i) };
let (lo_offset, lo_raw) = tokens[lo];
let (hi_offset, _) = tokens[hi];
let gap_start = lo_offset + lo_raw.len();
if !adjacent_gap_is_bridgeable(text, gap_start, hi_offset) {
return None;
}
let candidate = strip_delimiters(tokens[next_i].1);
if is_bridge_fragment_shape(candidate) {
return Some(next_i);
}
if is_delimiter_only_token(candidate) && glue_skipped < MAX_BRIDGE_GLUE_TOKENS {
glue_skipped += 1;
i = next_i;
continue;
}
return None;
}
}
pub(super) fn bridge_fragment_chain<'a>(
tokens: &[(usize, &'a str)],
text: &str,
anchor_idx: usize,
) -> Vec<&'a str> {
let mut start = anchor_idx;
let mut end = anchor_idx;
let mut fragment_count = 1usize;
loop {
let mut extended = false;
if fragment_count < MAX_BRIDGE_FRAGMENTS && start > 0 {
if let Some(new_start) = probe_bridge_fragment(tokens, text, start, -1) {
start = new_start;
fragment_count += 1;
extended = true;
}
}
if fragment_count < MAX_BRIDGE_FRAGMENTS && end + 1 < tokens.len() {
if let Some(new_end) = probe_bridge_fragment(tokens, text, end, 1) {
end = new_end;
fragment_count += 1;
extended = true;
}
}
if !extended {
break;
}
}
tokens[start..=end]
.iter()
.map(|&(_, raw)| strip_delimiters(raw))
.filter(|stripped| !is_delimiter_only_token(stripped))
.collect()
}
pub(super) fn trailing_bridge_fragment_cut(window: &str) -> Option<usize> {
let tokens = tokenize_entropy_tokens(window);
let mut idx = tokens.len().checked_sub(1)?;
let mut fragment_budget = MAX_BRIDGE_FRAGMENTS - 1;
let mut glue_budget = MAX_BRIDGE_GLUE_TOKENS;
let mut cut_at = None;
loop {
let (offset, raw) = tokens[idx];
let candidate = strip_delimiters(raw);
if is_bridge_fragment_shape(candidate) {
if fragment_budget == 0 {
break;
}
fragment_budget -= 1;
glue_budget = MAX_BRIDGE_GLUE_TOKENS;
cut_at = Some(offset);
} else if is_delimiter_only_token(candidate) {
if glue_budget == 0 {
break;
}
glue_budget -= 1;
} else {
break;
}
if idx == 0 {
break;
}
let (prev_offset, prev_raw) = tokens[idx - 1];
let gap_start = prev_offset + prev_raw.len();
if !adjacent_gap_is_bridgeable(window, gap_start, offset) {
break;
}
idx -= 1;
}
cut_at
}
pub(super) fn contains_word(low_window: &str, needle: &str, underscore_is_word_char: bool) -> bool {
let is_word_char = |c: char| c.is_ascii_alphanumeric() || (underscore_is_word_char && c == '_');
let mut start = 0;
while let Some(rel) = low_window[start..].find(needle) {
let abs = start + rel;
let before_ok = abs == 0
|| low_window[..abs]
.chars()
.next_back()
.is_none_or(|c| !is_word_char(c));
let after_end = abs + needle.len();
let after_ok = after_end >= low_window.len()
|| low_window[after_end..]
.chars()
.next()
.is_none_or(|c| !is_word_char(c));
if before_ok && after_ok {
return true;
}
start = abs + needle.len().max(1);
}
false
}
pub(super) fn contains_bounded_word(low_window: &str, needle: &str) -> bool {
if needle != "key" {
return contains_word(low_window, needle, false);
}
low_window
.split(|c: char| !c.is_ascii_alphanumeric() && c != '_')
.any(|label| {
if !contains_word(label, needle, false) {
return false;
}
let end = label.as_ptr() as usize - low_window.as_ptr() as usize + label.len();
let after = low_window[end..].trim_start_matches(is_assignment_label_gap);
!(is_lookup_key_label(label) && after.starts_with([':', '=']))
})
}