<commit_before>#![feature(libc,question_mark)]
extern crate libc;

use std::any::Any;
use std::fs;
use std::io;
use std::io::Read;
use std::path::Path;
use std::process::{Command, Stdio};
use std::str::from_utf8_unchecked;

/// Shortcut to path->filename conversion.
///
/// Returns the unchanged `path` if there is a character encoding error or something.
pub fn filename<'a> (path: &'a str) -> &'a str {
  match Path::new (path) .file_name() {
    Some (filename) => match filename.to_str() {
      Some (fstr) => if fstr.ends_with (".rs") {&fstr[0 .. fstr.len() - 3]} else {fstr},
      None => path},
    None => path}}

mod gstuff {pub fn filename<'a> (path: &'a str) -> &'a str {super::filename (path)}}

// A trick to use the `try_s` macro from both the outside and inside of the crate.
//mod gstuff {pub fn filename<'a> (path: &'a str) -> &'a str {::filename (path)}}

/// Returns on error, converting the `Err` value to `String` and prepending the current location.
///
/// cf. http://www.reddit.com/r/rust/comments/29wwzw/error_handling_and_result_types/cipcm9a
#[macro_export] macro_rules! try_s {
  ($e: expr) => {match $e {Ok (ok) => ok, Err (err) => {return Err (format! ("{}:{}] {}", ::gstuff::filename (file!()), line!(), err));}}}}

// Like `try_s`, but takes a reference.
#[macro_export] macro_rules! try_sp {
  ($e: expr) => {match $e {&Ok (ref ok) => ok,
    &Err (ref err) => {return Err (format! ("{}:{}] {:?}", ::gstuff::filename (file!()), line!(), err));}}}}

/// Returns a `Err(String)`, prepending the current location (file name and line number) to the string.
///
/// Examples: `ERR! ("too bad")`; `ERR! ("{}", foo)`;
#[macro_export] macro_rules! ERR {
  ($format: expr, $($args: tt)+) => {Err (format! (concat! ("{}:{}] ", $format), ::gstuff::filename (file!()), line!(), $($args)+))};
  ($format: expr) => {Err (format! (concat! ("{}:{}] ", $format), ::gstuff::filename (file!()), line!()))}}

/// A helper to build a string on the stack.
///
/// Given an array it makes a writeable cursor available to the passed code block.
///
/// Returns a &str slice pointing at memory between the array start and the cursor.
///
/// Example:
///
///     use std::io::Write;
///     let mut foobar: [u8; 128] = unsafe {std::mem::uninitialized()};
///     let foobar = gstring! (foobar, {
///         write! (foobar, "foo") .expect ("!write");
///         write! (foobar, "bar") .expect ("!write");
///     });
///
/// Alternatives: https://crates.io/crates/stack.
#[macro_export] macro_rules! gstring {($array: ident, $code: block) => {{
  let end = {
    let mut $array = ::std::io::Cursor::new (&mut $array[..]);
    let $array = &mut $array;
    $code;
    $array.position() as usize};
  unsafe {::std::str::from_utf8_unchecked (&$array[0..end])}}}}

/// Takes a netstring from the front of the slice.
///
/// Returns the unpacked netstring and the remainder of the slice.
pub fn netstring (at: &[u8]) -> Result<(&[u8], &[u8]), String> {
  let length_end = match at.iter().position (|&ch| ch < b'0' || ch > b'9') {Some (l) if l > 0 => l, _ => return ERR! ("No len.")};
  match at.get (length_end) {Some (&ch) if ch == b':' => (), _ => return ERR! ("No colon.")};
  let length = unsafe {from_utf8_unchecked (&at[0 .. length_end])};
  let length: usize = try_s! (length.parse());
  let bulk_pos = 0 + length_end + 1;
  let bulk_end = bulk_pos + length;
  match at.get (bulk_end) {Some (&ch) if ch == b',' => (), _ => return ERR! ("No comma.")}
  Ok ((&at[bulk_pos .. bulk_end], &at[bulk_end + 1 ..]))}

/// Wraps `gethostname` to fetch the current hostname into a temporary buffer.
#[cfg(unix)]
pub fn with_hostname (visitor: &mut FnMut (&[u8])) -> Result<(), std::io::Error> {
  use libc::{size_t, gethostname};  // http://man7.org/linux/man-pages/man2/gethostname.2.html
  use std::ffi::CStr;
  use std::io;

  let mut buf = [0; 128];
  let rc = unsafe {gethostname (buf.as_mut_ptr(), (buf.len() - 1) as size_t)};
  if rc == 0 {
    let cs = unsafe {CStr::from_ptr (buf.as_ptr())};
    Ok (visitor (cs.to_bytes()))
  } else {
    Err (io::Error::last_os_error())}}

#[cfg(unix)] #[test] fn test_hostname() {
  let mut hostname = String::new();
  with_hostname (&mut |bytes| hostname = String::from_utf8_lossy (bytes) .into_owned()) .unwrap();}

/// Read contents of the file into a String.
///
/// Returns an empty string if the file is not present under the given path.
pub fn slurp (path: &AsRef<Path>) -> String {
  let mut file = match fs::File::open (path) {
    Ok (f) => f,
    Err (ref err) if err.kind() == io::ErrorKind::NotFound => return String::new(),
    Err (err) => panic! ("Can't open {:?}: {}", path.as_ref(), err)};
  let mut buf = String::new();
  file.read_to_string (&mut buf) .expect ("!read");
  buf}

/// Runs a command in a shell, returning stderr+stdout on success.
///
/// Sometimes we need something simpler than constructing a Command.
///
/// If the command failed then returns it's stderr
pub fn slurp_prog (command: &str) -> Result<String, String> {
  let output = match Command::new ("bash") .arg ("-c") .arg (command) .output() {
    Ok (output) => output,
    Err (ref err) if err.kind() == io::ErrorKind::NotFound => {  // "sh" was not found, try a different name.
      try_s! (Command::new ("sh") .arg ("-c") .arg (command) .output())},
    Err (err) => return ERR! ("{}", err)};

  let combined_output: String = if output.stderr.is_empty() {
    try_s! (String::from_utf8 (output.stdout))
  } else if output.stdout.is_empty() {
    try_s! (String::from_utf8 (output.stderr))
  } else {
    let mut buf = String::with_capacity (output.stderr.len() + output.stdout.len());
    buf.push_str (try_s! (std::str::from_utf8 (&output.stderr[..])));
    buf.push_str (try_s! (std::str::from_utf8 (&output.stdout[..])));
    buf};

  if output.status.success() {Ok (combined_output)} else {Err (combined_output)}}

#[test] fn test_slurp_prog() {
  let foo = match slurp_prog ("echo foo") {Ok (foo) => foo, Err (err) => panic! ("{}", err)};
  assert_eq! (foo.trim(), "foo");}

/// Run a command, printing it first. Stdout and stderr are forwarded through (`inherit`).
pub fn cmd (cmd: &str) -> Result<(), String> {
  println! ("$ {}", cmd);
  let status = try_s! (Command::new ("bash") .arg ("-c") .arg (cmd) .stdout (Stdio::inherit()) .stderr (Stdio::inherit()) .status());
  if !status.success() {Err (format! ("Command returned an error status: {}", status))} else {Ok(())}}

/// Useful with panic handlers.
pub fn any_to_str<'a> (message: &'a Box<Any + Send + 'static>) -> Option<&'a str> {
  if let Some (message) = message.downcast_ref::<&str>() {return Some (message)}
  if let Some (message) = message.downcast_ref::<String>() {return Some (&message[..])}
  return None}

// --- nom extensions ---

/// Implements the /(?x) (.*?) (remainder)/ pattern:
/// looks for remainder first, then returns a tuple with the prefix and the remainder.
/// Discussion: https://www.reddit.com/r/rust/comments/4yokxd/crash_course_into_nom_kind_of_question/
#[macro_export]
macro_rules! take_until_parse_s (
  ($i: expr, $submac: ident! ($($args:tt)*)) => ({
    let input = $i as &str;
    let mut ret = IResult::Error (nom::Err::Position (nom::ErrorKind::Custom (0), input));
    for (pos, _) in $i.char_indices() {
      match $submac! (&input[pos..], $($args)*) {
        IResult::Done (i,o)    => {ret = IResult::Done (i, (&input[0..pos], o)); break},  // Found the remainder!
        IResult::Error(_)      => continue,  // Keep looking.
        IResult::Incomplete(_) => continue}}  // Keep looking.

    if !ret.is_done() {
      // Last chance. See if subparser accepts an empty string.
      if let IResult::Done (i,o) = $submac! ("", $($args)*) {
        ret = IResult::Done (i, (input, o))}}  // Empty remainder was accepted.

    ret});

  ($i: expr, $f: expr) => (take_until_parse_s! ($i, call! ($f));););

/// `$starts` is an optional `Pattern` used to optimize the `$submac` search.
/// For example, with jetscii: `take_until_find_parse_s! ("foo bar", ascii_chars! ('b'), tag_s! ("bar"))`.
#[macro_export]
macro_rules! take_until_find_parse_s (
  ($i: expr, $starts: expr, $submac: ident! ($($args:tt)*)) => ({
    let input = $i as &str;
    let mut ret = IResult::Error (nom::Err::Position (nom::ErrorKind::Custom (0), input));
    for (pos, _) in $i.match_indices ($starts) {
      match $submac! (&input[pos..], $($args)*) {
        IResult::Done (i,o)    => {ret = IResult::Done (i, (&input[0..pos], o)); break},  // Found the remainder!
        IResult::Error(_)      => continue,  // Keep looking.
        IResult::Incomplete(_) => continue}}  // Keep looking.

    if !ret.is_done() {
      // Last chance. See if subparser accepts an empty string.
      if let IResult::Done (i,o) = $submac! ("", $($args)*) {
        ret = IResult::Done (i, (input, o))}}  // Empty remainder was accepted.

    ret});

  ($i: expr, $starts: expr, $f: expr) => (take_until_find_parse_s! ($i, $starts, call! ($f));););
<commit_msg>Empty remainder doesn't make much sense around non-empty `$starts`.<commit_after>#![feature(libc,question_mark)]
extern crate libc;

use std::any::Any;
use std::fs;
use std::io;
use std::io::Read;
use std::path::Path;
use std::process::{Command, Stdio};
use std::str::from_utf8_unchecked;

/// Shortcut to path->filename conversion.
///
/// Returns the unchanged `path` if there is a character encoding error or something.
pub fn filename<'a> (path: &'a str) -> &'a str {
  match Path::new (path) .file_name() {
    Some (filename) => match filename.to_str() {
      Some (fstr) => if fstr.ends_with (".rs") {&fstr[0 .. fstr.len() - 3]} else {fstr},
      None => path},
    None => path}}

mod gstuff {pub fn filename<'a> (path: &'a str) -> &'a str {super::filename (path)}}

// A trick to use the `try_s` macro from both the outside and inside of the crate.
//mod gstuff {pub fn filename<'a> (path: &'a str) -> &'a str {::filename (path)}}

/// Returns on error, converting the `Err` value to `String` and prepending the current location.
///
/// cf. http://www.reddit.com/r/rust/comments/29wwzw/error_handling_and_result_types/cipcm9a
#[macro_export] macro_rules! try_s {
  ($e: expr) => {match $e {Ok (ok) => ok, Err (err) => {return Err (format! ("{}:{}] {}", ::gstuff::filename (file!()), line!(), err));}}}}

// Like `try_s`, but takes a reference.
#[macro_export] macro_rules! try_sp {
  ($e: expr) => {match $e {&Ok (ref ok) => ok,
    &Err (ref err) => {return Err (format! ("{}:{}] {:?}", ::gstuff::filename (file!()), line!(), err));}}}}

