<commit_before>#[macro_use]
extern crate clap;

use clap::{App, Arg, ArgMatches, SubCommand};
use rusqlite as rs;
use std::path::Path;

use std::error::Error;
use std::vec::Vec;

fn main() {
    let matches = App::new("Karmator db maintance batch")
        .version(crate_version!())
        .author(crate_authors!("\n"))
        .about("Handles the maintance work on the karmator db")
        .arg(
            Arg::with_name("FILE")
                .help("Database file to operate on")
                .required(true)
                .index(1),
        )
        .subcommand(
            SubCommand::with_name("runs")
                .about("Detect runs of votes")
                .arg(
                    Arg::with_name("min")
                        .short("m")
                        .help("Min count of runs before outputting")
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("delete")
                        .long("delete")
                        .help("Delete the runs detected"),
                ),
        )
        .get_matches();

    let filename = matches.value_of("FILE").unwrap_or("db.sqlite");
    match matches.subcommand() {
        ("runs", Some(m)) => run(m, filename),
        _ => {
            println!("{}", matches.usage());
            Ok(())
        }
    };
}

#[derive(Debug, Clone)]
struct Vote {
    id: i32,
    by_whom_name: String,
    for_what_name: String,
    amount: i8,
}
impl PartialEq for Vote {
    fn eq(&self, other: &Self) -> bool {
        (self.by_whom_name == other.by_whom_name)
            && (self.for_what_name == other.for_what_name)
            && (self.amount == other.amount)
    }
}

#[derive(Debug)]
struct RunVal {
    oldest_id: i32,
    newest_id: i32,
    by_whom_name: String,
    for_what_name: String,
    amount: i8,
    count: u32,
}

fn get_run_val(srv: &Vote, pv: &Vote, count: u32) -> RunVal {
    RunVal {
        oldest_id: srv.id,
        newest_id: pv.id,
        by_whom_name: srv.by_whom_name.clone(),
        for_what_name: srv.for_what_name.clone(),
        amount: srv.amount,
        count: count,
    }
}

fn str_amount(amount: i8) -> &'static str {
    match amount {
        -1 => "Down",
        0 => "Side",
        1 => "Up",
        _ => panic!("invalid amount"),
    }
}

fn run(matches: &ArgMatches, filename: &str) -> Result<(), Box<dyn Error>> {
    let min = value_t!(matches, "min", u32).unwrap_or(10);
    let delete = matches.is_present("delete");

    let conn =
        rs::Connection::open_with_flags(Path::new(filename), rs::OpenFlags::SQLITE_OPEN_READ_WRITE)
            .expect(&format!("Connection error: {}", filename));

    let mut stmt = conn.prepare("SELECT id, by_whom_name, for_what_name, amount FROM votes")?;
    let vote_iter = stmt.query_map(rs::params![], |row| {
        Ok(Vote {
            id: row.get(0)?,
            by_whom_name: row.get(1)?,
            for_what_name: row.get(2)?,
            amount: row.get(3)?,
        })
    })?;

    // Time to compute the run
    let mut runs = Vec::new();

    let mut start_run_vote = None;
    let mut prev_vote = None;
    let mut count = 0;

    for rvote in vote_iter {
        let vote = rvote?;

        match (&start_run_vote, &prev_vote) {
            (None, None) => {
                start_run_vote = Some(vote.clone());
                prev_vote = Some(vote);
                count = 1; // Run of 1
            }
            (Some(srv), Some(pv)) => {
                if pv == &vote {
                    // Current vote + prev vote are the same, inc prev vote
                    prev_vote = Some(vote);
                    count += 1;
                } else {
                    // Current vote != prev vote, record the run, and reset
                    runs.push(get_run_val(srv, pv, count));

                    start_run_vote = Some(vote.clone());
                    prev_vote = Some(vote);
                    count = 1; // Run of 1
                }
            }
            (_, _) => panic!("Shouldn't happen"),
        };
    }

    // Record the last run
    runs.push(get_run_val(
        &start_run_vote.unwrap(),
        &prev_vote.unwrap(),
        count,
    ));

    if delete {
        // Scan and delete the offenders
        let mut stmt = conn.prepare("DELETE FROM votes WHERE id >= ? and id <= ?")?;
        for r in &runs {
            if r.count > min {
                let deleted = stmt.execute(rs::params![r.oldest_id, r.newest_id])?;

                if (r.count as usize) != deleted {
                    panic!("Expected: {} to be deleted, got {}", r.count, deleted);
                }
            }
        }
    } else {
        // Now we can scan for anything that > min and print them
        println!(
            "{: >8}, {: >8}, {: >14.14}, {: >14.14}, {: >6}, {: >5}",
            "start_id", "end_id", "by_whom_name", "for_what_name", "amount", "count"
        );
        for r in &runs {
            if r.count > min {
                println!(
                    "{: >8}, {: >8}, {: >14.14}, {: >14.14}, {: >6}, {: >5}",
                    r.oldest_id,
                    r.newest_id,
                    r.by_whom_name,
                    r.for_what_name,
                    str_amount(r.amount),
                    r.count
                );
            }
        }
    }

    Ok(())
}
<commit_msg>set default to 20<commit_after>#[macro_use]
extern crate clap;

use clap::{App, Arg, ArgMatches, SubCommand};
use rusqlite as rs;
use std::path::Path;

use std::error::Error;
use std::vec::Vec;

fn main() {
    let matches = App::new("Karmator db maintance batch")
        .version(crate_version!())
        .author(crate_authors!("\n"))
        .about("Handles the maintance work on the karmator db")
        .arg(
            Arg::with_name("FILE")
                .help("Database file to operate on")
                .required(true)
                .index(1),
        )
        .subcommand(
            SubCommand::with_name("runs")
                .about("Detect runs of votes")
                .arg(
                    Arg::with_name("min")
                        .short("m")
                        .help("Min count of runs before outputting")
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("delete")
                        .long("delete")
                        .help("Delete the runs detected"),
                ),
        )
        .get_matches();

    let filename = matches.value_of("FILE").unwrap_or("db.sqlite");
    match matches.subcommand() {
        ("runs", Some(m)) => run(m, filename),
        _ => {
            println!("{}", matches.usage());
            Ok(())
        }
    };
}

#[derive(Debug, Clone)]
struct Vote {
    id: i32,
    by_whom_name: String,
    for_what_name: String,
    amount: i8,
}
impl PartialEq for Vote {
    fn eq(&self, other: &Self) -> bool {
        (self.by_whom_name == other.by_whom_name)
            && (self.for_what_name == other.for_what_name)
            && (self.amount == other.amount)
    }
}

#[derive(Debug)]
struct RunVal {
    oldest_id: i32,
    newest_id: i32,
    by_whom_name: String,
    for_what_name: String,
    amount: i8,
    count: u32,
}

fn get_run_val(srv: &Vote, pv: &Vote, count: u32) -> RunVal {
    RunVal {
        oldest_id: srv.id,
        newest_id: pv.id,
        by_whom_name: srv.by_whom_name.clone(),
        for_what_name: srv.for_what_name.clone(),
        amount: srv.amount,
        count: count,
    }
}

fn str_amount(amount: i8) -> &'static str {
    match amount {
        -1 => "Down",
        0 => "Side",
        1 => "Up",
        _ => panic!("invalid amount"),
    }
}

fn run(matches: &ArgMatches, filename: &str) -> Result<(), Box<dyn Error>> {
    let min = value_t!(matches, "min", u32).unwrap_or(20);
    let delete = matches.is_present("delete");

    let conn =
        rs::Connection::open_with_flags(Path::new(filename), rs::OpenFlags::SQLITE_OPEN_READ_WRITE)
            .expect(&format!("Connection error: {}", filename));

    let mut stmt = conn.prepare("SELECT id, by_whom_name, for_what_name, amount FROM votes")?;
    let vote_iter = stmt.query_map(rs::params![], |row| {
        Ok(Vote {
            id: row.get(0)?,
            by_whom_name: row.get(1)?,
            for_what_name: row.get(2)?,
            amount: row.get(3)?,
        })
    })?;

    // Time to compute the run
    let mut runs = Vec::new();

    let mut start_run_vote = None;
    let mut prev_vote = None;
    let mut count = 0;

    for rvote in vote_iter {
        let vote = rvote?;

        match (&start_run_vote, &prev_vote) {
            (None, None) => {
                start_run_vote = Some(vote.clone());
                prev_vote = Some(vote);
                count = 1; // Run of 1
            }
            (Some(srv), Some(pv)) => {
                if pv == &vote {
                    // Current vote + prev vote are the same, inc prev vote
                    prev_vote = Some(vote);
                    count += 1;
                } else {
                    // Current vote != prev vote, record the run, and reset
                    runs.push(get_run_val(srv, pv, count));

                    start_run_vote = Some(vote.clone());
                    prev_vote = Some(vote);
                    count = 1; // Run of 1
                }
            }
            (_, _) => panic!("Shouldn't happen"),
        };
    }

    // Record the last run
    runs.push(get_run_val(
        &start_run_vote.unwrap(),
        &prev_vote.unwrap(),
        count,
    ));

    if delete {
        // Scan and delete the offenders
        let mut stmt = conn.prepare("DELETE FROM votes WHERE id >= ? and id <= ?")?;
        for r in &runs {
            if r.count > min {
                let deleted = stmt.execute(rs::params![r.oldest_id, r.newest_id])?;

                if (r.count as usize) != deleted {
                    panic!("Expected: {} to be deleted, got {}", r.count, deleted);
                }
            }
        }
    } else {
        // Now we can scan for anything that > min and print them
        println!(
            "{: >8}, {: >8}, {: >14.14}, {: >14.14}, {: >6}, {: >5}",
            "start_id", "end_id", "by_whom_name", "for_what_name", "amount", "count"
        );
        for r in &runs {
            if r.count > min {
                println!(
                    "{: >8}, {: >8}, {: >14.14}, {: >14.14}, {: >6}, {: >5}",
                    r.oldest_id,
                    r.newest_id,
                    r.by_whom_name,
                    r.for_what_name,
                    str_amount(r.amount),
                    r.count
                );
            }
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>use std::io::prelude::*;
use std::fs;
use std::path;

use rustc_serialize::json;
use rustc_serialize::{Decodable, Encodable};

use super::VaultStorage;
use super::StorageResult;
use super::StorageResultOption;

pub struct Storage {
    pub path: &'static str
}

impl Storage {

    fn ensure_storage_path(&self, key: &String) -> StorageResult<path::PathBuf> {
        let mut path = path::PathBuf::from(self.path);
        path.push(key);
        path.push(key[0..2].to_string());
        path.push(key[2..4].to_string());
        path.push(key[4..6].to_string());
        fs::create_dir_all(&path)?;
        path.push(key);
        path.set_extension("json");
        Ok(path)
    }

}

impl VaultStorage for Storage {

    fn dump<T: Encodable>(&self, id: &String, storable: T) -> StorageResult<()> {
        let path = self.ensure_storage_path(id)?;
        let mut storage = fs::File::create(&path)?;
        storage.write_all(json::encode(&storable).unwrap().as_bytes())?;
        Ok(())
    }

    fn delete(&self, id: &String) -> StorageResultOption<()> {
        let path = self.ensure_storage_path(id)?;
        if !(path.exists()) { return Ok(None) };
        fs::remove_file(path)?;
        Ok(Some(()))
    }

    fn load<T: Decodable>(&self, id: &String) -> StorageResultOption<T> {
        let path = self.ensure_storage_path(id)?;
        if !(path.exists()) { return Ok(None) };
        let mut storage = fs::File::open(&path)?;
        let mut string = String::new();
        storage.read_to_string(&mut string)?;
        Ok(Some(json::decode(&string)?))
    }
}<commit_msg>Fix file storage.<commit_after>use std::io::prelude::*;
use std::fs;
use std::path;

use rustc_serialize::json;
use rustc_serialize::{Decodable, Encodable};

use super::VaultStorage;
use super::StorageResult;
use super::StorageResultOption;

pub struct Storage {
    pub path: &'static str
}

impl Storage {

    fn ensure_storage_path(&self, key: &String) -> StorageResult<path::PathBuf> {
        let mut path = path::PathBuf::from(self.path);
        path.push(key[0..2].to_string());
        path.push(key[2..4].to_string());
        path.push(key[4..6].to_string());
        fs::create_dir_all(&path)?;
        path.push(key);
        path.set_extension("json");
        Ok(path)
    }

}

impl VaultStorage for Storage {

    fn dump<T: Encodable>(&self, id: &String, storable: T) -> StorageResult<()> {
        let path = self.ensure_storage_path(id)?;
        let mut storage = fs::File::create(&path)?;
        storage.write_all(json::encode(&storable).unwrap().as_bytes())?;
        Ok(())
    }

    fn delete(&self, id: &String) -> StorageResultOption<()> {
        let path = self.ensure_storage_path(id)?;
        if !(path.exists()) { return Ok(None) };
        fs::remove_file(path)?;
        Ok(Some(()))
    }

    fn load<T: Decodable>(&self, id: &String) -> StorageResultOption<T> {
        let path = self.ensure_storage_path(id)?;
        if !(path.exists()) { return Ok(None) };
        let mut storage = fs::File::open(&path)?;
        let mut string = String::new();
        storage.read_to_string(&mut string)?;
        Ok(Some(json::decode(&string)?))
    }
}<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-flags: -C no-prepopulate-passes
// ignore-tidy-linelength

#![crate_type = "lib"]

// Below, these constants are defined as enum variants that by itself would
// have a lower alignment than the enum type. Ensure that we mark them
// correctly with the higher alignment of the enum.

// CHECK: @STATIC = {{.*}}, align 4

// This checks the constants from inline_enum_const
// CHECK: @byte_str.{{[0-9]+}} = {{.*}}, align 2

// This checks the constants from {low,high}_align_const, they share the same
// constant, but the alignment differs, so the higher one should be used
// CHECK: [[LOW_HIGH:@byte_str.[0-9]+]] = {{.*}}, align 4

#[derive(Copy, Clone)]

// repr(i16) is required for the {low,high}_align_const test
#[repr(i16)]
pub enum E<A, B> {
    A(A),
    B(B),
}

#[no_mangle]
pub static STATIC: E<i16, i32> = E::A(0);

// CHECK-LABEL: @static_enum_const
#[no_mangle]
pub fn static_enum_const() -> E<i16, i32> {
   STATIC
}

// CHECK-LABEL: @inline_enum_const
#[no_mangle]
pub fn inline_enum_const() -> E<i8, i16> {
    *&E::A(0)
}

// CHECK-LABEL: @low_align_const
#[no_mangle]
pub fn low_align_const() -> E<i16, [i16; 3]> {
// Check that low_align_const and high_align_const use the same constant
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), i64 8, i32 2, i1 false)
    *&E::A(0)
}

// CHECK-LABEL: @high_align_const
#[no_mangle]
pub fn high_align_const() -> E<i16, i32> {
// Check that low_align_const and high_align_const use the same constant
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), i64 8, i32 4, i1 false)
    *&E::A(0)
}
<commit_msg>Adjust test which differs between 32 bit and 64 bit<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-flags: -C no-prepopulate-passes
// ignore-tidy-linelength

