<commit_before>use nom;
use nom::{Err, IResult};

use metadata;
use frame;
use subframe;

use metadata::{Metadata, StreamInfo, metadata_parser};
use frame::{frame_parser, Frame};
use utility::{ErrorKind, ByteStream, ReadStream, StreamProducer};

use std::io;
use std::usize;
use std::fs::File;

enum ParserState {
  Marker,
  Metadata,
  Frame,
}

/// FLAC stream that decodes and hold file information.
pub struct Stream {
  info: StreamInfo,
  metadata: Vec<Metadata>,
  frames: Vec<Frame>,
  state: ParserState,
  output: Vec<i32>,
  frame_index: usize,
}

named!(pub stream_parser <&[u8], Stream>,
  chain!(
    blocks: metadata_parser ~
    frames: many1!(apply!(frame_parser, &blocks.0)),
    move|| {
      Stream {
        info: blocks.0,
        metadata: blocks.1,
        frames: frames,
        state: ParserState::Marker,
        output: Vec::new(),
        frame_index: 0,
      }
    }
  )
);

impl Stream {
  /// Constructor for the default state of a FLAC stream.
  ///
  /// This doesn't actually decode anything, it just hold the default values
  /// of each field.
  pub fn new() -> Stream {
    Stream {
      info: StreamInfo::new(),
      metadata: Vec::new(),
      frames: Vec::new(),
      state: ParserState::Marker,
      output: Vec::new(),
      frame_index: 0,
    }
  }

  pub fn info(&self) -> StreamInfo {
    self.info
  }

  pub fn metadata(&self) -> &[Metadata] {
    &self.metadata
  }

  /// Constructs a decoder with the given file name.
  ///
  /// # Failures
  ///
  /// * `ErrorKind::NotFound` is returned when the given filename isn't found.
  /// * `ErrorKind::InvalidData` is returned when the data within the file
  ///   isn't valid FLAC data.
  pub fn from_file(filename: &str) -> io::Result<Stream> {
    File::open(filename).and_then(|file| {
      let mut producer = ReadStream::new(file);
      let error_str    = format!("parser: couldn't parse the given file {}",
                                 filename);

      Stream::from_stream_producer(&mut producer, &error_str)
    })
  }

  /// Constructs a decoder with the given buffer.
  ///
  /// This constructor assumes that an entire FLAC file is in the buffer.
  ///
  /// # Failures
  ///
  /// * `ErrorKind::InvalidData` is returned when the data within the buffer
  ///   isn't valid FLAC data.
  pub fn from_buffer(buffer: &[u8]) -> io::Result<Stream> {
    let mut producer = ByteStream::new(buffer);
    let error_str    = "parser: couldn't parse the buffer";

    Stream::from_stream_producer(&mut producer, error_str)
  }

  fn from_stream_producer<P>(producer: &mut P, error_str: &str)
                             -> io::Result<Stream>
   where P: StreamProducer {
    let mut is_error = false;
    let mut stream   = Stream {
      info: StreamInfo::new(),
      metadata: Vec::new(),
      frames: Vec::new(),
      state: ParserState::Marker,
      output: Vec::new(),
      frame_index: 0,
    };

    loop {
      match stream.handle(producer) {
        Ok(_)                         => break,
        Err(ErrorKind::EndOfInput)    => break,
        Err(ErrorKind::Consumed(_))   => continue,
        Err(ErrorKind::Incomplete(_)) => continue,
        Err(_)                        => {
          is_error = true;

          break;
        }
      }
    }

    if !is_error {
      let channels    = stream.info.channels as usize;
      let block_size  = stream.info.max_block_size as usize;
      let output_size = block_size * channels;

      stream.output.reserve_exact(output_size);

      unsafe { stream.output.set_len(output_size) }

      Ok(stream)
    } else {
      Err(io::Error::new(io::ErrorKind::InvalidData, error_str))
    }
  }

  pub fn iter(&mut self) -> Iter {
    Iter::new(self)
  }

