<commit_before>//! Various utilities.

use crate::errors::{bail, Result, ResultExt};
use crate::log;

use std;
use std::collections::HashMap;
use std::fmt::Debug;
use std::hash::BuildHasher;
use std::hash::Hash;
use std::path::PathBuf;
use std::process::Command;

#[cfg(windows)]
/// Returns proper executable file suffix on current platform.
/// Returns `".exe"` on Windows and `""` on other platforms.
pub fn exe_suffix() -> &'static str {
    return ".exe";
}

#[cfg(not(windows))]
/// Returns proper executable file suffix on current platform.
/// Returns `".exe"` on Windows and `""` on other platforms.
pub fn exe_suffix() -> &'static str {
    ""
}

/// Creates and empty collection at `hash[key]` if there isn't one already.
/// Adds `value` to `hash[key]` collection.
pub fn add_to_multihash<K, T, V, S>(hash: &mut HashMap<K, V, S>, key: K, value: T)
where
    K: Eq + Hash + Clone,
    V: Default + Extend<T>,
    S: BuildHasher,
{
    use std::collections::hash_map::Entry;
    match hash.entry(key) {
        Entry::Occupied(mut entry) => entry.get_mut().extend(std::iter::once(value)),
        Entry::Vacant(entry) => {
            let mut r = V::default();
            r.extend(std::iter::once(value));
            entry.insert(r);
        }
    }
}

/// Runs a command and checks that it was successful
pub fn run_command(command: &mut Command) -> Result<()> {
    log::status(format!("Executing command: {:?}", command));
    let status = command
        .status()
        .with_context(|_| format!("failed to run command: {:?}", command))?;
    if status.success() {
        Ok(())
    } else {
        bail!("command failed with {}: {:?}", status, command);
    }
}

#[derive(Debug)]
pub struct CommandOutput {
    pub status: ::std::process::ExitStatus,
    pub stdout: String,
    pub stderr: String,
}

impl CommandOutput {
    pub fn is_success(&self) -> bool {
        self.status.success()
    }
}

/// Runs a command and returns its output regardless of
/// whether it was successful
pub fn run_command_and_capture_output(command: &mut Command) -> Result<CommandOutput> {
    log::status(format!("Executing command: {:?}", command));
    command.stdout(std::process::Stdio::piped());
    command.stderr(std::process::Stdio::piped());
    let output = command
        .output()
        .with_context(|_| format!("failed to run command: {:?}", command))?;
    Ok(CommandOutput {
        stdout: String::from_utf8_lossy(&output.stdout).to_string(),
        stderr: String::from_utf8_lossy(&output.stderr).to_string(),
        status: output.status,
    })
}

/// Runs a command and returns its stdout if it was successful
pub fn get_command_output(command: &mut Command) -> Result<String> {
    log::status(format!("Executing command: {:?}", command));
    command.stdout(std::process::Stdio::piped());
    command.stderr(std::process::Stdio::piped());
    let output = command
        .output()
        .with_context(|_| format!("failed to run command: {:?}", command))?;
    if output.status.success() {
        Ok(String::from_utf8(output.stdout)
            .with_context(|_| "comand output is not valid unicode")?)
    } else {
        use std::io::Write;
        let mut stderr = std::io::stderr();
        writeln!(stderr, "Stdout:")?;
        stderr
            .write_all(&output.stdout)
            .with_context(|_| "output failed")?;
        writeln!(stderr, "Stderr:")?;
        stderr
            .write_all(&output.stderr)
            .with_context(|_| "output failed")?;
        bail!("command failed with {}: {:?}", output.status, command);
    }
}

/// Perform a map operation that can fail
pub trait MapIfOk<A> {
    /// Call closure `f` on each element of the collection and return
    /// `Vec` of values returned by the closure. If closure returns `Err`
    /// at some iteration, return that `Err` instead.
    fn map_if_ok<B, E, F: FnMut(A) -> std::result::Result<B, E>>(
        self,
        f: F,
    ) -> std::result::Result<Vec<B>, E>;
}

impl<A, T: IntoIterator<Item = A>> MapIfOk<A> for T {
    fn map_if_ok<B, E, F: FnMut(A) -> std::result::Result<B, E>>(
        self,
        f: F,
    ) -> std::result::Result<Vec<B>, E> {
        let mut f = f;
        let mut r = Vec::new();
        for item in self {
            r.push(f(item)?);
        }
        Ok(r)
    }
}

/// Reads environment variable `env_var_name`, adds `new_paths`
/// to acquired list of paths and returns the list formatted as path list
/// (without applying it).
#[allow(clippy::or_fun_call)]
pub fn add_env_path_item(
    env_var_name: &str,
    mut new_paths: Vec<PathBuf>,
) -> Result<std::ffi::OsString> {
    use std::env;
    for path in env::split_paths(&env::var(env_var_name).unwrap_or(String::new())) {
        if new_paths.iter().find(|&x| x == &path).is_none() {
            new_paths.push(path);
        }
    }
    Ok(env::join_paths(new_paths).with_context(|_| "env::join_paths failed")?)
}

pub trait PushVec<T> {
    fn push_vec(&mut self, vec: Vec<T>);
}

impl<T> PushVec<T> for Vec<T> {
    fn push_vec(&mut self, mut vec: Vec<T>) {
        self.append(&mut vec);
    }
}

pub trait DebugPrint {
    fn debug_print(self, text: &str) -> Self;
}

impl<T: Debug> DebugPrint for T {
    fn debug_print(self, text: &str) -> Self {
        println!("DebugPrint {} {:?}", text, self);
        self
    }
}
<commit_msg>simplify map_if_ok impl<commit_after>//! Various utilities.

use crate::errors::{bail, Result, ResultExt};
use crate::log;

use std;
use std::collections::HashMap;
use std::fmt::Debug;
use std::hash::BuildHasher;
use std::hash::Hash;
use std::path::PathBuf;
use std::process::Command;

#[cfg(windows)]
/// Returns proper executable file suffix on current platform.
/// Returns `".exe"` on Windows and `""` on other platforms.
pub fn exe_suffix() -> &'static str {
    return ".exe";
}

#[cfg(not(windows))]
/// Returns proper executable file suffix on current platform.
/// Returns `".exe"` on Windows and `""` on other platforms.
pub fn exe_suffix() -> &'static str {
    ""
}

/// Creates and empty collection at `hash[key]` if there isn't one already.
/// Adds `value` to `hash[key]` collection.
pub fn add_to_multihash<K, T, V, S>(hash: &mut HashMap<K, V, S>, key: K, value: T)
where
    K: Eq + Hash + Clone,
    V: Default + Extend<T>,
    S: BuildHasher,
{
    use std::collections::hash_map::Entry;
    match hash.entry(key) {
        Entry::Occupied(mut entry) => entry.get_mut().extend(std::iter::once(value)),
        Entry::Vacant(entry) => {
            let mut r = V::default();
            r.extend(std::iter::once(value));
            entry.insert(r);
        }
    }
}

/// Runs a command and checks that it was successful
pub fn run_command(command: &mut Command) -> Result<()> {
    log::status(format!("Executing command: {:?}", command));
    let status = command
        .status()
        .with_context(|_| format!("failed to run command: {:?}", command))?;
    if status.success() {
        Ok(())
    } else {
        bail!("command failed with {}: {:?}", status, command);
    }
}

#[derive(Debug)]
pub struct CommandOutput {
    pub status: ::std::process::ExitStatus,
    pub stdout: String,
    pub stderr: String,
}

impl CommandOutput {
    pub fn is_success(&self) -> bool {
        self.status.success()
    }
}

/// Runs a command and returns its output regardless of
/// whether it was successful
pub fn run_command_and_capture_output(command: &mut Command) -> Result<CommandOutput> {
    log::status(format!("Executing command: {:?}", command));
    command.stdout(std::process::Stdio::piped());
    command.stderr(std::process::Stdio::piped());
    let output = command
        .output()
        .with_context(|_| format!("failed to run command: {:?}", command))?;
    Ok(CommandOutput {
        stdout: String::from_utf8_lossy(&output.stdout).to_string(),
        stderr: String::from_utf8_lossy(&output.stderr).to_string(),
        status: output.status,
    })
}

/// Runs a command and returns its stdout if it was successful
pub fn get_command_output(command: &mut Command) -> Result<String> {
    log::status(format!("Executing command: {:?}", command));
    command.stdout(std::process::Stdio::piped());
    command.stderr(std::process::Stdio::piped());
    let output = command
        .output()
        .with_context(|_| format!("failed to run command: {:?}", command))?;
    if output.status.success() {
        Ok(String::from_utf8(output.stdout)
            .with_context(|_| "comand output is not valid unicode")?)
    } else {
        use std::io::Write;
        let mut stderr = std::io::stderr();
        writeln!(stderr, "Stdout:")?;
        stderr
            .write_all(&output.stdout)
            .with_context(|_| "output failed")?;
        writeln!(stderr, "Stderr:")?;
        stderr
            .write_all(&output.stderr)
            .with_context(|_| "output failed")?;
        bail!("command failed with {}: {:?}", output.status, command);
    }
}

/// Perform a map operation that can fail
pub trait MapIfOk<A> {
    /// Call closure `f` on each element of the collection and return
    /// `Vec` of values returned by the closure. If closure returns `Err`
    /// at some iteration, return that `Err` instead.
    fn map_if_ok<B, E, F: FnMut(A) -> std::result::Result<B, E>>(
        self,
        f: F,
    ) -> std::result::Result<Vec<B>, E>;
}

impl<A, T: IntoIterator<Item = A>> MapIfOk<A> for T {
    fn map_if_ok<B, E, F>(self, f: F) -> std::result::Result<Vec<B>, E>
    where
        F: FnMut(A) -> std::result::Result<B, E>,
    {
        self.into_iter().map(f).collect()
    }
}

/// Reads environment variable `env_var_name`, adds `new_paths`
/// to acquired list of paths and returns the list formatted as path list
/// (without applying it).
#[allow(clippy::or_fun_call)]
pub fn add_env_path_item(
    env_var_name: &str,
    mut new_paths: Vec<PathBuf>,
) -> Result<std::ffi::OsString> {
    use std::env;
    for path in env::split_paths(&env::var(env_var_name).unwrap_or(String::new())) {
        if new_paths.iter().find(|&x| x == &path).is_none() {
            new_paths.push(path);
        }
    }
    Ok(env::join_paths(new_paths).with_context(|_| "env::join_paths failed")?)
}

pub trait PushVec<T> {
    fn push_vec(&mut self, vec: Vec<T>);
}

impl<T> PushVec<T> for Vec<T> {
    fn push_vec(&mut self, mut vec: Vec<T>) {
        self.append(&mut vec);
    }
}

pub trait DebugPrint {
    fn debug_print(self, text: &str) -> Self;
}

impl<T: Debug> DebugPrint for T {
    fn debug_print(self, text: &str) -> Self {
        println!("DebugPrint {} {:?}", text, self);
        self
    }
}
<|endoftext|>


<commit_before>use state::ParseState;
use state::CharClass;
use error::ParseError::*;

// add functionality to
// build in ~str to shift a number
// of characters from the beginning

trait RegexInputStr {
  fn shiftn_char(&mut self, times: uint);
}

impl RegexInputStr for ~str {
  fn shiftn_char(&mut self, times: uint) {
    for _ in range(0, times) {
      self.shift_char();
    }
  }
}

// check for an err,
macro_rules! check_ok(
  ($f: expr) => (
    match $f {
      ParseOk => { }
      e => return e
    }
  );
)

// parse functions
//
// these take in a pointer to a ParseState and an input string,
// and finish / modify the ParseState

