1 use std::fmt::{self, Display, Write as _};
2 use std::slice;
3 use std::str;
4 
5 #[allow(non_camel_case_types)]
6 type c_char = i8;
7 
8 pub struct CStr {
9     ptr: *const u8,
10 }
11 
12 impl CStr {
from_ptr(ptr: *const c_char) -> Self13     pub unsafe fn from_ptr(ptr: *const c_char) -> Self {
14         CStr { ptr: ptr.cast() }
15     }
16 }
17 
18 impl Display for CStr {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result19     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
20         let len = unsafe { strlen(self.ptr) };
21         let mut bytes = unsafe { slice::from_raw_parts(self.ptr, len) };
22         loop {
23             match str::from_utf8(bytes) {
24                 Ok(valid) => return formatter.write_str(valid),
25                 Err(utf8_error) => {
26                     let valid_up_to = utf8_error.valid_up_to();
27                     let valid = unsafe { str::from_utf8_unchecked(&bytes[..valid_up_to]) };
28                     formatter.write_str(valid)?;
29                     formatter.write_char(char::REPLACEMENT_CHARACTER)?;
30                     if let Some(error_len) = utf8_error.error_len() {
31                         bytes = &bytes[valid_up_to + error_len..];
32                     } else {
33                         return Ok(());
34                     }
35                 }
36             }
37         }
38     }
39 }
40 
strlen(s: *const u8) -> usize41 unsafe fn strlen(s: *const u8) -> usize {
42     let mut end = s;
43     while *end != 0 {
44         end = end.add(1);
45     }
46     end.offset_from(s) as usize
47 }
48