use thiserror::Error;
use ytsaurus_yson::YsonError;
pub type Result<T, E = JobError> = std::result::Result<T, E>;
#[derive(Debug, Error)]
pub enum JobError {
#[error("reading job input: {0}")]
Read(#[source] std::io::Error),
#[error("writing to output table {table}: {source}")]
Write {
table: usize,
#[source]
source: std::io::Error,
},
#[error("invalid YSON at byte {offset} of the input stream: {source}")]
Yson {
offset: u64,
#[source]
source: YsonError,
},
#[error(
"input stream ended {buffered} bytes into an incomplete record at byte {offset}; \
the job was most likely killed or the upstream writer failed"
)]
TruncatedRecord {
offset: u64,
buffered: usize,
},
#[error(
"record at byte {offset} needs more than the {limit} byte buffer limit; \
raise it with JobReader::with_max_record_bytes if the data is genuinely this wide"
)]
RecordTooLarge {
offset: u64,
limit: usize,
},
#[error("malformed control record at byte {offset}: {reason}")]
BadControlRecord {
offset: u64,
reason: String,
},
#[error(
"output table {index} does not exist; this job has {count} output table(s){}",
known_tables(.names)
)]
UnknownTable {
index: usize,
count: usize,
names: Vec<String>,
},
#[error("serializing a row for output table {table}: {source}")]
Serialize {
table: usize,
#[source]
source: YsonError,
},
}
impl JobError {
#[must_use]
pub fn kind(&self) -> &'static str {
match self {
JobError::Read(_) => "read_failed",
JobError::Write { .. } => "write_failed",
JobError::Yson { .. } => "invalid_yson",
JobError::TruncatedRecord { .. } => "truncated_record",
JobError::RecordTooLarge { .. } => "record_too_large",
JobError::BadControlRecord { .. } => "bad_control_record",
JobError::UnknownTable { .. } => "unknown_table",
JobError::Serialize { .. } => "serialize_failed",
}
}
#[must_use]
pub fn is_row_local(&self) -> bool {
match self {
JobError::Yson { .. } | JobError::Serialize { .. } => true,
JobError::Read(_)
| JobError::Write { .. }
| JobError::TruncatedRecord { .. }
| JobError::RecordTooLarge { .. }
| JobError::BadControlRecord { .. }
| JobError::UnknownTable { .. } => false,
}
}
}
fn known_tables(names: &[String]) -> String {
if names.is_empty() {
String::new()
} else {
format!(": {}", names.join(", "))
}
}