<commit_before>use index::Index;

impl Index {
    /// Run a maintenance task on the index
    /// This must be run periodically by a background thread. It is not currently thread-safe
    pub fn run_maintenance_task(&self) -> Result<(), String> {
        let mut segment_stats = try!(self.store.get_segment_statistics());

        // TODO: Deactivate segments with 100% deletions
        // TODO: Vacuum segments with many deletions

        // Merge segments

        // Firstly we classify each active segment into one of 5 groups (based on the number of
        // total documents they have):
        // Group 1: 1 - 9 docs
        // Group 2: 10 - 99 docs
        // Group 3: 100 - 999 docs
        // Group 4: 1000 - 9999 docs
        // Group 5: 10000 - 65536 docs

        // The group with the most active segments can perform a merge. A merge can be done on
        // between 5 - 1000 segments at a time. The smallest segments get merged first.

        // Sort by total_docs in ascending order
        // TODO: Check that this is ascending order
        segment_stats.sort_by_key(|&(_, ref stats)| stats.total_docs());

        let mut segments_g1 = Vec::new();
        let mut segments_g2 = Vec::new();
        let mut segments_g3 = Vec::new();
        let mut segments_g4 = Vec::new();
        let mut segments_g5 = Vec::new();

        for (segment, stats) in segment_stats {
            match stats.total_docs() {
                1 ... 9 => segments_g1.push(segment),
                10 ... 99 => segments_g2.push(segment),
                100 ... 999 => segments_g3.push(segment),
                1000 ... 9999 => segments_g4.push(segment),
                10000 ... 65536 => segments_g5.push(segment),
                _ => {},
            }
        }

        // Now sort the groups by length in ascending order
        let mut segments_grouped = vec![segments_g1, segments_g2, segments_g3, segments_g4, segments_g5];
        segments_grouped.sort_by_key(|group| group.len());

        // The group with the most segments is our merge candidate. Check that it has above the
        // minimum number of documents to start a merge and truncate it to be less than the maximum.
        let mut group_to_merge = segments_grouped.pop().unwrap();

        if group_to_merge.len() >= 5 {
            // TODO: Check that we're not merging over 65536 docs
            group_to_merge.truncate(1000);
            try!(self.store.merge_segments(&group_to_merge));
            try!(self.store.purge_segments(&group_to_merge));
        }

        Ok(())
    }
}
<commit_msg>Prevent segment merges from creating too large segments<commit_after>use index::Index;

impl Index {
    /// Run a maintenance task on the index
    /// This must be run periodically by a background thread. It is not currently thread-safe
    pub fn run_maintenance_task(&self) -> Result<(), String> {
        let segment_stats = try!(self.store.get_segment_statistics());

        // TODO: Deactivate segments with 100% deletions
        // TODO: Vacuum segments with many deletions

        // Merge segments

        // Firstly we classify each active segment into one of 5 groups (based on the number of
        // total documents they have):
        // Group 1: 1 - 9 docs
        // Group 2: 10 - 99 docs
        // Group 3: 100 - 999 docs
        // Group 4: 1000 - 9999 docs
        // Group 5: 10000 - 65536 docs

        // The group with the most active segments can perform a merge. A merge can be done on
        // between 5 - 1000 segments at a time. The smallest segments get merged first.

        let mut segments_g1 = Vec::new();
        let mut segments_g2 = Vec::new();
        let mut segments_g3 = Vec::new();
        let mut segments_g4 = Vec::new();
        let mut segments_g5 = Vec::new();

        for (segment, stats) in segment_stats {
            match stats.total_docs() {
                1 ... 9 => segments_g1.push((segment, stats)),
                10 ... 99 => segments_g2.push((segment, stats)),
                100 ... 999 => segments_g3.push((segment, stats)),
                1000 ... 9999 => segments_g4.push((segment, stats)),
                10000 ... 65536 => segments_g5.push((segment, stats)),
                _ => {},
            }
        }

        // Now sort the groups by length in ascending order
        let mut segments_grouped = vec![segments_g1, segments_g2, segments_g3, segments_g4, segments_g5];
        segments_grouped.sort_by_key(|group| group.len());

        // The group with the most segments is our merge candidate. Check that it has above the
        // minimum number of documents to start a merge and truncate it to be less than the maximum.
        let mut group_to_merge = segments_grouped.pop().unwrap();

        if group_to_merge.len() < 3 {
            // No point in merging these
            return Ok(());
        }

        // Now we've found a group of segments to merge, we must check that all the docs will fit in a
        // single segment. If not, we choose the largest sub-group of segments to merge that fills the
        // quota as much as possible

        let mut current_doc_count: u32 = 0;
        let mut segment_ids = Vec::new();

        // Sort segments total_docs in descending order
        // TODO: Check that this is descending order
        group_to_merge.sort_by_key(|&(_, ref stats)| -stats.total_docs());

        for (segment, stats) in group_to_merge {
            if current_doc_count + stats.total_docs() as u32 > 65536 {
                // No space for this segment
                continue;
            }

            segment_ids.push(segment);
            current_doc_count += stats.total_docs() as u32;
        }

        // Merge segments
        try!(self.store.merge_segments(&segment_ids));
        try!(self.store.purge_segments(&segment_ids));

        Ok(())
    }
}
<|endoftext|>


<commit_before>use piston_window::*;

use ::game::block::Block;
use ::game::config::Config;

#[derive(Copy, Clone)]
pub enum Shape {
    I,
    J,
    L,
    O,
    S,
    T,
    Z,
}

#[derive(Copy, Clone)]
pub enum Direction {
    North,
    East,
    South,
    West,
}

pub enum MoveResult {
    Allow,
    Deny,
    Blocked,
}

#[derive(Copy, Clone)]
pub struct Tetromino {
    pub x: i32,
    pub y: i32,
    pub blocks: [[Option<Block>; 4]; 4],
    shape: Shape,
    direction: Direction,
}

pub struct TetrominoShape(Shape, [[Option<Block>; 4]; 4]);

impl Tetromino {
    pub fn new(shape: TetrominoShape, config: &Config) -> Tetromino {
        Tetromino {
            x: (config.grid_size.0 as i32 / 2) - 2,
            y: 0,
            shape: shape.0,
            blocks: shape.1,
            direction: Direction::North,
        }
    }

    pub fn can_move(&self, direction: Direction, grid: &[[Option<Block>; 10]; 22]) -> MoveResult {
        let mut y_dir = Self::get_y_direction(direction) as i32;
        let mut x_dir = Self::get_x_direction(direction) as i32;

        for y in 0..4 {
            for x in 0..4 {
                if let Some(ref block) = self.blocks[y][x] {
                    let x = ((self.x + x as i32) + x_dir) as isize;
                    let y = ((self.y + y as i32) + y_dir) as isize;

                    if y > 21 {
                        return MoveResult::Blocked;
                    }

                    if x < 0 || x > 9 {
                        return MoveResult::Deny;
                    }

                    if let Some(ref block) = grid[y as usize][x as usize] {
                        return MoveResult::Blocked;
                    }
                }
            }
        }

        MoveResult::Allow
    }

    fn get_y_direction(direction: Direction) -> isize {
        match direction {
            Direction::North => -1,
            Direction::South => 1,
            _ => 0,
        }
    }

    fn get_x_direction(direction: Direction) -> isize {
        match direction {
            Direction::East => 1,
            Direction::West => -1,
            _ => 0,
        }
    }

    pub fn drop_down(&mut self) {
        self.y = self.y + 1;
    }

    pub fn move_up(&mut self) {
        self.y = self.y - 1;
    }

    pub fn move_left(&mut self) {
        self.x = self.x - 1;
    }

    pub fn move_right(&mut self) {
        self.x = self.x + 1;
    }
}

pub struct TetrominoFactory {
    shapes: Vec<(Shape, [[Option<Block>; 4]; 4])>,
}

impl TetrominoFactory {
    pub fn new() -> TetrominoFactory {
        let mut shapes = vec![
            Self::create_I(),
            Self::create_J(),
            Self::create_L(),
            Self::create_O(),
            Self::create_S(),
            Self::create_T(),
            Self::create_Z(),
        ];

        TetrominoFactory { shapes: shapes }
    }

    pub fn create(&self, config: &Config) -> Tetromino {
        let shape = Self::create_S();
        Tetromino::new(TetrominoShape(shape.0, shape.1), &config)
    }

    fn create_I() -> (Shape, [[Option<Block>; 4]; 4]) {
        let i_color = [0.0, 1.0, 1.0, 1.0];
        let i = Some(Block::new(i_color));

        (Shape::I,
         [[None, i.clone(), None, None],
          [None, i.clone(), None, None],
          [None, i.clone(), None, None],
          [None, i.clone(), None, None]])
    }

    fn create_J() -> (Shape, [[Option<Block>; 4]; 4]) {
        let j_color = [0.0, 0.0, 1.0, 1.0];
        let j = Some(Block::new(j_color));

        (Shape::J,
         [[None, j.clone(), None, None],
          [None, j.clone(), None, None],
          [j.clone(), j.clone(), None, None],
          [None, None, None, None]])
    }

    fn create_L() -> (Shape, [[Option<Block>; 4]; 4]) {
        let l_color = [0.8, 0.5, 0.0, 1.0];
        let l = Some(Block::new(l_color));

        (Shape::L,
         [[None, l.clone(), None, None],
          [None, l.clone(), None, None],
          [None, l.clone(), l.clone(), None],
          [None, None, None, None]])
    }

