<commit_before>use super::*;
use redox::*;

use orbital::*;

impl Editor {
    /// Redraw the window
    pub fn redraw(&mut self) {
        // TODO: Only draw when relevant for the window
        let (mut pos_x, pos_y) = self.pos();
        // Redraw window
        self.window.set(Color::rgb(25, 25, 25));

        let w = self.window.width();

        pos_x += self.delta();

        if self.options.line_marker {
            self.window.rect(0, (pos_y - self.scroll_y) as isize * 16, w, 16, Color::rgb(45, 45, 45));
        }

        self.window.rect(8 * (pos_x - self.scroll_x) as isize,
                         16 * (pos_y - self.scroll_y) as isize,
                         8,
                         16,
                         Color::WHITE);

        let mut string = false;

        for (y, row) in self.text.iter().enumerate() {
            for (x, &c) in row.iter().enumerate() {
                // TODO: Move outta here
                let color = if self.options.highlight {
                    match c {
                        '\'' | '"' => {
                            string = !string;
                            (226, 225, 167) //(167, 222, 156)
                        },
                        _ if string => (226, 225, 167), //(167, 222, 156)
                        '!' | '@' | '#' | '$' | '%' | '^' | '&' | '|' | '*' | '+' | '-' | '/' | ':' | '=' | '<' | '>' => (198, 83, 83), //(228, 190, 175), //(194, 106, 71),
                        '.' | ',' => (241, 213, 226),
                        '(' | ')' | '[' | ']' | '{' | '}' => (164, 212, 125), //(195, 139, 75),
                        '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => (209, 209, 177),
                        _ => (255, 255, 255),
                    }
                } else {
                    (255, 255, 255)
                };

                let c = if c == '\t' { ' ' } else { c };

                if pos_x == x && pos_y == y {
                    self.window.char(8 * (x - self.scroll_x) as isize,
                                     16 * (y - self.scroll_y) as isize,
                                     c,
                                     Color::rgb(color.0 / 3, color.1 / 3, color.2 / 3));
                } else {
                    self.window.char(8 * (x - self.scroll_x) as isize,
                                     16 * (y - self.scroll_y) as isize,
                                     c,
                                     Color::rgb(color.0, color.1, color.2));
                }
            }
        }

        self.redraw_task = RedrawTask::Null;

        self.redraw_status_bar();
        self.window.sync();
    }

    /// Redraw the status bar
    pub fn redraw_status_bar(&mut self) {
        let h = self.window.height();
        let w = self.window.width();
        let mode = self.cursor().mode;
        self.window.rect(0, h as isize - 18 - {
            if mode == Mode::Primitive(PrimitiveMode::Prompt) {
                18
            } else {
                0
            }
        }, w, 18, Color::rgba(74, 74, 74, 255));

        let sb_mode = self.status_bar.mode.clone();
        status_bar(self, sb_mode, 0, 4);
        let sb_file = self.status_bar.file.clone();
        status_bar(self, sb_file, 1, 4);
        let sb_cmd = self.status_bar.cmd.clone();
        status_bar(self, sb_cmd, 2, 4);
        let sb_msg = self.status_bar.msg.clone();
        status_bar(self, sb_msg, 3, 4);

        for (n, c) in self.prompt.chars().enumerate() {
            self.window.char(n as isize * 8, h as isize - 16 - 1, c, Color::WHITE);
        }

        self.window.sync();
    }
}

fn status_bar(editor: &mut Editor, text: String, a: usize, b: usize) {

    let h = editor.window.height();
    let w = editor.window.width();
    //let y = editor.y();
    let mode = editor.cursor().mode;

    for (n, c) in (if text.len() > w / (8 * b) {
        text.chars().take(w / (8 * b) - 5).chain(vec!['.', '.', '.']).collect::<Vec<_>>()
    } else {
        text.chars().collect()
    }).into_iter().enumerate() {

        editor.window.char(((w * a) / b) as isize + (n as isize * 8), h as isize - 16 - 1 - {
            if mode == Mode::Primitive(PrimitiveMode::Prompt) {
                16 + 1 + 1
            } else {
                0
            }
        }, c, Color::WHITE);
    }
}

/// The statubar (showing various info about the current state of the editor)
pub struct StatusBar {
    /// The current mode
    pub mode: String,
    /// The cureent char
    pub file: String,
    /// The current command
    pub cmd: String,
    /// A message (such as an error or other info to the user)
    pub msg: String,
}

impl StatusBar {
    /// Create new status bar
    pub fn new() -> Self {
        StatusBar {
            mode: "Normal".to_string(),
            file: String::new(),
            cmd: String::new(),
            msg: "Welcome to Sodium!".to_string(),
        }
    }
}
<commit_msg>Use repeating element syntax where possible<commit_after>use super::*;
use redox::*;

use orbital::*;

impl Editor {
    /// Redraw the window
    pub fn redraw(&mut self) {
        // TODO: Only draw when relevant for the window
        let (mut pos_x, pos_y) = self.pos();
        // Redraw window
        self.window.set(Color::rgb(25, 25, 25));

        let w = self.window.width();

        pos_x += self.delta();

        if self.options.line_marker {
            self.window.rect(0, (pos_y - self.scroll_y) as isize * 16, w, 16, Color::rgb(45, 45, 45));
        }

        self.window.rect(8 * (pos_x - self.scroll_x) as isize,
                         16 * (pos_y - self.scroll_y) as isize,
                         8,
                         16,
                         Color::WHITE);

        let mut string = false;

        for (y, row) in self.text.iter().enumerate() {
            for (x, &c) in row.iter().enumerate() {
                // TODO: Move outta here
                let color = if self.options.highlight {
                    match c {
                        '\'' | '"' => {
                            string = !string;
                            (226, 225, 167) //(167, 222, 156)
                        },
                        _ if string => (226, 225, 167), //(167, 222, 156)
                        '!' | '@' | '#' | '$' | '%' | '^' | '&' | '|' | '*' | '+' | '-' | '/' | ':' | '=' | '<' | '>' => (198, 83, 83), //(228, 190, 175), //(194, 106, 71),
                        '.' | ',' => (241, 213, 226),
                        '(' | ')' | '[' | ']' | '{' | '}' => (164, 212, 125), //(195, 139, 75),
                        '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => (209, 209, 177),
                        _ => (255, 255, 255),
                    }
                } else {
                    (255, 255, 255)
                };

                let c = if c == '\t' { ' ' } else { c };

                if pos_x == x && pos_y == y {
                    self.window.char(8 * (x - self.scroll_x) as isize,
                                     16 * (y - self.scroll_y) as isize,
                                     c,
                                     Color::rgb(color.0 / 3, color.1 / 3, color.2 / 3));
                } else {
                    self.window.char(8 * (x - self.scroll_x) as isize,
                                     16 * (y - self.scroll_y) as isize,
                                     c,
                                     Color::rgb(color.0, color.1, color.2));
                }
            }
        }

        self.redraw_task = RedrawTask::Null;

        self.redraw_status_bar();
        self.window.sync();
    }

    /// Redraw the status bar
    pub fn redraw_status_bar(&mut self) {
        let h = self.window.height();
        let w = self.window.width();
        let mode = self.cursor().mode;
        self.window.rect(0, h as isize - 18 - {
            if mode == Mode::Primitive(PrimitiveMode::Prompt) {
                18
            } else {
                0
            }
        }, w, 18, Color::rgba(74, 74, 74, 255));

        let sb_mode = self.status_bar.mode.clone();
        status_bar(self, sb_mode, 0, 4);
        let sb_file = self.status_bar.file.clone();
        status_bar(self, sb_file, 1, 4);
        let sb_cmd = self.status_bar.cmd.clone();
        status_bar(self, sb_cmd, 2, 4);
        let sb_msg = self.status_bar.msg.clone();
        status_bar(self, sb_msg, 3, 4);

        for (n, c) in self.prompt.chars().enumerate() {
            self.window.char(n as isize * 8, h as isize - 16 - 1, c, Color::WHITE);
        }

        self.window.sync();
    }
}

fn status_bar(editor: &mut Editor, text: String, a: usize, b: usize) {

    let h = editor.window.height();
    let w = editor.window.width();
    //let y = editor.y();
    let mode = editor.cursor().mode;

    for (n, c) in (if text.len() > w / (8 * b) {
        text.chars().take(w / (8 * b) - 5).chain(vec!['.'; 3]).collect::<Vec<_>>()
    } else {
        text.chars().collect()
    }).into_iter().enumerate() {

        editor.window.char(((w * a) / b) as isize + (n as isize * 8), h as isize - 16 - 1 - {
            if mode == Mode::Primitive(PrimitiveMode::Prompt) {
                16 + 1 + 1
            } else {
                0
            }
        }, c, Color::WHITE);
    }
}

/// The statubar (showing various info about the current state of the editor)
pub struct StatusBar {
    /// The current mode
    pub mode: String,
    /// The cureent char
    pub file: String,
    /// The current command
    pub cmd: String,
    /// A message (such as an error or other info to the user)
    pub msg: String,
}

impl StatusBar {
    /// Create new status bar
    pub fn new() -> Self {
        StatusBar {
            mode: "Normal".to_string(),
            file: String::new(),
            cmd: String::new(),
            msg: "Welcome to Sodium!".to_string(),
        }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code,
        non_camel_case_types,
        non_snake_case,
        non_upper_case_globals,
        )]

// To Keep consistent with NiFpga
pub type int8_t = i8;
pub type uint8_t = u8;

pub type int16_t = i16;
pub type uint16_t = u16;

pub type int32_t = i32;
pub type uint32_t = u32;

pub type int64_t = i64;
pub type uint64_t = u64;

// NiFpga Types. Will be cleaned up later
pub type NiFpga_Bool = uint8_t;
pub type NiFpga_Status = int32_t;

pub type NiFpga_Session = uint32_t;

#[derive(Copy, Clone)]
#[repr(u32)]
#[derive(Debug)]
pub enum NiFpga_OpenAttribute {
    NiFpga_OpenAttribute_NoRun = 1
}

#[derive(Copy, Clone)]
#[repr(u32)]
#[derive(Debug)]
pub enum NiFpga_CloseAttribute {
    NiFpga_CloseAttribute_NoResetIfLastSession = 1
}

#[derive(Copy, Clone)]
#[repr(u32)]
#[derive(Debug)]
pub enum NiFpga_RunAttribute {
    NiFpga_RunAttribute_WaitUntilDone = 1
}

#[derive(Copy, Clone)]
#[repr(u32)]
#[derive(Debug)]
pub enum NiFpga_Irq {
    NiFpga_Irq_0  = 1 << 0,
    NiFpga_Irq_1  = 1 << 1,
    NiFpga_Irq_2  = 1 << 2,
    NiFpga_Irq_3  = 1 << 3,
    NiFpga_Irq_4  = 1 << 4,
    NiFpga_Irq_5  = 1 << 5,
    NiFpga_Irq_6  = 1 << 6,
    NiFpga_Irq_7  = 1 << 7,
    NiFpga_Irq_8  = 1 << 8,
    NiFpga_Irq_9  = 1 << 9,
    NiFpga_Irq_10 = 1 << 10,
    NiFpga_Irq_11 = 1 << 11,
    NiFpga_Irq_12 = 1 << 12,
    NiFpga_Irq_13 = 1 << 13,
    NiFpga_Irq_14 = 1 << 14,
    NiFpga_Irq_15 = 1 << 15,
    NiFpga_Irq_16 = 1 << 16,
    NiFpga_Irq_17 = 1 << 17,
    NiFpga_Irq_18 = 1 << 18,
    NiFpga_Irq_19 = 1 << 19,
    NiFpga_Irq_20 = 1 << 20,
    NiFpga_Irq_21 = 1 << 21,
    NiFpga_Irq_22 = 1 << 22,
    NiFpga_Irq_23 = 1 << 23,
    NiFpga_Irq_24 = 1 << 24,
    NiFpga_Irq_25 = 1 << 25,
    NiFpga_Irq_26 = 1 << 26,
    NiFpga_Irq_27 = 1 << 27,
    NiFpga_Irq_28 = 1 << 28,
    NiFpga_Irq_29 = 1 << 29,
    NiFpga_Irq_30 = 1 << 30,
    NiFpga_Irq_31 = 1 << 31
}

