use std::str::Chars;
pub fn to_url_safe(input:impl AsRef<str>) -> String {
ToUrlSafeIter::new(input.as_ref().chars()).collect()
}
pub fn from_url_safe(input:impl AsRef<str>) -> String {
FromUrlSafeIter::new(input.as_ref().chars()).collect()
}
pub struct ToUrlSafeIter<'a> {
pub chars: Chars<'a>,
}
impl<'a> ToUrlSafeIter<'a> {
pub fn new(chars:Chars<'a>) -> Self{
return ToUrlSafeIter {
chars,
};
}
}
impl<'a> Iterator for ToUrlSafeIter<'a> {
type Item = char;
fn next(&mut self) -> Option<char> {
match self.chars.next(){
None => None,
Some(ch) if ch == '+' => Some('-'),
Some(ch) if ch == '/' => Some('_'),
Some(ch) if ch == '=' => None,
ch => ch,
}
}
}
pub struct FromUrlSafeIter<'a> {
pub chars: Chars<'a>,
count:usize
}
impl<'a> FromUrlSafeIter<'a> {
pub fn new(chars:Chars<'a>) -> Self{
return FromUrlSafeIter {
chars,
count:0
};
}
}
impl<'a> Iterator for FromUrlSafeIter<'a> {
type Item = char;
fn next(&mut self) -> Option<char> {
let result= match self.chars.next(){
None if self.count % 4 > 0 => Some('='),
None => return None,
Some(ch) if ch == '-' => Some('+'),
Some(ch) if ch == '_' => Some('/'),
ch => ch,
};
self.count += 1;
result
}
}
#[cfg(test)]
mod tests {
use crate::{base64_url_safe, base64_url_unsafe};
use super::*;
#[test]
fn test_to_url_safe() {
assert_eq!(to_url_safe(r###"1234++/+//abc==="###), r###"1234--_-__abc"###)
}
#[test]
fn test_from_url_safe() {
assert_eq!(from_url_safe(r###"1234--_-__abc"###), r###"1234++/+//abc==="###)
}
#[test]
fn test_base64_url_unsafe_macro() {
let message = base64_url_unsafe!(r###"1234--_-__abc"###);
assert_eq!(message, r###"1234++/+//abc==="###);
}
#[test]
fn test_base64_url_safe_macro() {
let message = base64_url_safe!(r###"1234++/+//abc==="###);
assert_eq!(message, r###"1234--_-__abc"###);
}
}