    fn create_O() -> (Shape, [[Option<Block>; 4]; 4]) {
        let o_color = [1.0, 1.0, 0.0, 1.0];
        let o = Some(Block::new(o_color));

        (Shape::O,
         [[None, o.clone(), o.clone(), None],
          [None, o.clone(), o.clone(), None],
          [None, None, None, None],
          [None, None, None, None]])
    }

    fn create_S() -> (Shape, [[Option<Block>; 4]; 4]) {
        let s_color = [0.0, 1.0, 0.0, 1.0];
        let s = Some(Block::new(s_color));

        (Shape::S,
         [[None, s.clone(), s.clone(), None],
          [s.clone(), s.clone(), None, None],
          [None, None, None, None],
          [None, None, None, None]])
    }

    fn create_T() -> (Shape, [[Option<Block>; 4]; 4]) {
        let t_color = [1.0, 0.4, 0.7, 1.0];
        let t = Some(Block::new(t_color));

        (Shape::T,
         [[None, t.clone(), None, None],
          [t.clone(), t.clone(), t.clone(), None],
          [None, None, None, None],
          [None, None, None, None]])
    }

    fn create_Z() -> (Shape, [[Option<Block>; 4]; 4]) {
        let z_color = [1.0, 0.0, 0.0, 1.0];
        let z = Some(Block::new(z_color));

        (Shape::Z,
         [[z.clone(), z.clone(), None, None],
          [None, z.clone(), z.clone(), None],
          [None, None, None, None],
          [None, None, None, None]])
    }
}<commit_msg>Fixed blocking the move when touching another block<commit_after>use piston_window::*;

use ::game::block::Block;
use ::game::config::Config;

#[derive(Copy, Clone)]
pub enum Shape {
    I,
    J,
    L,
    O,
    S,
    T,
    Z,
}

#[derive(Copy, Clone)]
pub enum Direction {
    North,
    East,
    South,
    West,
}

pub enum MoveResult {
    Allow,
    Deny,
    Blocked,
}

#[derive(Copy, Clone)]
pub struct Tetromino {
    pub x: i32,
    pub y: i32,
    pub blocks: [[Option<Block>; 4]; 4],
    shape: Shape,
    direction: Direction,
}

pub struct TetrominoShape(Shape, [[Option<Block>; 4]; 4]);

impl Tetromino {
    pub fn new(shape: TetrominoShape, config: &Config) -> Tetromino {
        Tetromino {
            x: (config.grid_size.0 as i32 / 2) - 2,
            y: 0,
            shape: shape.0,
            blocks: shape.1,
            direction: Direction::North,
        }
    }

    /// Checks if the current block can move in a specific
    /// direction.
    pub fn can_move(&self, direction: Direction, grid: &[[Option<Block>; 10]; 22]) -> MoveResult {

        // Determine the direction on each axis we're attempting to move
        let mut y_dir = Self::get_y_direction(direction) as i32;
        let mut x_dir = Self::get_x_direction(direction) as i32;

        // Loop over each block of this tetromino and compare it
        // to the offset within the grid where we want to move to
        for y in 0..4 {
            for x in 0..4 {
                if let Some(ref block) = self.blocks[y][x] {
                    let x = ((self.x + x as i32) + x_dir) as isize;
                    let y = ((self.y + y as i32) + y_dir) as isize;

                    // Check if we've hit the bottom
                    if y > 21 {
                        return MoveResult::Blocked;
                    }

                    // Check if we're touching the edges
                    if x < 0 || x > 9 {
                        return MoveResult::Deny;
                    }

                    // Otherwise check if we're smashing in to another block
                    if let Some(ref block) = grid[y as usize][x as usize] {
                        // Deny left and right.. but block downwards
                        match direction {
                            Direction::East | Direction::West => return MoveResult::Deny,
                            Direction::North | Direction::South => return MoveResult::Blocked,
                        }
                    }
                }
            }
        }

        MoveResult::Allow
    }

    fn get_y_direction(direction: Direction) -> isize {
        match direction {
            Direction::North => -1,
            Direction::South => 1,
            _ => 0,
        }
    }

    fn get_x_direction(direction: Direction) -> isize {
        match direction {
            Direction::East => 1,
            Direction::West => -1,
            _ => 0,
        }
    }

    pub fn drop_down(&mut self) {
        self.y = self.y + 1;
    }

    pub fn move_up(&mut self) {
        self.y = self.y - 1;
    }

    pub fn move_left(&mut self) {
        self.x = self.x - 1;
    }

    pub fn move_right(&mut self) {
        self.x = self.x + 1;
    }
}

pub struct TetrominoFactory {
    shapes: Vec<(Shape, [[Option<Block>; 4]; 4])>,
}

impl TetrominoFactory {
    pub fn new() -> TetrominoFactory {
        let mut shapes = vec![
            Self::create_I(),
            Self::create_J(),
            Self::create_L(),
            Self::create_O(),
            Self::create_S(),
            Self::create_T(),
            Self::create_Z(),
        ];

        TetrominoFactory { shapes: shapes }
    }

    pub fn create(&self, config: &Config) -> Tetromino {
        let shape = Self::create_I();
        Tetromino::new(TetrominoShape(shape.0, shape.1), &config)
    }

    fn create_I() -> (Shape, [[Option<Block>; 4]; 4]) {
        let i_color = [0.0, 1.0, 1.0, 1.0];
        let i = Some(Block::new(i_color));

        (Shape::I,
         [[None, i.clone(), None, None],
          [None, i.clone(), None, None],
          [None, i.clone(), None, None],
          [None, i.clone(), None, None]])
    }

    fn create_J() -> (Shape, [[Option<Block>; 4]; 4]) {
        let j_color = [0.0, 0.0, 1.0, 1.0];
        let j = Some(Block::new(j_color));

        (Shape::J,
         [[None, j.clone(), None, None],
          [None, j.clone(), None, None],
          [j.clone(), j.clone(), None, None],
          [None, None, None, None]])
    }

    fn create_L() -> (Shape, [[Option<Block>; 4]; 4]) {
        let l_color = [0.8, 0.5, 0.0, 1.0];
        let l = Some(Block::new(l_color));

        (Shape::L,
         [[None, l.clone(), None, None],
          [None, l.clone(), None, None],
          [None, l.clone(), l.clone(), None],
          [None, None, None, None]])
    }

    fn create_O() -> (Shape, [[Option<Block>; 4]; 4]) {
        let o_color = [1.0, 1.0, 0.0, 1.0];
        let o = Some(Block::new(o_color));

        (Shape::O,
         [[None, o.clone(), o.clone(), None],
          [None, o.clone(), o.clone(), None],
          [None, None, None, None],
          [None, None, None, None]])
    }

    fn create_S() -> (Shape, [[Option<Block>; 4]; 4]) {
        let s_color = [0.0, 1.0, 0.0, 1.0];
        let s = Some(Block::new(s_color));

        (Shape::S,
         [[None, s.clone(), s.clone(), None],
          [s.clone(), s.clone(), None, None],
          [None, None, None, None],
          [None, None, None, None]])
    }

    fn create_T() -> (Shape, [[Option<Block>; 4]; 4]) {
        let t_color = [1.0, 0.4, 0.7, 1.0];
        let t = Some(Block::new(t_color));

        (Shape::T,
         [[None, t.clone(), None, None],
          [t.clone(), t.clone(), t.clone(), None],
          [None, None, None, None],
          [None, None, None, None]])
    }

    fn create_Z() -> (Shape, [[Option<Block>; 4]; 4]) {
        let z_color = [1.0, 0.0, 0.0, 1.0];
        let z = Some(Block::new(z_color));

        (Shape::Z,
         [[z.clone(), z.clone(), None, None],
          [None, z.clone(), z.clone(), None],
          [None, None, None, None],
          [None, None, None, None]])
    }
}<|endoftext|>


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

use lazycell::AtomicLazyCell;

use fall_tree::{File, Node, AstNode, Text};
use fall_tree::search::child_of_type;
use fall_tree::search::ast;

use {FallFile, SynRule, RefExpr, RefKind, CallExpr, SYN_RULE};

mod calls;
mod diagnostics;
use self::diagnostics::Diagnostics;

pub use self::calls::CallKind;

pub struct Analysis<'f> {
    file: FallFile<'f>,

    diagnostics: Diagnostics,
    used_rules: AtomicLazyCell<HashSet<Node<'f>>>,
    contexts: AtomicLazyCell<Vec<Text<'f>>>,
}

impl<'f> Analysis<'f> {
    pub fn new(file: FallFile) -> Analysis {
        Analysis {
            file,
            diagnostics: Diagnostics::new(),
            used_rules: AtomicLazyCell::new(),
            contexts: AtomicLazyCell::new(),
        }
    }

    pub fn file(&self) -> FallFile<'f> {
        self.file
    }

    pub fn is_unused(&self, rule: SynRule<'f>) -> bool {
        !self.used_rules().contains(&rule.node())
    }

    pub fn resolve_call(&self, call: CallExpr<'f>) -> Option<CallKind<'f>> {
        calls::resolve(self, call)
    }

    fn contexts(&self) -> &[Text<'f>] {
        if !self.contexts.filled() {
            let _ = self.contexts.fill(calls::contexts(self));
        }
        self.contexts.borrow().unwrap().as_ref()
    }

    fn used_rules(&self) -> &HashSet<Node<'f>> {
        if !self.used_rules.filled() {
            let _ = self.used_rules.fill(self.calculate_used_rules());
        }
        self.used_rules.borrow().unwrap()
    }

    fn calculate_used_rules(&self) -> HashSet<Node<'f>> {
        use CallKind;
        ast::descendants_of_type::<RefExpr>(self.file.node())
            .into_iter()
            .filter_map(|node| node.resolve())
            .filter_map(|r| match r {
                RefKind::RuleReference(rule) => Some(rule.node()),
                _ => None
            })
            .chain(
                ast::descendants_of_type::<CallExpr>(self.file.node())
                    .into_iter()
                    .filter_map(|call| call.kind().ok())
                    .filter_map(|kind| match kind {
                        CallKind::RuleCall(rule, ..) => Some(rule.node()),
                        _ => None,
                    })
            )
            .chain(child_of_type(self.file.node(), SYN_RULE).into_iter())
            .collect()
    }
}

