<commit_before>// Copyright 2016 Philipp Oppermann. See the README.md
// file at the top-level directory of this distribution.
//
// 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.

mod idt;

macro_rules! save_scratch_registers {
    () => {
        asm!("push rax
              push rcx
              push rdx
              push rsi
              push rdi
              push r8
              push r9
              push r10
              push r11
        " :::: "intel", "volatile");
    }
}

macro_rules! restore_scratch_registers {
    () => {
        asm!("pop r11
              pop r10
              pop r9
              pop r8
              pop rdi
              pop rsi
              pop rdx
              pop rcx
              pop rax
            " :::: "intel", "volatile");
    }
}

macro_rules! handler {
    ($name: ident) => {{
        #[naked]
        extern "C" fn wrapper() -> ! {
            unsafe {
                save_scratch_registers!();
                asm!("mov rdi, rsp
                      add rdi, 9*8 // calculate exception stack frame pointer
                      call $0"
                      :: "i"($name as extern "C" fn(
                          *const ExceptionStackFrame))
                      : "rdi" : "intel");

                restore_scratch_registers!();
                asm!("iretq" :::: "intel", "volatile");
                ::core::intrinsics::unreachable();
            }
        }
        wrapper
    }}
}

macro_rules! handler_with_error_code {
    ($name: ident) => {{
        #[naked]
        extern "C" fn wrapper() -> ! {
            unsafe {
                save_scratch_registers!();
                asm!("mov rsi, [rsp + 9*8] // load error code into rsi
                      mov rdi, rsp
                      add rdi, 10*8 // calculate exception stack frame pointer
                      sub rsp, 8 // align the stack pointer
                      call $0
                      add rsp, 8 // undo stack pointer alignment
                      " :: "i"($name as extern "C" fn(
                          *const ExceptionStackFrame, u64))
                      : "rdi","rsi" : "intel");
                restore_scratch_registers!();
                asm!("add rsp, 8 // pop error code
                      iretq" :::: "intel", "volatile");
                ::core::intrinsics::unreachable();
            }
        }
        wrapper
    }}
}

lazy_static! {
    static ref IDT: idt::Idt = {
        let mut idt = idt::Idt::new();

        idt.set_handler(0, handler!(divide_by_zero_handler));
        idt.set_handler(3, handler!(breakpoint_handler));
        idt.set_handler(6, handler!(invalid_opcode_handler));
        idt.set_handler(14, handler_with_error_code!(page_fault_handler));

        idt
    };
}

pub fn init() {
    IDT.load();
}

#[derive(Debug)]
#[repr(C)]
struct ExceptionStackFrame {
    instruction_pointer: u64,
    code_segment: u64,
    cpu_flags: u64,
    stack_pointer: u64,
    stack_segment: u64,
}

extern "C" fn divide_by_zero_handler(stack_frame: *const ExceptionStackFrame) {
    let stack_frame = unsafe { &*stack_frame };
    println!("\nEXCEPTION: DIVIDE BY ZERO\n{:#?}", stack_frame);
    loop {}
}

extern "C" fn breakpoint_handler(stack_frame: *const ExceptionStackFrame) {
    let stack_frame = unsafe { &*stack_frame };
    println!("\nEXCEPTION: BREAKPOINT at {:#x}\n{:#?}",
             stack_frame.instruction_pointer,
             stack_frame);
}

extern "C" fn invalid_opcode_handler(stack_frame: *const ExceptionStackFrame) {
    let stack_frame = unsafe { &*stack_frame };
    println!("\nEXCEPTION: INVALID OPCODE at {:#x}\n{:#?}",
             stack_frame.instruction_pointer,
             *stack_frame);
    loop {}
}

bitflags! {
    flags PageFaultErrorCode: u64 {
        const PROTECTION_VIOLATION = 1 << 0,
        const CAUSED_BY_WRITE = 1 << 1,
        const USER_MODE = 1 << 2,
        const MALFORMED_TABLE = 1 << 3,
        const INSTRUCTION_FETCH = 1 << 4,
    }
}

extern "C" fn page_fault_handler(stack_frame: *const ExceptionStackFrame, error_code: u64) {
    let stack_frame = unsafe { &*stack_frame };
    use x86::controlregs;
    println!("\nEXCEPTION: PAGE FAULT while accessing {:#x}\nerror code: \
                                  {:?}\n{:#?}",
             unsafe { controlregs::cr2() },
             PageFaultErrorCode::from_bits(error_code).unwrap(),
             stack_frame);
    loop {}
}
<commit_msg>Use references for the ExceptionStackFrame argument<commit_after>// Copyright 2016 Philipp Oppermann. See the README.md
// file at the top-level directory of this distribution.
//
// 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.

mod idt;

macro_rules! save_scratch_registers {
    () => {
        asm!("push rax
              push rcx
              push rdx
              push rsi
              push rdi
              push r8
              push r9
              push r10
              push r11
        " :::: "intel", "volatile");
    }
}

macro_rules! restore_scratch_registers {
    () => {
        asm!("pop r11
              pop r10
              pop r9
              pop r8
              pop rdi
              pop rsi
              pop rdx
              pop rcx
              pop rax
            " :::: "intel", "volatile");
    }
}

macro_rules! handler {
    ($name: ident) => {{
        #[naked]
        extern "C" fn wrapper() -> ! {
            unsafe {
                save_scratch_registers!();
                asm!("mov rdi, rsp
                      add rdi, 9*8 // calculate exception stack frame pointer
                      call $0"
                      :: "i"($name as extern "C" fn(
                          &ExceptionStackFrame))
                      : "rdi" : "intel");

                restore_scratch_registers!();
                asm!("iretq" :::: "intel", "volatile");
                ::core::intrinsics::unreachable();
            }
        }
        wrapper
    }}
}

macro_rules! handler_with_error_code {
    ($name: ident) => {{
        #[naked]
        extern "C" fn wrapper() -> ! {
            unsafe {
                save_scratch_registers!();
                asm!("mov rsi, [rsp + 9*8] // load error code into rsi
                      mov rdi, rsp
                      add rdi, 10*8 // calculate exception stack frame pointer
                      sub rsp, 8 // align the stack pointer
                      call $0
                      add rsp, 8 // undo stack pointer alignment
                      " :: "i"($name as extern "C" fn(
                          &ExceptionStackFrame, u64))
                      : "rdi","rsi" : "intel");
                restore_scratch_registers!();
                asm!("add rsp, 8 // pop error code
                      iretq" :::: "intel", "volatile");
                ::core::intrinsics::unreachable();
            }
        }
        wrapper
    }}
}

lazy_static! {
    static ref IDT: idt::Idt = {
        let mut idt = idt::Idt::new();

        idt.set_handler(0, handler!(divide_by_zero_handler));
        idt.set_handler(3, handler!(breakpoint_handler));
        idt.set_handler(6, handler!(invalid_opcode_handler));
        idt.set_handler(14, handler_with_error_code!(page_fault_handler));

        idt
    };
}

pub fn init() {
    IDT.load();
}

#[derive(Debug)]
#[repr(C)]
struct ExceptionStackFrame {
    instruction_pointer: u64,
    code_segment: u64,
    cpu_flags: u64,
    stack_pointer: u64,
    stack_segment: u64,
}

extern "C" fn divide_by_zero_handler(stack_frame: &ExceptionStackFrame) {
    println!("\nEXCEPTION: DIVIDE BY ZERO\n{:#?}", stack_frame);
    loop {}
}

extern "C" fn breakpoint_handler(stack_frame: &ExceptionStackFrame) {
    println!("\nEXCEPTION: BREAKPOINT at {:#x}\n{:#?}",
             stack_frame.instruction_pointer,
             stack_frame);
}

extern "C" fn invalid_opcode_handler(stack_frame: &ExceptionStackFrame) {
    println!("\nEXCEPTION: INVALID OPCODE at {:#x}\n{:#?}",
             stack_frame.instruction_pointer,
             stack_frame);
    loop {}
}

bitflags! {
    flags PageFaultErrorCode: u64 {
        const PROTECTION_VIOLATION = 1 << 0,
        const CAUSED_BY_WRITE = 1 << 1,
        const USER_MODE = 1 << 2,
        const MALFORMED_TABLE = 1 << 3,
        const INSTRUCTION_FETCH = 1 << 4,
    }
}

extern "C" fn page_fault_handler(stack_frame: &ExceptionStackFrame, error_code: u64) {
    use x86::controlregs;
    println!("\nEXCEPTION: PAGE FAULT while accessing {:#x}\nerror code: \
                                  {:?}\n{:#?}",
             unsafe { controlregs::cr2() },
             PageFaultErrorCode::from_bits(error_code).unwrap(),
             stack_frame);
    loop {}
}
<|endoftext|>


<commit_before>
use ::ioports::*;

const PIC1_COMMAND_PORT_OLD: u16 = 0x20;
static mut PIC1_COMMAND_PORT: IOPort<u8, u8> = IOPort::new(0x20);
const PIC1_DATA_PORT: u16 = 0x21;
const PIC1_IDT_START: u8 = 32;

const PIC2_COMMAND_PORT: u16 = 0xA0;
const PIC2_DATA_PORT: u16 = 0xA1;
const PIC2_IDT_START: u8 = 40;

pub unsafe fn init() {
    // initialization command
//    write::<u8>(PIC1_COMMAND_PORT_OLD, 0x11);
    PIC1_COMMAND_PORT.write(0x11);
    write::<u8>(PIC2_COMMAND_PORT, 0x11);

    write::<u8>(PIC1_DATA_PORT, PIC1_IDT_START);
    write::<u8>(PIC2_DATA_PORT, PIC2_IDT_START);

    // the slave pic on the second place
    write::<u8>(PIC1_DATA_PORT, 0b0000_0100);
    write::<u8>(PIC2_DATA_PORT, 2);

    // just some not interesting parameters
    write::<u8>(PIC1_DATA_PORT, 0x01);
    write::<u8>(PIC2_DATA_PORT, 0x01);

    // set empty interrupt masks
    write::<u8>(PIC1_DATA_PORT, 0);
    write::<u8>(PIC2_DATA_PORT, 0);
}

//pub fn lock(num: u8) {
//    port;
//    uint8_t value;
//
//    if(IRQline < 8) {
//        port = PIC1_DATA;
//    } else {
//        port = PIC2_DATA;
//        IRQline -= 8;
//    }
//    value = inb(port) | (1 << IRQline);
//    outb(port, value);
//}

//pub fn unlock(num: u8) {
//
//}
//

pub fn lock_all() {
    unsafe {
        write::<u8>(PIC1_DATA_PORT, 0xFF);
        write::<u8>(PIC2_DATA_PORT, 0xFF);
    }
}

//pub fn unlock_all() {
//
//}
<commit_msg>pic use new ioports<commit_after>
// TODO: refactor it! Should be `struct Pic`

use ::ioports::*;

static mut PIC1_COMMAND: IOPort<u8, u8> = IOPort::new(0x20);
static mut PIC1_DATA: IOPort<u8, u8> = IOPort::new(0x21);
const PIC1_IDT_START: u8 = 32;

static mut PIC2_COMMAND: IOPort<u8, u8> = IOPort::new(0xA0);
static mut PIC2_DATA: IOPort<u8, u8> = IOPort::new(0xA1);
const PIC2_IDT_START: u8 = 40;

pub unsafe fn init() {
    // initialization command
    PIC1_COMMAND.write(0x11);
    PIC2_COMMAND.write(0x11);

    PIC1_DATA.write(PIC1_IDT_START);
    PIC2_DATA.write(PIC2_IDT_START);

    // the slave pic on the second place
    PIC1_DATA.write(0b0000_0100);
    PIC2_DATA.write(2);

    // just some not interesting parameters
    PIC1_DATA.write(0x01);
    PIC2_DATA.write(0x01);

    // clear interrupt masks
    PIC1_DATA.write(0);
    PIC2_DATA.write(0);
}

//pub fn lock(num: u8) {
//    port;
//    uint8_t value;
//
//    if(IRQline < 8) {
//        port = PIC1_DATA;
//    } else {
//        port = PIC2_DATA;
//        IRQline -= 8;
//    }
//    value = inb(port) | (1 << IRQline);
//    outb(port, value);
//}

//pub fn unlock(num: u8) {
//
//}
//

pub fn lock_all() {
    unsafe {
        PIC1_DATA.write(0xFF);
        PIC2_DATA.write(0xFF);
    }
}

//pub fn unlock_all() {
//
//}
<|endoftext|>


<commit_before>//! List project issues
//!
//! https://docs.gitlab.com/ce/api/issues.html#list-project-issues
//!
//! # List project issues
//!
//! Get a list of a project's issues.
//!
//! ```text
//! GET /projects/ID/issues
//! GET /projects/ID/issues?state=opened
//! GET /projects/ID/issues?state=closed
//! GET /projects/ID/issues?labels=foo
//! GET /projects/ID/issues?labels=foo,bar
//! GET /projects/ID/issues?labels=foo,bar&state=opened
//! GET /projects/ID/issues?milestone=1.0.0
//! GET /projects/ID/issues?milestone=1.0.0&state=opened
//! GET /projects/ID/issues?iid=42
//! ```
//!
//! | Attribute | Type | Required | Description |
//! | --------- | ---- | -------- | ----------- |
//! | `id`      | integer | yes   | The ID of a project |
//! | `iid`     | integer | no    | Return the issue having the given `iid` |
//! | `state`   | string  | no    | Return all issues or just those that are `opened` or `closed`|
//! | `labels`  | string  | no    | Comma-separated list of label names, issues with any of the labels will be returned |
//! | `milestone` | string| no    | The milestone title |
//! | `order_by`| string  | no    | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` |
//! | `sort`    | string  | no    | Return requests sorted in `asc` or `desc` order. Default is `desc`  |
//!

// use serde_urlencoded;

use BuildQuery;
use Issues;
use issues::ProjectsIssuesListerInternal;

use ::errors::*;

#[derive(Debug, Clone)]
pub struct IssuesLister<'a> {
    gl: &'a ::GitLab,
    /// The ID of a group
    id: i64,
    internal: ProjectsIssuesListerInternal,
}

impl<'a> IssuesLister<'a> {
    pub fn new(gl: &'a ::GitLab, id: i64) -> IssuesLister {
        IssuesLister {
            gl: gl,
            id: id,
            internal: ProjectsIssuesListerInternal {
                iid: None,
                state: None,
                labels: None,
                milestone: None,
                order_by: None,
                sort: None,
            },
        }
    }

    pub fn iid(&'a mut self, iid: i64) -> &'a mut IssuesLister {
        self.internal.iid = Some(iid);
        self
    }

    pub fn state(&'a mut self, state: ::issues::State) -> &'a mut IssuesLister {
        self.internal.state = Some(state);
        self
    }

    pub fn milestone(&'a mut self, milestone: String) -> &'a mut IssuesLister {
        self.internal.milestone = Some(milestone);
        self
    }

    pub fn labels(&'a mut self, labels: Vec<String>) -> &'a mut IssuesLister {
        self.internal.labels = Some(labels);
        self
    }

    pub fn order_by(&'a mut self, order_by: ::issues::ListingOrderBy) -> &'a mut IssuesLister {
        self.internal.order_by = Some(order_by);
        self
    }

    pub fn sort(&'a mut self, sort: ::ListingSort) -> &'a mut IssuesLister {
        self.internal.sort = Some(sort);
        self
    }

    /// Commit the lister: Query GitLab and return a list of issues.
    pub fn list(&self) -> Result<Issues> {
        let query = self.build_query();
        debug!("query: {:?}", query);

        self.gl.get(&query).chain_err(|| format!("cannot get query {}", query))
    }
}

impl<'a> BuildQuery for IssuesLister<'a> {
    fn build_query(&self) -> String {
        // NOTE: Can't use `serde_urlencoded` since it cannot serialize a Vec<T>
        //       See https://github.com/nox/serde_urlencoded/issues/6
        // let encoded = serde_urlencoded::to_string(&self.internal).unwrap();

        let mut query = format!("projects/{}/issues", self.id);
        let amp_char = "&";
        let comma_char = ",";
        let none_char = "";
        let mut split_char = &none_char;

        // Append a "?" only if at least one of the `Option` is `Some(_)` or if
        // strings contain something.
        query.push_str(match (&self.internal.state,
                              &self.internal.labels,
                              &self.internal.milestone,
                              &self.internal.order_by,
                              &self.internal.sort) {
            (&None, &None, &None, &None, &None) => "",
            _ => "?",
        });

        self.internal.iid.as_ref().map(|iid| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("iid=");
            query.push_str(&iid.to_string());
        });

        self.internal.state.map(|state| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("state=");
            query.push_str(match state {
                ::issues::State::Opened => "opened",
                ::issues::State::Closed => "closed",
            });
        });

        self.internal.labels.as_ref().map(|labels| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("labels=");

            let mut array_split_char = &none_char;
            for label in labels {
                query.push_str(array_split_char);
                query.push_str(&label.to_string());
                array_split_char = &comma_char;
            }
        });

        self.internal.milestone.as_ref().map(|milestone| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("milestone=");
            query.push_str(milestone);
        });

        self.internal.order_by.map(|order_by| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("order_by=");
            query.push_str(match order_by {
                ::issues::ListingOrderBy::CreatedAt => "created_at",
                ::issues::ListingOrderBy::UpdatedAt => "updated_at",
            });
        });

        self.internal.sort.map(|sort| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("sort=");
            query.push_str(match sort {
                ::ListingSort::Asc => "asc",
                ::ListingSort::Desc => "desc",
            });
        });

        query
    }
}

#[cfg(test)]
mod tests {
    use BuildQuery;

    const TEST_PROJECT_ID: i64 = 123;

    #[test]
    fn build_query_default() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues", TEST_PROJECT_ID);

        let lister = gl.issues();
        let lister = lister.project(TEST_PROJECT_ID);
        let query = lister.build_query();
        assert_eq!(query, expected_string);

        let lister = gl.issues().project(TEST_PROJECT_ID);
        let query = lister.build_query();
        assert_eq!(query, expected_string);

        let query = gl.issues().project(TEST_PROJECT_ID).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_state() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues?state=opened", TEST_PROJECT_ID);
        let query =
            gl.issues().project(TEST_PROJECT_ID).state(::issues::State::Opened).build_query();
        assert_eq!(query, expected_string);

        let expected_string = format!("projects/{}/issues?state=closed", TEST_PROJECT_ID);
        let query =
            gl.issues().project(TEST_PROJECT_ID).state(::issues::State::Closed).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_skip_groups() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues?labels=label1,label2,label3",
                                      TEST_PROJECT_ID);
        let query = gl.issues()
            .project(TEST_PROJECT_ID)
            .labels(vec![String::from("label1"), String::from("label2"), String::from("label3")])
            .build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_order_by() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues?order_by=created_at", TEST_PROJECT_ID);
        let query = gl.issues()
            .project(TEST_PROJECT_ID)
            .order_by(::issues::ListingOrderBy::CreatedAt)
            .build_query();
        assert_eq!(query, expected_string);

        let expected_string = format!("projects/{}/issues?order_by=updated_at", TEST_PROJECT_ID);
        let query = gl.issues()
            .project(TEST_PROJECT_ID)
            .order_by(::issues::ListingOrderBy::UpdatedAt)
            .build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_sort() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues?sort=asc", TEST_PROJECT_ID);
        let query = gl.issues().project(TEST_PROJECT_ID).sort(::ListingSort::Asc).build_query();
        assert_eq!(query, expected_string);

        let expected_string = format!("projects/{}/issues?sort=desc", TEST_PROJECT_ID);
        let query = gl.issues().project(TEST_PROJECT_ID).sort(::ListingSort::Desc).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_multiple() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues?order_by=created_at&sort=asc",
                                      TEST_PROJECT_ID);
        let query = gl.issues()
            .project(TEST_PROJECT_ID)
            .sort(::ListingSort::Asc)
            .order_by(::issues::ListingOrderBy::CreatedAt)
            .build_query();
        assert_eq!(query, expected_string);
    }
}
<commit_msg>Use `serde_urlencoded` in `issues::projects`'s `build_query()` too<commit_after>//! List project issues
//!
//! https://docs.gitlab.com/ce/api/issues.html#list-project-issues
//!
//! # List project issues
//!
//! Get a list of a project's issues.
//!
//! ```text
//! GET /projects/ID/issues
//! GET /projects/ID/issues?state=opened
//! GET /projects/ID/issues?state=closed
//! GET /projects/ID/issues?labels=foo
//! GET /projects/ID/issues?labels=foo,bar
//! GET /projects/ID/issues?labels=foo,bar&state=opened
//! GET /projects/ID/issues?milestone=1.0.0
//! GET /projects/ID/issues?milestone=1.0.0&state=opened
//! GET /projects/ID/issues?iid=42
//! ```
//!
//! | Attribute | Type | Required | Description |
//! | --------- | ---- | -------- | ----------- |
//! | `id`      | integer | yes   | The ID of a project |
//! | `iid`     | integer | no    | Return the issue having the given `iid` |
//! | `state`   | string  | no    | Return all issues or just those that are `opened` or `closed`|
//! | `labels`  | string  | no    | Comma-separated list of label names, issues with any of the labels will be returned |
//! | `milestone` | string| no    | The milestone title |
//! | `order_by`| string  | no    | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` |
//! | `sort`    | string  | no    | Return requests sorted in `asc` or `desc` order. Default is `desc`  |
//!

