<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/. */

use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::Bindings::CloseEventBinding;
use dom::bindings::codegen::Bindings::CloseEventBinding::CloseEventMethods;
use dom::bindings::codegen::InheritTypes::EventCast;
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JSRef,Temporary, Rootable};
use dom::bindings::utils::reflect_dom_object;
use dom::event::{Event, EventTypeId, EventBubbles, EventCancelable};
use script_task::ScriptChan;
use std::borrow::ToOwned;
use std::cell::Cell;
use util::str::DOMString;

#[dom_struct]
pub struct CloseEvent{
    event: Event,
    wasClean: Cell<bool>,
    code: Cell<u16>,
    reason: DOMRefCell<DOMString>
}

impl CloseEvent{
    pub fn new_inherited(type_id: EventTypeId) -> CloseEvent{
        CloseEvent{
            event: Event::new_inherited(type_id),
            wasClean: Cell::new(true),
            code: Cell::new(0),
            reason: DOMRefCell::new("".to_owned())
        }
    }

    pub fn new(global: GlobalRef,
               type_: DOMString,
               bubbles: EventBubbles,
               cancelable: EventCancelable,
               wasClean: bool,
               code: u16,
               reason: DOMString) -> Temporary<CloseEvent> {
        let ev = reflect_dom_object(box CloseEvent::new_inherited(EventTypeId::CloseEvent),
                                    global,
                                    CloseEventBinding::Wrap);
        let ev = ev.root();
        let event: JSRef<Event> = EventCast::from_ref(ev.r());
        event.InitEvent(type_,
                        bubbles == EventBubbles::Bubbles,
                        cancelable == EventCancelable::Cancelable);
        let ev = ev.r();
        ev.wasClean.set(wasClean);
        ev.code.set(code);
        *ev.reason.borrow_mut() = reason;
        Temporary::from_rooted(ev)
    }

    pub fn Constructor(global: GlobalRef,
                       type_: DOMString,
                       init: &CloseEventBinding::CloseEventInit) -> Fallible<Temporary<CloseEvent>> {
        let clean_status = init.wasClean.unwrap_or(true);
        let cd = init.code.unwrap_or(0);
        let rsn = match init.reason.as_ref() {
            Some(reason) => reason.clone(),
            None => "".to_owned(),
        };
        let bubbles = if init.parent.bubbles { EventBubbles::Bubbles } else { EventBubbles::DoesNotBubble };
        let cancelable = if init.parent.cancelable { EventCancelable::Cancelable } else { EventCancelable::NotCancelable };
        Ok(CloseEvent::new(global, type_, bubbles, cancelable, clean_status, cd, rsn))
    }
}

impl<'a> CloseEventMethods for JSRef<'a, CloseEvent>{
    fn WasClean(self) -> bool {
        self.wasClean.get()
    }

    fn Code(self) -> u16 {
        self.code.get()
    }

    fn Reason(self) -> DOMString {
        let reason = self.reason.borrow();
        reason.clone()
    }
}
<commit_msg>Improve formatting in closeevent.rs.<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/. */

use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::Bindings::CloseEventBinding;
use dom::bindings::codegen::Bindings::CloseEventBinding::CloseEventMethods;
use dom::bindings::codegen::InheritTypes::EventCast;
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JSRef, Temporary, Rootable};
use dom::bindings::utils::reflect_dom_object;
use dom::event::{Event, EventTypeId, EventBubbles, EventCancelable};
use script_task::ScriptChan;

use util::str::DOMString;

use std::borrow::ToOwned;
use std::cell::Cell;

#[dom_struct]
pub struct CloseEvent {
    event: Event,
    wasClean: Cell<bool>,
    code: Cell<u16>,
    reason: DOMRefCell<DOMString>
}

impl CloseEvent {
    pub fn new_inherited(type_id: EventTypeId) -> CloseEvent {
        CloseEvent {
            event: Event::new_inherited(type_id),
            wasClean: Cell::new(true),
            code: Cell::new(0),
            reason: DOMRefCell::new("".to_owned())
        }
    }

    pub fn new(global: GlobalRef,
               type_: DOMString,
               bubbles: EventBubbles,
               cancelable: EventCancelable,
               wasClean: bool,
               code: u16,
               reason: DOMString) -> Temporary<CloseEvent> {
        let ev = reflect_dom_object(box CloseEvent::new_inherited(EventTypeId::CloseEvent),
                                    global,
                                    CloseEventBinding::Wrap);
        let ev = ev.root();
        let event: JSRef<Event> = EventCast::from_ref(ev.r());
        event.InitEvent(type_,
                        bubbles == EventBubbles::Bubbles,
                        cancelable == EventCancelable::Cancelable);
        let ev = ev.r();
        ev.wasClean.set(wasClean);
        ev.code.set(code);
        *ev.reason.borrow_mut() = reason;
        Temporary::from_rooted(ev)
    }

    pub fn Constructor(global: GlobalRef,
                       type_: DOMString,
                       init: &CloseEventBinding::CloseEventInit)
                       -> Fallible<Temporary<CloseEvent>> {
        let clean_status = init.wasClean.unwrap_or(true);
        let cd = init.code.unwrap_or(0);
        let rsn = match init.reason.as_ref() {
            Some(reason) => reason.clone(),
            None => "".to_owned(),
        };
        let bubbles = if init.parent.bubbles { EventBubbles::Bubbles } else { EventBubbles::DoesNotBubble };
        let cancelable = if init.parent.cancelable { EventCancelable::Cancelable } else { EventCancelable::NotCancelable };
        Ok(CloseEvent::new(global, type_, bubbles, cancelable, clean_status, cd, rsn))
    }
}

impl<'a> CloseEventMethods for JSRef<'a, CloseEvent> {
    fn WasClean(self) -> bool {
        self.wasClean.get()
    }

    fn Code(self) -> u16 {
        self.code.get()
    }

    fn Reason(self) -> DOMString {
        let reason = self.reason.borrow();
        reason.clone()
    }
}
<|endoftext|>


<commit_before>extern crate wobj = "wavefront-obj";

use piston::AssetStore;
use std::io;

use vertex::Vertex;

#[deriving(PartialEq, Eq, FromPrimitive, Show)]
pub enum Type {
    Slab = 0,
}

static TYPE_LEN: uint = 1;

impl Type {
    pub fn get_obj_file(&self) -> Option<&'static str> {
        match *self {
            Slab => Some("slab.obj"),
        }
    }

    pub fn to_uint(&self) -> uint {
        *self as uint
    }
}

pub struct TypeIterator {
    ty: uint,
}

impl TypeIterator {
    pub fn new() -> TypeIterator {
        TypeIterator {
            ty: 0
        }
    }
}

impl Iterator<Type> for TypeIterator {
    fn next(&mut self) -> Option<Type> {
        match self.ty {
            x if x < TYPE_LEN => {
                self.ty += 1;
                FromPrimitive::from_uint(x)
            },
            _ => None
        }
    }
}

pub struct Data {
    pub objs: Vec<Option<wobj::obj::ObjSet>>,
}

impl Data {
    pub fn from_asset_store(asset_store: &AssetStore) -> Data {
        Data {
            objs: read_objs(asset_store)
        }
    }
}

pub fn read_objs(asset_store: &AssetStore) -> Vec<Option<wobj::obj::ObjSet>> {
    let mut vec = Vec::new();
    for it in TypeIterator::new() {
        match it.get_obj_file() {
            None => vec.push(None),
            Some(file) => vec.push(Some({
                    let txt = io::File::open(&asset_store.path(file).unwrap()).read_to_string().unwrap();
                    wobj::obj::parse(txt).unwrap()
                }))
        }
    }
    vec
}

/// Stores [start, end) ranges to vertices.
pub struct VertexRange(uint, uint);

impl VertexRange {
    /// Extracts the coordinates of the corners and stores it in a list.
    ///
    /// Returns the range where the object is stored in the list.
    pub fn add_vertices(
        obj: &wobj::obj::Object,
        vertices: &mut Vec<Vertex>
    ) -> VertexRange {
        let start = vertices.len();
        for v in obj.vertices.iter() {
            vertices.push(Vertex::new([v.x as f32, v.y as f32, v.z as f32]));
        }
        VertexRange(start, vertices.len())
    }
}

/// Stores [start, end) ranges to indices.
pub struct IndexRange(uint, uint);

impl IndexRange {
    /// Extracts the indices from the triangles and stores it in a list.
    ///
    /// Returns the range where the geometry is stored in the list.
    pub fn add_indices(
        geom: &wobj::obj::Geometry,
        VertexRange(offset, _): VertexRange,
        indices: &mut Vec<u32>
    ) -> IndexRange {
        let start = indices.len();
        for shape in geom.shapes.iter() {
            match *shape {
                // Extract triangles and offset them relative to the
                // position in the vertex mesh.
                wobj::obj::Triangle((a, _), (b, _), (c, _)) => {
                    indices.push((a + offset) as u32);
                    indices.push((b + offset) as u32);
                    indices.push((c + offset) as u32);
                },
                _ => {}
            }
        }
        IndexRange(start, indices.len())
    }
}

/// Stores [start, end) ranges for objects.
///
/// This points to a range of index ranges.
pub struct ObjectRange(uint, uint);

impl ObjectRange {
    pub fn add_object(
        obj: &wobj::obj::Object,
        vertices: &mut Vec<Vertex>,
        indices: &mut Vec<u32>,
        index_ranges: &mut Vec<IndexRange>
    ) -> ObjectRange {
        let vertex_range = VertexRange::add_vertices(obj, vertices);
        let start = index_ranges.len();
        for geom in obj.geometry.iter() {
            index_ranges.push(IndexRange::add_indices(geom, vertex_range, indices))
        }
        ObjectRange(start, index_ranges.len())
    }
}

<commit_msg>Added ObjSetRange<commit_after>extern crate wobj = "wavefront-obj";

use piston::AssetStore;
use std::io;

use vertex::Vertex;

#[deriving(PartialEq, Eq, FromPrimitive, Show)]
pub enum Type {
    Slab = 0,
}

static TYPE_LEN: uint = 1;

impl Type {
    pub fn get_obj_file(&self) -> Option<&'static str> {
        match *self {
            Slab => Some("slab.obj"),
        }
    }

    pub fn to_uint(&self) -> uint {
        *self as uint
    }
}

pub struct TypeIterator {
    ty: uint,
}

impl TypeIterator {
    pub fn new() -> TypeIterator {
        TypeIterator {
            ty: 0
        }
    }
}

impl Iterator<Type> for TypeIterator {
    fn next(&mut self) -> Option<Type> {
        match self.ty {
            x if x < TYPE_LEN => {
                self.ty += 1;
                FromPrimitive::from_uint(x)
            },
            _ => None
        }
    }
}

pub struct Data {
    pub objs: Vec<Option<wobj::obj::ObjSet>>,
}

impl Data {
    pub fn from_asset_store(asset_store: &AssetStore) -> Data {
        Data {
            objs: read_objs(asset_store)
        }
    }
}

