<commit_before>// Copyright 2013 The rust-pcre authors.
//
// 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.

#[link(name = "pcre", vers = "0.1")];
#[crate_type = "lib"];

use std::libc::{c_int, c_uchar, c_void};
use std::option::{Option};
use std::ptr;
use std::vec;

pub type options = c_int;
pub type study_options = c_int;

pub static PCRE_CASELESS: options = 0x00000001;
pub static PCRE_MULTILINE: options = 0x00000002;
pub static PCRE_DOTALL: options = 0x00000004;
pub static PCRE_EXTENDED: options = 0x00000008;
pub static PCRE_ANCHORED: options = 0x00000010;
pub static PCRE_DOLLAR_ENDONLY: options = 0x00000020;
pub static PCRE_EXTRA: options = 0x00000040;
pub static PCRE_NOTBOL: options = 0x00000080;
pub static PCRE_NOTEOL: options = 0x00000100;
pub static PCRE_UNGREEDY: options = 0x00000200;
pub static PCRE_NOTEMPTY: options = 0x00000400;
pub static PCRE_UTF8: options = 0x00000800;
pub static PCRE_UTF16: options = 0x00000800;
pub static PCRE_UTF32: options = 0x00000800;
pub static PCRE_NO_AUTO_CAPTURE: options = 0x00001000;
pub static PCRE_NO_UTF8_CHECK: options = 0x00002000;
pub static PCRE_NO_UTF16_CHECK: options = 0x00002000;
pub static PCRE_NO_UTF32_CHECK: options = 0x00002000;
pub static PCRE_AUTO_CALLOUT: options = 0x00004000;
pub static PCRE_PARTIAL_SOFT: options = 0x00008000;
pub static PCRE_PARTIAL: options = 0x00008000;
pub static PCRE_NEVER_UTF: options = 0x00010000;
pub static PCRE_DFA_SHORTEST: options = 0x00010000;
pub static PCRE_DFA_RESTART: options = 0x00020000;
pub static PCRE_FIRSTLINE: options = 0x00040000;
pub static PCRE_DUPNAMES: options = 0x00080000;
pub static PCRE_NEWLINE_CR: options = 0x00100000;
pub static PCRE_NEWLINE_LF: options = 0x00200000;
pub static PCRE_NEWLINE_CRLF: options = 0x00300000;
pub static PCRE_NEWLINE_ANY: options = 0x00400000;
pub static PCRE_NEWLINE_ANYCRLF: options = 0x00500000;
pub static PCRE_BSR_ANYCRLF: options = 0x00800000;
pub static PCRE_BSR_UNICODE: options = 0x01000000;
pub static PCRE_JAVASCRIPT_COMPAT: options = 0x02000000;
pub static PCRE_NO_START_OPTIMIZE: options = 0x04000000;
pub static PCRE_NO_START_OPTIMISE: options = 0x04000000;
pub static PCRE_PARTIAL_HARD: options = 0x08000000;
pub static PCRE_NOTEMPTY_ATSTART: options = 0x10000000;
pub static PCRE_UCP: options = 0x20000000;

pub static PCRE_STUDY_JIT_COMPILE: study_options = 0x0001;
pub static PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE: study_options = 0x0002;
pub static PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE: study_options = 0x0004;
pub static PCRE_STUDY_EXTRA_NEEDED: study_options = 0x0008;

mod detail;

pub struct Pcre {

    priv code: *detail::pcre,

    priv extra: *detail::pcre_extra,

    priv capture_count_: uint

}

pub struct Match<'self> {

    priv subject: &'self str,

    priv ovector: ~[c_int]

}

impl Pcre {
    fn compile(pattern: &str) -> Pcre {
        Pcre::compile_with_options(pattern, 0)
    }

    fn compile_with_options(pattern: &str, options: options) -> Pcre {
        do pattern.with_c_str |pattern_c_str| {
            // Use the default character tables.
            let tableptr: *c_uchar = ptr::null();
            let code = detail::pcre_compile(pattern_c_str, options, tableptr);
            assert!(ptr::is_not_null(code));

            let extra: *detail::pcre_extra = ptr::null();

            let mut capture_count: c_int = 0;
            detail::pcre_fullinfo(code, extra, detail::PCRE_INFO_CAPTURECOUNT, &mut capture_count as *mut c_int as *mut c_void);

            Pcre {
                code: code,
                extra: extra,
                capture_count_: capture_count as uint
            }
        }
    }

    fn capture_count(&self) -> uint {
        self.capture_count_
    }

    fn exec<'a>(&self, subject: &'a str) -> Option<Match<'a>> {
        self.exec_from(subject, 0)
    }

    fn exec_from<'a>(&self, subject: &'a str, startoffset: uint) -> Option<Match<'a>> {
        self.exec_from_with_options(subject, startoffset, 0)
    }

    fn exec_from_with_options<'a>(&self, subject: &'a str, startoffset: uint, options: options) -> Option<Match<'a>> {
        let ovecsize = (self.capture_count_ + 1) * 3;
        let mut ovector: ~[c_int] = vec::from_elem(ovecsize, 0 as c_int);

        unsafe {
            do subject.with_c_str_unchecked |subject_c_str| -> Option<Match<'a>> {
                if detail::pcre_exec(self.code, self.extra, subject_c_str, subject.len() as c_int, startoffset as c_int, options, vec::raw::to_mut_ptr(ovector), ovecsize as c_int) {
                    Some(Match {
                        subject: subject,
                        // TODO: Is it possible to avoid to_owned()?
                        // Probably need multiple lifetime parameters:
                        // https://mail.mozilla.org/pipermail/rust-dev/2013-September/005829.html
                        ovector: ovector.slice_to((self.capture_count_ + 1) * 2).to_owned()
                    })
                } else {
                    None
                }
            }
        }
    }

    fn study(&mut self) -> bool {
        self.study_with_options(0)
    }

    fn study_with_options(&mut self, options: study_options) -> bool {
        // Free any current study data.
        detail::pcre_free_study(self.extra);
        self.extra = ptr::null();

        let extra = detail::pcre_study(self.code, options);
        self.extra = extra;
        ptr::is_not_null(extra)
    }
}

impl Drop for Pcre {
    fn drop(&mut self) {
        detail::pcre_free_study(self.extra);
        self.extra = ptr::null();
        detail::pcre_free(self.code as *c_void);
        self.code = ptr::null();
    }
}

impl<'self> Match<'self> {

    fn group_start(&self, n: uint) -> uint {
        self.ovector[(n * 2) as uint] as uint
    }

    fn group_end(&self, n: uint) -> uint {
        self.ovector[(n * 2 + 1) as uint] as uint
    }

    fn group_len(&self, n: uint) -> uint {
        let group_offsets = self.ovector.slice_from((n * 2) as uint);
        (group_offsets[1] - group_offsets[0]) as uint
    }

    fn group(&self, n: uint) -> &'self str {
        let group_offsets = self.ovector.slice_from((n * 2) as uint);
        let start = group_offsets[0];
        let end = group_offsets[1];
        self.subject.slice(start as uint, end as uint)
    }

}

#[cfg(test)]
mod test {

    #[test]
    #[should_fail]
    fn test_compile_nul() {
        // Nul bytes are not allowed in the pattern string.
        ::Pcre::compile("\0abc");
    }

    #[test]
    #[should_fail]
    fn test_compile_bad_pattern() {
        ::Pcre::compile("[");
    }

    #[test]
    fn test_compile_capture_count() {
        let re = ::Pcre::compile("(?:abc)(def)");
        assert_eq!(re.capture_count(), 1u);
    }

    #[test]
    fn test_exec_basic() {
        let re = ::Pcre::compile("^...$");
        assert_eq!(re.capture_count(), 0u);
        let m = re.exec("abc").unwrap();
        assert_eq!(m.group(0), "abc");
    }

    #[test]
    fn test_exec_no_match() {
        let re = ::Pcre::compile("abc");
        assert!(re.exec("def").is_none());
    }

    #[test]
    fn test_exec_nul_byte() {
        // Nul bytes *are* allowed in subject strings, however.
        let re = ::Pcre::compile("abc\\0def");
        let m = re.exec("abc\0def").unwrap();
        assert_eq!(m.group(0), "abc\0def");
    }

    #[test]
    fn test_exec_from_basic() {
        let re = ::Pcre::compile("abc");
        let subject = "abcabc";
        let m1 = re.exec_from(subject, 1u).unwrap();
        assert_eq!(m1.group_start(0u), 3u);
        assert_eq!(m1.group_end(0u), 6u);
        assert_eq!(m1.group_len(0u), 3u);
        let m2 = re.exec(subject).unwrap();
        assert_eq!(m2.group_start(0u), 0u);
    }

    #[test]
    fn test_study_basic() {
        let mut re = ::Pcre::compile("abc");
        let mut study_res = re.study();
        assert!(study_res);
        // Re-study the pattern two more times (to check for leaks when the test program
        // is run through Valgrind).
        study_res = re.study();
        assert!(study_res);
        study_res = re.study();
        assert!(study_res);
    }
}
<commit_msg>Make the `Pcre` and `Match` impl methods public<commit_after>// Copyright 2013 The rust-pcre authors.
//
// 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.

#[link(name = "pcre", vers = "0.1")];
#[crate_type = "lib"];

use std::libc::{c_int, c_uchar, c_void};
use std::option::{Option};
use std::ptr;
use std::vec;

pub type options = c_int;
pub type study_options = c_int;

pub static PCRE_CASELESS: options = 0x00000001;
pub static PCRE_MULTILINE: options = 0x00000002;
pub static PCRE_DOTALL: options = 0x00000004;
pub static PCRE_EXTENDED: options = 0x00000008;
pub static PCRE_ANCHORED: options = 0x00000010;
pub static PCRE_DOLLAR_ENDONLY: options = 0x00000020;
pub static PCRE_EXTRA: options = 0x00000040;
pub static PCRE_NOTBOL: options = 0x00000080;
pub static PCRE_NOTEOL: options = 0x00000100;
pub static PCRE_UNGREEDY: options = 0x00000200;
pub static PCRE_NOTEMPTY: options = 0x00000400;
pub static PCRE_UTF8: options = 0x00000800;
pub static PCRE_UTF16: options = 0x00000800;
pub static PCRE_UTF32: options = 0x00000800;
pub static PCRE_NO_AUTO_CAPTURE: options = 0x00001000;
pub static PCRE_NO_UTF8_CHECK: options = 0x00002000;
pub static PCRE_NO_UTF16_CHECK: options = 0x00002000;
pub static PCRE_NO_UTF32_CHECK: options = 0x00002000;
pub static PCRE_AUTO_CALLOUT: options = 0x00004000;
pub static PCRE_PARTIAL_SOFT: options = 0x00008000;
pub static PCRE_PARTIAL: options = 0x00008000;
pub static PCRE_NEVER_UTF: options = 0x00010000;
pub static PCRE_DFA_SHORTEST: options = 0x00010000;
pub static PCRE_DFA_RESTART: options = 0x00020000;
pub static PCRE_FIRSTLINE: options = 0x00040000;
pub static PCRE_DUPNAMES: options = 0x00080000;
pub static PCRE_NEWLINE_CR: options = 0x00100000;
pub static PCRE_NEWLINE_LF: options = 0x00200000;
pub static PCRE_NEWLINE_CRLF: options = 0x00300000;
pub static PCRE_NEWLINE_ANY: options = 0x00400000;
pub static PCRE_NEWLINE_ANYCRLF: options = 0x00500000;
pub static PCRE_BSR_ANYCRLF: options = 0x00800000;
pub static PCRE_BSR_UNICODE: options = 0x01000000;
pub static PCRE_JAVASCRIPT_COMPAT: options = 0x02000000;
pub static PCRE_NO_START_OPTIMIZE: options = 0x04000000;
pub static PCRE_NO_START_OPTIMISE: options = 0x04000000;
pub static PCRE_PARTIAL_HARD: options = 0x08000000;
pub static PCRE_NOTEMPTY_ATSTART: options = 0x10000000;
pub static PCRE_UCP: options = 0x20000000;

pub static PCRE_STUDY_JIT_COMPILE: study_options = 0x0001;
pub static PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE: study_options = 0x0002;
pub static PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE: study_options = 0x0004;
pub static PCRE_STUDY_EXTRA_NEEDED: study_options = 0x0008;

mod detail;

pub struct Pcre {

    priv code: *detail::pcre,

    priv extra: *detail::pcre_extra,

    priv capture_count_: uint

}

pub struct Match<'self> {

    priv subject: &'self str,

    priv ovector: ~[c_int]

}

