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
#![deny(missing_docs, missing_debug_implementations)]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(feature = "unsize", feature(fixed_size_array))]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(all(feature = "base32", any(feature = "std", feature = "alloc")))]
pub(crate) const B32A: base32::Alphabet =
base32::Alphabet::RFC4648 { padding: false };
#[cfg(not(feature = "only-gauth"))]
pub(crate) mod alg;
#[cfg(not(feature = "only-gauth"))]
pub use alg::*;
mod array;
pub use array::Array;
mod hotp;
pub use hotp::HOTP;
mod totp;
pub use totp::TOTP;
#[cfg(all(feature = "base32", any(feature = "alloc", feature = "std")))]
mod err {
#[cfg(feature = "cstr")]
use std::str::Utf8Error;
#[derive(Debug)]
pub enum Error {
#[cfg(feature = "cstr")]
Utf8(Utf8Error),
BadEnc,
}
impl core::fmt::Display for Error {
fn fmt(
&self,
f: &mut core::fmt::Formatter,
) -> core::fmt::Result {
match self {
#[cfg(feature = "cstr")]
Self::Utf8(ref e) => core::fmt::Display::fmt(e, f),
Self::BadEnc => f.write_str("Bad base32 encoding"),
}
}
}
#[cfg(feature = "cstr")]
impl From<Utf8Error> for Error {
fn from(e: Utf8Error) -> Self {
Self::Utf8(e)
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {}
}
#[cfg(all(feature = "base32", any(feature = "alloc", feature = "std")))]
pub use err::Error;
#[cfg(all(feature = "base32", any(feature = "alloc", feature = "std")))]
mod segs {
#[cfg(feature = "alloc")]
use alloc::string::String;
use core::cmp::min;
#[derive(Debug)]
pub struct Segs {
pub(crate) sec: String,
pub(crate) chunk_size: usize,
pub(crate) curr: usize,
}
impl Iterator for Segs {
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
if self.curr >= self.sec.len() {
None
} else {
let (off, ()) = (self.curr, self.curr += self.chunk_size);
let end = min(self.curr, self.sec.len());
let next = self.sec.get(off..end)?;
Some(next.into())
}
}
}
impl Segs {
pub fn join<S: AsRef<str>>(
self,
sep: S,
) -> String {
let s = sep.as_ref();
let cap =
self.sec.len() + s.len() * (self.sec.len() / self.chunk_size) + 1;
let mut first = true;
self.fold(String::with_capacity(cap), |mut acc, seg| {
if first {
first = false;
} else {
acc.push_str(s);
}
acc.push_str(&seg);
acc
})
}
}
}
#[cfg(all(feature = "base32", any(feature = "alloc", feature = "std")))]
pub use segs::Segs;