<commit_before>#[macro_use]
extern crate websocat;

extern crate futures;
extern crate tokio_core;
extern crate tokio_stdin_stdout;

extern crate env_logger;

#[cfg(feature="openssl-probe")]
extern crate openssl_probe;

#[macro_use]
extern crate structopt;

use structopt::StructOpt;

use tokio_core::reactor::Core;

use websocat::{spec, Options, SpecifierClass, WebsocatConfiguration};

type Result<T> = std::result::Result<T, Box<std::error::Error>>;

#[derive(StructOpt, Debug)]
#[structopt(
    after_help = "
Basic examples:
  Command-line websocket client:
    websocat ws://echo.websocket.org/

  Listen websocket and redirect it to a TCP port:
    websocat ws-l:127.0.0.1:8080 tcp:127.0.0.1:5678

  See more examples with the --long-help option

Short list of specifiers (see --long-help):
  ws:// wss:// - inetd: ws-listen: inetd-ws: tcp: tcp-l: ws-c:
  autoreconnect: reuse: mirror: threadedstdio: clogged:
  literal: literalreply: assert: udp-connect: open-async:
  readfile: writefile: open-fd: unix-connect: unix-listen:
  unix-dgram: abstract-connect: abstract-listen:
  exec: sh-c:
", usage="websocat [FLAGS] [OPTIONS] <s1> [s2]"
)]
struct Opt {
    /// First, listening/connecting specifier. See --long-help for info about specifiers.
    s1: String,
    /// Second, connecting specifier
    s2: Option<String>,

    #[structopt(
        short = "u",
        long = "unidirectional",
        help = "Inhibit copying data from right specifier to left"
    )]
    unidirectional: bool,
    #[structopt(
        short = "U",
        long = "unidirectional-reverse",
        help = "Inhibit copying data from left specifier to right"
    )]
    unidirectional_reverse: bool,

    #[structopt(
        long = "exit-on-eof",
        short = "E",
        help = "Close a data transfer direction if the other one reached EOF"
    )]
    exit_on_eof: bool,

    #[structopt(
        short = "t", long = "text", help = "Send text WebSocket messages instead of binary"
    )]
    websocket_text_mode: bool,

    #[structopt(long = "oneshot", help = "Serve only once. Not to be confused with -1 (--one-message)")]
    oneshot: bool,

    #[structopt(long = "long-help", help = "Show full help aboput specifiers and examples")]
    longhelp: bool,

    #[structopt(
        long = "dump-spec",
        help = "Instead of running, dump the specifiers representation to stdout"
    )]
    dumpspec: bool,

    #[structopt(long = "protocol", help = "Specify Sec-WebSocket-Protocol: header")]
    websocket_protocol: Option<String>,

    #[structopt(long = "udp-oneshot", help = "udp-listen: replies only one packet per client")]
    udp_oneshot_mode: bool,

    #[structopt(long = "unlink", help = "Unlink listening UNIX socket before binding to it")]
    unlink_unix_socket: bool,

    #[structopt(
        long = "exec-args",
        raw(allow_hyphen_values = r#"true"#),
        help = "Arguments for the `exec:` specifier. Must be the last option, everything after it gets into the exec args list."
    )]
    exec_args: Vec<String>,

    #[structopt(
        long = "ws-c-uri", help = "URI to use for ws-c: specifier", default_value = "ws://0.0.0.0/"
    )]
    ws_c_uri: String,

    #[structopt(
        long = "linemode-retain-newlines",
        help = "In --line mode, don't chop off trailing \\n from messages"
    )]
    linemode_retain_newlines: bool,

    #[structopt(
        short = "-l", long = "--line", help = "Make each WebSocket message correspond to one line"
    )]
    linemode: bool,

    #[structopt(long="origin",help="Add Origin HTTP header to websocket client request")]
    origin: Option<String>,

    #[structopt(
        long="header",
        short="H",
        help="Add custom HTTP header to websocket client request. Separate header name and value with a colon and optionally a single space. Can be used multiple times.",
        parse(try_from_str="interpret_custom_header"),
    )]
    custom_headers: Vec<(String,Vec<u8>)>,

    #[structopt(long="websocket-version", help="Override the Sec-WebSocket-Version value")]
    websocket_version: Option<String>,

    #[structopt(long="no-close", short="n", help="Don't send Close message to websocket on EOF")]
    websocket_dont_close: bool,

    #[structopt(
        short="1",
        long="one-message",
        help="Send and/or receive only one message. Use with --no-close and/or -u/-U.",
    )]
    one_message : bool,

    // TODO: -v --quiet
}

// TODO: make it byte-oriented/OsStr?
fn interpret_custom_header(x:&str) -> Result<(String,Vec<u8>)> {
    let colon = x.find(':');
    let colon = if let Some(colon) = colon { colon } else {
        Err("Argument to --header must contain `:` character")?
    };
    let hn = &x[0..colon];
    let mut hv = &x[colon+1..];
    if hv.chars().next() == Some(' ') {
        hv = &x[colon+2..];
    }
    Ok((hn.to_owned(), hv.as_bytes().to_vec()))
}

fn longhelp() {
    // TODO: promote first alias to title
    println!(
        r#"(see also the usual --help message)

Positional arguments to websocat are generally called specifiers.
Specifiers are ways to obtain a connection from some string representation (i.e. address).

Specifiers may be argumentless (like `mirror:`), can accept an argument (which
may be some path or socket address, like `tcp:`), or can accept a subspecifier
(like `reuse:` or `autoreconnect:`).

Here is the full list of specifier classes in this WebSocat build:

"#
    );

    fn help1(sc: &SpecifierClass) {
        let n = sc.get_name().replace("Class", "");
        let prefixes = sc
            .get_prefixes()
            .iter()
            .map(|x| format!("`{}`", x))
            .collect::<Vec<_>>()
            .join(", ");
        println!("### {}\n\n* {}", n, prefixes);

        let help =
            sc
            .help()
            //.lines()
            //.map(|x|format!("    {}",x))
            //.collect::<Vec<_>>()
            //.join("\n")
            ;
        println!("{}\n", help);
    }

    macro_rules! my {
        ($x:expr) => {
            help1(&$x);
        };
    }

    list_of_all_specifier_classes!(my);

    println!(
        r#"

TODO:
  sctp:
  ssl:

Final example just for fun: wacky mode

    websocat ws-c:ws-l:ws-c:- tcp:127.0.0.1:5678

Connect to a websocket using stdin/stdout as a transport,
then accept a websocket connection over the previous websocket used as a transport,
then connect to a websocket using previous step as a transport,
then forward resulting connection to the TCP port.

(Excercise to the reader: manage to make it actually connect to 5678).
"#
    );
}

fn run() -> Result<()> {
    if std::env::args().nth(1).unwrap_or_default() == "--long-help" {
        longhelp();
        return Ok(());
    }

    let mut cmd = Opt::from_args();

    if cmd.longhelp {
        longhelp();
        return Ok(());
    }

    if false
    //    || cmd.oneshot
    {
        Err("This mode is not implemented")?
    }

    #[cfg(feature="openssl-probe")] {
        openssl_probe::init_ssl_cert_env_vars();
    }

    let mut opts = {
        macro_rules! opts {
            ($($o:ident)*) => {
                Options {
                    $($o : cmd.$o,)*
                }
            };
        }
        opts!(
            websocket_text_mode
            websocket_protocol
            udp_oneshot_mode
            unidirectional
            unidirectional_reverse
            exit_on_eof
            oneshot
            unlink_unix_socket
            exec_args
            ws_c_uri
            linemode_retain_newlines
            origin
            custom_headers
            websocket_version
            websocket_dont_close
            one_message
        )
    };

    let (s1, s2) = if let Some(ref cmds2) = cmd.s2 {
        (spec(&cmd.s1)?, spec(cmds2)?)
    } else {
        if ! (cmd.s1.starts_with("ws://") || cmd.s1.starts_with("wss://")) {
            Err("Simple one-argument mode is only for connecting to websockets. Use explicit two-argument websocat invocation for advanced features.")?;
        }
        // Easy mode
        cmd.linemode = true;
        opts.websocket_text_mode = true;
        if opts.websocket_protocol == None {
            opts.websocket_protocol = Some("tcp".to_owned());
        }
        (spec("-")?, spec(&cmd.s1)?)
    };

    let mut websocat = WebsocatConfiguration { opts, s1, s2 };

    if cmd.linemode {
        use websocat::lints::AutoInstallLinemodeConcern::*;
        websocat = match websocat.auto_install_linemode() {
            Ok(x) => x,
            Err((NoWebsocket,_)) => Err("No websocket usage is specified. Use line2msg: and msg2line: specifiers manually if needed.")?,
            Err((MultipleWebsocket,_)) => Err("Multiple websocket usages are specified. Use line2msg: and msg2line: specifiers manually if needed.")?,
            Err((AlreadyLine,_)) => Err("Can't auto-insert msg2line:/line2msg: if you have already manually specified some of them")?,
        }
    }

    while let Some(concern) = websocat.get_concern() {
        use websocat::lints::ConfigurationConcern::*;
        if concern == StdinToStdout {
            if cmd.dumpspec {
                println!("cat mode");
                return Ok(());
            }

            // Degenerate mode: just copy stdin to stdout and call it a day
            ::std::io::copy(&mut ::std::io::stdin(), &mut ::std::io::stdout())?;
            return Ok(());
        }

        if concern == DegenerateMode {
            if cmd.dumpspec {
                println!("noop");
            }
            return Ok(());
        }

        if concern == StdioConflict {
            Err("Too many usages of stdin/stdout")?;
        }

        if concern == NeedsStdioReuser {
            eprintln!("Warning: replies on stdio get directed at random connected client");
            websocat = websocat.auto_install_reuser();
            continue;
        }

        if concern == NeedsStdioReuser2 {
            websocat = websocat.auto_install_reuser();
            continue;
        }

        if concern == MultipleReusers {
            eprintln!("Specifier dump: {:?} {:?}", websocat.s1, websocat.s2);
            Err("Multiple reusers is not allowed")?;
        }
        break;
    }

    if cmd.dumpspec {
        println!("{:?}", websocat.s1);
        println!("{:?}", websocat.s2);
        println!("{:?}", websocat.opts);
        return Ok(());
    }

    let mut core = Core::new()?;

    let prog = websocat.serve(
        core.handle(),
        std::rc::Rc::new(|e| {
            eprintln!("websocat: {}", e);
        }),
    );
    core.run(prog).map_err(|()| "error running".to_string())?;
    Ok(())
}

fn main() {
    env_logger::init();
    let r = run();

    if let Err(e) = r {
        eprintln!("websocat: {}", e);
        ::std::process::exit(1);
    }
}
<commit_msg>Rectify message about wrong simple mode usage<commit_after>#[macro_use]
extern crate websocat;

extern crate futures;
extern crate tokio_core;
extern crate tokio_stdin_stdout;

extern crate env_logger;

#[cfg(feature="openssl-probe")]
extern crate openssl_probe;

#[macro_use]
extern crate structopt;

use structopt::StructOpt;

use tokio_core::reactor::Core;

use websocat::{spec, Options, SpecifierClass, WebsocatConfiguration};

type Result<T> = std::result::Result<T, Box<std::error::Error>>;

