2019-09-15 08:40:45 +00:00
|
|
|
use crate::Error;
|
2020-02-10 12:21:48 +00:00
|
|
|
use core::iter;
|
2019-09-06 10:55:00 +00:00
|
|
|
|
2020-03-28 09:46:07 +00:00
|
|
|
/// This is an extension trait that adds the below method to `bool`.
|
|
|
|
/// Those methods are already planned for the standard library, but are not
|
|
|
|
/// stable at the time of writing this comment.
|
|
|
|
///
|
|
|
|
/// The current status can be seen here:
|
|
|
|
/// <https://github.com/rust-lang/rust/issues/64260>
|
|
|
|
///
|
|
|
|
/// This trait exists to allow publishing a new version (requires stable
|
|
|
|
/// release) and the functions are prefixed with an `a` to prevent naming
|
|
|
|
/// conflicts with the coming std functions.
|
|
|
|
// TODO: replace this trait with std version as soon as it is stabilized
|
|
|
|
pub(crate) trait BoolExt {
|
|
|
|
#[must_use]
|
|
|
|
fn athen_some<T>(self, t: T) -> Option<T>;
|
|
|
|
|
|
|
|
#[must_use]
|
|
|
|
fn athen<T, F: FnOnce() -> T>(self, f: F) -> Option<T>;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BoolExt for bool {
|
|
|
|
#[inline]
|
|
|
|
fn athen_some<T>(self, t: T) -> Option<T> {
|
|
|
|
if self {
|
|
|
|
Some(t)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn athen<T, F: FnOnce() -> T>(self, f: F) -> Option<T> {
|
|
|
|
if self {
|
|
|
|
Some(f())
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-05 14:24:48 +00:00
|
|
|
macro_rules! required_version {
|
|
|
|
( $( $tag:expr ),* ) => {
|
|
|
|
::core::iter::empty()
|
|
|
|
$(
|
|
|
|
.chain(::core::iter::once($tag.required_version()))
|
|
|
|
)*
|
|
|
|
.max()
|
|
|
|
.unwrap_or_default()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-15 08:40:45 +00:00
|
|
|
pub(crate) fn parse_yes_or_no<T: AsRef<str>>(s: T) -> crate::Result<bool> {
|
2019-09-08 09:30:52 +00:00
|
|
|
match s.as_ref() {
|
2019-09-06 10:55:00 +00:00
|
|
|
"YES" => Ok(true),
|
|
|
|
"NO" => Ok(false),
|
2019-09-13 14:06:52 +00:00
|
|
|
_ => Err(Error::invalid_input()),
|
2019-09-06 10:55:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-08 09:30:52 +00:00
|
|
|
/// According to the documentation the following characters are forbidden
|
|
|
|
/// inside a quoted string:
|
|
|
|
/// - carriage return (`\r`)
|
|
|
|
/// - new line (`\n`)
|
|
|
|
/// - double quotes (`"`)
|
|
|
|
///
|
|
|
|
/// Therefore it is safe to simply remove any occurence of those characters.
|
|
|
|
/// [rfc8216#section-4.2](https://tools.ietf.org/html/rfc8216#section-4.2)
|
2020-02-10 12:21:48 +00:00
|
|
|
pub(crate) fn unquote<T: AsRef<str>>(value: T) -> String {
|
2019-09-08 09:30:52 +00:00
|
|
|
value
|
2020-02-10 12:21:48 +00:00
|
|
|
.as_ref()
|
|
|
|
.chars()
|
|
|
|
.filter(|c| *c != '"' && *c != '\n' && *c != '\r')
|
|
|
|
.collect()
|
2019-09-08 09:30:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Puts a string inside quotes.
|
2020-02-10 12:21:48 +00:00
|
|
|
#[allow(clippy::needless_pass_by_value)]
|
2019-09-08 09:30:52 +00:00
|
|
|
pub(crate) fn quote<T: ToString>(value: T) -> String {
|
2019-10-03 15:01:15 +00:00
|
|
|
// the replace is for the case, that quote is called on an already quoted
|
|
|
|
// string, which could cause problems!
|
2020-02-10 12:21:48 +00:00
|
|
|
iter::once('"')
|
|
|
|
.chain(value.to_string().chars().filter(|c| *c != '"'))
|
|
|
|
.chain(iter::once('"'))
|
|
|
|
.collect()
|
2019-09-08 09:30:52 +00:00
|
|
|
}
|
|
|
|
|
2019-10-03 15:01:15 +00:00
|
|
|
/// Checks, if the given tag is at the start of the input. If this is the case,
|
|
|
|
/// it will remove it and return the rest of the input.
|
2019-09-13 14:06:52 +00:00
|
|
|
///
|
|
|
|
/// # Error
|
2020-02-06 11:28:54 +00:00
|
|
|
///
|
2019-10-03 15:01:15 +00:00
|
|
|
/// This function will return `Error::MissingTag`, if the input doesn't start
|
|
|
|
/// with the tag, that has been passed to this function.
|
2019-09-10 09:05:20 +00:00
|
|
|
pub(crate) fn tag<T>(input: &str, tag: T) -> crate::Result<&str>
|
|
|
|
where
|
|
|
|
T: AsRef<str>,
|
|
|
|
{
|
2019-09-22 16:00:38 +00:00
|
|
|
if !input.trim().starts_with(tag.as_ref()) {
|
2019-09-13 14:06:52 +00:00
|
|
|
return Err(Error::missing_tag(tag.as_ref(), input));
|
2019-09-10 09:05:20 +00:00
|
|
|
}
|
2020-02-06 11:28:54 +00:00
|
|
|
|
|
|
|
Ok(input.trim().split_at(tag.as_ref().len()).1)
|
2019-09-10 09:05:20 +00:00
|
|
|
}
|
|
|
|
|
2019-09-08 09:30:52 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
2019-10-08 13:42:33 +00:00
|
|
|
use pretty_assertions::assert_eq;
|
2019-09-08 09:30:52 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_parse_yes_or_no() {
|
|
|
|
assert!(parse_yes_or_no("YES").unwrap());
|
|
|
|
assert!(!parse_yes_or_no("NO").unwrap());
|
2019-09-22 18:33:40 +00:00
|
|
|
assert!(parse_yes_or_no("garbage").is_err());
|
2019-09-08 09:30:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_unquote() {
|
|
|
|
assert_eq!(unquote("\"TestValue\""), "TestValue".to_string());
|
|
|
|
assert_eq!(unquote("\"TestValue\n\""), "TestValue".to_string());
|
|
|
|
assert_eq!(unquote("\"TestValue\n\r\""), "TestValue".to_string());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_quote() {
|
|
|
|
assert_eq!(quote("value"), "\"value\"".to_string());
|
|
|
|
assert_eq!(quote("\"value\""), "\"value\"".to_string());
|
|
|
|
}
|
2019-09-10 09:05:20 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_tag() {
|
|
|
|
let input = "HelloMyFriendThisIsASampleString";
|
|
|
|
|
|
|
|
let input = tag(input, "Hello").unwrap();
|
|
|
|
assert_eq!(input, "MyFriendThisIsASampleString");
|
|
|
|
|
|
|
|
let input = tag(input, "My").unwrap();
|
|
|
|
assert_eq!(input, "FriendThisIsASampleString");
|
|
|
|
|
|
|
|
let input = tag(input, "FriendThisIs").unwrap();
|
|
|
|
assert_eq!(input, "ASampleString");
|
|
|
|
|
|
|
|
let input = tag(input, "A").unwrap();
|
|
|
|
assert_eq!(input, "SampleString");
|
2019-09-22 18:33:40 +00:00
|
|
|
|
|
|
|
assert!(tag(input, "B").is_err());
|
2020-02-06 11:28:54 +00:00
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
tag(
|
|
|
|
concat!(
|
|
|
|
"\n #EXTM3U\n",
|
|
|
|
" #EXT-X-TARGETDURATION:5220\n",
|
|
|
|
" #EXTINF:0,\n",
|
|
|
|
" http://media.example.com/entire1.ts\n",
|
|
|
|
" #EXTINF:5220,\n",
|
|
|
|
" http://media.example.com/entire2.ts\n",
|
|
|
|
" #EXT-X-ENDLIST"
|
|
|
|
),
|
|
|
|
"#EXTM3U"
|
|
|
|
)
|
|
|
|
.unwrap(),
|
|
|
|
concat!(
|
|
|
|
"\n",
|
|
|
|
" #EXT-X-TARGETDURATION:5220\n",
|
|
|
|
" #EXTINF:0,\n",
|
|
|
|
" http://media.example.com/entire1.ts\n",
|
|
|
|
" #EXTINF:5220,\n",
|
|
|
|
" http://media.example.com/entire2.ts\n",
|
|
|
|
" #EXT-X-ENDLIST"
|
|
|
|
)
|
|
|
|
);
|
2019-09-10 09:05:20 +00:00
|
|
|
}
|
2019-09-08 09:30:52 +00:00
|
|
|
}
|