Skip to main content

base64_const/
url_safe_util.rs

1use 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}