/// Returns a `Err(String)`, prepending the current location (file name and line number) to the string.
///
/// Examples: `ERR! ("too bad")`; `ERR! ("{}", foo)`;
#[macro_export] macro_rules! ERR {
  ($format: expr, $($args: tt)+) => {Err (format! (concat! ("{}:{}] ", $format), ::gstuff::filename (file!()), line!(), $($args)+))};
  ($format: expr) => {Err (format! (concat! ("{}:{}] ", $format), ::gstuff::filename (file!()), line!()))}}

/// A helper to build a string on the stack.
///
/// Given an array it makes a writeable cursor available to the passed code block.
///
/// Returns a &str slice pointing at memory between the array start and the cursor.
///
/// Example:
///
///     use std::io::Write;
///     let mut foobar: [u8; 128] = unsafe {std::mem::uninitialized()};
///     let foobar = gstring! (foobar, {
///         write! (foobar, "foo") .expect ("!write");
///         write! (foobar, "bar") .expect ("!write");
///     });
///
/// Alternatives: https://crates.io/crates/stack.
#[macro_export] macro_rules! gstring {($array: ident, $code: block) => {{
  let end = {
    let mut $array = ::std::io::Cursor::new (&mut $array[..]);
    let $array = &mut $array;
    $code;
    $array.position() as usize};
  unsafe {::std::str::from_utf8_unchecked (&$array[0..end])}}}}

/// Takes a netstring from the front of the slice.
///
/// Returns the unpacked netstring and the remainder of the slice.
pub fn netstring (at: &[u8]) -> Result<(&[u8], &[u8]), String> {
  let length_end = match at.iter().position (|&ch| ch < b'0' || ch > b'9') {Some (l) if l > 0 => l, _ => return ERR! ("No len.")};
  match at.get (length_end) {Some (&ch) if ch == b':' => (), _ => return ERR! ("No colon.")};
  let length = unsafe {from_utf8_unchecked (&at[0 .. length_end])};
  let length: usize = try_s! (length.parse());
  let bulk_pos = 0 + length_end + 1;
  let bulk_end = bulk_pos + length;
  match at.get (bulk_end) {Some (&ch) if ch == b',' => (), _ => return ERR! ("No comma.")}
  Ok ((&at[bulk_pos .. bulk_end], &at[bulk_end + 1 ..]))}

/// Wraps `gethostname` to fetch the current hostname into a temporary buffer.
#[cfg(unix)]
pub fn with_hostname (visitor: &mut FnMut (&[u8])) -> Result<(), std::io::Error> {
  use libc::{size_t, gethostname};  // http://man7.org/linux/man-pages/man2/gethostname.2.html
  use std::ffi::CStr;
  use std::io;

  let mut buf = [0; 128];
  let rc = unsafe {gethostname (buf.as_mut_ptr(), (buf.len() - 1) as size_t)};
  if rc == 0 {
    let cs = unsafe {CStr::from_ptr (buf.as_ptr())};
    Ok (visitor (cs.to_bytes()))
  } else {
    Err (io::Error::last_os_error())}}

#[cfg(unix)] #[test] fn test_hostname() {
  let mut hostname = String::new();
  with_hostname (&mut |bytes| hostname = String::from_utf8_lossy (bytes) .into_owned()) .unwrap();}

/// Read contents of the file into a String.
///
/// Returns an empty string if the file is not present under the given path.
pub fn slurp (path: &AsRef<Path>) -> String {
  let mut file = match fs::File::open (path) {
    Ok (f) => f,
    Err (ref err) if err.kind() == io::ErrorKind::NotFound => return String::new(),
    Err (err) => panic! ("Can't open {:?}: {}", path.as_ref(), err)};
  let mut buf = String::new();
  file.read_to_string (&mut buf) .expect ("!read");
  buf}

/// Runs a command in a shell, returning stderr+stdout on success.
///
/// Sometimes we need something simpler than constructing a Command.
///
/// If the command failed then returns it's stderr
pub fn slurp_prog (command: &str) -> Result<String, String> {
  let output = match Command::new ("bash") .arg ("-c") .arg (command) .output() {
    Ok (output) => output,
    Err (ref err) if err.kind() == io::ErrorKind::NotFound => {  // "sh" was not found, try a different name.
      try_s! (Command::new ("sh") .arg ("-c") .arg (command) .output())},
    Err (err) => return ERR! ("{}", err)};

  let combined_output: String = if output.stderr.is_empty() {
    try_s! (String::from_utf8 (output.stdout))
  } else if output.stdout.is_empty() {
    try_s! (String::from_utf8 (output.stderr))
  } else {
    let mut buf = String::with_capacity (output.stderr.len() + output.stdout.len());
    buf.push_str (try_s! (std::str::from_utf8 (&output.stderr[..])));
    buf.push_str (try_s! (std::str::from_utf8 (&output.stdout[..])));
    buf};

  if output.status.success() {Ok (combined_output)} else {Err (combined_output)}}

#[test] fn test_slurp_prog() {
  let foo = match slurp_prog ("echo foo") {Ok (foo) => foo, Err (err) => panic! ("{}", err)};
  assert_eq! (foo.trim(), "foo");}

/// Run a command, printing it first. Stdout and stderr are forwarded through (`inherit`).
pub fn cmd (cmd: &str) -> Result<(), String> {
  println! ("$ {}", cmd);
  let status = try_s! (Command::new ("bash") .arg ("-c") .arg (cmd) .stdout (Stdio::inherit()) .stderr (Stdio::inherit()) .status());
  if !status.success() {Err (format! ("Command returned an error status: {}", status))} else {Ok(())}}

/// Useful with panic handlers.
pub fn any_to_str<'a> (message: &'a Box<Any + Send + 'static>) -> Option<&'a str> {
  if let Some (message) = message.downcast_ref::<&str>() {return Some (message)}
  if let Some (message) = message.downcast_ref::<String>() {return Some (&message[..])}
  return None}

// --- nom extensions ---

/// Implements the /(?x) (.*?) (remainder)/ pattern:
/// looks for remainder first, then returns a tuple with the prefix and the remainder.
/// Discussion: https://www.reddit.com/r/rust/comments/4yokxd/crash_course_into_nom_kind_of_question/
#[macro_export]
macro_rules! take_until_parse_s (
  ($i: expr, $submac: ident! ($($args:tt)*)) => ({
    let input = $i as &str;
    let mut ret = IResult::Error (nom::Err::Position (nom::ErrorKind::Custom (0), input));
    for (pos, _) in $i.char_indices() {
      match $submac! (&input[pos..], $($args)*) {
        IResult::Done (i,o)    => {ret = IResult::Done (i, (&input[0..pos], o)); break},  // Found the remainder!
        IResult::Error(_)      => continue,  // Keep looking.
        IResult::Incomplete(_) => continue}}  // Keep looking.

    if !ret.is_done() {
      // Last chance. See if subparser accepts an empty string.
      if let IResult::Done (i,o) = $submac! ("", $($args)*) {
        ret = IResult::Done (i, (input, o))}}  // Empty remainder was accepted.

    ret});

  ($i: expr, $f: expr) => (take_until_parse_s! ($i, call! ($f));););

/// `$starts` is an optional `Pattern` used to optimize the `$submac` search.
/// For example, with jetscii: `take_until_find_parse_s! ("foo bar", ascii_chars! ('b'), tag_s! ("bar"))`.
#[macro_export]
macro_rules! take_until_find_parse_s (
  ($i: expr, $starts: expr, $submac: ident! ($($args:tt)*)) => ({
    let input = $i as &str;
    let mut ret = IResult::Error (nom::Err::Position (nom::ErrorKind::Custom (0), input));
    for (pos, _) in $i.match_indices ($starts) {
      match $submac! (&input[pos..], $($args)*) {
        IResult::Done (i,o)    => {ret = IResult::Done (i, (&input[0..pos], o)); break},  // Found the remainder!
        IResult::Error(_)      => continue,  // Keep looking.
        IResult::Incomplete(_) => continue}}  // Keep looking.
    ret});

  ($i: expr, $starts: expr, $f: expr) => (take_until_find_parse_s! ($i, $starts, call! ($f));););
<|endoftext|>


<commit_before>use std::path::Path;

/// Shortcut to path->filename conversion.
///
/// Returns the unchanged `path` if there is a character encoding error or something.
pub fn filename<'a> (path: &'a str) -> &'a str {
  match Path::new (path) .file_name() {
    Some (filename) => match filename.to_str() {
      Some (fstr) => if fstr.ends_with (".rs") {&fstr[0 .. fstr.len() - 3]} else {fstr},
      None => path},
    None => path}}

// A trick to use the `try_s` macro from both the outside and inside of the crate.
//mod gstuff {pub fn filename<'a> (path: &'a str) -> &'a str {::filename (path)}}

/// Returns on error, converting the `Err` value to `String` and prepending the current location.
///
/// cf. http://www.reddit.com/r/rust/comments/29wwzw/error_handling_and_result_types/cipcm9a
#[macro_export] macro_rules! try_s {
  ($e: expr) => {match $e {Ok (ok) => ok, Err (err) => {return Err (format! ("{}:{}] {}", ::gstuff::filename (file!()), line!(), err));}}}}

// Like `try_s`, but takes a reference.
#[macro_export] macro_rules! try_sp {
  ($e: expr) => {match $e {&Ok (ref ok) => ok,
    &Err (ref err) => {return Err (format! ("{}:{}] {:?}", ::gstuff::filename (file!()), line!(), err));}}}}

/// Returns a `Err(String)`, prepending the current location (file name and line number) to the string.
///
/// Examples: `ERR! ("too bad")`; `ERR! ("{}", foo)`;
#[macro_export] macro_rules! ERR {
  ($format: expr, $($args: tt)+) => {Err (format! (concat! ("{}:{}] ", $format), ::gstuff::filename (file!()), line!(), $($args)+))};
  ($format: expr) => {Err (format! (concat! ("{}:{}] ", $format), ::gstuff::filename (file!()), line!()))}}

/// A helper to build a string on the stack.
///
/// Given an array it makes a writeable cursor available to the passed code block.
///
/// Returns a &str slice pointing at memory between the array start and the cursor.
///
/// Example:
///
///     use std::io::Write;
///     let mut foobar: [u8; 128] = unsafe {std::mem::uninitialized()};
///     let foobar = gstring! (foobar, {
///         write! (foobar, "foo") .expect ("!write");
///         write! (foobar, "bar") .expect ("!write");
///     });
///
/// Alternatives: https://crates.io/crates/stack.
#[macro_export] macro_rules! gstring {($array: ident, $code: block) => {{
  let end = {
    let mut $array = ::std::io::Cursor::new (&mut $array[..]);
    let $array = &mut $array;
    $code;
    $array.position() as usize};
  unsafe {::std::str::from_utf8_unchecked (&$array[0..end])}}}}
<commit_msg>Netstring decoding.<commit_after>use std::path::Path;

/// Shortcut to path->filename conversion.
///
/// Returns the unchanged `path` if there is a character encoding error or something.
pub fn filename<'a> (path: &'a str) -> &'a str {
  match Path::new (path) .file_name() {
    Some (filename) => match filename.to_str() {
      Some (fstr) => if fstr.ends_with (".rs") {&fstr[0 .. fstr.len() - 3]} else {fstr},
      None => path},
    None => path}}

// A trick to use the `try_s` macro from both the outside and inside of the crate.
//mod gstuff {pub fn filename<'a> (path: &'a str) -> &'a str {::filename (path)}}

/// Returns on error, converting the `Err` value to `String` and prepending the current location.
///
/// cf. http://www.reddit.com/r/rust/comments/29wwzw/error_handling_and_result_types/cipcm9a
#[macro_export] macro_rules! try_s {
  ($e: expr) => {match $e {Ok (ok) => ok, Err (err) => {return Err (format! ("{}:{}] {}", ::gstuff::filename (file!()), line!(), err));}}}}

// Like `try_s`, but takes a reference.
#[macro_export] macro_rules! try_sp {
  ($e: expr) => {match $e {&Ok (ref ok) => ok,
    &Err (ref err) => {return Err (format! ("{}:{}] {:?}", ::gstuff::filename (file!()), line!(), err));}}}}