#[derive(StructOpt, Debug)]
#[structopt(
    after_help = "
Basic examples:
  Command-line websocket client:
    websocat ws://echo.websocket.org/

  Listen websocket and redirect it to a TCP port:
    websocat ws-l:127.0.0.1:8080 tcp:127.0.0.1:5678

  See more examples with the --long-help option

Short list of specifiers (see --long-help):
  ws:// wss:// - inetd: ws-listen: inetd-ws: tcp: tcp-l: ws-c:
  autoreconnect: reuse: mirror: threadedstdio: clogged:
  literal: literalreply: assert: udp-connect: open-async:
  readfile: writefile: open-fd: unix-connect: unix-listen:
  unix-dgram: abstract-connect: abstract-listen:
  exec: sh-c:
", usage="websocat [FLAGS] [OPTIONS] <s1> [s2]"
)]
struct Opt {
    /// First, listening/connecting specifier. See --long-help for info about specifiers.
    s1: String,
    /// Second, connecting specifier
    s2: Option<String>,

    #[structopt(
        short = "u",
        long = "unidirectional",
        help = "Inhibit copying data from right specifier to left"
    )]
    unidirectional: bool,
    #[structopt(
        short = "U",
        long = "unidirectional-reverse",
        help = "Inhibit copying data from left specifier to right"
    )]
    unidirectional_reverse: bool,

    #[structopt(
        long = "exit-on-eof",
        short = "E",
        help = "Close a data transfer direction if the other one reached EOF"
    )]
    exit_on_eof: bool,

    #[structopt(
        short = "t", long = "text", help = "Send text WebSocket messages instead of binary"
    )]
    websocket_text_mode: bool,

    #[structopt(long = "oneshot", help = "Serve only once. Not to be confused with -1 (--one-message)")]
    oneshot: bool,

    #[structopt(long = "long-help", help = "Show full help aboput specifiers and examples")]
    longhelp: bool,

    #[structopt(
        long = "dump-spec",
        help = "Instead of running, dump the specifiers representation to stdout"
    )]
    dumpspec: bool,

    #[structopt(long = "protocol", help = "Specify Sec-WebSocket-Protocol: header")]
    websocket_protocol: Option<String>,

    #[structopt(long = "udp-oneshot", help = "udp-listen: replies only one packet per client")]
    udp_oneshot_mode: bool,

    #[structopt(long = "unlink", help = "Unlink listening UNIX socket before binding to it")]
    unlink_unix_socket: bool,

    #[structopt(
        long = "exec-args",
        raw(allow_hyphen_values = r#"true"#),
        help = "Arguments for the `exec:` specifier. Must be the last option, everything after it gets into the exec args list."
    )]
    exec_args: Vec<String>,

    #[structopt(
        long = "ws-c-uri", help = "URI to use for ws-c: specifier", default_value = "ws://0.0.0.0/"
    )]
    ws_c_uri: String,

    #[structopt(
        long = "linemode-retain-newlines",
        help = "In --line mode, don't chop off trailing \\n from messages"
    )]
    linemode_retain_newlines: bool,

    #[structopt(
        short = "-l", long = "--line", help = "Make each WebSocket message correspond to one line"
    )]
    linemode: bool,

    #[structopt(long="origin",help="Add Origin HTTP header to websocket client request")]
    origin: Option<String>,

    #[structopt(
        long="header",
        short="H",
        help="Add custom HTTP header to websocket client request. Separate header name and value with a colon and optionally a single space. Can be used multiple times.",
        parse(try_from_str="interpret_custom_header"),
    )]
    custom_headers: Vec<(String,Vec<u8>)>,

    #[structopt(long="websocket-version", help="Override the Sec-WebSocket-Version value")]
    websocket_version: Option<String>,

    #[structopt(long="no-close", short="n", help="Don't send Close message to websocket on EOF")]
    websocket_dont_close: bool,

    #[structopt(
        short="1",
        long="one-message",
        help="Send and/or receive only one message. Use with --no-close and/or -u/-U.",
    )]
    one_message : bool,

    // TODO: -v --quiet
}

// TODO: make it byte-oriented/OsStr?
fn interpret_custom_header(x:&str) -> Result<(String,Vec<u8>)> {
    let colon = x.find(':');
    let colon = if let Some(colon) = colon { colon } else {
        Err("Argument to --header must contain `:` character")?
    };
    let hn = &x[0..colon];
    let mut hv = &x[colon+1..];
    if hv.chars().next() == Some(' ') {
        hv = &x[colon+2..];
    }
    Ok((hn.to_owned(), hv.as_bytes().to_vec()))
}

fn longhelp() {
    // TODO: promote first alias to title
    println!(
        r#"(see also the usual --help message)

Positional arguments to websocat are generally called specifiers.
Specifiers are ways to obtain a connection from some string representation (i.e. address).

Specifiers may be argumentless (like `mirror:`), can accept an argument (which
may be some path or socket address, like `tcp:`), or can accept a subspecifier
(like `reuse:` or `autoreconnect:`).

Here is the full list of specifier classes in this WebSocat build:

"#
    );

    fn help1(sc: &SpecifierClass) {
        let n = sc.get_name().replace("Class", "");
        let prefixes = sc
            .get_prefixes()
            .iter()
            .map(|x| format!("`{}`", x))
            .collect::<Vec<_>>()
            .join(", ");
        println!("### {}\n\n* {}", n, prefixes);

        let help =
            sc
            .help()
            //.lines()
            //.map(|x|format!("    {}",x))
            //.collect::<Vec<_>>()
            //.join("\n")
            ;
        println!("{}\n", help);
    }

    macro_rules! my {
        ($x:expr) => {
            help1(&$x);
        };
    }

    list_of_all_specifier_classes!(my);

    println!(
        r#"

TODO:
  sctp:
  ssl:

Final example just for fun: wacky mode

    websocat ws-c:ws-l:ws-c:- tcp:127.0.0.1:5678

Connect to a websocket using stdin/stdout as a transport,
then accept a websocket connection over the previous websocket used as a transport,
then connect to a websocket using previous step as a transport,
then forward resulting connection to the TCP port.

(Excercise to the reader: manage to make it actually connect to 5678).
"#
    );
}

fn run() -> Result<()> {
    if std::env::args().nth(1).unwrap_or_default() == "--long-help" {
        longhelp();
        return Ok(());
    }

    let mut cmd = Opt::from_args();

    if cmd.longhelp {
        longhelp();
        return Ok(());
    }

    if false
    //    || cmd.oneshot
    {
        Err("This mode is not implemented")?
    }

    #[cfg(feature="openssl-probe")] {
        openssl_probe::init_ssl_cert_env_vars();
    }

    let mut opts = {
        macro_rules! opts {
            ($($o:ident)*) => {
                Options {
                    $($o : cmd.$o,)*
                }
            };
        }
        opts!(
            websocket_text_mode
            websocket_protocol
            udp_oneshot_mode
            unidirectional
            unidirectional_reverse
            exit_on_eof
            oneshot
            unlink_unix_socket
            exec_args
            ws_c_uri
            linemode_retain_newlines
            origin
            custom_headers
            websocket_version
            websocket_dont_close
            one_message
        )
    };

    let (s1, s2) = if let Some(ref cmds2) = cmd.s2 {
        (spec(&cmd.s1)?, spec(cmds2)?)
    } else {
        if ! (cmd.s1.starts_with("ws://") || cmd.s1.starts_with("wss://")) {
            // TODO: message for -s server mode
            eprintln!("Specify ws:// or wss:// URI to connect to a websocket");
            Err("Invalid command-line parameters")?;
        }
        // Easy mode
        cmd.linemode = true;
        opts.websocket_text_mode = true;
        if opts.websocket_protocol == None {
            opts.websocket_protocol = Some("tcp".to_owned());
        }
        (spec("-")?, spec(&cmd.s1)?)
    };

    let mut websocat = WebsocatConfiguration { opts, s1, s2 };

    if cmd.linemode {
        use websocat::lints::AutoInstallLinemodeConcern::*;
        websocat = match websocat.auto_install_linemode() {
            Ok(x) => x,
            Err((NoWebsocket,_)) => Err("No websocket usage is specified. Use line2msg: and msg2line: specifiers manually if needed.")?,
            Err((MultipleWebsocket,_)) => Err("Multiple websocket usages are specified. Use line2msg: and msg2line: specifiers manually if needed.")?,
            Err((AlreadyLine,_)) => Err("Can't auto-insert msg2line:/line2msg: if you have already manually specified some of them")?,
        }
    }

    while let Some(concern) = websocat.get_concern() {
        use websocat::lints::ConfigurationConcern::*;
        if concern == StdinToStdout {
            if cmd.dumpspec {
                println!("cat mode");
                return Ok(());
            }

            // Degenerate mode: just copy stdin to stdout and call it a day
            ::std::io::copy(&mut ::std::io::stdin(), &mut ::std::io::stdout())?;
            return Ok(());
        }

        if concern == DegenerateMode {
            if cmd.dumpspec {
                println!("noop");
            }
            return Ok(());
        }

        if concern == StdioConflict {
            Err("Too many usages of stdin/stdout")?;
        }

        if concern == NeedsStdioReuser {
            eprintln!("Warning: replies on stdio get directed at random connected client");
            websocat = websocat.auto_install_reuser();
            continue;
        }

        if concern == NeedsStdioReuser2 {
            websocat = websocat.auto_install_reuser();
            continue;
        }

        if concern == MultipleReusers {
            eprintln!("Specifier dump: {:?} {:?}", websocat.s1, websocat.s2);
            Err("Multiple reusers is not allowed")?;
        }
        break;
    }

    if cmd.dumpspec {
        println!("{:?}", websocat.s1);
        println!("{:?}", websocat.s2);
        println!("{:?}", websocat.opts);
        return Ok(());
    }

    let mut core = Core::new()?;

    let prog = websocat.serve(
        core.handle(),
        std::rc::Rc::new(|e| {
            eprintln!("websocat: {}", e);
        }),
    );
    core.run(prog).map_err(|()| "error running".to_string())?;
    Ok(())
}

fn main() {
    env_logger::init();
    let r = run();

    if let Err(e) = r {
        eprintln!("websocat: {}", e);
        ::std::process::exit(1);
    }
}
<|endoftext|>


<commit_before>use std;
use time;
use env_logger;
use portaudio;
use rgsl;

fn scale_step() -> f64 {
  (2.0 as f64).powf(1.0 / 12.0)
}

fn scale_steps(f: f64) -> u32 {
  let ratio = f / 440.0;
  let steps = ratio.log(scale_step());
  steps.round() as u32
}

fn string_err<Ok, Err: std::fmt::Display>(r: Result<Ok, Err>) -> Result<Ok, String> {
  r.map_err(|err| format!("{}", err))
}

fn sine_wave(sample_frequency: f32, start: u32, end: u32) -> Vec<f32> {
  let mut buf = Vec::new();

  let semitones_above_a = 1;

  let f = (440.0 * scale_step().powf(semitones_above_a as f64)) as f32;

  for t in start .. end {
    let t = t as f32 / sample_frequency;
    let sample = (t * f * 2.0 * std::f32::consts::PI).sin();
    let amplitude = 1.0;
    buf.push(sample * amplitude);
  }

  buf
}

