<commit_before>use std::io::fs;
use std::io::fs::PathExtensions;
use std::io::{File, IoResult, USER_RWX};

// A simple implementation of `$ cat path`
fn cat(path: &Path) -> IoResult<String> {
    File::open(path).and_then(|mut f| f.read_to_string())
}

// A simple implementation of `$ echo s > path`
fn echo(s: &str, path: &Path) -> IoResult<()> {
    File::create(path).and_then(|mut f| f.write_str(s))
}

// A simple implementation of `$ touch path` (ignores existing files)
fn touch(path: &Path) -> IoResult<()> {
    if !path.exists() {
        File::create(path).and_then(|_| Ok(()))
    } else {
        Ok(())
    }
}

fn main() {
    println!("`mkdir a`");
    // Create a directory, returns `IoResult<()>`
    match fs::mkdir(&Path::new("a"), USER_RWX) {
        Err(why) => println!("! {}", why.kind),
        Ok(_) => {},
    }

    println!("`echo hello > a/b.txt`");
    // The previous match can be simplified using the `unwrap_or_else` method
    echo("hello", &Path::new("a/b.txt")).unwrap_or_else(|why| {
        println!("! {}", why.kind);
    });

    println!("`mkdir -p a/c/d`");
    // Recursively create a directory, returns `IoResult<()>`
    fs::mkdir_recursive(&Path::new("a/c/d"), USER_RWX).unwrap_or_else(|why| {
        println!("! {}", why.kind);
    });

    println!("`touch a/c/e.txt`");
    touch(&Path::new("a/c/e.txt")).unwrap_or_else(|why| {
        println!("! {}", why.kind);
    });

    println!("`ln -s ../b.txt a/c/b.txt`");
    // Create a symbolic link, returns `IoResult<()>`
    fs::symlink(&Path::new("../b.txt"),
                &Path::new("a/c/b.txt")).unwrap_or_else(|why| {
        println!("! {}", why.kind);
    });

    println!("`cat a/c/b.txt`");
    match cat(&Path::new("a/c/b.txt")) {
        Err(why) => println!("! {}", why.kind),
        Ok(s) => println!("> {}", s),
    }

    println!("`ls a`");
    // Read the contents of a directory, returns `IoResult<Vec<Path>>`
    match fs::readdir(&Path::new("a")) {
        Err(why) => println!("! {}", why.kind),
        Ok(paths) => for path in paths.iter() {
            println!("> {}", path.display());
        },
    }

    println!("`walk a`");
    // Recursively walk over the contents of a directory, returns
    // `Directories`, which implements the `Iterator<Path> trait
    match fs::walk_dir(&Path::new("a")) {
        Err(why) => println!("! {}", why.kind),
        Ok(mut paths) => for path in paths {
            println!("> {}", path.display());
        },
    }

    println!("`rm a/c/e.txt`");
    // Remove a file, returns `IoResult<()>`
    fs::unlink(&Path::new("a/c/e.txt")).unwrap_or_else(|why| {
        println!("! {}", why.kind);
    });

    println!("`rmdir a/c/d`");
    // Remove an empty directory, returns `IoResult<()>`
    fs::rmdir(&Path::new("a/c/d")).unwrap_or_else(|why| {
        println!("! {}", why.kind);
    });
}
<commit_msg>Change prompt symbol in comments from $ to %. Close #334<commit_after>use std::io::fs;
use std::io::fs::PathExtensions;
use std::io::{File, IoResult, USER_RWX};

// A simple implementation of `% cat path`
fn cat(path: &Path) -> IoResult<String> {
    File::open(path).and_then(|mut f| f.read_to_string())
}

// A simple implementation of `% echo s > path`
fn echo(s: &str, path: &Path) -> IoResult<()> {
    File::create(path).and_then(|mut f| f.write_str(s))
}

// A simple implementation of `% touch path` (ignores existing files)
fn touch(path: &Path) -> IoResult<()> {
    if !path.exists() {
        File::create(path).and_then(|_| Ok(()))
    } else {
        Ok(())
    }
}

fn main() {
    println!("`mkdir a`");
    // Create a directory, returns `IoResult<()>`
    match fs::mkdir(&Path::new("a"), USER_RWX) {
        Err(why) => println!("! {}", why.kind),
        Ok(_) => {},
    }

    println!("`echo hello > a/b.txt`");
    // The previous match can be simplified using the `unwrap_or_else` method
    echo("hello", &Path::new("a/b.txt")).unwrap_or_else(|why| {
        println!("! {}", why.kind);
    });

    println!("`mkdir -p a/c/d`");
    // Recursively create a directory, returns `IoResult<()>`
    fs::mkdir_recursive(&Path::new("a/c/d"), USER_RWX).unwrap_or_else(|why| {
        println!("! {}", why.kind);
    });

    println!("`touch a/c/e.txt`");
    touch(&Path::new("a/c/e.txt")).unwrap_or_else(|why| {
        println!("! {}", why.kind);
    });

    println!("`ln -s ../b.txt a/c/b.txt`");
    // Create a symbolic link, returns `IoResult<()>`
    fs::symlink(&Path::new("../b.txt"),
                &Path::new("a/c/b.txt")).unwrap_or_else(|why| {
        println!("! {}", why.kind);
    });

    println!("`cat a/c/b.txt`");
    match cat(&Path::new("a/c/b.txt")) {
        Err(why) => println!("! {}", why.kind),
        Ok(s) => println!("> {}", s),
    }

    println!("`ls a`");
    // Read the contents of a directory, returns `IoResult<Vec<Path>>`
    match fs::readdir(&Path::new("a")) {
        Err(why) => println!("! {}", why.kind),
        Ok(paths) => for path in paths.iter() {
            println!("> {}", path.display());
        },
    }

    println!("`walk a`");
    // Recursively walk over the contents of a directory, returns
    // `Directories`, which implements the `Iterator<Path> trait
    match fs::walk_dir(&Path::new("a")) {
        Err(why) => println!("! {}", why.kind),
        Ok(mut paths) => for path in paths {
            println!("> {}", path.display());
        },
    }

    println!("`rm a/c/e.txt`");
    // Remove a file, returns `IoResult<()>`
    fs::unlink(&Path::new("a/c/e.txt")).unwrap_or_else(|why| {
        println!("! {}", why.kind);
    });

    println!("`rmdir a/c/d`");
    // Remove an empty directory, returns `IoResult<()>`
    fs::rmdir(&Path::new("a/c/d")).unwrap_or_else(|why| {
        println!("! {}", why.kind);
    });
}
<|endoftext|>


<commit_before>extern crate euclid;
#[macro_use]
extern crate glium;
extern crate image;

extern crate vitral;

use std::path::Path;
use glium::{DisplayBuild, Surface};
use glium::glutin;
use glium::index::PrimitiveType;
use euclid::Point2D;

use vitral::Context;

type GliumTexture = glium::texture::CompressedSrgbTexture2d;

struct Backend {
    display: glium::Display,
    program: glium::Program,
    textures: Vec<GliumTexture>,
}

impl Backend {
    pub fn new(display: glium::Display, program: glium::Program) -> Backend {
        Backend {
            display: display,
            program: program,
            textures: Vec::new(),
        }
    }

    pub fn make_texture(&mut self, img: vitral::ImageBuffer) -> usize {
        let dim = (img.width(), img.height());
        let raw = glium::texture::RawImage2d::from_raw_rgba(img.into_raw(),
                                                            dim);
        let tex = glium::texture::CompressedSrgbTexture2d::new(&self.display,
                                                               raw)
                      .unwrap();
        self.textures.push(tex);
        self.textures.len() - 1
    }

    pub fn update(&self, context: &mut Context<usize, Vertex>) -> bool {
        let mut target = self.display.draw();
        target.clear_color(0.0, 0.0, 0.0, 0.0);
        let (w, h) = target.get_dimensions();

        for batch in context.end_frame() {
            // building the uniforms
            let uniforms = uniform! {
                matrix: [
                    [2.0 / w as f32, 0.0, 0.0, -1.0],
                    [0.0, -2.0 / h as f32, 0.0, 1.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0f32]
                ],
                tex: glium::uniforms::Sampler::new(&self.textures[batch.texture])
                    .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest),
            };

            let vertex_buffer = {
                glium::VertexBuffer::new(&self.display, &batch.vertices)
                    .unwrap()
            };

            // building the index buffer
            let index_buffer =
                glium::IndexBuffer::new(&self.display,
                                        PrimitiveType::TrianglesList,
                                        &batch.triangle_indices)
                    .unwrap();

            let params = glium::draw_parameters::DrawParameters {
                scissor: batch.clip.map(|clip| {
                    glium::Rect {
                        left: clip.origin.x as u32,
                        bottom: h - (clip.origin.y + clip.size.height) as u32,
                        width: clip.size.width as u32,
                        height: clip.size.height as u32,
                    }
                }),
                blend: glium::Blend::alpha_blending(),
                ..Default::default()
            };

            target.draw(&vertex_buffer,
                        &index_buffer,
                        &self.program,
                        &uniforms,
                        &params)
                  .unwrap();
        }

        target.finish().unwrap();

        // polling and handling the events received by the window
        for event in self.display.poll_events() {
            match event {
                glutin::Event::Closed => return false,
                glutin::Event::MouseMoved(x, y) => {
                    context.input_mouse_move(x, y)
                }
                glutin::Event::MouseInput(state, button) => {
                    context.input_mouse_button(match button {
                                                   glutin::MouseButton::Left => {
                                                       vitral::MouseButton::Left
                                                   }
                                                   glutin::MouseButton::Right => {
                                                       vitral::MouseButton::Right
                                                   }
                                                   _ => vitral::MouseButton::Middle,
                                               },
                                               state == glutin::ElementState::Pressed)
                }
                glutin::Event::ReceivedCharacter(c) => context.input_char(c),
                glutin::Event::KeyboardInput(s, _, Some(vk)) => {
                    let is_down = s == glutin::ElementState::Pressed;
                    use glium::glutin::VirtualKeyCode::*;
                    match vk {
                        Tab => {
                            context.input_key_state(vitral::Keycode::Tab,
                                                    is_down)
                        }
                        LShift | RShift => {
                            context.input_key_state(vitral::Keycode::Shift,
                                                    is_down)
                        }
                        LControl | RControl => {
                            context.input_key_state(vitral::Keycode::Ctrl,
                                                    is_down)
                        }
                        NumpadEnter | Return => {
                            context.input_key_state(vitral::Keycode::Enter,
                                                    is_down)
                        }
                        Back => {
                            context.input_key_state(vitral::Keycode::Backspace,
                                                    is_down)
                        }
                        Delete => {
                            context.input_key_state(vitral::Keycode::Del,
                                                    is_down)
                        }
                        Numpad8 | Up => {
                            context.input_key_state(vitral::Keycode::Up,
                                                    is_down)
                        }
                        Numpad2 | Down => {
                            context.input_key_state(vitral::Keycode::Down,
                                                    is_down)
                        }
                        Numpad4 | Left => {
                            context.input_key_state(vitral::Keycode::Left,
                                                    is_down)
                        }
                        Numpad6 | Right => {
                            context.input_key_state(vitral::Keycode::Right,
                                                    is_down)
                        }
                        _ => {}
                    }
                }
                _ => (),
            }
        }

        true
    }
}

