<commit_before>#[no_core];
#[allow(vecs_implicitly_copyable)];
#[allow(non_camel_case_types)];
#[legacy_modes];

extern mod core(vers = "0.4");
extern mod std(vers = "0.4");
extern mod rustc(vers = "0.4");
extern mod syntax(vers = "0.4");

use core::*;

// -*- rust -*-
use result::{Ok, Err};
use io::ReaderUtil;
use std::getopts;
use std::map::HashMap;
use getopts::{opt_present};
use rustc::driver::driver::*;
use syntax::codemap;
use syntax::diagnostic;
use rustc::driver::session;
use rustc::middle::lint;

fn version(argv0: &str) {
    let mut vers = ~"unknown version";
    let env_vers = env!("CFG_VERSION");
    if env_vers.len() != 0 { vers = env_vers; }
    io::println(fmt!("%s %s", argv0, vers));
    io::println(fmt!("host: %s", host_triple()));
}

fn usage(argv0: &str) {
    io::println(fmt!("Usage: %s [options] <input>\n", argv0) +
                 ~"
Options:

    --bin              Compile an executable crate (default)
    -c                 Compile and assemble, but do not link
    --cfg <cfgspec>    Configure the compilation environment
    --emit-llvm        Produce an LLVM bitcode file
    -g                 Produce debug info (experimental)
    --gc               Garbage collect shared data (experimental/temporary)
    -h --help          Display this message
    -L <path>          Add a directory to the library search path
    --lib              Compile a library crate
    --ls               List the symbols defined by a compiled library crate
    --jit              Execute using JIT (experimental)
    --no-trans         Run all passes except translation; no output
    -O                 Equivalent to --opt-level=2
    -o <filename>      Write output to <filename>
    --opt-level <lvl>  Optimize with possible levels 0-3
    --out-dir <dir>    Write output to compiler-chosen filename in <dir>
    --parse-only       Parse only; do not compile, assemble, or link
    --pretty [type]    Pretty-print the input instead of compiling;
                       valid types are: normal (un-annotated source),
                       expanded (crates expanded), typed (crates expanded,
                       with type annotations), or identified (fully
                       parenthesized, AST nodes and blocks with IDs)
    -S                 Compile only; do not assemble or link
    --save-temps       Write intermediate files (.bc, .opt.bc, .o)
                       in addition to normal output
    --static           Use or produce static libraries or binaries
                       (experimental)
    --sysroot <path>   Override the system root
    --test             Build a test harness
    --target <triple>  Target cpu-manufacturer-kernel[-os] to compile for
                       (default: host triple)
                       (see http://sources.redhat.com/autobook/autobook/
                       autobook_17.html for detail)

    -(W|A|D|F) help    Print available 'lint' checks and default settings

    -W <foo>           warn about <foo> by default
    -A <foo>           allow <foo> by default
    -D <foo>           deny <foo> by default
    -F <foo>           forbid <foo> (deny, and deny all overrides)

    -Z help            list internal options for debugging rustc

    -v --version       Print version info and exit
");
}

fn describe_warnings() {
    let lint_dict = lint::get_lint_dict();
    let mut max_key = 0;
    for lint_dict.each_key |k| { max_key = uint::max(k.len(), max_key); }
    fn padded(max: uint, s: &str) -> ~str {
        str::from_bytes(vec::from_elem(max - s.len(), ' ' as u8)) + s
    }
    io::println(fmt!("\nAvailable lint checks:\n"));
    io::println(fmt!("    %s  %7.7s  %s",
                     padded(max_key, ~"name"), ~"default", ~"meaning"));
    io::println(fmt!("    %s  %7.7s  %s\n",
                     padded(max_key, ~"----"), ~"-------", ~"-------"));
    for lint_dict.each |k, v| {
        let k = str::replace(k, ~"_", ~"-");
        io::println(fmt!("    %s  %7.7s  %s",
                         padded(max_key, k),
                         match v.default {
                             lint::allow => ~"allow",
                             lint::warn => ~"warn",
                             lint::deny => ~"deny",
                             lint::forbid => ~"forbid"
                         },
                         v.desc));
    }
    io::println(~"");
}

fn describe_debug_flags() {
    io::println(fmt!("\nAvailable debug options:\n"));
    for session::debugging_opts_map().each |pair| {
        let (name, desc, _) = *pair;
        io::println(fmt!("    -Z%-20s -- %s", name, desc));
    }
}

fn run_compiler(args: &~[~str], demitter: diagnostic::emitter) {
    // Don't display log spew by default. Can override with RUST_LOG.
    logging::console_off();

    let mut args = *args;
    let binary = args.shift();

    if args.is_empty() { usage(binary); return; }

    let matches =
        match getopts::getopts(args, opts()) {
          Ok(m) => m,
          Err(f) => {
            early_error(demitter, getopts::fail_str(f))
          }
        };

    if opt_present(matches, ~"h") || opt_present(matches, ~"help") {
        usage(binary);
        return;
    }

    let lint_flags = vec::append(getopts::opt_strs(matches, ~"W"),
                                 getopts::opt_strs(matches, ~"warn"));
    if lint_flags.contains(&~"help") {
        describe_warnings();
        return;
    }

    if getopts::opt_strs(matches, ~"Z").contains(&~"help") {
        describe_debug_flags();
        return;
    }

    if opt_present(matches, ~"v") || opt_present(matches, ~"version") {
        version(binary);
        return;
    }
    let input = match vec::len(matches.free) {
      0u => early_error(demitter, ~"no input filename given"),
      1u => {
        let ifile = matches.free[0];
        if ifile == ~"-" {
            let src = str::from_bytes(io::stdin().read_whole_stream());
            str_input(src)
        } else {
            file_input(Path(ifile))
        }
      }
      _ => early_error(demitter, ~"multiple input filenames provided")
    };

    let sopts = build_session_options(binary, matches, demitter);
    let sess = build_session(sopts, demitter);
    let odir = getopts::opt_maybe_str(matches, ~"out-dir");
    let odir = odir.map(|o| Path(*o));
    let ofile = getopts::opt_maybe_str(matches, ~"o");
    let ofile = ofile.map(|o| Path(*o));
    let cfg = build_configuration(sess, binary, input);
    let pretty =
        option::map(&getopts::opt_default(matches, ~"pretty",
                                         ~"normal"),
                    |a| parse_pretty(sess, *a) );
    match pretty {
      Some::<pp_mode>(ppm) => {
        pretty_print_input(sess, cfg, input, ppm);
        return;
      }
      None::<pp_mode> => {/* continue */ }
    }
    let ls = opt_present(matches, ~"ls");
    if ls {
        match input {
          file_input(ifile) => {
            list_metadata(sess, &ifile, io::stdout());
          }
          str_input(_) => {
            early_error(demitter, ~"can not list metadata for stdin");
          }
        }
        return;
    }

    compile_input(sess, cfg, input, &odir, &ofile);
}

enum monitor_msg {
    fatal,
    done,
}

impl monitor_msg : cmp::Eq {
    pure fn eq(other: &monitor_msg) -> bool {
        (self as uint) == ((*other) as uint)
    }
    pure fn ne(other: &monitor_msg) -> bool { !self.eq(other) }
}

/*
This is a sanity check that any failure of the compiler is performed
through the diagnostic module and reported properly - we shouldn't be calling
plain-old-fail on any execution path that might be taken. Since we have
console logging off by default, hitting a plain fail statement would make the
compiler silently exit, which would be terrible.

This method wraps the compiler in a subtask and injects a function into the
diagnostic emitter which records when we hit a fatal error. If the task
fails without recording a fatal error then we've encountered a compiler
bug and need to present an error.
*/
fn monitor(+f: fn~(diagnostic::emitter)) {
    let p = comm::Port();
    let ch = comm::Chan(&p);

    match do task::try |move f| {

        // The 'diagnostics emitter'. Every error, warning, etc. should
        // go through this function.
        let demitter = fn@(cmsp: Option<(codemap::codemap, codemap::span)>,
                           msg: &str, lvl: diagnostic::level) {
            if lvl == diagnostic::fatal {
                comm::send(ch, fatal);
            }
            diagnostic::emit(cmsp, msg, lvl);
        };

        struct finally {
            ch: comm::Chan<monitor_msg>,
            drop { comm::send(self.ch, done); }
        }

        let _finally = finally { ch: ch };

        f(demitter)
    } {
        result::Ok(_) => { /* fallthrough */ }
        result::Err(_) => {
            // Task failed without emitting a fatal diagnostic
            if comm::recv(p) == done {
                diagnostic::emit(
                    None,
                    diagnostic::ice_msg(~"unexpected failure"),
                    diagnostic::error);

                for [
                    ~"the compiler hit an unexpected failure path. \
                     this is a bug",
                    ~"try running with RUST_LOG=rustc=0,::rt::backtrace \
                     to get further details and report the results \
                     to github.com/mozilla/rust/issues"
                ]/_.each |note| {
                    diagnostic::emit(None, *note, diagnostic::note)
                }
            }
            // Fail so the process returns a failure code
            fail;
        }
    }
}

fn main() {
    let mut args = os::args();
    do monitor |move args, demitter| {
        run_compiler(&args, demitter);
    }
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>Touchup the debug flag description printing<commit_after>#[no_core];
#[allow(vecs_implicitly_copyable)];
#[allow(non_camel_case_types)];
#[legacy_modes];

extern mod core(vers = "0.4");
extern mod std(vers = "0.4");
extern mod rustc(vers = "0.4");
extern mod syntax(vers = "0.4");

use core::*;

// -*- rust -*-
use result::{Ok, Err};
use io::ReaderUtil;
use std::getopts;
use std::map::HashMap;
use getopts::{opt_present};
use rustc::driver::driver::*;
use syntax::codemap;
use syntax::diagnostic;
use rustc::driver::session;
use rustc::middle::lint;

fn version(argv0: &str) {
    let mut vers = ~"unknown version";
    let env_vers = env!("CFG_VERSION");
    if env_vers.len() != 0 { vers = env_vers; }
    io::println(fmt!("%s %s", argv0, vers));
    io::println(fmt!("host: %s", host_triple()));
}

fn usage(argv0: &str) {
    io::println(fmt!("Usage: %s [options] <input>\n", argv0) +
                 ~"
Options:

    --bin              Compile an executable crate (default)
    -c                 Compile and assemble, but do not link
    --cfg <cfgspec>    Configure the compilation environment
    --emit-llvm        Produce an LLVM bitcode file
    -g                 Produce debug info (experimental)
    --gc               Garbage collect shared data (experimental/temporary)
    -h --help          Display this message
    -L <path>          Add a directory to the library search path
    --lib              Compile a library crate
    --ls               List the symbols defined by a compiled library crate
    --jit              Execute using JIT (experimental)
    --no-trans         Run all passes except translation; no output
    -O                 Equivalent to --opt-level=2
    -o <filename>      Write output to <filename>
    --opt-level <lvl>  Optimize with possible levels 0-3
    --out-dir <dir>    Write output to compiler-chosen filename in <dir>
    --parse-only       Parse only; do not compile, assemble, or link
    --pretty [type]    Pretty-print the input instead of compiling;
                       valid types are: normal (un-annotated source),
                       expanded (crates expanded), typed (crates expanded,
                       with type annotations), or identified (fully
                       parenthesized, AST nodes and blocks with IDs)
    -S                 Compile only; do not assemble or link
    --save-temps       Write intermediate files (.bc, .opt.bc, .o)
                       in addition to normal output
    --static           Use or produce static libraries or binaries
                       (experimental)
    --sysroot <path>   Override the system root
    --test             Build a test harness
    --target <triple>  Target cpu-manufacturer-kernel[-os] to compile for
                       (default: host triple)
                       (see http://sources.redhat.com/autobook/autobook/
                       autobook_17.html for detail)

    -(W|A|D|F) help    Print available 'lint' checks and default settings

    -W <foo>           warn about <foo> by default
    -A <foo>           allow <foo> by default
    -D <foo>           deny <foo> by default
    -F <foo>           forbid <foo> (deny, and deny all overrides)

    -Z help            list internal options for debugging rustc

    -v --version       Print version info and exit
");
}

fn describe_warnings() {
    let lint_dict = lint::get_lint_dict();
    let mut max_key = 0;
    for lint_dict.each_key |k| { max_key = uint::max(k.len(), max_key); }
    fn padded(max: uint, s: &str) -> ~str {
        str::from_bytes(vec::from_elem(max - s.len(), ' ' as u8)) + s
    }
    io::println(fmt!("\nAvailable lint checks:\n"));
    io::println(fmt!("    %s  %7.7s  %s",
                     padded(max_key, ~"name"), ~"default", ~"meaning"));
    io::println(fmt!("    %s  %7.7s  %s\n",
                     padded(max_key, ~"----"), ~"-------", ~"-------"));
    for lint_dict.each |k, v| {
        let k = str::replace(k, ~"_", ~"-");
        io::println(fmt!("    %s  %7.7s  %s",
                         padded(max_key, k),
                         match v.default {
                             lint::allow => ~"allow",
                             lint::warn => ~"warn",
                             lint::deny => ~"deny",
                             lint::forbid => ~"forbid"
                         },
                         v.desc));
    }
    io::println(~"");
}

fn describe_debug_flags() {
    io::println(fmt!("\nAvailable debug options:\n"));
    for session::debugging_opts_map().each |pair| {
        let (name, desc, _) = *pair;
        io::println(fmt!("    -Z %-20s -- %s", name, desc));
    }
}

fn run_compiler(args: &~[~str], demitter: diagnostic::emitter) {
    // Don't display log spew by default. Can override with RUST_LOG.
    logging::console_off();

    let mut args = *args;
    let binary = args.shift();

    if args.is_empty() { usage(binary); return; }

    let matches =
        match getopts::getopts(args, opts()) {
          Ok(m) => m,
          Err(f) => {
            early_error(demitter, getopts::fail_str(f))
          }
        };

    if opt_present(matches, ~"h") || opt_present(matches, ~"help") {
        usage(binary);
        return;
    }

    let lint_flags = vec::append(getopts::opt_strs(matches, ~"W"),
                                 getopts::opt_strs(matches, ~"warn"));
    if lint_flags.contains(&~"help") {
        describe_warnings();
        return;
    }

    if getopts::opt_strs(matches, ~"Z").contains(&~"help") {
        describe_debug_flags();
        return;
    }

    if opt_present(matches, ~"v") || opt_present(matches, ~"version") {
        version(binary);
        return;
    }
    let input = match vec::len(matches.free) {
      0u => early_error(demitter, ~"no input filename given"),
      1u => {
        let ifile = matches.free[0];
        if ifile == ~"-" {
            let src = str::from_bytes(io::stdin().read_whole_stream());
            str_input(src)
        } else {
            file_input(Path(ifile))
        }
      }
      _ => early_error(demitter, ~"multiple input filenames provided")
    };

    let sopts = build_session_options(binary, matches, demitter);
    let sess = build_session(sopts, demitter);
    let odir = getopts::opt_maybe_str(matches, ~"out-dir");
    let odir = odir.map(|o| Path(*o));
    let ofile = getopts::opt_maybe_str(matches, ~"o");
    let ofile = ofile.map(|o| Path(*o));
    let cfg = build_configuration(sess, binary, input);
    let pretty =
        option::map(&getopts::opt_default(matches, ~"pretty",
                                         ~"normal"),
                    |a| parse_pretty(sess, *a) );
    match pretty {
      Some::<pp_mode>(ppm) => {
        pretty_print_input(sess, cfg, input, ppm);
        return;
      }
      None::<pp_mode> => {/* continue */ }
    }
    let ls = opt_present(matches, ~"ls");
    if ls {
        match input {
          file_input(ifile) => {
            list_metadata(sess, &ifile, io::stdout());
          }
          str_input(_) => {
            early_error(demitter, ~"can not list metadata for stdin");
          }
        }
        return;
    }

    compile_input(sess, cfg, input, &odir, &ofile);
}

enum monitor_msg {
    fatal,
    done,
}

impl monitor_msg : cmp::Eq {
    pure fn eq(other: &monitor_msg) -> bool {
        (self as uint) == ((*other) as uint)
    }
    pure fn ne(other: &monitor_msg) -> bool { !self.eq(other) }
}

/*
This is a sanity check that any failure of the compiler is performed
through the diagnostic module and reported properly - we shouldn't be calling
plain-old-fail on any execution path that might be taken. Since we have
console logging off by default, hitting a plain fail statement would make the
compiler silently exit, which would be terrible.

This method wraps the compiler in a subtask and injects a function into the
diagnostic emitter which records when we hit a fatal error. If the task
fails without recording a fatal error then we've encountered a compiler
bug and need to present an error.
*/
fn monitor(+f: fn~(diagnostic::emitter)) {
    let p = comm::Port();
    let ch = comm::Chan(&p);

    match do task::try |move f| {

        // The 'diagnostics emitter'. Every error, warning, etc. should
        // go through this function.
        let demitter = fn@(cmsp: Option<(codemap::codemap, codemap::span)>,
                           msg: &str, lvl: diagnostic::level) {
            if lvl == diagnostic::fatal {
                comm::send(ch, fatal);
            }
            diagnostic::emit(cmsp, msg, lvl);
        };

        struct finally {
            ch: comm::Chan<monitor_msg>,
            drop { comm::send(self.ch, done); }
        }

        let _finally = finally { ch: ch };

        f(demitter)
    } {
        result::Ok(_) => { /* fallthrough */ }
        result::Err(_) => {
            // Task failed without emitting a fatal diagnostic
            if comm::recv(p) == done {
                diagnostic::emit(
                    None,
                    diagnostic::ice_msg(~"unexpected failure"),
                    diagnostic::error);

                for [
                    ~"the compiler hit an unexpected failure path. \
                     this is a bug",
                    ~"try running with RUST_LOG=rustc=0,::rt::backtrace \
                     to get further details and report the results \
                     to github.com/mozilla/rust/issues"
                ]/_.each |note| {
                    diagnostic::emit(None, *note, diagnostic::note)
                }
            }
            // Fail so the process returns a failure code
            fail;
        }
    }
}

fn main() {
    let mut args = os::args();
    do monitor |move args, demitter| {
        run_compiler(&args, demitter);
    }
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>extern crate gtk;
extern crate glib;
extern crate gstreamer as gst;

#[cfg(any(feature = "profiling-listener", feature = "profiling-tracker"))]
use chrono::Utc;

use std::rc::Rc;
use std::cell::RefCell;

use std::path::PathBuf;

use std::sync::mpsc::{channel, Receiver};

use gtk::prelude::*;

use media::{Context, ContextMessage};
use media::ContextMessage::*;

use super::{AudioController, InfoController, VideoController};

pub struct MainController {
    window: gtk::ApplicationWindow,
    header_bar: gtk::HeaderBar,
    play_pause_btn: gtk::ToolButton,

    video_ctrl: VideoController,
    info_ctrl: InfoController,
    audio_ctrl: AudioController,

    context: Option<Context>,
    seeking: bool,

    this_opt: Option<Rc<RefCell<MainController>>>,
    keep_going: bool,
    listener_src: Option<glib::SourceId>,
    tracker_src: Option<glib::SourceId>,
}

impl MainController {
    pub fn new(builder: gtk::Builder) -> Rc<RefCell<Self>> {
        let this = Rc::new(RefCell::new(MainController {
            window: builder.get_object("application-window").unwrap(),
            header_bar: builder.get_object("header-bar").unwrap(),
            play_pause_btn: builder.get_object("play_pause-toolbutton").unwrap(),

            video_ctrl: VideoController::new(&builder),
            info_ctrl: InfoController::new(&builder),
            audio_ctrl: AudioController::new(&builder),

            context: None,
            seeking: false,

            this_opt: None,
            keep_going: true,
            listener_src: None,
            tracker_src: None,
        }));

        {
            let mut this_mut = this.borrow_mut();

            let this_rc = Rc::clone(&this);
            this_mut.this_opt = Some(this_rc);

            this_mut.window.connect_delete_event(|_, _| {
                gtk::main_quit();
                Inhibit(false)
            });
            this_mut.window.set_titlebar(&this_mut.header_bar);

            let this_rc = Rc::clone(&this);
            this_mut.play_pause_btn.connect_clicked(move |_| {
                this_rc.borrow_mut().play_pause();
            });

            // TODO: add key bindings to seek by steps
            // play/pause, etc.

            this_mut.video_ctrl.register_callbacks(&this);
            this_mut.info_ctrl.register_callbacks(&this);
            this_mut.audio_ctrl.register_callbacks(&this);
        }

        let open_btn: gtk::Button = builder.get_object("open-btn").unwrap();
        let this_rc = Rc::clone(&this);
        open_btn.connect_clicked(move |_| {
            this_rc.borrow_mut().select_media();
        });

        this
    }

    pub fn show_all(&self) {
        self.window.show_all();
    }

    fn play_pause(&mut self) {
        let context =
            match self.context.take() {
                Some(context) => context,
                None => {
                    self.select_media();
                    return;
                },
            };

        match context.get_state() {
            gst::State::Paused => {
                self.register_tracker(17); // 60 Hz
                self.play_pause_btn.set_icon_name("media-playback-pause");
                context.play().unwrap();
            }
            gst::State::Playing => {
                context.pause().unwrap();
                self.play_pause_btn.set_icon_name("media-playback-start");
                self.remove_tracker();
            },
            state => println!("Can't play/pause in state {:?}", state),
        };

        self.context = Some(context);
    }

    fn stop(&mut self) {
        if let Some(context) = self.context.as_mut() {
            context.stop();
        };

        // remove callbacks in order to avoid conflict on borrowing of self
        self.remove_listener();
        self.remove_tracker();

        self.audio_ctrl.cleanup();

        self.play_pause_btn.set_icon_name("media-playback-start");
    }

    pub fn seek(&mut self, position: u64) {
        self.seeking = true;
        self.info_ctrl.seek(position);
        self.audio_ctrl.seek(position);
        self.context.as_ref()
            .expect("No context found while seeking in media")
            .seek(position);
        // update position eventhough the stream
        // is not sync yet for the user to notice
        // the seek request in being handled
    }

    fn select_media(&mut self) {
        self.stop();

        let file_dlg = gtk::FileChooserDialog::new(
            Some("Open a media file"),
            Some(&self.window),
            gtk::FileChooserAction::Open,
        );
        // Note: couldn't find equivalents for STOCK_OK
        file_dlg.add_button("Open", gtk::ResponseType::Ok.into());

        if file_dlg.run() == gtk::ResponseType::Ok.into() {
            self.open_media(file_dlg.get_filename().unwrap());
        }

        file_dlg.close();
    }

    fn remove_listener(&mut self) {
        if let Some(source_id) = self.listener_src.take() {
            glib::source_remove(source_id);
        }
    }

    fn register_listener(&mut self,
        timeout: u32,
        ui_rx: Receiver<ContextMessage>,
    ) {
        let this_rc = Rc::clone(self.this_opt.as_ref().unwrap());

        self.listener_src = Some(gtk::timeout_add(timeout, move || {
            let mut keep_going = true;

            for message in ui_rx.try_iter() {
                match message {
                    AsyncDone => {
                        this_rc.borrow_mut().seeking = false;
                    },
                    InitDone => {
                        let mut this_mut = this_rc.borrow_mut();

                        let context = this_mut.context.take()
                            .expect("MainController: InitDone but no context available");

                        this_mut.header_bar.set_subtitle(
                            Some(context.file_name.as_str())
                        );

                        this_mut.info_ctrl.new_media(&context);
                        this_mut.video_ctrl.new_media(&context);
                        this_mut.audio_ctrl.new_media(&context);

                        this_mut.context = Some(context);
                    },
                    Eos => {
                        let this = this_rc.borrow_mut();

                        this.audio_ctrl.tick();
                        this.play_pause_btn.set_icon_name("media-playback-start");
                    },
                    FailedToOpenMedia => {
                        eprintln!("ERROR: failed to open media");

                        let mut this_mut = this_rc.borrow_mut();

                        this_mut.context = None;
                        this_mut.keep_going = false;
                        keep_going = false;
                    },
                };

                if !keep_going { break; }
            }

            if !keep_going {
                let mut this_mut = this_rc.borrow_mut();
                this_mut.listener_src = None;
                this_mut.tracker_src = None;
            }

            glib::Continue(keep_going)
        }));
    }

    fn remove_tracker(&mut self) {
        if let Some(source_id) = self.tracker_src.take() {
            glib::source_remove(source_id);
        }
    }

    fn register_tracker(&mut self, timeout: u32) {
        let this_rc = Rc::clone(self.this_opt.as_ref().unwrap());

        self.tracker_src = Some(gtk::timeout_add(timeout, move || {
            #[cfg(feature = "profiling-tracker")]
            let start = Utc::now();

            let mut this_mut = this_rc.borrow_mut();

            #[cfg(feature = "profiling-tracker")]
            let before_tick = Utc::now();

            if !this_mut.seeking {
                let position = this_mut.context.as_mut()
                    .expect("No context in tracker while getting position")
                    .get_position();
                this_mut.info_ctrl.tick(position);
            }

            this_mut.audio_ctrl.tick();

            #[cfg(feature = "profiling-tracker")]
            let end = Utc::now();

            #[cfg(feature = "profiling-tracker")]
            println!("tracker,{},{},{}",
                start.time().format("%H:%M:%S%.6f"),
                before_tick.time().format("%H:%M:%S%.6f"),
                end.time().format("%H:%M:%S%.6f"),
            );

            glib::Continue(this_mut.keep_going)
        }));
    }

    fn open_media(&mut self, filepath: PathBuf) {
        assert_eq!(self.listener_src, None);

        self.info_ctrl.cleanup();
        self.audio_ctrl.cleanup();
        self.header_bar.set_subtitle("");

        let (ctx_tx, ui_rx) = channel();

        self.seeking = false;
        self.keep_going = true;
        self.register_listener(250, ui_rx);

        match Context::new(
            filepath,
            self.audio_ctrl.get_dbl_buffer_mtx(),
            self.video_ctrl.video_box.clone(),
            ctx_tx
        ) {
            Ok(context) => {
                self.context = Some(context);
            },
            Err(error) => eprintln!("Error opening media: {}", error),
        };
    }
}
<commit_msg>Remove tracker after EOS (#37)<commit_after>extern crate gtk;
extern crate glib;
extern crate gstreamer as gst;

#[cfg(any(feature = "profiling-listener", feature = "profiling-tracker"))]
use chrono::Utc;

use std::rc::Rc;
use std::cell::RefCell;

use std::path::PathBuf;

use std::sync::mpsc::{channel, Receiver};

use gtk::prelude::*;

use media::{Context, ContextMessage};
use media::ContextMessage::*;

use super::{AudioController, InfoController, VideoController};

#[derive(PartialEq)]
pub enum ControllerState {
    Stopped,
    Paused,
    Playing,
}

const LISTENER_PERIOD: u32 = 250; // 250 ms (4 Hz)
const TRACKER_PERIOD:  u32 = 17;  //  17 ms (60 Hz)

pub struct MainController {
    window: gtk::ApplicationWindow,
    header_bar: gtk::HeaderBar,
    play_pause_btn: gtk::ToolButton,

    video_ctrl: VideoController,
    info_ctrl: InfoController,
    audio_ctrl: AudioController,

    context: Option<Context>,
    state: ControllerState,
    duration: u64,
    seeking: bool,

    this_opt: Option<Rc<RefCell<MainController>>>,
    keep_going: bool,
    listener_src: Option<glib::SourceId>,
    tracker_src: Option<glib::SourceId>,
}

impl MainController {
    pub fn new(builder: gtk::Builder) -> Rc<RefCell<Self>> {
        let this = Rc::new(RefCell::new(MainController {
            window: builder.get_object("application-window").unwrap(),
            header_bar: builder.get_object("header-bar").unwrap(),
            play_pause_btn: builder.get_object("play_pause-toolbutton").unwrap(),

            video_ctrl: VideoController::new(&builder),
            info_ctrl: InfoController::new(&builder),
            audio_ctrl: AudioController::new(&builder),

            context: None,
            state: ControllerState::Stopped,
            duration: 0,
            seeking: false,

            this_opt: None,
            keep_going: true,
            listener_src: None,
            tracker_src: None,
        }));

        {
            let mut this_mut = this.borrow_mut();

            let this_rc = Rc::clone(&this);
            this_mut.this_opt = Some(this_rc);

            this_mut.window.connect_delete_event(|_, _| {
                gtk::main_quit();
                Inhibit(false)
            });
            this_mut.window.set_titlebar(&this_mut.header_bar);

            let this_rc = Rc::clone(&this);
            this_mut.play_pause_btn.connect_clicked(move |_| {
                this_rc.borrow_mut().play_pause();
            });

            // TODO: add key bindings to seek by steps
            // play/pause, etc.

            this_mut.video_ctrl.register_callbacks(&this);
            this_mut.info_ctrl.register_callbacks(&this);
            this_mut.audio_ctrl.register_callbacks(&this);
        }

        let open_btn: gtk::Button = builder.get_object("open-btn").unwrap();
        let this_rc = Rc::clone(&this);
        open_btn.connect_clicked(move |_| {
            this_rc.borrow_mut().select_media();
        });

        this
    }

    pub fn show_all(&self) {
        self.window.show_all();
    }

    fn play_pause(&mut self) {
        let mut context =
            match self.context.take() {
                Some(context) => context,
                None => {
                    self.select_media();
                    return;
                },
            };

        match context.get_state() {
            gst::State::Paused => {
                if context.get_position() < self.duration {
                    self.register_tracker(TRACKER_PERIOD);
                    self.play_pause_btn.set_icon_name("media-playback-pause");
                    self.state = ControllerState::Playing;
                    context.play().unwrap();
                    self.context = Some(context);
                } else {
                    self.context = Some(context);
                    self.seek(0);
                }
            }
            gst::State::Playing => {
                context.pause().unwrap();
                self.play_pause_btn.set_icon_name("media-playback-start");
                self.remove_tracker();
                self.state = ControllerState::Paused;
                self.context = Some(context);
            },
            state => {
                println!("Can't play/pause in state {:?}", state);
                self.context = Some(context);
            },
        };
    }

    fn stop(&mut self) {
        if let Some(context) = self.context.as_mut() {
            context.stop();
        };

        // remove callbacks in order to avoid conflict on borrowing of self
        self.remove_listener();
        self.remove_tracker();

        self.audio_ctrl.cleanup();

        self.play_pause_btn.set_icon_name("media-playback-start");

        self.state = ControllerState::Stopped;
        self.duration = 0;
    }

    pub fn seek(&mut self, position: u64) {
        if self.state != ControllerState::Stopped {
            self.seeking = true;
            // update position eventhough the stream
            // is not sync yet for the user to notice
            // the seek request in being handled
            self.info_ctrl.seek(position);
            self.audio_ctrl.seek(position);
            self.context.as_ref()
                .expect("MainController::seek no context")
                .seek(position);

            if self.state == ControllerState::Paused {
                self.register_tracker(TRACKER_PERIOD);
                self.play_pause_btn.set_icon_name("media-playback-pause");
                self.context.as_mut().unwrap().play().unwrap();
            }
        }
    }

    fn select_media(&mut self) {
        self.stop();

        let file_dlg = gtk::FileChooserDialog::new(
            Some("Open a media file"),
            Some(&self.window),
            gtk::FileChooserAction::Open,
        );
        // Note: couldn't find equivalents for STOCK_OK
        file_dlg.add_button("Open", gtk::ResponseType::Ok.into());

        if file_dlg.run() == gtk::ResponseType::Ok.into() {
            self.open_media(file_dlg.get_filename().unwrap());
        }

        file_dlg.close();
    }

    fn remove_listener(&mut self) {
        if let Some(source_id) = self.listener_src.take() {
            glib::source_remove(source_id);
        }
    }

    fn register_listener(&mut self,
        timeout: u32,
        ui_rx: Receiver<ContextMessage>,
    ) {
        if self.listener_src.is_some() {
            return;
        }

        let this_rc = Rc::clone(self.this_opt.as_ref().unwrap());

        self.listener_src = Some(gtk::timeout_add(timeout, move || {
            let mut keep_going = true;

            for message in ui_rx.try_iter() {
                match message {
                    AsyncDone => {
                        this_rc.borrow_mut().seeking = false;
                    },
                    InitDone => {
                        let mut this_mut = this_rc.borrow_mut();

                        let context = this_mut.context.take()
                            .expect("MainController: InitDone but no context available");

                        this_mut.header_bar.set_subtitle(
                            Some(context.file_name.as_str())
                        );

                        this_mut.duration = context.get_duration();

                        this_mut.info_ctrl.new_media(&context);
                        this_mut.video_ctrl.new_media(&context);
                        this_mut.audio_ctrl.new_media(&context);

                        this_mut.context = Some(context);
                    },
                    Eos => {
                        let mut this = this_rc.borrow_mut();

                        this.audio_ctrl.tick();
                        this.play_pause_btn.set_icon_name("media-playback-start");
                        this.state = ControllerState::Paused;
                        this.remove_tracker();
                    },
                    FailedToOpenMedia => {
                        eprintln!("ERROR: failed to open media");

                        let mut this_mut = this_rc.borrow_mut();

                        this_mut.context = None;
                        this_mut.keep_going = false;
                        keep_going = false;
                    },
                };

                if !keep_going { break; }
            }

            if !keep_going {
                let mut this_mut = this_rc.borrow_mut();
                this_mut.listener_src = None;
                this_mut.tracker_src = None;
            }

            glib::Continue(keep_going)
        }));
    }

    fn remove_tracker(&mut self) {
        if let Some(source_id) = self.tracker_src.take() {
            glib::source_remove(source_id);
        }
    }

    fn register_tracker(&mut self, timeout: u32) {
        if self.tracker_src.is_some() {
            return;
        }

        let this_rc = Rc::clone(self.this_opt.as_ref().unwrap());

        self.tracker_src = Some(gtk::timeout_add(timeout, move || {
            #[cfg(feature = "profiling-tracker")]
            let start = Utc::now();

            let mut keep_going = true;

            let mut this_mut = this_rc.borrow_mut();

            #[cfg(feature = "profiling-tracker")]
            let before_tick = Utc::now();

            let position = this_mut.context.as_mut()
                .expect("MainController::tracker no context while getting position")
                .get_position();
            this_mut.info_ctrl.tick(position);
            this_mut.audio_ctrl.tick();

            if position > this_mut.duration {
                // this check is necessary as EOS is not sent
                // after the first EOS even afte a seek
                if let Some(context) = this_mut.context.as_mut() {
                    context.pause().unwrap();
                }
                this_mut.play_pause_btn.set_icon_name("media-playback-start");
                this_mut.state = ControllerState::Paused;
                this_mut.tracker_src = None;
                keep_going = false;
            }

            #[cfg(feature = "profiling-tracker")]
            let end = Utc::now();

            #[cfg(feature = "profiling-tracker")]
            println!("tracker,{},{},{}",
                start.time().format("%H:%M:%S%.6f"),
                before_tick.time().format("%H:%M:%S%.6f"),
                end.time().format("%H:%M:%S%.6f"),
            );

            glib::Continue(this_mut.keep_going && keep_going)
        }));
    }

    fn open_media(&mut self, filepath: PathBuf) {
        assert_eq!(self.listener_src, None);

        self.info_ctrl.cleanup();
        self.audio_ctrl.cleanup();
        self.header_bar.set_subtitle("");

        let (ctx_tx, ui_rx) = channel();

        self.seeking = false;
        self.keep_going = true;
        self.register_listener(LISTENER_PERIOD, ui_rx);

        match Context::new(
            filepath,
            self.audio_ctrl.get_dbl_buffer_mtx(),
            self.video_ctrl.video_box.clone(),
            ctx_tx
        ) {
            Ok(context) => {
                self.context = Some(context);
            },
            Err(error) => eprintln!("Error opening media: {}", error),
        };
    }
}
<|endoftext|>


<commit_before>extern crate gtk;
extern crate glib;
extern crate gstreamer as gst;

use std::rc::{Rc, Weak};
use std::cell::RefCell;

use std::path::PathBuf;

use std::sync::mpsc::{channel, Receiver, Sender};

use gtk::prelude::*;
use gtk::{ApplicationWindow, Button, FileChooserAction, FileChooserDialog,
          HeaderBar, ResponseType, Label, ToolButton};

use ::media::{Context, ContextMessage, Timestamp};
use ::media::ContextMessage::*;

use super::{AudioController, InfoController, VideoController};

pub struct MainController {
    window: ApplicationWindow,
    header_bar: HeaderBar,
    play_pause_btn: ToolButton,
    position_lbl: Label,
    info_ctrl: InfoController,
    video_ctrl: VideoController,
    audio_ctrl: Rc<RefCell<AudioController>>,

    ctx: Option<Context>,

    self_weak: Option<Weak<RefCell<MainController>>>,
    listener_src: Option<glib::SourceId>
}

impl MainController {
    pub fn new(builder: gtk::Builder) -> Rc<RefCell<Self>> {
        let this = Rc::new(RefCell::new(MainController {
            window: builder.get_object("application-window").unwrap(),
            header_bar: builder.get_object("header-bar").unwrap(),
            play_pause_btn: builder.get_object("play_pause-toolbutton").unwrap(),
            position_lbl: builder.get_object("position-lbl").unwrap(),
            info_ctrl: InfoController::new(&builder),
            video_ctrl: VideoController::new(&builder),
            audio_ctrl: AudioController::new(&builder),
            ctx: None,
            self_weak: None,
            listener_src: None,
        }));

        let this_weak = Rc::downgrade(&this);
        {
            let mut this_mut = this.borrow_mut();
            this_mut.window.connect_delete_event(|_, _| {
                gtk::main_quit();
                Inhibit(false)
            });
            this_mut.window.set_titlebar(&this_mut.header_bar);

            let this_weak_clone = this_weak.clone();
            this_mut.play_pause_btn.connect_clicked(move |_| {
                let this = this_weak_clone.upgrade()
                    .expect("Main controller is no longer available for play/pause");
                this.borrow_mut().play_pause();
            });

            let this_weak = Rc::downgrade(&this);
            this_mut.self_weak = Some(this_weak);
        }

        let open_btn: Button = builder.get_object("open-btn").unwrap();
        let this_weak_clone = this_weak.clone();
        open_btn.connect_clicked(move |_| {
            let this = this_weak_clone.upgrade()
                .expect("Main controller is no longer available for select_media");
            this.borrow_mut().select_media();
        });

        this
    }

    pub fn show_all(&self) {
        self.window.show_all();
    }

    pub fn play_pause(&mut self) {
        match self.ctx {
            Some(ref mut ctx) => match ctx.play_pause().unwrap() {
                gst::State::Playing => self.play_pause_btn.set_icon_name("media-playback-pause"),
                gst::State::Paused => {
                    self.play_pause_btn.set_icon_name("media-playback-start");
                    self.audio_ctrl.borrow_mut().force_redraw();
                },
                _ => (),
            },
            None => (),
        };
    }

    pub fn stop(&mut self) {
        if let Some(context) = self.ctx.as_mut() {
            context.stop();
            if let Some(source_id) = self.listener_src {
                // remove listerner in order to avoid conflict on borrowing of self
                glib::source_remove(source_id);
            }
            self.listener_src = None;
        }
        self.play_pause_btn.set_icon_name("media-playback-start");
    }

    fn process_message(&mut self,
        message: ContextMessage,
        ui_tx_opt: Option<&Sender<ContextMessage>>
    ) -> bool
    {
        let mut keep_going = true;
        match message {
            AsyncDone => {
                println!("Received AsyncDone");
            },
            InitDone => {
                println!("Received InitDone");

                let context = self.ctx.as_ref()
                    .expect("Received InitDone, but context is not available");

                self.info_ctrl.new_media(context);
                self.video_ctrl.new_media(context);
                self.audio_ctrl.borrow_mut().new_media(context);

                self.header_bar.set_subtitle(Some(context.file_name.as_str()));
            },
            Eos => {
                println!("Received Eos");
                self.play_pause_btn.set_icon_name("media-playback-start");
                // TODO: seek to the begining
                keep_going = false;
            },
            FailedToOpenMedia => {
                eprintln!("ERROR: failed to open media");
                self.ctx = None;
                keep_going = false;
            },
            HaveAudioBuffer(audio_buffer) => {
                self.audio_ctrl.borrow_mut().have_buffer(audio_buffer);
            },
            HaveVideoWidget(video_widget) => {
                //println!("Received HaveVideoWidget");
                let ui_tx = ui_tx_opt.as_ref()
                    .expect("Received HaveVideoWidget, but no ui_tx is defined");
                self.video_ctrl.have_widget(video_widget);
                ui_tx.send(GotVideoWidget)
                    .expect("Failed to send GotVideoWidget to context");
            },
            _ => {
                eprintln!("Received an unexpected message => will quit listner");
                keep_going = false;
            },
        };

        if !keep_going {
            self.listener_src = None;
        }

        keep_going
    }

    fn select_media(&mut self) {
        self.stop();

        let file_dlg = FileChooserDialog::new(
            Some("Open a media file"),
            Some(&self.window),
            FileChooserAction::Open,
        );
        // Note: couldn't find equivalents for STOCK_OK
        file_dlg.add_button("Open", ResponseType::Ok.into());

        let result = file_dlg.run();

        if result == ResponseType::Ok.into() {
            self.open_media(file_dlg.get_filename().unwrap());
        }
        else { () }

        file_dlg.close();
    }

    // TODO: change name `listener` as it is no longer just a listener
    // but rather a controller loop
    fn register_listener(&mut self,
        ui_rx: Receiver<ContextMessage>,
        timeout: u32,
        ui_tx_opt: Option<Sender<ContextMessage>>,
    )
    {
        let this_weak = self.self_weak.as_ref()
            .expect("Failed to get ref on MainController's weak Rc for register_listener")
            .clone();

        self.listener_src = Some(gtk::timeout_add(timeout, move || {
            let mut keep_going = true;
            let mut msg_iter = ui_rx.try_iter();

            let this = this_weak.upgrade()
                .expect("Main controller is no longer available for ctx channel listener");
            let mut this_mut = this.borrow_mut();

            for msg in msg_iter.next() {
                keep_going = this_mut.process_message(msg, ui_tx_opt.as_ref());
                if !keep_going { break; }
            }

            let position = match this_mut.ctx {
                Some(ref ctx) => if ctx.state == gst::State::Playing {
                    let position = Timestamp::from_nano(ctx.get_position());
                    this_mut.position_lbl.set_text(&format!("{}", position));
                    position
                }
                else {
                    Timestamp::new()
                },
                None => Timestamp::new(),
            };

            if position.nano > 0 {
                this_mut.audio_ctrl.borrow_mut().have_position(position.nano);
            }

            if !keep_going { println!("Exiting listener"); }
            glib::Continue(keep_going)
        }));
    }

    fn open_media(&mut self, filepath: PathBuf) {
        assert_eq!(self.listener_src, None);

        self.audio_ctrl.borrow_mut().clear();
        self.position_lbl.set_text("00:00.000");

        let (ctx_tx, ui_rx) = channel();
        let (ui_tx, ctx_rx) = channel();

        self.register_listener(ui_rx, 20, Some(ui_tx));

        match Context::open_media_path(filepath, ctx_tx, ctx_rx) {
            Ok(ctx) => self.ctx = Some(ctx),
            Err(error) => eprintln!("Error opening media: {}", error),
        };
    }
}
<commit_msg>Split msg listerner and position tracker (#20)<commit_after>extern crate gtk;
extern crate glib;
extern crate gstreamer as gst;

use std::rc::{Rc, Weak};
use std::cell::RefCell;

use std::path::PathBuf;

use std::sync::mpsc::{channel, Receiver, Sender};

use gtk::prelude::*;
use gtk::{ApplicationWindow, Button, FileChooserAction, FileChooserDialog,
          HeaderBar, ResponseType, Label, ToolButton};

use ::media::{Context, ContextMessage, Timestamp};
use ::media::ContextMessage::*;

use super::{AudioController, InfoController, VideoController};

pub struct MainController {
    window: ApplicationWindow,
    header_bar: HeaderBar,
    play_pause_btn: ToolButton,
    position_lbl: Label,
    info_ctrl: InfoController,
    video_ctrl: VideoController,
    audio_ctrl: Rc<RefCell<AudioController>>,

    ctx: Option<Context>,

    self_weak: Option<Weak<RefCell<MainController>>>,
    keep_going: bool,
    listener_src: Option<glib::SourceId>,
    listener_calls: usize,
    listener_usefull_calls: usize,
    tracker_src: Option<glib::SourceId>,
}

impl MainController {
    pub fn new(builder: gtk::Builder) -> Rc<RefCell<Self>> {
        let this = Rc::new(RefCell::new(MainController {
            window: builder.get_object("application-window").unwrap(),
            header_bar: builder.get_object("header-bar").unwrap(),
            play_pause_btn: builder.get_object("play_pause-toolbutton").unwrap(),
            position_lbl: builder.get_object("position-lbl").unwrap(),
            info_ctrl: InfoController::new(&builder),
            video_ctrl: VideoController::new(&builder),
            audio_ctrl: AudioController::new(&builder),
            ctx: None,
            self_weak: None,
            keep_going: true,
            listener_src: None,
            listener_calls: 0,
            listener_usefull_calls: 0,
            tracker_src: None,
        }));

        let this_weak = Rc::downgrade(&this);
        {
            let mut this_mut = this.borrow_mut();
            this_mut.window.connect_delete_event(|_, _| {
                gtk::main_quit();
                Inhibit(false)
            });
            this_mut.window.set_titlebar(&this_mut.header_bar);

            let this_weak_clone = this_weak.clone();
            this_mut.play_pause_btn.connect_clicked(move |_| {
                let this = this_weak_clone.upgrade()
                    .expect("Main controller is no longer available for play/pause");
                this.borrow_mut().play_pause();
            });

            let this_weak = Rc::downgrade(&this);
            this_mut.self_weak = Some(this_weak);
        }

        let open_btn: Button = builder.get_object("open-btn").unwrap();
        let this_weak_clone = this_weak.clone();
        open_btn.connect_clicked(move |_| {
            let this = this_weak_clone.upgrade()
                .expect("Main controller is no longer available for select_media");
            this.borrow_mut().select_media();
        });

        this
    }

    pub fn show_all(&self) {
        self.window.show_all();
    }

    pub fn play_pause(&mut self) {
        match self.ctx {
            Some(ref mut ctx) => match ctx.play_pause().unwrap() {
                gst::State::Playing => self.play_pause_btn.set_icon_name("media-playback-pause"),
                gst::State::Paused => {
                    self.play_pause_btn.set_icon_name("media-playback-start");
                    self.audio_ctrl.borrow_mut().force_redraw();
                },
                _ => (),
            },
            None => (),
        };
    }

    pub fn stop(&mut self) {
        if let Some(context) = self.ctx.as_mut() {
            context.stop();

            println!("Listener usefull calls: {} / {} ({}%)",
                self.listener_calls, self.listener_usefull_calls,
                100 * self.listener_usefull_calls / self.listener_calls,
            );

            self.listener_calls = 0;
            self.listener_usefull_calls = 0;

            // remove callbacks in order to avoid conflict on borrowing of self
            if let Some(source_id) = self.listener_src {
                glib::source_remove(source_id);
            }
            self.listener_src = None;
            if let Some(source_id) = self.tracker_src {
                glib::source_remove(source_id);
            }
            self.tracker_src = None;
        }
        self.play_pause_btn.set_icon_name("media-playback-start");
    }

    fn select_media(&mut self) {
        self.stop();

        let file_dlg = FileChooserDialog::new(
            Some("Open a media file"),
            Some(&self.window),
            FileChooserAction::Open,
        );
        // Note: couldn't find equivalents for STOCK_OK
        file_dlg.add_button("Open", ResponseType::Ok.into());

        let result = file_dlg.run();

        if result == ResponseType::Ok.into() {
            self.open_media(file_dlg.get_filename().unwrap());
        }
        else { () }

        file_dlg.close();
    }

    fn register_listener(&mut self,
        ui_rx: Receiver<ContextMessage>,
        timeout: u32,
        ui_tx_opt: Option<Sender<ContextMessage>>,
    )
    {
        let this_weak = self.self_weak.as_ref()
            .expect("Failed to get ref on MainController's weak Rc for register_listener")
            .clone();

        self.listener_src = Some(gtk::timeout_add(timeout, move || {
            let mut message_iter = ui_rx.try_iter();

            let this = this_weak.upgrade()
                .expect("Main controller is no longer available for ctx channel listener");
            let mut this_mut = this.borrow_mut();
            this_mut.listener_calls += 1;

            let mut was_usefull = false;
            for message in message_iter.next() {
                was_usefull = true;

                match message {
                    AsyncDone => {
                        println!("Received AsyncDone");
                    },
                    InitDone => {
                        println!("Received InitDone");

                        let context = this_mut.ctx.take()
                            .expect("Received InitDone, but context is not available");

                        this_mut.info_ctrl.new_media(&context);
                        this_mut.video_ctrl.new_media(&context);
                        this_mut.audio_ctrl.borrow_mut().new_media(&context);
                        {
                            this_mut.header_bar.set_subtitle(Some(context.file_name.as_str()));
                        }

                        this_mut.ctx = Some(context);
                    },
                    Eos => {
                        println!("Received Eos");
                        this_mut.play_pause_btn.set_icon_name("media-playback-start");
                        // TODO: seek to the begining
                        this_mut.keep_going = false;
                    },
                    FailedToOpenMedia => {
                        eprintln!("ERROR: failed to open media");
                        this_mut.ctx = None;
                        this_mut.keep_going = false;
                    },
                    HaveAudioBuffer(audio_buffer) => {
                        this_mut.audio_ctrl.borrow_mut().have_buffer(audio_buffer);
                    },
                    HaveVideoWidget(video_widget) => {
                        //println!("Received HaveVideoWidget");
                        let ui_tx = ui_tx_opt.as_ref()
                            .expect("Received HaveVideoWidget, but no ui_tx is defined");
                        this_mut.video_ctrl.have_widget(video_widget);
                        ui_tx.send(GotVideoWidget)
                            .expect("Failed to send GotVideoWidget to context");
                    },
                    _ => {
                        eprintln!("Received an unexpected message => will quit listner");
                        this_mut.keep_going = false;
                    },
                };

                if !this_mut.keep_going { break; }
            }

            if was_usefull {
                this_mut.listener_usefull_calls += 1;
            }

            if !this_mut.keep_going {
                this_mut.listener_src = None;
                println!("Exiting listener");
            }

            glib::Continue(this_mut.keep_going)
        }));
    }

    fn register_tracker(&mut self, timeout: u32) {
        let this_weak = self.self_weak.as_ref()
            .expect("Failed to get ref on MainController's weak Rc for register_tracker")
            .clone();

        self.tracker_src = Some(gtk::timeout_add(timeout, move || {
            let this = this_weak.upgrade()
                .expect("Main controller is no longer available for tracker");
            let mut this_mut = this.borrow_mut();
            if !this_mut.keep_going {
            }

            let position = match this_mut.ctx {
                Some(ref ctx) => if ctx.state == gst::State::Playing {
                    let position = Timestamp::from_nano(ctx.get_position());
                    this_mut.position_lbl.set_text(&format!("{}", position));
                    position
                }
                else {
                    Timestamp::new()
                },
                None => Timestamp::new(),
            };

            if position.nano > 0 {
                this_mut.audio_ctrl.borrow_mut().have_position(position.nano);
            }

            if !this_mut.keep_going {
                this_mut.tracker_src = None;
                println!("Exiting tracker");
            }

            glib::Continue(this_mut.keep_going)
        }));
    }

    fn open_media(&mut self, filepath: PathBuf) {
        assert_eq!(self.listener_src, None);

        self.audio_ctrl.borrow_mut().clear();
        self.position_lbl.set_text("00:00.000");

        let (ctx_tx, ui_rx) = channel();
        let (ui_tx, ctx_rx) = channel();

        self.keep_going = true;
        self.register_listener(ui_rx, 13, Some(ui_tx));
        self.register_tracker(31);

        match Context::open_media_path(filepath, ctx_tx, ctx_rx) {
            Ok(ctx) => self.ctx = Some(ctx),
            Err(error) => eprintln!("Error opening media: {}", error),
        };
    }
}
<|endoftext|>


<commit_before>/* Cymbalum, Molecular Simulation in Rust - Copyright (C) 2015 Guillaume Fraux
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
 */

//! `Particle` type and manipulation.

use ::types::Vector3D;
use super::PeriodicTable;

/// The Particle type hold basic data about a particle in the system. It is self
/// contained, so that it will be easy to send data between parrallels
/// processes.
#[derive(Clone, Debug)]
pub struct Particle {
    /// Particle name
    name: String,
    /// Particle kind, an index for potentials lookup
    kind: u16,
    /// Particle mass
    mass: f64,
    /// Particle positions
    position: Vector3D,
    /// Particle velocity, if needed
    velocity: Vector3D,
}

impl Particle {
    /// Create a new `Particle` from a name
    pub fn new<S: Into<String>>(n: S) -> Particle {
        let name = n.into();
        let mass = match PeriodicTable::mass(&*name) {
            Some(val) => val,
            None => panic!("Could not find the mass for the {} particle", name)
        };
        Particle{name: name,
                 mass: mass as f64,
                 kind: u16::max_value(),
                 position: Vector3D::new(0.0, 0.0, 0.0),
                 velocity: Vector3D::new(0.0, 0.0, 0.0)}
    }

    /// Get the particle name
    #[inline] pub fn name<'a>(&'a self) -> &'a str {
        &self.name
    }

    /// Set the particle name
    #[inline] pub fn set_name<S>(&mut self, name: S) where S: Into<String> {
        self.name = name.into();
    }

    /// Get the particle kind. This kind is used for fast lookup in interactions
    /// tables
    #[inline] pub fn kind(&self) -> u16 {
        self.kind
    }

    /// Set the particle kind.
    #[inline] pub fn set_kind(&mut self, kind: u16) {
        self.kind = kind;
    }

    /// Get the particle mass
    #[inline] pub fn mass(&self) -> f64 {
        self.mass
    }

    /// Set the particle mass
    #[inline] pub fn set_mass(&mut self, mass: f64) {
        self.mass = mass;
    }

    /// Get the particle position
    #[inline] pub fn position<'a>(&'a self) -> &'a Vector3D {
        &self.position
    }

    /// Set the particle position
    #[inline] pub fn set_position(&mut self, pos: Vector3D) {
        self.position = pos;
    }

    /// Add `dr` to the particle position
    #[inline] pub fn add_position(&mut self, dr: Vector3D) {
        self.position = self.position + dr;
    }

    /// Get the particle velocity
    #[inline] pub fn velocity<'a>(&'a self) -> &'a Vector3D {
        &self.velocity
    }

    /// Set the particle velocity
    #[inline] pub fn set_velocity(&mut self, vel: Vector3D) {
        self.velocity = vel;
    }

    /// Add `dv` to the particle velocity
    #[inline] pub fn add_velocity(&mut self, dv: Vector3D) {
        self.velocity = self.velocity + dv;
    }
}

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

    #[test]
    fn name() {
        let mut part = Particle::new("O");
        assert_eq!(part.name(), "O");

        part.set_name("H");
        assert_eq!(part.name(), "H");

        let name = "Zn";
        part.set_name(name);
        assert_eq!(part.name(), "Zn");
    }

    #[test]
    fn mass() {
        let mut part = Particle::new("O");
        part.set_mass(16.0);
        assert_eq!(part.mass(), 16.0);
    }

    #[test]
    fn kind() {
        let mut part = Particle::new("O");
        part.set_kind(42);
        assert_eq!(part.kind(), 42);
    }

    #[test]
    fn coordinates() {
        let mut part = Particle::new("O");
        assert_eq!(part.position(), &Vector3D::new(0.0, 0.0, 0.0));

        part.set_position(Vector3D::new(1.0, 2.0, 3.0));
        assert_eq!(part.position(), &Vector3D::new(1.0, 2.0, 3.0));

        part.set_velocity(Vector3D::new(1.0, 2.0, 3.0));
        assert_eq!(part.velocity(), &Vector3D::new(1.0, 2.0, 3.0));
    }
}
<commit_msg>Add a charge field in Particle<commit_after>/* Cymbalum, Molecular Simulation in Rust - Copyright (C) 2015 Guillaume Fraux
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
 */

