<commit_before>#![feature(plugin, custom_attribute)]
#![plugin(gfx_macros)]

extern crate piston;
extern crate vecmath;
extern crate camera_controllers;
extern crate gfx;
extern crate gfx_device_gl;
extern crate sdl2_window;

use std::cell::RefCell;
use piston::quack::Set;
use piston::window::{ WindowSettings, CaptureCursor };
use camera_controllers::{
    FirstPersonSettings,
    FirstPerson,
    CameraPerspective,
    model_view_projection
};
use gfx::traits::*;
use sdl2_window::{ Sdl2Window, OpenGL };

//----------------------------------------
// Cube associated data

#[vertex_format]
#[derive(Copy)]
struct Vertex {
    #[as_float]
    a_pos: [i8; 3],
    #[as_float]
    a_tex_coord: [u8; 2],
}

impl Vertex {
    fn new(pos: [i8; 3], tc: [u8; 2]) -> Vertex {
        Vertex {
            a_pos: pos,
            a_tex_coord: tc,
        }
    }
}

#[shader_param]
struct Params<R: gfx::Resources> {
    u_model_view_proj: [[f32; 4]; 4],
    t_color: gfx::shade::TextureParam<R>,
}

const VERTEX_SRC: [&'static [u8]; 2] = [ b"
    #version 120
    attribute vec3 a_pos;
    attribute vec2 a_tex_coord;
    varying vec2 v_TexCoord;
    uniform mat4 u_model_view_proj;
    void main() {
        v_TexCoord = a_tex_coord;
        gl_Position = u_model_view_proj * vec4(a_pos, 1.0);
    }
", b"
    #version 150 core
    in vec3 a_pos;
    in vec2 a_tex_coord;
    out vec2 v_TexCoord;
    uniform mat4 u_model_view_proj;
    void main() {
        v_TexCoord = a_tex_coord;
        gl_Position = u_model_view_proj * vec4(a_pos, 1.0);
    }
"];

const FRAGMENT_SRC: [&'static [u8]; 2] = [ b"
    #version 120
    varying vec2 v_TexCoord;
    uniform sampler2D t_color;
    void main() {
        vec4 tex = texture2D(t_color, v_TexCoord);
        float blend = dot(v_TexCoord-vec2(0.5,0.5), v_TexCoord-vec2(0.5,0.5));
        gl_FragColor = mix(tex, vec4(0.0,0.0,0.0,0.0), blend*1.0);
    }
", b"
    #version 150 core
    in vec2 v_TexCoord;
    out vec4 o_Color;
    uniform sampler2D t_color;
    void main() {
        vec4 tex = texture(t_color, v_TexCoord);
        float blend = dot(v_TexCoord-vec2(0.5,0.5), v_TexCoord-vec2(0.5,0.5));
        o_Color = mix(tex, vec4(0.0,0.0,0.0,0.0), blend*1.0);
    }
"];

//----------------------------------------

fn main() {
    let (win_width, win_height) = (640, 480);
    let mut window = Sdl2Window::new(
        OpenGL::_3_2,
        WindowSettings {
            title: "piston-example-gfx_cube".to_string(),
            size: [win_width, win_height],
            fullscreen: false,
            exit_on_esc: true,
            samples: 4,
        }
    );

    window.set_mut(CaptureCursor(true));

    let vertex = gfx::ShaderSource {
        glsl_120: Some(VERTEX_SRC[0]),
        glsl_150: Some(VERTEX_SRC[1]),
        .. gfx::ShaderSource::empty()
    };
    let fragment = gfx::ShaderSource {
        glsl_120: Some(FRAGMENT_SRC[0]),
        glsl_150: Some(FRAGMENT_SRC[1]),
        .. gfx::ShaderSource::empty()
    };

    let mut device = gfx_device_gl::GlDevice::new(Sdl2Window::get_proc_address);
    let frame = gfx::Frame::new(win_width as u16, win_height as u16);
    let state = gfx::DrawState::new().depth(gfx::state::Comparison::LessEqual, true);

    let vertex_data = vec![
        //top (0, 0, 1)
        Vertex::new([-1, -1,  1], [0, 0]),
        Vertex::new([ 1, -1,  1], [1, 0]),
        Vertex::new([ 1,  1,  1], [1, 1]),
        Vertex::new([-1,  1,  1], [0, 1]),
        //bottom (0, 0, -1)
        Vertex::new([ 1,  1, -1], [0, 0]),
        Vertex::new([-1,  1, -1], [1, 0]),
        Vertex::new([-1, -1, -1], [1, 1]),
        Vertex::new([ 1, -1, -1], [0, 1]),
        //right (1, 0, 0)
        Vertex::new([ 1, -1, -1], [0, 0]),
        Vertex::new([ 1,  1, -1], [1, 0]),
        Vertex::new([ 1,  1,  1], [1, 1]),
        Vertex::new([ 1, -1,  1], [0, 1]),
        //left (-1, 0, 0)
        Vertex::new([-1,  1,  1], [0, 0]),
        Vertex::new([-1, -1,  1], [1, 0]),
        Vertex::new([-1, -1, -1], [1, 1]),
        Vertex::new([-1,  1, -1], [0, 1]),
        //front (0, 1, 0)
        Vertex::new([-1,  1, -1], [0, 0]),
        Vertex::new([ 1,  1, -1], [1, 0]),
        Vertex::new([ 1,  1,  1], [1, 1]),
        Vertex::new([-1,  1,  1], [0, 1]),
        //back (0, -1, 0)
        Vertex::new([ 1, -1,  1], [0, 0]),
        Vertex::new([-1, -1,  1], [1, 0]),
        Vertex::new([-1, -1, -1], [1, 1]),
        Vertex::new([ 1, -1, -1], [0, 1]),
    ];

    let mesh = device.create_mesh(&vertex_data);

    let index_data: &[u8] = &[
         0,  1,  2,  2,  3,  0, // top
         4,  6,  5,  6,  4,  7, // bottom
         8,  9, 10, 10, 11,  8, // right
        12, 14, 13, 14, 12, 16, // left
        16, 18, 17, 18, 16, 19, // front
        20, 21, 22, 22, 23, 20, // back
    ];

    let slice = device.create_buffer_index(index_data)
                      .to_slice(gfx::PrimitiveType::TriangleList);

    let tinfo = gfx::tex::TextureInfo {
        width: 1,
        height: 1,
        depth: 1,
        levels: 1,
        kind: gfx::tex::TextureKind::Texture2D,
        format: gfx::tex::RGBA8,
    };
    let img_info = tinfo.to_image_info();
    let texture = device.create_texture(tinfo).unwrap();
    device.update_texture(
        &texture,
        &img_info,
        &[0x20u8, 0xA0, 0xC0, 0x00]
    ).unwrap();

    let sampler = device.create_sampler(
        gfx::tex::SamplerInfo::new(
            gfx::tex::FilterMethod::Bilinear,
            gfx::tex::WrapMode::Clamp
        )
    );

    let shader_model = device.get_capabilities().shader_model;

    let program = device.link_program(
        vertex.choose(shader_model).unwrap(),
        fragment.choose(shader_model).unwrap()
    ).unwrap();

    let mut graphics = device.into_graphics();

    let data = Params {
        u_model_view_proj: vecmath::mat4_id(),
        t_color: (texture, Some(sampler)),
    };

    let mut batch = graphics.make_batch(&program, data, &mesh, slice, &state).unwrap();

    let model = vecmath::mat4_id();
    let projection = CameraPerspective {
        fov: 90.0,
        near_clip: 0.1,
        far_clip: 1000.0,
        aspect_ratio: (win_width as f32) / (win_height as f32)
    }.projection();
    let mut first_person = FirstPerson::new(
        [0.5, 0.5, 4.0],
        FirstPersonSettings::keyboard_wasd()
    );

    let window = RefCell::new(window);
    for e in piston::events(&window) {
        use piston::event::*;

        first_person.event(&e);

        if let Some(args) = e.render_args() {
            graphics.clear(
                gfx::ClearData {
                    color: [0.3, 0.3, 0.3, 1.0],
                    depth: 1.0,
                    stencil: 0,
                },
                gfx::COLOR | gfx::DEPTH,
                &frame
            );
            batch.params.u_model_view_proj = model_view_projection(
                model,
                first_person.camera(args.ext_dt).orthogonal(),
                projection
            );
            graphics.draw(&batch, &frame).unwrap();
            graphics.end_frame();
        }

        if let Some(_) = e.after_render_args() {
            graphics.device.after_frame();
        }
    }
}
<commit_msg>Updated gfx_cube example<commit_after>#![feature(plugin, custom_attribute)]
#![plugin(gfx_macros)]

extern crate piston;
extern crate vecmath;
extern crate camera_controllers;
extern crate gfx;
extern crate gfx_device_gl;
extern crate sdl2_window;

use std::rc::Rc;
use std::cell::RefCell;
use piston::quack::Set;
use piston::window::{ WindowSettings, CaptureCursor };
use camera_controllers::{
    FirstPersonSettings,
    FirstPerson,
    CameraPerspective,
    model_view_projection
};
use gfx::traits::*;
use sdl2_window::{ Sdl2Window, OpenGL };

//----------------------------------------
// Cube associated data

#[vertex_format]
#[derive(Copy)]
struct Vertex {
    #[as_float]
    a_pos: [i8; 3],
    #[as_float]
    a_tex_coord: [u8; 2],
}

impl Vertex {
    fn new(pos: [i8; 3], tc: [u8; 2]) -> Vertex {
        Vertex {
            a_pos: pos,
            a_tex_coord: tc,
        }
    }
}

#[shader_param]
struct Params<R: gfx::Resources> {
    u_model_view_proj: [[f32; 4]; 4],
    t_color: gfx::shade::TextureParam<R>,
}

const VERTEX_SRC: [&'static [u8]; 2] = [ b"
    #version 120
    attribute vec3 a_pos;
    attribute vec2 a_tex_coord;
    varying vec2 v_TexCoord;
    uniform mat4 u_model_view_proj;
    void main() {
        v_TexCoord = a_tex_coord;
        gl_Position = u_model_view_proj * vec4(a_pos, 1.0);
    }
", b"
    #version 150 core
    in vec3 a_pos;
    in vec2 a_tex_coord;
    out vec2 v_TexCoord;
    uniform mat4 u_model_view_proj;
    void main() {
        v_TexCoord = a_tex_coord;
        gl_Position = u_model_view_proj * vec4(a_pos, 1.0);
    }
"];

const FRAGMENT_SRC: [&'static [u8]; 2] = [ b"
    #version 120
    varying vec2 v_TexCoord;
    uniform sampler2D t_color;
    void main() {
        vec4 tex = texture2D(t_color, v_TexCoord);
        float blend = dot(v_TexCoord-vec2(0.5,0.5), v_TexCoord-vec2(0.5,0.5));
        gl_FragColor = mix(tex, vec4(0.0,0.0,0.0,0.0), blend*1.0);
    }
", b"
    #version 150 core
    in vec2 v_TexCoord;
    out vec4 o_Color;
    uniform sampler2D t_color;
    void main() {
        vec4 tex = texture(t_color, v_TexCoord);
        float blend = dot(v_TexCoord-vec2(0.5,0.5), v_TexCoord-vec2(0.5,0.5));
        o_Color = mix(tex, vec4(0.0,0.0,0.0,0.0), blend*1.0);
    }
"];

//----------------------------------------

fn main() {
    let (win_width, win_height) = (640, 480);
    let mut window = Sdl2Window::new(
        OpenGL::_3_2,
        WindowSettings {
            title: "piston-example-gfx_cube".to_string(),
            size: [win_width, win_height],
            fullscreen: false,
            exit_on_esc: true,
            samples: 4,
        }
    );

    window.set_mut(CaptureCursor(true));

    let vertex = gfx::ShaderSource {
        glsl_120: Some(VERTEX_SRC[0]),
        glsl_150: Some(VERTEX_SRC[1]),
        .. gfx::ShaderSource::empty()
    };
    let fragment = gfx::ShaderSource {
        glsl_120: Some(FRAGMENT_SRC[0]),
        glsl_150: Some(FRAGMENT_SRC[1]),
        .. gfx::ShaderSource::empty()
    };

    let mut device = gfx_device_gl::GlDevice::new(Sdl2Window::get_proc_address);
    let frame = gfx::Frame::new(win_width as u16, win_height as u16);
    let state = gfx::DrawState::new().depth(gfx::state::Comparison::LessEqual, true);

    let vertex_data = vec![
        //top (0, 0, 1)
        Vertex::new([-1, -1,  1], [0, 0]),
        Vertex::new([ 1, -1,  1], [1, 0]),
        Vertex::new([ 1,  1,  1], [1, 1]),
        Vertex::new([-1,  1,  1], [0, 1]),
        //bottom (0, 0, -1)
        Vertex::new([ 1,  1, -1], [0, 0]),
        Vertex::new([-1,  1, -1], [1, 0]),
        Vertex::new([-1, -1, -1], [1, 1]),
        Vertex::new([ 1, -1, -1], [0, 1]),
        //right (1, 0, 0)
        Vertex::new([ 1, -1, -1], [0, 0]),
        Vertex::new([ 1,  1, -1], [1, 0]),
        Vertex::new([ 1,  1,  1], [1, 1]),
        Vertex::new([ 1, -1,  1], [0, 1]),
        //left (-1, 0, 0)
        Vertex::new([-1,  1,  1], [0, 0]),
        Vertex::new([-1, -1,  1], [1, 0]),
        Vertex::new([-1, -1, -1], [1, 1]),
        Vertex::new([-1,  1, -1], [0, 1]),
        //front (0, 1, 0)
        Vertex::new([-1,  1, -1], [0, 0]),
        Vertex::new([ 1,  1, -1], [1, 0]),
        Vertex::new([ 1,  1,  1], [1, 1]),
        Vertex::new([-1,  1,  1], [0, 1]),
        //back (0, -1, 0)
        Vertex::new([ 1, -1,  1], [0, 0]),
        Vertex::new([-1, -1,  1], [1, 0]),
        Vertex::new([-1, -1, -1], [1, 1]),
        Vertex::new([ 1, -1, -1], [0, 1]),
    ];

    let mesh = device.create_mesh(&vertex_data);

    let index_data: &[u8] = &[
         0,  1,  2,  2,  3,  0, // top
         4,  6,  5,  6,  4,  7, // bottom
         8,  9, 10, 10, 11,  8, // right
        12, 14, 13, 14, 12, 16, // left
        16, 18, 17, 18, 16, 19, // front
        20, 21, 22, 22, 23, 20, // back
    ];

    let slice = device.create_buffer_index(index_data)
                      .to_slice(gfx::PrimitiveType::TriangleList);

    let tinfo = gfx::tex::TextureInfo {
        width: 1,
        height: 1,
        depth: 1,
        levels: 1,
        kind: gfx::tex::TextureKind::Texture2D,
        format: gfx::tex::RGBA8,
    };
    let img_info = tinfo.to_image_info();
    let texture = device.create_texture(tinfo).unwrap();
    device.update_texture(
        &texture,
        &img_info,
        &[0x20u8, 0xA0, 0xC0, 0x00]
    ).unwrap();

    let sampler = device.create_sampler(
        gfx::tex::SamplerInfo::new(
            gfx::tex::FilterMethod::Bilinear,
            gfx::tex::WrapMode::Clamp
        )
    );

    let shader_model = device.get_capabilities().shader_model;

    let program = device.link_program(
        vertex.choose(shader_model).unwrap(),
        fragment.choose(shader_model).unwrap()
    ).unwrap();

    let mut graphics = device.into_graphics();

    let data = Params {
        u_model_view_proj: vecmath::mat4_id(),
        t_color: (texture, Some(sampler)),
    };

    let mut batch = graphics.make_batch(&program, data, &mesh, slice, &state).unwrap();

    let model = vecmath::mat4_id();
    let projection = CameraPerspective {
        fov: 90.0,
        near_clip: 0.1,
        far_clip: 1000.0,
        aspect_ratio: (win_width as f32) / (win_height as f32)
    }.projection();
    let mut first_person = FirstPerson::new(
        [0.5, 0.5, 4.0],
        FirstPersonSettings::keyboard_wasd()
    );

    let window = Rc::new(RefCell::new(window));
    for e in piston::events(window) {
        use piston::event::*;

        first_person.event(&e);

        if let Some(args) = e.render_args() {
            graphics.clear(
                gfx::ClearData {
                    color: [0.3, 0.3, 0.3, 1.0],
                    depth: 1.0,
                    stencil: 0,
                },
                gfx::COLOR | gfx::DEPTH,
                &frame
            );
            batch.params.u_model_view_proj = model_view_projection(
                model,
                first_person.camera(args.ext_dt).orthogonal(),
                projection
            );
            graphics.draw(&batch, &frame).unwrap();
            graphics.end_frame();
        }

        if let Some(_) = e.after_render_args() {
            graphics.device.after_frame();
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;

extern crate futures;
extern crate grpc;

mod test_misc;

use grpc::*;
use grpc::rt::*;

use test_misc::*;

fn echo_fn(_: RequestOptions, req: String) -> SingleResponse<String> {
    SingleResponse::completed(req)
}

fn reverse_fn(_: RequestOptions, req: String) -> SingleResponse<String> {
    SingleResponse::completed(req.chars().rev().collect())
}

#[test]
fn multiple_services() {
    let mut server = ServerBuilder::new_plain();
    server.http.set_port(0);

    let echo = string_string_method("/foo/echo", GrpcStreaming::Unary);
    let reverse = string_string_method("/bar/reverse", GrpcStreaming::Unary);

    server.add_service(ServerServiceDefinition::new("/foo", vec![
        ServerMethod::new(
            echo.clone(),
            MethodHandlerUnary::new(echo_fn))
    ]));

    server.add_service(ServerServiceDefinition::new("/bar", vec![
        ServerMethod::new(
            reverse.clone(),
            MethodHandlerUnary::new(reverse_fn))
    ]));

    let server = server.build().expect("server");

    let port = server.local_addr().port().expect("port");

    let client = Client::new_plain("::1", port, ClientConf::new())
        .expect("client");

    assert_eq!(
        "abc".to_owned(),
        client.call_unary(
            RequestOptions::new(), "abc".to_owned(), echo).wait_drop_metadata().unwrap());

    assert_eq!(
        "zyx".to_owned(),
        client.call_unary(
            RequestOptions::new(), "xyz".to_owned(), reverse).wait_drop_metadata().unwrap());
}
<commit_msg>With logger<commit_after>#[macro_use]
extern crate log;
extern crate env_logger;

extern crate futures;
extern crate grpc;

mod test_misc;

use grpc::*;
use grpc::rt::*;

use test_misc::*;

fn echo_fn(_: RequestOptions, req: String) -> SingleResponse<String> {
    SingleResponse::completed(req)
}

fn reverse_fn(_: RequestOptions, req: String) -> SingleResponse<String> {
    SingleResponse::completed(req.chars().rev().collect())
}

#[test]
fn multiple_services() {
    drop(env_logger::try_init());

    let mut server = ServerBuilder::new_plain();
    server.http.set_port(0);

    let echo = string_string_method("/foo/echo", GrpcStreaming::Unary);
    let reverse = string_string_method("/bar/reverse", GrpcStreaming::Unary);

    server.add_service(ServerServiceDefinition::new("/foo", vec![
        ServerMethod::new(
            echo.clone(),
            MethodHandlerUnary::new(echo_fn))
    ]));

    server.add_service(ServerServiceDefinition::new("/bar", vec![
        ServerMethod::new(
            reverse.clone(),
            MethodHandlerUnary::new(reverse_fn))
    ]));

    let server = server.build().expect("server");

    let port = server.local_addr().port().expect("port");

    let client = Client::new_plain("::1", port, ClientConf::new())
        .expect("client");

    assert_eq!(
        "abc".to_owned(),
        client.call_unary(
            RequestOptions::new(), "abc".to_owned(), echo).wait_drop_metadata().unwrap());

    assert_eq!(
        "zyx".to_owned(),
        client.call_unary(
            RequestOptions::new(), "xyz".to_owned(), reverse).wait_drop_metadata().unwrap());
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{BufRead, BufReader, BufWriter, Write};
use std::path::{Path, PathBuf};

use atty::Stream;
use grep::matcher::{Captures, Matcher};
use grep::regex::{RegexMatcher, RegexMatcherBuilder};
use grep::searcher::{
    BinaryDetection, Searcher, SearcherBuilder, Sink, SinkContext, SinkContextKind, SinkMatch,
};
use ignore::WalkBuilder;
use structopt::StructOpt;
use text_io::read;

#[derive(Debug, StructOpt)]
#[structopt(name = "fnr")]
/// Look for things, optionally replace them.
struct Opts {
    /// Run case insensitive search
    #[structopt(short = "i", long)]
    ignore_case: bool,

    /// Modify files in place.
    #[structopt(short, long)]
    write: bool,

    /// Confirm each modification before making it.
    #[structopt(short, long)]
    prompt: bool,

    /// Print lines after matches.
    #[structopt(short = "A", long)]
    after: Option<usize>,

    /// Print lines before matches.
    #[structopt(short = "B", long)]
    before: Option<usize>,

    /// Print lines before and after matches.
    #[structopt(short = "C", long)]
    context: Option<usize>,

    /// What to search for.
    #[structopt(name = "FIND")]
    find: String,

    /// What to replace it with.
    #[structopt(name = "REPLACE")]
    replace: String,

    /// Locations to search. Current directory if not specified.
    #[structopt(name = "PATH", parse(from_os_str))]
    paths: Vec<PathBuf>,
}

#[derive(Debug, Clone)]
struct Line(u64, String);

#[derive(Debug)]
struct SearchMatch {
    line: Line,
    context_pre: Vec<Line>,
    context_post: Vec<Line>,
}

impl SearchMatch {
    fn as_change(&self, line: String) -> Change {
        return Change {
            line_number: self.line.0,
            new_line: line,
        };
    }

    fn display_change(&self, replacement_line: &str) {
        for line in &self.context_pre {
            print!("    {}: {}", line.0, line.1);
        }

        // TODO: Multiple matches on same line
        // TODO: Disable colors when not atty
        // TODO: Align line number with padding.
        print!("\x1B[31m-   {}: {}\x1B[0m", self.line.0, self.line.1);
        print!("\x1B[32m+   {}: {}\x1B[0m", self.line.0, replacement_line);

        for line in &self.context_post {
            print!("    {}: {}", line.0, line.1);
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
enum MatchState {
    Init,
    Before,
    Match,
    After,
}

#[derive(Debug)]
struct SearchMatchCollector {
    state: MatchState,

    cur_context_pre: Vec<Line>,
    cur_context_post: Vec<Line>,
    cur_match_line: Option<Line>,

    matches: Vec<SearchMatch>,
}

impl SearchMatchCollector {
    fn new() -> SearchMatchCollector {
        return SearchMatchCollector {
            state: MatchState::Init,
            cur_match_line: None,
            cur_context_pre: Vec::new(),
            cur_context_post: Vec::new(),
            matches: Vec::new(),
        };
    }

    fn maybe_emit(&mut self) {
        if let Some(line) = &self.cur_match_line {
            // TODO: clones are wasteful here.
            let m = SearchMatch {
                line: line.clone(),
                context_pre: self.cur_context_pre.clone(),
                context_post: self.cur_context_post.clone(),
            };

            self.matches.push(m);
            self.reset();
        }
    }

    fn reset(&mut self) {
        self.state = MatchState::Init;

        self.cur_match_line = None;
        self.cur_context_pre.clear();
        self.cur_context_post.clear();
    }

    #[inline]
    fn transition(&mut self, next: MatchState) {
        match (self.state, next) {
            // Beginning a new match or ending a previous one
            (MatchState::Match, MatchState::Before)       // Have before context, no after context
            | (MatchState::Match, MatchState::Match)      // No before context, no after context
            | (MatchState::After, MatchState::Before)     // Have before context, have after context
            | (MatchState::After, MatchState::Match) => { // Have after context, no before context
                self.maybe_emit();
            }

            (_prev, next) => {
                self.state = next;
            }
        }
    }

    fn collect(&mut self) -> &Vec<SearchMatch> {
        self.maybe_emit();
        return &self.matches;
    }
}

impl Drop for SearchMatchCollector {
    fn drop(&mut self) {
        self.maybe_emit();
    }
}

impl Sink for SearchMatchCollector {
    type Error = std::io::Error;

    fn matched(
        &mut self,
        _searcher: &Searcher,
        mat: &SinkMatch<'_>,
    ) -> Result<bool, std::io::Error> {
        self.transition(MatchState::Match);

        // TODO: handle errors
        let line = Line(
            mat.line_number().expect("grab line number"),
            String::from_utf8_lossy(mat.bytes()).to_string(),
        );

        self.cur_match_line = Some(line);

        Ok(true)
    }

    fn context(
        &mut self,
        _searcher: &Searcher,
        ctx: &SinkContext<'_>,
    ) -> Result<bool, std::io::Error> {
        // TODO: handle errors.
        // TODO: can we avoid the additional .to_string() by storing a COW instead?
        let line = Line(
            ctx.line_number().expect("grab line number"),
            String::from_utf8_lossy(ctx.bytes()).to_string(),
        );

        match ctx.kind() {
            &SinkContextKind::Before => {
                self.transition(MatchState::Before);
                self.cur_context_pre.push(line);
            }
            &SinkContextKind::After => {
                self.transition(MatchState::After);
                self.cur_context_post.push(line);
            }
            &SinkContextKind::Other => {}
        }

        Ok(true)
    }
}

trait Replacer {
    fn replace(&self, input: &str) -> Option<String>;
}

struct RegexReplacer<'a> {
    matcher: &'a RegexMatcher,
    template: &'a str,
}

impl<'a> Replacer for RegexReplacer<'a> {
    fn replace(&self, input: &str) -> Option<String> {
        let mut caps = self.matcher.new_captures().unwrap();
        let mut dst = vec![];

        self.matcher
            .replace_with_captures(input.as_bytes(), &mut caps, &mut dst, |caps, dst| {
                caps.interpolate(
                    |name| self.matcher.capture_index(name),
                    input.as_bytes(),
                    self.template.as_bytes(),
                    dst,
                );
                true
            })
            .unwrap();

        Some(String::from_utf8_lossy(&dst).to_string())
    }
}

#[derive(Debug)]
struct Change {
    line_number: u64,
    // TODO: use slice here
    new_line: String,
}

struct SearchMatchProcessor<'a> {
    replacer: &'a dyn Replacer,
    replacement_decider: ReplacementDecider,

    total_matches: usize,
    total_replacements: usize,
}

impl<'a> SearchMatchProcessor<'a> {
    fn new(
        replacer: &'a dyn Replacer,
        replacement_decider: ReplacementDecider,
    ) -> SearchMatchProcessor<'a> {
        return SearchMatchProcessor {
            replacer,
            replacement_decider,

            total_matches: 0,
            total_replacements: 0,
        };
    }

    fn handle_path(
        &mut self,
        path: &Path,
        matches: &Vec<SearchMatch>,
    ) -> Result<(), std::io::Error> {
        if matches.is_empty() {
            return Ok(());
        }
        println!(
            "--- {}: {} matching line{}",
            path.display(),
            matches.len(),
            if matches.len() == 1 { "" } else { "s" }
        );
        self.total_matches += matches.len();
        self.replacement_decider.reset_local_decision();

        let mut change_list = vec![];
        for m in matches {
            let replacement = if let Some(r) = self.replacer.replace(&m.line.1) {
                r
            } else {
                println!("TODO: replacer failed on line");
                continue;
            };

            let decision = self.replacement_decider.decide(m, &replacement);
            let change = match decision {
                ReplacementDecision::Accept => m.as_change(replacement),
                ReplacementDecision::Ignore => continue,
                ReplacementDecision::Edit => {
                    let mut line = read_input("Replace with [^D to skip] ")?;
                    if line == "" {
                        println!("... skipped ...");
                        continue;
                    }

                    line.push('\n');
                    m.display_change(&line);
                    println!("--");
                    m.as_change(line)
                }
            };

            change_list.push(change);
            self.total_replacements += 1;
        }

        if !change_list.is_empty() {
            self.apply_changes(path, &mut change_list)?;
        }

        Ok(())
    }

    fn apply_changes(&self, path: &Path, mut changes: &[Change]) -> Result<(), std::io::Error> {
        /*println!(
            "{}: {} change{}",
            path.display(),
            changes.len(),
            if changes.len() != 1 { "s" } else { "" }
        );*/
        let dst_path = path.with_extension("~");
        let src = File::open(path)?;
        let dst = File::create(&dst_path)?;

        let mut reader = BufReader::new(src);
        let mut writer = BufWriter::new(dst);

        let mut line_num = 0;
        loop {
            let mut line = String::new();
            let bytes_read = reader.read_line(&mut line)?;
            // EOF reached
            if bytes_read == 0 {
                break;
            }

            line_num += 1;

            if !changes.is_empty() && changes[0].line_number == line_num {
                writer.write(changes[0].new_line.as_bytes())?;
                changes = &changes[1..];
            } else {
                writer.write(line.as_bytes())?;
            }
        }

        std::fs::rename(dst_path, path)?;
        return Ok(());
    }

    fn finalize(&self) {
        println!(
            "All done. Replaced {} of {} matches",
            self.total_replacements, self.total_matches
        );
    }
}

#[derive(Debug, Copy, Clone)]
enum ReplacementDecision {
    Accept,
    Ignore,
    Edit,
}

fn read_input(prompt: &str) -> Result<String, std::io::Error> {
    print!("{}", prompt);
    std::io::stdout().flush()?;

    Ok(read!("{}\n"))
}

struct ReplacementDecider {
    should_prompt: bool,
    global_decision: Option<ReplacementDecision>,
    local_decision: Option<ReplacementDecision>,
}

impl ReplacementDecider {
    fn with_prompt() -> ReplacementDecider {
        return ReplacementDecider {
            should_prompt: true,
            global_decision: None,
            local_decision: None,
        };
    }

    fn constantly(decision: ReplacementDecision) -> ReplacementDecider {
        return ReplacementDecider {
            should_prompt: false,
            global_decision: Some(decision),
            local_decision: None,
        };
    }

    fn reset_local_decision(&mut self) {
        self.local_decision = None;
    }

    fn decide(&mut self, match_: &SearchMatch, replacement: &str) -> ReplacementDecision {
        // TODO: Should we display this always?
        match_.display_change(replacement);

        if let Some(decision) = self.global_decision {
            return decision;
        } else if let Some(decision) = self.local_decision {
            return decision;
        }

        if !self.should_prompt {
            panic!("invalid state: no decision, but should not prompt");
        }

        return self.prompt_for_decision();
    }

    fn prompt_for_decision(&mut self) -> ReplacementDecision {
        loop {
            let line = read_input("Stage this replacement [y,n,q,a,e,d,?] ").unwrap();

            return match line.as_str() {
                "y" => ReplacementDecision::Accept,
                "n" => ReplacementDecision::Ignore,
                "q" => {
                    self.global_decision = Some(ReplacementDecision::Ignore);
                    ReplacementDecision::Ignore
                }
                "a" => {
                    self.local_decision = Some(ReplacementDecision::Accept);
                    ReplacementDecision::Accept
                }
                "d" => {
                    self.local_decision = Some(ReplacementDecision::Ignore);
                    ReplacementDecision::Ignore
                }
                "e" => ReplacementDecision::Edit,

                "?" | _ => {
                    println!(
                        "\x1B[31m
Y - replace this line
n - do not replace this line
q - quit; do not replace this line or any remaining ones
a - replace this line and all remaining ones in this file
d - do not replace this line nor any remaining ones in this file
e - edit this replacement
? - show help
\x1B[0m"
                    );
                    continue;
                }
            };
        }
    }
}

fn main() {
    let opts: Opts = Opts::from_args();
    println!("Parsed opts: {:?}", opts);

    let matcher = RegexMatcherBuilder::new()
        .case_insensitive(opts.ignore_case)
        .build(&opts.find)
        .expect("bad pattern");

    let mut searcher = SearcherBuilder::new()
        .binary_detection(BinaryDetection::quit(0x00))
        .line_number(true)
        .before_context(opts.before.or(opts.context).unwrap_or(2))
        .after_context(opts.after.or(opts.context).unwrap_or(2))
        .build();

    // TODO: Confirm that template does not reference more capture groups than exist.
    let replacer = RegexReplacer {
        matcher: &matcher,
        template: &opts.replace,
    };

    if opts.write && opts.prompt {
        eprintln!("both --write and --prompt given, ignore --write.");
    }

    let replacement_decider = if opts.prompt {
        ReplacementDecider::with_prompt()
    } else if opts.write {
        ReplacementDecider::constantly(ReplacementDecision::Accept)
    } else {
        ReplacementDecider::constantly(ReplacementDecision::Ignore)
    };

    let mut proc = SearchMatchProcessor::new(&replacer, replacement_decider);

    let paths = if opts.paths.is_empty() {
        if !atty::is(Stream::Stdin) {
            if opts.prompt {
                panic!("Cannot use --prompt when reading files from stdin!");
            }
            let mut paths = vec![];
            for line in std::io::stdin().lock().lines() {
                paths.push(Path::new(&line.unwrap()).to_owned());
            }
            paths
        } else {
            vec![Path::new(".").to_owned()]
        }
    } else {
        opts.paths
    };

    // TODO: Add path exclusions
    let mut file_walker = WalkBuilder::new(paths[0].clone());
    for path in &paths[1..] {
        file_walker.add(path);
    }

    // TODO: These settings can be given by command line args.
    file_walker
        .ignore(true)
        .git_ignore(true)
        .git_exclude(true)
        .parents(true);

    // TODO: There exists a parallel file walker
    for dir_entry in file_walker.build() {
        let dir_entry = dir_entry.unwrap();
        let path = dir_entry.path();
        if !path.is_file() {
            continue;
        }

        let mut sink = SearchMatchCollector::new();

        searcher
            .search_path(&matcher, dir_entry.path(), &mut sink)
            .expect("search failed");

        let matches = sink.collect();
        proc.handle_path(path, matches).expect("handle path");
    }

    if !opts.write {
        println!("Use -w, --write to modify files in place.");
    }

    proc.finalize();
}
<commit_msg>Add -S, --smart-case<commit_after>use std::fs::File;
use std::io::{BufRead, BufReader, BufWriter, Write};
use std::path::{Path, PathBuf};

use atty::Stream;
use grep::matcher::{Captures, Matcher};
use grep::regex::{RegexMatcher, RegexMatcherBuilder};
use grep::searcher::{
    BinaryDetection, Searcher, SearcherBuilder, Sink, SinkContext, SinkContextKind, SinkMatch,
};
use ignore::WalkBuilder;
use structopt::StructOpt;
use text_io::read;

#[derive(Debug, StructOpt)]
#[structopt(name = "fnr")]
/// Look for things, optionally replace them.
struct Opts {
    /// Match case insensitively.
    #[structopt(short = "i", long)]
    ignore_case: bool,

    /// Match case sensitively.
    #[structopt(short = "s", long)]
    case_sensitive: bool,

    /// Use case sensitive match if FIND has uppercase characters,
    /// insensitively otherwise.
    // TODO: This is still a little jank. Prints out as if it needed a
    // value, and messes up arg parsing if it appears first.
    // Option<bool> might be better.
    #[structopt(short = "S", long, parse(try_from_str), default_value = "true")]
    smart_case: bool,

    /// Modify files in place.
    #[structopt(short, long)]
    write: bool,

    /// Confirm each modification before making it.
    #[structopt(short, long)]
    prompt: bool,

    /// Print lines after matches.
    #[structopt(short = "A", long)]
    after: Option<usize>,

    /// Print lines before matches.
    #[structopt(short = "B", long)]
    before: Option<usize>,

    /// Print lines before and after matches.
    #[structopt(short = "C", long)]
    context: Option<usize>,

    /// What to search for.
    #[structopt(name = "FIND")]
    find: String,

    /// What to replace it with.
    #[structopt(name = "REPLACE")]
    replace: String,

    /// Locations to search. Current directory if not specified.
    #[structopt(name = "PATH", parse(from_os_str))]
    paths: Vec<PathBuf>,
}

#[derive(Debug, Clone)]
struct Line(u64, String);

#[derive(Debug)]
struct SearchMatch {
    line: Line,
    context_pre: Vec<Line>,
    context_post: Vec<Line>,
}

impl SearchMatch {
    fn as_change(&self, line: String) -> Change {
        return Change {
            line_number: self.line.0,
            new_line: line,
        };
    }

    fn display_change(&self, replacement_line: &str) {
        for line in &self.context_pre {
            print!("    {}: {}", line.0, line.1);
        }

        // TODO: Multiple matches on same line
        // TODO: Disable colors when not atty
        // TODO: Align line number with padding.
        print!("\x1B[31m-   {}: {}\x1B[0m", self.line.0, self.line.1);
        print!("\x1B[32m+   {}: {}\x1B[0m", self.line.0, replacement_line);

        for line in &self.context_post {
            print!("    {}: {}", line.0, line.1);
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
enum MatchState {
    Init,
    Before,
    Match,
    After,
}

#[derive(Debug)]
struct SearchMatchCollector {
    state: MatchState,

    cur_context_pre: Vec<Line>,
    cur_context_post: Vec<Line>,
    cur_match_line: Option<Line>,

    matches: Vec<SearchMatch>,
}

impl SearchMatchCollector {
    fn new() -> SearchMatchCollector {
        return SearchMatchCollector {
            state: MatchState::Init,
            cur_match_line: None,
            cur_context_pre: Vec::new(),
            cur_context_post: Vec::new(),
            matches: Vec::new(),
        };
    }

    fn maybe_emit(&mut self) {
        if let Some(line) = &self.cur_match_line {
            // TODO: clones are wasteful here.
            let m = SearchMatch {
                line: line.clone(),
                context_pre: self.cur_context_pre.clone(),
                context_post: self.cur_context_post.clone(),
            };

            self.matches.push(m);
            self.reset();
        }
    }

    fn reset(&mut self) {
        self.state = MatchState::Init;

        self.cur_match_line = None;
        self.cur_context_pre.clear();
        self.cur_context_post.clear();
    }

    #[inline]
    fn transition(&mut self, next: MatchState) {
        match (self.state, next) {
            // Beginning a new match or ending a previous one
            (MatchState::Match, MatchState::Before)       // Have before context, no after context
            | (MatchState::Match, MatchState::Match)      // No before context, no after context
            | (MatchState::After, MatchState::Before)     // Have before context, have after context
            | (MatchState::After, MatchState::Match) => { // Have after context, no before context
                self.maybe_emit();
            }

            (_prev, next) => {
                self.state = next;
            }
        }
    }

    fn collect(&mut self) -> &Vec<SearchMatch> {
        self.maybe_emit();
        return &self.matches;
    }
}

impl Drop for SearchMatchCollector {
    fn drop(&mut self) {
        self.maybe_emit();
    }
}

impl Sink for SearchMatchCollector {
    type Error = std::io::Error;

    fn matched(
        &mut self,
        _searcher: &Searcher,
        mat: &SinkMatch<'_>,
    ) -> Result<bool, std::io::Error> {
        self.transition(MatchState::Match);

        // TODO: handle errors
        let line = Line(
            mat.line_number().expect("grab line number"),
            String::from_utf8_lossy(mat.bytes()).to_string(),
        );

        self.cur_match_line = Some(line);

        Ok(true)
    }

    fn context(
        &mut self,
        _searcher: &Searcher,
        ctx: &SinkContext<'_>,
    ) -> Result<bool, std::io::Error> {
        // TODO: handle errors.
        // TODO: can we avoid the additional .to_string() by storing a COW instead?
        let line = Line(
            ctx.line_number().expect("grab line number"),
            String::from_utf8_lossy(ctx.bytes()).to_string(),
        );

        match ctx.kind() {
            &SinkContextKind::Before => {
                self.transition(MatchState::Before);
                self.cur_context_pre.push(line);
            }
            &SinkContextKind::After => {
                self.transition(MatchState::After);
                self.cur_context_post.push(line);
            }
            &SinkContextKind::Other => {}
        }

        Ok(true)
    }
}

trait Replacer {
    fn replace(&self, input: &str) -> Option<String>;
}

struct RegexReplacer<'a> {
    matcher: &'a RegexMatcher,
    template: &'a str,
}

impl<'a> Replacer for RegexReplacer<'a> {
    fn replace(&self, input: &str) -> Option<String> {
        let mut caps = self.matcher.new_captures().unwrap();
        let mut dst = vec![];

        self.matcher
            .replace_with_captures(input.as_bytes(), &mut caps, &mut dst, |caps, dst| {
                caps.interpolate(
                    |name| self.matcher.capture_index(name),
                    input.as_bytes(),
                    self.template.as_bytes(),
                    dst,
                );
                true
            })
            .unwrap();

        Some(String::from_utf8_lossy(&dst).to_string())
    }
}

#[derive(Debug)]
struct Change {
    line_number: u64,
    // TODO: use slice here
    new_line: String,
}

struct SearchMatchProcessor<'a> {
    replacer: &'a dyn Replacer,
    replacement_decider: ReplacementDecider,

    total_matches: usize,
    total_replacements: usize,
}

impl<'a> SearchMatchProcessor<'a> {
    fn new(
        replacer: &'a dyn Replacer,
        replacement_decider: ReplacementDecider,
    ) -> SearchMatchProcessor<'a> {
        return SearchMatchProcessor {
            replacer,
            replacement_decider,

            total_matches: 0,
            total_replacements: 0,
        };
    }

    fn handle_path(
        &mut self,
        path: &Path,
        matches: &Vec<SearchMatch>,
    ) -> Result<(), std::io::Error> {
        if matches.is_empty() {
            return Ok(());
        }
        println!(
            "--- {}: {} matching line{}",
            path.display(),
            matches.len(),
            if matches.len() == 1 { "" } else { "s" }
        );
        self.total_matches += matches.len();
        self.replacement_decider.reset_local_decision();

        let mut change_list = vec![];
        for m in matches {
            let replacement = if let Some(r) = self.replacer.replace(&m.line.1) {
                r
            } else {
                println!("TODO: replacer failed on line");
                continue;
            };

            let decision = self.replacement_decider.decide(m, &replacement);
            let change = match decision {
                ReplacementDecision::Accept => m.as_change(replacement),
                ReplacementDecision::Ignore => continue,
                ReplacementDecision::Edit => {
                    let mut line = read_input("Replace with [^D to skip] ")?;
                    if line == "" {
                        println!("... skipped ...");
                        continue;
                    }

                    line.push('\n');
                    m.display_change(&line);
                    println!("--");
                    m.as_change(line)
                }
            };

            change_list.push(change);
            self.total_replacements += 1;
        }

        if !change_list.is_empty() {
            self.apply_changes(path, &mut change_list)?;
        }

        Ok(())
    }

    fn apply_changes(&self, path: &Path, mut changes: &[Change]) -> Result<(), std::io::Error> {
        /*println!(
            "{}: {} change{}",
            path.display(),
            changes.len(),
            if changes.len() != 1 { "s" } else { "" }
        );*/
        let dst_path = path.with_extension("~");
        let src = File::open(path)?;
        let dst = File::create(&dst_path)?;

        let mut reader = BufReader::new(src);
        let mut writer = BufWriter::new(dst);

        let mut line_num = 0;
        loop {
            let mut line = String::new();
            let bytes_read = reader.read_line(&mut line)?;
            // EOF reached
            if bytes_read == 0 {
                break;
            }

            line_num += 1;

            if !changes.is_empty() && changes[0].line_number == line_num {
                writer.write(changes[0].new_line.as_bytes())?;
                changes = &changes[1..];
            } else {
                writer.write(line.as_bytes())?;
            }
        }

        std::fs::rename(dst_path, path)?;
        return Ok(());
    }

    fn finalize(&self) {
        println!(
            "All done. Replaced {} of {} matches",
            self.total_replacements, self.total_matches
        );
    }
}

#[derive(Debug, Copy, Clone)]
enum ReplacementDecision {
    Accept,
    Ignore,
    Edit,
}

fn read_input(prompt: &str) -> Result<String, std::io::Error> {
    print!("{}", prompt);
    std::io::stdout().flush()?;

    Ok(read!("{}\n"))
}

struct ReplacementDecider {
    should_prompt: bool,
    global_decision: Option<ReplacementDecision>,
    local_decision: Option<ReplacementDecision>,
}

impl ReplacementDecider {
    fn with_prompt() -> ReplacementDecider {
        return ReplacementDecider {
            should_prompt: true,
            global_decision: None,
            local_decision: None,
        };
    }

    fn constantly(decision: ReplacementDecision) -> ReplacementDecider {
        return ReplacementDecider {
            should_prompt: false,
            global_decision: Some(decision),
            local_decision: None,
        };
    }

    fn reset_local_decision(&mut self) {
        self.local_decision = None;
    }

    fn decide(&mut self, match_: &SearchMatch, replacement: &str) -> ReplacementDecision {
        // TODO: Should we display this always?
        match_.display_change(replacement);

        if let Some(decision) = self.global_decision {
            return decision;
        } else if let Some(decision) = self.local_decision {
            return decision;
        }

        if !self.should_prompt {
            panic!("invalid state: no decision, but should not prompt");
        }

        return self.prompt_for_decision();
    }

    fn prompt_for_decision(&mut self) -> ReplacementDecision {
        loop {
            let line = read_input("Stage this replacement [y,n,q,a,e,d,?] ").unwrap();

            return match line.as_str() {
                "y" => ReplacementDecision::Accept,
                "n" => ReplacementDecision::Ignore,
                "q" => {
                    self.global_decision = Some(ReplacementDecision::Ignore);
                    ReplacementDecision::Ignore
                }
                "a" => {
                    self.local_decision = Some(ReplacementDecision::Accept);
                    ReplacementDecision::Accept
                }
                "d" => {
                    self.local_decision = Some(ReplacementDecision::Ignore);
                    ReplacementDecision::Ignore
                }
                "e" => ReplacementDecision::Edit,

                "?" | _ => {
                    println!(
                        "\x1B[31m
Y - replace this line
n - do not replace this line
q - quit; do not replace this line or any remaining ones
a - replace this line and all remaining ones in this file
d - do not replace this line nor any remaining ones in this file
e - edit this replacement
? - show help
\x1B[0m"
                    );
                    continue;
                }
            };
        }
    }
}

fn main() {
    let opts: Opts = Opts::from_args();
    println!("Parsed opts: {:?}", opts);

    let matcher = RegexMatcherBuilder::new()
        .case_insensitive(!opts.case_sensitive && opts.ignore_case)
        .case_smart(!opts.case_sensitive && opts.smart_case)
        .build(&opts.find)
        .expect("bad pattern");

    let mut searcher = SearcherBuilder::new()
        .binary_detection(BinaryDetection::quit(0x00))
        .line_number(true)
        .before_context(opts.before.or(opts.context).unwrap_or(2))
        .after_context(opts.after.or(opts.context).unwrap_or(2))
        .build();

    // TODO: Confirm that template does not reference more capture groups than exist.
    let replacer = RegexReplacer {
        matcher: &matcher,
        template: &opts.replace,
    };

    if opts.write && opts.prompt {
        eprintln!("both --write and --prompt given, ignore --write.");
    }

    let replacement_decider = if opts.prompt {
        ReplacementDecider::with_prompt()
    } else if opts.write {
        ReplacementDecider::constantly(ReplacementDecision::Accept)
    } else {
        ReplacementDecider::constantly(ReplacementDecision::Ignore)
    };

    let mut proc = SearchMatchProcessor::new(&replacer, replacement_decider);

    let paths = if opts.paths.is_empty() {
        if !atty::is(Stream::Stdin) {
            if opts.prompt {
                panic!("Cannot use --prompt when reading files from stdin!");
            }
            let mut paths = vec![];
            for line in std::io::stdin().lock().lines() {
                paths.push(Path::new(&line.unwrap()).to_owned());
            }
            paths
        } else {
            vec![Path::new(".").to_owned()]
        }
    } else {
        opts.paths
    };

    // TODO: Add path exclusions
    let mut file_walker = WalkBuilder::new(paths[0].clone());
    for path in &paths[1..] {
        file_walker.add(path);
    }

    // TODO: These settings can be given by command line args.
    file_walker
        .ignore(true)
        .git_ignore(true)
        .git_exclude(true)
        .parents(true);

    // TODO: There exists a parallel file walker
    for dir_entry in file_walker.build() {
        let dir_entry = dir_entry.unwrap();
        let path = dir_entry.path();
        if !path.is_file() {
            continue;
        }

        let mut sink = SearchMatchCollector::new();

        searcher
            .search_path(&matcher, dir_entry.path(), &mut sink)
            .expect("search failed");

        let matches = sink.collect();
        proc.handle_path(path, matches).expect("handle path");
    }

    if !opts.write {
        println!("Use -w, --write to modify files in place.");
    }

    proc.finalize();
}
<|endoftext|>


<commit_before>#![cfg(test)]

extern crate protobuf;

extern crate protobuf_test_common;

#[cfg(feature = "with-bytes")]
extern crate bytes;

mod v2;

// `cfg(proto3)` is emitted by `build.rs`

#[cfg(proto3)]
mod v3;

mod common;

#[cfg(proto3)]
mod google;

mod interop;

mod include_generated;
<commit_msg>Enable accidentally deleted v3 tests<commit_after>#![cfg(test)]

extern crate protobuf;

extern crate protobuf_test_common;

#[cfg(feature = "with-bytes")]
extern crate bytes;

mod v2;
mod v3;

mod common;

mod google;

mod interop;

mod include_generated;
<|endoftext|>


<commit_before>extern mod std;

use core::libc::{c_char, c_int, c_void};
use core::option::{Some, None};
use core::result::{Ok, Err};
use core::either::Either;
use core::result::Result;
use consts::*;

enum Pcre {}
enum PcreExtra {}
struct PcreRes {
    p: *Pcre,
    drop { unsafe { c::free(self.p as *c_void); } }
}

/// The result type of `compile`
pub type CompileResult = Result<Pattern, CompileErr>;

/// The result type of `exec`
pub type ExecResult = Result<Match, ExecErr>;

/// The result type of `search`
pub type SearchResult = Result<Match, RegexErr>;

// The result type of `replace`
pub type ReplaceResult = Result<@~str, RegexErr>;

/// The type that represents compile error
pub struct CompileErr {
    code: int,
    reason: @~str,
    offset: uint,
}

/// The type that represents exec error
pub type ExecErr = int;

/// Either compile or exec error
pub enum RegexErr {
    CompileErr(CompileErr),
    ExecErr(ExecErr),
}

/// Compiled regular expression
pub struct Pattern {
    str: @~str,
    priv pcre_res: @PcreRes,
}

/// Match
pub struct Match {
    subject: @~str,
    pattern: Pattern,
    priv captures: @~[int],
}

#[nolink]
#[abi = "cdecl"]
extern mod c {
    fn free(p: *c_void);
}

extern mod pcre {
    fn pcre_compile2(pattern: *c_char, options: c_int,
                     errorcodeptr: *c_int,
                     errptr: **c_char, erroffset: *c_int,
                     tableptr: *c_char) -> *Pcre;
    fn pcre_exec(code: *Pcre, extra: *PcreExtra,
                 subject: *c_char, length: c_int, startoffset: c_int,
                 options: c_int, ovector: * c_int, ovecsize: c_int) -> c_int;
    fn pcre_fullinfo(code: *Pcre, extra: *PcreExtra,
                     what: c_int, where: *c_void) -> c_int;
    fn pcre_get_stringnumber(code: *Pcre, name: *c_char) -> c_int;
}

pub trait PatternUtil {
    fn info_capture_count(self) -> uint;
    fn info_name_count(self) -> uint;
    fn info_name_entry_size(self) -> uint;
    fn with_name_table(self, blk: &fn(*u8));
    fn group_count(self) -> uint;
    fn group_names(self) -> ~[~str];
}

impl PatternUtil for Pattern {
    fn info_capture_count(self) -> uint {
        let count = -1 as c_int;
        unsafe {
            pcre::pcre_fullinfo(self.pcre_res.p, ptr::null(),
                                PCRE_INFO_CAPTURECOUNT as c_int,
                                ptr::addr_of(&count) as *c_void);
        }
        assert!(count >= 0 as c_int);
        return count as uint;
    }

    fn info_name_count(self) -> uint {
        let count = -1 as c_int;
        unsafe {
            pcre::pcre_fullinfo(self.pcre_res.p, ptr::null(),
                                PCRE_INFO_NAMECOUNT as c_int,
                                ptr::addr_of(&count) as *c_void);
        }
        assert!(count >= 0 as c_int);
        return count as uint;
    }

    fn info_name_entry_size(self) -> uint {
        let size = -1 as c_int;
        unsafe {
            pcre::pcre_fullinfo(self.pcre_res.p, ptr::null(),
                                PCRE_INFO_NAMEENTRYSIZE as c_int,
                                ptr::addr_of(&size) as *c_void);
        }
        assert!(size >= 0 as c_int);
        return size as uint;
    }

    fn with_name_table(self, blk: &fn(*u8)) {
        let table = ptr::null::<u8>();
        unsafe {
            pcre::pcre_fullinfo(self.pcre_res.p, ptr::null(),
                                PCRE_INFO_NAMETABLE as c_int,
                                ptr::addr_of(&table) as *c_void);
        }
        assert!(table != ptr::null::<u8>());
        blk(table);
    }

    fn group_count(self) -> uint {
        return self.info_capture_count();
    }

    fn group_names(self) -> ~[~str] {
        let count = self.info_name_count();
        if count == 0u { return ~[]; }
        let size = self.info_name_entry_size();
        let mut names: ~[~str] = ~[];
        unsafe {
            do self.with_name_table |table| {
                for uint::range(0u, count) |i| {
                    let p = ptr::offset(table, size * i + 2u);
                    let s = str::raw::from_c_str(p as *c_char);
                    vec::push(&mut names, s);
                }
            }
        }
        return names;
    }
}

pub trait PatternLike {
    fn compile(&self, options: int) -> CompileResult;
}

impl PatternLike for &str {
    fn compile(&self, options: int) -> CompileResult {
        compile(*self, options)
    }
}

impl PatternLike for ~str {
    fn compile(&self, options: int) -> CompileResult {
        compile(*self, options)
    }
}

impl PatternLike for @str {
    fn compile(&self, options: int) -> CompileResult {
        compile(*self, options)
    }
}

impl PatternLike for Pattern {
    fn compile(&self, _options: int) -> CompileResult {
        Ok(*self)
    }
}

impl PatternLike for CompileResult {
    fn compile(&self, _options: int) -> CompileResult {
        *self
    }
}

pub trait MatchExtensions {
    fn matched(self) -> ~str;
    fn prematch(self) -> ~str;
    fn postmatch(self) -> ~str;
    fn begin(self) -> uint;
    fn end(self) -> uint;
    fn group(self, i: uint) -> Option<@~str>;
    fn named_group(self, name: &str) -> Option<@~str>;
    fn subgroups(self) -> ~[~str];
    fn subgroups_iter(self, blk: &fn(&str));
    fn group_count(self) -> uint;
    fn group_names(self) -> ~[~str];
}

impl MatchExtensions for Match {
    fn matched(self) -> ~str {
        return str::slice(*self.subject, self.begin(), self.end());
    }

    fn prematch(self) -> ~str {
        return str::slice(*self.subject, 0u, self.begin());
    }

    fn postmatch(self) -> ~str {
        return str::slice(*self.subject ,self.end(),
                          str::char_len(*self.subject));
    }

    fn begin(self) -> uint {
        return self.captures[0] as uint;
    }

    fn end(self) -> uint {
        return self.captures[1] as uint;
    }

    fn group(self, i: uint) -> Option<@~str> {
        if i > self.group_count() {
            return None;
        }
        let i1 = self.captures[i * 2u];
        let i2 = self.captures[i * 2u + 1u];
        if(i1 < 0 || i2 < 0) {
            return None;
        }
        return Some(@str::slice(*self.subject, i1 as uint, i2 as uint));
    }

    fn named_group(self, name: &str) -> Option<@~str> {
        let i =  unsafe {
            str::as_buf(name, |s, _n| {
                pcre::pcre_get_stringnumber(self.pattern.pcre_res.p,
                                            s as *c_char)
            })
        };
        if i <= 0 as c_int { return None; }
        return self.group(i as uint);
    }

    fn subgroups(self) -> ~[~str] {
        let mut v = ~[];
        unsafe {
            vec::reserve(&mut v, self.group_count());
            do self.subgroups_iter |subgroup| {
                vec::push(&mut v, str::from_slice(subgroup));
            }
        }
        return v;
    }

    fn subgroups_iter(self, blk: &fn(&str)) {
        for uint::range(1u, self.group_count() + 1u) |i| {
            match self.group(i) {
              Some(s) => blk(*s),
              None => fail!(),
            }
        }
    }

    fn group_count(self) -> uint {
        return vec::len(*self.captures) / 2u - 1u;
    }

    fn group_names(self) -> ~[~str] {
        return self.pattern.group_names();
    }
}

pub fn compile(pattern: &str, options: int) -> CompileResult {
    if options | COMPILE_OPTIONS != COMPILE_OPTIONS {
        warn!("unrecognized option bit(s) are set");
    }

    let options = options | PCRE_NO_UTF8_CHECK; // str is always valid
    let errcode = 0 as c_int;
    let errreason: *c_char = ptr::null();
    let erroffset = 0 as c_int;
    let p = unsafe {
        str::as_buf(pattern, |pat, _n| {
            pcre::pcre_compile2(pat as *c_char,
                                options as c_int,
                                ptr::addr_of(&errcode),
                                ptr::addr_of(&errreason),
                                ptr::addr_of(&erroffset),
                                ptr::null())
        })
    };
    if p == ptr::null() {
        let reason = unsafe { @str::raw::from_c_str(errreason) };
        return Err(CompileErr {code: errcode as int,
                               reason: reason,
                               offset: erroffset as uint});
    }
    return Ok(Pattern {str: @str::from_slice(pattern),
                       pcre_res: @PcreRes {p: p}});
}

pub fn exec(pattern: Pattern,
            subject: &str, offset: uint,
            options: int) -> ExecResult {

    if (options | EXEC_OPTIONS) != EXEC_OPTIONS {
        warn!("unrecognized option bit(s) are set");
    }

    let options = options | PCRE_NO_UTF8_CHECK; // str is always valid

    let count = (pattern.info_capture_count() + 1u) as c_int;
    let mut ovec = vec::from_elem((count as uint) * 3u, 0u as c_int);

    let ret_code = unsafe {
        str::as_buf(subject, |s, _n| {
            pcre::pcre_exec(pattern.pcre_res.p, ptr::null(),
                            s as *c_char, str::len(subject) as c_int,
                            offset as c_int, options as c_int,
                            vec::raw::to_ptr(ovec) as *c_int,
                            count * (3 as c_int)) as int
        })
    };

    if ret_code < 0 { return Err(ret_code as ExecErr); }

    // Truncate the working space.
    unsafe { vec::raw::set_len(&mut ovec, count as uint * 2u) }

    let mut captures: ~[int] = ~[];
    unsafe { vec::reserve(&mut captures, vec::len(ovec)); }
    for ovec.each |o| {
        unsafe { vec::push(&mut captures, *o as int); }
    }
    assert!(vec::len(captures) % 2u == 0u);

    return Ok(Match {subject: @str::from_slice(subject),
                     pattern: pattern,
                     captures: @captures});
}

pub fn search<T: PatternLike>(pattern: T, subject: &str,
                              options: int)
                              -> SearchResult {
    return search_from(pattern, subject, 0u, options);
}

pub fn search_from<T: PatternLike>(pattern: T, subject: &str,
                                   offset: uint, options: int)
                                   -> SearchResult {
    assert!(offset <= str::len(subject));

    let c_opts = options & COMPILE_OPTIONS;
    let e_opts = options & EXEC_OPTIONS;

    let c = pattern.compile(c_opts);
    match c {
        Ok(pattern) => {
            let e = exec(pattern, subject, offset, e_opts);
            match e {
                Ok(m) => {
                    return Ok(m);
                }
                Err(e_err) => {
                    return Err(ExecErr(e_err));
                }
            }
        }
        Err(c_err) => {
            return Err(CompileErr(c_err));
        }
    }
}

pub fn replace<T: PatternLike + Copy>(pattern: T, subject: &str,
                                      repl: &str, options: int)
                                      -> ReplaceResult {
    return replace_fn_from(pattern, subject,
                           |_m| { str::from_slice(repl) }, 0u, options);
}

pub fn replace_from<T: PatternLike + Copy>(pattern: T, subject: &str,
                                           repl: &str,  offset: uint,
                                           options: int)
                                           -> ReplaceResult {
    return replace_fn_from(pattern, subject,
                           |_m| { str::from_slice(repl) }, offset, options);
}

pub fn replace_fn<T: PatternLike + Copy>(pattern: T, subject: &str,
                                         repl_fn: &fn(Match) -> ~str,
                                         options: int)
                                         -> ReplaceResult {
    return replace_fn_from(pattern, subject, repl_fn, 0u, options);
}

pub fn replace_fn_from<T: PatternLike + Copy>(pattern: T, subject: &str,
                                              repl_fn: &fn(Match) -> ~str,
                                              offset: uint,
                                              options: int)
                                              -> ReplaceResult {
    let r = search_from(pattern, subject, offset, options);
    match r {
        Ok(m) => {
            return Ok(@(m.prematch() + repl_fn(m) + m.postmatch()));
        }
        Err(e) => { return Err(e); }
    }
}

pub fn replace_all<T: PatternLike + Copy>(pattern: T, subject: &str,
                                          repl: &str,
                                          options: int)
                                          -> ReplaceResult {
    return replace_all_fn_from(pattern, subject,
                               |_m| { str::from_slice(repl) }, 0u, options);
}

pub fn replace_all_fn<T: PatternLike + Copy>(pattern: T, subject: &str,
                                             repl_fn: &fn(Match) -> ~str,
                                             options: int)
                                             -> ReplaceResult {
    return replace_all_fn_from(pattern, subject, repl_fn, 0u, options);
}

pub fn replace_all_from<T: PatternLike + Copy>(pattern: T, subject: &str,
                                               repl: &str,
                                               offset: uint,
                                               options: int)
                                               -> ReplaceResult {
    return replace_all_fn_from(pattern, subject,
                               |_m| { str::from_slice(repl) }, offset, options);
}

pub fn replace_all_fn_from<T: PatternLike + Copy>(pattern: T, subject: &str,
                                                  repl_fn: &fn(Match) -> ~str,
                                                  offset: uint,
                                                  options: int)
                                                  -> ReplaceResult {
    let mut offset = offset;
    let subject_len = str::len(subject);
    assert!(offset <= subject_len);

    let mut s = str::slice(subject, 0, offset);
    loop {
        let r = search_from(pattern, subject, offset, options);
        match r {
            Ok(m) => {
                s += str::slice(subject, offset, m.begin());
                s += repl_fn(m);
                offset = m.end();
            }
            Err(ExecErr(e)) if e == PCRE_ERROR_NOMATCH => {
                if offset != subject_len {
                    s += str::slice(subject, offset, subject_len);
                }
                break;
            }
            Err(e) => {
                return Err(copy e);
            }
        }
    }
    return Ok(@s);
}

pub fn fmt_compile_err(e: CompileErr) -> ~str {
    return fmt!("error %d: %s at offset %u", e.code, *e.reason, e.offset);
}

/// Return true iff `sr` indicates that the subject did not match the pattern
pub fn is_nomatch(sr: SearchResult) -> bool {
    match sr {
        Err(ExecErr(e)) if e == PCRE_ERROR_NOMATCH => true,
        _ => false,
    }
}
<commit_msg>Remove an unused import<commit_after>extern mod std;

use core::libc::{c_char, c_int, c_void};
use core::option::{Some, None};
use core::result::{Ok, Err};
use core::result::Result;
use consts::*;

enum Pcre {}
enum PcreExtra {}
struct PcreRes {
    p: *Pcre,
    drop { unsafe { c::free(self.p as *c_void); } }
}

/// The result type of `compile`
pub type CompileResult = Result<Pattern, CompileErr>;

/// The result type of `exec`
pub type ExecResult = Result<Match, ExecErr>;

/// The result type of `search`
pub type SearchResult = Result<Match, RegexErr>;

// The result type of `replace`
pub type ReplaceResult = Result<@~str, RegexErr>;

/// The type that represents compile error
pub struct CompileErr {
    code: int,
    reason: @~str,
    offset: uint,
}

/// The type that represents exec error
pub type ExecErr = int;

/// Either compile or exec error
pub enum RegexErr {
    CompileErr(CompileErr),
    ExecErr(ExecErr),
}

/// Compiled regular expression
pub struct Pattern {
    str: @~str,
    priv pcre_res: @PcreRes,
}

/// Match
pub struct Match {
    subject: @~str,
    pattern: Pattern,
    priv captures: @~[int],
}

#[nolink]
#[abi = "cdecl"]
extern mod c {
    fn free(p: *c_void);
}

extern mod pcre {
    fn pcre_compile2(pattern: *c_char, options: c_int,
                     errorcodeptr: *c_int,
                     errptr: **c_char, erroffset: *c_int,
                     tableptr: *c_char) -> *Pcre;
    fn pcre_exec(code: *Pcre, extra: *PcreExtra,
                 subject: *c_char, length: c_int, startoffset: c_int,
                 options: c_int, ovector: * c_int, ovecsize: c_int) -> c_int;
    fn pcre_fullinfo(code: *Pcre, extra: *PcreExtra,
                     what: c_int, where: *c_void) -> c_int;
    fn pcre_get_stringnumber(code: *Pcre, name: *c_char) -> c_int;
}

pub trait PatternUtil {
    fn info_capture_count(self) -> uint;
    fn info_name_count(self) -> uint;
    fn info_name_entry_size(self) -> uint;
    fn with_name_table(self, blk: &fn(*u8));
    fn group_count(self) -> uint;
    fn group_names(self) -> ~[~str];
}

impl PatternUtil for Pattern {
    fn info_capture_count(self) -> uint {
        let count = -1 as c_int;
        unsafe {
            pcre::pcre_fullinfo(self.pcre_res.p, ptr::null(),
                                PCRE_INFO_CAPTURECOUNT as c_int,
                                ptr::addr_of(&count) as *c_void);
        }
        assert!(count >= 0 as c_int);
        return count as uint;
    }

    fn info_name_count(self) -> uint {
        let count = -1 as c_int;
        unsafe {
            pcre::pcre_fullinfo(self.pcre_res.p, ptr::null(),
                                PCRE_INFO_NAMECOUNT as c_int,
                                ptr::addr_of(&count) as *c_void);
        }
        assert!(count >= 0 as c_int);
        return count as uint;
    }

    fn info_name_entry_size(self) -> uint {
        let size = -1 as c_int;
        unsafe {
            pcre::pcre_fullinfo(self.pcre_res.p, ptr::null(),
                                PCRE_INFO_NAMEENTRYSIZE as c_int,
                                ptr::addr_of(&size) as *c_void);
        }
        assert!(size >= 0 as c_int);
        return size as uint;
    }

    fn with_name_table(self, blk: &fn(*u8)) {
        let table = ptr::null::<u8>();
        unsafe {
            pcre::pcre_fullinfo(self.pcre_res.p, ptr::null(),
                                PCRE_INFO_NAMETABLE as c_int,
                                ptr::addr_of(&table) as *c_void);
        }
        assert!(table != ptr::null::<u8>());
        blk(table);
    }

    fn group_count(self) -> uint {
        return self.info_capture_count();
    }

    fn group_names(self) -> ~[~str] {
        let count = self.info_name_count();
        if count == 0u { return ~[]; }
        let size = self.info_name_entry_size();
        let mut names: ~[~str] = ~[];
        unsafe {
            do self.with_name_table |table| {
                for uint::range(0u, count) |i| {
                    let p = ptr::offset(table, size * i + 2u);
                    let s = str::raw::from_c_str(p as *c_char);
                    vec::push(&mut names, s);
                }
            }
        }
        return names;
    }
}

pub trait PatternLike {
    fn compile(&self, options: int) -> CompileResult;
}

impl PatternLike for &str {
    fn compile(&self, options: int) -> CompileResult {
        compile(*self, options)
    }
}

impl PatternLike for ~str {
    fn compile(&self, options: int) -> CompileResult {
        compile(*self, options)
    }
}

impl PatternLike for @str {
    fn compile(&self, options: int) -> CompileResult {
        compile(*self, options)
    }
}

impl PatternLike for Pattern {
    fn compile(&self, _options: int) -> CompileResult {
        Ok(*self)
    }
}

impl PatternLike for CompileResult {
    fn compile(&self, _options: int) -> CompileResult {
        *self
    }
}

pub trait MatchExtensions {
    fn matched(self) -> ~str;
    fn prematch(self) -> ~str;
    fn postmatch(self) -> ~str;
    fn begin(self) -> uint;
    fn end(self) -> uint;
    fn group(self, i: uint) -> Option<@~str>;
    fn named_group(self, name: &str) -> Option<@~str>;
    fn subgroups(self) -> ~[~str];
    fn subgroups_iter(self, blk: &fn(&str));
    fn group_count(self) -> uint;
    fn group_names(self) -> ~[~str];
}

impl MatchExtensions for Match {
    fn matched(self) -> ~str {
        return str::slice(*self.subject, self.begin(), self.end());
    }

    fn prematch(self) -> ~str {
        return str::slice(*self.subject, 0u, self.begin());
    }

    fn postmatch(self) -> ~str {
        return str::slice(*self.subject ,self.end(),
                          str::char_len(*self.subject));
    }

    fn begin(self) -> uint {
        return self.captures[0] as uint;
    }

    fn end(self) -> uint {
        return self.captures[1] as uint;
    }

    fn group(self, i: uint) -> Option<@~str> {
        if i > self.group_count() {
            return None;
        }
        let i1 = self.captures[i * 2u];
        let i2 = self.captures[i * 2u + 1u];
        if(i1 < 0 || i2 < 0) {
            return None;
        }
        return Some(@str::slice(*self.subject, i1 as uint, i2 as uint));
    }

    fn named_group(self, name: &str) -> Option<@~str> {
        let i =  unsafe {
            str::as_buf(name, |s, _n| {
                pcre::pcre_get_stringnumber(self.pattern.pcre_res.p,
                                            s as *c_char)
            })
        };
        if i <= 0 as c_int { return None; }
        return self.group(i as uint);
    }

    fn subgroups(self) -> ~[~str] {
        let mut v = ~[];
        unsafe {
            vec::reserve(&mut v, self.group_count());
            do self.subgroups_iter |subgroup| {
                vec::push(&mut v, str::from_slice(subgroup));
            }
        }
        return v;
    }

    fn subgroups_iter(self, blk: &fn(&str)) {
        for uint::range(1u, self.group_count() + 1u) |i| {
            match self.group(i) {
              Some(s) => blk(*s),
              None => fail!(),
            }
        }
    }

    fn group_count(self) -> uint {
        return vec::len(*self.captures) / 2u - 1u;
    }

    fn group_names(self) -> ~[~str] {
        return self.pattern.group_names();
    }
}

pub fn compile(pattern: &str, options: int) -> CompileResult {
    if options | COMPILE_OPTIONS != COMPILE_OPTIONS {
        warn!("unrecognized option bit(s) are set");
    }

    let options = options | PCRE_NO_UTF8_CHECK; // str is always valid
    let errcode = 0 as c_int;
    let errreason: *c_char = ptr::null();
    let erroffset = 0 as c_int;
    let p = unsafe {
        str::as_buf(pattern, |pat, _n| {
            pcre::pcre_compile2(pat as *c_char,
                                options as c_int,
                                ptr::addr_of(&errcode),
                                ptr::addr_of(&errreason),
                                ptr::addr_of(&erroffset),
                                ptr::null())
        })
    };
    if p == ptr::null() {
        let reason = unsafe { @str::raw::from_c_str(errreason) };
        return Err(CompileErr {code: errcode as int,
                               reason: reason,
                               offset: erroffset as uint});
    }
    return Ok(Pattern {str: @str::from_slice(pattern),
                       pcre_res: @PcreRes {p: p}});
}

pub fn exec(pattern: Pattern,
            subject: &str, offset: uint,
            options: int) -> ExecResult {

    if (options | EXEC_OPTIONS) != EXEC_OPTIONS {
        warn!("unrecognized option bit(s) are set");
    }

    let options = options | PCRE_NO_UTF8_CHECK; // str is always valid

    let count = (pattern.info_capture_count() + 1u) as c_int;
    let mut ovec = vec::from_elem((count as uint) * 3u, 0u as c_int);

    let ret_code = unsafe {
        str::as_buf(subject, |s, _n| {
            pcre::pcre_exec(pattern.pcre_res.p, ptr::null(),
                            s as *c_char, str::len(subject) as c_int,
                            offset as c_int, options as c_int,
                            vec::raw::to_ptr(ovec) as *c_int,
                            count * (3 as c_int)) as int
        })
    };

    if ret_code < 0 { return Err(ret_code as ExecErr); }

    // Truncate the working space.
    unsafe { vec::raw::set_len(&mut ovec, count as uint * 2u) }

    let mut captures: ~[int] = ~[];
    unsafe { vec::reserve(&mut captures, vec::len(ovec)); }
    for ovec.each |o| {
        unsafe { vec::push(&mut captures, *o as int); }
    }
    assert!(vec::len(captures) % 2u == 0u);

    return Ok(Match {subject: @str::from_slice(subject),
                     pattern: pattern,
                     captures: @captures});
}

pub fn search<T: PatternLike>(pattern: T, subject: &str,
                              options: int)
                              -> SearchResult {
    return search_from(pattern, subject, 0u, options);
}

pub fn search_from<T: PatternLike>(pattern: T, subject: &str,
                                   offset: uint, options: int)
                                   -> SearchResult {
    assert!(offset <= str::len(subject));

    let c_opts = options & COMPILE_OPTIONS;
    let e_opts = options & EXEC_OPTIONS;

    let c = pattern.compile(c_opts);
    match c {
        Ok(pattern) => {
            let e = exec(pattern, subject, offset, e_opts);
            match e {
                Ok(m) => {
                    return Ok(m);
                }
                Err(e_err) => {
                    return Err(ExecErr(e_err));
                }
            }
        }
        Err(c_err) => {
            return Err(CompileErr(c_err));
        }
    }
}

pub fn replace<T: PatternLike + Copy>(pattern: T, subject: &str,
                                      repl: &str, options: int)
                                      -> ReplaceResult {
    return replace_fn_from(pattern, subject,
                           |_m| { str::from_slice(repl) }, 0u, options);
}

pub fn replace_from<T: PatternLike + Copy>(pattern: T, subject: &str,
                                           repl: &str,  offset: uint,
                                           options: int)
                                           -> ReplaceResult {
    return replace_fn_from(pattern, subject,
                           |_m| { str::from_slice(repl) }, offset, options);
}

pub fn replace_fn<T: PatternLike + Copy>(pattern: T, subject: &str,
                                         repl_fn: &fn(Match) -> ~str,
                                         options: int)
                                         -> ReplaceResult {
    return replace_fn_from(pattern, subject, repl_fn, 0u, options);
}

pub fn replace_fn_from<T: PatternLike + Copy>(pattern: T, subject: &str,
                                              repl_fn: &fn(Match) -> ~str,
                                              offset: uint,
                                              options: int)
                                              -> ReplaceResult {
    let r = search_from(pattern, subject, offset, options);
    match r {
        Ok(m) => {
            return Ok(@(m.prematch() + repl_fn(m) + m.postmatch()));
        }
        Err(e) => { return Err(e); }
    }
}

pub fn replace_all<T: PatternLike + Copy>(pattern: T, subject: &str,
                                          repl: &str,
                                          options: int)
                                          -> ReplaceResult {
    return replace_all_fn_from(pattern, subject,
                               |_m| { str::from_slice(repl) }, 0u, options);
}

pub fn replace_all_fn<T: PatternLike + Copy>(pattern: T, subject: &str,
                                             repl_fn: &fn(Match) -> ~str,
                                             options: int)
                                             -> ReplaceResult {
    return replace_all_fn_from(pattern, subject, repl_fn, 0u, options);
}

pub fn replace_all_from<T: PatternLike + Copy>(pattern: T, subject: &str,
                                               repl: &str,
                                               offset: uint,
                                               options: int)
                                               -> ReplaceResult {
    return replace_all_fn_from(pattern, subject,
                               |_m| { str::from_slice(repl) }, offset, options);
}

pub fn replace_all_fn_from<T: PatternLike + Copy>(pattern: T, subject: &str,
                                                  repl_fn: &fn(Match) -> ~str,
                                                  offset: uint,
                                                  options: int)
                                                  -> ReplaceResult {
    let mut offset = offset;
    let subject_len = str::len(subject);
    assert!(offset <= subject_len);

    let mut s = str::slice(subject, 0, offset);
    loop {
        let r = search_from(pattern, subject, offset, options);
        match r {
            Ok(m) => {
                s += str::slice(subject, offset, m.begin());
                s += repl_fn(m);
                offset = m.end();
            }
            Err(ExecErr(e)) if e == PCRE_ERROR_NOMATCH => {
                if offset != subject_len {
                    s += str::slice(subject, offset, subject_len);
                }
                break;
            }
            Err(e) => {
                return Err(copy e);
            }
        }
    }
    return Ok(@s);
}

pub fn fmt_compile_err(e: CompileErr) -> ~str {
    return fmt!("error %d: %s at offset %u", e.code, *e.reason, e.offset);
}

/// Return true iff `sr` indicates that the subject did not match the pattern
pub fn is_nomatch(sr: SearchResult) -> bool {
    match sr {
        Err(ExecErr(e)) if e == PCRE_ERROR_NOMATCH => true,
        _ => false,
    }
}
<|endoftext|>


<commit_before>extern crate clap;

use clap::{App, Arg};

fn main() {
	let matches = App::new("MyApp")
						.version("1.0")
						.author("Kevin K. <kbknapp@gmail.com>")
						.about("Does awesome things")
						.arg(Arg::new("config")
									.short("c")
									.long("config")
									.help("Sets a custom config file")
									.takes_value(true))
						.arg(Arg::new("output")
									.help("Sets an optional output file")
									.index(1))
						.arg(Arg::new("debug")
									.short("d")
 								.multiple(true)
									.help("Turn debugging information on"))
						.get_matches();

	if let Some(o) = matches.value_of("output") {
		println!("Value for output: {}", o);
	}

	if let Some(c) = matches.value_of("config") {
		println!("Value for config: {}", c);
	}

	match matches.occurrences_of("debug") {
 		0 => println!("Debug mode is off"),
		1 => println!("Debug mode is kind of on"),
		2 => println!("Debug mode is on"),
		3 | _ => println!("Don't be crazy"),
 	}
	print!("App is running...");
	println!("done.");
}<commit_msg>Delete main.rs<commit_after><|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2015 Johan Johansson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Infer types where explicit type signatures are not available

use super::{ AST, ExprMeta, Expr, Item, Type, TypedBinding };

// TODO: Add some way to check whether something was inferred
// in order to loop while things are still happening

/// returns [Arg types, Body type]
fn extract_fn_sig(sig: &mut Type) -> Result<(&mut [Type], &mut Type), String> {
	match sig {
		&mut Type::Construct(ref mut constructor, ref mut construct_args) if constructor == "fn" =>
		{
			let len = construct_args.len();
			if len == 0 {
				Err("extract_fn_sig: `fn` construct lacks arguments".into())
			} else {
				let (mut arg_types, mut return_type) = construct_args.split_at_mut(len - 1);
				Ok((arg_types, &mut return_type[0]))
			}
		},
		t => Err(format!("extract_fn_sig: Expected type `<fn _ ...>`, found `{:?}`", t))
	}
}

impl super::FnDef {
	fn infer_types(&mut self, binding_stack: &mut Vec<TypedBinding>) -> Result<(), String> {
		// TODO: inferral of function signature
		let old_stack_len = binding_stack.len();

		let infer_body_to = if let Some(sig) = self.binding.type_sig.as_mut() {
			match extract_fn_sig(sig) {
				Ok((fn_arg_tys, fn_body_ty)) => {
					for (fn_arg_ty, arg_bind) in fn_arg_tys.iter_mut()
						.zip(self.arg_bindings.iter_mut())
						.filter(|&(_, ref arg_bind)| arg_bind.type_sig.is_none())
					{
						arg_bind.type_sig = Some(fn_arg_ty.clone());
					}
					Some(fn_body_ty)
				},
				Err(e) => return Err(e)
			}
		} else {
			None
		};

		binding_stack.extend(self.arg_bindings.iter().cloned());

		self.body.infer_types(infer_body_to.map(|t| &*t), binding_stack);

		// TODO: Get binding types from stack

		binding_stack.truncate(old_stack_len);
		Ok(())
	}
}

impl super::ConstDef {
	fn infer_types(&mut self, binding_stack: &mut Vec<TypedBinding>) -> Result<(), String> {
		// TODO: infer type for binding and vice versa
		self.body.infer_types(self.binding.type_sig.as_ref(), binding_stack);

		self.binding.type_sig = self.body.coerce_type.clone();
		Ok(())
	}
}

impl super::ItemMeta {
	pub fn infer_types(&mut self, binding_stack: &mut Vec<TypedBinding>) -> Result<(), String> {
		match *self.item {
			Item::FnDef(ref mut def) => def.infer_types(binding_stack),
			Item::ConstDef(ref mut def) => def.infer_types(binding_stack),
			Item::Use(_) => Ok(()),
		}
	}
}

impl super::SExpr {
	fn get_type(&self, binding_stack: &[TypedBinding]) -> Option<Type> {
		self.func.get_type(binding_stack)
	}

	fn infer_types(&mut self, _: Option<&Type>, binding_stack: &mut Vec<TypedBinding>) {
		self.func.infer_types(None, binding_stack);

		if let Expr::Lambda(ref mut lambda) = *self.func.value {
			for (sexpr_arg, lambda_arg) in
				self.args.iter_mut().zip(lambda.arg_bindings.iter_mut())
			{
				sexpr_arg.infer_types(lambda_arg.type_sig.as_ref(), binding_stack);
				lambda_arg.type_sig = sexpr_arg.get_type(binding_stack);
			}
		} else {
			for arg in &mut self.args {
				arg.infer_types(None, binding_stack);
			}
		}

		self.func.infer_types(None, binding_stack);
	}
}

impl super::Block {
	fn get_type(&self, binding_stack: &[TypedBinding]) -> Option<Type> {
		self.exprs.last().and_then(|expr| expr.get_type(binding_stack))
	}

	fn infer_types(&mut self, coerce_to: Option<&Type>, binding_stack: &mut Vec<TypedBinding>) {
		let old_stack_len = binding_stack.len();

		let all_but_last = self.exprs.len() - 1;
		for expr in self.exprs[0..all_but_last].iter_mut() {
			expr.infer_types(Some(&Type::Tuple(vec![])), binding_stack);
		}

		self.exprs.last_mut().unwrap().infer_types(coerce_to, binding_stack);

		binding_stack.truncate(old_stack_len);
	}
}

impl super::Cond {
	fn get_type(&self, binding_stack: &[TypedBinding]) -> Option<Type> {
		self.clauses.iter()
			.filter_map(|&(_, ref clause_expr)| clause_expr.get_type(binding_stack))
			.next()
	}

	fn infer_types(&mut self, coerce_to: Option<&Type>, binding_stack: &mut Vec<TypedBinding>) {
		let out_type = self.clauses.iter()
			.filter_map(|&(_, ref clause_expr)| clause_expr.coerce_type.as_ref())
			.next()
			.or(coerce_to)
			.map(|o| o.clone());

		for clause in &mut self.clauses {
			clause.0.infer_types(Some(&Type::Basic("bool".into())), binding_stack);
			clause.1.infer_types(out_type.as_ref(), binding_stack);
		}
	}
}

impl super::Lambda {
	fn get_type(&self, _: &[TypedBinding]) -> Option<Type> {
		// TODO: Fix this. Should be something like:
		// `Type::Construct(Type::Basic("Fn".into), vec![Type::Tuple(vec![ARG_TYPES]), BODY_TYPE])`
		None
	}

	fn infer_types(&mut self, coerce_to: Option<&Type>, binding_stack: &mut Vec<TypedBinding>) {
		binding_stack.extend(self.arg_bindings.iter().cloned());

		self.body.infer_types(coerce_to, binding_stack);

		let old_len = binding_stack.len() - self.arg_bindings.len();
		binding_stack.truncate(old_len);
	}
}

impl ExprMeta {
	fn get_type(&self, binding_stack: &[TypedBinding])-> Option<Type> {
		self.coerce_type.clone().or(match *self.value {
			Expr::Cond(ref cond) => cond.get_type(binding_stack),
			Expr::SExpr(ref sexpr) => sexpr.get_type(binding_stack),
			// TODO: `&str` should somehow be parameterised Construct, not just a string
			Expr::StrLit(_) => Some(Type::Basic("&'static str".into())),
			Expr::Lambda(ref lambda) => lambda.get_type(binding_stack),
			Expr::Block(ref block) => block.get_type(binding_stack),
			Expr::Nil => Some(Type::Tuple(vec![])),
			Expr::Binding(ref bnd) => binding_stack.iter()
				.rev()
				.find(|tb| bnd == tb.ident.as_ref())
				.map(|tb| tb.type_sig.clone())
				.unwrap_or(None),

			Expr::NumLit(_) => None,
		})
	}

	fn infer_types_for_child(&mut self, binding_stack: &mut Vec<TypedBinding>) {
		match *self.value {
			Expr::Cond(ref mut cond) => cond.infer_types(self.coerce_type.as_ref(), binding_stack),
			Expr::SExpr(ref mut sexpr) =>
				sexpr.infer_types(self.coerce_type.as_ref(), binding_stack),
			Expr::Lambda(ref mut lambda) =>
				lambda.infer_types(self.coerce_type.as_ref(), binding_stack),
			Expr::Block(ref mut block) =>
				block.infer_types(self.coerce_type.as_ref(), binding_stack),
			Expr::Binding(ref bnd) => if let Some(stack_binding) = binding_stack.iter_mut()
				.rev()
				.find(|tb| bnd == tb.ident.as_ref())
			{
				if self.coerce_type.is_none() {
					self.coerce_type = stack_binding.type_sig.clone();
				} else if stack_binding.type_sig.is_none() {
					stack_binding.type_sig = self.coerce_type.clone();
				}
			},
			// Doesn't have children to infer types for
			Expr::NumLit(_) | Expr::StrLit(_) | Expr::Nil => (),
		}
	}

	pub fn infer_type_from_below(&mut self, binding_stack: &[TypedBinding]) -> bool {
		if let Some(ty) = self.get_type(binding_stack) {
			self.coerce_type = Some(ty);
			true
		} else {
			false
		}
	}

	// Infer types for self and for children
	pub fn infer_types(&mut self, coerce_to: Option<&Type>, binding_stack: &mut Vec<TypedBinding>) {
		if self.coerce_type.is_some() {
			// We have a type, infer types for children,
			// resorting to coercing to our type if necessary
			self.infer_types_for_child(binding_stack);
		} else {
			// We don't have a type, try to infer types for children from below
			self.infer_types_for_child(binding_stack);
			if self.infer_type_from_below(&binding_stack) {
				// We got a type from below, redo procedure with coerce type available for children
				// that can't get types from below
				self.infer_types(None, binding_stack);
			} else {
				if let Some(coerce_type) = coerce_to {
					// We didn't get a type from below, resort to using type of parent to coerce to
					self.coerce_type = Some(coerce_type.clone());
					self.infer_types(None, binding_stack);
				}
			}
		}
	}
}

impl AST {
	pub fn infer_types(&mut self) {
		let mut binding_stack = Vec::with_capacity(10);

		for item in &mut self.items {
			item.infer_types(&mut binding_stack).unwrap();
		}
	}
}
<commit_msg>Remove old, innefective, incorrect inference impl<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2015 Johan Johansson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Infer types where explicit type signatures are not available

use super::{ AST };

impl AST {
	pub fn infer_types(&mut self) {
	}
}
<|endoftext|>