1#![cfg_attr(rustfmt, rustfmt::skip)]
2use_prelude!();
7use ::core::slice;
8
9ReprC! {
10 #[repr(transparent)]
11 #[derive(Clone, Copy)]
12 pub
18 struct char_p_ref['lt,] (
19 ptr::NonNullRef<c_char>,
20 PhantomCovariantLifetime<'lt>,
21 );
22}
23
24const NUL: u8 = b'\0';
25
26impl char_p_ref<'static> {
27 pub
28 const EMPTY: Self = unsafe {
29 Self::from_ptr_unchecked(ptr::NonNull::new_unchecked({
30 const IT: &u8 = &NUL;
31 IT as *const u8 as *mut u8
32 }))
33 };
34}
35
36impl<'lt> char_p_ref<'lt> {
37 pub
38 const
39 unsafe
40 fn from_ptr_unchecked (ptr: ptr::NonNull<u8>)
41 -> Self
42 {
43 Self(
44 ptr::NonNullRef(ptr.cast()),
45 PhantomCovariantLifetime::<'static>(PhantomData),
46 )
47 }
48}
49
50impl fmt::Debug
51 for char_p_ref<'_>
52{
53 fn fmt (self: &'_ Self, fmt: &'_ mut fmt::Formatter<'_>)
54 -> fmt::Result
55 {
56 fmt::Debug::fmt(self.to_str(), fmt)
57 }
58}
59
60impl fmt::Display
61 for char_p_ref<'_>
62{
63 fn fmt (self: &'_ Self, fmt: &'_ mut fmt::Formatter<'_>)
64 -> fmt::Result
65 {
66 fmt::Display::fmt(self.to_str(), fmt)
67 }
68}
69
70unsafe impl Send for char_p_ref<'_>
72where
73 for<'lt> &'lt [u8] : Send,
74{}
75
76unsafe impl Sync for char_p_ref<'_>
78where
79 for<'lt> &'lt [u8] : Sync,
80{}
81
82unsafe impl Send for char_p_raw
84{}
85
86unsafe impl Sync for char_p_raw
88{}
89
90#[derive(Debug)]
91pub
92struct InvalidNulTerminator<Payload> (
93 pub Payload,
94);
95
96impl<T> fmt::Display
97 for InvalidNulTerminator<T>
98{
99 fn fmt (self: &'_ Self, fmt: &'_ mut fmt::Formatter<'_>)
100 -> fmt::Result
101 {
102 fmt::Display::fmt(
103 "Null byte not at the expected terminating position",
104 fmt,
105 )
106 }
107}
108
109impl<'lt> TryFrom<&'lt str>
110 for char_p_ref<'lt>
111{
112 type Error = InvalidNulTerminator<()>;
113
114 fn try_from (s: &'lt str)
115 -> Result<
116 char_p_ref<'lt>,
117 InvalidNulTerminator<()>,
118 >
119 {
120 Ok(if let Some(len_minus_one) = s.len().checked_sub(1) {
121 unsafe {
122 if s.bytes().position(|b| b == NUL) != Some(len_minus_one) {
123 return Err(InvalidNulTerminator(()));
124 }
125 Self::from_ptr_unchecked(
126 ptr::NonNull::new(s.as_ptr() as _).unwrap()
127 )
128 }
129 } else {
130 char_p_ref::EMPTY
131 })
132 }
133}
134
135cfg_std! {
136 impl<T : fmt::Debug> ::std::error::Error
137 for InvalidNulTerminator<T>
138 {}
139
140 impl<'lt> From<&'lt ::std::ffi::CStr>
144 for char_p_ref<'lt>
145 {
146 #[inline]
147 fn from (s: &'lt ::std::ffi::CStr)
148 -> char_p_ref<'lt>
149 {
150 unsafe {
151 let _assert_valid_utf8 =
152 ::core::str::from_utf8(s.to_bytes())
153 .unwrap()
154 ;
155 Self::from_ptr_unchecked(
156 ptr::NonNull::new(s.as_ptr() as _)
157 .unwrap()
158 )
159 }
160 }
161 }
162}
163
164impl<'lt> char_p_ref<'lt> {
165 #[inline]
166 pub
167 fn bytes (self: char_p_ref<'lt>)
168 -> impl Iterator<Item = ::core::num::NonZeroU8> + 'lt
169 {
170 ::core::iter::from_fn({
171 let mut ptr = self.0.as_ptr().cast::<u8>();
172 move || {
173 let ret = ::core::num::NonZeroU8::new(unsafe { ptr.read() });
174 if ret.is_some() {
175 unsafe {
176 ptr = ptr.add(1);
177 }
178 }
179 ret
180 }
181 })
182 }
183
184 #[inline]
185 pub
186 fn to_nonzero_bytes (self: char_p_ref<'lt>)
187 -> &'lt [::core::num::NonZeroU8]
188 {
189 unsafe {
190 slice::from_raw_parts(
191 self.0.as_ptr().cast(),
192 self.bytes().count(),
193 )
194 }
195 }
196
197 #[inline]
198 pub
199 fn to_bytes (self: char_p_ref<'lt>)
200 -> &'lt [u8]
201 {
202 unsafe {
203 slice::from_raw_parts(
204 self.0.as_ptr().cast(),
205 self.bytes().count(),
206 )
207 }
208 }
209
210 #[inline]
211 pub
212 fn to_bytes_with_null (self: char_p_ref<'lt>)
213 -> &'lt [u8]
214 {
215 unsafe {
216 slice::from_raw_parts(
217 self.0.as_ptr().cast(),
218 self.bytes().count() + 1,
219 )
220 }
221 }
222
223 #[inline]
224 pub
225 fn to_str (self: char_p_ref<'lt>)
226 -> &'lt str
227 {
228 unsafe {
229 ::core::str::from_utf8_unchecked(self.to_bytes())
230 }
231 }
232
233 #[inline]
234 pub
235 fn to_str_with_null (self: char_p_ref<'lt>)
236 -> &'lt str
237 {
238 unsafe {
239 ::core::str::from_utf8_unchecked(self.to_bytes_with_null())
240 }
241 }
242
243 cfg_alloc! {
244 #[inline]
245 pub
247 fn to_string(&self)
248 -> rust::String
249 {
250 self.to_str().to_owned()
251 }
252
253 #[inline]
254 pub
255 fn to_owned (self: char_p_ref<'lt>)
256 -> char_p_boxed
257 {
258 char_p::new(self.to_str())
259 }
260 }
261}
262
263impl<'lt> Eq for char_p_ref<'lt> {}
264impl<'lt> PartialEq for char_p_ref<'lt> {
265 #[inline]
266 fn eq (self: &'_ Self, other: &'_ Self)
267 -> bool
268 {
269 *self.to_str() == *other.to_str()
270 }
271}
272
273ReprC! {
274 #[repr(transparent)]
275 #[allow(missing_copy_implementations)]
276 pub
282 struct char_p_raw (
283 ptr::NonNullRef<c_char>,
284 );
285}
286
287#[deny(unsafe_op_in_unsafe_fn)]
288impl char_p_raw {
289 pub
295 unsafe
296 fn as_ref<'borrow> (self: &'borrow Self)
297 -> char_p_ref<'borrow>
298 {
299 unsafe {
300 ::core::mem::transmute(self.0)
306 }
307 }
308}
309
310impl<'lt> From<char_p_ref<'lt>>
311 for char_p_raw
312{
313 #[inline]
314 fn from (it: char_p_ref<'lt>)
315 -> char_p_raw
316 {
317 unsafe {
318 mem::transmute(it)
319 }
320 }
321}
322
323impl fmt::Debug
324 for char_p_raw
325{
326 fn fmt (self: &'_ Self, fmt: &'_ mut fmt::Formatter<'_>)
327 -> fmt::Result
328 {
329 fmt .debug_tuple("char_p_raw")
330 .field(&self.0)
331 .finish()
332 }
333}
334
335cfg_alloc! {
336 #[inline]
344 pub
345 fn new<Str> (s: Str)
346 -> char_p_boxed
347 where
348 char_p_boxed : hidden::__<Str>,
349 {
350 MyFrom::my_from(s)
351 }
352
353 ReprC! {
354 #[repr(transparent)]
355 pub
361 struct char_p_boxed (
362 ptr::NonNullOwned<c_char>,
363 );
364 }
365
366 unsafe impl Send
368 for char_p_boxed
369 where
370 rust::Box<[u8]> : Send,
371 {}
372
373 unsafe impl Sync
375 for char_p_boxed
376 where
377 rust::Box<[u8]> : Sync,
378 {}
379
380 impl fmt::Debug
381 for char_p_boxed
382 {
383 fn fmt (self: &'_ Self, fmt: &'_ mut fmt::Formatter<'_>)
384 -> fmt::Result
385 {
386 fmt::Debug::fmt(&self.as_ref(), fmt)
387 }
388 }
389 impl fmt::Display
390 for char_p_boxed
391 {
392 fn fmt (self: &'_ Self, fmt: &'_ mut fmt::Formatter<'_>)
393 -> fmt::Result
394 {
395 fmt::Display::fmt(&self.as_ref(), fmt)
396 }
397 }
398
399 impl char_p_boxed {
400 #[inline]
401 pub
402 const
403 unsafe
404 fn from_ptr_unchecked (ptr: ptr::NonNull<u8>)
405 -> char_p_boxed
406 {
407 Self(
408 ptr::NonNullOwned(ptr.cast(), PhantomData),
409 )
410 }
411
412 #[inline]
413 pub
414 fn as_ref (self: &'_ char_p_boxed)
415 -> char_p_ref<'_>
416 {
417 unsafe {
418 mem::transmute(self.0.as_ref())
419 }
420 }
421 }
422
423 use hidden::__ as MyFrom; mod hidden {
424 pub
425 trait __<Orig> { fn my_from (it: Orig) -> Self; }
426 }
427 macro_rules! derive_MyFrom_from {(
428 $(
429 $(@for[$($generics:tt)*])?
430 $T:ty => $Intermediate:ty
431 ),* $(,)?
432 ) => ($(
433 impl$(<$($generics)*>)? MyFrom<$T>
434 for char_p_boxed
435 {
436 #[inline]
437 fn my_from (it: $T)
438 -> char_p_boxed
439 {
440 <Self as TryFrom<$Intermediate>>::try_from(it.into())
443 .unwrap_or_else(|s| panic!(concat!(
444 "Error, the string `{:?}` contains an inner nul byte",
445 " and can thus not be converted to a C string without ",
446 "truncating it.",
447 ), s))
448 }
449 }
450 )*)}
451 derive_MyFrom_from! {
452 @for['lt] &'lt str => rust::String,
453 @for['lt] str::Ref<'lt> => rust::String,
454 rust::String => rust::String,
455 repr_c::String => rust::String,
456 }
457 cfg_std! {
458 derive_MyFrom_from! {
459 @for['lt] &'lt ::std::ffi::CStr => ::std::ffi::CString,
460 ::std::ffi::CString => ::std::ffi::CString,
461 }
462 }
463
464 static EMPTY_SENTINEL: u8 = NUL;
469
470 impl TryFrom<rust::String> for char_p_boxed {
471 type Error = InvalidNulTerminator<rust::String>;
472
473 fn try_from (s: rust::String)
474 -> Result<
475 char_p_boxed,
476 InvalidNulTerminator<rust::String>,
477 >
478 {
479 Ok(if let ("" | "\0") = &*s {
480 unsafe {
481 Self::from_ptr_unchecked(ptr::NonNull::new_unchecked(
482 (&EMPTY_SENTINEL) as *const _ as *mut _
483 ))
484 }
485 } else {
486 let len_minus_one = s.len() - 1;
487 if s.as_bytes()[.. len_minus_one].contains(&NUL) {
488 return Err(InvalidNulTerminator(s));
489 }
490 let mut s = s;
491 if s.as_bytes()[len_minus_one] != NUL {
492 s.reserve_exact(1);
493 s.push(NUL as _);
494 }
495 let s: rust::Box<[u8]> = s.into_boxed_str().into();
496 unsafe {
497 Self::from_ptr_unchecked(
498 ptr::NonNull::new(rust::Box::into_raw(s) as *mut u8)
499 .unwrap()
500 )
501 }
502 })
503 }
504 }
505
506 impl Drop for char_p_boxed {
507 fn drop (self: &'_ mut char_p_boxed)
508 {
509 unsafe {
510 if ptr::eq(self.0.as_mut_ptr().cast(), &EMPTY_SENTINEL) {
511 return;
512 }
513 let num_bytes = self.to_bytes_with_null().len();
514 drop::<rust::Box<[u8]>>(
515 rust::Box::from_raw(slice::from_raw_parts_mut(
516 self.0.as_mut_ptr().cast(),
517 num_bytes,
518 ))
519 );
520 }
521 }
522 }
523
524 impl char_p_boxed {
525 #[inline]
526 pub
527 fn bytes<'lt> (self: &'lt char_p_boxed)
528 -> impl Iterator<Item = ::core::num::NonZeroU8> + 'lt
529 {
530 self.as_ref().bytes()
531 }
532
533 #[inline]
534 pub
535 fn to_nonzero_bytes (self: &'_ char_p_boxed)
536 -> &'_ [::core::num::NonZeroU8]
537 {
538 self.as_ref().to_nonzero_bytes()
539 }
540
541 #[inline]
542 pub
543 fn to_bytes (self: &'_ char_p_boxed)
544 -> &'_ [u8]
545 {
546 self.as_ref().to_bytes()
547 }
548
549 #[inline]
550 pub
551 fn to_bytes_with_null (self: &'_ char_p_boxed)
552 -> &'_ [u8]
553 {
554 self.as_ref().to_bytes_with_null()
555 }
556
557 #[inline]
558 pub
559 fn to_str (self: &'_ char_p_boxed)
560 -> &'_ str
561 {
562 self.as_ref().to_str()
563 }
564
565 #[inline]
566 pub
567 fn to_str_with_null (self: &'_ char_p_boxed)
568 -> &'_ str
569 {
570 self.as_ref().to_str_with_null()
571 }
572
573 pub
574 fn into_vec (mut self: char_p_boxed)
575 -> rust::Vec<u8>
576 {
577 if ptr::eq(self.0.as_mut_ptr().cast(), &EMPTY_SENTINEL) {
578 return vec![];
579 }
580 let num_bytes = self.to_bytes_with_null().len();
581 let ptr = mem::ManuallyDrop::new(self).0.as_mut_ptr();
582 let boxed_bytes = unsafe {
583 rust::Box::from_raw(slice::from_raw_parts_mut(
584 ptr.cast(),
585 num_bytes,
586 ))
587 };
588 let mut vec = rust::Vec::from(boxed_bytes);
589 vec.pop();
590 vec
591 }
592
593 #[inline]
594 pub
595 fn into_string (self: char_p_boxed)
596 -> rust::String
597 {
598 unsafe {
599 rust::String::from_utf8_unchecked(
600 self.into_vec()
601 )
602 }
603 }
604
605 #[inline]
606 pub
607 fn to_owned (self: &'_ char_p_boxed)
608 -> char_p_boxed
609 {
610 self.as_ref().to_owned()
611 }
612 }
613
614 impl Eq
615 for char_p_boxed
616 {}
617 impl PartialEq
618 for char_p_boxed {
619 #[inline]
620 fn eq (self: &'_ Self, other: &'_ Self)
621 -> bool
622 {
623 self.as_ref() == other.as_ref()
624 }
625 }
626
627 impl Clone
628 for char_p_boxed
629 {
630 #[inline]
631 fn clone (self: &'_ Self)
632 -> Self
633 {
634 self.to_owned()
635 }
636 }
637}
638
639cfg_std! {
640 impl From<::std::ffi::CString> for char_p_boxed {
644 fn from (s: ::std::ffi::CString)
645 -> char_p_boxed
646 {
647 let _assert_valid_utf8 =
648 ::core::str::from_utf8(s.as_bytes())
649 .unwrap()
650 ;
651 let s: rust::Box<[u8]> =
652 s .into_bytes_with_nul()
653 .into_boxed_slice()
654 ;
655 unsafe {
656 Self::from_ptr_unchecked(
657 ptr::NonNull::new(rust::Box::leak(s).as_mut_ptr())
658 .unwrap()
659 )
660 }
661 }
662 }
663}