aboutsummaryrefslogtreecommitdiff
path: root/src/passwordmaker/base_conversion/mod.rs
blob: bb3fbd6c32db93d591c6c0a61ad8fa2efa8321b2 (plain) (blame)
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
use std::convert::TryInto;
use iterative_conversion_impl::PadWithAZero;
pub(super) use iterative_conversion::IterativeBaseConversion;
pub(super) use iterative_conversion_impl::{SixteenBytes, ArbitraryBytes};

use self::iterative_conversion::ConstantMaxPotencyCache;

mod iterative_conversion;
mod iterative_conversion_impl;

/// Converts an input to a different base (which fits in usize). Returns the digits starting at the most significant one.
pub(super) trait BaseConversion {
    type Output : ExactSizeIterator<Item=usize>;
    fn convert_to_base(self, base : usize) -> Self::Output;
}

impl<T, const N : usize, const M : usize> BaseConversion for T 
    where T : ToArbitraryBytes<Output = ArbitraryBytes<N>>,
        for<'a> T::Output: From<&'a usize> + From<&'a u32> + PadWithAZero<Output = ArbitraryBytes<M>> + ConstantMaxPotencyCache<usize>,
{
    type Output = IterativeBaseConversion<ArbitraryBytes<N>, usize>;
    fn convert_to_base(self, base : usize) -> Self::Output {
        IterativeBaseConversion::new(self.to_arbitrary_bytes(), base)
    }
}

impl BaseConversion for [u8;16]{
    type Output = IterativeBaseConversion<SixteenBytes,usize>;
    fn convert_to_base(self, base : usize) -> IterativeBaseConversion<SixteenBytes,usize> {
        IterativeBaseConversion::new(SixteenBytes::new(u128::from_be_bytes(self)), base)
    }
}



// Rust 1.52 only has a very limited support for const generics. This means, we'll have to live with this not-too-constrained solution...
pub(super) trait ToArbitraryBytes {
    type Output;
    fn to_arbitrary_bytes(self) -> Self::Output;
}

//this could of course be done in a generic manner, but it's ugly without array_mut, which we don't have in Rust 1.52.
//Soo, pedestrian's approach :D 
impl ToArbitraryBytes for [u8;20] {
    type Output = ArbitraryBytes<5>;
    fn to_arbitrary_bytes(self) -> ArbitraryBytes<5> {
        ArbitraryBytes::new([
            u32::from_be_bytes(self[0..4].try_into().unwrap()),
            u32::from_be_bytes(self[4..8].try_into().unwrap()),
            u32::from_be_bytes(self[8..12].try_into().unwrap()),
            u32::from_be_bytes(self[12..16].try_into().unwrap()),
            u32::from_be_bytes(self[16..20].try_into().unwrap()),
        ])
    }
}

impl ToArbitraryBytes for [u8;32] {
    type Output = ArbitraryBytes<8>;
    fn to_arbitrary_bytes(self) -> ArbitraryBytes<8> {
        ArbitraryBytes::new([
            u32::from_be_bytes(self[0..4].try_into().unwrap()),
            u32::from_be_bytes(self[4..8].try_into().unwrap()),
            u32::from_be_bytes(self[8..12].try_into().unwrap()),
            u32::from_be_bytes(self[12..16].try_into().unwrap()),
            u32::from_be_bytes(self[16..20].try_into().unwrap()),
            u32::from_be_bytes(self[20..24].try_into().unwrap()),
            u32::from_be_bytes(self[24..28].try_into().unwrap()),
            u32::from_be_bytes(self[28..32].try_into().unwrap()),
        ])
    }
}