<commit_before>extern crate syntax;
extern crate rustc;
extern crate rustc_front;
extern crate rustc_driver;
extern crate rustc_metadata;
extern crate rustc_resolve as resolve;
extern crate rustc_typeck as typeck;

use self::syntax::codemap::{CodeMap, MultiSpan};
pub use self::syntax::errors::Level;
use self::syntax::errors::{self, RenderSpan};
use self::syntax::errors::emitter::Emitter;
use self::syntax::parse::token;
use self::rustc::front::map as hir_map;
use self::rustc::front::map::NodePrinter;
use self::rustc_front::lowering::{lower_crate, LoweringContext};
use self::rustc_front::print::pprust;
use self::rustc::session::{self, config};
use self::rustc_metadata::creader::LocalCrateReader;
use self::rustc_metadata::cstore::CStore;
use self::rustc::middle::{self, stability, ty};
use self::rustc::dep_graph::DepGraph;
use self::rustc_driver::driver;

//use std::cell::RefCell;
use std::env;
use std::collections::HashMap;
use std::ops::Range;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::rc::Rc;
use std::str;
use std::sync::{Arc, Weak};
use std::sync::mpsc::{channel, Sender, Receiver};
use std::thread;

#[cfg(windows)]
const EXE_SUFFIX: &'static str = "exe";
#[cfg(not(windows))]
const EXE_SUFFIX: &'static str = "";

fn get_rustc_dir_path() -> PathBuf {
    if cfg!(windows) {
        env::current_exe().unwrap().parent().unwrap().to_path_buf()
    } else {
        let out = Command::new("which").arg("rustc").output().unwrap();
        if !out.status.success() {
            panic!("Failed to get rustc path: {}", String::from_utf8(out.stderr).unwrap());
        }
        Path::new(str::from_utf8(&out.stdout).unwrap().trim()).parent().unwrap().to_path_buf()
    }
}

pub fn init_env() {
    if cfg!(windows) {
        // Set up %PATH% to be able to run the bundled `rustc.exe`.
        if let Some(path) = env::var_os("PATH") {
            let mut paths = env::split_paths(&path).collect::<Vec<_>>();
            paths.push(get_rustc_dir_path());
            let new_path = env::join_paths(paths.iter()).unwrap();
            env::set_var("PATH", &new_path);
        }
    }
}

pub fn compile_and_run(path: &Path) {
    let path = env::current_dir().unwrap().join(path);
    assert!(path.is_absolute());
    let exe = path.with_extension(EXE_SUFFIX);

    // There seems to be a bug that Rust programs (including `rustc.exe`) ran with inherited
    // std{in,out,err} via `.status()` or `.spawn()` produce a "`xyz.exe` has stopped working"
    // message unconditionally.
    if cfg!(windows) {
        let out = Command::new("rustc").arg(&path).arg("-o").arg(&exe).output().unwrap();
        println!("{}\n{}", String::from_utf8(out.stdout).unwrap(), String::from_utf8(out.stderr).unwrap());
        if !out.status.success() {
            println!("compilation failed");
        } else {
            match Command::new(&exe).output() {
                Err(e) => {
                    println!("failed to execute `{:?}`: {}", exe, e);
                }
                Ok(out) => {
                    println!("{}\n{}", String::from_utf8(out.stdout).unwrap(),
                                       String::from_utf8(out.stderr).unwrap());
                }
            }
        }
    } else {
        if let Ok(status) = Command::new("rustc").arg(&path).arg("-o").arg(&exe).status() {
            if status.success() {
                if let Err(e) = Command::new(&exe).spawn() {
                    println!("failed to execute `{:?}`: {}", exe, e);
                }
            }
        }
    }
}

enum Req {
    TypesAtOffset(usize, Range<usize>)
}

enum Res {
    Done,
    Aborted,
    Diagnostic(Diagnostic),
    TypesAtOffset(usize, Vec<(Range<usize>, String)>)
}

struct Diagnostic {
    line: usize,
    col: usize,
    level: Level,
    message: String
}

struct ErrorLogger {
    tx: Sender<Res>,
    codemap: Rc<CodeMap>,
    file_end: usize
}

impl Emitter for ErrorLogger {
    fn emit(&mut self, span: Option<&MultiSpan>,
            msg: &str, _code: Option<&str>, lvl: Level) {
        if msg.starts_with("aborting due to ") {
            return;
        }
        let (line, col) = match span.map(|s| s.to_span_bounds()) {
            Some(sp) => {
                if sp.hi.0 as usize <= self.file_end {
                    let pos = self.codemap.lookup_char_pos(sp.lo);
                    (pos.line - 1, pos.col.0)
                } else {
                    (0, 0)
                }
            }
            None => (0, 0)
        };
        let _ = self.tx.send(Res::Diagnostic(Diagnostic {
            line: line,
            col: col,
            level: lvl,
            message: msg.to_owned()
        }));
    }

    fn custom_emit(&mut self, sp: &RenderSpan, msg: &str, lvl: Level) {
        let msp = match *sp {
            RenderSpan::FullSpan(ref msp) |
            RenderSpan::FileLine(ref msp) |
            RenderSpan::EndSpan(ref msp) => Some(msp),
            RenderSpan::Suggestion(_) => None
        };
        self.emit(msp, msg, None, lvl);
    }
}

fn rustc_thread(input: String, mut lifeline: Arc<()>,
                rx: Receiver<Req>, tx: Sender<Res>,
                file_end: usize) -> Result<(), usize> {
    macro_rules! still_alive {
        () => (lifeline = match Weak::upgrade(&Arc::downgrade(&{lifeline})) {
                Some(x) => x, None => return Ok(())
        })
    }
    let input = config::Input::Str(input);

    let rustc_dir_path = get_rustc_dir_path();

    let sessopts = config::Options {
        maybe_sysroot: Some(rustc_dir_path.parent().unwrap().to_path_buf()),
        ..config::basic_options().clone()
    };

    let codemap = Rc::new(CodeMap::new());
    let emitter = Box::new(ErrorLogger {
        tx: tx.clone(),
        codemap: codemap.clone(),
        file_end: file_end
    });
    let diagnostic_handler = errors::Handler::with_emitter(true, false, emitter);

    let cstore = Rc::new(CStore::new(token::get_ident_interner()));
    let sess = session::build_session_(sessopts,
                                       None,
                                       diagnostic_handler,
                                       codemap,
                                       cstore.clone());

    let cfg = config::build_configuration(&sess);

    still_alive!();
    let krate = driver::phase_1_parse_input(&sess, cfg, &input);

    still_alive!();
    let krate = driver::phase_2_configure_and_expand(&sess, &cstore, krate, "r3", None)
        .expect("phase_2_configure_and_expand aborted");

    still_alive!();
    let krate = driver::assign_node_ids(&sess, krate);

    let lcx = LoweringContext::new(&sess, Some(&krate));
    let dep_graph = DepGraph::new(false);
    let mut hir_forest = hir_map::Forest::new(lower_crate(&lcx, &krate), dep_graph);
    let arenas = ty::CtxtArenas::new();

    still_alive!();
    let hir_map = hir_map::map_crate(&mut hir_forest);

    still_alive!();
    LocalCrateReader::new(&sess, &cstore, &hir_map).read_crates();
    let lang_items = middle::lang_items::collect_language_items(&sess, &hir_map);

    still_alive!();
    let resolve::CrateMap {
        def_map,
        freevars,
        trait_map,
        ..
    } = resolve::resolve_crate(&sess,
                               &hir_map,
                               resolve::MakeGlobMap::No);

    // Discard MTWT tables that aren't required past resolution.
    syntax::ext::mtwt::clear_tables();

    still_alive!();
    let named_region_map = try!(middle::resolve_lifetime::krate(&sess, &hir_map, &def_map.borrow()));

    still_alive!();
    let region_map = middle::region::resolve_crate(&sess, &hir_map);

    //middle::check_loop::check_crate(&sess, krate);

    //middle::check_static_recursion::check_crate(&sess, krate, &def_map, &hir_map);

    still_alive!();
    let stability_idx = stability::Index::new(&hir_map);
    ty::ctxt::create_and_enter(&sess,
                               &arenas,
                               def_map,
                               named_region_map,
                               hir_map,
                               freevars,
                               region_map,
                               lang_items,
                               stability_idx, |tcx| {
        /*typeck::collect::collect_item_types(tcx);
        tcx.sess.abort_if_errors();

        still_alive!();
        typeck::variance::infer_variance(tcx);

        still_alive!();
        let ccx = typeck::CrateCtxt {
            trait_map: trait_map,
            all_traits: RefCell::new(None),
            tcx: tcx
        };
        typeck::coherence::check_coherence(&ccx);*/
        try!(typeck::check_crate(tcx, trait_map));

        let _ = tx.send(Res::Done);

        for req in rx.iter() {
            still_alive!();
            match req {
                Req::TypesAtOffset(offset, line) => {
                    let mut out = vec![];
                    for (&id, ty) in tcx.node_types().iter() {
                        let node =  if let Some(node) = tcx.map.find(id) {
                            node
                        } else {
                            continue;
                        };
                        // Avoid statements, they're always ().
                        if let hir_map::NodeStmt(_) = node {
                            continue;
                        }
                        if let Some(sp) = tcx.map.opt_span(id) {
                            /*
                            // Avoid peeking at macro expansions.
                            if sp.expn_id != codemap::NO_EXPANSION {
                                continue;
                            }*/

                            let (lo, hi) = (sp.lo.0 as usize, sp.hi.0 as usize);
                            if line.start <= lo && lo <= offset && offset <= hi && hi <= line.end {
                                match node {
                                    // These cannot be reliably printed.
                                    hir_map::NodeLocal(_) | hir_map::NodeStructCtor(_) => {}
                                    // There is an associated NodeExpr(ExprBlock) where this actually matters.
                                    hir_map::NodeBlock(_) => continue,
                                    _ => {
                                        let node_string = pprust::to_string(|s| s.print_node(&node));
                                        let span_string = tcx.sess.codemap().span_to_snippet(sp).unwrap();
                                        let is_macro = regex!(r"^\w+\s*!\s*[\(\[\{]").is_match(&span_string);
                                        if !is_macro && node_string.replace(" ", "") != span_string.replace(" ", "") {
                                            continue;
                                        }
                                    }
                                }
                                let clean = regex!(concat![r"\b(",
                                    "core::(option::Option|result::Result)|",
                                    "collections::(vec::Vec|string::String)",
                                r")\b"]);
                                let ty_string = clean.replace_all(&ty.to_string(), |c: &::regex::Captures| {
                                    c.at(0).unwrap().split(':').next_back().unwrap().to_owned()
                                });
                                out.push((lo-line.start..hi-line.start, ty_string));
                            }
                        }
                    }
                    let _ = tx.send(Res::TypesAtOffset(offset, out));
                }
            }
        }

        Ok(())
    })
}

