use std::ffi::{CStr, CString};
use std::marker::PhantomData;
pub fn start_trace<T: AsRef<CStr>>(name: &T) {
start_trace_cstr(name.as_ref())
}
#[cfg(all(target_env = "ohos", not(feature = "max_level_off")))]
fn start_trace_cstr(name: &CStr) {
unsafe {
hitrace_sys::OH_HiTrace_StartTrace(name.as_ptr());
}
}
#[cfg(any(not(target_env = "ohos"), feature = "max_level_off"))]
fn start_trace_cstr(_: &CStr) {}
pub fn finish_trace() {
#[cfg(all(target_env = "ohos", not(feature = "max_level_off")))]
fn finish_trace_() {
unsafe {
hitrace_sys::OH_HiTrace_FinishTrace();
}
}
#[cfg(any(not(target_env = "ohos"), feature = "max_level_off"))]
fn finish_trace_() {}
finish_trace_()
}
#[cfg(all(target_env = "ohos", not(feature = "max_level_off")))]
fn trace_metric_cstr(name: &CStr, count: i64) {
unsafe {
hitrace_sys::OH_HiTrace_CountTrace(name.as_ptr(), count);
}
}
#[cfg(any(not(target_env = "ohos"), feature = "max_level_off"))]
fn trace_metric_cstr(_: &CStr, _: i64) {}
fn trace_metric<T: AsRef<CStr>, C: Into<i64>>(name: &T, count: C) {
trace_metric_cstr(name.as_ref(), count.into());
}
pub fn trace_metric_str<C: Into<i64>>(name: &str, count: C) {
let c_string = CString::new(name).expect("Failed to convert to CString");
trace_metric(&c_string, count.into());
}
pub fn trace_metric_saturating<T: AsRef<CStr>>(name: &T, count: impl SaturatingIntoI64) {
trace_metric_cstr(name.as_ref(), count.saturating_into());
}
pub fn trace_metric_saturating_str(name: &str, count: impl SaturatingIntoI64) {
let c_string = CString::new(name).expect("Failed to convert to CString");
trace_metric_saturating(&c_string, count);
}
pub trait SaturatingIntoI64 {
fn saturating_into(self) -> i64;
}
impl SaturatingIntoI64 for u64 {
fn saturating_into(self) -> i64 {
self.min(i64::MAX as u64) as i64
}
}
impl SaturatingIntoI64 for i128 {
fn saturating_into(self) -> i64 {
if self > i64::MAX as i128 {
i64::MAX
} else if self < i64::MIN as i128 {
i64::MIN
} else {
self as i64
}
}
}
impl SaturatingIntoI64 for u128 {
fn saturating_into(self) -> i64 {
self.min(i64::MAX as u128) as i64
}
}
impl SaturatingIntoI64 for usize {
fn saturating_into(self) -> i64 {
self.min(i64::MAX as usize) as i64
}
}
impl SaturatingIntoI64 for isize {
fn saturating_into(self) -> i64 {
if self > i64::MAX as isize {
i64::MAX
} else if self < i64::MIN as isize {
i64::MIN
} else {
self as i64
}
}
}
pub struct ScopedTrace {
phantom_data: PhantomData<*mut u8>,
}
impl ScopedTrace {
#[must_use]
pub fn start_trace<T: AsRef<CStr>>(name: &T) -> Self {
start_trace(name);
Self {
phantom_data: PhantomData,
}
}
#[must_use]
pub fn start_trace_str(name: &str) -> Self {
Self::start_trace(&CString::new(name).expect("Contained null-byte"))
}
#[doc(hidden)]
pub unsafe fn _start_trace_str_with_null(name_with_null: &str) -> Self {
#[cfg(any(not(target_env = "ohos"), feature = "max_level_off"))]
let _ = name_with_null;
#[cfg(all(target_env = "ohos", not(feature = "max_level_off")))]
unsafe {
hitrace_sys::OH_HiTrace_StartTrace(name_with_null.as_ptr());
}
Self {
phantom_data: PhantomData,
}
}
}
impl Drop for ScopedTrace {
fn drop(&mut self) {
finish_trace()
}
}
#[cfg(test)]
mod test {
use static_assertions::assert_not_impl_any;
use crate::ScopedTrace;
assert_not_impl_any!(ScopedTrace: Send, Sync);
}