pub fn read_objs(asset_store: &AssetStore) -> Vec<Option<wobj::obj::ObjSet>> {
    let mut vec = Vec::new();
    for it in TypeIterator::new() {
        match it.get_obj_file() {
            None => vec.push(None),
            Some(file) => vec.push(Some({
                    let txt = io::File::open(&asset_store.path(file).unwrap()).read_to_string().unwrap();
                    wobj::obj::parse(txt).unwrap()
                }))
        }
    }
    vec
}

/// Stores [start, end) ranges to vertices.
pub struct VertexRange(uint, uint);

impl VertexRange {
    /// Extracts the coordinates of the corners and stores it in a list.
    ///
    /// Returns the range where the object is stored in the list.
    pub fn add_vertices(
        obj: &wobj::obj::Object,
        vertices: &mut Vec<Vertex>
    ) -> VertexRange {
        let start = vertices.len();
        for v in obj.vertices.iter() {
            vertices.push(Vertex::new([v.x as f32, v.y as f32, v.z as f32]));
        }
        VertexRange(start, vertices.len())
    }
}

/// Stores [start, end) ranges to indices.
pub struct IndexRange(uint, uint);

impl IndexRange {
    /// Extracts the indices from the triangles and stores it in a list.
    ///
    /// Returns the range where the geometry is stored in the list.
    pub fn add_indices(
        geom: &wobj::obj::Geometry,
        VertexRange(offset, _): VertexRange,
        indices: &mut Vec<u32>
    ) -> IndexRange {
        let start = indices.len();
        for shape in geom.shapes.iter() {
            match *shape {
                // Extract triangles and offset them relative to the
                // position in the vertex mesh.
                wobj::obj::Triangle((a, _), (b, _), (c, _)) => {
                    indices.push((a + offset) as u32);
                    indices.push((b + offset) as u32);
                    indices.push((c + offset) as u32);
                },
                _ => {}
            }
        }
        IndexRange(start, indices.len())
    }
}

/// Stores [start, end) ranges for objects.
///
/// This points to a range of index ranges.
pub struct ObjectRange(uint, uint);

impl ObjectRange {
    pub fn add_object(
        obj: &wobj::obj::Object,
        vertices: &mut Vec<Vertex>,
        indices: &mut Vec<u32>,
        index_ranges: &mut Vec<IndexRange>
    ) -> ObjectRange {
        let vertex_range = VertexRange::add_vertices(obj, vertices);
        let start = index_ranges.len();
        for geom in obj.geometry.iter() {
            index_ranges.push(IndexRange::add_indices(geom, vertex_range, indices))
        }
        ObjectRange(start, index_ranges.len())
    }
}

/// Stores [start, end) for object sets (one OBJ file).
///
/// This points to a range of object ranges.
pub struct ObjSetRange(uint, uint);

impl ObjSetRange {
    pub fn add_obj_set(
        obj_set: &wobj::obj::ObjSet,
        vertices: &mut Vec<Vertex>,
        indices: &mut Vec<u32>,
        index_ranges: &mut Vec<IndexRange>,
        objs: &mut Vec<ObjectRange>
    ) -> ObjSetRange {
        let start = objs.len();
        for obj in obj_set.objects.iter() {
            objs.push(
                ObjectRange::add_object(
                    obj,
                    vertices,
                    indices,
                    index_ranges
                )
            );
        }
        ObjSetRange(start, objs.len())
    }
}

<|endoftext|>


<commit_before>use gfx;
use gfx_app::{ColorFormat, DepthFormat};
use physics::{Dimensions, Position};
use cgmath::{Matrix4, SquareMatrix, Deg};
use specs;
use gfx_app::graphics::load_texture;
use character::gfx_macros::{pipe, CharacterData, CharacterSheetSettings, VertexData, CharacterPosition};
use data;

pub mod gfx_macros;
pub mod character;

const SHADER_VERT: &'static [u8] = include_bytes!("character.v.glsl");
const SHADER_FRAG: &'static [u8] = include_bytes!("character.f.glsl");

impl CharacterData {
  pub fn new(data: [f32; 4]) -> CharacterData {
    CharacterData { data: data }
  }
}

#[derive(Debug, Clone)]
pub struct Drawable {
  locals: CharacterPosition,
}

impl Drawable {
  pub fn new() -> Drawable {
    Drawable {
      locals: CharacterPosition {
        transform: Matrix4::identity().into()
      },
    }
  }

  pub fn update(&mut self, world_to_clip: &Matrix4<f32>, pos: &Position) {
    self.locals.transform = (world_to_clip * pos.model_to_world()).into();
  }
}

impl specs::Component for Drawable {
  type Storage = specs::VecStorage<Drawable>;
}

pub struct DrawSystem<R: gfx::Resources> {
  bundle: gfx::pso::bundle::Bundle<R, pipe::Data<R>>,
  data: Vec<CharacterData>,
}

impl<R: gfx::Resources> DrawSystem<R> {
  pub fn new<F>(factory: &mut F,
                rtv: gfx::handle::RenderTargetView<R, ColorFormat>,
                dsv: gfx::handle::DepthStencilView<R, DepthFormat>) -> DrawSystem<R>
    where F: gfx::Factory<R> {
    use gfx::traits::FactoryExt;

    let tilesheet_bytes = &include_bytes!("../../assets/character.png")[..];
    let vertex_data: Vec<VertexData> =
      vec![VertexData {
        pos: [-0.5, -0.5, 0.0],
        buf_pos: [0.0, 0.0]
      }, VertexData {
        pos: [0.0, 0.5, 0.0],
        buf_pos: [0.0, 0.0]
      }, VertexData {
        pos: [0.5, -0.5, 0.0],
        buf_pos: [0.0, 0.0]
      }];

    let (vertex_buf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data, ());

    let tile_texture = load_texture(factory, tilesheet_bytes).unwrap();

    let pso = factory
      .create_pipeline_simple(SHADER_VERT,
                              SHADER_FRAG,
                              pipe::new())
      .unwrap();

    let pipeline_data = pipe::Data {
      vbuf: vertex_buf,
      locals: factory.create_constant_buffer(1),
      character: factory.create_constant_buffer(512),
      character_cb: factory.create_constant_buffer(1),
      charactersheet: (tile_texture, factory.create_sampler_linear()),
      out_color: rtv,
      out_depth: dsv,
    };

    DrawSystem {
      bundle: gfx::Bundle::new(slice, pso, pipeline_data),
      data: data::load_character(),
    }
  }

  pub fn draw<C>(&mut self,
                 drawable: &Drawable,
                 encoder: &mut gfx::Encoder<R, C>)
    where C: gfx::CommandBuffer<R> {
    encoder.update_constant_buffer(&self.bundle.data.locals, &drawable.locals);
    encoder.update_buffer(&self.bundle.data.character, &self.data.as_slice(), 0).unwrap();
    encoder.update_constant_buffer(&self.bundle.data.character_cb, &CharacterSheetSettings {
      charactersheet_idx: [1.0, 0.0, 0.0, 0.0],
      charactersheet_size: [32.0, 32.0, 32.0, 32.0],
      offsets: [0.0, 0.0],
    });
    self.bundle.encode(encoder);
  }
}

#[derive(Debug)]
pub struct PreDrawSystem;

impl PreDrawSystem {
  pub fn new() -> PreDrawSystem {
    PreDrawSystem {}
  }
}

impl<C> specs::System<C> for PreDrawSystem {
  fn run(&mut self, arg: specs::RunArg, _: C) {
    use specs::Join;
    let (mut character, dim) =
      arg.fetch(|w| (
        w.write::<Drawable>(),
        w.read_resource::<Dimensions>()));

    for c in (&mut character).join() {
      let world_to_clip = dim.world_to_clip();
      let pos = Position::new(100.0, 100.0, Deg(0.0).into(), 100.0);
      c.update(&world_to_clip, &pos);
    }
  }
}
<commit_msg>Add VertexData constructor<commit_after>use gfx;
use gfx_app::{ColorFormat, DepthFormat};
use physics::{Dimensions, Position};
use cgmath::{Matrix4, SquareMatrix, Deg};
use specs;
use gfx_app::graphics::load_texture;
use character::gfx_macros::{pipe, CharacterData, CharacterSheetSettings, VertexData, CharacterPosition};
use data;

pub mod gfx_macros;
pub mod character;

const SHADER_VERT: &'static [u8] = include_bytes!("character.v.glsl");
const SHADER_FRAG: &'static [u8] = include_bytes!("character.f.glsl");

impl CharacterData {
  pub fn new(data: [f32; 4]) -> CharacterData {
    CharacterData { data: data }
  }
}

#[derive(Debug, Clone)]
pub struct Drawable {
  locals: CharacterPosition,
}

impl VertexData {
  fn new(pos: [f32; 3], buf_pos: [f32; 2]) -> VertexData {
    VertexData {
      pos: pos,
      buf_pos: buf_pos,
    }
  }
}

impl Drawable {
  pub fn new() -> Drawable {
    Drawable {
      locals: CharacterPosition {
        transform: Matrix4::identity().into()
      },
    }
  }

  pub fn update(&mut self, world_to_clip: &Matrix4<f32>, pos: &Position) {
    self.locals.transform = (world_to_clip * pos.model_to_world()).into();
  }
}

impl specs::Component for Drawable {
  type Storage = specs::VecStorage<Drawable>;
}

pub struct DrawSystem<R: gfx::Resources> {
  bundle: gfx::pso::bundle::Bundle<R, pipe::Data<R>>,
  data: Vec<CharacterData>,
}

impl<R: gfx::Resources> DrawSystem<R> {
  pub fn new<F>(factory: &mut F,
                rtv: gfx::handle::RenderTargetView<R, ColorFormat>,
                dsv: gfx::handle::DepthStencilView<R, DepthFormat>) -> DrawSystem<R>
    where F: gfx::Factory<R> {
    use gfx::traits::FactoryExt;

    let tilesheet_bytes = &include_bytes!("../../assets/character.png")[..];
    let vertex_data: Vec<VertexData> =
      vec![
        VertexData::new([-100.0, -150.0, 0.0], [0.0, 150.0]),
        VertexData::new([100.0, -150.0, 0.0], [100.0, 150.0]),
        VertexData::new([100.0, 150.0, 0.0], [100.0, 0.0]),
        VertexData::new([-100.0, -150.0, 0.0], [0.0, 150.0]),
        VertexData::new([100.0, 150.0, 0.0], [100.0, 0.0]),
        VertexData::new([-100.0, 150.0, 0.0], [0.0, 0.0]),
      ];

    let (vertex_buf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data, ());

    let tile_texture = load_texture(factory, tilesheet_bytes).unwrap();

    let pso = factory
      .create_pipeline_simple(SHADER_VERT,
                              SHADER_FRAG,
                              pipe::new())
      .unwrap();

    let pipeline_data = pipe::Data {
      vbuf: vertex_buf,
      locals: factory.create_constant_buffer(1),
      character: factory.create_constant_buffer(512),
      character_cb: factory.create_constant_buffer(1),
      charactersheet: (tile_texture, factory.create_sampler_linear()),
      out_color: rtv,
      out_depth: dsv,
    };

    DrawSystem {
      bundle: gfx::Bundle::new(slice, pso, pipeline_data),
      data: data::load_character(),
    }
  }

