///|
/// Consumes the next value.
pub fn[A] next(self : T[A]) -> A? {
  (self.run)()
}

///|
pub fn[A] peek(self : T[A]) -> A? {
  match (self.run)() {
    None => None
    Some(v) => {
      let used = false
      let run = self.run
      self.run = fn() {
        match used {
          true => run()
          false => Some(v)
        }
      }
      Some(v)
    }
  }
}

///|
/// Consumes the iterator, returning the last value.
pub fn[A] last(self : T[A]) -> A? {
  loop (None, self.next()) {
    (_, Some(v)) => continue (Some(v), self.next())
    (v, None) => v
  }
}

///|
/// Consumes the iterator, counting and returning the number of iterations.
pub fn[A] count(self : T[A]) -> Int {
  let mut i = 0
  loop self.next() {
    Some(_) => {
      i += 1
      continue self.next()
    }
    None => i
  }
}

///|
/// Takes the first `n` elements from the iterator.
pub fn[A] take(self : T[A], n : Int) -> T[A] {
  let mut i = 0
  {
    run: fn() {
      if i < n {
        match (self.run)() {
          None => None
          Some(v) => {
            i += 1
            Some(v)
          }
        }
      } else {
        None
      }
    },
  }
}

///|
/// Takes elements from the iterator while the predicate returns `true`.
pub fn[A] take_while(self : T[A], f : (A) -> Bool) -> T[A] {
  let mut end = false
  {
    run: fn() {
      if not(end) {
        match (self.run)() {
          None => None
          Some(v) =>
            if f(v) {
              Some(v)
            } else {
              end = true
              None
            }
        }
      } else {
        None
      }
    },
  }
}

///|
/// Drops the first `n` elements from the iterator.
/// 
/// Note: The function is lazy, which only skips elements when it is requested.
pub fn[A] drop(self : T[A], n : Int) -> T[A] {
  let mut i : Int = 0
  let mut dropped = false
  {
    run: fn() {
      if not(dropped) {
        while i < n {
          i += 1
          (self.run)() |> ignore
        }
        dropped = true
        (self.run)()
      } else {
        (self.run)()
      }
    },
  }
}

///|
/// Skips elements from the iterator while the predicate returns `true`.
/// 
/// Note: The function is lazy, which only skips elements when it is requested.
pub fn[A] drop_while(self : T[A], f : (A) -> Bool) -> T[A] {
  let mut dropped = false
  {
    run: fn() {
      if not(dropped) {
        while self.next() is Some(v) && not(dropped) {
          if f(v) {
            continue
          } else {
            dropped = true
          }
        }
        (self.run)()
      } else {
        (self.run)()
      }
    },
  }
}

///|
/// Collects the elements of the iterator into an array.
pub fn[A] collect(self : T[A]) -> Array[A] {
  let array = Array::new()
  while self.next() is Some(v) {
    array.push(v)
  }
  array
}

///|
/// Applies `f` to each element of the iterator.
pub fn[A] each(self : T[A], f : (A) -> Unit) -> Unit {
  while self.next() is Some(v) {
    f(v)
  }
}

///|
/// Applies `f` to each element of the iterator, passing the index as a parameter.
pub fn[A] eachi(self : T[A], f : (Int, A) -> Unit) -> Unit {
  let mut i = 0
  while self.next() is Some(v) {
    f(i, v)
    i += 1
  }
}

///|
/// Concatenates the elements of the iterator into a string, separated by `separator`.
pub fn[A : Show] join(self : T[A], separator~ : String) -> String {
  let builder = StringBuilder::new()
  match self.next() {
    Some(v) => builder.write_string("\{v}")
    None => return ""
  }
  loop self.next() {
    Some(v) => {
      builder.write_string(separator)
      builder.write_string(v.to_string())
      continue self.next()
    }
    None => builder.to_string()
  }
}

///|
/// Finds the first element in the iterator that satisfies the predicate, or `None` if no such element is found.
pub fn[A] find_first(self : T[A], pred : (A) -> Bool) -> A? {
  while self.next() is Some(v) {
    if pred(v) {
      break Some(v)
    }
  } else {
    None
  }
}

///|
/// Folds the elements of the iterator using the given function, starting with the given initial value.
pub fn[A, B] fold(self : T[A], init~ : B, f : (B, A) -> B) -> B {
  let mut acc = init
  loop self.next() {
    Some(v) => {
      acc = f(acc, v)
      continue self.next()
    }
    None => acc
  }
}

///|
/// Returns the nth element of the iterator, or `None` if there isn't one.
pub fn[A] nth(self : T[A], n : Int) -> A? {
  self.drop(n).peek()
}

///|
/// Returns the maximum element of the iterator, or `None` if the iterator is empty.
pub fn[A : Compare] minimum(self : T[A]) -> A? {
  let mut min = None
  loop self.next() {
    Some(v) => {
      match min {
        None => min = Some(v)
        Some(min_v) => if v < min_v { min = Some(v) }
      }
      continue self.next()
    }
    None => min
  }
}

///|
/// Returns the minimum element of the iterator, or `None` if the iterator is empty.
pub fn[A : Compare] maximum(self : T[A]) -> A? {
  let mut max = None
  loop self.next() {
    Some(v) => {
      match max {
        None => max = Some(v)
        Some(max_v) => if v > max_v { max = Some(v) }
      }
      continue self.next()
    }
    None => max
  }
}

///|
pub impl[A : Show] Show for T[A] with output(self, logger) {
  logger.write_iter(self.iter())
}