// XXX: An exact copy of Vitral vertex struct, just so that I can derive a
// Glium vertex implementatino for it.
#[derive(Copy, Clone)]
pub struct Vertex {
    pub pos: [f32; 2],
    pub color: [f32; 4],
    pub tex: [f32; 2],
}
implement_vertex!(Vertex, pos, color, tex);

impl vitral::Vertex for Vertex {
    fn new(pos: [f32; 2], color: [f32; 4], texcoord: [f32; 2]) -> Self {
        Vertex {
            pos: pos,
            color: color,
            tex: texcoord,
        }
    }
}

fn main() {
    // Construct Glium backend.
    let display = glutin::WindowBuilder::new()
                      .build_glium()
                      .unwrap();

    // building the display, ie. the main object
    let program = program!(
        &display,
        150 => {
        vertex: "
            #version 150 core

            uniform mat4 matrix;

            in vec2 pos;
            in vec4 color;
            in vec2 tex;

            out vec4 vColor;
            out vec2 vTexcoord;

            void main() {
                gl_Position = vec4(pos, 0.0, 1.0) * matrix;
                vColor = color;
                vTexcoord = tex;
            }
        ",

        fragment: "
            #version 150 core
            uniform sampler2D tex;
            in vec4 vColor;
            in vec2 vTexcoord;
            out vec4 f_color;

            void main() {
                f_color = vColor * texture(tex, vTexcoord);
            }
        "})
                      .unwrap();

    let mut backend = Backend::new(display, program);

    // Construct Vitral context.
    let mut context: Context<usize, Vertex>;
    let mut builder = vitral::Builder::new();
    let image = builder.add_image(&image::open(&Path::new("julia.png"))
                                       .unwrap());
    context = builder.build(|img| backend.make_texture(img));

    let font = context.default_font();

    let mut test_input = String::new();

    // Run the program.
    loop {
        context.begin_frame();

        context.draw_image(image,
                           Point2D::new(100.0, 100.0),
                           [1.0, 1.0, 1.0, 1.0]);

        if context.button("Hello, world") {
            println!("Click");
        }

        if context.button("Another button") {
            println!("Clack {}", test_input);
        }

        context.text_input(font,
                           Point2D::new(10.0, 120.0),
                           [0.8, 0.8, 0.8, 1.0],
                           &mut test_input);

        if !backend.update(&mut context) {
            return;
        }
    }
}
<commit_msg>Factor the glium update code<commit_after>extern crate euclid;
#[macro_use]
extern crate glium;
extern crate image;

extern crate vitral;

use std::path::Path;
use glium::{DisplayBuild, Surface};
use glium::glutin;
use glium::index::PrimitiveType;
use euclid::Point2D;

use vitral::Context;

type GliumTexture = glium::texture::CompressedSrgbTexture2d;

struct Backend {
    display: glium::Display,
    program: glium::Program,
    textures: Vec<GliumTexture>,
}

impl Backend {
    pub fn new(display: glium::Display, program: glium::Program) -> Backend {
        Backend {
            display: display,
            program: program,
            textures: Vec::new(),
        }
    }

    pub fn make_texture(&mut self, img: vitral::ImageBuffer) -> usize {
        let dim = (img.width(), img.height());
        let raw = glium::texture::RawImage2d::from_raw_rgba(img.into_raw(),
                                                            dim);
        let tex = glium::texture::CompressedSrgbTexture2d::new(&self.display,
                                                               raw)
                      .unwrap();
        self.textures.push(tex);
        self.textures.len() - 1
    }

    fn process_events<V>(&self, context: &mut Context<usize, V>) -> bool
        where V: vitral::Vertex
    {
        // polling and handling the events received by the window
        for event in self.display.poll_events() {
            match event {
                glutin::Event::Closed => return false,
                glutin::Event::MouseMoved(x, y) => {
                    context.input_mouse_move(x, y)
                }
                glutin::Event::MouseInput(state, button) => {
                    context.input_mouse_button(match button {
                                                   glutin::MouseButton::Left => {
                                                       vitral::MouseButton::Left
                                                   }
                                                   glutin::MouseButton::Right => {
                                                       vitral::MouseButton::Right
                                                   }
                                                   _ => vitral::MouseButton::Middle,
                                               },
                                               state == glutin::ElementState::Pressed)
                }
                glutin::Event::ReceivedCharacter(c) => context.input_char(c),
                glutin::Event::KeyboardInput(s, _, Some(vk)) => {
                    let is_down = s == glutin::ElementState::Pressed;
                    use glium::glutin::VirtualKeyCode::*;
                    match vk {
                        Tab => {
                            context.input_key_state(vitral::Keycode::Tab,
                                                    is_down)
                        }
                        LShift | RShift => {
                            context.input_key_state(vitral::Keycode::Shift,
                                                    is_down)
                        }
                        LControl | RControl => {
                            context.input_key_state(vitral::Keycode::Ctrl,
                                                    is_down)
                        }
                        NumpadEnter | Return => {
                            context.input_key_state(vitral::Keycode::Enter,
                                                    is_down)
                        }
                        Back => {
                            context.input_key_state(vitral::Keycode::Backspace,
                                                    is_down)
                        }
                        Delete => {
                            context.input_key_state(vitral::Keycode::Del,
                                                    is_down)
                        }
                        Numpad8 | Up => {
                            context.input_key_state(vitral::Keycode::Up,
                                                    is_down)
                        }
                        Numpad2 | Down => {
                            context.input_key_state(vitral::Keycode::Down,
                                                    is_down)
                        }
                        Numpad4 | Left => {
                            context.input_key_state(vitral::Keycode::Left,
                                                    is_down)
                        }
                        Numpad6 | Right => {
                            context.input_key_state(vitral::Keycode::Right,
                                                    is_down)
                        }
                        _ => {}
                    }
                }
                _ => (),
            }
        }

        true
    }

    pub fn update<V>(&self, context: &mut Context<usize, V>) -> bool
        where V: vitral::Vertex + glium::Vertex
    {
        let mut target = self.display.draw();
        target.clear_color(0.0, 0.0, 0.0, 0.0);
        let (w, h) = target.get_dimensions();

        for batch in context.end_frame() {
            // building the uniforms
            let uniforms = uniform! {
                matrix: [
                    [2.0 / w as f32, 0.0, 0.0, -1.0],
                    [0.0, -2.0 / h as f32, 0.0, 1.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0f32]
                ],
                tex: glium::uniforms::Sampler::new(&self.textures[batch.texture])
                    .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest),
            };

            let vertex_buffer = {
                glium::VertexBuffer::new(&self.display, &batch.vertices)
                    .unwrap()
            };

            // building the index buffer
            let index_buffer =
                glium::IndexBuffer::new(&self.display,
                                        PrimitiveType::TrianglesList,
                                        &batch.triangle_indices)
                    .unwrap();

            let params = glium::draw_parameters::DrawParameters {
                scissor: batch.clip.map(|clip| {
                    glium::Rect {
                        left: clip.origin.x as u32,
                        bottom: h - (clip.origin.y + clip.size.height) as u32,
                        width: clip.size.width as u32,
                        height: clip.size.height as u32,
                    }
                }),
                blend: glium::Blend::alpha_blending(),
                ..Default::default()
            };

            target.draw(&vertex_buffer,
                        &index_buffer,
                        &self.program,
                        &uniforms,
                        &params)
                  .unwrap();
        }

        target.finish().unwrap();

        self.process_events(context)
    }
}

// XXX: An exact copy of Vitral vertex struct, just so that I can derive a
// Glium vertex implementatino for it.
#[derive(Copy, Clone)]
pub struct Vertex {
    pub pos: [f32; 2],
    pub color: [f32; 4],
    pub tex: [f32; 2],
}
implement_vertex!(Vertex, pos, color, tex);

impl vitral::Vertex for Vertex {
    fn new(pos: [f32; 2], color: [f32; 4], texcoord: [f32; 2]) -> Self {
        Vertex {
            pos: pos,
            color: color,
            tex: texcoord,
        }
    }
}

fn main() {
    // Construct Glium backend.
    let display = glutin::WindowBuilder::new()
                      .build_glium()
                      .unwrap();

    // building the display, ie. the main object
    let program = program!(
        &display,
        150 => {
        vertex: "
            #version 150 core

            uniform mat4 matrix;

            in vec2 pos;
            in vec4 color;
            in vec2 tex;

            out vec4 vColor;
            out vec2 vTexcoord;

            void main() {
                gl_Position = vec4(pos, 0.0, 1.0) * matrix;
                vColor = color;
                vTexcoord = tex;
            }
        ",

        fragment: "
            #version 150 core
            uniform sampler2D tex;
            in vec4 vColor;
            in vec2 vTexcoord;
            out vec4 f_color;

            void main() {
                f_color = vColor * texture(tex, vTexcoord);
            }
        "})
                      .unwrap();

    let mut backend = Backend::new(display, program);

    // Construct Vitral context.
    let mut context: Context<usize, Vertex>;
    let mut builder = vitral::Builder::new();
    let image = builder.add_image(&image::open(&Path::new("julia.png"))
                                       .unwrap());
    context = builder.build(|img| backend.make_texture(img));

    let font = context.default_font();

    let mut test_input = String::new();

    // Run the program.
    loop {
        context.begin_frame();

        context.draw_image(image,
                           Point2D::new(100.0, 100.0),
                           [1.0, 1.0, 1.0, 1.0]);

        if context.button("Hello, world") {
            println!("Click");
        }

        if context.button("Another button") {
            println!("Clack {}", test_input);
        }

        context.text_input(font,
                           Point2D::new(10.0, 120.0),
                           [0.8, 0.8, 0.8, 1.0],
                           &mut test_input);

        if !backend.update(&mut context) {
            return;
        }
    }
}
<|endoftext|>


<commit_before>extern crate iron;

use std::io::net::ip::Ipv4Addr;

use iron::iron::Iron;
use iron::ingot::{Ingot, Status, Continue};
use iron::furnace::Furnace;
use iron::furnace::ironfurnace::IronFurnace;
use iron::alloy::Alloy;
use iron::request::Request;
use iron::request::ironrequest::IronRequest;
use iron::response::Response;
use iron::response::ironresponse::IronResponse;

#[deriving(Clone)]
struct HelloWorld;

impl<'a, Rq: Request, Rs: Response<'a>> Ingot<'a, Rq, Rs> for HelloWorld {
    fn enter(&mut self, _request: &mut Rq, response: &mut Rs, _alloy: &mut Alloy) -> Status {
        response.write(bytes!("Hello World!"));
        Continue
    }
}

fn main() {
    let mut server: Iron<IronRequest, IronResponse<'static>, IronFurnace<IronRequest, IronResponse<'static>>> =
        Iron::new();
    server.smelt(HelloWorld);
    server.listen(Ipv4Addr(127, 0, 0, 1), 3000);
}

<commit_msg>(refactor) Refactored hello for new IronResponse.<commit_after>extern crate iron;

use std::io::net::ip::Ipv4Addr;

use iron::iron::Iron;
use iron::ingot::{Ingot, Status, Continue};
use iron::furnace::Furnace;
use iron::furnace::ironfurnace::IronFurnace;
use iron::alloy::Alloy;
use iron::request::Request;
use iron::request::ironrequest::IronRequest;
use iron::response::Response;
use iron::response::ironresponse::IronResponse;

#[deriving(Clone)]
struct HelloWorld;

impl<Rq: Request, Rs: Response> Ingot<Rq, Rs> for HelloWorld {
    fn enter(&mut self, _request: &mut Rq, response: &mut Rs, _alloy: &mut Alloy) -> Status {
        response.write(bytes!("Hello World!"));
        Continue
    }
}

fn main() {
    let mut server: Iron<IronRequest, IronResponse<'static, 'static>, IronFurnace<IronRequest, IronResponse<'static, 'static>>> =
        Iron::new();
    server.smelt(HelloWorld);
    server.listen(Ipv4Addr(127, 0, 0, 1), 3000);
}

<|endoftext|>


<commit_before>use conduit::{Request, Response};
use conduit_middleware::Middleware;

use curl;
use curl::easy::{Easy, List};

use oauth2::*;

use serde_json;
use serde::Deserialize;

use std::str;
use std::error::Error;
use std::collections::HashMap;

use app::App;
use util::{CargoResult, internal, ChainError, human};
use Uploader;

/// Does all the nonsense for sending a GET to Github. Doesn't handle parsing
/// because custom error-code handling may be desirable. Use
/// `parse_github_response` to handle the "common" processing of responses.
pub fn github(app: &App, url: &str, auth: &Token) -> Result<(Easy, Vec<u8>), curl::Error> {
    let url = format!("{}://api.github.com{}", app.config.api_protocol, url);
    info!("GITHUB HTTP: {}", url);

    let mut headers = List::new();
    headers
        .append("Accept: application/vnd.github.v3+json")
        .unwrap();
    headers.append("User-Agent: hello!").unwrap();
    headers
        .append(&format!("Authorization: token {}", auth.access_token))
        .unwrap();

    let mut handle = app.handle();
    handle.url(&url).unwrap();
    handle.get(true).unwrap();
    handle.http_headers(headers).unwrap();

    let mut data = Vec::new();
    {
        let mut transfer = handle.transfer();
        transfer
            .write_function(|buf| {
                data.extend_from_slice(buf);
                Ok(buf.len())
            })
            .unwrap();
        transfer.perform()?;
    }
    Ok((handle, data))
}

/// Checks for normal responses
pub fn parse_github_response<'de, 'a: 'de, T: Deserialize<'de>>(
    mut resp: Easy,
    data: &'a [u8],
) -> CargoResult<T> {
    match resp.response_code().unwrap() {
        200 => {} // Ok!
        403 => {
            return Err(human(
                "It looks like you don't have permission \
                 to query a necessary property from Github \
                 to complete this request. \
                 You may need to re-authenticate on \
                 crates.io to grant permission to read \
                 github org memberships. Just go to \
                 https://crates.io/login",
            ));
        }
        n => {
            let resp = String::from_utf8_lossy(data);
            return Err(internal(&format_args!(
                "didn't get a 200 result from \
                 github, got {} with: {}",
                n,
                resp
            )));
        }
    }

    let json = str::from_utf8(data).ok().chain_error(|| {
        internal("github didn't send a utf8-response")
    })?;

    serde_json::from_str(json).chain_error(|| internal("github didn't send a valid json response"))
}

/// Gets a token with the given string as the access token, but all
/// other info null'd out. Generally, just to be fed to the `github` fn.
pub fn token(token: String) -> Token {
    Token {
        access_token: token,
        scopes: Vec::new(),
        token_type: String::new(),
    }
}

#[derive(Clone, Debug)]
pub struct SecurityHeadersMiddleware {
    headers: HashMap<String, Vec<String>>,
}

impl SecurityHeadersMiddleware {
    pub fn new(uploader: &Uploader) -> Self {
        let mut headers = HashMap::new();

        headers.insert(
            "X-Content-Type-Options".into(),
            vec!["nosniff".into()],
        );

        headers.insert(
            "X-Frame-Options".into(),
            vec!["SAMEORIGIN".into()],
        );

        headers.insert(
            "X-XSS-Protection".into(),
            vec!["1; mode=block".into()],
        );

        let s3_host = match *uploader {
            Uploader::S3 { ref bucket, .. } => bucket.host(),
            _ => unreachable!("This middleware should only be used in the production environment, \
                               which should also require an S3 uploader, QED"),
        };

        // It would be better if we didn't have to have 'unsafe-eval' in the `script-src`
        // policy, but google charts (used for the download graph on crate pages) uses `eval`
        // to load scripts. Remove 'unsafe-eval' if google fixes the issue:
        // https://github.com/google/google-visualization-issues/issues/1356
        // or if we switch to a different graph generation library.
        headers.insert(
            "Content-Security-Policy".into(),
            vec![
                format!("default-src 'self'; \
                  connect-src 'self' https://docs.rs {}; \
                  script-src 'self' 'unsafe-eval' \
                             https://www.google-analytics.com https://www.google.com; \
                  style-src 'self' https://www.google.com https://ajax.googleapis.com; \
                  img-src *; \
                  object-src 'none'",
                  s3_host
                ),
            ],
        );

        SecurityHeadersMiddleware { headers }
    }
}

impl Middleware for SecurityHeadersMiddleware {
    fn after(
        &self,
        _: &mut Request,
        mut res: Result<Response, Box<Error + Send>>,
    ) -> Result<Response, Box<Error + Send>> {
        if let Ok(ref mut response) = res {
            response.headers.extend(self.headers.clone());
        }
        res
    }
}
<commit_msg>Oops this really is only the host and doesn't include the protocol<commit_after>use conduit::{Request, Response};
use conduit_middleware::Middleware;

use curl;
use curl::easy::{Easy, List};

use oauth2::*;

use serde_json;
use serde::Deserialize;

use std::str;
use std::error::Error;
use std::collections::HashMap;

use app::App;
use util::{CargoResult, internal, ChainError, human};
use Uploader;

/// Does all the nonsense for sending a GET to Github. Doesn't handle parsing
/// because custom error-code handling may be desirable. Use
/// `parse_github_response` to handle the "common" processing of responses.
pub fn github(app: &App, url: &str, auth: &Token) -> Result<(Easy, Vec<u8>), curl::Error> {
    let url = format!("{}://api.github.com{}", app.config.api_protocol, url);
    info!("GITHUB HTTP: {}", url);

    let mut headers = List::new();
    headers
        .append("Accept: application/vnd.github.v3+json")
        .unwrap();
    headers.append("User-Agent: hello!").unwrap();
    headers
        .append(&format!("Authorization: token {}", auth.access_token))
        .unwrap();

    let mut handle = app.handle();
    handle.url(&url).unwrap();
    handle.get(true).unwrap();
    handle.http_headers(headers).unwrap();

    let mut data = Vec::new();
    {
        let mut transfer = handle.transfer();
        transfer
            .write_function(|buf| {
                data.extend_from_slice(buf);
                Ok(buf.len())
            })
            .unwrap();
        transfer.perform()?;
    }
    Ok((handle, data))
}

/// Checks for normal responses
pub fn parse_github_response<'de, 'a: 'de, T: Deserialize<'de>>(
    mut resp: Easy,
    data: &'a [u8],
) -> CargoResult<T> {
    match resp.response_code().unwrap() {
        200 => {} // Ok!
        403 => {
            return Err(human(
                "It looks like you don't have permission \
                 to query a necessary property from Github \
                 to complete this request. \
                 You may need to re-authenticate on \
                 crates.io to grant permission to read \
                 github org memberships. Just go to \
                 https://crates.io/login",
            ));
        }
        n => {
            let resp = String::from_utf8_lossy(data);
            return Err(internal(&format_args!(
                "didn't get a 200 result from \
                 github, got {} with: {}",
                n,
                resp
            )));
        }
    }

    let json = str::from_utf8(data).ok().chain_error(|| {
        internal("github didn't send a utf8-response")
    })?;

    serde_json::from_str(json).chain_error(|| internal("github didn't send a valid json response"))
}

/// Gets a token with the given string as the access token, but all
/// other info null'd out. Generally, just to be fed to the `github` fn.
pub fn token(token: String) -> Token {
    Token {
        access_token: token,
        scopes: Vec::new(),
        token_type: String::new(),
    }
}

#[derive(Clone, Debug)]
pub struct SecurityHeadersMiddleware {
    headers: HashMap<String, Vec<String>>,
}

impl SecurityHeadersMiddleware {
    pub fn new(uploader: &Uploader) -> Self {
        let mut headers = HashMap::new();

        headers.insert(
            "X-Content-Type-Options".into(),
            vec!["nosniff".into()],
        );

        headers.insert(
            "X-Frame-Options".into(),
            vec!["SAMEORIGIN".into()],
        );

        headers.insert(
            "X-XSS-Protection".into(),
            vec!["1; mode=block".into()],
        );

        let s3_host = match *uploader {
            Uploader::S3 { ref bucket, .. } => bucket.host(),
            _ => unreachable!("This middleware should only be used in the production environment, \
                               which should also require an S3 uploader, QED"),
        };

        // It would be better if we didn't have to have 'unsafe-eval' in the `script-src`
        // policy, but google charts (used for the download graph on crate pages) uses `eval`
        // to load scripts. Remove 'unsafe-eval' if google fixes the issue:
        // https://github.com/google/google-visualization-issues/issues/1356
        // or if we switch to a different graph generation library.
        headers.insert(
            "Content-Security-Policy".into(),
            vec![
                format!("default-src 'self'; \
                  connect-src 'self' https://docs.rs https://{}; \
                  script-src 'self' 'unsafe-eval' \
                             https://www.google-analytics.com https://www.google.com; \
                  style-src 'self' https://www.google.com https://ajax.googleapis.com; \
                  img-src *; \
                  object-src 'none'",
                  s3_host
                ),
            ],
        );

        SecurityHeadersMiddleware { headers }
    }
}

impl Middleware for SecurityHeadersMiddleware {
    fn after(
        &self,
        _: &mut Request,
        mut res: Result<Response, Box<Error + Send>>,
    ) -> Result<Response, Box<Error + Send>> {
        if let Ok(ref mut response) = res {
            response.headers.extend(self.headers.clone());
        }
        res
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Element nodes.

use dom::attrlist::AttrList;
use dom::bindings::utils::{Reflectable, DOMString, ErrorResult, Fallible, Reflector};
use dom::bindings::utils::{null_str_as_empty, NamespaceError};
use dom::bindings::utils::{InvalidCharacter, QName, Name, InvalidXMLName, xml_name_type};
use dom::htmlcollection::HTMLCollection;
use dom::clientrect::ClientRect;
use dom::clientrectlist::ClientRectList;
use dom::document::AbstractDocument;
use dom::node::{ElementNodeTypeId, Node, ScriptView, AbstractNode};
use dom::attr:: Attr;
use dom::document;
use dom::namespace;
use dom::namespace::Namespace;
use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery};
use layout_interface::{ContentBoxesResponse};
use style;
use servo_util::tree::{TreeNodeRef, ElementLike};

use std::comm;
use std::hashmap::HashMap;
use std::str::{eq, eq_slice};
use std::ascii::StrAsciiExt;

pub struct Element {
    node: Node<ScriptView>,
    tag_name: ~str,     // TODO: This should be an atom, not a ~str.
    attrs: HashMap<~str, ~[@mut Attr]>,
    attrs_insert_order: ~[(~str, Namespace)], // store an order of attributes.
    style_attribute: Option<style::PropertyDeclarationBlock>,
    attr_list: Option<@mut AttrList>
}

impl Reflectable for Element {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.node.reflector()
    }

    fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
        self.node.mut_reflector()
    }
}

#[deriving(Eq)]
pub enum ElementTypeId {
    HTMLElementTypeId,
    HTMLAnchorElementTypeId,
    HTMLAppletElementTypeId,
    HTMLAreaElementTypeId,
    HTMLAudioElementTypeId,
    HTMLBaseElementTypeId,
    HTMLBRElementTypeId,
    HTMLBodyElementTypeId,
    HTMLButtonElementTypeId,
    HTMLCanvasElementTypeId,
    HTMLDataElementTypeId,
    HTMLDataListElementTypeId,
    HTMLDirectoryElementTypeId,
    HTMLDListElementTypeId,
    HTMLDivElementTypeId,
    HTMLEmbedElementTypeId,
    HTMLFieldSetElementTypeId,
    HTMLFontElementTypeId,
    HTMLFormElementTypeId,
    HTMLFrameElementTypeId,
    HTMLFrameSetElementTypeId,
    HTMLHRElementTypeId,
    HTMLHeadElementTypeId,
    HTMLHeadingElementTypeId,
    HTMLHtmlElementTypeId,
    HTMLIframeElementTypeId,
    HTMLImageElementTypeId,
    HTMLInputElementTypeId,
    HTMLLabelElementTypeId,
    HTMLLegendElementTypeId,
    HTMLLinkElementTypeId,
    HTMLLIElementTypeId,
    HTMLMainElementTypeId,
    HTMLMapElementTypeId,
    HTMLMediaElementTypeId,
    HTMLMetaElementTypeId,
    HTMLMeterElementTypeId,
    HTMLModElementTypeId,
    HTMLObjectElementTypeId,
    HTMLOListElementTypeId,
    HTMLOptGroupElementTypeId,
    HTMLOptionElementTypeId,
    HTMLOutputElementTypeId,
    HTMLParagraphElementTypeId,
    HTMLParamElementTypeId,
    HTMLPreElementTypeId,
    HTMLProgressElementTypeId,
    HTMLQuoteElementTypeId,
    HTMLScriptElementTypeId,
    HTMLSelectElementTypeId,
    HTMLSourceElementTypeId,
    HTMLSpanElementTypeId,
    HTMLStyleElementTypeId,
    HTMLTableElementTypeId,
    HTMLTableCaptionElementTypeId,
    HTMLTableCellElementTypeId,
    HTMLTableDataCellElementTypeId,
    HTMLTableHeaderCellElementTypeId,
    HTMLTableColElementTypeId,
    HTMLTableRowElementTypeId,
    HTMLTableSectionElementTypeId,
    HTMLTemplateElementTypeId,
    HTMLTextAreaElementTypeId,
    HTMLTimeElementTypeId,
    HTMLTitleElementTypeId,
    HTMLTrackElementTypeId,
    HTMLUListElementTypeId,
    HTMLVideoElementTypeId,
    HTMLUnknownElementTypeId,
}

//
// Element methods
//

impl ElementLike for Element {
    fn get_local_name<'a>(&'a self) -> &'a str {
        self.tag_name.as_slice()
    }

    fn get_attr(&self, name: &str) -> Option<~str> {
        self.get_attribute(None, name).map(|attr| attr.value.clone())
    }

    fn get_link(&self) -> Option<~str>{
        // FIXME: This is HTML only.
        match self.node.type_id {
            // http://www.whatwg.org/specs/web-apps/current-work/multipage/selectors.html#selector-link
            ElementNodeTypeId(HTMLAnchorElementTypeId) |
            ElementNodeTypeId(HTMLAreaElementTypeId) |
            ElementNodeTypeId(HTMLLinkElementTypeId)
            => self.get_attr("href"),
            _ => None,
        }
    }
}

