pub fn utf16_length(text: &str) -> usize {
return text.chars().map(char::len_utf16).sum();
}
pub fn utf16_prefix(text: &str, limit: usize) -> String {
let mut kept: String = String::new();
let mut used: usize = 0;
for character in text.chars() {
let width: usize = character.len_utf16();
if used + width > limit {
break;
}
kept.push(character);
used += width;
}
return kept;
}
pub fn js_number_text(value: f64) -> String {
if value == 0.0 {
return String::from("0");
}
let sign: &str = if value < 0.0 { "-" } else { "" };
let scientific: String = format!("{:e}", value.abs());
let (mantissa, exponent_text) = scientific.split_once('e').unwrap_or((scientific.as_str(), "0"));
let digits: String = mantissa.replace('.', "");
let exponent: i32 = exponent_text.parse::<i32>().unwrap_or(0);
let count: i32 = i32::try_from(digits.len()).unwrap_or(i32::MAX);
let point: i32 = exponent + 1;
let body: String = if count <= point && point <= 21 {
format!("{digits}{}", "0".repeat(usize::try_from(point - count).unwrap_or(0)))
} else if 0 < point && point <= 21 {
let split: usize = usize::try_from(point).unwrap_or(0);
format!("{}.{}", &digits[..split], &digits[split..])
} else if -6 < point && point <= 0 {
format!("0.{}{digits}", "0".repeat(usize::try_from(-point).unwrap_or(0)))
} else {
let power: i32 = point - 1;
let power_sign: &str = if power < 0 { "-" } else { "+" };
let lead: &str = &digits[..1];
let rest: &str = &digits[1..];
if rest.is_empty() {
format!("{lead}e{power_sign}{}", power.abs())
} else {
format!("{lead}.{rest}e{power_sign}{}", power.abs())
}
};
return format!("{sign}{body}");
}
pub fn seconds_with_tenth(milliseconds: u64) -> String {
const TIE_PERIOD_MS: u64 = 500;
const TIE_REMAINDER_MS: u64 = 250;
const TENTH_MS: u64 = 100;
if milliseconds % TIE_PERIOD_MS == TIE_REMAINDER_MS {
let tenths: u64 = milliseconds / TENTH_MS + 1;
return format!("{}.{}", tenths / 10, tenths % 10);
}
let seconds: f64 = milliseconds as f64 / 1000.0;
return format!("{seconds:.1}");
}
pub fn commit_subject(message: &str) -> String {
let mut paragraph: Vec<&str> = Vec::new();
for line in message.split('\n') {
let trimmed: &str = line.trim_end();
if trimmed.trim_start().is_empty() {
if paragraph.is_empty() {
continue;
}
break;
}
paragraph.push(trimmed);
}
return paragraph.join(" ").trim().to_string();
}
pub fn on_one_line(text: &str) -> String {
let mut line: String = String::with_capacity(text.len());
for character in text.chars() {
match character {
'\n' => line.push_str("\\n"),
'\r' => line.push_str("\\r"),
'\t' => line.push_str("\\t"),
other if other.is_control() || other == '\u{2028}' || other == '\u{2029}' => {
line.push_str(&format!("\\u{{{:x}}}", u32::from(other)));
}
other => line.push(other),
}
}
return line;
}
#[cfg(test)]
#[path = "standards_review_text_tests.rs"]
mod tests;