use brk_error::{Error, Result}; use brk_rpc::Client; use brk_types::{CheckedSub, Height}; pub struct Selector; impl Selector { pub fn parse(s: &str, client: &Client) -> Result<(Height, Height)> { let (a, b) = s.split_once("..").unwrap_or((s, s)); let needs_tip = |p: &str| p == "tip" || p.starts_with("tip-"); let tip = if needs_tip(a) || needs_tip(b) { Some(client.get_last_height()?) } else { None }; let start = Self::endpoint(a, tip)?; let end = Self::endpoint(b, tip)?; if end < start { return Err(Error::Parse(format!( "range end {end} before start {start}" ))); } Ok((start, end)) } fn endpoint(s: &str, tip: Option) -> Result { if s == "tip" { return Ok(tip.expect("tip pre-resolved when input contains 'tip'")); } if let Some(rest) = s.strip_prefix("tip-") { let n: u32 = rest .parse() .map_err(|_| Error::Parse(format!("bad tip offset: {s}")))?; let tip = tip.expect("tip pre-resolved when input contains 'tip'"); return tip .checked_sub(n) .ok_or_else(|| Error::Parse(format!("tip-{n} underflows genesis"))); } let n: u32 = s .parse() .map_err(|_| Error::Parse(format!("bad height: {s}")))?; Ok(Height::new(n)) } }