impl<'self> Element {
    pub fn new(type_id: ElementTypeId, tag_name: ~str, document: AbstractDocument) -> Element {
        Element {
            node: Node::new(ElementNodeTypeId(type_id), document),
            tag_name: tag_name,
            attrs: HashMap::new(),
            attrs_insert_order: ~[],
            attr_list: None,
            style_attribute: None,
        }
    }

    pub fn normalize_attr_name(&self, name: Option<DOMString>) -> ~str {
        //FIXME: Throw for XML-invalid names
        let owner = self.node.owner_doc();
        if owner.document().doctype == document::HTML { // && self.namespace == Namespace::HTML
            null_str_as_empty(&name).to_ascii_lower()
        } else {
            null_str_as_empty(&name)
        }
    }

    pub fn get_attribute<'a>(&'a self,
                         namespace_url: Option<DOMString>,
                         name: &str) -> Option<@mut Attr> {
        let namespace = Namespace::from_str(namespace_url);
        // FIXME: only case-insensitive in the HTML namespace (as opposed to SVG, etc.)
        let name = name.to_ascii_lower();
        self.attrs.find_equiv(&name).and_then(|attrs| {
            do attrs.iter().find |attr| {
                eq_slice(attr.local_name, name) && attr.namespace == namespace
            }.map(|x| *x)
        })
    }

    pub fn set_attr(&mut self,
                    abstract_self: AbstractNode<ScriptView>,
                    name: DOMString,
                    value: DOMString) -> ErrorResult {
        self.set_attribute(abstract_self, namespace::Null, name, value)
    }

    pub fn set_attribute(&mut self,
                         abstract_self: AbstractNode<ScriptView>,
                         namespace: Namespace,
                         raw_name: DOMString,
                         value: DOMString) -> ErrorResult {
        //FIXME: Throw for XML-invalid names
        //FIXME: Throw for XMLNS-invalid names
        let name = raw_name.to_ascii_lower();
        let (prefix, local_name) = if name.contains(":")  {
            let parts: ~[&str] = name.splitn_iter(':', 1).collect();
            (Some(parts[0].to_owned()), parts[1].to_owned())
        } else {
            (None, name.clone())
        };
        match prefix {
            Some(ref prefix_str) => {
                if (namespace == namespace::Null ||
                    (eq(prefix_str, &~"xml") && namespace != namespace::XML) ||
                    (eq(prefix_str, &~"xmlns") && namespace != namespace::XMLNS)) {
                    return Err(NamespaceError);
                }
            },
            None => {}
        }

        // FIXME: reduce the time of `value.clone()`.
        let win = self.node.owner_doc().document().window;
        let new_attr = Attr::new_ns(win, local_name.clone(), value.clone(),
                                    name.clone(), namespace.clone(), prefix);
        self.attrs.mangle(local_name.clone(), new_attr,
                          |new_name: &~str, new_value: @mut Attr| {
                              // register to the ordered list.
                              let order_value = (new_name.clone(), new_value.namespace.clone());
                              self.attrs_insert_order.push(order_value);
                              ~[new_value]
                          },
                          |name, old_value: &mut ~[@mut Attr], new_value: @mut Attr| {
                              // update value.
                              let mut found = false;
                              for attr in old_value.mut_iter() {
                                  if eq_slice(attr.local_name, *name) &&
                                     attr.namespace == new_value.namespace {
                                      *attr = new_value;
                                      found = true;
                                      break;
                                  }

                              }
                              if !found {
                                  old_value.push(new_value);
                                  let order_value = (name.clone(), new_value.namespace.clone());
                                  self.attrs_insert_order.push(order_value);
                              }
                          });

        self.after_set_attr(abstract_self, &namespace, local_name, value);
        Ok(())
    }

    fn after_set_attr(&mut self,
                      abstract_self: AbstractNode<ScriptView>,
                      namespace: &Namespace,
                      local_name: DOMString,
                      value: DOMString) {

        if "style" == local_name && *namespace == namespace::Null {
             self.style_attribute = Some(style::parse_style_attribute(value));
        }

        // TODO: update owner document's id hashmap for `document.getElementById()`
        //       if `name` == "id".

        //XXXjdm We really need something like a vtable so we can call AfterSetAttr.
        //       This hardcoding is awful.
        match abstract_self.type_id() {
            ElementNodeTypeId(HTMLImageElementTypeId) => {
                do abstract_self.with_mut_image_element |image| {
                    image.AfterSetAttr(local_name.clone(), value.clone());
                }
            }
            ElementNodeTypeId(HTMLIframeElementTypeId) => {
                do abstract_self.with_mut_iframe_element |iframe| {
                    iframe.AfterSetAttr(local_name.clone(), value.clone());
                }
            }
            _ => ()
        }

        if abstract_self.is_in_doc() {
            let document = self.node.owner_doc();
            document.document().content_changed();
        }
    }
}