#[derive(Copy, Clone, PartialEq, Debug)]
pub enum State {
    Compiling,
    Aborted,
    Waiting,
    TypesAtOffset(usize)
}

pub struct Rustc {
    pub file_end: usize,
    _lifeline: Arc<()>,
    req_tx: Sender<Req>,
    res_rx: Receiver<Res>,
    pub state: State,
    // True if error.
    pub diagnostics: HashMap<usize, Vec<(Level, usize, String)>>,
    pub errors: usize,
    pub types_at_offset: Option<Vec<(Range<usize>, String)>>
}

impl Rustc {
    pub fn start(input: String) -> Rustc {
        let lifeline = Arc::new(());
        let lifeline2 = lifeline.clone();
        let (req_tx, req_rx) = channel();
        let (res_tx, res_rx) = channel();
        let input_len = input.len();
        thread::spawn(move || {
            let res_tx2 = res_tx.clone();
            let res = thread::catch_panic(move || {
                let _ = rustc_thread(input, lifeline2, req_rx, res_tx, input_len);
            });
            if res.is_err() {
                let _ = res_tx2.send(Res::Aborted);
            }
        });
        Rustc {
            file_end: input_len,
            _lifeline: lifeline,
            req_tx: req_tx,
            res_rx: res_rx,
            state: State::Compiling,
            diagnostics: HashMap::new(),
            errors: 0,
            types_at_offset: None
        }
    }

    pub fn update(&mut self) -> bool {
        let mut dirty = false;
        while let Ok(res) = self.res_rx.try_recv() {
            match res {
                Res::Done => {
                    assert_eq!(self.state, State::Compiling);
                    self.state = State::Waiting;
                }
                Res::Aborted => {
                    assert!(self.errors > 0, "aborted without errors?!");
                    self.state = State::Aborted;
                }
                Res::Diagnostic(d) => {
                     match d.level {
                        Level::Bug | Level::Fatal | Level::Error => {
                            self.errors += 1;
                        }
                        _ => {}
                    }
                    self.diagnostics.entry(d.line).or_insert(vec![]).push((d.level, d.col, d.message));
                    dirty = true;
                }
                Res::TypesAtOffset(offset, result) => {
                    if self.state == State::TypesAtOffset(offset) {
                        self.state = State::Waiting;
                        self.types_at_offset = Some(result);
                        dirty = true;
                    }
                }
            }
        }
        dirty
    }

    pub fn types_at_offset(&mut self, offset: usize, line: Range<usize>) {
        self.types_at_offset = None;
        self.state = State::TypesAtOffset(offset);
        let _ = self.req_tx.send(Req::TypesAtOffset(offset, line));
    }
}
<commit_msg>Update rustc.rs<commit_after>extern crate syntax;
extern crate rustc;
extern crate rustc_front;
extern crate rustc_driver;
extern crate rustc_metadata;
extern crate rustc_resolve as resolve;
extern crate rustc_typeck as typeck;

use self::syntax::codemap::{CodeMap, MultiSpan};
pub use self::syntax::errors::Level;
use self::syntax::errors::{self, RenderSpan};
use self::syntax::errors::emitter::Emitter;
use self::syntax::parse::token;
use self::rustc::front::map as hir_map;
use self::rustc::front::map::NodePrinter;
use self::rustc_front::lowering::{lower_crate, LoweringContext};
use self::rustc_front::print::pprust;
use self::rustc::session::{self, config};
use self::rustc_metadata::creader::LocalCrateReader;
use self::rustc_metadata::cstore::CStore;
use self::rustc::middle::{self, stability, ty};
use self::rustc::dep_graph::DepGraph;
use self::rustc_driver::driver;

//use std::cell::RefCell;
use std::env;
use std::collections::HashMap;
use std::ops::Range;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::rc::Rc;
use std::str;
use std::sync::{Arc, Weak};
use std::sync::mpsc::{channel, Sender, Receiver};
use std::thread;

#[cfg(windows)]
const EXE_SUFFIX: &'static str = "exe";
#[cfg(not(windows))]
const EXE_SUFFIX: &'static str = "";

fn get_rustc_dir_path() -> PathBuf {
    if cfg!(windows) {
        env::current_exe().unwrap().parent().unwrap().to_path_buf()
    } else {
        let out = Command::new("which").arg("rustc").output().unwrap();
        if !out.status.success() {
            panic!("Failed to get rustc path: {}", String::from_utf8(out.stderr).unwrap());
        }
        Path::new(str::from_utf8(&out.stdout).unwrap().trim()).parent().unwrap().to_path_buf()
    }
}

pub fn init_env() {
    if cfg!(windows) {
        // Set up %PATH% to be able to run the bundled `rustc.exe`.
        if let Some(path) = env::var_os("PATH") {
            let mut paths = env::split_paths(&path).collect::<Vec<_>>();
            paths.push(get_rustc_dir_path());
            let new_path = env::join_paths(paths.iter()).unwrap();
            env::set_var("PATH", &new_path);
        }
    }
}

pub fn compile_and_run(path: &Path) {
    let path = env::current_dir().unwrap().join(path);
    assert!(path.is_absolute());
    let exe = path.with_extension(EXE_SUFFIX);

    // There seems to be a bug that Rust programs (including `rustc.exe`) ran with inherited
    // std{in,out,err} via `.status()` or `.spawn()` produce a "`xyz.exe` has stopped working"
    // message unconditionally.
    if cfg!(windows) {
        let out = Command::new("rustc").arg(&path).arg("-o").arg(&exe).output().unwrap();
        println!("{}\n{}", String::from_utf8(out.stdout).unwrap(), String::from_utf8(out.stderr).unwrap());
        if !out.status.success() {
            println!("compilation failed");
        } else {
            match Command::new(&exe).output() {
                Err(e) => {
                    println!("failed to execute `{:?}`: {}", exe, e);
                }
                Ok(out) => {
                    println!("{}\n{}", String::from_utf8(out.stdout).unwrap(),
                                       String::from_utf8(out.stderr).unwrap());
                }
            }
        }
    } else {
        if let Ok(status) = Command::new("rustc").arg(&path).arg("-o").arg(&exe).status() {
            if status.success() {
                if let Err(e) = Command::new(&exe).spawn() {
                    println!("failed to execute `{:?}`: {}", exe, e);
                }
            }
        }
    }
}

enum Req {
    TypesAtOffset(usize, Range<usize>)
}

enum Res {
    Done,
    Aborted,
    Diagnostic(Diagnostic),
    TypesAtOffset(usize, Vec<(Range<usize>, String)>)
}

struct Diagnostic {
    line: usize,
    col: usize,
    level: Level,
    message: String
}

struct ErrorLogger {
    tx: Sender<Res>,
    codemap: Rc<CodeMap>,
    file_end: usize
}

impl Emitter for ErrorLogger {
    fn emit(&mut self, span: Option<&MultiSpan>,
            msg: &str, _code: Option<&str>, lvl: Level) {
        if msg.starts_with("aborting due to ") {
            return;
        }
        let (line, col) = match span.map(|s| s.to_span_bounds()) {
            Some(sp) => {
                if sp.hi.0 as usize <= self.file_end {
                    let pos = self.codemap.lookup_char_pos(sp.lo);
                    (pos.line - 1, pos.col.0)
                } else {
                    (0, 0)
                }
            }
            None => (0, 0)
        };
        let _ = self.tx.send(Res::Diagnostic(Diagnostic {
            line: line,
            col: col,
            level: lvl,
            message: msg.to_owned()
        }));
    }

    fn custom_emit(&mut self, sp: &RenderSpan, msg: &str, lvl: Level) {
        let msp = match *sp {
            RenderSpan::FullSpan(ref msp) |
            RenderSpan::FileLine(ref msp) |
            RenderSpan::EndSpan(ref msp) => Some(msp),
            RenderSpan::Suggestion(_) => None
        };
        self.emit(msp, msg, None, lvl);
    }
}