  fn next_frame<'a>(&'a mut self) -> Option<&'a [i32]> {
    if self.frames.is_empty() || self.frame_index >= self.frames.len() {
      None
    } else {
      let frame       = &self.frames[self.frame_index];
      let channels    = frame.header.channels as usize;
      let block_size  = frame.header.block_size as usize;
      let mut channel = 0;

      for subframe in &frame.subframes[0..channels] {
        let start  = channel * block_size;
        let end    = (channel + 1) * block_size;
        let output = &mut self.output[start..end];

        subframe::decode(&subframe, output);

        channel += 1;
      }

      frame::decode(frame.header.channel_assignment, &mut self.output);

      self.frame_index += 1;

      Some(&self.output[0..(block_size * channels)])
    }
  }

  fn handle_marker<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(0);

    match tag!(input, "fLaC") {
      IResult::Done(i, _)    => {
        self.state = ParserState::Metadata;

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_metadata<'a>(&mut self, input: &'a [u8])
                         -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(1);

    match metadata::block(input) {
      IResult::Done(i, block) => {
        let is_last = block.is_last;

        if let metadata::Data::StreamInfo(info) = block.data {
          self.info = info;
        } else {
          self.metadata.push(block);
        }

        if is_last {
          self.state = ParserState::Frame;
        }

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_frame<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(2);

    match frame_parser(input, &self.info) {
      IResult::Done(i, frame) => {
        self.frames.push(frame);

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle<S: StreamProducer>(&mut self, stream: &mut S)
                               -> Result<(), ErrorKind> {
    stream.parse(|input| {
      match self.state {
        ParserState::Marker   => self.handle_marker(input),
        ParserState::Metadata => self.handle_metadata(input),
        ParserState::Frame    => self.handle_frame(input),
      }
    })
  }
}

pub struct Iter<'a> {
  stream: &'a mut Stream,
  channel: usize,
  frame_index: usize,
  block_size: usize,
  sample_index: usize,
  samples_left: u64,
}

impl<'a> Iter<'a> {
  pub fn new(stream: &'a mut Stream) -> Iter<'a> {
    let samples_left = stream.info.total_samples;

    Iter {
      stream: stream,
      channel: 0,
      frame_index: 0,
      block_size: 0,
      sample_index: 0,
      samples_left: samples_left,
    }
  }
}

impl<'a> Iterator for Iter<'a> {
  type Item = i32;

  fn next(&mut self) -> Option<Self::Item> {
    if self.block_size == 0 || self.sample_index == self.block_size {
      if self.stream.next_frame().is_none() {
        return None;
      } else {
        let frame = &self.stream.frames[self.frame_index];

        self.sample_index = 0;
        self.block_size   = frame.header.block_size as usize;
      }
    }

    let channels = self.stream.info.channels as usize;
    let index    = self.sample_index + (self.channel * self.block_size);
    let sample   = self.stream.output[index];

    self.channel      += 1;
    self.samples_left -= 1;

    // Reset current channel
    if self.channel == channels {
      self.channel       = 0;
      self.sample_index += 1;
    }

    Some(sample)
  }

  fn size_hint(&self) -> (usize, Option<usize>) {
    let samples_left = self.samples_left as usize;
    let max_value    = usize::max_value() as u64;

    // There is a chance that samples_left will be larger than a usize since
    // it is a u64. Make the upper bound None when it is.
    if self.samples_left > max_value {
      (samples_left, None)
    } else {
      (samples_left, Some(samples_left))
    }
  }
}

impl<'a> IntoIterator for &'a mut Stream {
  type Item     = i32;
  type IntoIter = Iter<'a>;

  fn into_iter(self) -> Self::IntoIter {
    self.iter()
  }
}
<commit_msg>Add documentation for the two getter functions<commit_after>use nom;
use nom::{Err, IResult};

use metadata;
use frame;
use subframe;

use metadata::{Metadata, StreamInfo, metadata_parser};
use frame::{frame_parser, Frame};
use utility::{ErrorKind, ByteStream, ReadStream, StreamProducer};

use std::io;
use std::usize;
use std::fs::File;

enum ParserState {
  Marker,
  Metadata,
  Frame,
}

/// FLAC stream that decodes and hold file information.
pub struct Stream {
  info: StreamInfo,
  metadata: Vec<Metadata>,
  frames: Vec<Frame>,
  state: ParserState,
  output: Vec<i32>,
  frame_index: usize,
}

named!(pub stream_parser <&[u8], Stream>,
  chain!(
    blocks: metadata_parser ~
    frames: many1!(apply!(frame_parser, &blocks.0)),
    move|| {
      Stream {
        info: blocks.0,
        metadata: blocks.1,
        frames: frames,
        state: ParserState::Marker,
        output: Vec::new(),
        frame_index: 0,
      }
    }
  )
);

impl Stream {
  /// Constructor for the default state of a FLAC stream.
  ///
  /// This doesn't actually decode anything, it just hold the default values
  /// of each field.
  pub fn new() -> Stream {
    Stream {
      info: StreamInfo::new(),
      metadata: Vec::new(),
      frames: Vec::new(),
      state: ParserState::Marker,
      output: Vec::new(),
      frame_index: 0,
    }
  }

  /// Returns information for the current stream.
  pub fn info(&self) -> StreamInfo {
    self.info
  }

  /// Returns a slice of `Metadata`
  ///
  /// This slice excludes `StreamInfo`, which is located in `Stream::info`.
  /// Everything else is related to metadata for the FLAC stream is in the
  /// slice.
  pub fn metadata(&self) -> &[Metadata] {
    &self.metadata
  }

  /// Constructs a decoder with the given file name.
  ///
  /// # Failures
  ///
  /// * `ErrorKind::NotFound` is returned when the given filename isn't found.
  /// * `ErrorKind::InvalidData` is returned when the data within the file
  ///   isn't valid FLAC data.
  pub fn from_file(filename: &str) -> io::Result<Stream> {
    File::open(filename).and_then(|file| {
      let mut producer = ReadStream::new(file);
      let error_str    = format!("parser: couldn't parse the given file {}",
                                 filename);

      Stream::from_stream_producer(&mut producer, &error_str)
    })
  }

  /// Constructs a decoder with the given buffer.
  ///
  /// This constructor assumes that an entire FLAC file is in the buffer.
  ///
  /// # Failures
  ///
  /// * `ErrorKind::InvalidData` is returned when the data within the buffer
  ///   isn't valid FLAC data.
  pub fn from_buffer(buffer: &[u8]) -> io::Result<Stream> {
    let mut producer = ByteStream::new(buffer);
    let error_str    = "parser: couldn't parse the buffer";

    Stream::from_stream_producer(&mut producer, error_str)
  }

  fn from_stream_producer<P>(producer: &mut P, error_str: &str)
                             -> io::Result<Stream>
   where P: StreamProducer {
    let mut is_error = false;
    let mut stream   = Stream {
      info: StreamInfo::new(),
      metadata: Vec::new(),
      frames: Vec::new(),
      state: ParserState::Marker,
      output: Vec::new(),
      frame_index: 0,
    };

    loop {
      match stream.handle(producer) {
        Ok(_)                         => break,
        Err(ErrorKind::EndOfInput)    => break,
        Err(ErrorKind::Consumed(_))   => continue,
        Err(ErrorKind::Incomplete(_)) => continue,
        Err(_)                        => {
          is_error = true;

          break;
        }
      }
    }

    if !is_error {
      let channels    = stream.info.channels as usize;
      let block_size  = stream.info.max_block_size as usize;
      let output_size = block_size * channels;

      stream.output.reserve_exact(output_size);

      unsafe { stream.output.set_len(output_size) }

      Ok(stream)
    } else {
      Err(io::Error::new(io::ErrorKind::InvalidData, error_str))
    }
  }

  pub fn iter(&mut self) -> Iter {
    Iter::new(self)
  }

  fn next_frame<'a>(&'a mut self) -> Option<&'a [i32]> {
    if self.frames.is_empty() || self.frame_index >= self.frames.len() {
      None
    } else {
      let frame       = &self.frames[self.frame_index];
      let channels    = frame.header.channels as usize;
      let block_size  = frame.header.block_size as usize;
      let mut channel = 0;

      for subframe in &frame.subframes[0..channels] {
        let start  = channel * block_size;
        let end    = (channel + 1) * block_size;
        let output = &mut self.output[start..end];

        subframe::decode(&subframe, output);

        channel += 1;
      }

      frame::decode(frame.header.channel_assignment, &mut self.output);

      self.frame_index += 1;

      Some(&self.output[0..(block_size * channels)])
    }
  }

  fn handle_marker<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(0);

    match tag!(input, "fLaC") {
      IResult::Done(i, _)    => {
        self.state = ParserState::Metadata;

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_metadata<'a>(&mut self, input: &'a [u8])
                         -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(1);

    match metadata::block(input) {
      IResult::Done(i, block) => {
        let is_last = block.is_last;

        if let metadata::Data::StreamInfo(info) = block.data {
          self.info = info;
        } else {
          self.metadata.push(block);
        }

        if is_last {
          self.state = ParserState::Frame;
        }

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_frame<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(2);

    match frame_parser(input, &self.info) {
      IResult::Done(i, frame) => {
        self.frames.push(frame);

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle<S: StreamProducer>(&mut self, stream: &mut S)
                               -> Result<(), ErrorKind> {
    stream.parse(|input| {
      match self.state {
        ParserState::Marker   => self.handle_marker(input),
        ParserState::Metadata => self.handle_metadata(input),
        ParserState::Frame    => self.handle_frame(input),
      }
    })
  }
}

pub struct Iter<'a> {
  stream: &'a mut Stream,
  channel: usize,
  frame_index: usize,
  block_size: usize,
  sample_index: usize,
  samples_left: u64,
}

impl<'a> Iter<'a> {
  pub fn new(stream: &'a mut Stream) -> Iter<'a> {
    let samples_left = stream.info.total_samples;

    Iter {
      stream: stream,
      channel: 0,
      frame_index: 0,
      block_size: 0,
      sample_index: 0,
      samples_left: samples_left,
    }
  }
}

impl<'a> Iterator for Iter<'a> {
  type Item = i32;

  fn next(&mut self) -> Option<Self::Item> {
    if self.block_size == 0 || self.sample_index == self.block_size {
      if self.stream.next_frame().is_none() {
        return None;
      } else {
        let frame = &self.stream.frames[self.frame_index];

        self.sample_index = 0;
        self.block_size   = frame.header.block_size as usize;
      }
    }

    let channels = self.stream.info.channels as usize;
    let index    = self.sample_index + (self.channel * self.block_size);
    let sample   = self.stream.output[index];

    self.channel      += 1;
    self.samples_left -= 1;

    // Reset current channel
    if self.channel == channels {
      self.channel       = 0;
      self.sample_index += 1;
    }

    Some(sample)
  }

  fn size_hint(&self) -> (usize, Option<usize>) {
    let samples_left = self.samples_left as usize;
    let max_value    = usize::max_value() as u64;

    // There is a chance that samples_left will be larger than a usize since
    // it is a u64. Make the upper bound None when it is.
    if self.samples_left > max_value {
      (samples_left, None)
    } else {
      (samples_left, Some(samples_left))
    }
  }
}

impl<'a> IntoIterator for &'a mut Stream {
  type Item     = i32;
  type IntoIter = Iter<'a>;

  fn into_iter(self) -> Self::IntoIter {
    self.iter()
  }
}
<|endoftext|>


<commit_before>// Copyright 2015-2016 Daniel P. Clark & array_tool Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

/// A string is a collection so we should have more methods for handling strings.
pub mod string {
  /// Justify - expand line to given width
  pub trait Justify {
    /// # Example
    /// ```
    /// use array_tool::string::Justify;
    ///
    /// "asd asdf asd".justify_line(14);
    /// ```
    ///
    /// # Output
    /// ```text
    /// "asd  asdf  asd"
    /// ```
    fn justify_line(&self, width: usize) -> String;
  }

  impl Justify for &'static str {
    fn justify_line(&self, width: usize) -> String {
      let trimmed = self.trim() ;
      let len = trimmed.len();
      if len >= width { return self.to_string(); };
      let difference = width - len;
      let iter = trimmed.split_whitespace();
      let spaces = iter.count() - 1;
      let mut iter = trimmed.split_whitespace().peekable();
      if spaces == 0 { return self.to_string(); }
      let mut obj = String::with_capacity(width);

      let div = difference / spaces;
      let mut remainder = difference % spaces;

      loop {
        match iter.next() {
          Some(x) => {
            obj.push_str( x );
            let val = if remainder > 0 {
              remainder = remainder - 1;
              div + 1
            } else { div };
            for _ in 0..val+1 {
              match &iter.peek() { // Don't add spaces if last word
                &Some(_) => {
                  obj.push_str( " " );
                },
                &None => {},
              }
            }
          },
          None => { break },
        }
      }
      obj
    }
  }

  /// Substitute string character for each index given
  pub trait SubstMarks {
    /// # Example
    /// ```
    /// use array_tool::string::SubstMarks;
    ///
    /// "asdf asdf asdf".subst_marks(vec![0,5,8], "Z");
    /// ```
    ///
    /// # Output
    /// ```text
    /// "Zsdf ZsdZ asdf"
    /// ```
    fn subst_marks(&self, marks: Vec<usize>, chr: &'static str) -> String;
  }
  impl SubstMarks for &'static str {
    fn subst_marks(&self, marks: Vec<usize>, chr: &'static str) -> String {
      let mut output = String::with_capacity(self.len());
      for x in 0..self.len() {
        if marks.contains(&x) {
          output.push_str(chr)
        } else {
          output.push(self.chars().nth(x).unwrap())
        }
      }
      output
    }
  }

  /// After whitespace
  pub trait AfterWhitespace {
    /// Given offset method will seek from there to end of string to find the first
    /// non white space.  Resulting value is counted from offset.
    fn seek_end_of_whitespace(&self, offset: usize) -> Option<usize>;
  }
  impl AfterWhitespace for &'static str {
    #![allow(unsafe_code)]
    fn seek_end_of_whitespace(&self, offset: usize) -> Option<usize> {
      if self.len() < offset { return None; };
      let mut seeker = unsafe { self.slice_unchecked(offset, self.len()) }.chars();
      let mut val = None;
      let mut indx = 0;
      loop {
        match seeker.next() {
          Some(x) => {
            if x.ne(&" ".chars().next().unwrap()) {
              val = Some(indx);
              break;
            }
            indx += 1;
          },
          None => { break; },
        }
      }
      val
    }
  }

  /// Word wrapping
  pub trait WordWrap {
    ///  White space is treated as valid content and new lines will only be swapped in for
    ///  the last white space character at the end of the given width.  White space may reach beyond
    ///  the width you've provided.  You will need to trim end of lines in your own output (e.g.
    ///  splitting string at each new line and printing the line with trim_right).  Or just trust
    ///  that lines that are beyond the width are just white space and only print the width -
    ///  ignoring tailing white space.
    ///
    /// # Example
    /// ```
    /// use array_tool::string::WordWrap;
    ///
    /// "asd asdf asd".word_wrap(8);
    /// ```
    ///
    /// # Output
    /// ```text
    /// "asd asdf\nasd"
    /// ```
    fn word_wrap(&self, width: usize) -> String;
  }
  impl WordWrap for &'static str {
    #![allow(unsafe_code)]
    fn word_wrap(&self, width: usize) -> String {
      let mut markers = vec![];
      fn wordwrap(t: &'static str, chunk: usize, offset: usize, mrkrs: &mut Vec<usize>) -> String {
        let nl = unsafe {
          t.slice_unchecked(offset,offset+chunk+1) // Check if "\n" esists even 1 beyond chunk
        }.rfind("\n");
        match nl {
          None => {
            let mark = unsafe {
              t.slice_unchecked(offset,offset+chunk)
            }.rfind(" ");
            match mark {
              Some(x) => {
                let mut eows = x; // end of white space
                // check if white space continues
                if offset+chunk < t.len() {
                  match t.seek_end_of_whitespace(offset+x) {
                    Some(a) => {
                      if a.ne(&0) {
                        eows = x+a-1;
                      }
                    },
                    None => {},
                  }
                }
                if offset+chunk < t.len() {
                  if !["\n".chars().next().unwrap(), " ".chars().next().unwrap()].contains(
                    &t.chars().nth(offset+eows+1).unwrap()
                  ) {
                    mrkrs.push(offset+eows)
                  }
                };
                wordwrap(t, chunk, offset+eows+1, mrkrs)
              },
              None => {
                if offset+chunk < t.len() { // String may continue
                  wordwrap(t, chunk, offset+1, mrkrs) // Recurse + 1 until next space
                } else {
                  use string::SubstMarks;

                  return t.subst_marks(mrkrs.to_vec(), "\n")
                }
              },
            }
          },
          Some(x) => {
            wordwrap(t, chunk, offset+x+1, mrkrs)
          },
        }
      };
      wordwrap(self, width, 0, &mut markers)
    }
  }
}
<commit_msg>fix type [ci skip]<commit_after>// Copyright 2015-2016 Daniel P. Clark & array_tool Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

/// A string is a collection so we should have more methods for handling strings.
pub mod string {
  /// Justify - expand line to given width
  pub trait Justify {
    /// # Example
    /// ```
    /// use array_tool::string::Justify;
    ///
    /// "asd asdf asd".justify_line(14);
    /// ```
    ///
    /// # Output
    /// ```text
    /// "asd  asdf  asd"
    /// ```
    fn justify_line(&self, width: usize) -> String;
  }

  impl Justify for &'static str {
    fn justify_line(&self, width: usize) -> String {
      let trimmed = self.trim() ;
      let len = trimmed.len();
      if len >= width { return self.to_string(); };
      let difference = width - len;
      let iter = trimmed.split_whitespace();
      let spaces = iter.count() - 1;
      let mut iter = trimmed.split_whitespace().peekable();
      if spaces == 0 { return self.to_string(); }
      let mut obj = String::with_capacity(width);

      let div = difference / spaces;
      let mut remainder = difference % spaces;

      loop {
        match iter.next() {
          Some(x) => {
            obj.push_str( x );
            let val = if remainder > 0 {
              remainder = remainder - 1;
              div + 1
            } else { div };
            for _ in 0..val+1 {
              match &iter.peek() { // Don't add spaces if last word
                &Some(_) => {
                  obj.push_str( " " );
                },
                &None => {},
              }
            }
          },
          None => { break },
        }
      }
      obj
    }
  }

  /// Substitute string character for each index given
  pub trait SubstMarks {
    /// # Example
    /// ```
    /// use array_tool::string::SubstMarks;
    ///
    /// "asdf asdf asdf".subst_marks(vec![0,5,8], "Z");
    /// ```
    ///
    /// # Output
    /// ```text
    /// "Zsdf ZsdZ asdf"
    /// ```
    fn subst_marks(&self, marks: Vec<usize>, chr: &'static str) -> String;
  }
  impl SubstMarks for &'static str {
    fn subst_marks(&self, marks: Vec<usize>, chr: &'static str) -> String {
      let mut output = String::with_capacity(self.len());
      for x in 0..self.len() {
        if marks.contains(&x) {
          output.push_str(chr)
        } else {
          output.push(self.chars().nth(x).unwrap())
        }
      }
      output
    }
  }

  /// After whitespace
  pub trait AfterWhitespace {
    /// Given offset method will seek from there to end of string to find the first
    /// non white space.  Resulting value is counted from offset.
    fn seek_end_of_whitespace(&self, offset: usize) -> Option<usize>;
  }
  impl AfterWhitespace for &'static str {
    #![allow(unsafe_code)]
    fn seek_end_of_whitespace(&self, offset: usize) -> Option<usize> {
      if self.len() < offset { return None; };
      let mut seeker = unsafe { self.slice_unchecked(offset, self.len()) }.chars();
      let mut val = None;
      let mut indx = 0;
      loop {
        match seeker.next() {
          Some(x) => {
            if x.ne(&" ".chars().next().unwrap()) {
              val = Some(indx);
              break;
            }
            indx += 1;
          },
          None => { break; },
        }
      }
      val
    }
  }

  /// Word wrapping
  pub trait WordWrap {
    ///  White space is treated as valid content and new lines will only be swapped in for
    ///  the last white space character at the end of the given width.  White space may reach beyond
    ///  the width you've provided.  You will need to trim end of lines in your own output (e.g.
    ///  splitting string at each new line and printing the line with trim_right).  Or just trust
    ///  that lines that are beyond the width are just white space and only print the width -
    ///  ignoring tailing white space.
    ///
    /// # Example
    /// ```
    /// use array_tool::string::WordWrap;
    ///
    /// "asd asdf asd".word_wrap(8);
    /// ```
    ///
    /// # Output
    /// ```text
    /// "asd asdf\nasd"
    /// ```
    fn word_wrap(&self, width: usize) -> String;
  }
  impl WordWrap for &'static str {
    #![allow(unsafe_code)]
    fn word_wrap(&self, width: usize) -> String {
      let mut markers = vec![];
      fn wordwrap(t: &'static str, chunk: usize, offset: usize, mrkrs: &mut Vec<usize>) -> String {
        let nl = unsafe {
          t.slice_unchecked(offset,offset+chunk+1) // Check if "\n" exists even 1 beyond chunk
        }.rfind("\n");
        match nl {
          None => {
            let mark = unsafe {
              t.slice_unchecked(offset,offset+chunk)
            }.rfind(" ");
            match mark {
              Some(x) => {
                let mut eows = x; // end of white space
                // check if white space continues
                if offset+chunk < t.len() {
                  match t.seek_end_of_whitespace(offset+x) {
                    Some(a) => {
                      if a.ne(&0) {
                        eows = x+a-1;
                      }
                    },
                    None => {},
                  }
                }
                if offset+chunk < t.len() {
                  if !["\n".chars().next().unwrap(), " ".chars().next().unwrap()].contains(
                    &t.chars().nth(offset+eows+1).unwrap()
                  ) {
                    mrkrs.push(offset+eows)
                  }
                };
                wordwrap(t, chunk, offset+eows+1, mrkrs)
              },
              None => {
                if offset+chunk < t.len() { // String may continue
                  wordwrap(t, chunk, offset+1, mrkrs) // Recurse + 1 until next space
                } else {
                  use string::SubstMarks;

                  return t.subst_marks(mrkrs.to_vec(), "\n")
                }
              },
            }
          },
          Some(x) => {
            wordwrap(t, chunk, offset+x+1, mrkrs)
          },
        }
      };
      wordwrap(self, width, 0, &mut markers)
    }
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2018, Alessandro Ghedini
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use ::Result;

use std::cmp;
use std::collections::hash_map;
use std::collections::BinaryHeap;
use std::collections::VecDeque;
use std::ops::Deref;

#[derive(Default)]
pub struct Stream {
    recv: RecvBuf,
    send: SendBuf,

    pub tx_data: usize,
    pub max_tx_data: usize,
}

impl Stream {
    pub fn new(max_data: usize) -> Stream {
        Stream {
            recv: RecvBuf::default(),
            send: SendBuf::default(),

            tx_data: 0,
            max_tx_data: max_data,
        }
    }

    pub fn push_recv(&mut self, buf: RangeBuf) -> Result<()> {
        self.recv.push(buf)
    }

    pub fn pop_recv(&mut self) -> Result<RangeBuf> {
        self.recv.pop()
    }

    pub fn push_send(&mut self, data: &[u8], fin: bool) -> Result<()> {
        self.send.push(data, fin)
    }

    pub fn pop_send(&mut self, max_len: usize) -> Result<RangeBuf> {
        self.send.pop(max_len)
    }

    pub fn can_read(&self) -> bool {
        self.recv.ready()
    }

    pub fn can_write(&self) -> bool {
        self.send.ready()
    }
}

pub struct StreamIterator<'a> {
    streams: hash_map::Iter<'a, u64, Stream>,
}

impl<'a> StreamIterator<'a> {
    pub fn new(streams: hash_map::Iter<'a, u64, Stream>) -> StreamIterator {
        StreamIterator {
            streams,
        }
    }
}

impl<'a> Iterator for StreamIterator<'a> {
    type Item = u64;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            match self.streams.next() {
                Some((k, s)) => {
                    if !s.can_read() {
                        continue;
                    }

                    return Some(*k);
                },

                None => return None,
            }
        }
    }
}

