Lifetimes as single tokens from cursor
diff --git a/src/buffer.rs b/src/buffer.rs
index 9c5738f..b918a9a 100644
--- a/src/buffer.rs
+++ b/src/buffer.rs
@@ -20,12 +20,13 @@
     feature = "proc-macro"
 ))]
 use proc_macro as pm;
-use proc_macro2::{Delimiter, Ident, Literal, Span, TokenStream};
-use proc_macro2::{Group, Punct, TokenTree};
+use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
 
 use std::marker::PhantomData;
 use std::ptr;
 
+use Lifetime;
+
 /// Internal type which is used instead of `TokenTree` to represent a token tree
 /// within a `TokenBuffer`.
 enum Entry {
@@ -266,7 +267,9 @@
     pub fn punct(mut self) -> Option<(Punct, Cursor<'a>)> {
         self.ignore_none();
         match *self.entry() {
-            Entry::Punct(ref op) => Some((op.clone(), unsafe { self.bump() })),
+            Entry::Punct(ref op) if op.as_char() != '\'' => {
+                Some((op.clone(), unsafe { self.bump() }))
+            }
             _ => None,
         }
     }
@@ -281,6 +284,28 @@
         }
     }
 
+    /// If the cursor is pointing at a `Lifetime`, returns it along with a
+    /// cursor pointing at the next `TokenTree`.
+    pub fn lifetime(mut self) -> Option<(Lifetime, Cursor<'a>)> {
+        self.ignore_none();
+        match *self.entry() {
+            Entry::Punct(ref op) if op.as_char() == '\'' && op.spacing() == Spacing::Joint => {
+                let next = unsafe { self.bump() };
+                match next.ident() {
+                    Some((ident, rest)) => {
+                        let lifetime = Lifetime {
+                            apostrophe: op.span(),
+                            ident: ident,
+                        };
+                        Some((lifetime, rest))
+                    }
+                    None => None,
+                }
+            }
+            _ => None,
+        }
+    }
+
     /// Copies all remaining tokens visible from this cursor into a
     /// `TokenStream`.
     pub fn token_stream(self) -> TokenStream {
diff --git a/src/generics.rs b/src/generics.rs
index 5476192..8903408 100644
--- a/src/generics.rs
+++ b/src/generics.rs
@@ -802,7 +802,7 @@
 
     impl Parse for WherePredicate {
         fn parse(input: ParseStream) -> Result<Self> {
-            if input.peek(Lifetime) && input.peek3(Token![:]) {
+            if input.peek(Lifetime) && input.peek2(Token![:]) {
                 Ok(WherePredicate::Lifetime(PredicateLifetime {
                     lifetime: input.parse()?,
                     colon_token: input.parse()?,
diff --git a/src/lifetime.rs b/src/lifetime.rs
index 2df7ca8..e19cc97 100644
--- a/src/lifetime.rs
+++ b/src/lifetime.rs
@@ -118,23 +118,14 @@
 pub mod parsing {
     use super::*;
 
-    use proc_macro2::Spacing;
-
-    use ext::IdentExt;
     use parse::{Parse, ParseStream, Result};
 
     impl Parse for Lifetime {
         fn parse(input: ParseStream) -> Result<Self> {
-            Ok(Lifetime {
-                apostrophe: input.step(|cursor| {
-                    if let Some((punct, rest)) = cursor.punct() {
-                        if punct.as_char() == '\'' && punct.spacing() == Spacing::Joint {
-                            return Ok((punct.span(), rest));
-                        }
-                    }
-                    Err(cursor.error("expected lifetime"))
-                })?,
-                ident: input.call(Ident::parse_any)?,
+            input.step(|cursor| {
+                cursor
+                    .lifetime()
+                    .ok_or_else(|| cursor.error("expected lifetime"))
             })
         }
     }
diff --git a/src/parse.rs b/src/parse.rs
index 3419303..afd0800 100644
--- a/src/parse.rs
+++ b/src/parse.rs
@@ -227,6 +227,18 @@
     }
 }
 
+fn skip(input: ParseStream) -> bool {
+    input.step(|cursor| {
+        if let Some((_lifetime, rest)) = cursor.lifetime() {
+            Ok((true, rest))
+        } else if let Some((_token, rest)) = cursor.token_tree() {
+            Ok((true, rest))
+        } else {
+            Ok((false, *cursor))
+        }
+    }).unwrap()
+}
+
 impl<'a> ParseBuffer<'a> {
     // Not public API.
     #[doc(hidden)]
@@ -266,28 +278,13 @@
     }
 
     pub fn peek2<T: Peek>(&self, token: T) -> bool {
-        if self.is_empty() {
-            return false;
-        }
         let ahead = self.fork();
-        ahead
-            .step(|cursor| Ok(cursor.token_tree().unwrap()))
-            .unwrap();
-        ahead.peek(token)
+        skip(&ahead) && ahead.peek(token)
     }
 
     pub fn peek3<T: Peek>(&self, token: T) -> bool {
-        if self.is_empty() {
-            return false;
-        }
         let ahead = self.fork();
-        ahead
-            .step(|cursor| Ok(cursor.token_tree().unwrap()))
-            .unwrap();
-        ahead
-            .step(|cursor| Ok(cursor.token_tree().unwrap()))
-            .unwrap();
-        ahead.peek(token)
+        skip(&ahead) && skip(&ahead) && ahead.peek(token)
     }
 
     pub fn parse_terminated<T, P: Parse>(
diff --git a/src/path.rs b/src/path.rs
index 3c4ce07..2dafac8 100644
--- a/src/path.rs
+++ b/src/path.rs
@@ -241,7 +241,7 @@
 
     impl Parse for GenericArgument {
         fn parse(input: ParseStream) -> Result<Self> {
-            if input.peek(Lifetime) && !input.peek3(Token![+]) {
+            if input.peek(Lifetime) && !input.peek2(Token![+]) {
                 return Ok(GenericArgument::Lifetime(input.parse()?));
             }