fn rustc_thread(input: String, mut lifeline: Arc<()>,
                rx: Receiver<Req>, tx: Sender<Res>,
                file_end: usize) -> Result<(), usize> {
    macro_rules! still_alive {
        () => (lifeline = match Weak::upgrade(&Arc::downgrade(&{lifeline})) {
                Some(x) => x, None => return Ok(())
        })
    }
    let input = config::Input::Str(input);

    let rustc_dir_path = get_rustc_dir_path();

    let sessopts = config::Options {
        maybe_sysroot: Some(rustc_dir_path.parent().unwrap().to_path_buf()),
        ..config::basic_options().clone()
    };

    let codemap = Rc::new(CodeMap::new());
    let emitter = Box::new(ErrorLogger {
        tx: tx.clone(),
        codemap: codemap.clone(),
        file_end: file_end
    });
    let diagnostic_handler = errors::Handler::with_emitter(true, false, emitter);

    let cstore = Rc::new(CStore::new(token::get_ident_interner()));
    let sess = session::build_session_(sessopts,
                                       None,
                                       diagnostic_handler,
                                       codemap,
                                       cstore.clone());

    let cfg = config::build_configuration(&sess);

    still_alive!();
    let krate = driver::phase_1_parse_input(&sess, cfg, &input);

    still_alive!();
    let krate = driver::phase_2_configure_and_expand(&sess, &cstore, krate, "rid3", None)
        .expect("phase_2_configure_and_expand aborted");

    still_alive!();
    let krate = driver::assign_node_ids(&sess, krate);

    let lcx = LoweringContext::new(&sess, Some(&krate));
    let dep_graph = DepGraph::new(false);
    let mut hir_forest = hir_map::Forest::new(lower_crate(&lcx, &krate), dep_graph);
    let arenas = ty::CtxtArenas::new();

    still_alive!();
    let hir_map = hir_map::map_crate(&mut hir_forest);

    still_alive!();
    LocalCrateReader::new(&sess, &cstore, &hir_map).read_crates();
    let lang_items = middle::lang_items::collect_language_items(&sess, &hir_map);

    still_alive!();
    let resolve::CrateMap {
        def_map,
        freevars,
        trait_map,
        ..
    } = resolve::resolve_crate(&sess,
                               &hir_map,
                               resolve::MakeGlobMap::No);

    // Discard MTWT tables that aren't required past resolution.
    syntax::ext::mtwt::clear_tables();

    still_alive!();
    let named_region_map = try!(middle::resolve_lifetime::krate(&sess, &hir_map, &def_map.borrow()));

    still_alive!();
    let region_map = middle::region::resolve_crate(&sess, &hir_map);

    //middle::check_loop::check_crate(&sess, krate);

    //middle::check_static_recursion::check_crate(&sess, krate, &def_map, &hir_map);

    still_alive!();
    let stability_idx = stability::Index::new(&hir_map);
    ty::ctxt::create_and_enter(&sess,
                               &arenas,
                               def_map,
                               named_region_map,
                               hir_map,
                               freevars,
                               region_map,
                               lang_items,
                               stability_idx, |tcx| {
        /*typeck::collect::collect_item_types(tcx);
        tcx.sess.abort_if_errors();

        still_alive!();
        typeck::variance::infer_variance(tcx);

        still_alive!();
        let ccx = typeck::CrateCtxt {
            trait_map: trait_map,
            all_traits: RefCell::new(None),
            tcx: tcx
        };
        typeck::coherence::check_coherence(&ccx);*/
        try!(typeck::check_crate(tcx, trait_map));

        let _ = tx.send(Res::Done);

        for req in rx.iter() {
            still_alive!();
            match req {
                Req::TypesAtOffset(offset, line) => {
                    let mut out = vec![];
                    for (&id, ty) in tcx.node_types().iter() {
                        let node =  if let Some(node) = tcx.map.find(id) {
                            node
                        } else {
                            continue;
                        };
                        // Avoid statements, they're always ().
                        if let hir_map::NodeStmt(_) = node {
                            continue;
                        }
                        if let Some(sp) = tcx.map.opt_span(id) {
                            /*
                            // Avoid peeking at macro expansions.
                            if sp.expn_id != codemap::NO_EXPANSION {
                                continue;
                            }*/

                            let (lo, hi) = (sp.lo.0 as usize, sp.hi.0 as usize);
                            if line.start <= lo && lo <= offset && offset <= hi && hi <= line.end {
                                match node {
                                    // These cannot be reliably printed.
                                    hir_map::NodeLocal(_) | hir_map::NodeStructCtor(_) => {}
                                    // There is an associated NodeExpr(ExprBlock) where this actually matters.
                                    hir_map::NodeBlock(_) => continue,
                                    _ => {
                                        let node_string = pprust::to_string(|s| s.print_node(&node));
                                        let span_string = tcx.sess.codemap().span_to_snippet(sp).unwrap();
                                        let is_macro = regex!(r"^\w+\s*!\s*[\(\[\{]").is_match(&span_string);
                                        if !is_macro && node_string.replace(" ", "") != span_string.replace(" ", "") {
                                            continue;
                                        }
                                    }
                                }
                                let clean = regex!(concat![r"\b(",
                                    "core::(option::Option|result::Result)|",
                                    "collections::(vec::Vec|string::String)",
                                r")\b"]);
                                let ty_string = clean.replace_all(&ty.to_string(), |c: &::regex::Captures| {
                                    c.at(0).unwrap().split(':').next_back().unwrap().to_owned()
                                });
                                out.push((lo-line.start..hi-line.start, ty_string));
                            }
                        }
                    }
                    let _ = tx.send(Res::TypesAtOffset(offset, out));
                }
            }
        }

        Ok(())
    })
}

#[derive(Copy, Clone, PartialEq, Debug)]
pub enum State {
    Compiling,
    Aborted,
    Waiting,
    TypesAtOffset(usize)
}

pub struct Rustc {
    pub file_end: usize,
    _lifeline: Arc<()>,
    req_tx: Sender<Req>,
    res_rx: Receiver<Res>,
    pub state: State,
    // True if error.
    pub diagnostics: HashMap<usize, Vec<(Level, usize, String)>>,
    pub errors: usize,
    pub types_at_offset: Option<Vec<(Range<usize>, String)>>
}

impl Rustc {
    pub fn start(input: String) -> Rustc {
        let lifeline = Arc::new(());
        let lifeline2 = lifeline.clone();
        let (req_tx, req_rx) = channel();
        let (res_tx, res_rx) = channel();
        let input_len = input.len();
        thread::spawn(move || {
            let res_tx2 = res_tx.clone();
            let res = thread::catch_panic(move || {
                let _ = rustc_thread(input, lifeline2, req_rx, res_tx, input_len);
            });
            if res.is_err() {
                let _ = res_tx2.send(Res::Aborted);
            }
        });
        Rustc {
            file_end: input_len,
            _lifeline: lifeline,
            req_tx: req_tx,
            res_rx: res_rx,
            state: State::Compiling,
            diagnostics: HashMap::new(),
            errors: 0,
            types_at_offset: None
        }
    }

    pub fn update(&mut self) -> bool {
        let mut dirty = false;
        while let Ok(res) = self.res_rx.try_recv() {
            match res {
                Res::Done => {
                    assert_eq!(self.state, State::Compiling);
                    self.state = State::Waiting;
                }
                Res::Aborted => {
                    assert!(self.errors > 0, "aborted without errors?!");
                    self.state = State::Aborted;
                }
                Res::Diagnostic(d) => {
                     match d.level {
                        Level::Bug | Level::Fatal | Level::Error => {
                            self.errors += 1;
                        }
                        _ => {}
                    }
                    self.diagnostics.entry(d.line).or_insert(vec![]).push((d.level, d.col, d.message));
                    dirty = true;
                }
                Res::TypesAtOffset(offset, result) => {
                    if self.state == State::TypesAtOffset(offset) {
                        self.state = State::Waiting;
                        self.types_at_offset = Some(result);
                        dirty = true;
                    }
                }
            }
        }
        dirty
    }

    pub fn types_at_offset(&mut self, offset: usize, line: Range<usize>) {
        self.types_at_offset = None;
        self.state = State::TypesAtOffset(offset);
        let _ = self.req_tx.send(Req::TypesAtOffset(offset, line));
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code, unused_variables)]
use alloc::heap::{Heap, Alloc, Layout};
use bytes::BytesMut;

use std::sync::Arc;

use audiosample::*;
use pixel::*;
use timeinfo::*;

#[derive(Fail, Debug)]
pub enum FrameError {
    #[fail(display = "Invalid Index")]
    InvalidIndex,
    #[fail(display = "Invalid Conversion")]
    InvalidConversion,
}

use self::FrameError::*;

// TODO: Document
// TODO: Change it to provide Droppable/Seekable information or use a separate enum?
#[derive(Clone, Debug, PartialEq)]
pub enum PictureType {
    UNKNOWN,
    I,
    P,
    B,
    S,
    SI,
    SP,
    SB,
    BI,
}

#[derive(Clone, Debug, PartialEq)]
pub struct VideoInfo {
    pub pic_type: PictureType,
    pub width: usize,
    pub height: usize,
    pub format: Arc<Formaton>,
}

impl VideoInfo {
    fn size(&self, align: usize) -> usize {
        let mut size = 0;
        for &component in self.format.into_iter() {
            if let Some(c) = component {
                size += c.get_data_size(self.width, self.height, align);
            }
        }
        size
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct AudioInfo {
    pub samples: usize,
    pub rate: usize,
    pub map: ChannelMap,
    pub format: Arc<Soniton>,
}

impl AudioInfo {
    fn size(&self, align: usize) -> usize {
        self.format.get_audio_size(self.samples, align) * self.map.len()
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum MediaKind {
    Video(VideoInfo),
    Audio(AudioInfo),
}

use std::convert::From;

impl From<VideoInfo> for MediaKind {
    fn from(v: VideoInfo) -> Self {
        MediaKind::Video(v)
    }
}

impl From<AudioInfo> for MediaKind {
    fn from(a: AudioInfo) -> Self {
        MediaKind::Audio(a)
    }
}

use self::MediaKind::*;

pub trait FrameBuffer : Send + Sync {
    fn linesize(&self, idx: usize) -> Result<usize, FrameError>;
    fn count(&self) -> usize;
    fn as_slice_inner<'a>(&'a self, idx: usize) -> Result<&'a [u8], FrameError>;
    fn as_mut_slice_inner<'a>(&'a mut self, idx: usize) -> Result<&'a mut [u8], FrameError>;
}

pub trait FrameBufferConv<T> : FrameBuffer {
    fn as_slice<'a>(&'a self, idx: usize) -> Result<&'a [T], FrameError> {
        let size = mem::size_of::<T>();
        if (self.linesize(idx)? % size) != 0 {
            Err(InvalidConversion)
        } else {
            let s = self.as_slice_inner(idx)?;
            let r = unsafe {
                slice::from_raw_parts::<T>(mem::transmute(s.as_ptr()), s.len() / size)
            };

            Ok(r)
        }
    }
    fn as_mut_slice<'a>(&'a mut self, idx: usize) -> Result<&'a mut [T], FrameError> {
        let size = mem::size_of::<T>();
        if (self.linesize(idx)? % size) != 0 {
            Err(InvalidConversion)
        } else {
            let s = self.as_mut_slice_inner(idx)?;
            let r = unsafe {
                slice::from_raw_parts_mut::<T>(mem::transmute(s.as_ptr()), s.len() / size)
            };

            Ok(r)
        }
    }
}

impl FrameBufferConv<u8> for FrameBuffer {}
impl FrameBufferConv<i16> for FrameBuffer {}
impl FrameBufferConv<f32> for FrameBuffer {}

use std::fmt;

impl fmt::Debug for FrameBuffer {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "FrameBuffer")
    }
}

#[derive(Debug)]
pub struct Frame {
    pub kind: MediaKind,
    pub buf: Box<FrameBuffer>,
    pub t: TimeInfo,
}

const ALIGNMENT: usize = 32;

struct Plane {
    buf: BytesMut,
    linesize: usize,
}

struct DefaultFrameBuffer {
    buf: BytesMut,
    planes: Vec<Plane>,
}

impl FrameBuffer for DefaultFrameBuffer {
    fn linesize(&self, idx: usize) -> Result<usize, FrameError> {
        match self.planes.get(idx) {
            None => Err(InvalidIndex),
            Some(plane) => Ok(plane.linesize),
        }
    }
    fn count(&self) -> usize {
        self.planes.len()
    }

    fn as_slice_inner<'a>(&'a self, idx: usize) -> Result<&'a [u8], FrameError> {
        match self.planes.get(idx) {
            None => Err(InvalidIndex),
            Some(plane) => Ok(&plane.buf),
        }
    }
    fn as_mut_slice_inner<'a>(&'a mut self, idx: usize) -> Result<&'a mut [u8], FrameError> {
        match self.planes.get_mut(idx) {
            None => Err(InvalidIndex),
            Some(plane) => Ok(&mut plane.buf),
        }
    }
}