fn play_pitch() -> Result<(), String> {
  info!("Writing..");

  let f = 44100;
  let buf_size = 1 << 10;

  let mut stream: portaudio::pa::Stream<f32, f32> = portaudio::pa::Stream::new();
  try!(string_err(
    stream.open_default_blocking(
      f as f64,
      buf_size,
      0,
      1,
      portaudio::pa::SampleFormat::Float32,
    )));
  try!(string_err(stream.start()));

  let start_time = time::precise_time_ns();
  let mut i = 0;
  while time::precise_time_ns() <= start_time + 4_000_000_000 {
    let buf = sine_wave(f as f32, i*buf_size, (i+1)*buf_size);
    assert!(buf.len() == buf_size as usize);
    try!(string_err(stream.write(buf, buf_size)));

    i = i + 1;
  }

  try!(string_err(stream.stop()));

  Ok(())
}

fn detect_pitch() -> Result<(), String> {
  let f = 44100;
  let buf_size = 1 << 10;
  assert!(buf_size & (buf_size - 1) == 0);

  info!("Reading..");

  let mut stream: portaudio::pa::Stream<f32, f32> = portaudio::pa::Stream::new();
  try!(string_err(
    stream.open_default_blocking(
      f as f64,
      buf_size,
      1,
      0,
      portaudio::pa::SampleFormat::Float32,
    )));
  try!(string_err(stream.start()));

  let mut buf = Vec::new();
  let start_time = time::precise_time_ns();
  while time::precise_time_ns() <= start_time + 2_000_000_000 || (buf.len() & (buf.len() - 1)) != 0 {
    let new = try!(string_err(stream.read(buf_size)));
    assert!(new.len () == buf_size as usize);
    buf.extend(new.into_iter().map(|f| f as f64));
  }

  try!(string_err(stream.stop()));

  info!("Collected {} samples", buf.len());

  info!("Pitch detecting..");

  let len = buf.len();
  let r = rgsl::fft::real_radix2::transform(&mut buf, 1, len);
  if r != rgsl::Value::Success {
    return Err(format!("rgsl returned {:?}", r));
  }

  let (max_idx, _max_val) =
    buf.iter()
      .enumerate()
      .take(len / 2)
      .fold((0, 0.0), |(max_idx, max_val), (i, val)| {
        if *val > max_val {
          (i, *val)
        } else {
          (max_idx, max_val)
        }
      });

  info!("Max index is {}", max_idx);
  let f = max_idx as f64 / buf.len() as f64 * f as f64;
  println!("Estimated frequency is {}", f);
  println!("{} semitones away from middle A", scale_steps(f));

  Ok(())
}

fn errorful_main() -> Result<(), String> {
  try!(string_err(env_logger::init()));
  try!(string_err(portaudio::pa::initialize()));

  try!(detect_pitch());

  Ok(())
}

#[main]
fn main() {
  errorful_main().unwrap();
}
<commit_msg>Print human-readable notes<commit_after>use std;
use time;
use env_logger;
use portaudio;
use rgsl;

fn scale_step() -> f64 {
  (2.0 as f64).powf(1.0 / 12.0)
}

fn scale_steps(f: f64) -> i32 {
  let ratio = f / 440.0;
  let steps = ratio.log(scale_step());
  steps.round() as i32
}

fn string_err<Ok, Err: std::fmt::Display>(r: Result<Ok, Err>) -> Result<Ok, String> {
  r.map_err(|err| format!("{}", err))
}

fn sine_wave(sample_frequency: f32, start: u32, end: u32) -> Vec<f32> {
  let mut buf = Vec::new();

  let semitones_above_a = 1;

  let f = (440.0 * scale_step().powf(semitones_above_a as f64)) as f32;

  for t in start .. end {
    let t = t as f32 / sample_frequency;
    let sample = (t * f * 2.0 * std::f32::consts::PI).sin();
    let amplitude = 1.0;
    buf.push(sample * amplitude);
  }

  buf
}

fn play_pitch() -> Result<(), String> {
  info!("Writing..");

  let f = 44100;
  let buf_size = 1 << 10;

  let mut stream: portaudio::pa::Stream<f32, f32> = portaudio::pa::Stream::new();
  try!(string_err(
    stream.open_default_blocking(
      f as f64,
      buf_size,
      0,
      1,
      portaudio::pa::SampleFormat::Float32,
    )));
  try!(string_err(stream.start()));

  let start_time = time::precise_time_ns();
  let mut i = 0;
  while time::precise_time_ns() <= start_time + 4_000_000_000 {
    let buf = sine_wave(f as f32, i*buf_size, (i+1)*buf_size);
    assert!(buf.len() == buf_size as usize);
    try!(string_err(stream.write(buf, buf_size)));

    i = i + 1;
  }

  try!(string_err(stream.stop()));

  Ok(())
}

fn display_note(note: u32) -> &'static str {
  let notes = [
    "A",
    "A#/Bb",
    "B",
    "C",
    "C#/Db",
    "D",
    "D#/Eb",
    "E",
    "F",
    "F#/Gb",
    "G",
    "G#/Ab",
  ];
  notes[note as usize]
}

fn record(sample_frequency: f64) -> Result<Vec<f64>, String> {
  let buf_size = 1 << 10;
  assert!(buf_size & (buf_size - 1) == 0);

  info!("Reading..");

  let mut stream: portaudio::pa::Stream<f32, f32> = portaudio::pa::Stream::new();
  try!(string_err(
    stream.open_default_blocking(
      sample_frequency,
      buf_size,
      1,
      0,
      portaudio::pa::SampleFormat::Float32,
    )));
  try!(string_err(stream.start()));

  let mut buf = Vec::new();
  let start_time = time::precise_time_ns();
  while time::precise_time_ns() <= start_time + 2_000_000_000 || (buf.len() & (buf.len() - 1)) != 0 {
    let new = try!(string_err(stream.read(buf_size)));
    assert!(new.len () == buf_size as usize);
    buf.extend(new.into_iter().map(|f| f as f64));
  }

  try!(string_err(stream.stop()));

  Ok(buf)
}

fn detect_frequency(mut samples: Vec<f64>, timestep: f64) -> Result<f64, String> {
  let len = samples.len();
  let r = rgsl::fft::real_radix2::transform(&mut samples, 1, len);
  if r != rgsl::Value::Success {
    return Err(format!("rgsl returned {:?}", r));
  }

  let (max_idx, _max_val) =
    samples.iter()
      .enumerate()
      .take(len / 2)
      .fold((0, 0.0), |(max_idx, max_val), (i, val)| {
        if *val > max_val {
          (i, *val)
        } else {
          (max_idx, max_val)
        }
      });

  debug!("Max index is {}", max_idx);
  Ok(max_idx as f64 / samples.len() as f64 / timestep)
}

fn human_readable_frequency(f: f64) -> String {
  let scale_steps = scale_steps(f);

  info!("Estimated frequency is {} ({} semitones above middle A)", f, scale_steps);

  let octave = {
    // Octave is decided by the Cs, so make scale_steps relative to C4.
    let scale_steps = scale_steps + 9;
    4 + scale_steps / 12
  };
  let note = {
    let note = scale_steps % 12;
    let note = if note >= 0 { note } else { note + 12 };
    assert!(note >= 0);
    assert!(note < 12);
    note as u32
  };

  let note = display_note(note);

  if octave == 4 {
    format!("middle {} ({}{})", note, note, octave)
  } else {
    format!("{}{}", note, octave)
  }
}

fn detect_pitch() -> Result<(), String> {
  let sample_frequency = 44100.0;
  let samples = try!(record(sample_frequency));

  info!("Collected {} samples", samples.len());

  info!("Detecting pitch..");

  let f = try!(detect_frequency(samples, 1.0 / sample_frequency));

  println!("Estimated note is {}", human_readable_frequency(f));

  Ok(())
}

fn errorful_main() -> Result<(), String> {
  try!(string_err(env_logger::init()));
  try!(string_err(portaudio::pa::initialize()));

  try!(detect_pitch());

  Ok(())
}

#[main]
fn main() {
  errorful_main().unwrap();
}
<|endoftext|>


<commit_before>extern crate iron;
#[macro_use]
extern crate router;
extern crate staticfile;
extern crate mount;
extern crate urlencoded;
extern crate html5ever;
extern crate regex;
extern crate uuid;
extern crate chrono;
extern crate bodyparser;
extern crate serde;
extern crate serde_json;

use std::net::SocketAddrV4;
use std::net::Ipv4Addr;
use std::path::Path;
use iron::prelude::*;
use iron::status;
use iron::mime::Mime;
use staticfile::Static;
use mount::Mount;
use router::{Router};
use urlencoded::UrlEncodedQuery;
use urlencoded::UrlEncodedBody;
use std::str::FromStr;
use uuid::Uuid;

extern crate pink_spider;

use pink_spider::error::Error;
use pink_spider::scraper::extract;
use pink_spider::model::{Model, Track, Playlist, Album, Artist, Entry, Enclosure, Provider, PaginatedCollection};
use pink_spider::get_env;

fn to_err(e: serde_json::Error) -> Error { Error::from(e) }

pub fn index<'a, T: Model<'a>>(req: &mut Request) -> IronResult<Response> {
    let (page, per_page) = pagination_params(req);
    let items            = T::find(page, per_page);
    let body             = try!(serde_json::to_string(&items).map_err(to_err));
    Ok(Response::with((status::Ok, application_json(), body)))
}

pub fn index_entries(req: &mut Request) -> IronResult<Response> {
    pub fn index_entries2(req: &mut Request) -> Result<Response, Error> {
        let (page, per_page) = pagination_params(req);
        let ref params       = try!(req.get_ref::<UrlEncodedQuery>());
        let url              = params.get("url");
        let newer_than       = params.get("newer_than");
        let entries = if let (Some(url), Some(newer_than)) = (url, newer_than) {
            let feed = try!(Feed::find_by_url(&url[0]));
            let newer_than = newer_than[0].parse::<i64>()
                .map(|t| NaiveDateTime::from_timestamp(t, 0)).ok();
            Entry::find_by_feed_id(feed.id, newer_than, page, per_page)
        } else {
            Entry::find(page, per_page)
        };
        let body = try!(serde_json::to_string(&entries).map_err(to_err));
        Ok(Response::with((status::Ok, application_json(), body)))
    }
    index_entries2(req).map_err(|err| IronError::from(err))
}

pub fn index_entries_by_feed(req: &mut Request) -> IronResult<Response> {
    let (page, per_page) = pagination_params(req);
    let ref id           = req.extensions.get::<Router>().unwrap().find("id").unwrap();
    let feed             = try!(Feed::find_by_id(id));
    let entries          = Entry::find_by_feed_id(feed.id, None, page, per_page);
    let body             = try!(serde_json::to_string(&entries).map_err(to_err));
    Ok(Response::with((status::Ok, application_json(), body)))
}

pub fn mget<'a, T: Model<'a>>(req: &mut Request) -> IronResult<Response> {
    let ids              = try!(params_as_uuid_array(req));
    let items            = try!(T::mget(ids));
    let body             = try!(serde_json::to_string(&items).map_err(to_err));
    Ok(Response::with((status::Ok, application_json(), body)))
}

