use once_cell::sync::Lazy;
use std::{io::Read, sync::atomic::AtomicUsize};
use thiserror::Error;
pub mod config;
pub mod paths;
pub mod traits;
pub mod ui;
pub mod vec_ops;
mod vec_mut_accessor;
pub use vec_mut_accessor::VecMutAccessor;
mod atomic_flag;
pub use atomic_flag::AtomicFlag;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Side {
Left,
Right,
}
#[must_use]
pub fn strip_bom(bytes: &[u8]) -> &[u8] {
const BOM: [u8; 3] = [239, 187, 191];
if bytes[0..3] == BOM {
&bytes[3..]
} else {
bytes
}
}
#[must_use]
pub fn fold_lis<S: AsRef<str>>(items: &[S], indenting: usize) -> String {
let single_indent = " ";
let indent = single_indent.repeat(indenting);
items.iter().fold(String::new(), |mut acc, item| {
acc.push_str(&format!("{indent}<li>{}</li>\n", item.as_ref()));
acc
})
}
pub fn read_line(
reader: &mut impl Read,
buf: &mut [u8; 1],
) -> Result<Option<String>, ReadLineError> {
let mut line: Vec<u8> = Vec::new();
loop {
let n = reader.read(&mut buf[..])?;
if n == 0 || buf[0] == b'\n' {
break;
}
line.push(buf[0]);
}
if line.is_empty() {
Ok(None)
} else {
Ok(Some(String::from_utf8(line)?))
}
}
#[derive(Debug, Error)]
pub enum ReadLineError {
#[error("couldn't read file: {0}")]
IOError(#[from] std::io::Error),
#[error("invalid utf-8: {0}")]
FromUtf8Error(#[from] std::string::FromUtf8Error),
}
static ID_COUNTER: Lazy<AtomicUsize> = Lazy::new(|| AtomicUsize::new(0));
#[must_use]
pub fn fetch_inc_id() -> usize {
ID_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
}
#[must_use]
pub fn truncate(s: &String, width: f32) -> String {
const APPEND: &str = "...";
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
let max_chars: usize = (width / 7.0) as usize;
if s.len() > max_chars && max_chars > APPEND.len() {
let mut st: String = s.chars().take(max_chars - APPEND.len()).collect();
st.push_str(APPEND);
st
} else {
s.clone()
}
}