//! `Particle` type and manipulation.

use ::types::Vector3D;
use super::PeriodicTable;

/// The Particle type hold basic data about a particle in the system. It is self
/// contained, so that it will be easy to send data between parrallels
/// processes.
#[derive(Clone, Debug)]
pub struct Particle {
    /// Particle name
    name: String,
    /// Particle kind, an index for potentials lookup
    kind: u16,
    /// Particle mass
    mass: f64,
    /// Particle charge
    charge: f64,
    /// Particle positions
    position: Vector3D,
    /// Particle velocity, if needed
    velocity: Vector3D,
}

impl Particle {
    /// Create a new `Particle` from a name
    pub fn new<S: Into<String>>(n: S) -> Particle {
        let name = n.into();
        let mass = match PeriodicTable::mass(&*name) {
            Some(val) => val,
            None => panic!("Could not find the mass for the {} particle", name)
        };
        Particle{name: name,
                 mass: mass as f64,
                 charge: 0.0,
                 kind: u16::max_value(),
                 position: Vector3D::new(0.0, 0.0, 0.0),
                 velocity: Vector3D::new(0.0, 0.0, 0.0)}
    }

    /// Get the particle name
    #[inline] pub fn name<'a>(&'a self) -> &'a str {
        &self.name
    }

    /// Set the particle name
    #[inline] pub fn set_name<S>(&mut self, name: S) where S: Into<String> {
        self.name = name.into();
    }

    /// Get the particle kind. This kind is used for fast lookup in interactions
    /// tables
    #[inline] pub fn kind(&self) -> u16 {
        self.kind
    }

    /// Set the particle kind.
    #[inline] pub fn set_kind(&mut self, kind: u16) {
        self.kind = kind;
    }

    /// Get the particle mass
    #[inline] pub fn mass(&self) -> f64 {
        self.mass
    }

    /// Set the particle mass
    #[inline] pub fn set_mass(&mut self, mass: f64) {
        self.mass = mass;
    }

    /// Get the particle charge
    #[inline] pub fn charge(&self) -> f64 {
        self.charge
    }

    /// Set the particle charge
    #[inline] pub fn set_charge(&mut self, charge: f64) {
        self.charge = charge;
    }

    /// Get the particle position
    #[inline] pub fn position<'a>(&'a self) -> &'a Vector3D {
        &self.position
    }

    /// Set the particle position
    #[inline] pub fn set_position(&mut self, pos: Vector3D) {
        self.position = pos;
    }

    /// Add `dr` to the particle position
    #[inline] pub fn add_position(&mut self, dr: Vector3D) {
        self.position = self.position + dr;
    }

    /// Get the particle velocity
    #[inline] pub fn velocity<'a>(&'a self) -> &'a Vector3D {
        &self.velocity
    }

    /// Set the particle velocity
    #[inline] pub fn set_velocity(&mut self, vel: Vector3D) {
        self.velocity = vel;
    }

    /// Add `dv` to the particle velocity
    #[inline] pub fn add_velocity(&mut self, dv: Vector3D) {
        self.velocity = self.velocity + dv;
    }
}

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

    #[test]
    fn name() {
        let mut part = Particle::new("O");
        assert_eq!(part.name(), "O");

        part.set_name("H");
        assert_eq!(part.name(), "H");

        let name = "Zn";
        part.set_name(name);
        assert_eq!(part.name(), "Zn");
    }

    #[test]
    fn mass() {
        let mut part = Particle::new("O");
        part.set_mass(16.0);
        assert_eq!(part.mass(), 16.0);
    }

    #[test]
    fn charge() {
        let mut part = Particle::new("O");
        assert_eq!(part.charge(), 0.0);
        part.set_charge(-1.0);
        assert_eq!(part.charge(), -1.0);
    }

    #[test]
    fn kind() {
        let mut part = Particle::new("O");
        part.set_kind(42);
        assert_eq!(part.kind(), 42);
    }

    #[test]
    fn coordinates() {
        let mut part = Particle::new("O");
        assert_eq!(part.position(), &Vector3D::new(0.0, 0.0, 0.0));

        part.set_position(Vector3D::new(1.0, 2.0, 3.0));
        assert_eq!(part.position(), &Vector3D::new(1.0, 2.0, 3.0));

        part.set_velocity(Vector3D::new(1.0, 2.0, 3.0));
        assert_eq!(part.velocity(), &Vector3D::new(1.0, 2.0, 3.0));
    }
}
<|endoftext|>