/// Returns a `Err(String)`, prepending the current location (file name and line number) to the string.
///
/// Examples: `ERR! ("too bad")`; `ERR! ("{}", foo)`;
#[macro_export] macro_rules! ERR {
  ($format: expr, $($args: tt)+) => {Err (format! (concat! ("{}:{}] ", $format), ::gstuff::filename (file!()), line!(), $($args)+))};
  ($format: expr) => {Err (format! (concat! ("{}:{}] ", $format), ::gstuff::filename (file!()), line!()))}}

/// A helper to build a string on the stack.
///
/// Given an array it makes a writeable cursor available to the passed code block.
///
/// Returns a &str slice pointing at memory between the array start and the cursor.
///
/// Example:
///
///     use std::io::Write;
///     let mut foobar: [u8; 128] = unsafe {std::mem::uninitialized()};
///     let foobar = gstring! (foobar, {
///         write! (foobar, "foo") .expect ("!write");
///         write! (foobar, "bar") .expect ("!write");
///     });
///
/// Alternatives: https://crates.io/crates/stack.
#[macro_export] macro_rules! gstring {($array: ident, $code: block) => {{
  let end = {
    let mut $array = ::std::io::Cursor::new (&mut $array[..]);
    let $array = &mut $array;
    $code;
    $array.position() as usize};
  unsafe {::std::str::from_utf8_unchecked (&$array[0..end])}}}}

/// Takes a netstring from the front of the slice.
///
/// Returns the unpacked netstring and the remainder of the slice.
fn netstring (at: &[u8]) -> Result<(&[u8], &[u8]), String> {
  let length_end = match at.iter().position (|&ch| ch < b'0' || ch > b'9') {Some (l) if l > 0 => l, _ => return ERR! ("No len.")};
  match at.get (length_end) {Some (&ch) if ch == b':' => (), _ => return ERR! ("No colon.")};
  let length = unsafe {from_utf8_unchecked (&at[0 .. length_end])};
  let length: usize = try_s! (length.parse());
  let bulk_pos = 0 + length_end + 1;
  let bulk_end = bulk_pos + length;
  match at.get (bulk_end) {Some (&ch) if ch == b',' => (), _ => return ERR! ("No comma.")}
  Ok ((&at[bulk_pos .. bulk_end], &at[bulk_end + 1 ..]))}
<|endoftext|>


<commit_before>use std::thread;
use std::time::{Duration, Instant};

use sdl2;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;

use sdl2::pixels::Color;
use sdl2::rect::Rect; // TODO: abstract my own drawtypes?

use graphics::Display;
use input::Input;

pub static COLOR_BG: Color  = Color::RGB(0,0,0);
pub static COLOR_FPS: Color = Color::RGB(255,255,0);
pub static COLOR_PEN: Color = Color::RGB(125, 0, 175);

#[derive(Debug)]
enum BrushMode {
    Normal,
    Squareish,
    WowSoEdgy,
}

pub struct Engine {
	context:     sdl2::Sdl,
	controller:  Input,
	display:     Display,

    brush:  BrushMode,
    color:  (u8,u8,u8),
    cursor: (i32,i32),
}

impl Engine {
    pub fn new(context: sdl2::Sdl) -> Engine {
        let video_renderer = Display::new(&context);

        Engine {
            context:    context,
            controller: Input::new(),
            display:    video_renderer,

            brush:  BrushMode::Normal,
            color:  (125,0,175),
            cursor: (0,0),
        }
    }

    pub fn run(&mut self) {
        let target_fps_ms  = Duration::from_millis(1000 / 120); // TODO: const fn?

		let mut event_pump = self.context.event_pump().unwrap();
        let mut is_running = true;

        let mut frame_start_at;
        let mut elapsed_time = Duration::from_millis(0);

        // drawing state
        let mut bitmap = Some(self.display.get_texture(1280,720));
        let mut mouse_clicked = false;
        let mut last_point = None;

        // init bitmap to good state
        let mut _last = self.display.retarget().set(bitmap.take().unwrap());
        self.display.clear_buffer();
        bitmap = self.display.retarget().reset()
            .ok().expect("did not get target back");

        while is_running {
            frame_start_at  = Instant::now();

			// drain input event queue once per frame
			self.controller.begin_new_frame();
			for event in event_pump.poll_iter() {
				match event {
					Event::KeyDown { keycode, .. } => {
						self.controller.key_down_event(keycode.unwrap());
					},

					Event::KeyUp { keycode, .. } => {
						self.controller.key_up_event(keycode.unwrap());
					},

                    Event::MouseMotion { x, y, .. } => self.cursor = (x,y),

                    Event::MouseButtonDown { .. } => mouse_clicked = true,
                    Event::MouseButtonUp   { .. } => mouse_clicked = false,

					_ => {},
				}
			}

            // handle exit game
			if self.controller.was_key_released(Keycode::Escape) { is_running = false; }

            // erase canvas
            if self.controller.was_key_released(Keycode::E) {
                let mut _last = self.display.retarget().set(bitmap.take().unwrap());
                self.display.clear_buffer();
                bitmap = self.display.retarget().reset()
                    .ok().expect("did not get target back");
            }

            // switch brush
            if self.controller.was_key_released(Keycode::B) {
                self.brush = match self.brush { // TODO: better cycle?
                    BrushMode::Normal    => BrushMode::Squareish,
                    BrushMode::Squareish => BrushMode::WowSoEdgy,
                    BrushMode::WowSoEdgy => BrushMode::Squareish,
                }
            }

            if self.controller.is_key_held(Keycode::I) {
                self.color.0 = self.color.0.wrapping_add(0x01);
            } else if self.controller.is_key_held(Keycode::O) {
                self.color.1 = self.color.1.wrapping_add(0x01);
            } else if self.controller.is_key_held(Keycode::P) {
                self.color.2 = self.color.2.wrapping_add(0x01);
            }

            let brush_color = Color::RGB(self.color.0, self.color.1, self.color.2);
            if mouse_clicked {
                let (x2,y2) = self.cursor;

                if let Some((x1,y1)) = last_point {
                    let _last = self.display.retarget().set(bitmap.take().unwrap());

                    // let diffx = x2 - x1;
                    // let diffy = y2 - y1;
                    // println!("delta ({},{}), mag: {}", diffx, diffy, diffy-diffx);

                    match self.brush {
                        BrushMode::WowSoEdgy => for i in 0..10 {
                            self.display.draw_line(x1+i, y1, x2, y2+i, brush_color);
                        },

                        BrushMode::Squareish => for i in 0..5 {
                            self.display.draw_line(x1+i, y1, x2+i, y2, brush_color);
                        },

                        BrushMode::Normal => {},
                    }

                    bitmap = self.display.retarget().reset()
                        .ok().expect("did not get target back");
                } // NOTE: doesn't draw point if mouse held for single frame

                last_point = Some((x2,y2));
           } else { last_point = None; }

            // handle draw calls
			self.display.clear_buffer(); // clear back-buffer
            self.display.copy(bitmap.as_ref().unwrap());
            self.draw_cursor(brush_color);
            self.draw_debug(elapsed_time);
			self.display.switch_buffers();

            // sleep for <target> - <draw time> and floor to zero
            elapsed_time = frame_start_at.elapsed();
            let sleep_time = if elapsed_time > target_fps_ms {
                Duration::from_millis(0)
            } else { target_fps_ms - elapsed_time };

            thread::sleep(sleep_time);
        }
    }

    fn draw_cursor(&mut self, brush_color: Color) {
        self.display.fill_rect(Rect::new(self.cursor.0, self.cursor.1, 10, 10), brush_color);
    }

    fn draw_debug(&mut self, time: Duration) {
        let mut time_ms = time.as_secs() * 1000;        // -> millis
        time_ms += time.subsec_nanos() as u64 / (1000 * 1000); // /> micros /> millis

        let (hue_r, hue_g, hue_b) = self.color;

        let buf = format!("{}ms, e = erase all, b = brush ({:?}), hue(i,o,p) => ({:x},{:x},{:x})",
                          time_ms,
                          self.brush,
                          hue_r, hue_g, hue_b);
        self.display.blit_text(&buf[..], COLOR_FPS);
    }
}
<commit_msg>refactor display retargeting to texture<commit_after>use std::thread;
use std::time::{Duration, Instant};

use sdl2;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;

use sdl2::pixels::Color;
use sdl2::rect::Rect; // TODO: abstract my own drawtypes?
use sdl2::render::Texture;

use graphics::Display;
use input::Input;

pub static COLOR_BG: Color  = Color::RGB(0,0,0);
pub static COLOR_FPS: Color = Color::RGB(255,255,0);
pub static COLOR_PEN: Color = Color::RGB(125, 0, 175);

#[derive(Copy, Clone, Debug)]
enum BrushMode {
    Normal,
    Squareish,
    WowSoEdgy,
}

pub struct Engine {
	context:     sdl2::Sdl,
	controller:  Input,
	display:     Display,

    brush:  BrushMode,
    color:  (u8,u8,u8),
    cursor: (i32,i32),
}

impl Engine {
    pub fn new(context: sdl2::Sdl) -> Engine {
        let video_renderer = Display::new(&context);

        Engine {
            context:    context,
            controller: Input::new(),
            display:    video_renderer,

            brush:  BrushMode::Normal,
            color:  (125,0,175),
            cursor: (0,0),
        }
    }

    pub fn run(&mut self) {
        let target_fps_ms  = Duration::from_millis(1000 / 120); // TODO: const fn?

		let mut event_pump = self.context.event_pump().unwrap();
        let mut is_running = true;

        let mut frame_start_at;
        let mut elapsed_time = Duration::from_millis(0);

        // drawing state
        let mut regions = vec![];
        for i in 0..9 {
            regions.push(Some(self.display.get_texture(1280,720)));
        }

        let mut mouse_clicked = false;
        let mut last_point = None;

        // init bitmap to good state
        Engine::with_texture(&mut self.display, &mut regions[0], |io| { io.clear_buffer() });

        while is_running {
            frame_start_at  = Instant::now();

			// drain input event queue once per frame
			self.controller.begin_new_frame();
			for event in event_pump.poll_iter() {
				match event {
					Event::KeyDown { keycode, .. } => {
						self.controller.key_down_event(keycode.unwrap());
					},

					Event::KeyUp { keycode, .. } => {
						self.controller.key_up_event(keycode.unwrap());
					},

                    Event::MouseMotion { x, y, .. } => self.cursor = (x,y),

                    Event::MouseButtonDown { .. } => mouse_clicked = true,
                    Event::MouseButtonUp   { .. } => mouse_clicked = false,

					_ => {},
				}
			}

            // handle exit game
			if self.controller.was_key_released(Keycode::Escape) { is_running = false; }

            // erase canvas
            if self.controller.was_key_released(Keycode::E) {
                Engine::with_texture(&mut self.display, &mut regions[0], |io| { io.clear_buffer() });
            }

            // switch brush
            if self.controller.was_key_released(Keycode::B) {
                self.brush = match self.brush { // TODO: better cycle?
                    BrushMode::Normal    => BrushMode::Squareish,
                    BrushMode::Squareish => BrushMode::WowSoEdgy,
                    BrushMode::WowSoEdgy => BrushMode::Squareish,
                }
            }

            if self.controller.is_key_held(Keycode::I) {
                self.color.0 = self.color.0.wrapping_add(0x01);
            } else if self.controller.is_key_held(Keycode::O) {
                self.color.1 = self.color.1.wrapping_add(0x01);
            } else if self.controller.is_key_held(Keycode::P) {
                self.color.2 = self.color.2.wrapping_add(0x01);
            }

            let brush_color = Color::RGB(self.color.0, self.color.1, self.color.2);
            if mouse_clicked {
                let (x2,y2) = self.cursor;

                if let Some((x1,y1)) = last_point {

                    let brush = self.brush;
                    Engine::with_texture(&mut self.display, &mut regions[0], |display| {
                        match brush {
                            BrushMode::WowSoEdgy => for i in 0..10 {
                                display.draw_line(x1+i, y1, x2, y2+i, brush_color);
                            },

                            BrushMode::Squareish => for i in 0..5 {
                                display.draw_line(x1+i, y1, x2+i, y2, brush_color);
                            },

                            BrushMode::Normal => {},
                        }
                    });

                    // let diffx = x2 - x1;
                    // let diffy = y2 - y1;
                    // println!("delta ({},{}), mag: {}", diffx, diffy, diffy-diffx);
                } // NOTE: doesn't draw point if mouse held for single frame

                last_point = Some((x2,y2));
           } else { last_point = None; }

            // handle draw calls
			self.display.clear_buffer(); // clear back-buffer
            self.display.copy(regions[0].as_ref().unwrap());
            self.draw_cursor(brush_color);
            self.draw_debug(elapsed_time);
			self.display.switch_buffers();

            // sleep for <target> - <draw time> and floor to zero
            elapsed_time = frame_start_at.elapsed();
            let sleep_time = if elapsed_time > target_fps_ms {
                Duration::from_millis(0)
            } else { target_fps_ms - elapsed_time };

            thread::sleep(sleep_time);
        }
    }

