1pub unsafe trait Sentinel: Sized {
20 const SENTINEL: Self = Self::SENTINEL;
22
23 type Unwrapped;
26
27 #[inline]
31 fn unwrap_sentinel(this: Self) -> Option<Self::Unwrapped> {
32 if Self::is_sentinel(&this) {
33 None
34 } else {
35 Some(unsafe { Self::unwrap_sentinel_unchecked(this) })
38 }
39 }
40
41 #[inline]
47 unsafe fn unwrap_sentinel_unchecked(this: Self) -> Self::Unwrapped {
48 unsafe { Self::unwrap_sentinel(this).unwrap_unchecked() }
49 }
50
51 fn is_sentinel(this: &Self) -> bool;
53
54 unsafe fn find_sentinel_infinite(start: *const Self) -> usize {
61 let mut index = 0;
62 while !Self::is_sentinel(unsafe { &*start.add(index) }) {
63 index = index.wrapping_add(1);
64 }
65 index
66 }
67
68 #[inline]
72 fn find_sentinel(slice: &[Self]) -> Option<usize> {
73 slice.iter().position(Self::is_sentinel)
74 }
75}
76
77unsafe impl Sentinel for u8 {
78 const SENTINEL: Self = 0u8;
79
80 type Unwrapped = core::num::NonZeroU8;
81
82 #[inline(always)]
83 fn unwrap_sentinel(this: Self) -> Option<Self::Unwrapped> {
84 core::num::NonZeroU8::new(this)
85 }
86
87 #[inline(always)]
88 unsafe fn unwrap_sentinel_unchecked(this: Self) -> Self::Unwrapped {
89 unsafe { core::num::NonZeroU8::new_unchecked(this) }
90 }
91
92 #[inline(always)]
93 fn is_sentinel(value: &u8) -> bool {
94 *value == 0
95 }
96
97 #[inline(always)]
98 #[cfg(all(feature = "memchr", not(feature = "libc")))]
99 fn find_sentinel(slice: &[u8]) -> Option<usize> {
100 memchr::memchr(0, slice)
101 }
102
103 #[inline(always)]
104 #[cfg(feature = "libc")]
105 fn find_sentinel(slice: &[u8]) -> Option<usize> {
106 let ret =
107 unsafe { libc::memchr(slice.as_ptr() as _, b'\0' as _, slice.len()) as *const u8 };
108 if ret.is_null() {
109 None
110 } else {
111 Some(unsafe { ret.offset_from(slice.as_ptr()) } as usize)
112 }
113 }
114
115 #[cfg(feature = "libc")]
116 #[inline(always)]
117 unsafe fn find_sentinel_infinite(slice: *const u8) -> usize {
118 unsafe { libc::strlen(slice as _) }
119 }
120}
121
122unsafe impl Sentinel for i8 {
123 const SENTINEL: Self = 0i8;
124
125 type Unwrapped = core::num::NonZeroI8;
126
127 #[inline(always)]
128 fn unwrap_sentinel(this: Self) -> Option<Self::Unwrapped> {
129 core::num::NonZeroI8::new(this)
130 }
131
132 #[inline(always)]
133 unsafe fn unwrap_sentinel_unchecked(this: Self) -> Self::Unwrapped {
134 unsafe { core::num::NonZeroI8::new_unchecked(this) }
135 }
136
137 #[inline(always)]
138 fn is_sentinel(value: &i8) -> bool {
139 *value == 0
140 }
141
142 #[inline(always)]
143 #[cfg(all(feature = "memchr", not(feature = "libc")))]
144 fn find_sentinel(slice: &[i8]) -> Option<usize> {
145 unsafe { memchr::memchr(0, &*(slice as *const [i8] as *const [u8])) }
146 }
147
148 #[inline(always)]
149 #[cfg(feature = "libc")]
150 fn find_sentinel(slice: &[i8]) -> Option<usize> {
151 let ret =
152 unsafe { libc::memchr(slice.as_ptr() as _, b'\0' as _, slice.len()) as *const i8 };
153 if ret.is_null() {
154 None
155 } else {
156 Some(unsafe { ret.offset_from(slice.as_ptr()) } as usize)
157 }
158 }
159
160 #[cfg(feature = "libc")]
161 #[inline(always)]
162 unsafe fn find_sentinel_infinite(slice: *const i8) -> usize {
163 unsafe { libc::strlen(slice as _) }
164 }
165}
166
167unsafe impl Sentinel for bool {
168 const SENTINEL: Self = false;
169
170 type Unwrapped = bool;
171
172 #[inline(always)]
173 fn unwrap_sentinel(this: Self) -> Option<Self::Unwrapped> {
174 Some(this)
175 }
176
177 #[inline(always)]
178 unsafe fn unwrap_sentinel_unchecked(this: Self) -> Self::Unwrapped {
179 this
180 }
181
182 #[inline(always)]
183 fn is_sentinel(value: &bool) -> bool {
184 !*value
185 }
186
187 #[inline(always)]
188 #[cfg(all(feature = "memchr", not(feature = "libc")))]
189 fn find_sentinel(slice: &[bool]) -> Option<usize> {
190 unsafe { memchr::memchr(0, &*(slice as *const [bool] as *const [u8])) }
191 }
192
193 #[inline(always)]
194 #[cfg(feature = "libc")]
195 fn find_sentinel(slice: &[bool]) -> Option<usize> {
196 let ret =
197 unsafe { libc::memchr(slice.as_ptr() as _, false as _, slice.len()) as *const bool };
198 if ret.is_null() {
199 None
200 } else {
201 Some(unsafe { ret.offset_from(slice.as_ptr()) } as usize)
202 }
203 }
204
205 #[cfg(feature = "libc")]
206 #[inline(always)]
207 unsafe fn find_sentinel_infinite(slice: *const bool) -> usize {
208 unsafe { libc::strlen(slice as _) }
209 }
210}
211
212macro_rules! impl_Sentinel_zero {
213 ($($t:ty),* $(,)?) => {
214 $(
215 unsafe impl Sentinel for $t {
216 const SENTINEL: Self = 0;
217
218 type Unwrapped = $t;
219
220 #[inline(always)]
221 fn unwrap_sentinel(this: Self) -> Option<Self::Unwrapped> {
222 if this == 0 {
223 None
224 } else {
225 Some(this)
226 }
227 }
228
229 #[inline(always)]
230 unsafe fn unwrap_sentinel_unchecked(this: Self) -> Self::Unwrapped {
231 this
232 }
233
234 #[inline(always)]
235 fn is_sentinel(value: &$t) -> bool {
236 *value == 0
237 }
238 }
239 )*
240 };
241}
242
243impl_Sentinel_zero!(u16, i16, u32, i32, u64, i64, u128, i128, usize, isize,);
244
245unsafe impl<T> Sentinel for *const T {
246 const SENTINEL: Self = core::ptr::null();
247
248 type Unwrapped = Self;
249
250 #[inline(always)]
251 fn unwrap_sentinel(this: Self) -> Option<Self::Unwrapped> {
252 if this.is_null() {
253 None
254 } else {
255 Some(this)
256 }
257 }
258
259 #[inline(always)]
260 unsafe fn unwrap_sentinel_unchecked(this: Self) -> Self::Unwrapped {
261 this
262 }
263
264 #[inline(always)]
265 fn is_sentinel(value: &*const T) -> bool {
266 value.is_null()
267 }
268}
269
270unsafe impl<T> Sentinel for *mut T {
271 const SENTINEL: Self = core::ptr::null_mut();
272
273 type Unwrapped = Self;
274
275 #[inline(always)]
276 fn unwrap_sentinel(this: Self) -> Option<Self::Unwrapped> {
277 if this.is_null() {
278 None
279 } else {
280 Some(this)
281 }
282 }
283
284 #[inline(always)]
285 unsafe fn unwrap_sentinel_unchecked(this: Self) -> Self::Unwrapped {
286 this
287 }
288
289 #[inline(always)]
290 fn is_sentinel(value: &*mut T) -> bool {
291 value.is_null()
292 }
293}
294
295unsafe impl<T> Sentinel for Option<T> {
296 const SENTINEL: Self = None;
297
298 type Unwrapped = T;
299
300 #[inline(always)]
301 fn unwrap_sentinel(this: Self) -> Option<Self::Unwrapped> {
302 this
303 }
304
305 #[inline(always)]
306 unsafe fn unwrap_sentinel_unchecked(this: Self) -> Self::Unwrapped {
307 unsafe { this.unwrap_unchecked() }
308 }
309
310 #[inline(always)]
311 fn is_sentinel(value: &Option<T>) -> bool {
312 value.is_none()
313 }
314}