pub fn closing_brace(text: &str, open: usize) -> Option<usize> {
let mut depth = 0usize;
for (index, c) in text[open..].char_indices() {
match c {
'{' => depth += 1,
'}' => {
depth -= 1;
if depth == 0 {
return Some(open + index);
}
}
_ => {}
}
}
None
}
pub fn fallbacks(token: &str) -> Vec<&str> {
let mut parts = Vec::new();
let mut depth = 0i32;
let mut start = 0;
let bytes = token.as_bytes();
let mut index = 0;
while index < bytes.len() {
match bytes[index] {
b'{' => depth += 1,
b'}' => depth -= 1,
b'?' if depth == 0 && bytes.get(index + 1) == Some(&b'?') => {
parts.push(token[start..index].trim());
start = index + 2;
index += 1;
}
_ => {}
}
index += 1;
}
parts.push(token[start..].trim());
parts
}
pub fn env_name(source: &str) -> Option<&str> {
source.strip_prefix("env.").filter(|name| {
!name.is_empty()
&& name
.chars()
.all(|c| c.is_alphanumeric() || "_.()-".contains(c))
})
}