<commit_before>use tensor::{Tensor, NumLimits, THVec, THVecGeneric, THDims};
use num::NumCast;

impl<T: NumLimits> THVec<T> {
    pub fn new(dims: Vec<usize>, data: Vec<T>) -> Self {
        THVec {
            dims: dims,
            data: data,
        }
    }
}
impl THVecGeneric {
    pub fn new(dims: Vec<usize>, data: Vec<i64>) -> Self {
        THVecGeneric {
            dims: dims,
            data: data,
        }
    }
}
impl THDims {
    fn new(dims: Vec<usize>) -> Self {
        THDims { dims: dims }
    }
}
impl<T: NumLimits> From<Vec<Vec<Vec<T>>>> for THVec<T> {
    fn from(input: Vec<Vec<Vec<T>>>) -> Self {
        let dims = vec![input.len(), input[0].len(), input[0][0].len()];
        let v = input
            .iter()
            .flat_map(|d| d.iter())
            .flat_map(|d| d.iter())
            .map(|d| *d)
            .collect();
        THVec::new(dims, v)
    }
}
impl<T: NumLimits> From<Vec<Vec<T>>> for THVec<T> {
    fn from(input: Vec<Vec<T>>) -> Self {
        let dims = vec![input.len(), input[0].len()];
        let v = input.iter().flat_map(|d| d.iter()).map(|d| *d).collect();
        THVec::new(dims, v)
    }
}
impl<T: NumLimits> From<Vec<T>> for THVec<T> {
    fn from(input: Vec<T>) -> Self {
        let dims = vec![input.len()];
        THVec::new(dims, input)
    }
}
impl<T: NumLimits> From<T> for THVec<T> {
    fn from(input: T) -> Self {
        let v = vec![input];
        THVec::new(vec![], v)
    }
}
impl<T: NumLimits> From<T> for THVecGeneric {
    fn from(input: T) -> Self {
        let v: Vec<i64> = vec![<i64 as NumCast>::from(input).unwrap()];
        THVecGeneric::new(vec![], v)
    }
}

