<commit_before>#[crate_id(name="mkdir", vers="1.0.0", author="Nicholas Juszczak")];

/**
 * This file is part of the uutils coreutils package.
 *
 * (c) Nicholas Juszczak <juszczakn@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern mod extra;

use std::os;
use std::io::{fs, result, stderr};
use std::num::strconv;
use extra::getopts::groups;

static VERSION: &'static str = "1.0.0";

/**
 * Handles option parsing
 */
fn main() {
    let args = os::args();

    let opts = ~[
        // Linux-specific options, not implemented
        // groups::optflag("Z", "context", "set SELinux secutiry context" +
        // " of each created directory to CTX"),
        groups::optopt("m", "mode", "set file mode", "755"),
        groups::optflag("p", "parents", "make parent directories as needed"),
        groups::optflag("v", "verbose",
                        "print a message for each printed directory"),
        groups::optflag("h", "help", "display this help"),
        groups::optflag("", "version", "display this version")
    ];

    let matches = match groups::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => {
            writeln!(&mut stderr() as &mut Writer,
                     "Invalid options\n{}", f.to_err_msg());
            os::set_exit_status(1);
            return;
        }
    };

    if args.len() == 1 || matches.opt_present("help") {
        print_help(opts);
        return;
    }
    if matches.opt_present("version") {
        println("mkdir v" + VERSION);
        return;
    }
    let verbose_flag = matches.opt_present("verbose");
    let mk_parents = matches.opt_present("parents");

    // Translate a ~str in octal form to u32, default to 755
    // Not tested on Windows
    let mode_match = matches.opts_str(&[~"mode"]);
    let mode: u32 = if mode_match.is_some() {
        let m = mode_match.unwrap();
        let res = strconv::from_str_common(m, 8, false, false, false,
                                           strconv::ExpNone,
                                           false, false);
        if res.is_some() {
            res.unwrap()
        } else {
            writeln!(&mut stderr() as &mut Writer,
                     "Error: no mode given");
            os::set_exit_status(1);
            return;
        }
    } else {
        0o755
    };

    let dirs = matches.free;
    exec(dirs, mk_parents, mode, verbose_flag);
}

fn print_help(opts: &[groups::OptGroup]) {
    println!("mkdir v{} - make a new directory with the given path", VERSION);
    println("");
    println("Usage:");
    print(groups::usage("Create the given DIRECTORY(ies)" +
                        " if they do not exist", opts));
}

/**
 * Create the list of new directories
 */
fn exec(dirs: ~[~str], mk_parents: bool, mode: u32, verbose: bool) {
    let mut parent_dirs: ~[~str] = ~[];
    if mk_parents {
        for dir in dirs.iter() {
            let path = Path::new((*dir).clone());
            // Build list of parent dirs which need to be created
            let parent = path.dirname_str();
            match parent {
                Some(p) => {
                    if !Path::new(p).exists() {
                        parent_dirs.push(p.into_owned())
                    }
                },
                None => ()
            }
        }
    }
    // Recursively build parent dirs that are needed
    if !parent_dirs.is_empty() {
        exec(parent_dirs, mk_parents, mode, verbose);
    }

    for dir in dirs.iter() {
        let path = Path::new((*dir).clone());
        // Determine if parent directory to the one to
        // be created exists
        let parent = match path.dirname_str() {
            Some(p) => p,
            None => ""
        };
        let parent_exists = Path::new(parent).exists();
        if parent_exists && !path.exists() {
            // if mkdir failed return
            if !mkdir(&path, mode) {return;}
            if verbose {println(*dir);}
        } else {
            let mut error_msg = ~"";
            if !parent_exists {
                error_msg.push_str("Error: parent directory '");
                error_msg.push_str(parent);
                error_msg.push_str("' does not exist");
            } else {
                error_msg.push_str("Error: directory '");
                error_msg.push_str(*dir);
                error_msg.push_str("' already exists");
            }
            writeln!(&mut stderr() as &mut Writer,
                     "{}", error_msg);
            os::set_exit_status(1);
        }
    }
}

/**
 * Wrapper to catch errors, return false if failed
 */
fn mkdir(path: &Path, mode: u32) -> bool {
    match result(|| fs::mkdir(path, mode)) {
        Ok(_) => true,
        Err(e) => {
            writeln!(&mut stderr() as &mut Writer,
                     "mkdir: test {}", e.to_str());
            os::set_exit_status(1);
            false
        }
    }
}
<commit_msg>mkdir: update for latest Rust<commit_after>#[crate_id(name="mkdir", vers="1.0.0", author="Nicholas Juszczak")];

/**
 * This file is part of the uutils coreutils package.
 *
 * (c) Nicholas Juszczak <juszczakn@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern mod extra;

use std::os;
use std::io::{fs, result, stderr};
use std::num::strconv;
use extra::getopts::groups;

static VERSION: &'static str = "1.0.0";

/**
 * Handles option parsing
 */
fn main() {
    let args = os::args();

    let opts = ~[
        // Linux-specific options, not implemented
        // groups::optflag("Z", "context", "set SELinux secutiry context" +
        // " of each created directory to CTX"),
        groups::optopt("m", "mode", "set file mode", "755"),
        groups::optflag("p", "parents", "make parent directories as needed"),
        groups::optflag("v", "verbose",
                        "print a message for each printed directory"),
        groups::optflag("h", "help", "display this help"),
        groups::optflag("", "version", "display this version")
    ];

    let matches = match groups::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => {
            writeln!(&mut stderr() as &mut Writer,
                     "Invalid options\n{}", f.to_err_msg());
            os::set_exit_status(1);
            return;
        }
    };

    if args.len() == 1 || matches.opt_present("help") {
        print_help(opts);
        return;
    }
    if matches.opt_present("version") {
        println!("mkdir v{}", VERSION);
        return;
    }
    let verbose_flag = matches.opt_present("verbose");
    let mk_parents = matches.opt_present("parents");

    // Translate a ~str in octal form to u32, default to 755
    // Not tested on Windows
    let mode_match = matches.opts_str(&[~"mode"]);
    let mode: u32 = if mode_match.is_some() {
        let m = mode_match.unwrap();
        let res = strconv::from_str_common(m, 8, false, false, false,
                                           strconv::ExpNone,
                                           false, false);
        if res.is_some() {
            res.unwrap()
        } else {
            writeln!(&mut stderr() as &mut Writer,
                     "Error: no mode given");
            os::set_exit_status(1);
            return;
        }
    } else {
        0o755
    };

    let dirs = matches.free;
    exec(dirs, mk_parents, mode, verbose_flag);
}

fn print_help(opts: &[groups::OptGroup]) {
    println!("mkdir v{} - make a new directory with the given path", VERSION);
    println!("");
    println!("Usage:");
    print!("{}", groups::usage("Create the given DIRECTORY(ies)" +
                               " if they do not exist", opts));
}

/**
 * Create the list of new directories
 */
fn exec(dirs: ~[~str], mk_parents: bool, mode: u32, verbose: bool) {
    let mut parent_dirs: ~[~str] = ~[];
    if mk_parents {
        for dir in dirs.iter() {
            let path = Path::new((*dir).clone());
            // Build list of parent dirs which need to be created
            let parent = path.dirname_str();
            match parent {
                Some(p) => {
                    if !Path::new(p).exists() {
                        parent_dirs.push(p.into_owned())
                    }
                },
                None => ()
            }
        }
    }
    // Recursively build parent dirs that are needed
    if !parent_dirs.is_empty() {
        exec(parent_dirs, mk_parents, mode, verbose);
    }

    for dir in dirs.iter() {
        let path = Path::new((*dir).clone());
        // Determine if parent directory to the one to
        // be created exists
        let parent = match path.dirname_str() {
            Some(p) => p,
            None => ""
        };
        let parent_exists = Path::new(parent).exists();
        if parent_exists && !path.exists() {
            // if mkdir failed return
            if !mkdir(&path, mode) {return;}
            if verbose {println!("{}", *dir);}
        } else {
            let mut error_msg = ~"";
            if !parent_exists {
                error_msg.push_str("Error: parent directory '");
                error_msg.push_str(parent);
                error_msg.push_str("' does not exist");
            } else {
                error_msg.push_str("Error: directory '");
                error_msg.push_str(*dir);
                error_msg.push_str("' already exists");
            }
            writeln!(&mut stderr() as &mut Writer,
                     "{}", error_msg);
            os::set_exit_status(1);
        }
    }
}

/**
 * Wrapper to catch errors, return false if failed
 */