type NiFpga_IrqContext = *mut ::std::os::raw::c_void;
extern {
    fn NiFpga_Initialize() -> NiFpga_Status;
    fn NiFpga_Finalize() -> NiFpga_Status;
}
<commit_msg>Update fpga_types.rs<commit_after>#![allow(dead_code,
        non_camel_case_types,
        non_snake_case,
        non_upper_case_globals,
        )]

// To Keep consistent with NiFpga
pub type int8_t = i8;
pub type uint8_t = u8;

pub type int16_t = i16;
pub type uint16_t = u16;

pub type int32_t = i32;
pub type uint32_t = u32;

pub type int64_t = i64;
pub type uint64_t = u64;

// NiFpga Types. Will be cleaned up later
pub type NiFpga_Bool = uint8_t;
pub type NiFpga_Status = int32_t;

pub type NiFpga_Session = uint32_t;

#[derive(Copy, Clone)]
#[repr(u32)]
#[derive(Debug)]
pub enum NiFpga_OpenAttribute {
    NiFpga_OpenAttribute_NoRun = 1,
    Dummy
}

#[derive(Copy, Clone)]
#[repr(u32)]
#[derive(Debug)]
pub enum NiFpga_CloseAttribute {
    NiFpga_CloseAttribute_NoResetIfLastSession = 1,
    Dummy
}

#[derive(Copy, Clone)]
#[repr(u32)]
#[derive(Debug)]
pub enum NiFpga_RunAttribute {
    NiFpga_RunAttribute_WaitUntilDone = 1,
    Dummy
}

#[derive(Copy, Clone)]
#[repr(u32)]
#[derive(Debug)]
pub enum NiFpga_Irq {
    NiFpga_Irq_0  = 1 << 0,
    NiFpga_Irq_1  = 1 << 1,
    NiFpga_Irq_2  = 1 << 2,
    NiFpga_Irq_3  = 1 << 3,
    NiFpga_Irq_4  = 1 << 4,
    NiFpga_Irq_5  = 1 << 5,
    NiFpga_Irq_6  = 1 << 6,
    NiFpga_Irq_7  = 1 << 7,
    NiFpga_Irq_8  = 1 << 8,
    NiFpga_Irq_9  = 1 << 9,
    NiFpga_Irq_10 = 1 << 10,
    NiFpga_Irq_11 = 1 << 11,
    NiFpga_Irq_12 = 1 << 12,
    NiFpga_Irq_13 = 1 << 13,
    NiFpga_Irq_14 = 1 << 14,
    NiFpga_Irq_15 = 1 << 15,
    NiFpga_Irq_16 = 1 << 16,
    NiFpga_Irq_17 = 1 << 17,
    NiFpga_Irq_18 = 1 << 18,
    NiFpga_Irq_19 = 1 << 19,
    NiFpga_Irq_20 = 1 << 20,
    NiFpga_Irq_21 = 1 << 21,
    NiFpga_Irq_22 = 1 << 22,
    NiFpga_Irq_23 = 1 << 23,
    NiFpga_Irq_24 = 1 << 24,
    NiFpga_Irq_25 = 1 << 25,
    NiFpga_Irq_26 = 1 << 26,
    NiFpga_Irq_27 = 1 << 27,
    NiFpga_Irq_28 = 1 << 28,
    NiFpga_Irq_29 = 1 << 29,
    NiFpga_Irq_30 = 1 << 30,
    NiFpga_Irq_31 = 1 << 31
}

type NiFpga_IrqContext = *mut ::std::os::raw::c_void;
extern {
    fn NiFpga_Initialize() -> NiFpga_Status;
    fn NiFpga_Finalize() -> NiFpga_Status;
}
<|endoftext|>


<commit_before>extern crate serde_json;

/// Represents the valid json requests that can be made
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum SerialRequest {
  /// Open a port for reading
  Open { port: String },
  /// Take control of a port for writing
  WriteLock { handle: String, port: String },
  /// Release control of a port for writing
  /// If no port is given, release all write locks
  /// for all ports
  ReleaseWriteLock {
    handle: String,
    port: Option<String>,
  },
  /// Write data, only works if we have control
  Write {
    handle: String,
    port: String,
    data: String,
    base64: Option<bool>,
  },
}

/// Represents the possible error types
/// that can be returned
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum ErrorType {
  /// Failed to parse message
  JsonParseFailure,
  /// Unknown request
  UnknownRequest,
  /// Someone else has already locked the port for writing
  AlreadyWriteLocked,
  /// WriteLock needed
  NeedWriteLock,
  /// Error reading serial port
  ReadError,
  /// Error writing serial port
  WriteError,
}

/// Represents the valid serial responses that can be made
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum SerialResponse {
  /// Error response
  Error {
    kind: ErrorType,
    msg: String,
    detail: Option<String>,
    port: Option<String>,
    handle: Option<String>,
  },
  /// Data that was read from port
  Read {
    port: String,
    data: String,
    base64: Option<bool>,
  },
  /// Ok response showing that command was accepted
  Accepted { request: SerialRequest },
}

// json_ser_safely
<commit_msg>Add Close request, and closed response messages<commit_after>extern crate serde_json;

/// Represents the valid json requests that can be made
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum SerialRequest {
  /// Open a port for reading
  Open { port: String },
  /// Take control of a port for writing
  WriteLock { handle: String, port: String },
  /// Release control of a port for writing
  /// If no port is given, release all write locks
  /// for all ports
  ReleaseWriteLock {
    handle: String,
    port: Option<String>,
  },
  /// Write data, only works if we have control
  Write {
    handle: String,
    port: String,
    data: String,
    base64: Option<bool>,
  },
  /// Close a port
  Close { port: String },
}

/// Represents the possible error types
/// that can be returned
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum ErrorType {
  /// Failed to parse message
  JsonParseFailure,
  /// Unknown request
  UnknownRequest,
  /// Someone else has already locked the port for writing
  AlreadyWriteLocked,
  /// WriteLock needed
  NeedWriteLock,
  /// Error reading serial port
  ReadError,
  /// Error writing serial port
  WriteError,
}

/// Represents the valid serial responses that can be made
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum SerialResponse {
  /// Error response
  Error {
    kind: ErrorType,
    msg: String,
    detail: Option<String>,
    port: Option<String>,
    handle: Option<String>,
  },
  /// Data that was read from port
  Read {
    port: String,
    data: String,
    base64: Option<bool>,
  },
  /// Port was closed
  Closed { port: String },
  /// Ok response showing that command was accepted
  Accepted { request: SerialRequest },
}

// json_ser_safely
<|endoftext|>


<commit_before>extern crate frunk;
#[macro_use] // for the hlist macro
extern crate frunk_core;
extern crate time; //Time library

use frunk::*; // for the Generic trait and HList

mod common;

use common::*;

use self::time::*;

#[test]
fn test_struct_from_labelled_generic() {
    let h = hlist![field!((f, i, r, s, t, __, n, a, m, e), "Humpty"),
                   field!((l, a, s, t, __, n, a, m, e), "Drumpty"),
                   field!((a, g, e), 3)];
    let u: NewUser = from_labelled_generic(h);
    assert_eq!(u,
               NewUser {
                   first_name: "Humpty",
                   last_name: "Drumpty",
                   age: 3,
               });
}

#[test]
fn test_labelled_generic_names() {
    let u = NewUser {
        first_name: "Humpty",
        last_name: "Drumpty",
        age: 3,
    };
    let h = into_labelled_generic(u);
    let l_name_field: &Field<(l, a, s, t, __, n, a, m, e), _> = h.get();
    assert_eq!(l_name_field.name, "last_name");
    let f_name_field: &Field<(f, i, r, s, t, __, n, a, m, e), _> = h.get();
    assert_eq!(f_name_field.name, "first_name")
}

#[test]
fn test_struct_into_labelled_generic() {
    let u = NewUser {
        first_name: "Humpty",
        last_name: "Drumpty",
        age: 3,
    };
    let h = into_labelled_generic(u);
    assert_eq!(h,
               hlist![field!((f, i, r, s, t, __, n, a, m, e), "Humpty", "first_name"),
                      field!((l, a, s, t, __, n, a, m, e), "Drumpty", "last_name"),
                      field!((a, g, e), 3)]);
}

#[test]
fn test_reshaped_labelled_generic_conversion() {
    let n_u = NormalUser {
        first_name: "Moe",
        last_name: "Ali",
        age: 30,
    };
    // Convert to labelled-generic representation
    let n_gen = into_labelled_generic(n_u);
    // Reshape the labelled generic to fit the JumbledUser's generic Repr
    let (jumbled_gen, _): (<JumbledUser as LabelledGeneric>::Repr, _) = n_gen.sculpt();
    let j_u: JumbledUser = from_labelled_generic(jumbled_gen); // Done

    assert_eq!(j_u.first_name, "Moe");
    assert_eq!(j_u.last_name, "Ali");
    assert_eq!(j_u.age, 30)
}

#[test]
fn test_aligned_labelled_convert_from() {
    let n_u = NormalUser {
        first_name: "Moe",
        last_name: "Ali",
        age: 30,
    };
    // even less boilerplate than before
    let j_u: JumbledUser = sculpted_convert_from(n_u); // Done

    assert_eq!(j_u.first_name, "Moe");
    assert_eq!(j_u.last_name, "Ali");
    assert_eq!(j_u.age, 30)
}

/// Converts from the Input type to the Output type,
/// provided that the Output type has a compatible labelled representation
/// with Input *AND* has a created_at Time field
///
/// If we wanted to, we could even make the time field type a parameter too for
/// even more generalisation.
fn to_audited<O, I, Indices>(o: I) -> O
    where I: LabelledGeneric,
          O: LabelledGeneric,
          HCons<Field<(c, r, e, a, t, e, d, __, a, t), Tm>, <I as LabelledGeneric>::Repr>: Sculptor<<O as LabelledGeneric>::Repr, Indices>
{
    // Add created_at field to LabelledGeneric repr of I
    let i_with_time = HCons {
        head: field!((c, r, e, a, t, e, d, __, a, t), time::now()),
        tail: into_labelled_generic(o),
    };
    // sculpt it to fit Output LabelledGeneric representation
    let (compatible_with_o, _): (<O as LabelledGeneric>::Repr, _) = i_with_time.sculpt();
    // convert from LabelledGeneric to Output
    from_labelled_generic(compatible_with_o)
}

#[test]
fn test_generalised_auditing() {
    let now = time::now().tm_nsec;
    // Need to help the compiler out by annotating, but no biggie
    let n_u_audited: NormalUserWithAudit = to_audited(NormalUser::build());
    let j_u_audited: JumbledUserWithAudit = to_audited(JumbledUser::build());
    assert!(n_u_audited.created_at.tm_nsec >= now);
    assert!(j_u_audited.created_at.tm_nsec >= now);
}
<commit_msg>Add explanation for type params<commit_after>extern crate frunk;
#[macro_use] // for the hlist macro
extern crate frunk_core;
extern crate time; //Time library

use frunk::*; // for the Generic trait and HList

mod common;

use common::*;

use self::time::*;

