1use crate::{Error, HARDEND};
2
3use alloc::format;
4use alloc::string::String;
5use alloc::vec::Vec;
6use core::convert::From;
7
8#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
10pub struct BIP32Path(pub(crate) Vec<u32>);
11
12impl core::str::FromStr for BIP32Path {
13 type Err = Error;
14
15 fn from_str(path: &str) -> Result<Self, Self::Err> {
17 let mut paths = Vec::new();
18 let path = path.replace("/", "\n");
19
20 for p in path.lines() {
21 if p != "m" {
22 if p.ends_with('H') || p.ends_with('\'') {
23 let index: u32 = p[..p.len() - 1].parse().map_err(|_| Error::InvalidIndex)?;
24 if index < HARDEND {
25 paths.push(index + HARDEND);
26 } else {
27 return Err(Error::InvalidIndex);
28 }
29 } else {
30 let index: u32 = p.parse().map_err(|_| Error::InvalidIndex)?;
31 if index < HARDEND {
32 paths.push(index);
33 } else {
34 return Err(Error::InvalidIndex);
35 }
36 }
37 }
38 }
39
40 Ok(BIP32Path(paths))
41 }
42}
43
44impl core::fmt::Display for BIP32Path {
45 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
46 write!(
47 f,
48 "m/{}",
49 self.0
50 .iter()
51 .map(|index| {
52 if let Some(index) = index.checked_sub(HARDEND) {
53 format!("{}'", index)
54 } else {
55 format!("{}", index)
56 }
57 })
58 .collect::<Vec<String>>()
59 .join("/")
60 )
61 }
62}
63
64impl BIP32Path {
65 pub fn depth(&self) -> u8 {
67 self.0.len() as u8
68 }
69
70 pub fn index(&self, depth: u8) -> Option<&u32> {
72 self.0.get(depth as usize)
73 }
74
75 pub fn push(&mut self, index: u32) {
77 self.0.push(index);
78 }
79
80 pub fn pop(&mut self) -> Option<u32> {
82 self.0.pop()
83 }
84}
85
86impl From<Vec<u32>> for BIP32Path {
87 fn from(vector: Vec<u32>) -> Self {
88 BIP32Path(vector)
89 }
90}