use crate::error::{Error, Result}; use crate::index::DerivationIndex; use serde::{Deserialize, Serialize}; const PREFIX: &str = "m"; #[derive(Serialize, Deserialize, Clone, Debug, Default)] pub struct DerivationPath { pub(crate) path: Vec, } impl DerivationPath { pub fn iter(&self) -> impl Iterator { self.path.iter() } } impl std::str::FromStr for DerivationPath { type Err = Error; fn from_str(s: &str) -> Result { let mut iter = s.split('/'); if iter.next() != Some(PREFIX) { return Err(Error::UnknownPathPrefix); } Ok(Self { path: iter.map(DerivationIndex::from_str).collect::>()?, }) } } impl std::fmt::Display for DerivationPath { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{PREFIX}")?; for index in self.iter() { write!(f, "/{index}")?; } Ok(()) } } #[cfg(test)] mod tests { use super::*; use std::str::FromStr; #[test] #[should_panic] fn requires_master_path() { DerivationPath::from_str("1234/5678'").unwrap(); } #[test] fn equivalency() -> Result<()> { let paths = ["m/1234'/5678", "m/44'/0'/0'", "m"]; for path in paths { assert_eq!(&DerivationPath::from_str(path)?.to_string(), path); } Ok(()) } }