fn parse_charclass(t: &mut ~str, ps: &mut ParseState) -> ParseCode {

  let mut cc = CharClass::new();

  // we need to keep track of any [, ( in
  // the input, because we can just ignore
  // them
  let mut nbracket: uint = 0;

  // check to see if the first char following
  // '[' is a '^', if so, it is a negated char
  // class
  let negate = match t.char_at(0) {
    '^' => {
      t.shift_char();
      true
    },
    _ => false
  };

  while (t.len() > 0) {

    match t.char_at(0) {
      '[' => {
        nbracket += 1;
        t.shift_char();
      },
      ']' => {
        t.shift_char();
        if (nbracket > 0) {
          nbracket -= 1;
        } else {
          if (negate) {
            check_ok!(cc.negate());
          }
          ps.pushCharClass(cc);
          return ParseOk;
        }
      }
      c => {
        t.shift_char();

        // check to see if its this is part of a
        // range
        if (t.len() > 1) {
          match t.char_at(0) {
            '-' => {
              if (t.char_at(1) != ']') {
                match cc.addRange(c, t.char_at(1)) {
                  ParseOk => { },
                  e => return e,
                }
                t.shiftn_char(2);
              } else {
                cc.addRange(c, c);
              }
            }
            _ => {
              cc.addRange(c, c);
            }
          }
        } else {
          cc.addRange(c, c);
        }
      }
    }

  }

  ParseExpectedClosingBracket
}

// tries to determine if there
// is a repetition operation
// and parses it
// multiple cases:
// {a,b}: from a to be inclusive
// {a,}:  a unbounded
// {a}:   exactly a
fn parse_repetition(t: &mut ~str, ps: &mut ParseState) -> ParseCode {

  // check to make sure there are still
  // characters in the string
  macro_rules! check_bounds(
    () => (
      if (len == t.len()) {
        return ParseNotRepetition
      }
    )
  )

  let mut buf = ~"";
  let mut len = 0;

  while (len < t.len() && t.char_at(len).is_digit()) {
    buf.push_char(t.char_at(len));
    len += 1;
  }

  if (len == 0) {
    return ParseNotRepetition // no digits or end of string
  }

  // this is guaranteed to be a digit because
  // we only append it to the buffer if the char
  // is a digit
  let start = from_str::<uint>(buf).unwrap();

  buf.clear();

  check_bounds!();

  match t.char_at(len) {
    ',' => {
      len += 1;
    }
    '}' => {
      t.shiftn_char(len + 1);
      return ps.doBoundedRepetition(start, start);
    }
    _ => return ParseNotRepetition
  }

  check_bounds!();

  // if the next character is a }, unbounded repetition
  match t.char_at(len) {
    '}' => {
      t.shiftn_char(len + 1);
      return ps.doUnboundedRepetition(start);
    }
    x if x.is_digit() => { } // continue if x is a digit
    _ => return ParseNotRepetition
  }

  // this should be the ending digit
  while (len < t.len() && t.char_at(len).is_digit()) {
    buf.push_char(t.char_at(len));
    len += 1;
  }

  let end = from_str::<uint>(buf).unwrap();

  check_bounds!();

  match t.char_at(len) {
    '}' => {
      t.shiftn_char(len + 1);
      return ps.doBoundedRepetition(start, end);
    }
    _ => return ParseNotRepetition
  }
}

// parse an input string recursively
// ideally, we wouldn't parse an input string recursively
// because rust does not optimize tail end
// recursive calls, but...
// this way is pretty
pub fn parse_recursive(t: &mut ~str, ps: &mut ParseState) -> ParseCode {

  // cases for
  // parsing different characters
  // in the input string
  while (t.len() > 0) {

    match t.char_at(0) {
      '(' => {
        ps.doConcatenation();
        ps.pushLeftParen();

        t.shift_char();
        check_ok!(parse_recursive(t, ps));
        ps.doLeftParen();
        t.shift_char();
      }
      ')' => {
        if (ps.hasUnmatchedParens() && t.len() > 0) {
          break;
        }
        return ParseUnexpectedClosingParen;
      }

      '|' => {
        ps.doConcatenation();
        ps.pushAlternation();

        t.shift_char();
        check_ok!(parse_recursive(t, ps));
        ps.doAlternation();

        if (ps.hasUnmatchedParens()) {
          break;
        }
      }

      '*' => {
        t.shift_char();
        ps.doKleine();
      }
      '?' => {
        t.shift_char();
        ps.doZeroOrOne();
      }
      '+' => {
        t.shift_char();
        ps.doOneOrMore();
      }

      '{' => {
        t.shift_char();

        match parse_repetition(t, ps) {
          ParseOk => { },
          ParseNotRepetition => ps.pushLiteral("{"),
          e => return e
        }
      }

      '[' => {
        t.shift_char();
        check_ok!(parse_charclass(t, ps));
      }

      c => {
        ps.pushLiteral(c.to_str());
        t.shift_char();
      }
    }

    //ps.trace();

  }

  ps.doConcatenation();

  if (ps.hasUnmatchedParens() && t.len() == 0) {
    ParseExpectedClosingParen
  } else {
    ParseOk
  }
}

#[cfg(test)]
mod parse_tests {
  use super::*;
  use state::*;
  use error::ParseError::*;

  macro_rules! test_repetition(
    ($input: expr, $expect: pat) => (
      {
        let mut ps = ParseState::new();
        let ok = match parse_recursive(&mut $input, &mut ps) {
          $expect => true,
          _ => false
        };
        ps.trace();
        assert!(ok);
      }
    );
  )

  #[test]
  fn parse_bounded_repetition_ok() {
    test_repetition!(~"a{10}", ParseOk);
  }

  #[test]
  fn parse_unbounded_repetition_ok() {
    test_repetition!(~"b{10,}", ParseOk);
  }

  #[test]
  fn parse_bounded_range_repetition_ok() {
    test_repetition!(~"c{10,12}", ParseOk);
  }

  #[test]
  fn parse_bad_range_repetition_ok() {
    test_repetition!(~"c{10,x}", ParseOk);
  }

  #[test]
  fn parse_empty_range_err() {
    test_repetition!(~"d{12,10}", ParseEmptyRepetitionRange);
  }

  #[test]
  fn parse_negative_range_ok() {
    test_repetition!(~"e{-11}", ParseOk);
  }

  #[test]
  fn parse_no_comma_range_ok() {
    test_repetition!(~"f{10 11}", ParseOk);
  }

  #[test]
  fn parse_no_closing_curly_brace() {
    test_repetition!(~"g{10", ParseOk);
  }
}
<commit_msg>bad placement of macro in parse<commit_after>use state::ParseState;
use state::CharClass;
use error::ParseError::*;

// add functionality to
// build in ~str to shift a number
// of characters from the beginning

trait RegexInputStr {
  fn shiftn_char(&mut self, times: uint);
}

impl RegexInputStr for ~str {
  fn shiftn_char(&mut self, times: uint) {
    for _ in range(0, times) {
      self.shift_char();
    }
  }
}

// check for an err,
macro_rules! check_ok(
  ($f: expr) => (
    match $f {
      ParseOk => { }
      e => return e
    }
  );
)

// parse functions
//
// these take in a pointer to a ParseState and an input string,
// and finish / modify the ParseState

fn parse_charclass(t: &mut ~str, ps: &mut ParseState) -> ParseCode {

  let mut cc = CharClass::new();

  // we need to keep track of any [, ( in
  // the input, because we can just ignore
  // them
  let mut nbracket: uint = 0;

  // check to see if the first char following
  // '[' is a '^', if so, it is a negated char
  // class
  let negate = match t.char_at(0) {
    '^' => {
      t.shift_char();
      true
    },
    _ => false
  };

  while (t.len() > 0) {

    match t.char_at(0) {
      '[' => {
        nbracket += 1;
        t.shift_char();
      },
      ']' => {
        t.shift_char();
        if (nbracket > 0) {
          nbracket -= 1;
        } else {
          if (negate) {
            check_ok!(cc.negate());
          }
          ps.pushCharClass(cc);
          return ParseOk;
        }
      }
      c => {
        t.shift_char();

        // check to see if its this is part of a
        // range
        if (t.len() > 1) {
          match t.char_at(0) {
            '-' => {
              if (t.char_at(1) != ']') {
                match cc.addRange(c, t.char_at(1)) {
                  ParseOk => { },
                  e => return e,
                }
                t.shiftn_char(2);
              } else {
                cc.addRange(c, c);
              }
            }
            _ => {
              cc.addRange(c, c);
            }
          }
        } else {
          cc.addRange(c, c);
        }
      }
    }

  }

  ParseExpectedClosingBracket
}

// tries to determine if there
// is a repetition operation
// and parses it
// multiple cases:
// {a,b}: from a to be inclusive
// {a,}:  a unbounded
// {a}:   exactly a
fn parse_repetition(t: &mut ~str, ps: &mut ParseState) -> ParseCode {

  let mut buf = ~"";
  let mut len = 0;

  // check to make sure there are still
  // characters in the string
  macro_rules! check_bounds(
    () => (
      if (len == t.len()) {
        return ParseNotRepetition
      }
    )
  )

  while (len < t.len() && t.char_at(len).is_digit()) {
    buf.push_char(t.char_at(len));
    len += 1;
  }

  if (len == 0) {
    return ParseNotRepetition // no digits or end of string
  }

  // this is guaranteed to be a digit because
  // we only append it to the buffer if the char
  // is a digit
  let start = from_str::<uint>(buf).unwrap();

  buf.clear();

  check_bounds!();

  match t.char_at(len) {
    ',' => {
      len += 1;
    }
    '}' => {
      t.shiftn_char(len + 1);
      return ps.doBoundedRepetition(start, start);
    }
    _ => return ParseNotRepetition
  }

  check_bounds!();

  // if the next character is a }, unbounded repetition
  match t.char_at(len) {
    '}' => {
      t.shiftn_char(len + 1);
      return ps.doUnboundedRepetition(start);
    }
    x if x.is_digit() => { } // continue if x is a digit
    _ => return ParseNotRepetition
  }

  // this should be the ending digit
  while (len < t.len() && t.char_at(len).is_digit()) {
    buf.push_char(t.char_at(len));
    len += 1;
  }

  let end = from_str::<uint>(buf).unwrap();

  check_bounds!();

  match t.char_at(len) {
    '}' => {
      t.shiftn_char(len + 1);
      return ps.doBoundedRepetition(start, end);
    }
    _ => return ParseNotRepetition
  }
}

// parse an input string recursively
// ideally, we wouldn't parse an input string recursively
// because rust does not optimize tail end
// recursive calls, but...
// this way is pretty
pub fn parse_recursive(t: &mut ~str, ps: &mut ParseState) -> ParseCode {

  // cases for
  // parsing different characters
  // in the input string
  while (t.len() > 0) {

    match t.char_at(0) {
      '(' => {
        ps.doConcatenation();
        ps.pushLeftParen();

        t.shift_char();
        check_ok!(parse_recursive(t, ps));
        ps.doLeftParen();
        t.shift_char();
      }
      ')' => {
        if (ps.hasUnmatchedParens() && t.len() > 0) {
          break;
        }
        return ParseUnexpectedClosingParen;
      }

      '|' => {
        ps.doConcatenation();
        ps.pushAlternation();

        t.shift_char();
        check_ok!(parse_recursive(t, ps));
        ps.doAlternation();

        if (ps.hasUnmatchedParens()) {
          break;
        }
      }

      '*' => {
        t.shift_char();
        ps.doKleine();
      }
      '?' => {
        t.shift_char();
        ps.doZeroOrOne();
      }
      '+' => {
        t.shift_char();
        ps.doOneOrMore();
      }

      '{' => {
        t.shift_char();

        match parse_repetition(t, ps) {
          ParseOk => { },
          ParseNotRepetition => ps.pushLiteral("{"),
          e => return e
        }
      }

      '[' => {
        t.shift_char();
        check_ok!(parse_charclass(t, ps));
      }

      c => {
        ps.pushLiteral(c.to_str());
        t.shift_char();
      }
    }

    //ps.trace();

  }

  ps.doConcatenation();

  if (ps.hasUnmatchedParens() && t.len() == 0) {
    ParseExpectedClosingParen
  } else {
    ParseOk
  }
}

#[cfg(test)]
mod parse_tests {
  use super::*;
  use state::*;
  use error::ParseError::*;

  macro_rules! test_repetition(
    ($input: expr, $expect: pat) => (
      {
        let mut ps = ParseState::new();
        let ok = match parse_recursive(&mut $input, &mut ps) {
          $expect => true,
          _ => false
        };
        ps.trace();
        assert!(ok);
      }
    );
  )

  #[test]
  fn parse_bounded_repetition_ok() {
    test_repetition!(~"a{10}", ParseOk);
  }