impl Pcre {
    pub fn compile(pattern: &str) -> Pcre {
        Pcre::compile_with_options(pattern, 0)
    }

    pub fn compile_with_options(pattern: &str, options: options) -> Pcre {
        do pattern.with_c_str |pattern_c_str| {
            // Use the default character tables.
            let tableptr: *c_uchar = ptr::null();
            let code = detail::pcre_compile(pattern_c_str, options, tableptr);
            assert!(ptr::is_not_null(code));

            let extra: *detail::pcre_extra = ptr::null();

            let mut capture_count: c_int = 0;
            detail::pcre_fullinfo(code, extra, detail::PCRE_INFO_CAPTURECOUNT, &mut capture_count as *mut c_int as *mut c_void);

            Pcre {
                code: code,
                extra: extra,
                capture_count_: capture_count as uint
            }
        }
    }

    pub fn capture_count(&self) -> uint {
        self.capture_count_
    }

    pub fn exec<'a>(&self, subject: &'a str) -> Option<Match<'a>> {
        self.exec_from(subject, 0)
    }

    pub fn exec_from<'a>(&self, subject: &'a str, startoffset: uint) -> Option<Match<'a>> {
        self.exec_from_with_options(subject, startoffset, 0)
    }

    pub fn exec_from_with_options<'a>(&self, subject: &'a str, startoffset: uint, options: options) -> Option<Match<'a>> {
        let ovecsize = (self.capture_count_ + 1) * 3;
        let mut ovector: ~[c_int] = vec::from_elem(ovecsize, 0 as c_int);

        unsafe {
            do subject.with_c_str_unchecked |subject_c_str| -> Option<Match<'a>> {
                if detail::pcre_exec(self.code, self.extra, subject_c_str, subject.len() as c_int, startoffset as c_int, options, vec::raw::to_mut_ptr(ovector), ovecsize as c_int) {
                    Some(Match {
                        subject: subject,
                        // TODO: Is it possible to avoid to_owned()?
                        // Probably need multiple lifetime parameters:
                        // https://mail.mozilla.org/pipermail/rust-dev/2013-September/005829.html
                        ovector: ovector.slice_to((self.capture_count_ + 1) * 2).to_owned()
                    })
                } else {
                    None
                }
            }
        }
    }

    pub fn study(&mut self) -> bool {
        self.study_with_options(0)
    }

    pub fn study_with_options(&mut self, options: study_options) -> bool {
        // Free any current study data.
        detail::pcre_free_study(self.extra);
        self.extra = ptr::null();

        let extra = detail::pcre_study(self.code, options);
        self.extra = extra;
        ptr::is_not_null(extra)
    }
}

impl Drop for Pcre {
    fn drop(&mut self) {
        detail::pcre_free_study(self.extra);
        self.extra = ptr::null();
        detail::pcre_free(self.code as *c_void);
        self.code = ptr::null();
    }
}

impl<'self> Match<'self> {

    pub fn group_start(&self, n: uint) -> uint {
        self.ovector[(n * 2) as uint] as uint
    }

    pub fn group_end(&self, n: uint) -> uint {
        self.ovector[(n * 2 + 1) as uint] as uint
    }

    pub fn group_len(&self, n: uint) -> uint {
        let group_offsets = self.ovector.slice_from((n * 2) as uint);
        (group_offsets[1] - group_offsets[0]) as uint
    }

    pub fn group(&self, n: uint) -> &'self str {
        let group_offsets = self.ovector.slice_from((n * 2) as uint);
        let start = group_offsets[0];
        let end = group_offsets[1];
        self.subject.slice(start as uint, end as uint)
    }

}

#[cfg(test)]
mod test {

    #[test]
    #[should_fail]
    fn test_compile_nul() {
        // Nul bytes are not allowed in the pattern string.
        ::Pcre::compile("\0abc");
    }

    #[test]
    #[should_fail]
    fn test_compile_bad_pattern() {
        ::Pcre::compile("[");
    }

    #[test]
    fn test_compile_capture_count() {
        let re = ::Pcre::compile("(?:abc)(def)");
        assert_eq!(re.capture_count(), 1u);
    }

    #[test]
    fn test_exec_basic() {
        let re = ::Pcre::compile("^...$");
        assert_eq!(re.capture_count(), 0u);
        let m = re.exec("abc").unwrap();
        assert_eq!(m.group(0), "abc");
    }

    #[test]
    fn test_exec_no_match() {
        let re = ::Pcre::compile("abc");
        assert!(re.exec("def").is_none());
    }

    #[test]
    fn test_exec_nul_byte() {
        // Nul bytes *are* allowed in subject strings, however.
        let re = ::Pcre::compile("abc\\0def");
        let m = re.exec("abc\0def").unwrap();
        assert_eq!(m.group(0), "abc\0def");
    }

    #[test]
    fn test_exec_from_basic() {
        let re = ::Pcre::compile("abc");
        let subject = "abcabc";
        let m1 = re.exec_from(subject, 1u).unwrap();
        assert_eq!(m1.group_start(0u), 3u);
        assert_eq!(m1.group_end(0u), 6u);
        assert_eq!(m1.group_len(0u), 3u);
        let m2 = re.exec(subject).unwrap();
        assert_eq!(m2.group_start(0u), 0u);
    }

    #[test]
    fn test_study_basic() {
        let mut re = ::Pcre::compile("abc");
        let mut study_res = re.study();
        assert!(study_res);
        // Re-study the pattern two more times (to check for leaks when the test program
        // is run through Valgrind).
        study_res = re.study();
        assert!(study_res);
        study_res = re.study();
        assert!(study_res);
    }
}
<|endoftext|>


<commit_before>use std::collections::VecDeque;

use crate::{api::prelude::*, proc_macros::*};

/// This state can be used to operate on the `Pager` widget inside of callbacks.
#[derive(Debug, Clone, PartialEq)]
enum PagerAction {
    Next,
    Previous,
    Navigate(usize),
    NavigateToCurrent,
    Remove(usize),
    Insert(usize, Entity),
}

#[derive(Default, Clone, Debug, AsAny)]
pub struct PagerState {
    current_index: usize,
    actions: VecDeque<PagerAction>,
}

impl PagerState {
    // used internal to navigate to the current index.
    fn navigate_to_current_index(&mut self) {
        self.actions.push_front(PagerAction::NavigateToCurrent);
    }

    /// Navigates to the next child. If the current child is the last in the list nothing will happen.
    pub fn next(&mut self) {
        self.actions.push_front(PagerAction::Next);
    }

    /// Navigates to the previous child. If the current child is the first in the list nothing will happen.
    pub fn previous(&mut self) {
        self.actions.push_front(PagerAction::Previous);
    }

    /// Navigates to the given index. Is the index out of bounds nothing will happen.
    pub fn navigate(&mut self, index: usize) {
        self.actions.push_front(PagerAction::Navigate(index));
    }

    /// Removes the child on the given index. If the index is out of bounds nothing will happen.
    pub fn remove(&mut self, index: usize) {
        self.actions.push_front(PagerAction::Remove(index));
    }

    /// Inserts a child on the given position.
    pub fn insert(&mut self, index: usize, entity: Entity) {
        self.actions.push_front(PagerAction::Insert(index, entity));
    }
}

impl State for PagerState {
    fn init(&mut self, _registry: &mut Registry, ctx: &mut Context) {
        let current_index = Pager::correct_current_index(ctx);

        if let Some(count) = ctx.widget().children_count() {
            for i in 0..count {
                // make child on the current index always visible (todo: use current_index)
                if i == current_index {
                    if let Some(child) = &mut ctx.try_child_from_index(i) {
                        child.set("visibility", Visibility::Visible);
                    }

                    continue;
                }

                // collapse all other children
                if let Some(child) = &mut ctx.try_child_from_index(i) {
                    child.set("visibility", Visibility::Collapsed);
                }
            }
        }

        Pager::update_next_previous_enabled(ctx, current_index);
    }

    fn update(&mut self, _registry: &mut Registry, ctx: &mut Context) {
        if let Some(action) = self.actions.pop_front() {
            match action {
                PagerAction::Next => Pager::next(ctx, ctx.entity),
                PagerAction::Previous => Pager::previous(ctx, ctx.entity),
                PagerAction::Navigate(index) => Pager::navigate(ctx, ctx.entity, index),
                PagerAction::Remove(index) => Pager::remove(ctx, ctx.entity, index),
                PagerAction::Insert(index, entity) => Pager::insert(ctx, ctx.entity, index, entity),
                PagerAction::NavigateToCurrent => {
                    let current_index = Pager::correct_current_index(ctx);
                    Pager::navigate(ctx, ctx.entity, current_index);
                }
            }
        }
    }
}

widget!(
    /// `Pager` is a navigation widget that provides a stack based navigation.
    ///
    /// # Example
    ///
    /// ```rust
    /// tbd
    /// ```
    Pager<PagerState> {
        /// Defines the index of the current shown child.
        current_index: usize,

        /// Used to check if  next can be executed. If the current visible child is the last child next can not be executed.
        next_enabled: bool,

        /// Used to check if a previous can be executed. If the current visible child is the first child previous can not be executed.
        previous_enabled: bool
    }
);

impl Pager {
    // checks and updates if next and previous can be executed.
    fn update_next_previous_enabled(ctx: &mut Context, current_index: usize) {
        if current_index == 0 {
            Pager::next_enabled_set(&mut ctx.widget(), false);
        } else {
            Pager::next_enabled_set(&mut ctx.widget(), true);
        }

        if let Some(count) = ctx.widget().children_count() {
            if current_index == count - 1 {
                Pager::previous_enabled_set(&mut ctx.widget(), false);
            } else {
                Pager::previous_enabled_set(&mut ctx.widget(), true);
            }
        }
    }

    // corrects the current_index to bounds and returns the corrected value.
    fn correct_current_index(ctx: &mut Context) -> usize {
        let mut current_index = *Pager::current_index_ref(&ctx.widget());
        if let Some(count) = ctx.widget().children_count() {
            if current_index >= count {
                current_index = count - 1;
            }
        }

        Pager::current_index_set(&mut ctx.widget(), current_index);

        current_index
    }

    /// Navigates to the next child. If the current child is the last in the list nothing will happen.
    pub fn next(ctx: &mut Context, entity: Entity) {
        let current_index = *Pager::current_index_ref(&ctx.get_widget(entity));
        Pager::navigate(ctx, entity, current_index + 1);
    }

    /// Navigates to the previous child. If the current child is the first in the list nothing will happen.
    pub fn previous(ctx: &mut Context, entity: Entity) {
        let current_index = *Pager::current_index_ref(&ctx.get_widget(entity));
        Pager::navigate(ctx, entity, current_index - 1);
    }

    /// Navigates to the given index. Is the index out of bounds nothing will happen.
    pub fn navigate(ctx: &mut Context, entity: Entity, index: usize) {
        // update enabled next / previous
        Pager::panics_on_wrong_type(&ctx.get_widget(entity));

        let current_index = *Pager::current_index_ref(&ctx.get_widget(entity));

        if let Some(count) = ctx.get_widget(entity).children_count() {
            if index >= count {
                return;
            }

            if let Some(child) = &mut ctx.try_child_from_index(current_index) {
                child.set("visibility", Visibility::Collapsed);
            }

            if let Some(child) = &mut ctx.try_child_from_index(index) {
                child.set("visibility", Visibility::Visible);
            }

            Pager::current_index_set(&mut ctx.get_widget(entity), index);

            Pager::update_next_previous_enabled(ctx, index);
        }
    }

    /// Removes the child on the given index. If the index is out of bounds nothing will happen.
    pub fn remove(ctx: &mut Context, entity: Entity, index: usize) {
        // update enabled next / previous
        Pager::panics_on_wrong_type(&ctx.get_widget(entity));
    }

    /// Inserts a child on the given position.
    pub fn insert(ctx: &mut Context, entity: Entity, index: usize, child: Entity) {
        // update enabled next / previous
        Pager::panics_on_wrong_type(&ctx.get_widget(entity));
    }
}

impl Template for Pager {
    fn template(self, _id: Entity, _context: &mut BuildContext) -> Self {
        self.name("Pager").on_changed("current_index", |states, id| {
            states.get_mut::<PagerState>(id).navigate_to_current_index();
        })
    }
}
<commit_msg>add a todo<commit_after>use std::collections::VecDeque;

use crate::{api::prelude::*, proc_macros::*};

/// This state can be used to operate on the `Pager` widget inside of callbacks.
#[derive(Debug, Clone, PartialEq)]
enum PagerAction {
    Next,
    Previous,
    Navigate(usize),
    NavigateToCurrent,
    Remove(usize),
    Insert(usize, Entity),
}

