use std::collections::BTreeSet;
use std::fmt;
use serde::{Deserialize, Serialize};
use tsoracle_consensus::AdvancePayload;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SetFormatVersionPayload {
pub target: u8,
pub gated_members: BTreeSet<u64>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum HighWaterCommand {
Advance(AdvancePayload),
SetFormatVersion(SetFormatVersionPayload),
}
impl fmt::Display for HighWaterCommand {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
HighWaterCommand::Advance(AdvancePayload { at_least }) => {
write!(f, "Advance {{ at_least: {at_least} }}")
}
HighWaterCommand::SetFormatVersion(SetFormatVersionPayload {
target,
gated_members,
}) => {
let rendered: Vec<String> = gated_members.iter().map(|id| id.to_string()).collect();
write!(
f,
"SetFormatVersion {{ target: {target}, gated_members: [{}] }}",
rendered.join(", ")
)
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn display_renders_advance() {
let cmd = HighWaterCommand::Advance(AdvancePayload { at_least: 42 });
assert_eq!(format!("{cmd}"), "Advance { at_least: 42 }");
}
#[test]
fn display_renders_zero_at_least() {
let cmd = HighWaterCommand::Advance(AdvancePayload { at_least: 0 });
assert_eq!(format!("{cmd}"), "Advance { at_least: 0 }");
}
#[test]
fn postcard_round_trip_advance() {
let cmd = HighWaterCommand::Advance(AdvancePayload {
at_least: 1_234_567_890,
});
let bytes = postcard::to_stdvec(&cmd).expect("serialize");
let back: HighWaterCommand = postcard::from_bytes(&bytes).expect("deserialize");
assert_eq!(back, cmd);
}
#[test]
fn postcard_round_trip_zero() {
let cmd = HighWaterCommand::Advance(AdvancePayload { at_least: 0 });
let bytes = postcard::to_stdvec(&cmd).expect("serialize");
let back: HighWaterCommand = postcard::from_bytes(&bytes).expect("deserialize");
assert_eq!(back, cmd);
}
#[test]
fn postcard_round_trip_max() {
let cmd = HighWaterCommand::Advance(AdvancePayload { at_least: u64::MAX });
let bytes = postcard::to_stdvec(&cmd).expect("serialize");
let back: HighWaterCommand = postcard::from_bytes(&bytes).expect("deserialize");
assert_eq!(back, cmd);
}
#[test]
fn display_renders_set_format_version() {
let cmd = HighWaterCommand::SetFormatVersion(SetFormatVersionPayload {
target: 4,
gated_members: BTreeSet::from([1u64, 2u64, 3u64]),
});
assert_eq!(
format!("{cmd}"),
"SetFormatVersion { target: 4, gated_members: [1, 2, 3] }"
);
}
#[test]
fn postcard_round_trip_set_format_version() {
let cmd = HighWaterCommand::SetFormatVersion(SetFormatVersionPayload {
target: 7,
gated_members: BTreeSet::from([10u64, 20u64]),
});
let bytes = postcard::to_stdvec(&cmd).expect("serialize");
let back: HighWaterCommand = postcard::from_bytes(&bytes).expect("deserialize");
assert_eq!(back, cmd);
}
#[test]
fn postcard_round_trip_set_format_version_empty_gate() {
let cmd = HighWaterCommand::SetFormatVersion(SetFormatVersionPayload {
target: 4,
gated_members: BTreeSet::new(),
});
let bytes = postcard::to_stdvec(&cmd).expect("serialize");
let back: HighWaterCommand = postcard::from_bytes(&bytes).expect("deserialize");
assert_eq!(back, cmd);
}
}