Add CStr that can be lossy formatted without allocation

This commit is contained in:
David Tolnay 2022-07-08 09:35:26 -07:00
parent 47ad13e63c
commit 966ef05f32
No known key found for this signature in database
GPG key ID: F9BA143B95FF6D82
3 changed files with 66 additions and 30 deletions

47
src/bin/cstr/mod.rs Normal file
View file

@ -0,0 +1,47 @@
use std::fmt::{self, Display, Write as _};
use std::slice;
use std::str;
#[allow(non_camel_case_types)]
type c_char = i8;
pub struct CStr {
ptr: *const u8,
}
impl CStr {
pub unsafe fn from_ptr(ptr: *const c_char) -> Self {
CStr { ptr: ptr.cast() }
}
}
impl Display for CStr {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
let len = unsafe { strlen(self.ptr) };
let mut bytes = unsafe { slice::from_raw_parts(self.ptr, len) };
loop {
match str::from_utf8(bytes) {
Ok(valid) => return formatter.write_str(valid),
Err(utf8_error) => {
let valid_up_to = utf8_error.valid_up_to();
let valid = unsafe { str::from_utf8_unchecked(&bytes[..valid_up_to]) };
formatter.write_str(valid)?;
formatter.write_char(char::REPLACEMENT_CHARACTER)?;
if let Some(error_len) = utf8_error.error_len() {
bytes = &bytes[valid_up_to + error_len..];
} else {
return Ok(());
}
}
}
}
}
}
unsafe fn strlen(s: *const u8) -> usize {
let mut end = s;
while *end != 0 {
end = end.add(1);
}
end.offset_from(s) as usize
}

View file

@ -14,9 +14,12 @@
clippy::unreadable_literal
)]
mod cstr;
use self::cstr::CStr;
use std::env;
use std::error::Error;
use std::ffi::{c_void, CStr};
use std::ffi::c_void;
use std::fs::File;
use std::io::{self, Read, Write};
use std::mem::MaybeUninit;
@ -145,11 +148,7 @@ pub(crate) unsafe fn unsafe_main(
);
} else {
yaml_emitter_delete(emitter);
return Err(format!(
"Unknown event: '{}'",
CStr::from_ptr(line).to_string_lossy(),
)
.into());
return Err(format!("Unknown event: '{}'", CStr::from_ptr(line)).into());
}
if ok == 0 {
current_block = 13850764817919632987;
@ -164,16 +163,8 @@ pub(crate) unsafe fn unsafe_main(
13850764817919632987 => Err("Memory error: Not enough memory for creating an event".into()),
6684355725484023210 => Err(match (*emitter).error as u32 {
1 => "Memory error: Not enough memory for emitting".into(),
6 => format!(
"Writer error: {}",
CStr::from_ptr((*emitter).problem).to_string_lossy(),
)
.into(),
7 => format!(
"Emitter error: {}",
CStr::from_ptr((*emitter).problem).to_string_lossy(),
)
.into(),
6 => format!("Writer error: {}", CStr::from_ptr((*emitter).problem)).into(),
7 => format!("Emitter error: {}", CStr::from_ptr((*emitter).problem)).into(),
_ => "Internal error".into(),
}),
_ => Ok(()),

View file

@ -11,9 +11,12 @@
clippy::too_many_lines
)]
mod cstr;
use self::cstr::CStr;
use std::env;
use std::error::Error;
use std::ffi::{c_void, CStr};
use std::ffi::c_void;
use std::fmt::Write as _;
use std::fs::File;
use std::io::{self, Read, Write};
@ -59,10 +62,7 @@ pub(crate) unsafe fn unsafe_main(
yaml_parser_set_input(parser, Some(read_from_stdio), addr_of_mut!(stdin).cast());
loop {
if yaml_parser_parse(parser, event) == 0 {
let mut error = format!(
"Parse error: {}",
CStr::from_ptr((*parser).problem).to_string_lossy(),
);
let mut error = format!("Parse error: {}", CStr::from_ptr((*parser).problem));
if (*parser).problem_mark.line != 0 || (*parser).problem_mark.column != 0 {
let _ = write!(
error,
@ -99,15 +99,14 @@ pub(crate) unsafe fn unsafe_main(
let _ = write!(
stdout,
" &{}",
CStr::from_ptr((*event).data.mapping_start.anchor as *const i8)
.to_string_lossy(),
CStr::from_ptr((*event).data.mapping_start.anchor as *const i8),
);
}
if !((*event).data.mapping_start.tag).is_null() {
let _ = write!(
stdout,
" <{}>",
CStr::from_ptr((*event).data.mapping_start.tag as *const i8).to_string_lossy(),
CStr::from_ptr((*event).data.mapping_start.tag as *const i8),
);
}
let _ = writeln!(stdout);
@ -119,15 +118,14 @@ pub(crate) unsafe fn unsafe_main(
let _ = write!(
stdout,
" &{}",
CStr::from_ptr((*event).data.sequence_start.anchor as *const i8)
.to_string_lossy(),
CStr::from_ptr((*event).data.sequence_start.anchor as *const i8),
);
}
if !((*event).data.sequence_start.tag).is_null() {
let _ = write!(
stdout,
" <{}>",
CStr::from_ptr((*event).data.sequence_start.tag as *const i8).to_string_lossy(),
CStr::from_ptr((*event).data.sequence_start.tag as *const i8),
);
}
let _ = writeln!(stdout);
@ -139,14 +137,14 @@ pub(crate) unsafe fn unsafe_main(
let _ = write!(
stdout,
" &{}",
CStr::from_ptr((*event).data.scalar.anchor as *const i8).to_string_lossy(),
CStr::from_ptr((*event).data.scalar.anchor as *const i8),
);
}
if !((*event).data.scalar.tag).is_null() {
let _ = write!(
stdout,
" <{}>",
CStr::from_ptr((*event).data.scalar.tag as *const i8).to_string_lossy(),
CStr::from_ptr((*event).data.scalar.tag as *const i8),
);
}
match (*event).data.scalar.style as u32 {
@ -180,7 +178,7 @@ pub(crate) unsafe fn unsafe_main(
let _ = writeln!(
stdout,
"=ALI *{}",
CStr::from_ptr((*event).data.alias.anchor as *const i8).to_string_lossy(),
CStr::from_ptr((*event).data.alias.anchor as *const i8),
);
} else {
process::abort();