pub struct FileWithAnalysis {
    rent: rent::R
}

impl FileWithAnalysis {
    pub fn new(text: String) -> FileWithAnalysis {
        FileWithAnalysis::from_file(::parse(text))
    }

    fn from_file(file: File) -> FileWithAnalysis {
        FileWithAnalysis {
            rent: rent::R::new(Box::new(file), |file| {
                Analysis::new(FallFile::new(file.root()))
            })
        }
    }

    pub fn file(&self) -> &File {
        self.rent.head()
    }

    pub fn analyse<T, F: FnOnce(&Analysis) -> T>(&self, f: F) -> T {
        self.rent.rent(|a: &Analysis| f(a))
    }
}

rental! {
    mod rent {
        use super::*;

        #[rental]
        pub struct R {
            file: Box<File>,
            analysis: Analysis<'file>
        }
    }
}
<commit_msg>Unused rules use new call resolution<commit_after>use std::collections::HashSet;

use lazycell::AtomicLazyCell;

use fall_tree::{File, Node, AstNode, Text};
use fall_tree::search::child_of_type;
use fall_tree::search::ast;

use {FallFile, SynRule, RefExpr, RefKind, CallExpr, SYN_RULE};

mod calls;
mod diagnostics;

use self::diagnostics::Diagnostics;

pub use self::calls::CallKind;

pub struct Analysis<'f> {
    file: FallFile<'f>,

    diagnostics: Diagnostics,
    used_rules: AtomicLazyCell<HashSet<Node<'f>>>,
    contexts: AtomicLazyCell<Vec<Text<'f>>>,
}

impl<'f> Analysis<'f> {
    pub fn new(file: FallFile) -> Analysis {
        Analysis {
            file,
            diagnostics: Diagnostics::new(),
            used_rules: AtomicLazyCell::new(),
            contexts: AtomicLazyCell::new(),
        }
    }

    pub fn file(&self) -> FallFile<'f> {
        self.file
    }

    pub fn is_unused(&self, rule: SynRule<'f>) -> bool {
        !self.used_rules().contains(&rule.node())
    }

    pub fn resolve_call(&self, call: CallExpr<'f>) -> Option<CallKind<'f>> {
        calls::resolve(self, call)
    }

    fn contexts(&self) -> &[Text<'f>] {
        if !self.contexts.filled() {
            let _ = self.contexts.fill(calls::contexts(self));
        }
        self.contexts.borrow().unwrap().as_ref()
    }

    fn used_rules(&self) -> &HashSet<Node<'f>> {
        if !self.used_rules.filled() {
            let _ = self.used_rules.fill(self.calculate_used_rules());
        }
        self.used_rules.borrow().unwrap()
    }

    fn calculate_used_rules(&self) -> HashSet<Node<'f>> {
        ast::descendants_of_type::<RefExpr>(self.file.node())
            .into_iter()
            .filter_map(|node| node.resolve())
            .filter_map(|r| match r {
                RefKind::RuleReference(rule) => Some(rule.node()),
                _ => None
            })
            .chain(
                ast::descendants_of_type::<CallExpr>(self.file.node())
                    .into_iter()
                    .filter_map(|call| self.resolve_call(call))
                    .filter_map(|kind| match kind {
                        CallKind::RuleCall(rule, ..) => Some(rule.node()),
                        _ => None,
                    })
            )
            .chain(child_of_type(self.file.node(), SYN_RULE).into_iter())
            .collect()
    }
}

pub struct FileWithAnalysis {
    rent: rent::R
}

impl FileWithAnalysis {
    pub fn new(text: String) -> FileWithAnalysis {
        FileWithAnalysis::from_file(::parse(text))
    }

    fn from_file(file: File) -> FileWithAnalysis {
        FileWithAnalysis {
            rent: rent::R::new(Box::new(file), |file| {
                Analysis::new(FallFile::new(file.root()))
            })
        }
    }

    pub fn file(&self) -> &File {
        self.rent.head()
    }

    pub fn analyse<T, F: FnOnce(&Analysis) -> T>(&self, f: F) -> T {
        self.rent.rent(|a: &Analysis| f(a))
    }
}

rental! {
    mod rent {
        use super::*;

        #[rental]
        pub struct R {
            file: Box<File>,
            analysis: Analysis<'file>
        }
    }
}
<|endoftext|>


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

#![feature(globs, phase, macro_rules)]

extern crate syntax;
extern crate rustc;

#[phase(link)]
extern crate regex;

#[phase(link, plugin)]
extern crate log;

#[phase(plugin)] extern crate regex_macros;

use std::collections::HashMap;
use std::io::File;

use syntax::parse;
use syntax::parse::lexer;
use rustc::session::{mod, config};

use syntax::ast;
use syntax::ast::Name;
use syntax::parse::token;
use syntax::parse::lexer::TokenAndSpan;

fn parse_token_list(file: &str) -> HashMap<String, token::Token> {
    fn id() -> token::Token {
        token::Ident(ast::Ident { name: Name(0), ctxt: 0, }, token::Plain)
    }

    let mut res = HashMap::new();

    res.insert("-1".to_string(), token::Eof);

    for line in file.split('\n') {
        let eq = match line.trim().rfind('=') {
            Some(val) => val,
            None => continue
        };

        let val = line.slice_to(eq);
        let num = line.slice_from(eq + 1);

        let tok = match val {
            "SHR"               => token::BinOp(token::Shr),
            "DOLLAR"            => token::Dollar,
            "LT"                => token::Lt,
            "STAR"              => token::BinOp(token::Star),
            "FLOAT_SUFFIX"      => id(),
            "INT_SUFFIX"        => id(),
            "SHL"               => token::BinOp(token::Shl),
            "LBRACE"            => token::OpenDelim(token::Brace),
            "RARROW"            => token::RArrow,
            "LIT_STR"           => token::Literal(token::Str_(Name(0))),
            "DOTDOT"            => token::DotDot,
            "MOD_SEP"           => token::ModSep,
            "DOTDOTDOT"         => token::DotDotDot,
            "NOT"               => token::Not,
            "AND"               => token::BinOp(token::And),
            "LPAREN"            => token::OpenDelim(token::Paren),
            "ANDAND"            => token::AndAnd,
            "AT"                => token::At,
            "LBRACKET"          => token::OpenDelim(token::Bracket),
            "LIT_STR_RAW"       => token::Literal(token::StrRaw(Name(0), 0)),
            "RPAREN"            => token::CloseDelim(token::Paren),
            "SLASH"             => token::BinOp(token::Slash),
            "COMMA"             => token::Comma,
            "LIFETIME"          => token::Lifetime(ast::Ident { name: Name(0), ctxt: 0 }),
            "CARET"             => token::BinOp(token::Caret),
            "TILDE"             => token::Tilde,
            "IDENT"             => id(),
            "PLUS"              => token::BinOp(token::Plus),
            "LIT_CHAR"          => token::Literal(token::Char(Name(0))),
            "LIT_BYTE"          => token::Literal(token::Byte(Name(0))),
            "EQ"                => token::Eq,
            "RBRACKET"          => token::CloseDelim(token::Bracket),
            "COMMENT"           => token::Comment,
            "DOC_COMMENT"       => token::DocComment(Name(0)),
            "DOT"               => token::Dot,
            "EQEQ"              => token::EqEq,
            "NE"                => token::Ne,
            "GE"                => token::Ge,
            "PERCENT"           => token::BinOp(token::Percent),
            "RBRACE"            => token::CloseDelim(token::Brace),
            "BINOP"             => token::BinOp(token::Plus),
            "POUND"             => token::Pound,
            "OROR"              => token::OrOr,
            "LIT_INTEGER"       => token::Literal(token::Integer(Name(0))),
            "BINOPEQ"           => token::BinOpEq(token::Plus),
            "LIT_FLOAT"         => token::Literal(token::Float(Name(0))),
            "WHITESPACE"        => token::Whitespace,
            "UNDERSCORE"        => token::Underscore,
            "MINUS"             => token::BinOp(token::Minus),
            "SEMI"              => token::Semi,
            "COLON"             => token::Colon,
            "FAT_ARROW"         => token::FatArrow,
            "OR"                => token::BinOp(token::Or),
            "GT"                => token::Gt,
            "LE"                => token::Le,
            "LIT_BINARY"        => token::Literal(token::Binary(Name(0))),
            "LIT_BINARY_RAW"    => token::Literal(token::BinaryRaw(Name(0), 0)),
            _                   => continue,
        };

        res.insert(num.to_string(), tok);
    }

    debug!("Token map: {}", res);
    res
}

fn str_to_binop(s: &str) -> token::BinOpToken {
    match s {
        "+"     => token::Plus,
        "/"     => token::Slash,
        "-"     => token::Minus,
        "*"     => token::Star,
        "%"     => token::Percent,
        "^"     => token::Caret,
        "&"     => token::And,
        "|"     => token::Or,
        "<<"    => token::Shl,
        ">>"    => token::Shr,
        _       => panic!("Bad binop str `{}`", s),
    }
}

