<commit_before>use std::path;
use std::process;

use clap::{App, Arg, SubCommand};

use config;
use models;
use web;
use utils;

pub fn main() {
    let matches =
        App::new("mysteryshack")
        .version("0.1.0")
        .author("Markus Unterwaditzer & contributors")
        .about("A remoteStorage server.")
        .args_from_usage("-c --config=[CONFIG] 'Use specified config file, defaults to ./config'")
        .subcommand(SubCommand::with_name("serve")
                    .about("Start server"))
        .subcommand(SubCommand::with_name("user")
                    .about("User management")
                    .subcommand(SubCommand::with_name("create")
                                .about("Create a new user")
                                .arg(Arg::with_name("USERNAME")
                                     .help("The username")
                                     .required(true)
                                     .index(1)))
                    .subcommand(SubCommand::with_name("delete")
                                .about("Delete a user")
                                .arg(Arg::with_name("USERNAME")
                                     .help("The username")
                                     .required(true)
                                     .index(1)))
                    .subcommand_required(true))
        .subcommand_required(true)
        .get_matches();

    let config_path = path::Path::new(matches.value_of("CONFIG").unwrap_or("./config"));

    let config = match config::Config::read_file(config_path) {
        Ok(x) => x,
        Err(e) => {
            println!("Failed to parse config: {}", e);
            process::exit(1);
        }
    };

    if let Some(_) = matches.subcommand_matches("serve") {
        web::run_server(config);
    } else if let Some(user_matches) = matches.subcommand_matches("user") {
        if let Some(user_create_matches) = user_matches.subcommand_matches("create") {
            let username = user_create_matches.value_of("USERNAME").unwrap();

            let password_hash = match models::PasswordHash::from_password(
                utils::double_prompt("Password for new user: ")) {
                Ok(x) => x,
                Err(e) => {
                    println!("Failed to hash password: {}", e);
                    process::exit(1);
                }
            };

            match models::User::create(&config.data_path, username).map(|user| {
                user.set_password_hash(password_hash)
            }) {
                Ok(_) => (),
                Err(e) => {
                    println!("Failed to create user {}: {}", username, e);
                    process::exit(1);
                }
            };

            println!("Successfully created user {}", username);
        } else if let Some(user_delete_matches) = user_matches.subcommand_matches("delete") {
            let username = user_delete_matches.value_of("USERNAME").unwrap();
            let user = match models::User::get(&config.data_path, username) {
                Some(x) => x,
                None => {
                    println!("User does not exist: {}", username);
                    process::exit(1);
                }
            };

            println!("You are about to delete the user {} and ALL the user's user data. This
                     process is irreversible.", username);
            if !utils::prompt_confirm(format!("Do you want to delete the user {}?", username), false) {
                println!("Aborted!");
                process::exit(1);
            }

            match user.delete() {
                Ok(_) => println!("Successfully deleted user {}.", username),
                Err(e) => {
                    println!("Failed to delete user: {:?}", e);
                    process::exit(1);
                }
            };
        }
    }
}
<commit_msg>Remove hardcoded version number<commit_after>use std::path;
use std::process;

use clap::{App, Arg, SubCommand};

use config;
use models;
use web;
use utils;

pub fn main() {
    let matches =
        App::new("mysteryshack")
        .version(env!("CARGO_PKG_VERSION"))
        .author("Markus Unterwaditzer & contributors")
        .about("A remoteStorage server.")
        .args_from_usage("-c --config=[CONFIG] 'Use specified config file, defaults to ./config'")
        .subcommand(SubCommand::with_name("serve")
                    .about("Start server"))
        .subcommand(SubCommand::with_name("user")
                    .about("User management")
                    .subcommand(SubCommand::with_name("create")
                                .about("Create a new user")
                                .arg(Arg::with_name("USERNAME")
                                     .help("The username")
                                     .required(true)
                                     .index(1)))
                    .subcommand(SubCommand::with_name("delete")
                                .about("Delete a user")
                                .arg(Arg::with_name("USERNAME")
                                     .help("The username")
                                     .required(true)
                                     .index(1)))
                    .subcommand_required(true))
        .subcommand_required(true)
        .get_matches();

    let config_path = path::Path::new(matches.value_of("CONFIG").unwrap_or("./config"));

    let config = match config::Config::read_file(config_path) {
        Ok(x) => x,
        Err(e) => {
            println!("Failed to parse config: {}", e);
            process::exit(1);
        }
    };

    if let Some(_) = matches.subcommand_matches("serve") {
        web::run_server(config);
    } else if let Some(user_matches) = matches.subcommand_matches("user") {
        if let Some(user_create_matches) = user_matches.subcommand_matches("create") {
            let username = user_create_matches.value_of("USERNAME").unwrap();

            let password_hash = match models::PasswordHash::from_password(
                utils::double_prompt("Password for new user: ")) {
                Ok(x) => x,
                Err(e) => {
                    println!("Failed to hash password: {}", e);
                    process::exit(1);
                }
            };

            match models::User::create(&config.data_path, username).map(|user| {
                user.set_password_hash(password_hash)
            }) {
                Ok(_) => (),
                Err(e) => {
                    println!("Failed to create user {}: {}", username, e);
                    process::exit(1);
                }
            };

            println!("Successfully created user {}", username);
        } else if let Some(user_delete_matches) = user_matches.subcommand_matches("delete") {
            let username = user_delete_matches.value_of("USERNAME").unwrap();
            let user = match models::User::get(&config.data_path, username) {
                Some(x) => x,
                None => {
                    println!("User does not exist: {}", username);
                    process::exit(1);
                }
            };

            println!("You are about to delete the user {} and ALL the user's user data. This
                     process is irreversible.", username);
            if !utils::prompt_confirm(format!("Do you want to delete the user {}?", username), false) {
                println!("Aborted!");
                process::exit(1);
            }

            match user.delete() {
                Ok(_) => println!("Successfully deleted user {}.", username),
                Err(e) => {
                    println!("Failed to delete user: {:?}", e);
                    process::exit(1);
                }
            };
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2012 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.

#[macro_escape];

macro_rules! rterrln (
    ($( $arg:expr),+) => ( {
        ::rt::util::dumb_println(fmt!( $($arg),+ ));
    } )
)

// Some basic logging
macro_rules! rtdebug_ (
    ($( $arg:expr),+) => ( {
        rterrln!( $($arg),+ )
    } )
)

// An alternate version with no output, for turning off logging. An
// earlier attempt that did not call the fmt! macro was insufficient,
// as a case of the "let bind each variable" approach eventually
// failed without an error message describing the invocation site.
macro_rules! rtdebug (
    ($( $arg:expr),+) => ( {
        let _x = fmt!( $($arg),+ );
    })
)

macro_rules! rtassert (
    ( $arg:expr ) => ( {
        if !$arg {
            rtabort!("assertion failed: %s", stringify!($arg));
        }
    } )
)

macro_rules! rtabort(
    ($( $msg:expr),+) => ( {
        ::rt::util::abort(fmt!($($msg),+));
    } )
)

<commit_msg>Remove rtdebug_! and make rtdebug! work properly.<commit_after>// Copyright 2012 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.

#[macro_escape];

macro_rules! rterrln (
    ($( $arg:expr),+) => ( {
        ::rt::util::dumb_println(fmt!( $($arg),+ ));
    } )
)

// Some basic logging. Enabled by passing `--cfg rtdebug` to the libstd build.
macro_rules! rtdebug (
    ($( $arg:expr),+) => ( {
        if cfg!(rtdebug) {
            rterrln!( $($arg),+ )
        }
    })
)

macro_rules! rtassert (
    ( $arg:expr ) => ( {
        if !$arg {
            rtabort!("assertion failed: %s", stringify!($arg));
        }
    } )
)

macro_rules! rtabort(
    ($( $msg:expr),+) => ( {
        ::rt::util::abort(fmt!($($msg),+));
    } )
)

<|endoftext|>


<commit_before>
// Use this syntax to import more than one type from the same root type
use std::io::{self, Write};

fn fib(n: usize) -> usize {
    // Compared to C++, in Rust parenthesis around the expression for if/else
    // statements are not necessary. You can use them but the compiler will
    // warn you that they are unnecessary
    if n == 0 {
        // Numeric literals in Rust can be postfixed with the exact name of the
        // available numeric types, e.g. 1u32 or 2i64
        return 0usize;
    }
    else if n == 1 {
        // Returning values in Rust is also done by writing an expression
        // rather than
        // a statement. I.e. you can omit the trailing ";" at the end of the
        // expression, e.g.:
        //
        //   1usize
        //
        return 1usize;
    }
    else {
        return fib(n-1usize) + fib(n-2usize);
    }
}

fn main() {
    // "print!" is like "println!" which is used in most examples in the rust
    // book but it doesn't output a newline
    print!("Enter what Fibonacci number you want to compute: ");
    // We need to flush the buffer because print!() does not output a newline
    // character and does not flush; it uses STDOUT which is buffered
    io::stdout().flush().unwrap();

    // ::new() is an associated function implemented on a type, in this case on
    // type String, rather than an instance of String. They are basically
    // equivalent to C++'s static methods
    //
    // Making the variable "mut" (mutable) allows us to change it. In Rust
    // variables are constant (unmutable) by default
    let mut n = String::new();

    // stdin() returns an instance of std::io::Stdin, which represents a handle
    // to the STD output. Equivalent to C++'s std::cin
    //
    // .read_line() is used to read until a newline character is found
    //
    // .expect() checks the return type of .read_line(), which is an enum, and
    // uses the match control operator to check whether the function returned
    // an error enum variant or a success enum variant. On success, it returns
    // the value which the function returns upon success, whereas upon failure
    // it will panic and exit the program after printing the message we pased to
    // it.
    //
    // See enums in the Rust book and std::result, std::result::Result for more
    // information
    io::stdin().read_line(&mut n).expect("Failed to read from STDIN!");

    // In Rust we can perform variable "shadowing". Here the previous
    // declaration of "n" was of type String but now we declare a new variable
    // with name "n" but of numerical type, which is obtained by running the
    // .parse() method. When referring to "n" we will use the latest instance
    // of a type named "n" and not the String instance anymore.
    //
    // .parse() uses the trait FromStr to determine whether
    // a type supports this operation (converting to something from a String)
    let n: usize = n.trim().parse().expect("Invalid input!");

    println!("The computed value is: {}", fib(n));
}
<commit_msg>Idiomatic changes, dynamicprogrmaming version<commit_after>
// Use this syntax to import more than one type from the same root type
use std::io::{self, Write};

fn fib_recursive(n: u64) -> u64 {
    // Compared to C++, in Rust parenthesis around the expression for if/else
    // statements are not necessary. You can use them but the compiler will
    // warn you that they are unnecessary
    if n == 0 {
        // Numeric literals in Rust can be postfixed with the exact name of the
        // available numeric types, e.g. 1u32 or 2i64, you can also write 1_u32, etc
        // However, this isn't necessary most of the time, the rust compiler is able
        // to infer the type.
        0
    } else if n == 1 {
        // Most things in Rust are expressions, this if/else/else statement is
        // an expression, and we can tell Rust to return it, rather than writing
        // return 1; here, above, and below.
        1
    } else {
        fib_recursive(n - 1) + fib_recursive(n - 2)
    }
}

// A dynamic programming version of fib
fn fib_dp(n: u64) -> u64 {
    if n == 0 || n == 1 {
        n
    } else {
        let mut f1 = 0;
        let mut f2 = 1;
        let mut total = 0;

        // The underscore here tells Rust to throw away the value, I'm not going to use it.
        // On the right half of the 'in', I'm writing a range expression. If you're familiar
        // with python it's like range(2,n+1). The format of x..y is 'half-open', where
        // x is inclusive and y is exclusive
        for _ in 2..(n + 1) {
            total = f1 + f2;
            f1 = f2;
            f2 = total;
        }
        // again, here, we could have written return total; but it's often
        // more concise and idiomatic Rust to just write the value
        total
    }
}

fn main() {
    // "print!" is like "println!" which is used in most examples in the rust
    // book but it doesn't output a newline
    print!("Enter what Fibonacci number you want to compute: ");
    // We need to flush the buffer because print!() does not output a newline
    // character and does not flush; it uses STDOUT which is buffered
    io::stdout().flush().unwrap();

    // ::new() is an associated function implemented on a type, in this case on
    // type String, rather than an instance of String. They are basically
    // equivalent to C++'s static methods
    //
    // Making the variable "mut" (mutable) allows us to change it. In Rust
    // variables are constant (unmutable) by default
    let mut n = String::new();

    // stdin() returns an instance of std::io::Stdin, which represents a handle
    // to the STD output. Equivalent to C++'s std::cin
    //
    // .read_line() is used to read until a newline character is found
    //
    // .expect() checks the return type of .read_line(), which is an enum, and
    // uses the match control operator to check whether the function returned
    // an error enum variant or a success enum variant. On success, it returns
    // the value which the function returns upon success, whereas upon failure
    // it will panic and exit the program after printing the message we pased to
    // it.
    //
    // See enums in the Rust book and std::result, std::result::Result for more
    // information
    io::stdin()
        .read_line(&mut n)
        .expect("Failed to read from STDIN!");

    // In Rust we can perform variable "shadowing". Here the previous
    // declaration of "n" was of type String but now we declare a new variable
    // with name "n" but of numerical type, which is obtained by running the
    // .parse() method. When referring to "n" we will use the latest instance
    // of a type named "n" and not the String instance anymore.
    //
    // .parse() uses the trait FromStr to determine whether
    // a type supports this operation (converting to something from a String)
    let n: u64 = n.trim().parse().expect("Invalid input!");

    println!("The computed value is: {}", fib_recursive(n));
    println!("The computed value is: {}", fib_dp(n));
}
<|endoftext|>


<commit_before>use message::Message;
use state::State;
use std::time::Duration;

const FIRST_OPENS_DEFAULT: bool = false;
const LAST_CLOSES_DEFAULT: bool = false;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Conditions {
    pub timeout: Duration,
    pub renew_timeout: Option<Duration>,
    pub first_opens: bool,
    pub last_closes: bool,
    pub max_size: Option<usize>,
    pub patterns: Vec<String>,
}

impl Conditions {
    fn new(timeout: Duration) -> Conditions {
        Conditions {
            timeout: timeout,
            renew_timeout: None,
            first_opens: FIRST_OPENS_DEFAULT,
            last_closes: LAST_CLOSES_DEFAULT,
            max_size: None,
            patterns: Vec::new(),
        }
    }

    pub fn is_opening(&self, message: &Message) -> bool {
        if self.first_opens {
            message.ids().any(|x| x == self.patterns.first().unwrap())
        } else {
            true
        }
    }

    pub fn is_closing(&self, state: &State) -> bool {
        trace!("Conditions: shoud we close this context?");
        state.is_open() && self.is_closing_condition_met(state)
    }

    fn is_closing_condition_met(&self, state: &State) -> bool {
        self.is_max_size_reached(state) || self.is_closing_message(state) ||
        self.is_any_timer_expired(state)
    }

    fn is_max_size_reached(&self, state: &State) -> bool {
        self.max_size.map_or(false, |max_size| state.messages().len() >= max_size)
    }

    fn is_closing_message(&self, state: &State) -> bool {
        if self.last_closes {
            let last_message = state.messages().last().unwrap();
            last_message.ids().any(|x| x == self.patterns.last().unwrap())
        } else {
            false
        }
    }

    fn is_any_timer_expired(&self, state: &State) -> bool {
        self.is_timeout_expired(state) || self.is_renew_timeout_expired(state)
    }

    fn is_timeout_expired(&self, state: &State) -> bool {
        state.elapsed_time() >= self.timeout
    }

    fn is_renew_timeout_expired(&self, state: &State) -> bool {
        self.renew_timeout.map_or(false, |renew_timeout| {
            state.elapsed_time_since_last_message() >= renew_timeout
        })
    }
}

pub struct ConditionsBuilder {
    conditions: Conditions,
}

impl ConditionsBuilder {
    pub fn new(timeout: Duration) -> ConditionsBuilder {
        ConditionsBuilder { conditions: Conditions::new(timeout) }
    }

    pub fn renew_timeout(&mut self, timeout: Duration) -> &mut ConditionsBuilder {
        self.conditions.renew_timeout = Some(timeout);
        self
    }

    pub fn first_opens(&mut self, first_opens: bool) -> &mut ConditionsBuilder {
        self.conditions.first_opens = first_opens;
        self
    }

    pub fn last_closes(&mut self, last_closes: bool) -> &mut ConditionsBuilder {
        self.conditions.last_closes = last_closes;
        self
    }
    pub fn max_size(&mut self, max_size: usize) -> &mut ConditionsBuilder {
        self.conditions.max_size = Some(max_size);
        self
    }

    pub fn patterns(&mut self, patterns: Vec<String>) -> &mut ConditionsBuilder {
        self.conditions.patterns = patterns;
        self
    }

    pub fn build(&mut self) -> Conditions {
        self.conditions.clone()
    }
}

#[cfg(test)]
mod test {
    use serde_json::from_str;
    use super::Conditions;
    use std::rc::Rc;

    use message::MessageBuilder;
    use state::State;
    use super::ConditionsBuilder;
    use context::BaseContextBuilder;
    use uuid::Uuid;
    use std::time::Duration;

    #[test]
    fn test_given_condition_when_an_opening_message_is_received_then_the_state_becomes_opened() {
        let timeout = Duration::from_millis(100);
        let msg_id1 = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let msg_id2 = "21eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id1.clone(),
        ];
        let condition = ConditionsBuilder::new(timeout)
                            .patterns(patterns)
                            .first_opens(true)
                            .build();
        let msg_which_should_not_be_ignored = MessageBuilder::new(&msg_id1, "message").build();
        let msg_which_should_be_ignored = MessageBuilder::new(&msg_id2, "message").build();
        assert_false!(condition.is_opening(&msg_which_should_be_ignored));
        assert_true!(condition.is_opening(&msg_which_should_not_be_ignored));
    }

    #[test]
    fn test_given_condition_when_a_closing_message_is_received_then_the_state_becomes_closed() {
        let timeout = Duration::from_millis(100);
        let msg_id1 = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let msg_id2 = "21eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id1.clone(),
            msg_id2.clone(),
        ];
        let mut state = State::new();
        let conditions = ConditionsBuilder::new(timeout)
                             .patterns(patterns)
                             .last_closes(true)
                             .build();
        let context = BaseContextBuilder::new(Uuid::new_v4(), conditions).build();
        let msg_opening = Rc::new(MessageBuilder::new(&msg_id1, "message").build());
        let msg_closing = Rc::new(MessageBuilder::new(&msg_id2, "message").build());
        assert_false!(state.is_open());
        state.on_message(msg_opening, &context);
        assert_true!(state.is_open());
        state.on_message(msg_closing, &context);
        assert_false!(state.is_open());
    }

    #[test]
    fn test_given_conditions_in_json_when_we_have_only_the_required_ones_then_we_get_the_expected_result
        () {
        let json = r#"
        {
            "timeout": 100
        }
        "#;

        let conditions = from_str(json);
        println!("{:?}", &conditions);
        let conditions: Conditions = conditions.ok().expect("Failed to deserialize a Conditions \
                                                             struct with only a timeout field");
        assert_eq!(conditions.timeout, Duration::from_millis(100));
    }

    #[test]
    fn test_given_conditions_in_json_when_we_have_all_fields_then_we_get_the_expected_result() {
        let json = r#"
        {
            "timeout": 100,
            "renew_timeout": 50,
            "first_opens": true,
            "last_closes": false,
            "max_size": 42,
            "patterns": [
                "1f78c9f1-cd33-4f83-bbcd-9d59f73094d5",
                "2f78c9f1-cd33-4f83-bbcd-9d59f73094d5",
                "PATTERN_NAME"
            ]
        }
        "#;

        let expected_patterns = vec![
                "1f78c9f1-cd33-4f83-bbcd-9d59f73094d5".to_string(),
                "2f78c9f1-cd33-4f83-bbcd-9d59f73094d5".to_string(),
                "PATTERN_NAME".to_string(),
        ];
        let conditions = from_str(json);
        println!("{:?}", &conditions);
        let conditions: Conditions = conditions.ok()
                                               .expect("Failed to deserialize a Conditions struct");
        assert_eq!(conditions.timeout, Duration::from_millis(100));
        assert_eq!(conditions.renew_timeout, Some(Duration::from_millis(50)));
        assert_eq!(conditions.first_opens, true);
        assert_eq!(conditions.last_closes, false);
        assert_eq!(conditions.max_size, Some(42));
        assert_eq!(conditions.patterns, expected_patterns);
    }

    #[test]
    fn test_given_condition_when_there_are_no_patterns_then_any_message_can_open_the_context() {
        let timeout = Duration::from_millis(100);
        let msg_id = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let condition = ConditionsBuilder::new(timeout).build();
        let msg = MessageBuilder::new(&msg_id, "message").build();
        assert_true!(condition.is_opening(&msg));
    }

    #[test]
    fn test_given_condition_when_first_opens_is_set_then_the_right_message_can_open_the_context
        () {
        let timeout = Duration::from_millis(100);
        let patterns = vec![
                "p1".to_string(),
                "p2".to_string(),
                "p3".to_string(),
        ];
        let uuid = "e4f3f8b2-3135-4916-a5ea-621a754dab0d".to_string();
        let msg_id = "p1".to_string();
        let condition = ConditionsBuilder::new(timeout)
                            .patterns(patterns)
                            .first_opens(true)
                            .build();
        let msg = MessageBuilder::new(&uuid, "message").name(Some(&msg_id)).build();
        assert_true!(condition.is_opening(&msg));
    }

    #[test]
    fn test_given_conditions_when_last_closes_is_set_and_the_message_has_a_name_then_we_check_that_name
        () {
        let timeout = Duration::from_millis(100);
        let patterns = vec!["p1".to_string(), "p2".to_string()];
        let p1_uuid = "e4f3f8b2-3135-4916-a5ea-621a754dab0d".to_string();
        let p2_uuid = "f4f3f8b2-3135-4916-a5ea-621a754dab0d".to_string();
        let p1 = "p1".to_string();
        let p2 = "p2".to_string();
        let mut state = State::new();
        let conditions = ConditionsBuilder::new(timeout)
                             .patterns(patterns)
                             .first_opens(true)
                             .last_closes(true)
                             .build();
        let p1_msg = MessageBuilder::new(&p1_uuid, "message").name(Some(&p1)).build();
        let p2_msg = MessageBuilder::new(&p2_uuid, "message").name(Some(&p2)).build();
        let context = BaseContextBuilder::new(Uuid::new_v4(), conditions).build();
        assert_false!(state.is_open());
        state.on_message(Rc::new(p1_msg), &context);
        state.on_message(Rc::new(p2_msg), &context);
        assert_false!(state.is_open());
    }

    #[test]
    fn test_given_condition_when_first_opens_is_set_but_there_are_no_patterns_then_we_do_not_panic() {
        let msg = MessageBuilder::new("e4f3f8b2-3135-4916-a5ea-621a754dab0d", "message")
                                 .name(Some("p1"))
                                 .build();
        let conditions = ConditionsBuilder::new(Duration::from_millis(100))
                             .patterns(Vec::new())
                             .first_opens(true)
                             .build();
        let context = BaseContextBuilder::new(Uuid::new_v4(), conditions).build();
        let mut state = State::new();
        state.on_message(Rc::new(msg), &context);
    }
}

mod deser {
    use super::{Conditions, FIRST_OPENS_DEFAULT, LAST_CLOSES_DEFAULT};
    use serde::de::{Deserialize, Deserializer, Error, MapVisitor, Visitor};
    use std::time::Duration;
    use duration::SerializableDuration;

    impl Deserialize for Conditions {
        fn deserialize<D>(deserializer: &mut D) -> Result<Conditions, D::Error>
            where D: Deserializer
        {
            deserializer.visit_struct("Conditions", &[], ConditionsVisitor)
        }
    }

    enum Field {
        Timeout,
        RenewTimeout,
        FirstOpens,
        LastCloses,
        MaxSize,
        Patterns,
    }

    impl Deserialize for Field {
        fn deserialize<D>(deserializer: &mut D) -> Result<Field, D::Error>
            where D: Deserializer
        {
            struct FieldVisitor;

            impl Visitor for FieldVisitor {
                type Value = Field;

                fn visit_str<E>(&mut self, value: &str) -> Result<Field, E>
                    where E: Error
                {
                    match value {
                        "timeout" => Ok(Field::Timeout),
                        "renew_timeout" => Ok(Field::RenewTimeout),
                        "first_opens" => Ok(Field::FirstOpens),
                        "last_closes" => Ok(Field::LastCloses),
                        "max_size" => Ok(Field::MaxSize),
                        "patterns" => Ok(Field::Patterns),
                        name @ _ => Err(Error::syntax(&format!("Unexpected field: {}", name))),
                    }
                }
            }

            deserializer.visit(FieldVisitor)
        }
    }

    struct ConditionsVisitor;

    impl Visitor for ConditionsVisitor {
        type Value = Conditions;

        fn visit_map<V>(&mut self, mut visitor: V) -> Result<Conditions, V::Error>
            where V: MapVisitor
        {
            let mut timeout: Option<SerializableDuration> = None;
            let mut renew_timeout: Option<SerializableDuration> = None;
            let mut first_opens = FIRST_OPENS_DEFAULT;
            let mut last_closes = LAST_CLOSES_DEFAULT;
            let mut max_size = None;
            let mut patterns = None;

            while let Some(field) = try!(visitor.visit_key()) {
                match field {
                    Field::Timeout => timeout = Some(try!(visitor.visit_value())),
                    Field::RenewTimeout => renew_timeout = Some(try!(visitor.visit_value())),
                    Field::FirstOpens => first_opens = try!(visitor.visit_value()),
                    Field::LastCloses => last_closes = try!(visitor.visit_value()),
                    Field::MaxSize => max_size = Some(try!(visitor.visit_value())),
                    Field::Patterns => patterns = Some(try!(visitor.visit_value())),
                }
            }

            let timeout: Duration = match timeout {
                Some(timeout) => timeout.0,
                None => return visitor.missing_field("timeout"),
            };

            let renew_timeout = renew_timeout.map(|timeout| timeout.0);

            try!(visitor.end());

            Ok(Conditions {
                timeout: timeout,
                renew_timeout: renew_timeout,
                first_opens: first_opens,
                last_closes: last_closes,
                max_size: max_size,
                patterns: patterns.unwrap_or(Vec::new()),
            })
        }
    }
}
<commit_msg>Conditions: don't call unwrap() in is_opening()<commit_after>use message::Message;
use state::State;
use std::time::Duration;

const FIRST_OPENS_DEFAULT: bool = false;
const LAST_CLOSES_DEFAULT: bool = false;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Conditions {
    pub timeout: Duration,
    pub renew_timeout: Option<Duration>,
    pub first_opens: bool,
    pub last_closes: bool,
    pub max_size: Option<usize>,
    pub patterns: Vec<String>,
}

impl Conditions {
    fn new(timeout: Duration) -> Conditions {
        Conditions {
            timeout: timeout,
            renew_timeout: None,
            first_opens: FIRST_OPENS_DEFAULT,
            last_closes: LAST_CLOSES_DEFAULT,
            max_size: None,
            patterns: Vec::new(),
        }
    }

    pub fn is_opening(&self, message: &Message) -> bool {
        if self.first_opens {
            self.patterns.first().iter().any(|first|{ message.ids().any(|id| &id == first)})
        } else {
            true
        }
    }

    pub fn is_closing(&self, state: &State) -> bool {
        trace!("Conditions: shoud we close this context?");
        state.is_open() && self.is_closing_condition_met(state)
    }

    fn is_closing_condition_met(&self, state: &State) -> bool {
        self.is_max_size_reached(state) || self.is_closing_message(state) ||
        self.is_any_timer_expired(state)
    }

    fn is_max_size_reached(&self, state: &State) -> bool {
        self.max_size.map_or(false, |max_size| state.messages().len() >= max_size)
    }

    fn is_closing_message(&self, state: &State) -> bool {
        if self.last_closes {
            let last_message = state.messages().last().unwrap();
            last_message.ids().any(|x| x == self.patterns.last().unwrap())
        } else {
            false
        }
    }

    fn is_any_timer_expired(&self, state: &State) -> bool {
        self.is_timeout_expired(state) || self.is_renew_timeout_expired(state)
    }

    fn is_timeout_expired(&self, state: &State) -> bool {
        state.elapsed_time() >= self.timeout
    }

    fn is_renew_timeout_expired(&self, state: &State) -> bool {
        self.renew_timeout.map_or(false, |renew_timeout| {
            state.elapsed_time_since_last_message() >= renew_timeout
        })
    }
}

pub struct ConditionsBuilder {
    conditions: Conditions,
}

impl ConditionsBuilder {
    pub fn new(timeout: Duration) -> ConditionsBuilder {
        ConditionsBuilder { conditions: Conditions::new(timeout) }
    }

    pub fn renew_timeout(&mut self, timeout: Duration) -> &mut ConditionsBuilder {
        self.conditions.renew_timeout = Some(timeout);
        self
    }

    pub fn first_opens(&mut self, first_opens: bool) -> &mut ConditionsBuilder {
        self.conditions.first_opens = first_opens;
        self
    }

    pub fn last_closes(&mut self, last_closes: bool) -> &mut ConditionsBuilder {
        self.conditions.last_closes = last_closes;
        self
    }
    pub fn max_size(&mut self, max_size: usize) -> &mut ConditionsBuilder {
        self.conditions.max_size = Some(max_size);
        self
    }

    pub fn patterns(&mut self, patterns: Vec<String>) -> &mut ConditionsBuilder {
        self.conditions.patterns = patterns;
        self
    }

    pub fn build(&mut self) -> Conditions {
        self.conditions.clone()
    }
}

#[cfg(test)]
mod test {
    use serde_json::from_str;
    use super::Conditions;
    use std::rc::Rc;

    use message::MessageBuilder;
    use state::State;
    use super::ConditionsBuilder;
    use context::BaseContextBuilder;
    use uuid::Uuid;
    use std::time::Duration;

    #[test]
    fn test_given_condition_when_an_opening_message_is_received_then_the_state_becomes_opened() {
        let timeout = Duration::from_millis(100);
        let msg_id1 = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let msg_id2 = "21eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id1.clone(),
        ];
        let condition = ConditionsBuilder::new(timeout)
                            .patterns(patterns)
                            .first_opens(true)
                            .build();
        let msg_which_should_not_be_ignored = MessageBuilder::new(&msg_id1, "message").build();
        let msg_which_should_be_ignored = MessageBuilder::new(&msg_id2, "message").build();
        assert_false!(condition.is_opening(&msg_which_should_be_ignored));
        assert_true!(condition.is_opening(&msg_which_should_not_be_ignored));
    }

    #[test]
    fn test_given_condition_when_a_closing_message_is_received_then_the_state_becomes_closed() {
        let timeout = Duration::from_millis(100);
        let msg_id1 = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let msg_id2 = "21eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id1.clone(),
            msg_id2.clone(),
        ];
        let mut state = State::new();
        let conditions = ConditionsBuilder::new(timeout)
                             .patterns(patterns)
                             .last_closes(true)
                             .build();
        let context = BaseContextBuilder::new(Uuid::new_v4(), conditions).build();
        let msg_opening = Rc::new(MessageBuilder::new(&msg_id1, "message").build());
        let msg_closing = Rc::new(MessageBuilder::new(&msg_id2, "message").build());
        assert_false!(state.is_open());
        state.on_message(msg_opening, &context);
        assert_true!(state.is_open());
        state.on_message(msg_closing, &context);
        assert_false!(state.is_open());
    }

    #[test]
    fn test_given_conditions_in_json_when_we_have_only_the_required_ones_then_we_get_the_expected_result
        () {
        let json = r#"
        {
            "timeout": 100
        }
        "#;

        let conditions = from_str(json);
        println!("{:?}", &conditions);
        let conditions: Conditions = conditions.ok().expect("Failed to deserialize a Conditions \
                                                             struct with only a timeout field");
        assert_eq!(conditions.timeout, Duration::from_millis(100));
    }

    #[test]
    fn test_given_conditions_in_json_when_we_have_all_fields_then_we_get_the_expected_result() {
        let json = r#"
        {
            "timeout": 100,
            "renew_timeout": 50,
            "first_opens": true,
            "last_closes": false,
            "max_size": 42,
            "patterns": [
                "1f78c9f1-cd33-4f83-bbcd-9d59f73094d5",
                "2f78c9f1-cd33-4f83-bbcd-9d59f73094d5",
                "PATTERN_NAME"
            ]
        }
        "#;

        let expected_patterns = vec![
                "1f78c9f1-cd33-4f83-bbcd-9d59f73094d5".to_string(),
                "2f78c9f1-cd33-4f83-bbcd-9d59f73094d5".to_string(),
                "PATTERN_NAME".to_string(),
        ];
        let conditions = from_str(json);
        println!("{:?}", &conditions);
        let conditions: Conditions = conditions.ok()
                                               .expect("Failed to deserialize a Conditions struct");
        assert_eq!(conditions.timeout, Duration::from_millis(100));
        assert_eq!(conditions.renew_timeout, Some(Duration::from_millis(50)));
        assert_eq!(conditions.first_opens, true);
        assert_eq!(conditions.last_closes, false);
        assert_eq!(conditions.max_size, Some(42));
        assert_eq!(conditions.patterns, expected_patterns);
    }

    #[test]
    fn test_given_condition_when_there_are_no_patterns_then_any_message_can_open_the_context() {
        let timeout = Duration::from_millis(100);
        let msg_id = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let condition = ConditionsBuilder::new(timeout).build();
        let msg = MessageBuilder::new(&msg_id, "message").build();
        assert_true!(condition.is_opening(&msg));
    }

    #[test]
    fn test_given_condition_when_first_opens_is_set_then_the_right_message_can_open_the_context
        () {
        let timeout = Duration::from_millis(100);
        let patterns = vec![
                "p1".to_string(),
                "p2".to_string(),
                "p3".to_string(),
        ];
        let uuid = "e4f3f8b2-3135-4916-a5ea-621a754dab0d".to_string();
        let msg_id = "p1".to_string();
        let condition = ConditionsBuilder::new(timeout)
                            .patterns(patterns)
                            .first_opens(true)
                            .build();
        let msg = MessageBuilder::new(&uuid, "message").name(Some(&msg_id)).build();
        assert_true!(condition.is_opening(&msg));
    }

    #[test]
    fn test_given_conditions_when_last_closes_is_set_and_the_message_has_a_name_then_we_check_that_name
        () {
        let timeout = Duration::from_millis(100);
        let patterns = vec!["p1".to_string(), "p2".to_string()];
        let p1_uuid = "e4f3f8b2-3135-4916-a5ea-621a754dab0d".to_string();
        let p2_uuid = "f4f3f8b2-3135-4916-a5ea-621a754dab0d".to_string();
        let p1 = "p1".to_string();
        let p2 = "p2".to_string();
        let mut state = State::new();
        let conditions = ConditionsBuilder::new(timeout)
                             .patterns(patterns)
                             .first_opens(true)
                             .last_closes(true)
                             .build();
        let p1_msg = MessageBuilder::new(&p1_uuid, "message").name(Some(&p1)).build();
        let p2_msg = MessageBuilder::new(&p2_uuid, "message").name(Some(&p2)).build();
        let context = BaseContextBuilder::new(Uuid::new_v4(), conditions).build();
        assert_false!(state.is_open());
        state.on_message(Rc::new(p1_msg), &context);
        state.on_message(Rc::new(p2_msg), &context);
        assert_false!(state.is_open());
    }

    #[test]
    fn test_given_condition_when_first_opens_is_set_but_there_are_no_patterns_then_we_do_not_panic() {
        let msg = MessageBuilder::new("e4f3f8b2-3135-4916-a5ea-621a754dab0d", "message")
                                 .name(Some("p1"))
                                 .build();
        let conditions = ConditionsBuilder::new(Duration::from_millis(100))
                             .patterns(Vec::new())
                             .first_opens(true)
                             .build();
        let context = BaseContextBuilder::new(Uuid::new_v4(), conditions).build();
        let mut state = State::new();
        state.on_message(Rc::new(msg), &context);
    }
}

mod deser {
    use super::{Conditions, FIRST_OPENS_DEFAULT, LAST_CLOSES_DEFAULT};
    use serde::de::{Deserialize, Deserializer, Error, MapVisitor, Visitor};
    use std::time::Duration;
    use duration::SerializableDuration;

    impl Deserialize for Conditions {
        fn deserialize<D>(deserializer: &mut D) -> Result<Conditions, D::Error>
            where D: Deserializer
        {
            deserializer.visit_struct("Conditions", &[], ConditionsVisitor)
        }
    }

    enum Field {
        Timeout,
        RenewTimeout,
        FirstOpens,
        LastCloses,
        MaxSize,
        Patterns,
    }

    impl Deserialize for Field {
        fn deserialize<D>(deserializer: &mut D) -> Result<Field, D::Error>
            where D: Deserializer
        {
            struct FieldVisitor;

            impl Visitor for FieldVisitor {
                type Value = Field;

                fn visit_str<E>(&mut self, value: &str) -> Result<Field, E>
                    where E: Error
                {
                    match value {
                        "timeout" => Ok(Field::Timeout),
                        "renew_timeout" => Ok(Field::RenewTimeout),
                        "first_opens" => Ok(Field::FirstOpens),
                        "last_closes" => Ok(Field::LastCloses),
                        "max_size" => Ok(Field::MaxSize),
                        "patterns" => Ok(Field::Patterns),
                        name @ _ => Err(Error::syntax(&format!("Unexpected field: {}", name))),
                    }
                }
            }

            deserializer.visit(FieldVisitor)
        }
    }

    struct ConditionsVisitor;

    impl Visitor for ConditionsVisitor {
        type Value = Conditions;

        fn visit_map<V>(&mut self, mut visitor: V) -> Result<Conditions, V::Error>
            where V: MapVisitor
        {
            let mut timeout: Option<SerializableDuration> = None;
            let mut renew_timeout: Option<SerializableDuration> = None;
            let mut first_opens = FIRST_OPENS_DEFAULT;
            let mut last_closes = LAST_CLOSES_DEFAULT;
            let mut max_size = None;
            let mut patterns = None;

            while let Some(field) = try!(visitor.visit_key()) {
                match field {
                    Field::Timeout => timeout = Some(try!(visitor.visit_value())),
                    Field::RenewTimeout => renew_timeout = Some(try!(visitor.visit_value())),
                    Field::FirstOpens => first_opens = try!(visitor.visit_value()),
                    Field::LastCloses => last_closes = try!(visitor.visit_value()),
                    Field::MaxSize => max_size = Some(try!(visitor.visit_value())),
                    Field::Patterns => patterns = Some(try!(visitor.visit_value())),
                }
            }

            let timeout: Duration = match timeout {
                Some(timeout) => timeout.0,
                None => return visitor.missing_field("timeout"),
            };

            let renew_timeout = renew_timeout.map(|timeout| timeout.0);

            try!(visitor.end());

            Ok(Conditions {
                timeout: timeout,
                renew_timeout: renew_timeout,
                first_opens: first_opens,
                last_closes: last_closes,
                max_size: max_size,
                patterns: patterns.unwrap_or(Vec::new()),
            })
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::RingBuf;
use std::sync::Future;
use std::fmt;

use core_plugins::{
    MessageResponder,
    CtcpVersionResponder,
};

use parse::IrcMsg;
use event::IrcEvent;
use message_types::{client, server};
pub use connection::IrcConnectionCommand::{
    RawWrite,
    AddWatcher,
    AddBundler,
};

use watchers::{
    Bundler,
    BundlerManager,
    RegisterEventWatcher,
    RegisterResult,
    JoinBundlerTrigger,
    JoinResult,
    JoinEventWatcher,
    WhoBundlerTrigger,
    WhoResult,
    WhoEventWatcher,
    EventWatcher,
    BundlerTrigger,
};

pub enum IrcConnectionCommand {
    RawWrite(Vec<u8>),
    AddWatcher(Box<EventWatcher+Send>),
    AddBundler(Box<Bundler+Send>),
}

impl IrcConnectionCommand {
    pub fn raw_write(message: Vec<u8>) -> IrcConnectionCommand {
        IrcConnectionCommand::RawWrite(message)
    }
}

impl fmt::Show for IrcConnectionCommand {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            IrcConnectionCommand::RawWrite(ref s) => write!(f, "RawWrite({:?})", s),
            IrcConnectionCommand::AddWatcher(ref ew) => write!(f, "AddWatcher({:?}(...))", ew.get_name()),
            IrcConnectionCommand::AddBundler(ref bun) => write!(f, "AddBundler({:?}(...))", bun.get_name()),
        }
    }
}

pub struct IrcConnectionBuf {
    // Lines coming from the server
    incoming_lines: RingBuf<Vec<u8>>,

    // Lines going out to the server
    outgoing_msgs: RingBuf<Vec<u8>>,

    // Internal command queue
    command_queue: RingBuf<IrcConnectionCommand>,

    // Automatic responders e.g. the PING and CTCP handlers
    responders: RingBuf<Box<MessageResponder+Send>>,

    // manages active bundlers and emits events when they finish
    bundler_man: BundlerManager,

    // Current nickname held by the client
    current_nick: Option<String>,
}

impl IrcConnectionBuf {
    pub fn new() -> IrcConnectionBuf {
        let mut out = IrcConnectionBuf {
            incoming_lines: RingBuf::new(),
            outgoing_msgs: RingBuf::new(),
            command_queue: RingBuf::new(),
            responders: RingBuf::new(),
            bundler_man: BundlerManager::new(),
            current_nick: None,
        };
        out.responders.push_back(Box::new(CtcpVersionResponder::new()));
        out.bundler_man.add_bundler_trigger(Box::new(JoinBundlerTrigger::new()));
        out.bundler_man.add_bundler_trigger(Box::new(WhoBundlerTrigger::new()));
        out
    }

    pub fn push_line(&mut self, msg: Vec<u8>) {
        self.incoming_lines.push_back(msg);
    }

    pub fn pop_line(&mut self) -> Option<Vec<u8>> {
        match self.outgoing_msgs.pop_front() {
            Some(mut outgoing_line) => {
                outgoing_line.push_all(b"\r\n");
                Some(outgoing_line)
            },
            None => None
        }
    }

    fn add_watcher(&mut self, watcher: Box<EventWatcher+Send>) {
        self.bundler_man.add_watcher(watcher);
    }

    fn add_bundler(&mut self, bundler: Box<Bundler+Send>) {
        self.bundler_man.add_bundler(bundler);
    }

    pub fn dispatch(&mut self) -> Vec<IrcEvent> {
        while let Some(command) = self.command_queue.pop_front() {
            use self::IrcConnectionCommand::{RawWrite, AddWatcher, AddBundler};
            match command {
                RawWrite(value) => self.outgoing_msgs.push_back(value),
                AddWatcher(value) => self.add_watcher(value),
                AddBundler(value) => self.add_bundler(value),
            }
        }

        let mut outgoing_events = Vec::new();

        while let Some(incoming) = self.incoming_lines.pop_front() {
            let incoming_copy = incoming.clone();

            let msg = match IrcMsg::new(incoming) {
                Ok(msg) => msg,
                Err(reason) => {
                    panic!("Invalid msg: {:?} for {:?}", reason, incoming_copy);
                }
            };

            if msg.get_command() == "001" {
                self.current_nick = Some(String::from_utf8_lossy(&msg[0]).into_owned());
            }

            let msg = {
                let tymsg = server::IncomingMsg::from_msg(msg);

                if let server::IncomingMsg::Ping(ref msg) = tymsg {
                    if let Ok(response) = msg.get_response() {
                        self.outgoing_msgs.push_back(response.into_bytes());
                    }
                }

                if let server::IncomingMsg::Nick(ref msg) = tymsg {
                    if let Some(current_nick) = self.current_nick.clone() {
                        if current_nick.as_slice() == msg.get_nick() {
                            self.current_nick = Some(msg.get_new_nick().to_string())
                        }
                    }
                }

                tymsg.into_irc_msg()
            };

            outgoing_events.extend(self.bundler_man.on_irc_msg(&msg).into_iter());
            for responder in self.responders.iter_mut() {
                for resp_msg in responder.on_irc_msg(&msg).into_iter() {
                    self.outgoing_msgs.push_back(resp_msg.into_bytes());
                }
            }
        }

        outgoing_events
    }

    pub fn register(&mut self, nick: &str) -> Future<RegisterResult> {
        use self::IrcConnectionCommand::AddWatcher;

        let mut reg_watcher = RegisterEventWatcher::new();
        let result_future = reg_watcher.get_future();
        let watcher: Box<EventWatcher+Send> = Box::new(reg_watcher);

        self.command_queue.push_back(AddWatcher(watcher));
        self.outgoing_msgs.push_back(client::Nick::new(nick).into_irc_msg().into_bytes());
        self.outgoing_msgs.push_back(client::User::new(
            "rustirc", "0", "*", "http://github.com/infinityb/rust-irc"
        ).into_irc_msg().into_bytes());

        result_future
    }

    pub fn join(&mut self, channel: &str) -> Future<JoinResult> {
        use self::IrcConnectionCommand::AddWatcher;

        let mut join_watcher = JoinEventWatcher::new(channel.as_bytes());
        let result_future = join_watcher.get_future();
        let watcher: Box<EventWatcher+Send> = Box::new(join_watcher);

        self.command_queue.push_back(AddWatcher(watcher));
        self.outgoing_msgs.push_back(client::Join::new(channel).into_irc_msg().into_bytes());
        result_future

    }

    pub fn who(&mut self, target: &str) -> Future<WhoResult> {
        use self::IrcConnectionCommand::AddWatcher;

        let mut who_watcher = WhoEventWatcher::new(target.as_bytes());
        let result_future = who_watcher.get_future();
        let watcher: Box<EventWatcher+Send> = Box::new(who_watcher);

        self.command_queue.push_back(AddWatcher(watcher));
        self.outgoing_msgs.push_back(client::Who::new(target).into_irc_msg().into_bytes());
        result_future
    }
}

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

    #[test]
    fn test_pingpong() {
        let mut conn = IrcConnectionBuf::new();

        assert_eq!(conn.pop_line(), None);
        conn.push_line(b"PING pretend-server\r\n".to_vec());
        assert_eq!(conn.pop_line(), None);

        assert_eq!(conn.dispatch().len(), 1);
        assert_eq!(conn.pop_line(), Some(b"PONG pretend-server\r\n".to_vec()));
    }
}
<commit_msg>dispatch shouldn't return Events<commit_after>use std::collections::RingBuf;
use std::sync::Future;
use std::fmt;

use core_plugins::{
    MessageResponder,
    CtcpVersionResponder,
};

use parse::IrcMsg;
use event::IrcEvent;
use message_types::{client, server};
pub use connection::IrcConnectionCommand::{
    RawWrite,
    AddWatcher,
    AddBundler,
};

use watchers::{
    Bundler,
    BundlerManager,
    RegisterEventWatcher,
    RegisterResult,
    JoinBundlerTrigger,
    JoinResult,
    JoinEventWatcher,
    WhoBundlerTrigger,
    WhoResult,
    WhoEventWatcher,
    EventWatcher,
    BundlerTrigger,
};

pub enum IrcConnectionCommand {
    RawWrite(Vec<u8>),
    AddWatcher(Box<EventWatcher+Send>),
    AddBundler(Box<Bundler+Send>),
}

impl IrcConnectionCommand {
    pub fn raw_write(message: Vec<u8>) -> IrcConnectionCommand {
        IrcConnectionCommand::RawWrite(message)
    }
}

impl fmt::Show for IrcConnectionCommand {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            IrcConnectionCommand::RawWrite(ref s) => write!(f, "RawWrite({:?})", s),
            IrcConnectionCommand::AddWatcher(ref ew) => write!(f, "AddWatcher({:?}(...))", ew.get_name()),
            IrcConnectionCommand::AddBundler(ref bun) => write!(f, "AddBundler({:?}(...))", bun.get_name()),
        }
    }
}