#[derive(Default)]
struct RecvBuf {
    data: BinaryHeap<RangeBuf>,
    off: usize,
    len: usize,
}

impl RecvBuf {
    fn push(&mut self, buf: RangeBuf) -> Result<()> {
        self.len = cmp::max(self.len, buf.off + buf.len());

        self.data.push(buf);

        Ok(())
    }

    fn pop(&mut self) -> Result<RangeBuf> {
        let mut out = RangeBuf::default();

        while self.ready() {
            let mut buf = match self.data.pop() {
                Some(v) => v,
                None => break,
            };

            self.off += buf.len();
            self.len -= buf.len();

            out.fin = out.fin || buf.fin();

            out.data.append(&mut buf.data);
        }

        Ok(out)
    }

    fn ready(&self) -> bool {
        let buf = match self.data.peek() {
            Some(v) => v,
            None => return false,
        };

        buf.off == self.off
    }

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

#[derive(Default)]
struct SendBuf {
    data: VecDeque<RangeBuf>,
    off: usize,
    len: usize,
}

impl SendBuf {
    fn push(&mut self, data: &[u8], fin: bool) -> Result<()> {
        let buf = RangeBuf::from(data, self.off, fin);

        self.off += buf.len();
        self.len += buf.len();

        self.data.push_back(buf);

        Ok(())
    }

    fn pop(&mut self, max_len: usize) -> Result<RangeBuf> {
        let mut out = RangeBuf::default();
        let mut out_len = max_len;

        while out_len > 0 && self.ready() {
            let mut buf = match self.data.pop_front() {
                Some(v) => v,
                None => break,
            };

            if buf.len() > out_len {
                let new_buf = RangeBuf {
                    data: buf.data.split_off(out_len),
                    off: buf.off + out_len,
                    fin: buf.fin,
                };

                buf.fin = false;

                self.data.push_front(new_buf);
            }

            if out.len() == 0 {
                out.off = buf.off;
            }

            self.len -= buf.len();

            out_len -= buf.len();

            out.fin = out.fin || buf.fin();

            out.data.append(&mut buf.data);
        }

        Ok(out)
    }

    fn ready(&self) -> bool {
        self.len() > 0
    }

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

#[derive(Debug, Default, Eq)]
pub struct RangeBuf {
    data: Vec<u8>,
    off: usize,
    fin: bool,
}

impl RangeBuf {
    pub fn from(buf: &[u8], off: usize, fin: bool) -> RangeBuf {
        RangeBuf {
            data: Vec::from(buf),
            off,
            fin,
        }
    }

    pub fn fin(&self) -> bool {
        self.fin
    }

    pub fn off(&self) -> usize {
        self.off
    }

    pub fn len(&self) -> usize {
        self.data.len()
    }
}

impl Deref for RangeBuf {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        &self.data
    }
}

impl Ord for RangeBuf {
    fn cmp(&self, other: &RangeBuf) -> cmp::Ordering {
        // Invert ordering to implement min-heap.
        self.off.cmp(&other.off).reverse()
    }
}

impl PartialOrd for RangeBuf {
    fn partial_cmp(&self, other: &RangeBuf) -> Option<cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialEq for RangeBuf {
    fn eq(&self, other: &RangeBuf) -> bool {
        self.off == other.off
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn empty_read() {
        let mut buf = RecvBuf::default();
        assert_eq!(buf.len(), 0);

        let read = buf.pop().unwrap();
        assert_eq!(read.len(), 0);
    }

    #[test]
    fn ordered_read() {
        let mut buf = RecvBuf::default();
        assert_eq!(buf.len(), 0);

        let first = RangeBuf::from(b"hello", 0, false);
        let second = RangeBuf::from(b"world", 5, false);
        let third = RangeBuf::from(b"something", 10, false);

        assert!(buf.push(second).is_ok());
        assert_eq!(buf.len(), 10);

        let read = buf.pop().unwrap();
        assert_eq!(read.len(), 0);

        assert!(buf.push(third).is_ok());
        assert_eq!(buf.len(), 19);

        assert!(buf.push(first).is_ok());
        assert_eq!(buf.len(), 19);

        let read = buf.pop().unwrap();
        assert_eq!(read.len(), 19);
        assert_eq!(&read[..], b"helloworldsomething");
        assert_eq!(buf.len(), 0);

        let read = buf.pop().unwrap();
        assert_eq!(read.len(), 0);
    }

    #[test]
    fn incomplete_read() {
        let mut buf = RecvBuf::default();
        assert_eq!(buf.len(), 0);

        let first = RangeBuf::from(b"something", 0, false);
        let second = RangeBuf::from(b"helloworld", 9, false);

        assert!(buf.push(second).is_ok());
        assert_eq!(buf.len(), 19);

        let read = buf.pop().unwrap();
        assert_eq!(read.len(), 0);

        assert!(buf.push(first).is_ok());
        assert_eq!(buf.len(), 19);

        let read = buf.pop().unwrap();
        assert_eq!(read.len(), 19);
        assert_eq!(&read[..], b"somethinghelloworld");
        assert_eq!(buf.len(), 0);
    }

    #[test]
    fn empty_write() {
        let mut buf = RecvBuf::default();
        assert_eq!(buf.len(), 0);

        let write = buf.pop().unwrap();
        assert_eq!(write.len(), 0);
    }

    #[test]
    fn multi_write() {
        let mut buf = SendBuf::default();
        assert_eq!(buf.len(), 0);

        let first: [u8; 9] = *b"something";
        let second: [u8; 10] = *b"helloworld";

        assert!(buf.push(&first, false).is_ok());
        assert_eq!(buf.len(), 9);

        assert!(buf.push(&second, false).is_ok());
        assert_eq!(buf.len(), 19);

        let write = buf.pop(128).unwrap();
        assert_eq!(write.len(), 19);
        assert_eq!(&write[..], b"somethinghelloworld");
        assert_eq!(buf.len(), 0);
    }

    #[test]
    fn split_write() {
        let mut buf = SendBuf::default();
        assert_eq!(buf.len(), 0);

        let first: [u8; 9] = *b"something";
        let second: [u8; 10] = *b"helloworld";

        assert!(buf.push(&first, false).is_ok());
        assert_eq!(buf.len(), 9);

        assert!(buf.push(&second, true).is_ok());
        assert_eq!(buf.len(), 19);

        let write = buf.pop(10).unwrap();
        assert_eq!(write.off(), 0);
        assert_eq!(write.len(), 10);
        assert_eq!(&write[..], b"somethingh");
        assert_eq!(buf.len(), 9);

        let write = buf.pop(5).unwrap();
        assert_eq!(write.off(), 10);
        assert_eq!(write.len(), 5);
        assert_eq!(&write[..], b"ellow");
        assert_eq!(buf.len(), 4);

        let write = buf.pop(10).unwrap();
        assert_eq!(write.off(), 15);
        assert_eq!(write.len(), 4);
        assert_eq!(&write[..], b"orld");
        assert_eq!(buf.len(), 0);
    }
}
<commit_msg>stream: silence unused function warning<commit_after>// Copyright (c) 2018, Alessandro Ghedini
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use ::Result;

use std::cmp;
use std::collections::hash_map;
use std::collections::BinaryHeap;
use std::collections::VecDeque;
use std::ops::Deref;

#[derive(Default)]
pub struct Stream {
    recv: RecvBuf,
    send: SendBuf,

    pub tx_data: usize,
    pub max_tx_data: usize,
}

impl Stream {
    pub fn new(max_data: usize) -> Stream {
        Stream {
            recv: RecvBuf::default(),
            send: SendBuf::default(),

            tx_data: 0,
            max_tx_data: max_data,
        }
    }

    pub fn push_recv(&mut self, buf: RangeBuf) -> Result<()> {
        self.recv.push(buf)
    }

    pub fn pop_recv(&mut self) -> Result<RangeBuf> {
        self.recv.pop()
    }

    pub fn push_send(&mut self, data: &[u8], fin: bool) -> Result<()> {
        self.send.push(data, fin)
    }

    pub fn pop_send(&mut self, max_len: usize) -> Result<RangeBuf> {
        self.send.pop(max_len)
    }

    pub fn can_read(&self) -> bool {
        self.recv.ready()
    }

    pub fn can_write(&self) -> bool {
        self.send.ready()
    }
}

pub struct StreamIterator<'a> {
    streams: hash_map::Iter<'a, u64, Stream>,
}

impl<'a> StreamIterator<'a> {
    pub fn new(streams: hash_map::Iter<'a, u64, Stream>) -> StreamIterator {
        StreamIterator {
            streams,
        }
    }
}

impl<'a> Iterator for StreamIterator<'a> {
    type Item = u64;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            match self.streams.next() {
                Some((k, s)) => {
                    if !s.can_read() {
                        continue;
                    }

                    return Some(*k);
                },

                None => return None,
            }
        }
    }
}

