base64_const/
url_safe_util.rs1use std::str::Chars;
2
3pub fn to_url_safe(input:impl AsRef<str>) -> String {
4 ToUrlSafeIter::new(input.as_ref().chars()).collect()
5}
6
7pub fn from_url_safe(input:impl AsRef<str>) -> String {
8 FromUrlSafeIter::new(input.as_ref().chars()).collect()
9}
10
11
12pub struct ToUrlSafeIter<'a> {
13 pub chars: Chars<'a>,
14}
15
16impl<'a> ToUrlSafeIter<'a> {
17 pub fn new(chars:Chars<'a>) -> Self{
18 return ToUrlSafeIter {
19 chars,
20 };
21 }
22}
23
24impl<'a> Iterator for ToUrlSafeIter<'a> {
25 type Item = char;
26
27 fn next(&mut self) -> Option<char> {
28 match self.chars.next(){
29 None => None,
30 Some(ch) if ch == '+' => Some('-'),
31 Some(ch) if ch == '/' => Some('_'),
32 Some(ch) if ch == '=' => None,
33 ch => ch,
34 }
35 }
36}
37
38pub struct FromUrlSafeIter<'a> {
39 pub chars: Chars<'a>,
40 count:usize
41}
42
43impl<'a> FromUrlSafeIter<'a> {
44 pub fn new(chars:Chars<'a>) -> Self{
45 return FromUrlSafeIter {
46 chars,
47 count:0
48 };
49 }
50}
51
52impl<'a> Iterator for FromUrlSafeIter<'a> {
53 type Item = char;
54
55 fn next(&mut self) -> Option<char> {
56 let result= match self.chars.next(){
57 None if self.count % 4 > 0 => Some('='),
58 None => return None,
59 Some(ch) if ch == '-' => Some('+'),
60 Some(ch) if ch == '_' => Some('/'),
61 ch => ch,
62 };
63 self.count += 1;
64 result
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use crate::{base64_url_safe, base64_url_unsafe};
71
72 use super::*;
73
74 #[test]
75 fn test_to_url_safe() {
76 assert_eq!(to_url_safe(r###"1234++/+//abc==="###), r###"1234--_-__abc"###)
77 }
78
79 #[test]
80 fn test_from_url_safe() {
81 assert_eq!(from_url_safe(r###"1234--_-__abc"###), r###"1234++/+//abc==="###)
82 }
83
84 #[test]
85 fn test_base64_url_unsafe_macro() {
86 let message = base64_url_unsafe!(r###"1234--_-__abc"###);
87 assert_eq!(message, r###"1234++/+//abc==="###);
88 }
89
90 #[test]
91 fn test_base64_url_safe_macro() {
92 let message = base64_url_safe!(r###"1234++/+//abc==="###);
93 assert_eq!(message, r###"1234--_-__abc"###);
94 }
95}