impl DefaultFrameBuffer {
    pub fn new<'a>(kind: &'a MediaKind) -> DefaultFrameBuffer {
        match kind {
            &Video(ref video) => {
                let size = video.size(ALIGNMENT);
                let data = unsafe {
                    Heap.alloc(Layout::from_size_align(size, ALIGNMENT).unwrap())
                        .unwrap()
                };
                //let data = unsafe { Heap.alloc_zeroed(Layout::from_size_align(size, ALIGNMENT)) };
                let buf = BytesMut::from(unsafe { Vec::from_raw_parts(data, size, size) });
                let mut buffer = DefaultFrameBuffer {
                    buf: buf,
                    planes: Vec::new(),
                };
                for &component in video.format.iter() {
                    if let Some(c) = component {
                        let planesize = c.get_data_size(video.width, video.height, ALIGNMENT);
                        let linesize = c.get_linesize(video.width, ALIGNMENT);
                        buffer.planes.push(Plane {
                            buf: buffer.buf.split_to(planesize),
                            linesize: linesize,
                        });
                    }
                }
                buffer
            },
            &Audio(ref audio) => {
                let size = audio.size(ALIGNMENT);
                let data = unsafe {
                    Heap.alloc(Layout::from_size_align(size, ALIGNMENT).unwrap())
                        .unwrap()
                };
                let buf = BytesMut::from(unsafe { Vec::from_raw_parts(data, size, size) });
                let mut buffer = DefaultFrameBuffer {
                    buf: buf,
                    planes: Vec::new(),
                };
                for _ in 0..audio.map.len() {
                    let size = audio.format.get_audio_size(audio.samples, ALIGNMENT);
                    buffer.planes.push(Plane {
                        buf: buffer.buf.split_to(size),
                        linesize: size,
                    });
                }
                buffer
            },
        }
    }
}

pub type ArcFrame = Arc<Frame>;

pub fn new_default_frame<T>(kind: T, t: Option<TimeInfo>) -> Frame
where T: Into<MediaKind> + Clone
{
    let k = kind.into();
    let buf = DefaultFrameBuffer::new(&k);

    Frame {
        kind: k,
        buf: box buf,
        t: t.unwrap_or_default(),
    }
}

use std::ptr::copy_nonoverlapping;

fn copy_plane(
    dst: &mut [u8],
    dst_linesize: usize,
    src: &[u8],
    src_linesize: usize,
    w: usize,
    h: usize,
) {
    let dst_chunks = dst.chunks_mut(dst_linesize);
    let src_chunks = src.chunks(src_linesize);

    for (d, s) in dst_chunks.zip(src_chunks).take(h) {
        unsafe {
            copy_nonoverlapping(s.as_ptr(), d.as_mut_ptr(), w);
        }
    }
}

fn copy_image<'a, IM, IU, I>(
    dst: IM,
    dst_linesizes: IU,
    src: I,
    src_linesizes: IU,
    w: usize,
    h: usize,
    fmt: &Formaton,
) where
    IM: Iterator<Item = &'a mut [u8]>,
    I: Iterator<Item = &'a [u8]>,
    IU: Iterator<Item = usize>,
{
    let dst_iter = dst.zip(dst_linesizes);
    let src_iter = src.zip(src_linesizes);
    let iter = dst_iter.zip(src_iter).zip(fmt.iter());

    for (((d, d_linesize), (s, s_linesize)), c) in iter {
        copy_plane(
            d,
            d_linesize,
            s,
            s_linesize,
            c.unwrap().get_width(w),
            c.unwrap().get_height(h),
        );
    }
}

// TODO: Add proper tests
fn copy_to_frame<'a, I, IU>(dst: &mut Frame, mut src: I, mut src_linesize: IU, w: usize, h: usize)
where
    I: Iterator<Item = &'a [u8]>,
    IU: Iterator<Item = usize>,
{
    if let MediaKind::Video(ref fmt) = dst.kind {
        let mut f_iter = fmt.format.iter();
        let w = fmt.width;
        let h = fmt.height;
        for i in 0..dst.buf.count() {
            let d_linesize = dst.buf.linesize(i).unwrap();
            let s_linesize = src_linesize.next().unwrap();
            let d = dst.buf.as_mut_slice(i).unwrap();
            let s = src.next().unwrap();
            let c = f_iter.next().unwrap();
            copy_plane(
                d,
                d_linesize,
                s,
                s_linesize,
                c.unwrap().get_width(w),
                c.unwrap().get_height(h),
            );
        }
    } else {
        unimplemented!();
    }
}

use std::mem;
use std::slice;

// TODO make it a separate trait
impl Frame {
    pub fn copy_from_slice<'a, I, IU>(&mut self, mut src: I, mut src_linesize: IU)
    where
        I: Iterator<Item = &'a [u8]>,
        IU: Iterator<Item = usize>,
    {
        if let MediaKind::Video(ref fmt) = self.kind {
            let mut f_iter = fmt.format.iter();
            let w = fmt.width;
            let h = fmt.height;
            for i in 0..self.buf.count() {
                let d_linesize = self.buf.linesize(i).unwrap();
                let s_linesize = src_linesize.next().unwrap();
                let d = self.buf.as_mut_slice(i).unwrap();
                let s = src.next().unwrap();
                let c = f_iter.next().unwrap();
                copy_plane(
                    d,
                    d_linesize,
                    s,
                    s_linesize,
                    c.unwrap().get_width(w),
                    c.unwrap().get_height(h),
                );
            }
        } else {
            unimplemented!();
        }
    }

    pub fn copy_from_raw_parts<'a, I, IU>(&mut self, mut src: I, mut src_linesize: IU)
    where
        I: Iterator<Item = *const u8>,
        IU: Iterator<Item = usize>,
    {
        if let MediaKind::Video(ref fmt) = self.kind {
            let mut f_iter = fmt.format.iter();
            let w = fmt.width;
            let h = fmt.height;
            for i in 0..self.buf.count() {
                let d_linesize = self.buf.linesize(i).unwrap();
                let s_linesize = src_linesize.next().unwrap();
                let d = self.buf.as_mut_slice(i).unwrap();
                let c = f_iter.next().unwrap();
                let r = src.next().unwrap();
                let hb = c.unwrap().get_height(h);
                let s = unsafe { slice::from_raw_parts(r, hb * s_linesize) };
                copy_plane(d, d_linesize, s, s_linesize, c.unwrap().get_width(w), hb);
                mem::forget(s);
            }
        } else {
            unimplemented!();
        }
    }
}

<commit_msg>frame: Restrict the FrameBufferConv to the supported types<commit_after>#![allow(dead_code, unused_variables)]
use alloc::heap::{Heap, Alloc, Layout};
use bytes::BytesMut;

use std::sync::Arc;

use audiosample::*;
use pixel::*;
use timeinfo::*;

#[derive(Fail, Debug)]
pub enum FrameError {
    #[fail(display = "Invalid Index")]
    InvalidIndex,
    #[fail(display = "Invalid Conversion")]
    InvalidConversion,
}

use self::FrameError::*;

// TODO: Document
// TODO: Change it to provide Droppable/Seekable information or use a separate enum?
#[derive(Clone, Debug, PartialEq)]
pub enum PictureType {
    UNKNOWN,
    I,
    P,
    B,
    S,
    SI,
    SP,
    SB,
    BI,
}

#[derive(Clone, Debug, PartialEq)]
pub struct VideoInfo {
    pub pic_type: PictureType,
    pub width: usize,
    pub height: usize,
    pub format: Arc<Formaton>,
}

impl VideoInfo {
    fn size(&self, align: usize) -> usize {
        let mut size = 0;
        for &component in self.format.into_iter() {
            if let Some(c) = component {
                size += c.get_data_size(self.width, self.height, align);
            }
        }
        size
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct AudioInfo {
    pub samples: usize,
    pub rate: usize,
    pub map: ChannelMap,
    pub format: Arc<Soniton>,
}

impl AudioInfo {
    fn size(&self, align: usize) -> usize {
        self.format.get_audio_size(self.samples, align) * self.map.len()
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum MediaKind {
    Video(VideoInfo),
    Audio(AudioInfo),
}

use std::convert::From;

impl From<VideoInfo> for MediaKind {
    fn from(v: VideoInfo) -> Self {
        MediaKind::Video(v)
    }
}

impl From<AudioInfo> for MediaKind {
    fn from(a: AudioInfo) -> Self {
        MediaKind::Audio(a)
    }
}

use self::MediaKind::*;

pub trait FrameBuffer : Send + Sync {
    fn linesize(&self, idx: usize) -> Result<usize, FrameError>;
    fn count(&self) -> usize;
    fn as_slice_inner<'a>(&'a self, idx: usize) -> Result<&'a [u8], FrameError>;
    fn as_mut_slice_inner<'a>(&'a mut self, idx: usize) -> Result<&'a mut [u8], FrameError>;
}

mod private {
    pub trait Supported {}
    impl Supported for u8 {}
    impl Supported for i16 {}
    impl Supported for f32 {}
}

pub trait FrameBufferConv<T: private::Supported> : FrameBuffer {
    fn as_slice<'a>(&'a self, idx: usize) -> Result<&'a [T], FrameError> {
        let size = mem::size_of::<T>();
        if (self.linesize(idx)? % size) != 0 {
            Err(InvalidConversion)
        } else {
            let s = self.as_slice_inner(idx)?;
            let r = unsafe {
                slice::from_raw_parts::<T>(mem::transmute(s.as_ptr()), s.len() / size)
            };

            Ok(r)
        }
    }
    fn as_mut_slice<'a>(&'a mut self, idx: usize) -> Result<&'a mut [T], FrameError> {
        let size = mem::size_of::<T>();
        if (self.linesize(idx)? % size) != 0 {
            Err(InvalidConversion)
        } else {
            let s = self.as_mut_slice_inner(idx)?;
            let r = unsafe {
                slice::from_raw_parts_mut::<T>(mem::transmute(s.as_ptr()), s.len() / size)
            };

            Ok(r)
        }
    }
}

impl FrameBufferConv<u8> for FrameBuffer {}
impl FrameBufferConv<i16> for FrameBuffer {}
impl FrameBufferConv<f32> for FrameBuffer {}

use std::fmt;

impl fmt::Debug for FrameBuffer {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "FrameBuffer")
    }
}

#[derive(Debug)]
pub struct Frame {
    pub kind: MediaKind,
    pub buf: Box<FrameBuffer>,
    pub t: TimeInfo,
}

const ALIGNMENT: usize = 32;

struct Plane {
    buf: BytesMut,
    linesize: usize,
}

struct DefaultFrameBuffer {
    buf: BytesMut,
    planes: Vec<Plane>,
}

