x = x * 26 + c as u64 - 'a' as u64 + 1; if x > Self::SUPPLY { bail!("sat name out of range"); } } _ => bail!("invalid character in sat name: {c}"), } } Ok(Sat(Self::SUPPLY - x)) } fn from_degree(degree: &str) -> Result { let (cycle_number, rest) = degree .split_once('°') .ok_or_else(|| anyhow!("missing degree symbol"))?; let cycle_number = cycle_number.parse::()?; let (epoch_offset, rest) = rest .split_once('′') .ok_or_else(|| anyhow!("missing minute symbol"))?; let epoch_offset = epoch_offset.parse::()?; if epoch_offset >= SUBSIDY_HALVING_INTERVAL { bail!("invalid epoch offset"); } let (period_offset, rest) = rest .split_once('″') .ok_or_else(|| anyhow!("missing second symbol"))?; let period_offset = period_offset.parse::()?; if period_offset >= DIFFCHANGE_INTERVAL { bail!("invalid period offset"); } let cycle_start_epoch = cycle_number * CYCLE_EPOCHS;