use serde_urlencoded;

use BuildQuery;
use Issues;
use issues::ProjectsIssuesListerInternal;

use ::errors::*;

#[derive(Debug, Clone)]
pub struct IssuesLister<'a> {
    gl: &'a ::GitLab,
    /// The ID of a group
    id: i64,
    internal: ProjectsIssuesListerInternal,
}

impl<'a> IssuesLister<'a> {
    pub fn new(gl: &'a ::GitLab, id: i64) -> IssuesLister {
        IssuesLister {
            gl: gl,
            id: id,
            internal: ProjectsIssuesListerInternal {
                iid: None,
                state: None,
                labels: None,
                milestone: None,
                order_by: None,
                sort: None,
            },
        }
    }

    pub fn iid(&'a mut self, iid: i64) -> &'a mut IssuesLister {
        self.internal.iid = Some(iid);
        self
    }

    pub fn state(&'a mut self, state: ::issues::State) -> &'a mut IssuesLister {
        self.internal.state = Some(state);
        self
    }

    pub fn milestone(&'a mut self, milestone: String) -> &'a mut IssuesLister {
        self.internal.milestone = Some(milestone);
        self
    }

    pub fn labels(&'a mut self, labels: Vec<String>) -> &'a mut IssuesLister {
        self.internal.labels = Some(labels);
        self
    }

    pub fn order_by(&'a mut self, order_by: ::issues::ListingOrderBy) -> &'a mut IssuesLister {
        self.internal.order_by = Some(order_by);
        self
    }

    pub fn sort(&'a mut self, sort: ::ListingSort) -> &'a mut IssuesLister {
        self.internal.sort = Some(sort);
        self
    }

    /// Commit the lister: Query GitLab and return a list of issues.
    pub fn list(&self) -> Result<Issues> {
        let query = self.build_query();
        debug!("query: {:?}", query);

        self.gl.get(&query).chain_err(|| format!("cannot get query {}", query))
    }
}

impl<'a> BuildQuery for IssuesLister<'a> {
    fn build_query(&self) -> String {
        // NOTE: Can't use `serde_urlencoded` since it cannot serialize a Vec<T>
        //       See https://github.com/nox/serde_urlencoded/issues/6
        // let encoded = serde_urlencoded::to_string(&self.internal).unwrap();

        let mut query = format!("projects/{}/issues", self.id);
        let amp_char = "&";
        let comma_char = ",";
        let none_char = "";
        let mut split_char = &none_char;

        // Append a "?" only if at least one of the `Option` is `Some(_)` or if
        // strings contain something.
        query.push_str(match (&self.internal.state,
                              &self.internal.labels,
                              &self.internal.milestone,
                              &self.internal.order_by,
                              &self.internal.sort) {
            (&None, &None, &None, &None, &None) => "",
            _ => "?",
        });

        self.internal.iid.as_ref().map(|iid| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("iid=");
            query.push_str(&iid.to_string());
        });

        self.internal.state.map(|state| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("state=");
            query.push_str(match state {
                ::issues::State::Opened => "opened",
                ::issues::State::Closed => "closed",
            });
        });

        self.internal.labels.as_ref().map(|labels| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("labels=");

            let mut array_split_char = &none_char;
            for label in labels {
                query.push_str(array_split_char);
                query.push_str(&label.to_string());
                array_split_char = &comma_char;
            }
        });

        self.internal.milestone.as_ref().map(|milestone| {
            query.push_str(split_char);
            split_char = &amp_char;

            let params = &[("milestone", milestone)];
            query.push_str(&serde_urlencoded::to_string(&params).unwrap());
        });

        self.internal.order_by.map(|order_by| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("order_by=");
            query.push_str(match order_by {
                ::issues::ListingOrderBy::CreatedAt => "created_at",
                ::issues::ListingOrderBy::UpdatedAt => "updated_at",
            });
        });

        self.internal.sort.map(|sort| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("sort=");
            query.push_str(match sort {
                ::ListingSort::Asc => "asc",
                ::ListingSort::Desc => "desc",
            });
        });

        query
    }
}

#[cfg(test)]
mod tests {
    use BuildQuery;