  #[test]
  fn parse_unbounded_repetition_ok() {
    test_repetition!(~"b{10,}", ParseOk);
  }

  #[test]
  fn parse_bounded_range_repetition_ok() {
    test_repetition!(~"c{10,12}", ParseOk);
  }

  #[test]
  fn parse_bad_range_repetition_ok() {
    test_repetition!(~"c{10,x}", ParseOk);
  }

  #[test]
  fn parse_empty_range_err() {
    test_repetition!(~"d{12,10}", ParseEmptyRepetitionRange);
  }

  #[test]
  fn parse_negative_range_ok() {
    test_repetition!(~"e{-11}", ParseOk);
  }

  #[test]
  fn parse_no_comma_range_ok() {
    test_repetition!(~"f{10 11}", ParseOk);
  }

  #[test]
  fn parse_no_closing_curly_brace() {
    test_repetition!(~"g{10", ParseOk);
  }
}
<|endoftext|>


<commit_before>use std::io::{BufReader, ErrorKind, Result};
use std::net::{SocketAddr, TcpStream};
use std::thread;
use std::time::Duration;

use mio::{net::TcpListener, Evented, Events, Poll, PollOpt, Ready, Registration, Token};
use slab::Slab;

use birch::client::{ClientAuth, ClientConnection, ClientEvent};
use birch::network::NetworkConnection;
use birch::socket::{IrcReader, IrcSocketConfig, IrcWriter};

// TODO: blah
type NetworkId = usize;
type ClientId = usize;

struct Socket {
    reader: BufReader<mio::net::TcpStream>,
    writer: mio::net::TcpStream,
}

impl Evented for Socket {
    fn register(
        &self,
        poll: &Poll,
        token: Token,
        interest: Ready,
        opts: PollOpt,
    ) -> Result<()> {
        self.writer.register(poll, token, interest, opts)
    }

    fn reregister(
        &self,
        poll: &Poll,
        token: Token,
        interest: Ready,
        opts: PollOpt,
    ) -> Result<()> {
        self.writer.reregister(poll, token, interest, opts)
    }

    fn deregister(&self, poll: &Poll) -> Result<()> {
        poll.deregister(&self.writer)
    }
}

impl Socket {
    fn from_stream(stream: mio::net::TcpStream) -> Result<Self> {
        let reader = BufReader::new(stream.try_clone()?);
        Ok(Self {
            reader,
            writer: stream,
        })
    }
}

impl std::io::Read for Socket {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        self.reader.read(buf)
    }
}

impl std::io::Write for Socket {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        self.writer.write(buf)
    }

    fn flush(&mut self) -> Result<()> {
        self.writer.flush()
    }
}

pub struct Ticker(Registration);

impl Ticker {
    pub fn new(interval: Duration) -> Self {
        let (registration, set_readiness) = Registration::new2();

        thread::spawn(move || loop {
            thread::sleep(interval);
            set_readiness.set_readiness(Ready::readable()).unwrap();
        });

        Self(registration)
    }
}

impl Evented for Ticker {
    fn register(
        &self,
        poll: &Poll,
        token: Token,
        interest: Ready,
        opts: PollOpt,
    ) -> Result<()> {
        self.0.register(poll, token, interest, opts)
    }

    fn reregister(
        &self,
        poll: &Poll,
        token: Token,
        interest: Ready,
        opts: PollOpt,
    ) -> Result<()> {
        self.0.reregister(poll, token, interest, opts)
    }

    fn deregister(&self, poll: &Poll) -> Result<()> {
        poll.deregister(&self.0)
    }
}

struct Client {
    socket: Socket,
    conn: ClientConnection,
    network: Option<NetworkId>,
}

impl Client {
    fn new(stream: mio::net::TcpStream) -> Self {
        let socket = Socket::from_stream(stream).expect("create client socket");
        let conn = ClientConnection::new();

        Self {
            socket,
            conn,
            network: None,
        }
    }
}

struct NetworkConfig {
    network_name: String,
    nick: String,
    socket: IrcSocketConfig,
    auth: (String, String),
}

impl NetworkConfig {
    fn create_socket(&self) -> Result<Socket> {
        let stream =
            mio::net::TcpStream::from_stream(TcpStream::connect(&self.socket.addr)?)?;
        Socket::from_stream(stream)
    }
}

struct Network {
    socket: Socket,
    conn: NetworkConnection,
    config: NetworkConfig,
    connected: bool,
}

impl Network {
    fn new(config: NetworkConfig) -> Result<Self> {
        let socket = config.create_socket()?;
        let conn = NetworkConnection::new(&config.nick);

        Ok(Self {
            socket,
            conn,
            config,
            connected: true,
        })
    }

    fn reconnect(&mut self) -> Result<()> {
        self.socket = self.config.create_socket()?;
        self.conn.initialize()?;
        self.connected = true;

        Ok(())
    }

    // TODO: blah, this could be better
    fn authenticate(&self, auth: &ClientAuth) -> bool {
        auth.network == self.config.network_name
            && auth.user == self.config.auth.0
            && auth.password == self.config.auth.1
    }
}

#[derive(PartialEq)]
enum SocketKind {
    Ticker,
    Listener,
    Network(NetworkId),
    Client(ClientId),
}

struct BirchServer {
    sockets: Slab<SocketKind>,
    clients: Slab<Client>,
    // TODO: Since networks aren't dynamic, no benefit really to having this be a slab
    networks: Slab<Network>,
}

impl BirchServer {
    fn new() -> Self {
        Self {
            sockets: Slab::with_capacity(1024),
            clients: Slab::with_capacity(32),
            networks: Slab::with_capacity(16),
        }
    }

    fn accept_client(&mut self, poll: &Poll, socket: mio::net::TcpStream) -> Result<()> {
        let client_id = self.clients.insert(Client::new(socket));
        let token = self.sockets.insert(SocketKind::Client(client_id));

        poll.register(
            &self.clients.get(client_id).unwrap().socket,
            Token(token),
            Ready::readable(),
            PollOpt::edge(),
        )?;

        println!("Client connected: client_id={} token={}", client_id, token);
        Ok(())
    }

    fn handle_network_message(&mut self, network_id: NetworkId) -> Result<()> {
        let network = self
            .networks
            .get_mut(network_id)
            .expect("activity on unassigned networks id");

        let msg = network.socket.reader.read_message()?;

        println!("[birch <- \u{1b}[37;1mnet\u{1b}[0m] {}", msg);
        network.conn.handle(&msg)?;

        for msg in network.conn.network_messages() {
            println!("[\u{1b}[37;1mbirch\u{1b}[0m -> net] {}", msg);
            network.socket.write_message(&msg)?;
        }

        for msg in network.conn.user_messages() {
            let clients = self
                .clients
                .iter_mut()
                .filter(|(_, c)| c.network == Some(network_id));

            for (_, client) in clients {
                if let Err(err) = client.socket.write_message(&msg) {
                    println!("Failed to write to client: {}", err);
                }
            }
        }

        Ok(())
    }

    fn handle_client_message(&mut self, client_id: ClientId) -> Result<()> {
        let client = self
            .clients
            .get_mut(client_id)
            .expect("activity on unassigned client id");

        let msg = client.socket.reader.read_message()?;

        println!(
            "[birch <- \u{1b}[37;1mclient({})\u{1b}[0m] {}",
            client_id, msg
        );

        client.conn.handle_message(&msg)?;

        for event in client.conn.events() {
            match event {
                ClientEvent::WriteNetwork(ref _msg) => unimplemented!(),
                ClientEvent::WriteClient(ref msg) => client.socket.write_message(msg)?,
                ClientEvent::RegistrationComplete => {
                    // TODO: Update client's nick
                    match client.network {
                        Some(id) => {
                            let network = self
                                .networks
                                .get_mut(id)
                                .expect("client referencing unknown network");

                            network.conn.state.welcome_user(&mut client.socket)?;
                        }
                        None => panic!("registration completed without network"),
                    }
                }
                ClientEvent::AuthAttempt(auth) => {
                    let id = self
                        .networks
                        .iter()
                        .find(|(_, n)| n.authenticate(&auth))
                        .map(|(id, _)| id);

                    // TODO: set auth result back on client.conn
                    client.network = id
                }
            }
        }

        Ok(())
    }

    fn ping_clients(&mut self, poll: &Poll) -> Result<()> {
        let mut to_remove = Vec::new();
        for (id, client) in self.clients.iter_mut() {
            if !client.conn.ping() {
                println!("client({}) timed out", id);
                to_remove.push(id);
            }

            // TODO: remove duplication
            for event in client.conn.events() {
                match event {
                    ClientEvent::WriteClient(ref msg) => {
                        client.socket.write_message(msg)?
                    }
                    _ => unreachable!(),
                }
            }
        }

        for client_id in to_remove.iter() {
            self.remove_client(poll, *client_id)?;
        }

        Ok(())
    }

    // TODO: This is a bit too complicated
    fn remove_client(&mut self, poll: &Poll, id: ClientId) -> Result<()> {
        let client = self.clients.remove(id);
        poll.deregister(&client.socket)?;

        let (tok, _) = self
            .sockets
            .iter()
            .find(|(_, s)| SocketKind::Client(id) == **s)
            .unwrap();

        self.sockets.remove(tok);
        Ok(())
    }

    fn reconnect_networks(&mut self, poll: &Poll) -> Result<()> {
        for (id, network) in self.networks.iter_mut().filter(|(_, n)| !n.connected) {
            println!("network {} is disconnected... attempting reconnect", id);
            match network.reconnect() {
                Ok(()) => poll.register(
                    &network.socket,
                    Token(self.sockets.insert(SocketKind::Network(id))),
                    Ready::readable(),
                    PollOpt::edge(),
                )?,
                Err(err) => println!("reconnect failed: {}", err),
            }
        }

        Ok(())
    }

    fn handle_poll_event(
        &mut self,
        poll: &Poll,
        listener: &TcpListener,
        token: Token,
    ) -> Result<()> {
        match self.sockets.get(token.0) {
            None => panic!("token not associated with a socket: {:?}", token),

            Some(&SocketKind::Ticker) => {
                self.ping_clients(poll)?;
                self.reconnect_networks(poll)?;
            }

            Some(&SocketKind::Listener) => loop {
                match listener.accept() {
                    Ok((socket, _)) => self.accept_client(&poll, socket)?,
                    Err(ref e) if e.kind() == ErrorKind::WouldBlock => break,
                    e => panic!("failed to accept err={:?}", e),
                }
            },

            Some(&SocketKind::Network(network_id)) => loop {
                match self.handle_network_message(network_id) {
                    Ok(_) => (),
                    Err(ref e) if e.kind() == ErrorKind::WouldBlock => break,
                    Err(e) => {
                        // TODO: Reconnection logic
                        println!("Network errored, disconnecting: {}", e);
                        self.sockets.remove(token.0);
                        let mut network = self.networks.get_mut(network_id).unwrap();
                        network.connected = false;
                        poll.deregister(&network.socket)?;
                        break;
                    }
                }
            },
            Some(&SocketKind::Client(client_id)) => loop {
                match self.handle_client_message(client_id) {
                    Ok(_) => (),
                    Err(ref e) if e.kind() == ErrorKind::WouldBlock => break,
                    Err(e) => {
                        println!("Client errored, disconnecting: {}", e);
                        self.remove_client(poll, client_id)?;
                        break;
                    }
                }
            },
        }

        Ok(())
    }

    fn add_network(&mut self, config: NetworkConfig) -> Result<NetworkId> {
        let mut network = Network::new(config)?;
        network.conn.initialize()?;

        let token = self.networks.insert(network);
        self.sockets.insert(SocketKind::Network(token));

        Ok(token)
    }