impl Element {
    pub fn TagName(&self) -> DOMString {
        self.tag_name.to_owned().to_ascii_upper()
    }

    pub fn Id(&self, _abstract_self: AbstractNode<ScriptView>) -> DOMString {
        match self.get_attr(&"id") {
            Some(x) => x,
            None => ~""
        }
    }

    pub fn SetId(&mut self, abstract_self: AbstractNode<ScriptView>, id: DOMString) {
        self.set_attribute(abstract_self, namespace::Null, ~"id", id);
    }

    pub fn Attributes(&mut self, abstract_self: AbstractNode<ScriptView>) -> @mut AttrList {
        match self.attr_list {
            None => {
                let window = self.node.owner_doc().document().window;
                let list = AttrList::new(window, abstract_self);
                self.attr_list = Some(list);
                list
            }
            Some(list) => list
        }
    }

    pub fn GetAttribute(&self, name: DOMString) -> Option<DOMString> {
        self.get_attr(name).map(|s| s.to_owned())
    }

    pub fn GetAttributeNS(&self, namespace: Option<DOMString>, local_name: DOMString) -> Option<DOMString> {
        self.get_attribute(namespace, local_name)
            .map(|attr| attr.value.clone())
    }

    pub fn SetAttribute(&mut self,
                        abstract_self: AbstractNode<ScriptView>,
                        name: DOMString,
                        value: DOMString) -> ErrorResult {
        self.set_attr(abstract_self, name, value);
        Ok(())
    }

    pub fn SetAttributeNS(&mut self,
                          abstract_self: AbstractNode<ScriptView>,
                          namespace_url: Option<DOMString>,
                          name: DOMString,
                          value: DOMString) -> ErrorResult {
        let name_type = xml_name_type(name);
        match name_type {
            InvalidXMLName => return Err(InvalidCharacter),
            Name => return Err(NamespaceError),
            QName => {}
        }

        let namespace = Namespace::from_str(namespace_url);
        self.set_attribute(abstract_self, namespace, name, value)
    }