impl FrameBuffer for DefaultFrameBuffer {
    fn linesize(&self, idx: usize) -> Result<usize, FrameError> {
        match self.planes.get(idx) {
            None => Err(InvalidIndex),
            Some(plane) => Ok(plane.linesize),
        }
    }
    fn count(&self) -> usize {
        self.planes.len()
    }

    fn as_slice_inner<'a>(&'a self, idx: usize) -> Result<&'a [u8], FrameError> {
        match self.planes.get(idx) {
            None => Err(InvalidIndex),
            Some(plane) => Ok(&plane.buf),
        }
    }
    fn as_mut_slice_inner<'a>(&'a mut self, idx: usize) -> Result<&'a mut [u8], FrameError> {
        match self.planes.get_mut(idx) {
            None => Err(InvalidIndex),
            Some(plane) => Ok(&mut plane.buf),
        }
    }
}

impl DefaultFrameBuffer {
    pub fn new<'a>(kind: &'a MediaKind) -> DefaultFrameBuffer {
        match kind {
            &Video(ref video) => {
                let size = video.size(ALIGNMENT);
                let data = unsafe {
                    Heap.alloc(Layout::from_size_align(size, ALIGNMENT).unwrap())
                        .unwrap()
                };
                //let data = unsafe { Heap.alloc_zeroed(Layout::from_size_align(size, ALIGNMENT)) };
                let buf = BytesMut::from(unsafe { Vec::from_raw_parts(data, size, size) });
                let mut buffer = DefaultFrameBuffer {
                    buf: buf,
                    planes: Vec::new(),
                };
                for &component in video.format.iter() {
                    if let Some(c) = component {
                        let planesize = c.get_data_size(video.width, video.height, ALIGNMENT);
                        let linesize = c.get_linesize(video.width, ALIGNMENT);
                        buffer.planes.push(Plane {
                            buf: buffer.buf.split_to(planesize),
                            linesize: linesize,
                        });
                    }
                }
                buffer
            },
            &Audio(ref audio) => {
                let size = audio.size(ALIGNMENT);
                let data = unsafe {
                    Heap.alloc(Layout::from_size_align(size, ALIGNMENT).unwrap())
                        .unwrap()
                };
                let buf = BytesMut::from(unsafe { Vec::from_raw_parts(data, size, size) });
                let mut buffer = DefaultFrameBuffer {
                    buf: buf,
                    planes: Vec::new(),
                };
                for _ in 0..audio.map.len() {
                    let size = audio.format.get_audio_size(audio.samples, ALIGNMENT);
                    buffer.planes.push(Plane {
                        buf: buffer.buf.split_to(size),
                        linesize: size,
                    });
                }
                buffer
            },
        }
    }
}

pub type ArcFrame = Arc<Frame>;

pub fn new_default_frame<T>(kind: T, t: Option<TimeInfo>) -> Frame
where T: Into<MediaKind> + Clone
{
    let k = kind.into();
    let buf = DefaultFrameBuffer::new(&k);

    Frame {
        kind: k,
        buf: box buf,
        t: t.unwrap_or_default(),
    }
}

use std::ptr::copy_nonoverlapping;

fn copy_plane(
    dst: &mut [u8],
    dst_linesize: usize,
    src: &[u8],
    src_linesize: usize,
    w: usize,
    h: usize,
) {
    let dst_chunks = dst.chunks_mut(dst_linesize);
    let src_chunks = src.chunks(src_linesize);

    for (d, s) in dst_chunks.zip(src_chunks).take(h) {
        unsafe {
            copy_nonoverlapping(s.as_ptr(), d.as_mut_ptr(), w);
        }
    }
}

fn copy_image<'a, IM, IU, I>(
    dst: IM,
    dst_linesizes: IU,
    src: I,
    src_linesizes: IU,
    w: usize,
    h: usize,
    fmt: &Formaton,
) where
    IM: Iterator<Item = &'a mut [u8]>,
    I: Iterator<Item = &'a [u8]>,
    IU: Iterator<Item = usize>,
{
    let dst_iter = dst.zip(dst_linesizes);
    let src_iter = src.zip(src_linesizes);
    let iter = dst_iter.zip(src_iter).zip(fmt.iter());

    for (((d, d_linesize), (s, s_linesize)), c) in iter {
        copy_plane(
            d,
            d_linesize,
            s,
            s_linesize,
            c.unwrap().get_width(w),
            c.unwrap().get_height(h),
        );
    }
}

// TODO: Add proper tests
fn copy_to_frame<'a, I, IU>(dst: &mut Frame, mut src: I, mut src_linesize: IU, w: usize, h: usize)
where
    I: Iterator<Item = &'a [u8]>,
    IU: Iterator<Item = usize>,
{
    if let MediaKind::Video(ref fmt) = dst.kind {
        let mut f_iter = fmt.format.iter();
        let w = fmt.width;
        let h = fmt.height;
        for i in 0..dst.buf.count() {
            let d_linesize = dst.buf.linesize(i).unwrap();
            let s_linesize = src_linesize.next().unwrap();
            let d = dst.buf.as_mut_slice(i).unwrap();
            let s = src.next().unwrap();
            let c = f_iter.next().unwrap();
            copy_plane(
                d,
                d_linesize,
                s,
                s_linesize,
                c.unwrap().get_width(w),
                c.unwrap().get_height(h),
            );
        }
    } else {
        unimplemented!();
    }
}

use std::mem;
use std::slice;

// TODO make it a separate trait
impl Frame {
    pub fn copy_from_slice<'a, I, IU>(&mut self, mut src: I, mut src_linesize: IU)
    where
        I: Iterator<Item = &'a [u8]>,
        IU: Iterator<Item = usize>,
    {
        if let MediaKind::Video(ref fmt) = self.kind {
            let mut f_iter = fmt.format.iter();
            let w = fmt.width;
            let h = fmt.height;
            for i in 0..self.buf.count() {
                let d_linesize = self.buf.linesize(i).unwrap();
                let s_linesize = src_linesize.next().unwrap();
                let d = self.buf.as_mut_slice(i).unwrap();
                let s = src.next().unwrap();
                let c = f_iter.next().unwrap();
                copy_plane(
                    d,
                    d_linesize,
                    s,
                    s_linesize,
                    c.unwrap().get_width(w),
                    c.unwrap().get_height(h),
                );
            }
        } else {
            unimplemented!();
        }
    }

    pub fn copy_from_raw_parts<'a, I, IU>(&mut self, mut src: I, mut src_linesize: IU)
    where
        I: Iterator<Item = *const u8>,
        IU: Iterator<Item = usize>,
    {
        if let MediaKind::Video(ref fmt) = self.kind {
            let mut f_iter = fmt.format.iter();
            let w = fmt.width;
            let h = fmt.height;
            for i in 0..self.buf.count() {
                let d_linesize = self.buf.linesize(i).unwrap();
                let s_linesize = src_linesize.next().unwrap();
                let d = self.buf.as_mut_slice(i).unwrap();
                let c = f_iter.next().unwrap();
                let r = src.next().unwrap();
                let hb = c.unwrap().get_height(h);
                let s = unsafe { slice::from_raw_parts(r, hb * s_linesize) };
                copy_plane(d, d_linesize, s, s_linesize, c.unwrap().get_width(w), hb);
                mem::forget(s);
            }
        } else {
            unimplemented!();
        }
    }
}

<|endoftext|>


<commit_before>extern crate libc;
extern crate pocketsphinx_sys as bindings;

use std::ptr;
use std::ffi::{CStr, CString};
use std::mem;
use libc::c_char;

pub struct CmdLn {
    raw: *mut bindings::cmd_ln_t,

    // Holds argument strings because Sphinx doesn't copy them and
    // assumes they are valid as long as `cmd_ln_t` is alive.
    #[allow(dead_code)]
    args: Vec<CString>,
}

impl CmdLn {
    pub fn init(strict: bool, args: &[&str]) -> Option<Self> {
        // Sphinx assumes that `args` are valid as long as returned
        // `cmd_ln_t` is alive, so copy them.
        let c_args: Vec<_> = args.iter().map(|s| CString::new(*s).unwrap()).collect();
        let args_ptrs: Vec<_> = c_args.iter().map(|s| s.as_ptr()).collect();
        let raw = unsafe {
            bindings::cmd_ln_parse_r(ptr::null_mut(),
                                     bindings::ps_args(),
                                     args_ptrs.len() as i32,
                                     args_ptrs.as_ptr(),
                                     strict as i32)
        };
        if raw.is_null() {
            return None;
        }
        Some(CmdLn{raw: raw, args: c_args})
    }

    fn into_raw(mut self) -> *mut bindings::cmd_ln_t {
        mem::replace(&mut self.raw, ptr::null_mut())
    }
}

impl Drop for CmdLn {
    fn drop(&mut self) {
        if !self.raw.is_null() {
            let ref_count = unsafe { bindings::cmd_ln_free_r(self.raw) };
            assert!(ref_count == 0);
        }
    }
}

pub struct PsDecoder {
    raw: *mut bindings::ps_decoder_t,
}

impl PsDecoder {
    pub fn init(config: CmdLn) -> Self {
        let raw = unsafe { bindings::ps_init(config.into_raw()) };
        assert!(!raw.is_null());
        PsDecoder{raw: raw}
    }

    pub fn start_utt(&self, utt_id: Option<&str>) -> std::result::Result<(), ()>  {
        let (_id_cstr, id_ptr) = utt_id.map_or_else(
            ||  { (CString::new("").unwrap(), ptr::null()) },
            |s| {
                let cstr = CString::new(s).unwrap();
                let cptr = cstr.as_ptr();
                (cstr, cptr)
            }
        );
        let code = unsafe { bindings::ps_start_utt(self.raw, id_ptr) };
        if code == 0 { Ok(()) } else { Err(()) }
    }

    pub fn process_raw(&self,
                       data: &[i16],
                       no_search: bool,
                       full_utt: bool) -> std::result::Result<i32, ()> {
        let frames = unsafe {
            bindings::ps_process_raw(self.raw, data.as_ptr(), data.len(),
                                     no_search as i32, full_utt as i32)
        };
        if frames < 0 { return Err(()); }
        Ok(frames)
    }

    pub fn end_utt(&self) -> std::result::Result<(), ()> {
        let code = unsafe { bindings::ps_end_utt(self.raw) };
        if code < 0 { return Err(()); }
        Ok(())
    }

