<commit_before>use regex::Regex;
use time::Timespec;

use timefmt::parse_time_str;

pub struct FileNameInfo<'a> {
    pub file_name: &'a str,
    pub info: Info,
}

#[derive(Eq, PartialEq, Debug)]
pub struct Info {
    pub tp: Type,
    pub compressed: bool,
    pub encrypted: bool,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Type {
    Full {
        time: Timespec,
        volume_number: usize,
    },
    FullManifest {
        time: Timespec,
        partial: bool,
    },
    Inc {
        start_time: Timespec,
        end_time: Timespec,
        volume_number: usize,
    },
    IncManifest {
        start_time: Timespec,
        end_time: Timespec,
        partial: bool,
    },
    FullSig {
        time: Timespec,
        partial: bool,
    },
    NewSig {
        start_time: Timespec,
        end_time: Timespec,
        partial: bool,
    },
}

pub struct FileNameParser {
    full_vol_re: Regex,
    full_manifest_re: Regex,
    inc_vol_re: Regex,
    inc_manifest_re: Regex,
    full_sig_re: Regex,
    new_sig_re: Regex,
}

impl<'a> FileNameInfo<'a> {
    pub fn new(name: &'a str, info: Info) -> Self {
        FileNameInfo {
            file_name: &name,
            info: info,
        }
    }

    pub fn start_time(&self) -> Timespec {
        self.info.tp.time_range().0
    }
}

impl Type {
    pub fn time_range(&self) -> (Timespec, Timespec) {
        match *self {
            Type::Full{ time, .. } |
            Type::FullSig{ time, .. } |
            Type::FullManifest{ time, .. } => (time, time),
            Type::Inc{ start_time, end_time, .. } |
            Type::IncManifest{ start_time, end_time, .. } |
            Type::NewSig{ start_time, end_time, .. } => (start_time, end_time),
        }
    }
}

impl FileNameParser {
    pub fn new() -> Self {
        FileNameParser {
            full_vol_re: Regex::new(r"^duplicity-full\.(?P<time>.*?)\.vol(?P<num>[0-9]+)\.difftar(?P<partial>(\.part))?($|\.)").unwrap(),
            full_manifest_re: Regex::new(r"^duplicity-full\.(?P<time>.*?)\.manifest(?P<partial>(\.part))?($|\.)").unwrap(),
            inc_vol_re: Regex::new(r"^duplicity-inc\.(?P<start_time>.*?)\.to\.(?P<end_time>.*?)\.vol(?P<num>[0-9]+)\.difftar($|\.)").unwrap(),
            inc_manifest_re: Regex::new(r"^duplicity-inc\.(?P<start_time>.*?)\.to\.(?P<end_time>.*?)\.manifest(?P<partial>(\.part))?(\.|$)").unwrap(),
            full_sig_re: Regex::new(r"^duplicity-full-signatures\.(?P<time>.*?)\.sigtar(?P<partial>(\.part))?(\.|$)").unwrap(),
            new_sig_re: Regex::new(r"^duplicity-new-signatures\.(?P<start_time>.*?)\.to\.(?P<end_time>.*?)\.sigtar(?P<partial>(\.part))?(\.|$)").unwrap(),
        }
    }

    pub fn parse(&self, filename: &str) -> Option<Info> {
        use std::ascii::AsciiExt;

        let lower_fname = filename.to_ascii_lowercase();
        let opt_type = self.check_full(&lower_fname)
                           .or(self.check_inc(&lower_fname))
                           .or(self.check_sig(&lower_fname));
        opt_type.map(|t| {
            Info {
                tp: t,
                compressed: is_compressed(lower_fname.as_ref()),
                encrypted: is_encrypted(lower_fname.as_ref()),
            }
        })
    }

    fn check_full(&self, filename: &str) -> Option<Type> {
        if let Some(captures) = self.full_vol_re.captures(filename) {
            let time = try_opt!(parse_time_str(captures.name("time").unwrap()));
            let vol_num = try_opt!(get_vol_num(captures.name("num").unwrap()));
            Some(Type::Full {
                time: time,
                volume_number: vol_num,
            })
        } else if let Some(captures) = self.full_manifest_re.captures(filename) {
            let time = try_opt!(parse_time_str(captures.name("time").unwrap()));
            Some(Type::FullManifest {
                time: time,
                partial: captures.name("partial").is_some(),
            })
        } else {
            None
        }
    }

    fn check_inc(&self, filename: &str) -> Option<Type> {
        if let Some(captures) = self.inc_vol_re.captures(filename) {
            let start_time = try_opt!(parse_time_str(captures.name("start_time").unwrap()));
            let end_time = try_opt!(parse_time_str(captures.name("end_time").unwrap()));
            let vol_num = try_opt!(get_vol_num(captures.name("num").unwrap()));
            Some(Type::Inc {
                start_time: start_time,
                end_time: end_time,
                volume_number: vol_num,
            })
        } else if let Some(captures) = self.inc_manifest_re.captures(filename) {
            let start_time = try_opt!(parse_time_str(captures.name("start_time").unwrap()));
            let end_time = try_opt!(parse_time_str(captures.name("end_time").unwrap()));
            Some(Type::IncManifest {
                start_time: start_time,
                end_time: end_time,
                partial: captures.name("partial").is_some(),
            })
        } else {
            None
        }
    }

    fn check_sig(&self, filename: &str) -> Option<Type> {
        if let Some(captures) = self.full_sig_re.captures(filename) {
            let time = try_opt!(parse_time_str(captures.name("time").unwrap()));
            Some(Type::FullSig {
                time: time,
                partial: captures.name("partial").is_some(),
            })
        } else if let Some(captures) = self.new_sig_re.captures(filename) {
            let start_time = try_opt!(parse_time_str(captures.name("start_time").unwrap()));
            let end_time = try_opt!(parse_time_str(captures.name("end_time").unwrap()));
            Some(Type::NewSig {
                start_time: start_time,
                end_time: end_time,
                partial: captures.name("partial").is_some(),
            })
        } else {
            None
        }
    }
}

fn get_vol_num(s: &str) -> Option<usize> {
    s.parse::<usize>().ok()
}

fn is_encrypted(s: &str) -> bool {
    s.ends_with(".gpg") || s.ends_with(".g")
}

fn is_compressed(s: &str) -> bool {
    s.ends_with(".gz") || s.ends_with(".z")
}

#[cfg(test)]
mod test {
    use super::*;
    use timefmt::parse_time_str;

    #[test]
    fn parser_test() {
        let parser = FileNameParser::new();
        // invalid
        assert_eq!(parser.parse("invalid"), None);
        // full
        assert_eq!(parser.parse("duplicity-full.20150617T182545Z.vol1.difftar.gz"),
                   Some(Info {
                       tp: Type::Full {
                           time: parse_time_str("20150617t182545z").unwrap(),
                           volume_number: 1,
                       },
                       compressed: true,
                       encrypted: false,
                   }));
        // full manifest
        assert_eq!(parser.parse("duplicity-full.20150617T182545Z.manifest"),
                   Some(Info {
                       tp: Type::FullManifest {
                           time: parse_time_str("20150617t182545z").unwrap(),
                           partial: false,
                       },
                       compressed: false,
                       encrypted: false,
                   }));
        // inc
        assert_eq!(parser.parse("duplicity-inc.20150617T182629Z.to.20150617T182650Z.vol1.difftar.gz"),
                   Some(Info{ tp: Type::Inc{ start_time: parse_time_str("20150617t182629z").unwrap(),
                                             end_time: parse_time_str("20150617t182650z").unwrap(),
                                             volume_number: 1 },
                              compressed: true,
                              encrypted: false }));
        // inc manifest
        assert_eq!(parser.parse("duplicity-inc.20150617T182545Z.to.20150617T182629Z.manifest"),
                   Some(Info {
                       tp: Type::IncManifest {
                           start_time: parse_time_str("20150617t182545z").unwrap(),
                           end_time: parse_time_str("20150617t182629z").unwrap(),
                           partial: false,
                       },
                       compressed: false,
                       encrypted: false,
                   }));
        // new sig
        assert_eq!(parser.parse("duplicity-new-signatures.20150617T182545Z.to.20150617T182629Z.sigtar.gz"),
                   Some(Info{ tp: Type::NewSig{ start_time: parse_time_str("20150617t182545z").unwrap(),
                                                end_time: parse_time_str("20150617t182629z").unwrap(),
                                                partial: false },
                              compressed: true,
                              encrypted: false }));
        // full sig
        assert_eq!(parser.parse("duplicity-full-signatures.20150617T182545Z.sigtar.gz"),
                   Some(Info {
                       tp: Type::FullSig {
                           time: parse_time_str("20150617t182545z").unwrap(),
                           partial: false,
                       },
                       compressed: true,
                       encrypted: false,
                   }));
    }
}
<commit_msg>Do not implement copy for file_naming::Type<commit_after>use regex::Regex;
use time::Timespec;

use timefmt::parse_time_str;

pub struct FileNameInfo<'a> {
    pub file_name: &'a str,
    pub info: Info,
}

#[derive(Clone, Eq, PartialEq, Debug)]
pub struct Info {
    pub tp: Type,
    pub compressed: bool,
    pub encrypted: bool,
}

#[allow(missing_copy_implementations)]
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Type {
    Full {
        time: Timespec,
        volume_number: usize,
    },
    FullManifest {
        time: Timespec,
        partial: bool,
    },
    Inc {
        start_time: Timespec,
        end_time: Timespec,
        volume_number: usize,
    },
    IncManifest {
        start_time: Timespec,
        end_time: Timespec,
        partial: bool,
    },
    FullSig {
        time: Timespec,
        partial: bool,
    },
    NewSig {
        start_time: Timespec,
        end_time: Timespec,
        partial: bool,
    },
}

pub struct FileNameParser {
    full_vol_re: Regex,
    full_manifest_re: Regex,
    inc_vol_re: Regex,
    inc_manifest_re: Regex,
    full_sig_re: Regex,
    new_sig_re: Regex,
}

impl<'a> FileNameInfo<'a> {
    pub fn new(name: &'a str, info: Info) -> Self {
        FileNameInfo {
            file_name: &name,
            info: info,
        }
    }

    pub fn start_time(&self) -> Timespec {
        self.info.tp.time_range().0
    }
}

impl Type {
    pub fn time_range(&self) -> (Timespec, Timespec) {
        match *self {
            Type::Full{ time, .. } |
            Type::FullSig{ time, .. } |
            Type::FullManifest{ time, .. } => (time, time),
            Type::Inc{ start_time, end_time, .. } |
            Type::IncManifest{ start_time, end_time, .. } |
            Type::NewSig{ start_time, end_time, .. } => (start_time, end_time),
        }
    }
}

