Documentation for punctuated module
diff --git a/src/punctuated.rs b/src/punctuated.rs
index fda3c10..ca34d22 100644
--- a/src/punctuated.rs
+++ b/src/punctuated.rs
@@ -6,12 +6,46 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+//! A punctuated sequence of syntax tree nodes separated by punctuation.
+//!
+//! Lots of things in Rust are punctuated sequences.
+//!
+//! - The fields of a struct are `Punctuated<Field, Token![,]>`.
+//! - The segments of a path are `Punctuated<PathSegment, Token![::]>`.
+//! - The bounds on a generic parameter are `Punctuated<TypeParamBound, Token![+]>`.
+//! - The arguments to a function call are `Punctuated<Expr, Token![,]>`.
+//!
+//! This module provides a common representation for these punctuated sequences
+//! in the form of the [`Punctuated<T, P>`] type. We store a vector of pairs of
+//! syntax tree node + punctuation, where every node in the sequence is followed
+//! by punctuation except for possibly the final one.
+//!
+//! [`Punctuated<T, P>`]: struct.Punctuated.html
+//!
+//! ```text
+//! a_function_call(arg1, arg2, arg3);
+//! ^^^^^ ~~~~~ ^^^^
+//! ```
+
use std::iter::FromIterator;
use std::slice;
use std::vec;
#[cfg(feature = "extra-traits")]
use std::fmt::{self, Debug};
+#[cfg(feature = "parsing")]
+use synom::{Synom, PResult};
+#[cfg(feature = "parsing")]
+use buffer::Cursor;
+#[cfg(feature = "parsing")]
+use parse_error;
+
+/// A punctuated sequence of syntax tree nodes of type `T` separated by
+/// punctuation of type `P`.
+///
+/// Refer to the [module documentation] for details about punctuated sequences.
+///
+/// [module documentation]: index.html
#[cfg_attr(feature = "extra-traits", derive(Eq, PartialEq, Hash))]
#[cfg_attr(feature = "clone-impls", derive(Clone))]
pub struct Punctuated<T, P> {
@@ -19,18 +53,26 @@
}
impl<T, P> Punctuated<T, P> {
+ /// Creates an empty punctuated sequence.
pub fn new() -> Punctuated<T, P> {
Punctuated { inner: Vec::new() }
}
+ /// Determines whether this punctuated sequence is empty, meaning it
+ /// contains no syntax tree nodes or punctuation.
pub fn is_empty(&self) -> bool {
self.inner.len() == 0
}
+ /// Returns the number of syntax tree nodes in this punctuated sequence.
+ ///
+ /// This is the number of nodes of type `T`, not counting the punctuation of
+ /// type `P`.
pub fn len(&self) -> usize {
self.inner.len()
}
+ /// Borrows the first punctuated pair in this sequence.
pub fn first(&self) -> Option<Pair<&T, &P>> {
self.inner.first().map(|&(ref t, ref d)| match *d {
Some(ref d) => Pair::Punctuated(t, d),
@@ -38,6 +80,7 @@
})
}
+ /// Borrows the last punctuated pair in this sequence.
pub fn last(&self) -> Option<Pair<&T, &P>> {
self.inner.last().map(|&(ref t, ref d)| match *d {
Some(ref d) => Pair::Punctuated(t, d),
@@ -45,6 +88,7 @@
})
}
+ /// Mutably borrows the last punctuated pair in this sequence.
pub fn last_mut(&mut self) -> Option<Pair<&mut T, &mut P>> {
self.inner
.last_mut()
@@ -54,41 +98,69 @@
})
}
+ /// Returns an iterator over borrowed syntax tree nodes of type `&T`.
pub fn iter(&self) -> Iter<T, P> {
Iter {
inner: self.inner.iter(),
}
}
+ /// Returns an iterator over mutably borrowed syntax tree nodes of type
+ /// `&mut T`.
pub fn iter_mut(&mut self) -> IterMut<T, P> {
IterMut {
inner: self.inner.iter_mut(),
}
}
+ /// Returns an iterator over the contents of this sequence as borrowed
+ /// punctuated pairs.
pub fn pairs(&self) -> Pairs<T, P> {
Pairs {
inner: self.inner.iter(),
}
}
+ /// Returns an iterator over the contents of this sequence as mutably
+ /// borrowed punctuated pairs.
pub fn pairs_mut(&mut self) -> PairsMut<T, P> {
PairsMut {
inner: self.inner.iter_mut(),
}
}
+ /// Returns an iterator over the contents of this sequence as owned
+ /// punctuated pairs.
pub fn into_pairs(self) -> IntoPairs<T, P> {
IntoPairs {
inner: self.inner.into_iter(),
}
}
+ /// Appends a syntax tree node onto the end of this punctuated sequence. The
+ /// sequence must previously have a trailing punctuation.
+ ///
+ /// Use [`push`] instead if the punctuated sequence may or may not already
+ /// have trailing punctuation.
+ ///
+ /// [`push`]: #method.push
+ ///
+ /// # Panics
+ ///
+ /// Panics if the sequence does not already have a trailing punctuation when
+ /// this method is called.
pub fn push_value(&mut self, value: T) {
assert!(self.empty_or_trailing());
self.inner.push((value, None));
}
+ /// Appends a trailing punctuation onto the end of this punctuated sequence.
+ /// The sequence must be non-empty and must not already have trailing
+ /// punctuation.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the sequence is empty or already has a trailing punctuation.
pub fn push_punct(&mut self, punctuation: P) {
assert!(!self.is_empty());
let last = self.inner.last_mut().unwrap();
@@ -96,10 +168,14 @@
last.1 = Some(punctuation);
}
+ /// Removes the last punctuated pair from this sequence, or `None` if the
+ /// sequence is empty.
pub fn pop(&mut self) -> Option<Pair<T, P>> {
self.inner.pop().map(|(t, d)| Pair::new(t, d))
}
+ /// Determines whether this punctuated sequence ends with a trailing
+ /// punctuation.
pub fn trailing_punct(&self) -> bool {
self.inner
.last()
@@ -123,6 +199,11 @@
where
P: Default,
{
+ /// Appends a syntax tree node onto the end of this punctuated sequence.
+ ///
+ /// If there is not a trailing punctuation in this sequence when this method
+ /// is called, the default value of punctuation type `P` is inserted before
+ /// the given value of type `T`.
pub fn push(&mut self, value: T) {
if !self.empty_or_trailing() {
self.push_punct(Default::default());
@@ -192,6 +273,11 @@
}
}
+/// An iterator over borrowed pairs of type `Pair<&T, &P>`.
+///
+/// Refer to the [module documentation] for details about punctuated sequences.
+///
+/// [module documentation]: index.html
pub struct Pairs<'a, T: 'a, P: 'a> {
inner: slice::Iter<'a, (T, Option<P>)>,
}
@@ -207,6 +293,11 @@
}
}
+/// An iterator over mutably borrowed pairs of type `Pair<&mut T, &mut P>`.
+///
+/// Refer to the [module documentation] for details about punctuated sequences.
+///
+/// [module documentation]: index.html
pub struct PairsMut<'a, T: 'a, P: 'a> {
inner: slice::IterMut<'a, (T, Option<P>)>,
}
@@ -222,6 +313,11 @@
}
}
+/// An iterator over owned pairs of type `Pair<T, P>`.
+///
+/// Refer to the [module documentation] for details about punctuated sequences.
+///
+/// [module documentation]: index.html
pub struct IntoPairs<T, P> {
inner: vec::IntoIter<(T, Option<P>)>,
}
@@ -237,6 +333,11 @@
}
}
+/// An iterator over owned values of type `T`.
+///
+/// Refer to the [module documentation] for details about punctuated sequences.
+///
+/// [module documentation]: index.html
pub struct IntoIter<T, P> {
inner: vec::IntoIter<(T, Option<P>)>,
}
@@ -249,6 +350,11 @@
}
}
+/// An iterator over borrowed values of type `&T`.
+///
+/// Refer to the [module documentation] for details about punctuated sequences.
+///
+/// [module documentation]: index.html
pub struct Iter<'a, T: 'a, P: 'a> {
inner: slice::Iter<'a, (T, Option<P>)>,
}
@@ -261,6 +367,11 @@
}
}
+/// An iterator over mutably borrowed values of type `&mut T`.
+///
+/// Refer to the [module documentation] for details about punctuated sequences.
+///
+/// [module documentation]: index.html
pub struct IterMut<'a, T: 'a, P: 'a> {
inner: slice::IterMut<'a, (T, Option<P>)>,
}
@@ -273,30 +384,42 @@
}
}
+/// A single syntax tree node of type `T` followed by its trailing punctuation
+/// of type `P` if any.
+///
+/// Refer to the [module documentation] for details about punctuated sequences.
+///
+/// [module documentation]: index.html
pub enum Pair<T, P> {
Punctuated(T, P),
End(T),
}
impl<T, P> Pair<T, P> {
+ /// Extracts the syntax tree node from this punctuated pair, discarding the
+ /// following punctuation.
pub fn into_value(self) -> T {
match self {
Pair::Punctuated(t, _) | Pair::End(t) => t,
}
}
+ /// Borrows the syntax tree node from this punctuated pair.
pub fn value(&self) -> &T {
match *self {
Pair::Punctuated(ref t, _) | Pair::End(ref t) => t,
}
}
+ /// Mutably borrows the syntax tree node from this punctuated pair.
pub fn value_mut(&mut self) -> &mut T {
match *self {
Pair::Punctuated(ref mut t, _) | Pair::End(ref mut t) => t,
}
}
+ /// Borrows the punctuation from this punctuated pair, unless this pair is
+ /// the final one and there is no trailing punctuation.
pub fn punct(&self) -> Option<&P> {
match *self {
Pair::Punctuated(_, ref d) => Some(d),
@@ -304,6 +427,8 @@
}
}
+ /// Creates a punctuated pair out of a syntax tree node and an optional
+ /// following punctuation.
pub fn new(t: T, d: Option<P>) -> Self {
match d {
Some(d) => Pair::Punctuated(t, d),
@@ -311,6 +436,8 @@
}
}
+ /// Produces this punctuated pair as a tuple of syntax tree node and
+ /// optional following punctuation.
pub fn into_tuple(self) -> (T, Option<P>) {
match self {
Pair::Punctuated(t, d) => (t, Some(d)),
@@ -320,116 +447,126 @@
}
#[cfg(feature = "parsing")]
-mod parsing {
- use super::Punctuated;
- use synom::Synom;
- use buffer::Cursor;
- use parse_error;
- use synom::PResult;
+impl<T, P> Punctuated<T, P>
+where
+ T: Synom,
+ P: Synom,
+{
+ /// Parse **zero or more** syntax tree nodes with punctuation in between and
+ /// **no trailing** punctuation.
+ pub fn parse_separated(input: Cursor) -> PResult<Self> {
+ Self::parse_separated_with(input, T::parse)
+ }
- impl<T, P> Punctuated<T, P>
- where
- T: Synom,
- P: Synom,
- {
- pub fn parse_separated(input: Cursor) -> PResult<Self> {
- Self::parse(input, T::parse, false)
- }
+ /// Parse **one or more** syntax tree nodes with punctuation in bewteen and
+ /// **no trailing** punctuation.
+ /// allowing trailing punctuation.
+ pub fn parse_separated_nonempty(input: Cursor) -> PResult<Self> {
+ Self::parse_separated_nonempty_with(input, T::parse)
+ }
- pub fn parse_separated_nonempty(input: Cursor) -> PResult<Self> {
- Self::parse_separated_nonempty_with(input, T::parse)
- }
+ /// Parse **zero or more** syntax tree nodes with punctuation in between and
+ /// **optional trailing** punctuation.
+ pub fn parse_terminated(input: Cursor) -> PResult<Self> {
+ Self::parse_terminated_with(input, T::parse)
+ }
- pub fn parse_terminated(input: Cursor) -> PResult<Self> {
- Self::parse_terminated_with(input, T::parse)
- }
+ /// Parse **one or more** syntax tree nodes with punctuation in between and
+ /// **optional trailing** punctuation.
+ pub fn parse_terminated_nonempty(input: Cursor) -> PResult<Self> {
+ Self::parse_terminated_nonempty_with(input, T::parse)
+ }
+}
- pub fn parse_terminated_nonempty(input: Cursor) -> PResult<Self> {
- Self::parse_terminated_nonempty_with(input, T::parse)
+#[cfg(feature = "parsing")]
+impl<T, P> Punctuated<T, P>
+where
+ P: Synom,
+{
+ /// Parse **zero or more** syntax tree nodes using the given parser with
+ /// punctuation in between and **no trailing** punctuation.
+ pub fn parse_separated_with(
+ input: Cursor,
+ parse: fn(Cursor) -> PResult<T>,
+ ) -> PResult<Self> {
+ Self::parse(input, parse, false)
+ }
+
+ /// Parse **one or more** syntax tree nodes using the given parser with
+ /// punctuation in between and **no trailing** punctuation.
+ pub fn parse_separated_nonempty_with(
+ input: Cursor,
+ parse: fn(Cursor) -> PResult<T>,
+ ) -> PResult<Self> {
+ match Self::parse(input, parse, false) {
+ Ok((ref b, _)) if b.is_empty() => parse_error(),
+ other => other,
}
}
- impl<T, P> Punctuated<T, P>
- where
- P: Synom,
- {
- pub fn parse_separated_with(
- input: Cursor,
- parse: fn(Cursor) -> PResult<T>,
- ) -> PResult<Self> {
- Self::parse(input, parse, false)
+ /// Parse **zero or more** syntax tree nodes using the given parser with
+ /// punctuation in between and **optional trailing** punctuation.
+ pub fn parse_terminated_with(
+ input: Cursor,
+ parse: fn(Cursor) -> PResult<T>,
+ ) -> PResult<Self> {
+ Self::parse(input, parse, true)
+ }
+
+ /// Parse **one or more** syntax tree nodes using the given parser with
+ /// punctuation in between and **optional trailing** punctuation.
+ pub fn parse_terminated_nonempty_with(
+ input: Cursor,
+ parse: fn(Cursor) -> PResult<T>,
+ ) -> PResult<Self> {
+ match Self::parse(input, parse, true) {
+ Ok((ref b, _)) if b.is_empty() => parse_error(),
+ other => other,
}
+ }
- pub fn parse_separated_nonempty_with(
- input: Cursor,
- parse: fn(Cursor) -> PResult<T>,
- ) -> PResult<Self> {
- match Self::parse(input, parse, false) {
- Ok((ref b, _)) if b.is_empty() => parse_error(),
- other => other,
- }
- }
+ fn parse(
+ mut input: Cursor,
+ parse: fn(Cursor) -> PResult<T>,
+ terminated: bool,
+ ) -> PResult<Self> {
+ let mut res = Punctuated::new();
- pub fn parse_terminated_with(
- input: Cursor,
- parse: fn(Cursor) -> PResult<T>,
- ) -> PResult<Self> {
- Self::parse(input, parse, true)
- }
-
- pub fn parse_terminated_nonempty_with(
- input: Cursor,
- parse: fn(Cursor) -> PResult<T>,
- ) -> PResult<Self> {
- match Self::parse(input, parse, true) {
- Ok((ref b, _)) if b.is_empty() => parse_error(),
- other => other,
- }
- }
-
- fn parse(
- mut input: Cursor,
- parse: fn(Cursor) -> PResult<T>,
- terminated: bool,
- ) -> PResult<Self> {
- let mut res = Punctuated::new();
-
- // get the first element
- match parse(input) {
- Err(_) => Ok((res, input)),
- Ok((o, i)) => {
- if i == input {
- return parse_error();
- }
- input = i;
- res.push_value(o);
-
- // get the separator first
- while let Ok((s, i2)) = P::parse(input) {
- if i2 == input {
- break;
- }
-
- // get the element next
- if let Ok((o3, i3)) = parse(i2) {
- if i3 == i2 {
- break;
- }
- res.push_punct(s);
- res.push_value(o3);
- input = i3;
- } else {
- break;
- }
- }
- if terminated {
- if let Ok((sep, after)) = P::parse(input) {
- res.push_punct(sep);
- input = after;
- }
- }
- Ok((res, input))
+ // get the first element
+ match parse(input) {
+ Err(_) => Ok((res, input)),
+ Ok((o, i)) => {
+ if i == input {
+ return parse_error();
}
+ input = i;
+ res.push_value(o);
+
+ // get the separator first
+ while let Ok((s, i2)) = P::parse(input) {
+ if i2 == input {
+ break;
+ }
+
+ // get the element next
+ if let Ok((o3, i3)) = parse(i2) {
+ if i3 == i2 {
+ break;
+ }
+ res.push_punct(s);
+ res.push_value(o3);
+ input = i3;
+ } else {
+ break;
+ }
+ }
+ if terminated {
+ if let Ok((sep, after)) = P::parse(input) {
+ res.push_punct(sep);
+ input = after;
+ }
+ }
+ Ok((res, input))
}
}
}