#[allow(unused_variables)]
impl<T: NumLimits> From<()> for THVec<T> {
    fn from(input: ()) -> Self {
        THVec::new(vec![], vec![])
    }
}
#[allow(unused_variables)]
impl From<()> for THVecGeneric {
    fn from(input: ()) -> Self {
        THVecGeneric::new(vec![], vec![])
    }
}
#[allow(unused_variables)]
impl From<()> for THDims {
    fn from(input: ()) -> Self {
        THDims::new(vec![])
    }
}
impl<T: NumLimits> From<(usize, usize)> for THVec<T> {
    fn from(input: (usize, usize)) -> Self {
        THVec::new(vec![input.0, input.1], vec![])
    }
}
impl From<(usize, usize)> for THVecGeneric {
    fn from(input: (usize, usize)) -> Self {

        THVecGeneric::new(vec![input.0, input.1], vec![])
    }
}
impl From<(usize)> for THVecGeneric {
    fn from(input: (usize)) -> Self {

        THVecGeneric::new(vec![input], vec![])
    }
}
impl<T: NumLimits> From<(usize)> for THVec<T> {
    fn from(input: (usize)) -> Self {
        THVec::new(vec![input], vec![])
    }
}
impl<T: NumLimits> From<Vec<usize>> for THVec<T> {
    fn from(input: Vec<usize>) -> Self {
        THVec::new(input, vec![])
    }
}
impl From<Vec<usize>> for THVecGeneric {
    fn from(input: Vec<usize>) -> Self {
        THVecGeneric::new(input, vec![])
    }
}
impl From<Vec<usize>> for THDims {
    fn from(input: Vec<usize>) -> Self {
        THDims::new(input)
    }
}
impl<S: NumLimits, D: NumLimits> From<Tensor<S>> for THVec<D> {
    fn from(input: Tensor<S>) -> Self {
        unimplemented!()
    }
}
impl<T: NumLimits> From<Vec<THVec<T>>> for THVec<T> {
    fn from(input: Vec<THVec<T>>) -> Self {
        unimplemented!()
    }
}
impl<S: NumLimits, D: NumLimits> From<Vec<Tensor<S>>> for THVec<D> {
    fn from(input: Vec<Tensor<S>>) -> Self {
        let mut d: Vec<D> = Vec::with_capacity(input.len() * input[0].len());
        let len = input[0].len();
        let mut tmp: Vec<S> = Vec::with_capacity(len);
        for t in input {
            t.get_storage(&mut tmp);
            for j in 0..len {
                d.push(<D as ::num::NumCast>::from(tmp[j]).unwrap());
            }
        }
        let mut sizes = input[0].size();
        let mut dims = vec![input.len()];
        dims.append(&mut sizes);
        THVec::new(dims, d)
    }
}
impl From<THVecGeneric> for THVec<u8> {
    fn from(input: THVecGeneric) -> Self {
        let data: Vec<u8> = input
            .data
            .iter()
            .map(|t| <u8 as NumCast>::from(*t).unwrap())
            .collect();
        THVec::new(input.dims.clone(), data)
    }
}
impl From<THVecGeneric> for THVec<f32> {
    fn from(input: THVecGeneric) -> Self {
        let data: Vec<f32> = input
            .data
            .iter()
            .map(|t| <f32 as NumCast>::from(*t).unwrap())
            .collect();
        THVec::new(input.dims.clone(), data)
    }
}
impl From<THVecGeneric> for THVec<i64> {
    fn from(input: THVecGeneric) -> Self {
        let data: Vec<i64> = input
            .data
            .iter()
            .map(|t| <i64 as NumCast>::from(*t).unwrap())
            .collect();
        THVec::new(input.dims.clone(), data)
    }
}