#[derive(Default)]
struct RecvBuf {
    data: BinaryHeap<RangeBuf>,
    off: usize,
    len: usize,
}

impl RecvBuf {
    fn push(&mut self, buf: RangeBuf) -> Result<()> {
        self.len = cmp::max(self.len, buf.off + buf.len());

        self.data.push(buf);

        Ok(())
    }

    fn pop(&mut self) -> Result<RangeBuf> {
        let mut out = RangeBuf::default();

        while self.ready() {
            let mut buf = match self.data.pop() {
                Some(v) => v,
                None => break,
            };

            self.off += buf.len();
            self.len -= buf.len();

            out.fin = out.fin || buf.fin();

            out.data.append(&mut buf.data);
        }

        Ok(out)
    }

    fn ready(&self) -> bool {
        if self.len() == 0 {
            return false;
        }

        let buf = match self.data.peek() {
            Some(v) => v,
            None => return false,
        };

        buf.off == self.off
    }

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

#[derive(Default)]
struct SendBuf {
    data: VecDeque<RangeBuf>,
    off: usize,
    len: usize,
}

impl SendBuf {
    fn push(&mut self, data: &[u8], fin: bool) -> Result<()> {
        let buf = RangeBuf::from(data, self.off, fin);

        self.off += buf.len();
        self.len += buf.len();

        self.data.push_back(buf);

        Ok(())
    }

    fn pop(&mut self, max_len: usize) -> Result<RangeBuf> {
        let mut out = RangeBuf::default();
        let mut out_len = max_len;

        while out_len > 0 && self.ready() {
            let mut buf = match self.data.pop_front() {
                Some(v) => v,
                None => break,
            };

            if buf.len() > out_len {
                let new_buf = RangeBuf {
                    data: buf.data.split_off(out_len),
                    off: buf.off + out_len,
                    fin: buf.fin,
                };

                buf.fin = false;

                self.data.push_front(new_buf);
            }

            if out.len() == 0 {
                out.off = buf.off;
            }

            self.len -= buf.len();

            out_len -= buf.len();

            out.fin = out.fin || buf.fin();

            out.data.append(&mut buf.data);
        }

        Ok(out)
    }

    fn ready(&self) -> bool {
        self.len() > 0
    }

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

#[derive(Debug, Default, Eq)]
pub struct RangeBuf {
    data: Vec<u8>,
    off: usize,
    fin: bool,
}

impl RangeBuf {
    pub fn from(buf: &[u8], off: usize, fin: bool) -> RangeBuf {
        RangeBuf {
            data: Vec::from(buf),
            off,
            fin,
        }
    }

    pub fn fin(&self) -> bool {
        self.fin
    }

    pub fn off(&self) -> usize {
        self.off
    }