#![crate_type = "lib"]

// Below, these constants are defined as enum variants that by itself would
// have a lower alignment than the enum type. Ensure that we mark them
// correctly with the higher alignment of the enum.

// CHECK: @STATIC = {{.*}}, align 4

// This checks the constants from inline_enum_const
// CHECK: @byte_str.{{[0-9]+}} = {{.*}}, align 2

// This checks the constants from {low,high}_align_const, they share the same
// constant, but the alignment differs, so the higher one should be used
// CHECK: [[LOW_HIGH:@byte_str.[0-9]+]] = {{.*}}, align 4

#[derive(Copy, Clone)]

// repr(i16) is required for the {low,high}_align_const test
#[repr(i16)]
pub enum E<A, B> {
    A(A),
    B(B),
}

#[no_mangle]
pub static STATIC: E<i16, i32> = E::A(0);

// CHECK-LABEL: @static_enum_const
#[no_mangle]
pub fn static_enum_const() -> E<i16, i32> {
   STATIC
}

// CHECK-LABEL: @inline_enum_const
#[no_mangle]
pub fn inline_enum_const() -> E<i8, i16> {
    *&E::A(0)
}

// CHECK-LABEL: @low_align_const
#[no_mangle]
pub fn low_align_const() -> E<i16, [i16; 3]> {
// Check that low_align_const and high_align_const use the same constant
// CHECK: i8* getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0),
    *&E::A(0)
}

// CHECK-LABEL: @high_align_const
#[no_mangle]
pub fn high_align_const() -> E<i16, i32> {
// Check that low_align_const and high_align_const use the same constant
// CHECK: i8* getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0),
    *&E::A(0)
}
<|endoftext|>


<commit_before>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Confirm that we don't accidently divide or mod by zero in llvm_type

// compile-pass

#![feature(test)]

mod a {
    pub trait A {}
}

mod b {
    pub struct Builder {}

    pub fn new() -> Builder {
        Builder {}
    }

    impl Builder {
        pub fn with_a(&mut self, _a: fn() -> ::a::A) {}
    }
}

pub use self::b::new;

fn main() {}
<commit_msg>remove feature line from test<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Confirm that we don't accidently divide or mod by zero in llvm_type

// compile-pass

mod a {
    pub trait A {}
}

mod b {
    pub struct Builder {}

    pub fn new() -> Builder {
        Builder {}
    }

    impl Builder {
        pub fn with_a(&mut self, _a: fn() -> ::a::A) {}
    }
}

pub use self::b::new;

fn main() {}
<|endoftext|>


<commit_before>use chrono::*;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use std::fmt;
use timeclock::direction::Direction;

static DATETIMEFMT: &'static str = "%Y-%m-%dT%H:%M:%S%z";

fn fmt_datetime(time: DateTime<FixedOffset>) -> String {
    let dr = time.format(DATETIMEFMT);
    format!("{}", dr)
}

fn parse_datetime(s: &str) -> ParseResult<DateTime<FixedOffset>> {
    DateTime::parse_from_str(s, DATETIMEFMT)
}

#[derive(Clone,Debug,PartialEq)]
pub struct TimeEntry {
    pub dir: Direction,
    pub time: DateTime<FixedOffset>,
    pub memo: String,
}

impl TimeEntry {
    #[allow(dead_code)]
    pub fn new(dir: Direction,
               time: DateTime<FixedOffset>,
               memo: &str)
               -> Self {
        TimeEntry {
            dir: dir,
            time: time,
            memo: memo.to_owned(),
        }
    }
}

impl Encodable for TimeEntry {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_struct("TimeEntry", 3, |s| {
            try!(s.emit_struct_field("dir", 0, |s| self.dir.encode(s)));
            try!(s.emit_struct_field("time", 1, |s| {
                return s.emit_str(fmt_datetime(self.time).as_ref());
            }));
            try!(s.emit_struct_field("memo", 2, |s| self.memo.encode(s)));
            Ok(())
        })
    }
}

impl Decodable for TimeEntry {
    fn decode<D: Decoder>(d: &mut D) -> Result<TimeEntry, D::Error> {
        d.read_struct("TimeEntry", 0, |d| {
            Ok(TimeEntry {
                dir: try!(d.read_struct_field("dir", 0, |d|
                        Decodable::decode(d))),
                time: {
                    let a_str: String = try!(d.read_struct_field("time", 0,
                            |d| d.read_str()));
                    let es = format!("Can't parse {}", a_str);
                    let dt = parse_datetime(&a_str);
                    match dt {
                        Ok(d) => d,
                        Err(_) => return Err(d.error(&es)),
                    }
                },
                memo: try!(d.read_struct_field("memo", 0, |d|
                        Decodable::decode(d))),
            })
        })
    }
}

impl fmt::Display for TimeEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let time = self.time.format("%F %I:%M %P");
        f.write_fmt(format_args!("{:3} {} {}", self.dir, time, self.memo))
    }
}

#[derive(Debug,PartialEq)]
pub struct TimeEntryPair {
    start: TimeEntry,
    end: TimeEntry,
}

impl TimeEntryPair {
    pub fn new(s: TimeEntry, e: TimeEntry) -> Self {
        TimeEntryPair { start: s, end: e }
    }

    pub fn start(&self) -> &TimeEntry {
        &self.start
    }

    pub fn end(&self) -> &TimeEntry {
        &self.end
    }
}

#[cfg(test)]
mod tests {
    use csv;
    use std::io::Cursor;
    use super::*;
    use timeclock::direction::Direction;
    use timeclock::now;
    use timeclock::timeentry::{fmt_datetime, parse_datetime};

    #[test]
    fn timeentry_constructor_test() {
        let time = now();
        let te = TimeEntry::new(Direction::In, time, "Memo");
        assert_eq!(te.dir, Direction::In);
        assert_eq!(te.time, time);
        assert_eq!(te.memo, "Memo");
    }

    #[test]
    fn encode_timeentry_test() {
        let mut wtr = csv::Writer::from_memory();
        let timenow = now();
        let expected = format!("In,{},test memo\n", fmt_datetime(timenow));
        let _ = wtr.encode(TimeEntry {
            dir: Direction::In,
            time: timenow,
            memo: "test memo".to_owned(),
        });
        assert!(wtr.as_string() == expected);
    }

    #[test]
    fn decode_timeentry_test() {
        let timestr = "2017-01-05T14:04:16-0600";
        let expected_time = parse_datetime(timestr).unwrap();
        let memo = "test memo";
        let s = format!("In,{0:},{1:}\nOut,{0:},{1:}\n", timestr, memo);
        let vs = s.as_bytes();
        let buff = Cursor::new(vs);
        let mut rdr = csv::Reader::from_reader(buff).has_headers(false);
        let records =
            rdr.decode().collect::<csv::Result<Vec<TimeEntry>>>().unwrap();

        assert!(records[0].dir == Direction::In);
        assert!(records[1].dir == Direction::Out);
        assert!(records[0].time == expected_time);
        assert!(records[1].time == expected_time);
        assert!(records[0].memo == memo);
        assert!(records[1].memo == memo);
        assert!(records.len() == 2);
    }
}<commit_msg>Removed dead_code attribute on TimeEntry::new<commit_after>use chrono::*;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use std::fmt;
use timeclock::direction::Direction;

static DATETIMEFMT: &'static str = "%Y-%m-%dT%H:%M:%S%z";

fn fmt_datetime(time: DateTime<FixedOffset>) -> String {
    let dr = time.format(DATETIMEFMT);
    format!("{}", dr)
}

fn parse_datetime(s: &str) -> ParseResult<DateTime<FixedOffset>> {
    DateTime::parse_from_str(s, DATETIMEFMT)
}

#[derive(Clone,Debug,PartialEq)]
pub struct TimeEntry {
    pub dir: Direction,
    pub time: DateTime<FixedOffset>,
    pub memo: String,
}

impl TimeEntry {
    pub fn new(dir: Direction,
               time: DateTime<FixedOffset>,
               memo: &str)
               -> Self {
        TimeEntry {
            dir: dir,
            time: time,
            memo: memo.to_owned(),
        }
    }
}