/// Assuming a string/binary literal, strip out the leading/trailing
/// hashes and surrounding quotes/raw/binary prefix.
fn fix(mut lit: &str) -> ast::Name {
    if lit.char_at(0) == 'r' {
        if lit.char_at(1) == 'b' {
            lit = lit.slice_from(2)
        } else {
            lit = lit.slice_from(1);
        }
    } else if lit.char_at(0) == 'b' {
        lit = lit.slice_from(1);
    }

    let leading_hashes = count(lit);

    // +1/-1 to adjust for single quotes
    parse::token::intern(lit.slice(leading_hashes + 1, lit.len() - leading_hashes - 1))
}

/// Assuming a char/byte literal, strip the 'b' prefix and the single quotes.
fn fixchar(mut lit: &str) -> ast::Name {
    if lit.char_at(0) == 'b' {
        lit = lit.slice_from(1);
    }

    parse::token::intern(lit.slice(1, lit.len() - 1))
}

fn count(lit: &str) -> uint {
    lit.chars().take_while(|c| *c == '#').count()
}

fn parse_antlr_token(s: &str, tokens: &HashMap<String, token::Token>) -> TokenAndSpan {
    let re = regex!(
      r"\[@(?P<seq>\d+),(?P<start>\d+):(?P<end>\d+)='(?P<content>.+?)',<(?P<toknum>-?\d+)>,\d+:\d+]"
    );

    let m = re.captures(s).expect(format!("The regex didn't match {}", s).as_slice());
    let start = m.name("start").unwrap_or("");
    let end = m.name("end").unwrap_or("");
    let toknum = m.name("toknum").unwrap_or("");
    let content = m.name("content").unwrap_or("");

    let proto_tok = tokens.get(toknum).expect(format!("didn't find token {} in the map",
                                                              toknum).as_slice());

    let nm = parse::token::intern(content);

    debug!("What we got: content (`{}`), proto: {}", content, proto_tok);

    let real_tok = match *proto_tok {
        token::BinOp(..)           => token::BinOp(str_to_binop(content)),
        token::BinOpEq(..)         => token::BinOpEq(str_to_binop(content.slice_to(
                                                                    content.len() - 1))),
        token::Literal(token::Str_(..))      => token::Literal(token::Str_(fix(content))),
        token::Literal(token::StrRaw(..))    => token::Literal(token::StrRaw(fix(content),
                                                                             count(content))),
        token::Literal(token::Char(..))      => token::Literal(token::Char(fixchar(content))),
        token::Literal(token::Byte(..))      => token::Literal(token::Byte(fixchar(content))),
        token::DocComment(..)      => token::DocComment(nm),
        token::Literal(token::Integer(..))   => token::Literal(token::Integer(nm)),
        token::Literal(token::Float(..))     => token::Literal(token::Float(nm)),
        token::Literal(token::Binary(..))    => token::Literal(token::Binary(nm)),
        token::Literal(token::BinaryRaw(..)) => token::Literal(token::BinaryRaw(fix(content),
                                                                                count(content))),
        token::Ident(..)           => token::Ident(ast::Ident { name: nm, ctxt: 0 },
                                                   token::ModName),
        token::Lifetime(..)        => token::Lifetime(ast::Ident { name: nm, ctxt: 0 }),
        ref t => t.clone()
    };

    let offset = if real_tok == token::Eof
 {
        1
    } else {
        0
    };

    let sp = syntax::codemap::Span {
        lo: syntax::codemap::BytePos(from_str::<u32>(start).unwrap() - offset),
        hi: syntax::codemap::BytePos(from_str::<u32>(end).unwrap() + 1),
        expn_id: syntax::codemap::NO_EXPANSION
    };

    TokenAndSpan {
        tok: real_tok,
        sp: sp
    }
}

fn tok_cmp(a: &token::Token, b: &token::Token) -> bool {
    match a {
        &token::Ident(id, _) => match b {
                &token::Ident(id2, _) => id == id2,
                _ => false
        },
        _ => a == b
    }
}

fn main() {
    fn next(r: &mut lexer::StringReader) -> TokenAndSpan {
        use syntax::parse::lexer::Reader;
        r.next_token()
    }

    let args = std::os::args();

    let mut token_file = File::open(&Path::new(args[2].as_slice()));
    let token_map = parse_token_list(token_file.read_to_string().unwrap().as_slice());

    let mut stdin = std::io::stdin();
    let mut antlr_tokens = stdin.lines().map(|l| parse_antlr_token(l.unwrap().as_slice().trim(),
                                                                   &token_map));

    let code = File::open(&Path::new(args[1].as_slice())).unwrap().read_to_string().unwrap();
    let options = config::basic_options();
    let session = session::build_session(options, None,
                                         syntax::diagnostics::registry::Registry::new(&[]));
    let filemap = parse::string_to_filemap(&session.parse_sess,
                                           code,
                                           String::from_str("<n/a>"));
    let mut lexer = lexer::StringReader::new(session.diagnostic(), filemap);

    for antlr_tok in antlr_tokens {
        let rustc_tok = next(&mut lexer);
        if rustc_tok.tok == token::Eof && antlr_tok.tok == token::Eof {
            continue
        }

        assert!(rustc_tok.sp == antlr_tok.sp, "{} and {} have different spans", rustc_tok,
                antlr_tok);

        macro_rules! matches (
            ( $($x:pat),+ ) => (
                match rustc_tok.tok {
                    $($x => match antlr_tok.tok {
                        $x => {
                            if !tok_cmp(&rustc_tok.tok, &antlr_tok.tok) {
                                // FIXME #15677: needs more robust escaping in
                                // antlr
                                warn!("Different names for {} and {}", rustc_tok, antlr_tok);
                            }
                        }
                        _ => panic!("{} is not {}", antlr_tok, rustc_tok)
                    },)*
                    ref c => assert!(c == &antlr_tok.tok, "{} is not {}", rustc_tok, antlr_tok)
                }
            )
        )

        matches!(
            token::Literal(token::Byte(..)),
            token::Literal(token::Char(..)),
            token::Literal(token::Integer(..)),
            token::Literal(token::Float(..)),
            token::Literal(token::Str_(..)),
            token::Literal(token::StrRaw(..)),
            token::Literal(token::Binary(..)),
            token::Literal(token::BinaryRaw(..)),
            token::Ident(..),
            token::Lifetime(..),
            token::Interpolated(..),
            token::DocComment(..),
            token::Shebang(..)
        );
    }
}
<commit_msg>Update grammer/verify.rs to work with recent master<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(globs, phase, macro_rules)]

extern crate syntax;
extern crate rustc;

#[phase(link)]
extern crate regex;

#[phase(link, plugin)]
extern crate log;

#[phase(plugin)] extern crate regex_macros;

use std::collections::HashMap;
use std::io::File;

use syntax::parse;
use syntax::parse::lexer;
use rustc::session::{mod, config};

use syntax::ast;
use syntax::ast::Name;
use syntax::parse::token;
use syntax::parse::lexer::TokenAndSpan;

fn parse_token_list(file: &str) -> HashMap<String, token::Token> {
    fn id() -> token::Token {
        token::Ident(ast::Ident { name: Name(0), ctxt: 0, }, token::Plain)
    }

    let mut res = HashMap::new();

    res.insert("-1".to_string(), token::Eof);

    for line in file.split('\n') {
        let eq = match line.trim().rfind('=') {
            Some(val) => val,
            None => continue
        };

        let val = line.slice_to(eq);
        let num = line.slice_from(eq + 1);

        let tok = match val {
            "SHR"               => token::BinOp(token::Shr),
            "DOLLAR"            => token::Dollar,
            "LT"                => token::Lt,
            "STAR"              => token::BinOp(token::Star),
            "FLOAT_SUFFIX"      => id(),
            "INT_SUFFIX"        => id(),
            "SHL"               => token::BinOp(token::Shl),
            "LBRACE"            => token::OpenDelim(token::Brace),
            "RARROW"            => token::RArrow,
            "LIT_STR"           => token::Literal(token::Str_(Name(0)), None),
            "DOTDOT"            => token::DotDot,
            "MOD_SEP"           => token::ModSep,
            "DOTDOTDOT"         => token::DotDotDot,
            "NOT"               => token::Not,
            "AND"               => token::BinOp(token::And),
            "LPAREN"            => token::OpenDelim(token::Paren),
            "ANDAND"            => token::AndAnd,
            "AT"                => token::At,
            "LBRACKET"          => token::OpenDelim(token::Bracket),
            "LIT_STR_RAW"       => token::Literal(token::StrRaw(Name(0), 0), None),
            "RPAREN"            => token::CloseDelim(token::Paren),
            "SLASH"             => token::BinOp(token::Slash),
            "COMMA"             => token::Comma,
            "LIFETIME"          => token::Lifetime(ast::Ident { name: Name(0), ctxt: 0 }),
            "CARET"             => token::BinOp(token::Caret),
            "TILDE"             => token::Tilde,
            "IDENT"             => id(),
            "PLUS"              => token::BinOp(token::Plus),
            "LIT_CHAR"          => token::Literal(token::Char(Name(0)), None),
            "LIT_BYTE"          => token::Literal(token::Byte(Name(0)), None),
            "EQ"                => token::Eq,
            "RBRACKET"          => token::CloseDelim(token::Bracket),
            "COMMENT"           => token::Comment,
            "DOC_COMMENT"       => token::DocComment(Name(0)),
            "DOT"               => token::Dot,
            "EQEQ"              => token::EqEq,
            "NE"                => token::Ne,
            "GE"                => token::Ge,
            "PERCENT"           => token::BinOp(token::Percent),
            "RBRACE"            => token::CloseDelim(token::Brace),
            "BINOP"             => token::BinOp(token::Plus),
            "POUND"             => token::Pound,
            "OROR"              => token::OrOr,
            "LIT_INTEGER"       => token::Literal(token::Integer(Name(0)), None),
            "BINOPEQ"           => token::BinOpEq(token::Plus),
            "LIT_FLOAT"         => token::Literal(token::Float(Name(0)), None),
            "WHITESPACE"        => token::Whitespace,
            "UNDERSCORE"        => token::Underscore,
            "MINUS"             => token::BinOp(token::Minus),
            "SEMI"              => token::Semi,
            "COLON"             => token::Colon,
            "FAT_ARROW"         => token::FatArrow,
            "OR"                => token::BinOp(token::Or),
            "GT"                => token::Gt,
            "LE"                => token::Le,
            "LIT_BINARY"        => token::Literal(token::Binary(Name(0)), None),
            "LIT_BINARY_RAW"    => token::Literal(token::BinaryRaw(Name(0), 0), None),
            _                   => continue,
        };

        res.insert(num.to_string(), tok);
    }

    debug!("Token map: {}", res);
    res
}