#[derive(Default, Clone, Debug, AsAny)]
pub struct PagerState {
    current_index: usize,
    actions: VecDeque<PagerAction>,
}

impl PagerState {
    // used internal to navigate to the current index.
    fn navigate_to_current_index(&mut self) {
        self.actions.push_front(PagerAction::NavigateToCurrent);
    }

    /// Navigates to the next child. If the current child is the last in the list nothing will happen.
    pub fn next(&mut self) {
        self.actions.push_front(PagerAction::Next);
    }

    /// Navigates to the previous child. If the current child is the first in the list nothing will happen.
    pub fn previous(&mut self) {
        self.actions.push_front(PagerAction::Previous);
    }

    /// Navigates to the given index. Is the index out of bounds nothing will happen.
    pub fn navigate(&mut self, index: usize) {
        self.actions.push_front(PagerAction::Navigate(index));
    }

    /// Removes the child on the given index. If the index is out of bounds nothing will happen.
    pub fn remove(&mut self, index: usize) {
        self.actions.push_front(PagerAction::Remove(index));
    }

    /// Inserts a child on the given position.
    pub fn insert(&mut self, index: usize, entity: Entity) {
        self.actions.push_front(PagerAction::Insert(index, entity));
    }
}

impl State for PagerState {
    fn init(&mut self, _registry: &mut Registry, ctx: &mut Context) {
        let current_index = Pager::correct_current_index(ctx);

        if let Some(count) = ctx.widget().children_count() {
            for i in 0..count {
                // make child on the current index always visible (todo: use current_index)
                if i == current_index {
                    if let Some(child) = &mut ctx.try_child_from_index(i) {
                        child.set("visibility", Visibility::Visible);
                    }

                    continue;
                }

                // collapse all other children
                if let Some(child) = &mut ctx.try_child_from_index(i) {
                    child.set("visibility", Visibility::Collapsed);
                }
            }
        }

        Pager::update_next_previous_enabled(ctx, current_index);
    }

    fn update(&mut self, _registry: &mut Registry, ctx: &mut Context) {
        if let Some(action) = self.actions.pop_front() {
            match action {
                PagerAction::Next => Pager::next(ctx, ctx.entity),
                PagerAction::Previous => Pager::previous(ctx, ctx.entity),
                PagerAction::Navigate(index) => Pager::navigate(ctx, ctx.entity, index),
                PagerAction::Remove(index) => Pager::remove(ctx, ctx.entity, index),
                PagerAction::Insert(index, entity) => Pager::insert(ctx, ctx.entity, index, entity),
                PagerAction::NavigateToCurrent => {
                    let current_index = Pager::correct_current_index(ctx);
                    Pager::navigate(ctx, ctx.entity, current_index);
                }
            }
        }
    }
}

widget!(
    /// `Pager` is a navigation widget that provides a stack based navigation.
    ///
    /// # Example
    ///
    /// ```rust
    /// tbd
    /// ```
    Pager<PagerState> {
        /// Defines the index of the current shown child.
        current_index: usize,

        /// Used to check if  next can be executed. If the current visible child is the last child next can not be executed.
        next_enabled: bool,

        /// Used to check if a previous can be executed. If the current visible child is the first child previous can not be executed.
        previous_enabled: bool
    }
);

impl Pager {
    // checks and updates if next and previous can be executed.
    fn update_next_previous_enabled(ctx: &mut Context, current_index: usize) {
        if current_index == 0 {
            Pager::next_enabled_set(&mut ctx.widget(), false);
        } else {
            Pager::next_enabled_set(&mut ctx.widget(), true);
        }

        if let Some(count) = ctx.widget().children_count() {
            if current_index == count - 1 {
                Pager::previous_enabled_set(&mut ctx.widget(), false);
            } else {
                Pager::previous_enabled_set(&mut ctx.widget(), true);
            }
        }
    }

    // corrects the current_index to bounds and returns the corrected value.
    fn correct_current_index(ctx: &mut Context) -> usize {
        let mut current_index = *Pager::current_index_ref(&ctx.widget());
        if let Some(count) = ctx.widget().children_count() {
            if current_index >= count {
                current_index = count - 1;
            }
        }

        Pager::current_index_set(&mut ctx.widget(), current_index);

        current_index
    }

    /// Navigates to the next child. If the current child is the last in the list nothing will happen.
    pub fn next(ctx: &mut Context, entity: Entity) {
        let current_index = *Pager::current_index_ref(&ctx.get_widget(entity));
        Pager::navigate(ctx, entity, current_index + 1);
    }

    /// Navigates to the previous child. If the current child is the first in the list nothing will happen.
    pub fn previous(ctx: &mut Context, entity: Entity) {
        let current_index = *Pager::current_index_ref(&ctx.get_widget(entity));
        Pager::navigate(ctx, entity, current_index - 1);
    }

    /// Navigates to the given index. Is the index out of bounds nothing will happen.
    pub fn navigate(ctx: &mut Context, entity: Entity, index: usize) {
        // update enabled next / previous
        Pager::panics_on_wrong_type(&ctx.get_widget(entity));

        let current_index = *Pager::current_index_ref(&ctx.get_widget(entity));

        if let Some(count) = ctx.get_widget(entity).children_count() {
            if index >= count {
                return;
            }

            if let Some(child) = &mut ctx.try_child_from_index(current_index) {
                child.set("visibility", Visibility::Collapsed);
            }

            if let Some(child) = &mut ctx.try_child_from_index(index) {
                child.set("visibility", Visibility::Visible);
            }

            Pager::current_index_set(&mut ctx.get_widget(entity), index);

            Pager::update_next_previous_enabled(ctx, index);
        }
    }

    /// Removes the child on the given index. If the index is out of bounds nothing will happen.
    pub fn remove(ctx: &mut Context, entity: Entity, index: usize) {
        // update enabled next / previous
        Pager::panics_on_wrong_type(&ctx.get_widget(entity));
    }

    /// Inserts a child on the given position.
    pub fn insert(ctx: &mut Context, entity: Entity, index: usize, child: Entity) {
        // update enabled next / previous
        Pager::panics_on_wrong_type(&ctx.get_widget(entity));
    }

    // todo add push method
}