pub struct IrcConnectionBuf {
    // Lines coming from the server
    incoming_lines: RingBuf<Vec<u8>>,

    // Lines going out to the server
    outgoing_msgs: RingBuf<Vec<u8>>,

    // outgoing event queue
    event_queue: RingBuf<IrcEvent>,

    // Internal command queue
    command_queue: RingBuf<IrcConnectionCommand>,

    // Automatic responders e.g. the PING and CTCP handlers
    responders: RingBuf<Box<MessageResponder+Send>>,

    // manages active bundlers and emits events when they finish
    bundler_man: BundlerManager,

    // Current nickname held by the client
    current_nick: Option<String>,
}

impl IrcConnectionBuf {
    pub fn new() -> IrcConnectionBuf {
        let mut out = IrcConnectionBuf {
            incoming_lines: RingBuf::new(),
            outgoing_msgs: RingBuf::new(),
            event_queue: RingBuf::new(),
            command_queue: RingBuf::new(),
            responders: RingBuf::new(),
            bundler_man: BundlerManager::new(),
            current_nick: None,
        };
        out.responders.push_back(Box::new(CtcpVersionResponder::new()));
        out.bundler_man.add_bundler_trigger(Box::new(JoinBundlerTrigger::new()));
        out.bundler_man.add_bundler_trigger(Box::new(WhoBundlerTrigger::new()));
        out
    }

