use alloc::string::String;
#[derive(
Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
)]
#[serde(transparent)]
pub struct SpillRef(String);
impl SpillRef {
#[must_use]
pub fn new(id: impl Into<String>) -> Self {
Self(id.into())
}
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
}
impl core::fmt::Display for SpillRef {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(&self.0)
}
}
impl core::ops::Deref for SpillRef {
type Target = str;
fn deref(&self) -> &str {
&self.0
}
}
impl AsRef<str> for SpillRef {
fn as_ref(&self) -> &str {
&self.0
}
}
impl From<String> for SpillRef {
fn from(s: String) -> Self {
Self(s)
}
}
impl From<&str> for SpillRef {
fn from(s: &str) -> Self {
Self(s.into())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SpillContext<'a> {
pub tool_name: &'a str,
pub opaque_tag: Option<&'a str>,
}
impl<'a> SpillContext<'a> {
pub const ANONYMOUS: Self = Self {
tool_name: "anonymous",
opaque_tag: None,
};
#[must_use]
pub const fn new(tool_name: &'a str) -> Self {
Self {
tool_name,
opaque_tag: None,
}
}
#[must_use]
pub const fn with_tag(mut self, opaque_tag: &'a str) -> Self {
self.opaque_tag = Some(opaque_tag);
self
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SpillError {
CapacityExceeded {
limit: usize,
attempted: usize,
},
StorageFailed(String),
Timeout,
Rejected(String),
Other(String),
}
impl core::fmt::Display for SpillError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::CapacityExceeded { limit, attempted } => {
write!(
f,
"spill capacity exceeded: attempted {attempted} bytes with limit of {limit} bytes"
)
}
Self::StorageFailed(msg) => write!(f, "spill storage failed: {msg}"),
Self::Timeout => write!(f, "spill operation timed out"),
Self::Rejected(msg) => write!(f, "spill rejected: {msg}"),
Self::Other(msg) => write!(f, "spill error: {msg}"),
}
}
}
impl core::error::Error for SpillError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SpillDisposition {
NotConfigured,
Spilled(SpillRef),
Failed(SpillError),
}
impl SpillDisposition {
#[must_use]
pub const fn spill_ref(&self) -> Option<&SpillRef> {
match self {
Self::Spilled(handle) => Some(handle),
Self::NotConfigured | Self::Failed(_) => None,
}
}
#[must_use]
pub const fn error(&self) -> Option<&SpillError> {
match self {
Self::Failed(error) => Some(error),
Self::NotConfigured | Self::Spilled(_) => None,
}
}
}
pub trait OutputSpillSink: Send + Sync + core::fmt::Debug {
fn spill(&self, ctx: &SpillContext<'_>, full: &str) -> Result<SpillRef, SpillError>;
}