    fn serve(&mut self, bind_addr: &SocketAddr) -> Result<()> {
        let poll = Poll::new()?;

        // TODO: is this iffy? Should we just store the Poll object on
        // the struct itself?
        for (id, network) in self.networks.iter_mut() {
            poll.register(
                &network.socket,
                Token(id),
                Ready::readable(),
                PollOpt::edge(),
            )?;
        }

        let listener = TcpListener::bind(bind_addr)?;
        {
            let tok = self.sockets.insert(SocketKind::Listener);
            poll.register(&listener, Token(tok), Ready::readable(), PollOpt::edge())?;
        }

        let ticker = Ticker::new(Duration::from_secs(60));
        {
            let tok = self.sockets.insert(SocketKind::Ticker);
            poll.register(&ticker, Token(tok), Ready::readable(), PollOpt::edge())?;
        }

        loop {
            let mut events = Events::with_capacity(128);
            poll.poll(&mut events, None)?;

            for ev in events {
                self.handle_poll_event(&poll, &listener, ev.token())?;
            }
        }
    }
}

fn main() -> Result<()> {
    let config = NetworkConfig {
        network_name: "freenode".to_string(),
        nick: "ep".to_string(),
        auth: ("foo".to_string(), "bar".to_string()),
        socket: IrcSocketConfig {
            addr: "irc.freenode.net:6667".parse().unwrap(),
            max_retries: Some(3),
        },
    };

    let mut server = BirchServer::new();
    server.add_network(config)?;

    server.serve(&"127.0.0.1:9123".parse().unwrap())
}
<commit_msg>Swap imports to make mio first class<commit_after>use std::io::{BufReader, ErrorKind, Result};
use std::net::SocketAddr;
use std::thread;
use std::time::Duration;

use mio::net::{TcpListener, TcpStream};
use mio::{Evented, Events, Poll, PollOpt, Ready, Registration, Token};
use slab::Slab;

use birch::client::{ClientAuth, ClientConnection, ClientEvent};
use birch::network::NetworkConnection;
use birch::socket::{IrcReader, IrcSocketConfig, IrcWriter};

// TODO: blah
type NetworkId = usize;
type ClientId = usize;

struct Socket {
    reader: BufReader<TcpStream>,
    writer: TcpStream,
}

impl Evented for Socket {
    fn register(
        &self,
        poll: &Poll,
        token: Token,
        interest: Ready,
        opts: PollOpt,
    ) -> Result<()> {
        self.writer.register(poll, token, interest, opts)
    }

    fn reregister(
        &self,
        poll: &Poll,
        token: Token,
        interest: Ready,
        opts: PollOpt,
    ) -> Result<()> {
        self.writer.reregister(poll, token, interest, opts)
    }

    fn deregister(&self, poll: &Poll) -> Result<()> {
        poll.deregister(&self.writer)
    }
}

impl Socket {
    fn from_stream(stream: TcpStream) -> Result<Self> {
        let reader = BufReader::new(stream.try_clone()?);
        Ok(Self {
            reader,
            writer: stream,
        })
    }
}

impl std::io::Read for Socket {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        self.reader.read(buf)
    }
}

impl std::io::Write for Socket {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        self.writer.write(buf)
    }

    fn flush(&mut self) -> Result<()> {
        self.writer.flush()
    }
}

pub struct Ticker(Registration);

impl Ticker {
    pub fn new(interval: Duration) -> Self {
        let (registration, set_readiness) = Registration::new2();

        thread::spawn(move || loop {
            thread::sleep(interval);
            set_readiness.set_readiness(Ready::readable()).unwrap();
        });

        Self(registration)
    }
}

impl Evented for Ticker {
    fn register(
        &self,
        poll: &Poll,
        token: Token,
        interest: Ready,
        opts: PollOpt,
    ) -> Result<()> {
        self.0.register(poll, token, interest, opts)
    }

    fn reregister(
        &self,
        poll: &Poll,
        token: Token,
        interest: Ready,
        opts: PollOpt,
    ) -> Result<()> {
        self.0.reregister(poll, token, interest, opts)
    }

    fn deregister(&self, poll: &Poll) -> Result<()> {
        poll.deregister(&self.0)
    }
}

struct Client {
    socket: Socket,
    conn: ClientConnection,
    network: Option<NetworkId>,
}

impl Client {
    fn new(stream: TcpStream) -> Self {
        let socket = Socket::from_stream(stream).expect("create client socket");
        let conn = ClientConnection::new();

        Self {
            socket,
            conn,
            network: None,
        }
    }
}

struct NetworkConfig {
    network_name: String,
    nick: String,
    socket: IrcSocketConfig,
    auth: (String, String),
}

impl NetworkConfig {
    fn create_socket(&self) -> Result<Socket> {
        let stream =
            mio::net::TcpStream::from_stream(TcpStream::connect(&self.socket.addr)?)?;
        Socket::from_stream(stream)
    }
}

struct Network {
    socket: Socket,
    conn: NetworkConnection,
    config: NetworkConfig,
    connected: bool,
}

impl Network {
    fn new(config: NetworkConfig) -> Result<Self> {
        let socket = config.create_socket()?;
        let conn = NetworkConnection::new(&config.nick);

        Ok(Self {
            socket,
            conn,
            config,
            connected: true,
        })
    }

    fn reconnect(&mut self) -> Result<()> {
        self.socket = self.config.create_socket()?;
        self.conn.initialize()?;
        self.connected = true;

        Ok(())
    }

    // TODO: blah, this could be better
    fn authenticate(&self, auth: &ClientAuth) -> bool {
        auth.network == self.config.network_name
            && auth.user == self.config.auth.0
            && auth.password == self.config.auth.1
    }
}

#[derive(PartialEq)]
enum SocketKind {
    Ticker,
    Listener,
    Network(NetworkId),
    Client(ClientId),
}

struct BirchServer {
    sockets: Slab<SocketKind>,
    clients: Slab<Client>,
    // TODO: Since networks aren't dynamic, no benefit really to having this be a slab
    networks: Slab<Network>,
}

impl BirchServer {
    fn new() -> Self {
        Self {
            sockets: Slab::with_capacity(1024),
            clients: Slab::with_capacity(32),
            networks: Slab::with_capacity(16),
        }
    }

    fn accept_client(&mut self, poll: &Poll, socket: TcpStream) -> Result<()> {
        let client_id = self.clients.insert(Client::new(socket));
        let token = self.sockets.insert(SocketKind::Client(client_id));

        poll.register(
            &self.clients.get(client_id).unwrap().socket,
            Token(token),
            Ready::readable(),
            PollOpt::edge(),
        )?;

        println!("Client connected: client_id={} token={}", client_id, token);
        Ok(())
    }

    fn handle_network_message(&mut self, network_id: NetworkId) -> Result<()> {
        let network = self
            .networks
            .get_mut(network_id)
            .expect("activity on unassigned networks id");

        let msg = network.socket.reader.read_message()?;

        println!("[birch <- \u{1b}[37;1mnet\u{1b}[0m] {}", msg);
        network.conn.handle(&msg)?;

        for msg in network.conn.network_messages() {
            println!("[\u{1b}[37;1mbirch\u{1b}[0m -> net] {}", msg);
            network.socket.write_message(&msg)?;
        }

        for msg in network.conn.user_messages() {
            let clients = self
                .clients
                .iter_mut()
                .filter(|(_, c)| c.network == Some(network_id));

            for (_, client) in clients {
                if let Err(err) = client.socket.write_message(&msg) {
                    println!("Failed to write to client: {}", err);
                }
            }
        }

        Ok(())
    }

    fn handle_client_message(&mut self, client_id: ClientId) -> Result<()> {
        let client = self
            .clients
            .get_mut(client_id)
            .expect("activity on unassigned client id");

        let msg = client.socket.reader.read_message()?;

        println!(
            "[birch <- \u{1b}[37;1mclient({})\u{1b}[0m] {}",
            client_id, msg
        );

        client.conn.handle_message(&msg)?;

        for event in client.conn.events() {
            match event {
                ClientEvent::WriteNetwork(ref _msg) => unimplemented!(),
                ClientEvent::WriteClient(ref msg) => client.socket.write_message(msg)?,
                ClientEvent::RegistrationComplete => {
                    // TODO: Update client's nick
                    match client.network {
                        Some(id) => {
                            let network = self
                                .networks
                                .get_mut(id)
                                .expect("client referencing unknown network");

                            network.conn.state.welcome_user(&mut client.socket)?;
                        }
                        None => panic!("registration completed without network"),
                    }
                }
                ClientEvent::AuthAttempt(auth) => {
                    let id = self
                        .networks
                        .iter()
                        .find(|(_, n)| n.authenticate(&auth))
                        .map(|(id, _)| id);

                    // TODO: set auth result back on client.conn
                    client.network = id
                }
            }
        }

        Ok(())
    }

    fn ping_clients(&mut self, poll: &Poll) -> Result<()> {
        let mut to_remove = Vec::new();
        for (id, client) in self.clients.iter_mut() {
            if !client.conn.ping() {
                println!("client({}) timed out", id);
                to_remove.push(id);
            }

            // TODO: remove duplication
            for event in client.conn.events() {
                match event {
                    ClientEvent::WriteClient(ref msg) => {
                        client.socket.write_message(msg)?
                    }
                    _ => unreachable!(),
                }
            }
        }

        for client_id in to_remove.iter() {
            self.remove_client(poll, *client_id)?;
        }

        Ok(())
    }

    // TODO: This is a bit too complicated
    fn remove_client(&mut self, poll: &Poll, id: ClientId) -> Result<()> {
        let client = self.clients.remove(id);
        poll.deregister(&client.socket)?;

        let (tok, _) = self
            .sockets
            .iter()
            .find(|(_, s)| SocketKind::Client(id) == **s)
            .unwrap();

        self.sockets.remove(tok);
        Ok(())
    }

    fn reconnect_networks(&mut self, poll: &Poll) -> Result<()> {
        for (id, network) in self.networks.iter_mut().filter(|(_, n)| !n.connected) {
            println!("network {} is disconnected... attempting reconnect", id);
            match network.reconnect() {
                Ok(()) => poll.register(
                    &network.socket,
                    Token(self.sockets.insert(SocketKind::Network(id))),
                    Ready::readable(),
                    PollOpt::edge(),
                )?,
                Err(err) => println!("reconnect failed: {}", err),
            }
        }

        Ok(())
    }

    fn handle_poll_event(
        &mut self,
        poll: &Poll,
        listener: &TcpListener,
        token: Token,
    ) -> Result<()> {
        match self.sockets.get(token.0) {
            None => panic!("token not associated with a socket: {:?}", token),

            Some(&SocketKind::Ticker) => {
                self.ping_clients(poll)?;
                self.reconnect_networks(poll)?;
            }

            Some(&SocketKind::Listener) => loop {
                match listener.accept() {
                    Ok((socket, _)) => self.accept_client(&poll, socket)?,
                    Err(ref e) if e.kind() == ErrorKind::WouldBlock => break,
                    e => panic!("failed to accept err={:?}", e),
                }
            },

            Some(&SocketKind::Network(network_id)) => loop {
                match self.handle_network_message(network_id) {
                    Ok(_) => (),
                    Err(ref e) if e.kind() == ErrorKind::WouldBlock => break,
                    Err(e) => {
                        // TODO: Reconnection logic
                        println!("Network errored, disconnecting: {}", e);
                        self.sockets.remove(token.0);
                        let mut network = self.networks.get_mut(network_id).unwrap();
                        network.connected = false;
                        poll.deregister(&network.socket)?;
                        break;
                    }
                }
            },
            Some(&SocketKind::Client(client_id)) => loop {
                match self.handle_client_message(client_id) {
                    Ok(_) => (),
                    Err(ref e) if e.kind() == ErrorKind::WouldBlock => break,
                    Err(e) => {
                        println!("Client errored, disconnecting: {}", e);
                        self.remove_client(poll, client_id)?;
                        break;
                    }
                }
            },
        }

        Ok(())
    }

    fn add_network(&mut self, config: NetworkConfig) -> Result<NetworkId> {
        let mut network = Network::new(config)?;
        network.conn.initialize()?;

        let token = self.networks.insert(network);
        self.sockets.insert(SocketKind::Network(token));

        Ok(token)
    }