fn str_to_binop(s: &str) -> token::BinOpToken {
    match s {
        "+"     => token::Plus,
        "/"     => token::Slash,
        "-"     => token::Minus,
        "*"     => token::Star,
        "%"     => token::Percent,
        "^"     => token::Caret,
        "&"     => token::And,
        "|"     => token::Or,
        "<<"    => token::Shl,
        ">>"    => token::Shr,
        _       => panic!("Bad binop str `{}`", s),
    }
}

/// Assuming a string/binary literal, strip out the leading/trailing
/// hashes and surrounding quotes/raw/binary prefix.
fn fix(mut lit: &str) -> ast::Name {
    if lit.char_at(0) == 'r' {
        if lit.char_at(1) == 'b' {
            lit = lit.slice_from(2)
        } else {
            lit = lit.slice_from(1);
        }
    } else if lit.char_at(0) == 'b' {
        lit = lit.slice_from(1);
    }

    let leading_hashes = count(lit);

    // +1/-1 to adjust for single quotes
    parse::token::intern(lit.slice(leading_hashes + 1, lit.len() - leading_hashes - 1))
}

/// Assuming a char/byte literal, strip the 'b' prefix and the single quotes.
fn fixchar(mut lit: &str) -> ast::Name {
    if lit.char_at(0) == 'b' {
        lit = lit.slice_from(1);
    }

    parse::token::intern(lit.slice(1, lit.len() - 1))
}

fn count(lit: &str) -> uint {
    lit.chars().take_while(|c| *c == '#').count()
}

fn parse_antlr_token(s: &str, tokens: &HashMap<String, token::Token>) -> TokenAndSpan {
    let re = regex!(
      r"\[@(?P<seq>\d+),(?P<start>\d+):(?P<end>\d+)='(?P<content>.+?)',<(?P<toknum>-?\d+)>,\d+:\d+]"
    );

    let m = re.captures(s).expect(format!("The regex didn't match {}", s).as_slice());
    let start = m.name("start").unwrap_or("");
    let end = m.name("end").unwrap_or("");
    let toknum = m.name("toknum").unwrap_or("");
    let content = m.name("content").unwrap_or("");

    let proto_tok = tokens.get(toknum).expect(format!("didn't find token {} in the map",
                                                              toknum).as_slice());

    let nm = parse::token::intern(content);

    debug!("What we got: content (`{}`), proto: {}", content, proto_tok);

    let real_tok = match *proto_tok {
        token::BinOp(..)           => token::BinOp(str_to_binop(content)),
        token::BinOpEq(..)         => token::BinOpEq(str_to_binop(content.slice_to(
                                                                    content.len() - 1))),
        token::Literal(token::Str_(..), n)      => token::Literal(token::Str_(fix(content)), n),
        token::Literal(token::StrRaw(..), n)    => token::Literal(token::StrRaw(fix(content),
                                                                             count(content)), n),
        token::Literal(token::Char(..), n)      => token::Literal(token::Char(fixchar(content)), n),
        token::Literal(token::Byte(..), n)      => token::Literal(token::Byte(fixchar(content)), n),
        token::DocComment(..)      => token::DocComment(nm),
        token::Literal(token::Integer(..), n)   => token::Literal(token::Integer(nm), n),
        token::Literal(token::Float(..), n)     => token::Literal(token::Float(nm), n),
        token::Literal(token::Binary(..), n)    => token::Literal(token::Binary(nm), n),
        token::Literal(token::BinaryRaw(..), n) => token::Literal(token::BinaryRaw(fix(content),
                                                                                count(content)), n),
        token::Ident(..)           => token::Ident(ast::Ident { name: nm, ctxt: 0 },
                                                   token::ModName),
        token::Lifetime(..)        => token::Lifetime(ast::Ident { name: nm, ctxt: 0 }),
        ref t => t.clone()
    };

    let offset = if real_tok == token::Eof
 {
        1
    } else {
        0
    };

    let sp = syntax::codemap::Span {
        lo: syntax::codemap::BytePos(start.parse::<u32>().unwrap() - offset),
        hi: syntax::codemap::BytePos(end.parse::<u32>().unwrap() + 1),
        expn_id: syntax::codemap::NO_EXPANSION
    };

    TokenAndSpan {
        tok: real_tok,
        sp: sp
    }
}

fn tok_cmp(a: &token::Token, b: &token::Token) -> bool {
    match a {
        &token::Ident(id, _) => match b {
                &token::Ident(id2, _) => id == id2,
                _ => false
        },
        _ => a == b
    }
}

fn main() {
    fn next(r: &mut lexer::StringReader) -> TokenAndSpan {
        use syntax::parse::lexer::Reader;
        r.next_token()
    }

    let args = std::os::args();

    let mut token_file = File::open(&Path::new(args[2].as_slice()));
    let token_map = parse_token_list(token_file.read_to_string().unwrap().as_slice());

    let mut stdin = std::io::stdin();
    let mut lock = stdin.lock();
    let lines = lock.lines();
    let mut antlr_tokens = lines.map(|l| parse_antlr_token(l.unwrap().as_slice().trim(),
                                                                   &token_map));

    let code = File::open(&Path::new(args[1].as_slice())).unwrap().read_to_string().unwrap();
    let options = config::basic_options();
    let session = session::build_session(options, None,
                                         syntax::diagnostics::registry::Registry::new(&[]));
    let filemap = parse::string_to_filemap(&session.parse_sess,
                                           code,
                                           String::from_str("<n/a>"));
    let mut lexer = lexer::StringReader::new(session.diagnostic(), filemap);

    for antlr_tok in antlr_tokens {
        let rustc_tok = next(&mut lexer);
        if rustc_tok.tok == token::Eof && antlr_tok.tok == token::Eof {
            continue
        }

        assert!(rustc_tok.sp == antlr_tok.sp, "{} and {} have different spans", rustc_tok,
                antlr_tok);

        macro_rules! matches (
            ( $($x:pat),+ ) => (
                match rustc_tok.tok {
                    $($x => match antlr_tok.tok {
                        $x => {
                            if !tok_cmp(&rustc_tok.tok, &antlr_tok.tok) {
                                // FIXME #15677: needs more robust escaping in
                                // antlr
                                warn!("Different names for {} and {}", rustc_tok, antlr_tok);
                            }
                        }
                        _ => panic!("{} is not {}", antlr_tok, rustc_tok)
                    },)*
                    ref c => assert!(c == &antlr_tok.tok, "{} is not {}", rustc_tok, antlr_tok)
                }
            )
        );

        matches!(
            token::Literal(token::Byte(..), _),
            token::Literal(token::Char(..), _),
            token::Literal(token::Integer(..), _),
            token::Literal(token::Float(..), _),
            token::Literal(token::Str_(..), _),
            token::Literal(token::StrRaw(..), _),
            token::Literal(token::Binary(..), _),
            token::Literal(token::BinaryRaw(..), _),
            token::Ident(..),
            token::Lifetime(..),
            token::Interpolated(..),
            token::DocComment(..),
            token::Shebang(..)
        );
    }
}
<|endoftext|>


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

//! Local state for external blobs and their states.

use std::sync::mpsc;
use sodiumoxide::randombytes::randombytes;

use std::collections::HashMap;

use diesel;
use diesel::prelude::*;
use diesel::sqlite::SqliteConnection;

use process::{Process, MsgHandler};
use tags;
use util;

use super::schema;

pub type IndexProcess = Process<Msg, Reply>;

#[derive(Clone, Debug)]
pub struct BlobDesc {
    pub name: Vec<u8>,
    pub id: i64,
}

pub enum Msg {
    /// Reserve an internal `BlobDesc` for a new blob.
    Reserve,

    /// Report that this blob is in the process of being committed to persistent storage. If a
    /// blob is in this state when the system starts up, it may or may not exist in the persistent
    /// storage, but **should not** be referenced elsewhere, and is therefore safe to delete.
    InAir(BlobDesc),

    /// Report that this blob has been fully committed to persistent storage. We can now use its
    /// reference internally. Only committed blobs are considered "safe to use".
    CommitDone(BlobDesc),

    Tag(BlobDesc, tags::Tag),
    TagAll(tags::Tag),
    ListByTag(tags::Tag),
    DeleteByTag(tags::Tag),

    Flush,
}

pub enum Reply {
    Reserved(BlobDesc),
    Listing(mpsc::Receiver<BlobDesc>),
    CommitOk,
    Ok,
}

pub struct Index {
    conn: SqliteConnection,
    next_id: i64,
    reserved: HashMap<Vec<u8>, BlobDesc>,
}

