use std::fmt;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Clone)]
pub struct Error(pub String);
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}
impl std::error::Error for Error {}
impl From<std::io::Error> for Error {
fn from(e: std::io::Error) -> Self {
Error(e.to_string())
}
}
impl From<serde_json::Error> for Error {
fn from(e: serde_json::Error) -> Self {
Error(format!("json: {e}"))
}
}
impl From<toml::de::Error> for Error {
fn from(e: toml::de::Error) -> Self {
Error(format!("toml: {e}"))
}
}
pub fn err<T>(msg: impl Into<String>) -> Result<T> {
Err(Error(msg.into()))
}
pub fn now_iso() -> String {
time::OffsetDateTime::now_utc()
.format(&time::format_description::well_known::Rfc3339)
.unwrap_or_default()
}
pub fn now_ms() -> u128 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_millis())
.unwrap_or(0)
}
pub fn sha256_hex(bytes: &[u8]) -> String {
rightkit_fs::digest::sha256_bytes(bytes)
}
pub fn new_id() -> String {
uuid::Uuid::new_v4().to_string()
}
pub fn sleep_ms(ms: u64) {
std::thread::sleep(Duration::from_millis(ms));
}
pub fn tail(s: &str, max: usize) -> String {
if s.len() <= max {
return s.to_string();
}
let mut start = s.len() - max;
while !s.is_char_boundary(start) {
start += 1;
}
s[start..].to_string()
}
pub fn require_text(value: &str, name: &str) -> Result<String> {
let v = value.trim();
if v.is_empty() {
return err(format!("{name} is required"));
}
Ok(v.to_string())
}
pub fn platform() -> Result<&'static str> {
if cfg!(target_os = "macos") {
Ok("darwin")
} else if cfg!(target_os = "windows") {
Ok("windows")
} else {
err(format!(
"rightkit-qa supports macOS and Windows, received {}",
std::env::consts::OS
))
}
}