use std::str::FromStr;
use snops_checkpoint::RetentionSpan;
use crate::format::{DataFormat, DataFormatReader, DataHeaderOf, DataReadError};
#[derive(Debug, Copy, Default, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase", untagged)]
pub enum DocHeightRequest {
#[default]
#[serde(with = "super::strings::top")]
Top,
Absolute(u32),
Checkpoint(snops_checkpoint::RetentionSpan),
}
impl FromStr for DocHeightRequest {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"top" => Ok(DocHeightRequest::Top),
s => {
if let Ok(height) = s.parse() {
Ok(DocHeightRequest::Absolute(height))
} else if let Ok(span) = s.parse() {
Ok(DocHeightRequest::Checkpoint(span))
} else {
Err(format!("invalid DocHeightRequest: {}", s))
}
}
}
}
}
impl DataFormat for DocHeightRequest {
type Header = (u8, DataHeaderOf<RetentionSpan>);
const LATEST_HEADER: Self::Header = (1, RetentionSpan::LATEST_HEADER);
fn write_data<W: std::io::prelude::Write>(
&self,
writer: &mut W,
) -> Result<usize, crate::format::DataWriteError> {
match self {
DocHeightRequest::Top => 0u8.write_data(writer),
DocHeightRequest::Absolute(height) => {
Ok(1u8.write_data(writer)? + height.write_data(writer)?)
}
DocHeightRequest::Checkpoint(retention) => {
Ok(2u8.write_data(writer)? + retention.write_data(writer)?)
}
}
}
fn read_data<R: std::io::prelude::Read>(
reader: &mut R,
header: &Self::Header,
) -> Result<Self, DataReadError> {
if header.0 != Self::LATEST_HEADER.0 {
return Err(DataReadError::unsupported(
"DocHeightRequest",
Self::LATEST_HEADER.0,
header.0,
));
}
match reader.read_data(&())? {
0u8 => Ok(DocHeightRequest::Top),
1u8 => Ok(DocHeightRequest::Absolute(reader.read_data(&())?)),
2u8 => Ok(DocHeightRequest::Checkpoint(reader.read_data(&header.1)?)),
n => Err(DataReadError::Custom(format!(
"invalid DocHeightRequest discrminant: {n}"
))),
}
}
}
#[derive(Debug, Default, Copy, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum HeightRequest {
#[default]
Top,
Absolute(u32),
Checkpoint(snops_checkpoint::RetentionSpan),
}
impl DataFormat for HeightRequest {
type Header = (u8, DataHeaderOf<RetentionSpan>);
const LATEST_HEADER: Self::Header = (1, RetentionSpan::LATEST_HEADER);
fn write_data<W: std::io::prelude::Write>(
&self,
writer: &mut W,
) -> Result<usize, crate::format::DataWriteError> {
match self {
HeightRequest::Top => 0u8.write_data(writer),
HeightRequest::Absolute(height) => {
Ok(1u8.write_data(writer)? + height.write_data(writer)?)
}
HeightRequest::Checkpoint(retention) => {
Ok(2u8.write_data(writer)? + retention.write_data(writer)?)
}
}
}
fn read_data<R: std::io::prelude::Read>(
reader: &mut R,
header: &Self::Header,
) -> Result<Self, DataReadError> {
if header.0 != Self::LATEST_HEADER.0 {
return Err(DataReadError::unsupported(
"HeightRequest",
Self::LATEST_HEADER.0,
header.0,
));
}
match reader.read_data(&())? {
0u8 => Ok(HeightRequest::Top),
1u8 => Ok(HeightRequest::Absolute(reader.read_data(&())?)),
2u8 => Ok(HeightRequest::Checkpoint(reader.read_data(&header.1)?)),
n => Err(DataReadError::Custom(format!(
"invalid HeightRequest discrminant: {n}"
))),
}
}
}
impl HeightRequest {
pub fn is_top(&self) -> bool {
*self == Self::Top
}
pub fn reset(&self) -> bool {
*self == Self::Absolute(0)
}
}
impl From<DocHeightRequest> for HeightRequest {
fn from(req: DocHeightRequest) -> Self {
match req {
DocHeightRequest::Top => Self::Top,
DocHeightRequest::Absolute(h) => Self::Absolute(h),
DocHeightRequest::Checkpoint(c) => Self::Checkpoint(c),
}
}
}