    pub fn push_line(&mut self, msg: Vec<u8>) {
        self.incoming_lines.push_back(msg);
    }

    pub fn pop_line(&mut self) -> Option<Vec<u8>> {
        match self.outgoing_msgs.pop_front() {
            Some(mut outgoing_line) => {
                outgoing_line.push_all(b"\r\n");
                Some(outgoing_line)
            },
            None => None
        }
    }

    fn add_watcher(&mut self, watcher: Box<EventWatcher+Send>) {
        self.bundler_man.add_watcher(watcher);
    }

    fn add_bundler(&mut self, bundler: Box<Bundler+Send>) {
        self.bundler_man.add_bundler(bundler);
    }

    pub fn dispatch(&mut self) {
        while let Some(command) = self.command_queue.pop_front() {
            use self::IrcConnectionCommand::{RawWrite, AddWatcher, AddBundler};
            match command {
                RawWrite(value) => self.outgoing_msgs.push_back(value),
                AddWatcher(value) => self.add_watcher(value),
                AddBundler(value) => self.add_bundler(value),
            }
        }

        while let Some(incoming) = self.incoming_lines.pop_front() {
            let incoming_copy = incoming.clone();

            let msg = match IrcMsg::new(incoming) {
                Ok(msg) => msg,
                Err(reason) => {
                    panic!("Invalid msg: {:?} for {:?}", reason, incoming_copy);
                }
            };

            if msg.get_command() == "001" {
                self.current_nick = Some(String::from_utf8_lossy(&msg[0]).into_owned());
            }

            let msg = {
                let tymsg = server::IncomingMsg::from_msg(msg);

                if let server::IncomingMsg::Ping(ref msg) = tymsg {
                    if let Ok(response) = msg.get_response() {
                        self.outgoing_msgs.push_back(response.into_bytes());
                    }
                }

                if let server::IncomingMsg::Nick(ref msg) = tymsg {
                    if let Some(current_nick) = self.current_nick.clone() {
                        if current_nick.as_slice() == msg.get_nick() {
                            self.current_nick = Some(msg.get_new_nick().to_string())
                        }
                    }
                }

                tymsg.into_irc_msg()
            };

            self.event_queue.extend(self.bundler_man.on_irc_msg(&msg).into_iter());
            for responder in self.responders.iter_mut() {
                for resp_msg in responder.on_irc_msg(&msg).into_iter() {
                    self.outgoing_msgs.push_back(resp_msg.into_bytes());
                }
            }
        }
    }