    fn serve(&mut self, bind_addr: &SocketAddr) -> Result<()> {
        let poll = Poll::new()?;

        // TODO: is this iffy? Should we just store the Poll object on
        // the struct itself?
        for (id, network) in self.networks.iter_mut() {
            poll.register(
                &network.socket,
                Token(id),
                Ready::readable(),
                PollOpt::edge(),
            )?;
        }

        let listener = TcpListener::bind(bind_addr)?;
        {
            let tok = self.sockets.insert(SocketKind::Listener);
            poll.register(&listener, Token(tok), Ready::readable(), PollOpt::edge())?;
        }

        let ticker = Ticker::new(Duration::from_secs(60));
        {
            let tok = self.sockets.insert(SocketKind::Ticker);
            poll.register(&ticker, Token(tok), Ready::readable(), PollOpt::edge())?;
        }

        loop {
            let mut events = Events::with_capacity(128);
            poll.poll(&mut events, None)?;

            for ev in events {
                self.handle_poll_event(&poll, &listener, ev.token())?;
            }
        }
    }
}

fn main() -> Result<()> {
    let config = NetworkConfig {
        network_name: "freenode".to_string(),
        nick: "ep".to_string(),
        auth: ("foo".to_string(), "bar".to_string()),
        socket: IrcSocketConfig {
            addr: "irc.freenode.net:6667".parse().unwrap(),
            max_retries: Some(3),
        },
    };

    let mut server = BirchServer::new();
    server.add_network(config)?;

    server.serve(&"127.0.0.1:9123".parse().unwrap())
}
<|endoftext|>


<commit_before>
extern crate elmesque;
extern crate gfx;
extern crate gfx_device_gl;
extern crate gfx_graphics;
extern crate glutin_window;
extern crate graphics;
extern crate num;
extern crate shader_version;
extern crate piston;

use elmesque::{Form, Renderer};
use gfx::traits::*;
use gfx_graphics::{Gfx2d, GlyphCache};
use glutin_window::GlutinWindow;
use piston::event::{Event, Events};
use piston::window::{Size, Window, WindowSettings};

fn main() {

    let window = GlutinWindow::new(
        shader_version::opengl::OpenGL::_3_2,
        WindowSettings::new(
            "Elmesque".to_string(),
            Size { width: 1180, height: 580 },
        )
        .exit_on_esc(true)
        .samples(4)
    );
    let (mut device, mut factory) = gfx_device_gl::create(|s| window.window.get_proc_address(s));
    let mut g2d = Gfx2d::new(&mut device, &mut factory);
    let mut renderer = factory.create_renderer();
    let Size { width, height } = window.size();
    let output = factory.make_fake_output(width as u16, height as u16);
    let font_path = ::std::path::Path::new("./assets/NotoSans/NotoSans-Regular.ttf");
    let mut glyph_cache = GlyphCache::new(&font_path, &mut factory).unwrap();
    let event_iter = window.events().ups(180).max_fps(60);
    let mut secs = 0.0;
    for event in event_iter {
        match event {
            Event::Render(args) => {
                g2d.draw(&mut renderer, &output, args.viewport(), |_, graphics| {
                    let (w, h) = (args.width as f64, args.height as f64);

                    let mut renderer = Renderer::new(w, h, graphics).character_cache(&mut glyph_cache);

                    // Construct some freeform graphics aka a `Form`.
                    let form = elmesque_demo_form(secs);

                    // Convert the form to an `Element` for rendering.
                    elmesque::form::collage(w as i32, h as i32, vec![form])
                        .clear(elmesque::color::black())
                        .draw(&mut renderer);

                });
                device.submit(renderer.as_buffer());
                renderer.reset();
                glyph_cache.update(&mut factory);
            },
            Event::Update(args) => secs += args.dt,
            _ => (),
        }
    }
}

/// Demo of grouping multiple forms into a new single form, transformable at any stage.
pub fn elmesque_demo_form(secs: f64) -> Form {
    use elmesque::color::{blue, dark_blue, light_blue, dark_purple, white};
    use elmesque::form::{circle, group, ngon, oval, point_path, rect, solid, text, traced};
    use elmesque::text::Text;
    use elmesque::utils::{degrees};
    use num::Float;

    // Time to get creative!
    group(vec![

        rect(60.0, 40.0).filled(blue())
            .shift(secs.sin() * 50.0, secs.cos() * 50.0)
            .alpha(((secs * 200.0).cos() * 0.5 + 0.5) as f32)
            .rotate(-secs),

        rect(100.0, 10.0).filled(dark_blue())
            .shift((secs * 5.0).sin() * 200.0, (secs * 5.0).cos() * 200.0)
            .alpha(((secs * 2.0).cos() * 0.5 + 0.5) as f32)
            .rotate(-(secs * 5.0)),

        rect(10.0, 300.0).filled(blue())
            .alpha(((secs * 3.0).sin() * 0.25 + 0.75) as f32)
            .rotate(-(secs * 1.5)),

        rect(5.0, (secs * 0.1).sin() * 600.0 + 300.0).filled(light_blue())
            .alpha(((secs).cos() * 0.25 + 0.75) as f32)
            .rotate(secs * 0.75),

        rect(3.0, 2000.0).filled(dark_blue())
            .alpha(((secs * 100.0).cos() * 0.5 + 0.25) as f32)
            .rotate(-(secs * 0.5)),

        oval(3.0, 2000.0 * (secs * 60.0).sin()).filled(light_blue())
            .alpha(((secs * 100.0).cos() * 0.5 + 0.25) as f32)
            .rotate(-(secs * 0.6)),

        rect(10.0, 750.0).filled(blue())
            .alpha(((secs * 2.0).cos() * 0.5 + 0.25) as f32)
            .rotate(-(secs * 1.85)),

        circle((secs * 0.5).sin() * 1500.0).outlined(solid(dark_purple()))
            .alpha(((secs * 0.2).sin() * 0.25 + 0.35) as f32)
            .rotate(-(secs * 0.5)),

        ngon(12, (secs * 0.1).cos() * 100.0 + 300.0).filled(blue())
            .alpha((0.25 * secs.cos()) as f32)
            .rotate(secs * 0.5),

        ngon(9, (secs * 0.1).cos() * 200.0 + 250.0).outlined(solid(dark_blue()))
            .alpha(((0.33 * secs).sin() + 0.15) as f32)
            .rotate(secs * 0.2),

        rect(300.0, 20.0).filled(light_blue())
            .shift((secs * 1.5).cos() * 250.0, (secs * 1.5).sin() * 250.0)
            .alpha(((secs * 4.5).cos() * 0.25 + 0.35) as f32)
            .rotate(secs * 1.5 + degrees(90.0)),

        traced(
            solid(light_blue()),
            point_path(vec![(-500.0, 100.0), (0.0, 250.0 * secs.sin()), (500.0, 100.0)])
        ).alpha(((secs * 0.2).sin() * 0.25 + 0.35) as f32),

        traced(
            solid(blue()),
            point_path(vec![(-500.0, 0.0), (0.0, 0.0), (500.0, 0.0)])
        ).alpha(((secs * 4.5).cos() * 0.25 + 0.35) as f32),

        traced(
            solid(dark_blue()),
            point_path(vec![(-500.0, -100.0), (0.0, -250.0 * secs.sin()), (500.0, -100.0)])
        ).alpha(((secs * 0.15).cos() * 0.25 + 0.35) as f32),

        text(Text::from_string("elmesque".to_string()).color(white())),

    ]).rotate(degrees(secs.sin() * 360.0))
      .scale((secs * 0.05).cos() * 0.2 + 0.9)

}

<commit_msg>fix for https://github.com/mitchmindtree/elmesque/issues/13 incorrect output dimensions on retina<commit_after>
extern crate elmesque;
extern crate gfx;
extern crate gfx_device_gl;
extern crate gfx_graphics;
extern crate glutin_window;
extern crate graphics;
extern crate num;
extern crate shader_version;
extern crate piston;

use elmesque::{Form, Renderer};
use gfx::traits::*;
use gfx_graphics::{Gfx2d, GlyphCache};
use glutin_window::GlutinWindow;
use piston::event::{Event, Events};
use piston::window::{Size, Window, WindowSettings};

fn main() {

    let window = GlutinWindow::new(
        shader_version::opengl::OpenGL::_3_2,
        WindowSettings::new(
            "Elmesque".to_string(),
            Size { width: 1180, height: 580 },
        )
        .exit_on_esc(true)
        .samples(4)
    );
    let (mut device, mut factory) = gfx_device_gl::create(|s| window.window.get_proc_address(s));
    let mut g2d = Gfx2d::new(&mut device, &mut factory);
    let mut renderer = factory.create_renderer();
    let Size { width, height } = window.draw_size();
    let output = factory.make_fake_output(width as u16, height as u16);
    let font_path = ::std::path::Path::new("./assets/NotoSans/NotoSans-Regular.ttf");
    let mut glyph_cache = GlyphCache::new(&font_path, &mut factory).unwrap();
    let event_iter = window.events().ups(180).max_fps(60);
    let mut secs = 0.0;
    for event in event_iter {
        match event {
            Event::Render(args) => {
                g2d.draw(&mut renderer, &output, args.viewport(), |_, graphics| {
                    let (w, h) = (args.width as f64, args.height as f64);

                    let mut renderer = Renderer::new(w, h, graphics).character_cache(&mut glyph_cache);

                    // Construct some freeform graphics aka a `Form`.
                    let form = elmesque_demo_form(secs);

                    // Convert the form to an `Element` for rendering.
                    elmesque::form::collage(w as i32, h as i32, vec![form])
                        .clear(elmesque::color::black())
                        .draw(&mut renderer);

                });
                device.submit(renderer.as_buffer());
                renderer.reset();
                glyph_cache.update(&mut factory);
            },
            Event::Update(args) => secs += args.dt,
            _ => (),
        }
    }
}

/// Demo of grouping multiple forms into a new single form, transformable at any stage.
pub fn elmesque_demo_form(secs: f64) -> Form {
    use elmesque::color::{blue, dark_blue, light_blue, dark_purple, white};
    use elmesque::form::{circle, group, ngon, oval, point_path, rect, solid, text, traced};
    use elmesque::text::Text;
    use elmesque::utils::{degrees};
    use num::Float;

    // Time to get creative!
    group(vec![

        rect(60.0, 40.0).filled(blue())
            .shift(secs.sin() * 50.0, secs.cos() * 50.0)
            .alpha(((secs * 200.0).cos() * 0.5 + 0.5) as f32)
            .rotate(-secs),

        rect(100.0, 10.0).filled(dark_blue())
            .shift((secs * 5.0).sin() * 200.0, (secs * 5.0).cos() * 200.0)
            .alpha(((secs * 2.0).cos() * 0.5 + 0.5) as f32)
            .rotate(-(secs * 5.0)),

        rect(10.0, 300.0).filled(blue())
            .alpha(((secs * 3.0).sin() * 0.25 + 0.75) as f32)
            .rotate(-(secs * 1.5)),

        rect(5.0, (secs * 0.1).sin() * 600.0 + 300.0).filled(light_blue())
            .alpha(((secs).cos() * 0.25 + 0.75) as f32)
            .rotate(secs * 0.75),

        rect(3.0, 2000.0).filled(dark_blue())
            .alpha(((secs * 100.0).cos() * 0.5 + 0.25) as f32)
            .rotate(-(secs * 0.5)),

        oval(3.0, 2000.0 * (secs * 60.0).sin()).filled(light_blue())
            .alpha(((secs * 100.0).cos() * 0.5 + 0.25) as f32)
            .rotate(-(secs * 0.6)),

        rect(10.0, 750.0).filled(blue())
            .alpha(((secs * 2.0).cos() * 0.5 + 0.25) as f32)
            .rotate(-(secs * 1.85)),

        circle((secs * 0.5).sin() * 1500.0).outlined(solid(dark_purple()))
            .alpha(((secs * 0.2).sin() * 0.25 + 0.35) as f32)
            .rotate(-(secs * 0.5)),

        ngon(12, (secs * 0.1).cos() * 100.0 + 300.0).filled(blue())
            .alpha((0.25 * secs.cos()) as f32)
            .rotate(secs * 0.5),

        ngon(9, (secs * 0.1).cos() * 200.0 + 250.0).outlined(solid(dark_blue()))
            .alpha(((0.33 * secs).sin() + 0.15) as f32)
            .rotate(secs * 0.2),

        rect(300.0, 20.0).filled(light_blue())
            .shift((secs * 1.5).cos() * 250.0, (secs * 1.5).sin() * 250.0)
            .alpha(((secs * 4.5).cos() * 0.25 + 0.35) as f32)
            .rotate(secs * 1.5 + degrees(90.0)),

        traced(
            solid(light_blue()),
            point_path(vec![(-500.0, 100.0), (0.0, 250.0 * secs.sin()), (500.0, 100.0)])
        ).alpha(((secs * 0.2).sin() * 0.25 + 0.35) as f32),

        traced(
            solid(blue()),
            point_path(vec![(-500.0, 0.0), (0.0, 0.0), (500.0, 0.0)])
        ).alpha(((secs * 4.5).cos() * 0.25 + 0.35) as f32),

        traced(
            solid(dark_blue()),
            point_path(vec![(-500.0, -100.0), (0.0, -250.0 * secs.sin()), (500.0, -100.0)])
        ).alpha(((secs * 0.15).cos() * 0.25 + 0.35) as f32),

        text(Text::from_string("elmesque".to_string()).color(white())),

    ]).rotate(degrees(secs.sin() * 360.0))
      .scale((secs * 0.05).cos() * 0.2 + 0.9)

}