    fn with_texture<F>(io: &mut Display, target: &mut Option<Texture>, mut mutator: F)
        where F: FnMut(&mut Display) -> () {

        let _last = io.retarget().set(target.take().unwrap());
        mutator(io);
        *target = io.retarget().reset()
                        .ok().expect("did not get target back");
    }

    fn draw_cursor(&mut self, brush_color: Color) {
        self.display.fill_rect(Rect::new(self.cursor.0, self.cursor.1, 10, 10), brush_color);
    }

    fn draw_debug(&mut self, time: Duration) {
        let mut time_ms = time.as_secs() * 1000;        // -> millis
        time_ms += time.subsec_nanos() as u64 / (1000 * 1000); // /> micros /> millis

        let (hue_r, hue_g, hue_b) = self.color;
        let buf = format!("{}ms, e = erase all, b = brush ({:?}), hue(i,o,p) => ({:x},{:x},{:x})",
                          time_ms,
                          self.brush,
                          hue_r, hue_g, hue_b);
        self.display.blit_text(&buf[..], COLOR_FPS);
    }
}
<|endoftext|>


<commit_before>//! Thread-safe connections on IrcStreams.
#[cfg(feature = "ssl")] use std::error::Error as StdError;
use std::io::prelude::*;
use std::io::{BufReader, BufWriter, Result};
use std::io::Error;
use std::io::ErrorKind;
use std::net::TcpStream;
#[cfg(feature = "ssl")] use std::result::Result as StdResult;
use std::sync::{Mutex, MutexGuard};
#[cfg(feature = "encode")] use encoding::{DecoderTrap, EncoderTrap, Encoding};
#[cfg(feature = "encode")] use encoding::label::encoding_from_whatwg_label;
use client::data::Message;
use client::data::kinds::{IrcRead, IrcWrite};
#[cfg(feature = "ssl")] use openssl::ssl::{SslContext, SslMethod, SslStream};
#[cfg(feature = "ssl")] use openssl::ssl::error::SslError;

/// A thread-safe connection.
pub struct Connection<T: IrcRead, U: IrcWrite> {
    reader: Mutex<T>,
    writer: Mutex<U>,
}

/// A Connection over a buffered NetStream.
pub type NetConnection = Connection<BufReader<NetStream>, BufWriter<NetStream>>;
/// An internal type
type NetReadWritePair = (BufReader<NetStream>, BufWriter<NetStream>);

impl Connection<BufReader<NetStream>, BufWriter<NetStream>> {
    /// Creates a thread-safe TCP connection to the specified server.
    pub fn connect(host: &str, port: u16) -> Result<NetConnection> {
        let (reader, writer) = try!(Connection::connect_internal(host, port));
        Ok(Connection::new(reader, writer))
    }

    /// connects to the specified server and returns a reader-writer pair.
    fn connect_internal(host: &str, port: u16) -> Result<NetReadWritePair> {
        let socket = try!(TcpStream::connect(&format!("{}:{}", host, port)[..]));
        Ok((BufReader::new(NetStream::UnsecuredTcpStream(try!(socket.try_clone()))),
            BufWriter::new(NetStream::UnsecuredTcpStream(socket))))
    }

    /// Creates a thread-safe TCP connection to the specified server over SSL.
    /// If the library is compiled without SSL support, this method panics.
    pub fn connect_ssl(host: &str, port: u16) -> Result<NetConnection> {
        let (reader, writer) = try!(Connection::connect_ssl_internal(host, port));
        Ok(Connection::new(reader, writer))
    }

    /// Connects over SSL to the specified server and returns a reader-writer pair.
    #[cfg(feature = "ssl")]
    fn connect_ssl_internal(host: &str, port: u16) -> Result<NetReadWritePair> {
        let socket = try!(TcpStream::connect(&format!("{}:{}", host, port)[..]));
        let ssl = try!(ssl_to_io(SslContext::new(SslMethod::Tlsv1)));
        let ssl_socket = try!(ssl_to_io(SslStream::new(&ssl, socket)));
        Ok((BufReader::new(NetStream::SslTcpStream(try!(ssl_socket.try_clone()))),
            BufWriter::new(NetStream::SslTcpStream(ssl_socket))))
    }

    /// Panics because SSL support is not compiled in.
    #[cfg(not(feature = "ssl"))]
    fn connect_ssl_internal(host: &str, port: u16) -> Result<NetReadWritePair> {
        panic!("Cannot connect to {}:{} over SSL without compiling with SSL support.", host, port)
    }

    /// Reconnects to the specified server, dropping the current connection.
    pub fn reconnect(&self, host: &str, port: u16) -> Result<()> {
        let use_ssl = match self.reader.lock().unwrap().get_ref() {
            &NetStream::UnsecuredTcpStream(_) =>  false,
            #[cfg(feature = "ssl")]
            &NetStream::SslTcpStream(_) => true,
        };
        let (reader, writer) = if use_ssl {
            try!(Connection::connect_ssl_internal(host, port))
        } else {
            try!(Connection::connect_internal(host, port))
        };
        *self.reader.lock().unwrap() = reader;
        *self.writer.lock().unwrap() = writer;
        Ok(())
    }

    /*
    FIXME: removed until set_keepalive is stabilized.
    /// Sets the keepalive for the network stream.
    #[unstable = "Rust IO has not stabilized."]
    pub fn set_keepalive(&self, delay_in_seconds: Option<u32>) -> Result<()> {
        self.mod_stream(|tcp| tcp.set_keepalive(delay_in_seconds))
    }

    /// Modifies the internal TcpStream using a function.
    fn mod_stream<F>(&self, f: F) -> Result<()> where F: FnOnce(&mut TcpStream) -> Result<()> {
        match self.reader.lock().unwrap().get_mut() {
            &mut NetStream::UnsecuredTcpStream(ref mut tcp) => f(tcp),
            #[cfg(feature = "ssl")]
            &mut NetStream::SslTcpStream(ref mut ssl) => f(ssl.get_mut()),
        }
    }
    */
}

impl<T: IrcRead, U: IrcWrite> Connection<T, U> {
    /// Creates a new connection from an IrcReader and an IrcWriter.
    pub fn new(reader: T, writer: U) -> Connection<T, U> {
        Connection {
            reader: Mutex::new(reader),
            writer: Mutex::new(writer),
        }
    }

    /// Sends a Message over this connection.
    #[cfg(feature = "encode")]
    pub fn send<M: Into<Message>>(&self, to_msg: M, encoding: &str) -> Result<()> {
        let encoding = match encoding_from_whatwg_label(encoding) {
            Some(enc) => enc,
            None => return Err(Error::new(
                ErrorKind::InvalidInput, &format!("Failed to find encoder. ({})", encoding)[..]
            ))
        };
        let msg: Message = to_msg.into();
        let data = match encoding.encode(&msg.into_string(), EncoderTrap::Replace) {
            Ok(data) => data,
            Err(data) => return Err(Error::new(ErrorKind::InvalidInput,
                &format!("Failed to encode {} as {}.", data, encoding.name())[..]
            ))
        };
        let mut writer = self.writer.lock().unwrap();
        try!(writer.write_all(&data));
        writer.flush()
    }

    /// Sends a message over this connection.
    #[cfg(not(feature = "encode"))]
    pub fn send<M: Into<Message>>(&self, to_msg: M) -> Result<()> {
        let mut writer = self.writer.lock().unwrap();
        let msg: Message = to_msg.into();
        try!(writer.write_all(&msg.into_string().as_bytes()));
        writer.flush()
    }

    /// Receives a single line from this connection.
    #[cfg(feature = "encoding")]
    pub fn recv(&self, encoding: &str) -> Result<String> {
        let encoding = match encoding_from_whatwg_label(encoding) {
            Some(enc) => enc,
            None => return Err(Error::new(
                ErrorKind::InvalidInput, &format!("Failed to find decoder. ({})", encoding)[..]
            ))
        };
        let mut buf = Vec::new();
        self.reader.lock().unwrap().read_until(b'\n', &mut buf).and_then(|_|
            match encoding.decode(&buf, DecoderTrap::Replace) {
                _ if buf.is_empty() => Err(Error::new(ErrorKind::Other, "EOF")),
                Ok(data) => Ok(data),
                Err(data) => return Err(Error::new(ErrorKind::InvalidInput,
                    &format!("Failed to decode {} as {}.", data, encoding.name())[..]
                ))
            }
        )
    }

    /// Receives a single line from this connection.
    #[cfg(not(feature = "encoding"))]
    pub fn recv(&self) -> Result<String> {
        let mut ret = String::new();
        try!(self.reader.lock().unwrap().read_line(&mut ret));
        if ret.is_empty() {
            Err(Error::new(ErrorKind::Other, "EOF"))
        } else {
            Ok(ret)
        }
    }

    /// Acquires the Reader lock.
    pub fn reader<'a>(&'a self) -> MutexGuard<'a, T> {
        self.reader.lock().unwrap()
    }

    /// Acquires the Writer lock.
    pub fn writer<'a>(&'a self) -> MutexGuard<'a, U> {
        self.writer.lock().unwrap()
    }
}

/// Converts a Result<T, SslError> into an Result<T>.
#[cfg(feature = "ssl")]
fn ssl_to_io<T>(res: StdResult<T, SslError>) -> Result<T> {
    match res {
        Ok(x) => Ok(x),
        Err(e) => Err(Error::new(ErrorKind::Other,
            &format!("An SSL error occurred. ({})", e.description())[..]
        )),
    }
}

/// An abstraction over different networked streams.
pub enum NetStream {
    /// An unsecured TcpStream.
    UnsecuredTcpStream(TcpStream),
    /// An SSL-secured TcpStream.
    /// This is only available when compiled with SSL support.
    #[cfg(feature = "ssl")]
    SslTcpStream(SslStream<TcpStream>),
}

impl Read for NetStream {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        match self {
            &mut NetStream::UnsecuredTcpStream(ref mut stream) => stream.read(buf),
            #[cfg(feature = "ssl")]
            &mut NetStream::SslTcpStream(ref mut stream) => stream.read(buf),
        }
    }
}

impl Write for NetStream {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        match self {
            &mut NetStream::UnsecuredTcpStream(ref mut stream) => stream.write(buf),
            #[cfg(feature = "ssl")]
            &mut NetStream::SslTcpStream(ref mut stream) => stream.write(buf),
        }
    }

    fn flush(&mut self) -> Result<()> {
        match self {
            &mut NetStream::UnsecuredTcpStream(ref mut stream) => stream.flush(),
            #[cfg(feature = "ssl")]
            &mut NetStream::SslTcpStream(ref mut stream) => stream.flush(),
        }
    }
}

#[cfg(test)]
mod test {
    use super::Connection;
    use std::io::{Cursor, sink};
    use client::data::message::Message;
    use client::test::buf_empty;
    #[cfg(feature = "encode")] use encoding::{DecoderTrap, Encoding};
    #[cfg(feature = "encode")] use encoding::all::{ISO_8859_15, UTF_8};