    pub fn len(&self) -> usize {
        self.data.len()
    }
}

impl Deref for RangeBuf {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        &self.data
    }
}

impl Ord for RangeBuf {
    fn cmp(&self, other: &RangeBuf) -> cmp::Ordering {
        // Invert ordering to implement min-heap.
        self.off.cmp(&other.off).reverse()
    }
}

impl PartialOrd for RangeBuf {
    fn partial_cmp(&self, other: &RangeBuf) -> Option<cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialEq for RangeBuf {
    fn eq(&self, other: &RangeBuf) -> bool {
        self.off == other.off
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn empty_read() {
        let mut buf = RecvBuf::default();
        assert_eq!(buf.len(), 0);

        let read = buf.pop().unwrap();
        assert_eq!(read.len(), 0);
    }

    #[test]
    fn ordered_read() {
        let mut buf = RecvBuf::default();
        assert_eq!(buf.len(), 0);

        let first = RangeBuf::from(b"hello", 0, false);
        let second = RangeBuf::from(b"world", 5, false);
        let third = RangeBuf::from(b"something", 10, false);

        assert!(buf.push(second).is_ok());
        assert_eq!(buf.len(), 10);

        let read = buf.pop().unwrap();
        assert_eq!(read.len(), 0);

        assert!(buf.push(third).is_ok());
        assert_eq!(buf.len(), 19);

        assert!(buf.push(first).is_ok());
        assert_eq!(buf.len(), 19);

        let read = buf.pop().unwrap();
        assert_eq!(read.len(), 19);
        assert_eq!(&read[..], b"helloworldsomething");
        assert_eq!(buf.len(), 0);

        let read = buf.pop().unwrap();
        assert_eq!(read.len(), 0);
    }

    #[test]
    fn incomplete_read() {
        let mut buf = RecvBuf::default();
        assert_eq!(buf.len(), 0);

        let first = RangeBuf::from(b"something", 0, false);
        let second = RangeBuf::from(b"helloworld", 9, false);

        assert!(buf.push(second).is_ok());
        assert_eq!(buf.len(), 19);

        let read = buf.pop().unwrap();
        assert_eq!(read.len(), 0);

        assert!(buf.push(first).is_ok());
        assert_eq!(buf.len(), 19);

        let read = buf.pop().unwrap();
        assert_eq!(read.len(), 19);
        assert_eq!(&read[..], b"somethinghelloworld");
        assert_eq!(buf.len(), 0);
    }

    #[test]
    fn empty_write() {
        let mut buf = RecvBuf::default();
        assert_eq!(buf.len(), 0);

        let write = buf.pop().unwrap();
        assert_eq!(write.len(), 0);
    }

    #[test]
    fn multi_write() {
        let mut buf = SendBuf::default();
        assert_eq!(buf.len(), 0);

        let first: [u8; 9] = *b"something";
        let second: [u8; 10] = *b"helloworld";

        assert!(buf.push(&first, false).is_ok());
        assert_eq!(buf.len(), 9);

        assert!(buf.push(&second, false).is_ok());
        assert_eq!(buf.len(), 19);

        let write = buf.pop(128).unwrap();
        assert_eq!(write.len(), 19);
        assert_eq!(&write[..], b"somethinghelloworld");
        assert_eq!(buf.len(), 0);
    }

    #[test]
    fn split_write() {
        let mut buf = SendBuf::default();
        assert_eq!(buf.len(), 0);

        let first: [u8; 9] = *b"something";
        let second: [u8; 10] = *b"helloworld";

        assert!(buf.push(&first, false).is_ok());
        assert_eq!(buf.len(), 9);

        assert!(buf.push(&second, true).is_ok());
        assert_eq!(buf.len(), 19);

        let write = buf.pop(10).unwrap();
        assert_eq!(write.off(), 0);
        assert_eq!(write.len(), 10);
        assert_eq!(&write[..], b"somethingh");
        assert_eq!(buf.len(), 9);

        let write = buf.pop(5).unwrap();
        assert_eq!(write.off(), 10);
        assert_eq!(write.len(), 5);
        assert_eq!(&write[..], b"ellow");
        assert_eq!(buf.len(), 4);

        let write = buf.pop(10).unwrap();
        assert_eq!(write.off(), 15);
        assert_eq!(write.len(), 4);
        assert_eq!(&write[..], b"orld");
        assert_eq!(buf.len(), 0);
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::fmt;
use std::cmp::min;
use std::sync::{Arc, Mutex, MutexGuard};

use rotor::mio;

/// In memory stream
///
/// The struct pretends to be `mio::Evented` but it have `unimplemented` panic
/// when actually added to the loop. I.e. it should be used in tests which
/// use plain state machine, and not the event loop.
///
/// Clarification: it implements `Read`/`Write` but, it's not a pipe. I.e.
/// buffers for `Read` and `Write` are separate. You use `push_xxx` methods to
/// add data for the next `Read::read`.
///
/// You should clone the stream. Feed one to the application and second one
/// to the unit testing code.
#[derive(Clone)]
pub struct MemIo(Arc<Mutex<Bufs>>);

struct Bufs {
    input: Vec<u8>,
    input_closed: bool,
    output: Vec<u8>,
}

impl MemIo {
    /// Create a stream
    ///
    /// Stream start empty
    pub fn new() -> MemIo {
        MemIo(Arc::new(Mutex::new(Bufs {
            input: Vec::new(),
            input_closed: false,
            output: Vec::new(),
        })))
    }
    /// Push some bytes to an input buffer of an application
    pub fn push_bytes<T:AsRef<[u8]>>(&mut self, val: T) {
        let mut bufs = self.bufs();
        bufs.input.extend(val.as_ref());
        assert!(!bufs.input_closed);
    }
    /// Marks input as closed so application gets end-of-stream event on next
    /// read
    pub fn shutdown_input(&self) {
        self.bufs().input_closed = true;
    }
    /// Get output as a string
    ///
    /// This is created by `String::from_utf8_lossy` so kinda works for binary
    /// data too, but not exactly. If you need to compare some non-textual
    /// data use `output_bytes()`
    ///
    /// The data in the buffer are not discarded. Next call will return same
    /// data again.
    pub fn output_str(&self) -> String {
        // Unfortunately we can't return a slice, because of borrowing rules
        // but it's for unit tests, so we don't care performance
        String::from_utf8_lossy(&self.bufs().output).to_string()
    }
    /// Get data in the output buffer
    ///
    /// The data in the buffer are not discarded. Next call will return same
    /// data again.
    pub fn output_bytes(&self) -> Vec<u8> {
        // Unfortunately we can't return a slice, because of borrowing rules
        // but it's for unit tests, so we don't care performance
        self.bufs().output.clone()
    }
    fn bufs(&self) -> MutexGuard<Bufs> {
        self.0.lock().expect("Poisoned MemIo (mock stream)")
    }
}

impl fmt::Debug for MemIo {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let bufs = self.bufs();
        fmt.debug_struct("MemIo")
        .field("input", &String::from_utf8_lossy(&bufs.input))
        .field("input_closed", &bufs.input_closed)
        .field("output", &String::from_utf8_lossy(&bufs.output))
        .finish()
    }
}

impl io::Read for MemIo {
    fn read(&mut self, val: &mut [u8]) -> io::Result<usize> {
        let mut bufs = self.bufs();
        let bytes = min(val.len(), bufs.input.len());
        if bytes > 0 {
            println!("val {:?}", val);
            assert_eq!(io::copy(
                &mut io::Cursor::new(&bufs.input),
                &mut io::Cursor::new(val))
                .expect("copy always work"), bytes as u64);
            bufs.input.drain(..bytes);
            Ok(bytes)
        } else {
            if bufs.input_closed {
                Ok(0)
            } else {
                Err(io::Error::new(io::ErrorKind::WouldBlock,
                    "no data in mocked input buffer"))
            }
        }
    }
}
impl io::Write for MemIo {
    fn write(&mut self, val: &[u8]) -> io::Result<usize> {
        let mut bufs = self.bufs();
        io::copy(&mut io::Cursor::new(val), &mut bufs.output)
            .map(|x| x as usize)
    }
    fn flush(&mut self) -> io::Result<()> { Ok(()) }
}

impl mio::Evented for MemIo {
    fn register(&self, _selector: &mut mio::Selector,
        _token: mio::Token, _interest: mio::EventSet, _opts: mio::PollOpt)
        -> io::Result<()>
    { unreachable!("trying to poll on mock stream") }
    fn reregister(&self, _selector: &mut mio::Selector, _token: mio::Token,
        _interest: mio::EventSet, _opts: mio::PollOpt) -> io::Result<()>
    { unreachable!("trying to poll on mock stream") }
    fn deregister(&self, _selector: &mut mio::Selector) -> io::Result<()>
    { unreachable!("trying to poll on mock stream") }
}

#[cfg(test)]
mod self_test {
    use std::io::{Read, Write};
    use super::MemIo;

    #[test]
    fn input() {
        let mut s = MemIo::new();
        s.push_bytes("hello world");
        s.shutdown_input();
        let mut b = String::new();
        assert_eq!(s.read_to_string(&mut b).unwrap(), 11);
        assert_eq!(&b, "hello world");
    }

    #[test]
    fn output() {
        let mut s = MemIo::new();
        s.write(b"hello").expect("write failed");
        s.write(b"world").expect("write failed");
        assert_eq!(s.output_str(), "helloworld");
    }

}
<commit_msg>Remove debugging print<commit_after>use std::io;
use std::fmt;
use std::cmp::min;
use std::sync::{Arc, Mutex, MutexGuard};

use rotor::mio;

/// In memory stream
///
/// The struct pretends to be `mio::Evented` but it have `unimplemented` panic
/// when actually added to the loop. I.e. it should be used in tests which
/// use plain state machine, and not the event loop.
///
/// Clarification: it implements `Read`/`Write` but, it's not a pipe. I.e.
/// buffers for `Read` and `Write` are separate. You use `push_xxx` methods to
/// add data for the next `Read::read`.
///
/// You should clone the stream. Feed one to the application and second one
/// to the unit testing code.
#[derive(Clone)]
pub struct MemIo(Arc<Mutex<Bufs>>);

struct Bufs {
    input: Vec<u8>,
    input_closed: bool,
    output: Vec<u8>,
}

impl MemIo {
    /// Create a stream
    ///
    /// Stream start empty
    pub fn new() -> MemIo {
        MemIo(Arc::new(Mutex::new(Bufs {
            input: Vec::new(),
            input_closed: false,
            output: Vec::new(),
        })))
    }
    /// Push some bytes to an input buffer of an application
    pub fn push_bytes<T:AsRef<[u8]>>(&mut self, val: T) {
        let mut bufs = self.bufs();
        bufs.input.extend(val.as_ref());
        assert!(!bufs.input_closed);
    }
    /// Marks input as closed so application gets end-of-stream event on next
    /// read
    pub fn shutdown_input(&self) {
        self.bufs().input_closed = true;
    }
    /// Get output as a string
    ///
    /// This is created by `String::from_utf8_lossy` so kinda works for binary
    /// data too, but not exactly. If you need to compare some non-textual
    /// data use `output_bytes()`
    ///
    /// The data in the buffer are not discarded. Next call will return same
    /// data again.
    pub fn output_str(&self) -> String {
        // Unfortunately we can't return a slice, because of borrowing rules
        // but it's for unit tests, so we don't care performance
        String::from_utf8_lossy(&self.bufs().output).to_string()
    }
    /// Get data in the output buffer
    ///
    /// The data in the buffer are not discarded. Next call will return same
    /// data again.
    pub fn output_bytes(&self) -> Vec<u8> {
        // Unfortunately we can't return a slice, because of borrowing rules
        // but it's for unit tests, so we don't care performance
        self.bufs().output.clone()
    }
    fn bufs(&self) -> MutexGuard<Bufs> {
        self.0.lock().expect("Poisoned MemIo (mock stream)")
    }
}

impl fmt::Debug for MemIo {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let bufs = self.bufs();
        fmt.debug_struct("MemIo")
        .field("input", &String::from_utf8_lossy(&bufs.input))
        .field("input_closed", &bufs.input_closed)
        .field("output", &String::from_utf8_lossy(&bufs.output))
        .finish()
    }
}

impl io::Read for MemIo {
    fn read(&mut self, val: &mut [u8]) -> io::Result<usize> {
        let mut bufs = self.bufs();
        let bytes = min(val.len(), bufs.input.len());
        if bytes > 0 {
            assert_eq!(io::copy(
                &mut io::Cursor::new(&bufs.input),
                &mut io::Cursor::new(val))
                .expect("copy always work"), bytes as u64);
            bufs.input.drain(..bytes);
            Ok(bytes)
        } else {
            if bufs.input_closed {
                Ok(0)
            } else {
                Err(io::Error::new(io::ErrorKind::WouldBlock,
                    "no data in mocked input buffer"))
            }
        }
    }
}
impl io::Write for MemIo {
    fn write(&mut self, val: &[u8]) -> io::Result<usize> {
        let mut bufs = self.bufs();
        io::copy(&mut io::Cursor::new(val), &mut bufs.output)
            .map(|x| x as usize)
    }
    fn flush(&mut self) -> io::Result<()> { Ok(()) }
}

impl mio::Evented for MemIo {
    fn register(&self, _selector: &mut mio::Selector,
        _token: mio::Token, _interest: mio::EventSet, _opts: mio::PollOpt)
        -> io::Result<()>
    { unreachable!("trying to poll on mock stream") }
    fn reregister(&self, _selector: &mut mio::Selector, _token: mio::Token,
        _interest: mio::EventSet, _opts: mio::PollOpt) -> io::Result<()>
    { unreachable!("trying to poll on mock stream") }
    fn deregister(&self, _selector: &mut mio::Selector) -> io::Result<()>
    { unreachable!("trying to poll on mock stream") }
}

#[cfg(test)]
mod self_test {
    use std::io::{Read, Write};
    use super::MemIo;

    #[test]
    fn input() {
        let mut s = MemIo::new();
        s.push_bytes("hello world");
        s.shutdown_input();
        let mut b = String::new();
        assert_eq!(s.read_to_string(&mut b).unwrap(), 11);
        assert_eq!(&b, "hello world");
    }

    #[test]
    fn output() {
        let mut s = MemIo::new();
        s.write(b"hello").expect("write failed");
        s.write(b"world").expect("write failed");
        assert_eq!(s.output_str(), "helloworld");
    }

}
<|endoftext|>


<commit_before>use odbc_sys::*;
use std::cmp::min;
use std::mem::size_of;

/// Indicates a type which can be used as a target in `Statement::get_data()`.
pub unsafe trait Target {
    /// C Data type of the buffer returned by `value_ptr()`.
    fn c_data_type() -> SqlCDataType;
    /// Pointer to the buffer in which should be filled with data.
    fn value_ptr(&mut self) -> SQLPOINTER;
    /// Length of the buffer returned by `value_ptr()` in bytes.
    fn buffer_len(&self) -> SQLLEN;
}

unsafe impl Target for [SQLCHAR] {
    fn c_data_type() -> SqlCDataType {
        SQL_C_CHAR
    }

    fn value_ptr(&mut self) -> SQLPOINTER {
        self.as_mut_ptr() as SQLPOINTER
    }

    fn buffer_len(&self) -> SQLLEN {
        min(self.len() as SQLLEN, SQLLEN::max_value())
    }
}

unsafe impl Target for SQLSMALLINT {
    fn c_data_type() -> SqlCDataType {
        SQL_C_SSHORT
    }

    fn value_ptr(&mut self) -> SQLPOINTER {
        let ptr: *mut Self = self;
        ptr as SQLPOINTER
    }

    fn buffer_len(&self) -> SQLLEN {
        size_of::<Self>() as SQLLEN
    }
}

unsafe impl Target for SQLUSMALLINT {
    fn c_data_type() -> SqlCDataType {
        SQL_C_USHORT
    }

    fn value_ptr(&mut self) -> SQLPOINTER {
        let ptr: *mut Self = self;
        ptr as SQLPOINTER
    }

    fn buffer_len(&self) -> SQLLEN {
        size_of::<Self>() as SQLLEN
    }
}

unsafe impl Target for SQLINTEGER {
    fn c_data_type() -> SqlCDataType {
        SQL_C_SLONG
    }

    fn value_ptr(&mut self) -> SQLPOINTER {
        let ptr: *mut Self = self;
        ptr as SQLPOINTER
    }

    fn buffer_len(&self) -> SQLLEN {
        size_of::<Self>() as SQLLEN
    }
}

unsafe impl Target for SQLUINTEGER {
    fn c_data_type() -> SqlCDataType {
        SQL_C_ULONG
    }

    fn value_ptr(&mut self) -> SQLPOINTER {
        let ptr: *mut Self = self;
        ptr as SQLPOINTER
    }

    fn buffer_len(&self) -> SQLLEN {
        size_of::<Self>() as SQLLEN
    }
}

unsafe impl Target for f32 {
    fn c_data_type() -> SqlCDataType {
        SQL_C_FLOAT
    }

    fn value_ptr(&mut self) -> SQLPOINTER {
        let ptr: *mut Self = self;
        ptr as SQLPOINTER
    }

    fn buffer_len(&self) -> SQLLEN {
        size_of::<Self>() as SQLLEN
    }
}

unsafe impl Target for f64 {
    fn c_data_type() -> SqlCDataType {
        SQL_C_DOUBLE
    }

    fn value_ptr(&mut self) -> SQLPOINTER {
        let ptr: *mut Self = self;
        ptr as SQLPOINTER
    }

    fn buffer_len(&self) -> SQLLEN {
        size_of::<Self>() as SQLLEN
    }
}

unsafe impl Target for i8 {
    fn c_data_type() -> SqlCDataType {
        SQL_C_STINYINT
    }

    fn value_ptr(&mut self) -> SQLPOINTER {
        let ptr: *mut Self = self;
        ptr as SQLPOINTER
    }

    fn buffer_len(&self) -> SQLLEN {
        size_of::<Self>() as SQLLEN
    }
}

unsafe impl Target for SQLCHAR {
    fn c_data_type() -> SqlCDataType {
        SQL_C_UTINYINT
    }

    fn value_ptr(&mut self) -> SQLPOINTER {
        let ptr: *mut Self = self;
        ptr as SQLPOINTER
    }

    fn buffer_len(&self) -> SQLLEN {
        size_of::<Self>() as SQLLEN
    }
}

unsafe impl Target for i64 {
    fn c_data_type() -> SqlCDataType {
        SQL_C_SBIGINT
    }

    fn value_ptr(&mut self) -> SQLPOINTER {
        let ptr: *mut Self = self;
        ptr as SQLPOINTER
    }

    fn buffer_len(&self) -> SQLLEN {
        size_of::<Self>() as SQLLEN
    }
}

unsafe impl Target for u64 {
    fn c_data_type() -> SqlCDataType {
        SQL_C_UBIGINT
    }

    fn value_ptr(&mut self) -> SQLPOINTER {
        let ptr: *mut Self = self;
        ptr as SQLPOINTER
    }

    fn buffer_len(&self) -> SQLLEN {
        size_of::<Self>() as SQLLEN
    }
}<commit_msg>switch [u8] Target type to binary<commit_after>use odbc_sys::*;
use std::cmp::min;
use std::mem::size_of;

/// Indicates a type which can be used as a target in `Statement::get_data()`.
pub unsafe trait Target {
    /// C Data type of the buffer returned by `value_ptr()`.
    fn c_data_type() -> SqlCDataType;
    /// Pointer to the buffer in which should be filled with data.
    fn value_ptr(&mut self) -> SQLPOINTER;
    /// Length of the buffer returned by `value_ptr()` in bytes.
    fn buffer_len(&self) -> SQLLEN;
}

unsafe impl Target for [SQLCHAR] {
    fn c_data_type() -> SqlCDataType {
        SQL_C_BINARY
    }

    fn value_ptr(&mut self) -> SQLPOINTER {
        self.as_mut_ptr() as SQLPOINTER
    }

    fn buffer_len(&self) -> SQLLEN {
        min(self.len() as SQLLEN, SQLLEN::max_value())
    }
}

unsafe impl Target for SQLSMALLINT {
    fn c_data_type() -> SqlCDataType {
        SQL_C_SSHORT
    }

    fn value_ptr(&mut self) -> SQLPOINTER {
        let ptr: *mut Self = self;
        ptr as SQLPOINTER
    }

    fn buffer_len(&self) -> SQLLEN {
        size_of::<Self>() as SQLLEN
    }
}

unsafe impl Target for SQLUSMALLINT {
    fn c_data_type() -> SqlCDataType {
        SQL_C_USHORT
    }

    fn value_ptr(&mut self) -> SQLPOINTER {
        let ptr: *mut Self = self;
        ptr as SQLPOINTER
    }

    fn buffer_len(&self) -> SQLLEN {
        size_of::<Self>() as SQLLEN
    }
}

unsafe impl Target for SQLINTEGER {
    fn c_data_type() -> SqlCDataType {
        SQL_C_SLONG
    }

    fn value_ptr(&mut self) -> SQLPOINTER {
        let ptr: *mut Self = self;
        ptr as SQLPOINTER
    }

    fn buffer_len(&self) -> SQLLEN {
        size_of::<Self>() as SQLLEN
    }
}

unsafe impl Target for SQLUINTEGER {
    fn c_data_type() -> SqlCDataType {
        SQL_C_ULONG
    }

    fn value_ptr(&mut self) -> SQLPOINTER {
        let ptr: *mut Self = self;
        ptr as SQLPOINTER
    }

    fn buffer_len(&self) -> SQLLEN {
        size_of::<Self>() as SQLLEN
    }
}

unsafe impl Target for f32 {
    fn c_data_type() -> SqlCDataType {
        SQL_C_FLOAT
    }

    fn value_ptr(&mut self) -> SQLPOINTER {
        let ptr: *mut Self = self;
        ptr as SQLPOINTER
    }

    fn buffer_len(&self) -> SQLLEN {
        size_of::<Self>() as SQLLEN
    }
}

unsafe impl Target for f64 {
    fn c_data_type() -> SqlCDataType {
        SQL_C_DOUBLE
    }

    fn value_ptr(&mut self) -> SQLPOINTER {
        let ptr: *mut Self = self;
        ptr as SQLPOINTER
    }

    fn buffer_len(&self) -> SQLLEN {
        size_of::<Self>() as SQLLEN
    }
}

unsafe impl Target for i8 {
    fn c_data_type() -> SqlCDataType {
        SQL_C_STINYINT
    }

    fn value_ptr(&mut self) -> SQLPOINTER {
        let ptr: *mut Self = self;
        ptr as SQLPOINTER
    }

    fn buffer_len(&self) -> SQLLEN {
        size_of::<Self>() as SQLLEN
    }
}

unsafe impl Target for SQLCHAR {
    fn c_data_type() -> SqlCDataType {
        SQL_C_UTINYINT
    }

    fn value_ptr(&mut self) -> SQLPOINTER {
        let ptr: *mut Self = self;
        ptr as SQLPOINTER
    }

    fn buffer_len(&self) -> SQLLEN {
        size_of::<Self>() as SQLLEN
    }
}

unsafe impl Target for i64 {
    fn c_data_type() -> SqlCDataType {
        SQL_C_SBIGINT
    }

    fn value_ptr(&mut self) -> SQLPOINTER {
        let ptr: *mut Self = self;
        ptr as SQLPOINTER
    }

    fn buffer_len(&self) -> SQLLEN {
        size_of::<Self>() as SQLLEN
    }
}

unsafe impl Target for u64 {
    fn c_data_type() -> SqlCDataType {
        SQL_C_UBIGINT
    }

    fn value_ptr(&mut self) -> SQLPOINTER {
        let ptr: *mut Self = self;
        ptr as SQLPOINTER
    }

    fn buffer_len(&self) -> SQLLEN {
        size_of::<Self>() as SQLLEN
    }
}<|endoftext|>


<commit_before>use std::ops;
use time::Duration;
use output::Output;
use playlist::Playlist;
use song::Id;

pub trait ToPlaylistName {
    fn to_name(&self) -> &str;
}

impl ToPlaylistName for Playlist {
    fn to_name(&self) -> &str {
        &*self.name
    }
}

impl<'a> ToPlaylistName for &'a Playlist {
    fn to_name(&self) -> &str {
        &*self.name
    }
}

impl ToPlaylistName for str {
    fn to_name(&self) -> &str {
        self
    }
}

impl ToPlaylistName for String {
    fn to_name(&self) -> &str {
        &*self
    }
}

pub trait ToSeconds {
    fn to_seconds(self) -> f64;
}

impl ToSeconds for i64 {
    fn to_seconds(self) -> f64 {
        self as f64
    }
}

impl ToSeconds for f64 {
    fn to_seconds(self) -> f64 {
        self
    }
}

impl ToSeconds for Duration {
    fn to_seconds(self) -> f64 {
        self.num_milliseconds() as f64 / 1000.0
    }
}

pub trait IsId {
    fn is_id() -> bool { false }
}

pub trait ToQueueRangeOrPlace : IsId {
    fn to_range(self) -> String;
}

pub trait ToQueueRange {
    fn to_range(self) -> String;
}

impl<T: ToQueuePlace> ToQueueRangeOrPlace for T {
    fn to_range(self) -> String {
        format!("{}", self.to_place())
    }
}

impl ToQueueRange for ops::Range<u32> {
    fn to_range(self) -> String {
        format!("{}:{}", self.start, self.end)
    }
}

impl ToQueueRangeOrPlace for ops::Range<u32> {
    fn to_range(self) -> String {
        ToQueueRange::to_range(self)
    }
}

impl ToQueueRange for ops::RangeTo<u32> {
    fn to_range(self) -> String {
        format!(":{}", self.end)
    }
}

impl ToQueueRangeOrPlace for ops::RangeTo<u32> {
    fn to_range(self) -> String {
        ToQueueRange::to_range(self)
    }
}

impl ToQueueRange for ops::RangeFrom<u32> {
    fn to_range(self) -> String {
        format!("{}:", self.start)
    }
}

impl ToQueueRangeOrPlace for ops::RangeFrom<u32> {
    fn to_range(self) -> String {
        ToQueueRange::to_range(self)
    }
}

impl ToQueueRange for ops::RangeFull {
    fn to_range(self) -> String {
        String::new()
    }
}

impl ToQueueRangeOrPlace for ops::RangeFull {
    fn to_range(self) -> String {
        ToQueueRange::to_range(self)
    }
}

pub trait ToQueuePlace : IsId {
    fn to_place(self) -> u32;
}

impl ToQueuePlace for Id {
    fn to_place(self) -> u32 {
        self.0
    }
}

impl ToQueuePlace for u32 {
    fn to_place(self) -> u32 {
        self
    }
}

impl IsId for u32 {}
impl IsId for ops::Range<u32> {}
impl IsId for ops::RangeTo<u32> {}
impl IsId for ops::RangeFrom<u32> {}
impl IsId for ops::RangeFull {}
impl IsId for Id {
    fn is_id() -> bool {
        true
    }
}

pub trait ToOutputId {
    fn to_output_id(self) -> u32;
}

impl ToOutputId for u32 {
    fn to_output_id(self) -> u32 {
        self
    }
}
impl ToOutputId for Output {
    fn to_output_id(self) -> u32 {
        self.id
    }
}
<commit_msg>accept ref to string as playlist name<commit_after>use std::ops;
use time::Duration;
use output::Output;
use playlist::Playlist;
use song::Id;

pub trait ToPlaylistName {
    fn to_name(&self) -> &str;
}

impl ToPlaylistName for Playlist {
    fn to_name(&self) -> &str {
        &*self.name
    }
}

impl<'a> ToPlaylistName for &'a Playlist {
    fn to_name(&self) -> &str {
        &*self.name
    }
}

impl<'a> ToPlaylistName for &'a String {
    fn to_name(&self) -> &str {
        &*self
    }
}

impl ToPlaylistName for str {
    fn to_name(&self) -> &str {
        self
    }
}

impl ToPlaylistName for String {
    fn to_name(&self) -> &str {
        &*self
    }
}

pub trait ToSeconds {
    fn to_seconds(self) -> f64;
}

impl ToSeconds for i64 {
    fn to_seconds(self) -> f64 {
        self as f64
    }
}

impl ToSeconds for f64 {
    fn to_seconds(self) -> f64 {
        self
    }
}

impl ToSeconds for Duration {
    fn to_seconds(self) -> f64 {
        self.num_milliseconds() as f64 / 1000.0
    }
}

pub trait IsId {
    fn is_id() -> bool { false }
}

pub trait ToQueueRangeOrPlace : IsId {
    fn to_range(self) -> String;
}

pub trait ToQueueRange {
    fn to_range(self) -> String;
}

impl<T: ToQueuePlace> ToQueueRangeOrPlace for T {
    fn to_range(self) -> String {
        format!("{}", self.to_place())
    }
}

impl ToQueueRange for ops::Range<u32> {
    fn to_range(self) -> String {
        format!("{}:{}", self.start, self.end)
    }
}

impl ToQueueRangeOrPlace for ops::Range<u32> {
    fn to_range(self) -> String {
        ToQueueRange::to_range(self)
    }
}

impl ToQueueRange for ops::RangeTo<u32> {
    fn to_range(self) -> String {
        format!(":{}", self.end)
    }
}

impl ToQueueRangeOrPlace for ops::RangeTo<u32> {
    fn to_range(self) -> String {
        ToQueueRange::to_range(self)
    }
}

impl ToQueueRange for ops::RangeFrom<u32> {
    fn to_range(self) -> String {
        format!("{}:", self.start)
    }
}

impl ToQueueRangeOrPlace for ops::RangeFrom<u32> {
    fn to_range(self) -> String {
        ToQueueRange::to_range(self)
    }
}

impl ToQueueRange for ops::RangeFull {
    fn to_range(self) -> String {
        String::new()
    }
}

impl ToQueueRangeOrPlace for ops::RangeFull {
    fn to_range(self) -> String {
        ToQueueRange::to_range(self)
    }
}

pub trait ToQueuePlace : IsId {
    fn to_place(self) -> u32;
}

impl ToQueuePlace for Id {
    fn to_place(self) -> u32 {
        self.0
    }
}

impl ToQueuePlace for u32 {
    fn to_place(self) -> u32 {
        self
    }
}

impl IsId for u32 {}
impl IsId for ops::Range<u32> {}
impl IsId for ops::RangeTo<u32> {}
impl IsId for ops::RangeFrom<u32> {}
impl IsId for ops::RangeFull {}
impl IsId for Id {
    fn is_id() -> bool {
        true
    }
}

pub trait ToOutputId {
    fn to_output_id(self) -> u32;
}

impl ToOutputId for u32 {
    fn to_output_id(self) -> u32 {
        self
    }
}
impl ToOutputId for Output {
    fn to_output_id(self) -> u32 {
        self.id
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

use model::{Color, FieldCoord, HexCoord};

pub struct Board {
    /*
                ____
               /    \
          ____/  +y  \____
         /    \      /    \
        /      \____/  +x  \
        \      /    \      /
         \____/      \____/
         /    \      /    \
        /  -x  \____/      \
        \      /    \      /
         \____/  -y  \____/
              \      /
               \____/

        The hex board uses an axial coordinate system with (0, 0) at the center. The x-axis slopes
        up to the right, and the y-axis goes up and down. The board is stored as a dense 2D array,
        because a ragged array won't work (since each row would have to be a different type).

        See http://www.redblobgames.com/grids/hexagons/#coordinates-axial for more info.
    */
    board: [[Option<Hex>; 5]; 5],
    black_pieces: u32,
    black_hexes: u32,
    white_pieces: u32,
    white_hexes: u32,
}

// Fields are numbered clockwise from the top. Even indicies are black, odd indicies are white.
type Hex = [Field; 6];

// There's no need to store the color of the piece on this field, since only white pieces can be on
// white fields, and vice versa.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Field {
    Piece,
    Empty,
}

impl Board {
    #[cfg_attr(rustfmt, rustfmt_skip)]
    /// Create a new board with the "Laurentius" starting position.
    pub fn new() -> Board {
        let mut board = Board {
            board: [[None; 5]; 5],
            black_pieces: 18,
            black_hexes: 0,
            white_pieces: 18,
            white_hexes: 0,
        };

        // (0, 0) is the only empty hex.
        board.set_hex(&HexCoord::new(0, 0), Some([Field::Empty; 6]));

        // All other hexes have exactly two pieces on them in the starting position.
        let piece_locations = [
            (-2,  2, 0, 4),
            (-2,  1, 0, 3),
            (-2,  0, 3, 5),
            (-1,  2, 1, 4),
            (-1,  1, 0, 4),
            (-1,  0, 3, 5),
            (-1, -1, 2, 5),
            ( 0,  2, 1, 5),
            ( 0,  1, 1, 5),
            ( 0, -1, 2, 4),
            ( 0, -2, 2, 4),
            ( 1,  1, 2, 5),
            ( 1,  0, 0, 2),
            ( 1, -1, 1, 3),
            ( 1, -2, 1, 4),
            ( 2,  0, 0, 2),
            ( 2, -1, 0, 3),
            ( 2, -2, 1, 3),
        ];

        for &(x, y, f1, f2) in &piece_locations {
            let mut hex = [Field::Empty; 6];
            hex[f1] = Field::Piece;
            hex[f2] = Field::Piece;
            board.set_hex(&HexCoord::new(x, y), Some(hex));
        }

        board
    }
    pub fn move_piece(&mut self, from: &FieldCoord, to: &FieldCoord) -> bool {
        let movable = self.is_piece_on_field(from) && !self.is_piece_on_field(to)
            && self.get_field_vertex_neighbors(from).contains(to);

        if movable {
            self.set_field(from, Field::Empty);
            self.set_field(to, Field::Piece);

            let mover = from.color();
            let (capture_count, mut fields_to_check) = self.check_hexes(&from.to_hex());
            fields_to_check.append(&mut self.get_field_edge_neighbors(to));
            self.check_captures(&fields_to_check, &mover);

            match mover {
                Color::White => self.white_hexes += capture_count,
                Color::Black => self.black_hexes += capture_count,
            }
        }
        movable
    }
    pub fn can_exchange(&self, player: &Color) -> bool {
        2 <= match *player {
            Color::Black => self.black_hexes,
            Color::White => self.white_hexes,
        }
    }
    pub fn exchange_piece(&mut self, coord: &FieldCoord) -> bool {
        let exchanger = coord.color().switch();
        let exchangable = self.can_exchange(&exchanger) && self.is_piece_on_field(coord);

        if exchangable {
            self.remove_piece(coord);
            match exchanger {
                Color::White => self.white_hexes -= 2,
                Color::Black => self.black_hexes -= 2,
            }

            // Players don't collect hexes removed due to an exchange
            let (_, fields_to_check) = self.check_hexes(&coord.to_hex());
            self.check_captures(&fields_to_check, &exchanger);
        }
        exchangable
    }
    /// > extant (adj.): Still in existence; not destroyed, lost, or extinct (The Free Dictionary)
    ///
    /// Return the coordinates of the hexes that have not been removed yet.
    pub fn extant_hexes(&self) -> Vec<HexCoord> {
        let mut coords = vec![];
        for x in -2..3 {
            for y in -2..3 {
                coords.push((x, y));
            }
        }
        coords
            .iter()
            .filter_map(|&coord| self.try_hex(coord))
            .collect()
    }
    pub fn black_pieces(&self) -> u32 {
        self.black_pieces
    }
    pub fn black_hexes(&self) -> u32 {
        self.black_hexes
    }
    pub fn white_pieces(&self) -> u32 {
        self.white_pieces
    }
    pub fn white_hexes(&self) -> u32 {
        self.white_hexes
    }
}

// Field and piece methods
impl Board {
    fn get_field(&self, coord: &FieldCoord) -> &Field {
        match *self.get_hex(&coord.to_hex()) {
            Some(ref hex) => &hex[coord.f as usize],
            None => panic!(
                "Cannot get field {} on removed hex at {:?}",
                coord.f,
                coord.to_hex()
            ),
        }
    }
    fn set_field(&mut self, coord: &FieldCoord, field: Field) {
        match *self.get_hex(&coord.to_hex()) {
            Some(mut hex) => {
                hex[coord.f as usize] = field;
                self.set_hex(&coord.to_hex(), Some(hex));
            }
            None => panic!(
                "Cannot set field {} on removed hex at {:?}",
                coord.f,
                coord.to_hex()
            ),
        }
    }
    /// Return fields that share an edge with the given field. These fields are always the opposite
    /// color of the given field. If all of a piece's edge neighbors are occupied, that piece might
    /// be capturable.
    fn get_field_edge_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![
            // There are always two edge neighbors on the same hex as the given field
            FieldCoord::new(coord.x, coord.y, (coord.f + 1) % 6),
            FieldCoord::new(coord.x, coord.y, (coord.f + 5) % 6),
        ];

        if let Some(hex) = self.get_hex_neighbor(&coord.to_hex(), coord.f) {
            neighbors.push(hex.to_field((coord.f + 3) % 6));
        }

        neighbors
    }
    /// Return fields that share a vertex with the given field and have the same color as the given
    /// field. Pieces can move to fields that are vertex neighbors of the field they are on.
    fn get_field_vertex_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        // A field's vertex neighbors can be defined as the edge neighbors of its edge neighbors
        let mut neighbors = vec![];
        for field in self.get_field_edge_neighbors(coord) {
            neighbors.append(&mut self.get_field_edge_neighbors(&field));
        }
        // A field is not its own neighbor
        neighbors.into_iter().filter(|n| n != coord).collect()
    }
    pub fn is_piece_on_field(&self, coord: &FieldCoord) -> bool {
        self.get_field(coord) == &Field::Piece
    }
    pub fn get_available_moves(&self, field: &FieldCoord) -> Vec<FieldCoord> {
        if self.is_piece_on_field(field) {
            self.get_field_vertex_neighbors(field)
                .into_iter()
                .filter(|c| !self.is_piece_on_field(c))
                .collect()
        } else {
            vec![]
        }
    }
    fn remove_piece(&mut self, coord: &FieldCoord) {
        assert!(
            self.is_piece_on_field(coord),
            "There is no piece at {:?} to remove",
            coord
        );
        self.set_field(coord, Field::Empty);
        match coord.color() {
            Color::Black => self.black_pieces -= 1,
            Color::White => self.white_pieces -= 1,
        }
    }
    fn check_captures(&mut self, fields_to_check: &[FieldCoord], capturer: &Color) {
        for field in fields_to_check {
            if field.color() != *capturer && self.is_piece_on_field(field)
                && self.get_field_edge_neighbors(field)
                    .iter()
                    .all(|coord| self.is_piece_on_field(coord))
            {
                self.remove_piece(field);
            }
        }
    }
}

// Hex methods
impl Board {
    fn get_hex(&self, coord: &HexCoord) -> &Option<Hex> {
        &self.board[(coord.x + 2) as usize][(coord.y + 2) as usize]
    }
    fn set_hex(&mut self, coord: &HexCoord, hex: Option<Hex>) {
        self.board[(coord.x + 2) as usize][(coord.y + 2) as usize] = hex;
    }
    fn get_hex_neighbor(&self, coord: &HexCoord, direction: u32) -> Option<HexCoord> {
        assert!(direction < 6);

        let neighbors = [
            (coord.x, coord.y + 1),
            (coord.x + 1, coord.y),
            (coord.x + 1, coord.y - 1),
            (coord.x, coord.y - 1),
            (coord.x - 1, coord.y),
            (coord.x - 1, coord.y + 1),
        ];

        self.try_hex(neighbors[direction as usize])
    }
    /// A hex is removable (and must be removed) if it is empty and is "attached to the board by 3
    /// or less adjacent sides."
    fn is_hex_removable(&self, coord: &HexCoord) -> bool {
        match *self.get_hex(coord) {
            Some(hex) => if hex != [Field::Empty; 6] {
                return false;
            },
            None => return false,
        }

        let has_neighbor = |f| self.get_hex_neighbor(coord, f).is_some();
        let is_adjacent = |f| has_neighbor((f + 1) % 6) || has_neighbor((f + 5) % 6);

        let mut neighbor_count = 0;
        for f in 0..6 {
            if has_neighbor(f) {
                if is_adjacent(f) {
                    neighbor_count += 1;
                } else {
                    return false;
                }
            }
        }

        match neighbor_count {
            0 => panic!("A hex at {:?} is empty and has no neighbors", coord),
            1 | 2 | 3 => true,
            _ => false,
        }
    }
    fn remove_hex(&mut self, coord: &HexCoord) -> bool {
        let removable = self.is_hex_removable(coord);

        if removable {
            self.set_hex(coord, None);
        }
        removable
    }
    fn try_hex(&self, coord: (i32, i32)) -> Option<HexCoord> {
        if let Some(coord) = HexCoord::try_new(coord.0, coord.1) {
            if self.get_hex(&coord).is_some() {
                return Some(coord);
            }
        }
        None
    }
    fn check_hexes(&mut self, coord: &HexCoord) -> (u32, Vec<FieldCoord>) {
        let mut remove_count = 0;
        let mut fields = vec![];

        if self.remove_hex(coord) {
            remove_count += 1;
            for f in 0..6 {
                if let Some(neighbor) = self.get_hex_neighbor(coord, f) {
                    let (new_remove_count, mut new_fields) = self.check_hexes(&neighbor);
                    if new_remove_count == 0 {
                        fields.push(neighbor.to_field((f + 3) % 6));
                    } else {
                        remove_count += new_remove_count;
                        fields.append(&mut new_fields);
                    }
                }
            }
        }
        (remove_count, fields)
    }
}
<commit_msg>Move all public Board methods into one impl block<commit_after>/*
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

use model::{Color, FieldCoord, HexCoord};

pub struct Board {
    /*
                ____
               /    \
          ____/  +y  \____
         /    \      /    \
        /      \____/  +x  \
        \      /    \      /
         \____/      \____/
         /    \      /    \
        /  -x  \____/      \
        \      /    \      /
         \____/  -y  \____/
              \      /
               \____/

        The hex board uses an axial coordinate system with (0, 0) at the center. The x-axis slopes
        up to the right, and the y-axis goes up and down. The board is stored as a dense 2D array,
        because a ragged array won't work (since each row would have to be a different type).

        See http://www.redblobgames.com/grids/hexagons/#coordinates-axial for more info.
    */
    board: [[Option<Hex>; 5]; 5],
    black_pieces: u32,
    black_hexes: u32,
    white_pieces: u32,
    white_hexes: u32,
}

// Fields are numbered clockwise from the top. Even indicies are black, odd indicies are white.
type Hex = [Field; 6];

// There's no need to store the color of the piece on this field, since only white pieces can be on
// white fields, and vice versa.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Field {
    Piece,
    Empty,
}

