use base64::engine::general_purpose::URL_SAFE_NO_PAD as Base64Engine;
use base64::engine::Engine as _;
#[derive(Copy, Clone, Debug)]
pub struct Uri<'a> {
pub original: &'a str,
pub scheme: Scheme,
pub scheme_name: Option<&'a str>,
pub after_scheme: &'a str,
pub data_type: Option<&'a str>,
pub data: Option<&'a str>,
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Scheme {
File,
Data,
None,
Other,
}
pub fn parse_uri(source: &str) -> Uri {
let (scheme_name, after_scheme): (Option<&str>, &str) = {
let mut scheme_it = source.splitn(2, ':');
let first = scheme_it.next();
let second = scheme_it.next();
if let Some(rest) = second {
(first, rest)
} else {
(None, first.unwrap())
}
};
if scheme_name == Some("data") {
let mut it = after_scheme.splitn(2, ',');
Uri {
original: source,
scheme: Scheme::Data,
scheme_name,
after_scheme,
data_type: it.next(),
data: it.next(),
}
} else if let Some(name) = scheme_name {
let scheme = match name {
"file" => Scheme::File,
_ => Scheme::Other,
};
Uri {
original: source,
scheme,
scheme_name,
after_scheme,
data_type: None,
data: None,
}
} else {
Uri {
original: source,
scheme: Scheme::None,
scheme_name,
after_scheme,
data_type: None,
data: None,
}
}
}
pub fn decode_base64(source: &str) -> Result<Vec<u8>, base64::DecodeError> {
Base64Engine.decode(source)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn split() {
let r: Vec<_> = "abc:def".splitn(2, ':').collect();
assert!(r == vec!["abc", "def"], "{r:?}");
}
#[test]
fn simple() {
let u: Uri = parse_uri("Random stuff");
assert!(
matches!(
u,
Uri {
original: "Random stuff",
scheme: Scheme::None,
scheme_name: None,
after_scheme: "Random stuff",
data_type: None,
data: None,
}
),
"{u:?}"
)
}
#[test]
fn file() {
let u: Uri = parse_uri("file:filename.test");
assert!(
matches!(
u,
Uri {
original: "file:filename.test",
scheme: Scheme::File,
scheme_name: Some("file"),
after_scheme: "filename.test",
data_type: None,
data: None,
}
),
"{u:?}"
)
}
#[test]
fn other() {
let u: Uri = parse_uri("what:Stuff");
assert!(
matches!(
u,
Uri {
original: "what:Stuff",
scheme: Scheme::Other,
scheme_name: Some("what"),
after_scheme: "Stuff",
data_type: None,
data: None,
}
),
"{u:?}"
)
}
#[test]
fn data() {
let u: Uri = parse_uri("data:type,ABCDEFG");
assert!(
matches!(
u,
Uri {
original: "data:type,ABCDEFG",
scheme: Scheme::Data,
scheme_name: Some("data"),
after_scheme: "type,ABCDEFG",
data_type: Some("type"),
data: Some("ABCDEFG"),
}
),
"{u:?}"
)
}
}