<|endoftext|>


<commit_before>extern crate docopt;
extern crate flac;
extern crate rustc_serialize;

use docopt::Docopt;
use flac::{ReadStream, Stream, StreamProducer};

use std::env;
use std::fs::File;

const USAGE: &'static str = "
Usage: metadata streaminfo <input>
       metadata --help

Options:
  -h, --help   Show this message.
";

#[derive(Debug, RustcDecodable)]
struct Arguments {
  arg_input: String,
  cmd_streaminfo: bool,
}

fn print_stream_info<P: StreamProducer>(stream: &Stream<P>) {
  let info = stream.info();

  println!("StreamInfo
  Minimum block size: {}
  Maximum block size: {}
  Maximum frame size: {}
  Maximum frame size: {}
  Sample rate: {} Hz
  Number of channels: {}
  Bits per sample: {}
  Total samples: {}
  MD5 sum: {:?}",
  info.min_block_size, info.max_block_size,
  info.min_frame_size, info.max_frame_size,
  info.sample_rate, info.channels, info.bits_per_sample, info.total_samples,
  info.md5_sum);
}

fn main() {
  let args: Arguments = Docopt::new(USAGE)
    .and_then(|d| d.argv(env::args()).decode())
    .unwrap_or_else(|e| e.exit());

  let stream = Stream::<ReadStream<File>>::from_file(&args.arg_input)
                 .expect("Couldn't parse file");

  if args.cmd_streaminfo {
    print_stream_info(&stream);
  }
}
<commit_msg>Format md5 to be a single string<commit_after>extern crate docopt;
extern crate flac;
extern crate rustc_serialize;

use docopt::Docopt;
use flac::{ReadStream, Stream, StreamProducer};

use std::env;
use std::fs::File;

const USAGE: &'static str = "
Usage: metadata streaminfo <input>
       metadata --help

Options:
  -h, --help   Show this message.
";

#[derive(Debug, RustcDecodable)]
struct Arguments {
  arg_input: String,
  cmd_streaminfo: bool,
}

fn print_stream_info<P: StreamProducer>(stream: &Stream<P>) {
  let info    = stream.info();
  let mut md5 = String::with_capacity(32);

  for byte in &info.md5_sum {
    let hex = format!("{:02x}", byte);

    md5.push_str(&hex);
  }

  println!("StreamInfo
  Minimum block size: {}
  Maximum block size: {}
  Maximum frame size: {}
  Maximum frame size: {}
  Sample rate: {} Hz
  Number of channels: {}
  Bits per sample: {}
  Total samples: {}
  MD5 sum: {}",
  info.min_block_size, info.max_block_size,
  info.min_frame_size, info.max_frame_size,
  info.sample_rate, info.channels, info.bits_per_sample,
  info.total_samples, md5);
}

fn main() {
  let args: Arguments = Docopt::new(USAGE)
    .and_then(|d| d.argv(env::args()).decode())
    .unwrap_or_else(|e| e.exit());

  let stream = Stream::<ReadStream<File>>::from_file(&args.arg_input)
                 .expect("Couldn't parse file");

  if args.cmd_streaminfo {
    print_stream_info(&stream);
  }
}
<|endoftext|>


<commit_before>extern crate docopt;
extern crate flac;
extern crate rustc_serialize;

#[macro_use]
mod commands;

use std::env;

use commands::{streaminfo, comments, seektable, picture};
use docopt::Docopt;

const USAGE: &'static str = "
Usage: metadata <command> [<args>...]
       metadata [options] [<filename>]

Options:
  --list      List all blocks by name.
  -h, --help  Show this message.

Commands:
  streaminfo  Display stream information.
  comments    Display or export comment tags.
  seektable   Display seek table.
  picture     Export pictures.
";

#[derive(Debug, RustcDecodable)]
struct Arguments {
  arg_command: Option<Command>,
  arg_filename: Option<String>,
  flag_list: bool,
  arg_args: Vec<String>,
}

#[derive(Clone, Copy, Debug, RustcDecodable)]
enum Command {
  StreamInfo,
  Comments,
  SeekTable,
  Picture,
}

fn handle_subcommand(command: Command) {
  match command {
    Command::StreamInfo => command!(streaminfo),
    Command::Comments   => command!(comments),
    Command::SeekTable  => command!(seektable),
    Command::Picture    => command!(picture),
  }
}

fn main() {
  let args: Arguments = Docopt::new(USAGE)
    .and_then(|d| d.options_first(true).decode())
    .unwrap_or_else(|e| e.exit());

  if let Some(command) = args.arg_command {
    handle_subcommand(command);
  } else {
    println!("{}", USAGE);
  }
}
<commit_msg>Add CLI hook for the list flag<commit_after>extern crate docopt;
extern crate flac;
extern crate rustc_serialize;

#[macro_use]
mod commands;

use std::env;

use commands::{streaminfo, comments, seektable, picture, list_block_names};
use docopt::Docopt;

const USAGE: &'static str = "
Usage: metadata <command> [<args>...]
       metadata [options] [<filename>]

Options:
  --list      List all blocks by name.
  -h, --help  Show this message.

Commands:
  streaminfo  Display stream information.
  comments    Display or export comment tags.
  seektable   Display seek table.
  picture     Export pictures.
";

#[derive(Debug, RustcDecodable)]
struct Arguments {
  arg_command: Option<Command>,
  arg_filename: Option<String>,
  flag_list: bool,
  arg_args: Vec<String>,
}

#[derive(Clone, Copy, Debug, RustcDecodable)]
enum Command {
  StreamInfo,
  Comments,
  SeekTable,
  Picture,
}

fn handle_subcommand(command: Command) {
  match command {
    Command::StreamInfo => command!(streaminfo),
    Command::Comments   => command!(comments),
    Command::SeekTable  => command!(seektable),
    Command::Picture    => command!(picture),
  }
}

fn main() {
  let args: Arguments = Docopt::new(USAGE)
    .and_then(|d| d.options_first(true).decode())
    .unwrap_or_else(|e| e.exit());

  if let Some(command) = args.arg_command {
    handle_subcommand(command);
  } else if let Some(ref filename) = args.arg_filename {
    if args.flag_list {
      list_block_names(filename);
    }
  } else {
    println!("{}", USAGE);
  }
}
<|endoftext|>


<commit_before>extern crate gl;
extern crate sdl2;
extern crate yaglw;

use gl::types::*;
use sdl2::event::Event;
use std::mem;
use std::time::duration::Duration;
use std::io::timer;

use yaglw::gl_context::GLContext;
use yaglw::shader::Shader;
use yaglw::vertex_buffer::{GLArray, GLBuffer, GLType, VertexAttribData, DrawMode};

#[repr(C)]
#[derive(Copy)]
struct Vertex {
  pub position: [GLfloat; 2],
  pub color: [GLfloat; 3],
}

const VERTEX_SHADER: &'static str = "
  #version 130

  in vec2 position;
  in vec3 color;

  out vec3 v_color;

  void main() {
    v_color = color;
    gl_Position = vec4(position, 0, 1);
  }
";

const FRAGMENT_SHADER: &'static str = "
  #version 130

  in vec3 v_color;

  void main() {
    gl_FragColor = vec4(v_color, 1.0);
  }
";

pub fn main() {
  let window = make_window();

  let _sdl_gl_context = window.gl_create_context().unwrap();

  // Load the OpenGL function pointers.
  gl::load_with(|s| unsafe {
    mem::transmute(sdl2::video::gl_get_proc_address(s))
  });

  let (gl, mut gl_context) = unsafe {
    GLContext::new()
  };

  let vertices = [
    Vertex {
      position: [0.0, 0.5],
      color: [1.0, 0.0, 0.0],
    },
    Vertex {
      position: [-0.5, -0.5],
      color: [0.0, 1.0, 0.0],
    },
    Vertex {
      position: [0.5, -0.5],
      color: [0.0, 0.0, 1.0],
    },
  ];

  let mut vbo = GLBuffer::new(&gl, &mut gl_context, 3);
  vbo.push(&mut gl_context, &vertices);

  let attribs = [
    VertexAttribData {
      name: "position",
      size: 2,
      unit: GLType::Float,
    },
    VertexAttribData {
      name: "color",
      size: 3,
      unit: GLType::Float,
    },
  ];

  let components = [
    ((gl::VERTEX_SHADER, VERTEX_SHADER)),
    ((gl::FRAGMENT_SHADER, FRAGMENT_SHADER)),
  ];

  let shader = Shader::new(&gl, components.iter().map(|&(ty, s)| (ty, String::from_str(s))));
  shader.use_shader(&mut gl_context);

  let vao =
    GLArray::new(
      &gl,
      &mut gl_context,
      &shader,
      &attribs,
      DrawMode::Triangles,
      vbo,
    );
  vao.bind(&mut gl_context);

  match gl_context.get_error() {
    gl::NO_ERROR => {},
    err => {
      println!("OpenGL error 0x{:x} in setup", err);
      return;
    },
  }

  while !quit_event() {
    gl_context.clear_buffer();
    vao.draw(&mut gl_context);
    // swap buffers
    window.gl_swap_window();

    timer::sleep(Duration::milliseconds(10));
  }
}

fn make_window() -> sdl2::video::Window {
  sdl2::init(sdl2::INIT_EVERYTHING);

  sdl2::video::gl_set_attribute(sdl2::video::GLAttr::GLContextMajorVersion, 3);
  sdl2::video::gl_set_attribute(sdl2::video::GLAttr::GLContextMinorVersion, 0);
  sdl2::video::gl_set_attribute(
    sdl2::video::GLAttr::GLContextProfileMask,
    sdl2::video::GLProfile::GLCoreProfile as i32,
  );

  sdl2::video::Window::new(
    "Triangle",
    sdl2::video::WindowPos::PosCentered,
    sdl2::video::WindowPos::PosCentered,
    800,
    600,
    sdl2::video::OPENGL,
  ).unwrap()
}

fn quit_event() -> bool {
  loop {
    match sdl2::event::poll_event() {
      Event::None => {
        return false;
      },
      Event::Quit(_) => {
        return true;
      }
      Event::AppTerminating(_) => {
        return true;
      }
      _ => {},
    }
  }
}
<commit_msg>std::io -> std::old_io<commit_after>extern crate gl;
extern crate sdl2;
extern crate yaglw;

use gl::types::*;
use sdl2::event::Event;
use std::mem;
use std::time::duration::Duration;
use std::old_io::timer;

use yaglw::gl_context::GLContext;
use yaglw::shader::Shader;
use yaglw::vertex_buffer::{GLArray, GLBuffer, GLType, VertexAttribData, DrawMode};

#[repr(C)]
#[derive(Copy)]
struct Vertex {
  pub position: [GLfloat; 2],
  pub color: [GLfloat; 3],
}

const VERTEX_SHADER: &'static str = "
  #version 130

  in vec2 position;
  in vec3 color;

  out vec3 v_color;

  void main() {
    v_color = color;
    gl_Position = vec4(position, 0, 1);
  }
";

const FRAGMENT_SHADER: &'static str = "
  #version 130

  in vec3 v_color;

  void main() {
    gl_FragColor = vec4(v_color, 1.0);
  }