impl<T: NumLimits> From<THVec<T>> for THDims {
    fn from(input: THVec<T>) -> Self {
        THDims::new(input.dims.clone())
    }
}
impl From<THVecGeneric> for THDims {
    fn from(input: THVecGeneric) -> Self {
        THDims::new(input.dims.clone())
    }
}

trait TensorNew<T: NumLimits> {
    fn tensor_new(arg: THDims) -> Tensor<T>;
}

impl<T: NumLimits> TensorNew<T> for Tensor<T> {
    #[allow(unused_variables)]
    default fn tensor_new(arg: THDims) -> Tensor<T> {
        unreachable!()
    }
}

impl TensorNew<u8> for Tensor<u8> {
    fn tensor_new(arg: THDims) -> Tensor<u8> {
        let t = ::RcMutNew(::tensor::ByteTensor::with_capacity(arg.dims.as_slice()));
        ::tensor::Tensor { value: t }
    }
}
impl TensorNew<i64> for Tensor<i64> {
    fn tensor_new(arg: THDims) -> Tensor<i64> {
        let t = ::RcMutNew(::tensor::LongTensor::with_capacity(arg.dims.as_slice()));
        ::tensor::Tensor { value: t }
    }
}
impl TensorNew<f32> for Tensor<f32> {
    fn tensor_new(arg: THDims) -> Tensor<f32> {
        let t = ::RcMutNew(::tensor::FloatTensor::with_capacity(arg.dims.as_slice()));
        ::tensor::Tensor { value: t }
    }
}
impl TensorNew<f64> for Tensor<f64> {
    fn tensor_new(arg: THDims) -> Tensor<f64> {
        let t = ::RcMutNew(::tensor::DoubleTensor::with_capacity(arg.dims.as_slice()));
        ::tensor::Tensor { value: t }
    }
}