impl Index {
    pub fn new(path: String) -> Index {
        let conn = SqliteConnection::establish(&path).expect("Could not open SQLite database");

        let mut bi = Index {
                    conn: conn,
                    next_id: -1,
                    reserved: HashMap::new(),
                };

        let dir = diesel::migrations::find_migrations_directory().unwrap();
        diesel::migrations::run_pending_migrations_in_directory(&bi.conn,
                                                                &dir,
                                                                &mut util::InfoWriter)
            .unwrap();
        bi.conn.begin_transaction().unwrap();
        bi.refresh_next_id();
        bi
    }

    #[cfg(test)]
    pub fn new_for_testing() -> Index {
        Index::new(":memory:".to_string())
    }

    fn new_blob_desc(&mut self) -> BlobDesc {
        BlobDesc {
            name: randombytes(24),
            id: self.next_id(),
        }
    }

    fn refresh_next_id(&mut self) {
        use diesel::expression::max;
        use super::schema::blobs::dsl::*;

        let id_opt = blobs.select(max(id).nullable())
                          .first::<Option<i64>>(&self.conn)
                          .optional()
                          .expect("Error querying blobs")
                          .and_then(|x| x);

        self.next_id = 1 + id_opt.unwrap_or(0);
    }

    fn next_id(&mut self) -> i64 {
        let id = self.next_id;
        self.next_id += 1;
        id
    }

    fn reserve(&mut self) -> BlobDesc {
        let blob = self.new_blob_desc();
        self.reserved.insert(blob.name.clone(), blob.clone());
        blob
    }

    fn in_air(&mut self, blob: &BlobDesc) {
        assert!(self.reserved.get(&blob.name).is_some(),
                "blob was not reserved!");
        use super::schema::blobs::dsl::*;

        let new = schema::NewBlob {
            id: blob.id,
            name: &blob.name,
            tag: tags::Tag::InProgress as i32,
        };
        diesel::insert(&new)
            .into(blobs)
            .execute(&self.conn)
            .expect("Error inserting blob");

        self.new_transaction();
    }

    fn new_transaction(&mut self) {
        self.conn.commit_transaction().unwrap();
        self.conn.begin_transaction().unwrap();
    }

    fn commit_blob(&mut self, blob: &BlobDesc) {
        assert!(self.reserved.get(&blob.name).is_some(),
                "blob was not reserved!");
        use super::schema::blobs::dsl::*;

        diesel::update(blobs.find(blob.id)).set(tag.eq(tags::Tag::Done as i32))
                                           .execute(&self.conn)
                                           .expect("Error updating blob");
        self.new_transaction();
    }

    fn tag(&mut self, tag_: tags::Tag, target: Option<BlobDesc>) {
        use super::schema::blobs::dsl::*;
        match target {
            None =>
                diesel::update(blobs).set(tag.eq(tag_ as i32))
                                     .execute(&self.conn)
                                     .expect("Error updating blob tags"),
            Some(ref t) if t.id > 0 =>
                diesel::update(blobs.find(t.id)).set(tag.eq(tag_ as i32))
                                                .execute(&self.conn)
                                                .expect("Error updating blob tags"),
            Some(ref t) if !t.name.is_empty() =>
                diesel::update(blobs.filter(name.eq(&t.name))).set(tag.eq(tag_ as i32))
                                                              .execute(&self.conn)
                                                              .expect("Error updating blob tags"),
            _ => unreachable!(),
        };
    }

    fn delete_by_tag(&mut self, tag_: tags::Tag) {
        use super::schema::blobs::dsl::*;
        diesel::delete(blobs.filter(tag.eq(tag_ as i32)))
                .execute(&self.conn)
                .expect("Error deleting blobs");
    }

    fn list_by_tag(&mut self, tag_: tags::Tag) -> mpsc::Receiver<BlobDesc> {
        use super::schema::blobs::dsl::*;
        let (sender, receiver) = mpsc::channel();

        let blobs_ = blobs.filter(tag.eq(tag_ as i32))
                          .load::<schema::Blob>(&self.conn)
                          .expect("Error listing blobs");
        for blob_ in blobs_ {
            if let Err(_) = sender.send(BlobDesc {
                id: blob_.id,
                name: blob_.name,
            }) {
                break; // channel closed.
            }
        }
        return receiver;
    }
}

impl Drop for Index {
    fn drop(&mut self) {
        self.conn.commit_transaction().unwrap();
    }
}

impl MsgHandler<Msg, Reply> for Index {
    fn handle(&mut self, msg: Msg, reply: Box<Fn(Reply)>) {
        match msg {
            Msg::Reserve => {
                return reply(Reply::Reserved(self.reserve()));
            }
            Msg::InAir(blob) => {
                self.in_air(&blob);
                return reply(Reply::CommitOk);
            }
            Msg::CommitDone(blob) => {
                self.commit_blob(&blob);
                return reply(Reply::CommitOk);
            }
            Msg::Flush => {
                self.new_transaction();
                return reply(Reply::CommitOk);
            }
            Msg::Tag(blob, tag) => {
                self.tag(tag, Some(blob));
                reply(Reply::Ok);
            }
            Msg::TagAll(tag) => {
                self.tag(tag, None);
                reply(Reply::Ok);
            }
            Msg::ListByTag(tag) => {
                reply(Reply::Listing(self.list_by_tag(tag)));
            }
            Msg::DeleteByTag(tag) => {
                self.delete_by_tag(tag);
                reply(Reply::Ok);
            }
        }
    }
}
<commit_msg>We explicitly commit, do not implicitly commit on Drop.<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Local state for external blobs and their states.

use std::sync::mpsc;
use sodiumoxide::randombytes::randombytes;

use std::collections::HashMap;

use diesel;
use diesel::prelude::*;
use diesel::sqlite::SqliteConnection;

use process::{Process, MsgHandler};
use tags;
use util;

use super::schema;

pub type IndexProcess = Process<Msg, Reply>;

#[derive(Clone, Debug)]
pub struct BlobDesc {
    pub name: Vec<u8>,
    pub id: i64,
}

pub enum Msg {
    /// Reserve an internal `BlobDesc` for a new blob.
    Reserve,

    /// Report that this blob is in the process of being committed to persistent storage. If a
    /// blob is in this state when the system starts up, it may or may not exist in the persistent
    /// storage, but **should not** be referenced elsewhere, and is therefore safe to delete.
    InAir(BlobDesc),

    /// Report that this blob has been fully committed to persistent storage. We can now use its
    /// reference internally. Only committed blobs are considered "safe to use".
    CommitDone(BlobDesc),

    Tag(BlobDesc, tags::Tag),
    TagAll(tags::Tag),
    ListByTag(tags::Tag),
    DeleteByTag(tags::Tag),

    Flush,
}

pub enum Reply {
    Reserved(BlobDesc),
    Listing(mpsc::Receiver<BlobDesc>),
    CommitOk,
    Ok,
}

pub struct Index {
    conn: SqliteConnection,
    next_id: i64,
    reserved: HashMap<Vec<u8>, BlobDesc>,
}

impl Index {
    pub fn new(path: String) -> Index {
        let conn = SqliteConnection::establish(&path).expect("Could not open SQLite database");

        let mut bi = Index {
                    conn: conn,
                    next_id: -1,
                    reserved: HashMap::new(),
                };

        let dir = diesel::migrations::find_migrations_directory().unwrap();
        diesel::migrations::run_pending_migrations_in_directory(&bi.conn,
                                                                &dir,
                                                                &mut util::InfoWriter)
            .unwrap();
        bi.conn.begin_transaction().unwrap();
        bi.refresh_next_id();
        bi
    }

    #[cfg(test)]
    pub fn new_for_testing() -> Index {
        Index::new(":memory:".to_string())
    }

    fn new_blob_desc(&mut self) -> BlobDesc {
        BlobDesc {
            name: randombytes(24),
            id: self.next_id(),
        }
    }

    fn refresh_next_id(&mut self) {
        use diesel::expression::max;
        use super::schema::blobs::dsl::*;

        let id_opt = blobs.select(max(id).nullable())
                          .first::<Option<i64>>(&self.conn)
                          .optional()
                          .expect("Error querying blobs")
                          .and_then(|x| x);

        self.next_id = 1 + id_opt.unwrap_or(0);
    }

    fn next_id(&mut self) -> i64 {
        let id = self.next_id;
        self.next_id += 1;
        id
    }

    fn reserve(&mut self) -> BlobDesc {
        let blob = self.new_blob_desc();
        self.reserved.insert(blob.name.clone(), blob.clone());
        blob
    }

    fn in_air(&mut self, blob: &BlobDesc) {
        assert!(self.reserved.get(&blob.name).is_some(),
                "blob was not reserved!");
        use super::schema::blobs::dsl::*;

        let new = schema::NewBlob {
            id: blob.id,
            name: &blob.name,
            tag: tags::Tag::InProgress as i32,
        };
        diesel::insert(&new)
            .into(blobs)
            .execute(&self.conn)
            .expect("Error inserting blob");

        self.new_transaction();
    }

    fn new_transaction(&mut self) {
        self.conn.commit_transaction().unwrap();
        self.conn.begin_transaction().unwrap();
    }

    fn commit_blob(&mut self, blob: &BlobDesc) {
        assert!(self.reserved.get(&blob.name).is_some(),
                "blob was not reserved!");
        use super::schema::blobs::dsl::*;

        diesel::update(blobs.find(blob.id)).set(tag.eq(tags::Tag::Done as i32))
                                           .execute(&self.conn)
                                           .expect("Error updating blob");
        self.new_transaction();
    }