fn mkdir(path: &Path, mode: u32) -> bool {
    match result(|| fs::mkdir(path, mode)) {
        Ok(_) => true,
        Err(e) => {
            writeln!(&mut stderr() as &mut Writer,
                     "mkdir: test {}", e.to_str());
            os::set_exit_status(1);
            false
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::convert::From;
use std::sync::mpsc::{sync_channel, SyncSender, Receiver};
use std::io::{self, Read};

use rustc_serialize::json::{self, DecoderError};
use url::Url;
use hyper;
use hyper::client::request::Request;
use hyper::method::Method::Get;
use time::{Timespec, get_time, Duration, SteadyTime};

use irc::parse::IrcMsg;

use command_mapper::{
    RustBotPlugin,
    CommandMapperDispatch,
    IrcBotConfigurator,
    Format,
    Token,
};

static UPCOMING_URL: &'static str = "http://anime.yshi.org/api/calendar/upcoming/100";

const CMD_UPCOMING: Token = Token(0);

#[derive(RustcDecodable, RustcEncodable, Clone)]
struct Upcoming {
    title_name: String,
    syoboi_pid: i32,
    start_time: i64,
    end_time: i64,
    count: String,
    start_offset: i64,
    episode_name: String,
    channel_name: String,
    special_name: String,
    comment: String,
}

impl Upcoming {
    pub fn start_time(&self) -> Timespec {
        Timespec::new(self.start_time, 0)
    }

    pub fn start_offset(&self) -> Duration {
        Duration::seconds(self.start_offset)
    }
}

impl fmt::Display for Upcoming {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let now = get_time();
        write!(f, "{} episode {} airs in {} on {}",
            self.title_name, self.count,
            self.start_time() - now,
            self.channel_name)
    }
}

#[derive(Debug)]
enum ApiFailure {
    RequestError(hyper::Error),
    ResponseReadError(io::Error),
    ResponseDeserializeError(DecoderError)
}

impl From<hyper::Error> for ApiFailure {
    fn from(err: hyper::Error) -> ApiFailure {
        ApiFailure::RequestError(err)
    }
}

impl From<io::Error> for ApiFailure {
    fn from(err: io::Error) -> ApiFailure {
        ApiFailure::ResponseReadError(err)
    }
}

impl From<DecoderError> for ApiFailure {
    fn from(err: DecoderError) -> ApiFailure {
        ApiFailure::ResponseDeserializeError(err)
    }
}

fn get_upcoming() -> Result<Vec<Upcoming>, ApiFailure> {
    let url = Url::parse(UPCOMING_URL).ok().expect("Invalid UPCOMING_URL");
    let mut resp = try!(try!(try!(Request::new(Get, url)).start()).send());

    let mut body = String::new();
    try!(resp.read_to_string(&mut body));
    Ok(try!(json::decode::<Vec<Upcoming>>(&body)))
}

pub struct AnimeCalendarPlugin {
    sender: Option<SyncSender<(CommandMapperDispatch, IrcMsg)>>
}

impl AnimeCalendarPlugin {
    pub fn new() -> AnimeCalendarPlugin {
        AnimeCalendarPlugin { sender: None }
    }

    pub fn get_plugin_name() -> &'static str {
        "animecalendar"
    }
}

struct CacheItem<T, E> {
    retrieval_time: SteadyTime,
    value: Result<T, E>
}

struct Cache<T, E> {
    negative_expiry: Duration,
    positive_expiry: Duration,
    item: Option<CacheItem<T, E>>,
}

impl<T, E> Cache<T, E> {
    fn new() -> Cache<T, E> {
        Cache {
            negative_expiry: Duration::seconds(30),
            positive_expiry: Duration::minutes(5),
            item: None,
        }
    }

    fn is_valid(&self) -> bool {
        self.get().is_some()
    }

    fn set<'a>(&'a mut self, result: Result<T, E>) -> &'a Result<T, E> {
        self.item = Some(CacheItem {
            retrieval_time: SteadyTime::now(),
            value: result,
        });
        &self.item.as_ref().unwrap().value
    }

    fn get<'a>(&'a self) -> Option<&'a Result<T, E>> {
        let now = SteadyTime::now();
        match self.item {
            Some(ref item) => match item.value.is_ok() {
                true if now < item.retrieval_time + self.positive_expiry => {
                    Some(&item.value)
                },
                false if now < item.retrieval_time + self.negative_expiry => {
                    Some(&item.value)
                },
                _ => None
            },
            None => None,
        }
    }

    fn get_or_else<'a, F>(&'a mut self, func: F) -> &'a Result<T, E> where F: FnOnce() -> Result<T, E> {
        if self.is_valid() {
            self.get().unwrap()
        } else {
            let value = func();
            self.set(value)
        }
    }
}

struct AniCalInternal {
    cache: Cache<Vec<Upcoming>, ApiFailure>,
}

// This could be made allocation-free
fn lower_contains(haystack: &str, needle: &str) -> bool {
    let haystack = haystack.to_lowercase();
    let needle = needle.to_lowercase();

    haystack.contains(&needle)
}

impl AniCalInternal {
    fn new() -> AniCalInternal {
        AniCalInternal {
            cache: Cache::new(),
        }
    }

    fn handle_upcoming(&mut self, m: &CommandMapperDispatch, search: &str) {
        match *self.cache.get_or_else(get_upcoming) {
            Ok(ref records) => {
                let now = get_time();
                let found_records = records.iter()
                    .filter(|r| lower_contains(&r.title_name, search))
                    .filter(|r| r.start_time() > now);
                for record in found_records {
                    m.reply(&format!("{}", record));
                }

            }
            Err(ref err) => m.reply(&format!("err: {:?}", err)),
        }
    }

    fn start(&mut self, rx: Receiver<(CommandMapperDispatch, IrcMsg)>) {
        for (m, _) in rx.iter() {
            let command_phrase = m.command();
            match command_phrase.token {
                CMD_UPCOMING => match command_phrase.get::<String>(&"search") {
                    Some(ref search) => self.handle_upcoming(&m, search),
                    None => (),
                },
                _ => ()
            }
        }
    }
}

impl RustBotPlugin for AnimeCalendarPlugin {
    fn configure(&mut self, conf: &mut IrcBotConfigurator) {
        conf.map_format(CMD_UPCOMING, Format::from_str("upcoming {*search}").unwrap());
    }

    fn start(&mut self) {
        info!("started AnimeCalendarPlugin");
        let (tx, rx) = sync_channel(10);
        self.sender = Some(tx);

        let _ = ::std::thread::Builder::new().name("plugin-animecalendar".to_string()).spawn(move || {
            info!("AniCalInternal started.");
            AniCalInternal::new().start(rx);
        });
    }

    fn dispatch_cmd(&mut self, m: &CommandMapperDispatch, message: &IrcMsg) {
        info!("dispatching AnimeCalendarPlugin command");
        match self.sender {
            Some(ref sender) => {
                if let Err(err) = sender.send((m.clone(), message.clone())) {
                    m.reply(&format!("Service ``animecalendar'' unavailable: {:?}", err));
                }
            }
            None => ()
        };
    }
}

<commit_msg>animecalendar: Limit upcomings to 5 results<commit_after>use std::fmt;
use std::convert::From;
use std::sync::mpsc::{sync_channel, SyncSender, Receiver};
use std::io::{self, Read};

use rustc_serialize::json::{self, DecoderError};
use url::Url;
use hyper;
use hyper::client::request::Request;
use hyper::method::Method::Get;
use time::{Timespec, get_time, Duration, SteadyTime};

use irc::parse::IrcMsg;

use command_mapper::{
    RustBotPlugin,
    CommandMapperDispatch,
    IrcBotConfigurator,
    Format,
    Token,
};

static UPCOMING_URL: &'static str = "http://anime.yshi.org/api/calendar/upcoming/100";

const CMD_UPCOMING: Token = Token(0);

#[derive(RustcDecodable, RustcEncodable, Clone)]
struct Upcoming {
    title_name: String,
    syoboi_pid: i32,
    start_time: i64,
    end_time: i64,
    count: String,
    start_offset: i64,
    episode_name: String,
    channel_name: String,
    special_name: String,
    comment: String,
}

impl Upcoming {
    pub fn start_time(&self) -> Timespec {
        Timespec::new(self.start_time, 0)
    }

    pub fn start_offset(&self) -> Duration {
        Duration::seconds(self.start_offset)
    }
}

impl fmt::Display for Upcoming {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let now = get_time();
        write!(f, "{} episode {} airs in {} on {}",
            self.title_name, self.count,
            self.start_time() - now,
            self.channel_name)
    }
}

#[derive(Debug)]
enum ApiFailure {
    RequestError(hyper::Error),
    ResponseReadError(io::Error),
    ResponseDeserializeError(DecoderError)
}

impl From<hyper::Error> for ApiFailure {
    fn from(err: hyper::Error) -> ApiFailure {
        ApiFailure::RequestError(err)
    }
}

impl From<io::Error> for ApiFailure {
    fn from(err: io::Error) -> ApiFailure {
        ApiFailure::ResponseReadError(err)
    }
}

impl From<DecoderError> for ApiFailure {
    fn from(err: DecoderError) -> ApiFailure {
        ApiFailure::ResponseDeserializeError(err)
    }
}