    #[test]
    #[cfg(not(feature = "encode"))]
    fn send() {
        let conn = Connection::new(buf_empty(), Vec::new());
        assert!(conn.send(
            Message::new(None, "PRIVMSG", Some(vec!["test"]), Some("Testing!"))
        ).is_ok());
        let data = String::from_utf8(conn.writer().to_vec()).unwrap();
        assert_eq!(&data[..], "PRIVMSG test :Testing!\r\n");
    }

    #[test]
    #[cfg(not(feature = "encode"))]
    fn send_str() {
        let exp = "PRIVMSG test :Testing!\r\n";
        let conn = Connection::new(buf_empty(), Vec::new());
        assert!(conn.send(exp).is_ok());
        let data = String::from_utf8(conn.writer().to_vec()).unwrap();
        assert_eq!(&data[..], exp);
    }

    #[test]
    #[cfg(feature = "encode")]
    fn send_utf8() {
        let conn = Connection::new(buf_empty(), Vec::new());
        assert!(conn.send(
            Message::new(None, "PRIVMSG", Some(vec!["test"]), Some("€ŠšŽžŒœŸ")), "UTF-8"
        ).is_ok());
        let data = UTF_8.decode(&conn.writer(), DecoderTrap::Strict).unwrap();
        assert_eq!(&data[..], "PRIVMSG test :€ŠšŽžŒœŸ\r\n");
    }

    #[test]
    #[cfg(feature = "encode")]
    fn send_utf8_str() {
        let exp = "PRIVMSG test :€ŠšŽžŒœŸ\r\n";
        let conn = Connection::new(buf_empty(), Vec::new());
        assert!(conn.send(exp, "UTF-8").is_ok());
        let data = UTF_8.decode(&conn.writer(), DecoderTrap::Strict).unwrap();
        assert_eq!(&data[..], exp);
    }

    #[test]
    #[cfg(feature = "encode")]
    fn send_iso885915() {
        let conn = Connection::new(buf_empty(), Vec::new());
        assert!(conn.send(
            Message::new(None, "PRIVMSG", Some(vec!["test"]), Some("€ŠšŽžŒœŸ")), "l9"
        ).is_ok());
        let data = ISO_8859_15.decode(&conn.writer(), DecoderTrap::Strict).unwrap();
        assert_eq!(&data[..], "PRIVMSG test :€ŠšŽžŒœŸ\r\n");
    }

    #[test]
    #[cfg(feature = "encode")]
    fn send_iso885915_str() {
        let exp = "PRIVMSG test :€ŠšŽžŒœŸ\r\n";
        let conn = Connection::new(buf_empty(), Vec::new());
        assert!(conn.send(exp, "l9").is_ok());
        let data = ISO_8859_15.decode(&conn.writer(), DecoderTrap::Strict).unwrap();
        assert_eq!(&data[..], exp);
    }

    #[test]
    #[cfg(not(feature = "encode"))]
    fn recv() {
        let conn = Connection::new(
            Cursor::new("PRIVMSG test :Testing!\r\n".as_bytes().to_vec()), sink()
        );
        assert_eq!(&conn.recv().unwrap()[..], "PRIVMSG test :Testing!\r\n");
    }

    #[test]
    #[cfg(feature = "encode")]
    fn recv_utf8() {
        let conn = Connection::new(
            Cursor::new(b"PRIVMSG test :Testing!\r\n".to_vec()), sink()
        );
        assert_eq!(&conn.recv("UTF-8").unwrap()[..], "PRIVMSG test :Testing!\r\n");
    }

    #[test]
    #[cfg(feature = "encode")]
    fn recv_iso885915() {
        let data = [0xA4, 0xA6, 0xA8, 0xB4, 0xB8, 0xBC, 0xBD, 0xBE];
        let conn = Connection::new(Cursor::new({
            let mut vec = Vec::new();
            vec.extend("PRIVMSG test :".as_bytes());
            vec.extend(data.iter());
            vec.extend("\r\n".as_bytes());
            vec.into_iter().map(|b| *b).collect::<Vec<_>>()
        }), sink());
        assert_eq!(&conn.recv("l9").unwrap()[..], "PRIVMSG test :€ŠšŽžŒœŸ\r\n");
    }
}
<commit_msg>Fixed test compilation.<commit_after>//! Thread-safe connections on IrcStreams.
#[cfg(feature = "ssl")] use std::error::Error as StdError;
use std::io::prelude::*;
use std::io::{BufReader, BufWriter, Result};
use std::io::Error;
use std::io::ErrorKind;
use std::net::TcpStream;
#[cfg(feature = "ssl")] use std::result::Result as StdResult;
use std::sync::{Mutex, MutexGuard};
#[cfg(feature = "encode")] use encoding::{DecoderTrap, EncoderTrap, Encoding};
#[cfg(feature = "encode")] use encoding::label::encoding_from_whatwg_label;
use client::data::Message;
use client::data::kinds::{IrcRead, IrcWrite};
#[cfg(feature = "ssl")] use openssl::ssl::{SslContext, SslMethod, SslStream};
#[cfg(feature = "ssl")] use openssl::ssl::error::SslError;

/// A thread-safe connection.
pub struct Connection<T: IrcRead, U: IrcWrite> {
    reader: Mutex<T>,
    writer: Mutex<U>,
}

/// A Connection over a buffered NetStream.
pub type NetConnection = Connection<BufReader<NetStream>, BufWriter<NetStream>>;
/// An internal type
type NetReadWritePair = (BufReader<NetStream>, BufWriter<NetStream>);

impl Connection<BufReader<NetStream>, BufWriter<NetStream>> {
    /// Creates a thread-safe TCP connection to the specified server.
    pub fn connect(host: &str, port: u16) -> Result<NetConnection> {
        let (reader, writer) = try!(Connection::connect_internal(host, port));
        Ok(Connection::new(reader, writer))
    }

    /// connects to the specified server and returns a reader-writer pair.
    fn connect_internal(host: &str, port: u16) -> Result<NetReadWritePair> {
        let socket = try!(TcpStream::connect(&format!("{}:{}", host, port)[..]));
        Ok((BufReader::new(NetStream::UnsecuredTcpStream(try!(socket.try_clone()))),
            BufWriter::new(NetStream::UnsecuredTcpStream(socket))))
    }

    /// Creates a thread-safe TCP connection to the specified server over SSL.
    /// If the library is compiled without SSL support, this method panics.
    pub fn connect_ssl(host: &str, port: u16) -> Result<NetConnection> {
        let (reader, writer) = try!(Connection::connect_ssl_internal(host, port));
        Ok(Connection::new(reader, writer))
    }

    /// Connects over SSL to the specified server and returns a reader-writer pair.
    #[cfg(feature = "ssl")]
    fn connect_ssl_internal(host: &str, port: u16) -> Result<NetReadWritePair> {
        let socket = try!(TcpStream::connect(&format!("{}:{}", host, port)[..]));
        let ssl = try!(ssl_to_io(SslContext::new(SslMethod::Tlsv1)));
        let ssl_socket = try!(ssl_to_io(SslStream::new(&ssl, socket)));
        Ok((BufReader::new(NetStream::SslTcpStream(try!(ssl_socket.try_clone()))),
            BufWriter::new(NetStream::SslTcpStream(ssl_socket))))
    }

    /// Panics because SSL support is not compiled in.
    #[cfg(not(feature = "ssl"))]
    fn connect_ssl_internal(host: &str, port: u16) -> Result<NetReadWritePair> {
        panic!("Cannot connect to {}:{} over SSL without compiling with SSL support.", host, port)
    }

    /// Reconnects to the specified server, dropping the current connection.
    pub fn reconnect(&self, host: &str, port: u16) -> Result<()> {
        let use_ssl = match self.reader.lock().unwrap().get_ref() {
            &NetStream::UnsecuredTcpStream(_) =>  false,
            #[cfg(feature = "ssl")]
            &NetStream::SslTcpStream(_) => true,
        };
        let (reader, writer) = if use_ssl {
            try!(Connection::connect_ssl_internal(host, port))
        } else {
            try!(Connection::connect_internal(host, port))
        };
        *self.reader.lock().unwrap() = reader;
        *self.writer.lock().unwrap() = writer;
        Ok(())
    }

    /*
    FIXME: removed until set_keepalive is stabilized.
    /// Sets the keepalive for the network stream.
    #[unstable = "Rust IO has not stabilized."]
    pub fn set_keepalive(&self, delay_in_seconds: Option<u32>) -> Result<()> {
        self.mod_stream(|tcp| tcp.set_keepalive(delay_in_seconds))
    }

    /// Modifies the internal TcpStream using a function.
    fn mod_stream<F>(&self, f: F) -> Result<()> where F: FnOnce(&mut TcpStream) -> Result<()> {
        match self.reader.lock().unwrap().get_mut() {
            &mut NetStream::UnsecuredTcpStream(ref mut tcp) => f(tcp),
            #[cfg(feature = "ssl")]
            &mut NetStream::SslTcpStream(ref mut ssl) => f(ssl.get_mut()),
        }
    }
    */
}

impl<T: IrcRead, U: IrcWrite> Connection<T, U> {
    /// Creates a new connection from an IrcReader and an IrcWriter.
    pub fn new(reader: T, writer: U) -> Connection<T, U> {
        Connection {
            reader: Mutex::new(reader),
            writer: Mutex::new(writer),
        }
    }

    /// Sends a Message over this connection.
    #[cfg(feature = "encode")]
    pub fn send<M: Into<Message>>(&self, to_msg: M, encoding: &str) -> Result<()> {
        let encoding = match encoding_from_whatwg_label(encoding) {
            Some(enc) => enc,
            None => return Err(Error::new(
                ErrorKind::InvalidInput, &format!("Failed to find encoder. ({})", encoding)[..]
            ))
        };
        let msg: Message = to_msg.into();
        let data = match encoding.encode(&msg.into_string(), EncoderTrap::Replace) {
            Ok(data) => data,
            Err(data) => return Err(Error::new(ErrorKind::InvalidInput,
                &format!("Failed to encode {} as {}.", data, encoding.name())[..]
            ))
        };
        let mut writer = self.writer.lock().unwrap();
        try!(writer.write_all(&data));
        writer.flush()
    }

    /// Sends a message over this connection.
    #[cfg(not(feature = "encode"))]
    pub fn send<M: Into<Message>>(&self, to_msg: M) -> Result<()> {
        let mut writer = self.writer.lock().unwrap();
        let msg: Message = to_msg.into();
        try!(writer.write_all(&msg.into_string().as_bytes()));
        writer.flush()
    }

    /// Receives a single line from this connection.
    #[cfg(feature = "encoding")]
    pub fn recv(&self, encoding: &str) -> Result<String> {
        let encoding = match encoding_from_whatwg_label(encoding) {
            Some(enc) => enc,
            None => return Err(Error::new(
                ErrorKind::InvalidInput, &format!("Failed to find decoder. ({})", encoding)[..]
            ))
        };
        let mut buf = Vec::new();
        self.reader.lock().unwrap().read_until(b'\n', &mut buf).and_then(|_|
            match encoding.decode(&buf, DecoderTrap::Replace) {
                _ if buf.is_empty() => Err(Error::new(ErrorKind::Other, "EOF")),
                Ok(data) => Ok(data),
                Err(data) => return Err(Error::new(ErrorKind::InvalidInput,
                    &format!("Failed to decode {} as {}.", data, encoding.name())[..]
                ))
            }
        )
    }

    /// Receives a single line from this connection.
    #[cfg(not(feature = "encoding"))]
    pub fn recv(&self) -> Result<String> {
        let mut ret = String::new();
        try!(self.reader.lock().unwrap().read_line(&mut ret));
        if ret.is_empty() {
            Err(Error::new(ErrorKind::Other, "EOF"))
        } else {
            Ok(ret)
        }
    }