    pub fn RemoveAttribute(&self, _name: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn RemoveAttributeNS(&self, _namespace: Option<DOMString>, _localname: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn HasAttribute(&self, name: DOMString) -> bool {
        self.GetAttribute(name).is_some()
    }

    pub fn HasAttributeNS(&self, namespace: Option<DOMString>, local_name: DOMString) -> bool {
        self.GetAttributeNS(namespace, local_name).is_some()
    }

    pub fn GetElementsByTagName(&self, _localname: DOMString) -> @mut HTMLCollection {
        HTMLCollection::new(self.node.owner_doc().document().window, ~[])
    }

    pub fn GetElementsByTagNameNS(&self, _namespace: Option<DOMString>, _localname: DOMString) -> Fallible<@mut HTMLCollection> {
        Ok(HTMLCollection::new(self.node.owner_doc().document().window, ~[]))
    }

    pub fn GetElementsByClassName(&self, _names: DOMString) -> @mut HTMLCollection {
        HTMLCollection::new(self.node.owner_doc().document().window, ~[])
    }

    pub fn MozMatchesSelector(&self, _selector: DOMString) -> Fallible<bool> {
        Ok(false)
    }

    pub fn SetCapture(&self, _retargetToElement: bool) {
    }

    pub fn ReleaseCapture(&self) {
    }

    pub fn MozRequestFullScreen(&self) {
    }

    pub fn MozRequestPointerLock(&self) {
    }

    pub fn GetClientRects(&self, abstract_self: AbstractNode<ScriptView>) -> @mut ClientRectList {
        let win = self.node.owner_doc().document().window;
        let node = abstract_self;
        assert!(node.is_element());
        let (port, chan) = comm::stream();
        let rects =
            match win.page.query_layout(ContentBoxesQuery(node, chan), port) {
                ContentBoxesResponse(rects) => {
                    do rects.map |r| {
                        ClientRect::new(
                            win,
                            r.origin.y.to_f32().unwrap(),
                            (r.origin.y + r.size.height).to_f32().unwrap(),
                            r.origin.x.to_f32().unwrap(),
                            (r.origin.x + r.size.width).to_f32().unwrap())
                    }
                },
            };

        ClientRectList::new(win, rects)
    }

    pub fn GetBoundingClientRect(&self, abstract_self: AbstractNode<ScriptView>) -> @mut ClientRect {
        let win = self.node.owner_doc().document().window;
        let node = abstract_self;
        assert!(node.is_element());
        let (port, chan) = comm::stream();
        match win.page.query_layout(ContentBoxQuery(node, chan), port) {
            ContentBoxResponse(rect) => {
                ClientRect::new(
                    win,
                    rect.origin.y.to_f32().unwrap(),
                    (rect.origin.y + rect.size.height).to_f32().unwrap(),
                    rect.origin.x.to_f32().unwrap(),
                    (rect.origin.x + rect.size.width).to_f32().unwrap())
            }
        }
    }

    pub fn ScrollIntoView(&self, _top: bool) {
    }

    pub fn ScrollTop(&self) -> i32 {
        0
    }

    pub fn SetScrollTop(&mut self, _scroll_top: i32) {
    }

    pub fn ScrollLeft(&self) -> i32 {
        0
    }

    pub fn SetScrollLeft(&mut self, _scroll_left: i32) {
    }

    pub fn ScrollWidth(&self) -> i32 {
        0
    }

    pub fn ScrollHeight(&self) -> i32 {
        0
    }

    pub fn ClientTop(&self) -> i32 {
        0
    }

    pub fn ClientLeft(&self) -> i32 {
        0
    }

    pub fn ClientWidth(&self) -> i32 {
        0
    }

    pub fn ClientHeight(&self) -> i32 {
        0
    }

    pub fn GetInnerHTML(&self) -> Fallible<DOMString> {
        Ok(~"")
    }

    pub fn SetInnerHTML(&mut self, _value: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn GetOuterHTML(&self) -> Fallible<DOMString> {
        Ok(~"")
    }

    pub fn SetOuterHTML(&mut self, _value: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn InsertAdjacentHTML(&mut self, _position: DOMString, _text: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn QuerySelector(&self, _selectors: DOMString) -> Fallible<Option<AbstractNode<ScriptView>>> {
        Ok(None)
    }
}
<commit_msg>auto merge of #1259 : Ms2ger/servo/get-attr, r=jdm<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Element nodes.

use dom::attrlist::AttrList;
use dom::bindings::utils::{Reflectable, DOMString, ErrorResult, Fallible, Reflector};
use dom::bindings::utils::{null_str_as_empty, NamespaceError};
use dom::bindings::utils::{InvalidCharacter, QName, Name, InvalidXMLName, xml_name_type};
use dom::htmlcollection::HTMLCollection;
use dom::clientrect::ClientRect;
use dom::clientrectlist::ClientRectList;
use dom::document::AbstractDocument;
use dom::node::{ElementNodeTypeId, Node, ScriptView, AbstractNode};
use dom::attr:: Attr;
use dom::document;
use dom::namespace;
use dom::namespace::Namespace;
use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery};
use layout_interface::{ContentBoxesResponse};
use style;
use servo_util::tree::{TreeNodeRef, ElementLike};

use std::comm;
use std::hashmap::HashMap;
use std::str::{eq, eq_slice};
use std::ascii::StrAsciiExt;

pub struct Element {
    node: Node<ScriptView>,
    tag_name: ~str,     // TODO: This should be an atom, not a ~str.
    attrs: HashMap<~str, ~[@mut Attr]>,
    attrs_insert_order: ~[(~str, Namespace)], // store an order of attributes.
    style_attribute: Option<style::PropertyDeclarationBlock>,
    attr_list: Option<@mut AttrList>
}

impl Reflectable for Element {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.node.reflector()
    }

    fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
        self.node.mut_reflector()
    }
}

#[deriving(Eq)]
pub enum ElementTypeId {
    HTMLElementTypeId,
    HTMLAnchorElementTypeId,
    HTMLAppletElementTypeId,
    HTMLAreaElementTypeId,
    HTMLAudioElementTypeId,
    HTMLBaseElementTypeId,
    HTMLBRElementTypeId,
    HTMLBodyElementTypeId,
    HTMLButtonElementTypeId,
    HTMLCanvasElementTypeId,
    HTMLDataElementTypeId,
    HTMLDataListElementTypeId,
    HTMLDirectoryElementTypeId,
    HTMLDListElementTypeId,
    HTMLDivElementTypeId,
    HTMLEmbedElementTypeId,
    HTMLFieldSetElementTypeId,
    HTMLFontElementTypeId,
    HTMLFormElementTypeId,
    HTMLFrameElementTypeId,
    HTMLFrameSetElementTypeId,
    HTMLHRElementTypeId,
    HTMLHeadElementTypeId,
    HTMLHeadingElementTypeId,
    HTMLHtmlElementTypeId,
    HTMLIframeElementTypeId,
    HTMLImageElementTypeId,
    HTMLInputElementTypeId,
    HTMLLabelElementTypeId,
    HTMLLegendElementTypeId,
    HTMLLinkElementTypeId,
    HTMLLIElementTypeId,
    HTMLMainElementTypeId,
    HTMLMapElementTypeId,
    HTMLMediaElementTypeId,
    HTMLMetaElementTypeId,
    HTMLMeterElementTypeId,
    HTMLModElementTypeId,
    HTMLObjectElementTypeId,
    HTMLOListElementTypeId,
    HTMLOptGroupElementTypeId,
    HTMLOptionElementTypeId,
    HTMLOutputElementTypeId,
    HTMLParagraphElementTypeId,
    HTMLParamElementTypeId,
    HTMLPreElementTypeId,
    HTMLProgressElementTypeId,
    HTMLQuoteElementTypeId,
    HTMLScriptElementTypeId,
    HTMLSelectElementTypeId,
    HTMLSourceElementTypeId,
    HTMLSpanElementTypeId,
    HTMLStyleElementTypeId,
    HTMLTableElementTypeId,
    HTMLTableCaptionElementTypeId,
    HTMLTableCellElementTypeId,
    HTMLTableDataCellElementTypeId,
    HTMLTableHeaderCellElementTypeId,
    HTMLTableColElementTypeId,
    HTMLTableRowElementTypeId,
    HTMLTableSectionElementTypeId,
    HTMLTemplateElementTypeId,
    HTMLTextAreaElementTypeId,
    HTMLTimeElementTypeId,
    HTMLTitleElementTypeId,
    HTMLTrackElementTypeId,
    HTMLUListElementTypeId,
    HTMLVideoElementTypeId,
    HTMLUnknownElementTypeId,
}

//
// Element methods
//

impl ElementLike for Element {
    fn get_local_name<'a>(&'a self) -> &'a str {
        self.tag_name.as_slice()
    }

    fn get_attr(&self, name: &str) -> Option<~str> {
        self.get_attribute(None, name).map(|attr| attr.value.clone())
    }

    fn get_link(&self) -> Option<~str>{
        // FIXME: This is HTML only.
        match self.node.type_id {
            // http://www.whatwg.org/specs/web-apps/current-work/multipage/selectors.html#selector-link
            ElementNodeTypeId(HTMLAnchorElementTypeId) |
            ElementNodeTypeId(HTMLAreaElementTypeId) |
            ElementNodeTypeId(HTMLLinkElementTypeId)
            => self.get_attr("href"),
            _ => None,
        }
    }
}

impl<'self> Element {
    pub fn new(type_id: ElementTypeId, tag_name: ~str, document: AbstractDocument) -> Element {
        Element {
            node: Node::new(ElementNodeTypeId(type_id), document),
            tag_name: tag_name,
            attrs: HashMap::new(),
            attrs_insert_order: ~[],
            attr_list: None,
            style_attribute: None,
        }
    }

    pub fn normalize_attr_name(&self, name: Option<DOMString>) -> ~str {
        //FIXME: Throw for XML-invalid names
        let owner = self.node.owner_doc();
        if owner.document().doctype == document::HTML { // && self.namespace == Namespace::HTML
            null_str_as_empty(&name).to_ascii_lower()
        } else {
            null_str_as_empty(&name)
        }
    }

    pub fn get_attribute(&self,
                         namespace_url: Option<DOMString>,
                         name: &str) -> Option<@mut Attr> {
        let namespace = Namespace::from_str(namespace_url);
        // FIXME: only case-insensitive in the HTML namespace (as opposed to SVG, etc.)
        let name = name.to_ascii_lower();
        self.attrs.find_equiv(&name).and_then(|attrs| {
            do attrs.iter().find |attr| {
                eq_slice(attr.local_name, name) && attr.namespace == namespace
            }.map(|x| *x)
        })
    }

    pub fn set_attr(&mut self,
                    abstract_self: AbstractNode<ScriptView>,
                    name: DOMString,
                    value: DOMString) -> ErrorResult {
        self.set_attribute(abstract_self, namespace::Null, name, value)
    }

    pub fn set_attribute(&mut self,
                         abstract_self: AbstractNode<ScriptView>,
                         namespace: Namespace,
                         raw_name: DOMString,
                         value: DOMString) -> ErrorResult {
        //FIXME: Throw for XML-invalid names
        //FIXME: Throw for XMLNS-invalid names
        let name = raw_name.to_ascii_lower();
        let (prefix, local_name) = if name.contains(":")  {
            let parts: ~[&str] = name.splitn_iter(':', 1).collect();
            (Some(parts[0].to_owned()), parts[1].to_owned())
        } else {
            (None, name.clone())
        };
        match prefix {
            Some(ref prefix_str) => {
                if (namespace == namespace::Null ||
                    (eq(prefix_str, &~"xml") && namespace != namespace::XML) ||
                    (eq(prefix_str, &~"xmlns") && namespace != namespace::XMLNS)) {
                    return Err(NamespaceError);
                }
            },
            None => {}
        }

        // FIXME: reduce the time of `value.clone()`.
        let win = self.node.owner_doc().document().window;
        let new_attr = Attr::new_ns(win, local_name.clone(), value.clone(),
                                    name.clone(), namespace.clone(), prefix);
        self.attrs.mangle(local_name.clone(), new_attr,
                          |new_name: &~str, new_value: @mut Attr| {
                              // register to the ordered list.
                              let order_value = (new_name.clone(), new_value.namespace.clone());
                              self.attrs_insert_order.push(order_value);
                              ~[new_value]
                          },
                          |name, old_value: &mut ~[@mut Attr], new_value: @mut Attr| {
                              // update value.
                              let mut found = false;
                              for attr in old_value.mut_iter() {
                                  if eq_slice(attr.local_name, *name) &&
                                     attr.namespace == new_value.namespace {
                                      *attr = new_value;
                                      found = true;
                                      break;
                                  }

                              }
                              if !found {
                                  old_value.push(new_value);
                                  let order_value = (name.clone(), new_value.namespace.clone());
                                  self.attrs_insert_order.push(order_value);
                              }
                          });

        self.after_set_attr(abstract_self, &namespace, local_name, value);
        Ok(())
    }

    fn after_set_attr(&mut self,
                      abstract_self: AbstractNode<ScriptView>,
                      namespace: &Namespace,
                      local_name: DOMString,
                      value: DOMString) {

        if "style" == local_name && *namespace == namespace::Null {
             self.style_attribute = Some(style::parse_style_attribute(value));
        }

        // TODO: update owner document's id hashmap for `document.getElementById()`
        //       if `name` == "id".

        //XXXjdm We really need something like a vtable so we can call AfterSetAttr.
        //       This hardcoding is awful.
        match abstract_self.type_id() {
            ElementNodeTypeId(HTMLImageElementTypeId) => {
                do abstract_self.with_mut_image_element |image| {
                    image.AfterSetAttr(local_name.clone(), value.clone());
                }
            }
            ElementNodeTypeId(HTMLIframeElementTypeId) => {
                do abstract_self.with_mut_iframe_element |iframe| {
                    iframe.AfterSetAttr(local_name.clone(), value.clone());
                }
            }
            _ => ()
        }

        if abstract_self.is_in_doc() {
            let document = self.node.owner_doc();
            document.document().content_changed();
        }
    }
}

