1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
//! Derivation paths

use crate::{ChildNumber, Error, Result};
//use alloc::vec::{self, Vec};
use core::{
    fmt::{self, Display},
    str::FromStr,
};

/// Prefix for all derivation paths.
const PREFIX: &str = "m";

/// Derivation paths within a hierarchical keyspace.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct DerivationPath {
    path: Vec<ChildNumber>,
}

impl DerivationPath {
    /// Iterate over the [`ChildNumber`] values in this derivation path.
    pub fn iter(&self) -> impl Iterator<Item = ChildNumber> + '_ {
        self.path.iter().cloned()
    }

    /// Is this derivation path empty? (i.e. the root)
    pub fn is_empty(&self) -> bool {
        self.path.is_empty()
    }

    /// Get the count of [`ChildNumber`] values in this derivation path.
    pub fn len(&self) -> usize {
        self.path.len()
    }

    /// Get the parent [`DerivationPath`] for the current one.
    ///
    /// Returns `None` if this is already the root path.
    pub fn parent(&self) -> Option<Self> {
        self.path.len().checked_sub(1).map(|n| {
            let mut parent = self.clone();
            parent.path.truncate(n);
            parent
        })
    }

    /// Push a [`ChildNumber`] onto an existing derivation path.
    pub fn push(&mut self, child_number: ChildNumber) {
        self.path.push(child_number)
    }
}

impl AsRef<[ChildNumber]> for DerivationPath {
    fn as_ref(&self) -> &[ChildNumber] {
        &self.path
    }
}

impl Display for DerivationPath {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(PREFIX)?;

        for child_number in self.iter() {
            write!(f, "/{}", child_number)?;
        }

        Ok(())
    }
}

impl Extend<ChildNumber> for DerivationPath {
    fn extend<T>(&mut self, iter: T)
    where
        T: IntoIterator<Item = ChildNumber>,
    {
        self.path.extend(iter);
    }
}

impl FromStr for DerivationPath {
    type Err = Error;

    fn from_str(path: &str) -> Result<DerivationPath> {
        let mut path = path.split('/');

        if path.next() != Some(PREFIX) {
            return Err(Error::String(format!("Derivation don't start with `{PREFIX}/`")));
        }

        Ok(DerivationPath { path: path.map(str::parse).collect::<Result<_>>()? })
    }
}

impl IntoIterator for DerivationPath {
    type Item = ChildNumber;
    type IntoIter = std::vec::IntoIter<ChildNumber>;

    fn into_iter(self) -> std::vec::IntoIter<ChildNumber> {
        self.path.into_iter()
    }
}

#[cfg(test)]
mod tests {
    use super::DerivationPath;
    //use alloc::string::ToString;

    /// BIP32 test vectors
    // TODO(tarcieri): consolidate test vectors
    #[test]
    fn round_trip() {
        let path_m = "m";
        assert_eq!(path_m.parse::<DerivationPath>().unwrap().to_string(), path_m);

        let path_m_0 = "m/0";
        assert_eq!(path_m_0.parse::<DerivationPath>().unwrap().to_string(), path_m_0);

        let path_m_0_2147483647h = "m/0/2147483647'";
        assert_eq!(path_m_0_2147483647h.parse::<DerivationPath>().unwrap().to_string(), path_m_0_2147483647h);

        let path_m_0_2147483647h_1 = "m/0/2147483647'/1";
        assert_eq!(path_m_0_2147483647h_1.parse::<DerivationPath>().unwrap().to_string(), path_m_0_2147483647h_1);

        let path_m_0_2147483647h_1_2147483646h = "m/0/2147483647'/1/2147483646'";
        assert_eq!(
            path_m_0_2147483647h_1_2147483646h.parse::<DerivationPath>().unwrap().to_string(),
            path_m_0_2147483647h_1_2147483646h
        );

        let path_m_0_2147483647h_1_2147483646h_2 = "m/0/2147483647'/1/2147483646'/2";
        assert_eq!(
            path_m_0_2147483647h_1_2147483646h_2.parse::<DerivationPath>().unwrap().to_string(),
            path_m_0_2147483647h_1_2147483646h_2
        );
    }

    #[test]
    fn parent() {
        let path_m_0_2147483647h = "m/0/2147483647'".parse::<DerivationPath>().unwrap();
        let path_m_0 = path_m_0_2147483647h.parent().unwrap();
        assert_eq!("m/0", path_m_0.to_string());

        let path_m = path_m_0.parent().unwrap();
        assert_eq!("m", path_m.to_string());
        assert_eq!(path_m.parent(), None);
    }
}