pub fn byte_tensor<T>(arg: T) -> Tensor<u8>
    where T: Into<THVec<u8>>
{
    tensor(arg)
}
pub fn long_tensor<T>(arg: T) -> Tensor<i64>
    where T: Into<THVec<i64>>
{
    tensor(arg)
}
pub fn float_tensor<T>(arg: T) -> Tensor<f32>
    where T: Into<THVec<f32>>
{
    tensor(arg)
}
pub fn double_tensor<T>(arg: T) -> Tensor<f64>
    where T: Into<THVec<f64>>
{
    tensor(arg)
}
pub fn tensor<S, T>(arg: S) -> Tensor<T>
    where T: NumLimits,
          S: Into<THVec<T>>
{
    let t: THVec<T> = arg.into();
    Tensor::tensor_new(t.into())
}
<commit_msg>avoid consuming t<commit_after>use tensor::{Tensor, NumLimits, THVec, THVecGeneric, THDims};
use num::NumCast;

impl<T: NumLimits> THVec<T> {
    pub fn new(dims: Vec<usize>, data: Vec<T>) -> Self {
        THVec {
            dims: dims,
            data: data,
        }
    }
}
impl THVecGeneric {
    pub fn new(dims: Vec<usize>, data: Vec<i64>) -> Self {
        THVecGeneric {
            dims: dims,
            data: data,
        }
    }
}
impl THDims {
    fn new(dims: Vec<usize>) -> Self {
        THDims { dims: dims }
    }
}
impl<T: NumLimits> From<Vec<Vec<Vec<T>>>> for THVec<T> {
    fn from(input: Vec<Vec<Vec<T>>>) -> Self {
        let dims = vec![input.len(), input[0].len(), input[0][0].len()];
        let v = input
            .iter()
            .flat_map(|d| d.iter())
            .flat_map(|d| d.iter())
            .map(|d| *d)
            .collect();
        THVec::new(dims, v)
    }
}
impl<T: NumLimits> From<Vec<Vec<T>>> for THVec<T> {
    fn from(input: Vec<Vec<T>>) -> Self {
        let dims = vec![input.len(), input[0].len()];
        let v = input.iter().flat_map(|d| d.iter()).map(|d| *d).collect();
        THVec::new(dims, v)
    }
}
impl<T: NumLimits> From<Vec<T>> for THVec<T> {
    fn from(input: Vec<T>) -> Self {
        let dims = vec![input.len()];
        THVec::new(dims, input)
    }
}
impl<T: NumLimits> From<T> for THVec<T> {
    fn from(input: T) -> Self {
        let v = vec![input];
        THVec::new(vec![], v)
    }
}
impl<T: NumLimits> From<T> for THVecGeneric {
    fn from(input: T) -> Self {
        let v: Vec<i64> = vec![<i64 as NumCast>::from(input).unwrap()];
        THVecGeneric::new(vec![], v)
    }
}