  pub fn draw<C>(&mut self,
                 drawable: &Drawable,
                 encoder: &mut gfx::Encoder<R, C>)
    where C: gfx::CommandBuffer<R> {
    encoder.update_constant_buffer(&self.bundle.data.locals, &drawable.locals);
    encoder.update_buffer(&self.bundle.data.character, &self.data.as_slice(), 0).unwrap();
    encoder.update_constant_buffer(&self.bundle.data.character_cb, &CharacterSheetSettings {
      charactersheet_idx: [1.0, 0.0, 0.0, 0.0],
      charactersheet_size: [32.0, 32.0, 32.0, 32.0],
      offsets: [0.0, 0.0],
    });
    self.bundle.encode(encoder);
  }
}

#[derive(Debug)]
pub struct PreDrawSystem;

impl PreDrawSystem {
  pub fn new() -> PreDrawSystem {
    PreDrawSystem {}
  }
}

impl<C> specs::System<C> for PreDrawSystem {
  fn run(&mut self, arg: specs::RunArg, _: C) {
    use specs::Join;
    let (mut character, dim) =
      arg.fetch(|w| (
        w.write::<Drawable>(),
        w.read_resource::<Dimensions>()));

    for c in (&mut character).join() {
      let world_to_clip = dim.world_to_clip();
      let pos = Position::new(100.0, 100.0, Deg(0.0).into(), 100.0);
      c.update(&world_to_clip, &pos);
    }
  }
}
<|endoftext|>


<commit_before>///! Handle `cargo add` arguments
use semver;
use std::error::Error;
use cargo_edit::Dependency;
use fetch::{get_crate_name_from_github, get_crate_name_from_gitlab, get_crate_name_from_path,
            get_latest_version};

macro_rules! toml_table {
    ($($key:expr => $value:expr),+) => {
        {
            let mut dep = BTreeMap::new();
            $(dep.insert(String::from($key), $value);)+
            toml::Value::Table(dep)
        }
    }
}

#[derive(Debug, RustcDecodable)]
/// Docopts input args.
pub struct Args {
    /// Crate name (usage 1)
    pub arg_crate: String,
    /// Crate names (usage 2)
    pub arg_crates: Vec<String>,
    /// dev-dependency
    pub flag_dev: bool,
    /// build-dependency
    pub flag_build: bool,
    /// Version
    pub flag_vers: Option<String>,
    /// Git repo Path
    pub flag_git: Option<String>,
    /// Crate directory path
    pub flag_path: Option<String>,
    /// Crate directory path
    pub flag_target: Option<String>,
    /// Optional dependency
    pub flag_optional: bool,
    /// `Cargo.toml` path
    pub flag_manifest_path: Option<String>,
    /// `--version`
    pub flag_version: bool,
    /// `---upgrade`
    pub flag_upgrade: Option<String>,
}

impl Args {
    /// Get depenency section
    pub fn get_section(&self) -> Vec<String> {
        if self.flag_dev {
            vec!["dev-dependencies".to_owned()]
        } else if self.flag_build {
            vec!["build-dependencies".to_owned()]
        } else {
            if let Some(ref target) = self.flag_target {
                if target.is_empty() {
                    panic!("Target specification may not be empty");
                }
                vec!["target".to_owned(), target.clone(), "dependencies".to_owned()]
            } else {
                vec!["dependencies".to_owned()]
            }
        }
    }

    /// Build dependencies from arguments
    pub fn parse_dependencies(&self) -> Result<Vec<Dependency>, Box<Error>> {
        if !self.arg_crates.is_empty() {
            let mut result = Vec::<Dependency>::new();
            for arg_crate in &self.arg_crates {
                let le_crate = if crate_name_has_version(&arg_crate) {
                                   try!(parse_crate_name_with_version(arg_crate))
                               } else {
                                   let v = try!(get_latest_version(&self.arg_crate));
                                   Dependency::new(arg_crate).set_version(&v)
                               }
                               .set_optional(self.flag_optional);

                result.push(le_crate);
            }
            return Ok(result);
        }

        if crate_name_has_version(&self.arg_crate) {
            return Ok(vec![try!(parse_crate_name_with_version(&self.arg_crate))
                               .set_optional(self.flag_optional)]);
        }

        let dependency = if !crate_name_is_url_or_path(&self.arg_crate) {
                             let dependency = Dependency::new(&self.arg_crate);

                             if let Some(ref version) = self.flag_vers {
                                 try!(semver::VersionReq::parse(&version));
                                 dependency.set_version(version)
                             } else if let Some(ref repo) = self.flag_git {
                                 dependency.set_git(repo)
                             } else if let Some(ref path) = self.flag_path {
                                 dependency.set_path(path)
                             } else {
                                 let mut v = try!(get_latest_version(&self.arg_crate));
                                 v = self.get_upgrade_prefix().to_owned() + &v;
                                 dependency.set_version(&v)
                             }
                         } else {
                             try!(parse_crate_name_from_uri(&self.arg_crate))
                         }
                         .set_optional(self.flag_optional);

        Ok(vec![dependency])
    }

    fn get_upgrade_prefix(&self) -> &'static str {
        match self.flag_upgrade {
            None => &"",
            Some(ref u) => match u.to_uppercase().as_ref() {
                "NONE" => &"=",
                "PATCH" => &"~",
                "MINOR" => &"^",
                "ALL" => &">=",
                _ => {
                    println!("WARN: cannot understand upgrade option \"{}\", using default", u);
                    &""
                },
            },
        }
    }
}

impl Default for Args {
    fn default() -> Args {
        Args {
            arg_crate: "demo".to_owned(),
            arg_crates: vec![],
            flag_dev: false,
            flag_build: false,
            flag_vers: None,
            flag_git: None,
            flag_path: None,
            flag_target: None,
            flag_optional: false,
            flag_manifest_path: None,
            flag_version: false,
            flag_upgrade: None,
        }
    }
}

fn crate_name_has_version(name: &str) -> bool {
    name.contains('@')
}

fn crate_name_is_url_or_path(name: &str) -> bool {
    crate_name_is_github_url(name) || crate_name_is_gitlab_url(name) || crate_name_is_path(name)
}

fn crate_name_is_github_url(name: &str) -> bool {
    name.contains("https://github.com")
}

fn crate_name_is_gitlab_url(name: &str) -> bool {
    name.contains("https://gitlab.com")
}

fn crate_name_is_path(name: &str) -> bool {
    // FIXME: how else can we check if the name is a (possibly invalid) path?
    name.contains('.') || name.contains('/') || name.contains('\\')
}

fn parse_crate_name_with_version(name: &str) -> Result<Dependency, Box<Error>> {
    assert!(crate_name_has_version(&name));

    let xs: Vec<&str> = name.splitn(2, '@').collect();
    let (name, version) = (xs[0], xs[1]);
    try!(semver::VersionReq::parse(&version));

    Ok(Dependency::new(name).set_version(version))
}

fn parse_crate_name_from_uri(name: &str) -> Result<Dependency, Box<Error>> {
    if crate_name_is_github_url(name) {
        if let Ok(ref crate_name) = get_crate_name_from_github(name) {
            return Ok(Dependency::new(crate_name).set_git(name));
        }
    } else if crate_name_is_gitlab_url(name) {
        if let Ok(ref crate_name) = get_crate_name_from_gitlab(name) {
            return Ok(Dependency::new(crate_name).set_git(name));
        }
    } else if crate_name_is_path(name) {
        if let Ok(ref crate_name) = get_crate_name_from_path(&name) {
            return Ok(Dependency::new(crate_name).set_path(name));
        }
    }

    Err(From::from(format!("Unable to obtain crate informations from `{}`.\n", name)))
}

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

    #[test]
    fn test_dependency_parsing() {
        let args = Args {
            arg_crate: "demo".to_owned(),
            flag_vers: Some("0.4.2".to_owned()),
            ..Args::default()
        };

        assert_eq!(args.parse_dependencies().unwrap(),
                   vec![Dependency::new("demo").set_version("0.4.2")]);
    }

    #[test]
    #[cfg(feature="test-external-apis")]
    fn test_repo_as_arg_parsing() {
        let github_url = "https://github.com/killercup/cargo-edit/";
        let args_github = Args { arg_crate: github_url.to_owned(), ..Args::default() };
        assert_eq!(args_github.parse_dependencies().unwrap(),
                    vec![Dependency::new("cargo-edit").set_git(github_url)]);

        let gitlab_url = "https://gitlab.com/Polly-lang/Polly.git";
        let args_gitlab = Args { arg_crate: gitlab_url.to_owned(), ..Args::default() };
        assert_eq!(args_gitlab.parse_dependencies().unwrap(),
                    vec![Dependency::new("polly").set_git(gitlab_url)]);
    }

    #[test]
    fn test_path_as_arg_parsing() {
        let self_path = ".";
        let args_path = Args { arg_crate: self_path.to_owned(), ..Args::default() };
        assert_eq!(args_path.parse_dependencies().unwrap(),
                   vec![Dependency::new("cargo-edit").set_path(self_path)]);
    }

}
<commit_msg>wip - adjusted to map syntax for brevity<commit_after>///! Handle `cargo add` arguments
use semver;
use std::error::Error;
use cargo_edit::Dependency;
use fetch::{get_crate_name_from_github, get_crate_name_from_gitlab, get_crate_name_from_path,
            get_latest_version};

macro_rules! toml_table {
    ($($key:expr => $value:expr),+) => {
        {
            let mut dep = BTreeMap::new();
            $(dep.insert(String::from($key), $value);)+
            toml::Value::Table(dep)
        }
    }
}

#[derive(Debug, RustcDecodable)]
/// Docopts input args.
pub struct Args {
    /// Crate name (usage 1)
    pub arg_crate: String,
    /// Crate names (usage 2)
    pub arg_crates: Vec<String>,
    /// dev-dependency
    pub flag_dev: bool,
    /// build-dependency
    pub flag_build: bool,
    /// Version
    pub flag_vers: Option<String>,
    /// Git repo Path
    pub flag_git: Option<String>,
    /// Crate directory path
    pub flag_path: Option<String>,
    /// Crate directory path
    pub flag_target: Option<String>,
    /// Optional dependency
    pub flag_optional: bool,
    /// `Cargo.toml` path
    pub flag_manifest_path: Option<String>,
    /// `--version`
    pub flag_version: bool,
    /// `---upgrade`
    pub flag_upgrade: Option<String>,
}

impl Args {
    /// Get depenency section
    pub fn get_section(&self) -> Vec<String> {
        if self.flag_dev {
            vec!["dev-dependencies".to_owned()]
        } else if self.flag_build {
            vec!["build-dependencies".to_owned()]
        } else {
            if let Some(ref target) = self.flag_target {
                if target.is_empty() {
                    panic!("Target specification may not be empty");
                }
                vec!["target".to_owned(), target.clone(), "dependencies".to_owned()]
            } else {
                vec!["dependencies".to_owned()]
            }
        }
    }

