use crate::utf8::CharEncodeUtf8;
pub struct Contains<'a, P>(pub &'a str, pub P);
impl Contains<'_, &str> {
pub const fn const_eval(&self) -> bool {
crate::str::contains(self.0, self.1)
}
}
impl Contains<'_, char> {
pub const fn const_eval(&self) -> bool {
let haystack = self.0;
let ch = CharEncodeUtf8::new(self.1);
let needle = ch.as_str();
crate::str::contains(haystack, needle)
}
}
#[macro_export]
macro_rules! contains {
($haystack: expr, $pattern: expr) => {{
$crate::__ctfe::Contains($haystack, $pattern).const_eval()
}};
}
pub struct StartsWith<'a, P>(pub &'a str, pub P);
impl StartsWith<'_, &str> {
pub const fn const_eval(&self) -> bool {
crate::str::starts_with(self.0, self.1)
}
}
impl StartsWith<'_, char> {
pub const fn const_eval(&self) -> bool {
let haystack = self.0.as_bytes();
let ch = CharEncodeUtf8::new(self.1);
let needle = ch.as_bytes();
crate::bytes::starts_with(haystack, needle)
}
}
#[macro_export]
macro_rules! starts_with {
($haystack: expr, $pattern: expr) => {{
$crate::__ctfe::StartsWith($haystack, $pattern).const_eval()
}};
}
pub struct EndsWith<'a, P>(pub &'a str, pub P);
impl EndsWith<'_, &str> {
pub const fn const_eval(&self) -> bool {
crate::str::ends_with(self.0, self.1)
}
}
impl EndsWith<'_, char> {
pub const fn const_eval(&self) -> bool {
let haystack = self.0.as_bytes();
let ch = CharEncodeUtf8::new(self.1);
let needle = ch.as_bytes();
crate::bytes::ends_with(haystack, needle)
}
}
#[macro_export]
macro_rules! ends_with {
($haystack: expr, $pattern: expr) => {{
$crate::__ctfe::EndsWith($haystack, $pattern).const_eval()
}};
}
pub struct StripPrefix<'a, P>(pub &'a str, pub P);
impl<'a> StripPrefix<'a, &str> {
pub const fn const_eval(&self) -> Option<&'a str> {
crate::str::strip_prefix(self.0, self.1)
}
}
pub struct StripSuffix<'a, P>(pub &'a str, pub P);
impl<'a> StripSuffix<'a, &str> {
pub const fn const_eval(&self) -> Option<&'a str> {
crate::str::strip_suffix(self.0, self.1)
}
}
#[macro_export]
macro_rules! strip_prefix {
($s: expr, $prefix: expr) => {{
$crate::__ctfe::StripPrefix($s, $prefix).const_eval()
}};
}
#[macro_export]
macro_rules! strip_suffix {
($s: expr, $suffix: expr) => {{
$crate::__ctfe::StripSuffix($s, $suffix).const_eval()
}};
}
#[cfg(test)]
mod tests {
use crate::unwrap;
#[test]
fn test_contains() {
const BANANAS: &str = "bananas";
const A: bool = contains!(BANANAS, "nana");
const B: bool = contains!(BANANAS, "apples");
const C: bool = contains!(BANANAS, 'c');
const D: bool = contains!(BANANAS, 'a');
assert_eq!([A, B, C, D], [true, false, false, true]);
let f = contains!("hello", "");
assert!(f);
}
#[test]
fn test_starts_with() {
const BANANAS: &str = "bananas";
const A: bool = starts_with!(BANANAS, "bana");
const B: bool = starts_with!(BANANAS, "nana");
const C: bool = starts_with!(BANANAS, 'b');
const D: bool = starts_with!(BANANAS, 'n');
assert_eq!([A, B, C, D], [true, false, true, false]);
let f = starts_with!("hello", "");
assert!(f);
}
#[test]
fn test_ends_with() {
const BANANAS: &str = "bananas";
const A: bool = ends_with!(BANANAS, "anas");
const B: bool = ends_with!(BANANAS, "nana");
const C: bool = ends_with!(BANANAS, 's');
const D: bool = ends_with!(BANANAS, 'b');
assert_eq!([A, B, C, D], [true, false, true, false]);
let f = ends_with!("hello", "");
assert!(f);
}
#[test]
fn test_strip_prefix() {
const R1: Option<&str> = strip_prefix!("foo:bar", "foo:");
const R2: Option<&str> = strip_prefix!("foo:bar", "bar");
const R3: Option<&str> = strip_prefix!("foofoo", "foo");
const R4: Option<&str> = strip_prefix!("", "");
assert_eq!(R1, Some("bar"));
assert_eq!(R2, None);
assert_eq!(R3, Some("foo"));
assert_eq!(R4, Some(""));
const FOO_BAR: &str = "foo:bar";
const BAR: &str = unwrap!(strip_prefix!(FOO_BAR, "foo:"));
assert_eq!(BAR, "bar");
}
#[test]
fn test_strip_suffix() {
const R1: Option<&str> = strip_suffix!("bar:foo", ":foo");
const R2: Option<&str> = strip_suffix!("bar:foo", "bar");
const R3: Option<&str> = strip_suffix!("foofoo", "foo");
const R4: Option<&str> = strip_suffix!("", "");
assert_eq!(R1, Some("bar"));
assert_eq!(R2, None);
assert_eq!(R3, Some("foo"));
assert_eq!(R4, Some(""));
const FOO_BAR: &str = "foo:bar";
const FOO: &str = unwrap!(strip_suffix!(FOO_BAR, ":bar"));
assert_eq!(FOO, "foo");
}
#[test]
fn test_find_runtime() {
use super::*;
let contains1 = Contains("hello world", "world");
assert!(contains1.const_eval());
let contains2 = Contains("hello", "x");
assert!(!contains2.const_eval());
let starts1 = StartsWith("hello", "he");
assert!(starts1.const_eval());
let starts2 = StartsWith("hello", "lo");
assert!(!starts2.const_eval());
let ends1 = EndsWith("hello", "lo");
assert!(ends1.const_eval());
let ends2 = EndsWith("hello", "he");
assert!(!ends2.const_eval());
let strip_pre = StripPrefix("hello world", "hello ");
let result = strip_pre.const_eval();
assert_eq!(result, Some("world"));
let strip_pre_none = StripPrefix("hello", "world");
let result_none = strip_pre_none.const_eval();
assert_eq!(result_none, None);
let strip_suf = StripSuffix("hello world", " world");
let result_suf = strip_suf.const_eval();
assert_eq!(result_suf, Some("hello"));
let strip_suf_none = StripSuffix("hello", "world");
let result_suf_none = strip_suf_none.const_eval();
assert_eq!(result_suf_none, None);
let contains_char = Contains("hello", 'e');
assert!(contains_char.const_eval());
let contains_char_none = Contains("hello", 'x');
assert!(!contains_char_none.const_eval());
let starts_char = StartsWith("hello", 'h');
assert!(starts_char.const_eval());
let starts_char_false = StartsWith("hello", 'e');
assert!(!starts_char_false.const_eval());
let ends_char = EndsWith("hello", 'o');
assert!(ends_char.const_eval());
let ends_char_false = EndsWith("hello", 'h');
assert!(!ends_char_false.const_eval());
}
}