impl Encodable for TimeEntry {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_struct("TimeEntry", 3, |s| {
            try!(s.emit_struct_field("dir", 0, |s| self.dir.encode(s)));
            try!(s.emit_struct_field("time", 1, |s| {
                return s.emit_str(fmt_datetime(self.time).as_ref());
            }));
            try!(s.emit_struct_field("memo", 2, |s| self.memo.encode(s)));
            Ok(())
        })
    }
}

impl Decodable for TimeEntry {
    fn decode<D: Decoder>(d: &mut D) -> Result<TimeEntry, D::Error> {
        d.read_struct("TimeEntry", 0, |d| {
            Ok(TimeEntry {
                dir: try!(d.read_struct_field("dir", 0, |d|
                        Decodable::decode(d))),
                time: {
                    let a_str: String = try!(d.read_struct_field("time", 0,
                            |d| d.read_str()));
                    let es = format!("Can't parse {}", a_str);
                    let dt = parse_datetime(&a_str);
                    match dt {
                        Ok(d) => d,
                        Err(_) => return Err(d.error(&es)),
                    }
                },
                memo: try!(d.read_struct_field("memo", 0, |d|
                        Decodable::decode(d))),
            })
        })
    }
}

impl fmt::Display for TimeEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let time = self.time.format("%F %I:%M %P");
        f.write_fmt(format_args!("{:3} {} {}", self.dir, time, self.memo))
    }
}

#[derive(Debug,PartialEq)]
pub struct TimeEntryPair {
    start: TimeEntry,
    end: TimeEntry,
}

impl TimeEntryPair {
    pub fn new(s: TimeEntry, e: TimeEntry) -> Self {
        TimeEntryPair { start: s, end: e }
    }

    pub fn start(&self) -> &TimeEntry {
        &self.start
    }

    pub fn end(&self) -> &TimeEntry {
        &self.end
    }
}

#[cfg(test)]
mod tests {
    use csv;
    use std::io::Cursor;
    use super::*;
    use timeclock::direction::Direction;
    use timeclock::now;
    use timeclock::timeentry::{fmt_datetime, parse_datetime};

    #[test]
    fn timeentry_constructor_test() {
        let time = now();
        let te = TimeEntry::new(Direction::In, time, "Memo");
        assert_eq!(te.dir, Direction::In);
        assert_eq!(te.time, time);
        assert_eq!(te.memo, "Memo");
    }

    #[test]
    fn encode_timeentry_test() {
        let mut wtr = csv::Writer::from_memory();
        let timenow = now();
        let expected = format!("In,{},test memo\n", fmt_datetime(timenow));
        let _ = wtr.encode(TimeEntry {
            dir: Direction::In,
            time: timenow,
            memo: "test memo".to_owned(),
        });
        assert!(wtr.as_string() == expected);
    }

    #[test]
    fn decode_timeentry_test() {
        let timestr = "2017-01-05T14:04:16-0600";
        let expected_time = parse_datetime(timestr).unwrap();
        let memo = "test memo";
        let s = format!("In,{0:},{1:}\nOut,{0:},{1:}\n", timestr, memo);
        let vs = s.as_bytes();
        let buff = Cursor::new(vs);
        let mut rdr = csv::Reader::from_reader(buff).has_headers(false);
        let records =
            rdr.decode().collect::<csv::Result<Vec<TimeEntry>>>().unwrap();

        assert!(records[0].dir == Direction::In);
        assert!(records[1].dir == Direction::Out);
        assert!(records[0].time == expected_time);
        assert!(records[1].time == expected_time);
        assert!(records[0].memo == memo);
        assert!(records[1].memo == memo);
        assert!(records.len() == 2);
    }
}<|endoftext|>


<commit_before>use color::PuyoColor;

#[derive(Clone, Debug, PartialEq)]
pub struct ColumnPuyo {
    x: usize,
    color: PuyoColor,
}

impl ColumnPuyo {
    pub fn new(x: usize, color: PuyoColor) -> ColumnPuyo {
        ColumnPuyo {
            x: x,
            color: color,
        }
    }

    pub fn x(&self) -> usize {
        self.x
    }

    pub fn color(&self) -> PuyoColor {
        self.color
    }

    pub fn valid(&self) -> bool {
        0 < self.x && self.x < 7
    }
}

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

    #[test]
    fn test_is_valid() {
        assert!(!ColumnPuyo::new(0, PuyoColor::EMPTY).valid());
        assert!(ColumnPuyo::new(1, PuyoColor::EMPTY).valid());
        assert!(ColumnPuyo::new(2, PuyoColor::EMPTY).valid());
        assert!(ColumnPuyo::new(3, PuyoColor::EMPTY).valid());
        assert!(ColumnPuyo::new(4, PuyoColor::EMPTY).valid());
        assert!(ColumnPuyo::new(5, PuyoColor::EMPTY).valid());
        assert!(ColumnPuyo::new(6, PuyoColor::EMPTY).valid());
        assert!(!ColumnPuyo::new(7, PuyoColor::EMPTY).valid());
    }
}
<commit_msg>:white_check_mark: Use documentation test in ColumnPuyo<commit_after>use color::PuyoColor;

#[derive(Clone, Debug, PartialEq)]
pub struct ColumnPuyo {
    x: usize,
    color: PuyoColor,
}

impl ColumnPuyo {
    pub fn new(x: usize, color: PuyoColor) -> ColumnPuyo {
        ColumnPuyo {
            x: x,
            color: color,
        }
    }

    pub fn x(&self) -> usize {
        self.x
    }

    pub fn color(&self) -> PuyoColor {
        self.color
    }

    /// Returns true if ColumnPuyo is valid. x should be 0 < x < 7.
    ///
    /// ```
    /// use puyocore::color::PuyoColor;
    /// use puyocore::column_puyo::ColumnPuyo;
    /// let cp0 = ColumnPuyo::new(0, PuyoColor::RED);
    /// let cp1 = ColumnPuyo::new(1, PuyoColor::RED);
    /// let cp6 = ColumnPuyo::new(1, PuyoColor::RED);
    /// let cp7 = ColumnPuyo::new(7, PuyoColor::RED);
    /// assert!(!cp0.valid());
    /// assert!(cp1.valid());
    /// assert!(cp6.valid());
    /// assert!(!cp7.valid());
    /// ```
    pub fn valid(&self) -> bool {
        0 < self.x && self.x < 7
    }
}
<|endoftext|>


<commit_before>extern crate gtk;
extern crate cairo;

extern crate ffmpeg;

use std::ops::{Deref, DerefMut};

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

use gtk::prelude::*;
use cairo::enums::{FontSlant, FontWeight};

use ffmpeg::format::stream::disposition::ATTACHED_PIC;

use ::media::Context;
use ::media::PacketNotifiable;

use super::MediaNotifiable;
use super::MediaController;

fn ffmpeg_pixel_format_to_cairo(ffmpeg_px: ffmpeg::format::Pixel) -> cairo::Format {
    match ffmpeg_px {
        ffmpeg::format::Pixel::ARGB => cairo::Format::ARgb32,
        ffmpeg::format::Pixel::RGB24 => cairo::Format::Rgb24,
        ffmpeg::format::Pixel::RGB565LE => cairo::Format::Rgb16_565,
        _ => cairo::Format::Invalid,
    }
}

pub struct VideoController {
    media_ctl: MediaController,
    drawingarea: gtk::DrawingArea,
    message: String,
    frame: Option<ffmpeg::frame::Video>,
}

impl VideoController {
    pub fn new(builder: &gtk::Builder) -> Rc<RefCell<VideoController>> {
        // need a RefCell because the callbacks will use immutable versions of vc
        // when the UI controllers will get a mutable version from time to time
        let vc = Rc::new(RefCell::new(VideoController {
            media_ctl: MediaController::new(builder.get_object("video-container").unwrap()),
            drawingarea: builder.get_object("video-drawingarea").unwrap(),
            message: "video place holder".to_owned(),
            frame: None,
        }));

        let vc_for_cb = vc.clone();
        vc.borrow().drawingarea.connect_draw(move |_, cairo_ctx| {
            vc_for_cb.borrow().draw(&cairo_ctx);
            Inhibit(false)
        });

        vc
    }

    fn convert_to_rgb(&mut self, frame_in: &mut ffmpeg::frame::Video, time_base:
                      ffmpeg::Rational) -> Result<(ffmpeg::frame::Video), String> {
        let mut graph = ffmpeg::filter::Graph::new();
        let in_filter;
        match ffmpeg::filter::find("buffer") {
            Some(value) => in_filter = value,
            None => return Err("Couldn't get buffer".to_owned()),
        }

        // Fix deprecated formats
        let in_format = match frame_in.format() {
            ffmpeg::format::Pixel::YUVJ420P => ffmpeg::format::Pixel::YUV420P,
            ffmpeg::format::Pixel::YUVJ422P => ffmpeg::format::Pixel::YUV422P,
            ffmpeg::format::Pixel::YUVJ444P => ffmpeg::format::Pixel::YUV444P,
            ffmpeg::format::Pixel::YUVJ440P => ffmpeg::format::Pixel::YUV440P,
            other => other,
        };
        frame_in.set_format(in_format);
        let in_format_str = format!("{:?}", in_format).to_lowercase();
        let args = format!("width={}:height={}:pix_fmt={}:time_base={}:pixel_aspect={}",
                           frame_in.width(), frame_in.height(), in_format_str,
                           time_base, frame_in.aspect_ratio());
        println!("pad in args: {}", args);
        match graph.add(&in_filter, "in", &args) {
            Ok(_) => (),
            Err(error) => return Err(format!("Error adding in pad: {:?}", error)),
        }

        let out_filter;
        match ffmpeg::filter::find("buffersink") {
            Some(value) => out_filter = value,
            None => return Err("Couldn't get buffersink".to_owned()),
        }
        match graph.add(&out_filter, "out", "") {
            Ok(_) => (),
            Err(error) => return Err(format!("Error adding out pad: {:?}", error)),
        }
        {
            let mut out_pad = graph.get("out").unwrap();
            out_pad.set_pixel_format(ffmpeg::format::Pixel::RGB565LE);
        }

        {
            let in_parser;
            match graph.output("in", 0) {
                Ok(value) => in_parser = value,
                Err(error) => return Err(format!("Error getting output for in pad: {:?}", error)),
            }
            let out_parser;
            match in_parser.input("out", 0) {
                Ok(value) => out_parser = value,
                Err(error) => return Err(format!("Error getting input for out pad: {:?}", error)),
            }
            match out_parser.parse("copy") {
                Ok(_) => (),
                Err(error) => return Err(format!("Error parsing format: {:?}", error)),
            }
        }

        match graph.validate() {
            Ok(_) => (),
            Err(error) => return Err(format!("Error validating graph: {:?}", error)),
        }

        //println!("{}", graph.dump());

        graph.get("in").unwrap().source().add(&frame_in).unwrap();

        let mut frame_rgb = ffmpeg::frame::Video::empty();
		while let Ok(..) = graph.get("out").unwrap().sink().frame(&mut frame_rgb) {
        }

        Ok(frame_rgb)
    }