    const TEST_PROJECT_ID: i64 = 123;

    #[test]
    fn build_query_default() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues", TEST_PROJECT_ID);

        let lister = gl.issues();
        let lister = lister.project(TEST_PROJECT_ID);
        let query = lister.build_query();
        assert_eq!(query, expected_string);

        let lister = gl.issues().project(TEST_PROJECT_ID);
        let query = lister.build_query();
        assert_eq!(query, expected_string);

        let query = gl.issues().project(TEST_PROJECT_ID).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_state() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues?state=opened", TEST_PROJECT_ID);
        let query =
            gl.issues().project(TEST_PROJECT_ID).state(::issues::State::Opened).build_query();
        assert_eq!(query, expected_string);

        let expected_string = format!("projects/{}/issues?state=closed", TEST_PROJECT_ID);
        let query =
            gl.issues().project(TEST_PROJECT_ID).state(::issues::State::Closed).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_skip_groups() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues?labels=label1,label2,label3",
                                      TEST_PROJECT_ID);
        let query = gl.issues()
            .project(TEST_PROJECT_ID)
            .labels(vec![String::from("label1"), String::from("label2"), String::from("label3")])
            .build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_order_by() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues?order_by=created_at", TEST_PROJECT_ID);
        let query = gl.issues()
            .project(TEST_PROJECT_ID)
            .order_by(::issues::ListingOrderBy::CreatedAt)
            .build_query();
        assert_eq!(query, expected_string);