impl Element {
    pub fn TagName(&self) -> DOMString {
        self.tag_name.to_owned().to_ascii_upper()
    }

    pub fn Id(&self, _abstract_self: AbstractNode<ScriptView>) -> DOMString {
        match self.get_attr(&"id") {
            Some(x) => x,
            None => ~""
        }
    }

    pub fn SetId(&mut self, abstract_self: AbstractNode<ScriptView>, id: DOMString) {
        self.set_attribute(abstract_self, namespace::Null, ~"id", id);
    }

    pub fn Attributes(&mut self, abstract_self: AbstractNode<ScriptView>) -> @mut AttrList {
        match self.attr_list {
            None => {
                let window = self.node.owner_doc().document().window;
                let list = AttrList::new(window, abstract_self);
                self.attr_list = Some(list);
                list
            }
            Some(list) => list
        }
    }

    pub fn GetAttribute(&self, name: DOMString) -> Option<DOMString> {
        self.get_attr(name).map(|s| s.to_owned())
    }

    pub fn GetAttributeNS(&self, namespace: Option<DOMString>, local_name: DOMString) -> Option<DOMString> {
        self.get_attribute(namespace, local_name)
            .map(|attr| attr.value.clone())
    }

    pub fn SetAttribute(&mut self,
                        abstract_self: AbstractNode<ScriptView>,
                        name: DOMString,
                        value: DOMString) -> ErrorResult {
        self.set_attr(abstract_self, name, value);
        Ok(())
    }

    pub fn SetAttributeNS(&mut self,
                          abstract_self: AbstractNode<ScriptView>,
                          namespace_url: Option<DOMString>,
                          name: DOMString,
                          value: DOMString) -> ErrorResult {
        let name_type = xml_name_type(name);
        match name_type {
            InvalidXMLName => return Err(InvalidCharacter),
            Name => return Err(NamespaceError),
            QName => {}
        }

        let namespace = Namespace::from_str(namespace_url);
        self.set_attribute(abstract_self, namespace, name, value)
    }

    pub fn RemoveAttribute(&self, _name: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn RemoveAttributeNS(&self, _namespace: Option<DOMString>, _localname: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn HasAttribute(&self, name: DOMString) -> bool {
        self.GetAttribute(name).is_some()
    }

    pub fn HasAttributeNS(&self, namespace: Option<DOMString>, local_name: DOMString) -> bool {
        self.GetAttributeNS(namespace, local_name).is_some()
    }

    pub fn GetElementsByTagName(&self, _localname: DOMString) -> @mut HTMLCollection {
        HTMLCollection::new(self.node.owner_doc().document().window, ~[])
    }

    pub fn GetElementsByTagNameNS(&self, _namespace: Option<DOMString>, _localname: DOMString) -> Fallible<@mut HTMLCollection> {
        Ok(HTMLCollection::new(self.node.owner_doc().document().window, ~[]))
    }

    pub fn GetElementsByClassName(&self, _names: DOMString) -> @mut HTMLCollection {
        HTMLCollection::new(self.node.owner_doc().document().window, ~[])
    }

    pub fn MozMatchesSelector(&self, _selector: DOMString) -> Fallible<bool> {
        Ok(false)
    }

    pub fn SetCapture(&self, _retargetToElement: bool) {
    }

    pub fn ReleaseCapture(&self) {
    }

    pub fn MozRequestFullScreen(&self) {
    }

    pub fn MozRequestPointerLock(&self) {
    }

    pub fn GetClientRects(&self, abstract_self: AbstractNode<ScriptView>) -> @mut ClientRectList {
        let win = self.node.owner_doc().document().window;
        let node = abstract_self;
        assert!(node.is_element());
        let (port, chan) = comm::stream();
        let rects =
            match win.page.query_layout(ContentBoxesQuery(node, chan), port) {
                ContentBoxesResponse(rects) => {
                    do rects.map |r| {
                        ClientRect::new(
                            win,
                            r.origin.y.to_f32().unwrap(),
                            (r.origin.y + r.size.height).to_f32().unwrap(),
                            r.origin.x.to_f32().unwrap(),
                            (r.origin.x + r.size.width).to_f32().unwrap())
                    }
                },
            };

        ClientRectList::new(win, rects)
    }

    pub fn GetBoundingClientRect(&self, abstract_self: AbstractNode<ScriptView>) -> @mut ClientRect {
        let win = self.node.owner_doc().document().window;
        let node = abstract_self;
        assert!(node.is_element());
        let (port, chan) = comm::stream();
        match win.page.query_layout(ContentBoxQuery(node, chan), port) {
            ContentBoxResponse(rect) => {
                ClientRect::new(
                    win,
                    rect.origin.y.to_f32().unwrap(),
                    (rect.origin.y + rect.size.height).to_f32().unwrap(),
                    rect.origin.x.to_f32().unwrap(),
                    (rect.origin.x + rect.size.width).to_f32().unwrap())
            }
        }
    }

    pub fn ScrollIntoView(&self, _top: bool) {
    }

    pub fn ScrollTop(&self) -> i32 {
        0
    }

    pub fn SetScrollTop(&mut self, _scroll_top: i32) {
    }

    pub fn ScrollLeft(&self) -> i32 {
        0
    }

    pub fn SetScrollLeft(&mut self, _scroll_left: i32) {
    }

    pub fn ScrollWidth(&self) -> i32 {
        0
    }

    pub fn ScrollHeight(&self) -> i32 {
        0
    }

    pub fn ClientTop(&self) -> i32 {
        0
    }

    pub fn ClientLeft(&self) -> i32 {
        0
    }

    pub fn ClientWidth(&self) -> i32 {
        0
    }

    pub fn ClientHeight(&self) -> i32 {
        0
    }

    pub fn GetInnerHTML(&self) -> Fallible<DOMString> {
        Ok(~"")
    }

    pub fn SetInnerHTML(&mut self, _value: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn GetOuterHTML(&self) -> Fallible<DOMString> {
        Ok(~"")
    }

    pub fn SetOuterHTML(&mut self, _value: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn InsertAdjacentHTML(&mut self, _position: DOMString, _text: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn QuerySelector(&self, _selectors: DOMString) -> Fallible<Option<AbstractNode<ScriptView>>> {
        Ok(None)
    }
}
<|endoftext|>


<commit_before>//! `GenericArray` iterator implementation.

use super::{ArrayLength, GenericArray};
use core::iter::FusedIterator;
use core::mem::{MaybeUninit, ManuallyDrop};
use core::{cmp, fmt, ptr, mem};

/// An iterator that moves out of a `GenericArray`
pub struct GenericArrayIter<T, N: ArrayLength<T>> {
    // Invariants: index <= index_back <= N
    // Only values in array[index..index_back] are alive at any given time.
    // Values from array[..index] and array[index_back..] are already moved/dropped.
    array: ManuallyDrop<GenericArray<T, N>>,
    index: usize,
    index_back: usize,
}

#[cfg(test)]
mod test {
    use super::*;

    fn send<I: Send>(_iter: I) {}

    #[test]
    fn test_send_iter() {
        send(GenericArray::from([1, 2, 3, 4]).into_iter());
    }
}

impl<T, N> GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    /// Returns the remaining items of this iterator as a slice
    #[inline]
    pub fn as_slice(&self) -> &[T] {
        &self.array.as_slice()[self.index..self.index_back]
    }

    /// Returns the remaining items of this iterator as a mutable slice
    #[inline]
    pub fn as_mut_slice(&mut self) -> &mut [T] {
        &mut self.array.as_mut_slice()[self.index..self.index_back]
    }
}

impl<T, N> IntoIterator for GenericArray<T, N>
where
    N: ArrayLength<T>,
{
    type Item = T;
    type IntoIter = GenericArrayIter<T, N>;

    fn into_iter(self) -> Self::IntoIter {
        GenericArrayIter {
            array: ManuallyDrop::new(self),
            index: 0,
            index_back: N::USIZE,
        }
    }
}

// Based on work in rust-lang/rust#49000
impl<T: fmt::Debug, N> fmt::Debug for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("GenericArrayIter")
            .field(&self.as_slice())
            .finish()
    }
}

impl<T, N> Drop for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    #[inline]
    fn drop(&mut self) {
        if mem::needs_drop::<T>() {
            // Drop values that are still alive.
            for p in self.as_mut_slice() {
                unsafe {
                    ptr::drop_in_place(p);
                }
            }
        }
    }
}

// Based on work in rust-lang/rust#49000
impl<T: Clone, N> Clone for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    fn clone(&self) -> Self {
        // This places all cloned elements at the start of the new array iterator,
        // not at their original indices.
        unsafe {
            let mut array: MaybeUninit<GenericArray<T, N>> = MaybeUninit::uninit();
            let mut index_back = 0;

            for (dst, src) in (&mut *array.as_mut_ptr()).iter_mut().zip(self.as_slice()) {
                ptr::write(dst, src.clone());

                index_back += 1;
            }

            GenericArrayIter {
                array: ManuallyDrop::new(array.assume_init()),
                index: 0,
                index_back
            }
        }
    }
}