    pub fn pop_event(&mut self) -> Option<IrcEvent> {
        self.event_queue.pop_front()
    }

    pub fn register(&mut self, nick: &str) -> Future<RegisterResult> {
        use self::IrcConnectionCommand::AddWatcher;

        let mut reg_watcher = RegisterEventWatcher::new();
        let result_future = reg_watcher.get_future();
        let watcher: Box<EventWatcher+Send> = Box::new(reg_watcher);

        self.command_queue.push_back(AddWatcher(watcher));
        self.outgoing_msgs.push_back(client::Nick::new(nick).into_irc_msg().into_bytes());
        self.outgoing_msgs.push_back(client::User::new(
            "rustirc", "0", "*", "http://github.com/infinityb/rust-irc"
        ).into_irc_msg().into_bytes());

        result_future
    }

    pub fn join(&mut self, channel: &str) -> Future<JoinResult> {
        use self::IrcConnectionCommand::AddWatcher;

        let mut join_watcher = JoinEventWatcher::new(channel.as_bytes());
        let result_future = join_watcher.get_future();
        let watcher: Box<EventWatcher+Send> = Box::new(join_watcher);

        self.command_queue.push_back(AddWatcher(watcher));
        self.outgoing_msgs.push_back(client::Join::new(channel).into_irc_msg().into_bytes());
        result_future

    }