        let expected_string = format!("projects/{}/issues?order_by=updated_at", TEST_PROJECT_ID);
        let query = gl.issues()
            .project(TEST_PROJECT_ID)
            .order_by(::issues::ListingOrderBy::UpdatedAt)
            .build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_sort() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues?sort=asc", TEST_PROJECT_ID);
        let query = gl.issues().project(TEST_PROJECT_ID).sort(::ListingSort::Asc).build_query();
        assert_eq!(query, expected_string);

        let expected_string = format!("projects/{}/issues?sort=desc", TEST_PROJECT_ID);
        let query = gl.issues().project(TEST_PROJECT_ID).sort(::ListingSort::Desc).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_multiple() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues?order_by=created_at&sort=asc",
                                      TEST_PROJECT_ID);
        let query = gl.issues()
            .project(TEST_PROJECT_ID)
            .sort(::ListingSort::Asc)
            .order_by(::issues::ListingOrderBy::CreatedAt)
            .build_query();
        assert_eq!(query, expected_string);
    }
}
<|endoftext|>


<commit_before>//! Provides a testing environment for the `BeaconChain`, `Attester` and `BlockProposer` objects.
//!
//! This environment bypasses networking and client run-times and connects the `Attester` and `Proposer`
//! directly to the `BeaconChain` via an `Arc`.
//!
//! The `BeaconChainHarness` contains a single `BeaconChain` instance and many `ValidatorHarness`
//! instances. All of the `ValidatorHarness` instances work to advance the `BeaconChain` by
//! producing blocks and attestations.
//!
//! Example:
//! ```
//! use test_harness::BeaconChainHarness;
//! use types::ChainSpec;
//!
//! let validator_count = 8;
//! let spec = ChainSpec::few_validators();
//!
//! let mut harness = BeaconChainHarness::new(spec, validator_count);
//!
//! harness.advance_chain_with_block();
//!
//! let chain = harness.chain_dump().unwrap();
//!
//! // One block should have been built on top of the genesis block.
//! assert_eq!(chain.len(), 2);
//! ```

mod beacon_chain_harness;
pub mod test_case;
mod validator_harness;

pub use self::beacon_chain_harness::BeaconChainHarness;
pub use self::validator_harness::ValidatorHarness;
<commit_msg>Disable running docs example for test harness<commit_after>//! Provides a testing environment for the `BeaconChain`, `Attester` and `BlockProposer` objects.
//!
//! This environment bypasses networking and client run-times and connects the `Attester` and `Proposer`
//! directly to the `BeaconChain` via an `Arc`.
//!
//! The `BeaconChainHarness` contains a single `BeaconChain` instance and many `ValidatorHarness`
//! instances. All of the `ValidatorHarness` instances work to advance the `BeaconChain` by
//! producing blocks and attestations.
//!
//! Example:
//! ```rust,no_run
//! use test_harness::BeaconChainHarness;
//! use types::ChainSpec;
//!
//! let validator_count = 8;
//! let spec = ChainSpec::few_validators();
//!
//! let mut harness = BeaconChainHarness::new(spec, validator_count);
//!
//! harness.advance_chain_with_block();
//!
//! let chain = harness.chain_dump().unwrap();
//!
//! // One block should have been built on top of the genesis block.
//! assert_eq!(chain.len(), 2);
//! ```

mod beacon_chain_harness;
pub mod test_case;
mod validator_harness;

pub use self::beacon_chain_harness::BeaconChainHarness;
pub use self::validator_harness::ValidatorHarness;
<|endoftext|>


<commit_before>use super::{
    flags::*,
    flow_control::{insert_statement, Case, ElseIf, Function, Statement},
    job_control::JobControl,
    signals,
    status::*,
    Shell,
};
use crate::{
    parser::{
        assignments::is_array,
        expand_string, parse_and_validate,
        pipelines::{PipeItem, Pipeline},
        ForValueExpression, StatementSplitter,
    },
    shell::{assignments::VariableStore, variables::Value},
    types,
};
use itertools::Itertools;
use small;
use std::io::{stdout, Write};

macro_rules! handle_signal {
    ($signal:expr) => {
        match $signal {
            Condition::Break => break,
            Condition::SigInt => return Condition::SigInt,
            _ => (),
        }
    };
}

#[derive(Debug)]
pub(crate) enum Condition {
    Continue,
    Break,
    NoOp,
    SigInt,
}

pub(crate) trait FlowLogic {
    /// Receives a command and attempts to execute the contents.
    fn on_command(&mut self, command_string: &str);

    /// Executes all of the statements within a while block until a certain
    /// condition is met.
    fn execute_while(
        &mut self,
        expression: Vec<Statement>,
        statements: Vec<Statement>,
    ) -> Condition;

    /// Executes all of the statements within a for block for each value
    /// specified in the range.
    fn execute_for(
        &mut self,
        variables: &[types::Str],
        values: &[small::String],
        statements: Vec<Statement>,
    ) -> Condition;

    /// Conditionally executes branches of statements according to evaluated
    /// expressions
    fn execute_if(
        &mut self,
        expression: Vec<Statement>,
        success: Vec<Statement>,
        else_if: Vec<ElseIf>,
        failure: Vec<Statement>,
    ) -> Condition;

    /// Simply executes all supplied statements.
    fn execute_statements(&mut self, statements: Vec<Statement>) -> Condition;

    /// Executes a single statement
    fn execute_statement(&mut self, statement: Statement) -> Condition;

    /// Expand an expression and run a branch based on the value of the
    /// expanded expression
    fn execute_match(&mut self, expression: small::String, cases: Vec<Case>) -> Condition;
}

impl FlowLogic for Shell {
    fn execute_if(
        &mut self,
        expression: Vec<Statement>,
        success: Vec<Statement>,
        else_if: Vec<ElseIf>,
        failure: Vec<Statement>,
    ) -> Condition {
        // Try execute success branch
        if let Condition::SigInt = self.execute_statements(expression) {
            return Condition::SigInt;
        }
        if self.previous_status == 0 {
            return self.execute_statements(success);
        }

        // Try to execute else_if branches
        let else_if_conditions = else_if.into_iter().map(|cond| (cond.expression, cond.success));

        for (condition, statements) in else_if_conditions {
            if let Condition::SigInt = self.execute_statements(condition) {
                return Condition::SigInt;
            }

            if self.previous_status == 0 {
                return self.execute_statements(statements);
            }
        }

        self.execute_statements(failure)
    }

