#[cfg(any(feature = "statistics", feature = "token-tools"))]
use serde::Serialize;
#[cfg(any(feature = "statistics", feature = "token-tools"))]
const CHARS_PER_TOKEN: usize = 4;
#[cfg(any(feature = "statistics", feature = "token-tools"))]
#[derive(Serialize)]
pub struct TokenStats {
#[serde(rename = "hedlBytes")]
pub(crate) hedl_bytes: usize,
#[serde(rename = "hedlTokens")]
pub(crate) hedl_tokens: usize,
#[serde(rename = "hedlLines")]
pub(crate) hedl_lines: usize,
#[serde(rename = "jsonBytes")]
pub(crate) json_bytes: usize,
#[serde(rename = "jsonTokens")]
pub(crate) json_tokens: usize,
#[serde(rename = "savingsPercent")]
pub(crate) savings_percent: i32,
#[serde(rename = "tokensSaved")]
pub(crate) tokens_saved: i32,
}
#[cfg(any(feature = "statistics", feature = "token-tools"))]
#[inline]
pub(crate) fn estimate_tokens(text: &str) -> usize {
let bytes = text.as_bytes();
let byte_count = bytes.len();
if byte_count == 0 {
return 0;
}
let mut whitespace_count = 0usize;
let mut punct_count = 0usize;
let mut i = 0;
while i < byte_count {
let b = bytes[i];
if b < 128 {
whitespace_count += usize::from(matches!(b, b' ' | b'\t' | b'\n' | b'\r'));
punct_count += usize::from(matches!(
b,
b'!' | b'"'
| b'#'
| b'$'
| b'%'
| b'&'
| b'\''
| b'('
| b')'
| b'*'
| b'+'
| b','
| b'-'
| b'.'
| b'/'
| b':'
| b';'
| b'<'
| b'='
| b'>'
| b'?'
| b'@'
| b'['
| b'\\'
| b']'
| b'^'
| b'_'
| b'`'
| b'{'
| b'|'
| b'}'
| b'~'
));
i += 1;
} else {
let char_len = if b < 0b1110_0000 {
2
} else if b < 0b1111_0000 {
3
} else {
4
};
i += char_len;
}
}
(byte_count + whitespace_count + punct_count) / CHARS_PER_TOKEN
}