    /// Build dependencies from arguments
    pub fn parse_dependencies(&self) -> Result<Vec<Dependency>, Box<Error>> {
        if !self.arg_crates.is_empty() {
            let mut result = Vec::<Dependency>::new();
            for arg_crate in &self.arg_crates {
                let le_crate = if crate_name_has_version(&arg_crate) {
                                   try!(parse_crate_name_with_version(arg_crate))
                               } else {
                                   let v = try!(get_latest_version(&self.arg_crate));
                                   Dependency::new(arg_crate).set_version(&v)
                               }
                               .set_optional(self.flag_optional);

                result.push(le_crate);
            }
            return Ok(result);
        }

        if crate_name_has_version(&self.arg_crate) {
            return Ok(vec![try!(parse_crate_name_with_version(&self.arg_crate))
                               .set_optional(self.flag_optional)]);
        }

        let dependency = if !crate_name_is_url_or_path(&self.arg_crate) {
                             let dependency = Dependency::new(&self.arg_crate);

                             if let Some(ref version) = self.flag_vers {
                                 try!(semver::VersionReq::parse(&version));
                                 dependency.set_version(version)
                             } else if let Some(ref repo) = self.flag_git {
                                 dependency.set_git(repo)
                             } else if let Some(ref path) = self.flag_path {
                                 dependency.set_path(path)
                             } else {
								 let v = format!(
								 	"{prefix}{version}",
								 	prefix = self.get_upgrade_prefix().unwrap_or(""),
								 	version = try!(get_latest_version(&self.arg_crate))
								 );
								 dependency.set_version(&v)
                             }
                         } else {
                             try!(parse_crate_name_from_uri(&self.arg_crate))
                         }
                         .set_optional(self.flag_optional);

        Ok(vec![dependency])
    }

    fn get_upgrade_prefix(&self) -> Option<&'static str> {
		self.flag_upgrade.clone().map(|flag|
			match flag.to_uppercase().as_ref() {
                "NONE" => Some("="),
                "PATCH" => Some("~"),
                "MINOR" => Some("^"),
                "ALL" => Some(">="),
                _ => {
                    println!("WARN: cannot understand upgrade option \"{}\", using default", flag);
                    None
                },
            }
        ).unwrap_or(None)
    }
}

impl Default for Args {
    fn default() -> Args {
        Args {
            arg_crate: "demo".to_owned(),
            arg_crates: vec![],
            flag_dev: false,
            flag_build: false,
            flag_vers: None,
            flag_git: None,
            flag_path: None,
            flag_target: None,
            flag_optional: false,
            flag_manifest_path: None,
            flag_version: false,
            flag_upgrade: None,
        }
    }
}

fn crate_name_has_version(name: &str) -> bool {
    name.contains('@')
}

fn crate_name_is_url_or_path(name: &str) -> bool {
    crate_name_is_github_url(name) || crate_name_is_gitlab_url(name) || crate_name_is_path(name)
}

fn crate_name_is_github_url(name: &str) -> bool {
    name.contains("https://github.com")
}

fn crate_name_is_gitlab_url(name: &str) -> bool {
    name.contains("https://gitlab.com")
}

fn crate_name_is_path(name: &str) -> bool {
    // FIXME: how else can we check if the name is a (possibly invalid) path?
    name.contains('.') || name.contains('/') || name.contains('\\')
}

fn parse_crate_name_with_version(name: &str) -> Result<Dependency, Box<Error>> {
    assert!(crate_name_has_version(&name));

    let xs: Vec<&str> = name.splitn(2, '@').collect();
    let (name, version) = (xs[0], xs[1]);
    try!(semver::VersionReq::parse(&version));

    Ok(Dependency::new(name).set_version(version))
}

fn parse_crate_name_from_uri(name: &str) -> Result<Dependency, Box<Error>> {
    if crate_name_is_github_url(name) {
        if let Ok(ref crate_name) = get_crate_name_from_github(name) {
            return Ok(Dependency::new(crate_name).set_git(name));
        }
    } else if crate_name_is_gitlab_url(name) {
        if let Ok(ref crate_name) = get_crate_name_from_gitlab(name) {
            return Ok(Dependency::new(crate_name).set_git(name));
        }
    } else if crate_name_is_path(name) {
        if let Ok(ref crate_name) = get_crate_name_from_path(&name) {
            return Ok(Dependency::new(crate_name).set_path(name));
        }
    }

    Err(From::from(format!("Unable to obtain crate informations from `{}`.\n", name)))
}

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

    #[test]
    fn test_dependency_parsing() {
        let args = Args {
            arg_crate: "demo".to_owned(),
            flag_vers: Some("0.4.2".to_owned()),
            ..Args::default()
        };

        assert_eq!(args.parse_dependencies().unwrap(),
                   vec![Dependency::new("demo").set_version("0.4.2")]);
    }

    #[test]
    #[cfg(feature="test-external-apis")]
    fn test_repo_as_arg_parsing() {
        let github_url = "https://github.com/killercup/cargo-edit/";
        let args_github = Args { arg_crate: github_url.to_owned(), ..Args::default() };
        assert_eq!(args_github.parse_dependencies().unwrap(),
                    vec![Dependency::new("cargo-edit").set_git(github_url)]);

        let gitlab_url = "https://gitlab.com/Polly-lang/Polly.git";
        let args_gitlab = Args { arg_crate: gitlab_url.to_owned(), ..Args::default() };
        assert_eq!(args_gitlab.parse_dependencies().unwrap(),
                    vec![Dependency::new("polly").set_git(gitlab_url)]);
    }

    #[test]
    fn test_path_as_arg_parsing() {
        let self_path = ".";
        let args_path = Args { arg_crate: self_path.to_owned(), ..Args::default() };
        assert_eq!(args_path.parse_dependencies().unwrap(),
                   vec![Dependency::new("cargo-edit").set_path(self_path)]);
    }

}
<|endoftext|>


<commit_before>//! `cargo add`
#![warn(missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts,
        trivial_numeric_casts, unsafe_code, unstable_features, unused_import_braces,
        unused_qualifications)]

extern crate docopt;
#[macro_use]
extern crate error_chain;
extern crate semver;
#[macro_use]
extern crate serde_derive;
extern crate termcolor;

use std::process;
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};

extern crate cargo_edit;
use cargo_edit::{Dependency, Manifest};

mod args;
use args::Args;

mod errors {
    error_chain!{
        links {
            CargoEditLib(::cargo_edit::Error, ::cargo_edit::ErrorKind);
        }
    }
}
use errors::*;

static USAGE: &'static str = r#"
Usage:
    cargo add <crate> [--dev|--build|--optional] [--vers=<ver>|--git=<uri>|--path=<uri>] [options]
    cargo add <crates>... [--dev|--build|--optional] [options]
    cargo add (-h|--help)
    cargo add --version

Specify what crate to add:
    --vers <ver>            Specify the version to grab from the registry (crates.io).
                            You can also specify versions as part of the name, e.g
                            `cargo add bitflags@0.3.2`.
    --git <uri>             Specify a git repository to download the crate from.
    --path <uri>            Specify the path the crate should be loaded from.

Specify where to add the crate:
    -D --dev                Add crate as development dependency.
    -B --build              Add crate as build dependency.
    --optional              Add as an optional dependency (for use in features). This does not work
                            for `dev-dependencies` or `build-dependencies`.
    --target <target>       Add as dependency to the given target platform. This does not work
                            for `dev-dependencies` or `build-dependencies`.

Options:
    --upgrade=<method>      Choose method of semantic version upgrade. Must be one of
                            "none" (exact version), "patch" (`~` modifier), "minor"
                            (`^` modifier, default), or "all" (`>=`).
    --manifest-path=<path>  Path to the manifest to add a dependency to.
    --allow-prerelease      Include prerelease versions when fetching from crates.io (e.g.
                            '0.6.0-alpha'). Defaults to false.
    -q --quiet              Do not print any output in case of success.
    -h --help               Show this help page.
    -V --version            Show version.

This command allows you to add a dependency to a Cargo.toml manifest file. If <crate> is a github
or gitlab repository URL, or a local path, `cargo add` will try to automatically get the crate name
and set the appropriate `--git` or `--path` value.

Please note that Cargo treats versions like "1.2.3" as "^1.2.3" (and that "^1.2.3" is specified
as ">=1.2.3 and <2.0.0"). By default, `cargo add` will use this format, as it is the one that the
crates.io registry suggests. One goal of `cargo add` is to prevent you from using wildcard
dependencies (version set to "*").
"#;

fn print_msg(dep: &Dependency, section: Vec<String>, optional: bool) {
    let optional = if optional { "optional " } else { "" }.to_owned();
    let section = if section.len() == 1 {
        section[0].clone()
    } else {
        "dependencies for target ".to_owned() + &section[1]
    };

    let mut output = StandardStream::stdout(ColorChoice::Auto);
    output
        .set_color(ColorSpec::new().set_fg(Some(Color::Green)).set_bold(true))
        .unwrap();
    print!("{:>12}", "Adding");
    output.reset().unwrap();
    println!(
        " {} v{} to {}{}",
        dep.name,
        dep.version().unwrap_or(""),
        optional,
        section
    );
}

fn handle_add(args: &Args) -> Result<()> {
    let manifest_path = args.flag_manifest_path.as_ref().map(From::from);
    let mut manifest = Manifest::open(&manifest_path)?;
    let deps = &args.parse_dependencies()?;

    deps.iter()
        .map(|dep| {
            if !args.flag_quiet {
                print_msg(dep, args.get_section(), args.flag_optional);
            }
            manifest
                .insert_into_table(&args.get_section(), dep)
                .map_err(Into::into)
        })
        .collect::<Result<Vec<_>>>()
        .map_err(|err| {
            eprintln!("Could not edit `Cargo.toml`.\n\nERROR: {}", err);
            err
        })?;

    let mut file = Manifest::find_file(&manifest_path)?;
    manifest.write_to_file(&mut file)?;

    Ok(())
}

fn main() {
    let args = docopt::Docopt::new(USAGE)
        .and_then(|d| d.deserialize::<Args>())
        .unwrap_or_else(|err| err.exit());

    if args.flag_version {
        println!("cargo-add version {}", env!("CARGO_PKG_VERSION"));
        process::exit(0);
    }

    if let Err(err) = handle_add(&args) {
        eprintln!("Command failed due to unhandled error: {}\n", err);

        for e in err.iter().skip(1) {
            eprintln!("Caused by: {}", e);
        }

        if let Some(backtrace) = err.backtrace() {
            eprintln!("Backtrace: {:?}", backtrace);
        }

        process::exit(1);
    }
}
<commit_msg>borrow `section` instead of moving in `bin/add/print_msg()` (makes clippy happy)<commit_after>//! `cargo add`
#![warn(missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts,
        trivial_numeric_casts, unsafe_code, unstable_features, unused_import_braces,
        unused_qualifications)]

extern crate docopt;
#[macro_use]
extern crate error_chain;
extern crate semver;
#[macro_use]
extern crate serde_derive;
extern crate termcolor;

use std::process;
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};

extern crate cargo_edit;
use cargo_edit::{Dependency, Manifest};

mod args;
use args::Args;

mod errors {
    error_chain!{
        links {
            CargoEditLib(::cargo_edit::Error, ::cargo_edit::ErrorKind);
        }
    }
}
use errors::*;