fn params_as_uuid_array(req: &mut Request) -> IronResult<Vec<Uuid>> {
    match req.get::<bodyparser::Json>() {
        Ok(Some(serde_json::Value::Array(ids))) =>
            Ok(ids
               .iter()
               .map(|v| Uuid::parse_str(v.as_str().unwrap_or("")))
               .filter(|opt| opt.is_ok())
               .map(|opt| opt.unwrap())
               .collect()),
        _ => Err(IronError::from(Error::Unprocessable)),
    }
}

pub fn index_by_entry<'a, T: Enclosure<'a>>(req: &mut Request) -> IronResult<Response> {
    let ref entry_id = req.extensions.get::<Router>().unwrap().find("entry_id").unwrap();
    let uuid = try!(Uuid::parse_str(entry_id).map_err(|_| Error::Unprocessable));
    let items = T::find_by_entry_id(uuid);
    let col = PaginatedCollection {
        page:     0,
        per_page: items.len() as i64,
        total:    items.len() as i64,
        items:    items,
    };
    let body = try!(serde_json::to_string(&col).map_err(to_err));
    Ok(Response::with((status::Ok, application_json(), body)))
}

pub fn legacy_playlistify(req: &mut Request) -> IronResult<Response> {
    pub fn playlistify2(req: &mut Request) -> Result<Response, Error> {
        let ref params  = try!(req.get_ref::<UrlEncodedQuery>());
        let url         = try!(params.get("url").ok_or(Error::BadRequest));
        let defaults    = &vec!("false".to_string());
        let force_param = params.get("force").unwrap_or(defaults);
        let force       = force_param.len() > 0 && &force_param[0] == "true";
        let mut entry   = try!(find_or_playlistify_entry(&url[0], force));
        entry.tracks    = entry.tracks
            .iter()
            .filter(|t| t.provider == Provider::YouTube || t.provider == Provider::SoundCloud)
            .map(|t| t.clone())
            .collect();
        let body = try!(serde_json::to_string(&entry).map_err(to_err));
        Ok(Response::with((status::Ok, application_json(), body)))
    }
    playlistify2(req).map_err(|err| IronError::from(err))
}

pub fn playlistify(req: &mut Request) -> IronResult<Response> {
    pub fn playlistify2(req: &mut Request) -> Result<Response, Error> {
        let ref params  = try!(req.get_ref::<UrlEncodedQuery>());
        let url         = try!(params.get("url").ok_or(Error::BadRequest));
        let defaults    = &vec!("false".to_string());
        let force_param = params.get("force").unwrap_or(defaults);
        let force       = force_param.len() > 0 && &force_param[0] == "true";
        let entry       = try!(find_or_playlistify_entry(&url[0], force));
        let body        = try!(serde_json::to_string(&entry).map_err(to_err));
        Ok(Response::with((status::Ok, application_json(), body)))
    }
    playlistify2(req).map_err(|err| IronError::from(err))
}

pub fn find_or_playlistify_entry(url: &str, force: bool) -> Result<Entry, Error> {
    match Entry::find_by_url(url) {
        Ok(mut entry) => {
            println!("Get entry from database cache: {}", url);
            if force {
                println!("Update entry: {}", url);
                try!(entry.playlistify());
                Ok(entry)
            } else {
                Ok(entry)
            }
        },
        Err(_) => {
            let mut entry = try!(Entry::create_by_url(url.to_string()));
            try!(entry.playlistify());
            println!("Create new entry to database cache: {}", url);
            Ok(entry)
        },
    }
}

pub fn update<'a, T: Enclosure<'a>>(req: &mut Request) -> IronResult<Response> {
    let mut enclosure = try!(T::find_by_id(&query_as_string(req, "id")));
    try!(enclosure.fetch_props());
    try!(enclosure.save());
    let body = try!(serde_json::to_string(&enclosure).map_err(to_err));
    Ok(Response::with((status::Ok, application_json(), body)))
}

pub fn show<'a, T: Enclosure<'a>>(req: &mut Request) -> IronResult<Response> {
    let provider   = req.extensions.get::<Router>().unwrap().find("provider").unwrap();
    let identifier = req.extensions.get::<Router>().unwrap().find("id").unwrap();
    let p = &Provider::new(provider.to_string());
    let enclosure = try!(T::find_by(p, identifier));
    let body      = try!(serde_json::to_string(&enclosure).map_err(to_err));
    Ok(Response::with((status::Ok, application_json(), body)))
}

pub fn show_by_id<'a, T: Model<'a>>(req: &mut Request) -> IronResult<Response> {
    let ref id = req.extensions.get::<Router>().unwrap().find("id").unwrap();
    let enclosure = try!(T::find_by_id(id));
    let body      = try!(serde_json::to_string(&enclosure).map_err(to_err));
    Ok(Response::with((status::Ok, application_json(), body)))
}

pub fn create<'a, T: Enclosure<'a>>(req: &mut Request) -> IronResult<Response> {
    let identifier     = try!(param_as_string(req, "identifier").ok_or(Error::BadRequest));
    let provider       = try!(param_as_string(req, "provider").ok_or(Error::BadRequest));
    let owner_id       = param_as_string(req, "owner_id");
    let url            = param_as_string(req, "url");
    let p              = Provider::new(provider.to_string());
    let mut enclosure  = try!(T::find_or_create(p, identifier.to_string()));
    enclosure.set_owner_id(owner_id);
    if let Some(url) = url {
        enclosure.set_url(url);
    }
    try!(enclosure.fetch_props());
    try!(enclosure.save());
    let body = try!(serde_json::to_string(&enclosure).map_err(to_err));
    Ok(Response::with((status::Ok, application_json(), body)))
}

fn param_as_string(req: &mut Request, key: &str) -> Option<String> {
    match req.get_ref::<UrlEncodedBody>() {
        Ok(ref params) => match params.get(key) {
            Some(val) => Some(val[0].clone()),
            None      => None
        },
        Err(_) => None
    }
}

fn query_as_string(req: &mut Request, key: &str) -> String {
    return req.extensions.get::<Router>().unwrap()
        .find(key).unwrap().to_string();
}

fn pagination_params(req: &mut Request) -> (i64, i64) {
    match req.get_ref::<UrlEncodedQuery>() {
        Ok(ref params) =>
            (params.get("page").unwrap()[0].to_string().parse::<i64>().unwrap(),
             params.get("per_page").unwrap()[0].to_string().parse::<i64>().unwrap()),
        Err(_) =>
            (0, 10)
    }
}

fn application_json() -> Mime {
    Mime::from_str("application/json").ok().unwrap()
}

pub fn main() {
    let path = Path::new("public");
    let mut mount = Mount::new();
    mount.mount("/web/", Static::new(Path::new(path)));
    let router = router!(
        web:                      get  "/*"                        => mount,
        legacy_playlistify:       get  "/playlistify"                    => legacy_playlistify,
        playlistify:              get  "/v1/playlistify"                 => playlistify,
        index_entries:            get  "/v1/entries"                     => index_entries,
        index_artists:            get  "/v1/artists"                     => index::<Artist>,
        mget_artists:             post "/v1/artists/.mget"               => mget::<Artist>,

        show_track_by_id:         get  "/v1/tracks/:id"                  => show_by_id::<Track>,
        show_track:               get  "/v1/tracks/:provider/:id"        => show::<Track>,
        mget_tracks:              post "/v1/tracks/.mget"                => mget::<Track>,
        create_track:             post "/v1/tracks"                      => create::<Track>,
        update_track:             post "/v1/tracks/:id"                  => update::<Track>,
        index_tracks:             get  "/v1/tracks"                      => index::<Track>,
        index_tracks_by_entry:    get  "/v1/entries/:entry_id/tracks"    => index_by_entry::<Track>,

        show_playlist_by_id:      get  "/v1/playlists/:id"               => show_by_id::<Playlist>,
        show_playlist:            get  "/v1/playlists/:provider/:id"     => show::<Playlist>,
        create_playlist:          post "/v1/playlists"                   => create::<Playlist>,
        update_playlist:          post "/v1/playlists/:id"               => update::<Playlist>,
        mget_playlists:           post "/v1/playlists/.mget"             => mget::<Playlist>,
        index_playlists:          get  "/v1/playlists"                   => index::<Playlist>,
        index_playlists_by_entry: get  "/v1/entries/:entry_id/playlists" => index_by_entry::<Playlist>,

        show_album_by_id:         get  "/v1/albums/:id"                  => show_by_id::<Album>,
        show_album:               get  "/v1/albums/:provider/:id"        => show::<Album>,
        mget_albums:              post "/v1/albums/.mget"                => mget::<Album>,
        create_album:             post "/v1/albums"                      => create::<Album>,
        update_album:             post "/v1/albums/:id"                  => update::<Album>,
        index_albums:             get  "/v1/albums"                      => index::<Album>,
        index_albums_by_entry:    get  "/v1/entries/:entry_id/albums"    => index_by_entry::<Album>,
    );
    let port_str = match get_env::var("PORT") {
        Some(n) => n,
        None    => "8080".to_string()
    };
    let port: u16 = match port_str.trim().parse() {
        Ok(n) => n,
        Err(_) => {
            println!("Faild to parse port");
            return;
        }
    };
    println!("PORT {}", port_str);
    let ip = Ipv4Addr::new(0, 0, 0, 0);
    Iron::new(router).http(SocketAddrV4::new(ip, port)).unwrap();
}
<commit_msg>Update pagination_params(): Set default per page if it is not specified<commit_after>extern crate iron;
#[macro_use]
extern crate router;
extern crate staticfile;
extern crate mount;
extern crate urlencoded;
extern crate html5ever;
extern crate regex;
extern crate uuid;
extern crate chrono;
extern crate bodyparser;
extern crate serde;
extern crate serde_json;

use std::net::SocketAddrV4;
use std::net::Ipv4Addr;
use std::path::Path;
use iron::prelude::*;
use iron::status;
use iron::mime::Mime;
use staticfile::Static;
use mount::Mount;
use router::{Router};
use urlencoded::UrlEncodedQuery;
use urlencoded::UrlEncodedBody;
use std::str::FromStr;
use uuid::Uuid;

extern crate pink_spider;

use pink_spider::error::Error;
use pink_spider::scraper::extract;
use pink_spider::model::{Model, Track, Playlist, Album, Artist, Entry, Enclosure, Provider, PaginatedCollection};
use pink_spider::get_env;

const DEFAULT_PER_PAGE: i64 = 25;

fn to_err(e: serde_json::Error) -> Error { Error::from(e) }

pub fn index<'a, T: Model<'a>>(req: &mut Request) -> IronResult<Response> {
    let (page, per_page) = pagination_params(req);
    let items            = T::find(page, per_page);
    let body             = try!(serde_json::to_string(&items).map_err(to_err));
    Ok(Response::with((status::Ok, application_json(), body)))
}

pub fn index_entries(req: &mut Request) -> IronResult<Response> {
    pub fn index_entries2(req: &mut Request) -> Result<Response, Error> {
        let (page, per_page) = pagination_params(req);
        let ref params       = try!(req.get_ref::<UrlEncodedQuery>());
        let url              = params.get("url");
        let newer_than       = params.get("newer_than");
        let entries = if let (Some(url), Some(newer_than)) = (url, newer_than) {
            let feed = try!(Feed::find_by_url(&url[0]));
            let newer_than = newer_than[0].parse::<i64>()
                .map(|t| NaiveDateTime::from_timestamp(t, 0)).ok();
            Entry::find_by_feed_id(feed.id, newer_than, page, per_page)
        } else {
            Entry::find(page, per_page)
        };
        let body = try!(serde_json::to_string(&entries).map_err(to_err));
        Ok(Response::with((status::Ok, application_json(), body)))
    }
    index_entries2(req).map_err(|err| IronError::from(err))
}