    /// Acquires the Reader lock.
    pub fn reader<'a>(&'a self) -> MutexGuard<'a, T> {
        self.reader.lock().unwrap()
    }

    /// Acquires the Writer lock.
    pub fn writer<'a>(&'a self) -> MutexGuard<'a, U> {
        self.writer.lock().unwrap()
    }
}

/// Converts a Result<T, SslError> into an Result<T>.
#[cfg(feature = "ssl")]
fn ssl_to_io<T>(res: StdResult<T, SslError>) -> Result<T> {
    match res {
        Ok(x) => Ok(x),
        Err(e) => Err(Error::new(ErrorKind::Other,
            &format!("An SSL error occurred. ({})", e.description())[..]
        )),
    }
}

/// An abstraction over different networked streams.
pub enum NetStream {
    /// An unsecured TcpStream.
    UnsecuredTcpStream(TcpStream),
    /// An SSL-secured TcpStream.
    /// This is only available when compiled with SSL support.
    #[cfg(feature = "ssl")]
    SslTcpStream(SslStream<TcpStream>),
}

impl Read for NetStream {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        match self {
            &mut NetStream::UnsecuredTcpStream(ref mut stream) => stream.read(buf),
            #[cfg(feature = "ssl")]
            &mut NetStream::SslTcpStream(ref mut stream) => stream.read(buf),
        }
    }
}

impl Write for NetStream {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        match self {
            &mut NetStream::UnsecuredTcpStream(ref mut stream) => stream.write(buf),
            #[cfg(feature = "ssl")]
            &mut NetStream::SslTcpStream(ref mut stream) => stream.write(buf),
        }
    }

    fn flush(&mut self) -> Result<()> {
        match self {
            &mut NetStream::UnsecuredTcpStream(ref mut stream) => stream.flush(),
            #[cfg(feature = "ssl")]
            &mut NetStream::SslTcpStream(ref mut stream) => stream.flush(),
        }
    }
}

#[cfg(test)]
mod test {
    use super::Connection;
    use std::io::{Cursor, sink};
    use client::data::message::Message;
    use client::test::buf_empty;
    #[cfg(feature = "encode")] use encoding::{DecoderTrap, Encoding};
    #[cfg(feature = "encode")] use encoding::all::{ISO_8859_15, UTF_8};

    #[test]
    #[cfg(not(feature = "encode"))]
    fn send() {
        let conn = Connection::new(buf_empty(), Vec::new());
        assert!(conn.send(
            Message::new(None, "PRIVMSG", Some(vec!["test"]), Some("Testing!"))
        ).is_ok());
        let data = String::from_utf8(conn.writer().to_vec()).unwrap();
        assert_eq!(&data[..], "PRIVMSG test :Testing!\r\n");
    }

    #[test]
    #[cfg(not(feature = "encode"))]
    fn send_str() {
        let exp = "PRIVMSG test :Testing!\r\n";
        let conn = Connection::new(buf_empty(), Vec::new());
        assert!(conn.send(exp).is_ok());
        let data = String::from_utf8(conn.writer().to_vec()).unwrap();
        assert_eq!(&data[..], exp);
    }

    #[test]
    #[cfg(feature = "encode")]
    fn send_utf8() {
        let conn = Connection::new(buf_empty(), Vec::new());
        assert!(conn.send(
            Message::new(None, "PRIVMSG", Some(vec!["test"]), Some("€ŠšŽžŒœŸ")), "UTF-8"
        ).is_ok());
        let data = UTF_8.decode(&conn.writer(), DecoderTrap::Strict).unwrap();
        assert_eq!(&data[..], "PRIVMSG test :€ŠšŽžŒœŸ\r\n");
    }

    #[test]
    #[cfg(feature = "encode")]
    fn send_utf8_str() {
        let exp = "PRIVMSG test :€ŠšŽžŒœŸ\r\n";
        let conn = Connection::new(buf_empty(), Vec::new());
        assert!(conn.send(exp, "UTF-8").is_ok());
        let data = UTF_8.decode(&conn.writer(), DecoderTrap::Strict).unwrap();
        assert_eq!(&data[..], exp);
    }

    #[test]
    #[cfg(feature = "encode")]
    fn send_iso885915() {
        let conn = Connection::new(buf_empty(), Vec::new());
        assert!(conn.send(
            Message::new(None, "PRIVMSG", Some(vec!["test"]), Some("€ŠšŽžŒœŸ")), "l9"
        ).is_ok());
        let data = ISO_8859_15.decode(&conn.writer(), DecoderTrap::Strict).unwrap();
        assert_eq!(&data[..], "PRIVMSG test :€ŠšŽžŒœŸ\r\n");
    }

    #[test]
    #[cfg(feature = "encode")]
    fn send_iso885915_str() {
        let exp = "PRIVMSG test :€ŠšŽžŒœŸ\r\n";
        let conn = Connection::new(buf_empty(), Vec::new());
        assert!(conn.send(exp, "l9").is_ok());
        let data = ISO_8859_15.decode(&conn.writer(), DecoderTrap::Strict).unwrap();
        assert_eq!(&data[..], exp);
    }

    #[test]
    #[cfg(not(feature = "encode"))]
    fn recv() {
        let conn = Connection::new(
            Cursor::new("PRIVMSG test :Testing!\r\n".as_bytes().to_vec()), sink()
        );
        assert_eq!(&conn.recv().unwrap()[..], "PRIVMSG test :Testing!\r\n");
    }

    #[test]
    #[cfg(feature = "encode")]
    fn recv_utf8() {
        let conn = Connection::new(
            Cursor::new(b"PRIVMSG test :Testing!\r\n".to_vec()), sink()
        );
        assert_eq!(&conn.recv("UTF-8").unwrap()[..], "PRIVMSG test :Testing!\r\n");
    }

    #[test]
    #[cfg(feature = "encode")]
    fn recv_iso885915() {
        let data = [0xA4, 0xA6, 0xA8, 0xB4, 0xB8, 0xBC, 0xBD, 0xBE];
        let conn = Connection::new(Cursor::new({
            let mut vec = Vec::new();
            vec.extend("PRIVMSG test :".as_bytes());
            vec.extend(data.iter());
            vec.extend("\r\n".as_bytes());
            vec.into_iter().collect::<Vec<_>>()
        }), sink());
        assert_eq!(&conn.recv("l9").unwrap()[..], "PRIVMSG test :€ŠšŽžŒœŸ\r\n");
    }
}
<|endoftext|>


<commit_before>//! Define results and error. `Result<T, CabotError>`
use std::error::Error;
use std::fmt::{self, Display};
use std::io::Error as IOError;
use std::string::FromUtf8Error;

use rustls::TLSError;
use url::ParseError as UrlParseError;

#[derive(Debug)]
/// Errors in cabot
pub enum CabotError {
    IOError(IOError),
    CertificateError(TLSError),
    UrlParseError(UrlParseError),
    DNSLookupError(String),
    SchemeError(String),
    HostnameParseError(String),
    OpaqueUrlError(String),
    HttpResponseParseError(String),
    EncodingError(FromUtf8Error),
}

impl Display for CabotError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let description = match self {
            CabotError::SchemeError(scheme) => format!("Unmanaged Scheme: {}", scheme),
            CabotError::OpaqueUrlError(url) => format!("Opaque URL Error: {}", url),
            CabotError::HostnameParseError(name) => format!("Invalid Hostname: {}", name),
            CabotError::UrlParseError(err) => format!("URL Parse Error: {}", err),
            CabotError::IOError(err) => format!("IO Error: {:?}", err),
            CabotError::DNSLookupError(err) => format!("DNS Lookup Error: {}", err),
            CabotError::CertificateError(err) => format!("Certificate Error: {}", err),
            // Unexpexcted Error, not used
            CabotError::HttpResponseParseError(err) => format!("HTTP Response Parse Error: {}", err),
            CabotError::EncodingError(err) => format!("Utf8 Encoding Error: {}", err),
        };
        write!(f, "{:?}: {}", self, description)
    }
}

impl Error for CabotError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        let err: Option<&(dyn Error + 'static)> = match self {
            CabotError::UrlParseError(err) => Some(err),
            CabotError::IOError(err) => Some(err),
            CabotError::CertificateError(err) => Some(err),
            CabotError::EncodingError(err) => Some(err),
            _ => None
        };
        err
    }
}

impl From<IOError> for CabotError {
    fn from(err: IOError) -> CabotError {
        CabotError::IOError(err)
    }
}

impl From<TLSError> for CabotError {
    fn from(err: TLSError) -> CabotError {
        CabotError::CertificateError(err)
    }
}

impl From<UrlParseError> for CabotError {
    fn from(err: UrlParseError) -> CabotError {
        CabotError::UrlParseError(err)
    }
}

impl From<FromUtf8Error> for CabotError {
    fn from(err: FromUtf8Error) -> CabotError {
        CabotError::EncodingError(err)
    }
}
<commit_msg>Fix error display format<commit_after>//! Define results and error. `Result<T, CabotError>`
use std::error::Error;
use std::fmt::{self, Display};
use std::io::Error as IOError;
use std::string::FromUtf8Error;

use rustls::TLSError;
use url::ParseError as UrlParseError;

#[derive(Debug)]
/// Errors in cabot
pub enum CabotError {
    IOError(IOError),
    CertificateError(TLSError),
    UrlParseError(UrlParseError),
    DNSLookupError(String),
    SchemeError(String),
    HostnameParseError(String),
    OpaqueUrlError(String),
    HttpResponseParseError(String),
    EncodingError(FromUtf8Error),
}

impl Display for CabotError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let description = match self {
            CabotError::SchemeError(scheme) => format!("Unmanaged Scheme: {}", scheme),
            CabotError::OpaqueUrlError(url) => format!("Opaque URL Error: {}", url),
            CabotError::HostnameParseError(name) => format!("Invalid Hostname: {}", name),
            CabotError::UrlParseError(err) => format!("URL Parse Error: {}", err),
            CabotError::IOError(err) => format!("IO Error: {}", err),
            CabotError::DNSLookupError(err) => format!("DNS Lookup Error: {}", err),
            CabotError::CertificateError(err) => format!("Certificate Error: {}", err),
            // Unexpexcted Error, not used
            CabotError::HttpResponseParseError(err) => format!("HTTP Response Parse Error: {}", err),
            CabotError::EncodingError(err) => format!("Utf8 Encoding Error: {}", err),
        };
        write!(f, "{}", description)
    }
}

impl Error for CabotError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        let err: Option<&(dyn Error + 'static)> = match self {
            CabotError::UrlParseError(err) => Some(err),
            CabotError::IOError(err) => Some(err),
            CabotError::CertificateError(err) => Some(err),
            CabotError::EncodingError(err) => Some(err),
            _ => None
        };
        err
    }
}

impl From<IOError> for CabotError {
    fn from(err: IOError) -> CabotError {
        CabotError::IOError(err)
    }
}

impl From<TLSError> for CabotError {
    fn from(err: TLSError) -> CabotError {
        CabotError::CertificateError(err)
    }
}

impl From<UrlParseError> for CabotError {
    fn from(err: UrlParseError) -> CabotError {
        CabotError::UrlParseError(err)
    }
}

impl From<FromUtf8Error> for CabotError {
    fn from(err: FromUtf8Error) -> CabotError {
        CabotError::EncodingError(err)
    }
}
<|endoftext|>


<commit_before>use diesel::*;
use dotenv::dotenv;
use std::env;

#[cfg(all(feature = "postgres", feature = "backend_specific_database_url"))]
infer_schema!("dotenv:PG_DATABASE_URL");
#[cfg(all(feature = "sqlite", feature = "backend_specific_database_url"))]
infer_schema!("dotenv:SQLITE_DATABASE_URL");
#[cfg(all(feature = "mysql", feature = "backend_specific_database_url"))]
infer_schema!("dotenv:MYSQL_DATABASE_URL");
#[cfg(not(feature = "backend_specific_database_url"))]
infer_schema!("dotenv:DATABASE_URL");