    pub fn who(&mut self, target: &str) -> Future<WhoResult> {
        use self::IrcConnectionCommand::AddWatcher;

        let mut who_watcher = WhoEventWatcher::new(target.as_bytes());
        let result_future = who_watcher.get_future();
        let watcher: Box<EventWatcher+Send> = Box::new(who_watcher);

        self.command_queue.push_back(AddWatcher(watcher));
        self.outgoing_msgs.push_back(client::Who::new(target).into_irc_msg().into_bytes());
        result_future
    }
}

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

    #[test]
    fn test_pingpong() {
        let mut conn = IrcConnectionBuf::new();

        assert_eq!(conn.pop_line(), None);
        conn.push_line(b"PING pretend-server\r\n".to_vec());
        assert_eq!(conn.pop_line(), None);

        assert_eq!(conn.dispatch().len(), 1);
        assert_eq!(conn.pop_line(), Some(b"PONG pretend-server\r\n".to_vec()));
    }
}
<|endoftext|>


<commit_before>use crate::{KeyNotFoundError, ReadOnly, StringKey};
use std::borrow::Cow;
use std::convert::TryInto;
use std::ffi::{CStr, CString};

pub trait ReadableKey: AsRef<elektra_sys::Key> + PartialEq + Eq + PartialOrd + Ord {
    /// The type returned by value.
    type GetValue;