    fn execute_for(
        &mut self,
        variables: &[types::Str],
        values: &[small::String],
        statements: Vec<Statement>,
    ) -> Condition {
        macro_rules! set_vars_then_exec {
            ($chunk:expr, $def:expr) => {
                for (key, value) in variables.iter().zip($chunk.chain(::std::iter::repeat($def))) {
                    if key != "_" {
                        self.set(key, value.clone());
                    }
                }

                handle_signal!(self.execute_statements(statements.clone()));
            };
        }

        let default = ::small::String::new();

        match ForValueExpression::new(values, self) {
            ForValueExpression::Multiple(values) => {
                for chunk in &values.iter().chunks(variables.len()) {
                    set_vars_then_exec!(chunk, &default);
                }
            }
            ForValueExpression::Normal(values) => {
                for chunk in &values.lines().chunks(variables.len()) {
                    set_vars_then_exec!(chunk, "");
                }
            }
            ForValueExpression::Range(range) => {
                for chunk in &range.chunks(variables.len()) {
                    set_vars_then_exec!(chunk, default.clone());
                }
            }
        };

        Condition::NoOp
    }

    fn execute_while(
        &mut self,
        expression: Vec<Statement>,
        statements: Vec<Statement>,
    ) -> Condition {
        loop {
            self.execute_statements(expression.clone());
            if self.previous_status != 0 {
                return Condition::NoOp;
            }

            // Cloning is needed so the statement can be re-iterated again if needed.
            match self.execute_statements(statements.clone()) {
                Condition::Break => return Condition::NoOp,
                Condition::SigInt => return Condition::SigInt,
                _ => (),
            }
        }
    }

    fn execute_statement(&mut self, statement: Statement) -> Condition {
        match statement {
            Statement::Error(number) => {
                self.previous_status = number;
                self.variables.set("?", self.previous_status.to_string());
                self.flow_control.reset();
            }
            Statement::Let(action) => {
                self.previous_status = self.local(action);
                self.variables.set("?", self.previous_status.to_string());
            }
            Statement::Export(action) => {
                self.previous_status = self.export(action);
                self.variables.set("?", self.previous_status.to_string());
            }
            Statement::While { expression, statements } => {
                if let Condition::SigInt = self.execute_while(expression, statements) {
                    return Condition::SigInt;
                }
            }
            Statement::For { variables, values, statements } => {
                if let Condition::SigInt = self.execute_for(&variables, &values, statements) {
                    return Condition::SigInt;
                }
            }
            Statement::If { expression, success, else_if, failure, .. } => {
                match self.execute_if(expression, success, else_if, failure) {
                    Condition::Break => return Condition::Break,
                    Condition::Continue => return Condition::Continue,
                    Condition::NoOp => (),
                    Condition::SigInt => return Condition::SigInt,
                }
            }
            Statement::Function { name, args, statements, description } => {
                self.variables
                    .set(&name, Function::new(description, name.clone(), args, statements));
            }
            Statement::Pipeline(pipeline) => match expand_pipeline(&self, &pipeline) {
                Ok((mut pipeline, statements)) => {
                    if !pipeline.items.is_empty() {
                        self.run_pipeline(&mut pipeline);
                    }
                    if self.flags & ERR_EXIT != 0 && self.previous_status != SUCCESS {
                        let status = self.previous_status;
                        self.exit(status);
                    }
                    if !statements.is_empty() {
                        self.execute_statements(statements);
                    }
                }
                Err(e) => {
                    eprintln!("ion: pipeline expansion error: {}", e);
                    self.previous_status = FAILURE;
                    self.variables.set("?", self.previous_status.to_string());
                    self.flow_control.reset();
                    return Condition::Break;
                }
            },
            Statement::Time(box_statement) => {
                let time = ::std::time::Instant::now();

                let condition = self.execute_statement(*box_statement);

                let duration = time.elapsed();
                let seconds = duration.as_secs();
                let nanoseconds = duration.subsec_nanos();

                let stdout = stdout();
                let mut stdout = stdout.lock();
                let _ = if seconds > 60 {
                    writeln!(
                        stdout,
                        "real    {}m{:02}.{:09}s",
                        seconds / 60,
                        seconds % 60,
                        nanoseconds
                    )
                } else {
                    writeln!(stdout, "real    {}.{:09}s", seconds, nanoseconds)
                };
                match condition {
                    Condition::Break => return Condition::Break,
                    Condition::Continue => return Condition::Continue,
                    Condition::NoOp => (),
                    Condition::SigInt => return Condition::SigInt,
                }
            }
            Statement::And(box_statement) => {
                let condition = match self.previous_status {
                    SUCCESS => self.execute_statement(*box_statement),
                    _ => Condition::NoOp,
                };

                match condition {
                    Condition::Break => return Condition::Break,
                    Condition::Continue => return Condition::Continue,
                    Condition::NoOp => (),
                    Condition::SigInt => return Condition::SigInt,
                }
            }
            Statement::Or(box_statement) => {
                let condition = match self.previous_status {
                    FAILURE => self.execute_statement(*box_statement),
                    _ => Condition::NoOp,
                };

                match condition {
                    Condition::Break => return Condition::Break,
                    Condition::Continue => return Condition::Continue,
                    Condition::NoOp => (),
                    Condition::SigInt => return Condition::SigInt,
                }
            }
            Statement::Not(box_statement) => {
                // NOTE: Should the condition be used?
                let _condition = self.execute_statement(*box_statement);
                match self.previous_status {
                    FAILURE => self.previous_status = SUCCESS,
                    SUCCESS => self.previous_status = FAILURE,
                    _ => (),
                }
                let previous_status = self.previous_status.to_string();
                self.set("?", previous_status);
            }
            Statement::Break => return Condition::Break,
            Statement::Continue => return Condition::Continue,
            Statement::Match { expression, cases } => match self.execute_match(expression, cases) {
                Condition::Break => return Condition::Break,
                Condition::Continue => return Condition::Continue,
                Condition::NoOp => (),
                Condition::SigInt => return Condition::SigInt,
            },
            _ => {}
        }
        if let Some(signal) = signals::SignalHandler.next() {
            if self.handle_signal(signal) {
                self.exit(get_signal_code(signal));
            }
            Condition::SigInt
        } else if self.break_flow {
            self.break_flow = false;
            Condition::SigInt
        } else {
            Condition::NoOp
        }
    }

    fn execute_statements(&mut self, statements: Vec<Statement>) -> Condition {
        self.variables.new_scope(false);

        let mut condition = None;
        for statement in statements {
            match self.execute_statement(statement) {
                Condition::NoOp => {}
                cond => {
                    condition = Some(cond);
                    break;
                }
            }
        }

        self.variables.pop_scope();

        condition.unwrap_or(Condition::NoOp)
    }

    fn execute_match(&mut self, expression: small::String, cases: Vec<Case>) -> Condition {
        // Logic for determining if the LHS of a match-case construct (the value we are
        // matching against) matches the RHS of a match-case construct (a value
        // in a case statement). For example, checking to see if the value
        // "foo" matches the pattern "bar" would be invoked like so :
        // ```ignore
        // matches("foo", "bar")
        // ```
        fn matches(lhs: &types::Array, rhs: &types::Array) -> bool {
            for v in lhs {
                if rhs.contains(&v) {
                    return true;
                }
            }
            false
        }

        let is_array = is_array(&expression);
        let value = expand_string(&expression, self, false);
        let mut condition = Condition::NoOp;
        for case in cases {
            // let pattern_is_array = is_array(&value);
            let pattern = case.value.map(|v| expand_string(&v, self, false));
            match pattern {
                None => {
                    let mut previous_bind = None;
                    if let Some(ref bind) = case.binding {
                        if is_array {
                            previous_bind =
                                self.variables.get::<types::Array>(bind).map(Value::Array);
                            self.variables.set(&bind, value.clone());
                        } else {
                            previous_bind = self.variables.get::<types::Str>(bind).map(Value::Str);
                            self.set(&bind, value.join(" "));
                        }
                    }

                    if let Some(statement) = case.conditional {
                        self.on_command(&statement);
                        if self.previous_status != SUCCESS {
                            continue;
                        }
                    }

                    condition = self.execute_statements(case.statements);

                    if let Some(ref bind) = case.binding {
                        if let Some(value) = previous_bind {
                            match value {
                                str_ @ Value::Str(_) => {
                                    self.set(bind, str_);
                                }
                                array @ Value::Array(_) => {
                                    self.variables.set(bind, array);
                                }
                                map @ Value::HashMap(_) => {
                                    self.variables.set(bind, map);
                                }
                                _ => (),
                            }
                        }
                    }

                    break;
                }
                Some(ref v) if matches(v, &value) => {
                    let mut previous_bind = None;
                    if let Some(ref bind) = case.binding {
                        if is_array {
                            previous_bind =
                                self.variables.get::<types::Array>(bind).map(Value::Array);
                            self.variables.set(&bind, value.clone());
                        } else {
                            previous_bind = self.variables.get::<types::Str>(bind).map(Value::Str);
                            self.set(&bind, value.join(" "));
                        }
                    }

                    if let Some(statement) = case.conditional {
                        self.on_command(&statement);
                        if self.previous_status != SUCCESS {
                            continue;
                        }
                    }

                    condition = self.execute_statements(case.statements);

                    if let Some(ref bind) = case.binding {
                        if let Some(value) = previous_bind {
                            match value {
                                str_ @ Value::Str(_) => {
                                    self.set(bind, str_);
                                }
                                array @ Value::Array(_) => {
                                    self.set(bind, array);
                                }
                                map @ Value::HashMap(_) => {
                                    self.set(bind, map);
                                }
                                _ => (),
                            }
                        }
                    }

                    break;
                }
                Some(_) => (),
            }
        }
        condition
    }

