pkce_std/encoding.rs
1//! Encoding functionality.
2//!
3//! This module provides functions to encode data to Base64.
4//!
5//! There are also [`try_length`] and [`length`] functions to calculate the
6//! length of the encoded data.
7//!
8//! # Examples
9//!
10//! ```
11//! use pkce_std::encoding::{encode, length};
12//!
13//! let data = "Hello, world!";
14//!
15//! let encoded = encode(data);
16//!
17//! assert_eq!(encoded.len(), length(data.len()));
18//! ```
19
20use base64::engine::{general_purpose::URL_SAFE_NO_PAD, Engine};
21
22/// Encodes given data into Base64.
23///
24/// This function uses the URL-safe and no-padding variant of Base64.
25///
26/// # Examples
27///
28/// ```
29/// use pkce_std::encoding::encode;
30///
31/// let data = "Hello, world!";
32///
33/// assert_eq!(encode(data), "SGVsbG8sIHdvcmxkIQ");
34/// ```
35pub fn encode<D: AsRef<[u8]>>(data: D) -> String {
36 URL_SAFE_NO_PAD.encode(data)
37}
38
39/// Computes the length of the Base64 encoded data from the given length.
40///
41/// # Examples
42///
43/// ```
44/// use pkce_std::encoding::try_length;
45///
46/// assert_eq!(try_length(32), Some(43));
47///
48/// assert_eq!(try_length(usize::MAX), None);
49/// ```
50pub const fn try_length(bytes: usize) -> Option<usize> {
51 let remainder = bytes % 3;
52 let chunks = bytes / 3;
53
54 let Some(length) = chunks.checked_mul(4) else {
55 return None;
56 };
57
58 if remainder == 0 {
59 Some(length)
60 } else {
61 length.checked_add(remainder + 1)
62 }
63}
64
65/// The `overflow` literal.
66pub const OVERFLOW: &str = "overflow";
67
68/// Calls [`try_length`] and panics if the result is [`None`].
69///
70/// The only reason for this function to panic is an overflow.
71///
72/// # Panics
73///
74/// This function panics if the result of [`try_length`] is [`None`].
75///
76/// # Examples
77///
78/// Regular usage:
79///
80/// ```
81/// use pkce_std::encoding::length;
82///
83/// assert_eq!(length(96), 128);
84/// ```
85///
86/// Overflow:
87///
88/// ```should_panic
89/// use pkce_std::encoding::length;
90///
91/// length(usize::MAX);
92/// ```
93pub const fn length(bytes: usize) -> usize {
94 try_length(bytes).expect(OVERFLOW)
95}