    fn draw(&self, cr: &cairo::Context) {
        let allocation = self.drawingarea.get_allocation();

        match self.frame {
            Some(ref frame) => {
                let planes = frame.planes();
                if planes > 0 {
                    /*
                    println!("format: {:?}, width: {}, stride: {}",
                             frame.format(), frame.width(), frame.stride(0));
                    let test_surface = cairo::ImageSurface::create(
                            ffmpeg_pixel_format_to_cairo(frame.format()),
                            frame.width() as i32, frame.height() as i32
                        );
                    println!("expected stride: {}", test_surface.get_stride());
                    */

                    let surface = cairo::ImageSurface::create_for_data(
                            frame.data(0).to_vec().into_boxed_slice(), |_| {},
                            ffmpeg_pixel_format_to_cairo(frame.format()),
                            frame.width() as i32, frame.height() as i32,
                            frame.stride(0) as i32
                        );

                    let x;
                    let y;
                    let mut width_scale = allocation.width as f64 / surface.get_width() as f64;
                    let mut height_scale = allocation.height as f64 / surface.get_height() as f64;
                    let ratio = width_scale / height_scale;
                    if ratio > 0f64 {
                        width_scale /= ratio;
                        x = (allocation.width as f64 - width_scale * (surface.get_width() as f64)).abs();
                        y = 0f64;
                    }
                    else {
                        height_scale /= ratio;
                        x = 0f64;
                        y = (allocation.height as f64 - height_scale * (surface.get_height() as f64)).abs();
                    }
                    println!("aw {}, ah {}, sw {}, sh {}, ratio {}, x {}, y {}",
                             allocation.width, allocation.height, surface.get_width(), surface.get_height(), ratio, x, y);
                    cr.scale(width_scale, height_scale);
                    cr.set_source_surface(&surface, x, y);
                    cr.paint();
                }
            },
            None => {
                cr.scale(allocation.width as f64, allocation.height as f64);
                cr.select_font_face("Sans", FontSlant::Normal, FontWeight::Normal);
                cr.set_font_size(0.07);

                cr.move_to(0.1, 0.53);
                cr.show_text(&self.message);
            },
        }
    }
}

impl Deref for VideoController {
	type Target = MediaController;

	fn deref(&self) -> &Self::Target {
		&self.media_ctl
	}
}

impl DerefMut for VideoController {
	fn deref_mut(&mut self) -> &mut Self::Target {
		&mut self.media_ctl
	}
}

impl MediaNotifiable for VideoController {
    fn new_media(&mut self, context: &mut Context) {
        self.frame = None;
        self.message = match context.video_stream.as_mut() {
            Some(stream) => {
                self.set_index(stream.index);

                self.show();
                println!("\n** Video stream\n{:?}", &stream);

                let stream_type;
                if stream.disposition | ATTACHED_PIC == ATTACHED_PIC {
                    stream_type = "image";
                }
                else {
                    stream_type = "video stream";
                }
                format!("{} {}", stream_type, self.stream_index().unwrap())
            },
            None => {
                self.hide();
                "no video stream".to_owned()
            },
        };

        self.drawingarea.queue_draw();
    }
}