    fn on_command(&mut self, command_string: &str) {
        self.break_flow = false;
        let iterator = StatementSplitter::new(command_string).map(parse_and_validate);

        // Go through all of the statements and build up the block stack
        // When block is done return statement for execution.
        for statement in iterator {
            match insert_statement(&mut self.flow_control, statement) {
                Err(why) => {
                    eprintln!("{}", why);
                    self.flow_control.reset();
                    return;
                }
                Ok(Some(stm)) => {
                    let _ = self.execute_statement(stm);
                }
                Ok(None) => {}
            }
        }
    }
}

/// Expand a pipeline containing aliases. As aliases can split the pipeline by having logical
/// operators in them, the function returns the first half of the pipeline and the rest of the
/// statements, where the last statement has the other half of the pipeline merged.
fn expand_pipeline(
    shell: &Shell,
    pipeline: &Pipeline,
) -> Result<(Pipeline, Vec<Statement>), String> {
    let mut item_iter = pipeline.items.iter();
    let mut items: Vec<PipeItem> = Vec::new();
    let mut statements = Vec::new();

    while let Some(item) = item_iter.next() {
        let possible_alias = shell.variables.get::<types::Alias>(item.job.command.as_ref());
        if let Some(alias) = possible_alias {
            statements = StatementSplitter::new(alias.0.as_str()).map(parse_and_validate).collect();

            // First item in the alias should be a pipeline item, otherwise it cannot
            // be placed into a pipeline!
            let len = statements.len();
            if let Some(Statement::Pipeline(ref mut pline)) = statements.first_mut() {
                // Connect inputs and outputs of alias to pipeline
                if let Some(first) = pline.items.first_mut() {
                    first.inputs = item.inputs.clone();

                    // Add alias arguments to expanded args if there's any.
                    if item.job.args.len() > 1 {
                        for arg in &item.job.args[1..] {
                            first.job.args.push(arg.clone());
                        }
                    }
                }
                if len == 1 {
                    if let Some(last) = pline.items.last_mut() {
                        last.outputs = item.outputs.clone();
                        last.job.kind = item.job.kind;
                    }
                }
                items.append(&mut pline.items);
                statements.remove(0);
            }

            // Handle pipeline being broken half by i.e.: '&&' or '||'
            if !statements.is_empty() {
                let err = match statements.last_mut().unwrap() {
                    Statement::And(ref mut boxed_stm)
                    | Statement::Or(ref mut boxed_stm)
                    | Statement::Not(ref mut boxed_stm)
                    | Statement::Time(ref mut boxed_stm) => {
                        let stm = &mut **boxed_stm;
                        if let Statement::Pipeline(ref mut pline) = stm {
                            // Set output of alias to be the output of last pipeline.
                            if let Some(last) = pline.items.last_mut() {
                                last.outputs = item.outputs.clone();
                                last.job.kind = item.job.kind;
                            }
                            // Append rest of the pipeline to the last pipeline in the
                            // alias.
                            for item in item_iter {
                                pline.items.push(item.clone());
                            }
                            // No error
                            false
                        } else {
                            // Error in expansion
                            true
                        }
                    }
                    _ => false,
                };
                if err {
                    return Err(format!(
                        "unable to pipe outputs of alias: '{} = {}'",
                        item.job.command.as_str(),
                        alias.0.as_str()
                    ));
                }
                break;
            }
        } else {
            items.push(item.clone());
        }
    }
    Ok((Pipeline { items }, statements))
}
<commit_msg>Trim down matching length and remove macro<commit_after>use super::{
    flags::*,
    flow_control::{insert_statement, Case, ElseIf, Function, Statement},
    job_control::JobControl,
    signals,
    status::*,
    Shell,
};
use crate::{
    parser::{
        assignments::is_array,
        expand_string, parse_and_validate,
        pipelines::{PipeItem, Pipeline},
        ForValueExpression, StatementSplitter,
    },
    shell::{assignments::VariableStore, variables::Value},
    types,
};
use itertools::Itertools;
use small;
use std::io::{stdout, Write};

macro_rules! handle_signal {
    ($signal:expr) => {
        match $signal {
            Condition::Break => break,
            Condition::SigInt => return Condition::SigInt,
            _ => (),
        }
    };
}

#[derive(Debug)]
pub(crate) enum Condition {
    Continue,
    Break,
    NoOp,
    SigInt,
}

pub(crate) trait FlowLogic {
    /// Receives a command and attempts to execute the contents.
    fn on_command(&mut self, command_string: &str);

    /// Executes all of the statements within a while block until a certain
    /// condition is met.
    fn execute_while(
        &mut self,
        expression: Vec<Statement>,
        statements: Vec<Statement>,
    ) -> Condition;

    /// Executes all of the statements within a for block for each value
    /// specified in the range.
    fn execute_for(
        &mut self,
        variables: &[types::Str],
        values: &[small::String],
        statements: Vec<Statement>,
    ) -> Condition;

    /// Conditionally executes branches of statements according to evaluated
    /// expressions
    fn execute_if(
        &mut self,
        expression: Vec<Statement>,
        success: Vec<Statement>,
        else_if: Vec<ElseIf>,
        failure: Vec<Statement>,
    ) -> Condition;

    /// Simply executes all supplied statements.
    fn execute_statements(&mut self, statements: Vec<Statement>) -> Condition;

    /// Executes a single statement
    fn execute_statement(&mut self, statement: Statement) -> Condition;

    /// Expand an expression and run a branch based on the value of the
    /// expanded expression
    fn execute_match(&mut self, expression: small::String, cases: Vec<Case>) -> Condition;
}

impl FlowLogic for Shell {
    fn execute_if(
        &mut self,
        expression: Vec<Statement>,
        success: Vec<Statement>,
        else_if: Vec<ElseIf>,
        failure: Vec<Statement>,
    ) -> Condition {
        // Try execute success branch
        if let Condition::SigInt = self.execute_statements(expression) {
            return Condition::SigInt;
        }
        if self.previous_status == 0 {
            return self.execute_statements(success);
        }

        // Try to execute else_if branches
        for ElseIf { expression, success } in else_if {
            if let Condition::SigInt = self.execute_statements(expression) {
                return Condition::SigInt;
            }

            if self.previous_status == 0 {
                return self.execute_statements(success);
            }
        }

        self.execute_statements(failure)
    }

    fn execute_for(
        &mut self,
        variables: &[types::Str],
        values: &[small::String],
        statements: Vec<Statement>,
    ) -> Condition {
        macro_rules! set_vars_then_exec {
            ($chunk:expr, $def:expr) => {
                for (key, value) in variables.iter().zip($chunk.chain(::std::iter::repeat($def))) {
                    if key != "_" {
                        self.set(key, value.clone());
                    }
                }

                handle_signal!(self.execute_statements(statements.clone()));
            };
        }

        let default = ::small::String::new();

        match ForValueExpression::new(values, self) {
            ForValueExpression::Multiple(values) => {
                for chunk in &values.iter().chunks(variables.len()) {
                    set_vars_then_exec!(chunk, &default);
                }
            }
            ForValueExpression::Normal(values) => {
                for chunk in &values.lines().chunks(variables.len()) {
                    set_vars_then_exec!(chunk, "");
                }
            }
            ForValueExpression::Range(range) => {
                for chunk in &range.chunks(variables.len()) {
                    set_vars_then_exec!(chunk, default.clone());
                }
            }
        };

        Condition::NoOp
    }

