use libc::c_char;
use std::ffi::CStr;
use std::sync::Mutex;
pub fn split_once<'a>(value: &'a str, deliminator: &str) -> (&'a str, Option<&'a str>) {
let mut splitter = value.splitn(2, deliminator);
(splitter.next().unwrap(), splitter.next())
}
pub unsafe fn parse_cstr(raw_ptr: *const c_char) -> Option<String> {
if raw_ptr.is_null() {
return None;
}
let raw_cstr: &CStr = CStr::from_ptr(raw_ptr);
raw_cstr.to_str().ok().map(str::to_string)
}
lazy_static! {
static ref PRINTED_WARNINGS: Mutex<Vec<String>> = Mutex::new(Vec::new());
}
pub fn warn_once(message: impl Into<String>) {
let message: String = message.into();
if let Ok(mut printed_warnings) = PRINTED_WARNINGS.lock() {
if !printed_warnings.contains(&message) {
eprintln!("{}", message);
printed_warnings.push(message);
}
} else {
eprintln!("Warning: internal lock poisoned.");
eprintln!("{}", message);
}
}
pub fn parse_number(string: &str) -> Option<f64> {
const ALLOWED_CHARS: &str = "0123456789-.";
match string {
"-" => Some(-1.0),
"" => Some(1.0),
_ => {
if string.chars().all(|c| ALLOWED_CHARS.contains(c)) {
string.parse().ok()
} else {
None
}
}
}
}
pub fn strip_prefix<'a>(string: &'a str, prefix: &str) -> Option<&'a str> {
if string.starts_with(prefix) {
Some(&string[prefix.len()..string.len()])
} else {
None
}
}
pub fn strip_suffix<'a>(string: &'a str, suffix: &str) -> Option<&'a str> {
if string.ends_with(suffix) {
Some(&string[0..string.len() - suffix.len()])
} else {
None
}
}
#[test]
fn unittest() {
assert_eq!(strip_prefix("foobar", "foo"), Some("bar"));
assert_eq!(strip_prefix("foofoobar", "foo"), Some("foobar"));
assert_eq!(strip_prefix("foobaz", "baz"), None);
assert_eq!(strip_suffix("foobar", "bar"), Some("foo"));
assert_eq!(strip_suffix("foobarbar", "bar"), Some("foobar"));
assert_eq!(strip_suffix("foobaz", "bar"), None);
}