#[cfg(not(feature = "std"))]
use crate::nostd_prelude::*;
pub(crate) fn norm_index(idx: i64, len: usize) -> Option<usize> {
let len = len as i64;
let i = if idx < 0 { idx + len } else { idx };
if i < 0 || i >= len {
None
} else {
Some(i as usize)
}
}
pub(crate) fn range_bounds(start: i64, stop: i64, len: usize) -> Option<(usize, usize)> {
if len == 0 {
return None;
}
let len = len as i64;
let s = (if start < 0 { start + len } else { start }).max(0);
let e = (if stop < 0 { stop + len } else { stop }).min(len - 1);
if s > e || s >= len {
None
} else {
Some((s as usize, e as usize))
}
}
pub(crate) fn parse_i64(b: &[u8]) -> Option<i64> {
core::str::from_utf8(b).ok()?.parse::<i64>().ok()
}
pub(crate) fn parse_canonical_i64(b: &[u8]) -> Option<i64> {
if b.is_empty() || b.len() > 20 {
return None;
}
let first = b[0];
if !first.is_ascii_digit() && first != b'-' {
return None;
}
let n = core::str::from_utf8(b).ok()?.parse::<i64>().ok()?;
let mut buf = itoa_i64_stack();
let s = format_i64_into(n, &mut buf);
if s == b { Some(n) } else { None }
}
pub(crate) fn format_i64_into(n: i64, buf: &mut [u8; 20]) -> &[u8] {
let (mut n_abs, neg) = if n < 0 {
((n as i128).unsigned_abs() as u64, true)
} else {
(n as u64, false)
};
let mut i = buf.len();
if n_abs == 0 {
i -= 1;
buf[i] = b'0';
} else {
while n_abs > 0 {
i -= 1;
buf[i] = b'0' + (n_abs % 10) as u8;
n_abs /= 10;
}
}
if neg {
i -= 1;
buf[i] = b'-';
}
&buf[i..]
}
#[inline]
pub(crate) fn itoa_i64_stack() -> [u8; 20] {
[0u8; 20]
}
#[inline]
pub(crate) fn bulk_header_into(out: &mut Vec<u8>, len: usize) {
out.push(b'$');
let mut buf = [0u8; 20];
let mut n = len;
let mut i = buf.len();
if n == 0 {
i -= 1;
buf[i] = b'0';
} else {
while n > 0 {
i -= 1;
buf[i] = b'0' + (n % 10) as u8;
n /= 10;
}
}
out.extend_from_slice(&buf[i..]);
out.extend_from_slice(b"\r\n");
}
pub(crate) fn parse_f64(b: &[u8]) -> Option<f64> {
let f: f64 = core::str::from_utf8(b).ok()?.trim().parse().ok()?;
f.is_finite().then_some(f)
}
pub fn glob_match(pat: &[u8], s: &[u8]) -> bool {
glob(pat, s)
}
fn glob(p: &[u8], s: &[u8]) -> bool {
let (mut pi, mut si) = (0usize, 0usize);
let mut star_pi: Option<usize> = None;
let mut star_si = 0usize;
while si < s.len() {
if pi < p.len() && p[pi] == b'*' {
while pi < p.len() && p[pi] == b'*' {
pi += 1;
}
star_pi = Some(pi);
star_si = si;
continue;
}
if pi < p.len()
&& let Some(width) = match_token(&p[pi..], s[si])
{
pi += width;
si += 1;
continue;
}
let Some(anchor) = star_pi else {
return false;
};
pi = anchor;
star_si += 1;
si = star_si;
}
while pi < p.len() && p[pi] == b'*' {
pi += 1;
}
pi == p.len()
}
fn match_token(p: &[u8], ch: u8) -> Option<usize> {
match p[0] {
b'?' => Some(1),
b'[' => {
let (matched, rest) = match_class(&p[1..], ch);
matched.then(|| p.len() - rest.len())
}
b'\\' if p.len() >= 2 => (p[1] == ch).then_some(2),
c => (c == ch).then_some(1),
}
}
fn match_class(p: &[u8], ch: u8) -> (bool, &[u8]) {
let mut i = 0;
let negate = p.first() == Some(&b'^');
if negate {
i += 1;
}
let mut matched = false;
while i < p.len() && p[i] != b']' {
if p[i] == b'\\' && i + 1 < p.len() {
matched |= p[i + 1] == ch;
i += 2;
} else if i + 2 < p.len() && p[i + 1] == b'-' && p[i + 2] != b']' {
let (lo, hi) = if p[i] <= p[i + 2] {
(p[i], p[i + 2])
} else {
(p[i + 2], p[i])
};
matched |= (lo..=hi).contains(&ch);
i += 3;
} else {
matched |= p[i] == ch;
i += 1;
}
}
if i < p.len() {
i += 1; }
(matched ^ negate, &p[i..])
}
pub(crate) fn fmt_num(v: f64) -> Vec<u8> {
#[cfg(feature = "std")]
#[allow(clippy::float_cmp)]
let is_integer_valued = v == v.trunc();
#[cfg(not(feature = "std"))]
#[allow(clippy::float_cmp)]
let is_integer_valued = v == ((v as i64) as f64);
if is_integer_valued && v.abs() < 1e17 {
(v as i64).to_string().into_bytes()
} else {
format!("{v}").into_bytes()
}
}
#[inline]
pub(crate) fn apply_delta(v: &mut u64, delta: i64) {
if delta >= 0 {
*v = v.saturating_add(delta as u64);
} else {
*v = v.saturating_sub((-delta) as u64);
}
}
#[inline]
pub(crate) fn key_heap_bytes_for(key: &[u8]) -> u64 {
if key.len() <= 22 { 0 } else { key.len() as u64 }
}