#[test]
fn test_struct_from_labelled_generic() {
    let h = hlist![field!((f, i, r, s, t, __, n, a, m, e), "Humpty"),
                   field!((l, a, s, t, __, n, a, m, e), "Drumpty"),
                   field!((a, g, e), 3)];
    let u: NewUser = from_labelled_generic(h);
    assert_eq!(u,
               NewUser {
                   first_name: "Humpty",
                   last_name: "Drumpty",
                   age: 3,
               });
}

#[test]
fn test_labelled_generic_names() {
    let u = NewUser {
        first_name: "Humpty",
        last_name: "Drumpty",
        age: 3,
    };
    let h = into_labelled_generic(u);
    let l_name_field: &Field<(l, a, s, t, __, n, a, m, e), _> = h.get();
    assert_eq!(l_name_field.name, "last_name");
    let f_name_field: &Field<(f, i, r, s, t, __, n, a, m, e), _> = h.get();
    assert_eq!(f_name_field.name, "first_name")
}

#[test]
fn test_struct_into_labelled_generic() {
    let u = NewUser {
        first_name: "Humpty",
        last_name: "Drumpty",
        age: 3,
    };
    let h = into_labelled_generic(u);
    assert_eq!(h,
               hlist![field!((f, i, r, s, t, __, n, a, m, e), "Humpty", "first_name"),
                      field!((l, a, s, t, __, n, a, m, e), "Drumpty", "last_name"),
                      field!((a, g, e), 3)]);
}

#[test]
fn test_reshaped_labelled_generic_conversion() {
    let n_u = NormalUser {
        first_name: "Moe",
        last_name: "Ali",
        age: 30,
    };
    // Convert to labelled-generic representation
    let n_gen = into_labelled_generic(n_u);
    // Reshape the labelled generic to fit the JumbledUser's generic Repr
    let (jumbled_gen, _): (<JumbledUser as LabelledGeneric>::Repr, _) = n_gen.sculpt();
    let j_u: JumbledUser = from_labelled_generic(jumbled_gen); // Done

    assert_eq!(j_u.first_name, "Moe");
    assert_eq!(j_u.last_name, "Ali");
    assert_eq!(j_u.age, 30)
}

#[test]
fn test_aligned_labelled_convert_from() {
    let n_u = NormalUser {
        first_name: "Moe",
        last_name: "Ali",
        age: 30,
    };
    // even less boilerplate than before
    let j_u: JumbledUser = sculpted_convert_from(n_u); // Done

    assert_eq!(j_u.first_name, "Moe");
    assert_eq!(j_u.last_name, "Ali");
    assert_eq!(j_u.age, 30)
}

/// Converts from the Input type to the Output type,
/// provided that the Output type has a compatible labelled representation
/// with Input *AND* has a created_at Time field
///
/// If we wanted to, we could even make the time field type a parameter too for
/// even more generalisation.
///
/// Type parameters:
///
/// I stands for Input
/// O stands for Output
/// Indices is for the indices used for sculpting I with created_at Field into O's generic representation
fn to_audited<I, O, Indices>(o: I) -> O
    where I: LabelledGeneric,
          O: LabelledGeneric,
          HCons<Field<(c, r, e, a, t, e, d, __, a, t), Tm>, <I as LabelledGeneric>::Repr>: Sculptor<<O as LabelledGeneric>::Repr, Indices>
{
    // Add created_at field to LabelledGeneric repr of I
    let i_with_time = HCons {
        head: field!((c, r, e, a, t, e, d, __, a, t), time::now()),
        tail: into_labelled_generic(o),
    };
    // sculpt it to fit Output LabelledGeneric representation
    let (compatible_with_o, _): (<O as LabelledGeneric>::Repr, _) = i_with_time.sculpt();
    // convert from LabelledGeneric to Output
    from_labelled_generic(compatible_with_o)
}

#[test]
fn test_generalised_auditing() {
    let now = time::now().tm_nsec;
    // Need to help the compiler out by annotating, but no biggie
    let n_u_audited: NormalUserWithAudit = to_audited(NormalUser::build());
    let j_u_audited: JumbledUserWithAudit = to_audited(JumbledUser::build());
    assert!(n_u_audited.created_at.tm_nsec >= now);
    assert!(j_u_audited.created_at.tm_nsec >= now);
}
<|endoftext|>


<commit_before><commit_msg>Remove commented-out code<commit_after><|endoftext|>


<commit_before>use std::mem::size_of;

use super::*;

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub(crate) struct Node {
    pub(crate) id: PageId,
    pub(crate) data: Data,
    pub(crate) next: Option<PageId>,
    pub(crate) lo: IVec,
    pub(crate) hi: IVec,
}

impl Node {
    #[inline]
    pub(crate) fn size_in_bytes(&self) -> u64 {
        let self_sz = size_of::<Self>() as u64;
        let lo_sz = self.lo.size_in_bytes();
        let hi_sz = self.hi.size_in_bytes();
        let data_sz = self.data.size_in_bytes();

        self_sz
            .saturating_add(lo_sz)
            .saturating_add(hi_sz)
            .saturating_add(data_sz)
    }

    pub(crate) fn apply(
        &mut self,
        frag: &Frag,
        merge_operator: Option<usize>,
    ) {
        use self::Frag::*;

        match *frag {
            Set(ref k, ref v) => {
                // (when hi is empty, it means it's unbounded)
                if self.hi.is_empty()
                    || prefix_cmp_encoded(k, &self.hi, &self.lo)
                        == std::cmp::Ordering::Less
                {
                    self.set_leaf(k.clone(), v.clone());
                } else {
                    panic!("tried to consolidate set at key <= hi")
                }
            }
            Merge(ref k, ref v) => {
                // (when hi is empty, it means it's unbounded)
                if self.hi.is_empty()
                    || prefix_cmp_encoded(k, &self.hi, &self.lo)
                        == std::cmp::Ordering::Less
                {
                    let merge_fn_ptr = merge_operator
                        .expect("must have a merge operator set");
                    unsafe {
                        let merge_fn: MergeOperator =
                            std::mem::transmute(merge_fn_ptr);
                        self.merge_leaf(
                            k.clone(),
                            v.clone(),
                            merge_fn,
                        );
                    }
                } else {
                    panic!("tried to consolidate set at key <= hi")
                }
            }
            ChildSplit(ref child_split) => {
                self.child_split(child_split);
            }
            ParentSplit(ref parent_split) => {
                self.parent_split(parent_split);
            }
            Del(ref k) => {
                // (when hi is empty, it means it's unbounded)
                if self.hi.is_empty()
                    || prefix_cmp_encoded(k, &self.hi, &self.lo)
                        == std::cmp::Ordering::Less
                {
                    self.del_leaf(k);
                } else {
                    panic!("tried to consolidate del at key <= hi")
                }
            }
            Base(_) => {
                panic!("encountered base page in middle of chain")
            }
        }
    }

    pub(crate) fn set_leaf(&mut self, key: IVec, val: IVec) {
        if let Data::Leaf(ref mut records) = self.data {
            let search =
                records.binary_search_by(|&(ref k, ref _v)| {
                    prefix_cmp(k, &*key)
                });
            if let Ok(idx) = search {
                records[idx] = (key, val);
            } else {
                records.push((key, val));
                records.sort_unstable_by(|a, b| {
                    prefix_cmp(&*a.0, &*b.0)
                });
            }
        } else {
            panic!("tried to Set a value to an index");
        }
    }

    pub(crate) fn merge_leaf(
        &mut self,
        key: IVec,
        val: IVec,
        merge_fn: MergeOperator,
    ) {
        if let Data::Leaf(ref mut records) = self.data {
            let search =
                records.binary_search_by(|&(ref k, ref _v)| {
                    prefix_cmp(k, &*key)
                });

            let decoded_k = prefix_decode(&self.lo, &key);
            if let Ok(idx) = search {
                let new = merge_fn(
                    &*decoded_k,
                    Some(&records[idx].1),
                    &val,
                );
                if let Some(new) = new {
                    records[idx] = (key, new.into());
                } else {
                    records.remove(idx);
                }
            } else {
                let new = merge_fn(&*decoded_k, None, &val);
                if let Some(new) = new {
                    records.push((key, new.into()));
                    records.sort_unstable_by(|a, b| {
                        prefix_cmp(&*a.0, &*b.0)
                    });
                }
            }
        } else {
            panic!("tried to Merge a value to an index");
        }
    }

    pub(crate) fn child_split(&mut self, cs: &ChildSplit) {
        self.data.drop_gte(&cs.at, &self.lo);
        self.hi = cs.at.clone();
        self.next = Some(cs.to);
    }

    pub(crate) fn parent_split(&mut self, ps: &ParentSplit) {
        if let Data::Index(ref mut ptrs) = self.data {
            let encoded_sep = prefix_encode(&self.lo, &ps.at);
            ptrs.push((encoded_sep, ps.to));
            ptrs.sort_unstable_by(|a, b| prefix_cmp(&*a.0, &*b.0));
        } else {
            panic!("tried to attach a ParentSplit to a Leaf chain");
        }
    }

    pub(crate) fn del_leaf(&mut self, key: &IVec) {
        if let Data::Leaf(ref mut records) = self.data {
            let search =
                records.binary_search_by(|&(ref k, ref _v)| {
                    prefix_cmp(k, &*key)
                });
            if let Ok(idx) = search {
                records.remove(idx);
            }
        } else {
            panic!("tried to attach a Del to an Index chain");
        }
    }

    pub(crate) fn should_split(&self, max_sz: u64) -> bool {
        self.data.len() > 2 && self.size_in_bytes() > max_sz
    }

    pub(crate) fn split(&self, id: PageId) -> Node {
        let (split, right_data) = self.data.split(&self.lo);
        Node {
            id,
            data: right_data,
            next: self.next,
            lo: split,
            hi: self.hi.clone(),
        }
    }
}
<commit_msg>Prefer inserting at index instead of sorting<commit_after>use std::mem::size_of;

use super::*;

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub(crate) struct Node {
    pub(crate) id: PageId,
    pub(crate) data: Data,
    pub(crate) next: Option<PageId>,
    pub(crate) lo: IVec,
    pub(crate) hi: IVec,
}

impl Node {
    #[inline]
    pub(crate) fn size_in_bytes(&self) -> u64 {
        let self_sz = size_of::<Self>() as u64;
        let lo_sz = self.lo.size_in_bytes();
        let hi_sz = self.hi.size_in_bytes();
        let data_sz = self.data.size_in_bytes();

        self_sz
            .saturating_add(lo_sz)
            .saturating_add(hi_sz)
            .saturating_add(data_sz)
    }

    pub(crate) fn apply(
        &mut self,
        frag: &Frag,
        merge_operator: Option<usize>,
    ) {
        use self::Frag::*;

        match *frag {
            Set(ref k, ref v) => {
                // (when hi is empty, it means it's unbounded)
                if self.hi.is_empty()
                    || prefix_cmp_encoded(k, &self.hi, &self.lo)
                        == std::cmp::Ordering::Less
                {
                    self.set_leaf(k.clone(), v.clone());
                } else {
                    panic!("tried to consolidate set at key <= hi")
                }
            }
            Merge(ref k, ref v) => {
                // (when hi is empty, it means it's unbounded)
                if self.hi.is_empty()
                    || prefix_cmp_encoded(k, &self.hi, &self.lo)
                        == std::cmp::Ordering::Less
                {
                    let merge_fn_ptr = merge_operator
                        .expect("must have a merge operator set");
                    unsafe {
                        let merge_fn: MergeOperator =
                            std::mem::transmute(merge_fn_ptr);
                        self.merge_leaf(
                            k.clone(),
                            v.clone(),
                            merge_fn,
                        );
                    }
                } else {
                    panic!("tried to consolidate set at key <= hi")
                }
            }
            ChildSplit(ref child_split) => {
                self.child_split(child_split);
            }
            ParentSplit(ref parent_split) => {
                self.parent_split(parent_split);
            }
            Del(ref k) => {
                // (when hi is empty, it means it's unbounded)
                if self.hi.is_empty()
                    || prefix_cmp_encoded(k, &self.hi, &self.lo)
                        == std::cmp::Ordering::Less
                {
                    self.del_leaf(k);
                } else {
                    panic!("tried to consolidate del at key <= hi")
                }
            }
            Base(_) => {
                panic!("encountered base page in middle of chain")
            }
        }
    }

