Coverage Report

Created: 2025-11-11 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/base64ct-1.8.0/src/alphabet.rs
Line
Count
Source
1
//! Base64 alphabets.
2
3
// TODO(tarcieri): explicitly checked/wrapped arithmetic
4
#![allow(clippy::arithmetic_side_effects)]
5
6
use core::{fmt::Debug, ops::RangeInclusive};
7
8
pub mod bcrypt;
9
pub mod crypt;
10
pub mod shacrypt;
11
pub mod standard;
12
pub mod url;
13
14
/// Core encoder/decoder functions for a particular Base64 alphabet.
15
pub trait Alphabet: 'static + Copy + Debug + Eq + Send + Sized + Sync {
16
    /// First character in this Base64 alphabet.
17
    const BASE: u8;
18
19
    /// Decoder passes
20
    const DECODER: &'static [DecodeStep];
21
22
    /// Encoder passes
23
    const ENCODER: &'static [EncodeStep];
24
25
    /// Is this encoding padded?
26
    const PADDED: bool;
27
28
    /// Unpadded equivalent of this alphabet.
29
    ///
30
    /// For alphabets that are unpadded to begin with, this should be `Self`.
31
    type Unpadded: Alphabet;
32
33
    /// Decode 3 bytes of a Base64 message.
34
    #[inline(always)]
35
0
    fn decode_3bytes(src: &[u8], dst: &mut [u8]) -> i16 {
36
0
        debug_assert_eq!(src.len(), 4);
37
0
        debug_assert!(dst.len() >= 3, "dst too short: {}", dst.len());
38
39
0
        let c0 = Self::decode_6bits(src[0]);
40
0
        let c1 = Self::decode_6bits(src[1]);
41
0
        let c2 = Self::decode_6bits(src[2]);
42
0
        let c3 = Self::decode_6bits(src[3]);
43
44
0
        dst[0] = ((c0 << 2) | (c1 >> 4)) as u8;
45
0
        dst[1] = ((c1 << 4) | (c2 >> 2)) as u8;
46
0
        dst[2] = ((c2 << 6) | c3) as u8;
47
48
0
        ((c0 | c1 | c2 | c3) >> 8) & 1
49
0
    }
Unexecuted instantiation: <base64ct::alphabet::crypt::Base64Crypt as base64ct::alphabet::Alphabet>::decode_3bytes
Unexecuted instantiation: <base64ct::alphabet::bcrypt::Base64Bcrypt as base64ct::alphabet::Alphabet>::decode_3bytes
Unexecuted instantiation: <base64ct::alphabet::standard::Base64Unpadded as base64ct::alphabet::Alphabet>::decode_3bytes
Unexecuted instantiation: <_ as base64ct::alphabet::Alphabet>::decode_3bytes
50
51
    /// Decode 6-bits of a Base64 message.
52
0
    fn decode_6bits(src: u8) -> i16 {
53
0
        let mut ret: i16 = -1;
54
55
0
        for step in Self::DECODER {
56
0
            ret += match step {
57
0
                DecodeStep::Range(range, offset) => {
58
                    // Compute exclusive range from inclusive one
59
0
                    let start = *range.start() as i16 - 1;
60
0
                    let end = *range.end() as i16 + 1;
61
0
                    (((start - src as i16) & (src as i16 - end)) >> 8) & (src as i16 + *offset)
62
                }
63
0
                DecodeStep::Eq(value, offset) => {
64
0
                    let start = *value as i16 - 1;
65
0
                    let end = *value as i16 + 1;
66
0
                    (((start - src as i16) & (src as i16 - end)) >> 8) & *offset
67
                }
68
            };
69
        }
70
71
0
        ret
72
0
    }
Unexecuted instantiation: <base64ct::alphabet::crypt::Base64Crypt as base64ct::alphabet::Alphabet>::decode_6bits
Unexecuted instantiation: <base64ct::alphabet::bcrypt::Base64Bcrypt as base64ct::alphabet::Alphabet>::decode_6bits
Unexecuted instantiation: <base64ct::alphabet::standard::Base64Unpadded as base64ct::alphabet::Alphabet>::decode_6bits
Unexecuted instantiation: <_ as base64ct::alphabet::Alphabet>::decode_6bits
73
74
    /// Encode 3-bytes of a Base64 message.
75
    #[inline(always)]
76
0
    fn encode_3bytes(src: &[u8], dst: &mut [u8]) {
77
0
        debug_assert_eq!(src.len(), 3);
78
0
        debug_assert!(dst.len() >= 4, "dst too short: {}", dst.len());
79
80
0
        let b0 = src[0] as i16;
81
0
        let b1 = src[1] as i16;
82
0
        let b2 = src[2] as i16;
83
84
0
        dst[0] = Self::encode_6bits(b0 >> 2);
85
0
        dst[1] = Self::encode_6bits(((b0 << 4) | (b1 >> 4)) & 63);
86
0
        dst[2] = Self::encode_6bits(((b1 << 2) | (b2 >> 6)) & 63);
87
0
        dst[3] = Self::encode_6bits(b2 & 63);
88
0
    }
Unexecuted instantiation: <base64ct::alphabet::crypt::Base64Crypt as base64ct::alphabet::Alphabet>::encode_3bytes
Unexecuted instantiation: <base64ct::alphabet::bcrypt::Base64Bcrypt as base64ct::alphabet::Alphabet>::encode_3bytes
Unexecuted instantiation: <base64ct::alphabet::standard::Base64Unpadded as base64ct::alphabet::Alphabet>::encode_3bytes
Unexecuted instantiation: <_ as base64ct::alphabet::Alphabet>::encode_3bytes
89
90
    /// Encode 6-bits of a Base64 message.
91
    #[inline(always)]
92
0
    fn encode_6bits(src: i16) -> u8 {
93
0
        let mut diff = src + Self::BASE as i16;
94
95
0
        for &step in Self::ENCODER {
96
0
            diff += match step {
97
0
                EncodeStep::Apply(threshold, offset) => ((threshold as i16 - diff) >> 8) & offset,
98
0
                EncodeStep::Diff(threshold, offset) => ((threshold as i16 - src) >> 8) & offset,
99
            };
100
        }
101
102
0
        diff as u8
103
0
    }
Unexecuted instantiation: <base64ct::alphabet::crypt::Base64Crypt as base64ct::alphabet::Alphabet>::encode_6bits
Unexecuted instantiation: <base64ct::alphabet::bcrypt::Base64Bcrypt as base64ct::alphabet::Alphabet>::encode_6bits
Unexecuted instantiation: <base64ct::alphabet::standard::Base64Unpadded as base64ct::alphabet::Alphabet>::encode_6bits
Unexecuted instantiation: <_ as base64ct::alphabet::Alphabet>::encode_6bits
104
}
105
106
/// Constant-time decoder step.
107
#[derive(Debug)]
108
pub enum DecodeStep {
109
    /// Match the given range, offsetting the input on match.
110
    Range(RangeInclusive<u8>, i16),
111
112
    /// Match the given value, returning the associated offset on match.
113
    Eq(u8, i16),
114
}
115
116
/// Constant-time encoder step.
117
#[derive(Copy, Clone, Debug)]
118
pub enum EncodeStep {
119
    /// Apply the given offset to the cumulative result on match.
120
    Apply(u8, i16),
121
122
    /// Compute a difference using the given offset on match.
123
    Diff(u8, i16),
124
}