static USAGE: &'static str = r#"
Usage:
    cargo add <crate> [--dev|--build|--optional] [--vers=<ver>|--git=<uri>|--path=<uri>] [options]
    cargo add <crates>... [--dev|--build|--optional] [options]
    cargo add (-h|--help)
    cargo add --version

Specify what crate to add:
    --vers <ver>            Specify the version to grab from the registry (crates.io).
                            You can also specify versions as part of the name, e.g
                            `cargo add bitflags@0.3.2`.
    --git <uri>             Specify a git repository to download the crate from.
    --path <uri>            Specify the path the crate should be loaded from.

Specify where to add the crate:
    -D --dev                Add crate as development dependency.
    -B --build              Add crate as build dependency.
    --optional              Add as an optional dependency (for use in features). This does not work
                            for `dev-dependencies` or `build-dependencies`.
    --target <target>       Add as dependency to the given target platform. This does not work
                            for `dev-dependencies` or `build-dependencies`.

Options:
    --upgrade=<method>      Choose method of semantic version upgrade. Must be one of
                            "none" (exact version), "patch" (`~` modifier), "minor"
                            (`^` modifier, default), or "all" (`>=`).
    --manifest-path=<path>  Path to the manifest to add a dependency to.
    --allow-prerelease      Include prerelease versions when fetching from crates.io (e.g.
                            '0.6.0-alpha'). Defaults to false.
    -q --quiet              Do not print any output in case of success.
    -h --help               Show this help page.
    -V --version            Show version.

This command allows you to add a dependency to a Cargo.toml manifest file. If <crate> is a github
or gitlab repository URL, or a local path, `cargo add` will try to automatically get the crate name
and set the appropriate `--git` or `--path` value.

Please note that Cargo treats versions like "1.2.3" as "^1.2.3" (and that "^1.2.3" is specified
as ">=1.2.3 and <2.0.0"). By default, `cargo add` will use this format, as it is the one that the
crates.io registry suggests. One goal of `cargo add` is to prevent you from using wildcard
dependencies (version set to "*").
"#;

fn print_msg(dep: &Dependency, section: &[String], optional: bool) {
    let optional = if optional { "optional " } else { "" }.to_owned();
    let section = if section.len() == 1 {
        section[0].clone()
    } else {
        "dependencies for target ".to_owned() + &section[1]
    };

    let mut output = StandardStream::stdout(ColorChoice::Auto);
    output
        .set_color(ColorSpec::new().set_fg(Some(Color::Green)).set_bold(true))
        .unwrap();
    print!("{:>12}", "Adding");
    output.reset().unwrap();
    println!(
        " {} v{} to {}{}",
        dep.name,
        dep.version().unwrap_or(""),
        optional,
        section
    );
}

fn handle_add(args: &Args) -> Result<()> {
    let manifest_path = args.flag_manifest_path.as_ref().map(From::from);
    let mut manifest = Manifest::open(&manifest_path)?;
    let deps = &args.parse_dependencies()?;

    deps.iter()
        .map(|dep| {
            if !args.flag_quiet {
                print_msg(dep, &args.get_section(), args.flag_optional);
            }
            manifest
                .insert_into_table(&args.get_section(), dep)
                .map_err(Into::into)
        })
        .collect::<Result<Vec<_>>>()
        .map_err(|err| {
            eprintln!("Could not edit `Cargo.toml`.\n\nERROR: {}", err);
            err
        })?;

    let mut file = Manifest::find_file(&manifest_path)?;
    manifest.write_to_file(&mut file)?;

    Ok(())
}

fn main() {
    let args = docopt::Docopt::new(USAGE)
        .and_then(|d| d.deserialize::<Args>())
        .unwrap_or_else(|err| err.exit());

    if args.flag_version {
        println!("cargo-add version {}", env!("CARGO_PKG_VERSION"));
        process::exit(0);
    }

    if let Err(err) = handle_add(&args) {
        eprintln!("Command failed due to unhandled error: {}\n", err);

        for e in err.iter().skip(1) {
            eprintln!("Caused by: {}", e);
        }

        if let Some(backtrace) = err.backtrace() {
            eprintln!("Backtrace: {:?}", backtrace);
        }

        process::exit(1);
    }
}
<|endoftext|>


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

extern crate word_count;

fn check_word_count(s: &str, pairs: Vec<(&str, u32)>) {
    // The reason for the awkward code in here is to ensure that the failure
    // message for assert_eq! is as informative as possible. A simpler
    // solution would simply check the length of the map, and then
    // check for the presence and value of each key in the given pairs vector.
    let mut m: HashMap<String, u32> = word_count::word_count(s);
    for &(k, v) in pairs.iter() {
        assert_eq!((k, m.remove(&k.to_string()).unwrap_or(0)), (k, v));
    }
    // may fail with a message that clearly shows all extra pairs in the map
    assert_eq!(m.iter().collect::<Vec<(&String,&u32)>>(), vec!());
}

#[test]
fn test_no_words() {
    check_word_count("", vec![]);
    check_word_count("-!@#$ $#() @@@", vec![]);
}

#[test]
#[ignore]
fn test_count_one_word() {
    check_word_count("word", vec![("word", 1)]);
}

#[test]
#[ignore]
fn test_count_one_of_each() {
    check_word_count(
        "one of each",
        vec![("one", 1),
             ("of", 1),
             ("each", 1)]);
}

#[test]
#[ignore]
fn test_count_multiple_occurrences() {
    check_word_count(
        "one fish two fish red fish blue fish",
        vec![("one", 1),
             ("fish", 4),
             ("two", 1),
             ("red", 1),
             ("blue", 1)]);
}

#[test]
#[ignore]
fn test_ignore_punctuation() {
    check_word_count(
        "car : carpet as java : javascript!!&@$%^&",
        vec![("car", 1),
             ("carpet", 1),
             ("as", 1),
             ("java", 1),
             ("javascript", 1)]);
}

#[test]
#[ignore]
fn test_include_numbers() {
    check_word_count(
        "testing, 1, 2 testing",
        vec![("testing", 2),
             ("1", 1),
             ("2", 1)]);
}

#[test]
#[ignore]
fn test_normalize_case() {
    check_word_count(
        "go Go GO",
        vec![("go", 3)]);
}

#[test]
#[ignore]
fn test_prefix_punctuation() {
    check_word_count(
        "!%%#testing, 1, 2 testing",
        vec![("testing", 2),
             ("1", 1),
             ("2", 1)]);
}

