use crate::error::BoxError;
use bytes::Bytes;
pub mod sealed {
use super::{BoxError, Bytes};
pub trait EncodeValue<T>: Send + Sync + 'static {
fn encode_value(&self, value: &T) -> Result<Bytes, BoxError>;
}
pub trait DecodeValue<T>: Send + Sync + 'static {
fn decode_value(&self, bytes: Bytes) -> Result<T, BoxError>;
}
}
pub trait Encoder: Send + Sync + 'static {
fn encode<T>(&self, value: &T) -> Result<Bytes, BoxError>
where
Self: sealed::EncodeValue<T>,
{
sealed::EncodeValue::encode_value(self, value)
}
}
pub trait Decoder: Send + Sync + 'static {
fn decode<T>(&self, bytes: Bytes) -> Result<T, BoxError>
where
Self: sealed::DecodeValue<T>,
{
sealed::DecodeValue::decode_value(self, bytes)
}
}
pub trait Codec: Encoder + Decoder {}
impl<U> Codec for U where U: Encoder + Decoder {}
pub trait CodecIdentity {
fn codec_id(&self) -> crate::snapshot_format::CodecId;
}
impl<C: CodecIdentity> CodecIdentity for std::sync::Arc<C> {
fn codec_id(&self) -> crate::snapshot_format::CodecId {
(**self).codec_id()
}
}
pub trait SnapshotCodec:
Encoder
+ Decoder
+ CodecIdentity
+ sealed::EncodeValue<crate::snapshot::WorkflowSnapshot>
+ sealed::DecodeValue<crate::snapshot::WorkflowSnapshot>
{
}
impl<C> SnapshotCodec for C where
C: Encoder
+ Decoder
+ CodecIdentity
+ sealed::EncodeValue<crate::snapshot::WorkflowSnapshot>
+ sealed::DecodeValue<crate::snapshot::WorkflowSnapshot>
{
}
impl<C, T> sealed::EncodeValue<T> for std::sync::Arc<C>
where
C: sealed::EncodeValue<T>,
{
fn encode_value(&self, value: &T) -> Result<Bytes, BoxError> {
(**self).encode_value(value)
}
}
impl<C, T> sealed::DecodeValue<T> for std::sync::Arc<C>
where
C: sealed::DecodeValue<T>,
{
fn decode_value(&self, bytes: Bytes) -> Result<T, BoxError> {
(**self).decode_value(bytes)
}
}
impl<C> Encoder for std::sync::Arc<C> where C: Encoder {}
impl<C> Decoder for std::sync::Arc<C> where C: Decoder {}
pub trait EnvelopeCodec: Send + Sync {
fn decode_string(&self, bytes: &[u8]) -> Result<String, BoxError>;
fn encode_branch_envelope(&self, key: &str, result_bytes: &[u8]) -> Result<Bytes, BoxError>;
fn encode_named_results(&self, results: &[(String, Bytes)]) -> Result<Bytes, BoxError>;
}
impl<C: EnvelopeCodec> EnvelopeCodec for &C {
fn decode_string(&self, bytes: &[u8]) -> Result<String, BoxError> {
(**self).decode_string(bytes)
}
fn encode_branch_envelope(&self, key: &str, result_bytes: &[u8]) -> Result<Bytes, BoxError> {
(**self).encode_branch_envelope(key, result_bytes)
}
fn encode_named_results(&self, results: &[(String, Bytes)]) -> Result<Bytes, BoxError> {
(**self).encode_named_results(results)
}
}
impl<C: EnvelopeCodec> EnvelopeCodec for std::sync::Arc<C> {
fn decode_string(&self, bytes: &[u8]) -> Result<String, BoxError> {
(**self).decode_string(bytes)
}
fn encode_branch_envelope(&self, key: &str, result_bytes: &[u8]) -> Result<Bytes, BoxError> {
(**self).encode_branch_envelope(key, result_bytes)
}
fn encode_named_results(&self, results: &[(String, Bytes)]) -> Result<Bytes, BoxError> {
(**self).encode_named_results(results)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, strum::AsRefStr, strum::EnumString)]
#[strum(serialize_all = "snake_case")]
pub enum LoopDecision {
Again,
Done,
}
#[must_use]
pub fn encode_loop_envelope(decision: LoopDecision, inner_bytes: &[u8]) -> Bytes {
let mut buf = Vec::with_capacity(1 + inner_bytes.len());
buf.push(match decision {
LoopDecision::Again => 0,
LoopDecision::Done => 1,
});
buf.extend_from_slice(inner_bytes);
Bytes::from(buf)
}
pub fn decode_loop_envelope(bytes: &[u8]) -> Result<(LoopDecision, Bytes), BoxError> {
let &tag = bytes.first().ok_or("empty loop envelope")?;
let decision = match tag {
0 => LoopDecision::Again,
1 => LoopDecision::Done,
_ => return Err(format!("invalid loop envelope tag: {tag:#04x}").into()),
};
let inner = bytes
.get(1..)
.ok_or("unexpected empty loop envelope payload")?;
Ok((decision, Bytes::copy_from_slice(inner)))
}