#[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Insertable, AsChangeset, QueryableByName)]
#[table_name = "users"]
pub struct User {
    pub id: i32,
    pub name: String,
    pub hair_color: Option<String>,
}

impl User {
    pub fn new(id: i32, name: &str) -> Self {
        User {
            id: id,
            name: name.to_string(),
            hair_color: None,
        }
    }

    pub fn with_hair_color(id: i32, name: &str, hair_color: &str) -> Self {
        User {
            id: id,
            name: name.to_string(),
            hair_color: Some(hair_color.to_string()),
        }
    }

    pub fn new_post(&self, title: &str, body: Option<&str>) -> NewPost {
        NewPost::new(self.id, title, body)
    }
}

#[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations)]
#[belongs_to(Post)]
pub struct Comment {
    id: i32,
    post_id: i32,
    text: String,
}

impl Comment {
    pub fn new(id: i32, post_id: i32, text: &str) -> Self {
        Comment {
            id: id,
            post_id: post_id,
            text: text.into(),
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Queryable, Insertable, Associations, Identifiable)]
#[belongs_to(User)]
#[belongs_to(Post)]
#[table_name = "followings"]
#[primary_key(user_id, post_id)]
pub struct Following {
    pub user_id: i32,
    pub post_id: i32,
    pub email_notifications: bool,
}

#[cfg_attr(feature = "postgres", path = "postgres_specific_schema.rs")]
#[cfg_attr(not(feature = "postgres"), path = "backend_specifics.rs")]
mod backend_specifics;

pub use self::backend_specifics::*;

#[derive(Debug, PartialEq, Eq, Queryable, Clone, Insertable, AsChangeset)]
#[table_name = "users"]
pub struct NewUser {
    pub name: String,
    pub hair_color: Option<String>,
}

impl NewUser {
    pub fn new(name: &str, hair_color: Option<&str>) -> Self {
        NewUser {
            name: name.to_string(),
            hair_color: hair_color.map(|s| s.to_string()),
        }
    }
}

#[derive(Insertable)]
#[table_name = "posts"]
pub struct NewPost {
    user_id: i32,
    title: String,
    body: Option<String>,
}

impl NewPost {
    pub fn new(user_id: i32, title: &str, body: Option<&str>) -> Self {
        NewPost {
            user_id: user_id,
            title: title.into(),
            body: body.map(|b| b.into()),
        }
    }
}

#[derive(Debug, Clone, Copy, Insertable)]
#[table_name = "comments"]
pub struct NewComment<'a>(
    #[column_name(post_id)] pub i32,
    #[column_name(text)] pub &'a str,
);

#[derive(PartialEq, Eq, Debug, Clone, Insertable)]
#[table_name = "fk_tests"]
pub struct FkTest {
    id: i32,
    fk_id: i32,
}

impl FkTest {
    pub fn new(id: i32, fk_id: i32) -> Self {
        FkTest {
            id: id,
            fk_id: fk_id,
        }
    }
}

#[derive(Queryable, Insertable)]
#[table_name = "nullable_table"]
pub struct NullableColumn {
    id: i32,
    value: Option<i32>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Queryable, Insertable, Identifiable, Associations)]
#[table_name = "likes"]
#[primary_key(user_id, comment_id)]
#[belongs_to(User)]
#[belongs_to(Comment)]
pub struct Like {
    pub user_id: i32,
    pub comment_id: i32,
}

#[cfg(feature = "postgres")]
pub type TestConnection = PgConnection;
#[cfg(feature = "sqlite")]
pub type TestConnection = SqliteConnection;
#[cfg(feature = "mysql")]
pub type TestConnection = MysqlConnection;

pub type TestBackend = <TestConnection as Connection>::Backend;

pub fn connection() -> TestConnection {
    let result = connection_without_transaction();
    #[cfg(feature = "sqlite")]
    result.execute("PRAGMA foreign_keys = ON").unwrap();
    result.begin_test_transaction().unwrap();
    result
}

#[cfg(feature = "postgres")]
pub fn connection_without_transaction() -> TestConnection {
    dotenv().ok();
    let connection_url = env::var("PG_DATABASE_URL")
        .or_else(|_| env::var("DATABASE_URL"))
        .expect("DATABASE_URL must be set in order to run tests");
    PgConnection::establish(&connection_url).unwrap()
}

#[cfg(feature = "sqlite")]
embed_migrations!("../migrations/sqlite");

#[cfg(feature = "sqlite")]
pub fn connection_without_transaction() -> TestConnection {
    let connection = SqliteConnection::establish(":memory:").unwrap();
    embedded_migrations::run(&connection).unwrap();
    connection
}

#[cfg(feature = "mysql")]
pub fn connection_without_transaction() -> TestConnection {
    dotenv().ok();
    let connection_url = env::var("MYSQL_DATABASE_URL")
        .or_else(|_| env::var("DATABASE_URL"))
        .expect("DATABASE_URL must be set in order to run tests");
    MysqlConnection::establish(&connection_url).unwrap()
}

#[cfg(feature = "postgres")]
pub fn disable_foreign_keys(connection: &TestConnection) {
    connection.execute("SET CONSTRAINTS ALL DEFERRED").unwrap();
}

#[cfg(feature = "mysql")]
pub fn disable_foreign_keys(connection: &TestConnection) {
    connection.execute("SET FOREIGN_KEY_CHECKS = 0").unwrap();
}

#[cfg(feature = "sqlite")]
pub fn disable_foreign_keys(connection: &TestConnection) {
    connection
        .execute("PRAGMA defer_foreign_keys = ON")
        .unwrap();
}

#[cfg(feature = "sqlite")]
pub fn drop_table_cascade(connection: &TestConnection, table: &str) {
    connection
        .execute(&format!("DROP TABLE {}", table))
        .unwrap();
}

#[cfg(not(feature = "sqlite"))]
pub fn drop_table_cascade(connection: &TestConnection, table: &str) {
    connection
        .execute(&format!("DROP TABLE {} CASCADE", table))
        .unwrap();
}

sql_function!(nextval, nextval_t, (a: types::VarChar) -> types::BigInt);

pub fn connection_with_sean_and_tess_in_users_table() -> TestConnection {
    let connection = connection();
    insert_sean_and_tess_into_users_table(&connection);
    connection
}

pub fn insert_sean_and_tess_into_users_table(connection: &TestConnection) {
    connection
        .execute("INSERT INTO users (id, name) VALUES (1, 'Sean'), (2, 'Tess')")
        .unwrap();
    ensure_primary_key_seq_greater_than(2, &connection);
}

pub fn connection_with_nullable_table_data() -> TestConnection {
    let connection = connection();

    let test_data = vec![
        NullableColumn { id: 1, value: None },
        NullableColumn { id: 2, value: None },
        NullableColumn {
            id: 3,
            value: Some(1),
        },
        NullableColumn {
            id: 4,
            value: Some(2),
        },
        NullableColumn {
            id: 5,
            value: Some(1),
        },
    ];
    insert_into(nullable_table::table)
        .values(&test_data)
        .execute(&connection)
        .unwrap();

    connection
}

fn ensure_primary_key_seq_greater_than(x: i64, connection: &TestConnection) {
    if cfg!(feature = "postgres") {
        for _ in 0..x {
            select(nextval("users_id_seq")).execute(connection).unwrap();
        }
    }
}

pub fn find_user_by_name(name: &str, connection: &TestConnection) -> User {
    users::table
        .filter(users::name.eq(name))
        .first(connection)
        .unwrap()
}
<commit_msg>Run rustfmt<commit_after>use diesel::*;
use dotenv::dotenv;
use std::env;

#[cfg(all(feature = "postgres", feature = "backend_specific_database_url"))]
infer_schema!("dotenv:PG_DATABASE_URL");
#[cfg(all(feature = "sqlite", feature = "backend_specific_database_url"))]
infer_schema!("dotenv:SQLITE_DATABASE_URL");
#[cfg(all(feature = "mysql", feature = "backend_specific_database_url"))]
infer_schema!("dotenv:MYSQL_DATABASE_URL");
#[cfg(not(feature = "backend_specific_database_url"))]
infer_schema!("dotenv:DATABASE_URL");

#[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Insertable, AsChangeset,
         QueryableByName)]
#[table_name = "users"]
pub struct User {
    pub id: i32,
    pub name: String,
    pub hair_color: Option<String>,
}

impl User {
    pub fn new(id: i32, name: &str) -> Self {
        User {
            id: id,
            name: name.to_string(),
            hair_color: None,
        }
    }

    pub fn with_hair_color(id: i32, name: &str, hair_color: &str) -> Self {
        User {
            id: id,
            name: name.to_string(),
            hair_color: Some(hair_color.to_string()),
        }
    }

    pub fn new_post(&self, title: &str, body: Option<&str>) -> NewPost {
        NewPost::new(self.id, title, body)
    }
}

#[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations)]
#[belongs_to(Post)]
pub struct Comment {
    id: i32,
    post_id: i32,
    text: String,
}

impl Comment {
    pub fn new(id: i32, post_id: i32, text: &str) -> Self {
        Comment {
            id: id,
            post_id: post_id,
            text: text.into(),
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Queryable, Insertable, Associations, Identifiable)]
#[belongs_to(User)]
#[belongs_to(Post)]
#[table_name = "followings"]
#[primary_key(user_id, post_id)]
pub struct Following {
    pub user_id: i32,
    pub post_id: i32,
    pub email_notifications: bool,
}

#[cfg_attr(feature = "postgres", path = "postgres_specific_schema.rs")]
#[cfg_attr(not(feature = "postgres"), path = "backend_specifics.rs")]
mod backend_specifics;

pub use self::backend_specifics::*;

#[derive(Debug, PartialEq, Eq, Queryable, Clone, Insertable, AsChangeset)]
#[table_name = "users"]
pub struct NewUser {
    pub name: String,
    pub hair_color: Option<String>,
}

impl NewUser {
    pub fn new(name: &str, hair_color: Option<&str>) -> Self {
        NewUser {
            name: name.to_string(),
            hair_color: hair_color.map(|s| s.to_string()),
        }
    }
}

#[derive(Insertable)]
#[table_name = "posts"]
pub struct NewPost {
    user_id: i32,
    title: String,
    body: Option<String>,
}

impl NewPost {
    pub fn new(user_id: i32, title: &str, body: Option<&str>) -> Self {
        NewPost {
            user_id: user_id,
            title: title.into(),
            body: body.map(|b| b.into()),
        }
    }
}

#[derive(Debug, Clone, Copy, Insertable)]
#[table_name = "comments"]
pub struct NewComment<'a>(
    #[column_name(post_id)] pub i32,
    #[column_name(text)] pub &'a str,
);

#[derive(PartialEq, Eq, Debug, Clone, Insertable)]
#[table_name = "fk_tests"]
pub struct FkTest {
    id: i32,
    fk_id: i32,
}

impl FkTest {
    pub fn new(id: i32, fk_id: i32) -> Self {
        FkTest {
            id: id,
            fk_id: fk_id,
        }
    }
}

#[derive(Queryable, Insertable)]
#[table_name = "nullable_table"]
pub struct NullableColumn {
    id: i32,
    value: Option<i32>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Queryable, Insertable, Identifiable, Associations)]
#[table_name = "likes"]
#[primary_key(user_id, comment_id)]
#[belongs_to(User)]
#[belongs_to(Comment)]
pub struct Like {
    pub user_id: i32,
    pub comment_id: i32,
}

#[cfg(feature = "postgres")]
pub type TestConnection = PgConnection;
#[cfg(feature = "sqlite")]
pub type TestConnection = SqliteConnection;
#[cfg(feature = "mysql")]
pub type TestConnection = MysqlConnection;

pub type TestBackend = <TestConnection as Connection>::Backend;

pub fn connection() -> TestConnection {
    let result = connection_without_transaction();
    #[cfg(feature = "sqlite")]
    result.execute("PRAGMA foreign_keys = ON").unwrap();
    result.begin_test_transaction().unwrap();
    result
}