// Public methods
impl Board {
    #[cfg_attr(rustfmt, rustfmt_skip)]
    /// Create a new board with the "Laurentius" starting position.
    pub fn new() -> Board {
        let mut board = Board {
            board: [[None; 5]; 5],
            black_pieces: 18,
            black_hexes: 0,
            white_pieces: 18,
            white_hexes: 0,
        };

        // (0, 0) is the only empty hex.
        board.set_hex(&HexCoord::new(0, 0), Some([Field::Empty; 6]));

        // All other hexes have exactly two pieces on them in the starting position.
        let piece_locations = [
            (-2,  2, 0, 4),
            (-2,  1, 0, 3),
            (-2,  0, 3, 5),
            (-1,  2, 1, 4),
            (-1,  1, 0, 4),
            (-1,  0, 3, 5),
            (-1, -1, 2, 5),
            ( 0,  2, 1, 5),
            ( 0,  1, 1, 5),
            ( 0, -1, 2, 4),
            ( 0, -2, 2, 4),
            ( 1,  1, 2, 5),
            ( 1,  0, 0, 2),
            ( 1, -1, 1, 3),
            ( 1, -2, 1, 4),
            ( 2,  0, 0, 2),
            ( 2, -1, 0, 3),
            ( 2, -2, 1, 3),
        ];

        for &(x, y, f1, f2) in &piece_locations {
            let mut hex = [Field::Empty; 6];
            hex[f1] = Field::Piece;
            hex[f2] = Field::Piece;
            board.set_hex(&HexCoord::new(x, y), Some(hex));
        }

        board
    }
    pub fn move_piece(&mut self, from: &FieldCoord, to: &FieldCoord) -> bool {
        let movable = self.is_piece_on_field(from) && !self.is_piece_on_field(to)
            && self.get_field_vertex_neighbors(from).contains(to);

        if movable {
            self.set_field(from, Field::Empty);
            self.set_field(to, Field::Piece);

            let mover = from.color();
            let (capture_count, mut fields_to_check) = self.check_hexes(&from.to_hex());
            fields_to_check.append(&mut self.get_field_edge_neighbors(to));
            self.check_captures(&fields_to_check, &mover);

            match mover {
                Color::White => self.white_hexes += capture_count,
                Color::Black => self.black_hexes += capture_count,
            }
        }
        movable
    }
    pub fn get_available_moves(&self, field: &FieldCoord) -> Vec<FieldCoord> {
        if self.is_piece_on_field(field) {
            self.get_field_vertex_neighbors(field)
                .into_iter()
                .filter(|c| !self.is_piece_on_field(c))
                .collect()
        } else {
            vec![]
        }
    }
    pub fn can_exchange(&self, player: &Color) -> bool {
        2 <= match *player {
            Color::Black => self.black_hexes,
            Color::White => self.white_hexes,
        }
    }
    pub fn exchange_piece(&mut self, coord: &FieldCoord) -> bool {
        let exchanger = coord.color().switch();
        let exchangable = self.can_exchange(&exchanger) && self.is_piece_on_field(coord);

        if exchangable {
            self.remove_piece(coord);
            match exchanger {
                Color::White => self.white_hexes -= 2,
                Color::Black => self.black_hexes -= 2,
            }

            // Players don't collect hexes removed due to an exchange
            let (_, fields_to_check) = self.check_hexes(&coord.to_hex());
            self.check_captures(&fields_to_check, &exchanger);
        }
        exchangable
    }
    pub fn is_piece_on_field(&self, coord: &FieldCoord) -> bool {
        self.get_field(coord) == &Field::Piece
    }
    /// > extant (adj.): Still in existence; not destroyed, lost, or extinct (The Free Dictionary)
    ///
    /// Return the coordinates of the hexes that have not been removed yet.
    pub fn extant_hexes(&self) -> Vec<HexCoord> {
        let mut coords = vec![];
        for x in -2..3 {
            for y in -2..3 {
                coords.push((x, y));
            }
        }
        coords
            .iter()
            .filter_map(|&coord| self.try_hex(coord))
            .collect()
    }
    pub fn black_pieces(&self) -> u32 {
        self.black_pieces
    }
    pub fn black_hexes(&self) -> u32 {
        self.black_hexes
    }
    pub fn white_pieces(&self) -> u32 {
        self.white_pieces
    }
    pub fn white_hexes(&self) -> u32 {
        self.white_hexes
    }
}