    fn tag(&mut self, tag_: tags::Tag, target: Option<BlobDesc>) {
        use super::schema::blobs::dsl::*;
        match target {
            None =>
                diesel::update(blobs).set(tag.eq(tag_ as i32))
                                     .execute(&self.conn)
                                     .expect("Error updating blob tags"),
            Some(ref t) if t.id > 0 =>
                diesel::update(blobs.find(t.id)).set(tag.eq(tag_ as i32))
                                                .execute(&self.conn)
                                                .expect("Error updating blob tags"),
            Some(ref t) if !t.name.is_empty() =>
                diesel::update(blobs.filter(name.eq(&t.name))).set(tag.eq(tag_ as i32))
                                                              .execute(&self.conn)
                                                              .expect("Error updating blob tags"),
            _ => unreachable!(),
        };
    }

    fn delete_by_tag(&mut self, tag_: tags::Tag) {
        use super::schema::blobs::dsl::*;
        diesel::delete(blobs.filter(tag.eq(tag_ as i32)))
                .execute(&self.conn)
                .expect("Error deleting blobs");
    }

    fn list_by_tag(&mut self, tag_: tags::Tag) -> mpsc::Receiver<BlobDesc> {
        use super::schema::blobs::dsl::*;
        let (sender, receiver) = mpsc::channel();

        let blobs_ = blobs.filter(tag.eq(tag_ as i32))
                          .load::<schema::Blob>(&self.conn)
                          .expect("Error listing blobs");
        for blob_ in blobs_ {
            if let Err(_) = sender.send(BlobDesc {
                id: blob_.id,
                name: blob_.name,
            }) {
                break; // channel closed.
            }
        }
        return receiver;
    }
}

impl MsgHandler<Msg, Reply> for Index {
    fn handle(&mut self, msg: Msg, reply: Box<Fn(Reply)>) {
        match msg {
            Msg::Reserve => {
                return reply(Reply::Reserved(self.reserve()));
            }
            Msg::InAir(blob) => {
                self.in_air(&blob);
                return reply(Reply::CommitOk);
            }
            Msg::CommitDone(blob) => {
                self.commit_blob(&blob);
                return reply(Reply::CommitOk);
            }
            Msg::Flush => {
                self.new_transaction();
                return reply(Reply::CommitOk);
            }
            Msg::Tag(blob, tag) => {
                self.tag(tag, Some(blob));
                reply(Reply::Ok);
            }
            Msg::TagAll(tag) => {
                self.tag(tag, None);
                reply(Reply::Ok);
            }
            Msg::ListByTag(tag) => {
                reply(Reply::Listing(self.list_by_tag(tag)));
            }
            Msg::DeleteByTag(tag) => {
                self.delete_by_tag(tag);
                reply(Reply::Ok);
            }
        }
    }
}
<|endoftext|>


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

enum E { V1(isize), V0 }
const C: &'static [E] = &[E::V0, E::V1(0xDEADBEE)];
static C0: E = C[0];
static C1: E = C[1];
const D: &'static [E; 2] = &[E::V0, E::V1(0xDEAFBEE)];
static D0: E = D[0];
static D1: E = D[1];

pub fn main() {
    match C0 {
        E::V0 => (),
        _ => panic!()
    }
    match C1 {
        E::V1(n) => assert_eq!(n, 0xDEADBEE),
        _ => panic!()
    }

    match D0 {
        E::V0 => (),
        _ => panic!()
    }
    match D1 {
        E::V1(n) => assert_eq!(n, 0xDEAFBEE),
        _ => panic!()
    }
}
<commit_msg>fix run-pass test that required `Copy` impl<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[derive(Copy, Clone)]
enum E { V1(isize), V0 }

const C: &'static [E] = &[E::V0, E::V1(0xDEADBEE)];
static C0: E = C[0];
static C1: E = C[1];
const D: &'static [E; 2] = &[E::V0, E::V1(0xDEAFBEE)];
static D0: E = D[0];
static D1: E = D[1];

pub fn main() {
    match C0 {
        E::V0 => (),
        _ => panic!()
    }
    match C1 {
        E::V1(n) => assert_eq!(n, 0xDEADBEE),
        _ => panic!()
    }

    match D0 {
        E::V0 => (),
        _ => panic!()
    }
    match D1 {
        E::V1(n) => assert_eq!(n, 0xDEAFBEE),
        _ => panic!()
    }
}
<|endoftext|>


<commit_before>mod idt;

macro_rules! handler {
    ($name: ident) => {{
        #[naked]
        extern "C" fn wrapper() -> ! {
            unsafe {
                asm!("mov rdi, rsp
                      sub rsp, 8 // align the stack pointer
                      call $0"
                      :: "i"($name as extern "C" fn(
                          *const ExceptionStackFrame) -> !)
                      : "rdi" : "intel");
                ::core::intrinsics::unreachable();
            }
        }
        wrapper
    }}
}

macro_rules! handler_with_error_code {
    ($name: ident) => {{
        #[naked]
        extern "C" fn wrapper() -> ! {
            unsafe {
                asm!("pop rsi // pop error code into rsi
                      mov rdi, rsp
                      sub rsp, 8 // align the stack pointer
                      call $0"
                      :: "i"($name as extern "C" fn(
                          *const ExceptionStackFrame, u64) -> !)
                      : "rdi" : "intel");
                ::core::intrinsics::unreachable();
            }
        }
        wrapper
    }}
}

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

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

        idt
    };
}

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

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

use vga_buffer::print_error;

extern "C" fn divide_by_zero_handler(stack_frame: *const ExceptionStackFrame)
    -> !
{
    unsafe {
        print_error(format_args!("EXCEPTION: DIVIDE BY ZERO\n{:#?}",
            *stack_frame));
    }
    loop {}
}

extern "C" fn invalid_opcode_handler(stack_frame: *const ExceptionStackFrame)
    -> !
{
    unsafe {
        print_error(format_args!("EXCEPTION: INVALID OPCODE at {:#x}\n{:#?}",
            (*stack_frame).instruction_pointer, *stack_frame));
    }
    loop {}
}

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

extern "C" fn page_fault_handler(stack_frame: *const ExceptionStackFrame,
                                 error_code: u64) -> !
{
    use x86::controlregs;
    unsafe {
        print_error(format_args!(
            "EXCEPTION: PAGE FAULT while accessing {:#x}\
            \nerror code: {:?}\n{:#?}",
            controlregs::cr2(),
            PageFaultErrorCode::from_bits(error_code).unwrap(),
            *stack_frame));
    }
    loop {}
}
<commit_msg>Run rustfmt<commit_after>mod idt;

macro_rules! handler {
    ($name: ident) => {{
        #[naked]
        extern "C" fn wrapper() -> ! {
            unsafe {
                asm!("mov rdi, rsp
                      sub rsp, 8 // align the stack pointer
                      call $0"
                      :: "i"($name as extern "C" fn(
                          *const ExceptionStackFrame) -> !)
                      : "rdi" : "intel");
                ::core::intrinsics::unreachable();
            }
        }
        wrapper
    }}
}

macro_rules! handler_with_error_code {
    ($name: ident) => {{
        #[naked]
        extern "C" fn wrapper() -> ! {
            unsafe {
                asm!("pop rsi // pop error code into rsi
                      mov rdi, rsp
                      sub rsp, 8 // align the stack pointer
                      call $0"
                      :: "i"($name as extern "C" fn(
                          *const ExceptionStackFrame, u64) -> !)
                      : "rdi" : "intel");
                ::core::intrinsics::unreachable();
            }
        }
        wrapper
    }}
}

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

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

        idt
    };
}

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

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

use vga_buffer::print_error;

extern "C" fn divide_by_zero_handler(stack_frame: *const ExceptionStackFrame) -> ! {
    unsafe {
        print_error(format_args!("EXCEPTION: DIVIDE BY ZERO\n{:#?}", *stack_frame));
    }
    loop {}
}

extern "C" fn invalid_opcode_handler(stack_frame: *const ExceptionStackFrame) -> ! {
    unsafe {
        print_error(format_args!("EXCEPTION: INVALID OPCODE at {:#x}\n{:#?}",
                                 (*stack_frame).instruction_pointer,
                                 *stack_frame));
    }
    loop {}
}

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

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


<commit_before>use crate::Ipv4Net;
use crate::Ipv6Net;
use crate::IpNet;

use schemars::{JsonSchema, gen::SchemaGenerator, schema::{SubschemaValidation, Schema, SchemaObject, StringValidation, Metadata, SingleOrVec, InstanceType}};

impl JsonSchema for Ipv4Net {
    fn schema_name() -> String {
        "Ipv4Net".to_string()
    }

    fn json_schema(_gen: &mut SchemaGenerator) -> Schema {
        Schema::Object(SchemaObject {
            metadata: Some(Box::new(Metadata {
                title: Some("Ipv4 Network".to_string()),
                description: Some("Ipv4 address with subnet mask".to_string()),
                examples: vec![schemars::_serde_json::Value::String("0.0.0.0/0".to_string())],
                ..Default::default()
            })),
            instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))),
            string: Some(Box::new(StringValidation {
                pattern: Some(r#"\b(?:(?:2(?:[0-4][0-9]|5[0-5])|[0-1]?[0-9]?[0-9])\.){3}(?:(?:2([0-4][0-9]|5[0-5])|[0-1]?[0-9]?[0-9]))\/(?:(?:3([0-2])|[0-2]?[0-9]))\b$"#),
                ..Default::default()
            })),
            ..Default::default()
        })
    }
}
impl JsonSchema for Ipv6Net {
    fn schema_name() -> String {
        "Ipv6Net".to_string()
    }