    pub fn get_hyp(&self) -> Option<(String, String, i32)> {
        let mut score: i32 = 0;
        let mut c_utt_id: *const c_char = ptr::null();
        let c_hyp = unsafe { bindings::ps_get_hyp(self.raw, &mut score, &mut c_utt_id) };
        if c_hyp.is_null() { return None; }

        let hyp = unsafe { CStr::from_ptr(c_hyp) }.to_string_lossy().into_owned();
        let utt_id = unsafe { CStr::from_ptr(c_utt_id) }.to_string_lossy().into_owned();
        Some((hyp, utt_id, score))
    }
}

impl Drop for PsDecoder {
    fn drop(&mut self) {
        let ref_count = unsafe { bindings::ps_free(self.raw) };
        assert!(ref_count == 0);
    }
}
<commit_msg>Make utt_id returned by `get_hyp` optional<commit_after>extern crate libc;
extern crate pocketsphinx_sys as bindings;

use std::ptr;
use std::ffi::{CStr, CString};
use std::mem;
use libc::c_char;

pub struct CmdLn {
    raw: *mut bindings::cmd_ln_t,

    // Holds argument strings because Sphinx doesn't copy them and
    // assumes they are valid as long as `cmd_ln_t` is alive.
    #[allow(dead_code)]
    args: Vec<CString>,
}

impl CmdLn {
    pub fn init(strict: bool, args: &[&str]) -> Option<Self> {
        // Sphinx assumes that `args` are valid as long as returned
        // `cmd_ln_t` is alive, so copy them.
        let c_args: Vec<_> = args.iter().map(|s| CString::new(*s).unwrap()).collect();
        let args_ptrs: Vec<_> = c_args.iter().map(|s| s.as_ptr()).collect();
        let raw = unsafe {
            bindings::cmd_ln_parse_r(ptr::null_mut(),
                                     bindings::ps_args(),
                                     args_ptrs.len() as i32,
                                     args_ptrs.as_ptr(),
                                     strict as i32)
        };
        if raw.is_null() {
            return None;
        }
        Some(CmdLn{raw: raw, args: c_args})
    }

    fn into_raw(mut self) -> *mut bindings::cmd_ln_t {
        mem::replace(&mut self.raw, ptr::null_mut())
    }
}

impl Drop for CmdLn {
    fn drop(&mut self) {
        if !self.raw.is_null() {
            let ref_count = unsafe { bindings::cmd_ln_free_r(self.raw) };
            assert!(ref_count == 0);
        }
    }
}

pub struct PsDecoder {
    raw: *mut bindings::ps_decoder_t,
}

impl PsDecoder {
    pub fn init(config: CmdLn) -> Self {
        let raw = unsafe { bindings::ps_init(config.into_raw()) };
        assert!(!raw.is_null());
        PsDecoder{raw: raw}
    }

    pub fn start_utt(&self, utt_id: Option<&str>) -> std::result::Result<(), ()>  {
        let (_id_cstr, id_ptr) = utt_id.map_or_else(
            ||  { (CString::new("").unwrap(), ptr::null()) },
            |s| {
                let cstr = CString::new(s).unwrap();
                let cptr = cstr.as_ptr();
                (cstr, cptr)
            }
        );
        let code = unsafe { bindings::ps_start_utt(self.raw, id_ptr) };
        if code == 0 { Ok(()) } else { Err(()) }
    }

    pub fn process_raw(&self,
                       data: &[i16],
                       no_search: bool,
                       full_utt: bool) -> std::result::Result<i32, ()> {
        let frames = unsafe {
            bindings::ps_process_raw(self.raw, data.as_ptr(), data.len(),
                                     no_search as i32, full_utt as i32)
        };
        if frames < 0 { return Err(()); }
        Ok(frames)
    }

    pub fn end_utt(&self) -> std::result::Result<(), ()> {
        let code = unsafe { bindings::ps_end_utt(self.raw) };
        if code < 0 { return Err(()); }
        Ok(())
    }

    pub fn get_hyp(&self) -> Option<(String, Option<String>, i32)> {
        let mut score: i32 = 0;
        let mut c_utt_id: *const c_char = ptr::null();
        let c_hyp = unsafe { bindings::ps_get_hyp(self.raw, &mut score, &mut c_utt_id) };
        if c_hyp.is_null() { return None; }

        let hyp = unsafe { CStr::from_ptr(c_hyp) }.to_string_lossy().into_owned();
        let utt_id = if c_utt_id.is_null() {
            None
        } else {
            Some(unsafe { CStr::from_ptr(c_utt_id) }.to_string_lossy().into_owned())
        };
        Some((hyp, utt_id, score))
    }
}

impl Drop for PsDecoder {
    fn drop(&mut self) {
        let ref_count = unsafe { bindings::ps_free(self.raw) };
        assert!(ref_count == 0);
    }
}
<|endoftext|>


<commit_before>//! socketCAN support.
//!
//! The Linux kernel supports using CAN-devices using a network-like API
//! (see https://www.kernel.org/doc/Documentation/networking/can.txt). This
//! crate allows easy access to this functionality without having to wrestle
//! libc calls.

extern crate itertools;
extern crate libc;
extern crate nix;

use libc::{c_int, c_short, c_void, c_uint, socket, SOCK_RAW, close, bind,
           sockaddr, read, write};
use itertools::Itertools;
use std::{io, error, fmt};
use std::mem::size_of;
use nix::net::if_::if_nametoindex;

// constants stolen from C headers
const AF_CAN: c_int = 29;
const PF_CAN: c_int = 29;
const CAN_RAW: c_int = 1;

/// if set, uses 29 bit extended format
pub const EFF_FLAG: u32 = 0x80000000;

/// remote transmission request flag
pub const RTR_FLAG: u32 = 0x40000000;

/// error flag
pub const ERR_FLAG: u32 = 0x20000000;

/// valid bits in standard frame id
pub const SFF_MASK: u32 = 0x000007ff;

/// valid bits in extended frame id
pub const EFF_MASK: u32 = 0x1fffffff;

/// valid bits in error frame
pub const ERR_MASK: u32 = 0x1fffffff;

#[derive(Debug)]
#[repr(C)]
struct CANAddr {
    _af_can: c_short,
    if_index: c_int,  // address familiy,
    rx_id: u32,
    tx_id: u32,
}

#[derive(Debug)]
pub enum CANSocketOpenError {
    /// Device could not be found
    LookupError(nix::Error),

    /// System error while trying to look up device name
    IOError(io::Error),
}

impl fmt::Display for CANSocketOpenError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CANSocketOpenError::LookupError(ref e) =>
                write!(f, "CAN Device not found: {}", e),
            CANSocketOpenError::IOError(ref e) =>
                write!(f, "IO: {}", e),
        }
    }
}

impl error::Error for CANSocketOpenError {
    fn description(&self) -> &str {
        match *self {
            CANSocketOpenError::LookupError(_)
                => "can device not found",
            CANSocketOpenError::IOError(ref e)
                => e.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            CANSocketOpenError::LookupError(ref e) => Some(e),
            CANSocketOpenError::IOError(ref e) => Some(e),
        }
    }
}

#[derive(Debug)]
pub enum ConstructionError {
    IDTooLarge,
    TooMuchData,
}

impl fmt::Display for ConstructionError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ConstructionError::IDTooLarge
                => write!(f, "CAN ID too large"),
            ConstructionError::TooMuchData
                => write!(f, "Payload is larger than CAN maximum of 8 bytes")
        }
    }
}

impl error::Error for ConstructionError {
    fn description(&self) -> &str {
        match *self {
            ConstructionError::IDTooLarge => "can id too large",
            ConstructionError::TooMuchData => "too much data",
        }
    }
}

impl From<nix::Error> for CANSocketOpenError {
    fn from(e: nix::Error) -> CANSocketOpenError {
        CANSocketOpenError::LookupError(e)
    }
}

impl From<io::Error> for CANSocketOpenError {
    fn from(e: io::Error) -> CANSocketOpenError {
        CANSocketOpenError::IOError(e)
    }
}

/// A socket for a CAN device. Just a wrapped file descriptor.
///
/// Will be closed upon deallocation. To close manually, use std::drop::Drop.
pub struct CANSocket {
    fd: c_int,
}

impl CANSocket {
    /// Open a named CAN device.
    ///
    /// Usually the more common case, opens a socket can device by name, such
    /// as "vcan0" or "socan0".
    pub fn open(ifname: &str) -> Result<CANSocket, CANSocketOpenError> {
        let if_index = try!(if_nametoindex(ifname));
        CANSocket::open_if(if_index)
    }

    /// Open CAN device by interface number.
    ///
    /// Opens a CAN device by kernel interface number.
    pub fn open_if(if_index: c_uint) -> Result<CANSocket, CANSocketOpenError> {
        let addr = CANAddr{
            _af_can: AF_CAN as c_short,
            if_index: if_index as c_int,
            rx_id: 0, // ?
            tx_id: 0, // ?
        };

        // open socket
        let sock_fd;
        unsafe {
            sock_fd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
        }

        if sock_fd == -1 {
            return Err(CANSocketOpenError::from(io::Error::last_os_error()));
        }

        // bind it
        let bind_rv;
        unsafe {
            let sockaddr_ptr = &addr as *const CANAddr;
            bind_rv = bind(sock_fd, sockaddr_ptr as *const sockaddr,
                size_of::<CANAddr> () as u32);
        }

        if bind_rv == -1 {
            let e = io::Error::last_os_error();
            unsafe {
                close(sock_fd);
            }
            return Err(CANSocketOpenError::from(e))
        }

        Ok(CANSocket{fd: sock_fd})
    }

    fn close(&mut self) -> io::Result<()> {
        unsafe {
            let rv = close(self.fd);
            if rv != -1 {
                return Err(io::Error::last_os_error());
            }
        }
        Ok(())
    }

    /// Blocking read a single can frame.
    pub fn read_frame(&self) -> io::Result<CANFrame> {
        let mut frame = CANFrame{
            _id: 0,
            _data_len: 0,
            _pad: 0,
            _res0: 0,
            _res1: 0,
            _data: [0; 8],
        };

        let read_rv = unsafe {
            let frame_ptr = &mut frame as *mut CANFrame;
            read(self.fd, frame_ptr as *mut c_void, size_of::<CANFrame>())
        };

        if read_rv as usize != size_of::<CANFrame>() {
            return Err(io::Error::last_os_error());
        }

        Ok(frame)
    }

    pub fn write_frame(&self, frame: &CANFrame) -> io::Result<()> {
        // not a mutable reference needed (see std::net::UdpSocket) for
        // a comparison
        // debug!("Sending: {:?}", frame);

        let write_rv = unsafe {
            let frame_ptr = frame as *const CANFrame;
            write(self.fd, frame_ptr as *const c_void, size_of::<CANFrame>())
        };

        if write_rv as usize != size_of::<CANFrame>() {
            return Err(io::Error::last_os_error());
        }

        Ok(())
    }
}

