pub unsafe trait Sentinel: Sized {
const SENTINEL: Self = Self::SENTINEL;
type Unwrapped;
#[inline]
fn unwrap_sentinel(this: Self) -> Option<Self::Unwrapped> {
if Self::is_sentinel(&this) {
None
} else {
Some(unsafe { Self::unwrap_sentinel_unchecked(this) })
}
}
#[inline]
unsafe fn unwrap_sentinel_unchecked(this: Self) -> Self::Unwrapped {
unsafe { Self::unwrap_sentinel(this).unwrap_unchecked() }
}
fn is_sentinel(this: &Self) -> bool;
unsafe fn find_sentinel_infinite(start: *const Self) -> usize {
let mut index = 0;
while !Self::is_sentinel(unsafe { &*start.add(index) }) {
index = index.wrapping_add(1);
}
index
}
#[inline]
fn find_sentinel(slice: &[Self]) -> Option<usize> {
slice.iter().position(Self::is_sentinel)
}
}
unsafe impl Sentinel for u8 {
const SENTINEL: Self = 0u8;
type Unwrapped = core::num::NonZeroU8;
#[inline(always)]
fn unwrap_sentinel(this: Self) -> Option<Self::Unwrapped> {
core::num::NonZeroU8::new(this)
}
#[inline(always)]
unsafe fn unwrap_sentinel_unchecked(this: Self) -> Self::Unwrapped {
unsafe { core::num::NonZeroU8::new_unchecked(this) }
}
#[inline(always)]
fn is_sentinel(value: &u8) -> bool {
*value == 0
}
#[inline(always)]
#[cfg(all(feature = "memchr", not(feature = "libc")))]
fn find_sentinel(slice: &[u8]) -> Option<usize> {
memchr::memchr(0, slice)
}
#[inline(always)]
#[cfg(feature = "libc")]
fn find_sentinel(slice: &[u8]) -> Option<usize> {
let ret =
unsafe { libc::memchr(slice.as_ptr() as _, b'\0' as _, slice.len()) as *const u8 };
if ret.is_null() {
None
} else {
Some(unsafe { ret.offset_from(slice.as_ptr()) } as usize)
}
}
#[cfg(feature = "libc")]
#[inline(always)]
unsafe fn find_sentinel_infinite(slice: *const u8) -> usize {
unsafe { libc::strlen(slice as _) }
}
}
unsafe impl Sentinel for i8 {
const SENTINEL: Self = 0i8;
type Unwrapped = core::num::NonZeroI8;
#[inline(always)]
fn unwrap_sentinel(this: Self) -> Option<Self::Unwrapped> {
core::num::NonZeroI8::new(this)
}
#[inline(always)]
unsafe fn unwrap_sentinel_unchecked(this: Self) -> Self::Unwrapped {
unsafe { core::num::NonZeroI8::new_unchecked(this) }
}
#[inline(always)]
fn is_sentinel(value: &i8) -> bool {
*value == 0
}
#[inline(always)]
#[cfg(all(feature = "memchr", not(feature = "libc")))]
fn find_sentinel(slice: &[i8]) -> Option<usize> {
unsafe { memchr::memchr(0, &*(slice as *const [i8] as *const [u8])) }
}
#[inline(always)]
#[cfg(feature = "libc")]
fn find_sentinel(slice: &[i8]) -> Option<usize> {
let ret =
unsafe { libc::memchr(slice.as_ptr() as _, b'\0' as _, slice.len()) as *const i8 };
if ret.is_null() {
None
} else {
Some(unsafe { ret.offset_from(slice.as_ptr()) } as usize)
}
}
#[cfg(feature = "libc")]
#[inline(always)]
unsafe fn find_sentinel_infinite(slice: *const i8) -> usize {
unsafe { libc::strlen(slice as _) }
}
}
unsafe impl Sentinel for bool {
const SENTINEL: Self = false;
type Unwrapped = bool;
#[inline(always)]
fn unwrap_sentinel(this: Self) -> Option<Self::Unwrapped> {
Some(this)
}
#[inline(always)]
unsafe fn unwrap_sentinel_unchecked(this: Self) -> Self::Unwrapped {
this
}
#[inline(always)]
fn is_sentinel(value: &bool) -> bool {
!*value
}
#[inline(always)]
#[cfg(all(feature = "memchr", not(feature = "libc")))]
fn find_sentinel(slice: &[bool]) -> Option<usize> {
unsafe { memchr::memchr(0, &*(slice as *const [bool] as *const [u8])) }
}
#[inline(always)]
#[cfg(feature = "libc")]
fn find_sentinel(slice: &[bool]) -> Option<usize> {
let ret =
unsafe { libc::memchr(slice.as_ptr() as _, false as _, slice.len()) as *const bool };
if ret.is_null() {
None
} else {
Some(unsafe { ret.offset_from(slice.as_ptr()) } as usize)
}
}
#[cfg(feature = "libc")]
#[inline(always)]
unsafe fn find_sentinel_infinite(slice: *const bool) -> usize {
unsafe { libc::strlen(slice as _) }
}
}
macro_rules! impl_Sentinel_zero {
($($t:ty),* $(,)?) => {
$(
unsafe impl Sentinel for $t {
const SENTINEL: Self = 0;
type Unwrapped = $t;
#[inline(always)]
fn unwrap_sentinel(this: Self) -> Option<Self::Unwrapped> {
if this == 0 {
None
} else {
Some(this)
}
}
#[inline(always)]
unsafe fn unwrap_sentinel_unchecked(this: Self) -> Self::Unwrapped {
this
}
#[inline(always)]
fn is_sentinel(value: &$t) -> bool {
*value == 0
}
}
)*
};
}
impl_Sentinel_zero!(u16, i16, u32, i32, u64, i64, u128, i128, usize, isize,);
unsafe impl<T> Sentinel for *const T {
const SENTINEL: Self = core::ptr::null();
type Unwrapped = Self;
#[inline(always)]
fn unwrap_sentinel(this: Self) -> Option<Self::Unwrapped> {
if this.is_null() {
None
} else {
Some(this)
}
}
#[inline(always)]
unsafe fn unwrap_sentinel_unchecked(this: Self) -> Self::Unwrapped {
this
}
#[inline(always)]
fn is_sentinel(value: &*const T) -> bool {
value.is_null()
}
}
unsafe impl<T> Sentinel for *mut T {
const SENTINEL: Self = core::ptr::null_mut();
type Unwrapped = Self;
#[inline(always)]
fn unwrap_sentinel(this: Self) -> Option<Self::Unwrapped> {
if this.is_null() {
None
} else {
Some(this)
}
}
#[inline(always)]
unsafe fn unwrap_sentinel_unchecked(this: Self) -> Self::Unwrapped {
this
}
#[inline(always)]
fn is_sentinel(value: &*mut T) -> bool {
value.is_null()
}
}
unsafe impl<T> Sentinel for Option<T> {
const SENTINEL: Self = None;
type Unwrapped = T;
#[inline(always)]
fn unwrap_sentinel(this: Self) -> Option<Self::Unwrapped> {
this
}
#[inline(always)]
unsafe fn unwrap_sentinel_unchecked(this: Self) -> Self::Unwrapped {
unsafe { this.unwrap_unchecked() }
}
#[inline(always)]
fn is_sentinel(value: &Option<T>) -> bool {
value.is_none()
}
}