#[allow(unused_variables)]
impl<T: NumLimits> From<()> for THVec<T> {
    fn from(input: ()) -> Self {
        THVec::new(vec![], vec![])
    }
}
#[allow(unused_variables)]
impl From<()> for THVecGeneric {
    fn from(input: ()) -> Self {
        THVecGeneric::new(vec![], vec![])
    }
}
#[allow(unused_variables)]
impl From<()> for THDims {
    fn from(input: ()) -> Self {
        THDims::new(vec![])
    }
}
impl<T: NumLimits> From<(usize, usize)> for THVec<T> {
    fn from(input: (usize, usize)) -> Self {
        THVec::new(vec![input.0, input.1], vec![])
    }
}
impl From<(usize, usize)> for THVecGeneric {
    fn from(input: (usize, usize)) -> Self {

        THVecGeneric::new(vec![input.0, input.1], vec![])
    }
}
impl From<(usize)> for THVecGeneric {
    fn from(input: (usize)) -> Self {

        THVecGeneric::new(vec![input], vec![])
    }
}
impl<T: NumLimits> From<(usize)> for THVec<T> {
    fn from(input: (usize)) -> Self {
        THVec::new(vec![input], vec![])
    }
}
impl<T: NumLimits> From<Vec<usize>> for THVec<T> {
    fn from(input: Vec<usize>) -> Self {
        THVec::new(input, vec![])
    }
}
impl From<Vec<usize>> for THVecGeneric {
    fn from(input: Vec<usize>) -> Self {
        THVecGeneric::new(input, vec![])
    }
}
impl From<Vec<usize>> for THDims {
    fn from(input: Vec<usize>) -> Self {
        THDims::new(input)
    }
}
impl<S: NumLimits, D: NumLimits> From<Tensor<S>> for THVec<D> {
    fn from(input: Tensor<S>) -> Self {
        unimplemented!()
    }
}
impl<T: NumLimits> From<Vec<THVec<T>>> for THVec<T> {
    fn from(input: Vec<THVec<T>>) -> Self {
        unimplemented!()
    }
}
impl<S: NumLimits, D: NumLimits> From<Vec<Tensor<S>>> for THVec<D> {
    fn from(input: Vec<Tensor<S>>) -> Self {
        let mut d: Vec<D> = Vec::with_capacity(input.len() * input[0].len());
        let len = input[0].len();
        let mut tmp: Vec<S> = Vec::with_capacity(len);
        for t in &input {
            t.get_storage(&mut tmp);
            for j in 0..len {
                d.push(<D as ::num::NumCast>::from(tmp[j]).unwrap());
            }
        }
        let mut sizes = input[0].size();
        let mut dims = vec![input.len()];
        dims.append(&mut sizes);
        THVec::new(dims, d)
    }
}
impl From<THVecGeneric> for THVec<u8> {
    fn from(input: THVecGeneric) -> Self {
        let data: Vec<u8> = input
            .data
            .iter()
            .map(|t| <u8 as NumCast>::from(*t).unwrap())
            .collect();
        THVec::new(input.dims.clone(), data)
    }
}
impl From<THVecGeneric> for THVec<f32> {
    fn from(input: THVecGeneric) -> Self {
        let data: Vec<f32> = input
            .data
            .iter()
            .map(|t| <f32 as NumCast>::from(*t).unwrap())
            .collect();
        THVec::new(input.dims.clone(), data)
    }
}
impl From<THVecGeneric> for THVec<i64> {
    fn from(input: THVecGeneric) -> Self {
        let data: Vec<i64> = input
            .data
            .iter()
            .map(|t| <i64 as NumCast>::from(*t).unwrap())
            .collect();
        THVec::new(input.dims.clone(), data)
    }
}

impl<T: NumLimits> From<THVec<T>> for THDims {
    fn from(input: THVec<T>) -> Self {
        THDims::new(input.dims.clone())
    }
}
impl From<THVecGeneric> for THDims {
    fn from(input: THVecGeneric) -> Self {
        THDims::new(input.dims.clone())
    }
}

trait TensorNew<T: NumLimits> {
    fn tensor_new(arg: THDims) -> Tensor<T>;
}

impl<T: NumLimits> TensorNew<T> for Tensor<T> {
    #[allow(unused_variables)]
    default fn tensor_new(arg: THDims) -> Tensor<T> {
        unreachable!()
    }
}

impl TensorNew<u8> for Tensor<u8> {
    fn tensor_new(arg: THDims) -> Tensor<u8> {
        let t = ::RcMutNew(::tensor::ByteTensor::with_capacity(arg.dims.as_slice()));
        ::tensor::Tensor { value: t }
    }
}
impl TensorNew<i64> for Tensor<i64> {
    fn tensor_new(arg: THDims) -> Tensor<i64> {
        let t = ::RcMutNew(::tensor::LongTensor::with_capacity(arg.dims.as_slice()));
        ::tensor::Tensor { value: t }
    }
}
impl TensorNew<f32> for Tensor<f32> {
    fn tensor_new(arg: THDims) -> Tensor<f32> {
        let t = ::RcMutNew(::tensor::FloatTensor::with_capacity(arg.dims.as_slice()));
        ::tensor::Tensor { value: t }
    }
}
impl TensorNew<f64> for Tensor<f64> {
    fn tensor_new(arg: THDims) -> Tensor<f64> {
        let t = ::RcMutNew(::tensor::DoubleTensor::with_capacity(arg.dims.as_slice()));
        ::tensor::Tensor { value: t }
    }
}

pub fn byte_tensor<T>(arg: T) -> Tensor<u8>
    where T: Into<THVec<u8>>
{
    tensor(arg)
}
pub fn long_tensor<T>(arg: T) -> Tensor<i64>
    where T: Into<THVec<i64>>
{
    tensor(arg)
}
pub fn float_tensor<T>(arg: T) -> Tensor<f32>
    where T: Into<THVec<f32>>
{
    tensor(arg)
}
pub fn double_tensor<T>(arg: T) -> Tensor<f64>
    where T: Into<THVec<f64>>
{
    tensor(arg)
}
pub fn tensor<S, T>(arg: S) -> Tensor<T>
    where T: NumLimits,
          S: Into<THVec<T>>
{
    let t: THVec<T> = arg.into();
    Tensor::tensor_new(t.into())
}
<|endoftext|>


<commit_before>use cache::Cache;
use client_query::*;
use dns;
use mio::*;
use nix::sys::socket::{bind, setsockopt, sockopt, AddressFamily, SockFlag, SockType, SockLevel, SockAddr, socket, InetAddr};
use std::io;
use std::net::{UdpSocket, SocketAddr};
use std::os::unix::io::{RawFd, FromRawFd};
use std::str::FromStr;
use std::sync::Arc;
use std::sync::atomic::Ordering;
use std::thread;
use std::time::Instant;
use super::RPDNSContext;
use varz::Varz;