    pub(crate) fn set_leaf(&mut self, key: IVec, val: IVec) {
        if let Data::Leaf(ref mut records) = self.data {
            let search =
                records.binary_search_by(|(k, _)| {
                    prefix_cmp(k, &key)
                });
            match search {
                Ok(idx) => records[idx] = (key, val),
                Err(idx) => records.insert(idx, (key, val)),
            }
        } else {
            panic!("tried to Set a value to an index");
        }
    }

    pub(crate) fn merge_leaf(
        &mut self,
        key: IVec,
        val: IVec,
        merge_fn: MergeOperator,
    ) {
        if let Data::Leaf(ref mut records) = self.data {
            let search =
                records.binary_search_by(|(k, _)| {
                    prefix_cmp(k, &key)
                });

            let decoded_k = prefix_decode(&self.lo, &key);

            match search {
                Ok(idx) => {
                    let new = merge_fn(
                        &*decoded_k,
                        Some(&records[idx].1),
                        &val,
                    );
                    if let Some(new) = new {
                        records[idx] = (key, new.into());
                    } else {
                        records.remove(idx);
                    }
                },
                Err(idx) => {
                    let new = merge_fn(&*decoded_k, None, &val);
                    if let Some(new) = new {
                        records.insert(idx, (key, new.into()));
                    }
                }
            }
        } else {
            panic!("tried to Merge a value to an index");
        }
    }

    pub(crate) fn child_split(&mut self, cs: &ChildSplit) {
        self.data.drop_gte(&cs.at, &self.lo);
        self.hi = cs.at.clone();
        self.next = Some(cs.to);
    }

    pub(crate) fn parent_split(&mut self, ps: &ParentSplit) {
        if let Data::Index(ref mut ptrs) = self.data {
            let encoded_sep = prefix_encode(&self.lo, &ps.at);
            match ptrs.binary_search_by(|a| prefix_cmp(&a.0, &encoded_sep)) {
                Ok(_) => panic!("must not have found ptr"),
                Err(idx) => ptrs.insert(idx, (encoded_sep, ps.to)),
            }
        } else {
            panic!("tried to attach a ParentSplit to a Leaf chain");
        }
    }

    pub(crate) fn del_leaf(&mut self, key: &IVec) {
        if let Data::Leaf(ref mut records) = self.data {
            let search =
                records.binary_search_by(|&(ref k, ref _v)| {
                    prefix_cmp(k, &*key)
                });
            if let Ok(idx) = search {
                records.remove(idx);
            }
        } else {
            panic!("tried to attach a Del to an Index chain");
        }
    }

    pub(crate) fn should_split(&self, max_sz: u64) -> bool {
        self.data.len() > 2 && self.size_in_bytes() > max_sz
    }

    pub(crate) fn split(&self, id: PageId) -> Node {
        let (split, right_data) = self.data.split(&self.lo);
        Node {
            id,
            data: right_data,
            next: self.next,
            lo: split,
            hi: self.hi.clone(),
        }
    }
}
<|endoftext|>


<commit_before>//! A forest of B+-trees.
//!
//! This crate provides a data structures representing a set of small ordered sets or maps.
//! It is implemented as a forest of B+-trees all allocating nodes out of the same pool.
//!
//! **These are not general purpose data structures that are somehow magically faster that the
//! standard library's `BTreeSet` and `BTreeMap` types.**
//!
//! The tradeoffs are different:
//!
//! - Keys and values are expected to be small and copyable. We optimize for 32-bit types.
//! - A comparator object is used to compare keys, allowing smaller "context free" keys.
//! - Empty trees have a very small 32-bit footprint.
//! - All the trees in a forest can be cleared in constant time.

#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)]
#![warn(unused_import_braces)]
#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::new_without_default))]
#![cfg_attr(
    feature = "cargo-clippy",
    warn(
        clippy::float_arithmetic,
        clippy::mut_mut,
        clippy::nonminimal_bool,
        clippy::option_map_unwrap_or,
        clippy::option_map_unwrap_or_else,
        clippy::print_stdout,
        clippy::unicode_not_nfc,
        clippy::use_self
    )
)]
#![no_std]

#[cfg(test)]
#[macro_use]
extern crate alloc;

#[macro_use]
extern crate cranelift_entity as entity;
use crate::entity::packed_option;

use core::borrow::BorrowMut;
use core::cmp::Ordering;

mod map;
mod node;
mod path;
mod pool;
mod set;

pub use self::map::{Map, MapCursor, MapForest, MapIter};
pub use self::set::{Set, SetCursor, SetForest, SetIter};

use self::node::NodeData;
use self::path::Path;
use self::pool::NodePool;

/// The maximum branching factor of an inner node in a B+-tree.
/// The minimum number of outgoing edges is `INNER_SIZE/2`.
const INNER_SIZE: usize = 8;

/// Given the worst case branching factor of `INNER_SIZE/2` = 4, this is the
/// worst case path length from the root node to a leaf node in a tree with 2^32
/// entries. We would run out of node references before we hit `MAX_PATH`.
const MAX_PATH: usize = 16;

/// Key comparator.
///
/// Keys don't need to implement `Ord`. They are compared using a comparator object which
/// provides a context for comparison.
pub trait Comparator<K>
where
    K: Copy,
{
    /// Compare keys `a` and `b`.
    ///
    /// This relation must provide a total ordering or the key space.
    fn cmp(&self, a: K, b: K) -> Ordering;

    /// Binary search for `k` in an ordered slice.
    ///
    /// Assume that `s` is already sorted according to this ordering, search for the key `k`.
    ///
    /// Returns `Ok(idx)` if `k` was found in the slice or `Err(idx)` with the position where it
    /// should be inserted to preserve the ordering.
    fn search(&self, k: K, s: &[K]) -> Result<usize, usize> {
        s.binary_search_by(|x| self.cmp(*x, k))
    }
}

/// Trivial comparator that doesn't actually provide any context.
impl<K> Comparator<K> for ()
where
    K: Copy + Ord,
{
    fn cmp(&self, a: K, b: K) -> Ordering {
        a.cmp(&b)
    }
}

/// Family of types shared by the map and set forest implementations.
trait Forest {
    /// The key type is present for both sets and maps.
    type Key: Copy;

    /// The value type is `()` for sets.
    type Value: Copy;

    /// An array of keys for the leaf nodes.
    type LeafKeys: Copy + BorrowMut<[Self::Key]>;

    /// An array of values for the leaf nodes.
    type LeafValues: Copy + BorrowMut<[Self::Value]>;

    /// Splat a single key into a whole array.
    fn splat_key(key: Self::Key) -> Self::LeafKeys;

    /// Splat a single value inst a whole array
    fn splat_value(value: Self::Value) -> Self::LeafValues;
}

/// A reference to a B+-tree node.
#[derive(Clone, Copy, PartialEq, Eq)]
struct Node(u32);
entity_impl!(Node, "node");

/// Empty type to be used as the "value" in B-trees representing sets.
#[derive(Clone, Copy)]
struct SetValue();

/// Insert `x` into `s` at position `i`, pushing out the last element.
fn slice_insert<T: Copy>(s: &mut [T], i: usize, x: T) {
    for j in (i + 1..s.len()).rev() {
        s[j] = s[j - 1];
    }
    s[i] = x;
}

/// Shift elements in `s` to the left by `n` positions.
fn slice_shift<T: Copy>(s: &mut [T], n: usize) {
    for j in 0..s.len() - n {
        s[j] = s[j + n];
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::entity::EntityRef;

    /// An opaque reference to an extended basic block in a function.
    #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
    pub struct Ebb(u32);
    entity_impl!(Ebb, "ebb");

    #[test]
    fn comparator() {
        let ebb1 = Ebb::new(1);
        let ebb2 = Ebb::new(2);
        let ebb3 = Ebb::new(3);
        let ebb4 = Ebb::new(4);
        let vals = [ebb1, ebb2, ebb4];
        let comp = ();
        assert_eq!(comp.search(ebb1, &vals), Ok(0));
        assert_eq!(comp.search(ebb3, &vals), Err(2));
        assert_eq!(comp.search(ebb4, &vals), Ok(2));
    }

    #[test]
    fn slice_insertion() {
        let mut a = ['a', 'b', 'c', 'd'];

        slice_insert(&mut a[0..1], 0, 'e');
        assert_eq!(a, ['e', 'b', 'c', 'd']);

        slice_insert(&mut a, 0, 'a');
        assert_eq!(a, ['a', 'e', 'b', 'c']);

        slice_insert(&mut a, 3, 'g');
        assert_eq!(a, ['a', 'e', 'b', 'g']);

        slice_insert(&mut a, 1, 'h');
        assert_eq!(a, ['a', 'h', 'e', 'b']);
    }

    #[test]
    fn slice_shifting() {
        let mut a = ['a', 'b', 'c', 'd'];

        slice_shift(&mut a[0..1], 1);
        assert_eq!(a, ['a', 'b', 'c', 'd']);

        slice_shift(&mut a[1..], 1);
        assert_eq!(a, ['a', 'c', 'd', 'd']);

        slice_shift(&mut a, 2);
        assert_eq!(a, ['d', 'd', 'd', 'd']);
    }
}
<commit_msg>cleanup: remove spurious macro_use in cranelift-bforest;<commit_after>//! A forest of B+-trees.
//!
//! This crate provides a data structures representing a set of small ordered sets or maps.
//! It is implemented as a forest of B+-trees all allocating nodes out of the same pool.
//!
//! **These are not general purpose data structures that are somehow magically faster that the
//! standard library's `BTreeSet` and `BTreeMap` types.**
//!
//! The tradeoffs are different:
//!
//! - Keys and values are expected to be small and copyable. We optimize for 32-bit types.
//! - A comparator object is used to compare keys, allowing smaller "context free" keys.
//! - Empty trees have a very small 32-bit footprint.
//! - All the trees in a forest can be cleared in constant time.

#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)]
#![warn(unused_import_braces)]
#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::new_without_default))]
#![cfg_attr(
    feature = "cargo-clippy",
    warn(
        clippy::float_arithmetic,
        clippy::mut_mut,
        clippy::nonminimal_bool,
        clippy::option_map_unwrap_or,
        clippy::option_map_unwrap_or_else,
        clippy::print_stdout,
        clippy::unicode_not_nfc,
        clippy::use_self
    )
)]
#![no_std]

#[cfg(test)]
extern crate alloc;

#[macro_use]
extern crate cranelift_entity as entity;
use crate::entity::packed_option;

use core::borrow::BorrowMut;
use core::cmp::Ordering;

mod map;
mod node;
mod path;
mod pool;
mod set;

pub use self::map::{Map, MapCursor, MapForest, MapIter};
pub use self::set::{Set, SetCursor, SetForest, SetIter};

use self::node::NodeData;
use self::path::Path;
use self::pool::NodePool;

/// The maximum branching factor of an inner node in a B+-tree.
/// The minimum number of outgoing edges is `INNER_SIZE/2`.
const INNER_SIZE: usize = 8;

