Skip to content

Commit e7fe1a2

Browse files
committed
std: add predicate pattern support to OsStr
Due to technical limitations adding support for predicate as patterns on OsStr slices must be done via core::pattern::Predicate wrapper type. This isn’t ideal but for the time being it’s the best option I’ve came up with. The core of the issue (as I understand it) is that FnMut is a foreign type in std crate where OsStr is defined. Using predicate as a pattern on OsStr is the final piece which now allows parsing command line arguments.
1 parent 237606c commit e7fe1a2

File tree

2 files changed

+136
-1
lines changed

2 files changed

+136
-1
lines changed

library/std/src/ffi/os_str.rs

+98
Original file line numberDiff line numberDiff line change
@@ -1731,6 +1731,104 @@ unsafe impl<'hs> ReverseSearcher<&'hs OsStr> for CharSearcher<'hs> {
17311731
#[unstable(feature = "pattern", issue = "27721")]
17321732
impl<'hs> DoubleEndedSearcher<&'hs OsStr> for CharSearcher<'hs> {}
17331733

1734+
#[unstable(feature = "pattern", issue = "27721")]
1735+
// FIXME: Using Predicate because of:
1736+
// error[E0210]: type parameter `F` must be covered by another type when it
1737+
// appears before the first local type (`OsStr`)
1738+
// --> library/std/src/ffi/os_str.rs:1697:11
1739+
// |
1740+
// 1697 | impl<'hs, F: FnMut(char) -> bool> core::pattern::Pattern<&'hs OsStr> for F {
1741+
// | ^ type parameter `F` must be covered by another type
1742+
// when it appears before the first local type (`OsStr`)
1743+
impl<'hs, F: FnMut(char) -> bool> core::pattern::Pattern<&'hs OsStr>
1744+
for core::pattern::Predicate<F>
1745+
{
1746+
type Searcher = PredicateSearcher<'hs, F>;
1747+
1748+
fn into_searcher(self, haystack: &'hs OsStr) -> Self::Searcher {
1749+
Self::Searcher::new(haystack, self.into_fn())
1750+
}
1751+
1752+
fn is_contained_in(self, haystack: &'hs OsStr) -> bool {
1753+
self.into_fn().is_contained_in(core::str_bytes::Bytes::from(haystack))
1754+
}
1755+
1756+
fn is_prefix_of(self, haystack: &'hs OsStr) -> bool {
1757+
self.into_fn().is_prefix_of(core::str_bytes::Bytes::from(haystack))
1758+
}
1759+
1760+
fn is_suffix_of(self, haystack: &'hs OsStr) -> bool {
1761+
self.into_fn().is_suffix_of(core::str_bytes::Bytes::from(haystack))
1762+
}
1763+
1764+
/// Removes the pattern from the front of haystack, if it matches.
1765+
fn strip_prefix_of(self, haystack: &'hs OsStr) -> Option<&'hs OsStr> {
1766+
self.into_fn()
1767+
.strip_prefix_of(core::str_bytes::Bytes::from(haystack))
1768+
.map(|bytes| bytes.into())
1769+
}
1770+
1771+
/// Removes the pattern from the back of haystack, if it matches.
1772+
fn strip_suffix_of(self, haystack: &'hs OsStr) -> Option<&'hs OsStr>
1773+
where
1774+
Self::Searcher: ReverseSearcher<&'hs OsStr>,
1775+
{
1776+
self.into_fn()
1777+
.strip_suffix_of(core::str_bytes::Bytes::from(haystack))
1778+
.map(|bytes| bytes.into())
1779+
}
1780+
}
1781+
1782+
#[derive(Clone, Debug)]
1783+
#[unstable(feature = "pattern", issue = "27721")]
1784+
pub struct PredicateSearcher<'hs, P>(core::str_bytes::PredicateSearcher<'hs, BytesFlavour, P>);
1785+
1786+
impl<'hs, P> PredicateSearcher<'hs, P> {
1787+
fn new(haystack: &'hs OsStr, pred: P) -> PredicateSearcher<'hs, P> {
1788+
Self(core::str_bytes::PredicateSearcher::new(haystack.into(), pred))
1789+
}
1790+
}
1791+
1792+
#[unstable(feature = "pattern", issue = "27721")]
1793+
unsafe impl<'hs, P: FnMut(char) -> bool> Searcher<&'hs OsStr> for PredicateSearcher<'hs, P> {
1794+
#[inline(always)]
1795+
fn haystack(&self) -> &'hs OsStr {
1796+
self.0.haystack().into()
1797+
}
1798+
1799+
#[inline(always)]
1800+
fn next(&mut self) -> SearchStep {
1801+
self.0.next()
1802+
}
1803+
#[inline(always)]
1804+
fn next_match(&mut self) -> Option<(usize, usize)> {
1805+
self.0.next_match()
1806+
}
1807+
#[inline(always)]
1808+
fn next_reject(&mut self) -> Option<(usize, usize)> {
1809+
self.0.next_reject()
1810+
}
1811+
}
1812+
1813+
#[unstable(feature = "pattern", issue = "27721")]
1814+
unsafe impl<'hs, P: FnMut(char) -> bool> ReverseSearcher<&'hs OsStr> for PredicateSearcher<'hs, P> {
1815+
#[inline(always)]
1816+
fn next_back(&mut self) -> SearchStep {
1817+
self.0.next_back()
1818+
}
1819+
#[inline(always)]
1820+
fn next_match_back(&mut self) -> Option<(usize, usize)> {
1821+
self.0.next_match_back()
1822+
}
1823+
#[inline(always)]
1824+
fn next_reject_back(&mut self) -> Option<(usize, usize)> {
1825+
self.0.next_reject_back()
1826+
}
1827+
}
1828+
1829+
#[unstable(feature = "pattern", issue = "27721")]
1830+
impl<'hs, P: FnMut(char) -> bool> DoubleEndedSearcher<&'hs OsStr> for PredicateSearcher<'hs, P> {}
1831+
17341832
#[unstable(feature = "pattern", issue = "27721")]
17351833
impl<'hs, 'p> core::pattern::Pattern<&'hs OsStr> for &'p str {
17361834
type Searcher = StrSearcher<'hs, 'p>;

library/std/tests/os_str.rs

+38-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![feature(associated_type_bounds, pattern)]
22

3-
use core::pattern::{Pattern, Searcher, ReverseSearcher};
3+
use core::pattern::{Pattern, Searcher, ReverseSearcher, predicate};
44
use std::borrow::Cow;
55
use std::ffi::{OsStr, OsString};
66

@@ -111,6 +111,23 @@ fn do_test_short_flag(valid: bool) {
111111
assert_eq!(Some(&*os("shórt")), arg.strip_prefix('-'));
112112
assert_eq!(Some(&*os("shórt")), arg.strip_prefix("-"));
113113
assert_eq!(None, arg.strip_prefix("--"));
114+
115+
// A bit awkward but closure can be used to test short options character
116+
// by character.
117+
let mut switch = '\0';
118+
let mut check_switch = |chr| {
119+
switch = chr;
120+
chr == 's' || chr == 'h'
121+
};
122+
assert_eq!(
123+
Some(&*os("hórt")),
124+
os("shórt").strip_prefix(predicate(&mut check_switch))
125+
);
126+
assert_eq!(
127+
Some(&*os("órt")),
128+
os("hórt").strip_prefix(predicate(&mut check_switch))
129+
);
130+
assert_eq!(None, os("órt").strip_prefix(predicate(&mut check_switch)));
114131
}
115132

116133
#[test]
@@ -157,15 +174,21 @@ fn test_le() {
157174
#[test]
158175
fn test_find() {
159176
assert_eq!(find("hello", 'l'), Some(2));
177+
assert_eq!(find("hello", predicate(|c: char| c == 'o')), Some(4));
160178
assert!(find("hello", 'x').is_none());
179+
assert!(find("hello", predicate(|c: char| c == 'x')).is_none());
161180
assert_eq!(find("ประเทศไทย中华Việt Nam", '华'), Some(30));
181+
assert_eq!(find("ประเทศไทย中华Việt Nam", predicate(|c: char| c == '华')), Some(30));
162182
}
163183

164184
#[test]
165185
fn test_rfind() {
166186
assert_eq!(rfind("hello", 'l'), Some(3));
187+
assert_eq!(rfind("hello", predicate(|c: char| c == 'o')), Some(4));
167188
assert!(rfind("hello", 'x').is_none());
189+
assert!(rfind("hello", predicate(|c: char| c == 'x')).is_none());
168190
assert_eq!(rfind("ประเทศไทย中华Việt Nam", '华'), Some(30));
191+
assert_eq!(rfind("ประเทศไทย中华Việt Nam", predicate(|c: char| c == '华')), Some(30));
169192
}
170193

171194
/*
@@ -1832,13 +1855,27 @@ fn test_split_char_iterator() {
18321855
rsplit.reverse();
18331856
assert_eq!(rsplit, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
18341857

1858+
let split: Vec<&OsStr> = os(data).split(predicate(|c: char| c == ' ')).collect();
1859+
assert_eq!(split, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
1860+
1861+
let mut rsplit: Vec<&OsStr> = os(data).split(predicate(|c: char| c == ' ')).rev().collect();
1862+
rsplit.reverse();
1863+
assert_eq!(rsplit, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
1864+
18351865
// Unicode
18361866
let split: Vec<&OsStr> = os(data).split('ä').collect();
18371867
assert_eq!(split, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
18381868

18391869
let mut rsplit: Vec<&OsStr> = os(data).split('ä').rev().collect();
18401870
rsplit.reverse();
18411871
assert_eq!(rsplit, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
1872+
1873+
let split: Vec<&OsStr> = os(data).split(predicate(|c: char| c == 'ä')).collect();
1874+
assert_eq!(split, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
1875+
1876+
let mut rsplit: Vec<&OsStr> = os(data).split(predicate(|c: char| c == 'ä')).rev().collect();
1877+
rsplit.reverse();
1878+
assert_eq!(rsplit, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
18421879
}
18431880

18441881
#[test]

0 commit comments

Comments
 (0)