    fn execute_while(
        &mut self,
        expression: Vec<Statement>,
        statements: Vec<Statement>,
    ) -> Condition {
        loop {
            self.execute_statements(expression.clone());
            if self.previous_status != 0 {
                return Condition::NoOp;
            }

            // Cloning is needed so the statement can be re-iterated again if needed.
            match self.execute_statements(statements.clone()) {
                Condition::Break => return Condition::NoOp,
                Condition::SigInt => return Condition::SigInt,
                _ => (),
            }
        }
    }

    fn execute_statement(&mut self, statement: Statement) -> Condition {
        match statement {
            Statement::Error(number) => {
                self.previous_status = number;
                self.variables.set("?", self.previous_status.to_string());
                self.flow_control.reset();
            }
            Statement::Let(action) => {
                self.previous_status = self.local(action);
                self.variables.set("?", self.previous_status.to_string());
            }
            Statement::Export(action) => {
                self.previous_status = self.export(action);
                self.variables.set("?", self.previous_status.to_string());
            }
            Statement::While { expression, statements } => {
                if let Condition::SigInt = self.execute_while(expression, statements) {
                    return Condition::SigInt;
                }
            }
            Statement::For { variables, values, statements } => {
                if let Condition::SigInt = self.execute_for(&variables, &values, statements) {
                    return Condition::SigInt;
                }
            }
            Statement::If { expression, success, else_if, failure, .. } => {
                match self.execute_if(expression, success, else_if, failure) {
                    Condition::Break => return Condition::Break,
                    Condition::Continue => return Condition::Continue,
                    Condition::NoOp => (),
                    Condition::SigInt => return Condition::SigInt,
                }
            }
            Statement::Function { name, args, statements, description } => {
                self.variables
                    .set(&name, Function::new(description, name.clone(), args, statements));
            }
            Statement::Pipeline(pipeline) => match expand_pipeline(&self, &pipeline) {
                Ok((mut pipeline, statements)) => {
                    if !pipeline.items.is_empty() {
                        self.run_pipeline(&mut pipeline);
                    }
                    if self.flags & ERR_EXIT != 0 && self.previous_status != SUCCESS {
                        let status = self.previous_status;
                        self.exit(status);
                    }
                    if !statements.is_empty() {
                        self.execute_statements(statements);
                    }
                }
                Err(e) => {
                    eprintln!("ion: pipeline expansion error: {}", e);
                    self.previous_status = FAILURE;
                    self.variables.set("?", self.previous_status.to_string());
                    self.flow_control.reset();
                    return Condition::Break;
                }
            },
            Statement::Time(box_statement) => {
                let time = ::std::time::Instant::now();

                let condition = self.execute_statement(*box_statement);

                let duration = time.elapsed();
                let seconds = duration.as_secs();
                let nanoseconds = duration.subsec_nanos();

                let stdout = stdout();
                let mut stdout = stdout.lock();
                let _ = if seconds > 60 {
                    writeln!(
                        stdout,
                        "real    {}m{:02}.{:09}s",
                        seconds / 60,
                        seconds % 60,
                        nanoseconds
                    )
                } else {
                    writeln!(stdout, "real    {}.{:09}s", seconds, nanoseconds)
                };
                match condition {
                    Condition::Break => return Condition::Break,
                    Condition::Continue => return Condition::Continue,
                    Condition::NoOp => (),
                    Condition::SigInt => return Condition::SigInt,
                }
            }
            Statement::And(box_statement) => {
                let condition = match self.previous_status {
                    SUCCESS => self.execute_statement(*box_statement),
                    _ => Condition::NoOp,
                };

                match condition {
                    Condition::Break => return Condition::Break,
                    Condition::Continue => return Condition::Continue,
                    Condition::NoOp => (),
                    Condition::SigInt => return Condition::SigInt,
                }
            }
            Statement::Or(box_statement) => {
                let condition = match self.previous_status {
                    FAILURE => self.execute_statement(*box_statement),
                    _ => Condition::NoOp,
                };

                match condition {
                    Condition::Break => return Condition::Break,
                    Condition::Continue => return Condition::Continue,
                    Condition::NoOp => (),
                    Condition::SigInt => return Condition::SigInt,
                }
            }
            Statement::Not(box_statement) => {
                // NOTE: Should the condition be used?
                let _condition = self.execute_statement(*box_statement);
                match self.previous_status {
                    FAILURE => self.previous_status = SUCCESS,
                    SUCCESS => self.previous_status = FAILURE,
                    _ => (),
                }
                let previous_status = self.previous_status.to_string();
                self.set("?", previous_status);
            }
            Statement::Break => return Condition::Break,
            Statement::Continue => return Condition::Continue,
            Statement::Match { expression, cases } => match self.execute_match(expression, cases) {
                Condition::Break => return Condition::Break,
                Condition::Continue => return Condition::Continue,
                Condition::NoOp => (),
                Condition::SigInt => return Condition::SigInt,
            },
            _ => {}
        }
        if let Some(signal) = signals::SignalHandler.next() {
            if self.handle_signal(signal) {
                self.exit(get_signal_code(signal));
            }
            Condition::SigInt
        } else if self.break_flow {
            self.break_flow = false;
            Condition::SigInt
        } else {
            Condition::NoOp
        }
    }

    fn execute_statements(&mut self, statements: Vec<Statement>) -> Condition {
        self.variables.new_scope(false);

        let mut condition = None;
        for statement in statements {
            match self.execute_statement(statement) {
                Condition::NoOp => {}
                cond => {
                    condition = Some(cond);
                    break;
                }
            }
        }

        self.variables.pop_scope();

        condition.unwrap_or(Condition::NoOp)
    }

    fn execute_match(&mut self, expression: small::String, cases: Vec<Case>) -> Condition {
        // Logic for determining if the LHS of a match-case construct (the value we are
        // matching against) matches the RHS of a match-case construct (a value
        // in a case statement). For example, checking to see if the value
        // "foo" matches the pattern "bar" would be invoked like so :
        // ```ignore
        // matches("foo", "bar")
        // ```
        let is_array = is_array(&expression);
        let value = expand_string(&expression, self, false);
        for case in cases.into_iter() {
            if case
                .value
                .map(|v| expand_string(&v, self, false))
                .filter(|v| v.iter().all(|v| !value.contains(v)))
                .is_none()
            {
                // let pattern_is_array = is_array(&value);
                let previous_bind = case.binding.as_ref().and_then(|bind| {
                    if is_array {
                        let out = self.variables.get::<types::Array>(bind).map(Value::Array);
                        self.set(&bind, value.clone());
                        out
                    } else {
                        let out = self.variables.get::<types::Str>(bind).map(Value::Str);
                        self.set(&bind, value.join(" "));
                        out
                    }
                });

                if let Some(statement) = case.conditional {
                    self.on_command(&statement);
                    if self.previous_status != SUCCESS {
                        continue;
                    }
                }

                let condition = self.execute_statements(case.statements);

                if let Some(ref bind) = case.binding {
                    if let Some(value) = previous_bind {
                        match value {
                            Value::HashMap(_) | Value::Array(_) | Value::Str(_) => {
                                self.set(bind, value);
                            }
                            _ => (),
                        }
                    }
                }

                return condition;
            }
        }
        return Condition::NoOp;
    }

    fn on_command(&mut self, command_string: &str) {
        self.break_flow = false;
        let iterator = StatementSplitter::new(command_string).map(parse_and_validate);

        // Go through all of the statements and build up the block stack
        // When block is done return statement for execution.
        for statement in iterator {
            match insert_statement(&mut self.flow_control, statement) {
                Err(why) => {
                    eprintln!("{}", why);
                    self.flow_control.reset();
                    return;
                }
                Ok(Some(stm)) => {
                    let _ = self.execute_statement(stm);
                }
                Ok(None) => {}
            }
        }
    }
}