// Field and piece methods
impl Board {
    fn get_field(&self, coord: &FieldCoord) -> &Field {
        match *self.get_hex(&coord.to_hex()) {
            Some(ref hex) => &hex[coord.f as usize],
            None => panic!(
                "Cannot get field {} on removed hex at {:?}",
                coord.f,
                coord.to_hex()
            ),
        }
    }
    fn set_field(&mut self, coord: &FieldCoord, field: Field) {
        match *self.get_hex(&coord.to_hex()) {
            Some(mut hex) => {
                hex[coord.f as usize] = field;
                self.set_hex(&coord.to_hex(), Some(hex));
            }
            None => panic!(
                "Cannot set field {} on removed hex at {:?}",
                coord.f,
                coord.to_hex()
            ),
        }
    }
    /// Return fields that share an edge with the given field. These fields are always the opposite
    /// color of the given field. If all of a piece's edge neighbors are occupied, that piece might
    /// be capturable.
    fn get_field_edge_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![
            // There are always two edge neighbors on the same hex as the given field
            FieldCoord::new(coord.x, coord.y, (coord.f + 1) % 6),
            FieldCoord::new(coord.x, coord.y, (coord.f + 5) % 6),
        ];

        if let Some(hex) = self.get_hex_neighbor(&coord.to_hex(), coord.f) {
            neighbors.push(hex.to_field((coord.f + 3) % 6));
        }