";

pub fn main() {
  let window = make_window();

  let _sdl_gl_context = window.gl_create_context().unwrap();

  // Load the OpenGL function pointers.
  gl::load_with(|s| unsafe {
    mem::transmute(sdl2::video::gl_get_proc_address(s))
  });

  let (gl, mut gl_context) = unsafe {
    GLContext::new()
  };

  let vertices = [
    Vertex {
      position: [0.0, 0.5],
      color: [1.0, 0.0, 0.0],
    },
    Vertex {
      position: [-0.5, -0.5],
      color: [0.0, 1.0, 0.0],
    },
    Vertex {
      position: [0.5, -0.5],
      color: [0.0, 0.0, 1.0],
    },
  ];

  let mut vbo = GLBuffer::new(&gl, &mut gl_context, 3);
  vbo.push(&mut gl_context, &vertices);

  let attribs = [
    VertexAttribData {
      name: "position",
      size: 2,
      unit: GLType::Float,
    },
    VertexAttribData {
      name: "color",
      size: 3,
      unit: GLType::Float,
    },
  ];

  let components = [
    ((gl::VERTEX_SHADER, VERTEX_SHADER)),
    ((gl::FRAGMENT_SHADER, FRAGMENT_SHADER)),
  ];

  let shader = Shader::new(&gl, components.iter().map(|&(ty, s)| (ty, String::from_str(s))));
  shader.use_shader(&mut gl_context);

  let vao =
    GLArray::new(
      &gl,
      &mut gl_context,
      &shader,
      &attribs,
      DrawMode::Triangles,
      vbo,
    );
  vao.bind(&mut gl_context);

  match gl_context.get_error() {
    gl::NO_ERROR => {},
    err => {
      println!("OpenGL error 0x{:x} in setup", err);
      return;
    },
  }

  while !quit_event() {
    gl_context.clear_buffer();
    vao.draw(&mut gl_context);
    // swap buffers
    window.gl_swap_window();

    timer::sleep(Duration::milliseconds(10));
  }
}

fn make_window() -> sdl2::video::Window {
  sdl2::init(sdl2::INIT_EVERYTHING);

  sdl2::video::gl_set_attribute(sdl2::video::GLAttr::GLContextMajorVersion, 3);
  sdl2::video::gl_set_attribute(sdl2::video::GLAttr::GLContextMinorVersion, 0);
  sdl2::video::gl_set_attribute(
    sdl2::video::GLAttr::GLContextProfileMask,
    sdl2::video::GLProfile::GLCoreProfile as i32,
  );

  sdl2::video::Window::new(
    "Triangle",
    sdl2::video::WindowPos::PosCentered,
    sdl2::video::WindowPos::PosCentered,
    800,
    600,
    sdl2::video::OPENGL,
  ).unwrap()
}

fn quit_event() -> bool {
  loop {
    match sdl2::event::poll_event() {
      Event::None => {
        return false;
      },
      Event::Quit(_) => {
        return true;
      }
      Event::AppTerminating(_) => {
        return true;
      }
      _ => {},
    }
  }
}
<|endoftext|>


<commit_before>use turtle::Turtle;
use chrono::{Local, Timelike};
use std::{thread, time};

fn main() {
    let hours = 12;
    let minutes = 60.0;
    let seconds = 60.0;
    let full_circle = 360.0;
    let second = time::Duration::from_millis(1000);

    let mut turtle = Turtle::new();
    turtle.set_speed("instant");
    turtle.hide();

    //A clock runs forever
    loop{
        //clean everything
        turtle.clear();
        turtle.pen_up();
        turtle.home();

        //Get local time
        let now = Local::now();

        //Draw the clock
        for i in 1..=hours{
            turtle.forward(205.0);
            turtle.set_pen_size(if (i - 1) % 3 == 0 {5.0} else {1.0});
            turtle.pen_down();
            turtle.forward(5.0);
            turtle.pen_up();
            turtle.home();
            turtle.right(full_circle / hours as f64 * i as f64);
        }
        turtle.pen_down();

        //Draw the hour hand
        turtle.home();
        turtle.right(full_circle / hours as f64 * now.hour() as f64);
        turtle.set_pen_size(5.0);
        turtle.forward(120.0);

        //Draw the minute hand
        turtle.home();
        turtle.right(full_circle / minutes * now.minute() as f64);
        turtle.set_pen_size(3.0);
        turtle.forward(150.0);

        //Draw the second hand
        turtle.home();
        turtle.right(full_circle / seconds * now.second() as f64);
        turtle.set_pen_size(1.0);
        turtle.forward(180.0);

        //And update every second
        thread::sleep(second);
    }
}<commit_msg>Minor formatting tweaks<commit_after>use std::{thread, time};

use chrono::{Local, Timelike};
use turtle::Turtle;

fn main() {
    let hours = 12;
    let minutes = 60.0;
    let seconds = 60.0;
    let full_circle = 360.0;
    let second = time::Duration::from_millis(1000);

    let mut turtle = Turtle::new();
    turtle.set_speed("instant");
    turtle.hide();

    // A clock runs forever
    loop {
        // Clear the screen
        turtle.clear();
        turtle.pen_up();
        turtle.home();

        // Get local time
        let now = Local::now();

        // Draw the clock
        for i in 1..=hours {
            turtle.forward(205.0);
            turtle.set_pen_size(if (i - 1) % 3 == 0 { 5.0 } else { 1.0 });

            turtle.pen_down();
            turtle.forward(5.0);
            turtle.pen_up();

            turtle.home();
            turtle.right(full_circle / hours as f64 * i as f64);
        }

        turtle.pen_down();

        // Draw the hour hand
        turtle.home();
        turtle.right(full_circle / hours as f64 * now.hour() as f64);
        turtle.set_pen_size(5.0);
        turtle.forward(120.0);

        // Draw the minute hand
        turtle.home();
        turtle.right(full_circle / minutes * now.minute() as f64);
        turtle.set_pen_size(3.0);
        turtle.forward(150.0);

        // Draw the second hand
        turtle.home();
        turtle.right(full_circle / seconds * now.second() as f64);
        turtle.set_pen_size(1.0);
        turtle.forward(180.0);

        // And update every second
        thread::sleep(second);
    }
}
<|endoftext|>


<commit_before>//! Module containing types and functions for mapping between byte indexes and line and column
//! locations

use pos::{BytePos, Column, Line, Location, Span};

/// Type which provides a bidirectional mapping between byte offsets and line and column locations
/// for some source file
#[derive(Clone, Debug)]
pub struct Lines {
    starting_bytes: Vec<BytePos>,
    end: usize,
}

impl Lines {
    /// Creates a mapping for `src`
    pub fn new(src: &str) -> Lines {
        use std::iter;

        let input_indices = src.as_bytes()
            .iter()
            .enumerate()
            .filter(|&(_, &b)| b == b'\n')
            .map(|(i, _)| BytePos::from(i + 1)); // index of first char in the line

        let starting_bytes = iter::once(BytePos::from(0)).chain(input_indices).collect();
        Lines {
            starting_bytes: starting_bytes,
            end: src.len(),
        }
    }

    /// Returns the byte offset of the start of `line_number`
    pub fn line(&self, line_number: Line) -> Option<BytePos> {
        let line_number = line_number.to_usize();
        self.starting_bytes.get(line_number).cloned()
    }

    /// Returns the line and column location of `byte`
    pub fn location(&self, byte: BytePos) -> Option<Location> {
        if byte.to_usize() <= self.end {
            let line_index = self.line_number_at_byte(byte);

            self.line(line_index).map(|line_byte| {
                Location {
                    line: line_index,
                    column: Column::from((byte - line_byte).to_usize()),
                    absolute: byte,
                }
            })
        } else {
            None
        }
    }

    /// Returns which line `byte` points to
    pub fn line_number_at_byte(&self, byte: BytePos) -> Line {
        let num_lines = self.starting_bytes.len();

        Line::from(
            (0..num_lines)
                .filter(|&i| self.starting_bytes[i] > byte)
                .map(|i| i - 1)
                .next()
                .unwrap_or(num_lines - 1),
        )
    }
}

/// Type which provides a bidirectional mapping between byte offsets and line and column locations
#[derive(Clone, Debug)]
pub struct Source<'a> {
    src: &'a str,
    /// The starting byte position of each line in `src`
    lines: Lines,
}

impl<'a> Source<'a> {
    pub fn new(src: &str) -> Source {
        Source {
            src: src,
            lines: Lines::new(src),
        }
    }

    /// Returns the string which defines the source
    pub fn src(&self) -> &'a str {
        self.src
    }

    /// Returns the byte offset and source of `line_number`
    pub fn line(&self, line_number: Line) -> Option<(BytePos, &str)> {
        self.lines.line(line_number).map(|start| {
            let line = match self.lines.starting_bytes.get(line_number.to_usize() + 1) {
                Some(end) => &self.src[start.to_usize()..end.to_usize() - 1], // Skip '\n'
                None => &self.src[start.to_usize()..],
            };

            (start, line)
        })
    }

    /// Returns the line number and the source at `byte`
    pub fn line_at_byte(&self, byte: BytePos) -> Option<(BytePos, &str)> {
        let line_number = self.line_number_at_byte(byte);
        self.line(line_number)
    }

    /// Returns which line `byte` points to
    pub fn line_number_at_byte(&self, byte: BytePos) -> Line {
        self.lines.line_number_at_byte(byte)
    }

    /// Returns the line and column location of `byte`
    pub fn location(&self, byte: BytePos) -> Option<Location> {
        self.lines.location(byte)
    }

    /// Returns the starting position of any comments and whitespace before `end`
    pub fn comment_start_before(&self, end: BytePos) -> BytePos {
        let mut iter = self.comments_between(Span::new(BytePos::from(0), end));
        // Scan from `end` until a non comment token is found
        for _ in iter.by_ref().rev() {}
        BytePos::from(iter.src.len())
    }

    pub fn comments_between(&self, span: Span<BytePos>) -> CommentIter<'a> {
        CommentIter {
            src: &self.src[span.start.to_usize()..span.end.to_usize()],
        }
    }
}

pub struct CommentIter<'a> {
    src: &'a str,
}

impl<'a> Iterator for CommentIter<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        if self.src.is_empty() {
            None
        } else {
            self.src = self.src
                .trim_matches(|c: char| c.is_whitespace() && c != '\n');
            if self.src.starts_with("//") && !self.src.starts_with("///") {
                let comment_line = self.src.lines().next().unwrap();
                self.src = &self.src[comment_line.len()..];
                self.src = if self.src.starts_with("\r\n") {
                    &self.src[2..]
                } else {
                    // \n
                    &self.src[1..]
                };
                Some(comment_line)
            } else if self.src.starts_with("/*") {
                self.src.find("*/").map(|i| {
                    let (comment, rest) = self.src.split_at(i + 2);
                    self.src = rest;
                    comment
                })
            } else if self.src.starts_with("\n") {
                self.src = &self.src[1..];
                Some("")
            } else {
                None
            }
        }
    }
}