impl<T, N> Iterator for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    type Item = T;

    #[inline]
    fn next(&mut self) -> Option<T> {
        if self.index < self.index_back {
            let p = unsafe { Some(ptr::read(self.array.get_unchecked(self.index))) };

            self.index += 1;

            p
        } else {
            None
        }
    }

    fn fold<B, F>(mut self, init: B, mut f: F) -> B
    where
        F: FnMut(B, Self::Item) -> B,
    {
        let ret = unsafe {
            let GenericArrayIter {
                ref array,
                ref mut index,
                index_back,
            } = self;

            let remaining = &array[*index..index_back];

            remaining.iter().fold(init, |acc, src| {
                let value = ptr::read(src);

                *index += 1;

                f(acc, value)
            })
        };

        // ensure the drop happens here after iteration
        drop(self);

        ret
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len();
        (len, Some(len))
    }

    #[inline]
    fn count(self) -> usize {
        self.len()
    }

    fn nth(&mut self, n: usize) -> Option<T> {
        // First consume values prior to the nth.
        let ndrop = cmp::min(n, self.len());

        for p in &mut self.array[self.index..self.index + ndrop] {
            self.index += 1;

            unsafe {
                ptr::drop_in_place(p);
            }
        }

        self.next()
    }

    #[inline]
    fn last(mut self) -> Option<T> {
        // Note, everything else will correctly drop first as `self` leaves scope.
        self.next_back()
    }
}

impl<T, N> DoubleEndedIterator for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    fn next_back(&mut self) -> Option<T> {
        if self.index < self.index_back {
            self.index_back -= 1;

            unsafe { Some(ptr::read(self.array.get_unchecked(self.index_back))) }
        } else {
            None
        }
    }

    fn rfold<B, F>(mut self, init: B, mut f: F) -> B
    where
        F: FnMut(B, Self::Item) -> B,
    {
        let ret = unsafe {
            let GenericArrayIter {
                ref array,
                index,
                ref mut index_back,
            } = self;

            let remaining = &array[index..*index_back];

            remaining.iter().rfold(init, |acc, src| {
                let value = ptr::read(src);

                *index_back -= 1;

                f(acc, value)
            })
        };

        // ensure the drop happens here after iteration
        drop(self);

        ret
    }
}

impl<T, N> ExactSizeIterator for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    fn len(&self) -> usize {
        self.index_back - self.index
    }
}

impl<T, N> FusedIterator for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
}

// TODO: Implement `TrustedLen` when stabilized
<commit_msg>Fully initialize new iterator upon clone (crudely)<commit_after>//! `GenericArray` iterator implementation.

use super::{ArrayLength, GenericArray};
use core::iter::FusedIterator;
use core::mem::ManuallyDrop;
use core::{cmp, fmt, ptr, mem};

/// An iterator that moves out of a `GenericArray`
pub struct GenericArrayIter<T, N: ArrayLength<T>> {
    // Invariants: index <= index_back <= N
    // Only values in array[index..index_back] are alive at any given time.
    // Values from array[..index] and array[index_back..] are already moved/dropped.
    array: ManuallyDrop<GenericArray<T, N>>,
    index: usize,
    index_back: usize,
}

#[cfg(test)]
mod test {
    use super::*;

    fn send<I: Send>(_iter: I) {}

    #[test]
    fn test_send_iter() {
        send(GenericArray::from([1, 2, 3, 4]).into_iter());
    }
}

impl<T, N> GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    /// Returns the remaining items of this iterator as a slice
    #[inline]
    pub fn as_slice(&self) -> &[T] {
        &self.array.as_slice()[self.index..self.index_back]
    }

    /// Returns the remaining items of this iterator as a mutable slice
    #[inline]
    pub fn as_mut_slice(&mut self) -> &mut [T] {
        &mut self.array.as_mut_slice()[self.index..self.index_back]
    }
}

impl<T, N> IntoIterator for GenericArray<T, N>
where
    N: ArrayLength<T>,
{
    type Item = T;
    type IntoIter = GenericArrayIter<T, N>;

    fn into_iter(self) -> Self::IntoIter {
        GenericArrayIter {
            array: ManuallyDrop::new(self),
            index: 0,
            index_back: N::USIZE,
        }
    }
}

// Based on work in rust-lang/rust#49000
impl<T: fmt::Debug, N> fmt::Debug for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("GenericArrayIter")
            .field(&self.as_slice())
            .finish()
    }
}

impl<T, N> Drop for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    #[inline]
    fn drop(&mut self) {
        if mem::needs_drop::<T>() {
            // Drop values that are still alive.
            for p in self.as_mut_slice() {
                unsafe {
                    ptr::drop_in_place(p);
                }
            }
        }
    }
}

// Based on work in rust-lang/rust#49000
impl<T: Clone, N> Clone for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    fn clone(&self) -> Self {
        // This places all cloned elements at the start of the new array iterator,
        // not at their original indices.
        unsafe {
            let mut array = ptr::read(&self.array);
            let mut index_back = 0;

            for (dst, src) in array.as_mut_slice().into_iter().zip(self.as_slice()) {
                ptr::write(dst, src.clone());
                index_back += 1;
            }

            GenericArrayIter {
                array,
                index: 0,
                index_back
            }
        }
    }
}

impl<T, N> Iterator for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    type Item = T;

    #[inline]
    fn next(&mut self) -> Option<T> {
        if self.index < self.index_back {
            let p = unsafe { Some(ptr::read(self.array.get_unchecked(self.index))) };

            self.index += 1;

            p
        } else {
            None
        }
    }

    fn fold<B, F>(mut self, init: B, mut f: F) -> B
    where
        F: FnMut(B, Self::Item) -> B,
    {
        let ret = unsafe {
            let GenericArrayIter {
                ref array,
                ref mut index,
                index_back,
            } = self;

            let remaining = &array[*index..index_back];

            remaining.iter().fold(init, |acc, src| {
                let value = ptr::read(src);

                *index += 1;

                f(acc, value)
            })
        };

        // ensure the drop happens here after iteration
        drop(self);

        ret
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len();
        (len, Some(len))
    }

    #[inline]
    fn count(self) -> usize {
        self.len()
    }

    fn nth(&mut self, n: usize) -> Option<T> {
        // First consume values prior to the nth.
        let ndrop = cmp::min(n, self.len());

        for p in &mut self.array[self.index..self.index + ndrop] {
            self.index += 1;

            unsafe {
                ptr::drop_in_place(p);
            }
        }

        self.next()
    }

    #[inline]
    fn last(mut self) -> Option<T> {
        // Note, everything else will correctly drop first as `self` leaves scope.
        self.next_back()
    }
}

impl<T, N> DoubleEndedIterator for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    fn next_back(&mut self) -> Option<T> {
        if self.index < self.index_back {
            self.index_back -= 1;

            unsafe { Some(ptr::read(self.array.get_unchecked(self.index_back))) }
        } else {
            None
        }
    }

    fn rfold<B, F>(mut self, init: B, mut f: F) -> B
    where
        F: FnMut(B, Self::Item) -> B,
    {
        let ret = unsafe {
            let GenericArrayIter {
                ref array,
                index,
                ref mut index_back,
            } = self;

            let remaining = &array[index..*index_back];

            remaining.iter().rfold(init, |acc, src| {
                let value = ptr::read(src);

                *index_back -= 1;

                f(acc, value)
            })
        };

        // ensure the drop happens here after iteration
        drop(self);

        ret
    }
}

impl<T, N> ExactSizeIterator for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    fn len(&self) -> usize {
        self.index_back - self.index
    }
}

impl<T, N> FusedIterator for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
}

// TODO: Implement `TrustedLen` when stabilized
<|endoftext|>


<commit_before>#![warn(bad_style,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results, unused_typecasts)]

#![feature(old_orphan_check)]

extern crate "twitter-api" as twitter;
extern crate "rustc-serialize" as rustc_serialize;
extern crate "oauth-client" as oauth;

use std::io::{File, Open, Read, Write, stdio};
use rustc_serialize::Decodable;
use rustc_serialize::json::{self, Json};
use oauth::Token;

const PATH: &'static str = "./tweet.conf";

#[derive(Show, RustcEncodable, RustcDecodable)]
pub struct Config {
    pub consumer_key: String,
    pub consumer_secret: String,
    pub access_key: String,
    pub access_secret: String
}

impl Config {
    pub fn read() -> Option<Config> {
        let path = Path::new(PATH);
        let mut file = match File::open_mode(&path, Open, Read) {
            Ok(f) => f,
            Err(_) => return None
        };
        let conf = Json::from_reader(&mut file).unwrap();
        Decodable::decode(&mut json::Decoder::new(conf)).ok()
    }

    pub fn write(&self) {
        let path = Path::new(PATH);
        let mut file = match File::open_mode(&path, Open, Write) {
            Ok(f) => f,
            Err(e) => panic!("{}", e)
        };
        let _ = file.write_line(json::encode(self).as_slice());
    }
}

fn console_input(prompt: &str) -> String {
    print!("{}\n\t", prompt);
    let line = stdio::stdin().read_line().unwrap();
    line.trim().to_string()
}

fn main() {
    let conf = match Config::read() {
        Some(c) => c,
        None => {
            let consumer_key    = console_input("input your consumer key:");
            let consumer_secret = console_input("input your consumer secret:");
            let consumer = Token::new(consumer_key, consumer_secret);

            let request = twitter::get_request_token(&consumer);
            println!("open the following url:");
            println!("\t{}", twitter::get_authorize_url(&request));
            let pin = console_input("input pin:");
            let access = twitter::get_access_token(&consumer, &request, pin.as_slice());

            let c = Config {
                consumer_key: consumer.key.to_string(),
                consumer_secret: consumer.secret.to_string(),
                access_key: access.key.to_string(),
                access_secret: access.secret.to_string()
            };
            c.write();
            c
        }
    };

    let consumer = Token::new(conf.consumer_key, conf.consumer_secret);
    let access = Token::new(conf.access_key, conf.access_secret);

    let status = console_input("What's happening?");
    twitter::tweet(&consumer, &access, status.as_slice());
}

<commit_msg>fix some warnings<commit_after>#![warn(bad_style,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results, unused_typecasts)]

extern crate "twitter-api" as twitter;
extern crate "rustc-serialize" as rustc_serialize;
extern crate "oauth-client" as oauth;

use std::io::{File, Open, Read, Write, stdio};
use rustc_serialize::Decodable;
use rustc_serialize::json::{self, Json};
use oauth::Token;

const PATH: &'static str = "./tweet.conf";

#[derive(Show, RustcEncodable, RustcDecodable)]
pub struct Config {
    pub consumer_key: String,
    pub consumer_secret: String,
    pub access_key: String,
    pub access_secret: String
}

impl Config {
    pub fn read() -> Option<Config> {
        let path = Path::new(PATH);
        let mut file = match File::open_mode(&path, Open, Read) {
            Ok(f) => f,
            Err(_) => return None
        };
        let conf = Json::from_reader(&mut file).unwrap();
        Decodable::decode(&mut json::Decoder::new(conf)).ok()
    }

    pub fn write(&self) {
        let path = Path::new(PATH);
        let mut file = match File::open_mode(&path, Open, Write) {
            Ok(f) => f,
            Err(e) => panic!("{}", e)
        };
        let _ = file.write_line(json::encode(self).as_slice());
    }
}

fn console_input(prompt: &str) -> String {
    print!("{}\n\t", prompt);
    let line = stdio::stdin().read_line().unwrap();
    line.trim().to_string()
}