impl FileNameParser {
    pub fn new() -> Self {
        FileNameParser {
            full_vol_re: Regex::new(r"^duplicity-full\.(?P<time>.*?)\.vol(?P<num>[0-9]+)\.difftar(?P<partial>(\.part))?($|\.)").unwrap(),
            full_manifest_re: Regex::new(r"^duplicity-full\.(?P<time>.*?)\.manifest(?P<partial>(\.part))?($|\.)").unwrap(),
            inc_vol_re: Regex::new(r"^duplicity-inc\.(?P<start_time>.*?)\.to\.(?P<end_time>.*?)\.vol(?P<num>[0-9]+)\.difftar($|\.)").unwrap(),
            inc_manifest_re: Regex::new(r"^duplicity-inc\.(?P<start_time>.*?)\.to\.(?P<end_time>.*?)\.manifest(?P<partial>(\.part))?(\.|$)").unwrap(),
            full_sig_re: Regex::new(r"^duplicity-full-signatures\.(?P<time>.*?)\.sigtar(?P<partial>(\.part))?(\.|$)").unwrap(),
            new_sig_re: Regex::new(r"^duplicity-new-signatures\.(?P<start_time>.*?)\.to\.(?P<end_time>.*?)\.sigtar(?P<partial>(\.part))?(\.|$)").unwrap(),
        }
    }

    pub fn parse(&self, filename: &str) -> Option<Info> {
        use std::ascii::AsciiExt;

        let lower_fname = filename.to_ascii_lowercase();
        let opt_type = self.check_full(&lower_fname)
                           .or(self.check_inc(&lower_fname))
                           .or(self.check_sig(&lower_fname));
        opt_type.map(|t| {
            Info {
                tp: t,
                compressed: is_compressed(lower_fname.as_ref()),
                encrypted: is_encrypted(lower_fname.as_ref()),
            }
        })
    }

    fn check_full(&self, filename: &str) -> Option<Type> {
        if let Some(captures) = self.full_vol_re.captures(filename) {
            let time = try_opt!(parse_time_str(captures.name("time").unwrap()));
            let vol_num = try_opt!(get_vol_num(captures.name("num").unwrap()));
            Some(Type::Full {
                time: time,
                volume_number: vol_num,
            })
        } else if let Some(captures) = self.full_manifest_re.captures(filename) {
            let time = try_opt!(parse_time_str(captures.name("time").unwrap()));
            Some(Type::FullManifest {
                time: time,
                partial: captures.name("partial").is_some(),
            })
        } else {
            None
        }
    }

    fn check_inc(&self, filename: &str) -> Option<Type> {
        if let Some(captures) = self.inc_vol_re.captures(filename) {
            let start_time = try_opt!(parse_time_str(captures.name("start_time").unwrap()));
            let end_time = try_opt!(parse_time_str(captures.name("end_time").unwrap()));
            let vol_num = try_opt!(get_vol_num(captures.name("num").unwrap()));
            Some(Type::Inc {
                start_time: start_time,
                end_time: end_time,
                volume_number: vol_num,
            })
        } else if let Some(captures) = self.inc_manifest_re.captures(filename) {
            let start_time = try_opt!(parse_time_str(captures.name("start_time").unwrap()));
            let end_time = try_opt!(parse_time_str(captures.name("end_time").unwrap()));
            Some(Type::IncManifest {
                start_time: start_time,
                end_time: end_time,
                partial: captures.name("partial").is_some(),
            })
        } else {
            None
        }
    }

    fn check_sig(&self, filename: &str) -> Option<Type> {
        if let Some(captures) = self.full_sig_re.captures(filename) {
            let time = try_opt!(parse_time_str(captures.name("time").unwrap()));
            Some(Type::FullSig {
                time: time,
                partial: captures.name("partial").is_some(),
            })
        } else if let Some(captures) = self.new_sig_re.captures(filename) {
            let start_time = try_opt!(parse_time_str(captures.name("start_time").unwrap()));
            let end_time = try_opt!(parse_time_str(captures.name("end_time").unwrap()));
            Some(Type::NewSig {
                start_time: start_time,
                end_time: end_time,
                partial: captures.name("partial").is_some(),
            })
        } else {
            None
        }
    }
}

fn get_vol_num(s: &str) -> Option<usize> {
    s.parse::<usize>().ok()
}

fn is_encrypted(s: &str) -> bool {
    s.ends_with(".gpg") || s.ends_with(".g")
}

fn is_compressed(s: &str) -> bool {
    s.ends_with(".gz") || s.ends_with(".z")
}

#[cfg(test)]
mod test {
    use super::*;
    use timefmt::parse_time_str;

    #[test]
    fn parser_test() {
        let parser = FileNameParser::new();
        // invalid
        assert_eq!(parser.parse("invalid"), None);
        // full
        assert_eq!(parser.parse("duplicity-full.20150617T182545Z.vol1.difftar.gz"),
                   Some(Info {
                       tp: Type::Full {
                           time: parse_time_str("20150617t182545z").unwrap(),
                           volume_number: 1,
                       },
                       compressed: true,
                       encrypted: false,
                   }));
        // full manifest
        assert_eq!(parser.parse("duplicity-full.20150617T182545Z.manifest"),
                   Some(Info {
                       tp: Type::FullManifest {
                           time: parse_time_str("20150617t182545z").unwrap(),
                           partial: false,
                       },
                       compressed: false,
                       encrypted: false,
                   }));
        // inc
        assert_eq!(parser.parse("duplicity-inc.20150617T182629Z.to.20150617T182650Z.vol1.difftar.gz"),
                   Some(Info{ tp: Type::Inc{ start_time: parse_time_str("20150617t182629z").unwrap(),
                                             end_time: parse_time_str("20150617t182650z").unwrap(),
                                             volume_number: 1 },
                              compressed: true,
                              encrypted: false }));
        // inc manifest
        assert_eq!(parser.parse("duplicity-inc.20150617T182545Z.to.20150617T182629Z.manifest"),
                   Some(Info {
                       tp: Type::IncManifest {
                           start_time: parse_time_str("20150617t182545z").unwrap(),
                           end_time: parse_time_str("20150617t182629z").unwrap(),
                           partial: false,
                       },
                       compressed: false,
                       encrypted: false,
                   }));
        // new sig
        assert_eq!(parser.parse("duplicity-new-signatures.20150617T182545Z.to.20150617T182629Z.sigtar.gz"),
                   Some(Info{ tp: Type::NewSig{ start_time: parse_time_str("20150617t182545z").unwrap(),
                                                end_time: parse_time_str("20150617t182629z").unwrap(),
                                                partial: false },
                              compressed: true,
                              encrypted: false }));
        // full sig
        assert_eq!(parser.parse("duplicity-full-signatures.20150617T182545Z.sigtar.gz"),
                   Some(Info {
                       tp: Type::FullSig {
                           time: parse_time_str("20150617t182545z").unwrap(),
                           partial: false,
                       },
                       compressed: true,
                       encrypted: false,
                   }));
    }
}
<|endoftext|>


<commit_before>use std::mem::transmute;
use std::marker::PhantomData;
use std::collections::VecDeque;

use super::instr::Instr;
use super::Operational;

pub struct Kleisli<I: Instr, A, B> {
    phan: PhantomData<(A, B)>,
    deque: VecDeque<Box<Fn(Box<()>) -> Operational<I, ()> + 'static>>
}

unsafe fn fn_transmute<I: Instr, A, B, F: 'static + Fn(Box<A>) -> Operational<I, B>>(f: F)
    -> Box<Fn(Box<()>) -> Operational<I, ()>> {
    Box::new(move |ptr| {
        let a_box = transmute::<Box<()>, Box<A>>(ptr);
        transmute(f(a_box))
    })
}

impl<I: Instr, A> Kleisli<I, A, A> {
    pub fn new() -> Kleisli<I, A, A> {
        Kleisli { phan: PhantomData, deque: VecDeque::new() }
    }
}

impl<I: 'static + Instr, A, B> Kleisli<I, A, B> {

    pub fn append<F, C>(mut self, f: F) -> Kleisli<I, A, C>
        where F: 'static + Fn(Box<B>) -> Operational<I, C> {
        let g = unsafe { fn_transmute(f) };
        (&mut self.deque).push_back(g);
        Kleisli { phan: PhantomData, deque: self.deque }
    }

    pub fn run(mut self, a: A) -> Operational<I, B> {
        unsafe {
            let mut r: Operational<I, ()> = transmute::<Operational<I, A>, _>(Operational::new(a));
            loop {
                match self.deque.pop_front() {
                    None => return transmute(r),
                    Some(f) => r = r.and_then_boxed(move |a| (*f)(a))
                }
            }
        }
    }

}

#[test]
fn kleisli_run_plus_one() {
    use super::instr::Identity;
    let k: Kleisli<Identity<()>, i32, i32> = Kleisli::new().append(|a| Operational::new(*a + 1));
    if let Operational::Pure(x) = k.run(42) {
        assert_eq!(*x, 43);
    }
}
<commit_msg>restrict kleisli parameter<commit_after>use std::mem::transmute;
use std::marker::PhantomData;
use std::collections::VecDeque;

use super::instr::Instr;
use super::Operational;

pub struct Kleisli<I: Instr<Param=A>, A, B> {
    phan: PhantomData<(A, B)>,
    deque: VecDeque<Box<Fn(Box<()>) -> Operational<I, ()> + 'static>>
}

unsafe fn fn_transmute<I: Instr, A, B, F: 'static + Fn(Box<A>) -> Operational<I, B>>(f: F)
    -> Box<Fn(Box<()>) -> Operational<I, ()>> {
    Box::new(move |ptr| {
        let a_box = transmute::<Box<()>, Box<A>>(ptr);
        transmute(f(a_box))
    })
}

impl<I: Instr<Param=A>, A> Kleisli<I, A, A> {
    pub fn new() -> Kleisli<I, A, A> {
        Kleisli { phan: PhantomData, deque: VecDeque::new() }
    }
}

impl<I: 'static + Instr<Param=A>, A, B> Kleisli<I, A, B> {

    pub fn append<F, C>(mut self, f: F) -> Kleisli<I, A, C>
        where F: 'static + Fn(Box<B>) -> Operational<I, C> {
        let g = unsafe { fn_transmute(f) };
        (&mut self.deque).push_back(g);
        Kleisli { phan: PhantomData, deque: self.deque }
    }

    pub fn run(mut self, a: A) -> Operational<I, B> {
        unsafe {
            let mut r: Operational<I, ()> = transmute::<Operational<I, A>, _>(Operational::new(a));
            loop {
                match self.deque.pop_front() {
                    None => return transmute(r),
                    Some(f) => r = r.and_then_boxed(move |a| (*f)(a))
                }
            }
        }
    }

}