pub fn index_entries_by_feed(req: &mut Request) -> IronResult<Response> {
    let (page, per_page) = pagination_params(req);
    let ref id           = req.extensions.get::<Router>().unwrap().find("id").unwrap();
    let feed             = try!(Feed::find_by_id(id));
    let entries          = Entry::find_by_feed_id(feed.id, None, page, per_page);
    let body             = try!(serde_json::to_string(&entries).map_err(to_err));
    Ok(Response::with((status::Ok, application_json(), body)))
}

pub fn mget<'a, T: Model<'a>>(req: &mut Request) -> IronResult<Response> {
    let ids              = try!(params_as_uuid_array(req));
    let items            = try!(T::mget(ids));
    let body             = try!(serde_json::to_string(&items).map_err(to_err));
    Ok(Response::with((status::Ok, application_json(), body)))
}

fn params_as_uuid_array(req: &mut Request) -> IronResult<Vec<Uuid>> {
    match req.get::<bodyparser::Json>() {
        Ok(Some(serde_json::Value::Array(ids))) =>
            Ok(ids
               .iter()
               .map(|v| Uuid::parse_str(v.as_str().unwrap_or("")))
               .filter(|opt| opt.is_ok())
               .map(|opt| opt.unwrap())
               .collect()),
        _ => Err(IronError::from(Error::Unprocessable)),
    }
}

pub fn index_by_entry<'a, T: Enclosure<'a>>(req: &mut Request) -> IronResult<Response> {
    let ref entry_id = req.extensions.get::<Router>().unwrap().find("entry_id").unwrap();
    let uuid = try!(Uuid::parse_str(entry_id).map_err(|_| Error::Unprocessable));
    let items = T::find_by_entry_id(uuid);
    let col = PaginatedCollection {
        page:     0,
        per_page: items.len() as i64,
        total:    items.len() as i64,
        items:    items,
    };
    let body = try!(serde_json::to_string(&col).map_err(to_err));
    Ok(Response::with((status::Ok, application_json(), body)))
}

pub fn legacy_playlistify(req: &mut Request) -> IronResult<Response> {
    pub fn playlistify2(req: &mut Request) -> Result<Response, Error> {
        let ref params  = try!(req.get_ref::<UrlEncodedQuery>());
        let url         = try!(params.get("url").ok_or(Error::BadRequest));
        let defaults    = &vec!("false".to_string());
        let force_param = params.get("force").unwrap_or(defaults);
        let force       = force_param.len() > 0 && &force_param[0] == "true";
        let mut entry   = try!(find_or_playlistify_entry(&url[0], force));
        entry.tracks    = entry.tracks
            .iter()
            .filter(|t| t.provider == Provider::YouTube || t.provider == Provider::SoundCloud)
            .map(|t| t.clone())
            .collect();
        let body = try!(serde_json::to_string(&entry).map_err(to_err));
        Ok(Response::with((status::Ok, application_json(), body)))
    }
    playlistify2(req).map_err(|err| IronError::from(err))
}

pub fn playlistify(req: &mut Request) -> IronResult<Response> {
    pub fn playlistify2(req: &mut Request) -> Result<Response, Error> {
        let ref params  = try!(req.get_ref::<UrlEncodedQuery>());
        let url         = try!(params.get("url").ok_or(Error::BadRequest));
        let defaults    = &vec!("false".to_string());
        let force_param = params.get("force").unwrap_or(defaults);
        let force       = force_param.len() > 0 && &force_param[0] == "true";
        let entry       = try!(find_or_playlistify_entry(&url[0], force));
        let body        = try!(serde_json::to_string(&entry).map_err(to_err));
        Ok(Response::with((status::Ok, application_json(), body)))
    }
    playlistify2(req).map_err(|err| IronError::from(err))
}

pub fn find_or_playlistify_entry(url: &str, force: bool) -> Result<Entry, Error> {
    match Entry::find_by_url(url) {
        Ok(mut entry) => {
            println!("Get entry from database cache: {}", url);
            if force {
                println!("Update entry: {}", url);
                try!(entry.playlistify());
                Ok(entry)
            } else {
                Ok(entry)
            }
        },
        Err(_) => {
            let mut entry = try!(Entry::create_by_url(url.to_string()));
            try!(entry.playlistify());
            println!("Create new entry to database cache: {}", url);
            Ok(entry)
        },
    }
}

pub fn update<'a, T: Enclosure<'a>>(req: &mut Request) -> IronResult<Response> {
    let mut enclosure = try!(T::find_by_id(&query_as_string(req, "id")));
    try!(enclosure.fetch_props());
    try!(enclosure.save());
    let body = try!(serde_json::to_string(&enclosure).map_err(to_err));
    Ok(Response::with((status::Ok, application_json(), body)))
}

pub fn show<'a, T: Enclosure<'a>>(req: &mut Request) -> IronResult<Response> {
    let provider   = req.extensions.get::<Router>().unwrap().find("provider").unwrap();
    let identifier = req.extensions.get::<Router>().unwrap().find("id").unwrap();
    let p = &Provider::new(provider.to_string());
    let enclosure = try!(T::find_by(p, identifier));
    let body      = try!(serde_json::to_string(&enclosure).map_err(to_err));
    Ok(Response::with((status::Ok, application_json(), body)))
}

pub fn show_by_id<'a, T: Model<'a>>(req: &mut Request) -> IronResult<Response> {
    let ref id = req.extensions.get::<Router>().unwrap().find("id").unwrap();
    let enclosure = try!(T::find_by_id(id));
    let body      = try!(serde_json::to_string(&enclosure).map_err(to_err));
    Ok(Response::with((status::Ok, application_json(), body)))
}

pub fn create<'a, T: Enclosure<'a>>(req: &mut Request) -> IronResult<Response> {
    let identifier     = try!(param_as_string(req, "identifier").ok_or(Error::BadRequest));
    let provider       = try!(param_as_string(req, "provider").ok_or(Error::BadRequest));
    let owner_id       = param_as_string(req, "owner_id");
    let url            = param_as_string(req, "url");
    let p              = Provider::new(provider.to_string());
    let mut enclosure  = try!(T::find_or_create(p, identifier.to_string()));
    enclosure.set_owner_id(owner_id);
    if let Some(url) = url {
        enclosure.set_url(url);
    }
    try!(enclosure.fetch_props());
    try!(enclosure.save());
    let body = try!(serde_json::to_string(&enclosure).map_err(to_err));
    Ok(Response::with((status::Ok, application_json(), body)))
}

fn param_as_string(req: &mut Request, key: &str) -> Option<String> {
    match req.get_ref::<UrlEncodedBody>() {
        Ok(ref params) => match params.get(key) {
            Some(val) => Some(val[0].clone()),
            None      => None
        },
        Err(_) => None
    }
}

fn query_as_string(req: &mut Request, key: &str) -> String {
    return req.extensions.get::<Router>().unwrap()
        .find(key).unwrap().to_string();
}

fn pagination_params(req: &mut Request) -> (i64, i64) {
    match req.get_ref::<UrlEncodedQuery>() {
        Ok(ref params) => {
            let page = params.get("page")
                             .and_then(|v| v[0].to_string().parse::<i64>().ok())
                             .unwrap_or(0);
            let per_page = params.get("per_page")
                                 .and_then(|v| v[0].to_string().parse::<i64>().ok())
                                 .unwrap_or(DEFAULT_PER_PAGE);
            (page, per_page)
        },
        Err(_) => (0, DEFAULT_PER_PAGE)
    }
}

fn application_json() -> Mime {
    Mime::from_str("application/json").ok().unwrap()
}

pub fn main() {
    let path = Path::new("public");
    let mut mount = Mount::new();
    mount.mount("/web/", Static::new(Path::new(path)));
    let router = router!(
        web:                      get  "/*"                        => mount,
        legacy_playlistify:       get  "/playlistify"                    => legacy_playlistify,
        playlistify:              get  "/v1/playlistify"                 => playlistify,
        index_entries:            get  "/v1/entries"                     => index_entries,
        index_artists:            get  "/v1/artists"                     => index::<Artist>,
        mget_artists:             post "/v1/artists/.mget"               => mget::<Artist>,

        show_track_by_id:         get  "/v1/tracks/:id"                  => show_by_id::<Track>,
        show_track:               get  "/v1/tracks/:provider/:id"        => show::<Track>,
        mget_tracks:              post "/v1/tracks/.mget"                => mget::<Track>,
        create_track:             post "/v1/tracks"                      => create::<Track>,
        update_track:             post "/v1/tracks/:id"                  => update::<Track>,
        index_tracks:             get  "/v1/tracks"                      => index::<Track>,
        index_tracks_by_entry:    get  "/v1/entries/:entry_id/tracks"    => index_by_entry::<Track>,

        show_playlist_by_id:      get  "/v1/playlists/:id"               => show_by_id::<Playlist>,
        show_playlist:            get  "/v1/playlists/:provider/:id"     => show::<Playlist>,
        create_playlist:          post "/v1/playlists"                   => create::<Playlist>,
        update_playlist:          post "/v1/playlists/:id"               => update::<Playlist>,
        mget_playlists:           post "/v1/playlists/.mget"             => mget::<Playlist>,
        index_playlists:          get  "/v1/playlists"                   => index::<Playlist>,
        index_playlists_by_entry: get  "/v1/entries/:entry_id/playlists" => index_by_entry::<Playlist>,

        show_album_by_id:         get  "/v1/albums/:id"                  => show_by_id::<Album>,
        show_album:               get  "/v1/albums/:provider/:id"        => show::<Album>,
        mget_albums:              post "/v1/albums/.mget"                => mget::<Album>,
        create_album:             post "/v1/albums"                      => create::<Album>,
        update_album:             post "/v1/albums/:id"                  => update::<Album>,
        index_albums:             get  "/v1/albums"                      => index::<Album>,
        index_albums_by_entry:    get  "/v1/entries/:entry_id/albums"    => index_by_entry::<Album>,
    );
    let port_str = match get_env::var("PORT") {
        Some(n) => n,
        None    => "8080".to_string()
    };
    let port: u16 = match port_str.trim().parse() {
        Ok(n) => n,
        Err(_) => {
            println!("Faild to parse port");
            return;
        }
    };
    println!("PORT {}", port_str);
    let ip = Ipv4Addr::new(0, 0, 0, 0);
    Iron::new(router).http(SocketAddrV4::new(ip, port)).unwrap();
}
<|endoftext|>


<commit_before>// Import the Ordering Enum from the Rust Standard Library
// http://doc.rust-lang.org/std/cmp/enum.Ordering.html
// Note: Enums are a powerful tool for data representation and 'generics' may be used
// to make Enums generic across Types to become even more powerful.
// Ordering Enum form used for Comparisons
// enum Ordering {
//   Less,
//   Equal,
//   Greater,
// }
// :: Symbol indicates a Namespace
// 'std' Module contains Sub-Module 'cmp' containing Sub-Sub-Module 'Ordering'
// The Enum Variants (Equal, Less, Greater) have been imported instead of just the Ordering
// Namespace itself to achieve compactness and convenience. This avoids full scoping and
// avoids long notation (i.e. use just Equal instead of Ordering::Equal), however name conflicts
// may arise (so it is best practice to import and apply the Namespace combined with a
// Variants together)
use std::cmp::Ordering;