/// Given the worst case branching factor of `INNER_SIZE/2` = 4, this is the
/// worst case path length from the root node to a leaf node in a tree with 2^32
/// entries. We would run out of node references before we hit `MAX_PATH`.
const MAX_PATH: usize = 16;

/// Key comparator.
///
/// Keys don't need to implement `Ord`. They are compared using a comparator object which
/// provides a context for comparison.
pub trait Comparator<K>
where
    K: Copy,
{
    /// Compare keys `a` and `b`.
    ///
    /// This relation must provide a total ordering or the key space.
    fn cmp(&self, a: K, b: K) -> Ordering;

    /// Binary search for `k` in an ordered slice.
    ///
    /// Assume that `s` is already sorted according to this ordering, search for the key `k`.
    ///
    /// Returns `Ok(idx)` if `k` was found in the slice or `Err(idx)` with the position where it
    /// should be inserted to preserve the ordering.
    fn search(&self, k: K, s: &[K]) -> Result<usize, usize> {
        s.binary_search_by(|x| self.cmp(*x, k))
    }
}

/// Trivial comparator that doesn't actually provide any context.
impl<K> Comparator<K> for ()
where
    K: Copy + Ord,
{
    fn cmp(&self, a: K, b: K) -> Ordering {
        a.cmp(&b)
    }
}

/// Family of types shared by the map and set forest implementations.
trait Forest {
    /// The key type is present for both sets and maps.
    type Key: Copy;

    /// The value type is `()` for sets.
    type Value: Copy;

    /// An array of keys for the leaf nodes.
    type LeafKeys: Copy + BorrowMut<[Self::Key]>;

    /// An array of values for the leaf nodes.
    type LeafValues: Copy + BorrowMut<[Self::Value]>;

    /// Splat a single key into a whole array.
    fn splat_key(key: Self::Key) -> Self::LeafKeys;

    /// Splat a single value inst a whole array
    fn splat_value(value: Self::Value) -> Self::LeafValues;
}

/// A reference to a B+-tree node.
#[derive(Clone, Copy, PartialEq, Eq)]
struct Node(u32);
entity_impl!(Node, "node");

/// Empty type to be used as the "value" in B-trees representing sets.
#[derive(Clone, Copy)]
struct SetValue();

/// Insert `x` into `s` at position `i`, pushing out the last element.
fn slice_insert<T: Copy>(s: &mut [T], i: usize, x: T) {
    for j in (i + 1..s.len()).rev() {
        s[j] = s[j - 1];
    }
    s[i] = x;
}

/// Shift elements in `s` to the left by `n` positions.
fn slice_shift<T: Copy>(s: &mut [T], n: usize) {
    for j in 0..s.len() - n {
        s[j] = s[j + n];
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::entity::EntityRef;

    /// An opaque reference to an extended basic block in a function.
    #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
    pub struct Ebb(u32);
    entity_impl!(Ebb, "ebb");

    #[test]
    fn comparator() {
        let ebb1 = Ebb::new(1);
        let ebb2 = Ebb::new(2);
        let ebb3 = Ebb::new(3);
        let ebb4 = Ebb::new(4);
        let vals = [ebb1, ebb2, ebb4];
        let comp = ();
        assert_eq!(comp.search(ebb1, &vals), Ok(0));
        assert_eq!(comp.search(ebb3, &vals), Err(2));
        assert_eq!(comp.search(ebb4, &vals), Ok(2));
    }

    #[test]
    fn slice_insertion() {
        let mut a = ['a', 'b', 'c', 'd'];

        slice_insert(&mut a[0..1], 0, 'e');
        assert_eq!(a, ['e', 'b', 'c', 'd']);

        slice_insert(&mut a, 0, 'a');
        assert_eq!(a, ['a', 'e', 'b', 'c']);

        slice_insert(&mut a, 3, 'g');
        assert_eq!(a, ['a', 'e', 'b', 'g']);

        slice_insert(&mut a, 1, 'h');
        assert_eq!(a, ['a', 'h', 'e', 'b']);
    }

    #[test]
    fn slice_shifting() {
        let mut a = ['a', 'b', 'c', 'd'];

        slice_shift(&mut a[0..1], 1);
        assert_eq!(a, ['a', 'b', 'c', 'd']);

        slice_shift(&mut a[1..], 1);
        assert_eq!(a, ['a', 'c', 'd', 'd']);

        slice_shift(&mut a, 2);
        assert_eq!(a, ['d', 'd', 'd', 'd']);
    }
}
<|endoftext|>


<commit_before>macro_rules! impl_traits {
    { $type:ident, $scalar:ty } => {
        impl<const LANES: usize> core::iter::Sum<Self> for crate::$type<LANES>
        where
            Self: crate::LanesAtMost32,
        {
            fn sum<I: core::iter::Iterator<Item = Self>>(iter: I) -> Self {
                iter.fold(Default::default(), core::ops::Add::add)
            }
        }

        impl<const LANES: usize> core::iter::Product<Self> for crate::$type<LANES>
        where
            Self: crate::LanesAtMost32,
        {
            fn product<I: core::iter::Iterator<Item = Self>>(iter: I) -> Self {
                iter.fold(Default::default(), core::ops::Mul::mul)
            }
        }

        impl<const LANES: usize> core::iter::Sum<crate::$type<LANES>> for $scalar
        where
            crate::$type<LANES>: crate::LanesAtMost32,
        {
            fn sum<I: core::iter::Iterator<Item = crate::$type<LANES>>>(iter: I) -> Self {
                iter.sum::<crate::$type<LANES>>().horizontal_sum()
            }
        }

        impl<const LANES: usize> core::iter::Product<crate::$type<LANES>> for $scalar
        where
            crate::$type<LANES>: crate::LanesAtMost32,
        {
            fn product<I: core::iter::Iterator<Item = crate::$type<LANES>>>(iter: I) -> Self {
                iter.product::<crate::$type<LANES>>().horizontal_product()
            }
        }

        impl<'a, const LANES: usize> core::iter::Sum<&'a Self> for crate::$type<LANES>
        where
            Self: crate::LanesAtMost32,
        {
            fn sum<I: core::iter::Iterator<Item = &'a Self>>(iter: I) -> Self {
                iter.fold(Default::default(), core::ops::Add::add)
            }
        }

        impl<'a, const LANES: usize> core::iter::Product<&'a Self> for crate::$type<LANES>
        where
            Self: crate::LanesAtMost32,
        {
            fn product<I: core::iter::Iterator<Item = &'a Self>>(iter: I) -> Self {
                iter.fold(Default::default(), core::ops::Mul::mul)
            }
        }

        impl<'a, const LANES: usize> core::iter::Sum<&'a crate::$type<LANES>> for $scalar
        where
            crate::$type<LANES>: crate::LanesAtMost32,
        {
            fn sum<I: core::iter::Iterator<Item = &'a crate::$type<LANES>>>(iter: I) -> Self {
                iter.sum::<crate::$type<LANES>>().horizontal_sum()
            }
        }

        impl<'a, const LANES: usize> core::iter::Product<&'a crate::$type<LANES>> for $scalar
        where
            crate::$type<LANES>: crate::LanesAtMost32,
        {
            fn product<I: core::iter::Iterator<Item = &'a crate::$type<LANES>>>(iter: I) -> Self {
                iter.product::<crate::$type<LANES>>().horizontal_product()
            }
        }
    }
}

impl_traits! { SimdF32, f32 }
impl_traits! { SimdF64, f64 }
impl_traits! { SimdU8, u8 }
impl_traits! { SimdU16, u16 }
impl_traits! { SimdU32, u32 }
impl_traits! { SimdU64, u64 }
impl_traits! { SimdUsize, usize }
impl_traits! { SimdI8, i8 }
impl_traits! { SimdI16, i16 }
impl_traits! { SimdI32, i32 }
impl_traits! { SimdI64, i64 }
impl_traits! { SimdIsize, isize }
<commit_msg>Remove scalar Sum/Product over questionable order of operations<commit_after>macro_rules! impl_traits {
    { $type:ident } => {
        impl<const LANES: usize> core::iter::Sum<Self> for crate::$type<LANES>
        where
            Self: crate::LanesAtMost32,
        {
            fn sum<I: core::iter::Iterator<Item = Self>>(iter: I) -> Self {
                iter.fold(Default::default(), core::ops::Add::add)
            }
        }

        impl<const LANES: usize> core::iter::Product<Self> for crate::$type<LANES>
        where
            Self: crate::LanesAtMost32,
        {
            fn product<I: core::iter::Iterator<Item = Self>>(iter: I) -> Self {
                iter.fold(Default::default(), core::ops::Mul::mul)
            }
        }

        impl<'a, const LANES: usize> core::iter::Sum<&'a Self> for crate::$type<LANES>
        where
            Self: crate::LanesAtMost32,
        {
            fn sum<I: core::iter::Iterator<Item = &'a Self>>(iter: I) -> Self {
                iter.fold(Default::default(), core::ops::Add::add)
            }
        }

        impl<'a, const LANES: usize> core::iter::Product<&'a Self> for crate::$type<LANES>
        where
            Self: crate::LanesAtMost32,
        {
            fn product<I: core::iter::Iterator<Item = &'a Self>>(iter: I) -> Self {
                iter.fold(Default::default(), core::ops::Mul::mul)
            }
        }
    }
}

impl_traits! { SimdF32 }
impl_traits! { SimdF64 }
impl_traits! { SimdU8 }
impl_traits! { SimdU16 }
impl_traits! { SimdU32 }
impl_traits! { SimdU64 }
impl_traits! { SimdUsize }
impl_traits! { SimdI8 }
impl_traits! { SimdI16 }
impl_traits! { SimdI32 }
impl_traits! { SimdI64 }
impl_traits! { SimdIsize }
<|endoftext|>


<commit_before>use ast;
use lexer;
use parser;

use interp::env;
use interp::types;

use core::hashmap::linear;
use core::to_bytes;

/*
 * aster - AST EvaulatoR
 *
 * aster evaluates a Prismo program via reduction of the AST.
 *
 * "It's pretty terrible."
 * -- Tony, 2013
 */

impl to_bytes::IterBytes for ast::RecordName {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
        match self {
            &ast::RecordName(n, s) => (n, s).iter_bytes(lsb0, f)
        }
    }
}

impl to_bytes::IterBytes for ast::DottedName {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
        match self {
            &ast::DottedName(s) => s.iter_bytes(lsb0, f)
        }
    }
}

pub struct Interp {
    record_types: @mut linear::LinearMap<@ast::RecordName, @ast::RecordDeclaration>,
    import_paths: @[Path],
    root: @mut env::Env<Interp>,
    argv: @[@str],
    filename: @str,
    current_frame: @mut option::Option<@mut Frame>
}

pub impl Interp {
    pub fn new(import_paths: @[Path], argv: @[@str], filename: @str) -> Interp {
        Interp {
            record_types: @mut linear::LinearMap::new(),
            import_paths: import_paths,
            root: @mut env::Env::new(),
            argv: argv,
            filename: filename,
            current_frame: @mut option::None
        }
    }
}

fn wind(interp: @mut Interp, env: @mut env::Env<Interp>, lineno: uint) -> @mut Frame {
    // allocate a new frame
    let frame = @mut Frame::new(interp, env, interp.filename, lineno);
    interp.current_frame = @mut option::Some(frame);
    frame
}

fn unwind(interp: @mut Interp) -> () {
    interp.current_frame = match *interp.current_frame {
        option::None => @mut option::None,
        option::Some(frame) => frame.parent
    };
}

pub struct Frame {
    parent: @mut option::Option<@mut Frame>,
    env: @mut env::Env<Interp>,
    file: @str,
    lineno: uint,
    exception: @mut option::Option<@mut types::Val<Interp>>
}

