5344d287a9
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
84 lines
2.7 KiB
Rust
84 lines
2.7 KiB
Rust
//! A text wire form of `u8`-keyed frames, shared by the edge tests.
|
|
|
|
use zset::{CodecError, Correction, Delta, EdgeCodec, Frame, Request, Stamp, ZSet};
|
|
|
|
type Z = ZSet<u8>;
|
|
|
|
/// A text wire form, to run the same histories through an encoding.
|
|
#[derive(Clone, Copy)]
|
|
pub struct Text;
|
|
|
|
pub fn zs(z: &Z) -> String {
|
|
z.iter()
|
|
.map(|(k, w)| format!("{k}:{w}"))
|
|
.collect::<Vec<_>>()
|
|
.join(",")
|
|
}
|
|
|
|
pub fn unzs(s: &str) -> Result<Z, CodecError> {
|
|
let bad = || CodecError(format!("bad entries {s:?}"));
|
|
s.split(',')
|
|
.filter(|p| !p.is_empty())
|
|
.map(|p| {
|
|
let (k, w) = p.split_once(':').ok_or_else(bad)?;
|
|
Ok((
|
|
k.parse::<u8>().map_err(|_| bad())?,
|
|
w.parse::<i64>().map_err(|_| bad())?,
|
|
))
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
impl EdgeCodec<u8> for Text {
|
|
type Wire = String;
|
|
|
|
fn encode(&self, f: &Frame<u8>) -> String {
|
|
match f {
|
|
Frame::Delta(d) => format!("D {} {} {} {}", d.epoch, d.from, d.to, zs(&d.delta)),
|
|
Frame::Correction(c) => {
|
|
format!("C {} {} {} {}", c.epoch, c.through, c.token, zs(&c.target))
|
|
}
|
|
Frame::Request(r) => match r.have {
|
|
Some(s) => format!("R {} {} {}", r.token, s.epoch, s.seq),
|
|
None => format!("R {}", r.token),
|
|
},
|
|
}
|
|
}
|
|
|
|
fn decode(&self, w: String) -> Result<Frame<u8>, CodecError> {
|
|
let bad = || CodecError(format!("bad frame {w:?}"));
|
|
let mut it = w.splitn(5, ' ');
|
|
let num = |s: Option<&str>| s.and_then(|s| s.parse::<u64>().ok()).ok_or_else(bad);
|
|
match it.next() {
|
|
Some("D") => Ok(Frame::Delta(Delta {
|
|
epoch: num(it.next())?,
|
|
from: num(it.next())?,
|
|
to: num(it.next())?,
|
|
delta: unzs(it.next().ok_or_else(bad)?)?,
|
|
})),
|
|
Some("C") => {
|
|
let mut it = w.splitn(5, ' ');
|
|
it.next();
|
|
Ok(Frame::Correction(Correction {
|
|
epoch: num(it.next())?,
|
|
through: num(it.next())?,
|
|
token: num(it.next())?,
|
|
target: unzs(it.next().ok_or_else(bad)?)?,
|
|
}))
|
|
}
|
|
Some("R") => {
|
|
let token = num(it.next())?;
|
|
let have = match it.next() {
|
|
None => None,
|
|
e => Some(Stamp {
|
|
epoch: num(e)?,
|
|
seq: num(it.next())?,
|
|
}),
|
|
};
|
|
Ok(Frame::Request(Request { have, token }))
|
|
}
|
|
_ => Err(bad()),
|
|
}
|
|
}
|
|
}
|