// Configure the Ordering Enum
// 'cmp' is a Function that compares two given parameters and returns an Ordering
// where depending on the difference between these parameters, the returned Ordering
// may be Ordering:Less, Ordering::Greater, or Ordering::Equal
// Variants of the Enum (Ordering) are Namespaced under the Enum itself.
fn cmp(a: i32, b: i32) -> Ordering {
  if a < b      { Ordering::Less }
  else if a > b { Ordering::Greater }
  else          { Ordering::Equal }
}

/*
  Rust is an Expression-Based Systems language.
  Declare main function
*/
fn main() {

    // Metaprogramming calling a macro and passing staticaly allocated string arg
    println!("Hello, world!");

    /*
      Variable binding expression.
      <let expression> is Full Pattern for Pattern Matching.
      Rust's Type Inference automatically determines an expression's Type.
      Alternatively be explicit and supply an expression's Type after a colon.
      Or simply annotate the Type in a comment to understand the Type Rust infers.
      Rust Bindings are immutable by Default.
      Mutable Bindings require 'mut' prefix for Type Safety.
    */
    let a: i32 = 5; // assign immutable binding 'a' with Type i32 and Value 5

    // If statement based on Branch concept
    if a == 5 {
      println!("x is five");
    } else {
      println!("x is not five");
    }

    let (x, y, z) = (1, 2, 3);  // assign immutable bindings x, y, z to 1, 2, 3

    let mut b: i32 = 10; // assign mutable binding 'b'
    b = 20; // re-assign to new Value

    /*
      Rust's 'If' is an Expression. It returns a value to initialise
      the 'Let' binding ("Declaration Statement") with. 'Let' is assigned an Expression.
      Assignment to an already bound variable is an Expression.
      Assignment Value in Rust is the special Unit Type () in Rust's Type System.
      In other languages 'If' is a Statements (does not return value).

      Rust's "Expression Statement" converts an Expression into a Statement.
      Semi-colons separate each Expression.
      Semi-colons convert Expression into Statement, throws Value away, returns Unit Type ()
      (causing Type Error when expect a different Type such as i32 to be valid)
    */
    let c: i32 = if b == 20 { 25 } else { 15 };  // Explicitely specify 'c' as of Integer Type
    println!("b is: {}", b); // Interpret interpolation with moustaches
    println!("c is: {}", c);

    incr(b, c); // Call Fn passing Args
    print_sum(b, c); // Call Fn passing Args

    // Compound Data Structure Type Tuple is simple fixed size ordered list where &str is String Slice
    let tuple1: (i32, &str) = (1, "hello"); // Mutable. Type annotated. Without: let x = (1, "hello");
    let mut tuple2: (i32, i32) = (1, 2); // Type annotated. Without: let x = (1, "hello");
    let tuple3: (i32, i32) = (3, 4);

    // Note that for a Tuple with a Single value the trailing commas are mandatory
    let (x,): (i32,) = (1,);

    if tuple2 != tuple3 {
        tuple2 = tuple3; // Assign Tuple to another Mutable Tuple (with same Arity and Types)
        println!("tuple2 and tuple3 not equal so assigning");
    } else {
        println!("tuple2 and tuple3 do not have same Arity, Types, Order, and Value, not assigning");
    }

    /*
      Destructuring Let (access parameters of Tuple).
      Let statement performs Multiple Bindings assignments when LHS and RHS Pattern Match
    */
    let (t1, t2) = tuple2;

    println!("t1 and t2 is {}", t1 + t2); // Note: Expects t1 and t2 to be same Type

    // Tuples to return Multiple Values from a Function
    let (tnt1, tnt2) = next_two(5);
    println!("tnt1, tnt2 = {}, {}", tnt1, tnt2);

    try_structs();

    try_tuple_structs();

    try_newtype();

    try_enums();

    try_pattern_matching();

    let n: i32 = 4;
    let mut o: i32 = 0;

    o = try_loops(n);

    println!("o is {}", o);

    // String Slices (aka String Literals) of Type &str are Statically Allocated (i.e. saved inside compiled program
    // and existing for entire run duration). The have fixed size and cannot be mutated (i.e. let mut).
    // stringLiteral is a binding reference to another string that is the Statically Allocated String Slice.
    let mut stringLiteral: &str = "String Slice / String Literal"; // Should not be able to declare as 'let mut'
    // In-Memory Strings (formerly StrBuf) allocate memorary and control their data. They cannot be converted into
    // the equivalent of a &'static str (Static String) like a &str, as In-Memory Strings are not pre-configured
    // to live for the entire lifetime of the compiled program like &str. They can infact be converted from String
    // into a slice &'a str by using the as_slice() method (retaining its original String lifetime)
    let mut stringInMemory: String = "In-Memory String".to_string();

    stringLiteral = try_strings(stringLiteral, stringInMemory);

    println!("stringLiteral is {}", stringLiteral);

}

/*
  Rust Structs are of Record Type form similar to Tuples.
  Elements in Structs each have a Name (aka Field/Member) and a Type
*/

// Declare a Struct with a name (camel case). Values Immutable by Default
struct PointInSpace {
    x: i32,
    y: i32
}

fn try_structs() {
  // Create Instance (Mutable) of Struct using Let and set each Field (any order)
  let mut origin = PointInSpace { x: 0, y: 0 }; // origin: PointInSpace

  origin.x = 20;

  println!("Origin is at ({}, {})", origin.x, origin.y); // Dot Notation to access Fields
}

/*
  Rust Tuple Structs are a hybrid data type similar to Tuple and Struct.
  Elements in Tuple Structs DO NOT have a Name, they only have a Type.
  Structs are preferred over Tuple Structs since they have actual Names for Elements.
  Note: Tuple Structs must use round brackets and colon
*/

struct Color (
  i32,
  i32,
  i32
);

struct PointInWater (
  i32,
  i32,
  i32
);

fn try_tuple_structs() {
  let black = Color(0, 0, 0);
  let origin = PointInWater(0, 0, 0);
}

// Declare a Newtype.
struct Inches (i32);

// Newtypes are Tuple Structs with only One Element. Beneficial for creating
// New Types similar to others (Cloning)
fn try_newtype() {
  let length = Inches(10);
  // Extract inner Integer Type by Desctructing the Let
  let Inches(integer_length) = length; // Assigns length to integer_length
  println!("Newtype length is {} inches", integer_length);
}

// Enums variants are a "Sum Type" that ties a set of alternatives to a specific name
fn try_enums() {
  // Define a Character to be either a Digit or Other. The alternative names may be
  // used via their fully scoped names i.e. Character::Other
  // Sub-datastructure types allowable in an Enum include Structs, Tuple Structs
  // Enums do not have access to operators: ==, !=, *, +, <, >=

  enum Character {
    Digit(i32), // Character::Digit is a name tied to an i32
    Missing, // Missing is just a name (not tied to a specific Type)
  }

  // Assignment
  let a  = Character::Digit(10);
  let b = Character::Missing;

  // Retrieve values contained in Enums, Error Handling where function output does not
  // match the expected Type
  match a {
    Character::Digit(n) => print!("\na is {} ", n),
    Character::Missing => print!("\na is missing"),
  }

  match b {
    Character::Digit(n) => print!("\nb is {}", n),
    Character::Missing => print!("\nb is missing"),
  }

  let x = 5;
  let y = 10;

  // // 'ordering' variable is of Ordering type (ordering: Ordering)
  // // so it contains one of the three values defined in the 'cmp' Function
  // // and we discover which one by using Conditional Operators to check
  // let ordering = cmp(x, y);

  // if ordering == Ordering::Less { println!("Less"); }
  // else if ordering == Ordering::Greater { println!("Greater"); }
  // else if ordering == Ordering::Equal { println!("Equal"); }

  // Replace the above 'if/else' with 'match' Pattern Matching expression instead
  // with less noise and which supports Exhaustiveness Checking across all
  // possible Variants of the Ordering Enum
  println!("{}", match cmp(x, y) {
    Ordering::Less => "\nless",
    Ordering::Greater => "\ngreater",
    Ordering::Equal => "\nequal",
  });

  // Equivalent to the above
  match cmp(x, y) {
    Ordering::Less => println!("\nless"),
    Ordering::Greater => println!("\ngreater"),
    Ordering::Equal => println!("\nequal"),
  };
}

// Pattern Matching is implemented by 'match' and allows elegantly deconstructing Enums
// (known as the Sum Type in Type Theory) whilst using the 'match' keyword
// instead of avoiding 'if/else' (for multiple or a complex set of option cases)
fn try_pattern_matching() {
  let x = 5;

  // 'match' takes Expression and branches into Arms depending on its Value.
  // Evaluation is performed only on the matching Arm.
  match x {
    // Arms are of the form 'val => expression'
    1 => println!("one"),
    2 => println!("two"),
    3 => println!("three"),
    4 => println!("four"),
    5 => println!("five"),
    // Exhaustiveness Checking ensures all possible patterns of Values are covered
    // with the '_' Catch-all- Arm so if any Expression used that were not included
    // (not all bases covered) it prevents a compile error (as '_' will match)
    _ => println!("something else"),
  }
}

fn try_loops(n: i32) -> (i32) {
  let mut o = 0;
  // For Loop with variable m over Iterator Expression 0..n (with start and end positions)
  // that produces a series of elements where each element is a loop itertion fetched from
  // the Iterator and bound to the variable m during each cycle through the loop body.
  // The Iterator is upper bound exclusive and so prints 0 through to n-1

  for m in 0..n {
    if m % 2 == 0 { continue; } // Approval condition only processes even iterations.
    println!("for loop with: {}", m);
    o += m;
  }

  let mut done: bool = false;

  println!("{}", o);

  while !done {
    o += o - 2;
    println!("while loop with: {}", o);
    if o % 3 == 0 { done = true; }
  }

  // Infinite Loop intentionally
  loop { // Use this instead of while true {}
    o -= 1;
    if o % 7 == 0 { break; } // End iteration early
  }

  return o;
}

// Strings are a re-sizable Data Structure.
// String is a sequence of Unicode scalar values validly encoded as a stream of UTF-8 bytes.
// Strings may contain null bytes (as they are not null-terminated)

