#![doc = include_str!("../README.md")]
#![no_std]
#![deny(missing_docs)]
use core::cell::UnsafeCell;
use core::ops::Index;
use core::sync::atomic::{AtomicU8, Ordering};
use sancov_sys as sys;
#[repr(transparent)]
pub struct Counters<const N: usize>(UnsafeCell<[u8; N]>);
unsafe impl<const N: usize> Send for Counters<N> {}
unsafe impl<const N: usize> Sync for Counters<N> {}
impl<const N: usize> Counters<N> {
pub const fn new() -> Self {
let _n_cannot_be_zero = [()][(N == 0) as usize];
Counters(UnsafeCell::new([0; N]))
}
#[inline]
pub fn as_array(&self) -> &[Counter; N] {
unsafe {
let ptr: *mut [u8; N] = self.0.get();
let ptr: *const [u8; N] = ptr as _;
let ptr: *const [Counter; N] = ptr as _;
&*ptr
}
}
pub fn register(&'static self) {
unsafe {
let start = self.as_array().as_ptr() as *const u8;
let end = start.add(N) as *const u8;
sys::__sanitizer_cov_8bit_counters_init(start, end);
}
}
#[inline]
#[cfg(feature = "hash_increment")]
pub fn hash_increment<T>(&self, x: &T)
where
T: ?Sized + core::hash::Hash,
{
assert_ne!(N, 0);
let i = fxhash::hash(x) % N;
self[i].increment();
}
}
impl<const N: usize> Index<usize> for Counters<N> {
type Output = Counter;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
assert!(index < N);
&self.as_array()[index]
}
}
#[repr(transparent)]
pub struct Counter(AtomicU8);
impl Counter {
#[inline]
pub fn increment(&self) {
let count = self.0.load(Ordering::Relaxed);
let (count, overflowed) = count.overflowing_add(1);
self.0.store(count + (overflowed as u8), Ordering::Relaxed);
}
pub fn saturating_increment(&self) {
let count = self.0.load(Ordering::Relaxed);
self.0.store(count.saturating_add(1), Ordering::Relaxed);
}
}
#[cfg(test)]
#[no_mangle]
pub fn __sanitizer_cov_8bit_counters_init(_: *const u8, _: *const u8) {}