impl<'a> DoubleEndedIterator for CommentIter<'a> {
    fn next_back(&mut self) -> Option<&'a str> {
        if self.src.is_empty() {
            None
        } else {
            self.src = self.src
                .trim_right_matches(|c: char| c.is_whitespace() && c != '\n');
            if self.src.ends_with("\n") {
                let comment_line = self.src[..self.src.len() - 1].lines().next_back().unwrap();
                let trimmed = comment_line.trim_left();

                let newline_len = if self.src.ends_with("\r\n") { 2 } else { 1 };
                self.src = &self.src[..(self.src.len() - newline_len)];

                if trimmed.starts_with("//") && !trimmed.starts_with("///") {
                    self.src = &self.src[..(self.src.len() - 2 - trimmed.len() - 1)];
                    Some(trimmed)
                } else {
                    Some("")
                }
            } else if self.src.ends_with("*/") {
                self.src.rfind("/*").map(|i| {
                    let (rest, comment) = self.src.split_at(i);
                    self.src = rest;
                    comment
                })
            } else {
                None
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use pos::{BytePos, Column, Line, Location};

    use super::Source;

    fn test_source() -> Source<'static> {
        Source::new("hello!\nhowdy\n\nhi萤\nbloop\n")
    }

    #[test]
    fn source_line() {
        let source = test_source();

        assert_eq!(
            source.line(Line::from(0)),
            Some((BytePos::from(0), "hello!"))
        );
        assert_eq!(
            source.line(Line::from(1)),
            Some((BytePos::from(7), "howdy"))
        );
        assert_eq!(source.line(Line::from(2)), Some((BytePos::from(13), "")));
        assert_eq!(
            source.line(Line::from(3)),
            Some((BytePos::from(14), "hi萤"))
        );
        assert_eq!(
            source.line(Line::from(4)),
            Some((BytePos::from(20), "bloop"))
        );
        assert_eq!(source.line(Line::from(5)), Some((BytePos::from(26), "")));
        assert_eq!(source.line(Line::from(6)), None);
    }

    #[test]
    fn source_line_number_at_byte() {
        let source = test_source();

        assert_eq!(source.line_number_at_byte(BytePos::from(0)), Line::from(0));
        assert_eq!(source.line_number_at_byte(BytePos::from(6)), Line::from(0));
        assert_eq!(source.line_number_at_byte(BytePos::from(7)), Line::from(1));
        assert_eq!(source.line_number_at_byte(BytePos::from(8)), Line::from(1));

        assert_eq!(source.line_number_at_byte(BytePos::from(12)), Line::from(1));
        assert_eq!(source.line_number_at_byte(BytePos::from(13)), Line::from(2));
        assert_eq!(source.line_number_at_byte(BytePos::from(14)), Line::from(3));
        assert_eq!(source.line_number_at_byte(BytePos::from(15)), Line::from(3));

        assert_eq!(source.line_number_at_byte(BytePos::from(18)), Line::from(3));
        assert_eq!(source.line_number_at_byte(BytePos::from(19)), Line::from(3));
        assert_eq!(source.line_number_at_byte(BytePos::from(20)), Line::from(4));

        assert_eq!(
            source.line_number_at_byte(BytePos::from(400)),
            Line::from(5)
        );
    }

    #[test]
    fn source_location() {
        let source = test_source();

        assert_eq!(
            source.location(BytePos::from(0)),
            Some(Location {
                line: Line::from(0),
                column: Column::from(0),
                absolute: BytePos::from(0),
            })
        );

        assert_eq!(
            source.location(BytePos::from(3)),
            Some(Location {
                line: Line::from(0),
                column: Column::from(3),
                absolute: BytePos::from(3),
            })
        );

        assert_eq!(
            source.location(BytePos::from(16)),
            Some(Location {
                line: Line::from(3),
                column: Column::from(2),
                absolute: BytePos::from(16),
            })
        );

        assert_eq!(source.location(BytePos::from(400)), None);
    }

    #[test]
    fn source_location_end_of_source() {
        let source = test_source();
        assert_eq!(
            source.location(BytePos::from(source.src.len())),
            Some(Location {
                line: Line::from(5),
                column: Column::from(0),
                absolute: BytePos::from(source.src.len()),
            })
        );
    }
}
<commit_msg>refactor: Generalize Lines::new to handle arbitrary byte iterators<commit_after>//! Module containing types and functions for mapping between byte indexes and line and column
//! locations

use pos::{BytePos, Column, Line, Location, Span};

/// Type which provides a bidirectional mapping between byte offsets and line and column locations
/// for some source file
#[derive(Clone, Debug)]
pub struct Lines {
    starting_bytes: Vec<BytePos>,
    end: usize,
}

impl Lines {
    /// Creates a mapping for `src`
    pub fn new<I>(src: I) -> Lines
    where
        I: IntoIterator<Item = u8>,
    {
        use std::iter;

        let mut len = 0;
        let starting_bytes = {
            let input_indices = src.into_iter()
                .inspect(|_| len += 1)
                .enumerate()
                .filter(|&(_, b)| b == b'\n')
                .map(|(i, _)| BytePos::from(i + 1)); // index of first char in the line

            iter::once(BytePos::from(0)).chain(input_indices).collect()
        };
        Lines {
            starting_bytes,
            end: len,
        }
    }

    /// Returns the byte offset of the start of `line_number`
    pub fn line(&self, line_number: Line) -> Option<BytePos> {
        let line_number = line_number.to_usize();
        self.starting_bytes.get(line_number).cloned()
    }

    /// Returns the line and column location of `byte`
    pub fn location(&self, byte: BytePos) -> Option<Location> {
        if byte.to_usize() <= self.end {
            let line_index = self.line_number_at_byte(byte);

            self.line(line_index).map(|line_byte| {
                Location {
                    line: line_index,
                    column: Column::from((byte - line_byte).to_usize()),
                    absolute: byte,
                }
            })
        } else {
            None
        }
    }

    /// Returns which line `byte` points to
    pub fn line_number_at_byte(&self, byte: BytePos) -> Line {
        let num_lines = self.starting_bytes.len();

        Line::from(
            (0..num_lines)
                .filter(|&i| self.starting_bytes[i] > byte)
                .map(|i| i - 1)
                .next()
                .unwrap_or(num_lines - 1),
        )
    }
}

/// Type which provides a bidirectional mapping between byte offsets and line and column locations
#[derive(Clone, Debug)]
pub struct Source<'a> {
    src: &'a str,
    /// The starting byte position of each line in `src`
    lines: Lines,
}

impl<'a> Source<'a> {
    pub fn new(src: &str) -> Source {
        Source {
            src: src,
            lines: Lines::new(src.as_bytes().iter().cloned()),
        }
    }

    /// Returns the string which defines the source
    pub fn src(&self) -> &'a str {
        self.src
    }

    /// Returns the byte offset and source of `line_number`
    pub fn line(&self, line_number: Line) -> Option<(BytePos, &str)> {
        self.lines.line(line_number).map(|start| {
            let line = match self.lines.starting_bytes.get(line_number.to_usize() + 1) {
                Some(end) => &self.src[start.to_usize()..end.to_usize() - 1], // Skip '\n'
                None => &self.src[start.to_usize()..],
            };

            (start, line)
        })
    }

    /// Returns the line number and the source at `byte`
    pub fn line_at_byte(&self, byte: BytePos) -> Option<(BytePos, &str)> {
        let line_number = self.line_number_at_byte(byte);
        self.line(line_number)
    }

    /// Returns which line `byte` points to
    pub fn line_number_at_byte(&self, byte: BytePos) -> Line {
        self.lines.line_number_at_byte(byte)
    }

    /// Returns the line and column location of `byte`
    pub fn location(&self, byte: BytePos) -> Option<Location> {
        self.lines.location(byte)
    }

    /// Returns the starting position of any comments and whitespace before `end`
    pub fn comment_start_before(&self, end: BytePos) -> BytePos {
        let mut iter = self.comments_between(Span::new(BytePos::from(0), end));
        // Scan from `end` until a non comment token is found
        for _ in iter.by_ref().rev() {}
        BytePos::from(iter.src.len())
    }

    pub fn comments_between(&self, span: Span<BytePos>) -> CommentIter<'a> {
        CommentIter {
            src: &self.src[span.start.to_usize()..span.end.to_usize()],
        }
    }
}

pub struct CommentIter<'a> {
    src: &'a str,
}

impl<'a> Iterator for CommentIter<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        if self.src.is_empty() {
            None
        } else {
            self.src = self.src
                .trim_matches(|c: char| c.is_whitespace() && c != '\n');
            if self.src.starts_with("//") && !self.src.starts_with("///") {
                let comment_line = self.src.lines().next().unwrap();
                self.src = &self.src[comment_line.len()..];
                self.src = if self.src.starts_with("\r\n") {
                    &self.src[2..]
                } else {
                    // \n
                    &self.src[1..]
                };
                Some(comment_line)
            } else if self.src.starts_with("/*") {
                self.src.find("*/").map(|i| {
                    let (comment, rest) = self.src.split_at(i + 2);
                    self.src = rest;
                    comment
                })
            } else if self.src.starts_with("\n") {
                self.src = &self.src[1..];
                Some("")
            } else {
                None
            }
        }
    }
}

impl<'a> DoubleEndedIterator for CommentIter<'a> {
    fn next_back(&mut self) -> Option<&'a str> {
        if self.src.is_empty() {
            None
        } else {
            self.src = self.src
                .trim_right_matches(|c: char| c.is_whitespace() && c != '\n');
            if self.src.ends_with("\n") {
                let comment_line = self.src[..self.src.len() - 1].lines().next_back().unwrap();
                let trimmed = comment_line.trim_left();

                let newline_len = if self.src.ends_with("\r\n") { 2 } else { 1 };
                self.src = &self.src[..(self.src.len() - newline_len)];

                if trimmed.starts_with("//") && !trimmed.starts_with("///") {
                    self.src = &self.src[..(self.src.len() - 2 - trimmed.len() - 1)];
                    Some(trimmed)
                } else {
                    Some("")
                }
            } else if self.src.ends_with("*/") {
                self.src.rfind("/*").map(|i| {
                    let (rest, comment) = self.src.split_at(i);
                    self.src = rest;
                    comment
                })
            } else {
                None
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use pos::{BytePos, Column, Line, Location};

    use super::Source;

    fn test_source() -> Source<'static> {
        Source::new("hello!\nhowdy\n\nhi萤\nbloop\n")
    }

    #[test]
    fn source_line() {
        let source = test_source();

        assert_eq!(
            source.line(Line::from(0)),
            Some((BytePos::from(0), "hello!"))
        );
        assert_eq!(
            source.line(Line::from(1)),
            Some((BytePos::from(7), "howdy"))
        );
        assert_eq!(source.line(Line::from(2)), Some((BytePos::from(13), "")));
        assert_eq!(
            source.line(Line::from(3)),
            Some((BytePos::from(14), "hi萤"))
        );
        assert_eq!(
            source.line(Line::from(4)),
            Some((BytePos::from(20), "bloop"))
        );
        assert_eq!(source.line(Line::from(5)), Some((BytePos::from(26), "")));
        assert_eq!(source.line(Line::from(6)), None);
    }

    #[test]
    fn source_line_number_at_byte() {
        let source = test_source();

        assert_eq!(source.line_number_at_byte(BytePos::from(0)), Line::from(0));
        assert_eq!(source.line_number_at_byte(BytePos::from(6)), Line::from(0));
        assert_eq!(source.line_number_at_byte(BytePos::from(7)), Line::from(1));
        assert_eq!(source.line_number_at_byte(BytePos::from(8)), Line::from(1));

        assert_eq!(source.line_number_at_byte(BytePos::from(12)), Line::from(1));
        assert_eq!(source.line_number_at_byte(BytePos::from(13)), Line::from(2));
        assert_eq!(source.line_number_at_byte(BytePos::from(14)), Line::from(3));
        assert_eq!(source.line_number_at_byte(BytePos::from(15)), Line::from(3));

        assert_eq!(source.line_number_at_byte(BytePos::from(18)), Line::from(3));
        assert_eq!(source.line_number_at_byte(BytePos::from(19)), Line::from(3));
        assert_eq!(source.line_number_at_byte(BytePos::from(20)), Line::from(4));

        assert_eq!(
            source.line_number_at_byte(BytePos::from(400)),
            Line::from(5)
        );
    }

    #[test]
    fn source_location() {
        let source = test_source();

        assert_eq!(
            source.location(BytePos::from(0)),
            Some(Location {
                line: Line::from(0),
                column: Column::from(0),
                absolute: BytePos::from(0),
            })
        );

        assert_eq!(
            source.location(BytePos::from(3)),
            Some(Location {
                line: Line::from(0),
                column: Column::from(3),
                absolute: BytePos::from(3),
            })
        );

        assert_eq!(
            source.location(BytePos::from(16)),
            Some(Location {
                line: Line::from(3),
                column: Column::from(2),
                absolute: BytePos::from(16),
            })
        );

        assert_eq!(source.location(BytePos::from(400)), None);
    }

    #[test]
    fn source_location_end_of_source() {
        let source = test_source();
        assert_eq!(
            source.location(BytePos::from(source.src.len())),
            Some(Location {
                line: Line::from(5),
                column: Column::from(0),
                absolute: BytePos::from(source.src.len()),
            })
        );
    }
}
<|endoftext|>