impl Drop for CANSocket {
    fn drop(&mut self) {
        self.close().ok();  // ignore result
    }
}

/// CANFrame
///
/// Same memory layout as the underlying kernel struct.
#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub struct CANFrame {
    /// 32 bit CAN_ID + EFF/RTR/ERR flags
    pub _id: u32,

    /// data length. Bytes beyond are not valid
    _data_len: u8,

    /// padding
    _pad: u8,

    /// reserved
    _res0: u8,

    /// reserved
    _res1: u8,

    /// buffer for data
    _data: [u8; 8],
}

impl CANFrame {
    pub fn new(id: u32, data: &[u8], rtr: bool, err: bool) -> Result<CANFrame,
    ConstructionError> {
        let mut _id = id;

        if data.len() > 8 {
            return Err(ConstructionError::TooMuchData)
        }

        if id > EFF_MASK {
            return Err(ConstructionError::IDTooLarge)
        }

        // set EFF_FLAG on large message
        if id > SFF_MASK {
            _id |= EFF_FLAG;
        }

        if rtr {
            _id |= RTR_FLAG;
        }

        if err {
            _id |= ERR_FLAG;
        }

        let mut full_data = [0; 8];

        // not cool =/
        for (n, c) in data.iter().enumerate() {
            full_data[n] = *c;
        }

        Ok(CANFrame{
            _id: _id,
            _data_len: data.len() as u8,
            _pad: 0,
            _res0: 0,
            _res1: 0,
            _data: full_data,
        })
    }

    /// Return the actual CAN ID (without EFF/RTR/ERR flags)
    pub fn id(&self) -> u32 {
        if self.is_extended() {
            self._id & EFF_MASK
        } else {
            self._id & SFF_MASK
        }
    }

    /// Return the error message
    pub fn err(&self) -> u32 {
        return self._id & ERR_MASK
    }

    /// Check if frame uses 29 bit extended frame format
    pub fn is_extended(&self) -> bool {
        self._id & EFF_FLAG != 0
    }

    /// Check if frame is an error message
    pub fn is_error(&self) -> bool {
        self._id & ERR_FLAG != 0
    }

    /// Check if frame is a remote transmission request
    pub fn is_rtr(&self) -> bool {
        self._id & RTR_FLAG != 0
    }

    /// A slice into the actual data. Slice will always be <= 8 bytes in length
    pub fn data(&self) -> &[u8] {
        &self._data[..(self._data_len as usize)]
    }
}

impl fmt::UpperHex for CANFrame {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "{:X}#", self.id()));

        let mut parts = self.data().iter().map(|v| format!("{:02X}", v));

        let sep = if f.alternate() { " " } else { " " };
        write!(f, "{}", parts.join(sep))
    }
}
<commit_msg>Cleaned up docs slightly.<commit_after>//! socketCAN support.
//!
//! The Linux kernel supports using CAN-devices through a network-like API
//! (see https://www.kernel.org/doc/Documentation/networking/can.txt). This
//! crate allows easy access to this functionality without having to wrestle
//! libc calls.

extern crate itertools;
extern crate libc;
extern crate nix;

use libc::{c_int, c_short, c_void, c_uint, socket, SOCK_RAW, close, bind,
           sockaddr, read, write};
use itertools::Itertools;
use std::{io, error, fmt};
use std::mem::size_of;
use nix::net::if_::if_nametoindex;

// constants stolen from C headers
const AF_CAN: c_int = 29;
const PF_CAN: c_int = 29;
const CAN_RAW: c_int = 1;

/// if set, indicate 29 bit extended format
pub const EFF_FLAG: u32 = 0x80000000;

/// remote transmission request flag
pub const RTR_FLAG: u32 = 0x40000000;

/// error flag
pub const ERR_FLAG: u32 = 0x20000000;

/// valid bits in standard frame id
pub const SFF_MASK: u32 = 0x000007ff;

/// valid bits in extended frame id
pub const EFF_MASK: u32 = 0x1fffffff;

/// valid bits in error frame
pub const ERR_MASK: u32 = 0x1fffffff;

#[derive(Debug)]
#[repr(C)]
struct CANAddr {
    _af_can: c_short,
    if_index: c_int,  // address familiy,
    rx_id: u32,
    tx_id: u32,
}

#[derive(Debug)]
/// Errors opening socket
pub enum CANSocketOpenError {
    /// Device could not be found
    LookupError(nix::Error),

    /// System error while trying to look up device name
    IOError(io::Error),
}

impl fmt::Display for CANSocketOpenError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CANSocketOpenError::LookupError(ref e) =>
                write!(f, "CAN Device not found: {}", e),
            CANSocketOpenError::IOError(ref e) =>
                write!(f, "IO: {}", e),
        }
    }
}

impl error::Error for CANSocketOpenError {
    fn description(&self) -> &str {
        match *self {
            CANSocketOpenError::LookupError(_)
                => "can device not found",
            CANSocketOpenError::IOError(ref e)
                => e.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            CANSocketOpenError::LookupError(ref e) => Some(e),
            CANSocketOpenError::IOError(ref e) => Some(e),
        }
    }
}

#[derive(Debug, Copy, Clone)]
/// Error that occurs when creating CAN packets
pub enum ConstructionError {
    IDTooLarge,  /// CAN ID was outside the range of valid IDs
    TooMuchData, /// More than 8 Bytes of payload data were passed in
}

impl fmt::Display for ConstructionError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ConstructionError::IDTooLarge
                => write!(f, "CAN ID too large"),
            ConstructionError::TooMuchData
                => write!(f, "Payload is larger than CAN maximum of 8 bytes")
        }
    }
}

impl error::Error for ConstructionError {
    fn description(&self) -> &str {
        match *self {
            ConstructionError::IDTooLarge => "can id too large",
            ConstructionError::TooMuchData => "too much data",
        }
    }
}

impl From<nix::Error> for CANSocketOpenError {
    fn from(e: nix::Error) -> CANSocketOpenError {
        CANSocketOpenError::LookupError(e)
    }
}

impl From<io::Error> for CANSocketOpenError {
    fn from(e: io::Error) -> CANSocketOpenError {
        CANSocketOpenError::IOError(e)
    }
}

/// A socket for a CAN device.
///
/// Will be closed upon deallocation. To close manually, use std::drop::Drop.
/// Internally this is just a wrapped file-descriptor.
pub struct CANSocket {
    fd: c_int,
}

impl CANSocket {
    /// Open a named CAN device.
    ///
    /// Usually the more common case, opens a socket can device by name, such
    /// as "vcan0" or "socan0".
    pub fn open(ifname: &str) -> Result<CANSocket, CANSocketOpenError> {
        let if_index = try!(if_nametoindex(ifname));
        CANSocket::open_if(if_index)
    }

    /// Open CAN device by interface number.
    ///
    /// Opens a CAN device by kernel interface number.
    pub fn open_if(if_index: c_uint) -> Result<CANSocket, CANSocketOpenError> {
        let addr = CANAddr{
            _af_can: AF_CAN as c_short,
            if_index: if_index as c_int,
            rx_id: 0, // ?
            tx_id: 0, // ?
        };

        // open socket
        let sock_fd;
        unsafe {
            sock_fd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
        }

        if sock_fd == -1 {
            return Err(CANSocketOpenError::from(io::Error::last_os_error()));
        }

        // bind it
        let bind_rv;
        unsafe {
            let sockaddr_ptr = &addr as *const CANAddr;
            bind_rv = bind(sock_fd, sockaddr_ptr as *const sockaddr,
                size_of::<CANAddr> () as u32);
        }

        if bind_rv == -1 {
            let e = io::Error::last_os_error();
            unsafe {
                close(sock_fd);
            }
            return Err(CANSocketOpenError::from(e))
        }

        Ok(CANSocket{fd: sock_fd})
    }

    fn close(&mut self) -> io::Result<()> {
        unsafe {
            let rv = close(self.fd);
            if rv != -1 {
                return Err(io::Error::last_os_error());
            }
        }
        Ok(())
    }

    /// Blocking read a single can frame.
    pub fn read_frame(&self) -> io::Result<CANFrame> {
        let mut frame = CANFrame{
            _id: 0,
            _data_len: 0,
            _pad: 0,
            _res0: 0,
            _res1: 0,
            _data: [0; 8],
        };

        let read_rv = unsafe {
            let frame_ptr = &mut frame as *mut CANFrame;
            read(self.fd, frame_ptr as *mut c_void, size_of::<CANFrame>())
        };

        if read_rv as usize != size_of::<CANFrame>() {
            return Err(io::Error::last_os_error());
        }

        Ok(frame)
    }

    /// Blocking write a single can frame.
    pub fn write_frame(&self, frame: &CANFrame) -> io::Result<()> {
        // not a mutable reference needed (see std::net::UdpSocket) for
        // a comparison
        // debug!("Sending: {:?}", frame);

        let write_rv = unsafe {
            let frame_ptr = frame as *const CANFrame;
            write(self.fd, frame_ptr as *const c_void, size_of::<CANFrame>())
        };

        if write_rv as usize != size_of::<CANFrame>() {
            return Err(io::Error::last_os_error());
        }

        Ok(())
    }
}

impl Drop for CANSocket {
    fn drop(&mut self) {
        self.close().ok();  // ignore result
    }
}

/// CANFrame
///
/// Uses the same memory layout as the underlying kernel struct for performance
/// reasons.
#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub struct CANFrame {
    /// 32 bit CAN_ID + EFF/RTR/ERR flags
    pub _id: u32,

    /// data length. Bytes beyond are not valid
    _data_len: u8,

    /// padding
    _pad: u8,

    /// reserved
    _res0: u8,

    /// reserved
    _res1: u8,

    /// buffer for data
    _data: [u8; 8],
}

impl CANFrame {
    pub fn new(id: u32, data: &[u8], rtr: bool, err: bool) -> Result<CANFrame,
    ConstructionError> {
        let mut _id = id;

        if data.len() > 8 {
            return Err(ConstructionError::TooMuchData)
        }

        if id > EFF_MASK {
            return Err(ConstructionError::IDTooLarge)
        }

        // set EFF_FLAG on large message
        if id > SFF_MASK {
            _id |= EFF_FLAG;
        }

        if rtr {
            _id |= RTR_FLAG;
        }

        if err {
            _id |= ERR_FLAG;
        }

        let mut full_data = [0; 8];

        // not cool =/
        for (n, c) in data.iter().enumerate() {
            full_data[n] = *c;
        }

        Ok(CANFrame{
            _id: _id,
            _data_len: data.len() as u8,
            _pad: 0,
            _res0: 0,
            _res1: 0,
            _data: full_data,
        })
    }