    /// Returns the value this key holds.
    /// # Examples
    /// ```
    /// # use elektra::{StringKey,WriteableKey,ReadableKey};
    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
    /// let mut key = StringKey::new("user/sw/app")?;
    /// key.set_value("myvalue");
    /// assert_eq!(key.value(), "myvalue");
    /// #
    /// #     Ok(())
    /// # }
    /// ```
    fn value(&self) -> Self::GetValue;

    /// Construct a new key from a raw key pointer
    unsafe fn from_ptr(ptr: *mut elektra_sys::Key) -> Self
    where
        Self: Sized;

    /// Return the name of the key as a borrowed slice.
    fn name(&self) -> Cow<str> {
        let c_str = unsafe { CStr::from_ptr(elektra_sys::keyName(self.as_ref())) };
        c_str.to_string_lossy()
    }

    /// Return the basename of the key as a borrowed slice.
    fn basename(&self) -> Cow<str> {
        let c_str = unsafe { CStr::from_ptr(elektra_sys::keyBaseName(self.as_ref())) };
        c_str.to_string_lossy()
    }

    /// Calculates number of bytes needed to store basename of key.
    fn basename_size(&self) -> isize {
        unsafe { elektra_sys::keyGetBaseNameSize(self.as_ref()) }
    }

    /// Bytes needed to store the key name including user domain and ending NULL.
    fn fullname_size(&self) -> usize {
        unsafe {
            elektra_sys::keyGetFullNameSize(self.as_ref())
                .try_into()
                .unwrap()
        }
    }

    /// Return how many references the key has.
    fn get_ref(&self) -> isize {
        unsafe { elektra_sys::keyGetRef(self.as_ref()) }
    }

    /// Returns the value of a meta-information which is current.
    fn current_meta(&self) -> ReadOnly<StringKey> {
        let key_ptr = unsafe { elektra_sys::keyCurrentMeta(self.as_ref()) };
        unsafe { ReadOnly::from_ptr(key_ptr as *mut elektra_sys::Key) }
    }

    /// Get key full name, including the user domain name.
    fn fullname(&self) -> String {
        let mut vec: Vec<u8> = Vec::with_capacity(self.fullname_size());

        let ret_val = unsafe {
            elektra_sys::keyGetFullName(
                self.as_ref(),
                vec.as_mut_ptr() as *mut std::os::raw::c_char,
                vec.capacity(),
            )
        };
        unsafe { vec.set_len(ret_val.try_into().unwrap()) };
        // Elektra strings are guaranteed not to contain NUL bytes
        unsafe {
            CStr::from_bytes_with_nul_unchecked(&vec)
                .to_string_lossy()
                .to_owned()
                .to_string()
        }
    }

    /// Returns the namespace of the name of this key.
    /// Note that there are some convenience methods implemented.
    ///
    /// # Examples
    /// ```
    /// # use elektra::{BinaryKey,WriteableKey,ReadableKey};
    /// # use elektra_sys;
    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
    /// let mut key = BinaryKey::new("user/sw/app")?;
    /// assert_eq!(key.namespace(), elektra_sys::KEY_NS_USER);
    /// #
    /// #     Ok(())
    /// # }
    /// ```
    fn namespace(&self) -> u32 {
        unsafe { elektra_sys::keyGetNamespace(self.as_ref())  as u32 }
    }

    /// Determines if the key is in the spec namespace
    fn is_spec(&self) -> bool {
        self.namespace() == elektra_sys::KEY_NS_SPEC
    }

    /// Determines if the key is in the dir namespace
    fn is_dir(&self) -> bool {
        self.namespace() == elektra_sys::KEY_NS_DIR
    }

    /// Determines if the key is in the proc namespace
    fn is_proc(&self) -> bool {
        self.namespace() == elektra_sys::KEY_NS_PROC
    }

    /// Determines if the key is in the user namespace
    fn is_user(&self) -> bool {
        self.namespace() == elektra_sys::KEY_NS_USER
    }

    /// Determines if the key is in the system namespace
    fn is_system(&self) -> bool {
        self.namespace() == elektra_sys::KEY_NS_SYSTEM
    }

    /// Determines if the key is a cascading key
    fn is_cascading(&self) -> bool {
        self.namespace() == elektra_sys::KEY_NS_CASCADING
    }

