use std::borrow::Cow;
use std::convert::TryFrom;
use std::ffi::{CStr, CString};
use std::time::{Duration, Instant};
use crate::private::try_get_api;
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct Signature<'a> {
sig: Cow<'a, CStr>,
}
impl<'a> Signature<'a> {
#[inline(always)]
pub const fn from_raw(sig: &'a CStr) -> Self {
Signature {
sig: Cow::Borrowed(sig),
}
}
#[inline(always)]
pub unsafe fn from_bytes_with_nul_unchecked(bytes: &'a [u8]) -> Self {
let sig = CStr::from_bytes_with_nul_unchecked(bytes);
Self::from_raw(sig)
}
#[inline(always)]
pub fn borrow(&self) -> Signature<'_> {
Signature {
sig: Cow::Borrowed(&*self.sig),
}
}
#[inline]
pub fn add_data(&self, time: Duration) {
add_data(self.borrow(), time)
}
#[inline]
pub fn profile<F, R>(&self, f: F) -> R
where
F: FnOnce() -> R,
{
profile(self.borrow(), f)
}
fn as_ptr(&self) -> *const libc::c_char {
self.sig.as_ptr()
}
}
impl Signature<'static> {
#[inline]
pub fn new(file: &str, line: u32, tag: &str) -> Self {
if file.find("::").is_some() {
panic!("file name should not contain `::`");
}
if tag.find("::").is_some() {
panic!("tag should not contain `::`");
}
let sig = CString::new(format!("{}::{}::{}", file, line, tag))
.expect("file and tag should not contain NUL bytes");
Self::from_raw_owned(sig)
}
#[inline(always)]
pub const fn from_raw_owned(sig: CString) -> Self {
Signature {
sig: Cow::Owned(sig),
}
}
}
#[inline]
pub fn add_data(signature: Signature<'_>, time: Duration) {
if let Some(api) = try_get_api() {
let time_in_usec = u64::try_from(time.as_micros())
.expect("microseconds in `time` should not exceed the range of u64");
unsafe {
(api.godot_nativescript_profiling_add_data)(signature.as_ptr(), time_in_usec);
}
}
}
#[inline]
pub fn profile<F, R>(signature: Signature<'_>, f: F) -> R
where
F: FnOnce() -> R,
{
let start = Instant::now();
let ret = f();
add_data(signature, Instant::now() - start);
ret
}