fn main() {
    let conf = match Config::read() {
        Some(c) => c,
        None => {
            let consumer_key    = console_input("input your consumer key:");
            let consumer_secret = console_input("input your consumer secret:");
            let consumer = Token::new(consumer_key, consumer_secret);

            let request = twitter::get_request_token(&consumer);
            println!("open the following url:");
            println!("\t{}", twitter::get_authorize_url(&request));
            let pin = console_input("input pin:");
            let access = twitter::get_access_token(&consumer, &request, pin.as_slice());

            let c = Config {
                consumer_key: consumer.key.to_string(),
                consumer_secret: consumer.secret.to_string(),
                access_key: access.key.to_string(),
                access_secret: access.secret.to_string()
            };
            c.write();
            c
        }
    };

    let consumer = Token::new(conf.consumer_key, conf.consumer_secret);
    let access = Token::new(conf.access_key, conf.access_secret);

    let status = console_input("What's happening?");
    twitter::tweet(&consumer, &access, status.as_slice());
}

<|endoftext|>


<commit_before>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
/// This module implements our vsock connection state machine. The heavy lifting is done by
/// `connection::VsockConnection`, while this file only defines some constants and helper structs.
mod connection;
mod txbuf;

use std::fmt;

pub use connection::VsockConnection;

pub mod defs {
    /// Vsock connection TX buffer capacity.
    pub const CONN_TX_BUF_SIZE: u32 = 64 * 1024;

    /// When the guest thinks we have less than this amount of free buffer space,
    /// we will send them a credit update packet.
    pub const CONN_CREDIT_UPDATE_THRESHOLD: u32 = 4 * 1024;

    /// Connection request timeout, in millis.
    pub const CONN_REQUEST_TIMEOUT_MS: u64 = 2000;

    /// Connection graceful shutdown timeout, in millis.
    pub const CONN_SHUTDOWN_TIMEOUT_MS: u64 = 2000;
}

#[derive(Debug)]
pub enum Error {
    /// Attempted to push data to a full TX buffer.
    TxBufFull,
    /// An I/O error occurred, when attempting to flush the connection TX buffer.
    TxBufFlush(std::io::Error),
    /// An I/O error occurred, when attempting to write data to the host-side stream.
    StreamWrite(std::io::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Self::TxBufFull => write!(f, "Attempted to push data to a full TX buffer"),
            Self::TxBufFlush(err) => write!(
                f,
                "An I/O error occurred, when attempting to flush the connection TX buffer: {}",
                err
            ),
            Self::StreamWrite(err) => write!(
                f,
                "An I/O error occurred, when attempting to write data to the host-side stream: {}",
                err
            ),
        }
    }
}

impl std::error::Error for Error {}

type Result<T> = std::result::Result<T, Error>;

/// A vsock connection state.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ConnState {
    /// The connection has been initiated by the host end, but is yet to be confirmed by the guest.
    LocalInit,
    /// The connection has been initiated by the guest, but we are yet to confirm it, by sending
    /// a response packet (VSOCK_OP_RESPONSE).
    PeerInit,
    /// The connection handshake has been performed successfully, and data can now be exchanged.
    Established,
    /// The host (AF_UNIX) socket was closed.
    LocalClosed,
    /// A VSOCK_OP_SHUTDOWN packet was received from the guest. The tuple represents the guest R/W
    /// indication: (will_not_recv_anymore_data, will_not_send_anymore_data).
    PeerClosed(bool, bool),
    /// The connection is scheduled to be forcefully terminated as soon as possible.
    Killed,
}

/// An RX indication, used by `VsockConnection` to schedule future `recv_pkt()` responses.
/// For instance, after being notified that there is available data to be read from the host stream
/// (via `notify()`), the connection will store a `PendingRx::Rw` to be later inspected by
/// `recv_pkt()`.
#[derive(Clone, Copy, PartialEq)]
enum PendingRx {
    /// We need to yield a connection request packet (VSOCK_OP_REQUEST).
    Request = 0,
    /// We need to yield a connection response packet (VSOCK_OP_RESPONSE).
    Response = 1,
    /// We need to yield a forceful connection termination packet (VSOCK_OP_RST).
    Rst = 2,
    /// We need to yield a data packet (VSOCK_OP_RW), by reading from the AF_UNIX socket.
    Rw = 3,
    /// We need to yield a credit update packet (VSOCK_OP_CREDIT_UPDATE).
    CreditUpdate = 4,
}
impl PendingRx {
    /// Transform the enum value into a bitmask, that can be used for set operations.
    fn into_mask(self) -> u16 {
        1u16 << (self as u16)
    }
}

/// A set of RX indications (`PendingRx` items).
struct PendingRxSet {
    data: u16,
}

impl PendingRxSet {
    /// Insert an item into the set.
    fn insert(&mut self, it: PendingRx) {
        self.data |= it.into_mask();
    }

    /// Remove an item from the set and return:
    /// - true, if the item was in the set; or
    /// - false, if the item wasn't in the set.
    fn remove(&mut self, it: PendingRx) -> bool {
        let ret = self.contains(it);
        self.data &= !it.into_mask();
        ret
    }

    /// Check if an item is present in this set.
    fn contains(&self, it: PendingRx) -> bool {
        self.data & it.into_mask() != 0
    }

    /// Check if the set is empty.
    fn is_empty(&self) -> bool {
        self.data == 0
    }
}

/// Create a set containing only one item.
impl From<PendingRx> for PendingRxSet {
    fn from(it: PendingRx) -> Self {
        Self {
            data: it.into_mask(),
        }
    }
}

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

    #[test]
    fn test_display_error() {
        assert_eq!(
            format!("{}", Error::TxBufFull),
            "Attempted to push data to a full TX buffer"
        );

        assert_eq!(
            format!(
                "{}",
                Error::TxBufFlush(std::io::Error::from(std::io::ErrorKind::Other))
            ),
            "An I/O error occurred, when attempting to flush the connection TX buffer: other os \
             error"
        );

        assert_eq!(
            format!(
                "{}",
                Error::StreamWrite(std::io::Error::from(std::io::ErrorKind::Other))
            ),
            "An I/O error occurred, when attempting to write data to the host-side stream: other \
             os error"
        );
    }
}
<commit_msg>Fix `test_display_error` vsock test<commit_after>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
/// This module implements our vsock connection state machine. The heavy lifting is done by
/// `connection::VsockConnection`, while this file only defines some constants and helper structs.
mod connection;
mod txbuf;

use std::fmt;

pub use connection::VsockConnection;

pub mod defs {
    /// Vsock connection TX buffer capacity.
    pub const CONN_TX_BUF_SIZE: u32 = 64 * 1024;

    /// When the guest thinks we have less than this amount of free buffer space,
    /// we will send them a credit update packet.
    pub const CONN_CREDIT_UPDATE_THRESHOLD: u32 = 4 * 1024;

    /// Connection request timeout, in millis.
    pub const CONN_REQUEST_TIMEOUT_MS: u64 = 2000;

    /// Connection graceful shutdown timeout, in millis.
    pub const CONN_SHUTDOWN_TIMEOUT_MS: u64 = 2000;
}

#[derive(Debug)]
pub enum Error {
    /// Attempted to push data to a full TX buffer.
    TxBufFull,
    /// An I/O error occurred, when attempting to flush the connection TX buffer.
    TxBufFlush(std::io::Error),
    /// An I/O error occurred, when attempting to write data to the host-side stream.
    StreamWrite(std::io::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Self::TxBufFull => write!(f, "Attempted to push data to a full TX buffer"),
            Self::TxBufFlush(err) => write!(
                f,
                "An I/O error occurred, when attempting to flush the connection TX buffer: {}",
                err
            ),
            Self::StreamWrite(err) => write!(
                f,
                "An I/O error occurred, when attempting to write data to the host-side stream: {}",
                err
            ),
        }
    }
}

impl std::error::Error for Error {}

type Result<T> = std::result::Result<T, Error>;

/// A vsock connection state.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ConnState {
    /// The connection has been initiated by the host end, but is yet to be confirmed by the guest.
    LocalInit,
    /// The connection has been initiated by the guest, but we are yet to confirm it, by sending
    /// a response packet (VSOCK_OP_RESPONSE).
    PeerInit,
    /// The connection handshake has been performed successfully, and data can now be exchanged.
    Established,
    /// The host (AF_UNIX) socket was closed.
    LocalClosed,
    /// A VSOCK_OP_SHUTDOWN packet was received from the guest. The tuple represents the guest R/W
    /// indication: (will_not_recv_anymore_data, will_not_send_anymore_data).
    PeerClosed(bool, bool),
    /// The connection is scheduled to be forcefully terminated as soon as possible.
    Killed,
}

/// An RX indication, used by `VsockConnection` to schedule future `recv_pkt()` responses.
/// For instance, after being notified that there is available data to be read from the host stream
/// (via `notify()`), the connection will store a `PendingRx::Rw` to be later inspected by
/// `recv_pkt()`.
#[derive(Clone, Copy, PartialEq)]
enum PendingRx {
    /// We need to yield a connection request packet (VSOCK_OP_REQUEST).
    Request = 0,
    /// We need to yield a connection response packet (VSOCK_OP_RESPONSE).
    Response = 1,
    /// We need to yield a forceful connection termination packet (VSOCK_OP_RST).
    Rst = 2,
    /// We need to yield a data packet (VSOCK_OP_RW), by reading from the AF_UNIX socket.
    Rw = 3,
    /// We need to yield a credit update packet (VSOCK_OP_CREDIT_UPDATE).
    CreditUpdate = 4,
}
impl PendingRx {
    /// Transform the enum value into a bitmask, that can be used for set operations.
    fn into_mask(self) -> u16 {
        1u16 << (self as u16)
    }
}

/// A set of RX indications (`PendingRx` items).
struct PendingRxSet {
    data: u16,
}

impl PendingRxSet {
    /// Insert an item into the set.
    fn insert(&mut self, it: PendingRx) {
        self.data |= it.into_mask();
    }

    /// Remove an item from the set and return:
    /// - true, if the item was in the set; or
    /// - false, if the item wasn't in the set.
    fn remove(&mut self, it: PendingRx) -> bool {
        let ret = self.contains(it);
        self.data &= !it.into_mask();
        ret
    }

    /// Check if an item is present in this set.
    fn contains(&self, it: PendingRx) -> bool {
        self.data & it.into_mask() != 0
    }

    /// Check if the set is empty.
    fn is_empty(&self) -> bool {
        self.data == 0
    }
}

/// Create a set containing only one item.
impl From<PendingRx> for PendingRxSet {
    fn from(it: PendingRx) -> Self {
        Self {
            data: it.into_mask(),
        }
    }
}

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

    #[test]
    fn test_display_error() {
        assert_eq!(
            format!("{}", Error::TxBufFull),
            "Attempted to push data to a full TX buffer"
        );

        assert_eq!(
            Error::TxBufFlush(std::io::Error::from(std::io::ErrorKind::Other)).to_string(),
            "An I/O error occurred, when attempting to flush the connection TX buffer: other error"
        );

        assert_eq!(
            Error::StreamWrite(std::io::Error::from(std::io::ErrorKind::Other)).to_string(),
            "An I/O error occurred, when attempting to write data to the host-side stream: other \
             error"
        );
    }
}
<|endoftext|>