    /// Returns the number of bytes needed to store the key's value, including the
    /// NULL terminator.
    ///
    /// # Examples
    /// ```
    /// # use elektra::{BinaryKey,WriteableKey,ReadableKey};
    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
    /// let mut key = BinaryKey::new("user/sw/app")?;
    /// key.set_value(b"12345");
    /// assert_eq!(key.value_size(), 5);
    /// #
    /// #     Ok(())
    /// # }
    /// ```
    fn value_size(&self) -> usize {
        let ret_val = unsafe { elektra_sys::keyGetValueSize(self.as_ref()) };
        // keyGetValueSize returns -1 on null pointers, but we can be sure self.ptr is valid
        // so this conversion is safe
        ret_val.try_into().unwrap()
    }

    /// Returns true if the key has a binary value.
    ///
    /// # Notes
    /// Note that this does not return true for a newly created BinaryKey,
    /// but only when actual binary data has been set, due to the underlying
    /// generic Key.
    ///
    /// # Examples
    /// ```
    /// # use elektra::{BinaryKey,WriteableKey,ReadableKey};
    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
    /// let mut key = BinaryKey::new("user/sw/app")?;
    /// key.set_value(b"");
    /// assert!(key.is_binary());
    /// #
    /// #     Ok(())
    /// # }
    /// ```
    fn is_binary(&self) -> bool {
        unsafe { elektra_sys::keyIsBinary(self.as_ref()) == 1 }
    }

    /// Returns true if the key has a string value.
    ///
    /// # Examples
    /// ```
    /// # use elektra::{StringKey,WriteableKey,ReadableKey};
    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
    /// let key = StringKey::new("user/sw/app")?;
    /// assert!(key.is_string());
    /// #
    /// #     Ok(())
    /// # }
    /// ```
    fn is_string(&self) -> bool {
        unsafe { elektra_sys::keyIsString(self.as_ref()) == 1 }
    }

    /// Returns true if other is below self
    ///
    /// # Examples
    /// ```
    /// # use elektra::{StringKey,WriteableKey,ReadableKey};
    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
    /// let key = StringKey::new("user/sw/app")?;
    /// let key2 = StringKey::new("user/sw/app/folder/key")?;
    /// assert!(key2.is_below(&key));
    /// #
    /// #     Ok(())
    /// # }
    /// ```
    fn is_below(&self, other: &Self) -> bool
    where
        Self: Sized,
    {
        unsafe { elektra_sys::keyIsBelow(other.as_ref(), self.as_ref()) == 1 }
    }

    /// Returns true if other is *directly* below self
    ///
    /// # Examples
    /// ```
    /// # use elektra::{StringKey,WriteableKey,ReadableKey};
    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
    /// let key = StringKey::new("user/sw/app")?;
    /// let key2 = StringKey::new("user/sw/app/key")?;
    /// assert!(key2.is_direct_below(&key));
    /// #
    /// #     Ok(())
    /// # }
    /// ```
    fn is_direct_below(&self, other: &Self) -> bool
    where
        Self: Sized,
    {
        unsafe { elektra_sys::keyIsDirectlyBelow(other.as_ref(), self.as_ref()) == 1 }
    }

    /// Returns true if the key is inactive.
    ///
    /// In Elektra terminology a hierarchy of keys is inactive if the
    /// rootkey's basename starts with '.'. So a key is also inactive
    /// if it is below an inactive key.
    /// # Examples
    /// ```
    /// # use elektra::{StringKey,WriteableKey,ReadableKey};
    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
    /// let key = StringKey::new("user/key/.hidden")?;
    /// assert!(key.is_inactive());
    /// #
    /// #     Ok(())
    /// # }
    /// ```
    fn is_inactive(&self) -> bool {
        unsafe { elektra_sys::keyIsInactive(self.as_ref()) == 1 }
    }

    /// Returns the metadata with the given metaname
    ///
    /// # Errors
    /// Returns `KeyNotFoundError` if no metakey with the given name was found.
    ///
    /// # Panics
    /// Panics if the provided string contains interior nul bytes.
    fn meta(&self, metaname: &str) -> Result<ReadOnly<StringKey<'_>>, KeyNotFoundError>
    where
        Self: Sized,
    {
        let cstr = CString::new(metaname).unwrap();
        let key_ptr = unsafe { elektra_sys::keyGetMeta(self.as_ref(), cstr.as_ptr()) };
        if key_ptr.is_null() {
            Err(KeyNotFoundError::new(metaname.to_owned()))
        } else {
            let key: ReadOnly<StringKey<'_>> = unsafe { ReadOnly::from_ptr(key_ptr as *mut elektra_sys::Key) };
            Ok(key)
        }
    }
}
<commit_msg>Rust: Rename is_direct_below to is_directly_below<commit_after>use crate::{KeyNotFoundError, ReadOnly, StringKey};
use std::borrow::Cow;
use std::convert::TryInto;
use std::ffi::{CStr, CString};

pub trait ReadableKey: AsRef<elektra_sys::Key> + PartialEq + Eq + PartialOrd + Ord {
    /// The type returned by value.
    type GetValue;

    /// Returns the value this key holds.
    /// # Examples
    /// ```
    /// # use elektra::{StringKey,WriteableKey,ReadableKey};
    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
    /// let mut key = StringKey::new("user/sw/app")?;
    /// key.set_value("myvalue");
    /// assert_eq!(key.value(), "myvalue");
    /// #
    /// #     Ok(())
    /// # }
    /// ```
    fn value(&self) -> Self::GetValue;

    /// Construct a new key from a raw key pointer
    unsafe fn from_ptr(ptr: *mut elektra_sys::Key) -> Self
    where
        Self: Sized;

    /// Return the name of the key as a borrowed slice.
    fn name(&self) -> Cow<str> {
        let c_str = unsafe { CStr::from_ptr(elektra_sys::keyName(self.as_ref())) };
        c_str.to_string_lossy()
    }

    /// Return the basename of the key as a borrowed slice.
    fn basename(&self) -> Cow<str> {
        let c_str = unsafe { CStr::from_ptr(elektra_sys::keyBaseName(self.as_ref())) };
        c_str.to_string_lossy()
    }

    /// Calculates number of bytes needed to store basename of key.
    fn basename_size(&self) -> isize {
        unsafe { elektra_sys::keyGetBaseNameSize(self.as_ref()) }
    }

    /// Bytes needed to store the key name including user domain and ending NULL.
    fn fullname_size(&self) -> usize {
        unsafe {
            elektra_sys::keyGetFullNameSize(self.as_ref())
                .try_into()
                .unwrap()
        }
    }

    /// Return how many references the key has.
    fn get_ref(&self) -> isize {
        unsafe { elektra_sys::keyGetRef(self.as_ref()) }
    }

    /// Returns the value of a meta-information which is current.
    fn current_meta(&self) -> ReadOnly<StringKey> {
        let key_ptr = unsafe { elektra_sys::keyCurrentMeta(self.as_ref()) };
        unsafe { ReadOnly::from_ptr(key_ptr as *mut elektra_sys::Key) }
    }

    /// Get key full name, including the user domain name.
    fn fullname(&self) -> String {
        let mut vec: Vec<u8> = Vec::with_capacity(self.fullname_size());

        let ret_val = unsafe {
            elektra_sys::keyGetFullName(
                self.as_ref(),
                vec.as_mut_ptr() as *mut std::os::raw::c_char,
                vec.capacity(),
            )
        };
        unsafe { vec.set_len(ret_val.try_into().unwrap()) };
        // Elektra strings are guaranteed not to contain NUL bytes
        unsafe {
            CStr::from_bytes_with_nul_unchecked(&vec)
                .to_string_lossy()
                .to_owned()
                .to_string()
        }
    }

    /// Returns the namespace of the name of this key.
    /// Note that there are some convenience methods implemented.
    ///
    /// # Examples
    /// ```
    /// # use elektra::{BinaryKey,WriteableKey,ReadableKey};
    /// # use elektra_sys;
    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
    /// let mut key = BinaryKey::new("user/sw/app")?;
    /// assert_eq!(key.namespace(), elektra_sys::KEY_NS_USER);
    /// #
    /// #     Ok(())
    /// # }
    /// ```
    fn namespace(&self) -> u32 {
        unsafe { elektra_sys::keyGetNamespace(self.as_ref())  as u32 }
    }

    /// Determines if the key is in the spec namespace
    fn is_spec(&self) -> bool {
        self.namespace() == elektra_sys::KEY_NS_SPEC
    }

    /// Determines if the key is in the dir namespace
    fn is_dir(&self) -> bool {
        self.namespace() == elektra_sys::KEY_NS_DIR
    }

    /// Determines if the key is in the proc namespace
    fn is_proc(&self) -> bool {
        self.namespace() == elektra_sys::KEY_NS_PROC
    }

    /// Determines if the key is in the user namespace
    fn is_user(&self) -> bool {
        self.namespace() == elektra_sys::KEY_NS_USER
    }

    /// Determines if the key is in the system namespace
    fn is_system(&self) -> bool {
        self.namespace() == elektra_sys::KEY_NS_SYSTEM
    }

    /// Determines if the key is a cascading key
    fn is_cascading(&self) -> bool {
        self.namespace() == elektra_sys::KEY_NS_CASCADING
    }

    /// Returns the number of bytes needed to store the key's value, including the
    /// NULL terminator.
    ///
    /// # Examples
    /// ```
    /// # use elektra::{BinaryKey,WriteableKey,ReadableKey};
    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
    /// let mut key = BinaryKey::new("user/sw/app")?;
    /// key.set_value(b"12345");
    /// assert_eq!(key.value_size(), 5);
    /// #
    /// #     Ok(())
    /// # }
    /// ```
    fn value_size(&self) -> usize {
        let ret_val = unsafe { elektra_sys::keyGetValueSize(self.as_ref()) };
        // keyGetValueSize returns -1 on null pointers, but we can be sure self.ptr is valid
        // so this conversion is safe
        ret_val.try_into().unwrap()
    }