fn try_strings(s_l: &str, s_m: String) -> &str {

  let mut _s_m: String = s_m; // Declare s_m as a mutable local variable _s_m

  let mut _s: String = s_l.to_string();
  _s.push_str(", is a growable string and is guaranteed to be UTF-8");
  println!("{}", _s);

  // Function to Convert Type &str into Type String (cheap solution that allocates it to memory)
  fn convert_to_string_in_memory_taking_string_in_memory(memory_string: String) {
    let memory_string_slice: &str = memory_string.as_slice();
    println!("Converted Type &str (String Slice / Literal) into Type String (In-Memory String): {}", memory_string_slice);
  }

  // Coerce Type &str into Type String
  convert_to_string_in_memory_taking_string_in_memory(_s_m);

  // Function to Convert Type String into Type &str
  fn convert_to_string_literal_taking_string_slice(slice: &str) {
    println!("Converted Type String (In-Memory String) into Type &str (String Slice / Literal): {}", slice);
  }

  // Coerce Type String into Type &str by prefixing with an & symbol
  convert_to_string_literal_taking_string_slice(&_s);

  // The following attempt to perform the same conversion with the parameter passed into the function gives error:
  //   - error: use of moved value: `s_m`
  //   - note: `s_m` moved here because it has type `collections::string::String`, which is moved by default
  //   - use `ref` to override

  // let mut _s_m2: String = s_m.to_string(); // Declare s_m as a mutable local variable _s_m

  // convert_to_string_literal_taking_string_slice(&_s_m2);

  return s_l;
}

// Returned Tuple is a Single Value (containing Multiple Values)
fn next_two(x: i32) -> (i32, i32) { (x + 1, x + 2) }

// All control paths must Return a Value
fn incr(m: i32, n: i32) -> i32 {
    if n < m {
      return n; // Early Return
    } else {
      println!("incrementing n from: {}", n);
      return n + 10;
    }
}

/*
  Rust forces Declare expected Type of incoming Fn Args. Type Inference in Fn body.
  Rust allows Declaration expected Type of outgoing Return Value after '->'
*/
fn print_sum(m: i32, n: i32) -> () { // Return the Unit Type () (aka nil)
    if m < n {
      println!("sum with m < n is: {}", m + n);
    } else {
      println!("sum with m >= n is: {}", m + n);
    }
}<commit_msg>Minor formatting fix<commit_after>// Import the Ordering Enum from the Rust Standard Library
// http://doc.rust-lang.org/std/cmp/enum.Ordering.html
// Note: Enums are a powerful tool for data representation and 'generics' may be used
// to make Enums generic across Types to become even more powerful.
// Ordering Enum form used for Comparisons
// enum Ordering {
//   Less,
//   Equal,
//   Greater,
// }
// :: Symbol indicates a Namespace
// 'std' Module contains Sub-Module 'cmp' containing Sub-Sub-Module 'Ordering'
// The Enum Variants (Equal, Less, Greater) have been imported instead of just the Ordering
// Namespace itself to achieve compactness and convenience. This avoids full scoping and
// avoids long notation (i.e. use just Equal instead of Ordering::Equal), however name conflicts
// may arise (so it is best practice to import and apply the Namespace combined with a
// Variants together)
use std::cmp::Ordering;

// Configure the Ordering Enum
// 'cmp' is a Function that compares two given parameters and returns an Ordering
// where depending on the difference between these parameters, the returned Ordering
// may be Ordering:Less, Ordering::Greater, or Ordering::Equal
// Variants of the Enum (Ordering) are Namespaced under the Enum itself.
fn cmp(a: i32, b: i32) -> Ordering {
  if a < b      { Ordering::Less }
  else if a > b { Ordering::Greater }
  else          { Ordering::Equal }
}

/*
  Rust is an Expression-Based Systems language.
  Declare main function
*/
fn main() {

    // Metaprogramming calling a macro and passing staticaly allocated string arg
    println!("Hello, world!");

    /*
      Variable binding expression.
      <let expression> is Full Pattern for Pattern Matching.
      Rust's Type Inference automatically determines an expression's Type.
      Alternatively be explicit and supply an expression's Type after a colon.
      Or simply annotate the Type in a comment to understand the Type Rust infers.
      Rust Bindings are immutable by Default.
      Mutable Bindings require 'mut' prefix for Type Safety.
    */
    let a: i32 = 5; // assign immutable binding 'a' with Type i32 and Value 5

    // If statement based on Branch concept
    if a == 5 {
      println!("x is five");
    } else {
      println!("x is not five");
    }

    let (x, y, z) = (1, 2, 3);  // assign immutable bindings x, y, z to 1, 2, 3

    let mut b: i32 = 10; // assign mutable binding 'b'
    b = 20; // re-assign to new Value

    /*
      Rust's 'If' is an Expression. It returns a value to initialise
      the 'Let' binding ("Declaration Statement") with. 'Let' is assigned an Expression.
      Assignment to an already bound variable is an Expression.
      Assignment Value in Rust is the special Unit Type () in Rust's Type System.
      In other languages 'If' is a Statements (does not return value).

      Rust's "Expression Statement" converts an Expression into a Statement.
      Semi-colons separate each Expression.
      Semi-colons convert Expression into Statement, throws Value away, returns Unit Type ()
      (causing Type Error when expect a different Type such as i32 to be valid)
    */
    let c: i32 = if b == 20 { 25 } else { 15 };  // Explicitely specify 'c' as of Integer Type
    println!("b is: {}", b); // Interpret interpolation with moustaches
    println!("c is: {}", c);

    incr(b, c); // Call Fn passing Args
    print_sum(b, c); // Call Fn passing Args

    // Compound Data Structure Type Tuple is simple fixed size ordered list where &str is String Slice
    let tuple1: (i32, &str) = (1, "hello"); // Mutable. Type annotated. Without: let x = (1, "hello");
    let mut tuple2: (i32, i32) = (1, 2); // Type annotated. Without: let x = (1, "hello");
    let tuple3: (i32, i32) = (3, 4);

    // Note that for a Tuple with a Single value the trailing commas are mandatory
    let (x,): (i32,) = (1,);

    if tuple2 != tuple3 {
        tuple2 = tuple3; // Assign Tuple to another Mutable Tuple (with same Arity and Types)
        println!("tuple2 and tuple3 not equal so assigning");
    } else {
        println!("tuple2 and tuple3 do not have same Arity, Types, Order, and Value, not assigning");
    }

    /*
      Destructuring Let (access parameters of Tuple).
      Let statement performs Multiple Bindings assignments when LHS and RHS Pattern Match
    */
    let (t1, t2) = tuple2;

    println!("t1 and t2 is {}", t1 + t2); // Note: Expects t1 and t2 to be same Type

    // Tuples to return Multiple Values from a Function
    let (tnt1, tnt2) = next_two(5);
    println!("tnt1, tnt2 = {}, {}", tnt1, tnt2);

    try_structs();

    try_tuple_structs();

    try_newtype();

    try_enums();

    try_pattern_matching();

    let n: i32 = 4;
    let mut o: i32 = 0;

    o = try_loops(n);

    println!("o is {}", o);

    // String Slices (aka String Literals) of Type &str are Statically Allocated (i.e. saved inside compiled program
    // and existing for entire run duration). The have fixed size and cannot be mutated (i.e. let mut).
    // stringLiteral is a binding reference to another string that is the Statically Allocated String Slice.
    let mut stringLiteral: &str = "String Slice / String Literal"; // Should not be able to declare as 'let mut'

    // In-Memory Strings (formerly StrBuf) allocate memorary and control their data. They cannot be converted into
    // the equivalent of a &'static str (Static String) like a &str, as In-Memory Strings are not pre-configured
    // to live for the entire lifetime of the compiled program like &str. They can infact be converted from String
    // into a slice &'a str by using the as_slice() method (retaining its original String lifetime)
    let mut stringInMemory: String = "In-Memory String".to_string();

    stringLiteral = try_strings(stringLiteral, stringInMemory);

    println!("stringLiteral is {}", stringLiteral);

}

/*
  Rust Structs are of Record Type form similar to Tuples.
  Elements in Structs each have a Name (aka Field/Member) and a Type
*/

// Declare a Struct with a name (camel case). Values Immutable by Default
struct PointInSpace {
    x: i32,
    y: i32
}

fn try_structs() {
  // Create Instance (Mutable) of Struct using Let and set each Field (any order)
  let mut origin = PointInSpace { x: 0, y: 0 }; // origin: PointInSpace

  origin.x = 20;

  println!("Origin is at ({}, {})", origin.x, origin.y); // Dot Notation to access Fields
}

/*
  Rust Tuple Structs are a hybrid data type similar to Tuple and Struct.
  Elements in Tuple Structs DO NOT have a Name, they only have a Type.
  Structs are preferred over Tuple Structs since they have actual Names for Elements.
  Note: Tuple Structs must use round brackets and colon
*/

struct Color (
  i32,
  i32,
  i32
);

struct PointInWater (
  i32,
  i32,
  i32
);

fn try_tuple_structs() {
  let black = Color(0, 0, 0);
  let origin = PointInWater(0, 0, 0);
}

// Declare a Newtype.
struct Inches (i32);

// Newtypes are Tuple Structs with only One Element. Beneficial for creating
// New Types similar to others (Cloning)
fn try_newtype() {
  let length = Inches(10);
  // Extract inner Integer Type by Desctructing the Let
  let Inches(integer_length) = length; // Assigns length to integer_length
  println!("Newtype length is {} inches", integer_length);
}

// Enums variants are a "Sum Type" that ties a set of alternatives to a specific name
fn try_enums() {
  // Define a Character to be either a Digit or Other. The alternative names may be
  // used via their fully scoped names i.e. Character::Other
  // Sub-datastructure types allowable in an Enum include Structs, Tuple Structs
  // Enums do not have access to operators: ==, !=, *, +, <, >=

  enum Character {
    Digit(i32), // Character::Digit is a name tied to an i32
    Missing, // Missing is just a name (not tied to a specific Type)
  }

  // Assignment
  let a  = Character::Digit(10);
  let b = Character::Missing;

  // Retrieve values contained in Enums, Error Handling where function output does not
  // match the expected Type
  match a {
    Character::Digit(n) => print!("\na is {} ", n),
    Character::Missing => print!("\na is missing"),
  }

  match b {
    Character::Digit(n) => print!("\nb is {}", n),
    Character::Missing => print!("\nb is missing"),
  }

  let x = 5;
  let y = 10;

  // // 'ordering' variable is of Ordering type (ordering: Ordering)
  // // so it contains one of the three values defined in the 'cmp' Function
  // // and we discover which one by using Conditional Operators to check
  // let ordering = cmp(x, y);

  // if ordering == Ordering::Less { println!("Less"); }
  // else if ordering == Ordering::Greater { println!("Greater"); }
  // else if ordering == Ordering::Equal { println!("Equal"); }

  // Replace the above 'if/else' with 'match' Pattern Matching expression instead
  // with less noise and which supports Exhaustiveness Checking across all
  // possible Variants of the Ordering Enum
  println!("{}", match cmp(x, y) {
    Ordering::Less => "\nless",
    Ordering::Greater => "\ngreater",
    Ordering::Equal => "\nequal",
  });

  // Equivalent to the above
  match cmp(x, y) {
    Ordering::Less => println!("\nless"),
    Ordering::Greater => println!("\ngreater"),
    Ordering::Equal => println!("\nequal"),
  };
}

// Pattern Matching is implemented by 'match' and allows elegantly deconstructing Enums
// (known as the Sum Type in Type Theory) whilst using the 'match' keyword
// instead of avoiding 'if/else' (for multiple or a complex set of option cases)
fn try_pattern_matching() {
  let x = 5;

  // 'match' takes Expression and branches into Arms depending on its Value.
  // Evaluation is performed only on the matching Arm.
  match x {
    // Arms are of the form 'val => expression'
    1 => println!("one"),
    2 => println!("two"),
    3 => println!("three"),
    4 => println!("four"),
    5 => println!("five"),
    // Exhaustiveness Checking ensures all possible patterns of Values are covered
    // with the '_' Catch-all- Arm so if any Expression used that were not included
    // (not all bases covered) it prevents a compile error (as '_' will match)
    _ => println!("something else"),
  }
}