        neighbors
    }
    /// Return fields that share a vertex with the given field and have the same color as the given
    /// field. Pieces can move to fields that are vertex neighbors of the field they are on.
    fn get_field_vertex_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        // A field's vertex neighbors can be defined as the edge neighbors of its edge neighbors
        let mut neighbors = vec![];
        for field in self.get_field_edge_neighbors(coord) {
            neighbors.append(&mut self.get_field_edge_neighbors(&field));
        }
        // A field is not its own neighbor
        neighbors.into_iter().filter(|n| n != coord).collect()
    }
    fn remove_piece(&mut self, coord: &FieldCoord) {
        assert!(
            self.is_piece_on_field(coord),
            "There is no piece at {:?} to remove",
            coord
        );
        self.set_field(coord, Field::Empty);
        match coord.color() {
            Color::Black => self.black_pieces -= 1,
            Color::White => self.white_pieces -= 1,
        }
    }
    fn check_captures(&mut self, fields_to_check: &[FieldCoord], capturer: &Color) {
        for field in fields_to_check {
            if field.color() != *capturer && self.is_piece_on_field(field)
                && self.get_field_edge_neighbors(field)
                    .iter()
                    .all(|coord| self.is_piece_on_field(coord))
            {
                self.remove_piece(field);
            }
        }
    }
}

// Hex methods
impl Board {
    fn get_hex(&self, coord: &HexCoord) -> &Option<Hex> {
        &self.board[(coord.x + 2) as usize][(coord.y + 2) as usize]
    }
    fn set_hex(&mut self, coord: &HexCoord, hex: Option<Hex>) {
        self.board[(coord.x + 2) as usize][(coord.y + 2) as usize] = hex;
    }
    fn get_hex_neighbor(&self, coord: &HexCoord, direction: u32) -> Option<HexCoord> {
        assert!(direction < 6);

        let neighbors = [
            (coord.x, coord.y + 1),
            (coord.x + 1, coord.y),
            (coord.x + 1, coord.y - 1),
            (coord.x, coord.y - 1),
            (coord.x - 1, coord.y),
            (coord.x - 1, coord.y + 1),
        ];

        self.try_hex(neighbors[direction as usize])
    }
    /// A hex is removable (and must be removed) if it is empty and is "attached to the board by 3
    /// or less adjacent sides."
    fn is_hex_removable(&self, coord: &HexCoord) -> bool {
        match *self.get_hex(coord) {
            Some(hex) => if hex != [Field::Empty; 6] {
                return false;
            },
            None => return false,
        }

        let has_neighbor = |f| self.get_hex_neighbor(coord, f).is_some();
        let is_adjacent = |f| has_neighbor((f + 1) % 6) || has_neighbor((f + 5) % 6);

        let mut neighbor_count = 0;
        for f in 0..6 {
            if has_neighbor(f) {
                if is_adjacent(f) {
                    neighbor_count += 1;
                } else {
                    return false;
                }
            }
        }

        match neighbor_count {
            0 => panic!("A hex at {:?} is empty and has no neighbors", coord),
            1 | 2 | 3 => true,
            _ => false,
        }
    }
    fn remove_hex(&mut self, coord: &HexCoord) -> bool {
        let removable = self.is_hex_removable(coord);

        if removable {
            self.set_hex(coord, None);
        }
        removable
    }
    fn try_hex(&self, coord: (i32, i32)) -> Option<HexCoord> {
        if let Some(coord) = HexCoord::try_new(coord.0, coord.1) {
            if self.get_hex(&coord).is_some() {
                return Some(coord);
            }
        }
        None
    }
    fn check_hexes(&mut self, coord: &HexCoord) -> (u32, Vec<FieldCoord>) {
        let mut remove_count = 0;
        let mut fields = vec![];

        if self.remove_hex(coord) {
            remove_count += 1;
            for f in 0..6 {
                if let Some(neighbor) = self.get_hex_neighbor(coord, f) {
                    let (new_remove_count, mut new_fields) = self.check_hexes(&neighbor);
                    if new_remove_count == 0 {
                        fields.push(neighbor.to_field((f + 3) % 6));
                    } else {
                        remove_count += new_remove_count;
                        fields.append(&mut new_fields);
                    }
                }
            }
        }
        (remove_count, fields)
    }
}
<|endoftext|>