    /// Returns true if the key has a binary value.
    ///
    /// # Notes
    /// Note that this does not return true for a newly created BinaryKey,
    /// but only when actual binary data has been set, due to the underlying
    /// generic Key.
    ///
    /// # Examples
    /// ```
    /// # use elektra::{BinaryKey,WriteableKey,ReadableKey};
    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
    /// let mut key = BinaryKey::new("user/sw/app")?;
    /// key.set_value(b"");
    /// assert!(key.is_binary());
    /// #
    /// #     Ok(())
    /// # }
    /// ```
    fn is_binary(&self) -> bool {
        unsafe { elektra_sys::keyIsBinary(self.as_ref()) == 1 }
    }

    /// Returns true if the key has a string value.
    ///
    /// # Examples
    /// ```
    /// # use elektra::{StringKey,WriteableKey,ReadableKey};
    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
    /// let key = StringKey::new("user/sw/app")?;
    /// assert!(key.is_string());
    /// #
    /// #     Ok(())
    /// # }
    /// ```
    fn is_string(&self) -> bool {
        unsafe { elektra_sys::keyIsString(self.as_ref()) == 1 }
    }

    /// Returns true if other is below self
    ///
    /// # Examples
    /// ```
    /// # use elektra::{StringKey,WriteableKey,ReadableKey};
    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
    /// let key = StringKey::new("user/sw/app")?;
    /// let key2 = StringKey::new("user/sw/app/folder/key")?;
    /// assert!(key2.is_below(&key));
    /// #
    /// #     Ok(())
    /// # }
    /// ```
    fn is_below(&self, other: &Self) -> bool
    where
        Self: Sized,
    {
        unsafe { elektra_sys::keyIsBelow(other.as_ref(), self.as_ref()) == 1 }
    }

    /// Returns true if other is *directly* below self
    ///
    /// # Examples
    /// ```
    /// # use elektra::{StringKey,WriteableKey,ReadableKey};
    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
    /// let key = StringKey::new("user/sw/app")?;
    /// let key2 = StringKey::new("user/sw/app/key")?;
    /// assert!(key2.is_directly_below(&key));
    /// #
    /// #     Ok(())
    /// # }
    /// ```
    fn is_directly_below(&self, other: &Self) -> bool
    where
        Self: Sized,
    {
        unsafe { elektra_sys::keyIsDirectlyBelow(other.as_ref(), self.as_ref()) == 1 }
    }

    /// Returns true if the key is inactive.
    ///
    /// In Elektra terminology a hierarchy of keys is inactive if the
    /// rootkey's basename starts with '.'. So a key is also inactive
    /// if it is below an inactive key.
    /// # Examples
    /// ```
    /// # use elektra::{StringKey,WriteableKey,ReadableKey};
    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
    /// let key = StringKey::new("user/key/.hidden")?;
    /// assert!(key.is_inactive());
    /// #
    /// #     Ok(())
    /// # }
    /// ```
    fn is_inactive(&self) -> bool {
        unsafe { elektra_sys::keyIsInactive(self.as_ref()) == 1 }
    }

    /// Returns the metadata with the given metaname
    ///
    /// # Errors
    /// Returns `KeyNotFoundError` if no metakey with the given name was found.
    ///
    /// # Panics
    /// Panics if the provided string contains interior nul bytes.
    fn meta(&self, metaname: &str) -> Result<ReadOnly<StringKey<'_>>, KeyNotFoundError>
    where
        Self: Sized,
    {
        let cstr = CString::new(metaname).unwrap();
        let key_ptr = unsafe { elektra_sys::keyGetMeta(self.as_ref(), cstr.as_ptr()) };
        if key_ptr.is_null() {
            Err(KeyNotFoundError::new(metaname.to_owned()))
        } else {
            let key: ReadOnly<StringKey<'_>> = unsafe { ReadOnly::from_ptr(key_ptr as *mut elektra_sys::Key) };
            Ok(key)
        }
    }
}
<|endoftext|>


<commit_before>use chrono::NaiveDateTime;

use super::schema::*;

#[derive(Clone, Debug, Eq, Ord, Insertable, PartialEq, PartialOrd)]
#[table_name="fcp_proposal"]
pub struct NewFcpProposal<'a> {
    pub fk_issue: i32,
    pub fk_initiator: i32,
    pub fk_initiating_comment: i32,
    pub disposition: &'a str,
    pub fk_bot_tracking_comment: i32,
    pub fcp_start: Option<NaiveDateTime>,
    pub fcp_closed: bool,
}

#[derive(AsChangeset, Clone, Debug, Deserialize, Eq, Ord,
         PartialEq, PartialOrd, Queryable, Serialize)]
#[table_name="fcp_proposal"]
pub struct FcpProposal {
    pub id: i32,
    pub fk_issue: i32,
    pub fk_initiator: i32,
    pub fk_initiating_comment: i32,
    pub disposition: String,
    pub fk_bot_tracking_comment: i32,
    pub fcp_start: Option<NaiveDateTime>,
    pub fcp_closed: bool,
}

#[derive(Clone, Debug, Eq, Insertable, Ord, PartialEq, PartialOrd, Serialize)]
#[table_name="fcp_review_request"]
pub struct NewFcpReviewRequest {
    pub fk_proposal: i32,
    pub fk_reviewer: i32,
    pub reviewed: bool,
}

#[derive(AsChangeset, Clone, Debug, Deserialize, Eq, Ord,
         PartialEq, PartialOrd, Queryable, Serialize)]
#[table_name="fcp_review_request"]
pub struct FcpReviewRequest {
    pub id: i32,
    pub fk_proposal: i32,
    pub fk_reviewer: i32,
    pub reviewed: bool,
}

#[derive(Clone, Debug, Eq, Insertable, Ord, PartialEq, PartialOrd)]
#[table_name="fcp_concern"]
pub struct NewFcpConcern<'a> {
    pub fk_proposal: i32,
    pub fk_initiator: i32,
    pub fk_resolved_comment: Option<i32>,
    pub name: &'a str,
    pub fk_initiating_comment: i32,
}

#[derive(AsChangeset, Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Queryable)]
#[table_name="fcp_concern"]
pub struct FcpConcern {
    pub id: i32,
    pub fk_proposal: i32,
    pub fk_initiator: i32,
    pub fk_resolved_comment: Option<i32>,
    pub name: String,
    pub fk_initiating_comment: i32,
}

#[derive(Clone, Debug, Eq, Insertable, Ord, PartialEq, PartialOrd)]
#[table_name="rfc_feedback_request"]
pub struct NewFeedbackRequest {
    pub fk_initiator: i32,
    pub fk_requested: i32,
    pub fk_issue: i32,
    pub fk_feedback_comment: Option<i32>,
}

#[derive(AsChangeset, Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Queryable)]
#[table_name="rfc_feedback_request"]
pub struct FeedbackRequest {
    pub id: i32,
    pub fk_initiator: i32,
    pub fk_requested: i32,
    pub fk_issue: i32,
    pub fk_feedback_comment: Option<i32>,
}
<commit_msg>try to solve issue #217. diesel.rs documentation was misinterpreted wrt. proposal.fcp_start = None. (#218)<commit_after>use chrono::NaiveDateTime;

use super::schema::*;

#[derive(Clone, Debug, Eq, Ord, Insertable, PartialEq, PartialOrd)]
#[table_name="fcp_proposal"]
pub struct NewFcpProposal<'a> {
    pub fk_issue: i32,
    pub fk_initiator: i32,
    pub fk_initiating_comment: i32,
    pub disposition: &'a str,
    pub fk_bot_tracking_comment: i32,
    pub fcp_start: Option<NaiveDateTime>,
    pub fcp_closed: bool,
}

#[derive(AsChangeset, Clone, Debug, Deserialize, Eq, Ord,
         PartialEq, PartialOrd, Queryable, Serialize)]
#[table_name="fcp_proposal"]
#[changeset_options(treat_none_as_null="true")]
pub struct FcpProposal {
    pub id: i32,
    pub fk_issue: i32,
    pub fk_initiator: i32,
    pub fk_initiating_comment: i32,
    pub disposition: String,
    pub fk_bot_tracking_comment: i32,
    pub fcp_start: Option<NaiveDateTime>,
    pub fcp_closed: bool,
}

#[derive(Clone, Debug, Eq, Insertable, Ord, PartialEq, PartialOrd, Serialize)]
#[table_name="fcp_review_request"]
pub struct NewFcpReviewRequest {
    pub fk_proposal: i32,
    pub fk_reviewer: i32,
    pub reviewed: bool,
}

#[derive(AsChangeset, Clone, Debug, Deserialize, Eq, Ord,
         PartialEq, PartialOrd, Queryable, Serialize)]
#[table_name="fcp_review_request"]
pub struct FcpReviewRequest {
    pub id: i32,
    pub fk_proposal: i32,
    pub fk_reviewer: i32,
    pub reviewed: bool,
}

#[derive(Clone, Debug, Eq, Insertable, Ord, PartialEq, PartialOrd)]
#[table_name="fcp_concern"]
pub struct NewFcpConcern<'a> {
    pub fk_proposal: i32,
    pub fk_initiator: i32,
    pub fk_resolved_comment: Option<i32>,
    pub name: &'a str,
    pub fk_initiating_comment: i32,
}

#[derive(AsChangeset, Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Queryable)]
#[table_name="fcp_concern"]
pub struct FcpConcern {
    pub id: i32,
    pub fk_proposal: i32,
    pub fk_initiator: i32,
    pub fk_resolved_comment: Option<i32>,
    pub name: String,
    pub fk_initiating_comment: i32,
}

#[derive(Clone, Debug, Eq, Insertable, Ord, PartialEq, PartialOrd)]
#[table_name="rfc_feedback_request"]
pub struct NewFeedbackRequest {
    pub fk_initiator: i32,
    pub fk_requested: i32,
    pub fk_issue: i32,
    pub fk_feedback_comment: Option<i32>,
}

#[derive(AsChangeset, Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Queryable)]
#[table_name="rfc_feedback_request"]
pub struct FeedbackRequest {
    pub id: i32,
    pub fk_initiator: i32,
    pub fk_requested: i32,
    pub fk_issue: i32,
    pub fk_feedback_comment: Option<i32>,
}
<|endoftext|>