use crate::{
errors::{ChildError, ChildStartError, ErrorList},
reporter::events::ExecutionResult,
};
use bstr::{ByteSlice, Lines};
use bytes::Bytes;
use std::{borrow::Cow, sync::OnceLock};
#[derive(Copy, Clone, PartialEq, Default, Debug)]
pub enum CaptureStrategy {
#[default]
Split,
Combined,
None,
}
#[derive(Clone, Debug)]
pub struct ChildSingleOutput {
pub buf: Bytes,
as_str: OnceLock<Option<Box<str>>>,
}
impl From<Bytes> for ChildSingleOutput {
#[inline]
fn from(buf: Bytes) -> Self {
Self {
buf,
as_str: OnceLock::new(),
}
}
}
impl ChildSingleOutput {
#[inline]
pub fn as_str_lossy(&self) -> &str {
let s = self
.as_str
.get_or_init(|| match String::from_utf8_lossy(&self.buf) {
Cow::Borrowed(_) => None,
Cow::Owned(s) => Some(s.into_boxed_str()),
});
match s {
Some(s) => s,
None => unsafe { std::str::from_utf8_unchecked(&self.buf) },
}
}
#[inline]
pub fn lines(&self) -> Lines<'_> {
self.buf.lines()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.buf.is_empty()
}
}
#[derive(Clone, Debug)]
pub enum ChildExecutionOutput {
Output {
result: Option<ExecutionResult>,
output: ChildOutput,
errors: Option<ErrorList<ChildError>>,
},
StartError(ChildStartError),
}
impl ChildExecutionOutput {
pub(crate) fn has_errors(&self) -> bool {
match self {
ChildExecutionOutput::Output { errors, result, .. } => {
if errors.is_some() {
return true;
}
if let Some(result) = result {
return !result.is_success();
}
false
}
ChildExecutionOutput::StartError(_) => true,
}
}
}
#[derive(Clone, Debug)]
pub enum ChildOutput {
Split(ChildSplitOutput),
Combined {
output: ChildSingleOutput,
},
}
#[derive(Clone, Debug)]
pub struct ChildSplitOutput {
pub stdout: Option<ChildSingleOutput>,
pub stderr: Option<ChildSingleOutput>,
}