#[test]
fn kleisli_run_plus_one() {
    use super::instr::Identity;
    let k: Kleisli<Identity<i32>, _, _> = Kleisli::new().append(|a| Operational::new(*a + 1));
    if let Operational::Pure(x) = k.run(42) {
        assert_eq!(*x, 43);
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::sync;
use std::fs;
use std::path;

use config::IntoLog;
use errors::LogError;
use api;
use config;

pub struct DispatchLogger {
    pub output: Vec<Box<api::Logger>>,
    pub level: api::Level,
    pub format: Box<config::Formatter>,
}

impl DispatchLogger {
    pub fn new(format: Box<config::Formatter>, config_output: Vec<config::OutputConfig>,
            level: api::Level) -> io::Result<DispatchLogger> {

        let output = try!(config_output.into_iter().fold(Ok(Vec::new()),
                     |processed: io::Result<Vec<Box<api::Logger>>>, next: config::OutputConfig| {
            // If an error has already been found, don't try to process any future outputs, just
            // continue passing along the error.
            let mut processed_so_far = try!(processed);
            return match next.into_logger() {
                Err(e) => Err(e), // If this one errors, return the error instead of the Vec so far
                Ok(processed_value) => {
                    // If it's ok, add the processed logger to the vec, and pass the vec along
                    processed_so_far.push(processed_value);
                    Ok(processed_so_far)
                }
            };
        }));

        return Ok(DispatchLogger {
            output: output,
            level: level,
            format: format,
        });
    }
}

impl api::Logger for DispatchLogger {
    fn log(&self, msg: &str, level: &api::Level) -> Result<(), LogError> {
        if *level < self.level {
            return Ok(());
        }
        let new_msg = (self.format)(msg, level);
        for logger in &self.output {
            try!(logger.log(&new_msg, level));
        }
        return Ok(());
    }
}

pub struct WriterLogger<T: io::Write> {
    writer: sync::Arc<sync::Mutex<T>>,
}

impl <T: io::Write + Send> WriterLogger<T> {
    pub fn new(writer: T) -> WriterLogger<T> {
        return WriterLogger {
            writer: sync::Arc::new(sync::Mutex::new(writer)),
        };
    }

    pub fn with_stdout() -> WriterLogger<io::Stdout> {
        return WriterLogger::new(io::stdout());
    }

    pub fn with_stderr() -> WriterLogger<io::Stderr> {
        return WriterLogger::new(io::stderr());
    }

    pub fn with_file<P: path::AsPath + ?Sized>(path: &P) -> io::Result<WriterLogger<fs::File>> {
        return Ok(WriterLogger::new(try!(fs::OpenOptions::new().write(true).append(true).open(path))));
    }
}

impl <T: io::Write + Send> api::Logger for WriterLogger<T> {
    fn log(&self, msg: &str, _level: &api::Level) -> Result<(), LogError> {
        try!(write!(try!(self.writer.lock()), "{}\n", msg));
        return Ok(());
    }
}

/// A logger implementation which does nothing with logged messages.
#[unstable]
#[derive(Copy)]
pub struct NullLogger;

impl api::Logger for NullLogger {
    fn log(&self, _msg: &str, _level: &api::Level) -> Result<(), LogError> {
        return Ok(());
    }
}
<commit_msg>Create log files if they don't already exist<commit_after>use std::io;
use std::sync;
use std::fs;
use std::path;

use config::IntoLog;
use errors::LogError;
use api;
use config;

pub struct DispatchLogger {
    pub output: Vec<Box<api::Logger>>,
    pub level: api::Level,
    pub format: Box<config::Formatter>,
}

impl DispatchLogger {
    pub fn new(format: Box<config::Formatter>, config_output: Vec<config::OutputConfig>,
            level: api::Level) -> io::Result<DispatchLogger> {

        let output = try!(config_output.into_iter().fold(Ok(Vec::new()),
                     |processed: io::Result<Vec<Box<api::Logger>>>, next: config::OutputConfig| {
            // If an error has already been found, don't try to process any future outputs, just
            // continue passing along the error.
            let mut processed_so_far = try!(processed);
            return match next.into_logger() {
                Err(e) => Err(e), // If this one errors, return the error instead of the Vec so far
                Ok(processed_value) => {
                    // If it's ok, add the processed logger to the vec, and pass the vec along
                    processed_so_far.push(processed_value);
                    Ok(processed_so_far)
                }
            };
        }));

        return Ok(DispatchLogger {
            output: output,
            level: level,
            format: format,
        });
    }
}

impl api::Logger for DispatchLogger {
    fn log(&self, msg: &str, level: &api::Level) -> Result<(), LogError> {
        if *level < self.level {
            return Ok(());
        }
        let new_msg = (self.format)(msg, level);
        for logger in &self.output {
            try!(logger.log(&new_msg, level));
        }
        return Ok(());
    }
}

pub struct WriterLogger<T: io::Write> {
    writer: sync::Arc<sync::Mutex<T>>,
}

impl <T: io::Write + Send> WriterLogger<T> {
    pub fn new(writer: T) -> WriterLogger<T> {
        return WriterLogger {
            writer: sync::Arc::new(sync::Mutex::new(writer)),
        };
    }

    pub fn with_stdout() -> WriterLogger<io::Stdout> {
        return WriterLogger::new(io::stdout());
    }

    pub fn with_stderr() -> WriterLogger<io::Stderr> {
        return WriterLogger::new(io::stderr());
    }

    pub fn with_file<P: path::AsPath + ?Sized>(path: &P) -> io::Result<WriterLogger<fs::File>> {
        return Ok(WriterLogger::new(try!(fs::OpenOptions::new().write(true).append(true)
                                            .create(true).open(path))));
    }
}

impl <T: io::Write + Send> api::Logger for WriterLogger<T> {
    fn log(&self, msg: &str, _level: &api::Level) -> Result<(), LogError> {
        try!(write!(try!(self.writer.lock()), "{}\n", msg));
        return Ok(());
    }
}

/// A logger implementation which does nothing with logged messages.
#[unstable]
#[derive(Copy)]
pub struct NullLogger;

impl api::Logger for NullLogger {
    fn log(&self, _msg: &str, _level: &api::Level) -> Result<(), LogError> {
        return Ok(());
    }
}
<|endoftext|>


<commit_before>//! Lua functionality

use hlua;
use hlua::{Lua, LuaError};
use hlua::any::AnyLuaValue;

use std::thread;

use std::fs::{File};
use std::path::Path;
use std::io::Write;

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

lazy_static! {
    /// Sends requests to the lua thread
    static ref SENDER: Mutex<Sender<LuaQuery>> = {
        let (tx, rx) = channel::<LuaQuery>();
        Mutex::new(tx)
    };

    /// Receives data back from the lua thread
    /// This should only be accessed by the lua thread itself.
    static ref RECEIVER: Mutex<Receiver<LuaResponse>> = {
        let (tx, rx) = channel::<LuaResponse>();
        Mutex::new(rx)
    };

    /// Whether the lua thread is currently running
    pub static ref RUNNING: RwLock<bool> = RwLock::new(false);
}

/// Messages sent to the lua thread
pub enum LuaQuery {
    /// Halt the lua thread
    Terminate,
    // Restart the lua thread
    Restart,
    /// Execute a string
    Execute(String),
    /// Execute a file
    ExecuteFile(String),
    /// Get a variable
    GetVariable(String),
    /// Set a value
    SetValue {
        name: Box<::std::borrow::Borrow<str> + Sized>,
        val: Box<hlua::Push<&'static mut Lua<'static>> + Sized>
    },
    /// Create a new array
    EmptyArray(String),
    /// Unused send type
    Unused,
}

/// Messages received from lua thread
pub enum LuaResponse {
    /// Lua variable obtained
    Variable(Option<AnyLuaValue>),
    /// Lua error
    Error(hlua::LuaError),
    /// A function is returned
    Function(hlua::functions_read::LuaFunction<String>)
}

unsafe impl Send for LuaQuery { }
unsafe impl Send for LuaResponse { }
unsafe impl Sync for LuaQuery { }
unsafe impl Sync for LuaResponse { }

/// Whether the lua thread is currently available
pub fn thread_running() -> bool {
    *RUNNING.read().unwrap()
}

/// Errors which may arise from attempting
/// to sending a message to the lua thread.
pub enum LuaSendError {
    ThreadClosed,
    Sender
}

/// Attemps to send a LuaQuery to the lua thread.
pub fn try_send(query: LuaQuery) -> Result<(), LuaSendError> {
    if !thread_running() { Err(LuaSendError::ThreadClosed) }
    else {
        match SENDER.lock().unwrap().send(query) {
            Ok(_) => Ok(()),
            Err(_) => Err(LuaSendError::Sender)
        }
    }
}

/// Sends a value to the lua thread.
///
/// # Panics
/// * If the lua thread is currently not running (check `lua::thread_running()`)
/// * If the sender was unable to send, which should only happen
/// if the lua thread isn't running.
pub fn send(query: LuaQuery) {
    if !thread_running() {
        panic!("lua: Attempted to message the lua thread while it is not active!");
    }
    SENDER.lock().unwrap().send(query).unwrap();
}

/// Initialize the lua thread
pub fn init() {
    trace!("Initializing...");
    let (query_tx, query_rx) = channel::<LuaQuery>();
    let (answer_tx, answer_rx) = channel::<LuaResponse>();
    {
        let mut sender = SENDER.lock().unwrap();
        let mut receiver = RECEIVER.lock().unwrap();

        *sender = query_tx;
        *receiver = answer_rx;
    }

    thread::spawn(move || {
        trace!("thread: Inside thread!");
        let sender = answer_tx;
        let receiver = query_rx;
        let mut lua = Lua::new();
        trace!("thread: Loading libraries...");
        lua.openlibs();
        trace!("thread: Libraries loaded");
        *RUNNING.write().unwrap() = true;
        trace!("thread: Testing hello world...");
        let mut file = File::create("/tmp/init.lua").unwrap();
        file.write(b"print('Hello world!')").unwrap();
        lua.execute_from_reader::<(), File>(File::open("/tmp/init.lua")
                                            .unwrap()).unwrap();
        trace!("thread: Done!");
        trace!("thread: Entering loop...");
        thread_main_loop(sender, receiver, &mut lua);
    });
    trace!("Created thread. Init finished.");
}

fn thread_main_loop(sender: Sender<LuaResponse>, receiver: Receiver<LuaQuery>,
                    lua: &mut Lua) {
    loop {
        let request = receiver.recv();
        match request {
            Err(e) => {
                error!("Lua thread: unable to receive message: {}", e);
                error!("Lua thread: now panicking!");
                *RUNNING.write().unwrap() = false;

                panic!("Lua thread: lost contact with host, exiting!");
            }
            Ok(message) => {
                trace!("Handling a request");
                thread_handle_message(&sender, message, lua);
            }
        }
    }
}

fn thread_handle_message(sender: &Sender<LuaResponse>, request: LuaQuery, lua: &mut Lua) {
    match request {
        LuaQuery::Terminate => {
            trace!("thread: Received terminate signal");
            *RUNNING.write().unwrap() = false;

            info!("thread: Lua thread terminating!");
            return;
        },

        LuaQuery::Restart => {
            trace!("thread: Received restart signal!");
            error!("thread: Lua thread restart not supported!");

            *RUNNING.write().unwrap() = false;

            panic!("Lua thread: Restart not supported!");
        },

        LuaQuery::Execute(code) => {
            trace!("thread: Received request to execute code");
            trace!("thread: Executing {:?}", code);

            match lua.execute::<()>(&code) {
                Err(error) => {
                    warn!("thread: Error executing code: {:?}", error);
                    let response = LuaResponse::Error(error);

                    thread_send(&sender, response);
                }
                Ok(_) => {
                    // This is gonna be really spammy one day
                    trace!("thread: Code executed okay.");
                }
            }
        },

        LuaQuery::ExecuteFile(name) => {
            trace!("thread: Received request to execute file {}", name);
            info!("thread: Executing {}", name);

            let path = Path::new(&name);
            let try_file = File::open(path);

            if let Ok(file) = try_file {
                let result = lua.execute_from_reader::<(), File>(file);
                if let Err(err) = result {
                    warn!("thread: Error executing {}!", name);

                    thread_send(&sender, LuaResponse::Error(err));
                }
                else {
                    trace!("thread: Execution of {} successful.", name);
                }
            }
            else { // Could not open file
                // Unwrap_err is used because we're in the else of let
                let read_error =
                    LuaError::ReadError(try_file.unwrap_err());

                thread_send(&sender, LuaResponse::Error(read_error));
            }
        },

        LuaQuery::GetVariable(varname) => {
            trace!("thread: Received request to get variable {}", varname);
            let var_result = lua.get(varname.as_str());

            match var_result {
                Some(var) => {
                    thread_send(&sender, LuaResponse::Variable(Some(var)));
                }
                None => {
                    warn!("thread: Unable to get variable {}", varname);

                    thread_send(&sender, LuaResponse::Variable(None));
                }
            }
        },

        LuaQuery::SetValue { name: name, val: val } => {
        },

        LuaQuery::EmptyArray(name) => {

        },

        _ => {
            panic!("Unimplemented send type for lua thread!");
        }
    }
}

fn thread_send(sender: &Sender<LuaResponse>, response: LuaResponse) {
    trace!("Called thread_send");
    match sender.send(response) {
        Err(e) => {
            error!("thread: Unable to broadcast response!");
            error!("thread: Shutting down in response to inability \
                    to continue!");
            panic!("Lua thread unable to communicate with main thread, \
                    shutting down!");
        }
        Ok(_) => {}
    }
}
<commit_msg>Add lua ping message types<commit_after>//! Lua functionality

use hlua;
use hlua::{Lua, LuaError};
use hlua::any::AnyLuaValue;

use std::thread;

use std::fs::{File};
use std::path::Path;
use std::io::Write;

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

lazy_static! {
    /// Sends requests to the lua thread
    static ref SENDER: Mutex<Sender<LuaQuery>> = {
        let (tx, rx) = channel::<LuaQuery>();
        Mutex::new(tx)
    };

    /// Receives data back from the lua thread
    /// This should only be accessed by the lua thread itself.
    static ref RECEIVER: Mutex<Receiver<LuaResponse>> = {
        let (tx, rx) = channel::<LuaResponse>();
        Mutex::new(rx)
    };

    /// Whether the lua thread is currently running
    pub static ref RUNNING: RwLock<bool> = RwLock::new(false);
}

/// Messages sent to the lua thread
pub enum LuaQuery {
    /// Halt the lua thread
    Terminate,
    // Restart the lua thread
    Restart,
    /// Execute a string
    Execute(String),
    /// Execute a file
    ExecuteFile(String),
    /// Get a variable
    GetVariable(String),
    /// Set a value
    SetValue {
        name: Box<::std::borrow::Borrow<str> + Sized>,
        val: Box<hlua::Push<&'static mut Lua<'static>> + Sized>
    },
    /// Create a new array
    EmptyArray(String),
    /// Message to ping the lua thread
    Ping,
    /// Unused send type
    Unused,
}

/// Messages received from lua thread
pub enum LuaResponse {
    /// Lua variable obtained
    Variable(Option<AnyLuaValue>),
    /// Lua error
    Error(hlua::LuaError),
    /// A function is returned
    Function(hlua::functions_read::LuaFunction<String>),
    /// Pong response from lua ping
    Pong,
    /// Unused response type
    Unused,
}

unsafe impl Send for LuaQuery { }
unsafe impl Send for LuaResponse { }
unsafe impl Sync for LuaQuery { }
unsafe impl Sync for LuaResponse { }

/// Whether the lua thread is currently available
pub fn thread_running() -> bool {
    *RUNNING.read().unwrap()
}

/// Errors which may arise from attempting
/// to sending a message to the lua thread.
pub enum LuaSendError {
    ThreadClosed,
    Sender
}

/// Attemps to send a LuaQuery to the lua thread.
pub fn try_send(query: LuaQuery) -> Result<(), LuaSendError> {
    if !thread_running() { Err(LuaSendError::ThreadClosed) }
    else {
        match SENDER.lock().unwrap().send(query) {
            Ok(_) => Ok(()),
            Err(_) => Err(LuaSendError::Sender)
        }
    }
}

/// Sends a value to the lua thread.
///
/// # Panics
/// * If the lua thread is currently not running (check `lua::thread_running()`)
/// * If the sender was unable to send, which should only happen
/// if the lua thread isn't running.
pub fn send(query: LuaQuery) {
    if !thread_running() {
        panic!("lua: Attempted to message the lua thread while it is not active!");
    }
    SENDER.lock().unwrap().send(query).unwrap();
}

/// Initialize the lua thread
pub fn init() {
    trace!("Initializing...");
    let (query_tx, query_rx) = channel::<LuaQuery>();
    let (answer_tx, answer_rx) = channel::<LuaResponse>();
    {
        let mut sender = SENDER.lock().unwrap();
        let mut receiver = RECEIVER.lock().unwrap();

        *sender = query_tx;
        *receiver = answer_rx;
    }

    thread::spawn(move || {
        trace!("thread: Inside thread!");
        let sender = answer_tx;
        let receiver = query_rx;
        let mut lua = Lua::new();
        trace!("thread: Loading libraries...");
        lua.openlibs();
        trace!("thread: Libraries loaded");
        *RUNNING.write().unwrap() = true;
        trace!("thread: Testing hello world...");
        let mut file = File::create("/tmp/init.lua").unwrap();
        file.write(b"print('Hello world!')").unwrap();
        lua.execute_from_reader::<(), File>(File::open("/tmp/init.lua")
                                            .unwrap()).unwrap();
        trace!("thread: Done!");
        trace!("thread: Entering loop...");
        thread_main_loop(sender, receiver, &mut lua);
    });
    trace!("Created thread. Init finished.");
}

fn thread_main_loop(sender: Sender<LuaResponse>, receiver: Receiver<LuaQuery>,
                    lua: &mut Lua) {
    loop {
        let request = receiver.recv();
        match request {
            Err(e) => {
                error!("Lua thread: unable to receive message: {}", e);
                error!("Lua thread: now panicking!");
                *RUNNING.write().unwrap() = false;

                panic!("Lua thread: lost contact with host, exiting!");
            }
            Ok(message) => {
                trace!("Handling a request");
                thread_handle_message(&sender, message, lua);
            }
        }
    }
}

fn thread_handle_message(sender: &Sender<LuaResponse>, request: LuaQuery, lua: &mut Lua) {
    match request {
        LuaQuery::Terminate => {
            trace!("thread: Received terminate signal");
            *RUNNING.write().unwrap() = false;

            info!("thread: Lua thread terminating!");
            return;
        },

        LuaQuery::Restart => {
            trace!("thread: Received restart signal!");
            error!("thread: Lua thread restart not supported!");

            *RUNNING.write().unwrap() = false;

            panic!("Lua thread: Restart not supported!");
        },

        LuaQuery::Execute(code) => {
            trace!("thread: Received request to execute code");
            trace!("thread: Executing {:?}", code);

            match lua.execute::<()>(&code) {
                Err(error) => {
                    warn!("thread: Error executing code: {:?}", error);
                    let response = LuaResponse::Error(error);

                    thread_send(&sender, response);
                }
                Ok(_) => {
                    // This is gonna be really spammy one day
                    trace!("thread: Code executed okay.");
                }
            }
        },

        LuaQuery::ExecuteFile(name) => {
            trace!("thread: Received request to execute file {}", name);
            info!("thread: Executing {}", name);

            let path = Path::new(&name);
            let try_file = File::open(path);

            if let Ok(file) = try_file {
                let result = lua.execute_from_reader::<(), File>(file);
                if let Err(err) = result {
                    warn!("thread: Error executing {}!", name);

                    thread_send(&sender, LuaResponse::Error(err));
                }
                else {
                    trace!("thread: Execution of {} successful.", name);
                }
            }
            else { // Could not open file
                // Unwrap_err is used because we're in the else of let
                let read_error =
                    LuaError::ReadError(try_file.unwrap_err());

                thread_send(&sender, LuaResponse::Error(read_error));
            }
        },

        LuaQuery::GetVariable(varname) => {
            trace!("thread: Received request to get variable {}", varname);
            let var_result = lua.get(varname.as_str());

            match var_result {
                Some(var) => {
                    thread_send(&sender, LuaResponse::Variable(Some(var)));
                }
                None => {
                    warn!("thread: Unable to get variable {}", varname);

                    thread_send(&sender, LuaResponse::Variable(None));
                }
            }
        },

        LuaQuery::SetValue { name: name, val: val } => {
        },

        LuaQuery::EmptyArray(name) => {

        },

        _ => {
            panic!("Unimplemented send type for lua thread!");
        }
    }
}

fn thread_send(sender: &Sender<LuaResponse>, response: LuaResponse) {
    trace!("Called thread_send");
    match sender.send(response) {
        Err(e) => {
            error!("thread: Unable to broadcast response!");
            error!("thread: Shutting down in response to inability \
                    to continue!");
            panic!("Lua thread unable to communicate with main thread, \
                    shutting down!");
        }
        Ok(_) => {}
    }
}
<|endoftext|>


<commit_before>use std::vec::Vec;

pub struct Machine {
    memory: Vec<u32>,
    counter: u32,
}

impl Machine {
    pub fn new() -> Machine {
        Machine {
            memory: vec![0; 2097152],
            counter: 0,
        }
    }

    pub fn with_data(data: Vec<u32>) -> Machine {
        Machine {
            memory: data,
            counter: 0,
        }
    }

    pub fn loc(&self) -> u32 {
        self.counter
    }

    pub fn dump(&self) -> &Vec<u32> {
        &self.memory
    }

    pub fn load(&mut self, data: Vec<u32>) {
        self.memory = data;
    }

    pub fn exec(&mut self, opcode: u32, a: u32, b: u32, c: u32) {
        match opcode {
            // PC <- M[A]
            1 => {
                self.counter = self.memory[a as usize];
            },

            // If M[B] = 0, then PC <- M[A]
            2 => {
                if 0 == self.memory[b as usize] {
                  self.counter = self.memory[a as usize];
                }
            },

            // M[A] <- PC
            3 => {
                self.memory[a as usize] = self.counter;
                self.counter += 4;
            },

            // M[A] <- M[B]
            4 => {
                self.memory[a as usize] = self.memory[b as usize];
                self.counter += 4;
            },

            // M[A] <- M[M[B]]
            5 => {
                let b = self.memory[b as usize];
                self.memory[a as usize] = self.memory[b as usize];
                self.counter += 4;
            },

            // M[M[B]] <- M[A]
            6 => {
                let b = self.memory[b as usize];
                self.memory[b as usize] = self.memory[a as usize];
                self.counter += 4;
            },

            // M[A] <- M[B] + M[C]
            7 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b + c;
                self.counter += 4;
            },

            // M[A] <- M[B] - M[C]
            8 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b - c;
                self.counter += 4;
            },

            // Unknown opcode
            _ => {
            },
        }
    }
}

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

    #[test]
    fn it_loads_data() {
        let mut m = Machine::new();
        assert_eq!(Some(&0), m.dump().first());

        m.load(vec![1]);
        assert_eq!(Some(&1), m.dump().first());
    }

    #[test]
    fn it_runs_opcode_1() {
        let mut m = Machine::with_data(vec![0, 2]);

        assert_eq!(0, m.loc());
        m.exec(1, 1, 0, 0);
        assert_eq!(2, m.loc());
    }

    #[test]
    fn it_runs_opcode_2_if() {
        let mut m = Machine::with_data(vec![0, 2]);

        assert_eq!(0, m.loc());
        m.exec(2, 1, 0, 0);
        assert_eq!(2, m.loc());
    }

    #[test]
    fn it_runs_opcode_2_else() {
        let mut m = Machine::with_data(vec![1, 2]);

        assert_eq!(0, m.loc());
        m.exec(2, 1, 0, 0);
        assert_eq!(0, m.loc());
    }

    #[test]
    fn it_runs_opcode_3() {
        let mut m = Machine::with_data(vec![1]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(3, 0, 0, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_4() {
        let mut m = Machine::with_data(vec![1, 0]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(4, 0, 1, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_5() {
        let mut m = Machine::with_data(vec![1, 2, 0]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(5, 0, 1, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_6() {
        let mut m = Machine::with_data(vec![1, 0]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(6, 1, 1, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_7() {
        let mut m = Machine::with_data(vec![1, 2, 3]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(7, 0, 1, 2);
        assert_eq!(Some(&5), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_8() {
        let mut m = Machine::with_data(vec![0, 3, 2]);

        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(8, 0, 1, 2);
        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(4, m.loc());
    }
}
<commit_msg>Test that opcode 9 works.<commit_after>use std::vec::Vec;

pub struct Machine {
    memory: Vec<u32>,
    counter: u32,
}

impl Machine {
    pub fn new() -> Machine {
        Machine {
            memory: vec![0; 2097152],
            counter: 0,
        }
    }

    pub fn with_data(data: Vec<u32>) -> Machine {
        Machine {
            memory: data,
            counter: 0,
        }
    }

    pub fn loc(&self) -> u32 {
        self.counter
    }

    pub fn dump(&self) -> &Vec<u32> {
        &self.memory
    }

    pub fn load(&mut self, data: Vec<u32>) {
        self.memory = data;
    }

    pub fn exec(&mut self, opcode: u32, a: u32, b: u32, c: u32) {
        match opcode {
            // PC <- M[A]
            1 => {
                self.counter = self.memory[a as usize];
            },

            // If M[B] = 0, then PC <- M[A]
            2 => {
                if 0 == self.memory[b as usize] {
                  self.counter = self.memory[a as usize];
                }
            },

            // M[A] <- PC
            3 => {
                self.memory[a as usize] = self.counter;
                self.counter += 4;
            },

            // M[A] <- M[B]
            4 => {
                self.memory[a as usize] = self.memory[b as usize];
                self.counter += 4;
            },

            // M[A] <- M[M[B]]
            5 => {
                let b = self.memory[b as usize];
                self.memory[a as usize] = self.memory[b as usize];
                self.counter += 4;
            },

            // M[M[B]] <- M[A]
            6 => {
                let b = self.memory[b as usize];
                self.memory[b as usize] = self.memory[a as usize];
                self.counter += 4;
            },

            // M[A] <- M[B] + M[C]
            7 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b + c;
                self.counter += 4;
            },

            // M[A] <- M[B] - M[C]
            8 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b - c;
                self.counter += 4;
            },

            // M[A] <- M[B] x M[C]
            9 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b * c;
                self.counter += 4;
            },

            // Unknown opcode
            _ => {
            },
        }
    }
}

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

    #[test]
    fn it_loads_data() {
        let mut m = Machine::new();
        assert_eq!(Some(&0), m.dump().first());

        m.load(vec![1]);
        assert_eq!(Some(&1), m.dump().first());
    }

    #[test]
    fn it_runs_opcode_1() {
        let mut m = Machine::with_data(vec![0, 2]);

        assert_eq!(0, m.loc());
        m.exec(1, 1, 0, 0);
        assert_eq!(2, m.loc());
    }

    #[test]
    fn it_runs_opcode_2_if() {
        let mut m = Machine::with_data(vec![0, 2]);

        assert_eq!(0, m.loc());
        m.exec(2, 1, 0, 0);
        assert_eq!(2, m.loc());
    }

    #[test]
    fn it_runs_opcode_2_else() {
        let mut m = Machine::with_data(vec![1, 2]);

        assert_eq!(0, m.loc());
        m.exec(2, 1, 0, 0);
        assert_eq!(0, m.loc());
    }

    #[test]
    fn it_runs_opcode_3() {
        let mut m = Machine::with_data(vec![1]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(3, 0, 0, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_4() {
        let mut m = Machine::with_data(vec![1, 0]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(4, 0, 1, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_5() {
        let mut m = Machine::with_data(vec![1, 2, 0]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(5, 0, 1, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_6() {
        let mut m = Machine::with_data(vec![1, 0]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(6, 1, 1, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_7() {
        let mut m = Machine::with_data(vec![1, 2, 3]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(7, 0, 1, 2);
        assert_eq!(Some(&5), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_8() {
        let mut m = Machine::with_data(vec![0, 3, 2]);

        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(8, 0, 1, 2);
        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_9() {
        let mut m = Machine::with_data(vec![1, 2, 3]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(9, 0, 1, 2);
        assert_eq!(Some(&6), m.dump().first());
        assert_eq!(4, m.loc());
    }
}
<|endoftext|>


<commit_before>//! Functions for creating and modifying messages to send across the message bus.
use std::ops::DerefMut;
use std::cell::RefCell;

use dbus_serialize::types::{Path,Variant,Value,BasicValue,Signature};

use marshal::{Marshal,pad_to_multiple};
use demarshal::{demarshal,DemarshalError};

#[derive(Debug,Default,PartialEq)]
pub struct MessageType(pub u8);
pub const MESSAGE_TYPE_INVALID : MessageType        = MessageType(0);
pub const MESSAGE_TYPE_METHOD_CALL : MessageType    = MessageType(1);
pub const MESSAGE_TYPE_METHOD_RETURN : MessageType  = MessageType(2);
pub const MESSAGE_TYPE_ERROR : MessageType          = MessageType(3);
pub const MESSAGE_TYPE_SIGNAL : MessageType         = MessageType(4);

pub const HEADER_FIELD_INVALID : u8     = 0;
pub const HEADER_FIELD_PATH: u8         = 1;
pub const HEADER_FIELD_INTERFACE: u8    = 2;
pub const HEADER_FIELD_MEMBER: u8       = 3;
pub const HEADER_FIELD_ERROR_NAME: u8   = 4;
pub const HEADER_FIELD_REPLY_SERIAL: u8 = 5;
pub const HEADER_FIELD_DESTINATION: u8  = 6;
pub const HEADER_FIELD_SENDER: u8       = 7;
pub const HEADER_FIELD_SIGNATURE: u8    = 8;

pub const FLAGS_NO_REPLY_EXPECTED : u8  = 1;

#[derive(Debug)]
pub struct HeaderField (
    pub u8,
    pub Variant
);

impl Marshal for HeaderField {
    fn dbus_encode(&self, buf: &mut Vec<u8>) -> usize {
        pad_to_multiple(buf, 8);
        let start_len = buf.len();
        let code = self.0 as u8;
        code.dbus_encode(buf);
        self.1.dbus_encode(buf);
        buf.len() - start_len
    }
    fn get_type(&self) -> String {
        "(yv)".to_owned()
    }
}

/// Represents a received message from the message bus
#[derive(Debug,Default)]
pub struct Message {
    pub big_endian: bool,
    pub message_type: MessageType,
    pub flags: u8,
    pub version: u8,
    pub serial: u32,
    pub headers: Vec<HeaderField>,
    pub body: Vec<u8>,

    body_cache: RefCell<Option<Result<Option<Vec<Value>>, DemarshalError>>>
}

impl Marshal for Message {
    fn dbus_encode (&self, buf: &mut Vec<u8>) -> usize {
        let endian = if self.big_endian { 'B' as u8 } else { 'l' as u8 };
        endian.dbus_encode(buf);
        self.message_type.0.dbus_encode(buf);
        self.flags.dbus_encode(buf);
        self.version.dbus_encode(buf);
        let len : u32 = self.body.len() as u32;
        len.dbus_encode(buf);
        self.serial.dbus_encode(buf);
        self.headers.dbus_encode(buf);
        pad_to_multiple(buf, 8);
        0
    }

    fn get_type (&self) -> String {
        panic!("Don't do that.")
    }
}

/// Create a Message for a D-Bus method call.  Once a Message is created, arguments
/// can be added with Message.add_arg
pub fn create_method_call (dest: &str, path: &str, iface: &str, method: &str) -> Message {
    Message {
        big_endian: false,
        message_type: MESSAGE_TYPE_METHOD_CALL,
        flags: 0,
        version: 1,
        serial: 0,
        headers: Vec::new(),
        body: Vec::new(),

        body_cache: RefCell::new(None),
    }.add_header(HEADER_FIELD_DESTINATION,
                 Variant::new(Value::from(dest), "s"))
     .add_header(HEADER_FIELD_PATH,
                 Variant::new(Value::BasicValue(BasicValue::ObjectPath(Path(path.to_owned()))), "o"))
     .add_header(HEADER_FIELD_INTERFACE,
                 Variant::new(Value::from(iface), "s"))
     .add_header(HEADER_FIELD_MEMBER,
                 Variant::new(Value::from(method), "s"))
}

/// Create a Message for a D-Bus method return.  Once created, return values can be added
/// with Message.add_arg
pub fn create_method_return(reply_serial: u32) -> Message {
    Message {
        big_endian: false,
        message_type: MESSAGE_TYPE_METHOD_RETURN,
        flags: 0,
        version: 1,
        serial: 0,
        headers: Vec::new(),
        body: Vec::new(),

        body_cache: RefCell::new(None),
    }.add_header(HEADER_FIELD_REPLY_SERIAL,
                 Variant::new(Value::from(reply_serial), "u"))
}

/// Create a Message for a D-Bus error.  Once created, return values can be added
/// with Message.add_arg
pub fn create_error(error_name: &str, reply_serial: u32) -> Message {
    Message {
        big_endian: false,
        message_type: MESSAGE_TYPE_ERROR,
        flags: 0,
        version: 1,
        serial: 0,
        headers: Vec::new(),
        body: Vec::new(),

        body_cache: RefCell::new(None),
    }.add_header(HEADER_FIELD_REPLY_SERIAL,
                 Variant::new(Value::from(reply_serial), "u"))
     .add_header(HEADER_FIELD_ERROR_NAME,
                 Variant::new(Value::from(error_name), "s"))
}

/// Create a Message for a D-Bus signal.  Once created, return values can be added
/// with Message.add_arg
pub fn create_signal(path: &str, interface: &str, member: &str) -> Message {
    Message {
        big_endian: false,
        message_type: MESSAGE_TYPE_SIGNAL,
        flags: 0,
        version: 1,
        serial: 0,
        headers: Vec::new(),
        body: Vec::new(),

        body_cache: RefCell::new(None),
    }.add_header(HEADER_FIELD_PATH,
                 Variant::new(Value::BasicValue(BasicValue::ObjectPath(Path(path.to_owned()))), "o"))
     .add_header(HEADER_FIELD_INTERFACE,
                 Variant::new(Value::from(interface), "s"))
     .add_header(HEADER_FIELD_MEMBER,
                 Variant::new(Value::from(member), "s"))
}

impl Message {
    /// Add the given argument to the Message.  Accepts anything that implements the Marshal
    /// trait, which is most basic types, as well as the general-purpose
    /// dbus_serialize::types::Value enum.
    ///
    /// Note that these calls can be chained together to add multiple arguments, see the example
    ///
    /// # Examples
    /// ```
    /// dbus_bytestream::message::create_method_call("foo", "/bar", "baz", "bloop")
    ///     .add_arg(&1)
    ///     .add_arg(&"string");
    /// ```
    pub fn add_arg(mut self, arg: &Marshal) -> Message {
        if let None = self.get_header(HEADER_FIELD_SIGNATURE) {
            let value = Value::BasicValue(BasicValue::Signature(Signature("".to_owned())));
            let variant = Variant::new(value, "g");
            self = self.add_header(HEADER_FIELD_SIGNATURE, variant);
        };
        {
            let b : &mut Box<Value> = &mut self.get_header_mut(HEADER_FIELD_SIGNATURE).unwrap().object;
            let val : &mut Value = b.deref_mut();
            match *val {
                Value::BasicValue(BasicValue::Signature(ref mut s)) => s.0.push_str(&arg.get_type()),
                _ => panic!("Garbage in signature field")
            };
        }
        arg.dbus_encode(&mut self.body);
        self
    }

    pub fn get_header(&self, name: u8) -> Option<&Variant> {
        self.headers.iter().position(|x| { x.0 == name })
            .map(|idx| &self.headers[idx].1)
    }

    pub fn get_header_mut(&mut self, name: u8) -> Option<&mut Variant> {
        match self.headers.iter().position(|x| { x.0 == name }) {
            Some(idx) => Some(&mut self.headers[idx].1),
            _ => None
        }
    }

    pub fn add_header(mut self, name: u8, val: Variant) -> Message {
        self.headers.push(HeaderField (name, val));
        self
    }

    /// Get the sequence of Values from out of a Message.  Returns None if the message doesn't have
    /// a body.
    pub fn get_body(&self) -> Result<Option<Vec<Value>>,DemarshalError> {
        if self.body.is_empty() {
            return Ok(None);
        }
        let cached = self.body_cache.borrow().is_some();
        if !cached {
            // Get the signature out of the headers
            let v = match self.headers.iter().position(|x| { x.0 == HEADER_FIELD_SIGNATURE }) {
                Some(idx) => &self.headers[idx].1,
                None => return Ok(None)
            };

            let sigval = match *v.object {
                Value::BasicValue(BasicValue::Signature(ref x)) => x,
                _ => return Ok(None)
            };

            let mut body = self.body.clone();
            let mut sig = "(".to_owned() + &sigval.0 + ")";
            let mut offset = 0;
            *self.body_cache.borrow_mut() = Some((|| {
                match try!(demarshal(&mut body, &mut offset, &mut sig)) {
                    Value::Struct(x) => Ok(Some(x.objects)),
                    x => panic!("Didn't get a struct: {:?}", x)
                }
            })());
        }
        self.body_cache.borrow().as_ref().unwrap().clone()
    }
}

#[test]
fn test_msg () {
    create_method_call("foo", "bar", "baz", "floob")
        .add_arg(&1)
        .add_arg(&2);
}
<commit_msg>message: derive MessageType from Eq<commit_after>//! Functions for creating and modifying messages to send across the message bus.
use std::ops::DerefMut;
use std::cell::RefCell;

use dbus_serialize::types::{Path,Variant,Value,BasicValue,Signature};

use marshal::{Marshal,pad_to_multiple};
use demarshal::{demarshal,DemarshalError};

#[derive(Debug,Default,PartialEq,Eq)]
pub struct MessageType(pub u8);
pub const MESSAGE_TYPE_INVALID : MessageType        = MessageType(0);
pub const MESSAGE_TYPE_METHOD_CALL : MessageType    = MessageType(1);
pub const MESSAGE_TYPE_METHOD_RETURN : MessageType  = MessageType(2);
pub const MESSAGE_TYPE_ERROR : MessageType          = MessageType(3);
pub const MESSAGE_TYPE_SIGNAL : MessageType         = MessageType(4);

pub const HEADER_FIELD_INVALID : u8     = 0;
pub const HEADER_FIELD_PATH: u8         = 1;
pub const HEADER_FIELD_INTERFACE: u8    = 2;
pub const HEADER_FIELD_MEMBER: u8       = 3;
pub const HEADER_FIELD_ERROR_NAME: u8   = 4;
pub const HEADER_FIELD_REPLY_SERIAL: u8 = 5;
pub const HEADER_FIELD_DESTINATION: u8  = 6;
pub const HEADER_FIELD_SENDER: u8       = 7;
pub const HEADER_FIELD_SIGNATURE: u8    = 8;

pub const FLAGS_NO_REPLY_EXPECTED : u8  = 1;

#[derive(Debug)]
pub struct HeaderField (
    pub u8,
    pub Variant
);

impl Marshal for HeaderField {
    fn dbus_encode(&self, buf: &mut Vec<u8>) -> usize {
        pad_to_multiple(buf, 8);
        let start_len = buf.len();
        let code = self.0 as u8;
        code.dbus_encode(buf);
        self.1.dbus_encode(buf);
        buf.len() - start_len
    }
    fn get_type(&self) -> String {
        "(yv)".to_owned()
    }
}

/// Represents a received message from the message bus
#[derive(Debug,Default)]
pub struct Message {
    pub big_endian: bool,
    pub message_type: MessageType,
    pub flags: u8,
    pub version: u8,
    pub serial: u32,
    pub headers: Vec<HeaderField>,
    pub body: Vec<u8>,

    body_cache: RefCell<Option<Result<Option<Vec<Value>>, DemarshalError>>>
}

impl Marshal for Message {
    fn dbus_encode (&self, buf: &mut Vec<u8>) -> usize {
        let endian = if self.big_endian { 'B' as u8 } else { 'l' as u8 };
        endian.dbus_encode(buf);
        self.message_type.0.dbus_encode(buf);
        self.flags.dbus_encode(buf);
        self.version.dbus_encode(buf);
        let len : u32 = self.body.len() as u32;
        len.dbus_encode(buf);
        self.serial.dbus_encode(buf);
        self.headers.dbus_encode(buf);
        pad_to_multiple(buf, 8);
        0
    }

    fn get_type (&self) -> String {
        panic!("Don't do that.")
    }
}

/// Create a Message for a D-Bus method call.  Once a Message is created, arguments
/// can be added with Message.add_arg
pub fn create_method_call (dest: &str, path: &str, iface: &str, method: &str) -> Message {
    Message {
        big_endian: false,
        message_type: MESSAGE_TYPE_METHOD_CALL,
        flags: 0,
        version: 1,
        serial: 0,
        headers: Vec::new(),
        body: Vec::new(),

        body_cache: RefCell::new(None),
    }.add_header(HEADER_FIELD_DESTINATION,
                 Variant::new(Value::from(dest), "s"))
     .add_header(HEADER_FIELD_PATH,
                 Variant::new(Value::BasicValue(BasicValue::ObjectPath(Path(path.to_owned()))), "o"))
     .add_header(HEADER_FIELD_INTERFACE,
                 Variant::new(Value::from(iface), "s"))
     .add_header(HEADER_FIELD_MEMBER,
                 Variant::new(Value::from(method), "s"))
}

/// Create a Message for a D-Bus method return.  Once created, return values can be added
/// with Message.add_arg
pub fn create_method_return(reply_serial: u32) -> Message {
    Message {
        big_endian: false,
        message_type: MESSAGE_TYPE_METHOD_RETURN,
        flags: 0,
        version: 1,
        serial: 0,
        headers: Vec::new(),
        body: Vec::new(),

        body_cache: RefCell::new(None),
    }.add_header(HEADER_FIELD_REPLY_SERIAL,
                 Variant::new(Value::from(reply_serial), "u"))
}

/// Create a Message for a D-Bus error.  Once created, return values can be added
/// with Message.add_arg
pub fn create_error(error_name: &str, reply_serial: u32) -> Message {
    Message {
        big_endian: false,
        message_type: MESSAGE_TYPE_ERROR,
        flags: 0,
        version: 1,
        serial: 0,
        headers: Vec::new(),
        body: Vec::new(),

        body_cache: RefCell::new(None),
    }.add_header(HEADER_FIELD_REPLY_SERIAL,
                 Variant::new(Value::from(reply_serial), "u"))
     .add_header(HEADER_FIELD_ERROR_NAME,
                 Variant::new(Value::from(error_name), "s"))
}

/// Create a Message for a D-Bus signal.  Once created, return values can be added
/// with Message.add_arg
pub fn create_signal(path: &str, interface: &str, member: &str) -> Message {
    Message {
        big_endian: false,
        message_type: MESSAGE_TYPE_SIGNAL,
        flags: 0,
        version: 1,
        serial: 0,
        headers: Vec::new(),
        body: Vec::new(),

        body_cache: RefCell::new(None),
    }.add_header(HEADER_FIELD_PATH,
                 Variant::new(Value::BasicValue(BasicValue::ObjectPath(Path(path.to_owned()))), "o"))
     .add_header(HEADER_FIELD_INTERFACE,
                 Variant::new(Value::from(interface), "s"))
     .add_header(HEADER_FIELD_MEMBER,
                 Variant::new(Value::from(member), "s"))
}

impl Message {
    /// Add the given argument to the Message.  Accepts anything that implements the Marshal
    /// trait, which is most basic types, as well as the general-purpose
    /// dbus_serialize::types::Value enum.
    ///
    /// Note that these calls can be chained together to add multiple arguments, see the example
    ///
    /// # Examples
    /// ```
    /// dbus_bytestream::message::create_method_call("foo", "/bar", "baz", "bloop")
    ///     .add_arg(&1)
    ///     .add_arg(&"string");
    /// ```
    pub fn add_arg(mut self, arg: &Marshal) -> Message {
        if let None = self.get_header(HEADER_FIELD_SIGNATURE) {
            let value = Value::BasicValue(BasicValue::Signature(Signature("".to_owned())));
            let variant = Variant::new(value, "g");
            self = self.add_header(HEADER_FIELD_SIGNATURE, variant);
        };
        {
            let b : &mut Box<Value> = &mut self.get_header_mut(HEADER_FIELD_SIGNATURE).unwrap().object;
            let val : &mut Value = b.deref_mut();
            match *val {
                Value::BasicValue(BasicValue::Signature(ref mut s)) => s.0.push_str(&arg.get_type()),
                _ => panic!("Garbage in signature field")
            };
        }
        arg.dbus_encode(&mut self.body);
        self
    }

    pub fn get_header(&self, name: u8) -> Option<&Variant> {
        self.headers.iter().position(|x| { x.0 == name })
            .map(|idx| &self.headers[idx].1)
    }

    pub fn get_header_mut(&mut self, name: u8) -> Option<&mut Variant> {
        match self.headers.iter().position(|x| { x.0 == name }) {
            Some(idx) => Some(&mut self.headers[idx].1),
            _ => None
        }
    }

    pub fn add_header(mut self, name: u8, val: Variant) -> Message {
        self.headers.push(HeaderField (name, val));
        self
    }

    /// Get the sequence of Values from out of a Message.  Returns None if the message doesn't have
    /// a body.
    pub fn get_body(&self) -> Result<Option<Vec<Value>>,DemarshalError> {
        if self.body.is_empty() {
            return Ok(None);
        }
        let cached = self.body_cache.borrow().is_some();
        if !cached {
            // Get the signature out of the headers
            let v = match self.headers.iter().position(|x| { x.0 == HEADER_FIELD_SIGNATURE }) {
                Some(idx) => &self.headers[idx].1,
                None => return Ok(None)
            };

            let sigval = match *v.object {
                Value::BasicValue(BasicValue::Signature(ref x)) => x,
                _ => return Ok(None)
            };

            let mut body = self.body.clone();
            let mut sig = "(".to_owned() + &sigval.0 + ")";
            let mut offset = 0;
            *self.body_cache.borrow_mut() = Some((|| {
                match try!(demarshal(&mut body, &mut offset, &mut sig)) {
                    Value::Struct(x) => Ok(Some(x.objects)),
                    x => panic!("Didn't get a struct: {:?}", x)
                }
            })());
        }
        self.body_cache.borrow().as_ref().unwrap().clone()
    }
}

#[test]
fn test_msg () {
    create_method_call("foo", "bar", "baz", "floob")
        .add_arg(&1)
        .add_arg(&2);
}
<|endoftext|>


<commit_before>use gemlab::util::SQRT_3;
use gemlab::StrError;
use plotpy::{Canvas, Plot, PolyCode};
use std::fmt::Write;
use std::fs;

const APPROXIMATED: bool = true;

// Equilateral triangle
//
//           /
//        2   \        0-----------2
//       / \   \        \         /
//      / ↑ \   l        \       /
//     /  h  \   \        \     /
//    /   ↓   \   \        \   /
//   /         \   /        \ /
//  0-----------1            1
//
//  |--s--|--s--|
//
//  |-----l-----|
//
// area = l * h / 2.0;
fn generate_equilateral_triangle(l: f64, x0: f64, y0: f64, flipped: bool) -> Vec<[f64; 2]> {
    let s = l / 2.0;
    let h = if APPROXIMATED { l * 1.7 / 2.0 } else { l * SQRT_3 / 2.0 };
    if flipped {
        return vec![[x0, y0 + h], [x0 + s, y0], [x0 + l, y0 + h]];
    } else {
        return vec![[x0, y0], [x0 + l, y0], [x0 + s, y0 + h]];
    }
}

fn main() -> Result<(), StrError> {
    // constants
    const L: f64 = 1.0;
    const NX: usize = 10;
    const NY: usize = 10;
    const X0: f64 = 0.0;
    const Y0: f64 = 0.0;
    let h = if APPROXIMATED { L * 1.7 / 2.0 } else { L * SQRT_3 / 2.0 };

    // generate triangles
    let mut y0 = Y0;
    let mut triangles: Vec<Vec<[f64; 2]>> = Vec::new();
    for j in 0..NY {
        let mut x0 = X0 + (j as f64) * L / 2.0;
        for _ in 0..NX {
            let tri = generate_equilateral_triangle(L, x0, y0, false);
            triangles.push(tri);
            x0 += L;
        }
        x0 = X0 + (j as f64) * L / 2.0 + L / 2.0;
        for _ in 0..NX {
            let tri = generate_equilateral_triangle(L, x0, y0, true);
            triangles.push(tri);
            x0 += L;
        }
        y0 += h;
    }

    // draw
    let filekey = format!("example_grid_search_gen_triangles_{}", triangles.len());
    let mut plot = Plot::new();
    draw_triangles(&mut plot, &triangles);
    plot.set_equal_axes(true)
        .set_figure_size_points(600.0, 600.0)
        .grid_and_labels("x", "y")
        .save(format!("/tmp/gemlab/{}.svg", filekey).as_str())?;

    // generate file for use in examples
    let mut buffer = String::new();
    write!(&mut buffer, "{}\n", triangles.len()).unwrap();
    for t in &triangles {
        write!(
            &mut buffer,
            "{:?} {:?} {:?} {:?} {:?} {:?}\n",
            t[0][0], t[0][1], t[1][0], t[1][1], t[2][0], t[2][1]
        )
        .unwrap();
    }
    let path = format!("/tmp/gemlab/{}.dat", filekey);
    fs::write(path, buffer).expect("cannot write file");
    Ok(())
}

fn draw_triangles(plot: &mut Plot, triangles: &Vec<Vec<[f64; 2]>>) {
    let mut xmin = vec![f64::MAX; 2];
    let mut xmax = vec![f64::MIN; 2];
    let mut canvas = Canvas::new();
    canvas.set_face_color("#fefddc").set_edge_color("#fcb827");
    for t in 0..triangles.len() {
        canvas.polycurve_begin();
        for m in 0..3 {
            for i in 0..2 {
                xmin[i] = f64::min(xmin[i], triangles[t][m][i]);
                xmax[i] = f64::max(xmax[i], triangles[t][m][i]);
            }
            let code = if m == 0 { PolyCode::MoveTo } else { PolyCode::LineTo };
            canvas.polycurve_add(&triangles[t][m][0], &triangles[t][m][1], code);
        }
        canvas.polycurve_end(true);
    }
    plot.add(&canvas);
    plot.set_range(xmin[0], xmax[0], xmin[1], xmax[1]);
}
<commit_msg>Impl coords/tris generation in example<commit_after>use gemlab::util::SQRT_3;
use gemlab::StrError;
use plotpy::{Canvas, Plot, PolyCode};
use std::collections::HashMap;
use std::fmt::Write;
use std::fs;

/// Generates approximated equilateral triangles instead of exact equilateral triangles
const APPROXIMATE_EQUILATERAL_TRIANGLE: bool = true;

/// Generates the coordinates/triangles lists instead of a single lists with the (repeated) triangle coordinates
const GEN_COORDINATES_TRIANGLES_LISTS: bool = true;

// Equilateral triangle
//
//           /
//        2   \        0-----------2
//       / \   \        \         /
//      / ↑ \   l        \       /
//     /  h  \   \        \     /
//    /   ↓   \   \        \   /
//   /         \   /        \ /
//  0-----------1            1
//
//  |--s--|--s--|
//
//  |-----l-----|
//
// area = l * h / 2.0;
fn generate_equilateral_triangle(l: f64, x0: f64, y0: f64, flipped: bool) -> Vec<[f64; 2]> {
    let s = l / 2.0;
    let h = if APPROXIMATE_EQUILATERAL_TRIANGLE {
        l * 1.7 / 2.0
    } else {
        l * SQRT_3 / 2.0
    };
    if flipped {
        return vec![[x0, y0 + h], [x0 + s, y0], [x0 + l, y0 + h]];
    } else {
        return vec![[x0, y0], [x0 + l, y0], [x0 + s, y0 + h]];
    }
}

fn main() -> Result<(), StrError> {
    // constants
    const L: f64 = 1.0;
    const NX: usize = 2;
    const NY: usize = 2;
    const X0: f64 = 0.0;
    const Y0: f64 = 0.0;
    let h = if APPROXIMATE_EQUILATERAL_TRIANGLE {
        L * 1.7 / 2.0
    } else {
        L * SQRT_3 / 2.0
    };

    // generate triangles
    let mut y0 = Y0;
    let mut triangles: Vec<Vec<[f64; 2]>> = Vec::new();
    for j in 0..NY {
        let mut x0 = X0 + (j as f64) * L / 2.0;
        for _ in 0..NX {
            let tri = generate_equilateral_triangle(L, x0, y0, false);
            triangles.push(tri);
            x0 += L;
        }
        x0 = X0 + (j as f64) * L / 2.0 + L / 2.0;
        for _ in 0..NX {
            let tri = generate_equilateral_triangle(L, x0, y0, true);
            triangles.push(tri);
            x0 += L;
        }
        y0 += h;
    }

    // draw
    let filekey = if GEN_COORDINATES_TRIANGLES_LISTS {
        // ct means coordinates/triangles
        format!("example_grid_search_gen_triangles_ct_{}", triangles.len())
    } else {
        format!("example_grid_search_gen_triangles_{}", triangles.len())
    };
    let mut plot = Plot::new();
    draw_triangles(&mut plot, &triangles);
    plot.set_equal_axes(true)
        .set_figure_size_points(600.0, 600.0)
        .grid_and_labels("x", "y")
        .save(format!("/tmp/gemlab/{}.svg", filekey).as_str())?;

    // generate file for use in examples
    let mut buffer = String::new();
    if GEN_COORDINATES_TRIANGLES_LISTS {
        const BIG: f64 = 1_000_000_000.0;
        let mut key2coords = HashMap::new();
        for t in &triangles {
            for m in 0..3 {
                let x = t[m][0];
                let y = t[m][1];
                assert!(x < BIG);
                assert!(y < BIG);
                let temperature = f64::sqrt(x * x + y * y);
                let key = ((x * BIG) as usize, (y * BIG) as usize);
                key2coords.insert(key, (x, y, temperature));
            }
        }
        let mut point_keys: Vec<_> = key2coords.keys().copied().collect();
        point_keys.sort();
        write!(&mut buffer, "{}\n", point_keys.len()).unwrap();
        for key in &point_keys {
            let (x, y, temperature) = key2coords.get(&key).unwrap();
            write!(&mut buffer, "{:?} {:?} {:?}\n", x, y, temperature).unwrap();
        }
        write!(&mut buffer, "{}\n", triangles.len()).unwrap();
        for t in &triangles {
            for m in 0..3 {
                let x = t[m][0];
                let y = t[m][1];
                let key = ((x * BIG) as usize, (y * BIG) as usize);
                let point_id = point_keys.iter().position(|k| *k == key).unwrap();
                write!(&mut buffer, "{:?} ", point_id).unwrap();
            }
            write!(&mut buffer, "\n").unwrap();
        }
    } else {
        write!(&mut buffer, "{}\n", triangles.len()).unwrap();
        for t in &triangles {
            write!(
                &mut buffer,
                "{:?} {:?} {:?} {:?} {:?} {:?}\n",
                t[0][0], t[0][1], t[1][0], t[1][1], t[2][0], t[2][1]
            )
            .unwrap();
        }
    }
    let path = format!("/tmp/gemlab/{}.dat", filekey);
    fs::write(path, buffer).expect("cannot write file");
    Ok(())
}

fn draw_triangles(plot: &mut Plot, triangles: &Vec<Vec<[f64; 2]>>) {
    let mut xmin = vec![f64::MAX; 2];
    let mut xmax = vec![f64::MIN; 2];
    let mut canvas = Canvas::new();
    canvas.set_face_color("#fefddc").set_edge_color("#fcb827");
    for t in 0..triangles.len() {
        canvas.polycurve_begin();
        for m in 0..3 {
            for i in 0..2 {
                xmin[i] = f64::min(xmin[i], triangles[t][m][i]);
                xmax[i] = f64::max(xmax[i], triangles[t][m][i]);
            }
            let code = if m == 0 { PolyCode::MoveTo } else { PolyCode::LineTo };
            canvas.polycurve_add(&triangles[t][m][0], &triangles[t][m][1], code);
        }
        canvas.polycurve_end(true);
    }
    plot.add(&canvas);
    plot.set_range(xmin[0], xmax[0], xmin[1], xmax[1]);
}
<|endoftext|>


<commit_before>#![deny(trivial_casts)]
#![deny(trivial_numeric_casts)]
#![deny(unused_import_braces)]
#![deny(variant_size_differences)]

#[macro_use]
extern crate diesel;

mod config;
mod database;
mod err;
mod file;
mod series;
mod tui;
mod user;
mod util;

use crate::config::Config;
use crate::database::Database;
use crate::file::SerializedFile;
use crate::series::config::SeriesConfig;
use crate::series::entry::SeriesEntry;
use crate::series::info::SeriesInfo;
use crate::series::{LastWatched, LoadedSeries, Series};
use crate::user::Users;
use anime::remote::Remote;
use anyhow::{anyhow, Context, Result};
use chrono::Utc;

const ANILIST_CLIENT_ID: u32 = 427;

pub struct CmdOptions {
    pub offline: bool,
    pub single: bool,
    pub sync: bool,
    pub series: Option<String>,
}

impl CmdOptions {
    fn from_env() -> Result<Self> {
        let mut args = pico_args::Arguments::from_env();

        if args.contains(["-h", "--help"]) {
            Self::print_help();
        }

        let result = Self {
            offline: args.contains(["-o", "--offline"]),
            single: args.contains("--play-one"),
            sync: args.contains("--sync"),
            series: args.free()?.into_iter().next(),
        };

        Ok(result)
    }

    fn print_help() {
        println!(concat!(
            "Usage: ",
            env!("CARGO_PKG_NAME"),
            " [series] [OPTIONS]\n"
        ));

        println!("Free arguments:");
        println!("  series - the nickname of the series to watch");

        println!();

        println!("Optional arguments:");
        println!("  -o, --offline  run the program in offline mode");
        println!("  --play-one     play a single episode from the last played series");
        println!("  --sync         syncronize changes made while offline to AniList");

        std::process::exit(0);
    }
}

fn main() -> Result<()> {
    let args = CmdOptions::from_env()?;

    if args.single {
        play_episode(args)
    } else if args.sync {
        sync(args)
    } else {
        tui::run(args)
    }
}

/// Initialize a new remote service specified by `args`.
///
/// If there are no users, returns Ok(None).
fn init_remote(args: &CmdOptions) -> Result<Option<Remote>> {
    use anime::remote::anilist::{AniList, Auth};

    if args.offline {
        Ok(Some(Remote::offline()))
    } else {
        let token = match Users::load_or_create()?.take_last_used_token() {
            Some(token) => token,
            None => return Ok(None),
        };

        let auth = Auth::retrieve(token)?;
        Ok(Some(AniList::Authenticated(auth).into()))
    }
}

fn sync(args: CmdOptions) -> Result<()> {
    if args.offline {
        return Err(anyhow!("must be online to run this command"));
    }

    let db = Database::open().context("failed to open database")?;
    let mut list_entries = SeriesEntry::entries_that_need_sync(&db)?;

    if list_entries.is_empty() {
        return Ok(());
    }

    let remote =
        init_remote(&args)?.ok_or_else(|| anyhow!("no users found\nadd one in the TUI"))?;

    for entry in &mut list_entries {
        match SeriesInfo::load(&db, entry.id()) {
            Ok(info) => println!("{} is being synced..", info.title_preferred),
            Err(err) => eprintln!(
                "warning: failed to get info for anime with ID {}: {}",
                entry.id(),
                err
            ),
        }

        entry.sync_to_remote(&remote)?;
        entry.save(&db)?;
    }

    Ok(())
}

fn play_episode(args: CmdOptions) -> Result<()> {
    use anime::remote::Status;

    let config = Config::load_or_create()?;
    let db = Database::open().context("failed to open database")?;
    let mut last_watched = LastWatched::load()?;

    let remote =
        init_remote(&args)?.ok_or_else(|| anyhow!("no users found\nadd one in the TUI"))?;

    let desired_series = args
        .series
        .as_ref()
        .or_else(|| last_watched.get())
        .ok_or_else(|| anyhow!("series name must be specified"))?;

    let mut series = {
        let cfg = SeriesConfig::load_by_name(&db, desired_series).with_context(|| {
            format!(
                "{} must be added to the program in the TUI first",
                desired_series
            )
        })?;

        match Series::load_from_config(cfg, &config, &db) {
            LoadedSeries::Complete(series) => series,
            LoadedSeries::Partial(_, err) => return Err(err.into()),
            LoadedSeries::None(_, err) => return Err(err),
        }
    };

    if last_watched.set(&series.data.config.nickname) {
        last_watched.save()?;
    }

    series.begin_watching(&remote, &config, &db)?;

    let progress_time = series.data.next_watch_progress_time(&config);
    let next_episode_num = series.data.entry.watched_episodes() + 1;

    series
        .play_episode(next_episode_num as u32, &config)?
        .wait()
        .context("waiting for episode to finish failed")?;

    if Utc::now() >= progress_time {
        series.episode_completed(&remote, &config, &db)?;

        if series.data.entry.status() == Status::Completed {
            println!("{} completed!", series.data.info.title_preferred);
        } else {
            println!(
                "{}/{} of {} completed",
                series.data.entry.watched_episodes(),
                series.data.info.episodes,
                series.data.info.title_preferred
            );
        }
    } else {
        println!("did not watch long enough to count episode as completed");
    }

    Ok(())
}
<commit_msg>anup: Enable most pedantic clippy warnings<commit_after>#![warn(clippy::pedantic)]
#![allow(clippy::clippy::cast_possible_truncation)]
#![allow(clippy::inline_always)]
#![allow(clippy::cast_precision_loss)]
#![allow(clippy::shadow_unrelated)]
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::missing_errors_doc)]
#![allow(clippy::cast_sign_loss)]
#![allow(clippy::map_err_ignore)]

#[macro_use]
extern crate diesel;

mod config;
mod database;
mod err;
mod file;
mod series;
mod tui;
mod user;
mod util;

use crate::config::Config;
use crate::database::Database;
use crate::file::SerializedFile;
use crate::series::config::SeriesConfig;
use crate::series::entry::SeriesEntry;
use crate::series::info::SeriesInfo;
use crate::series::{LastWatched, LoadedSeries, Series};
use crate::user::Users;
use anime::remote::Remote;
use anyhow::{anyhow, Context, Result};
use chrono::Utc;

const ANILIST_CLIENT_ID: u32 = 427;

pub struct CmdOptions {
    pub offline: bool,
    pub single: bool,
    pub sync: bool,
    pub series: Option<String>,
}

impl CmdOptions {
    fn from_env() -> Result<Self> {
        let mut args = pico_args::Arguments::from_env();

        if args.contains(["-h", "--help"]) {
            Self::print_help();
        }

        let result = Self {
            offline: args.contains(["-o", "--offline"]),
            single: args.contains("--play-one"),
            sync: args.contains("--sync"),
            series: args.free()?.into_iter().next(),
        };

        Ok(result)
    }

    fn print_help() {
        println!(concat!(
            "Usage: ",
            env!("CARGO_PKG_NAME"),
            " [series] [OPTIONS]\n"
        ));

        println!("Free arguments:");
        println!("  series - the nickname of the series to watch");

        println!();

        println!("Optional arguments:");
        println!("  -o, --offline  run the program in offline mode");
        println!("  --play-one     play a single episode from the last played series");
        println!("  --sync         syncronize changes made while offline to AniList");

        std::process::exit(0);
    }
}

fn main() -> Result<()> {
    let args = CmdOptions::from_env()?;

    if args.single {
        play_episode(args)
    } else if args.sync {
        sync(args)
    } else {
        tui::run(args)
    }
}

/// Initialize a new remote service specified by `args`.
///
/// If there are no users, returns Ok(None).
fn init_remote(args: &CmdOptions) -> Result<Option<Remote>> {
    use anime::remote::anilist::{AniList, Auth};

    if args.offline {
        Ok(Some(Remote::offline()))
    } else {
        let token = match Users::load_or_create()?.take_last_used_token() {
            Some(token) => token,
            None => return Ok(None),
        };

        let auth = Auth::retrieve(token)?;
        Ok(Some(AniList::Authenticated(auth).into()))
    }
}

fn sync(args: CmdOptions) -> Result<()> {
    if args.offline {
        return Err(anyhow!("must be online to run this command"));
    }

    let db = Database::open().context("failed to open database")?;
    let mut list_entries = SeriesEntry::entries_that_need_sync(&db)?;

    if list_entries.is_empty() {
        return Ok(());
    }

    let remote =
        init_remote(&args)?.ok_or_else(|| anyhow!("no users found\nadd one in the TUI"))?;

    for entry in &mut list_entries {
        match SeriesInfo::load(&db, entry.id()) {
            Ok(info) => println!("{} is being synced..", info.title_preferred),
            Err(err) => eprintln!(
                "warning: failed to get info for anime with ID {}: {}",
                entry.id(),
                err
            ),
        }

        entry.sync_to_remote(&remote)?;
        entry.save(&db)?;
    }

    Ok(())
}

fn play_episode(args: CmdOptions) -> Result<()> {
    use anime::remote::Status;

    let config = Config::load_or_create()?;
    let db = Database::open().context("failed to open database")?;
    let mut last_watched = LastWatched::load()?;

    let remote =
        init_remote(&args)?.ok_or_else(|| anyhow!("no users found\nadd one in the TUI"))?;

    let desired_series = args
        .series
        .as_ref()
        .or_else(|| last_watched.get())
        .ok_or_else(|| anyhow!("series name must be specified"))?;

    let mut series = {
        let cfg = SeriesConfig::load_by_name(&db, desired_series).with_context(|| {
            format!(
                "{} must be added to the program in the TUI first",
                desired_series
            )
        })?;

        match Series::load_from_config(cfg, &config, &db) {
            LoadedSeries::Complete(series) => series,
            LoadedSeries::Partial(_, err) => return Err(err.into()),
            LoadedSeries::None(_, err) => return Err(err),
        }
    };

    if last_watched.set(&series.data.config.nickname) {
        last_watched.save()?;
    }

    series.begin_watching(&remote, &config, &db)?;

    let progress_time = series.data.next_watch_progress_time(&config);
    let next_episode_num = series.data.entry.watched_episodes() + 1;

    series
        .play_episode(next_episode_num as u32, &config)?
        .wait()
        .context("waiting for episode to finish failed")?;

    if Utc::now() >= progress_time {
        series.episode_completed(&remote, &config, &db)?;

        if series.data.entry.status() == Status::Completed {
            println!("{} completed!", series.data.info.title_preferred);
        } else {
            println!(
                "{}/{} of {} completed",
                series.data.entry.watched_episodes(),
                series.data.info.episodes,
                series.data.info.title_preferred
            );
        }
    } else {
        println!("did not watch long enough to count episode as completed");
    }

    Ok(())
}
<|endoftext|>