#[cfg(coverage)]
use std::cell::Cell;
use std::collections::TryReserveError;
use std::io::{
Error,
Result,
};
fn allocation_error(error: TryReserveError) -> Error {
Error::other(format!("failed to reserve output buffer capacity: {error}"))
}
#[cfg(coverage)]
thread_local! {
static COVERAGE_RESERVE_FAIL_AFTER: Cell<usize> = const { Cell::new(usize::MAX) };
static COVERAGE_FAIL_NEXT_STRING_RESERVE: Cell<bool> = const { Cell::new(false) };
}
#[cfg(coverage)]
#[doc(hidden)]
pub fn coverage_fail_next_reserve() {
COVERAGE_RESERVE_FAIL_AFTER.with(|state| state.set(0));
}
#[cfg(coverage)]
#[doc(hidden)]
pub fn coverage_fail_reserve_after(successful_attempts: usize) {
COVERAGE_RESERVE_FAIL_AFTER.with(|state| state.set(successful_attempts));
}
#[cfg(coverage)]
#[doc(hidden)]
pub fn coverage_fail_next_string_reserve() {
COVERAGE_FAIL_NEXT_STRING_RESERVE.with(|state| state.set(true));
}
#[cfg(coverage)]
#[doc(hidden)]
pub fn coverage_reset_reserve_hooks() {
COVERAGE_RESERVE_FAIL_AFTER.with(|state| state.set(usize::MAX));
COVERAGE_FAIL_NEXT_STRING_RESERVE.with(|state| state.set(false));
}
#[cfg(coverage)]
fn coverage_maybe_fail_reserve<T>() -> Option<Result<T>> {
COVERAGE_RESERVE_FAIL_AFTER.with(|state| {
let remaining = state.get();
if remaining == usize::MAX {
return None;
}
if remaining == 0 {
state.set(usize::MAX);
return Some(Err(Error::other(
"failed to reserve output buffer capacity: coverage reserve failure",
)));
}
state.set(remaining - 1);
None
})
}
pub fn try_reserve_vec<T>(
output: &mut Vec<T>,
additional: usize,
) -> Result<()> {
#[cfg(coverage)]
if let Some(result) = coverage_maybe_fail_reserve::<()>() {
return result;
}
output.try_reserve(additional).map_err(allocation_error)
}
pub fn try_reserve_string(
output: &mut String,
additional: usize,
) -> Result<()> {
#[cfg(coverage)]
if COVERAGE_FAIL_NEXT_STRING_RESERVE.with(|state| {
let fail = state.get();
if fail {
state.set(false);
}
fail
}) {
return Err(Error::other(
"failed to reserve output buffer capacity: coverage reserve failure",
));
}
#[cfg(coverage)]
if let Some(result) = coverage_maybe_fail_reserve::<()>() {
return result;
}
output.try_reserve(additional).map_err(allocation_error)
}
pub(crate) fn create_vec<T>(len: usize, fill: T) -> Result<Vec<T>>
where
T: Copy,
{
let mut buffer = Vec::new();
try_reserve_vec(&mut buffer, len)?;
buffer.resize(len, fill);
Ok(buffer)
}