fn get_upcoming() -> Result<Vec<Upcoming>, ApiFailure> {
    let url = Url::parse(UPCOMING_URL).ok().expect("Invalid UPCOMING_URL");
    let mut resp = try!(try!(try!(Request::new(Get, url)).start()).send());

    let mut body = String::new();
    try!(resp.read_to_string(&mut body));
    Ok(try!(json::decode::<Vec<Upcoming>>(&body)))
}

pub struct AnimeCalendarPlugin {
    sender: Option<SyncSender<(CommandMapperDispatch, IrcMsg)>>
}

impl AnimeCalendarPlugin {
    pub fn new() -> AnimeCalendarPlugin {
        AnimeCalendarPlugin { sender: None }
    }

    pub fn get_plugin_name() -> &'static str {
        "animecalendar"
    }
}

struct CacheItem<T, E> {
    retrieval_time: SteadyTime,
    value: Result<T, E>
}

struct Cache<T, E> {
    negative_expiry: Duration,
    positive_expiry: Duration,
    item: Option<CacheItem<T, E>>,
}

impl<T, E> Cache<T, E> {
    fn new() -> Cache<T, E> {
        Cache {
            negative_expiry: Duration::seconds(30),
            positive_expiry: Duration::minutes(5),
            item: None,
        }
    }

    fn is_valid(&self) -> bool {
        self.get().is_some()
    }

    fn set<'a>(&'a mut self, result: Result<T, E>) -> &'a Result<T, E> {
        self.item = Some(CacheItem {
            retrieval_time: SteadyTime::now(),
            value: result,
        });
        &self.item.as_ref().unwrap().value
    }

    fn get<'a>(&'a self) -> Option<&'a Result<T, E>> {
        let now = SteadyTime::now();
        match self.item {
            Some(ref item) => match item.value.is_ok() {
                true if now < item.retrieval_time + self.positive_expiry => {
                    Some(&item.value)
                },
                false if now < item.retrieval_time + self.negative_expiry => {
                    Some(&item.value)
                },
                _ => None
            },
            None => None,
        }
    }

    fn get_or_else<'a, F>(&'a mut self, func: F) -> &'a Result<T, E> where F: FnOnce() -> Result<T, E> {
        if self.is_valid() {
            self.get().unwrap()
        } else {
            let value = func();
            self.set(value)
        }
    }
}

struct AniCalInternal {
    cache: Cache<Vec<Upcoming>, ApiFailure>,
}

// This could be made allocation-free
fn lower_contains(haystack: &str, needle: &str) -> bool {
    let haystack = haystack.to_lowercase();
    let needle = needle.to_lowercase();

    haystack.contains(&needle)
}

impl AniCalInternal {
    fn new() -> AniCalInternal {
        AniCalInternal {
            cache: Cache::new(),
        }
    }

    fn handle_upcoming(&mut self, m: &CommandMapperDispatch, search: &str) {
        match *self.cache.get_or_else(get_upcoming) {
            Ok(ref records) => {
                let now = get_time();
                let found_records = records.iter()
                    .filter(|r| lower_contains(&r.title_name, search))
                    .filter(|r| r.start_time() > now)
                    .take(5);
                for record in found_records {
                    m.reply(&format!("{}", record));
                }

            }
            Err(ref err) => m.reply(&format!("err: {:?}", err)),
        }
    }

    fn start(&mut self, rx: Receiver<(CommandMapperDispatch, IrcMsg)>) {
        for (m, _) in rx.iter() {
            let command_phrase = m.command();
            match command_phrase.token {
                CMD_UPCOMING => match command_phrase.get::<String>(&"search") {
                    Some(ref search) => self.handle_upcoming(&m, search),
                    None => (),
                },
                _ => ()
            }
        }
    }
}

impl RustBotPlugin for AnimeCalendarPlugin {
    fn configure(&mut self, conf: &mut IrcBotConfigurator) {
        conf.map_format(CMD_UPCOMING, Format::from_str("upcoming {*search}").unwrap());
    }

    fn start(&mut self) {
        info!("started AnimeCalendarPlugin");
        let (tx, rx) = sync_channel(10);
        self.sender = Some(tx);

        let _ = ::std::thread::Builder::new().name("plugin-animecalendar".to_string()).spawn(move || {
            info!("AniCalInternal started.");
            AniCalInternal::new().start(rx);
        });
    }

    fn dispatch_cmd(&mut self, m: &CommandMapperDispatch, message: &IrcMsg) {
        info!("dispatching AnimeCalendarPlugin command");
        match self.sender {
            Some(ref sender) => {
                if let Err(err) = sender.send((m.clone(), message.clone())) {
                    m.reply(&format!("Service ``animecalendar'' unavailable: {:?}", err));
                }
            }
            None => ()
        };
    }
}

<|endoftext|>


<commit_before>trait GerberCode {
    fn to_code(&self) -> String;
}

#[derive(Debug)]
enum Command {
    FunctionCode(FunctionCode),
    ExtendedCode(ExtendedCode),
}

#[derive(Debug)]
enum FunctionCode {
    DCode(DCode),
    GCode(GCode),
    MCode(MCode),
}

#[derive(Debug)]
enum ExtendedCode {
    FS,
    MO,
    AD,
    AM,
    SR,
    LP,
    TF,
    TA,
    TD,
}

#[derive(Debug)]
enum DCode {
    Operation,
    SelectAperture,
}

#[derive(Debug)]
enum GCode {
    InterpolationMode,
    RegionMode,
    QuadrantMode,
    Comment(String),
}

#[derive(Debug)]
enum MCode {
    EndOfFile,
}

impl GerberCode for GCode {
    fn to_code(&self) -> String {
        match self {
            &GCode::InterpolationMode => format!("TODO InterpolationMode"),
            &GCode::RegionMode => format!("TODO RegionMode"),
            &GCode::QuadrantMode => format!("TODO QuadrantMode"),
            &GCode::Comment(ref comment) => format!("G04 {} *\n", comment),
        }
    }
}

#[cfg(test)]
mod test {
    use super::{Command, FunctionCode, DCode, GCode};
    use super::GerberCode;

    #[test]
    fn test_gcode_debug() {
        let c = Command::FunctionCode(FunctionCode::GCode(GCode::Comment("test".to_string())));
        let debug = format!("{:?}", c);
        assert_eq!(debug, "FunctionCode(GCode(Comment(\"test\")))");
    }

    #[test]
    fn test_to_code() {
        let comment = GCode::Comment("testcomment".to_string());
        assert_eq!(comment.to_code(), "G04 testcomment *\n".to_string());
    }

}
<commit_msg>impl GerberCode for Vec<T: GerberCode><commit_after>trait GerberCode {
    fn to_code(&self) -> String;
}

#[derive(Debug)]
enum Command {
    FunctionCode(FunctionCode),
    ExtendedCode(ExtendedCode),
}

#[derive(Debug)]
enum FunctionCode {
    DCode(DCode),
    GCode(GCode),
    MCode(MCode),
}

#[derive(Debug)]
enum ExtendedCode {
    FS,
    MO,
    AD,
    AM,
    SR,
    LP,
    TF,
    TA,
    TD,
}

#[derive(Debug)]
enum DCode {
    Operation,
    SelectAperture,
}

#[derive(Debug)]
enum GCode {
    InterpolationMode,
    RegionMode,
    QuadrantMode,
    Comment(String),
}

#[derive(Debug)]
enum MCode {
    EndOfFile,
}

impl GerberCode for GCode {
    fn to_code(&self) -> String {
        match self {
            &GCode::InterpolationMode => format!("TODO InterpolationMode"),
            &GCode::RegionMode => format!("TODO RegionMode"),
            &GCode::QuadrantMode => format!("TODO QuadrantMode"),
            &GCode::Comment(ref comment) => format!("G04 {} *", comment),
        }
    }
}

impl<T: GerberCode> GerberCode for Vec<T> {
    fn to_code(&self) -> String {
        self.iter()
            .map(|g| g.to_code())
            .collect::<Vec<String>>()
            .join("\n")
    }
}

#[cfg(test)]
mod test {
    use super::{Command, FunctionCode, DCode, GCode};
    use super::GerberCode;

    #[test]
    fn test_gcode_debug() {
        let c = Command::FunctionCode(FunctionCode::GCode(GCode::Comment("test".to_string())));
        let debug = format!("{:?}", c);
        assert_eq!(debug, "FunctionCode(GCode(Comment(\"test\")))");
    }

    #[test]
    fn test_to_code() {
        let comment = GCode::Comment("testcomment".to_string());
        assert_eq!(comment.to_code(), "G04 testcomment *".to_string());
    }

    #[test]
    fn test_vec_to_code() {
        let mut v = Vec::new();
        v.push(GCode::Comment("comment 1".to_string()));
        v.push(GCode::Comment("another one".to_string()));
        assert_eq!(v.to_code(), "G04 comment 1 *\nG04 another one *".to_string());
    }

}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::default::Default;
use std::fs::File;
use std::io::{Read, Write};
use std::path::{Path, PathBuf};