    fn json_schema(_gen: &mut SchemaGenerator) -> Schema {
        Schema::Object(SchemaObject {
            metadata: Some(Box::new(Metadata {
                title: Some("Ipv6 Network".to_string()),
                description: Some("Ipv6 address with prefix".to_string()),
                examples: vec![schemars::_serde_json::Value::String("::/0".to_string())],
                ..Default::default()
            })),
            instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))),
            string: Some(Box::new(StringValidation {
                pattern: Some(r#"^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))$"#.to_string()),
                ..Default::default()
            })),
            ..Default::default()
        })
    }
}
impl JsonSchema for IpNet {
    fn schema_name() -> String {
        "IpNet".to_string()
    }

    fn json_schema(gen: &mut SchemaGenerator) -> Schema {
        Schema::Object(SchemaObject {
            metadata: Some(Box::new(Metadata {
                title: Some("Ip Network".to_string()),
                description: Some("Ip address (v4 or v6) with Prefix".to_string()),
                ..Default::default()
            })),
            subschemas: Some(Box::new(
                SubschemaValidation {
                    one_of: Some(vec![Ipv4Net::json_schema(gen), Ipv6Net::json_schema(gen)]),
                    ..Default::default()
                }
            )),
            ..Default::default()
        })
    }
}<commit_msg>Fix missing to_string() on pattern<commit_after>use crate::Ipv4Net;
use crate::Ipv6Net;
use crate::IpNet;

use schemars::{JsonSchema, gen::SchemaGenerator, schema::{SubschemaValidation, Schema, SchemaObject, StringValidation, Metadata, SingleOrVec, InstanceType}};

impl JsonSchema for Ipv4Net {
    fn schema_name() -> String {
        "Ipv4Net".to_string()
    }

    fn json_schema(_gen: &mut SchemaGenerator) -> Schema {
        Schema::Object(SchemaObject {
            metadata: Some(Box::new(Metadata {
                title: Some("Ipv4 Network".to_string()),
                description: Some("Ipv4 address with subnet mask".to_string()),
                examples: vec![schemars::_serde_json::Value::String("0.0.0.0/0".to_string())],
                ..Default::default()
            })),
            instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))),
            string: Some(Box::new(StringValidation {
                pattern: Some(r#"\b(?:(?:2(?:[0-4][0-9]|5[0-5])|[0-1]?[0-9]?[0-9])\.){3}(?:(?:2([0-4][0-9]|5[0-5])|[0-1]?[0-9]?[0-9]))\/(?:(?:3([0-2])|[0-2]?[0-9]))\b$"#.to_string()),
                ..Default::default()
            })),
            ..Default::default()
        })
    }
}
impl JsonSchema for Ipv6Net {
    fn schema_name() -> String {
        "Ipv6Net".to_string()
    }

    fn json_schema(_gen: &mut SchemaGenerator) -> Schema {
        Schema::Object(SchemaObject {
            metadata: Some(Box::new(Metadata {
                title: Some("Ipv6 Network".to_string()),
                description: Some("Ipv6 address with prefix".to_string()),
                examples: vec![schemars::_serde_json::Value::String("::/0".to_string())],
                ..Default::default()
            })),
            instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))),
            string: Some(Box::new(StringValidation {
                pattern: Some(r#"^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))$"#.to_string()),
                ..Default::default()
            })),
            ..Default::default()
        })
    }
}
impl JsonSchema for IpNet {
    fn schema_name() -> String {
        "IpNet".to_string()
    }

    fn json_schema(gen: &mut SchemaGenerator) -> Schema {
        Schema::Object(SchemaObject {
            metadata: Some(Box::new(Metadata {
                title: Some("Ip Network".to_string()),
                description: Some("Ip address (v4 or v6) with Prefix".to_string()),
                ..Default::default()
            })),
            subschemas: Some(Box::new(
                SubschemaValidation {
                    one_of: Some(vec![Ipv4Net::json_schema(gen), Ipv6Net::json_schema(gen)]),
                    ..Default::default()
                }
            )),
            ..Default::default()
        })
    }
}
<|endoftext|>


<commit_before>// Purge all references to a crate's version from the database.
//
// Please be super sure you want to do this before running this.
//
// Usage:
//      cargo run --bin delete-version crate-name version-number

#![deny(warnings)]

extern crate cargo_registry;
extern crate git2;
extern crate postgres;
extern crate rustc_serialize;

use std::path::PathBuf;

use cargo_registry::{http, env, App};
use cargo_registry::util::{CargoResult, human};

#[allow(dead_code)]
fn main() {
    git2::Repository::init("tmp/test").unwrap();
    let config = cargo_registry::Config {
        s3_bucket: String::new(),
        s3_access_key: String::new(),
        s3_secret_key: String::new(),
        s3_region: None,
        s3_proxy: None,
        session_key: String::new(),
        git_repo_checkout: PathBuf::from("tmp/test"),
        gh_client_id: env("GH_CLIENT_ID"),
        gh_client_secret: env("GH_CLIENT_SECRET"),
        db_url: env("DATABASE_URL"),
        env: cargo_registry::Env::Production,
        max_upload_size: 0,
        mirror: false,
    };
    let app = cargo_registry::App::new(&config);
    {
        let tx = app.database.get().unwrap();
        let tx = tx.transaction().unwrap();
        update(&app, &tx);
        tx.set_commit();
        tx.finish().unwrap();
    }
}

#[derive(RustcDecodable)]
struct GithubUser {
    login: String,
    id: i32,
}

fn update(app: &App, tx: &postgres::transaction::Transaction) {
    let mut rows = Vec::new();
    let query = "SELECT id, gh_login, gh_access_token, gh_avatar FROM users \
                  WHERE gh_id IS NULL";
    for row in &tx.query(query, &[]).unwrap() {
        let id: i32 = row.get("id");
        let login: String = row.get("gh_login");
        let token: String = row.get("gh_access_token");
        let avatar: Option<String> = row.get("gh_avatar");
        rows.push((id, login, http::token(token), avatar));
    }

    for (id, login, token, avatar) in rows {
        println!("attempt: {}/{}", id, login);
        let res = (|| -> CargoResult<()> {
            let url = format!("/users/{}", login);
            let (handle, resp) = http::github(app, &url, &token)?;
            let ghuser: GithubUser = http::parse_github_response(handle, resp)?;
            if let Some(ref avatar) = avatar {
                if !avatar.contains(&ghuser.id.to_string()) {
                    return Err(human(format!("avatar: {}", avatar)))
                }
            }
            if ghuser.login == login {
                tx.execute("UPDATE users SET gh_id = $1 WHERE id = $2",
                           &[&ghuser.id, &id])?;
                Ok(())
            } else {
                Err(human(format!("different login: {}", ghuser.login)))
            }
        })();
        if let Err(e) = res {
            println!("error for {}: {:?}", login, e);
        }
    }
}

<commit_msg>Remove a mut vec<commit_after>// Purge all references to a crate's version from the database.
//
// Please be super sure you want to do this before running this.
//
// Usage:
//      cargo run --bin delete-version crate-name version-number

#![deny(warnings)]

extern crate cargo_registry;
extern crate git2;
extern crate postgres;
extern crate rustc_serialize;

use std::path::PathBuf;

use cargo_registry::{http, env, App};
use cargo_registry::util::{CargoResult, human};

#[allow(dead_code)]
fn main() {
    git2::Repository::init("tmp/test").unwrap();
    let config = cargo_registry::Config {
        s3_bucket: String::new(),
        s3_access_key: String::new(),
        s3_secret_key: String::new(),
        s3_region: None,
        s3_proxy: None,
        session_key: String::new(),
        git_repo_checkout: PathBuf::from("tmp/test"),
        gh_client_id: env("GH_CLIENT_ID"),
        gh_client_secret: env("GH_CLIENT_SECRET"),
        db_url: env("DATABASE_URL"),
        env: cargo_registry::Env::Production,
        max_upload_size: 0,
        mirror: false,
    };
    let app = cargo_registry::App::new(&config);
    {
        let tx = app.database.get().unwrap();
        let tx = tx.transaction().unwrap();
        update(&app, &tx);
        tx.set_commit();
        tx.finish().unwrap();
    }
}

#[derive(RustcDecodable)]
struct GithubUser {
    login: String,
    id: i32,
}

fn update(app: &App, tx: &postgres::transaction::Transaction) {
    let query = "SELECT id, gh_login, gh_access_token, gh_avatar FROM users
                 WHERE gh_id IS NULL";
    let rows = tx.query(query, &[]).unwrap().into_iter().map(|row| {
        let id: i32 = row.get("id");
        let login: String = row.get("gh_login");
        let token: String = row.get("gh_access_token");
        let avatar: Option<String> = row.get("gh_avatar");
        (id, login, http::token(token), avatar)
    }).collect::<Vec<_>>();

    for (id, login, token, avatar) in rows {
        println!("attempt: {}/{}", id, login);
        let res = (|| -> CargoResult<()> {
            let url = format!("/users/{}", login);
            let (handle, resp) = http::github(app, &url, &token)?;
            let ghuser: GithubUser = http::parse_github_response(handle, resp)?;
            if let Some(ref avatar) = avatar {
                if !avatar.contains(&ghuser.id.to_string()) {
                    return Err(human(format!("avatar: {}", avatar)))
                }
            }
            if ghuser.login == login {
                tx.execute("UPDATE users SET gh_id = $1 WHERE id = $2",
                           &[&ghuser.id, &id])?;
                Ok(())
            } else {
                Err(human(format!("different login: {}", ghuser.login)))
            }
        })();
        if let Err(e) = res {
            println!("error for {}: {:?}", login, e);
        }
    }
}

<|endoftext|>