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) -> usize41unsafe 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