pcomb 0.3.0

A tiny parser combinator library.
Documentation
//! Traits representing slices: fat pointers to a contiguous ranges of data.
//!
//! See the documentation of the [Slice] trait, the main trait of this module.

extern crate alloc;
use alloc::string::String;
use core::ops::{RangeBounds, Bound};

use crate::parse::Parse;


/// A slice is a fat pointer to a contiguous range of data with fallible slicing
/// operations.
///
/// The slice should be cheap or free to clone and data should be indexed in
/// constant time. Two slices should be equal if their contents are equal.
pub trait Slice {
  type Output: Slice;

  /// Try to subslice this slice, yielding the subslice or None on a failure.
  ///
  /// Slicing a 0-length `a.slice(4..4)` and slicing using [std::ops::RangeFull]
  /// `a.slice(..)` must never fail.
  ///
  /// # Examples
  /// ```
  /// use pcomb::Slice;
  ///
  /// let arr = "hello world!";
  /// assert_eq!(arr.slice(1..4), Some("ell"));
  /// assert_eq!(arr.slice(6..), Some("world!"));
  /// assert_eq!(arr.slice(..), Some(arr));
  /// assert_eq!("café".slice(2..4), None);  // not on a character boundary
  /// ```
  fn slice<R: RangeBounds<usize>>(&self, bounds: R) -> Option<Self::Output>;

  /// Determine the length of this slice. Should be a cheap or free operation.
  ///
  /// # Examples
  /// ```
  /// use pcomb::Slice;
  ///
  /// let arr = "hello world!";
  /// assert_eq!(Slice::len(&arr), 12);
  ///
  /// let arr = &[1u32, 9, 6];
  /// assert_eq!(Slice::len(&arr), 3);
  /// ```
  fn len(&self) -> usize;

  /// Try to divide this slice into two non-overlapping subslices at index.
  /// Returns None if the index is out of bounds or if slicing failed.
  ///
  /// The first slice will contain all values from the interval `[0, index)` and
  /// the second from the interval `[index, len())`.
  ///
  /// # Examples
  /// ```
  /// use pcomb::Slice;
  ///
  /// let arr = &[1u32, 5, 3, 9, 10];
  /// let (left, right) = Slice::split_at(&arr, 2).unwrap();
  /// assert_eq!(left, &[1, 5]);
  /// assert_eq!(right, &[3, 9, 10]);
  /// ```
  fn split_at(&self, index: usize) -> Option<(Self::Output, Self::Output)> {
    Some((self.slice(..index)?, self.slice(index..)?))
  }

  /// Parse this slice using the given parser.
  ///
  /// Equivalent to `parser.parse(self)`.
  fn parse_with<P>(self, parser: P) -> Result<(Self, P::Output), P::Err>
  where P: Parse<Self>, Self: Sized {
    parser.parse(self)
  }
}

/// Internal: convert a RangeBounds into a pair of indices, given a length.
fn into_indices<R: RangeBounds<usize>>(bounds: R, len: usize) -> (usize, usize) {
  let start = match bounds.start_bound().cloned() {
    Bound::Included(idx) => idx,
    Bound::Excluded(idx) => idx + 1,
    Bound::Unbounded => 0,
  };

  let end = match bounds.end_bound().cloned() {
    Bound::Included(idx) => idx + 1,
    Bound::Excluded(idx) => idx,
    Bound::Unbounded => len,
  };

  (start, end)
}

impl Slice for &str {
  type Output = Self;

  fn slice<R: RangeBounds<usize>>(&self, bounds: R) -> Option<Self::Output> {
    // RangeBounds does not implement SliceIndex for whatever reason
    let (start, end) = into_indices(bounds, self.len());
    self.get(start..end)
  }

  fn len(&self) -> usize { str::len(self) }
}

impl<'a> Slice for &'a String {
  type Output = &'a str;

  fn slice<R: RangeBounds<usize>>(&self, bounds: R) -> Option<Self::Output> {
    // RangeBounds does not implement SliceIndex for whatever reason
    let (start, end) = into_indices(bounds, self.len());
    self.get(start..end)
  }

  fn len(&self) -> usize { str::len(self) }
}

impl<T> Slice for &[T] {
  type Output = Self;

  fn slice<R: RangeBounds<usize>>(&self, bounds: R) -> Option<Self::Output> {
    self.get((bounds.start_bound().cloned(), bounds.end_bound().cloned()))
  }

  fn len(&self) -> usize { <[T]>::len(self) }
}

impl<'a, T, const N: usize> Slice for &'a [T; N] {
  type Output = &'a [T];

  fn slice<R: RangeBounds<usize>>(&self, bounds: R) -> Option<Self::Output> {
    self.get((bounds.start_bound().cloned(), bounds.end_bound().cloned()))
  }

  fn len(&self) -> usize { N }
}

// impl<T: Read> Slice for T {
//   type Output = &[u8];

//   fn slice(&self, bounds: Range<usize>) -> Option<Self::Output> {
//     self.
//   }
//   fn len(&self) -> usize { todo!() }
// }

// impl<T: BufRead> Slice for T {
//   type Output = &[u8];

//   fn slice(&self, bounds: Range<usize>) -> Option<Self::Output> {
//     self.
//   }
//   fn len(&self) -> usize { todo!() }
// }