Skip to content

Commit

Permalink
Add internal impl_fn_for_zst macro for "named closure types"
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonSapin committed Feb 12, 2019
1 parent 75f9159 commit 92dcae4
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 113 deletions.
1 change: 1 addition & 0 deletions src/libcore/lib.rs
Expand Up @@ -95,6 +95,7 @@
#![feature(simd_ffi)]
#![feature(specialization)]
#![feature(staged_api)]
#![feature(std_internals)]
#![feature(stmt_expr_attributes)]
#![feature(unboxed_closures)]
#![feature(unsized_locals)]
Expand Down
46 changes: 46 additions & 0 deletions src/libcore/macros.rs
Expand Up @@ -749,3 +749,49 @@ mod builtin {
($cond:expr, $($arg:tt)+) => ({ /* compiler built-in */ });
}
}

/// Create a named zero-size type similar to a closure.
#[doc(hidden)]
#[macro_export]
#[unstable(feature = "std_internals", issue = "0")]
macro_rules! impl_fn_for_zst {
($(
$( #[$attr: meta] )*
// FIXME: when libcore is in the 2018 edition, use `?` repetition in
// $( <$( $li : lifetime ),+> )?
struct $Name: ident impl$( <$( $lifetime : lifetime ),+> )* Fn =
|$( $arg: ident: $ArgTy: ty ),*| -> $ReturnTy: ty
$body: block;
)+) => {
$(
$( #[$attr] )*
struct $Name;

impl $( <$( $lifetime ),+> )* Fn<($( $ArgTy, )*)> for $Name {
#[inline]
extern "rust-call" fn call(&self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
$body
}
}

impl $( <$( $lifetime ),+> )* FnMut<($( $ArgTy, )*)> for $Name {
#[inline]
extern "rust-call" fn call_mut(
&mut self,
($( $arg, )*): ($( $ArgTy, )*)
) -> $ReturnTy {
Fn::call(&*self, ($( $arg, )*))
}
}

impl $( <$( $lifetime ),+> )* FnOnce<($( $ArgTy, )*)> for $Name {
type Output = $ReturnTy;

#[inline]
extern "rust-call" fn call_once(self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
Fn::call(&self, ($( $arg, )*))
}
}
)+
}
}
141 changes: 28 additions & 113 deletions src/libcore/str/mod.rs
Expand Up @@ -1345,33 +1345,14 @@ impl FusedIterator for Lines<'_> {}
#[allow(deprecated)]
pub struct LinesAny<'a>(Lines<'a>);

/// A nameable, cloneable fn type
#[derive(Clone)]
struct LinesAnyMap;

impl<'a> Fn<(&'a str,)> for LinesAnyMap {
#[inline]
extern "rust-call" fn call(&self, (line,): (&'a str,)) -> &'a str {
impl_fn_for_zst! {
/// A nameable, cloneable fn type
#[derive(Clone)]
struct LinesAnyMap impl<'a> Fn = |line: &'a str| -> &'a str {
let l = line.len();
if l > 0 && line.as_bytes()[l - 1] == b'\r' { &line[0 .. l - 1] }
else { line }
}
}

impl<'a> FnMut<(&'a str,)> for LinesAnyMap {
#[inline]
extern "rust-call" fn call_mut(&mut self, (line,): (&'a str,)) -> &'a str {
Fn::call(&*self, (line,))
}
}

impl<'a> FnOnce<(&'a str,)> for LinesAnyMap {
type Output = &'a str;

#[inline]
extern "rust-call" fn call_once(self, (line,): (&'a str,)) -> &'a str {
Fn::call(&self, (line,))
}
};
}

#[stable(feature = "rust1", since = "1.0.0")]
Expand Down Expand Up @@ -2727,7 +2708,7 @@ impl str {
let inner = self
.as_bytes()
.split(IsAsciiWhitespace)
.filter(IsNotEmpty)
.filter(BytesIsNotEmpty)
.map(UnsafeBytesToStr);
SplitAsciiWhitespace { inner }
}
Expand Down Expand Up @@ -4011,102 +3992,36 @@ pub struct SplitWhitespace<'a> {
#[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
#[derive(Clone, Debug)]
pub struct SplitAsciiWhitespace<'a> {
inner: Map<Filter<SliceSplit<'a, u8, IsAsciiWhitespace>, IsNotEmpty>, UnsafeBytesToStr>,
}

#[derive(Clone)]
struct IsWhitespace;

impl FnOnce<(char, )> for IsWhitespace {
type Output = bool;

#[inline]
extern "rust-call" fn call_once(mut self, arg: (char, )) -> bool {
self.call_mut(arg)
}
inner: Map<Filter<SliceSplit<'a, u8, IsAsciiWhitespace>, BytesIsNotEmpty>, UnsafeBytesToStr>,
}

impl FnMut<(char, )> for IsWhitespace {
#[inline]
extern "rust-call" fn call_mut(&mut self, arg: (char, )) -> bool {
arg.0.is_whitespace()
}
}

#[derive(Clone)]
struct IsAsciiWhitespace;

impl<'a> FnOnce<(&'a u8, )> for IsAsciiWhitespace {
type Output = bool;

#[inline]
extern "rust-call" fn call_once(mut self, arg: (&u8, )) -> bool {
self.call_mut(arg)
}
}

impl<'a> FnMut<(&'a u8, )> for IsAsciiWhitespace {
#[inline]
extern "rust-call" fn call_mut(&mut self, arg: (&u8, )) -> bool {
arg.0.is_ascii_whitespace()
}
}

#[derive(Clone)]
struct IsNotEmpty;

impl<'a, 'b> FnOnce<(&'a &'b str, )> for IsNotEmpty {
type Output = bool;

#[inline]
extern "rust-call" fn call_once(mut self, arg: (&'a &'b str, )) -> bool {
self.call_mut(arg)
}
}

impl<'a, 'b> FnMut<(&'a &'b str, )> for IsNotEmpty {
#[inline]
extern "rust-call" fn call_mut(&mut self, arg: (&'a &'b str, )) -> bool {
!arg.0.is_empty()
}
}

impl<'a, 'b> FnOnce<(&'a &'b [u8], )> for IsNotEmpty {
type Output = bool;

#[inline]
extern "rust-call" fn call_once(mut self, arg: (&'a &'b [u8], )) -> bool {
self.call_mut(arg)
}
}

impl<'a, 'b> FnMut<(&'a &'b [u8], )> for IsNotEmpty {
#[inline]
extern "rust-call" fn call_mut(&mut self, arg: (&'a &'b [u8], )) -> bool {
!arg.0.is_empty()
}
}
impl_fn_for_zst! {
#[derive(Clone)]
struct IsWhitespace impl Fn = |c: char| -> bool {
c.is_whitespace()
};

#[derive(Clone)]
struct UnsafeBytesToStr;
#[derive(Clone)]
struct IsAsciiWhitespace impl Fn = |byte: &u8| -> bool {
byte.is_ascii_whitespace()
};

impl<'a> FnOnce<(&'a [u8], )> for UnsafeBytesToStr {
type Output = &'a str;
#[derive(Clone)]
struct IsNotEmpty impl<'a, 'b> Fn = |s: &'a &'b str| -> bool {
!s.is_empty()
};

#[inline]
extern "rust-call" fn call_once(mut self, arg: (&'a [u8], )) -> &'a str {
self.call_mut(arg)
}
}
#[derive(Clone)]
struct BytesIsNotEmpty impl<'a, 'b> Fn = |s: &'a &'b [u8]| -> bool {
!s.is_empty()
};

impl<'a> FnMut<(&'a [u8], )> for UnsafeBytesToStr {
#[inline]
extern "rust-call" fn call_mut(&mut self, arg: (&'a [u8], )) -> &'a str {
unsafe { from_utf8_unchecked(arg.0) }
}
#[derive(Clone)]
struct UnsafeBytesToStr impl<'a> Fn = |bytes: &'a [u8]| -> &'a str {
unsafe { from_utf8_unchecked(bytes) }
};
}


#[stable(feature = "split_whitespace", since = "1.1.0")]
impl<'a> Iterator for SplitWhitespace<'a> {
type Item = &'a str;
Expand Down

0 comments on commit 92dcae4

Please sign in to comment.