use super::{Outcome, OutcomeError};
use crate::outcome::error::ErrorKind;
pub fn zip<A: Clone, B: Clone>(a: Outcome<A>, b: Outcome<B>) -> Outcome<(A, B)> {
match (a, b) {
(Outcome::Ok(a), Outcome::Ok(b)) => Outcome::Ok((a, b)),
(Outcome::Err(e), _) | (_, Outcome::Err(e)) => Outcome::Err(e),
(Outcome::Cancelled { reason }, _) | (_, Outcome::Cancelled { reason }) => {
Outcome::Cancelled { reason }
}
(
Outcome::Retry {
after_ms,
attempt,
max_attempts,
reason,
},
_,
)
| (
_,
Outcome::Retry {
after_ms,
attempt,
max_attempts,
reason,
},
) => Outcome::Retry {
after_ms,
attempt,
max_attempts,
reason,
},
(
Outcome::Pending {
condition,
resume_token,
},
_,
)
| (
_,
Outcome::Pending {
condition,
resume_token,
},
) => Outcome::Pending {
condition,
resume_token,
},
(Outcome::Batch(a_items), Outcome::Batch(b_items)) => Outcome::Batch(
a_items
.into_iter()
.zip(b_items)
.map(|(a, b)| zip(a, b))
.collect(),
),
(Outcome::Batch(items), Outcome::Ok(b)) => Outcome::Batch(
items
.into_iter()
.map(|a| zip(a, Outcome::Ok(b.clone())))
.collect(),
),
(Outcome::Ok(a), Outcome::Batch(items)) => Outcome::Batch(
items
.into_iter()
.map(|b| zip(Outcome::Ok(a.clone()), b))
.collect(),
),
}
}
pub fn join_all<T>(outcomes: Vec<Outcome<T>>) -> Outcome<Vec<T>> {
let mut results = Vec::with_capacity(outcomes.len());
for outcome in outcomes {
match outcome {
Outcome::Ok(v) => results.push(v),
Outcome::Err(e) => return Outcome::Err(e),
Outcome::Cancelled { reason } => return Outcome::Cancelled { reason },
Outcome::Retry {
after_ms,
attempt,
max_attempts,
reason,
} => {
return Outcome::Retry {
after_ms,
attempt,
max_attempts,
reason,
};
}
Outcome::Pending {
condition,
resume_token,
} => {
return Outcome::Pending {
condition,
resume_token,
};
}
Outcome::Batch(inner) => {
match join_all(inner) {
Outcome::Ok(vs) => results.extend(vs),
Outcome::Err(e) => return Outcome::Err(e),
Outcome::Cancelled { reason } => return Outcome::Cancelled { reason },
Outcome::Retry {
after_ms,
attempt,
max_attempts,
reason,
} => {
return Outcome::Retry {
after_ms,
attempt,
max_attempts,
reason,
};
}
Outcome::Pending {
condition,
resume_token,
} => {
return Outcome::Pending {
condition,
resume_token,
};
}
Outcome::Batch(_) => {
unreachable!("join_all never returns Batch — it always returns Ok or an early-exit variant");
}
}
}
}
}
Outcome::Ok(results)
}
#[allow(clippy::wildcard_enum_match_arm)] pub fn join_any<T>(outcomes: Vec<Outcome<T>>) -> Outcome<T> {
let mut last_err = None;
for outcome in outcomes {
match outcome {
Outcome::Ok(v) => return Outcome::Ok(v),
Outcome::Err(e) => last_err = Some(e),
other => return other, }
}
match last_err {
Some(e) => Outcome::Err(e),
None => Outcome::Err(OutcomeError {
kind: ErrorKind::Internal,
message: "join_any called with empty vec".into(),
compensation: None,
retryable: false,
}),
}
}