pub impl Frame {
    pub fn new(interp: @mut Interp, env: @mut env::Env<Interp>, file: @str, lineno: uint) -> Frame {
        Frame {
            parent: interp.current_frame,
            env: env,
            file: file,
            lineno: lineno,
            exception: @mut option::None
        }
    }
}

pub fn import_module(interp: @mut Interp, name: &ast::DottedName, qualified: bool) -> () {
    let module_parts = (**name).to_owned().map(|x| (*x).to_owned());
    let mut parts = copy module_parts;

    vec::reverse(parts);
    let module_name = copy parts[0];
    let filename = fmt!("%s.pr", module_name);
    parts = vec::tail(parts).to_owned();
    vec::reverse(parts);

    let mut found = false;
    let mut paths = interp.import_paths.to_owned();

    for paths.each_mut |import_path| {
        // make a path inside the import path and check if that exists
        let base_path = (copy *import_path).push_many(parts);
        let path = base_path.push(filename);

        if os::path_exists(&path) {
            // make a copy of the import paths then give them to a new sub-interpreter
            let mut import_paths1 = interp.import_paths.to_owned();
            import_paths1.unshift(base_path);

            let interp1 = @mut Interp::new(at_vec::from_owned(import_paths1), interp.argv, path.to_str().to_managed());

            // run the file in the sub-interpreter
            run_file(interp1, &path);

            if qualified {
                let module_name = ast::Sym(module_name.to_managed());

                // qualified imports symbols from child interpreter into a module
                env::declare(interp.root, &module_name,
                             @mut types::Module(interp1.root.vars));

                for interp1.record_types.each_key |k| {
                    interp.record_types.insert(match *k {
                        @ast::RecordName(modu, name) => @ast::RecordName(@ast::DottedName(**modu + [module_name]), name)
                    }, *interp1.record_types.find(k).unwrap());
                }
            } else {
                // otherwise we just plop all the symbols in
                for interp1.root.vars.each_key |k| {
                    env::declare(interp.root, k, *interp1.root.vars.find(k).unwrap());
                }

                // import record types
                for interp1.record_types.each_key |k| {
                    interp.record_types.insert(*k, *interp1.record_types.find(k).unwrap());
                }
            }

            found = true;
            break;
        }
    };

    if !found {
        fail!(fmt!("couldn't import module %s", str::connect(module_parts, ".")))
    };
}

fn unify_pattern_basic(interp: @mut Interp, env: @mut env::Env<Interp>, pat: &ast::Pat, val: @mut types::Val<Interp>) -> bool {
    // perform pattern matching of basic patterns -- if a match fails, we leave all the symbols in
    // scope and not care. this is pretty bad.
    match *pat {
        ast::AnyPattern => true,
        ast::ManyPattern => false,
        ast::UnitPattern => match *val {
            types::Unit => true,
            _ => false
        },
        ast::LiteralPattern(lit) => *val == types:: gen_lit(lit),
        ast::SymbolPattern(sym) => {
            env::declare(env, &sym, val);
            true
        },
        ast::BoundPattern(sym, pat) => {
            let r = unify_pattern_basic(interp, env, pat, val);
            env::declare(env, &sym, val);
            r
        },
        ast::DisjunctivePattern(pat1, pat2) => {
            unify_pattern_basic(interp, env, pat1, val) || unify_pattern_basic(interp, env, pat2, val)
        },
        ast::ConjunctivePattern(pat1, pat2) => {
            unify_pattern_basic(interp, env, pat1, val) && unify_pattern_basic(interp, env, pat2, val)
        },
        ast::RecordPattern(pat_decl, pats) => fail!(~":V"),
        ast::ListPattern(pats) => match *val {
            types::List(vals) => {
                if vals.len() < pats.len() {
                    false
                } else {
                    match pats[pats.len() - 1] {
                        ast::ManyPattern => {
                            // pattern match with a spread argument
                            let mut ok = true;
                            let mut i = 0;
                            while i < pats.len() - 1 {
                                ok = unify_pattern_basic(interp, env, &pats[i], vals[i]);
                                if !ok { break; };
                                i += 1;
                            }
                            ok
                        },
                        _ => {
                            if vals.len() > pats.len() {
                                // no spread argument, :(
                                false
                            } else {
                                // pattern match with a full pattern list
                                let mut ok = true;
                                let mut i = 0;
                                while i < pats.len() {
                                    ok = unify_pattern_basic(interp, env, &pats[i], vals[i]);
                                    if !ok { break; };
                                    i += 1;
                                }
                                ok
                            }
                        }
                    }
                }
            },
            _ => false
        }
    }
}

fn unify_pattern_let(interp: @mut Interp, env: @mut env::Env<Interp>, pat: &ast::LetPat, val: @mut types::Val<Interp>) -> bool {
    match *pat {
        ast::BasicPattern(pat) => unify_pattern_basic(interp, env, &pat, val),
        _ => fail!(~":V")
    }
}

fn eval_exp(interp: @mut Interp, env: @mut env::Env<Interp>, exp: &ast::Exp) -> types::Val<Interp> {
    let frame = interp.current_frame.unwrap();

    let r = match exp.exp {
        ast::UnitExpression => types::Unit,
        ast::LiteralExpression(l) => types::gen_lit(l),
        ast::LambdaExpression(pat, exp) => types::Function(@[types::Fun {
            pattern: pat,
            body: exp,
            env: env
        }]),
        ast::ListExpression(exps) => {
            let mut vals = @[];

            for exps.each |exp| {
                vals += [@mut eval_exp(interp, env, exp)];
                if !frame.exception.is_none() {
                    return types::Unit;
                }
            }

            types::List(vals)
        },
        ast::SymbolExpression(sym) => {
            match env::find(env, &sym) {
                option::Some(x) => types::Unit,
                option::None => {
                    frame.exception = @mut option::Some(@mut types::String(fmt!("symbol `%s` not found in scope", *sym).to_managed()));
                    types::Unit
                }
            }
        },
        _ => fail!(~":V")
    };

    r
}

fn exec_stmt(interp: @mut Interp, env: @mut env::Env<Interp>, stmt: &ast::Stmt) -> () {
    let frame = interp.current_frame.unwrap();

    match stmt.stmt {
        ast::LetBindingStatement(pat, exp) => {
            if !unify_pattern_let(interp, env, &pat, @mut eval_exp(interp, env, &exp)) {
                // uh oh, we need to throw an exception and unwind
                frame.exception = @mut option::Some(@mut types::String(@"pattern match refuted"));
            }
        },
        ast::ExpressionStatement(exp) => { eval_exp(interp, env, &exp); }
    };
}

pub fn run_file(interp: @mut Interp, path: &Path) -> () {
    match io::file_reader(path) {
        result::Ok(r) => {
            let tokens = lexer::lex(r);
            let program = parser::parse(tokens);
            run(interp, program);
        },
        result::Err(f) => fail!(f)
    }
}

pub fn run(interp: @mut Interp, prog: ast::Program) -> () {
    for prog.imports.each |imp| {
        import_module(interp, &imp.module, imp.qualified);
    }

    for prog.records.each |rec| {
        interp.record_types.insert(@rec.name, @*rec);
    }

    for prog.body.each |stmt| {
        let mut frame = wind(interp, interp.root, stmt.lineno);

        exec_stmt(interp, interp.root, stmt);

        match *frame.exception {
            option::None => unwind(interp),
            option::Some(f) => {
                fail!(fmt!("%? in %s:%u", f, frame.file, frame.lineno))
            }
        }
    }
}
<commit_msg>Better tracebacks.<commit_after>use ast;
use lexer;
use parser;

use interp::env;
use interp::types;

use core::hashmap::linear;
use core::to_bytes;

/*
 * aster - AST EvaulatoR
 *
 * aster evaluates a Prismo program via reduction of the AST.
 *
 * "It's pretty terrible."
 * -- Tony, 2013
 */

impl to_bytes::IterBytes for ast::RecordName {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
        match self {
            &ast::RecordName(n, s) => (n, s).iter_bytes(lsb0, f)
        }
    }
}

impl to_bytes::IterBytes for ast::DottedName {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
        match self {
            &ast::DottedName(s) => s.iter_bytes(lsb0, f)
        }
    }
}

pub struct Interp {
    record_types: @mut linear::LinearMap<@ast::RecordName, @ast::RecordDeclaration>,
    import_paths: @[Path],
    root: @mut env::Env<Interp>,
    argv: @[@str],
    filename: @str,
    current_frame: @mut option::Option<@mut Frame>
}

pub impl Interp {
    pub fn new(import_paths: @[Path], argv: @[@str], filename: @str) -> Interp {
        Interp {
            record_types: @mut linear::LinearMap::new(),
            import_paths: import_paths,
            root: @mut env::Env::new(),
            argv: argv,
            filename: filename,
            current_frame: @mut option::None
        }
    }
}

fn wind(interp: @mut Interp, env: @mut env::Env<Interp>, lineno: uint) -> @mut Frame {
    // allocate a new frame
    let frame = @mut Frame::new(interp, env, interp.filename, lineno);
    interp.current_frame = @mut option::Some(frame);
    frame
}

fn unwind(interp: @mut Interp) -> () {
    interp.current_frame = match *interp.current_frame {
        option::None => @mut option::None,
        option::Some(frame) => frame.parent
    };
}

pub struct Frame {
    parent: @mut option::Option<@mut Frame>,
    env: @mut env::Env<Interp>,
    file: @str,
    lineno: uint,
    exception: @mut option::Option<@mut types::Val<Interp>>
}

pub impl Frame {
    pub fn new(interp: @mut Interp, env: @mut env::Env<Interp>, file: @str, lineno: uint) -> Frame {
        Frame {
            parent: interp.current_frame,
            env: env,
            file: file,
            lineno: lineno,
            exception: @mut option::None
        }
    }
}

pub fn import_module(interp: @mut Interp, name: &ast::DottedName, qualified: bool) -> () {
    let module_parts = (**name).to_owned().map(|x| (*x).to_owned());
    let mut parts = copy module_parts;

    vec::reverse(parts);
    let module_name = copy parts[0];
    let filename = fmt!("%s.pr", module_name);
    parts = vec::tail(parts).to_owned();
    vec::reverse(parts);

    let mut found = false;
    let mut paths = interp.import_paths.to_owned();

    for paths.each_mut |import_path| {
        // make a path inside the import path and check if that exists
        let base_path = (copy *import_path).push_many(parts);
        let path = base_path.push(filename);

        if os::path_exists(&path) {
            // make a copy of the import paths then give them to a new sub-interpreter
            let mut import_paths1 = interp.import_paths.to_owned();
            import_paths1.unshift(base_path);

            let interp1 = @mut Interp::new(at_vec::from_owned(import_paths1), interp.argv, path.to_str().to_managed());

            // run the file in the sub-interpreter
            run_file(interp1, &path);

            if qualified {
                let module_name = ast::Sym(module_name.to_managed());

                // qualified imports symbols from child interpreter into a module
                env::declare(interp.root, &module_name,
                             @mut types::Module(interp1.root.vars));

                for interp1.record_types.each_key |k| {
                    interp.record_types.insert(match *k {
                        @ast::RecordName(modu, name) => @ast::RecordName(@ast::DottedName(**modu + [module_name]), name)
                    }, *interp1.record_types.find(k).unwrap());
                }
            } else {
                // otherwise we just plop all the symbols in
                for interp1.root.vars.each_key |k| {
                    env::declare(interp.root, k, *interp1.root.vars.find(k).unwrap());
                }

                // import record types
                for interp1.record_types.each_key |k| {
                    interp.record_types.insert(*k, *interp1.record_types.find(k).unwrap());
                }
            }

            found = true;
            break;
        }
    };

    if !found {
        fail!(fmt!("couldn't import module %s", str::connect(module_parts, ".")))
    };
}