fn try_loops(n: i32) -> (i32) {
  let mut o = 0;
  // For Loop with variable m over Iterator Expression 0..n (with start and end positions)
  // that produces a series of elements where each element is a loop itertion fetched from
  // the Iterator and bound to the variable m during each cycle through the loop body.
  // The Iterator is upper bound exclusive and so prints 0 through to n-1

  for m in 0..n {
    if m % 2 == 0 { continue; } // Approval condition only processes even iterations.
    println!("for loop with: {}", m);
    o += m;
  }

  let mut done: bool = false;

  println!("{}", o);

  while !done {
    o += o - 2;
    println!("while loop with: {}", o);
    if o % 3 == 0 { done = true; }
  }

  // Infinite Loop intentionally
  loop { // Use this instead of while true {}
    o -= 1;
    if o % 7 == 0 { break; } // End iteration early
  }

  return o;
}

// Strings are a re-sizable Data Structure.
// String is a sequence of Unicode scalar values validly encoded as a stream of UTF-8 bytes.
// Strings may contain null bytes (as they are not null-terminated)

fn try_strings(s_l: &str, s_m: String) -> &str {

  let mut _s_m: String = s_m; // Declare s_m as a mutable local variable _s_m

  let mut _s: String = s_l.to_string();
  _s.push_str(", is a growable string and is guaranteed to be UTF-8");
  println!("{}", _s);

  // Function to Convert Type &str into Type String (cheap solution that allocates it to memory)
  fn convert_to_string_in_memory_taking_string_in_memory(memory_string: String) {
    let memory_string_slice: &str = memory_string.as_slice();
    println!("Converted Type &str (String Slice / Literal) into Type String (In-Memory String): {}", memory_string_slice);
  }

  // Coerce Type &str into Type String
  convert_to_string_in_memory_taking_string_in_memory(_s_m);

  // Function to Convert Type String into Type &str
  fn convert_to_string_literal_taking_string_slice(slice: &str) {
    println!("Converted Type String (In-Memory String) into Type &str (String Slice / Literal): {}", slice);
  }

  // Coerce Type String into Type &str by prefixing with an & symbol
  convert_to_string_literal_taking_string_slice(&_s);

  // The following attempt to perform the same conversion with the parameter passed into the function gives error:
  //   - error: use of moved value: `s_m`
  //   - note: `s_m` moved here because it has type `collections::string::String`, which is moved by default
  //   - use `ref` to override

  // let mut _s_m2: String = s_m.to_string(); // Declare s_m as a mutable local variable _s_m

  // convert_to_string_literal_taking_string_slice(&_s_m2);

  return s_l;
}

// Returned Tuple is a Single Value (containing Multiple Values)
fn next_two(x: i32) -> (i32, i32) { (x + 1, x + 2) }

// All control paths must Return a Value
fn incr(m: i32, n: i32) -> i32 {
    if n < m {
      return n; // Early Return
    } else {
      println!("incrementing n from: {}", n);
      return n + 10;
    }
}

/*
  Rust forces Declare expected Type of incoming Fn Args. Type Inference in Fn body.
  Rust allows Declaration expected Type of outgoing Return Value after '->'
*/
fn print_sum(m: i32, n: i32) -> () { // Return the Unit Type () (aka nil)
    if m < n {
      println!("sum with m < n is: {}", m + n);
    } else {
      println!("sum with m >= n is: {}", m + n);
    }
}<|endoftext|>


<commit_before>use clap::Parser;
use minus::Pager;
use std::env;
use std::error::Error;
use std::fmt::Write;

#[derive(Parser)]
#[command(author, version, about, long_about = Some("List the contents of the PATH environment variable"))]
struct Args {
    #[arg(short, long, default_value_t = false, help = "Page output")]
    page: bool,
}

fn main() -> Result<(), Box<dyn Error>> {
    let args = Args::parse();

    let key = "PATHY";
    match env::var(key) {
        Ok(paths) => {
            let path_items = env::split_paths(&paths);
            if args.page {
                let mut output = Pager::new();
                for path in path_items {
                    writeln!(output, "{}", path.display())?;
                }
                minus::page_all(output)?;
            } else {
                for path in path_items {
                    println!("{}", path.display())
                }
            }
            Ok(())
        }
        Err(e) => {
            eprintln!("Could not get {}: {}", key, e);
            Err(Box::new(e))
        }
    }
}
<commit_msg>Make main return Result<(), Box<dyn Error>> and return Err on error<commit_after>use clap::Parser;
use minus::Pager;
use std::env;
use std::error::Error;
use std::fmt::Write;

#[derive(Parser)]
#[command(author, version, about, long_about = Some("List the contents of the PATH environment variable"))]
struct Args {
    #[arg(short, long, default_value_t = false, help = "Page output")]
    page: bool,
}

fn main() -> Result<(), Box<dyn Error>> {
    let args = Args::parse();

    let key = "PATH";
    match env::var(key) {
        Ok(paths) => {
            let path_items = env::split_paths(&paths);
            if args.page {
                let mut output = Pager::new();
                for path in path_items {
                    writeln!(output, "{}", path.display())?;
                }
                minus::page_all(output)?;
            } else {
                for path in path_items {
                    println!("{}", path.display())
                }
            }
            Ok(())
        }
        Err(e) => {
            eprintln!("Could not get {}: {}", key, e);
            Err(Box::new(e))
        }
    }
}
<|endoftext|>


<commit_before>extern crate sassers;
extern crate docopt;

use docopt::Docopt;

fn main() {
    const VERSION: &'static str = env!("CARGO_PKG_VERSION");
    static USAGE: &'static str = "
Usage:
    sassers [-t <style>] <inputfile>
    sassers [-vh]

Options:
    -h, --help                   Show this message
    -v, --version                Show the version
    -t <style>, --style <style>  Output style [default: nested]
    ";

    let args = Docopt::new(USAGE)
                      .and_then(|d| d.parse())
                      .unwrap_or_else(|e| e.exit());

    if args.get_bool("-v") {
        println!("{}", VERSION);
    } else {
        let style = args.get_str("-t");
        let inputfile = args.get_str("<inputfile>");

        match sassers::compile(&inputfile, style) {
            Ok(compiled) => println!("{}", compiled),
            Err(e) => println!("Compilation failed: {}", e.message),
        }
    }
}
<commit_msg>Silence warnings about main when running tests<commit_after>extern crate sassers;
extern crate docopt;

#[cfg(not(test))]
fn main() {
    use docopt::Docopt;
    const VERSION: &'static str = env!("CARGO_PKG_VERSION");
    static USAGE: &'static str = "
Usage:
    sassers [-t <style>] <inputfile>
    sassers [-vh]

Options:
    -h, --help                   Show this message
    -v, --version                Show the version
    -t <style>, --style <style>  Output style [default: nested]
    ";

    let args = Docopt::new(USAGE)
                      .and_then(|d| d.parse())
                      .unwrap_or_else(|e| e.exit());

    if args.get_bool("-v") {
        println!("{}", VERSION);
    } else {
        let style = args.get_str("-t");
        let inputfile = args.get_str("<inputfile>");

        match sassers::compile(&inputfile, style) {
            Ok(compiled) => println!("{}", compiled),
            Err(e) => println!("Compilation failed: {}", e.message),
        }
    }
}
<|endoftext|>


<commit_before>
extern crate clap;
extern crate rand;
extern crate serde;
#[macro_use]
extern crate serde_derive;

use clap::{App, Arg, SubCommand};

mod types;
mod log;
mod descriptor;
mod command;
mod installer;
mod runner;

fn main() {
    let name = "make";
    let version = env!("CARGO_PKG_VERSION");
    let author = env!("CARGO_PKG_AUTHORS");
    let description = env!("CARGO_PKG_DESCRIPTION");

    let default_toml = "Makefile.toml";

    let mut build_file_arg = "-b, --buildFile=[FILE] 'Build toml file containing the build descriptor (default: ".to_string();
    build_file_arg.push_str(&default_toml);
    build_file_arg.push_str(" if exists)'");

    let matches = App::new("cargo")
        .subcommand(
            SubCommand::with_name(name)
                .version(version)
                .author(author)
                .about(description)
                .arg_from_usage(&build_file_arg)
                .arg_from_usage("-t, --task=[TASK NAME] 'The task name to execute (default: default)'")
                .arg(Arg::from_usage("-l, --loglevel=[LOG LEVEL] 'The log level (default: info)'").possible_values(&["verbose", "info", "error"]))
        )
        .get_matches();

    let (build_file, task, log_level) = if let Some(cmd_matches) = matches.subcommand_matches(name) {
        (cmd_matches.value_of("buildFile").unwrap_or(&default_toml), cmd_matches.value_of("task").unwrap_or("default"), cmd_matches.value_of("loglevel").unwrap_or("info"))
    } else {
        panic!("cargo-{} not invoked via cargo.", name);
    };

    let logger = log::create(log_level);

    logger.info::<()>("Using Build File: ", &[build_file], None);
    logger.info::<()>("Task: ", &[task], None);

    let config = descriptor::load(&build_file, &logger);

    runner::run(&logger, &config, &task);
}
<commit_msg>minor changes<commit_after>
extern crate clap;
extern crate rand;
extern crate serde;
#[macro_use]
extern crate serde_derive;

use clap::{App, Arg, SubCommand};

mod types;
mod log;
mod descriptor;
mod command;
mod installer;
mod runner;

fn main() {
    let name = "make";
    let version = env!("CARGO_PKG_VERSION");
    let author = env!("CARGO_PKG_AUTHORS");
    let description = env!("CARGO_PKG_DESCRIPTION");

    let default_toml = "Makefile.toml";

    let mut build_file_arg = "-b, --buildFile=[FILE] 'Build toml file containing the build descriptor (default: ".to_string();
    build_file_arg.push_str(&default_toml);
    build_file_arg.push_str(" if exists)'");

    let matches = App::new("cargo")
        .subcommand(
            SubCommand::with_name(name)
                .version(version)
                .author(author)
                .about(description)
                .arg_from_usage(&build_file_arg)
                .arg_from_usage("-t, --task=[TASK NAME] 'The task name to execute (default: default)'")
                .arg(Arg::from_usage("-l, --loglevel=[LOG LEVEL] 'The log level (default: info)'").possible_values(&["verbose", "info", "error"]))
        )
        .get_matches();

    match matches.subcommand_matches(name) {
        Some(cmd_matches) => {
            let build_file = cmd_matches.value_of("buildFile").unwrap_or(&default_toml);
            let task = cmd_matches.value_of("task").unwrap_or("default");
            let log_level = cmd_matches.value_of("loglevel").unwrap_or("info");

            let logger = log::create(log_level);

            logger.info::<()>("Using Build File: ", &[build_file], None);
            logger.info::<()>("Task: ", &[task], None);

            let config = descriptor::load(&build_file, &logger);

            runner::run(&logger, &config, &task);
        }
        None => panic!("cargo-{} not invoked via cargo command.", name)
    }
}
<|endoftext|>