use anyhow::{Context, Result};
use regex::Regex;
use sha2::{Digest, Sha256};
use std::time::{SystemTime, UNIX_EPOCH};
#[inline]
pub fn current_timestamp() -> u64 {
current_timestamp_result().unwrap_or(0)
}
#[inline]
pub fn current_timestamp_result() -> Result<u64> {
Ok(SystemTime::now()
.duration_since(UNIX_EPOCH)
.context("System clock is before UNIX_EPOCH while generating timestamp")?
.as_secs())
}
pub fn calculate_sha256(content: &[u8]) -> String {
let mut hasher = Sha256::new();
hasher.update(content);
let digest = hasher.finalize();
let mut output = String::with_capacity(digest.len() * 2);
for byte in digest {
output.push(nibble_to_hex(byte >> 4));
output.push(nibble_to_hex(byte & 0x0f));
}
output
}
fn nibble_to_hex(nibble: u8) -> char {
match nibble {
0..=9 => char::from(b'0' + nibble),
10..=15 => char::from(b'a' + (nibble - 10)),
_ => unreachable!("nibble must be in 0..=15"),
}
}
pub fn extract_toml_str(content: &str, key: &str) -> Option<String> {
let pkg_section = if let Some(start) = content.find("[package]") {
let rest = &content[start + "[package]".len()..];
if let Some(_next) = rest.find('\n') {
&content[start..]
} else {
&content[start..]
}
} else {
content
};
let pattern = format!(r#"(?m)^\s*{}\s*=\s*"([^"]+)"\s*$"#, regex::escape(key));
let re = Regex::new(&pattern).ok()?;
re.captures(pkg_section)
.and_then(|caps| caps.get(1).map(|m| m.as_str().to_owned()))
}
pub fn extract_readme_excerpt(md: &str, max_len: usize) -> String {
let mut excerpt = String::new();
for line in md.lines() {
if excerpt.len() > max_len {
break;
}
excerpt.push_str(line);
excerpt.push('\n');
if line.trim().starts_with("## ") && excerpt.len() > (max_len / 2) {
break;
}
}
if excerpt.len() > max_len {
excerpt.truncate(max_len);
excerpt.push_str("...\n");
}
excerpt
}
pub fn safe_replace_text(content: &str, old_str: &str, new_str: &str) -> Result<String> {
if old_str.is_empty() {
return Err(anyhow::anyhow!("old_string cannot be empty"));
}
if !content.contains(old_str) {
return Err(anyhow::anyhow!("Text '{}' not found in content", old_str));
}
Ok(content.replace(old_str, new_str))
}