diff --git a/chain-impl-mockchain/src/block.rs b/chain-impl-mockchain/src/block.rs index 7d3a6e5c0..666616f7d 100644 --- a/chain-impl-mockchain/src/block.rs +++ b/chain-impl-mockchain/src/block.rs @@ -3,7 +3,7 @@ use crate::key::{Hash, PrivateKey, PublicKey, Signature}; use crate::transaction::*; use chain_core::property; -use std::fmt; +use std::{error, fmt, num::ParseIntError, str}; /// Non unique identifier of the transaction position in the /// blockchain. There may be many transactions related to the same @@ -107,6 +107,51 @@ impl fmt::Display for BlockDate { } } +#[derive(Debug)] +pub enum BlockDateParseError { + DotMissing, + BadEpochId(ParseIntError), + BadSlotId(ParseIntError), +} + +const EXPECT_FORMAT_MESSAGE: &'static str = "expected block date format EPOCH.SLOT"; + +impl fmt::Display for BlockDateParseError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use BlockDateParseError::*; + match self { + DotMissing => write!(f, "{}", EXPECT_FORMAT_MESSAGE), + BadEpochId(_) => write!(f, "invalid epoch ID, {}", EXPECT_FORMAT_MESSAGE), + BadSlotId(_) => write!(f, "invalid slot ID, {}", EXPECT_FORMAT_MESSAGE), + } + } +} + +impl error::Error for BlockDateParseError { + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + use BlockDateParseError::*; + match self { + DotMissing => None, + BadEpochId(e) => Some(e), + BadSlotId(e) => Some(e), + } + } +} + +impl str::FromStr for BlockDate { + type Err = BlockDateParseError; + + fn from_str(s: &str) -> Result { + let (ep, sp) = match s.find('.') { + None => return Err(BlockDateParseError::DotMissing), + Some(pos) => s.split_at(pos), + }; + let epoch = str::parse::(ep).map_err(|e| BlockDateParseError::BadEpochId(e))?; + let slot_id = str::parse::(sp).map_err(|e| BlockDateParseError::BadSlotId(e))?; + Ok(BlockDate { epoch, slot_id }) + } +} + impl property::Block for Block { type Id = Hash; type Date = BlockDate;