use digest::Digest;
use ignore::WalkBuilder;
use serde_bytes;
use serde_cbor;
use serde_json;

use sha2;
use sha3;

use error;

#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
pub struct Database(Entry);

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Entry {
    Directory(BTreeMap<PathBuf, Entry>),
    File(HashSums),
}

impl Default for Entry {
    fn default() -> Entry {
        Entry::Directory(BTreeMap::default())
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct HashSums {
    sha2: HashSum,
    sha3: HashSum,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct HashSum(#[serde(with = "serde_bytes")] Vec<u8>);

#[derive(Default)]
struct Hashers {
    sha2: sha2::Sha256,
    sha3: sha3::Sha3_256,
}

impl Hashers {
    fn input(&mut self, input: &[u8]) {
        self.sha2.input(input);
        self.sha3.input(input);
    }
    fn result(self) -> HashSums {
        HashSums {
            sha2: HashSum(Vec::from(self.sha2.result().as_slice())),
            sha3: HashSum(Vec::from(self.sha3.result().as_slice())),
        }
    }
}

fn compute_hashes<P>(path: P) -> Result<HashSums, error::Error>
where
    P: AsRef<Path>
{
    let mut f = File::open(path)?;

    let mut hashers = Hashers::default();

    let mut buffer = [0; 4096];
    loop {
        let n = f.read(&mut buffer[..])?;
        if n == 0 { break }
        hashers.input(&buffer[0..n]);
    }
    Ok(hashers.result())
}

trait BTreeMapExt<K, V> where K: Ord, V: Default {
    fn get_mut_default(&mut self, key: K) -> &mut V;
}

impl<K, V> BTreeMapExt<K, V> for BTreeMap<K, V>
where
    K: Ord + Clone,
    V: Default,
{
    fn get_mut_default(&mut self, key: K) -> &mut V {
        if self.contains_key(&key) {
            match self.get_mut(&key) {
                Some(value) => value,
                None => unreachable!(), // Already checked that key exists
            }
        } else {
            {
                // FIXME: Would prefer to avoid the clone
                match self.insert(key.clone(), V::default()) {
                    Some(_) => unreachable!(), // Already checked for key
                    None => (),
                }
            }
            {
                match self.get_mut(&key) {
                    Some(value) => value,
                    None => unreachable!(), // Already checked that key exists
                }
            }
        }
    }
}

impl Entry {
    fn insert(&mut self, path: PathBuf, file: Entry) {
        // Inner nodes in the tree should always be directories. If
        // the node is not a directory, that means we are inserting a
        // duplicate file. However, this function is only called from
        // the directory walker, which makes it impossible to observe
        // any duplicates. (And the database, after construction, is
        // always immutable.)
        match self {
            &mut Entry::Directory(ref mut entries) => {
                let mut components = path.components();
                let count = components.clone().count();
                let first = Path::new(components.next().expect("unreachable").as_os_str()).to_owned();
                let rest = components.as_path().to_owned();
                if count > 1 {
                    let mut subentry = entries.get_mut_default(first);
                    subentry.insert(rest, file);
                } else {
                    match entries.insert(first, file) {
                        Some(_) => unreachable!(), // See above
                        None => (),
                    }
                }
            }
            &mut Entry::File(_) => unreachable!()
        }
    }
}

impl Database {
    fn insert(&mut self, path: PathBuf, entry: Entry) {
        self.0.insert(path, entry);
    }

    pub fn build<P>(path: P) -> Result<Database, error::Error>
    where
        P: AsRef<Path>
    {
        let mut database = Database::default();
        for entry in WalkBuilder::new(&path).build() {
            let entry = entry?;
            if entry.file_type().map_or(false, |t| t.is_file()) {
                let hashes = compute_hashes(entry.path())?;
                let result = Entry::File(hashes);
                let short_path = entry.path().strip_prefix(&path)?;
                database.insert(short_path.to_owned(), result);
            }
        }
        Ok(database)
    }

    pub fn dump_json<P>(&self, path: P) -> Result<(), error::Error>
    where
        P: AsRef<Path>
    {
        let json = serde_json::to_string(self)?;
        let mut f = File::create(path)?;
        write!(f, "{}", json)?;
        Ok(())
    }

    pub fn dump_cbor<P>(&self, path: P) -> Result<(), error::Error>
    where
        P: AsRef<Path>
    {
        let cbor = serde_cbor::to_vec(self)?;
        let mut f = File::create(path)?;
        f.write_all(cbor.as_slice())?;
        Ok(())
    }
}

// impl std::fmt::Display for Database {
//     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
//         for (path, entry) in self.0.iter() {
//             match entry {
//                 &Entry::File(ref hashes) => {
//                     let hash: Vec<_> = hashes.sha2.0.iter().map(
//                         |b| format!("{:02x}", b)).collect();
//                     writeln!(f, "{} {}", hash.join(""), Path::new(path).display())?
//                 }
//             }
//         }
//         Ok(())
//     }
// }
<commit_msg>Compute other metrics: file size, NUL bytes, non-ASCII bytes.<commit_after>use std::collections::BTreeMap;
use std::default::Default;
use std::fs::File;
use std::io::{Read, Write};
use std::path::{Path, PathBuf};

use digest::Digest;
use ignore::WalkBuilder;
use serde_bytes;
use serde_cbor;
use serde_json;

use sha2;
use sha3;

use error;

#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
pub struct Database(Entry);

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Entry {
    Directory(BTreeMap<PathBuf, Entry>),
    File(Metrics),
}

impl Default for Entry {
    fn default() -> Entry {
        Entry::Directory(BTreeMap::default())
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Metrics {
    sha2: HashSum,
    sha3: HashSum,
    size: u64,      // File size
    nul: bool,      // Does the file contain a NUL byte?
    nonascii: bool, // Does the file contain non-ASCII bytes?
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct HashSum(#[serde(with = "serde_bytes")] Vec<u8>);

#[derive(Default)]
struct EngineSize(u64);
impl EngineSize {
    fn input(&mut self, input: &[u8]) {
        self.0 += input.len() as u64;
    }
    fn result(self) -> u64 {
        self.0
    }
}

#[derive(Default)]
struct EngineNul(bool);
impl EngineNul {
    fn input(&mut self, input: &[u8]) {
        self.0 = self.0 || input.iter().any(|x| *x == 0);
    }
    fn result(self) -> bool {
        self.0
    }
}

#[derive(Default)]
struct EngineNonascii(bool);
impl EngineNonascii {
    fn input(&mut self, input: &[u8]) {
        self.0 = self.0 || input.iter().any(|x| x & 0x80 != 0);
    }
    fn result(self) -> bool {
        self.0
    }
}

#[derive(Default)]
struct Engines {
    sha2: sha2::Sha256,
    sha3: sha3::Sha3_256,
    size: EngineSize,
    nul: EngineNul,
    nonascii: EngineNonascii,
}

impl Engines {
    fn input(&mut self, input: &[u8]) {
        self.sha2.input(input);
        self.sha3.input(input);
        self.size.input(input);
        self.nul.input(input);
        self.nonascii.input(input);
    }
    fn result(self) -> Metrics {
        Metrics {
            sha2: HashSum(Vec::from(self.sha2.result().as_slice())),
            sha3: HashSum(Vec::from(self.sha3.result().as_slice())),
            size: self.size.result(),
            nul: self.nul.result(),
            nonascii: self.nonascii.result(),
        }
    }
}

fn compute_metrics<P>(path: P) -> Result<Metrics, error::Error>
where
    P: AsRef<Path>
{
    let mut f = File::open(path)?;

    let mut hashers = Engines::default();

    let mut buffer = [0; 4096];
    loop {
        let n = f.read(&mut buffer[..])?;
        if n == 0 { break }
        hashers.input(&buffer[0..n]);
    }
    Ok(hashers.result())
}

trait BTreeMapExt<K, V> where K: Ord, V: Default {
    fn get_mut_default(&mut self, key: K) -> &mut V;
}

impl<K, V> BTreeMapExt<K, V> for BTreeMap<K, V>
where
    K: Ord + Clone,
    V: Default,
{
    fn get_mut_default(&mut self, key: K) -> &mut V {
        if self.contains_key(&key) {
            match self.get_mut(&key) {
                Some(value) => value,
                None => unreachable!(), // Already checked that key exists
            }
        } else {
            {
                // FIXME: Would prefer to avoid the clone
                match self.insert(key.clone(), V::default()) {
                    Some(_) => unreachable!(), // Already checked for key
                    None => (),
                }
            }
            {
                match self.get_mut(&key) {
                    Some(value) => value,
                    None => unreachable!(), // Already checked that key exists
                }
            }
        }
    }
}

impl Entry {
    fn insert(&mut self, path: PathBuf, file: Entry) {
        // Inner nodes in the tree should always be directories. If
        // the node is not a directory, that means we are inserting a
        // duplicate file. However, this function is only called from
        // the directory walker, which makes it impossible to observe
        // any duplicates. (And the database, after construction, is
        // always immutable.)
        match self {
            &mut Entry::Directory(ref mut entries) => {
                let mut components = path.components();
                let count = components.clone().count();
                let first = Path::new(components.next().expect("unreachable").as_os_str()).to_owned();
                let rest = components.as_path().to_owned();
                if count > 1 {
                    let mut subentry = entries.get_mut_default(first);
                    subentry.insert(rest, file);
                } else {
                    match entries.insert(first, file) {
                        Some(_) => unreachable!(), // See above
                        None => (),
                    }
                }
            }
            &mut Entry::File(_) => unreachable!()
        }
    }
}

impl Database {
    fn insert(&mut self, path: PathBuf, entry: Entry) {
        self.0.insert(path, entry);
    }

    pub fn build<P>(path: P) -> Result<Database, error::Error>
    where
        P: AsRef<Path>
    {
        let mut database = Database::default();
        for entry in WalkBuilder::new(&path).build() {
            let entry = entry?;
            if entry.file_type().map_or(false, |t| t.is_file()) {
                let metrics = compute_metrics(entry.path())?;
                let result = Entry::File(metrics);
                let short_path = entry.path().strip_prefix(&path)?;
                database.insert(short_path.to_owned(), result);
            }
        }
        Ok(database)
    }

    pub fn dump_json<P>(&self, path: P) -> Result<(), error::Error>
    where
        P: AsRef<Path>
    {
        let json = serde_json::to_string(self)?;
        let mut f = File::create(path)?;
        write!(f, "{}", json)?;
        Ok(())
    }

    pub fn dump_cbor<P>(&self, path: P) -> Result<(), error::Error>
    where
        P: AsRef<Path>
    {
        let cbor = serde_cbor::to_vec(self)?;
        let mut f = File::create(path)?;
        f.write_all(cbor.as_slice())?;
        Ok(())
    }
}

// impl std::fmt::Display for Database {
//     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
//         for (path, entry) in self.0.iter() {
//             match entry {
//                 &Entry::File(ref hashes) => {
//                     let hash: Vec<_> = hashes.sha2.0.iter().map(
//                         |b| format!("{:02x}", b)).collect();
//                     writeln!(f, "{} {}", hash.join(""), Path::new(path).display())?
//                 }
//             }
//         }
//         Ok(())
//     }
// }
<|endoftext|>


<commit_before>//! Responsible for orchestrating all the different library components into
//! something cohesive. It effectively hides the rest of the library,
//! and all commands are meant to pass through this instead.

use std::collections::HashMap;
use osc_address::OscMessage;

use client::Client;
use render::{Renderer, RefRenderer};
use resman::ResMan;
use routing;
use routing::{Edge, Effect, NodeHandle, RouteGraph};
use routing::{adjlist, effect, routegraph};

struct Dispatch {
    /// Contains the toplevel description of the audio being generated.
    routegraph: RouteGraph,
    /// Collection of all objects that are rendering the routegraph,
    /// mapped by id.
    renderers: HashMap<u64, Box<Renderer>>,
    /// Resource manager. Knows where to find all data that might be stored
    /// outside the application.
    resman: ResMan,
    /// All clients that wish to receive notifications of state change or
    /// reults from the renderer, etc.
    clients: HashMap<u64, Box<Client>>,
}

/// OSC message to /<...>
#[derive(OscMessage)]
enum OscToplevel {
    /// Send a message to the primary RouteGraph
    #[osc_address(address="routegraph")]
    RouteGraph((), OscRouteGraph),
    /// Send a message to one of the Renderers.
    #[osc_address(address="renderer")]
    Renderer((), OscRenderer),
}

/// OSC message to /routegraph/<...>
#[derive(OscMessage)]
enum OscRouteGraph {
    #[osc_address(address="add_node")]
    AddNode((), (NodeHandle, adjlist::NodeData)),
    #[osc_address(address="add_edge")]
    AddEdge((), (Edge,)),
    #[osc_address(address="del_node")]
    DelNode((), (NodeHandle,)),
    #[osc_address(address="del_edge")]
    DelEdge((), (Edge,)),
}

/// OSC message to /renderer/<...>
#[derive(OscMessage)]
enum OscRenderer {
    /// Create a new renderer with id=msg payload.
    /// Currently instantiates a reference renderer with default settings.
    /// TODO: this should someday accept the typename of a renderer.
    #[osc_address(address="new")]
    New((), (u64,)),
    /// Delete the renderer that has id=msg payload.
    #[osc_address(address="del")]
    Del((), (u64,)),
    ById(u64, OscRendererById),
}

/// OSC message to /renderer/<renderer_id>/<...>
#[derive(OscMessage)]
enum OscRendererById {
    /// Render a range of samples from [a, b)
    /// Last argument indicates the number of channels to render.
    /// TODO: The channel count should become a property of the RouteGraph.
    #[osc_address(address="render")]
    RenderRange((), (u64, u64, u8)),
}

pub enum Error {
    RouteGraphError(routegraph::Error),
    EffectError(effect::Error),
}

type ResultE<T> = Result<T, Error>;

impl Dispatch {
    pub fn new() -> Dispatch {
        Dispatch {
            routegraph: RouteGraph::new(),
            renderers: HashMap::new(),
            resman: ResMan::new(),
            clients: HashMap::new(),
        }
    }
    /// Registers the client to receive event messages.
    /// Returns the id that has been assigned to the client.
    pub fn register_client(&mut self, c: Box<Client>) -> u64 {
        let id = 1+self.clients.keys().max().unwrap_or(&0);
        self.clients.insert(id, c);
        id
    }
    /// Process the OSC message.
    fn dispatch(&mut self, msg: OscToplevel) -> ResultE<()> {
        match msg {
            OscToplevel::RouteGraph((), rg_msg) => match rg_msg {
                OscRouteGraph::AddNode((), (handle, data)) => {
                    let node_data = match data {
                        adjlist::NodeData::Effect(meta) =>
                            routing::NodeData::Effect(Effect::from_meta(meta, &self.resman)?),
                        adjlist::NodeData::Graph(dag_handle) =>
                            routing::NodeData::Graph(dag_handle),
                    };
                    self.routegraph.add_node(handle.clone(), node_data.clone())?;
                    for watcher in self.renderers.values_mut() {
                        watcher.on_add_node(&handle, &node_data);
                    }
                }
                OscRouteGraph::AddEdge((), (edge,)) => {
                    self.routegraph.add_edge(edge.clone())?;
                    for watcher in self.renderers.values_mut() {
                        watcher.on_add_edge(&edge);
                    }
                }
                OscRouteGraph::DelNode((), (handle,)) => {
                    self.routegraph.del_node(handle.clone())?;
                    for watcher in self.renderers.values_mut() {
                        watcher.on_del_node(&handle);
                    }
                }
                OscRouteGraph::DelEdge((), (edge,)) => {
                    self.routegraph.del_edge(edge.clone());
                    for watcher in self.renderers.values_mut() {
                        watcher.on_del_edge(&edge);
                    }
                }
            },
            OscToplevel::Renderer((), rend_msg) => match rend_msg {
                // TODO: upon creation, we need to read the current graph into the new renderer.
                OscRenderer::New((), (id,)) => {
                    self.renderers.insert(id, Box::new(RefRenderer::new()));
                }
                OscRenderer::Del((), (id,)) => {
                    self.renderers.remove(&id);
                }
                OscRenderer::ById(id, rend_msg) => match rend_msg {
                    OscRendererById::RenderRange((), (start, stop, num_ch)) => {
                        // Avoid underflows if the range isn't positive.
                        if stop < start { return Ok(()); }
                        let size = (stop-start)*(num_ch as u64);
                        let mut buff: Vec<f32> = (0..size).map(|i| { 0f32}).collect();
                        // TODO: handle index error
                        self.renderers.get_mut(&id).unwrap().fill_buffer(&mut buff, start, num_ch);
                        self.audio_rendered(&buff, start, num_ch);
                    }
                }
            },
        }
        Ok(())
    }
}

/// Conversion from `routegraph::Error` for use with the `?` operator
impl From<routegraph::Error> for Error {
    fn from(e: routegraph::Error) -> Self {
        Error::RouteGraphError(e)
    }
}

/// Conversion from `effect::Error` for use with the `?` operator
impl From<effect::Error> for Error {
    fn from(e: effect::Error) -> Self {
        Error::EffectError(e)
    }
}

impl Client for Dispatch {
    fn audio_rendered(&mut self, buffer: &[f32], idx: u64, num_ch: u8) {
        for c in self.clients.values_mut() {
            c.audio_rendered(buffer, idx, num_ch);
        }
    }
}
<commit_msg>Use u32 for client/renderer id; not u64.<commit_after>//! Responsible for orchestrating all the different library components into
//! something cohesive. It effectively hides the rest of the library,
//! and all commands are meant to pass through this instead.

use std::collections::HashMap;
use osc_address::OscMessage;

use client::Client;
use render::{Renderer, RefRenderer};
use resman::ResMan;
use routing;
use routing::{Edge, Effect, NodeHandle, RouteGraph};
use routing::{adjlist, effect, routegraph};

struct Dispatch {
    /// Contains the toplevel description of the audio being generated.
    routegraph: RouteGraph,
    /// Collection of all objects that are rendering the routegraph,
    /// mapped by id.
    renderers: HashMap<u32, Box<Renderer>>,
    /// Resource manager. Knows where to find all data that might be stored
    /// outside the application.
    resman: ResMan,
    /// All clients that wish to receive notifications of state change or
    /// reults from the renderer, etc.
    clients: HashMap<u32, Box<Client>>,
}

/// OSC message to /<...>
#[derive(OscMessage)]
enum OscToplevel {
    /// Send a message to the primary RouteGraph
    #[osc_address(address="routegraph")]
    RouteGraph((), OscRouteGraph),
    /// Send a message to one of the Renderers.
    #[osc_address(address="renderer")]
    Renderer((), OscRenderer),
}

/// OSC message to /routegraph/<...>
#[derive(OscMessage)]
enum OscRouteGraph {
    #[osc_address(address="add_node")]
    AddNode((), (NodeHandle, adjlist::NodeData)),
    #[osc_address(address="add_edge")]
    AddEdge((), (Edge,)),
    #[osc_address(address="del_node")]
    DelNode((), (NodeHandle,)),
    #[osc_address(address="del_edge")]
    DelEdge((), (Edge,)),
}

/// OSC message to /renderer/<...>
#[derive(OscMessage)]
enum OscRenderer {
    /// Create a new renderer with id=msg payload.
    /// Currently instantiates a reference renderer with default settings.
    /// TODO: this should someday accept the typename of a renderer.
    #[osc_address(address="new")]
    New((), (u32,)),
    /// Delete the renderer that has id=msg payload.
    #[osc_address(address="del")]
    Del((), (u32,)),
    ById(u32, OscRendererById),
}

/// OSC message to /renderer/<renderer_id>/<...>
#[derive(OscMessage)]
enum OscRendererById {
    /// Render a range of samples from [a, b)
    /// Last argument indicates the number of channels to render.
    /// TODO: The channel count should become a property of the RouteGraph.
    #[osc_address(address="render")]
    RenderRange((), (u64, u64, u8)),
}

pub enum Error {
    RouteGraphError(routegraph::Error),
    EffectError(effect::Error),
}

type ResultE<T> = Result<T, Error>;

impl Dispatch {
    pub fn new() -> Dispatch {
        Dispatch {
            routegraph: RouteGraph::new(),
            renderers: HashMap::new(),
            resman: ResMan::new(),
            clients: HashMap::new(),
        }
    }
    /// Registers the client to receive event messages.
    /// Returns the id that has been assigned to the client.
    pub fn register_client(&mut self, c: Box<Client>) -> u32 {
        let id = 1+self.clients.keys().max().unwrap_or(&0);
        self.clients.insert(id, c);
        id
    }
    /// Process the OSC message.
    fn dispatch(&mut self, msg: OscToplevel) -> ResultE<()> {
        match msg {
            OscToplevel::RouteGraph((), rg_msg) => match rg_msg {
                OscRouteGraph::AddNode((), (handle, data)) => {
                    let node_data = match data {
                        adjlist::NodeData::Effect(meta) =>
                            routing::NodeData::Effect(Effect::from_meta(meta, &self.resman)?),
                        adjlist::NodeData::Graph(dag_handle) =>
                            routing::NodeData::Graph(dag_handle),
                    };
                    self.routegraph.add_node(handle.clone(), node_data.clone())?;
                    for watcher in self.renderers.values_mut() {
                        watcher.on_add_node(&handle, &node_data);
                    }
                }
                OscRouteGraph::AddEdge((), (edge,)) => {
                    self.routegraph.add_edge(edge.clone())?;
                    for watcher in self.renderers.values_mut() {
                        watcher.on_add_edge(&edge);
                    }
                }
                OscRouteGraph::DelNode((), (handle,)) => {
                    self.routegraph.del_node(handle.clone())?;
                    for watcher in self.renderers.values_mut() {
                        watcher.on_del_node(&handle);
                    }
                }
                OscRouteGraph::DelEdge((), (edge,)) => {
                    self.routegraph.del_edge(edge.clone());
                    for watcher in self.renderers.values_mut() {
                        watcher.on_del_edge(&edge);
                    }
                }
            },
            OscToplevel::Renderer((), rend_msg) => match rend_msg {
                // TODO: upon creation, we need to read the current graph into the new renderer.
                OscRenderer::New((), (id,)) => {
                    self.renderers.insert(id, Box::new(RefRenderer::new()));
                }
                OscRenderer::Del((), (id,)) => {
                    self.renderers.remove(&id);
                }
                OscRenderer::ById(id, rend_msg) => match rend_msg {
                    OscRendererById::RenderRange((), (start, stop, num_ch)) => {
                        // Avoid underflows if the range isn't positive.
                        if stop < start { return Ok(()); }
                        let size = (stop-start)*(num_ch as u64);
                        let mut buff: Vec<f32> = (0..size).map(|i| { 0f32}).collect();
                        // TODO: handle index error
                        self.renderers.get_mut(&id).unwrap().fill_buffer(&mut buff, start, num_ch);
                        self.audio_rendered(&buff, start, num_ch);
                    }
                }
            },
        }
        Ok(())
    }
}

/// Conversion from `routegraph::Error` for use with the `?` operator
impl From<routegraph::Error> for Error {
    fn from(e: routegraph::Error) -> Self {
        Error::RouteGraphError(e)
    }
}

/// Conversion from `effect::Error` for use with the `?` operator
impl From<effect::Error> for Error {
    fn from(e: effect::Error) -> Self {
        Error::EffectError(e)
    }
}

impl Client for Dispatch {
    fn audio_rendered(&mut self, buffer: &[f32], idx: u64, num_ch: u8) {
        for c in self.clients.values_mut() {
            c.audio_rendered(buffer, idx, num_ch);
        }
    }
}
<|endoftext|>


<commit_before>//! Lua IRC library
//!
//! Vends a package named 'irc' with a set of functions that manipulate the
//! current connection. Also provides event handling.
//!
//! Lua functions registered with irc.addhandler(event, f) are called with a
//! string argument representing the event, followed by the sender, then the
//! event's arguments.  Regular commands provide their arguments in the
//! expected fashion. CTCP commands are a bit different. CTCP actions provide 2
//! arguments: dst and text. CTCP commands and replies provide 2 or 3
//! arguments: CTCP command name, destionation, and text if provided.
//!
//! Note that the arguments of any arbitrary IRC command should not be assumed.
//! e.g. PRIVMSG should have 2 arguments: dst, and text. But the actual arguments
//! are provided by the IRC server and are not validated by the bot before being
//! passed to Lua. The only argument guarantees are made by the CTCP commands.
//!
//! Note: if the prefix was not provided for a given command, it will be given
//! to Lua as nil. Otherwise, it will be a table representation of the User.
//!
//! There are 5 special events that can be registered:
//!
//! irc.CONNECTED: No args
//! irc.DISCONNECTED: No args
//! irc.ACTION: Sender, destination, text
//! irc.CTCP: Sender, CTCP command, destination, optionally text
//! irc.CTCPREPLY: Sender, CTCP command, destination, optionally text
//!
//! A User (the sender value) is a table with the following values:
//!
//! raw: The raw text comprising the user
//! nick: The nickname of the user
//! user: The username of the user, if any (optional, may be nil)
//! host: The hostname of the user, if any (optional, may be nil)

use lua;
use irc::conn;
use irc::conn::{Conn, Event};
use std::{libc, mem, ptr, str};
use std::iter::range_inclusive;
use std::vec::MutableCloneableVector;

static EVT_CONNECTED: &'static str = "-CONNECTED";
static EVT_DISCONNECTED: &'static str = "-DISCONNECTED";
static EVT_ACTION: &'static str = "-ACTION";
static EVT_CTCP: &'static str = "-CTCP";
static EVT_CTCPREPLY: &'static str = "-CTCPREPLY";

pub extern "C" fn lua_require(L: *mut lua::raw::lua_State) -> libc::c_int {
    let mut L = unsafe { lua::State::from_lua_State(L) };
    // 1 argument is passed: modname

    // we're going to store the Conn in an Option in the registry
    // the key for the registry is lua_require as a lightuserdata
    L.pushlightuserdata(lua_require as *mut libc::c_void);
    let connptr = L.newuserdata(mem::size_of::<*mut Conn>()) as *mut *mut Conn;
    unsafe { *connptr = ptr::mut_null() };
    L.settable(lua::REGISTRYINDEX);

    // register our library functions
    L.newtable();
    L.registerlib(None, [
        ("addhandler", lua_addhandler),
        //("host", lua_host),
        //("me", lua_me),
        //("send_raw", lua_send_raw),
        //("set_nick", lua_set_nick),
        //("quit", lua_quit),
        ("privmsg", lua_privmsg),
        //("notice",  lua_notice),
        //("join", lua_join),
        //("quit", lua_quit)
    ]);

    // set a few constant values into the table
    L.pushstring(EVT_CONNECTED);
    L.setfield(-2, "CONNECTED");
    L.pushstring(EVT_DISCONNECTED);
    L.setfield(-2, "DISCONNECTED");
    L.pushstring(EVT_ACTION);
    L.setfield(-2, "ACTION");
    L.pushstring(EVT_CTCP);
    L.setfield(-2, "CTCP");
    L.pushstring(EVT_CTCPREPLY);
    L.setfield(-2, "CTCPREPLY");

    1
}

pub extern "C" fn lua_dispatch_event(L: *mut lua::raw::lua_State) -> libc::c_int {
    let mut L = unsafe { lua::State::from_lua_State(L) };

    // 1 arg: event

    let evtptr = L.touserdata(1) as *mut Event;
    L.argcheck(evtptr.is_not_null(), 1, "expected Event");
    let event = unsafe { &*evtptr };

    L.settop(0); // clear the stack

    // get the event name
    match *event {
        conn::Connected => {
            L.pushstring(EVT_CONNECTED);
        }
        conn::Disconnected => {
            L.pushstring(EVT_DISCONNECTED);
        }
        conn::LineReceived(ref line) => {
            let conn::Line{ref command, ref args, ref prefix} = *line;

            match *command {
                conn::IRCCode(code) => {
                    // construct our string on the stack
                    let mut buf = [0u8, ..64];
                    let n = {
                        // sadly MemWriter can't take a stack buffer
                        // so let's just create the string here
                        // then copy it to the stack
                        let s = code.to_str();
                        buf.copy_from(s.as_bytes())
                    };
                    let s = match str::from_utf8(buf.slice_to(n)) {
                        None => {
                            L.errorstr("could not format IRCCode");
                        }
                        Some(s) => s
                    };
                    L.pushstring(s);
                }
                conn::IRCCmd(ref cmd) => {
                    L.pushstring(cmd.as_slice());
                }
                conn::IRCAction(ref dst) => {
                    L.pushstring(EVT_ACTION);
                    L.pushbytes(dst.as_slice());
                }
                conn::IRCCTCP(ref cmd, ref dst) => {
                    L.pushstring(EVT_CTCP);
                    L.pushbytes(cmd.as_slice());
                    L.pushbytes(dst.as_slice());
                }
                conn::IRCCTCPReply(ref cmd, ref dst) => {
                    L.pushstring(EVT_CTCPREPLY);
                    L.pushbytes(cmd.as_slice());
                    L.pushbytes(dst.as_slice());
                }
            }

            // ensure we actually have a handler for this event before proceeding
            L.pushlightuserdata(lua_addhandler as *mut libc::c_void);
            L.gettable(lua::REGISTRYINDEX);
            if !L.istable(-1) {
                return 0;
            }
            L.pushvalue(1); // event name
            L.gettable(-2);
            if !L.istable(-1) || L.objlen(-1) == 0 {
                return 0;
            }
            // we have at least one handler; continue on
            L.pop(2);

            // construct the sender
            match *prefix {
                None => {
                    L.pushnil();
                }
                Some(ref user) => {
                    L.createtable(0, 4);
                    L.pushbytes(user.raw());
                    L.setfield(-2, "raw");
                    L.pushbytes(user.nick());
                    L.setfield(-2, "nick");
                    match user.user() {
                        None => L.pushnil(),
                        Some(v) => L.pushbytes(v)
                    }
                    L.setfield(-2, "user");
                    match user.user() {
                        None => L.pushnil(),
                        Some(v) => L.pushbytes(v)
                    }
                    L.setfield(-2, "host");
                }
            }
            // move sender just after the event name
            L.insert(2);
            // add any arguments
            for arg in args.iter() {
                L.pushbytes(*arg);
            }
        }
    }

    // our event arguments are all on the stack
    let nargs = L.gettop();
    // get the handler list and call each one with a copy of the arguments
    L.pushlightuserdata(lua_addhandler as *mut libc::c_void);
    L.gettable(lua::REGISTRYINDEX);
    if !L.istable(-1) {
        return 0; // no handlers
    }
    L.pushvalue(1); // event name
    L.gettable(-2);
    if !L.istable(-1) {
        return 0;
    }
    L.pushnil(); // first key
    while L.next(-2) {
        // key is -2, value is -1
        // copy all the arguments; deep-copy the sender table
        for i in range_inclusive(1, nargs) {
            if L.istable(i) {
                // copy it
                L.newtable();
                L.pushnil();
                while L.next(i) {
                    L.pushvalue(-2); // copy the key
                    L.insert(-2); // move it behind the value
                    L.settable(-4); // set key=value in the new table
                    // leave behind the key for next
                }
            } else {
                L.pushvalue(i);
            }
        }
        match L.pcall(nargs, 0, 0) {
            Ok(()) => (),
            Err(e) => {
                println!("Error dispatching IRC event: {}: {}", e, L.describe(-1));
                L.pop(1);
            }
        }
    }
    // we're done
    0
}

// unsafe because the Conn isn't really 'static
unsafe fn getconn(L: &mut lua::State) -> &'static mut Conn<'static> {
    L.pushlightuserdata(lua_require as *mut libc::c_void);
    L.gettable(lua::REGISTRYINDEX);
    let ptr = L.touserdata(-1) as *mut *mut Conn<'static>;
    if ptr.is_null() {
        L.errorstr("could not retrieve connection information");
    }
    let ptr = *ptr;
    if ptr.is_null() {
        L.errorstr("no active connection");
    }
    &mut *ptr
}

extern "C" fn lua_addhandler(L: *mut lua::raw::lua_State) -> libc::c_int {
    let mut L = unsafe { lua::State::from_lua_State(L) };

    // 2 args: event, func

    unsafe { L.checkbytes(1) };
    L.checktype(2, lua::Type::Function);

    L.settop(2); // throw away any extra values

    // get or create handler table; key is lua_addhandler
    L.pushlightuserdata(lua_addhandler as *mut libc::c_void);
    L.gettable(lua::REGISTRYINDEX);
    if !L.istable(3) {
        L.pop(1);
        L.newtable();
        L.pushlightuserdata(lua_addhandler as *mut libc::c_void);
        L.pushvalue(3);
        L.settable(lua::REGISTRYINDEX);
    }
    // table is stack entry 3

    // get or create the array
    L.pushvalue(1); // copy the event to the top
    L.gettable(3);
    if !L.istable(4) {
        L.pop(1);
        L.newtable();
        L.pushvalue(1); // copy event to top
        L.pushvalue(4);
        L.settable(3);
    }
    // array is stack entry 4

    L.objlen(4); // get table length
    let len = L.tointeger(5) + 1;
    L.pop(1);
    L.pushinteger(len);
    L.pushvalue(2); // copy function to top
    L.settable(4); // set ary[len+1]=func
    // and return
    0
}

extern "C" fn lua_privmsg(L: *mut lua::raw::lua_State) -> libc::c_int {
    let mut L = unsafe { lua::State::from_lua_State(L) };

    // 2 args: dst, message

    let dst = unsafe { L.checkbytes(1) };
    let msg = unsafe { L.checkbytes(2) };

    let conn = unsafe { getconn(&mut L) };

    conn.privmsg(dst, msg);
    0
}
<commit_msg>Fix bug in lua_addhandler()<commit_after>//! Lua IRC library
//!
//! Vends a package named 'irc' with a set of functions that manipulate the
//! current connection. Also provides event handling.
//!
//! Lua functions registered with irc.addhandler(event, f) are called with a
//! string argument representing the event, followed by the sender, then the
//! event's arguments.  Regular commands provide their arguments in the
//! expected fashion. CTCP commands are a bit different. CTCP actions provide 2
//! arguments: dst and text. CTCP commands and replies provide 2 or 3
//! arguments: CTCP command name, destionation, and text if provided.
//!
//! Note that the arguments of any arbitrary IRC command should not be assumed.
//! e.g. PRIVMSG should have 2 arguments: dst, and text. But the actual arguments
//! are provided by the IRC server and are not validated by the bot before being
//! passed to Lua. The only argument guarantees are made by the CTCP commands.
//!
//! Note: if the prefix was not provided for a given command, it will be given
//! to Lua as nil. Otherwise, it will be a table representation of the User.
//!
//! There are 5 special events that can be registered:
//!
//! irc.CONNECTED: No args
//! irc.DISCONNECTED: No args
//! irc.ACTION: Sender, destination, text
//! irc.CTCP: Sender, CTCP command, destination, optionally text
//! irc.CTCPREPLY: Sender, CTCP command, destination, optionally text
//!
//! A User (the sender value) is a table with the following values:
//!
//! raw: The raw text comprising the user
//! nick: The nickname of the user
//! user: The username of the user, if any (optional, may be nil)
//! host: The hostname of the user, if any (optional, may be nil)

use lua;
use irc::conn;
use irc::conn::{Conn, Event};
use std::{libc, mem, ptr, str};
use std::iter::range_inclusive;
use std::vec::MutableCloneableVector;

static EVT_CONNECTED: &'static str = "-CONNECTED";
static EVT_DISCONNECTED: &'static str = "-DISCONNECTED";
static EVT_ACTION: &'static str = "-ACTION";
static EVT_CTCP: &'static str = "-CTCP";
static EVT_CTCPREPLY: &'static str = "-CTCPREPLY";

pub extern "C" fn lua_require(L: *mut lua::raw::lua_State) -> libc::c_int {
    let mut L = unsafe { lua::State::from_lua_State(L) };
    // 1 argument is passed: modname

    // we're going to store the Conn in an Option in the registry
    // the key for the registry is lua_require as a lightuserdata
    L.pushlightuserdata(lua_require as *mut libc::c_void);
    let connptr = L.newuserdata(mem::size_of::<*mut Conn>()) as *mut *mut Conn;
    unsafe { *connptr = ptr::mut_null() };
    L.settable(lua::REGISTRYINDEX);

    // register our library functions
    L.newtable();
    L.registerlib(None, [
        ("addhandler", lua_addhandler),
        //("host", lua_host),
        //("me", lua_me),
        //("send_raw", lua_send_raw),
        //("set_nick", lua_set_nick),
        //("quit", lua_quit),
        ("privmsg", lua_privmsg),
        //("notice",  lua_notice),
        //("join", lua_join),
        //("quit", lua_quit)
    ]);

    // set a few constant values into the table
    L.pushstring(EVT_CONNECTED);
    L.setfield(-2, "CONNECTED");
    L.pushstring(EVT_DISCONNECTED);
    L.setfield(-2, "DISCONNECTED");
    L.pushstring(EVT_ACTION);
    L.setfield(-2, "ACTION");
    L.pushstring(EVT_CTCP);
    L.setfield(-2, "CTCP");
    L.pushstring(EVT_CTCPREPLY);
    L.setfield(-2, "CTCPREPLY");

    1
}

pub extern "C" fn lua_dispatch_event(L: *mut lua::raw::lua_State) -> libc::c_int {
    let mut L = unsafe { lua::State::from_lua_State(L) };

    // 1 arg: event

    let evtptr = L.touserdata(1) as *mut Event;
    L.argcheck(evtptr.is_not_null(), 1, "expected Event");
    let event = unsafe { &*evtptr };

    L.settop(0); // clear the stack

    // get the event name
    match *event {
        conn::Connected => {
            L.pushstring(EVT_CONNECTED);
        }
        conn::Disconnected => {
            L.pushstring(EVT_DISCONNECTED);
        }
        conn::LineReceived(ref line) => {
            let conn::Line{ref command, ref args, ref prefix} = *line;

            match *command {
                conn::IRCCode(code) => {
                    // construct our string on the stack
                    let mut buf = [0u8, ..64];
                    let n = {
                        // sadly MemWriter can't take a stack buffer
                        // so let's just create the string here
                        // then copy it to the stack
                        let s = code.to_str();
                        buf.copy_from(s.as_bytes())
                    };
                    let s = match str::from_utf8(buf.slice_to(n)) {
                        None => {
                            L.errorstr("could not format IRCCode");
                        }
                        Some(s) => s
                    };
                    L.pushstring(s);
                }
                conn::IRCCmd(ref cmd) => {
                    L.pushstring(cmd.as_slice());
                }
                conn::IRCAction(ref dst) => {
                    L.pushstring(EVT_ACTION);
                    L.pushbytes(dst.as_slice());
                }
                conn::IRCCTCP(ref cmd, ref dst) => {
                    L.pushstring(EVT_CTCP);
                    L.pushbytes(cmd.as_slice());
                    L.pushbytes(dst.as_slice());
                }
                conn::IRCCTCPReply(ref cmd, ref dst) => {
                    L.pushstring(EVT_CTCPREPLY);
                    L.pushbytes(cmd.as_slice());
                    L.pushbytes(dst.as_slice());
                }
            }

            // ensure we actually have a handler for this event before proceeding
            L.pushlightuserdata(lua_addhandler as *mut libc::c_void);
            L.gettable(lua::REGISTRYINDEX);
            if !L.istable(-1) {
                return 0;
            }
            L.pushvalue(1); // event name
            L.gettable(-2);
            if !L.istable(-1) || L.objlen(-1) == 0 {
                return 0;
            }
            // we have at least one handler; continue on
            L.pop(2);

            // construct the sender
            match *prefix {
                None => {
                    L.pushnil();
                }
                Some(ref user) => {
                    L.createtable(0, 4);
                    L.pushbytes(user.raw());
                    L.setfield(-2, "raw");
                    L.pushbytes(user.nick());
                    L.setfield(-2, "nick");
                    match user.user() {
                        None => L.pushnil(),
                        Some(v) => L.pushbytes(v)
                    }
                    L.setfield(-2, "user");
                    match user.user() {
                        None => L.pushnil(),
                        Some(v) => L.pushbytes(v)
                    }
                    L.setfield(-2, "host");
                }
            }
            // move sender just after the event name
            L.insert(2);
            // add any arguments
            for arg in args.iter() {
                L.pushbytes(*arg);
            }
        }
    }

    // our event arguments are all on the stack
    let nargs = L.gettop();
    // get the handler list and call each one with a copy of the arguments
    L.pushlightuserdata(lua_addhandler as *mut libc::c_void);
    L.gettable(lua::REGISTRYINDEX);
    if !L.istable(-1) {
        return 0; // no handlers
    }
    L.pushvalue(1); // event name
    L.gettable(-2);
    if !L.istable(-1) {
        return 0;
    }
    L.pushnil(); // first key
    while L.next(-2) {
        // key is -2, value is -1
        // copy all the arguments; deep-copy the sender table
        for i in range_inclusive(1, nargs) {
            if L.istable(i) {
                // copy it
                L.newtable();
                L.pushnil();
                while L.next(i) {
                    L.pushvalue(-2); // copy the key
                    L.insert(-2); // move it behind the value
                    L.settable(-4); // set key=value in the new table
                    // leave behind the key for next
                }
            } else {
                L.pushvalue(i);
            }
        }
        match L.pcall(nargs, 0, 0) {
            Ok(()) => (),
            Err(e) => {
                println!("Error dispatching IRC event: {}: {}", e, L.describe(-1));
                L.pop(1);
            }
        }
    }
    // we're done
    0
}

// unsafe because the Conn isn't really 'static
unsafe fn getconn(L: &mut lua::State) -> &'static mut Conn<'static> {
    L.pushlightuserdata(lua_require as *mut libc::c_void);
    L.gettable(lua::REGISTRYINDEX);
    let ptr = L.touserdata(-1) as *mut *mut Conn<'static>;
    if ptr.is_null() {
        L.errorstr("could not retrieve connection information");
    }
    let ptr = *ptr;
    if ptr.is_null() {
        L.errorstr("no active connection");
    }
    &mut *ptr
}

extern "C" fn lua_addhandler(L: *mut lua::raw::lua_State) -> libc::c_int {
    let mut L = unsafe { lua::State::from_lua_State(L) };

    // 2 args: event, func

    unsafe { L.checkbytes(1) };
    L.checktype(2, lua::Type::Function);

    L.settop(2); // throw away any extra values

    // get or create handler table; key is lua_addhandler
    L.pushlightuserdata(lua_addhandler as *mut libc::c_void);
    L.gettable(lua::REGISTRYINDEX);
    if !L.istable(3) {
        L.pop(1);
        L.newtable();
        L.pushlightuserdata(lua_addhandler as *mut libc::c_void);
        L.pushvalue(3);
        L.settable(lua::REGISTRYINDEX);
    }
    // table is stack entry 3

    // get or create the array
    L.pushvalue(1); // copy the event to the top
    L.gettable(3);
    if !L.istable(4) {
        L.pop(1);
        L.newtable();
        L.pushvalue(1); // copy event to top
        L.pushvalue(4);
        L.settable(3);
    }
    // array is stack entry 4

    let len = L.objlen(4); // get table length
    L.pushinteger(len as int + 1);
    L.pushvalue(2); // copy function to top
    L.settable(4); // set ary[len+1]=func
    // and return
    0
}

extern "C" fn lua_privmsg(L: *mut lua::raw::lua_State) -> libc::c_int {
    let mut L = unsafe { lua::State::from_lua_State(L) };

    // 2 args: dst, message

    let dst = unsafe { L.checkbytes(1) };
    let msg = unsafe { L.checkbytes(2) };

    let conn = unsafe { getconn(&mut L) };

    conn.privmsg(dst, msg);
    0
}
<|endoftext|>