/// Expand a pipeline containing aliases. As aliases can split the pipeline by having logical
/// operators in them, the function returns the first half of the pipeline and the rest of the
/// statements, where the last statement has the other half of the pipeline merged.
fn expand_pipeline(
    shell: &Shell,
    pipeline: &Pipeline,
) -> Result<(Pipeline, Vec<Statement>), String> {
    let mut item_iter = pipeline.items.iter();
    let mut items: Vec<PipeItem> = Vec::new();
    let mut statements = Vec::new();

    while let Some(item) = item_iter.next() {
        let possible_alias = shell.variables.get::<types::Alias>(item.job.command.as_ref());
        if let Some(alias) = possible_alias {
            statements = StatementSplitter::new(alias.0.as_str()).map(parse_and_validate).collect();

            // First item in the alias should be a pipeline item, otherwise it cannot
            // be placed into a pipeline!
            let len = statements.len();
            if let Some(Statement::Pipeline(ref mut pline)) = statements.first_mut() {
                // Connect inputs and outputs of alias to pipeline
                if let Some(first) = pline.items.first_mut() {
                    first.inputs = item.inputs.clone();

                    // Add alias arguments to expanded args if there's any.
                    if item.job.args.len() > 1 {
                        for arg in &item.job.args[1..] {
                            first.job.args.push(arg.clone());
                        }
                    }
                }
                if len == 1 {
                    if let Some(last) = pline.items.last_mut() {
                        last.outputs = item.outputs.clone();
                        last.job.kind = item.job.kind;
                    }
                }
                items.append(&mut pline.items);
                statements.remove(0);
            }

            // Handle pipeline being broken half by i.e.: '&&' or '||'
            if !statements.is_empty() {
                let err = match statements.last_mut().unwrap() {
                    Statement::And(ref mut boxed_stm)
                    | Statement::Or(ref mut boxed_stm)
                    | Statement::Not(ref mut boxed_stm)
                    | Statement::Time(ref mut boxed_stm) => {
                        let stm = &mut **boxed_stm;
                        if let Statement::Pipeline(ref mut pline) = stm {
                            // Set output of alias to be the output of last pipeline.
                            if let Some(last) = pline.items.last_mut() {
                                last.outputs = item.outputs.clone();
                                last.job.kind = item.job.kind;
                            }
                            // Append rest of the pipeline to the last pipeline in the
                            // alias.
                            for item in item_iter {
                                pline.items.push(item.clone());
                            }
                            // No error
                            false
                        } else {
                            // Error in expansion
                            true
                        }
                    }
                    _ => false,
                };
                if err {
                    return Err(format!(
                        "unable to pipe outputs of alias: '{} = {}'",
                        item.job.command.as_str(),
                        alias.0.as_str()
                    ));
                }
                break;
            }
        } else {
            items.push(item.clone());
        }
    }
    Ok((Pipeline { items }, statements))
}
<|endoftext|>


<commit_before>use log;
use log::{LogRecord, LogLevel, LogMetadata};
use collections::String;

#[repr(u16)]
enum SerialPortRegister {
    COM1Data = 0x3f8,
    COM1InterruptControl = 0x3f9,
    //COM1InterruptIDAndFIFO = 0x3fa,
    COM1LineControl = 0x3fb,
    COM1ModemControl = 0x3fc,
    COM1LineStatus = 0x3fd,
    //COM1ModemStatus = 0x3fe,
    //COM1Scratch = 0x3ff,
}

fn outw(port: SerialPortRegister, data: u16) {
    unsafe {
        asm!("outw %ax, %dx" : : "{dx}" (port as u16), "{ax}" (data));
    }
}

fn outb(port: SerialPortRegister, data: u8) {
    unsafe {
        asm!("outb %al, %dx" : : "{dx}" (port as u16), "{al}" (data));
    }
}

fn inb(port: SerialPortRegister) -> u8 {
    let data: u8;
    unsafe {
        asm!("inb %dx, %al" : "={al}"(data) : "{dx}"(port as u16));
    }
    data
}

impl SerialLogger {
    fn init(&self) {
        outw(SerialPortRegister::COM1LineControl, 0x83);
        outw(SerialPortRegister::COM1Data, 0x01);
        outw(SerialPortRegister::COM1InterruptControl, 0x00);
        outw(SerialPortRegister::COM1InterruptControl, 0x03);
        outw(SerialPortRegister::COM1ModemControl, 0x03);
        inb(SerialPortRegister::COM1Data);
    }

    fn write_string(&self, s: String) {
        for c in s.chars() {
            while (inb(SerialPortRegister::COM1LineStatus) & 0x20) != 0 {}
            outb(SerialPortRegister::COM1Data, c as u8);
        }
    }
}

#[derive(Default)]
struct SerialLogger(());

impl log::Log for SerialLogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= LogLevel::Info
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            let log_message = format!("{}: {}\0", record.level(), record.args());
            self.write_string(log_message);
        }
    }
}

pub fn init() -> Result<(), log::SetLoggerError> {
    unsafe {
        log::set_logger_raw(|max_log_level| {
            static LOGGER: SerialLogger = SerialLogger(());
            LOGGER.init();
            max_log_level.set(log::LogLevelFilter::Info);
            &LOGGER
        })
    }
}

pub fn shutdown() -> Result<(), log::ShutdownLoggerError> {
    log::shutdown_logger_raw().map(|_logger| {})
}
<commit_msg>Switch up serial initialization routine<commit_after>use log;
use log::{LogRecord, LogLevel, LogMetadata};
use collections::String;

#[repr(u16)]
enum SerialPortRegister {
    COM1Data = 0x3f8,
    COM1InterruptControl = 0x3f9,
    //COM1InterruptIDAndFIFO = 0x3fa,
    COM1LineControl = 0x3fb,
    COM1ModemControl = 0x3fc,
    COM1LineStatus = 0x3fd,
    //COM1ModemStatus = 0x3fe,
    //COM1Scratch = 0x3ff,
}

fn outw(port: SerialPortRegister, data: u16) {
    unsafe {
        asm!("outw %ax, %dx" : : "{dx}" (port as u16), "{ax}" (data));
    }
}

fn outb(port: SerialPortRegister, data: u8) {
    unsafe {
        asm!("outb %al, %dx" : : "{dx}" (port as u16), "{al}" (data));
    }
}

fn inb(port: SerialPortRegister) -> u8 {
    let data: u8;
    unsafe {
        asm!("inb %dx, %al" : "={al}"(data) : "{dx}"(port as u16));
    }
    data
}

impl SerialLogger {
    fn init(&self) {
        outw(SerialPortRegister::COM1InterruptControl, 0x00);
        outw(SerialPortRegister::COM1ModemControl, 0x80);
        outw(SerialPortRegister::COM1Data, 0x01);
        outw(SerialPortRegister::COM1InterruptControl, 0x00);
        outw(SerialPortRegister::COM1ModemControl, 0x03);
        outw(SerialPortRegister::COM1LineControl, 0xc7);
        outw(SerialPortRegister::COM1LineStatus, 0x0b);
        outw(SerialPortRegister::COM1InterruptControl, 0x01);

        /*
        outw(SerialPortRegister::COM1LineControl, 0x83);
        outw(SerialPortRegister::COM1Data, 0x01);
        outw(SerialPortRegister::COM1InterruptControl, 0x00);
        outw(SerialPortRegister::COM1InterruptControl, 0x03);
        outw(SerialPortRegister::COM1ModemControl, 0x03);
        inb(SerialPortRegister::COM1Data);
        */
    }

    fn write_string(&self, s: String) {
        for c in s.chars() {
            while (inb(SerialPortRegister::COM1LineStatus) & 0x20) != 0 {}
            outb(SerialPortRegister::COM1Data, c as u8);
        }
    }
}

#[derive(Default)]
struct SerialLogger(());

impl log::Log for SerialLogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= LogLevel::Info
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            let log_message = format!("{}: {}\0", record.level(), record.args());
            self.write_string(log_message);
        }
    }
}

pub fn init() -> Result<(), log::SetLoggerError> {
    unsafe {
        log::set_logger_raw(|max_log_level| {
            static LOGGER: SerialLogger = SerialLogger(());
            LOGGER.init();
            max_log_level.set(log::LogLevelFilter::Info);
            &LOGGER
        })
    }
}

pub fn shutdown() -> Result<(), log::ShutdownLoggerError> {
    log::shutdown_logger_raw().map(|_logger| {})
}
<|endoftext|>