    /// Return the actual CAN ID (without EFF/RTR/ERR flags)
    pub fn id(&self) -> u32 {
        if self.is_extended() {
            self._id & EFF_MASK
        } else {
            self._id & SFF_MASK
        }
    }

    /// Return the error message
    pub fn err(&self) -> u32 {
        return self._id & ERR_MASK
    }

    /// Check if frame uses 29 bit extended frame format
    pub fn is_extended(&self) -> bool {
        self._id & EFF_FLAG != 0
    }

    /// Check if frame is an error message
    pub fn is_error(&self) -> bool {
        self._id & ERR_FLAG != 0
    }

    /// Check if frame is a remote transmission request
    pub fn is_rtr(&self) -> bool {
        self._id & RTR_FLAG != 0
    }

    /// A slice into the actual data. Slice will always be <= 8 bytes in length
    pub fn data(&self) -> &[u8] {
        &self._data[..(self._data_len as usize)]
    }
}

impl fmt::UpperHex for CANFrame {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "{:X}#", self.id()));

        let mut parts = self.data().iter().map(|v| format!("{:02X}", v));

        let sep = if f.alternate() { " " } else { " " };
        write!(f, "{}", parts.join(sep))
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs, warnings)]

//! Request logging middleware for Iron

extern crate iron;
extern crate time;
extern crate term;

use iron::{AfterMiddleware, BeforeMiddleware, IronResult, IronError, Request, Response, status};
use iron::typemap::Key;
use term::{Terminal, stdout};

use std::io;
use std::error::Error;
use std::fmt::{self, Display, Formatter};

use format::FormatText::{Str, Method, URI, Status, ResponseTime};
use format::FormatColor::{ConstantColor, FunctionColor};
use format::FormatAttr::{ConstantAttrs, FunctionAttrs};
use format::{Format, FormatText};

pub mod format;

/// `Middleware` for logging request and response info to the terminal.
pub struct Logger {
    format: Option<Format>
}

impl Logger {
    /// Create a pair of `Logger` middlewares with the specified `format`. If a `None` is passed in, uses the default format:
    ///
    /// ```ignore
    /// {method} {uri} -> {status} ({response_time} ms)
    /// ```
    ///
    /// While the returned value can be passed straight to `Chain::link`, consider making the logger `BeforeMiddleware`
    /// the first in your chain and the logger `AfterMiddleware` the last by doing something like this:
    ///
    /// ```ignore
    /// let mut chain = Chain::new(handler);
    /// let (logger_before, logger_after) = Logger::new(None);
    /// chain.link_before(logger_before);
    /// // link other middlewares here...
    /// chain.link_after(logger_after);
    /// ```
    pub fn new(format: Option<Format>) -> (Logger, Logger) {
        (Logger { format: format.clone() }, Logger { format: format })
    }
}

struct StartTime;
impl Key for StartTime { type Value = u64; }

impl Logger {
    fn initialise(&self, req: &mut Request) {
        req.extensions.insert::<StartTime>(time::precise_time_ns());
    }

    fn log(&self, req: &mut Request, res: &Response) -> IronResult<()> {
        let exit_time = time::precise_time_ns();
        let entry_time = *req.extensions.get::<StartTime>().unwrap();

        let response_time_ms = (exit_time - entry_time) as f64 / 1000000.0;
        let Format(format) = self.format.clone().unwrap_or_default();

        {
            let render = |text: &FormatText| {
                match *text {
                    Str(ref string) => string.clone(),
                    Method => format!("{}", req.method),
                    URI => format!("{}", req.url),
                    Status => format!("{}", res.status.unwrap()),
                    ResponseTime => format!("{} ms", response_time_ms)
                }
            };

            let log = |mut t: Box<Terminal<io::Stdout> + Send>| -> io::Result<()> {
                for unit in format.iter() {
                    match unit.color {
                        ConstantColor(Some(color)) => { try!(t.fg(color)); }
                        ConstantColor(None) => (),
                        FunctionColor(f) => match f(req, res) {
                            Some(color) => { try!(t.fg(color)); }
                            None => ()
                        }
                    }
                    match unit.attrs {
                        ConstantAttrs(ref attrs) => {
                            for &attr in attrs.iter() {
                                try!(t.attr(attr));
                            }
                        }
                        FunctionAttrs(f) => {
                            for &attr in f(req, res).iter() {
                                try!(t.attr(attr));
                            }
                        }
                    }
                    try!(write!(t, "{}", render(&unit.text)));
                    try!(t.reset());
                }
                try!(writeln!(t, ""));
                Ok(())
            };

            match stdout() {
                Some(terminal) => {
                    match log(terminal) {
                        Ok(result) => result,
                        Err(err) => return Err(IronError::new(err, status::InternalServerError))
                    }
                }
                None => { return Err(IronError::new(CouldNotOpenTerminal,
                                                    status::InternalServerError)) }
            };
        }

        Ok(())
    }
}

impl BeforeMiddleware for Logger {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        self.initialise(req);
        Ok(())
    }

    fn catch(&self, req: &mut Request, err: IronError) -> IronResult<()> {
        self.initialise(req);
        Err(err)
    }
}

impl AfterMiddleware for Logger {
    fn after(&self, req: &mut Request, res: Response) -> IronResult<Response> {
        match self.log(req, &res) {
            Ok(_) => Ok(res),
            Err(log_err) => Err(log_err),
        }
    }

    fn catch(&self, req: &mut Request, err: IronError) -> IronResult<Response> {
        match self.log(req, &err.response) {
            Ok(_) => Err(err),
            Err(log_err) => Err(log_err),
        }
    }
}

/// Error returned when logger cannout access stdout.
#[derive(Debug, Clone, Copy)]
pub struct CouldNotOpenTerminal;

impl Error for CouldNotOpenTerminal {
    fn description(&self) -> &str {
        "Could Not Open Terminal"
    }
}

impl Display for CouldNotOpenTerminal {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Logger could not open stdout as a terminal.")
    }
}
<commit_msg>(cleanup) Use try macro<commit_after>#![deny(missing_docs, warnings)]

//! Request logging middleware for Iron

extern crate iron;
extern crate time;
extern crate term;

use iron::{AfterMiddleware, BeforeMiddleware, IronResult, IronError, Request, Response, status};
use iron::typemap::Key;
use term::{Terminal, stdout};

use std::io;
use std::error::Error;
use std::fmt::{self, Display, Formatter};

use format::FormatText::{Str, Method, URI, Status, ResponseTime};
use format::FormatColor::{ConstantColor, FunctionColor};
use format::FormatAttr::{ConstantAttrs, FunctionAttrs};
use format::{Format, FormatText};

pub mod format;

/// `Middleware` for logging request and response info to the terminal.
pub struct Logger {
    format: Option<Format>
}

impl Logger {
    /// Create a pair of `Logger` middlewares with the specified `format`. If a `None` is passed in, uses the default format:
    ///
    /// ```ignore
    /// {method} {uri} -> {status} ({response_time} ms)
    /// ```
    ///
    /// While the returned value can be passed straight to `Chain::link`, consider making the logger `BeforeMiddleware`
    /// the first in your chain and the logger `AfterMiddleware` the last by doing something like this:
    ///
    /// ```ignore
    /// let mut chain = Chain::new(handler);
    /// let (logger_before, logger_after) = Logger::new(None);
    /// chain.link_before(logger_before);
    /// // link other middlewares here...
    /// chain.link_after(logger_after);
    /// ```
    pub fn new(format: Option<Format>) -> (Logger, Logger) {
        (Logger { format: format.clone() }, Logger { format: format })
    }
}

struct StartTime;
impl Key for StartTime { type Value = u64; }

impl Logger {
    fn initialise(&self, req: &mut Request) {
        req.extensions.insert::<StartTime>(time::precise_time_ns());
    }

    fn log(&self, req: &mut Request, res: &Response) -> IronResult<()> {
        let exit_time = time::precise_time_ns();
        let entry_time = *req.extensions.get::<StartTime>().unwrap();

        let response_time_ms = (exit_time - entry_time) as f64 / 1000000.0;
        let Format(format) = self.format.clone().unwrap_or_default();

        {
            let render = |text: &FormatText| {
                match *text {
                    Str(ref string) => string.clone(),
                    Method => format!("{}", req.method),
                    URI => format!("{}", req.url),
                    Status => format!("{}", res.status.unwrap()),
                    ResponseTime => format!("{} ms", response_time_ms)
                }
            };

            let log = |mut t: Box<Terminal<io::Stdout> + Send>| -> io::Result<()> {
                for unit in format.iter() {
                    match unit.color {
                        ConstantColor(Some(color)) => { try!(t.fg(color)); }
                        ConstantColor(None) => (),
                        FunctionColor(f) => match f(req, res) {
                            Some(color) => { try!(t.fg(color)); }
                            None => ()
                        }
                    }
                    match unit.attrs {
                        ConstantAttrs(ref attrs) => {
                            for &attr in attrs.iter() {
                                try!(t.attr(attr));
                            }
                        }
                        FunctionAttrs(f) => {
                            for &attr in f(req, res).iter() {
                                try!(t.attr(attr));
                            }
                        }
                    }
                    try!(write!(t, "{}", render(&unit.text)));
                    try!(t.reset());
                }
                try!(writeln!(t, ""));
                Ok(())
            };

            match stdout() {
                Some(terminal) => {
                    match log(terminal) {
                        Ok(result) => result,
                        Err(err) => return Err(IronError::new(err, status::InternalServerError))
                    }
                }
                None => { return Err(IronError::new(CouldNotOpenTerminal,
                                                    status::InternalServerError)) }
            };
        }

        Ok(())
    }
}

impl BeforeMiddleware for Logger {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        self.initialise(req);
        Ok(())
    }

    fn catch(&self, req: &mut Request, err: IronError) -> IronResult<()> {
        self.initialise(req);
        Err(err)
    }
}

impl AfterMiddleware for Logger {
    fn after(&self, req: &mut Request, res: Response) -> IronResult<Response> {
        try!(self.log(req, &res));
        Ok(res)
    }

    fn catch(&self, req: &mut Request, err: IronError) -> IronResult<Response> {
        try!(self.log(req, &err.response));
        Err(err)
    }
}

/// Error returned when logger cannout access stdout.
#[derive(Debug, Clone, Copy)]
pub struct CouldNotOpenTerminal;

impl Error for CouldNotOpenTerminal {
    fn description(&self) -> &str {
        "Could Not Open Terminal"
    }
}

impl Display for CouldNotOpenTerminal {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Logger could not open stdout as a terminal.")
    }
}
<|endoftext|>