fn unify_pattern_basic(interp: @mut Interp, env: @mut env::Env<Interp>, pat: &ast::Pat, val: @mut types::Val<Interp>) -> bool {
    // perform pattern matching of basic patterns -- if a match fails, we leave all the symbols in
    // scope and not care. this is pretty bad.
    match *pat {
        ast::AnyPattern => true,
        ast::ManyPattern => false,
        ast::UnitPattern => match *val {
            types::Unit => true,
            _ => false
        },
        ast::LiteralPattern(lit) => *val == types:: gen_lit(lit),
        ast::SymbolPattern(sym) => {
            env::declare(env, &sym, val);
            true
        },
        ast::BoundPattern(sym, pat) => {
            let r = unify_pattern_basic(interp, env, pat, val);
            env::declare(env, &sym, val);
            r
        },
        ast::DisjunctivePattern(pat1, pat2) => {
            unify_pattern_basic(interp, env, pat1, val) || unify_pattern_basic(interp, env, pat2, val)
        },
        ast::ConjunctivePattern(pat1, pat2) => {
            unify_pattern_basic(interp, env, pat1, val) && unify_pattern_basic(interp, env, pat2, val)
        },
        ast::RecordPattern(pat_decl, pats) => fail!(~":V"),
        ast::ListPattern(pats) => match *val {
            types::List(vals) => {
                if vals.len() < pats.len() {
                    false
                } else {
                    match pats[pats.len() - 1] {
                        ast::ManyPattern => {
                            // pattern match with a spread argument
                            let mut ok = true;
                            let mut i = 0;
                            while i < pats.len() - 1 {
                                ok = unify_pattern_basic(interp, env, &pats[i], vals[i]);
                                if !ok { break; };
                                i += 1;
                            }
                            ok
                        },
                        _ => {
                            if vals.len() > pats.len() {
                                // no spread argument, :(
                                false
                            } else {
                                // pattern match with a full pattern list
                                let mut ok = true;
                                let mut i = 0;
                                while i < pats.len() {
                                    ok = unify_pattern_basic(interp, env, &pats[i], vals[i]);
                                    if !ok { break; };
                                    i += 1;
                                }
                                ok
                            }
                        }
                    }
                }
            },
            _ => false
        }
    }
}

fn unify_pattern_let(interp: @mut Interp, env: @mut env::Env<Interp>, pat: &ast::LetPat, val: @mut types::Val<Interp>) -> bool {
    match *pat {
        ast::BasicPattern(pat) => unify_pattern_basic(interp, env, &pat, val),
        _ => fail!(~":V")
    }
}

fn eval_exp(interp: @mut Interp, env: @mut env::Env<Interp>, exp: &ast::Exp) -> types::Val<Interp> {
    let frame = interp.current_frame.unwrap();

    let r = match exp.exp {
        ast::UnitExpression => types::Unit,
        ast::LiteralExpression(l) => types::gen_lit(l),
        ast::LambdaExpression(pat, exp) => types::Function(@[types::Fun {
            pattern: pat,
            body: exp,
            env: env
        }]),
        ast::ListExpression(exps) => {
            let mut vals = @[];

            for exps.each |exp| {
                vals += [@mut eval_exp(interp, env, exp)];
                if !frame.exception.is_none() {
                    return types::Unit;
                }
            }

            types::List(vals)
        },
        ast::SymbolExpression(sym) => {
            match env::find(env, &sym) {
                option::Some(x) => types::Unit,
                option::None => {
                    frame.exception = @mut option::Some(@mut types::String(fmt!("symbol `%s` not found in scope", *sym).to_managed()));
                    types::Unit
                }
            }
        },
        _ => fail!(~":V")
    };

    r
}

fn exec_stmt(interp: @mut Interp, env: @mut env::Env<Interp>, stmt: &ast::Stmt) -> () {
    let frame = interp.current_frame.unwrap();

    match stmt.stmt {
        ast::LetBindingStatement(pat, exp) => {
            if !unify_pattern_let(interp, env, &pat, @mut eval_exp(interp, env, &exp)) {
                // uh oh, we need to throw an exception and unwind
                frame.exception = @mut option::Some(@mut types::String(@"pattern match refuted"));
            }
        },
        ast::ExpressionStatement(exp) => { eval_exp(interp, env, &exp); }
    };
}

pub fn run_file(interp: @mut Interp, path: &Path) -> () {
    match io::file_reader(path) {
        result::Ok(r) => {
            let tokens = lexer::lex(r);
            let program = parser::parse(tokens);
            run(interp, program);
        },
        result::Err(f) => fail!(f)
    }
}