use super::{UDP_BUFFER_SIZE, DNS_MAX_UDP_SIZE, DNS_QUERY_MIN_SIZE, DNS_QUERY_MAX_SIZE};

pub struct UdpListener {
    socket: UdpSocket,
    resolver_tx: Sender<ClientQuery>,
    cache: Cache,
    varz: Arc<Varz>
}

impl UdpListener {
    fn run(mut self) -> io::Result<()> {
        debug!("udp listener socket={:?}", self.socket);
        let mut packet = [0u8; DNS_MAX_UDP_SIZE];
        loop {
            let (count, client_addr) = self.socket.recv_from(&mut packet).expect("UDP socket error");
            self.varz.client_queries_udp.fetch_add(1, Ordering::Relaxed);
            if count < DNS_QUERY_MIN_SIZE || count > DNS_QUERY_MAX_SIZE {
                info!("Short query using UDP");
                self.varz.client_queries_errors.fetch_add(1, Ordering::Relaxed);
                continue;
            }
            let packet = &packet[..count];
            let normalized_question = match dns::normalize(&packet, true) {
                Ok(normalized_question) => normalized_question,
                Err(e) => {
                    debug!("Error while parsing the question: {}", e);
                    self.varz.client_queries_errors.fetch_add(1, Ordering::Relaxed);
                    continue;
                }
            };
            let cache_entry = self.cache.get2(&normalized_question);
            if let Some(mut cache_entry) = cache_entry {
                if ! cache_entry.is_expired() {
                    self.varz.client_queries_cached.fetch_add(1, Ordering::Relaxed);
                    if cache_entry.packet.len() > normalized_question.payload_size as usize {
                        debug!("cached, but has to be truncated");
                        let packet = dns::build_tc_packet(&normalized_question).unwrap();
                        let _ = self.socket.send_to(&packet, &client_addr);
                        continue;
                    }
                    debug!("cached");
                    dns::set_tid(&mut cache_entry.packet, normalized_question.tid);
                    dns::overwrite_qname(&mut cache_entry.packet, &normalized_question.qname);
                    let _ = self.socket.send_to(&cache_entry.packet, &client_addr);
                    continue;
                }
                debug!("expired");
                self.varz.client_queries_expired.fetch_add(1, Ordering::Relaxed);
            }
            let client_query = ClientQuery {
                proto: ClientQueryProtocol::UDP,
                client_tok: None,
                client_addr: Some(client_addr),
                tcpclient_tx: None,
                normalized_question: normalized_question,
                ts: Instant::now()
            };
            let _ = self.resolver_tx.send(client_query);
        }
    }

    pub fn spawn(rpdns_context: &RPDNSContext, resolver_tx: Sender<ClientQuery>) -> io::Result<(thread::JoinHandle<()>)> {
        let udp_socket = rpdns_context.udp_socket.try_clone().expect("Unable to clone the UDP listening socket");
        let udp_listener = UdpListener {
            socket: udp_socket,
            resolver_tx: resolver_tx,
            cache: rpdns_context.cache.clone(),
            varz: rpdns_context.varz.clone()
        };
        let udp_listener_th = thread::spawn(move || {
            udp_listener.run().expect("Unable to spawn a UDP listener");
        });
        info!("UDP listener is ready");
        Ok((udp_listener_th))
    }
}

#[cfg(any(target_os = "linux", target_os = "android"))]
fn socket_udp_set_buffer_size(socket_fd: RawFd) {
    let _ = setsockopt(socket_fd, sockopt::SndBufForce, &UDP_BUFFER_SIZE);
    let _ = setsockopt(socket_fd, sockopt::RcvBufForce, &UDP_BUFFER_SIZE);
}

#[cfg(not(any(target_os = "linux", target_os = "android")))]
fn socket_udp_set_buffer_size(socket_fd: RawFd) {
    let _ = setsockopt(socket_fd, sockopt::SndBuf, &UDP_BUFFER_SIZE);
    let _ = setsockopt(socket_fd, sockopt::RcvBuf, &UDP_BUFFER_SIZE);
}

fn socket_udp_v4() -> io::Result<RawFd> {
    let socket_fd = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), SockLevel::Udp as i32)?;
    Ok(socket_fd)
}

fn socket_udp_v6() -> io::Result<RawFd> {
    let socket_fd = socket(AddressFamily::Inet6, SockType::Datagram, SockFlag::empty(), SockLevel::Udp as i32)?;
    Ok(socket_fd)
}

pub fn socket_udp_bound(addr: &str) -> io::Result<UdpSocket> {
    let actual: SocketAddr = FromStr::from_str(addr).expect("Invalid address");
    let nix_addr = SockAddr::Inet(InetAddr::from_std(&actual));
    let socket_fd = match actual {
        SocketAddr::V4(_) => socket_udp_v4()?,
        SocketAddr::V6(_) => socket_udp_v6()?
    };
    let _ = setsockopt(socket_fd, sockopt::ReuseAddr, &true);
    let _ = setsockopt(socket_fd, sockopt::ReusePort, &true);
    socket_udp_set_buffer_size(socket_fd);
    bind(socket_fd, &nix_addr).expect("Unable to bind a UDP socket");
    let socket: UdpSocket = unsafe { UdpSocket::from_raw_fd(socket_fd) };
    Ok(socket)
}
<commit_msg>Reformat<commit_after>use cache::Cache;
use client_query::*;
use dns;
use mio::*;
use nix::sys::socket::{bind, setsockopt, sockopt, AddressFamily, SockFlag, SockType, SockLevel,
                       SockAddr, socket, InetAddr};
use std::io;
use std::net::{UdpSocket, SocketAddr};
use std::os::unix::io::{RawFd, FromRawFd};
use std::str::FromStr;
use std::sync::Arc;
use std::sync::atomic::Ordering;
use std::thread;
use std::time::Instant;
use super::RPDNSContext;
use varz::Varz;

use super::{UDP_BUFFER_SIZE, DNS_MAX_UDP_SIZE, DNS_QUERY_MIN_SIZE, DNS_QUERY_MAX_SIZE};

pub struct UdpListener {
    socket: UdpSocket,
    resolver_tx: Sender<ClientQuery>,
    cache: Cache,
    varz: Arc<Varz>,
}

impl UdpListener {
    fn run(mut self) -> io::Result<()> {
        debug!("udp listener socket={:?}", self.socket);
        let mut packet = [0u8; DNS_MAX_UDP_SIZE];
        loop {
            let (count, client_addr) =
                self.socket.recv_from(&mut packet).expect("UDP socket error");
            self.varz.client_queries_udp.fetch_add(1, Ordering::Relaxed);
            if count < DNS_QUERY_MIN_SIZE || count > DNS_QUERY_MAX_SIZE {
                info!("Short query using UDP");
                self.varz.client_queries_errors.fetch_add(1, Ordering::Relaxed);
                continue;
            }
            let packet = &packet[..count];
            let normalized_question = match dns::normalize(&packet, true) {
                Ok(normalized_question) => normalized_question,
                Err(e) => {
                    debug!("Error while parsing the question: {}", e);
                    self.varz.client_queries_errors.fetch_add(1, Ordering::Relaxed);
                    continue;
                }
            };
            let cache_entry = self.cache.get2(&normalized_question);
            if let Some(mut cache_entry) = cache_entry {
                if !cache_entry.is_expired() {
                    self.varz.client_queries_cached.fetch_add(1, Ordering::Relaxed);
                    if cache_entry.packet.len() > normalized_question.payload_size as usize {
                        debug!("cached, but has to be truncated");
                        let packet = dns::build_tc_packet(&normalized_question).unwrap();
                        let _ = self.socket.send_to(&packet, &client_addr);
                        continue;
                    }
                    debug!("cached");
                    dns::set_tid(&mut cache_entry.packet, normalized_question.tid);
                    dns::overwrite_qname(&mut cache_entry.packet, &normalized_question.qname);
                    let _ = self.socket.send_to(&cache_entry.packet, &client_addr);
                    continue;
                }
                debug!("expired");
                self.varz.client_queries_expired.fetch_add(1, Ordering::Relaxed);
            }
            let client_query = ClientQuery {
                proto: ClientQueryProtocol::UDP,
                client_tok: None,
                client_addr: Some(client_addr),
                tcpclient_tx: None,
                normalized_question: normalized_question,
                ts: Instant::now(),
            };
            let _ = self.resolver_tx.send(client_query);
        }
    }

    pub fn spawn(rpdns_context: &RPDNSContext,
                 resolver_tx: Sender<ClientQuery>)
                 -> io::Result<(thread::JoinHandle<()>)> {
        let udp_socket =
            rpdns_context.udp_socket.try_clone().expect("Unable to clone the UDP listening socket");
        let udp_listener = UdpListener {
            socket: udp_socket,
            resolver_tx: resolver_tx,
            cache: rpdns_context.cache.clone(),
            varz: rpdns_context.varz.clone(),
        };
        let udp_listener_th = thread::spawn(move || {
            udp_listener.run().expect("Unable to spawn a UDP listener");
        });
        info!("UDP listener is ready");
        Ok((udp_listener_th))
    }
}

#[cfg(any(target_os = "linux", target_os = "android"))]
fn socket_udp_set_buffer_size(socket_fd: RawFd) {
    let _ = setsockopt(socket_fd, sockopt::SndBufForce, &UDP_BUFFER_SIZE);
    let _ = setsockopt(socket_fd, sockopt::RcvBufForce, &UDP_BUFFER_SIZE);
}

#[cfg(not(any(target_os = "linux", target_os = "android")))]
fn socket_udp_set_buffer_size(socket_fd: RawFd) {
    let _ = setsockopt(socket_fd, sockopt::SndBuf, &UDP_BUFFER_SIZE);
    let _ = setsockopt(socket_fd, sockopt::RcvBuf, &UDP_BUFFER_SIZE);
}

fn socket_udp_v4() -> io::Result<RawFd> {
    let socket_fd = socket(AddressFamily::Inet,
                           SockType::Datagram,
                           SockFlag::empty(),
                           SockLevel::Udp as i32)?;
    Ok(socket_fd)
}

fn socket_udp_v6() -> io::Result<RawFd> {
    let socket_fd = socket(AddressFamily::Inet6,
                           SockType::Datagram,
                           SockFlag::empty(),
                           SockLevel::Udp as i32)?;
    Ok(socket_fd)
}

pub fn socket_udp_bound(addr: &str) -> io::Result<UdpSocket> {
    let actual: SocketAddr = FromStr::from_str(addr).expect("Invalid address");
    let nix_addr = SockAddr::Inet(InetAddr::from_std(&actual));
    let socket_fd = match actual {
        SocketAddr::V4(_) => socket_udp_v4()?,
        SocketAddr::V6(_) => socket_udp_v6()?,
    };
    let _ = setsockopt(socket_fd, sockopt::ReuseAddr, &true);
    let _ = setsockopt(socket_fd, sockopt::ReusePort, &true);
    socket_udp_set_buffer_size(socket_fd);
    bind(socket_fd, &nix_addr).expect("Unable to bind a UDP socket");
    let socket: UdpSocket = unsafe { UdpSocket::from_raw_fd(socket_fd) };
    Ok(socket)
}
<|endoftext|>