impl Template for Pager {
    fn template(self, _id: Entity, _context: &mut BuildContext) -> Self {
        self.name("Pager").on_changed("current_index", |states, id| {
            states.get_mut::<PagerState>(id).navigate_to_current_index();
        })
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(not(feature = "tweetust"), allow(unused_imports))]

extern crate futures;
extern crate serde_json as json;
extern crate tokio_core;
extern crate twitter_stream;

use futures::{Future, Stream};
use std::fs::File;
use std::path::PathBuf;
use tokio_core::reactor::Core;
use twitter_stream::{Error, StreamMessage, Token, TwitterStream};

#[cfg(feature = "tweetust")]
fn main() {
    extern crate tweetust;

    // `credential.json` must have the following form:
    // {"consumer_key": "...", "consumer_secret": "...", "access_key": "...", "access_secret": "..."}

    let mut credential_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    credential_path.push("examples");
    credential_path.push("credential.json");

    let credential = File::open(credential_path).unwrap();
    let token: Token = json::from_reader(credential).unwrap();

    let mut core = Core::new().unwrap();

    let future_stream = TwitterStream::user(&token, &core.handle());
    let rest = tweetust::TwitterClient::new(token, tweetust::DefaultHttpHandler::with_https_connector().unwrap());

    // Information of the authenticated user:
    let user = rest.account().verify_credentials().execute().unwrap().object;

    let bot = future_stream.flatten_stream().for_each(|message| {
        if let StreamMessage::Tweet(tweet) = message {
            if tweet.user.id != user.id as u64
                && tweet.entities.user_mentions.iter().any(|mention| mention.id == user.id as u64)
            {
                println!("On {}, @{} tweeted: {:?}", tweet.created_at, tweet.user.screen_name, tweet.text);

                let response = format!("@{} {}", tweet.user.screen_name, tweet.text);
                rest.statuses()
                    .update(response)
                    .in_reply_to_status_id(tweet.id as _)
                    .execute()
                    .map_err(Error::custom)?;
            }
        }

        Ok(())
    });

    core.run(bot).unwrap();
}

#[cfg(not(feature = "tweetust"))]
fn main() {
    println!("This example needs `tweetust` feature");
}
<commit_msg>Tweak the `echo_bot` example<commit_after>#![cfg_attr(not(feature = "tweetust"), allow(unused_imports))]

extern crate futures;
extern crate serde_json as json;
extern crate tokio_core;
extern crate twitter_stream;

use futures::{Future, Stream};
use std::fs::File;
use std::path::PathBuf;
use tokio_core::reactor::Core;
use twitter_stream::{Error, StreamMessage, Token, TwitterStream};

#[cfg(feature = "tweetust")]
fn main() {
    extern crate tweetust;

    // `credential.json` must have the following form:
    // {"consumer_key": "...", "consumer_secret": "...", "access_key": "...", "access_secret": "..."}

    let mut credential_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    credential_path.push("examples");
    credential_path.push("credential.json");

    let credential = File::open(credential_path).unwrap();
    let token: Token = json::from_reader(credential).unwrap();

    let mut core = Core::new().unwrap();

    let stream = TwitterStream::user(&token, &core.handle()).flatten_stream();
    let rest = tweetust::TwitterClient::new(token, tweetust::DefaultHttpHandler::with_https_connector().unwrap());

    // Information of the authenticated user:
    let user = rest.account().verify_credentials().execute().unwrap().object;

    let bot = stream.for_each(|message| {
        if let StreamMessage::Tweet(tweet) = message {
            if tweet.user.id != user.id as u64
                && tweet.entities.user_mentions.iter().any(|mention| mention.id == user.id as u64)
            {
                println!("On {}, @{} tweeted: {:?}", tweet.created_at, tweet.user.screen_name, tweet.text);

                let response = format!("@{} {}", tweet.user.screen_name, tweet.text);
                rest.statuses()
                    .update(response)
                    .in_reply_to_status_id(tweet.id as _)
                    .execute()
                    .map_err(Error::custom)?;
            }
        }

        Ok(())
    });

    core.run(bot).unwrap();
}

#[cfg(not(feature = "tweetust"))]
fn main() {
    println!("This example needs `tweetust` feature");
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;

use nom::IResult;
use nom::bytes::complete::tag;

fn main() {
  let mut data = "abcabcabcabc";

  fn parser(i: &str) -> IResult<&str, &str> {
    tag("abc")(i)
  }

  let mut it = std::iter::from_fn(move|| {
    match parser(data) {
      Ok((i, o)) => {
        data = i;
        Some(o)
      },
      _ => None
    }
  });

  for value in it {
    println!("parser returned: {}", value);
  }
}
<commit_msg>example for the iterator combinator<commit_after>extern crate nom;

use nom::IResult;
use nom::bytes::complete::tag;
use nom::sequence::{separated_pair, terminated};
use nom::character::complete::alphanumeric1;
use nom::combinator::iterator;
use std::iter::Iterator;
use std::collections::HashMap;

fn main() {
  let mut data = "abcabcabcabc";
  let data2 = data.clone();

  fn parser(i: &str) -> IResult<&str, &str> {
    tag("abc")(i)
  }

  let it = std::iter::from_fn(move|| {
    match parser(data) {
      Ok((i, o)) => {
        data = i;
        Some(o)
      },
      _ => None
    }
  });

  for value in it {
    println!("parser returned: {}", value);
  }

  println!("\n********************\n");

  println!("data is now: {:?}", data2);

  let data = "abcabcabcabc";
  let res = std::iter::repeat(parser).take(3).try_fold((data, Vec::new()), |(data, mut acc), parser| {
    parser(data).map(|(i, o)| {
      acc.push(o);
      (i, acc)
    })
  });

  // will print "parser iterator returned: Ok(("abc", ["abc", "abc", "abc"]))"
  println!("\nparser iterator returned: {:?}", res);

  println!("\n********************\n");

  let data = "key1:value1,key2:value2,key3:value3,;";

  let mut nom_it = iterator(data, terminated(separated_pair(alphanumeric1, tag(":"), alphanumeric1), tag(",")));

  let res = nom_it.map(|(k, v)| (k.to_uppercase(), v)).collect::<HashMap<_, _>>();

  let parser_result: IResult<_, _> = nom_it.finish();
  let (remaining_input, ()) = parser_result.unwrap();

  // will print "iterator returned {"key1": "value1", "key3": "value3", "key2": "value2"}, remaining input is ';'"
  println!("iterator returned {:?}, remaining input is '{}'", res, remaining_input);
}
<|endoftext|>


<commit_before>extern crate octobot;
extern crate tempdir;

use std::fs::File;
use std::io::Write;
use std::path::PathBuf;

use octobot::git::Git;
use tempdir::TempDir;

struct GitTest {
    _dir: TempDir,
    git: Git,
    repo_dir: PathBuf,
}

impl GitTest {
    fn new() -> GitTest {
        let dir = TempDir::new("git_test.rs").expect("create temp dir for git_test.rs");

        let repo_dir = dir.path().join("repo");
        let remote_dir = dir.path().join("remote");
        std::fs::create_dir(&remote_dir).expect("create remote dir");

        let git = Git::new("the-host", "the-token", &repo_dir);
        let remote_git = Git::new("the-host", "the-token", &remote_dir);

        remote_git.run(&["--bare", "init"]).expect("init base repo");

        let test = GitTest {
            _dir: dir,
            git: git,
            repo_dir: repo_dir,
        };

        test.reclone();

        // add an initial commit to start with.
        test.add_repo_file("README.md", "# GitTest\n\n", "Initial README commit!");
        test.run_git(&["push"]);

        test
    }

    fn run_git(&self, args: &[&str]) -> String {
        self.git.run(args).expect(&format!("Failed running git: `{:?}`", args))
    }

    fn reclone(&self) {
        if self.repo_dir.exists() {
            std::fs::remove_dir_all(&self.repo_dir).expect("remove clone dir");
        }
        if !self.repo_dir.exists() {
            std::fs::create_dir(&self.repo_dir).expect("create clone dir");
        }

        self.git.run(&["clone", "../remote", "."]).expect("clone from bare repo");
    }

    fn add_repo_file(&self, path: &str, contents: &str, msg: &str) {
        self.write_file(path, contents);
        self.run_git(&["add", path]);
        self.run_git(&["commit", "-a", "-m", msg]);
    }

    fn write_file(&self, path: &str, contents: &str) {
        let path = self.repo_dir.join(path);
        if let Some(parent) = path.parent() {
            std::fs::create_dir_all(parent).expect(&format!("create dir '{:?}'", parent));
        }

        let mut file = File::create(path).expect("create file");
        file.write_all(contents.as_bytes()).expect("write contents to file");
    }
}

#[test]
fn test_current_branch() {
    let test = GitTest::new();

    assert_eq!(Ok("master".into()), test.git.current_branch());
    test.run_git(&["checkout", "-b", "other-branch"]);
    assert_eq!(Ok("other-branch".into()), test.git.current_branch());
}

#[test]
fn test_has_branch() {
    let test = GitTest::new();

    assert_eq!(Ok(true), test.git.has_branch("master"), "should have master branch");

    test.run_git(&["branch", "falcon"]);
    test.run_git(&["branch", "eagle"]);

    assert_eq!(Ok(true), test.git.has_branch("falcon"), "should have falcon branch");
    assert_eq!(Ok(true), test.git.has_branch("eagle"), "should have eagle branch");
    assert_eq!(Ok(false), test.git.has_branch("eagles"), "should NOT have eagles branch");
}

#[test]
fn test_does_branch_contain() {
    let test = GitTest::new();

    let commit = test.run_git(&["rev-parse", "HEAD"]);

    test.run_git(&["branch", "falcon"]);
    test.run_git(&["branch", "eagle"]);

    assert_eq!(Ok(true), test.git.does_branch_contain(&commit, "master"), "master should contain commit");
    assert_eq!(Ok(true), test.git.does_branch_contain(&commit, "eagle"), "eagle should contain commit");
    assert_eq!(Ok(true), test.git.does_branch_contain(&commit, "falcon"), "falcon should contain commit");

    test.run_git(&["checkout", "-b", "stallion"]);
    test.add_repo_file("horses.txt", "Stallion\nSteed\nMustang\n", "Horses and stuff");

    let commit2 = test.run_git(&["rev-parse", "HEAD"]);
    assert_eq!(Ok(true), test.git.does_branch_contain(&commit, "stallion"), "stallion should contain commit");
    assert_eq!(Ok(true), test.git.does_branch_contain(&commit2, "stallion"), "stallion should contain commit2");

    assert_eq!(Ok(false), test.git.does_branch_contain(&commit2, "master"), "master should not contain commit2");
    assert_eq!(Ok(false), test.git.does_branch_contain(&commit2, "eagle"), "eagle should not contain commit2");
    assert_eq!(Ok(false), test.git.does_branch_contain(&commit2, "falcon"), "falcon should not contain commit2");
}

#[test]
fn test_find_base_commit() {
    let test = GitTest::new();

    let base_commit = test.run_git(&["rev-parse", "HEAD"]);

    test.run_git(&["checkout", "-b", "falcon"]);
    test.add_repo_file("prarie-falcon.txt", "Prarie", "falcons 1");
    test.add_repo_file("new-zealand-falcon.txt", "New Zealand", "falcons 2");
    test.add_repo_file("peregrine-falcon.txt", "Peregrine", "falcons 3");
    test.run_git(&["push", "origin", "falcon"]);
    let falcon_commit = test.run_git(&["rev-parse", "HEAD"]);

    test.run_git(&["checkout", "-b", "horses", "master"]);
    test.add_repo_file("horses.txt", "Stallion\nSteed\nMustang\n", "Horses and stuff");
    test.run_git(&["push", "origin", "horses"]);
    let horses_commit = test.run_git(&["rev-parse", "HEAD"]);

    test.reclone();

    // now change master!
    test.run_git(&["checkout",  "master"]);
    test.add_repo_file("foo1.txt", "", "some other commit 1");
    test.add_repo_file("foo2.txt", "", "some other commit 2");
    let new_base_commit = test.run_git(&["rev-parse", "HEAD"]);
    test.run_git(&["push"]);

    // multiple commits back
    assert_eq!(Ok(base_commit.clone()), test.git.find_base_branch_commit(&falcon_commit, "master"));
    assert_eq!(Ok(base_commit.clone()), test.git.find_base_branch_commit("origin/falcon", "master"));

    // single commit back
    assert_eq!(Ok(base_commit.clone()), test.git.find_base_branch_commit(&horses_commit, "master"));
    assert_eq!(Ok(base_commit.clone()), test.git.find_base_branch_commit("origin/horses", "master"));

    // now rebase falcon!
    test.run_git(&["checkout", "falcon"]);
    test.run_git(&["rebase", "master"]);
    test.run_git(&["push", "-f"]);
    let new_falcon_commit = test.run_git(&["rev-parse", "HEAD"]);
    assert_eq!(Ok(base_commit.clone()), test.git.find_base_branch_commit(&falcon_commit, "master"));
    assert_eq!(Ok(new_base_commit.clone()), test.git.find_base_branch_commit(&new_falcon_commit, "master"));
    assert_eq!(Ok(new_base_commit.clone()), test.git.find_base_branch_commit("falcon", "master"));

    // now force-push and reclone to clear reflog
    test.run_git(&["push", "-f"]);
    test.reclone();

    // get a local 'falcon' reference
    test.run_git(&["checkout", "falcon"]);
    test.run_git(&["checkout", "master"]);
    let new_falcon_commit = test.run_git(&["rev-parse", "HEAD"]);
    assert_eq!(Ok(new_base_commit.clone()), test.git.find_base_branch_commit(&new_falcon_commit, "master"));
    assert_eq!(Ok(new_base_commit.clone()), test.git.find_base_branch_commit("falcon", "master"));

    // try rewriting the master branch. should stay the same...
    test.run_git(&["commit", "--amend", "-m", "some other commit 2 -- muaha. re-written!"]);
    test.run_git(&["push", "-f"]);
    let some_commit_1 = test.run_git(&["rev-parse", "HEAD^1"]);
    // --fork-point here knows that the base actually new_base_commit.
    assert_eq!(Ok(new_base_commit.clone()), test.git.find_base_branch_commit(&new_falcon_commit, "master"));

    // recloning again, reflog is gone, --fork-point would now fail.
    // regular merge-base is now be the one commit before the rewritten one.
    test.reclone();
    assert_eq!(Ok(some_commit_1.clone()), test.git.find_base_branch_commit(&new_falcon_commit, "master"));
}

#[test]
fn test_checkout_branch_new_local_branch() {
    let test = GitTest::new();

    let base_commit = test.run_git(&["rev-parse", "HEAD"]);

    test.add_repo_file("prarie-falcon.txt", "Prarie", "falcons 1");
    let new_commit = test.run_git(&["rev-parse", "HEAD"]);

    test.run_git(&["push"]);
    test.run_git(&["reset", "--hard", &base_commit]);

    assert_eq!(Ok(()), test.git.checkout_branch("some-new-branch", "origin/master"));
    let now_commit = test.run_git(&["rev-parse", "HEAD"]);

    assert_eq!(now_commit, new_commit);
    assert_eq!(Ok("some-new-branch".into()), test.git.current_branch());
}

#[test]
fn test_checkout_branch_with_ref() {
    let test = GitTest::new();

    let base_commit = test.run_git(&["rev-parse", "HEAD"]);
    test.add_repo_file("prarie-falcon.txt", "Prarie", "falcons 1");

    assert_eq!(Ok(()), test.git.checkout_branch("some-new-branch", &base_commit));
    let now_commit = test.run_git(&["rev-parse", "HEAD"]);

    assert_eq!(now_commit, base_commit);
    assert_eq!(Ok("some-new-branch".into()), test.git.current_branch());
}

#[test]
fn test_checkout_branch_already_checked_out() {
    let test = GitTest::new();

    let base_commit = test.run_git(&["rev-parse", "HEAD"]);

    test.add_repo_file("prarie-falcon.txt", "Prarie", "falcons 1");
    let new_commit = test.run_git(&["rev-parse", "HEAD"]);

    test.run_git(&["push"]);
    test.run_git(&["reset", "--hard", &base_commit]);

    assert_eq!(Ok(()), test.git.checkout_branch("master", "origin/master"));
    let now_commit = test.run_git(&["rev-parse", "HEAD"]);

    assert_eq!(now_commit, new_commit);
    assert_eq!(Ok("master".into()), test.git.current_branch());
}

#[test]
fn test_checkout_branch_already_exists() {
    let test = GitTest::new();

    let base_commit = test.run_git(&["rev-parse", "HEAD"]);
    test.run_git(&["branch", "the-branch"]);

    test.add_repo_file("prarie-falcon.txt", "Prarie", "falcons 1");
    let new_commit = test.run_git(&["rev-parse", "HEAD"]);
    test.run_git(&["push"]);

    test.run_git(&["reset", "--hard", &base_commit]);

    assert_eq!(Ok(()), test.git.checkout_branch("the-branch", "origin/master"));
    let now_commit = test.run_git(&["rev-parse", "HEAD"]);

    assert_eq!(now_commit, new_commit);
    assert_eq!(Ok("the-branch".into()), test.git.current_branch());
}

#[test]
fn test_get_commit_desc() {
    let test = GitTest::new();

    test.run_git(&["commit", "--amend", "-m", "I have just a subject"]);
    assert_eq!(Ok(("I have just a subject".into(), String::new())), test.git.get_commit_desc("HEAD"));

    test.run_git(&["commit", "--amend", "-m", "I have a subject\n\nAnd I have a body"]);
    assert_eq!(Ok(("I have a subject".into(), "And I have a body".into())), test.git.get_commit_desc("HEAD"));

    test.run_git(&["commit", "--amend", "-m", "I have a subject\nAnd I forgot to skip a line"]);
    assert_eq!(Ok(("I have a subject".into(), "And I forgot to skip a line".into())), test.git.get_commit_desc("HEAD"));
}
<commit_msg>Disable gpg signing in git tests! (#74)<commit_after>extern crate octobot;
extern crate tempdir;

use std::fs::File;
use std::io::Write;
use std::path::PathBuf;

use octobot::git::Git;
use tempdir::TempDir;

struct GitTest {
    _dir: TempDir,
    git: Git,
    repo_dir: PathBuf,
}

impl GitTest {
    fn new() -> GitTest {
        let dir = TempDir::new("git_test.rs").expect("create temp dir for git_test.rs");

        let repo_dir = dir.path().join("repo");
        let remote_dir = dir.path().join("remote");
        std::fs::create_dir(&remote_dir).expect("create remote dir");

        let git = Git::new("the-host", "the-token", &repo_dir);
        let remote_git = Git::new("the-host", "the-token", &remote_dir);

        remote_git.run(&["--bare", "init"]).expect("init base repo");

        let test = GitTest {
            _dir: dir,
            git: git,
            repo_dir: repo_dir,
        };

        test.reclone();

        // add an initial commit to start with.
        test.add_repo_file("README.md", "# GitTest\n\n", "Initial README commit!");
        test.run_git(&["push"]);

        test
    }

    fn run_git(&self, args: &[&str]) -> String {
        self.git.run(args).expect(&format!("Failed running git: `{:?}`", args))
    }

    fn reclone(&self) {
        if self.repo_dir.exists() {
            std::fs::remove_dir_all(&self.repo_dir).expect("remove clone dir");
        }
        if !self.repo_dir.exists() {
            std::fs::create_dir(&self.repo_dir).expect("create clone dir");
        }

        self.git.run(&["clone", "../remote", "."]).expect("clone from bare repo");
        self.git.run(&["config", "commit.gpgsign", "false"]).expect("turn off gpg signing");
    }

    fn add_repo_file(&self, path: &str, contents: &str, msg: &str) {
        self.write_file(path, contents);
        self.run_git(&["add", path]);
        self.run_git(&["commit", "-a", "-m", msg]);
    }

    fn write_file(&self, path: &str, contents: &str) {
        let path = self.repo_dir.join(path);
        if let Some(parent) = path.parent() {
            std::fs::create_dir_all(parent).expect(&format!("create dir '{:?}'", parent));
        }

        let mut file = File::create(path).expect("create file");
        file.write_all(contents.as_bytes()).expect("write contents to file");
    }
}

#[test]
fn test_current_branch() {
    let test = GitTest::new();

    assert_eq!(Ok("master".into()), test.git.current_branch());
    test.run_git(&["checkout", "-b", "other-branch"]);
    assert_eq!(Ok("other-branch".into()), test.git.current_branch());
}

#[test]
fn test_has_branch() {
    let test = GitTest::new();

    assert_eq!(Ok(true), test.git.has_branch("master"), "should have master branch");

    test.run_git(&["branch", "falcon"]);
    test.run_git(&["branch", "eagle"]);

    assert_eq!(Ok(true), test.git.has_branch("falcon"), "should have falcon branch");
    assert_eq!(Ok(true), test.git.has_branch("eagle"), "should have eagle branch");
    assert_eq!(Ok(false), test.git.has_branch("eagles"), "should NOT have eagles branch");
}

#[test]
fn test_does_branch_contain() {
    let test = GitTest::new();

    let commit = test.run_git(&["rev-parse", "HEAD"]);

    test.run_git(&["branch", "falcon"]);
    test.run_git(&["branch", "eagle"]);

    assert_eq!(Ok(true), test.git.does_branch_contain(&commit, "master"), "master should contain commit");
    assert_eq!(Ok(true), test.git.does_branch_contain(&commit, "eagle"), "eagle should contain commit");
    assert_eq!(Ok(true), test.git.does_branch_contain(&commit, "falcon"), "falcon should contain commit");

    test.run_git(&["checkout", "-b", "stallion"]);
    test.add_repo_file("horses.txt", "Stallion\nSteed\nMustang\n", "Horses and stuff");

    let commit2 = test.run_git(&["rev-parse", "HEAD"]);
    assert_eq!(Ok(true), test.git.does_branch_contain(&commit, "stallion"), "stallion should contain commit");
    assert_eq!(Ok(true), test.git.does_branch_contain(&commit2, "stallion"), "stallion should contain commit2");

    assert_eq!(Ok(false), test.git.does_branch_contain(&commit2, "master"), "master should not contain commit2");
    assert_eq!(Ok(false), test.git.does_branch_contain(&commit2, "eagle"), "eagle should not contain commit2");
    assert_eq!(Ok(false), test.git.does_branch_contain(&commit2, "falcon"), "falcon should not contain commit2");
}

#[test]
fn test_find_base_commit() {
    let test = GitTest::new();

    let base_commit = test.run_git(&["rev-parse", "HEAD"]);

    test.run_git(&["checkout", "-b", "falcon"]);
    test.add_repo_file("prarie-falcon.txt", "Prarie", "falcons 1");
    test.add_repo_file("new-zealand-falcon.txt", "New Zealand", "falcons 2");
    test.add_repo_file("peregrine-falcon.txt", "Peregrine", "falcons 3");
    test.run_git(&["push", "origin", "falcon"]);
    let falcon_commit = test.run_git(&["rev-parse", "HEAD"]);

    test.run_git(&["checkout", "-b", "horses", "master"]);
    test.add_repo_file("horses.txt", "Stallion\nSteed\nMustang\n", "Horses and stuff");
    test.run_git(&["push", "origin", "horses"]);
    let horses_commit = test.run_git(&["rev-parse", "HEAD"]);

    test.reclone();

    // now change master!
    test.run_git(&["checkout",  "master"]);
    test.add_repo_file("foo1.txt", "", "some other commit 1");
    test.add_repo_file("foo2.txt", "", "some other commit 2");
    let new_base_commit = test.run_git(&["rev-parse", "HEAD"]);
    test.run_git(&["push"]);

    // multiple commits back
    assert_eq!(Ok(base_commit.clone()), test.git.find_base_branch_commit(&falcon_commit, "master"));
    assert_eq!(Ok(base_commit.clone()), test.git.find_base_branch_commit("origin/falcon", "master"));

    // single commit back
    assert_eq!(Ok(base_commit.clone()), test.git.find_base_branch_commit(&horses_commit, "master"));
    assert_eq!(Ok(base_commit.clone()), test.git.find_base_branch_commit("origin/horses", "master"));

    // now rebase falcon!
    test.run_git(&["checkout", "falcon"]);
    test.run_git(&["rebase", "master"]);
    test.run_git(&["push", "-f"]);
    let new_falcon_commit = test.run_git(&["rev-parse", "HEAD"]);
    assert_eq!(Ok(base_commit.clone()), test.git.find_base_branch_commit(&falcon_commit, "master"));
    assert_eq!(Ok(new_base_commit.clone()), test.git.find_base_branch_commit(&new_falcon_commit, "master"));
    assert_eq!(Ok(new_base_commit.clone()), test.git.find_base_branch_commit("falcon", "master"));

    // now force-push and reclone to clear reflog
    test.run_git(&["push", "-f"]);
    test.reclone();

    // get a local 'falcon' reference
    test.run_git(&["checkout", "falcon"]);
    test.run_git(&["checkout", "master"]);
    let new_falcon_commit = test.run_git(&["rev-parse", "HEAD"]);
    assert_eq!(Ok(new_base_commit.clone()), test.git.find_base_branch_commit(&new_falcon_commit, "master"));
    assert_eq!(Ok(new_base_commit.clone()), test.git.find_base_branch_commit("falcon", "master"));

    // try rewriting the master branch. should stay the same...
    test.run_git(&["commit", "--amend", "-m", "some other commit 2 -- muaha. re-written!"]);
    test.run_git(&["push", "-f"]);
    let some_commit_1 = test.run_git(&["rev-parse", "HEAD^1"]);
    // --fork-point here knows that the base actually new_base_commit.
    assert_eq!(Ok(new_base_commit.clone()), test.git.find_base_branch_commit(&new_falcon_commit, "master"));

    // recloning again, reflog is gone, --fork-point would now fail.
    // regular merge-base is now be the one commit before the rewritten one.
    test.reclone();
    assert_eq!(Ok(some_commit_1.clone()), test.git.find_base_branch_commit(&new_falcon_commit, "master"));
}

#[test]
fn test_checkout_branch_new_local_branch() {
    let test = GitTest::new();

    let base_commit = test.run_git(&["rev-parse", "HEAD"]);

    test.add_repo_file("prarie-falcon.txt", "Prarie", "falcons 1");
    let new_commit = test.run_git(&["rev-parse", "HEAD"]);

    test.run_git(&["push"]);
    test.run_git(&["reset", "--hard", &base_commit]);

    assert_eq!(Ok(()), test.git.checkout_branch("some-new-branch", "origin/master"));
    let now_commit = test.run_git(&["rev-parse", "HEAD"]);

    assert_eq!(now_commit, new_commit);
    assert_eq!(Ok("some-new-branch".into()), test.git.current_branch());
}

#[test]
fn test_checkout_branch_with_ref() {
    let test = GitTest::new();

    let base_commit = test.run_git(&["rev-parse", "HEAD"]);
    test.add_repo_file("prarie-falcon.txt", "Prarie", "falcons 1");

    assert_eq!(Ok(()), test.git.checkout_branch("some-new-branch", &base_commit));
    let now_commit = test.run_git(&["rev-parse", "HEAD"]);

    assert_eq!(now_commit, base_commit);
    assert_eq!(Ok("some-new-branch".into()), test.git.current_branch());
}

#[test]
fn test_checkout_branch_already_checked_out() {
    let test = GitTest::new();

    let base_commit = test.run_git(&["rev-parse", "HEAD"]);

    test.add_repo_file("prarie-falcon.txt", "Prarie", "falcons 1");
    let new_commit = test.run_git(&["rev-parse", "HEAD"]);

    test.run_git(&["push"]);
    test.run_git(&["reset", "--hard", &base_commit]);

    assert_eq!(Ok(()), test.git.checkout_branch("master", "origin/master"));
    let now_commit = test.run_git(&["rev-parse", "HEAD"]);

    assert_eq!(now_commit, new_commit);
    assert_eq!(Ok("master".into()), test.git.current_branch());
}

#[test]
fn test_checkout_branch_already_exists() {
    let test = GitTest::new();

    let base_commit = test.run_git(&["rev-parse", "HEAD"]);
    test.run_git(&["branch", "the-branch"]);

    test.add_repo_file("prarie-falcon.txt", "Prarie", "falcons 1");
    let new_commit = test.run_git(&["rev-parse", "HEAD"]);
    test.run_git(&["push"]);

    test.run_git(&["reset", "--hard", &base_commit]);

    assert_eq!(Ok(()), test.git.checkout_branch("the-branch", "origin/master"));
    let now_commit = test.run_git(&["rev-parse", "HEAD"]);

    assert_eq!(now_commit, new_commit);
    assert_eq!(Ok("the-branch".into()), test.git.current_branch());
}

#[test]
fn test_get_commit_desc() {
    let test = GitTest::new();

    test.run_git(&["commit", "--amend", "-m", "I have just a subject"]);
    assert_eq!(Ok(("I have just a subject".into(), String::new())), test.git.get_commit_desc("HEAD"));

    test.run_git(&["commit", "--amend", "-m", "I have a subject\n\nAnd I have a body"]);
    assert_eq!(Ok(("I have a subject".into(), "And I have a body".into())), test.git.get_commit_desc("HEAD"));

    test.run_git(&["commit", "--amend", "-m", "I have a subject\nAnd I forgot to skip a line"]);
    assert_eq!(Ok(("I have a subject".into(), "And I forgot to skip a line".into())), test.git.get_commit_desc("HEAD"));
}
<|endoftext|>


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

// ignore-windows TempDir may cause IoError on windows: #10462

#![feature(convert)]
#![cfg_attr(test, deny(warnings)]

extern crate glob;
extern crate tempdir;

use glob::glob;
use std::env;
use std::path::PathBuf;
use std::fs;
use tempdir::TempDir;

#[test]
fn main() {
    fn mk_file(path: &str, directory: bool) {
        if directory {
            fs::create_dir(path).unwrap();
        } else {
            fs::File::create(path).unwrap();
        }
    }

    fn glob_vec(pattern: &str) -> Vec<PathBuf> {
        glob(pattern).unwrap().map(|r| r.unwrap()).collect()
    }

    let root = TempDir::new("glob-tests");
    let root = root.ok().expect("Should have created a temp directory");
    assert!(env::set_current_dir(root.path()).is_ok());

    mk_file("aaa", true);
    mk_file("aaa/apple", true);
    mk_file("aaa/orange", true);
    mk_file("aaa/tomato", true);
    mk_file("aaa/tomato/tomato.txt", false);
    mk_file("aaa/tomato/tomoto.txt", false);
    mk_file("bbb", true);
    mk_file("bbb/specials", true);
    mk_file("bbb/specials/!", false);

    // windows does not allow `*` or `?` characters to exist in filenames
    if env::consts::FAMILY != "windows" {
        mk_file("bbb/specials/*", false);
        mk_file("bbb/specials/?", false);
    }

    mk_file("bbb/specials/[", false);
    mk_file("bbb/specials/]", false);
    mk_file("ccc", true);
    mk_file("xyz", true);
    mk_file("xyz/x", false);
    mk_file("xyz/y", false);
    mk_file("xyz/z", false);

    mk_file("r", true);
    mk_file("r/current_dir.md", false);
    mk_file("r/one", true);
    mk_file("r/one/a.md", false);
    mk_file("r/one/another", true);
    mk_file("r/one/another/a.md", false);
    mk_file("r/one/another/deep", true);
    mk_file("r/one/another/deep/spelunking.md", false);
    mk_file("r/another", true);
    mk_file("r/another/a.md", false);
    mk_file("r/two", true);
    mk_file("r/two/b.md", false);
    mk_file("r/three", true);
    mk_file("r/three/c.md", false);

    // all recursive entities
    assert_eq!(glob_vec("r/**"), vec!(
        PathBuf::from("r/another"),
        PathBuf::from("r/one"),
        PathBuf::from("r/one/another"),
        PathBuf::from("r/one/another/deep"),
        PathBuf::from("r/three"),
        PathBuf::from("r/two")));

    // collapse consecutive recursive patterns
    assert_eq!(glob_vec("r/**/**"), vec!(
        PathBuf::from("r/another"),
        PathBuf::from("r/one"),
        PathBuf::from("r/one/another"),
        PathBuf::from("r/one/another/deep"),
        PathBuf::from("r/three"),
        PathBuf::from("r/two")));

    assert_eq!(glob_vec("r/**/*"), vec!(
        PathBuf::from("r/another"),
        PathBuf::from("r/another/a.md"),
        PathBuf::from("r/current_dir.md"),
        PathBuf::from("r/one"),
        PathBuf::from("r/one/a.md"),
        PathBuf::from("r/one/another"),
        PathBuf::from("r/one/another/a.md"),
        PathBuf::from("r/one/another/deep"),
        PathBuf::from("r/one/another/deep/spelunking.md"),
        PathBuf::from("r/three"),
        PathBuf::from("r/three/c.md"),
        PathBuf::from("r/two"),
        PathBuf::from("r/two/b.md")));

    // followed by a wildcard
    assert_eq!(glob_vec("r/**/*.md"), vec!(
        PathBuf::from("r/another/a.md"),
        PathBuf::from("r/current_dir.md"),
        PathBuf::from("r/one/a.md"),
        PathBuf::from("r/one/another/a.md"),
        PathBuf::from("r/one/another/deep/spelunking.md"),
        PathBuf::from("r/three/c.md"),
        PathBuf::from("r/two/b.md")));

    // followed by a precise pattern
    assert_eq!(glob_vec("r/one/**/a.md"), vec!(
        PathBuf::from("r/one/a.md"),
        PathBuf::from("r/one/another/a.md")));

    // followed by another recursive pattern
    // collapses consecutive recursives into one
    assert_eq!(glob_vec("r/one/**/**/a.md"), vec!(
        PathBuf::from("r/one/a.md"),
        PathBuf::from("r/one/another/a.md")));

    // followed by two precise patterns
    assert_eq!(glob_vec("r/**/another/a.md"), vec!(
        PathBuf::from("r/another/a.md"),
        PathBuf::from("r/one/another/a.md")));

    assert_eq!(glob_vec(""), Vec::new());
    assert_eq!(glob_vec("."), vec!(PathBuf::from(".")));
    assert_eq!(glob_vec(".."), vec!(PathBuf::from("..")));

    assert_eq!(glob_vec("aaa"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("aaa/"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("a"), Vec::new());
    assert_eq!(glob_vec("aa"), Vec::new());
    assert_eq!(glob_vec("aaaa"), Vec::new());

    assert_eq!(glob_vec("aaa/apple"), vec!(PathBuf::from("aaa/apple")));
    assert_eq!(glob_vec("aaa/apple/nope"), Vec::new());

    // windows should support both / and \ as directory separators
    if env::consts::FAMILY == "windows" {
        assert_eq!(glob_vec("aaa\\apple"), vec!(PathBuf::from("aaa/apple")));
    }

    assert_eq!(glob_vec("???/"), vec!(
        PathBuf::from("aaa"),
        PathBuf::from("bbb"),
        PathBuf::from("ccc"),
        PathBuf::from("xyz")));

    assert_eq!(glob_vec("aaa/tomato/tom?to.txt"), vec!(
        PathBuf::from("aaa/tomato/tomato.txt"),
        PathBuf::from("aaa/tomato/tomoto.txt")));

    assert_eq!(glob_vec("xyz/?"), vec!(
        PathBuf::from("xyz/x"),
        PathBuf::from("xyz/y"),
        PathBuf::from("xyz/z")));

    assert_eq!(glob_vec("a*"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("*a*"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("a*a"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("aaa*"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("*aaa"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("*aaa*"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("*a*a*a*"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("aaa*/"), vec!(PathBuf::from("aaa")));

    assert_eq!(glob_vec("aaa/*"), vec!(
        PathBuf::from("aaa/apple"),
        PathBuf::from("aaa/orange"),
        PathBuf::from("aaa/tomato")));

    assert_eq!(glob_vec("aaa/*a*"), vec!(
        PathBuf::from("aaa/apple"),
        PathBuf::from("aaa/orange"),
        PathBuf::from("aaa/tomato")));

    assert_eq!(glob_vec("*/*/*.txt"), vec!(
        PathBuf::from("aaa/tomato/tomato.txt"),
        PathBuf::from("aaa/tomato/tomoto.txt")));

    assert_eq!(glob_vec("*/*/t[aob]m?to[.]t[!y]t"), vec!(
        PathBuf::from("aaa/tomato/tomato.txt"),
        PathBuf::from("aaa/tomato/tomoto.txt")));

    assert_eq!(glob_vec("./aaa"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("./*"), glob_vec("*"));
    assert_eq!(glob_vec("*/..").pop().unwrap(), PathBuf::from("xyz/.."));
    assert_eq!(glob_vec("aaa/../bbb"), vec!(PathBuf::from("aaa/../bbb")));
    assert_eq!(glob_vec("nonexistent/../bbb"), Vec::new());
    assert_eq!(glob_vec("aaa/tomato/tomato.txt/.."), Vec::new());

    assert_eq!(glob_vec("aaa/tomato/tomato.txt/"), Vec::new());

    assert_eq!(glob_vec("aa[a]"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("aa[abc]"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("a[bca]a"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("aa[b]"), Vec::new());
    assert_eq!(glob_vec("aa[xyz]"), Vec::new());
    assert_eq!(glob_vec("aa[]]"), Vec::new());

    assert_eq!(glob_vec("aa[!b]"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("aa[!bcd]"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("a[!bcd]a"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("aa[!a]"), Vec::new());
    assert_eq!(glob_vec("aa[!abc]"), Vec::new());

    assert_eq!(glob_vec("bbb/specials/[[]"), vec!(PathBuf::from("bbb/specials/[")));
    assert_eq!(glob_vec("bbb/specials/!"), vec!(PathBuf::from("bbb/specials/!")));
    assert_eq!(glob_vec("bbb/specials/[]]"), vec!(PathBuf::from("bbb/specials/]")));

    if env::consts::FAMILY != "windows" {
        assert_eq!(glob_vec("bbb/specials/[*]"), vec!(PathBuf::from("bbb/specials/*")));
        assert_eq!(glob_vec("bbb/specials/[?]"), vec!(PathBuf::from("bbb/specials/?")));
    }

    if env::consts::FAMILY == "windows" {

        assert_eq!(glob_vec("bbb/specials/[![]"), vec!(
            PathBuf::from("bbb/specials/!"),
            PathBuf::from("bbb/specials/]")));

        assert_eq!(glob_vec("bbb/specials/[!]]"), vec!(
            PathBuf::from("bbb/specials/!"),
            PathBuf::from("bbb/specials/[")));

        assert_eq!(glob_vec("bbb/specials/[!!]"), vec!(
            PathBuf::from("bbb/specials/["),
            PathBuf::from("bbb/specials/]")));

    } else {

        assert_eq!(glob_vec("bbb/specials/[![]"), vec!(
            PathBuf::from("bbb/specials/!"),
            PathBuf::from("bbb/specials/*"),
            PathBuf::from("bbb/specials/?"),
            PathBuf::from("bbb/specials/]")));

        assert_eq!(glob_vec("bbb/specials/[!]]"), vec!(
            PathBuf::from("bbb/specials/!"),
            PathBuf::from("bbb/specials/*"),
            PathBuf::from("bbb/specials/?"),
            PathBuf::from("bbb/specials/[")));

        assert_eq!(glob_vec("bbb/specials/[!!]"), vec!(
            PathBuf::from("bbb/specials/*"),
            PathBuf::from("bbb/specials/?"),
            PathBuf::from("bbb/specials/["),
            PathBuf::from("bbb/specials/]")));

        assert_eq!(glob_vec("bbb/specials/[!*]"), vec!(
            PathBuf::from("bbb/specials/!"),
            PathBuf::from("bbb/specials/?"),
            PathBuf::from("bbb/specials/["),
            PathBuf::from("bbb/specials/]")));

        assert_eq!(glob_vec("bbb/specials/[!?]"), vec!(
            PathBuf::from("bbb/specials/!"),
            PathBuf::from("bbb/specials/*"),
            PathBuf::from("bbb/specials/["),
            PathBuf::from("bbb/specials/]")));

    }
}
<commit_msg>Fix tests<commit_after>// Copyright 2013-2014 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.

// ignore-windows TempDir may cause IoError on windows: #10462

#![feature(convert)]
#![cfg_attr(test, deny(warnings))]

extern crate glob;
extern crate tempdir;

use glob::glob;
use std::env;
use std::path::PathBuf;
use std::fs;
use tempdir::TempDir;

#[test]
fn main() {
    fn mk_file(path: &str, directory: bool) {
        if directory {
            fs::create_dir(path).unwrap();
        } else {
            fs::File::create(path).unwrap();
        }
    }

    fn glob_vec(pattern: &str) -> Vec<PathBuf> {
        glob(pattern).unwrap().map(|r| r.unwrap()).collect()
    }

    let root = TempDir::new("glob-tests");
    let root = root.ok().expect("Should have created a temp directory");
    assert!(env::set_current_dir(root.path()).is_ok());

    mk_file("aaa", true);
    mk_file("aaa/apple", true);
    mk_file("aaa/orange", true);
    mk_file("aaa/tomato", true);
    mk_file("aaa/tomato/tomato.txt", false);
    mk_file("aaa/tomato/tomoto.txt", false);
    mk_file("bbb", true);
    mk_file("bbb/specials", true);
    mk_file("bbb/specials/!", false);

    // windows does not allow `*` or `?` characters to exist in filenames
    if env::consts::FAMILY != "windows" {
        mk_file("bbb/specials/*", false);
        mk_file("bbb/specials/?", false);
    }

    mk_file("bbb/specials/[", false);
    mk_file("bbb/specials/]", false);
    mk_file("ccc", true);
    mk_file("xyz", true);
    mk_file("xyz/x", false);
    mk_file("xyz/y", false);
    mk_file("xyz/z", false);

    mk_file("r", true);
    mk_file("r/current_dir.md", false);
    mk_file("r/one", true);
    mk_file("r/one/a.md", false);
    mk_file("r/one/another", true);
    mk_file("r/one/another/a.md", false);
    mk_file("r/one/another/deep", true);
    mk_file("r/one/another/deep/spelunking.md", false);
    mk_file("r/another", true);
    mk_file("r/another/a.md", false);
    mk_file("r/two", true);
    mk_file("r/two/b.md", false);
    mk_file("r/three", true);
    mk_file("r/three/c.md", false);

    // all recursive entities
    assert_eq!(glob_vec("r/**"), vec!(
        PathBuf::from("r/another"),
        PathBuf::from("r/one"),
        PathBuf::from("r/one/another"),
        PathBuf::from("r/one/another/deep"),
        PathBuf::from("r/three"),
        PathBuf::from("r/two")));

    // collapse consecutive recursive patterns
    assert_eq!(glob_vec("r/**/**"), vec!(
        PathBuf::from("r/another"),
        PathBuf::from("r/one"),
        PathBuf::from("r/one/another"),
        PathBuf::from("r/one/another/deep"),
        PathBuf::from("r/three"),
        PathBuf::from("r/two")));

    assert_eq!(glob_vec("r/**/*"), vec!(
        PathBuf::from("r/another"),
        PathBuf::from("r/another/a.md"),
        PathBuf::from("r/current_dir.md"),
        PathBuf::from("r/one"),
        PathBuf::from("r/one/a.md"),
        PathBuf::from("r/one/another"),
        PathBuf::from("r/one/another/a.md"),
        PathBuf::from("r/one/another/deep"),
        PathBuf::from("r/one/another/deep/spelunking.md"),
        PathBuf::from("r/three"),
        PathBuf::from("r/three/c.md"),
        PathBuf::from("r/two"),
        PathBuf::from("r/two/b.md")));

    // followed by a wildcard
    assert_eq!(glob_vec("r/**/*.md"), vec!(
        PathBuf::from("r/another/a.md"),
        PathBuf::from("r/current_dir.md"),
        PathBuf::from("r/one/a.md"),
        PathBuf::from("r/one/another/a.md"),
        PathBuf::from("r/one/another/deep/spelunking.md"),
        PathBuf::from("r/three/c.md"),
        PathBuf::from("r/two/b.md")));

    // followed by a precise pattern
    assert_eq!(glob_vec("r/one/**/a.md"), vec!(
        PathBuf::from("r/one/a.md"),
        PathBuf::from("r/one/another/a.md")));

    // followed by another recursive pattern
    // collapses consecutive recursives into one
    assert_eq!(glob_vec("r/one/**/**/a.md"), vec!(
        PathBuf::from("r/one/a.md"),
        PathBuf::from("r/one/another/a.md")));

    // followed by two precise patterns
    assert_eq!(glob_vec("r/**/another/a.md"), vec!(
        PathBuf::from("r/another/a.md"),
        PathBuf::from("r/one/another/a.md")));

    assert_eq!(glob_vec(""), Vec::new());
    assert_eq!(glob_vec("."), vec!(PathBuf::from(".")));
    assert_eq!(glob_vec(".."), vec!(PathBuf::from("..")));

    assert_eq!(glob_vec("aaa"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("aaa/"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("a"), Vec::new());
    assert_eq!(glob_vec("aa"), Vec::new());
    assert_eq!(glob_vec("aaaa"), Vec::new());

    assert_eq!(glob_vec("aaa/apple"), vec!(PathBuf::from("aaa/apple")));
    assert_eq!(glob_vec("aaa/apple/nope"), Vec::new());

    // windows should support both / and \ as directory separators
    if env::consts::FAMILY == "windows" {
        assert_eq!(glob_vec("aaa\\apple"), vec!(PathBuf::from("aaa/apple")));
    }

    assert_eq!(glob_vec("???/"), vec!(
        PathBuf::from("aaa"),
        PathBuf::from("bbb"),
        PathBuf::from("ccc"),
        PathBuf::from("xyz")));

    assert_eq!(glob_vec("aaa/tomato/tom?to.txt"), vec!(
        PathBuf::from("aaa/tomato/tomato.txt"),
        PathBuf::from("aaa/tomato/tomoto.txt")));

    assert_eq!(glob_vec("xyz/?"), vec!(
        PathBuf::from("xyz/x"),
        PathBuf::from("xyz/y"),
        PathBuf::from("xyz/z")));

    assert_eq!(glob_vec("a*"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("*a*"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("a*a"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("aaa*"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("*aaa"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("*aaa*"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("*a*a*a*"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("aaa*/"), vec!(PathBuf::from("aaa")));

    assert_eq!(glob_vec("aaa/*"), vec!(
        PathBuf::from("aaa/apple"),
        PathBuf::from("aaa/orange"),
        PathBuf::from("aaa/tomato")));

    assert_eq!(glob_vec("aaa/*a*"), vec!(
        PathBuf::from("aaa/apple"),
        PathBuf::from("aaa/orange"),
        PathBuf::from("aaa/tomato")));

    assert_eq!(glob_vec("*/*/*.txt"), vec!(
        PathBuf::from("aaa/tomato/tomato.txt"),
        PathBuf::from("aaa/tomato/tomoto.txt")));

    assert_eq!(glob_vec("*/*/t[aob]m?to[.]t[!y]t"), vec!(
        PathBuf::from("aaa/tomato/tomato.txt"),
        PathBuf::from("aaa/tomato/tomoto.txt")));

    assert_eq!(glob_vec("./aaa"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("./*"), glob_vec("*"));
    assert_eq!(glob_vec("*/..").pop().unwrap(), PathBuf::from("xyz/.."));
    assert_eq!(glob_vec("aaa/../bbb"), vec!(PathBuf::from("aaa/../bbb")));
    assert_eq!(glob_vec("nonexistent/../bbb"), Vec::new());
    assert_eq!(glob_vec("aaa/tomato/tomato.txt/.."), Vec::new());

    assert_eq!(glob_vec("aaa/tomato/tomato.txt/"), Vec::new());

    assert_eq!(glob_vec("aa[a]"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("aa[abc]"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("a[bca]a"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("aa[b]"), Vec::new());
    assert_eq!(glob_vec("aa[xyz]"), Vec::new());
    assert_eq!(glob_vec("aa[]]"), Vec::new());

    assert_eq!(glob_vec("aa[!b]"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("aa[!bcd]"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("a[!bcd]a"), vec!(PathBuf::from("aaa")));
    assert_eq!(glob_vec("aa[!a]"), Vec::new());
    assert_eq!(glob_vec("aa[!abc]"), Vec::new());

    assert_eq!(glob_vec("bbb/specials/[[]"), vec!(PathBuf::from("bbb/specials/[")));
    assert_eq!(glob_vec("bbb/specials/!"), vec!(PathBuf::from("bbb/specials/!")));
    assert_eq!(glob_vec("bbb/specials/[]]"), vec!(PathBuf::from("bbb/specials/]")));

    if env::consts::FAMILY != "windows" {
        assert_eq!(glob_vec("bbb/specials/[*]"), vec!(PathBuf::from("bbb/specials/*")));
        assert_eq!(glob_vec("bbb/specials/[?]"), vec!(PathBuf::from("bbb/specials/?")));
    }

    if env::consts::FAMILY == "windows" {

        assert_eq!(glob_vec("bbb/specials/[![]"), vec!(
            PathBuf::from("bbb/specials/!"),
            PathBuf::from("bbb/specials/]")));

        assert_eq!(glob_vec("bbb/specials/[!]]"), vec!(
            PathBuf::from("bbb/specials/!"),
            PathBuf::from("bbb/specials/[")));

        assert_eq!(glob_vec("bbb/specials/[!!]"), vec!(
            PathBuf::from("bbb/specials/["),
            PathBuf::from("bbb/specials/]")));

    } else {

        assert_eq!(glob_vec("bbb/specials/[![]"), vec!(
            PathBuf::from("bbb/specials/!"),
            PathBuf::from("bbb/specials/*"),
            PathBuf::from("bbb/specials/?"),
            PathBuf::from("bbb/specials/]")));

        assert_eq!(glob_vec("bbb/specials/[!]]"), vec!(
            PathBuf::from("bbb/specials/!"),
            PathBuf::from("bbb/specials/*"),
            PathBuf::from("bbb/specials/?"),
            PathBuf::from("bbb/specials/[")));

        assert_eq!(glob_vec("bbb/specials/[!!]"), vec!(
            PathBuf::from("bbb/specials/*"),
            PathBuf::from("bbb/specials/?"),
            PathBuf::from("bbb/specials/["),
            PathBuf::from("bbb/specials/]")));

        assert_eq!(glob_vec("bbb/specials/[!*]"), vec!(
            PathBuf::from("bbb/specials/!"),
            PathBuf::from("bbb/specials/?"),
            PathBuf::from("bbb/specials/["),
            PathBuf::from("bbb/specials/]")));

        assert_eq!(glob_vec("bbb/specials/[!?]"), vec!(
            PathBuf::from("bbb/specials/!"),
            PathBuf::from("bbb/specials/*"),
            PathBuf::from("bbb/specials/["),
            PathBuf::from("bbb/specials/]")));

    }
}
<|endoftext|>


<commit_before>use std::str;

use cookie_factory::*;

#[derive(Debug,Clone,PartialEq)]
pub struct Request<'a> {
  pub method: &'a str,
  pub uri: &'a str,
  pub headers: Vec<Header<'a>>,
  pub body: &'a [u8],
}

#[derive(Debug,Clone,PartialEq)]
pub struct Header<'a> {
  pub name: &'a str,
  pub value: &'a str,
}

pub fn cf_request<'a, 'b, 'c>(i:(&'a mut [u8],usize), r: &'c Request<'b>) -> Result<(&'a mut [u8],usize),GenError> {
  do_gen!((i.0, i.1),
    gen_call!(cf_request_line, r.method, r.uri) >>
    gen_many!(&r.headers, cf_header) >>
    gen_slice!(b"\r\n") >>
    gen_slice!(r.body)
  )
}

pub fn cf_request_line<'a, 'b>(i:(&'a mut [u8],usize), method: &'b str, uri: &'b str) -> Result<(&'a mut [u8],usize),GenError> {
  do_gen!((i.0, i.1),
    gen_slice!(method.as_bytes()) >>
    gen_slice!(b" ") >>
    gen_slice!(uri.as_bytes()) >>
    gen_slice!(b" HTTP/1.1\r\n")
  )
}

pub fn cf_header<'a, 'b, 'c>(i:(&'a mut [u8],usize), h: &'c Header<'b>) -> Result<(&'a mut [u8],usize),GenError> {
  do_gen!((i.0, i.1),
    gen_slice!(h.name.as_bytes()) >>
    gen_slice!(b": ") >>
    gen_slice!(h.value.as_bytes()) >>
    gen_slice!(b"\r\n")
  )
}

#[derive(Debug,Clone,PartialEq)]
pub struct RequestHeaders<'a> {
  pub method: &'a str,
  pub uri: &'a str,
  pub headers: Vec<Header<'a>>,
}

pub fn fn_request<'a:'c, 'b: 'a, 'c>(r: &'b Request<'a>) -> impl SerializeFn<&'c mut[u8]> + 'a {
  move |out: &'c mut [u8]| {
    let out = fn_request_line(&r.method, &r.uri)(out)?;
    let out = all(r.headers.iter().map(fn_header))(out)?;
    let out = string("\r\n")(out)?;
    slice(r.body)(out)
  }
}

pub fn fn_request_line<'a:'c, 'c, S: AsRef<str>>(method: &'a S, uri: &'a S) -> impl SerializeFn<&'c mut[u8]> + 'a {
  move |out: &'c mut [u8]| {
    let out = string(method)(out)?;
    let out = string(" ")(out)?;
    let out = string(uri)(out)?;
    string(" HTTP/1.1\r\n")(out)
  }
}

pub fn fn_header<'a:'c, 'c>(h: &'a Header) -> impl SerializeFn<&'c mut[u8]> + 'a {
  move |out: &'c mut [u8]| {
    let out = string(h.name)(out)?;
    let out = string(": ")(out)?;
    let out = string(h.value)(out)?;
    string("\r\n")(out)
  }
}

pub fn fn_request_headers<'a:'c, 'c, 'b: 'a>(r: &'b RequestHeaders<'a>) -> impl SerializeFn<&'c mut[u8]> + 'a {
  move |out: &'c mut [u8]| {
    let out = fn_request_line(&r.method, &r.uri)(out)?;
    let out = all(r.headers.iter().map(fn_header))(out)?;
    string("\r\n")(out)
  }
}

pub fn fn_chunk<'a:'c,'c>(sl: &'a[u8]) -> impl SerializeFn<&'c mut[u8]> + 'a {
  move |out: &'c mut [u8]| {
    let out = hex(sl.len())(out)?;
    let out = string("\r\n")(out)?;
    let out = slice(sl)(out)?;
    string("\r\n")(out)
  }
}

/*
pub fn chunked_request<'a, 'b: 'a, 'c, T: Serializer + 'a>(r: &'b RequestHeaders<'a>) -> Then<impl Serializer + 'a, Stream<T>> {
  let s: Stream<T> = Stream::new();
  rw_request_headers(r).then(s)
}*/
<commit_msg>fix lifetime issues<commit_after>use std::str;

use cookie_factory::*;

#[derive(Debug,Clone,PartialEq)]
pub struct Request<'a> {
  pub method: &'a str,
  pub uri: &'a str,
  pub headers: Vec<Header<'a>>,
  pub body: &'a [u8],
}

#[derive(Debug,Clone,PartialEq)]
pub struct Header<'a> {
  pub name: &'a str,
  pub value: &'a str,
}

pub fn cf_request<'a, 'b, 'c>(i:(&'a mut [u8],usize), r: &'c Request<'b>) -> Result<(&'a mut [u8],usize),GenError> {
  do_gen!((i.0, i.1),
    gen_call!(cf_request_line, r.method, r.uri) >>
    gen_many!(&r.headers, cf_header) >>
    gen_slice!(b"\r\n") >>
    gen_slice!(r.body)
  )
}

pub fn cf_request_line<'a, 'b>(i:(&'a mut [u8],usize), method: &'b str, uri: &'b str) -> Result<(&'a mut [u8],usize),GenError> {
  do_gen!((i.0, i.1),
    gen_slice!(method.as_bytes()) >>
    gen_slice!(b" ") >>
    gen_slice!(uri.as_bytes()) >>
    gen_slice!(b" HTTP/1.1\r\n")
  )
}

pub fn cf_header<'a, 'b, 'c>(i:(&'a mut [u8],usize), h: &'c Header<'b>) -> Result<(&'a mut [u8],usize),GenError> {
  do_gen!((i.0, i.1),
    gen_slice!(h.name.as_bytes()) >>
    gen_slice!(b": ") >>
    gen_slice!(h.value.as_bytes()) >>
    gen_slice!(b"\r\n")
  )
}

#[derive(Debug,Clone,PartialEq)]
pub struct RequestHeaders<'a> {
  pub method: &'a str,
  pub uri: &'a str,
  pub headers: Vec<Header<'a>>,
}

pub fn fn_request<'a:'c, 'b: 'a, 'c>(r: &'b Request<'a>) -> impl SerializeFn<&'c mut[u8]> {
  move |out: &'c mut [u8]| {
    let out = fn_request_line(&r.method, &r.uri)(out)?;
    let out = all(r.headers.iter().map(fn_header))(out)?;
    let out = string("\r\n")(out)?;
    slice(r.body)(out)
  }
}

pub fn fn_request_line<'a:'c, 'c, S: AsRef<str>>(method: &'a S, uri: &'a S) -> impl SerializeFn<&'c mut[u8]> {
  move |out: &'c mut [u8]| {
    let out = string(method)(out)?;
    let out = string(" ")(out)?;
    let out = string(uri)(out)?;
    string(" HTTP/1.1\r\n")(out)
  }
}

pub fn fn_header<'a:'c, 'c>(h: &'a Header) -> impl SerializeFn<&'c mut[u8]> {
  move |out: &'c mut [u8]| {
    let out = string(h.name)(out)?;
    let out = string(": ")(out)?;
    let out = string(h.value)(out)?;
    string("\r\n")(out)
  }
}

pub fn fn_request_headers<'a:'c, 'c, 'b: 'a>(r: &'b RequestHeaders<'a>) -> impl SerializeFn<&'c mut[u8]> {
  move |out: &'c mut [u8]| {
    let out = fn_request_line(&r.method, &r.uri)(out)?;
    let out = all(r.headers.iter().map(fn_header))(out)?;
    string("\r\n")(out)
  }
}

pub fn fn_chunk<'a:'c,'c>(sl: &'a[u8]) -> impl SerializeFn<&'c mut[u8]> {
  move |out: &'c mut [u8]| {
    let out = hex(sl.len())(out)?;
    let out = string("\r\n")(out)?;
    let out = slice(sl)(out)?;
    string("\r\n")(out)
  }
}

/*
pub fn chunked_request<'a, 'b: 'a, 'c, T: Serializer + 'a>(r: &'b RequestHeaders<'a>) -> Then<impl Serializer + 'a, Stream<T>> {
  let s: Stream<T> = Stream::new();
  rw_request_headers(r).then(s)
}*/
<|endoftext|>


<commit_before>use internal::{ Color, ColorComponent };
use math::{
    hsv,
    margin_rectangle,
    relative_rectangle,
    relative_source_rectangle,
    Scalar,
};
use radians::Radians;

/// Implemented by contexts that contains color.
pub trait Colored: Sized {
    /// Multiplies with red, green, blue and alpha values.
    fn mul_rgba(
        &self,
        r: ColorComponent,
        g: ColorComponent,
        b: ColorComponent,
        a: ColorComponent
    ) -> Self;

    /// Mixes the current color with white.
    ///
    /// 0 is black and 1 is white.
    #[inline(always)]
    fn tint(&self, f: ColorComponent) -> Self {
        self.mul_rgba(f, f, f, 1.0)
    }

    /// Mixes the current color with black.
    ///
    /// 0 is white and 1 is black.
    #[inline(always)]
    fn shade(&self, f: ColorComponent) -> Self {
        let f = 1.0 - f;
        self.mul_rgba(f, f, f, 1.0)
    }

    /// Rotates hue by degrees.
    #[inline(always)]
    fn hue_deg(&self, angle: ColorComponent) -> Self {
        let pi: ColorComponent = Radians::_180();
        self.hue_rad(angle * pi / 180.0)
    }

    /// Rotates hue by radians.
    fn hue_rad(&self, angle: ColorComponent) -> Self;
}

impl Colored for Color {
    #[inline(always)]
    fn mul_rgba(
        &self,
        r: ColorComponent,
        g: ColorComponent,
        b: ColorComponent,
        a: ColorComponent
    ) -> Self {
        [self[0] * r, self[1] * g, self[2] * b, self[3] * a]
    }

    #[inline(always)]
    fn hue_rad(&self, angle: ColorComponent) -> Self {
        hsv(*self, angle, 1.0, 1.0)
    }
}

/// Should be implemented by contexts that have rectangle information.
pub trait Rectangled: Sized {
    /// Shrinks the current rectangle equally by all sides.
    fn margin(&self, m: Scalar) -> Self;

    /// Expands the current rectangle equally by all sides.
    #[inline(always)]
    fn expand(&self, m: Scalar) -> Self {
        self.margin(-m)
    }

    /// Moves to a relative rectangle using the current rectangle as tile.
    fn rel(&self, x: Scalar, y: Scalar) -> Self;
}

/*
impl<T: Get<Rect> + Set<Rect> + Clone> Rectangled for T {
    #[inline(always)]
    fn margin(&self, m: Scalar) -> Self {
        let Rect(val) = self.get();
        self.clone().set(Rect(margin_rectangle(val, m)))
    }

    #[inline(always)]
    fn rel(&self, x: Scalar, y: Scalar) -> Self {
        let Rect(val) = self.get();
        self.clone().set(Rect(relative_rectangle(val, [x, y])))
    }
}
*/

/// Should be implemented by contexts that
/// have source rectangle information.
pub trait SourceRectangled {
    /// Adds a source rectangle.
    fn src_rect(&self, x: i32, y: i32, w: i32, h: i32) -> Self;

    /// Moves to a relative source rectangle using
    /// the current source rectangle as tile.
    fn src_rel(&self, x: i32, y: i32) -> Self;

    /// Flips the source rectangle horizontally.
    fn src_flip_h(&self) -> Self;

    /// Flips the source rectangle vertically.
    fn src_flip_v(&self) -> Self;

    /// Flips the source rectangle horizontally and vertically.
    fn src_flip_hv(&self) -> Self;
}

/*
impl<T: Get<SrcRect>
      + Set<SrcRect>
      + Clone
> SourceRectangled for T {
    #[inline(always)]
    fn src_rect(&self, x: i32, y: i32, w: i32, h: i32) -> Self {
        self.clone().set(SrcRect([x, y, w, h]))
    }

    #[inline(always)]
    fn src_rel(&self, x: i32, y: i32) -> Self {
        let SrcRect(val) = self.get();
        self.clone().set(SrcRect(
            relative_source_rectangle(val, x, y)
        ))
    }

    #[inline(always)]
    fn src_flip_h(&self) -> Self {
        let SrcRect(source_rect) = self.get();
        self.clone().set(SrcRect([
            source_rect[0] + source_rect[2],
            source_rect[1],
            -source_rect[2],
            source_rect[3]
        ]))
    }

    #[inline(always)]
    fn src_flip_v(&self) -> Self {
        let SrcRect(source_rect) = self.get();
        self.clone().set(SrcRect([
            source_rect[0],
            source_rect[1] + source_rect[3],
            source_rect[2],
            -source_rect[3]
        ]))
    }

    #[inline(always)]
    fn src_flip_hv(&self) -> Self {
        let SrcRect(source_rect) = self.get();
        self.clone().set(SrcRect([
            source_rect[0] + source_rect[2],
            source_rect[1] + source_rect[3],
            -source_rect[2],
            -source_rect[3]
        ]))
    }
}
*/
<commit_msg>Made `Colored` take `self` by value<commit_after>use internal::{ Color, ColorComponent };
use math::{
    hsv,
    margin_rectangle,
    relative_rectangle,
    relative_source_rectangle,
    Scalar,
};
use radians::Radians;

/// Implemented by contexts that contains color.
pub trait Colored: Sized {
    /// Multiplies with red, green, blue and alpha values.
    fn mul_rgba(
        self,
        r: ColorComponent,
        g: ColorComponent,
        b: ColorComponent,
        a: ColorComponent
    ) -> Self;

    /// Mixes the current color with white.
    ///
    /// 0 is black and 1 is white.
    #[inline(always)]
    fn tint(self, f: ColorComponent) -> Self {
        self.mul_rgba(f, f, f, 1.0)
    }

    /// Mixes the current color with black.
    ///
    /// 0 is white and 1 is black.
    #[inline(always)]
    fn shade(self, f: ColorComponent) -> Self {
        let f = 1.0 - f;
        self.mul_rgba(f, f, f, 1.0)
    }

    /// Rotates hue by degrees.
    #[inline(always)]
    fn hue_deg(self, angle: ColorComponent) -> Self {
        let pi: ColorComponent = Radians::_180();
        self.hue_rad(angle * pi / 180.0)
    }

    /// Rotates hue by radians.
    fn hue_rad(self, angle: ColorComponent) -> Self;
}

impl Colored for Color {
    #[inline(always)]
    fn mul_rgba(
        self,
        r: ColorComponent,
        g: ColorComponent,
        b: ColorComponent,
        a: ColorComponent
    ) -> Self {
        [self[0] * r, self[1] * g, self[2] * b, self[3] * a]
    }

    #[inline(always)]
    fn hue_rad(self, angle: ColorComponent) -> Self {
        hsv(self, angle, 1.0, 1.0)
    }
}

/// Should be implemented by contexts that have rectangle information.
pub trait Rectangled: Sized {
    /// Shrinks the current rectangle equally by all sides.
    fn margin(&self, m: Scalar) -> Self;

    /// Expands the current rectangle equally by all sides.
    #[inline(always)]
    fn expand(&self, m: Scalar) -> Self {
        self.margin(-m)
    }

    /// Moves to a relative rectangle using the current rectangle as tile.
    fn rel(&self, x: Scalar, y: Scalar) -> Self;
}

/*
impl<T: Get<Rect> + Set<Rect> + Clone> Rectangled for T {
    #[inline(always)]
    fn margin(&self, m: Scalar) -> Self {
        let Rect(val) = self.get();
        self.clone().set(Rect(margin_rectangle(val, m)))
    }

    #[inline(always)]
    fn rel(&self, x: Scalar, y: Scalar) -> Self {
        let Rect(val) = self.get();
        self.clone().set(Rect(relative_rectangle(val, [x, y])))
    }
}
*/

/// Should be implemented by contexts that
/// have source rectangle information.
pub trait SourceRectangled {
    /// Adds a source rectangle.
    fn src_rect(&self, x: i32, y: i32, w: i32, h: i32) -> Self;

    /// Moves to a relative source rectangle using
    /// the current source rectangle as tile.
    fn src_rel(&self, x: i32, y: i32) -> Self;

    /// Flips the source rectangle horizontally.
    fn src_flip_h(&self) -> Self;

    /// Flips the source rectangle vertically.
    fn src_flip_v(&self) -> Self;

    /// Flips the source rectangle horizontally and vertically.
    fn src_flip_hv(&self) -> Self;
}

/*
impl<T: Get<SrcRect>
      + Set<SrcRect>
      + Clone
> SourceRectangled for T {
    #[inline(always)]
    fn src_rect(&self, x: i32, y: i32, w: i32, h: i32) -> Self {
        self.clone().set(SrcRect([x, y, w, h]))
    }

    #[inline(always)]
    fn src_rel(&self, x: i32, y: i32) -> Self {
        let SrcRect(val) = self.get();
        self.clone().set(SrcRect(
            relative_source_rectangle(val, x, y)
        ))
    }

    #[inline(always)]
    fn src_flip_h(&self) -> Self {
        let SrcRect(source_rect) = self.get();
        self.clone().set(SrcRect([
            source_rect[0] + source_rect[2],
            source_rect[1],
            -source_rect[2],
            source_rect[3]
        ]))
    }

    #[inline(always)]
    fn src_flip_v(&self) -> Self {
        let SrcRect(source_rect) = self.get();
        self.clone().set(SrcRect([
            source_rect[0],
            source_rect[1] + source_rect[3],
            source_rect[2],
            -source_rect[3]
        ]))
    }

    #[inline(always)]
    fn src_flip_hv(&self) -> Self {
        let SrcRect(source_rect) = self.get();
        self.clone().set(SrcRect([
            source_rect[0] + source_rect[2],
            source_rect[1] + source_rect[3],
            -source_rect[2],
            -source_rect[3]
        ]))
    }
}
*/
<|endoftext|>