#[test]
#[ignore]
fn test_symbols_are_separators() {
    check_word_count(
        "hey,my_spacebar_is_broken.",
        vec![("hey", 1),
             ("my", 1),
             ("spacebar", 1),
             ("is", 1),
             ("broken", 1)]);
}
<commit_msg>word-count: Follow the current canonical test set (#215)<commit_after>use std::collections::HashMap;

extern crate word_count;

fn check_word_count(s: &str, pairs: Vec<(&str, u32)>) {
    // The reason for the awkward code in here is to ensure that the failure
    // message for assert_eq! is as informative as possible. A simpler
    // solution would simply check the length of the map, and then
    // check for the presence and value of each key in the given pairs vector.
    let mut m: HashMap<String, u32> = word_count::word_count(s);
    for &(k, v) in pairs.iter() {
        assert_eq!((k, m.remove(&k.to_string()).unwrap_or(0)), (k, v));
    }
    // may fail with a message that clearly shows all extra pairs in the map
    assert_eq!(m.iter().collect::<Vec<(&String,&u32)>>(), vec!());
}

#[test]
fn test_count_one_word() {
    check_word_count("word", vec![("word", 1)]);
}

#[test]
#[ignore]
fn test_count_one_of_each() {
    check_word_count(
        "one of each",
        vec![("one", 1),
             ("of", 1),
             ("each", 1)]);
}

#[test]
#[ignore]
fn test_count_multiple_occurrences() {
    check_word_count(
        "one fish two fish red fish blue fish",
        vec![("one", 1),
             ("fish", 4),
             ("two", 1),
             ("red", 1),
             ("blue", 1)]);
}

#[test]
#[ignore]
fn test_ignore_punctuation() {
    check_word_count(
        "car : carpet as java : javascript!!&@$%^&",
        vec![("car", 1),
             ("carpet", 1),
             ("as", 1),
             ("java", 1),
             ("javascript", 1)]);
}

#[test]
#[ignore]
fn test_include_numbers() {
    check_word_count(
        "testing, 1, 2 testing",
        vec![("testing", 2),
             ("1", 1),
             ("2", 1)]);
}

#[test]
#[ignore]
fn test_normalize_case() {
    check_word_count(
        "go Go GO Stop stop",
        vec![("go", 3),
             ("stop", 2)]);
}
<|endoftext|>


<commit_before>#![crate_name = "chroot"]
#![feature(collections, core, old_io, os, old_path, rustc_private, std_misc)]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Vsevolod Velichko <torkvemada@sorokdva.net>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;
extern crate libc;

use getopts::{optflag, optopt, getopts, usage};
use c_types::{get_pw_from_args, get_group};
use libc::funcs::posix88::unistd::{execvp, setuid, setgid};
use std::ffi::{CStr, CString};
use std::old_io::fs::PathExtensions;
use std::iter::FromIterator;

#[path = "../common/util.rs"] #[macro_use] mod util;
#[path = "../common/c_types.rs"] mod c_types;

extern {
    fn chroot(path: *const libc::c_char) -> libc::c_int;
}

#[cfg(any(target_os = "macos", target_os = "freebsd"))]
extern {
    fn setgroups(size: libc::c_int, list: *const libc::gid_t) -> libc::c_int;
}

#[cfg(target_os = "linux")]
extern {
    fn setgroups(size: libc::size_t, list: *const libc::gid_t) -> libc::c_int;
}

static NAME: &'static str = "chroot";
static VERSION: &'static str = "1.0.0";

pub fn uumain(args: Vec<String>) -> i32 {
    let program = &args[0];

    let options = [
        optopt("u", "user", "User (ID or name) to switch before running the program", "USER"),
        optopt("g", "group", "Group (ID or name) to switch to", "GROUP"),
        optopt("G", "groups", "Comma-separated list of groups to switch to", "GROUP1,GROUP2…"),
        optopt("", "userspec", "Colon-separated user and group to switch to. \
                                Same as -u USER -g GROUP. \
                                Userspec has higher preference than -u and/or -g", "USER:GROUP"),
        optflag("h", "help", "Show help"),
        optflag("V", "version", "Show program's version")
    ];

    let opts = match getopts(args.tail(), &options) {
        Ok(m) => m,
        Err(f) => {
            show_error!("{}", f);
            help_menu(program.as_slice(), &options);
            return 1
        }
    };

    if opts.opt_present("V") { version(); return 0 }
    if opts.opt_present("h") { help_menu(program.as_slice(), &options); return 0 }

    if opts.free.len() == 0 {
        println!("Missing operand: NEWROOT");
        println!("Try `{} --help` for more information.", program.as_slice());
        return 1
    }

    let default_shell: &'static str = "/bin/sh";
    let default_option: &'static str = "-i";
    let user_shell = std::os::getenv("SHELL");

    let newroot = Path::new(opts.free[0].as_slice());
    if !newroot.is_dir() {
        crash!(1, "cannot change root directory to `{}`: no such directory", newroot.display());
    }

    let command: Vec<&str> = match opts.free.len() {
        1 => {
            let shell: &str = match user_shell {
                None => default_shell,
                Some(ref s) => s.as_slice()
            };
            vec!(shell, default_option)
        }
        _ => opts.free[1..opts.free.len()].iter().map(|x| x.as_slice()).collect()
    };

    set_context(&newroot, &opts);

    unsafe {
        let executable = CString::new(command[0]).unwrap().as_bytes_with_nul().as_ptr();
        let mut command_parts: Vec<*const u8> = command.iter().map(|x| CString::new(x.as_bytes()).unwrap().as_bytes_with_nul().as_ptr()).collect();
        command_parts.push(std::ptr::null());
        execvp(executable as *const libc::c_char, command_parts.as_ptr() as *mut *const libc::c_char) as i32
    }
}

fn set_context(root: &Path, options: &getopts::Matches) {
    let userspec_str = options.opt_str("userspec");
    let user_str = options.opt_str("user").unwrap_or_default();
    let group_str = options.opt_str("group").unwrap_or_default();
    let groups_str = options.opt_str("groups").unwrap_or_default();
    let userspec = match userspec_str {
        Some(ref u) => {
            let s: Vec<&str> = u.as_slice().split(':').collect();
            if s.len() != 2 {
                crash!(1, "invalid userspec: `{}`", u.as_slice())
            };
            s
        }
        None => Vec::new()
    };
    let user = if userspec.is_empty() { user_str.as_slice() } else { userspec[0].as_slice() };
    let group = if userspec.is_empty() { group_str.as_slice() } else { userspec[1].as_slice() };

    enter_chroot(root);

    set_groups_from_str(groups_str.as_slice());
    set_main_group(group);
    set_user(user);
}

fn enter_chroot(root: &Path) {
    let root_str = root.display();
    std::os::change_dir(root).unwrap();
    let err = unsafe {
        chroot(CString::new(b".").unwrap().as_bytes_with_nul().as_ptr() as *const libc::c_char)
    };
    if err != 0 {
        crash!(1, "cannot chroot to {}: {}", root_str, strerror(err).as_slice())
    };
}

fn set_main_group(group: &str) {
    if !group.is_empty() {
        let group_id = match get_group(group) {
            None => crash!(1, "no such group: {}", group),
            Some(g) => g.gr_gid
        };
        let err = unsafe { setgid(group_id) };
        if err != 0 {
            crash!(1, "cannot set gid to {}: {}", group_id, strerror(err).as_slice())
        }
    }
}

#[cfg(any(target_os = "macos", target_os = "freebsd"))]
fn set_groups(groups: Vec<libc::gid_t>) -> libc::c_int {
    unsafe {
        setgroups(groups.len() as libc::c_int,
                  groups.as_slice().as_ptr())
    }
}

#[cfg(target_os = "linux")]
fn set_groups(groups: Vec<libc::gid_t>) -> libc::c_int {
    unsafe {
        setgroups(groups.len() as libc::size_t,
                  groups.as_slice().as_ptr())
    }
}

fn set_groups_from_str(groups: &str) {
    if !groups.is_empty() {
        let groups_vec: Vec<libc::gid_t> = FromIterator::from_iter(
            groups.split(',').map(
                |x| match get_group(x) {
                    None => crash!(1, "no such group: {}", x),
                    Some(g) => g.gr_gid
                })
            );
        let err = set_groups(groups_vec);
        if err != 0 {
            crash!(1, "cannot set groups: {}", strerror(err).as_slice())
        }
    }
}

fn set_user(user: &str) {
    if !user.is_empty() {
        let user_id = get_pw_from_args(&vec!(String::from_str(user))).unwrap().pw_uid;
        let err = unsafe { setuid(user_id as libc::uid_t) };
        if err != 0 {
            crash!(1, "cannot set user to {}: {}", user, strerror(err).as_slice())
        }
    }
}

fn strerror(errno: i32) -> String {
    unsafe {
        let err = libc::funcs::c95::string::strerror(errno) as *const libc::c_char;
        let bytes= CStr::from_ptr(err).to_bytes();
        String::from_utf8_lossy(bytes).to_string()
    }
}

fn version() {
    println!("{} v{}", NAME, VERSION)
}

fn help_menu(program: &str, options: &[getopts::OptGroup]) {
    version();
    println!("Usage:");
    println!("  {} [OPTION]… NEWROOT [COMMAND [ARG]…]", program);
    println!("");
    print!("{}", usage(
            "Run COMMAND with root directory set to NEWROOT.\n\
             If COMMAND is not specified, it defaults to '${SHELL} -i'. \
             If ${SHELL} is not set, /bin/sh is used.", options))
}
<commit_msg>chroot new_io<commit_after>#![crate_name = "chroot"]
#![feature(collections, core, old_io, os, old_path, rustc_private, std_misc)]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Vsevolod Velichko <torkvemada@sorokdva.net>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;
extern crate libc;

use getopts::{optflag, optopt, getopts, usage};
use c_types::{get_pw_from_args, get_group};
use libc::funcs::posix88::unistd::{execvp, setuid, setgid};
use std::ffi::{CStr, CString};
use std::iter::FromIterator;
use std::path::Path;
use std::env;

#[path = "../common/util.rs"] #[macro_use] mod util;
#[path = "../common/c_types.rs"] mod c_types;

extern {
    fn chroot(path: *const libc::c_char) -> libc::c_int;
}

#[cfg(any(target_os = "macos", target_os = "freebsd"))]
extern {
    fn setgroups(size: libc::c_int, list: *const libc::gid_t) -> libc::c_int;
}

#[cfg(target_os = "linux")]
extern {
    fn setgroups(size: libc::size_t, list: *const libc::gid_t) -> libc::c_int;
}

static NAME: &'static str = "chroot";
static VERSION: &'static str = "1.0.0";

pub fn uumain(args: Vec<String>) -> i32 {
    let program = &args[0];

    let options = [
        optopt("u", "user", "User (ID or name) to switch before running the program", "USER"),
        optopt("g", "group", "Group (ID or name) to switch to", "GROUP"),
        optopt("G", "groups", "Comma-separated list of groups to switch to", "GROUP1,GROUP2…"),
        optopt("", "userspec", "Colon-separated user and group to switch to. \
                                Same as -u USER -g GROUP. \
                                Userspec has higher preference than -u and/or -g", "USER:GROUP"),
        optflag("h", "help", "Show help"),
        optflag("V", "version", "Show program's version")
    ];

    let opts = match getopts(args.tail(), &options) {
        Ok(m) => m,
        Err(f) => {
            show_error!("{}", f);
            help_menu(program.as_slice(), &options);
            return 1
        }
    };

    if opts.opt_present("V") { version(); return 0 }
    if opts.opt_present("h") { help_menu(program.as_slice(), &options); return 0 }

    if opts.free.len() == 0 {
        println!("Missing operand: NEWROOT");
        println!("Try `{} --help` for more information.", program.as_slice());
        return 1
    }

    let default_shell: &'static str = "/bin/sh";
    let default_option: &'static str = "-i";
    let user_shell = env::var("SHELL");

    let newroot = Path::new(opts.free[0].as_slice());
    if !newroot.is_dir() {
        crash!(1, "cannot change root directory to `{}`: no such directory", newroot.display());
    }

    let command: Vec<&str> = match opts.free.len() {
        1 => {
            let shell: &str = match user_shell {
                None => default_shell,
                Some(ref s) => s.as_slice()
            };
            vec!(shell, default_option)
        }
        _ => opts.free[1..opts.free.len()].iter().map(|x| x.as_slice()).collect()
    };

    set_context(&newroot, &opts);

    unsafe {
        let executable = CString::new(command[0]).unwrap().as_bytes_with_nul().as_ptr();
        let mut command_parts: Vec<*const u8> = command.iter().map(|x| CString::new(x.as_bytes()).unwrap().as_bytes_with_nul().as_ptr()).collect();
        command_parts.push(std::ptr::null());
        execvp(executable as *const libc::c_char, command_parts.as_ptr() as *mut *const libc::c_char) as i32
    }
}

fn set_context(root: &Path, options: &getopts::Matches) {
    let userspec_str = options.opt_str("userspec");
    let user_str = options.opt_str("user").unwrap_or_default();
    let group_str = options.opt_str("group").unwrap_or_default();
    let groups_str = options.opt_str("groups").unwrap_or_default();
    let userspec = match userspec_str {
        Some(ref u) => {
            let s: Vec<&str> = u.as_slice().split(':').collect();
            if s.len() != 2 {
                crash!(1, "invalid userspec: `{}`", u.as_slice())
            };
            s
        }
        None => Vec::new()
    };
    let user = if userspec.is_empty() { user_str.as_slice() } else { userspec[0].as_slice() };
    let group = if userspec.is_empty() { group_str.as_slice() } else { userspec[1].as_slice() };

    enter_chroot(root);

    set_groups_from_str(groups_str.as_slice());
    set_main_group(group);
    set_user(user);
}

fn enter_chroot(root: &Path) {
    let root_str = root.display();
    env::set_current_dir(root).unwrap();
    let err = unsafe {
        chroot(CString::new(b".").unwrap().as_bytes_with_nul().as_ptr() as *const libc::c_char)
    };
    if err != 0 {
        crash!(1, "cannot chroot to {}: {}", root_str, strerror(err).as_slice())
    };
}

fn set_main_group(group: &str) {
    if !group.is_empty() {
        let group_id = match get_group(group) {
            None => crash!(1, "no such group: {}", group),
            Some(g) => g.gr_gid
        };
        let err = unsafe { setgid(group_id) };
        if err != 0 {
            crash!(1, "cannot set gid to {}: {}", group_id, strerror(err).as_slice())
        }
    }
}

#[cfg(any(target_os = "macos", target_os = "freebsd"))]
fn set_groups(groups: Vec<libc::gid_t>) -> libc::c_int {
    unsafe {
        setgroups(groups.len() as libc::c_int,
                  groups.as_slice().as_ptr())
    }
}

#[cfg(target_os = "linux")]
fn set_groups(groups: Vec<libc::gid_t>) -> libc::c_int {
    unsafe {
        setgroups(groups.len() as libc::size_t,
                  groups.as_slice().as_ptr())
    }
}

fn set_groups_from_str(groups: &str) {
    if !groups.is_empty() {
        let groups_vec: Vec<libc::gid_t> = FromIterator::from_iter(
            groups.split(',').map(
                |x| match get_group(x) {
                    None => crash!(1, "no such group: {}", x),
                    Some(g) => g.gr_gid
                })
            );
        let err = set_groups(groups_vec);
        if err != 0 {
            crash!(1, "cannot set groups: {}", strerror(err).as_slice())
        }
    }
}

fn set_user(user: &str) {
    if !user.is_empty() {
        let user_id = get_pw_from_args(&vec!(String::from_str(user))).unwrap().pw_uid;
        let err = unsafe { setuid(user_id as libc::uid_t) };
        if err != 0 {
            crash!(1, "cannot set user to {}: {}", user, strerror(err).as_slice())
        }
    }
}

fn strerror(errno: i32) -> String {
    unsafe {
        let err = libc::funcs::c95::string::strerror(errno) as *const libc::c_char;
        let bytes= CStr::from_ptr(err).to_bytes();
        String::from_utf8_lossy(bytes).to_string()
    }
}

fn version() {
    println!("{} v{}", NAME, VERSION)
}

fn help_menu(program: &str, options: &[getopts::OptGroup]) {
    version();
    println!("Usage:");
    println!("  {} [OPTION]… NEWROOT [COMMAND [ARG]…]", program);
    println!("");
    print!("{}", usage(
            "Run COMMAND with root directory set to NEWROOT.\n\
             If COMMAND is not specified, it defaults to '${SHELL} -i'. \
             If ${SHELL} is not set, /bin/sh is used.", options))
}
<|endoftext|>


<commit_before>extern crate mio;

use std::sync::mpsc;
use mio::Sender;
use super::protocol::{
	ApiMessage,
	ApiRequestMessage,
	ApiResponseMessage
};
use ::encoding::{ encode, decode };
use super::ResponseHandle;

use ::conn::ConnectionMessage;

pub struct Client {
	app: String,
	io: Sender<ConnectionMessage>
}

impl Client {
	pub fn new(app: String, io: Sender<ConnectionMessage>) -> Client {
		Client {
			app: app,
			io: io
		}
	}

	pub fn request<Req: ApiMessage, Res: ApiMessage>(&self, msg: ApiRequestMessage<Req>) -> Result<ResponseHandle<ApiResponseMessage<Res>>, String> {
		let (tx, rx) = mpsc::channel();

		//Encode the message, then append its length to the front
		let mut msgbytes = encode(&msg).unwrap();
		let mut bytes = encode(&msgbytes.len()).unwrap();
		bytes.append(&mut msgbytes);

		self.io.send(ConnectionMessage::Request(tx, bytes));

		Ok(ResponseHandle::new(rx))
	}
}<commit_msg>changes to client<commit_after>extern crate mio;

use std::sync::mpsc;
use mio::Sender;
use super::protocol::{
	ApiMessage,
	ApiRequestMessage,
	ApiResponseMessage
};
use super::ResponseHandle;
use ::encoding::{ encode, decode };
use ::conn::ConnectionMessage;

pub struct Client {
	app: String,
	io: Sender<ConnectionMessage>
}

impl Client {
	pub fn new(app: String, io: Sender<ConnectionMessage>) -> Client {
		Client {
			app: app,
			io: io
		}
	}

	pub fn request<Req: ApiMessage, Res: ApiMessage>(&self, msg: ApiRequestMessage<Req>) -> Result<ResponseHandle<ApiResponseMessage<Res>>, String> {
		let (tx, rx) = mpsc::channel();

		//Encode the message, then append its length to the front
		let mut msgbytes = encode(&msg).unwrap();
		let mut bytes = encode(&msgbytes.len()).unwrap();
		bytes.append(&mut msgbytes);

		self.io.send(ConnectionMessage::Request(tx, bytes));

		Ok(ResponseHandle::new(rx))
	}

	pub fn execute<Req: ApiMessage>(&self, msg: ApiRequestMessage<Req>) {
		let mut msgbytes = encode(&msg).unwrap();
		let mut bytes = encode(&msgbytes.len()).unwrap();
		bytes.append(&mut msgbytes);

		self.io.send(ConnectionMessage::Execute(bytes));
	}
}<|endoftext|>


<commit_before>//
// base64.rs - base64 implementation
//
// The Base64 Alphabet
//
//  Value Encoding  Value Encoding  Value Encoding  Value Encoding
//   0 A            17 R            34 i            51 z
//   1 B            18 S            35 j            52 0
//   2 C            19 T            36 k            53 1
//   3 D            20 U            37 l            54 2
//   4 E            21 V            38 m            55 3
//   5 F            22 W            39 n            56 4
//   6 G            23 X            40 o            57 5
//   7 H            24 Y            41 p            58 6
//   8 I            25 Z            42 q            59 7
//   9 J            26 a            43 r            60 8
//  10 K            27 b            44 s            61 9
//  11 L            28 c            45 t            62 +
//  12 M            29 d            46 u            63 /
//  13 N            30 e            47 v
//  14 O            31 f            48 w         (pad) =
//  15 P            32 g            49 x
//  16 Q            33 h            50 y
//

use std;

import std::map;

export base64, mk_base64;

iface base64 {
    fn encode(src: [u8]) -> [u8];
    fn decode(src: [u8]) -> [u8];
    fn urlsafe_encode(src: [u8]) -> [u8];
    fn urlsafe_decode(src: [u8]) -> [u8];
}

fn mk_base64() -> base64 {
    type _base64 = {padd: u8, table: [u8]};
    impl of base64 for _base64 {
        fn encode(src: [u8]) -> [u8] {
            let srclen = vec::len(src);
            let targ = if srclen % 3u == 0u {
                vec::init_elt_mut((srclen / 3u) * 4u, 0u8)
            } else {
                vec::init_elt_mut((srclen / 3u + 1u) * 4u, 0u8)
            };
            let input = vec::init_elt_mut(3u, 0u8);
            let output = vec::init_elt_mut(4u, 0u8);
            let curr = 0u, src_curr = 0u;
            let table = self.table;

            while srclen > 2u {
                input[0] = src[src_curr];
                input[1] = src[src_curr + 1u];
                input[2] = src[src_curr + 2u];
                srclen -= 3u; src_curr += 3u;

                output[0] = input[0] >> 2u8;
                output[1] = ((input[0] &  3u8) << 4u8) | (input[1] >> 4u8);
                output[2] = ((input[1] & 15u8) << 2u8) | (input[2] >> 6u8);
                output[3] = input[2] & 63u8;

                targ[curr] = table[output[0]]; curr += 1u;
                targ[curr] = table[output[1]]; curr += 1u;
                targ[curr] = table[output[2]]; curr += 1u;
                targ[curr] = table[output[3]]; curr += 1u;
            }

            if srclen != 0u {
                input[0] = 0u8; input[1] = 0u8; input[2] = 0u8;

                alt srclen {
                  1u { input[0] = src[src_curr]; }
                  2u { input[0] = src[src_curr];
                       input[1] = src[src_curr + 1u]; }
                  _  { }
                }

                output[0] = input[0] >> 2u8;
                output[1] = ((input[0] &  3u8) << 4u8) | (input[1] >> 4u8);
                output[2] = ((input[1] & 15u8) << 2u8) | (input[2] >> 6u8);

                targ[curr] = table[output[0]]; curr += 1u;
                targ[curr] = table[output[1]]; curr += 1u;
                targ[curr] = if srclen == 1u {
                    self.padd
                } else {
                    table[output[2]]
                };
                curr += 1u; targ[curr] = self.padd; curr += 1u;
            }

            vec::from_mut(targ)
        }
        fn decode(src: [u8]) -> [u8] {
            let srclen = vec::len(src);
            let input  = vec::init_elt_mut(4u, 0u8);
            let output = vec::init_elt_mut(4u, 0u8);
            let targ = if src[srclen - 2u] == self.padd {
                vec::init_elt_mut(srclen / 4u * 3u - 2u, 0u8)
            } else if src[srclen - 1u] == self.padd {
                vec::init_elt_mut(srclen / 4u * 3u - 1u, 0u8)
            } else {
                vec::init_elt_mut(srclen / 4u * 3u, 0u8)
            };
            let c = -1;
            let curr = 0u, src_curr = 0u;
            let table = self.table;

            while srclen > 4u {
                input[0] = src[src_curr];
                input[1] = src[src_curr + 1u];
                input[2] = src[src_curr + 2u];
                input[3] = src[src_curr + 3u];
                srclen -= 4u; src_curr += 4u;

                c = idx(table, input[0]);
                if c == -1 { fail "malformed base64 string"; }
                output[0] = c as u8;

                c = idx(table, input[1]);
                if c == -1 { fail "malformed base64 string"; }
                output[1] = c as u8;

                c = idx(table, input[2]);
                if c == -1 { fail "malformed base64 string"; }
                output[2] = c as u8;

                c = idx(table, input[3]);
                if c == -1 { fail "malformed base64 string"; }
                output[3] = c as u8;

                targ[curr] = (output[0] << 2u8) | (output[1] >> 4u8);
                curr += 1u;

                targ[curr] =
                    ((output[1] & 15u8) << 4u8) | (output[2] >> 2u8);
                curr += 1u;

                targ[curr] = ((output[2] &  3u8) << 6u8) | output[3];
                curr += 1u;
            }

            if srclen == 4u {
                input[0] = src[src_curr];
                input[1] = src[src_curr + 1u];
                input[2] = src[src_curr + 2u];
                input[3] = src[src_curr + 3u];

                c = idx(table, input[0]);
                if c == -1 { fail "malformed base64 string"; }
                output[0] = c as u8;

                c = idx(table, input[1]);
                if c == -1 { fail "malformed base64 string"; }
                output[1] = c as u8;

                targ[curr] = (output[0] << 2u8) | (output[1] >> 4u8);
                curr += 1u;

                if input[2] == self.padd { ret vec::from_mut(targ); }

                c = idx(table, input[2]);
                if c == -1 { fail "malformed base64 string"; }
                output[2] = c as u8;

                targ[curr] = ((output[1] & 15u8) << 4u8) | (output[2] >> 2u8);
                curr += 1u;

                if input[3] == self.padd { ret vec::from_mut(targ); }

                c = idx(table, input[3]);
                if c == -1 { fail "malformed base64 string"; }
                output[3] = c as u8;

                targ[curr] = ((output[2] & 3u8) << 6u8) | output[3];
            } else {
                fail "malformed base64 string";
            }

            vec::from_mut(targ)
        }
        fn urlsafe_encode(src: [u8]) -> [u8] {
            let res = self.encode(src);
            vec::map(res) { |i|
                if i == 43u8 { 45u8 }
                else if i == 47u8 { 95u8 }
                else { i }
            }
        }
        fn urlsafe_decode(src: [u8]) -> [u8] {
            let src0 = vec::map(src) { |i|
                if i == 45u8 { 43u8 }
                else if i == 95u8 { 47u8 }
                else { i }
            };
            self.decode(src0)
        }
    }

    let table = vec::init_elt_mut(64u, 0u8), i = 0u8;
    u8::range(65u8, 91u8)  { |j| table[i] = j; i += 1u8; }
    u8::range(97u8, 123u8) { |j| table[i] = j; i += 1u8; }
    u8::range(48u8, 58u8)  { |j| table[i] = j; i += 1u8; }
    table[i] = 43u8; i += 1u8;
    table[i] = 47u8; i += 1u8;

    {padd: 61u8, table: vec::from_mut(table)} as base64
}

fn idx(elems: [const u8], x: u8) -> int {
    let i = 0;
    for e in elems {
        if e == x { ret i; }
        i += 1;
    }
    ret -1;
}

#[cfg(test)]
mod tests {
    import core::str::{from_bytes, bytes};
    enum mode {
        t_decode,
        t_encode,
        t_urlsafe_encode,
        t_urlsafe_decode
    }
    fn setup(t: mode) -> map::hashmap<str, str> {
        let m = map::new_str_hash::<str>();
        alt t {
          t_decode | t_urlsafe_decode {
            m.insert("cGxlYXN1cmUu", "pleasure.");
            m.insert("bGVhc3VyZS4=",  "leasure.");
            m.insert("ZWFzdXJlLg==",   "easure.");
            m.insert("YXN1cmUu",        "asure.");
            m.insert("c3VyZS4=",         "sure.");
          }
          t_encode | t_urlsafe_encode {
            m.insert("pleasure.", "cGxlYXN1cmUu");
            m.insert("leasure.",  "bGVhc3VyZS4=");
            m.insert("easure.",   "ZWFzdXJlLg==");
            m.insert("asure.",        "YXN1cmUu");
            m.insert("sure.",         "c3VyZS4=");
          }
        }
        m
    }
    fn do_test(t: mode) {
        let b64 = mk_base64();
        let m = setup(t);
        m.keys { |k|
            let expected = m.get(k);
            let actual = alt t {
              t_decode { from_bytes(b64.decode(bytes(k))) }
              t_encode { from_bytes(b64.encode(bytes(k))) }
              t_urlsafe_decode { from_bytes(b64.urlsafe_decode(bytes(k))) }
              t_urlsafe_encode { from_bytes(b64.urlsafe_encode(bytes(k))) }
            };
            #debug("expected: %s", expected);
            #debug("actual:   %s", actual);
            assert expected == actual;
        }
    }
    #[test]
    fn decode() { do_test(t_decode); }
    #[test]
    fn encode() { do_test(t_encode); }
    #[test]
    fn urlsafe_decode() { do_test(t_urlsafe_decode); }
    #[test]
    fn urlsafe_encode() { do_test(t_urlsafe_encode); }
}
<commit_msg>changes<commit_after>//
// base64.rs - base64 implementation
//
// The Base64 Alphabet
//
//  Value Encoding  Value Encoding  Value Encoding  Value Encoding
//   0 A            17 R            34 i            51 z
//   1 B            18 S            35 j            52 0
//   2 C            19 T            36 k            53 1
//   3 D            20 U            37 l            54 2
//   4 E            21 V            38 m            55 3
//   5 F            22 W            39 n            56 4
//   6 G            23 X            40 o            57 5
//   7 H            24 Y            41 p            58 6
//   8 I            25 Z            42 q            59 7
//   9 J            26 a            43 r            60 8
//  10 K            27 b            44 s            61 9
//  11 L            28 c            45 t            62 +
//  12 M            29 d            46 u            63 /
//  13 N            30 e            47 v
//  14 O            31 f            48 w         (pad) =
//  15 P            32 g            49 x
//  16 Q            33 h            50 y
//

use std;

import std::map;

export base64, mk_base64;

iface base64 {
    fn encode(src: [u8]) -> [u8];
    fn decode(src: [u8]) -> [u8];
    fn urlsafe_encode(src: [u8]) -> [u8];
    fn urlsafe_decode(src: [u8]) -> [u8];
}

fn mk_base64() -> base64 {
    type _base64 = {padd: u8, table: [u8]};
    impl of base64 for _base64 {
        fn encode(src: [u8]) -> [u8] {
            let srclen = vec::len(src);
            let targ = if srclen % 3u == 0u {
                vec::init_elt_mut((srclen / 3u) * 4u, 0u8)
            } else {
                vec::init_elt_mut((srclen / 3u + 1u) * 4u, 0u8)
            };
            let input = vec::init_elt_mut(3u, 0u8);
            let output = vec::init_elt_mut(4u, 0u8);
            let curr = 0u, src_curr = 0u;
            let table = self.table;

            while srclen > 2u {
                input[0] = src[src_curr];
                input[1] = src[src_curr + 1u];
                input[2] = src[src_curr + 2u];
                srclen -= 3u; src_curr += 3u;

                output[0] = input[0] >> 2u8;
                output[1] = ((input[0] &  3u8) << 4u8) | (input[1] >> 4u8);
                output[2] = ((input[1] & 15u8) << 2u8) | (input[2] >> 6u8);
                output[3] = input[2] & 63u8;

                targ[curr] = table[output[0]]; curr += 1u;
                targ[curr] = table[output[1]]; curr += 1u;
                targ[curr] = table[output[2]]; curr += 1u;
                targ[curr] = table[output[3]]; curr += 1u;
            }

            if srclen != 0u {
                input[0] = 0u8; input[1] = 0u8; input[2] = 0u8;

                alt srclen {
                  1u { input[0] = src[src_curr]; }
                  2u { input[0] = src[src_curr];
                       input[1] = src[src_curr + 1u]; }
                  _  { }
                }

                output[0] = input[0] >> 2u8;
                output[1] = ((input[0] &  3u8) << 4u8) | (input[1] >> 4u8);
                output[2] = ((input[1] & 15u8) << 2u8) | (input[2] >> 6u8);

                targ[curr] = table[output[0]]; curr += 1u;
                targ[curr] = table[output[1]]; curr += 1u;
                targ[curr] = if srclen == 1u {
                    self.padd
                } else {
                    table[output[2]]
                };
                curr += 1u; targ[curr] = self.padd; curr += 1u;
            }

            vec::from_mut(targ)
        }
        fn decode(src: [u8]) -> [u8] {
            let srclen = vec::len(src);
            let input  = vec::init_elt_mut(4u, 0u8);
            let output = vec::init_elt_mut(4u, 0u8);
            let targ = if src[srclen - 2u] == self.padd {
                vec::init_elt_mut(srclen / 4u * 3u - 2u, 0u8)
            } else if src[srclen - 1u] == self.padd {
                vec::init_elt_mut(srclen / 4u * 3u - 1u, 0u8)
            } else {
                vec::init_elt_mut(srclen / 4u * 3u, 0u8)
            };
            let curr = 0u, src_curr = 0u;
            let table = self.table;

            while srclen > 4u {
                input[0] = src[src_curr];
                input[1] = src[src_curr + 1u];
                input[2] = src[src_curr + 2u];
                input[3] = src[src_curr + 3u];
                srclen -= 4u; src_curr += 4u;

                output[0] = idx(table, input[0]);
                if output[0] == 64u8 { fail "malformed base64 string"; }

                output[1] = idx(table, input[1]);
                if output[1] == 64u8 { fail "malformed base64 string"; }

                output[2] = idx(table, input[2]);
                if output[2] == 64u8 { fail "malformed base64 string"; }

                output[3] = idx(table, input[3]);
                if output[3] == 64u8 { fail "malformed base64 string"; }

                targ[curr] = (output[0] << 2u8) | (output[1] >> 4u8);
                curr += 1u;

                targ[curr] =
                    ((output[1] & 15u8) << 4u8) | (output[2] >> 2u8);
                curr += 1u;

                targ[curr] = ((output[2] &  3u8) << 6u8) | output[3];
                curr += 1u;
            }

            if srclen == 4u {
                input[0] = src[src_curr];
                input[1] = src[src_curr + 1u];
                input[2] = src[src_curr + 2u];
                input[3] = src[src_curr + 3u];

                output[0] = idx(table, input[0]);
                if output[0] == 64u8 { fail "malformed base64 string"; }

                output[1] = idx(table, input[1]);
                if output[1] == 64u8 { fail "malformed base64 string"; }

                targ[curr] = (output[0] << 2u8) | (output[1] >> 4u8);
                curr += 1u;

                if input[2] == self.padd { ret vec::from_mut(targ); }

                output[2] = idx(table, input[2]);
                if output[2] == 64u8 { fail "malformed base64 string"; }

                targ[curr] = ((output[1] & 15u8) << 4u8) | (output[2] >> 2u8);
                curr += 1u;

                if input[3] == self.padd { ret vec::from_mut(targ); }

                output[3] = idx(table, input[3]);
                if output[3] == 64u8 { fail "malformed base64 string"; }

                targ[curr] = ((output[2] & 3u8) << 6u8) | output[3];
            } else {
                fail "malformed base64 string";
            }

            vec::from_mut(targ)
        }
        fn urlsafe_encode(src: [u8]) -> [u8] {
            let res = self.encode(src);
            vec::map(res) { |i|
                if i == 43u8 { 45u8 }
                else if i == 47u8 { 95u8 }
                else { i }
            }
        }
        fn urlsafe_decode(src: [u8]) -> [u8] {
            let src0 = vec::map(src) { |i|
                if i == 45u8 { 43u8 }
                else if i == 95u8 { 47u8 }
                else { i }
            };
            self.decode(src0)
        }
    }

    let table = vec::init_elt_mut(64u, 0u8), i = 0u8;
    u8::range(65u8, 91u8)  { |j| table[i] = j; i += 1u8; }
    u8::range(97u8, 123u8) { |j| table[i] = j; i += 1u8; }
    u8::range(48u8, 58u8)  { |j| table[i] = j; i += 1u8; }
    table[i] = 43u8; i += 1u8;
    table[i] = 47u8; i += 1u8;

    {padd: 61u8, table: vec::from_mut(table)} as base64
}

fn idx(elems: [const u8], x: u8) -> u8 {
    let i = 0u8;
    while i < 64u8 {
        if elems[i] == x { break; }
        i += 1u8;
    }
    ret i;
}

#[cfg(test)]
mod tests {
    import core::str::{from_bytes, bytes};
    enum mode {
        t_decode,
        t_encode,
        t_urlsafe_encode,
        t_urlsafe_decode
    }
    fn setup(t: mode) -> map::hashmap<str, str> {
        let m = map::new_str_hash::<str>();
        alt t {
          t_decode | t_urlsafe_decode {
            m.insert("cGxlYXN1cmUu", "pleasure.");
            m.insert("bGVhc3VyZS4=",  "leasure.");
            m.insert("ZWFzdXJlLg==",   "easure.");
            m.insert("YXN1cmUu",        "asure.");
            m.insert("c3VyZS4=",         "sure.");
          }
          t_encode | t_urlsafe_encode {
            m.insert("pleasure.", "cGxlYXN1cmUu");
            m.insert("leasure.",  "bGVhc3VyZS4=");
            m.insert("easure.",   "ZWFzdXJlLg==");
            m.insert("asure.",        "YXN1cmUu");
            m.insert("sure.",         "c3VyZS4=");
          }
        }
        m
    }
    fn do_test(t: mode) {
        let b64 = mk_base64();
        let m = setup(t);
        m.keys { |k|
            let expected = m.get(k);
            let actual = alt t {
              t_decode { from_bytes(b64.decode(bytes(k))) }
              t_encode { from_bytes(b64.encode(bytes(k))) }
              t_urlsafe_decode { from_bytes(b64.urlsafe_decode(bytes(k))) }
              t_urlsafe_encode { from_bytes(b64.urlsafe_encode(bytes(k))) }
            };
            #debug("expected: %s", expected);
            #debug("actual:   %s", actual);
            assert expected == actual;
        }
    }
    #[test]
    fn decode() { do_test(t_decode); }
    #[test]
    fn encode() { do_test(t_encode); }
    #[test]
    fn urlsafe_decode() { do_test(t_urlsafe_decode); }
    #[test]
    fn urlsafe_encode() { do_test(t_urlsafe_encode); }
}
<|endoftext|>