impl PacketNotifiable for VideoController {
    fn new_packet(&mut self, stream: &ffmpeg::format::stream::Stream, packet: &ffmpeg::codec::packet::Packet) {
        self.print_packet_content(stream, packet);

        let decoder = stream.codec().decoder();
        match decoder.video() {
            Ok(mut video) => {
                let mut frame = ffmpeg::frame::Video::new(video.format(), video.width(), video.height());
                match video.decode(packet, &mut frame) {
                    Ok(result) => if result {
                            let planes = frame.planes();
                            if planes > 0 {
                                println!("\tdecoded video frame, data len: {}", frame.data(0).len());

                                match self.convert_to_rgb(&mut frame, video.time_base()) {
                                    Ok(frame_rgb) => {
                                        self.frame = Some(frame_rgb);
                                    }
                                    Err(error) =>  println!("\tError converting to rgb: {:?}", error),
                                }
                            }
                            else {
                                println!("\tno planes found in frame");
                            }
                        }
                        else {
                            println!("\tfailed to decode video frame");
                        }
                    ,
                    Err(error) => println!("Error decoding video: {:?}", error),
                }
            },
            Err(error) => println!("Error getting video decoder: {:?}", error),
        }
    }
}
<commit_msg>Fix video scale and position (#1)<commit_after>extern crate gtk;
extern crate cairo;

extern crate ffmpeg;

use std::ops::{Deref, DerefMut};

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

use gtk::prelude::*;
use cairo::enums::{FontSlant, FontWeight};

use ffmpeg::format::stream::disposition::ATTACHED_PIC;

use ::media::Context;
use ::media::PacketNotifiable;

use super::MediaNotifiable;
use super::MediaController;

fn ffmpeg_pixel_format_to_cairo(ffmpeg_px: ffmpeg::format::Pixel) -> cairo::Format {
    match ffmpeg_px {
        ffmpeg::format::Pixel::ARGB => cairo::Format::ARgb32,
        ffmpeg::format::Pixel::RGB24 => cairo::Format::Rgb24,
        ffmpeg::format::Pixel::RGB565LE => cairo::Format::Rgb16_565,
        _ => cairo::Format::Invalid,
    }
}

pub struct VideoController {
    media_ctl: MediaController,
    drawingarea: gtk::DrawingArea,
    message: String,
    frame: Option<ffmpeg::frame::Video>,
}

impl VideoController {
    pub fn new(builder: &gtk::Builder) -> Rc<RefCell<VideoController>> {
        // need a RefCell because the callbacks will use immutable versions of vc
        // when the UI controllers will get a mutable version from time to time
        let vc = Rc::new(RefCell::new(VideoController {
            media_ctl: MediaController::new(builder.get_object("video-container").unwrap()),
            drawingarea: builder.get_object("video-drawingarea").unwrap(),
            message: "video place holder".to_owned(),
            frame: None,
        }));

        let vc_for_cb = vc.clone();
        vc.borrow().drawingarea.connect_draw(move |_, cairo_ctx| {
            vc_for_cb.borrow().draw(&cairo_ctx);
            Inhibit(false)
        });

        vc
    }

    fn convert_to_rgb(&mut self, frame_in: &mut ffmpeg::frame::Video, time_base:
                      ffmpeg::Rational) -> Result<(ffmpeg::frame::Video), String> {
        let mut graph = ffmpeg::filter::Graph::new();
        let in_filter;
        match ffmpeg::filter::find("buffer") {
            Some(value) => in_filter = value,
            None => return Err("Couldn't get buffer".to_owned()),
        }

        // Fix deprecated formats
        let in_format = match frame_in.format() {
            ffmpeg::format::Pixel::YUVJ420P => ffmpeg::format::Pixel::YUV420P,
            ffmpeg::format::Pixel::YUVJ422P => ffmpeg::format::Pixel::YUV422P,
            ffmpeg::format::Pixel::YUVJ444P => ffmpeg::format::Pixel::YUV444P,
            ffmpeg::format::Pixel::YUVJ440P => ffmpeg::format::Pixel::YUV440P,
            other => other,
        };
        frame_in.set_format(in_format);
        let in_format_str = format!("{:?}", in_format).to_lowercase();
        let args = format!("width={}:height={}:pix_fmt={}:time_base={}:pixel_aspect={}",
                           frame_in.width(), frame_in.height(), in_format_str,
                           time_base, frame_in.aspect_ratio());
        println!("pad in args: {}", args);
        match graph.add(&in_filter, "in", &args) {
            Ok(_) => (),
            Err(error) => return Err(format!("Error adding in pad: {:?}", error)),
        }

        let out_filter;
        match ffmpeg::filter::find("buffersink") {
            Some(value) => out_filter = value,
            None => return Err("Couldn't get buffersink".to_owned()),
        }
        match graph.add(&out_filter, "out", "") {
            Ok(_) => (),
            Err(error) => return Err(format!("Error adding out pad: {:?}", error)),
        }
        {
            let mut out_pad = graph.get("out").unwrap();
            out_pad.set_pixel_format(ffmpeg::format::Pixel::RGB565LE);
        }

        {
            let in_parser;
            match graph.output("in", 0) {
                Ok(value) => in_parser = value,
                Err(error) => return Err(format!("Error getting output for in pad: {:?}", error)),
            }
            let out_parser;
            match in_parser.input("out", 0) {
                Ok(value) => out_parser = value,
                Err(error) => return Err(format!("Error getting input for out pad: {:?}", error)),
            }
            match out_parser.parse("copy") {
                Ok(_) => (),
                Err(error) => return Err(format!("Error parsing format: {:?}", error)),
            }
        }

        match graph.validate() {
            Ok(_) => (),
            Err(error) => return Err(format!("Error validating graph: {:?}", error)),
        }

        //println!("{}", graph.dump());

        graph.get("in").unwrap().source().add(&frame_in).unwrap();

        let mut frame_rgb = ffmpeg::frame::Video::empty();
		while let Ok(..) = graph.get("out").unwrap().sink().frame(&mut frame_rgb) {
        }

        Ok(frame_rgb)
    }

    fn draw(&self, cr: &cairo::Context) {
        let allocation = self.drawingarea.get_allocation();

        match self.frame {
            Some(ref frame) => {
                let planes = frame.planes();
                if planes > 0 {
                    /*
                    println!("format: {:?}, width: {}, stride: {}",
                             frame.format(), frame.width(), frame.stride(0));
                    let test_surface = cairo::ImageSurface::create(
                            ffmpeg_pixel_format_to_cairo(frame.format()),
                            frame.width() as i32, frame.height() as i32
                        );
                    println!("expected stride: {}", test_surface.get_stride());
                    */

                    let surface = cairo::ImageSurface::create_for_data(
                            frame.data(0).to_vec().into_boxed_slice(), |_| {},
                            ffmpeg_pixel_format_to_cairo(frame.format()),
                            frame.width() as i32, frame.height() as i32,
                            frame.stride(0) as i32
                        );

                    let scale;
                    let alloc_ratio = allocation.width as f64 / allocation.height as f64;
                    let surface_ratio = surface.get_width() as f64 / surface.get_height() as f64;
                    if surface_ratio < alloc_ratio {
                        scale = allocation.height as f64 / surface.get_height() as f64;
                    }
                    else {
                        scale = allocation.width as f64 / surface.get_width() as f64;
                    }
                    let x = (allocation.width as f64 / scale - surface.get_width() as f64).abs() / 2f64;
                    let y = (allocation.height as f64 / scale - surface.get_height() as f64).abs() / 2f64;

                    cr.scale(scale, scale);
                    cr.set_source_surface(&surface, x, y);
                    cr.paint();
                }
            },
            None => {
                cr.scale(allocation.width as f64, allocation.height as f64);
                cr.select_font_face("Sans", FontSlant::Normal, FontWeight::Normal);
                cr.set_font_size(0.07);

                cr.move_to(0.1, 0.53);
                cr.show_text(&self.message);
            },
        }
    }
}

impl Deref for VideoController {
	type Target = MediaController;

	fn deref(&self) -> &Self::Target {
		&self.media_ctl
	}
}

impl DerefMut for VideoController {
	fn deref_mut(&mut self) -> &mut Self::Target {
		&mut self.media_ctl
	}
}

impl MediaNotifiable for VideoController {
    fn new_media(&mut self, context: &mut Context) {
        self.frame = None;
        self.message = match context.video_stream.as_mut() {
            Some(stream) => {
                self.set_index(stream.index);

                self.show();
                println!("\n** Video stream\n{:?}", &stream);

                let stream_type;
                if stream.disposition | ATTACHED_PIC == ATTACHED_PIC {
                    stream_type = "image";
                }
                else {
                    stream_type = "video stream";
                }
                format!("{} {}", stream_type, self.stream_index().unwrap())
            },
            None => {
                self.hide();
                "no video stream".to_owned()
            },
        };

        self.drawingarea.queue_draw();
    }
}

impl PacketNotifiable for VideoController {
    fn new_packet(&mut self, stream: &ffmpeg::format::stream::Stream, packet: &ffmpeg::codec::packet::Packet) {
        self.print_packet_content(stream, packet);

        let decoder = stream.codec().decoder();
        match decoder.video() {
            Ok(mut video) => {
                let mut frame = ffmpeg::frame::Video::new(video.format(), video.width(), video.height());
                match video.decode(packet, &mut frame) {
                    Ok(result) => if result {
                            let planes = frame.planes();
                            if planes > 0 {
                                println!("\tdecoded video frame, data len: {}", frame.data(0).len());

                                match self.convert_to_rgb(&mut frame, video.time_base()) {
                                    Ok(frame_rgb) => {
                                        self.frame = Some(frame_rgb);
                                    }
                                    Err(error) =>  println!("\tError converting to rgb: {:?}", error),
                                }
                            }
                            else {
                                println!("\tno planes found in frame");
                            }
                        }
                        else {
                            println!("\tfailed to decode video frame");
                        }
                    ,
                    Err(error) => println!("Error decoding video: {:?}", error),
                }
            },
            Err(error) => println!("Error getting video decoder: {:?}", error),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use rocksdb::DBCompressionType;

pub fn get_compression_by_string(tp: &str) -> DBCompressionType {
    match &*tp.to_owned().to_lowercase() {
        "no" => DBCompressionType::DBNo,
        "snappy" => DBCompressionType::DBSnappy,
        "zlib" => DBCompressionType::DBZlib,
        "bzip2" => DBCompressionType::DBBz2,
        "lz4" => DBCompressionType::DBLz4,
        "lz4hc" => DBCompressionType::DBLz4hc,
        _ => DBCompressionType::DBNo,
    }
}
<commit_msg>util: make clippy happy. (#623)<commit_after>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use rocksdb::DBCompressionType;

pub fn get_compression_by_string(tp: &str) -> DBCompressionType {
    match &*tp.to_owned().to_lowercase() {
        "no" => DBCompressionType::DBNo,
        "snappy" => DBCompressionType::DBSnappy,
        "zlib" => DBCompressionType::DBZlib,
        "bzip2" => DBCompressionType::DBBz2,
        "lz4" => DBCompressionType::DBLz4,
        "lz4hc" => DBCompressionType::DBLz4hc,
        _ => panic!("unsupported compression type {}", tp),
    }
}
<|endoftext|>


<commit_before>use Cursive;
use With;
use event::{Callback, Event, EventResult};
use std::collections::HashMap;
use std::rc::Rc;
use view::{View, ViewWrapper};

/// A wrapper view that can react to events.
///
/// This view registers a set of callbacks tied to specific events, to be run
/// in certain conditions.
///
/// **Note**: only one callback can be registered per event. Trying to register
/// a new one will replace any existing one for that event.
///
/// * Some callbacks are called only for vents ignored by the wrapped view
///   (those registered by [`on_event`] or [`on_event_inner`])
/// * Others are processed first, and can control whether the child view should
///   be given the event (those registered by [`on_pre_event`] or
///   [`on_pre_event_inner`]).
///
/// "Inner" callbacks ([`on_event_inner`] and [`on_pre_event_inner`]) are given
/// a reference to the inner wrapped view (but not to the `Cursive` root). They
/// can then return another callback, taking only a `&mut Cursive` root as
/// argument.
///
/// "Simple" callbacks ([`on_event`] and [`on_pre_event`]) skip this first
/// phase and are only called with a `&mut Cursive`.
///
/// [`on_event`]: struct.OnEventView.html#method.on_event
/// [`on_pre_event`]: struct.OnEventView.html#method.on_pre_event
/// [`on_event_inner`]: struct.OnEventView.html#method.on_event_inner
/// [`on_pre_event_inner`]: struct.OnEventView.html#method.on_pre_event_inner
///
/// # Examples
///
/// ```
/// # use cursive::event;;
/// # use cursive::views::{OnEventView, TextView};
/// let view = OnEventView::new(TextView::new("This view has an event!"))
///                         .on_event('q', |s| s.quit())
///                         .on_event(event::Key::Esc, |s| s.quit());
/// ```
pub struct OnEventView<T: View> {
    inner: T,
    callbacks: HashMap<Event, Action<T>>,
}

type InnerCallback<T> = Rc<Box<Fn(&mut T) -> Option<EventResult>>>;

struct Action<T> {
    phase: TriggerPhase,
    callback: InnerCallback<T>,
}

impl<T> Clone for Action<T> {
    fn clone(&self) -> Self {
        Action {
            phase: self.phase.clone(),
            callback: Rc::clone(&self.callback),
        }
    }
}

#[derive(PartialEq, Clone)]
enum TriggerPhase {
    BeforeChild,
    AfterChild,
}

impl<T: View> OnEventView<T> {
    /// Wraps the given view in a new OnEventView.
    pub fn new(view: T) -> Self {
        OnEventView {
            inner: view,
            callbacks: HashMap::new(),
        }
    }

    /// Registers a callback when the given event is ignored by the child.
    ///
    /// Chainable variant.
    pub fn on_event<F, R, E>(self, event: E, cb: F) -> Self
    where
        E: Into<Event>,
        F: 'static + Fn(&mut Cursive) -> R,
    {
        self.with(|s| s.set_on_event(event, cb))
    }

    /// Registers a callback when the given event is received.
    ///
    /// The child will never receive this event.
    ///
    /// Chainable variant.
    pub fn on_pre_event<F, R, E>(self, event: E, cb: F) -> Self
    where
        E: Into<Event>,
        F: 'static + Fn(&mut Cursive) -> R,
    {
        self.with(|s| s.set_on_pre_event(event, cb))
    }

    /// Registers a callback when the given event is received.
    ///
    /// The given callback will be run before the child view sees the event.
    ///
    /// * If the result is `None`, then the child view is given the event as
    ///   usual.
    /// * Otherwise, it bypasses the child view and directly processes the
    ///   result.
    ///
    /// Chainable variant.
    pub fn on_pre_event_inner<F, E>(self, event: E, cb: F) -> Self
    where
        E: Into<Event>,
        F: Fn(&mut T) -> Option<EventResult> + 'static,
    {
        self.with(|s| s.set_on_pre_event_inner(event, cb))
    }

    /// Registers a callback when the given event is ignored by the child.
    ///
    /// If the child view ignores the event, `cb` will be called with the
    /// child view as argument.
    /// If the result is not `None`, it will be processed as well.
    ///
    /// Chainable variant.
    pub fn on_event_inner<F, E>(self, event: E, cb: F) -> Self
    where
        E: Into<Event>,
        F: Fn(&mut T) -> Option<EventResult> + 'static,
    {
        self.with(|s| s.set_on_event_inner(event, cb))
    }

    /// Registers a callback when the given event is ignored by the child.
    pub fn set_on_event<F, R, E>(&mut self, event: E, cb: F)
    where
        E: Into<Event>,
        F: Fn(&mut Cursive) -> R + 'static,
    {
        let cb = Callback::from_fn(cb);
        let action =
            move |_: &mut T| Some(EventResult::Consumed(Some(cb.clone())));

        self.set_on_event_inner(event, action);
    }

    /// Registers a callback when the given event is received.
    ///
    /// The child will never receive this event.
    pub fn set_on_pre_event<F, R, E>(&mut self, event: E, cb: F)
    where
        E: Into<Event>,
        F: 'static + Fn(&mut Cursive) -> R,
    {
        let cb = Callback::from_fn(cb);
        // We want to clone the Callback every time we call the closure
        let action =
            move |_: &mut T| Some(EventResult::Consumed(Some(cb.clone())));

        self.set_on_pre_event_inner(event, action);
    }

    /// Registers a callback when the given event is received.
    ///
    /// The given callback will be run before the child view sees the event.
    ///
    /// * If the result is `None`, then the child view is given the event as
    ///   usual.
    /// * Otherwise, it bypasses the child view and directly processes the
    ///   result.
    pub fn set_on_pre_event_inner<F, E>(&mut self, event: E, cb: F)
    where
        E: Into<Event>,
        F: Fn(&mut T) -> Option<EventResult> + 'static,
    {
        self.callbacks.insert(
            event.into(),
            Action {
                phase: TriggerPhase::BeforeChild,
                callback: Rc::new(Box::new(cb)),
            },
        );
    }

    /// Registers a callback when the given event is ignored by the child.
    ///
    /// If the child view ignores the event, `cb` will be called with the
    /// child view as argument.
    /// If the result is not `None`, it will be processed as well.
    pub fn set_on_event_inner<F, E>(&mut self, event: E, cb: F)
    where
        E: Into<Event>,
        F: Fn(&mut T) -> Option<EventResult> + 'static,
    {
        self.callbacks.insert(
            event.into(),
            Action {
                phase: TriggerPhase::AfterChild,
                callback: Rc::new(Box::new(cb)),
            },
        );
    }
}

impl<T: View> ViewWrapper for OnEventView<T> {
    wrap_impl!(self.inner: T);

    fn wrap_on_event(&mut self, event: Event) -> EventResult {
        let action = self.callbacks.get(&event).cloned();
        let pre_child = action
            .as_ref()
            .map(|a| a.phase == TriggerPhase::BeforeChild)
            .unwrap_or(false);

        if pre_child {
            action
                .and_then(|a| (*a.callback)(&mut self.inner))
                .unwrap_or_else(|| self.inner.on_event(event))
        } else {
            self.inner.on_event(event).or_else(|| {
                action
                    .and_then(|a| (*a.callback)(&mut self.inner))
                    .unwrap_or(EventResult::Ignored)
            })
        }
    }
}
<commit_msg>Change OnEventView.inner to OnEventView.view<commit_after>use Cursive;
use With;
use event::{Callback, Event, EventResult};
use std::collections::HashMap;
use std::rc::Rc;
use view::{View, ViewWrapper};

/// A wrapper view that can react to events.
///
/// This view registers a set of callbacks tied to specific events, to be run
/// in certain conditions.
///
/// **Note**: only one callback can be registered per event. Trying to register
/// a new one will replace any existing one for that event.
///
/// * Some callbacks are called only for vents ignored by the wrapped view
///   (those registered by [`on_event`] or [`on_event_inner`])
/// * Others are processed first, and can control whether the child view should
///   be given the event (those registered by [`on_pre_event`] or
///   [`on_pre_event_inner`]).
///
/// "Inner" callbacks ([`on_event_inner`] and [`on_pre_event_inner`]) are given
/// a reference to the inner wrapped view (but not to the `Cursive` root). They
/// can then return another callback, taking only a `&mut Cursive` root as
/// argument.
///
/// "Simple" callbacks ([`on_event`] and [`on_pre_event`]) skip this first
/// phase and are only called with a `&mut Cursive`.
///
/// [`on_event`]: struct.OnEventView.html#method.on_event
/// [`on_pre_event`]: struct.OnEventView.html#method.on_pre_event
/// [`on_event_inner`]: struct.OnEventView.html#method.on_event_inner
/// [`on_pre_event_inner`]: struct.OnEventView.html#method.on_pre_event_inner
///
/// # Examples
///
/// ```
/// # use cursive::event;;
/// # use cursive::views::{OnEventView, TextView};
/// let view = OnEventView::new(TextView::new("This view has an event!"))
///                         .on_event('q', |s| s.quit())
///                         .on_event(event::Key::Esc, |s| s.quit());
/// ```
pub struct OnEventView<T: View> {
    view: T,
    callbacks: HashMap<Event, Action<T>>,
}

type InnerCallback<T> = Rc<Box<Fn(&mut T) -> Option<EventResult>>>;

struct Action<T> {
    phase: TriggerPhase,
    callback: InnerCallback<T>,
}

impl<T> Clone for Action<T> {
    fn clone(&self) -> Self {
        Action {
            phase: self.phase.clone(),
            callback: Rc::clone(&self.callback),
        }
    }
}

#[derive(PartialEq, Clone)]
enum TriggerPhase {
    BeforeChild,
    AfterChild,
}

impl<T: View> OnEventView<T> {
    /// Wraps the given view in a new OnEventView.
    pub fn new(view: T) -> Self {
        OnEventView {
            view: view,
            callbacks: HashMap::new(),
        }
    }

    /// Registers a callback when the given event is ignored by the child.
    ///
    /// Chainable variant.
    pub fn on_event<F, R, E>(self, event: E, cb: F) -> Self
    where
        E: Into<Event>,
        F: 'static + Fn(&mut Cursive) -> R,
    {
        self.with(|s| s.set_on_event(event, cb))
    }

    /// Registers a callback when the given event is received.
    ///
    /// The child will never receive this event.
    ///
    /// Chainable variant.
    pub fn on_pre_event<F, R, E>(self, event: E, cb: F) -> Self
    where
        E: Into<Event>,
        F: 'static + Fn(&mut Cursive) -> R,
    {
        self.with(|s| s.set_on_pre_event(event, cb))
    }

    /// Registers a callback when the given event is received.
    ///
    /// The given callback will be run before the child view sees the event.
    ///
    /// * If the result is `None`, then the child view is given the event as
    ///   usual.
    /// * Otherwise, it bypasses the child view and directly processes the
    ///   result.
    ///
    /// Chainable variant.
    pub fn on_pre_event_inner<F, E>(self, event: E, cb: F) -> Self
    where
        E: Into<Event>,
        F: Fn(&mut T) -> Option<EventResult> + 'static,
    {
        self.with(|s| s.set_on_pre_event_inner(event, cb))
    }

    /// Registers a callback when the given event is ignored by the child.
    ///
    /// If the child view ignores the event, `cb` will be called with the
    /// child view as argument.
    /// If the result is not `None`, it will be processed as well.
    ///
    /// Chainable variant.
    pub fn on_event_inner<F, E>(self, event: E, cb: F) -> Self
    where
        E: Into<Event>,
        F: Fn(&mut T) -> Option<EventResult> + 'static,
    {
        self.with(|s| s.set_on_event_inner(event, cb))
    }

    /// Registers a callback when the given event is ignored by the child.
    pub fn set_on_event<F, R, E>(&mut self, event: E, cb: F)
    where
        E: Into<Event>,
        F: Fn(&mut Cursive) -> R + 'static,
    {
        let cb = Callback::from_fn(cb);
        let action =
            move |_: &mut T| Some(EventResult::Consumed(Some(cb.clone())));

        self.set_on_event_inner(event, action);
    }

    /// Registers a callback when the given event is received.
    ///
    /// The child will never receive this event.
    pub fn set_on_pre_event<F, R, E>(&mut self, event: E, cb: F)
    where
        E: Into<Event>,
        F: 'static + Fn(&mut Cursive) -> R,
    {
        let cb = Callback::from_fn(cb);
        // We want to clone the Callback every time we call the closure
        let action =
            move |_: &mut T| Some(EventResult::Consumed(Some(cb.clone())));

        self.set_on_pre_event_inner(event, action);
    }

    /// Registers a callback when the given event is received.
    ///
    /// The given callback will be run before the child view sees the event.
    ///
    /// * If the result is `None`, then the child view is given the event as
    ///   usual.
    /// * Otherwise, it bypasses the child view and directly processes the
    ///   result.
    pub fn set_on_pre_event_inner<F, E>(&mut self, event: E, cb: F)
    where
        E: Into<Event>,
        F: Fn(&mut T) -> Option<EventResult> + 'static,
    {
        self.callbacks.insert(
            event.into(),
            Action {
                phase: TriggerPhase::BeforeChild,
                callback: Rc::new(Box::new(cb)),
            },
        );
    }

    /// Registers a callback when the given event is ignored by the child.
    ///
    /// If the child view ignores the event, `cb` will be called with the
    /// child view as argument.
    /// If the result is not `None`, it will be processed as well.
    pub fn set_on_event_inner<F, E>(&mut self, event: E, cb: F)
    where
        E: Into<Event>,
        F: Fn(&mut T) -> Option<EventResult> + 'static,
    {
        self.callbacks.insert(
            event.into(),
            Action {
                phase: TriggerPhase::AfterChild,
                callback: Rc::new(Box::new(cb)),
            },
        );
    }
}

impl<T: View> ViewWrapper for OnEventView<T> {
    wrap_impl!(self.view: T);

    fn wrap_on_event(&mut self, event: Event) -> EventResult {
        let action = self.callbacks.get(&event).cloned();
        let pre_child = action
            .as_ref()
            .map(|a| a.phase == TriggerPhase::BeforeChild)
            .unwrap_or(false);

        if pre_child {
            action
                .and_then(|a| (*a.callback)(&mut self.view))
                .unwrap_or_else(|| self.view.on_event(event))
        } else {
            self.view.on_event(event).or_else(|| {
                action
                    .and_then(|a| (*a.callback)(&mut self.view))
                    .unwrap_or(EventResult::Ignored)
            })
        }
    }
}
<|endoftext|>


<commit_before>//! Tests for the join code.

use Configuration;
use join::*;
use rand::{Rng, SeedableRng, XorShiftRng};
use thread_pool::*;
use unwind;

fn quick_sort<T: PartialOrd + Send>(v: &mut [T]) {
    if v.len() <= 1 {
        return;
    }

    let mid = partition(v);
    let (lo, hi) = v.split_at_mut(mid);
    join(|| quick_sort(lo), || quick_sort(hi));
}

fn partition<T: PartialOrd + Send>(v: &mut [T]) -> usize {
    let pivot = v.len() - 1;
    let mut i = 0;
    for j in 0..pivot {
        if v[j] <= v[pivot] {
            v.swap(i, j);
            i += 1;
        }
    }
    v.swap(i, pivot);
    i
}

#[test]
fn sort() {
    let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
    let mut data: Vec<_> = (0..6 * 1024).map(|_| rng.next_u32()).collect();
    let mut sorted_data = data.clone();
    sorted_data.sort();
    quick_sort(&mut data);
    assert_eq!(data, sorted_data);
}

#[test]
fn sort_in_pool() {
    let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
    let mut data: Vec<_> = (0..12 * 1024).map(|_| rng.next_u32()).collect();

    let pool = ThreadPool::new(Configuration::new()).unwrap();
    let mut sorted_data = data.clone();
    sorted_data.sort();
    pool.install(|| quick_sort(&mut data));
    assert_eq!(data, sorted_data);
}

#[test]
#[should_panic(expected = "Hello, world!")]
fn panic_propagate_a() {
    join(|| panic!("Hello, world!"), || ());
}

#[test]
#[should_panic(expected = "Hello, world!")]
fn panic_propagate_b() {
    join(|| (), || panic!("Hello, world!"));
}

#[test]
#[should_panic(expected = "Hello, world!")]
fn panic_propagate_both() {
    join(|| panic!("Hello, world!"), || panic!("Goodbye, world!"));
}

#[test]
fn panic_b_still_executes() {
    let mut x = false;
    match unwind::halt_unwinding(|| join(|| panic!("Hello, world!"), || x = true)) {
        Ok(_) => panic!("failed to propagate panic from closure A,"),
        Err(_) => assert!(x, "closure b failed to execute"),
    }
}

#[test]
fn join_context_both() {
    // If we're not in a pool, both should be marked stolen as they're injected.
    let (a, b) = join_context(|a| a, |b| b);
    assert!(a);
    assert!(b);
}

#[test]
fn join_context_neither() {
    // If we're already in a 1-thread pool, neither job should be stolen.
    let pool = ThreadPool::new(Configuration::new().num_threads(1)).unwrap();
    let (a, b) = pool.install(|| join_context(|a| a, |b| b));
    assert!(!a);
    assert!(!b);
}

#[test]
fn join_context_second() {
    use std::sync::Barrier;

    // If we're already in a 2-thread pool, the second job should be stolen.
    let barrier = Barrier::new(2);
    let pool = ThreadPool::new(Configuration::new().num_threads(2)).unwrap();
    let (a, b) = pool.install(|| join_context(|a| { barrier.wait(); a },
                                              |b| { barrier.wait(); b }));
    assert!(!a);
    assert!(b);
}
<commit_msg>Fix the join tests<commit_after>//! Tests for the join code.

use Configuration;
use join::*;
use rand::{Rng, SeedableRng, XorShiftRng};
use thread_pool::*;
use unwind;

fn quick_sort<T: PartialOrd + Send>(v: &mut [T]) {
    if v.len() <= 1 {
        return;
    }

    let mid = partition(v);
    let (lo, hi) = v.split_at_mut(mid);
    join(|| quick_sort(lo), || quick_sort(hi));
}

fn partition<T: PartialOrd + Send>(v: &mut [T]) -> usize {
    let pivot = v.len() - 1;
    let mut i = 0;
    for j in 0..pivot {
        if v[j] <= v[pivot] {
            v.swap(i, j);
            i += 1;
        }
    }
    v.swap(i, pivot);
    i
}

#[test]
fn sort() {
    let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
    let mut data: Vec<_> = (0..6 * 1024).map(|_| rng.next_u32()).collect();
    let mut sorted_data = data.clone();
    sorted_data.sort();
    quick_sort(&mut data);
    assert_eq!(data, sorted_data);
}

#[test]
fn sort_in_pool() {
    let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
    let mut data: Vec<_> = (0..12 * 1024).map(|_| rng.next_u32()).collect();

    let pool = ThreadPool::new(Configuration::new()).unwrap();
    let mut sorted_data = data.clone();
    sorted_data.sort();
    pool.install(|| quick_sort(&mut data));
    assert_eq!(data, sorted_data);
}

#[test]
#[should_panic(expected = "Hello, world!")]
fn panic_propagate_a() {
    join(|| panic!("Hello, world!"), || ());
}

#[test]
#[should_panic(expected = "Hello, world!")]
fn panic_propagate_b() {
    join(|| (), || panic!("Hello, world!"));
}

#[test]
#[should_panic(expected = "Hello, world!")]
fn panic_propagate_both() {
    join(|| panic!("Hello, world!"), || panic!("Goodbye, world!"));
}

#[test]
fn panic_b_still_executes() {
    let mut x = false;
    match unwind::halt_unwinding(|| join(|| panic!("Hello, world!"), || x = true)) {
        Ok(_) => panic!("failed to propagate panic from closure A,"),
        Err(_) => assert!(x, "closure b failed to execute"),
    }
}

#[test]
fn join_context_both() {
    // If we're not in a pool, both should be marked stolen as they're injected.
    let (a, b) = join_context(|a| a, |b| b);
    assert!(a.migrated());
    assert!(b.migrated());
}

#[test]
fn join_context_neither() {
    // If we're already in a 1-thread pool, neither job should be stolen.
    let pool = ThreadPool::new(Configuration::new().num_threads(1)).unwrap();
    let (a, b) = pool.install(|| join_context(|a| a, |b| b));
    assert!(!a.migrated());
    assert!(!b.migrated());
}

#[test]
fn join_context_second() {
    use std::sync::Barrier;

    // If we're already in a 2-thread pool, the second job should be stolen.
    let barrier = Barrier::new(2);
    let pool = ThreadPool::new(Configuration::new().num_threads(2)).unwrap();
    let (a, b) = pool.install(|| join_context(|a| { barrier.wait(); a },
                                              |b| { barrier.wait(); b }));
    assert!(!a.migrated());
    assert!(b.migrated());
}
<|endoftext|>


<commit_before>// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::cell::RefCell;
use std::collections::BTreeMap;
use std::path::PathBuf;
use std::rc::Rc;
use std::sync::Arc;
use std::thread;
use std::time::{Duration, Instant};

use anyhow::{anyhow, bail, Context};
use argh::FromArgs;
use base::{
    clone_descriptor, error, warn, Event, FromRawDescriptor, SafeDescriptor, Tube, UnixSeqpacket,
};
use cros_async::{AsyncWrapper, EventAsync, Executor, IoSourceExt};
use futures::future::{AbortHandle, Abortable};
use hypervisor::ProtectionType;
#[cfg(feature = "minigbm")]
use rutabaga_gfx::RutabagaGralloc;
use sync::Mutex;
use vm_memory::GuestMemory;
use vmm_vhost::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures};

use crate::virtio::vhost::user::device::{
    handler::{sys::Doorbell, VhostUserBackend},
    listener::{sys::VhostUserListener, VhostUserListenerTrait},
};
use crate::virtio::{base_features, wl, Queue, SharedMemoryMapper, SharedMemoryRegion};

const MAX_QUEUE_NUM: usize = wl::QUEUE_SIZES.len();
const MAX_VRING_LEN: u16 = wl::QUEUE_SIZE;

async fn run_out_queue(
    mut queue: Queue,
    mem: GuestMemory,
    doorbell: Arc<Mutex<Doorbell>>,
    kick_evt: EventAsync,
    wlstate: Rc<RefCell<wl::WlState>>,
) {
    loop {
        if let Err(e) = kick_evt.next_val().await {
            error!("Failed to read kick event for out queue: {}", e);
            break;
        }

        wl::process_out_queue(&doorbell, &mut queue, &mem, &mut wlstate.borrow_mut());
    }
}

async fn run_in_queue(
    mut queue: Queue,
    mem: GuestMemory,
    doorbell: Arc<Mutex<Doorbell>>,
    kick_evt: EventAsync,
    wlstate: Rc<RefCell<wl::WlState>>,
    wlstate_ctx: Box<dyn IoSourceExt<AsyncWrapper<SafeDescriptor>>>,
) {
    loop {
        if let Err(e) = wlstate_ctx.wait_readable().await {
            error!(
                "Failed to wait for inner WaitContext to become readable: {}",
                e
            );
            break;
        }

        if wl::process_in_queue(&doorbell, &mut queue, &mem, &mut wlstate.borrow_mut())
            == Err(wl::DescriptorsExhausted)
        {
            if let Err(e) = kick_evt.next_val().await {
                error!("Failed to read kick event for in queue: {}", e);
                break;
            }
        }
    }
}

struct WlBackend {
    ex: Executor,
    wayland_paths: Option<BTreeMap<String, PathBuf>>,
    mapper: Option<Box<dyn SharedMemoryMapper>>,
    resource_bridge: Option<Tube>,
    use_transition_flags: bool,
    use_send_vfd_v2: bool,
    use_shmem: bool,
    features: u64,
    acked_features: u64,
    wlstate: Option<Rc<RefCell<wl::WlState>>>,
    workers: [Option<AbortHandle>; MAX_QUEUE_NUM],
}

impl WlBackend {
    fn new(
        ex: &Executor,
        wayland_paths: BTreeMap<String, PathBuf>,
        resource_bridge: Option<Tube>,
    ) -> WlBackend {
        let features = base_features(ProtectionType::Unprotected)
            | 1 << wl::VIRTIO_WL_F_TRANS_FLAGS
            | 1 << wl::VIRTIO_WL_F_SEND_FENCES
            | 1 << wl::VIRTIO_WL_F_USE_SHMEM
            | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();
        WlBackend {
            ex: ex.clone(),
            wayland_paths: Some(wayland_paths),
            mapper: None,
            resource_bridge,
            use_transition_flags: false,
            use_send_vfd_v2: false,
            use_shmem: false,
            features,
            acked_features: 0,
            wlstate: None,
            workers: Default::default(),
        }
    }
}

impl VhostUserBackend for WlBackend {
    fn max_queue_num(&self) -> usize {
        return MAX_QUEUE_NUM;
    }

    fn max_vring_len(&self) -> u16 {
        return MAX_VRING_LEN;
    }

    fn features(&self) -> u64 {
        self.features
    }

    fn ack_features(&mut self, value: u64) -> anyhow::Result<()> {
        let unrequested_features = value & !self.features();
        if unrequested_features != 0 {
            bail!("invalid features are given: {:#x}", unrequested_features);
        }

        self.acked_features |= value;

        if value & (1 << wl::VIRTIO_WL_F_TRANS_FLAGS) != 0 {
            self.use_transition_flags = true;
        }
        if value & (1 << wl::VIRTIO_WL_F_SEND_FENCES) != 0 {
            self.use_send_vfd_v2 = true;
        }
        if value & (1 << wl::VIRTIO_WL_F_USE_SHMEM) != 0 {
            self.use_shmem = true;
        }

        Ok(())
    }

    fn acked_features(&self) -> u64 {
        self.acked_features
    }

    fn protocol_features(&self) -> VhostUserProtocolFeatures {
        VhostUserProtocolFeatures::SLAVE_REQ
    }

    fn ack_protocol_features(&mut self, features: u64) -> anyhow::Result<()> {
        if features != VhostUserProtocolFeatures::SLAVE_REQ.bits() {
            Err(anyhow!("Unexpected protocol features: {:#x}", features))
        } else {
            Ok(())
        }
    }

    fn acked_protocol_features(&self) -> u64 {
        VhostUserProtocolFeatures::empty().bits()
    }

    fn read_config(&self, _offset: u64, _dst: &mut [u8]) {}

    fn start_queue(
        &mut self,
        idx: usize,
        mut queue: Queue,
        mem: GuestMemory,
        doorbell: Arc<Mutex<Doorbell>>,
        kick_evt: Event,
    ) -> anyhow::Result<()> {
        if let Some(handle) = self.workers.get_mut(idx).and_then(Option::take) {
            warn!("Starting new queue handler without stopping old handler");
            handle.abort();
        }

        // Enable any virtqueue features that were negotiated (like VIRTIO_RING_F_EVENT_IDX).
        queue.ack_features(self.acked_features);

        let kick_evt = EventAsync::new(kick_evt, &self.ex)
            .context("failed to create EventAsync for kick_evt")?;

        if !self.use_shmem {
            bail!("Incompatible driver: vhost-user-wl requires shmem support");
        }

        // We use this de-structuring let binding to separate borrows so that the compiler doesn't
        // think we're borrowing all of `self` in the closure below.
        let WlBackend {
            ref mut wayland_paths,
            ref mut mapper,
            ref mut resource_bridge,
            ref use_transition_flags,
            ref use_send_vfd_v2,
            ..
        } = self;
        #[cfg(feature = "minigbm")]
        let gralloc = RutabagaGralloc::new().context("Failed to initailize gralloc")?;
        let wlstate = self
            .wlstate
            .get_or_insert_with(|| {
                Rc::new(RefCell::new(wl::WlState::new(
                    wayland_paths.take().expect("WlState already initialized"),
                    mapper.take().expect("WlState already initialized"),
                    *use_transition_flags,
                    *use_send_vfd_v2,
                    resource_bridge.take(),
                    #[cfg(feature = "minigbm")]
                    gralloc,
                    0, /* address_offset */
                )))
            })
            .clone();
        let (handle, registration) = AbortHandle::new_pair();
        match idx {
            0 => {
                let wlstate_ctx = clone_descriptor(wlstate.borrow().wait_ctx())
                    .map(|fd| {
                        // Safe because we just created this fd.
                        AsyncWrapper::new(unsafe { SafeDescriptor::from_raw_descriptor(fd) })
                    })
                    .context("failed to clone inner WaitContext for WlState")
                    .and_then(|ctx| {
                        self.ex
                            .async_from(ctx)
                            .context("failed to create async WaitContext")
                    })?;

                self.ex
                    .spawn_local(Abortable::new(
                        run_in_queue(queue, mem, doorbell, kick_evt, wlstate, wlstate_ctx),
                        registration,
                    ))
                    .detach();
            }
            1 => {
                self.ex
                    .spawn_local(Abortable::new(
                        run_out_queue(queue, mem, doorbell, kick_evt, wlstate),
                        registration,
                    ))
                    .detach();
            }
            _ => bail!("attempted to start unknown queue: {}", idx),
        }
        self.workers[idx] = Some(handle);
        Ok(())
    }

    fn stop_queue(&mut self, idx: usize) {
        if let Some(handle) = self.workers.get_mut(idx).and_then(Option::take) {
            handle.abort();
        }
    }
    fn reset(&mut self) {
        for handle in self.workers.iter_mut().filter_map(Option::take) {
            handle.abort();
        }
    }

    fn get_shared_memory_region(&self) -> Option<SharedMemoryRegion> {
        Some(SharedMemoryRegion {
            id: wl::WL_SHMEM_ID,
            length: wl::WL_SHMEM_SIZE,
        })
    }

    fn set_shared_memory_mapper(&mut self, mapper: Box<dyn SharedMemoryMapper>) {
        self.mapper = Some(mapper);
    }
}

pub fn parse_wayland_sock(value: &str) -> Result<(String, PathBuf), String> {
    let mut components = value.split(',');
    let path = PathBuf::from(match components.next() {
        None => return Err("missing socket path".to_string()),
        Some(c) => c,
    });
    let mut name = "";
    for c in components {
        let mut kv = c.splitn(2, '=');
        let (kind, value) = match (kv.next(), kv.next()) {
            (Some(kind), Some(value)) => (kind, value),
            _ => return Err(format!("option must be of the form `kind=value`: {}", c)),
        };
        match kind {
            "name" => name = value,
            _ => return Err(format!("unrecognized option: {}", kind)),
        }
    }

    Ok((name.to_string(), path))
}

#[derive(FromArgs)]
#[argh(subcommand, name = "wl")]
/// Wayland device
pub struct Options {
    #[argh(option, arg_name = "PATH")]
    /// path to bind a listening vhost-user socket
    socket: String,
    #[argh(option, from_str_fn(parse_wayland_sock), arg_name = "PATH[,name=NAME]")]
    /// path to one or more Wayland sockets. The unnamed socket is used for
    /// displaying virtual screens while the named ones are used for IPC
    wayland_sock: Vec<(String, PathBuf)>,
    #[argh(option, arg_name = "PATH")]
    /// path to the GPU resource bridge
    resource_bridge: Option<String>,
}

/// Starts a vhost-user wayland device.
/// Returns an error if the given `args` is invalid or the device fails to run.
pub fn run_wl_device(opts: Options) -> anyhow::Result<()> {
    let Options {
        wayland_sock,
        socket,
        resource_bridge,
    } = opts;

    let wayland_paths: BTreeMap<_, _> = wayland_sock.into_iter().collect();

    let resource_bridge = resource_bridge
        .map(|p| -> anyhow::Result<Tube> {
            let deadline = Instant::now() + Duration::from_secs(5);
            loop {
                match UnixSeqpacket::connect(&p) {
                    Ok(s) => return Ok(Tube::new(s)),
                    Err(e) => {
                        if Instant::now() < deadline {
                            thread::sleep(Duration::from_millis(50));
                        } else {
                            return Err(anyhow::Error::new(e));
                        }
                    }
                }
            }
        })
        .transpose()
        .context("failed to connect to resource bridge socket")?;

    let ex = Executor::new().context("failed to create executor")?;

    let backend = Box::new(WlBackend::new(&ex, wayland_paths, resource_bridge));

    let listener = VhostUserListener::new_socket(&socket, None)?;
    // run_until() returns an Result<Result<..>> which the ? operator lets us flatten.
    ex.run_until(listener.run_backend(backend, &ex))?
}
<commit_msg>devices: vhost-user: wl: add vvu support<commit_after>// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::cell::RefCell;
use std::collections::BTreeMap;
use std::path::PathBuf;
use std::rc::Rc;
use std::sync::Arc;
use std::thread;
use std::time::{Duration, Instant};

use anyhow::{anyhow, bail, Context};
use argh::FromArgs;
use base::{
    clone_descriptor, error, warn, Event, FromRawDescriptor, SafeDescriptor, Tube, UnixSeqpacket,
};
use cros_async::{AsyncWrapper, EventAsync, Executor, IoSourceExt};
use futures::future::{AbortHandle, Abortable};
use hypervisor::ProtectionType;
#[cfg(feature = "minigbm")]
use rutabaga_gfx::RutabagaGralloc;
use sync::Mutex;
use vm_memory::GuestMemory;
use vmm_vhost::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures};

use crate::virtio::vhost::user::device::{
    handler::{sys::Doorbell, VhostUserBackend},
    listener::{sys::VhostUserListener, VhostUserListenerTrait},
};
use crate::virtio::{base_features, wl, Queue, SharedMemoryMapper, SharedMemoryRegion};

const MAX_QUEUE_NUM: usize = wl::QUEUE_SIZES.len();
const MAX_VRING_LEN: u16 = wl::QUEUE_SIZE;

async fn run_out_queue(
    mut queue: Queue,
    mem: GuestMemory,
    doorbell: Arc<Mutex<Doorbell>>,
    kick_evt: EventAsync,
    wlstate: Rc<RefCell<wl::WlState>>,
) {
    loop {
        if let Err(e) = kick_evt.next_val().await {
            error!("Failed to read kick event for out queue: {}", e);
            break;
        }

        wl::process_out_queue(&doorbell, &mut queue, &mem, &mut wlstate.borrow_mut());
    }
}

async fn run_in_queue(
    mut queue: Queue,
    mem: GuestMemory,
    doorbell: Arc<Mutex<Doorbell>>,
    kick_evt: EventAsync,
    wlstate: Rc<RefCell<wl::WlState>>,
    wlstate_ctx: Box<dyn IoSourceExt<AsyncWrapper<SafeDescriptor>>>,
) {
    loop {
        if let Err(e) = wlstate_ctx.wait_readable().await {
            error!(
                "Failed to wait for inner WaitContext to become readable: {}",
                e
            );
            break;
        }

        if wl::process_in_queue(&doorbell, &mut queue, &mem, &mut wlstate.borrow_mut())
            == Err(wl::DescriptorsExhausted)
        {
            if let Err(e) = kick_evt.next_val().await {
                error!("Failed to read kick event for in queue: {}", e);
                break;
            }
        }
    }
}

struct WlBackend {
    ex: Executor,
    wayland_paths: Option<BTreeMap<String, PathBuf>>,
    mapper: Option<Box<dyn SharedMemoryMapper>>,
    resource_bridge: Option<Tube>,
    use_transition_flags: bool,
    use_send_vfd_v2: bool,
    use_shmem: bool,
    features: u64,
    acked_features: u64,
    wlstate: Option<Rc<RefCell<wl::WlState>>>,
    workers: [Option<AbortHandle>; MAX_QUEUE_NUM],
}

impl WlBackend {
    fn new(
        ex: &Executor,
        wayland_paths: BTreeMap<String, PathBuf>,
        resource_bridge: Option<Tube>,
    ) -> WlBackend {
        let features = base_features(ProtectionType::Unprotected)
            | 1 << wl::VIRTIO_WL_F_TRANS_FLAGS
            | 1 << wl::VIRTIO_WL_F_SEND_FENCES
            | 1 << wl::VIRTIO_WL_F_USE_SHMEM
            | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();
        WlBackend {
            ex: ex.clone(),
            wayland_paths: Some(wayland_paths),
            mapper: None,
            resource_bridge,
            use_transition_flags: false,
            use_send_vfd_v2: false,
            use_shmem: false,
            features,
            acked_features: 0,
            wlstate: None,
            workers: Default::default(),
        }
    }
}

impl VhostUserBackend for WlBackend {
    fn max_queue_num(&self) -> usize {
        return MAX_QUEUE_NUM;
    }

    fn max_vring_len(&self) -> u16 {
        return MAX_VRING_LEN;
    }

    fn features(&self) -> u64 {
        self.features
    }

    fn ack_features(&mut self, value: u64) -> anyhow::Result<()> {
        let unrequested_features = value & !self.features();
        if unrequested_features != 0 {
            bail!("invalid features are given: {:#x}", unrequested_features);
        }

        self.acked_features |= value;

        if value & (1 << wl::VIRTIO_WL_F_TRANS_FLAGS) != 0 {
            self.use_transition_flags = true;
        }
        if value & (1 << wl::VIRTIO_WL_F_SEND_FENCES) != 0 {
            self.use_send_vfd_v2 = true;
        }
        if value & (1 << wl::VIRTIO_WL_F_USE_SHMEM) != 0 {
            self.use_shmem = true;
        }

        Ok(())
    }

    fn acked_features(&self) -> u64 {
        self.acked_features
    }

    fn protocol_features(&self) -> VhostUserProtocolFeatures {
        VhostUserProtocolFeatures::SLAVE_REQ
    }

    fn ack_protocol_features(&mut self, features: u64) -> anyhow::Result<()> {
        if features != VhostUserProtocolFeatures::SLAVE_REQ.bits() {
            Err(anyhow!("Unexpected protocol features: {:#x}", features))
        } else {
            Ok(())
        }
    }

    fn acked_protocol_features(&self) -> u64 {
        VhostUserProtocolFeatures::empty().bits()
    }

    fn read_config(&self, _offset: u64, _dst: &mut [u8]) {}

    fn start_queue(
        &mut self,
        idx: usize,
        mut queue: Queue,
        mem: GuestMemory,
        doorbell: Arc<Mutex<Doorbell>>,
        kick_evt: Event,
    ) -> anyhow::Result<()> {
        if let Some(handle) = self.workers.get_mut(idx).and_then(Option::take) {
            warn!("Starting new queue handler without stopping old handler");
            handle.abort();
        }

        // Enable any virtqueue features that were negotiated (like VIRTIO_RING_F_EVENT_IDX).
        queue.ack_features(self.acked_features);

        let kick_evt = EventAsync::new(kick_evt, &self.ex)
            .context("failed to create EventAsync for kick_evt")?;

        if !self.use_shmem {
            bail!("Incompatible driver: vhost-user-wl requires shmem support");
        }

        // We use this de-structuring let binding to separate borrows so that the compiler doesn't
        // think we're borrowing all of `self` in the closure below.
        let WlBackend {
            ref mut wayland_paths,
            ref mut mapper,
            ref mut resource_bridge,
            ref use_transition_flags,
            ref use_send_vfd_v2,
            ..
        } = self;
        #[cfg(feature = "minigbm")]
        let gralloc = RutabagaGralloc::new().context("Failed to initailize gralloc")?;
        let wlstate = self
            .wlstate
            .get_or_insert_with(|| {
                Rc::new(RefCell::new(wl::WlState::new(
                    wayland_paths.take().expect("WlState already initialized"),
                    mapper.take().expect("WlState already initialized"),
                    *use_transition_flags,
                    *use_send_vfd_v2,
                    resource_bridge.take(),
                    #[cfg(feature = "minigbm")]
                    gralloc,
                    0, /* address_offset */
                )))
            })
            .clone();
        let (handle, registration) = AbortHandle::new_pair();
        match idx {
            0 => {
                let wlstate_ctx = clone_descriptor(wlstate.borrow().wait_ctx())
                    .map(|fd| {
                        // Safe because we just created this fd.
                        AsyncWrapper::new(unsafe { SafeDescriptor::from_raw_descriptor(fd) })
                    })
                    .context("failed to clone inner WaitContext for WlState")
                    .and_then(|ctx| {
                        self.ex
                            .async_from(ctx)
                            .context("failed to create async WaitContext")
                    })?;

                self.ex
                    .spawn_local(Abortable::new(
                        run_in_queue(queue, mem, doorbell, kick_evt, wlstate, wlstate_ctx),
                        registration,
                    ))
                    .detach();
            }
            1 => {
                self.ex
                    .spawn_local(Abortable::new(
                        run_out_queue(queue, mem, doorbell, kick_evt, wlstate),
                        registration,
                    ))
                    .detach();
            }
            _ => bail!("attempted to start unknown queue: {}", idx),
        }
        self.workers[idx] = Some(handle);
        Ok(())
    }

    fn stop_queue(&mut self, idx: usize) {
        if let Some(handle) = self.workers.get_mut(idx).and_then(Option::take) {
            handle.abort();
        }
    }
    fn reset(&mut self) {
        for handle in self.workers.iter_mut().filter_map(Option::take) {
            handle.abort();
        }
    }

    fn get_shared_memory_region(&self) -> Option<SharedMemoryRegion> {
        Some(SharedMemoryRegion {
            id: wl::WL_SHMEM_ID,
            length: wl::WL_SHMEM_SIZE,
        })
    }

    fn set_shared_memory_mapper(&mut self, mapper: Box<dyn SharedMemoryMapper>) {
        self.mapper = Some(mapper);
    }
}

pub fn parse_wayland_sock(value: &str) -> Result<(String, PathBuf), String> {
    let mut components = value.split(',');
    let path = PathBuf::from(match components.next() {
        None => return Err("missing socket path".to_string()),
        Some(c) => c,
    });
    let mut name = "";
    for c in components {
        let mut kv = c.splitn(2, '=');
        let (kind, value) = match (kv.next(), kv.next()) {
            (Some(kind), Some(value)) => (kind, value),
            _ => return Err(format!("option must be of the form `kind=value`: {}", c)),
        };
        match kind {
            "name" => name = value,
            _ => return Err(format!("unrecognized option: {}", kind)),
        }
    }

    Ok((name.to_string(), path))
}

#[derive(FromArgs)]
#[argh(subcommand, name = "wl")]
/// Wayland device
pub struct Options {
    #[argh(option, arg_name = "PATH")]
    /// path to bind a listening vhost-user socket
    socket: Option<String>,
    #[argh(option, arg_name = "STRING")]
    /// VFIO-PCI device name (e.g. '0000:00:07.0')
    vfio: Option<String>,
    #[argh(option, from_str_fn(parse_wayland_sock), arg_name = "PATH[,name=NAME]")]
    /// path to one or more Wayland sockets. The unnamed socket is used for
    /// displaying virtual screens while the named ones are used for IPC
    wayland_sock: Vec<(String, PathBuf)>,
    #[argh(option, arg_name = "PATH")]
    /// path to the GPU resource bridge
    resource_bridge: Option<String>,
}

/// Starts a vhost-user wayland device.
/// Returns an error if the given `args` is invalid or the device fails to run.
pub fn run_wl_device(opts: Options) -> anyhow::Result<()> {
    let Options {
        wayland_sock,
        socket,
        vfio,
        resource_bridge,
    } = opts;

    let wayland_paths: BTreeMap<_, _> = wayland_sock.into_iter().collect();

    let resource_bridge = resource_bridge
        .map(|p| -> anyhow::Result<Tube> {
            let deadline = Instant::now() + Duration::from_secs(5);
            loop {
                match UnixSeqpacket::connect(&p) {
                    Ok(s) => return Ok(Tube::new(s)),
                    Err(e) => {
                        if Instant::now() < deadline {
                            thread::sleep(Duration::from_millis(50));
                        } else {
                            return Err(anyhow::Error::new(e));
                        }
                    }
                }
            }
        })
        .transpose()
        .context("failed to connect to resource bridge socket")?;

    let ex = Executor::new().context("failed to create executor")?;

    let listener =
        VhostUserListener::new_from_socket_or_vfio(&socket, &vfio, wl::QUEUE_SIZES.len(), None)?;

    let backend = Box::new(WlBackend::new(&ex, wayland_paths, resource_bridge));
    // run_until() returns an Result<Result<..>> which the ? operator lets us flatten.
    ex.run_until(listener.run_backend(backend, &ex))?
}
<|endoftext|>