pub fn run(interp: @mut Interp, prog: ast::Program) -> () {
    for prog.imports.each |imp| {
        import_module(interp, &imp.module, imp.qualified);
    }

    for prog.records.each |rec| {
        interp.record_types.insert(@rec.name, @*rec);
    }

    for prog.body.each |stmt| {
        let mut frame = wind(interp, interp.root, stmt.lineno);

        exec_stmt(interp, interp.root, stmt);

        match *frame.exception {
            option::None => unwind(interp),
            option::Some(f) => {
                let mut current_frame = frame;
                let mut buf = ~[fmt!("Uncaught exception: %?", f)];
                loop {
                    buf += [fmt!("        from %s:%u", frame.file, frame.lineno)];
                    if current_frame.parent.is_none() { break; }
                    current_frame = current_frame.parent.unwrap();
                }
                io::println(str::connect(buf, "\n"));
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate lettre;

use std::env::temp_dir;

use lettre::transport::file::FileEmailTransport;
use lettre::transport::EmailTransport;
use lettre::email::EmailBuilder;

#[test]
fn file_transport() {
    let mut sender = FileEmailTransport::new(temp_dir());
    let email = EmailBuilder::new()
                    .to("root@localhost")
                    .from("user@localhost")
                    .body("Hello World!")
                    .subject("Hello")
                    .build()
                    .unwrap();
    let result = sender.send(email);
    assert!(result.is_ok());

    message_id = email.message_id();

}
<commit_msg>Improved test for File transport<commit_after>extern crate lettre;

use std::env::temp_dir;
use std::fs::File;
use std::fs::remove_file;
use std::io::Read;

use lettre::transport::file::FileEmailTransport;
use lettre::transport::EmailTransport;
use lettre::email::{SendableEmail, EmailBuilder};

#[test]
fn file_transport() {
    let mut sender = FileEmailTransport::new(temp_dir());
    let email = EmailBuilder::new()
                    .to("root@localhost")
                    .from("user@localhost")
                    .body("Hello World!")
                    .subject("Hello")
                    .build()
                    .unwrap();
    let result = sender.send(email.clone());
    assert!(result.is_ok());

    let message_id = email.message_id();
    let file = format!("{}/{}.txt", temp_dir().to_str().unwrap(), message_id);
    let mut f = File::open(file.clone()).unwrap();
    let mut buffer = String::new();
    let _ = f.read_to_string(&mut buffer);

    assert_eq!(buffer, format!("{}: from=<user@localhost> to=<root@localhost>\n{}", message_id, email.message()));

    remove_file(file).unwrap();
}
<|endoftext|>


<commit_before>use std::env;
use std::path::Path;
use rustc_serialize::json;
use rustc_serialize::json::{BuilderError, Json};
use curl::{ErrCode, http};
use curl::http::handle::{Method, Request};
use cargo_edit::Manifest;
use regex::Regex;

const REGISTRY_HOST: &'static str = "https://crates.io";

/// Query latest version from crates.io
///
/// The latest version will be returned as a string. This will fail, when
///
/// - there is no Internet connection,
/// - the response from crates.io is an error or in an incorrect format,
/// - or when a crate with the given name does not exist on crates.io.
pub fn get_latest_version(crate_name: &str) -> Result<String, FetchVersionError> {
    if env::var("CARGO_IS_TEST").is_ok() {
        // We are in a simulated reality. Nothing is real here.
        // FIXME: Use actual test handling code.
        return Ok("CURRENT_VERSION_TEST".into());
    }

    let crate_data = try!(fetch_cratesio(&format!("/crates/{}", crate_name)));
    let crate_json = try!(Json::from_str(&crate_data));

    crate_json.as_object()
        .and_then(|c| c.get("crate"))
        .and_then(|c| c.as_object())
        .and_then(|c| c.get("max_version"))
        .and_then(|v| v.as_string())
        .map(|v| v.to_owned())
        .ok_or(FetchVersionError::GetVersion)
}

quick_error! {
    #[derive(Debug)]
    pub enum FetchVersionError {
        CratesIo(err: CratesIoError) {
            from()
            description("crates.io Error")
            display("crates.io Error: {}", err)
            cause(err)
        }
        Json(err: BuilderError) {
            from()
            description("JSON Error")
            display("Error parsing JSON: {}", err)
            cause(err)
        }
        GetVersion { description("get version error") }
    }
}

// ---
// The following was mostly copied from [1] and is therefore
// (c) 2015 Alex Crichton <alex@alexcrichton.com>
//
// [1]: https://github.com/rust-lang/cargo/blob/bd690d8dff83c7b7714f236a08304ee20732382b/src/crates-io/lib.rs
// ---

fn fetch_cratesio(path: &str) -> Result<String, FetchVersionError> {
    let mut http_handle = http::Handle::new();
    let req = Request::new(&mut http_handle, Method::Get)
        .uri(format!("{}/api/v1{}", REGISTRY_HOST, path))
        .header("Accept", "application/json")
        .content_type("application/json");
    handle_request(req.exec()).map_err(From::from)
}

fn handle_request(response: Result<http::Response, ErrCode>) -> Result<String, CratesIoError> {
    let response = try!(response.map_err(CratesIoError::Curl));
    match response.get_code() {
        0 | 200 => {}
        403 => return Err(CratesIoError::Unauthorized),
        404 => return Err(CratesIoError::NotFound),
        _ => return Err(CratesIoError::NotOkResponse(response)),
    }

    let body = match String::from_utf8(response.move_body()) {
        Ok(body) => body,
        Err(..) => return Err(CratesIoError::NonUtf8Body),
    };

    if let Ok(errors) = json::decode::<ApiErrorList>(&body) {
        return Err(CratesIoError::Api(errors.errors.into_iter().map(|s| s.detail).collect()));
    }

    Ok(body)
}

#[derive(RustcDecodable)]
struct ApiErrorList {
    errors: Vec<ApiError>,
}
#[derive(RustcDecodable)]
struct ApiError {
    detail: String,
}

quick_error! {
    #[derive(Debug)]
    pub enum CratesIoError {
        Curl(e: ErrCode) {}
        NotOkResponse(e: http::Response)  {}
        NonUtf8Body  {}
        Api(e: Vec<String>)  {}
        Unauthorized  {}
        NotFound {}
    }
}

#[cfg_attr(rustfmt, rustfmt_skip)]
quick_error! {
    #[derive(Debug)]
    pub enum FetchGitError {
        FetchGit(err: CratesIoError) {
            from()
            description("fetch error: ")
            display("fetch error: {}", err)
            cause(err)
        }
        ParseRegex { description("parse error: unable to parse git repo url") }
        IncompleteCaptures { description("parse error: the git repo url seems incomplete") }
        LocalCargoToml { description("path error: unable to open Cargo.toml") }
        // RemoteCargoToml { description("path error: unable to open Cargo.toml from the provided repo") }
        ParseCargoToml { description("parse error: unable to parse the external Cargo.toml") }
    }
}

/// Query crate name by accessing a github repo Cargo.toml
///
/// The name will be returned as a string. This will fail, when
///
/// - there is no Internet connection,
/// - Cargo.toml is not present in the root of the master branch,
/// - the response from github is an error or in an incorrect format.
pub fn get_crate_name_from_github(repo: &str) -> Result<String, FetchGitError> {
    let re = Regex::new(r"^https://github.com/([-_0-9a-zA-Z]+)/([-_0-9a-zA-Z]+)(/|.git)?$")
        .unwrap();

    re.captures(repo)
        .ok_or(FetchGitError::ParseRegex)
        .and_then(|cap| {
            match (cap.at(1), cap.at(2)) {
                (Some(user), Some(repo)) => {
                    let url = format!("https://raw.githubusercontent.com/{}/{}/master/Cargo.toml",
                                      user,
                                      repo);

                    let data: Result<Manifest, _> = get_cargo_toml_from_git_url(&url)
                        .and_then(|m| {
                            m.parse()
                                .map_err(|_| FetchGitError::ParseCargoToml)
                        });
                    data.and_then(|ref manifest| get_name_from_manifest(manifest))
                }
                _ => Err(FetchGitError::IncompleteCaptures),
            }
        })
}

/// Query crate name by accessing a gitlab repo Cargo.toml
///
/// The name will be returned as a string. This will fail, when
///
/// - there is no Internet connection,
/// - Cargo.toml is not present in the root of the master branch,
/// - the response from gitlab is an error or in an incorrect format.
pub fn get_crate_name_from_gitlab(repo: &str) -> Result<String, FetchGitError> {
    let re = Regex::new(r"^https://gitlab.com/([-_0-9a-zA-Z]+)/([-_0-9a-zA-Z]+)(/|.git)?$")
        .unwrap();

    re.captures(repo)
        .ok_or(FetchGitError::ParseRegex)
        .and_then(|cap| {
            match (cap.at(1), cap.at(2)) {
                (Some(user), Some(repo)) => {
                    let url = format!("https://gitlab.com/{}/{}/raw/master/Cargo.toml", user, repo);

                    let data: Result<Manifest, _> = get_cargo_toml_from_git_url(&url)
                        .and_then(|m| {
                            m.parse()
                                .map_err(|_| FetchGitError::ParseCargoToml)
                        });
                    data.and_then(|ref manifest| get_name_from_manifest(manifest))
                }
                _ => Err(FetchGitError::IncompleteCaptures),
            }
        })
}

/// Query crate name by accessing Cargo.toml in a local path
///
/// The name will be returned as a string. This will fail, when
/// Cargo.toml is not present in the root of the path.
pub fn get_crate_name_from_path(path: &str) -> Result<String, FetchGitError> {
    let cargo_file = Path::new(path).join("Cargo.toml");
    Manifest::open(&cargo_file.to_str())
        .map_err(|_| FetchGitError::LocalCargoToml)
        .and_then(|ref manifest| get_name_from_manifest(manifest))
}

fn get_name_from_manifest(manifest: &Manifest) -> Result<String, FetchGitError> {
    manifest.data
        .get("package")
        .and_then(|m| m.lookup("name"))
        .and_then(|name| name.as_str().map(|s| s.to_string()))
        .ok_or(FetchGitError::ParseCargoToml)
}

fn get_cargo_toml_from_git_url(url: &str) -> Result<String, FetchGitError> {
    let mut http_handle = http::Handle::new();
    let req = Request::new(&mut http_handle, Method::Get)
        .uri(url)
        .header("Accept", "text/plain")
        .content_type("text/plain");
    handle_request(req.exec()).map_err(From::from)
}
<commit_msg>Improve fetch algorithm. Ignore yanked when no version is specified. Request only versions from server to save bandwith.<commit_after>use std::env;
use std::path::Path;
use rustc_serialize::json;
use rustc_serialize::json::{BuilderError, Json};
use curl::{ErrCode, http};
use curl::http::handle::{Method, Request};
use cargo_edit::Manifest;
use regex::Regex;

const REGISTRY_HOST: &'static str = "https://crates.io";

/// Query latest version from crates.io
///
/// The latest version will be returned as a string. This will fail, when
///
/// - there is no Internet connection,
/// - the response from crates.io is an error or in an incorrect format,
/// - or when a crate with the given name does not exist on crates.io.
pub fn get_latest_version(crate_name: &str) -> Result<String, FetchVersionError> {
    if env::var("CARGO_IS_TEST").is_ok() {
        // We are in a simulated reality. Nothing is real here.
        // FIXME: Use actual test handling code.
        return Ok("CURRENT_VERSION_TEST".into());
    }

    let crate_data = try!(fetch_cratesio(&format!("/crates/{}/versions", crate_name)));
    let crate_json = try!(Json::from_str(&crate_data));

    crate_json.as_object()
        .and_then(|c| c.get("versions"))
        .and_then(|c| c.as_array())
        .and_then(|c| {
            for version in c {
                let version_object = version.as_object();
                let yanked = version_object
                    .and_then(|v| v.get("yanked"))
                    .and_then(|v| v.as_boolean());
                if let Some(false) = yanked {
                    return version_object;
                }
            }
            return None;
        })
        .and_then(|v| v.get("num"))
        .and_then(|v| v.as_string())
        .map(|v| v.to_owned())
        .ok_or(FetchVersionError::GetVersion)
}

quick_error! {
    #[derive(Debug)]
    pub enum FetchVersionError {
        CratesIo(err: CratesIoError) {
            from()
            description("crates.io Error")
            display("crates.io Error: {}", err)
            cause(err)
        }
        Json(err: BuilderError) {
            from()
            description("JSON Error")
            display("Error parsing JSON: {}", err)
            cause(err)
        }
        GetVersion { description("get version error") }
    }
}

// ---
// The following was mostly copied from [1] and is therefore
// (c) 2015 Alex Crichton <alex@alexcrichton.com>
//
// [1]: https://github.com/rust-lang/cargo/blob/bd690d8dff83c7b7714f236a08304ee20732382b/src/crates-io/lib.rs
// ---

fn fetch_cratesio(path: &str) -> Result<String, FetchVersionError> {
    let mut http_handle = http::Handle::new();
    let req = Request::new(&mut http_handle, Method::Get)
        .uri(format!("{}/api/v1{}", REGISTRY_HOST, path))
        .header("Accept", "application/json")
        .content_type("application/json");
    handle_request(req.exec()).map_err(From::from)
}

fn handle_request(response: Result<http::Response, ErrCode>) -> Result<String, CratesIoError> {
    let response = try!(response.map_err(CratesIoError::Curl));
    match response.get_code() {
        0 | 200 => {}
        403 => return Err(CratesIoError::Unauthorized),
        404 => return Err(CratesIoError::NotFound),
        _ => return Err(CratesIoError::NotOkResponse(response)),
    }

    let body = match String::from_utf8(response.move_body()) {
        Ok(body) => body,
        Err(..) => return Err(CratesIoError::NonUtf8Body),
    };

    if let Ok(errors) = json::decode::<ApiErrorList>(&body) {
        return Err(CratesIoError::Api(errors.errors.into_iter().map(|s| s.detail).collect()));
    }

    Ok(body)
}

#[derive(RustcDecodable)]
struct ApiErrorList {
    errors: Vec<ApiError>,
}
#[derive(RustcDecodable)]
struct ApiError {
    detail: String,
}

quick_error! {
    #[derive(Debug)]
    pub enum CratesIoError {
        Curl(e: ErrCode) {}
        NotOkResponse(e: http::Response)  {}
        NonUtf8Body  {}
        Api(e: Vec<String>)  {}
        Unauthorized  {}
        NotFound {}
    }
}

#[cfg_attr(rustfmt, rustfmt_skip)]
quick_error! {
    #[derive(Debug)]
    pub enum FetchGitError {
        FetchGit(err: CratesIoError) {
            from()
            description("fetch error: ")
            display("fetch error: {}", err)
            cause(err)
        }
        ParseRegex { description("parse error: unable to parse git repo url") }
        IncompleteCaptures { description("parse error: the git repo url seems incomplete") }
        LocalCargoToml { description("path error: unable to open Cargo.toml") }
        // RemoteCargoToml { description("path error: unable to open Cargo.toml from the provided repo") }
        ParseCargoToml { description("parse error: unable to parse the external Cargo.toml") }
    }
}

/// Query crate name by accessing a github repo Cargo.toml
///
/// The name will be returned as a string. This will fail, when
///
/// - there is no Internet connection,
/// - Cargo.toml is not present in the root of the master branch,
/// - the response from github is an error or in an incorrect format.
pub fn get_crate_name_from_github(repo: &str) -> Result<String, FetchGitError> {
    let re = Regex::new(r"^https://github.com/([-_0-9a-zA-Z]+)/([-_0-9a-zA-Z]+)(/|.git)?$")
        .unwrap();

    re.captures(repo)
        .ok_or(FetchGitError::ParseRegex)
        .and_then(|cap| {
            match (cap.at(1), cap.at(2)) {
                (Some(user), Some(repo)) => {
                    let url = format!("https://raw.githubusercontent.com/{}/{}/master/Cargo.toml",
                                      user,
                                      repo);

                    let data: Result<Manifest, _> = get_cargo_toml_from_git_url(&url)
                        .and_then(|m| {
                            m.parse()
                                .map_err(|_| FetchGitError::ParseCargoToml)
                        });
                    data.and_then(|ref manifest| get_name_from_manifest(manifest))
                }
                _ => Err(FetchGitError::IncompleteCaptures),
            }
        })
}

/// Query crate name by accessing a gitlab repo Cargo.toml
///
/// The name will be returned as a string. This will fail, when
///
/// - there is no Internet connection,
/// - Cargo.toml is not present in the root of the master branch,
/// - the response from gitlab is an error or in an incorrect format.
pub fn get_crate_name_from_gitlab(repo: &str) -> Result<String, FetchGitError> {
    let re = Regex::new(r"^https://gitlab.com/([-_0-9a-zA-Z]+)/([-_0-9a-zA-Z]+)(/|.git)?$")
        .unwrap();

    re.captures(repo)
        .ok_or(FetchGitError::ParseRegex)
        .and_then(|cap| {
            match (cap.at(1), cap.at(2)) {
                (Some(user), Some(repo)) => {
                    let url = format!("https://gitlab.com/{}/{}/raw/master/Cargo.toml", user, repo);

                    let data: Result<Manifest, _> = get_cargo_toml_from_git_url(&url)
                        .and_then(|m| {
                            m.parse()
                                .map_err(|_| FetchGitError::ParseCargoToml)
                        });
                    data.and_then(|ref manifest| get_name_from_manifest(manifest))
                }
                _ => Err(FetchGitError::IncompleteCaptures),
            }
        })
}

/// Query crate name by accessing Cargo.toml in a local path
///
/// The name will be returned as a string. This will fail, when
/// Cargo.toml is not present in the root of the path.
pub fn get_crate_name_from_path(path: &str) -> Result<String, FetchGitError> {
    let cargo_file = Path::new(path).join("Cargo.toml");
    Manifest::open(&cargo_file.to_str())
        .map_err(|_| FetchGitError::LocalCargoToml)
        .and_then(|ref manifest| get_name_from_manifest(manifest))
}

fn get_name_from_manifest(manifest: &Manifest) -> Result<String, FetchGitError> {
    manifest.data
        .get("package")
        .and_then(|m| m.lookup("name"))
        .and_then(|name| name.as_str().map(|s| s.to_string()))
        .ok_or(FetchGitError::ParseCargoToml)
}

fn get_cargo_toml_from_git_url(url: &str) -> Result<String, FetchGitError> {
    let mut http_handle = http::Handle::new();
    let req = Request::new(&mut http_handle, Method::Get)
        .uri(url)
        .header("Accept", "text/plain")
        .content_type("text/plain");
    handle_request(req.exec()).map_err(From::from)
}
<|endoftext|>