#[cfg(feature = "postgres")]
pub fn connection_without_transaction() -> TestConnection {
    dotenv().ok();
    let connection_url = env::var("PG_DATABASE_URL")
        .or_else(|_| env::var("DATABASE_URL"))
        .expect("DATABASE_URL must be set in order to run tests");
    PgConnection::establish(&connection_url).unwrap()
}

#[cfg(feature = "sqlite")]
embed_migrations!("../migrations/sqlite");

#[cfg(feature = "sqlite")]
pub fn connection_without_transaction() -> TestConnection {
    let connection = SqliteConnection::establish(":memory:").unwrap();
    embedded_migrations::run(&connection).unwrap();
    connection
}

#[cfg(feature = "mysql")]
pub fn connection_without_transaction() -> TestConnection {
    dotenv().ok();
    let connection_url = env::var("MYSQL_DATABASE_URL")
        .or_else(|_| env::var("DATABASE_URL"))
        .expect("DATABASE_URL must be set in order to run tests");
    MysqlConnection::establish(&connection_url).unwrap()
}

#[cfg(feature = "postgres")]
pub fn disable_foreign_keys(connection: &TestConnection) {
    connection.execute("SET CONSTRAINTS ALL DEFERRED").unwrap();
}

#[cfg(feature = "mysql")]
pub fn disable_foreign_keys(connection: &TestConnection) {
    connection.execute("SET FOREIGN_KEY_CHECKS = 0").unwrap();
}

#[cfg(feature = "sqlite")]
pub fn disable_foreign_keys(connection: &TestConnection) {
    connection
        .execute("PRAGMA defer_foreign_keys = ON")
        .unwrap();
}

#[cfg(feature = "sqlite")]
pub fn drop_table_cascade(connection: &TestConnection, table: &str) {
    connection
        .execute(&format!("DROP TABLE {}", table))
        .unwrap();
}

#[cfg(not(feature = "sqlite"))]
pub fn drop_table_cascade(connection: &TestConnection, table: &str) {
    connection
        .execute(&format!("DROP TABLE {} CASCADE", table))
        .unwrap();
}

sql_function!(nextval, nextval_t, (a: types::VarChar) -> types::BigInt);

pub fn connection_with_sean_and_tess_in_users_table() -> TestConnection {
    let connection = connection();
    insert_sean_and_tess_into_users_table(&connection);
    connection
}

pub fn insert_sean_and_tess_into_users_table(connection: &TestConnection) {
    connection
        .execute("INSERT INTO users (id, name) VALUES (1, 'Sean'), (2, 'Tess')")
        .unwrap();
    ensure_primary_key_seq_greater_than(2, &connection);
}

pub fn connection_with_nullable_table_data() -> TestConnection {
    let connection = connection();

    let test_data = vec![
        NullableColumn { id: 1, value: None },
        NullableColumn { id: 2, value: None },
        NullableColumn {
            id: 3,
            value: Some(1),
        },
        NullableColumn {
            id: 4,
            value: Some(2),
        },
        NullableColumn {
            id: 5,
            value: Some(1),
        },
    ];
    insert_into(nullable_table::table)
        .values(&test_data)
        .execute(&connection)
        .unwrap();

    connection
}

fn ensure_primary_key_seq_greater_than(x: i64, connection: &TestConnection) {
    if cfg!(feature = "postgres") {
        for _ in 0..x {
            select(nextval("users_id_seq")).execute(connection).unwrap();
        }
    }
}

pub fn find_user_by_name(name: &str, connection: &TestConnection) -> User {
    users::table
        .filter(users::name.eq(name))
        .first(connection)
        .unwrap()
}
<|endoftext|>


<commit_before>#![allow(non_uppercase_statics)]

#[deriving(Clone,Show)]
pub enum Event {
    /// The size of the window has changed.
    Resized(uint, uint),

    /// The position of the window has changed.
    Moved(int, int),

    /// The window has been closed.
    Closed,

    /// The window received a unicode character.
    ReceivedCharacter(char),

    /// The window gained or lost focus.
    ///
    /// The parameter is true if the window has gained focus, and false if it has lost focus.
    Focused(bool),

    /// An event from the keyboard has been received.
    KeyboardInput(ElementState, ScanCode, Option<VirtualKeyCode>, KeyModifiers),

    /// The cursor has moved on the window.
    ///
    /// The parameter are the (x,y) coords in pixels relative to the top-left corner of the window.
    MouseMoved((int, int)),

    /// A positive value indicates that the wheel was rotated forward, away from the user;
    ///  a negative value indicates that the wheel was rotated backward, toward the user.
    MouseWheel(i32),

    /// An event from the mouse has been received.
    MouseInput(ElementState, MouseButton),
}

pub type ScanCode = u8;

bitflags!(
    #[deriving(Show)]
    flags KeyModifiers: u8 {
        const LeftControlModifier = 1,
        const RightControlModifier = 2,
        const LeftShitModifier = 4,
        const RightShitModifier = 8,
        const LeftAltModifier = 16,
        const RightRightModifier = 32,
        const NumLockModifier = 64,
        const CapsLockModifier = 128
    }
)

#[deriving(Show, Hash, PartialEq, Eq, Clone)]
pub enum ElementState {
    Pressed,
    Released,
}

#[deriving(Show, Hash, PartialEq, Eq, Clone)]
pub enum MouseButton {
    LeftMouseButton,
    RightMouseButton,
    MiddleMouseButton,
    OtherMouseButton(u8),
}

#[deriving(Show, Hash, PartialEq, Eq, Clone)]
pub enum VirtualKeyCode {
    Key0,
    Key1,
    Key2,
    Key3,
    Key4,
    Key5,
    Key6,
    Key7,
    Key8,
    Key9,
    A,
    AbntC1,
    AbntC2,
    Add,
    Apostrophe,
    Apps,
    At,
    Ax,
    B,
    Back,
    Backslash,
    C,
    Calculator,
    Capital,
    Colon,
    Comma,
    Convert,
    D,
    Decimal,
    Delete,
    Divide,
    Down,
    E,
    End,
    Equals,
    Escape,
    F,
    F1,
    F2,
    F3,
    F4,
    F5,
    F6,
    F7,
    F8,
    F9,
    F10,
    F11,
    F12,
    F13,
    F14,
    F15,
    G,
    Grave,
    H,
    Home,
    I,
    Insert,
    J,
    K,
    Kana,
    Kanji,
    L,
    LCracket,
    LControl,
    Left,
    LMenu,
    LShift,
    LWin,
    M,
    Mail,
    MediaSelect,
    MediaStop,
    Minus,
    Multiply,
    Mute,
    MyComputer,
    N,
    NextTrack,
    NoConvert,
    Numlock,
    Numpad0,
    Numpad1,
    Numpad2,
    Numpad3,
    Numpad4,
    Numpad5,
    Numpad6,
    Numpad7,
    Numpad8,
    Numpad9,
    NumpadComma,
    NumpadEnter,
    NumpadEquals,
    O,
    OEM102,
    P,
    PageDown,
    PageUp,
    Pause,
    Period,
    Playpause,
    Power,
    Prevtrack,
    Q,
    R,
    RBracket,
    RControl,
    Return,
    Right,
    RMenu,
    RShift,
    RWin,
    S,
    Scroll,
    Semicolon,
    Slash,
    Sleep,
    Snapshot,
    Space,
    Stop,
    Subtract,
    Sysrq,
    T,
    Tab,
    U,
    Underline,
    Unlabeled,
    Up,
    V,
    VolumeDown,
    VolumeUp,
    W,
    Wake,
    Webback,
    WebFavorites,
    WebForward,
    WebHome,
    WebRefresh,
    WebSearch,
    WebStop,
    X,
    Y,
    Yen,
    Z
}
<commit_msg>Changed statics to uppercase<commit_after>#[deriving(Clone,Show)]
pub enum Event {
    /// The size of the window has changed.
    Resized(uint, uint),

    /// The position of the window has changed.
    Moved(int, int),

    /// The window has been closed.
    Closed,

    /// The window received a unicode character.
    ReceivedCharacter(char),

    /// The window gained or lost focus.
    ///
    /// The parameter is true if the window has gained focus, and false if it has lost focus.
    Focused(bool),

    /// An event from the keyboard has been received.
    KeyboardInput(ElementState, ScanCode, Option<VirtualKeyCode>, KeyModifiers),

    /// The cursor has moved on the window.
    ///
    /// The parameter are the (x,y) coords in pixels relative to the top-left corner of the window.
    MouseMoved((int, int)),

    /// A positive value indicates that the wheel was rotated forward, away from the user;
    ///  a negative value indicates that the wheel was rotated backward, toward the user.
    MouseWheel(i32),

    /// An event from the mouse has been received.
    MouseInput(ElementState, MouseButton),
}

pub type ScanCode = u8;

bitflags!(
    #[deriving(Show)]
    flags KeyModifiers: u8 {
        const LEFT_CONTROL_MODIFIER = 1,
        const RIGHT_CONTROL_MODIFIER = 2,
        const LEFT_SHIFT_MODIFIER = 4,
        const RIGHT_SHIFT_MODIFIER = 8,
        const LEFT_ALT_MODIFIER = 16,
        const RIGHT_ALT_MODIFIER = 32,
        const NUM_LOCK_MODIFIER = 64,
        const CAPS_LOCK_MODIFIER = 128
    }
)

#[deriving(Show, Hash, PartialEq, Eq, Clone)]
pub enum ElementState {
    Pressed,
    Released,
}

#[deriving(Show, Hash, PartialEq, Eq, Clone)]
pub enum MouseButton {
    LeftMouseButton,
    RightMouseButton,
    MiddleMouseButton,
    OtherMouseButton(u8),
}

#[deriving(Show, Hash, PartialEq, Eq, Clone)]
pub enum VirtualKeyCode {
    Key0,
    Key1,
    Key2,
    Key3,
    Key4,
    Key5,
    Key6,
    Key7,
    Key8,
    Key9,
    A,
    AbntC1,
    AbntC2,
    Add,
    Apostrophe,
    Apps,
    At,
    Ax,
    B,
    Back,
    Backslash,
    C,
    Calculator,
    Capital,
    Colon,
    Comma,
    Convert,
    D,
    Decimal,
    Delete,
    Divide,
    Down,
    E,
    End,
    Equals,
    Escape,
    F,
    F1,
    F2,
    F3,
    F4,
    F5,
    F6,
    F7,
    F8,
    F9,
    F10,
    F11,
    F12,
    F13,
    F14,
    F15,
    G,
    Grave,
    H,
    Home,
    I,
    Insert,
    J,
    K,
    Kana,
    Kanji,
    L,
    LCracket,
    LControl,
    Left,
    LMenu,
    LShift,
    LWin,
    M,
    Mail,
    MediaSelect,
    MediaStop,
    Minus,
    Multiply,
    Mute,
    MyComputer,
    N,
    NextTrack,
    NoConvert,
    Numlock,
    Numpad0,
    Numpad1,
    Numpad2,
    Numpad3,
    Numpad4,
    Numpad5,
    Numpad6,
    Numpad7,
    Numpad8,
    Numpad9,
    NumpadComma,
    NumpadEnter,
    NumpadEquals,
    O,
    OEM102,
    P,
    PageDown,
    PageUp,
    Pause,
    Period,
    Playpause,
    Power,
    Prevtrack,
    Q,
    R,
    RBracket,
    RControl,
    Return,
    Right,
    RMenu,
    RShift,
    RWin,
    S,
    Scroll,
    Semicolon,
    Slash,
    Sleep,
    Snapshot,
    Space,
    Stop,
    Subtract,
    Sysrq,
    T,
    Tab,
    U,
    Underline,
    Unlabeled,
    Up,
    V,
    VolumeDown,
    VolumeUp,
    W,
    Wake,
    Webback,
    WebFavorites,
    WebForward,
    WebHome,
    WebRefresh,
    WebSearch,
    WebStop,
    X,
    Y,
    Yen,
    Z
}
<|endoftext|>