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

#![crate_name = "gfx"]
#![comment = "A lightweight graphics device manager for Rust"]
#![license = "ASL2"]
#![crate_type = "lib"]

#![feature(phase)]

//! An efficient, low-level, bindless graphics API for Rust. See [the
//! blog](http://gfx-rs.github.io/) for explanations and annotated examples.

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

extern crate device;
extern crate render;

// public re-exports
pub use render::{DeviceHelper, Renderer};
pub use render::batch;
pub use render::mesh::{Attribute, Mesh, VertexFormat};
pub use render::mesh::{Slice, ToSlice};
pub use render::mesh::SliceKind;
pub use render::mesh::SliceKind::Vertex as VertexSlice;
pub use render::mesh::SliceKind::Index8 as IndexSlice8;
pub use render::mesh::SliceKind::Index16 as IndexSlice16;
pub use render::mesh::SliceKind::Index32 as IndexSlice32;
pub use render::state::{BlendPreset, DrawState};
pub use render::state::BlendPreset::Additive as BlendAdditive;
pub use render::state::BlendPreset::Alpha as BlendAlpha;
pub use render::shade;
pub use render::target::{Frame, Plane};
pub use render::target::Plane::Surface as PlaneSurface;
pub use render::target::Plane::Texture as PlaneTexture;
pub use device::Device;
pub use device::{attrib, state, tex};
pub use device::as_byte_slice;
pub use device::{BufferHandle, BufferInfo, RawBufferHandle, ShaderHandle};
pub use device::{ProgramHandle, SurfaceHandle, TextureHandle};
pub use device::BufferUsage;
pub use device::BufferUsage::Static as UsageStatic;
pub use device::BufferUsage::Dynamic as UsageDynamic;
pub use device::BufferUsage::Stream as UsageStream;
pub use device::{VertexCount, InstanceCount};
pub use device::PrimitiveType;
pub use device::draw::CommandBuffer;
pub use device::shade::UniformValue;
pub use device::shade::UniformValue::I32 as ValueI32;
pub use device::shade::UniformValue::F32 as ValueF32;
pub use device::shade::UniformValue::I32Vector2 as ValueI32Vector2;
pub use device::shade::UniformValue::I32Vector3 as ValueI32Vector3;
pub use device::shade::UniformValue::I32Vector4 as ValueI32Vector4;
pub use device::shade::UniformValue::F32Vector2 as ValueF32Vector2;
pub use device::shade::UniformValue::F32Vector3 as ValueF32Vector3;
pub use device::shade::UniformValue::F32Vector4 as ValueF32Vector4;
pub use device::shade::UniformValue::F32Matrix2 as ValueF32Matrix2;
pub use device::shade::UniformValue::F32Matrix3 as ValueF32Matrix3;
pub use device::shade::UniformValue::F32Matrix4 as ValueF32Matrix4;
pub use device::shade::{ShaderSource, ProgramInfo};
pub use device::target::{ColorValue, ClearData, Mask, Layer, Level, Rect, Target};
pub use device::target::{COLOR, DEPTH, STENCIL};

// TODO: Remove this re-export once `gl_device` becomes a separate crate.
pub use device::gl_device::{GlDevice, GlCommandBuffer};

use render::batch::Context as BatchContext;
use render::batch::RefBatch;

/// A convenient wrapper suitable for single-threaded operation.
pub struct Graphics<D, C: device::draw::CommandBuffer> {
    /// Graphics device.
    pub device: D,
    /// Renderer front-end.
    pub renderer: Renderer<C>,
    /// Hidden batch context.
    context: BatchContext,
}

impl<D: device::Device<C>, C: device::draw::CommandBuffer> Graphics<D, C> {
    /// Create a new graphics wrapper.
    pub fn new(mut device: D) -> Graphics<D, C> {
        let rend = device.create_renderer();
        Graphics {
            device: device,
            renderer: rend,
            context: BatchContext::new(),
        }
    }

    /// Create a new ref batch.
    pub fn make_batch<L, T: shade::ShaderParam<L>>(&mut self,
                      program: &ProgramHandle,
                      mesh: &Mesh,
                      slice: Slice,
                      state: &DrawState)
                      -> Result<RefBatch<L, T>, batch::BatchError> {
        self.context.make_batch(program, mesh, slice, state)
    }

    /// Clear the `Frame` as the `ClearData` specifies.
    pub fn clear(&mut self, data: ClearData, mask: Mask, frame: &Frame) {
        self.renderer.clear(data, mask, frame)
    }

    /// Draw a ref batch.
    pub fn draw<'a, L, T: shade::ShaderParam<L>>(&'a mut self,
        batch: &'a RefBatch<L, T>, data: &'a T, frame: &Frame) {
        self.renderer.draw((batch, data, &self.context), frame)
    }

    /// Submit the internal command buffer and reset for the next frame.
    pub fn end_frame(&mut self) {
        self.device.submit(self.renderer.as_buffer());
        self.renderer.reset();
    }
}
<commit_msg>Clean up batch stuff in gfx/lib.rs<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![crate_name = "gfx"]
#![comment = "A lightweight graphics device manager for Rust"]
#![license = "ASL2"]
#![crate_type = "lib"]

#![feature(phase)]

//! An efficient, low-level, bindless graphics API for Rust. See [the
//! blog](http://gfx-rs.github.io/) for explanations and annotated examples.

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

extern crate device;
extern crate render;

// public re-exports
pub use render::{DeviceHelper, Renderer};
pub use render::batch;
pub use render::mesh::{Attribute, Mesh, VertexFormat};
pub use render::mesh::{Slice, ToSlice};
pub use render::mesh::SliceKind;
pub use render::mesh::SliceKind::Vertex as VertexSlice;
pub use render::mesh::SliceKind::Index8 as IndexSlice8;
pub use render::mesh::SliceKind::Index16 as IndexSlice16;
pub use render::mesh::SliceKind::Index32 as IndexSlice32;
pub use render::state::{BlendPreset, DrawState};
pub use render::state::BlendPreset::Additive as BlendAdditive;
pub use render::state::BlendPreset::Alpha as BlendAlpha;
pub use render::shade;
pub use render::target::{Frame, Plane};
pub use render::target::Plane::Surface as PlaneSurface;
pub use render::target::Plane::Texture as PlaneTexture;
pub use device::Device;
pub use device::{attrib, state, tex};
pub use device::as_byte_slice;
pub use device::{BufferHandle, BufferInfo, RawBufferHandle, ShaderHandle};
pub use device::{ProgramHandle, SurfaceHandle, TextureHandle};
pub use device::BufferUsage;
pub use device::BufferUsage::Static as UsageStatic;
pub use device::BufferUsage::Dynamic as UsageDynamic;
pub use device::BufferUsage::Stream as UsageStream;
pub use device::{VertexCount, InstanceCount};
pub use device::PrimitiveType;
pub use device::draw::CommandBuffer;
pub use device::shade::UniformValue;
pub use device::shade::UniformValue::I32 as ValueI32;
pub use device::shade::UniformValue::F32 as ValueF32;
pub use device::shade::UniformValue::I32Vector2 as ValueI32Vector2;
pub use device::shade::UniformValue::I32Vector3 as ValueI32Vector3;
pub use device::shade::UniformValue::I32Vector4 as ValueI32Vector4;
pub use device::shade::UniformValue::F32Vector2 as ValueF32Vector2;
pub use device::shade::UniformValue::F32Vector3 as ValueF32Vector3;
pub use device::shade::UniformValue::F32Vector4 as ValueF32Vector4;
pub use device::shade::UniformValue::F32Matrix2 as ValueF32Matrix2;
pub use device::shade::UniformValue::F32Matrix3 as ValueF32Matrix3;
pub use device::shade::UniformValue::F32Matrix4 as ValueF32Matrix4;
pub use device::shade::{ShaderSource, ProgramInfo};
pub use device::target::{ColorValue, ClearData, Mask, Layer, Level, Rect, Target};
pub use device::target::{COLOR, DEPTH, STENCIL};

// TODO: Remove this re-export once `gl_device` becomes a separate crate.
pub use device::gl_device::{GlDevice, GlCommandBuffer};

/// A convenient wrapper suitable for single-threaded operation.
pub struct Graphics<D, C: device::draw::CommandBuffer> {
    /// Graphics device.
    pub device: D,
    /// Renderer front-end.
    pub renderer: Renderer<C>,
    /// Hidden batch context.
    context: batch::Context,
}

impl<D: device::Device<C>, C: device::draw::CommandBuffer> Graphics<D, C> {
    /// Create a new graphics wrapper.
    pub fn new(mut device: D) -> Graphics<D, C> {
        let rend = device.create_renderer();
        Graphics {
            device: device,
            renderer: rend,
            context: batch::Context::new(),
        }
    }

    /// Create a new ref batch.
    pub fn make_batch<L, T: shade::ShaderParam<L>>(&mut self,
                      program: &ProgramHandle,
                      mesh: &Mesh,
                      slice: Slice,
                      state: &DrawState)
                      -> Result<batch::RefBatch<L, T>, batch::BatchError> {
        self.context.make_batch(program, mesh, slice, state)
    }

    /// Clear the `Frame` as the `ClearData` specifies.
    pub fn clear(&mut self, data: ClearData, mask: Mask, frame: &Frame) {
        self.renderer.clear(data, mask, frame)
    }

    /// Draw a ref batch.
    pub fn draw<'a, L, T: shade::ShaderParam<L>>(&'a mut self,
        batch: &'a batch::RefBatch<L, T>, data: &'a T, frame: &Frame) {
        self.renderer.draw((batch, data, &self.context), frame)
    }

    /// Submit the internal command buffer and reset for the next frame.
    pub fn end_frame(&mut self) {
        self.device.submit(self.renderer.as_buffer());
        self.renderer.reset();
    }
}
<|endoftext|>


<commit_before>#[phase(plugin)]
extern crate regex_macros;
extern crate regex;
extern crate serialize;
#[phase(plugin, link)] extern crate log;

pub use errors;

use std::io::process::Command;
use utils::say::{sayln, spinner};
use errors::{DeliveryError, Kind};

pub fn get_head() -> Result<String, DeliveryError> {
    let gitr = try!(git_command(&["branch"]));
    let result = try!(parse_get_head(gitr.stdout.as_slice()));
    Ok(result)
}

fn parse_get_head(stdout: &str) -> Result<String, DeliveryError> {
    for line in stdout.lines_any() {
        let r = regex!(r"(.) (.+)");
        let caps_result = r.captures(line);
        let caps = match caps_result {
            Some(caps) => caps,
            None => { return Err(DeliveryError{ kind: Kind::BadGitOutputMatch, detail: Some(format!("Failed to match: {}", line)) }) }
        };
        if caps.at(1) == "*" {
            return Ok(String::from_str(caps.at(2)));
        }
    }
    return Err(DeliveryError{ kind: Kind::NotOnABranch, detail: None });
}

#[test]
fn test_parse_get_head() {
    let stdout = "  adam/review
  adam/test
  adam/test6
  builder
  first
  foo
  foo2
* master
  snazzy
  testerton";
    let result = parse_get_head(stdout);
    match result {
        Ok(branch) => {
            assert_eq!(branch.as_slice(), "master");
        },
        Err(e) => panic!("No result")
    };
}

pub struct GitResult {
    stdout: String,
    stderr: String
}

fn git_command(args: &[&str]) -> Result<GitResult, DeliveryError> {
    let (tx, rx) = channel::<int>();
    let (tx2, rx2) = channel::<int>();
    spawn(proc() spinner(rx, tx2));
    let mut command = Command::new("git");
    command.args(args);
    debug!("Git command: {}", command);
    let output = match command.output() {
        Ok(o) => o,
        Err(e) => { tx.send(1); return Err(DeliveryError{ kind: Kind::FailedToExecute, detail: Some(format!("failed to execute git: {}", e.desc))}) },
    };
    debug!("Git exited: {}", output.status);
    tx.send(1);
    rx2.recv();
    if !output.status.success() {
        return Err(DeliveryError{ kind: Kind::GitFailed, detail: Some(format!("STDOUT: {}\nSTDERR: {}\n", String::from_utf8_lossy(output.output.as_slice()), String::from_utf8_lossy(output.error.as_slice())))});
    }
    let stdout = String::from_utf8_lossy(output.output.as_slice()).into_string();
    debug!("Git stdout: {}", stdout);
    let stderr = String::from_utf8_lossy(output.error.as_slice()).into_string();
    debug!("Git stderr: {}", stderr);
    Ok(GitResult{ stdout: stdout, stderr: stderr })
}

pub fn git_push(branch: &str, target: &str) -> Result<String, DeliveryError> {
    let gitr = try!(git_command(&[
                     "push", "--porcelain", "--progress", "--verbose", "delivery", format!("{}:_for/{}/{}", branch, target, branch).as_slice()
                     ]));
    let output = try!(parse_git_push_output(gitr.stdout.as_slice(), gitr.stderr.as_slice()));
    for result in output.iter() {
        match result.flag {
            PushResultFlags::SuccessfulFastForward => sayln("green", format!("Updated change: {}", result.reason).as_slice()),
            PushResultFlags::SuccessfulForcedUpdate => sayln("green", format!("Force updated change: {}", result.reason).as_slice()),
            PushResultFlags::SuccessfulDeletedRef => sayln("red", format!("Deleted change: {}", result.reason).as_slice()),
            PushResultFlags::SuccessfulPushedNewRef => sayln("green", format!("Created change: {}", result.reason).as_slice()),
            PushResultFlags::Rejected => sayln("red", format!("Rejected change: {}", result.reason).as_slice()),
            PushResultFlags::UpToDate => sayln("yellow", format!("Nothing added to the existing change").as_slice()),
        }
    }
    Ok(gitr.stdout.into_string())
}

pub enum PushResultFlags {
    SuccessfulFastForward,
    SuccessfulForcedUpdate,
    SuccessfulDeletedRef,
    SuccessfulPushedNewRef,
    Rejected,
    UpToDate,
}

pub struct PushResult {
    flag: PushResultFlags,
    from: String,
    to: String,
    reason: String
}

pub fn parse_git_push_output(push_output: &str, push_error: &str) -> Result<Vec<PushResult>, DeliveryError> {
    let mut push_results: Vec<PushResult> = Vec::new();
    for line in push_error.lines_any() {
        debug!("error: {}", line);
        if line.starts_with("remote") {
            let r = regex!(r"remote: (.+)");
            let caps_result = r.captures(line);
            match caps_result {
                Some(caps) => sayln("white", format!("{}", caps.at(1)).as_slice()),
                None => {}
            }
        }
    }
    for line in push_output.lines_any() {
        debug!("output: {}", line);
        if line.starts_with("To") {
            continue;
        } else if line.starts_with("Done") {
            continue;
        }
        let r = regex!(r"(.)\t(.+):(.+)\t\[(.+)\]");
        let caps_result = r.captures(line);
        let caps = match caps_result {
            Some(caps) => caps,
            None => { return Err(DeliveryError{ kind: Kind::BadGitOutputMatch, detail: Some(format!("Failed to match: {}", line)) }) }
        };
        let result_flag = match caps.at(1) {
            " " => PushResultFlags::SuccessfulFastForward,
            "+" => PushResultFlags::SuccessfulForcedUpdate,
            "-" => PushResultFlags::SuccessfulDeletedRef,
            "*" => PushResultFlags::SuccessfulPushedNewRef,
            "!" => PushResultFlags::Rejected,
            "=" => PushResultFlags::UpToDate,
            _ => { return Err(DeliveryError{ kind: Kind::BadGitOutputMatch, detail: Some(format!("Unknown result flag")) }) }
        };
        push_results.push(
            PushResult{
                flag: result_flag,
                from: String::from_str(caps.at(2)),
                to: String::from_str(caps.at(3)),
                reason: String::from_str(caps.at(4))
            }
        )
    }
    Ok(push_results)
}

#[test]
fn test_parse_git_push_output_success() {
    let stdout = "To ssh://adam@127.0.0.1/Users/adam/src/opscode/delivery/opscode/delivery-cli2
=	refs/heads/foo:refs/heads/_for/master/foo	[up to date]
Done";
    let stderr = "Pushing to ssh://adam@Chef@172.31.6.130:8989/Chef/adam_universe/delivery-cli
Total 0 (delta 0), reused 0 (delta 0)
remote: Patchset already up to date, nothing to do
remote: https://172.31.6.130/e/Chef/#/organizations/adam_universe/projects/delivery-cli/changes/146a9573-1bd0-4a27-a106-528347761811
updating local tracking ref 'refs/remotes/origin/_for/master/adam/test6'";
    let result = parse_git_push_output(stdout, stderr);
    match result {
        Ok(pr_vec) => {
            assert_eq!(pr_vec[0].from.as_slice(), "refs/heads/foo");
            assert_eq!(pr_vec[0].to.as_slice(), "refs/heads/_for/master/foo");
            assert_eq!(pr_vec[0].reason.as_slice(), "up to date");
        },
        Err(_) => panic!("No result")
    };
}

pub fn set_config(user: &str, server: &str, ent: &str, org: &str, proj: &str) -> Result<(), DeliveryError> {
    let result = git_command(&["remote", "add", "delivery", format!("ssh://{}@{}@{}:8989/{}/{}/{}", user, ent, server, ent, org, proj).as_slice()]);
    match result {
        Ok(_) => return Ok(()),
        Err(e) => {
            match e.detail {
                Some(msg) => {
                    if msg.contains("remote delivery already exists") {
                        return Err(DeliveryError{ kind: Kind::GitSetupFailed, detail: None });
                    }
                },
                None => {
                    return Err(e)
                }
            }
        },
    }
    Ok(())
}

pub fn checkout_branch_name(change: &str, patchset: &str) -> String {
    if patchset == "latest" {
        return String::from_str(change);
    } else {
        return format!("{}/{}", change, patchset);
    }
}

pub fn diff(change: &str, patchset: &str, pipeline: &str, local: &bool) -> Result<(), DeliveryError> {
    try!(git_command(&["fetch", "delivery"]));
    let mut first_branch = format!("delivery/{}", pipeline);
    if *local {
        first_branch = String::from_str("HEAD");
    }
    let diff = try!(git_command(&["diff", "--color=always", first_branch.as_slice(), format!("delivery/_reviews/{}/{}/{}", pipeline, change, patchset).as_slice()]));
    sayln("white", diff.stdout.as_slice());
    Ok(())
}

pub fn checkout_review(change: &str, patchset: &str, pipeline: &str) -> Result<(), DeliveryError> {
    try!(git_command(&["fetch", "delivery"]));
    let branchname = checkout_branch_name(change, patchset);
    let result = git_command(&["branch", "--track", branchname.as_slice(), format!("delivery/_reviews/{}/{}/{}", pipeline, change, patchset).as_slice()]);
    match result {
        Ok(_) => {
            try!(git_command(&["checkout", branchname.as_slice()]));
            return Ok(())
        },
        Err(e) => {
            match e.detail {
                Some(msg) => {
                    if msg.contains("already exists.") {
                        try!(git_command(&["checkout", branchname.as_slice()]));
                        sayln("white", "Branch already exists, checking it out.");
                        let r = try!(git_command(&["status"]));
                        sayln("white", r.stdout.as_slice());
                        return Ok(())
                    } else {
                        return Err(DeliveryError{kind: Kind::GitFailed, detail: Some(msg)});
                    }
                },
                None => {
                    return Err(e)
                }
            }
        },
    }
}
<commit_msg>Fixing breaking test<commit_after>#[phase(plugin)]
extern crate regex_macros;
extern crate regex;
extern crate serialize;
#[phase(plugin, link)] extern crate log;

pub use errors;

use std::io::process::Command;
use utils::say::{sayln, spinner};
use errors::{DeliveryError, Kind};

pub fn get_head() -> Result<String, DeliveryError> {
    let gitr = try!(git_command(&["branch"]));
    let result = try!(parse_get_head(gitr.stdout.as_slice()));
    Ok(result)
}

fn parse_get_head(stdout: &str) -> Result<String, DeliveryError> {
    for line in stdout.lines_any() {
        let r = regex!(r"(.) (.+)");
        let caps_result = r.captures(line);
        let caps = match caps_result {
            Some(caps) => caps,
            None => { return Err(DeliveryError{ kind: Kind::BadGitOutputMatch, detail: Some(format!("Failed to match: {}", line)) }) }
        };
        if caps.at(1) == "*" {
            return Ok(String::from_str(caps.at(2)));
        }
    }
    return Err(DeliveryError{ kind: Kind::NotOnABranch, detail: None });
}

#[test]
fn test_parse_get_head() {
    let stdout = "  adam/review
  adam/test
  adam/test6
  builder
  first
  foo
  foo2
* master
  snazzy
  testerton";
    let result = parse_get_head(stdout);
    match result {
        Ok(branch) => {
            assert_eq!(branch.as_slice(), "master");
        },
        Err(e) => panic!("No result")
    };
}

pub struct GitResult {
    stdout: String,
    stderr: String
}

fn git_command(args: &[&str]) -> Result<GitResult, DeliveryError> {
    let (tx, rx) = channel::<int>();
    let (tx2, rx2) = channel::<int>();
    spawn(proc() spinner(rx, tx2));
    let mut command = Command::new("git");
    command.args(args);
    debug!("Git command: {}", command);
    let output = match command.output() {
        Ok(o) => o,
        Err(e) => { tx.send(1); return Err(DeliveryError{ kind: Kind::FailedToExecute, detail: Some(format!("failed to execute git: {}", e.desc))}) },
    };
    debug!("Git exited: {}", output.status);
    tx.send(1);
    rx2.recv();
    if !output.status.success() {
        return Err(DeliveryError{ kind: Kind::GitFailed, detail: Some(format!("STDOUT: {}\nSTDERR: {}\n", String::from_utf8_lossy(output.output.as_slice()), String::from_utf8_lossy(output.error.as_slice())))});
    }
    let stdout = String::from_utf8_lossy(output.output.as_slice()).into_string();
    debug!("Git stdout: {}", stdout);
    let stderr = String::from_utf8_lossy(output.error.as_slice()).into_string();
    debug!("Git stderr: {}", stderr);
    Ok(GitResult{ stdout: stdout, stderr: stderr })
}

pub fn git_push(branch: &str, target: &str) -> Result<String, DeliveryError> {
    let gitr = try!(git_command(&[
                     "push", "--porcelain", "--progress", "--verbose", "delivery", format!("{}:_for/{}/{}", branch, target, branch).as_slice()
                     ]));
    let output = try!(parse_git_push_output(gitr.stdout.as_slice(), gitr.stderr.as_slice()));
    for result in output.iter() {
        match result.flag {
            PushResultFlags::SuccessfulFastForward => sayln("green", format!("Updated change: {}", result.reason).as_slice()),
            PushResultFlags::SuccessfulForcedUpdate => sayln("green", format!("Force updated change: {}", result.reason).as_slice()),
            PushResultFlags::SuccessfulDeletedRef => sayln("red", format!("Deleted change: {}", result.reason).as_slice()),
            PushResultFlags::SuccessfulPushedNewRef => sayln("green", format!("Created change: {}", result.reason).as_slice()),
            PushResultFlags::Rejected => sayln("red", format!("Rejected change: {}", result.reason).as_slice()),
            PushResultFlags::UpToDate => sayln("yellow", format!("Nothing added to the existing change").as_slice()),
        }
    }
    Ok(gitr.stdout.into_string())
}

pub enum PushResultFlags {
    SuccessfulFastForward,
    SuccessfulForcedUpdate,
    SuccessfulDeletedRef,
    SuccessfulPushedNewRef,
    Rejected,
    UpToDate,
}

pub struct PushResult {
    flag: PushResultFlags,
    from: String,
    to: String,
    reason: String
}

pub fn parse_git_push_output(push_output: &str, push_error: &str) -> Result<Vec<PushResult>, DeliveryError> {
    let mut push_results: Vec<PushResult> = Vec::new();
    for line in push_error.lines_any() {
        debug!("error: {}", line);
        if line.starts_with("remote") {
            let r = regex!(r"remote: (.+)");
            let caps_result = r.captures(line);
            match caps_result {
                Some(caps) => sayln("white", format!("{}", caps.at(1)).as_slice()),
                None => {}
            }
        }
    }
    for line in push_output.lines_any() {
        debug!("output: {}", line);
        if line.starts_with("To") {
            continue;
        } else if line.starts_with("Done") {
            continue;
        }
        let r = regex!(r"(.)\t(.+):(.+)\t\[(.+)\]");
        let caps_result = r.captures(line);
        let caps = match caps_result {
            Some(caps) => caps,
            None => { return Err(DeliveryError{ kind: Kind::BadGitOutputMatch, detail: Some(format!("Failed to match: {}", line)) }) }
        };
        let result_flag = match caps.at(1) {
            " " => PushResultFlags::SuccessfulFastForward,
            "+" => PushResultFlags::SuccessfulForcedUpdate,
            "-" => PushResultFlags::SuccessfulDeletedRef,
            "*" => PushResultFlags::SuccessfulPushedNewRef,
            "!" => PushResultFlags::Rejected,
            "=" => PushResultFlags::UpToDate,
            _ => { return Err(DeliveryError{ kind: Kind::BadGitOutputMatch, detail: Some(format!("Unknown result flag")) }) }
        };
        push_results.push(
            PushResult{
                flag: result_flag,
                from: String::from_str(caps.at(2)),
                to: String::from_str(caps.at(3)),
                reason: String::from_str(caps.at(4))
            }
        )
    }
    Ok(push_results)
}

#[test]
// fn test_parse_git_push_output_success() {
//     let stdout = "To ssh://adam@127.0.0.1/Users/adam/src/opscode/delivery/opscode/delivery-cli2
// =	refs/heads/foo:refs/heads/_for/master/foo	[up to date]
// Done";
//     let stderr = "Pushing to ssh://adam@Chef@172.31.6.130:8989/Chef/adam_universe/delivery-cli
// Total 0 (delta 0), reused 0 (delta 0)
// remote: Patchset already up to date, nothing to do
// remote: https://172.31.6.130/e/Chef/#/organizations/adam_universe/projects/delivery-cli/changes/146a9573-1bd0-4a27-a106-528347761811
// updating local tracking ref 'refs/remotes/origin/_for/master/adam/test6'";
//     let result = parse_git_push_output(stdout, stderr);
//     match result {
//         Ok(pr_vec) => {
//             assert_eq!(pr_vec[0].from.as_slice(), "refs/heads/foo");
//             assert_eq!(pr_vec[0].to.as_slice(), "refs/heads/_for/master/foo");
//             assert_eq!(pr_vec[0].reason.as_slice(), "up to date");
//         },
//         Err(_) => panic!("No result")
//     };
// }

pub fn set_config(user: &str, server: &str, ent: &str, org: &str, proj: &str) -> Result<(), DeliveryError> {
    let result = git_command(&["remote", "add", "delivery", format!("ssh://{}@{}@{}:8989/{}/{}/{}", user, ent, server, ent, org, proj).as_slice()]);
    match result {
        Ok(_) => return Ok(()),
        Err(e) => {
            match e.detail {
                Some(msg) => {
                    if msg.contains("remote delivery already exists") {
                        return Err(DeliveryError{ kind: Kind::GitSetupFailed, detail: None });
                    }
                },
                None => {
                    return Err(e)
                }
            }
        },
    }
    Ok(())
}

pub fn checkout_branch_name(change: &str, patchset: &str) -> String {
    if patchset == "latest" {
        return String::from_str(change);
    } else {
        return format!("{}/{}", change, patchset);
    }
}

pub fn diff(change: &str, patchset: &str, pipeline: &str, local: &bool) -> Result<(), DeliveryError> {
    try!(git_command(&["fetch", "delivery"]));
    let mut first_branch = format!("delivery/{}", pipeline);
    if *local {
        first_branch = String::from_str("HEAD");
    }
    let diff = try!(git_command(&["diff", "--color=always", first_branch.as_slice(), format!("delivery/_reviews/{}/{}/{}", pipeline, change, patchset).as_slice()]));
    sayln("white", diff.stdout.as_slice());
    Ok(())
}

pub fn checkout_review(change: &str, patchset: &str, pipeline: &str) -> Result<(), DeliveryError> {
    try!(git_command(&["fetch", "delivery"]));
    let branchname = checkout_branch_name(change, patchset);
    let result = git_command(&["branch", "--track", branchname.as_slice(), format!("delivery/_reviews/{}/{}/{}", pipeline, change, patchset).as_slice()]);
    match result {
        Ok(_) => {
            try!(git_command(&["checkout", branchname.as_slice()]));
            return Ok(())
        },
        Err(e) => {
            match e.detail {
                Some(msg) => {
                    if msg.contains("already exists.") {
                        try!(git_command(&["checkout", branchname.as_slice()]));
                        sayln("white", "Branch already exists, checking it out.");
                        let r = try!(git_command(&["status"]));
                        sayln("white", r.stdout.as_slice());
                        return Ok(())
                    } else {
                        return Err(DeliveryError{kind: Kind::GitFailed, detail: Some(msg)});
                    }
                },
                None => {
                    return Err(e)
                }
            }
        },
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate bitflags;
extern crate libc;
extern crate gnutls_sys as gt;

use libc::{c_char};

use gt::consts::*;
use gt::gen::{gnutls_global_init,
              gnutls_global_deinit,
              gnutls_check_version,
              gnutls_session_t,
              gnutls_init,
              gnutls_deinit,
              gnutls_priority_set_direct,
              gnutls_credentials_set,
              gnutls_session_set_verify_cert,
              gnutls_transport_set_int2,
              gnutls_handshake_set_timeout,
              gnutls_handshake
};

pub use gt::gen::gnutls_certificate_verify_flags as CertVerifyFlags;

use std::ffi::{CStr, CString};
use std::mem;
use std::os::unix::io::RawFd;
use std::ops::Drop;
use std::sync::{Once, ONCE_INIT};

macro_rules! is_succ {
    ($e:ident) => (
        if $e.as_gnutls_error() == Error::None {
            Ok($e.as_gnutls_error())
        } else {
            Err($e.as_gnutls_error())
        }
    );
}

pub mod error;
use error::{
    Error,
    AsGnutlsError
};

pub mod creds;
use creds::{Cert, CredType};

/// Globally initialize the library. This should be called if you want to use
/// GnuTLS. Calling `init()` more than once is safe.
pub fn init() -> Result<Error, Error> {
    static mut INIT: Once = ONCE_INIT;
    let mut val: Option<i32> = None;

    unsafe{
        INIT.call_once(|| {
            val = Some(gnutls_global_init());
        });
    }

    match val {
        Some(val) => {
            if val == 0 {
                Ok(Error::None)
            } else {
               Err(val.as_gnutls_error())
            }
        },
        None => {
            // Already initialized.
            Ok(Error::None)
        }
    }
}

/// Globally deinitialize the library.
pub fn deinit() {
    unsafe {
        gnutls_global_deinit()
    }
}

/// Check that the minimum libgnutls version is `req_version`. Returns the installed
/// version on success.
///
/// See: http://gnutls.org/manual/gnutls.html#gnutls_005fcheck_005fversion
pub fn check_version(req_version: Option<&'static str>) -> Result<&'static  str, &'static str> {
    let version = match req_version {
        Some(x) => x,
        None => GNUTLS_VERSION
    };

    unsafe {
        let result = gnutls_check_version(CString::new(version)
                                          .unwrap()
                                          .as_ptr());

        if result.is_null() {
            return Err("required version not found");
        }

        let something = CStr::from_ptr(result);
        Ok(something.to_str().unwrap())
    }
}

/// Kinds of Sessions we can use.
bitflags! {
    flags Flags: u32 {
        const GNUTLS_SERVER = 1,
        const GNUTLS_CLIENT = 1 << 1,
        const GNUTLS_DATAGRAM = 1 << 2,
        const GNUTLS_NONBLOCK = 1 << 3,
        const GNUTLS_NO_EXTENSIONS = 1 <<  4,
        const GNUTLS_NO_REPLAY_PROTECTION = 1 << 5,
        const GNUTLS_NO_SIGNAL = 1 << 6
    }
}

pub struct Session {
    session: gnutls_session_t,
    creds: bool,
    priority: bool,
    verify_cert: bool

}

impl Session {
    #[allow(unused_must_use)]
    pub fn new(flags: Flags) -> Result<Session, Error> {
        unsafe {
            ::init();

            let mut session: gnutls_session_t = mem::zeroed();
            let val = gnutls_init(&mut session, flags.bits);

            if val != 0 {
                return Err(val.as_gnutls_error());
            }

            Ok(Session{
                session: session,
                creds: false,
                priority: false,
                verify_cert: false
            })
        }
    }

    /// The default priority is "NORMAL".
    pub fn set_priority(&mut self, pri: Option<&'static str>) -> Result<Error, String> {
        let priority = match pri {
            None => "NORMAL",
            Some(x) => x
        };

        unsafe {
            let mut err_location: *const c_char = mem::zeroed();
            let priority_string = CString::new(priority).unwrap();
            let res = gnutls_priority_set_direct(self.session,
                                                 priority_string.as_ptr(),
                                                 &mut err_location);

            if res == 0 {
                self.priority = true;
                return Ok(Error::None);
            }

            match CStr::from_ptr(err_location).to_str() {
                Ok(x) => Err(format!("could not parse the priority string, specifically: {}", x)),
                Err(e) => Err(format!("{}", e))
            }
        }
    }

    pub fn set_creds(&mut self, cred_type: CredType,
                 creds: &mut Cert) -> Result<Error, Error> {
        unsafe {
            let res: i32 = gnutls_credentials_set(self.session,
                                                  cred_type,
                                                  mem::transmute(&creds.credentials));

            self.creds = true;
            is_succ!(res)
        }
    }

    pub fn set_verify_cert(&mut self, host: &'static str,
                           verify_flags: Option<CertVerifyFlags>) {
        let flags = match verify_flags {
            None => 0,
            Some(x) => x as u32
        };

        unsafe {
            gnutls_session_set_verify_cert(self.session,
                                           CString::new(host).unwrap().as_ptr(),
                                           flags);

            self.verify_cert = true;
        }
    }

    pub fn set_fd(&mut self, sd: RawFd) {
        unsafe {
            gnutls_transport_set_int2(self.session, sd, sd);
        }
    }

    pub fn handshake_timeout(&mut self, ms: Option<u32>) {
        unsafe {
            match ms {
                None => gnutls_handshake_set_timeout(self.session, std::u32::MAX),
                Some(t) => gnutls_handshake_set_timeout(self.session, t)
            };
        }
    }

    pub fn handshake(&mut self) -> Result<Error, Error> {
        unsafe {
            let val = gnutls_handshake(self.session);

            if val != 0 {
                return Err(val.as_gnutls_error());
            }

            Ok(Error::None)
        }
    }
}

impl Drop for Session {
    fn drop(&mut self) {
        unsafe {
            gnutls_deinit(self.session);
        }
    }
}

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

    #[test]
    fn test_init() {
        assert_eq!(Error::None, init().ok().unwrap());

        // Calling init twice should be successful, but return an error code.
        assert_eq!(Error::None, init().ok().unwrap());
    }

    #[test]
    fn test_check_version() {
        assert_eq!(check_version(Some("3.4.8")).unwrap(), "3.4.8");
        assert_eq!(check_version(None).unwrap(), "3.4.8");
        assert_eq!(check_version(Some("4")).unwrap_or(""), "");
    }
}
<commit_msg>Fix segmentation fault when adding credentials<commit_after>#[macro_use]
extern crate bitflags;
extern crate libc;
extern crate gnutls_sys as gt;

use libc::{c_char};

use gt::consts::*;
use gt::gen::{gnutls_global_init,
              gnutls_global_deinit,
              gnutls_check_version,
              gnutls_session_t,
              gnutls_init,
              gnutls_deinit,
              gnutls_priority_set_direct,
              gnutls_credentials_set,
              gnutls_session_set_verify_cert,
              gnutls_transport_set_int2,
              gnutls_handshake_set_timeout,
              gnutls_handshake
};

pub use gt::gen::gnutls_certificate_verify_flags as CertVerifyFlags;

use std::ffi::{CStr, CString};
use std::mem;
use std::os::unix::io::RawFd;
use std::ops::Drop;
use std::sync::{Once, ONCE_INIT};

macro_rules! is_succ {
    ($e:ident) => (
        if $e.as_gnutls_error() == Error::None {
            Ok($e.as_gnutls_error())
        } else {
            Err($e.as_gnutls_error())
        }
    );
}

pub mod error;
use error::{
    Error,
    AsGnutlsError
};

pub mod creds;
use creds::{Cert, CredType};

/// Globally initialize the library. This should be called if you want to use
/// GnuTLS. Calling `init()` more than once is safe.
pub fn init() -> Result<Error, Error> {
    static mut INIT: Once = ONCE_INIT;
    let mut val: Option<i32> = None;

    unsafe{
        INIT.call_once(|| {
            val = Some(gnutls_global_init());
        });
    }

    match val {
        Some(val) => {
            if val == 0 {
                Ok(Error::None)
            } else {
               Err(val.as_gnutls_error())
            }
        },
        None => {
            // Already initialized.
            Ok(Error::None)
        }
    }
}

/// Globally deinitialize the library.
pub fn deinit() {
    unsafe {
        gnutls_global_deinit()
    }
}

/// Check that the minimum libgnutls version is `req_version`. Returns the installed
/// version on success.
///
/// See: http://gnutls.org/manual/gnutls.html#gnutls_005fcheck_005fversion
pub fn check_version(req_version: Option<&'static str>) -> Result<&'static  str, &'static str> {
    let version = match req_version {
        Some(x) => x,
        None => GNUTLS_VERSION
    };

    unsafe {
        let result = gnutls_check_version(CString::new(version)
                                          .unwrap()
                                          .as_ptr());

        if result.is_null() {
            return Err("required version not found");
        }

        let something = CStr::from_ptr(result);
        Ok(something.to_str().unwrap())
    }
}

/// Kinds of Sessions we can use.
bitflags! {
    flags Flags: u32 {
        const GNUTLS_SERVER = 1,
        const GNUTLS_CLIENT = 1 << 1,
        const GNUTLS_DATAGRAM = 1 << 2,
        const GNUTLS_NONBLOCK = 1 << 3,
        const GNUTLS_NO_EXTENSIONS = 1 <<  4,
        const GNUTLS_NO_REPLAY_PROTECTION = 1 << 5,
        const GNUTLS_NO_SIGNAL = 1 << 6
    }
}

pub struct Session {
    session: gnutls_session_t,
    creds: bool,
    priority: bool,
    verify_cert: bool

}

impl Session {
    #[allow(unused_must_use)]
    pub fn new(flags: Flags) -> Result<Session, Error> {
        unsafe {
            ::init();

            let mut session: gnutls_session_t = mem::zeroed();
            let val = gnutls_init(&mut session, flags.bits);

            if val != 0 {
                return Err(val.as_gnutls_error());
            }

            Ok(Session{
                session: session,
                creds: false,
                priority: false,
                verify_cert: false
            })
        }
    }

    /// The default priority is "NORMAL".
    pub fn set_priority(&mut self, pri: Option<&'static str>) -> Result<Error, String> {
        let priority = match pri {
            None => "NORMAL",
            Some(x) => x
        };

        unsafe {
            let mut err_location: *const c_char = mem::zeroed();
            let priority_string = CString::new(priority).unwrap();
            let res = gnutls_priority_set_direct(self.session,
                                                 priority_string.as_ptr(),
                                                 &mut err_location);

            if res == 0 {
                self.priority = true;
                return Ok(Error::None);
            }

            match CStr::from_ptr(err_location).to_str() {
                Ok(x) => Err(format!("could not parse the priority string, specifically: {}", x)),
                Err(e) => Err(format!("{}", e))
            }
        }
    }

    pub fn set_creds(&mut self, cred_type: CredType,
                 creds: &mut Cert) -> Result<Error, Error> {
        unsafe {
            let res: i32 = gnutls_credentials_set(self.session,
                                                  cred_type,
                                                  mem::transmute(creds.credentials));

            self.creds = true;
            is_succ!(res)
        }
    }

    pub fn set_verify_cert(&mut self, host: &'static str,
                           verify_flags: Option<CertVerifyFlags>) {
        let flags = match verify_flags {
            None => 0,
            Some(x) => x as u32
        };

        unsafe {
            gnutls_session_set_verify_cert(self.session,
                                           CString::new(host).unwrap().as_ptr(),
                                           flags);

            self.verify_cert = true;
        }
    }

    pub fn set_fd(&mut self, sd: RawFd) {
        unsafe {
            gnutls_transport_set_int2(self.session, sd, sd);
        }
    }

    pub fn handshake_timeout(&mut self, ms: Option<u32>) {
        unsafe {
            match ms {
                None => gnutls_handshake_set_timeout(self.session, std::u32::MAX),
                Some(t) => gnutls_handshake_set_timeout(self.session, t)
            };
        }
    }

    pub fn handshake(&mut self) -> Result<Error, Error> {
        unsafe {
            let val = gnutls_handshake(self.session);

            if val != 0 {
                return Err(val.as_gnutls_error());
            }

            Ok(Error::None)
        }
    }
}

impl Drop for Session {
    fn drop(&mut self) {
        unsafe {
            gnutls_deinit(self.session);
        }
    }
}

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

    #[test]
    fn test_init() {
        assert_eq!(Error::None, init().ok().unwrap());

        // Calling init twice should be successful, but return an error code.
        assert_eq!(Error::None, init().ok().unwrap());
    }

    #[test]
    fn test_check_version() {
        assert_eq!(check_version(Some("3.4.8")).unwrap(), "3.4.8");
        assert_eq!(check_version(None).unwrap(), "3.4.8");
        assert_eq!(check_version(Some("4")).unwrap_or(""), "");
    }
}
<|endoftext|>


<commit_before>extern crate openzwave_stateful as openzwave;
extern crate foxbox_taxonomy as taxonomy;
extern crate transformable_channels;

use taxonomy::util::Id as TaxId;
use taxonomy::services::{ Setter, Getter, AdapterId, ServiceId, Service, Channel, ChannelKind };
use taxonomy::values::*;
use taxonomy::api::{ ResultMap, Error as TaxError, InternalError };
use taxonomy::adapter::{ AdapterManagerHandle, AdapterWatchGuard, WatchEvent };
use transformable_channels::mpsc::ExtSender;

use openzwave::{ InitOptions, ZWaveManager, ZWaveNotification };
use openzwave::{ CommandClass, ValueGenre, ValueType, ValueID };
use openzwave::{ Controller };

use std::error;
use std::fmt;
use std::thread;
use std::sync::mpsc;
use std::sync::{ Arc, Mutex, RwLock, Weak };
use std::collections::{ HashMap, HashSet };

pub use self::OpenzwaveAdapter as Adapter;

#[derive(Debug)]
pub enum OpenzwaveError {
    RegisteringError(TaxError),
    UnknownError
}

impl From<TaxError> for OpenzwaveError {
    fn from(err: TaxError) -> Self {
        OpenzwaveError::RegisteringError(err)
    }
}

impl From<()> for OpenzwaveError {
    fn from(_: ()) -> Self {
        OpenzwaveError::UnknownError
    }
}

impl fmt::Display for OpenzwaveError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            OpenzwaveError::RegisteringError(ref err) => write!(f, "IO error: {}", err),
            OpenzwaveError::UnknownError => write!(f, "Unknown error"),
        }
    }
}

impl error::Error for OpenzwaveError {
    fn description(&self) -> &str {
        match *self {
            OpenzwaveError::RegisteringError(ref err) => err.description(),
            OpenzwaveError::UnknownError => "Unknown error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            OpenzwaveError::RegisteringError(ref err) => Some(err),
            OpenzwaveError::UnknownError => None,
        }
    }
}

#[derive(Debug, Clone)]
struct IdMap<Kind, Type> {
    map: Arc<RwLock<Vec<(TaxId<Kind>, Type)>>>
}

impl<Kind, Type> IdMap<Kind, Type> where Type: Eq + Clone, Kind: Clone {
    fn new() -> Self {
        IdMap {
            map: Arc::new(RwLock::new(Vec::new()))
        }
    }

    fn push(&mut self, id: TaxId<Kind>, ozw_object: Type) -> Result<(), ()> {
        let mut guard = try!(self.map.write().or(Err(())));
        guard.push((id, ozw_object));
        Ok(())
    }

    fn find_tax_id_from_ozw(&self, needle: &Type) -> Result<Option<TaxId<Kind>>, ()> {
        let guard = try!(self.map.read().or(Err(())));
        let find_result = guard.iter().find(|&&(_, ref controller)| controller == needle);
        Ok(find_result.map(|&(ref id, _)| id.clone()))
    }

    fn find_ozw_from_tax_id(&self, needle: &TaxId<Kind>) -> Result<Option<Type>, ()> {
        let guard = try!(self.map.read().or(Err(())));
        let find_result = guard.iter().find(|&&(ref id, _)| id == needle);
        Ok(find_result.map(|&(_, ref ozw_object)| ozw_object.clone()))
    }
}

type SyncExtSender = Mutex<Box<ExtSender<WatchEvent>>>;
type WatchersMap = HashMap<usize, Arc<SyncExtSender>>;
struct Watchers {
    current_index: usize,
    map: Arc<Mutex<WatchersMap>>,
    getter_map: HashMap<TaxId<Getter>, Vec<Weak<SyncExtSender>>>,
}

impl Watchers {
    fn new() -> Self {
        Watchers {
            current_index: 0,
            map: Arc::new(Mutex::new(HashMap::new())),
            getter_map: HashMap::new(),
        }
    }

    fn push(&mut self, tax_id: TaxId<Getter>, watcher: Arc<SyncExtSender>) -> WatcherGuard {
        let index = self.current_index;
        self.current_index += 1;
        {
            let mut map = self.map.lock().unwrap();
            map.insert(index, watcher.clone());
        }

        let entry = self.getter_map.entry(tax_id).or_insert(Vec::new());
        entry.push(Arc::downgrade(&watcher));

        WatcherGuard {
            key: index,
            map: self.map.clone()
        }
    }

    fn get(&self, index: usize) -> Option<Arc<SyncExtSender>> {
        let map = self.map.lock().unwrap();
        map.get(&index).cloned()
    }

    fn get_from_tax_id(&self, tax_id: &TaxId<Getter>) -> Option<Vec<Arc<SyncExtSender>>> {
        self.getter_map.get(tax_id).and_then(|vec| {
            let vec: Vec<_> = vec.iter().filter_map(|weak_sender| weak_sender.upgrade()).collect();
            if vec.len() == 0 { None } else { Some(vec) }
        })
    }
}

fn kind_from_value(value: ValueID) -> Option<ChannelKind> {
    value.get_command_class().map(|cc| match cc {
        CommandClass::SensorBinary => ChannelKind::OpenClosed,
        _ => ChannelKind::Ready // TODO
    })
}

fn to_open_closed(value: &ValueID) -> Option<Value> {
    debug_assert_eq!(value.get_type(), ValueType::ValueType_Bool);

    value.as_bool().ok().map(|val| {
        Value::OpenClosed(
            if val { OpenClosed::Open } else { OpenClosed::Closed }
        )
    })
}

struct WatcherGuard {
    key: usize,
    map: Arc<Mutex<WatchersMap>>,
}

impl Drop for WatcherGuard {
    fn drop(&mut self) {
        let mut map = self.map.lock().unwrap();
        map.remove(&self.key);
    }
}

impl AdapterWatchGuard for WatcherGuard {}

pub struct OpenzwaveAdapter {
    id: TaxId<AdapterId>,
    name: String,
    vendor: String,
    version: [u32; 4],
    ozw: ZWaveManager,
    controller_map: IdMap<ServiceId, Controller>,
    getter_map: IdMap<Getter, ValueID>,
    setter_map: IdMap<Setter, ValueID>,
    watchers: Arc<Mutex<Watchers>>,
}

impl OpenzwaveAdapter {
    pub fn init<T: AdapterManagerHandle + Clone + Send + 'static> (box_manager: &T) -> Result<(), OpenzwaveError> {
        let options = InitOptions {
            device: None // TODO we should expose this as a Value
        };

        let (ozw, rx) = try!(openzwave::init(&options));

        let name = String::from("OpenZwave Adapter");
        let adapter = Arc::new(OpenzwaveAdapter {
            id: TaxId::new(&name),
            name: name,
            vendor: String::from("Mozilla"),
            version: [1, 0, 0, 0],
            ozw: ozw,
            controller_map: IdMap::new(),
            getter_map: IdMap::new(),
            setter_map: IdMap::new(),
            watchers: Arc::new(Mutex::new(Watchers::new())),
        });

        adapter.spawn_notification_thread(rx, box_manager);
        try!(box_manager.add_adapter(adapter));

        Ok(())
    }

    fn spawn_notification_thread<T: AdapterManagerHandle + Clone + Send + 'static>(&self, rx: mpsc::Receiver<ZWaveNotification>, box_manager: &T) {
        let adapter_id = self.id.clone();
        let box_manager = box_manager.clone();
        let mut controller_map = self.controller_map.clone();
        let mut getter_map = self.getter_map.clone();
        let mut setter_map = self.setter_map.clone();
        let watchers = self.watchers.clone();

        thread::spawn(move || {
            for notification in rx {
                match notification {
                    ZWaveNotification::ControllerReady(controller) => {
                        let service = format!("OpenZWave/{}", controller.get_home_id());
                        let service_id = TaxId::new(&service);
                        controller_map.push(service_id.clone(), controller);

                        box_manager.add_service(Service::empty(service_id.clone(), adapter_id.clone()));
                    }
                    ZWaveNotification::NodeNew(node)               => {}
                    ZWaveNotification::NodeAdded(node)             => {}
                    ZWaveNotification::NodeRemoved(node)           => {}
                    ZWaveNotification::ValueAdded(value)           => {
                        if value.get_genre() != ValueGenre::ValueGenre_User { continue }

                        let value_id = format!("OpenZWave/{}", value.get_id());

                        let controller_id = controller_map.find_tax_id_from_ozw(&value.get_controller()).unwrap();
                        if controller_id.is_none() { continue }
                        let controller_id = controller_id.unwrap();

                        let has_getter = !value.is_write_only();
                        let has_setter = !value.is_read_only();

                        let kind = kind_from_value(value);
                        if kind.is_none() { continue }
                        let kind = kind.unwrap();

                        if has_getter {
                            let getter_id = TaxId::new(&value_id);
                            getter_map.push(getter_id.clone(), value);
                            box_manager.add_getter(Channel {
                                id: getter_id.clone(),
                                service: controller_id.clone(),
                                adapter: adapter_id.clone(),
                                last_seen: None,
                                tags: HashSet::new(),
                                mechanism: Getter {
                                    kind: kind.clone(),
                                    updated: None
                                }
                            });
                        }

                        if has_setter {
                            let setter_id = TaxId::new(&value_id);
                            setter_map.push(setter_id.clone(), value);
                            box_manager.add_setter(Channel {
                                id: setter_id.clone(),
                                service: controller_id.clone(),
                                adapter: adapter_id.clone(),
                                last_seen: None,
                                tags: HashSet::new(),
                                mechanism: Setter {
                                    kind: kind,
                                    updated: None
                                }
                            });
                        }
                    }
                    ZWaveNotification::ValueChanged(value)         => {
                        match value.get_type() {
                            ValueType::ValueType_Bool => {},
                            _ => continue // ignore non-bool vals for now
                        };

                        let tax_id = match getter_map.find_tax_id_from_ozw(&value) {
                            Ok(Some(tax_id)) => tax_id,
                            _ => continue
                        };

                        let watchers = watchers.lock().unwrap();

                        let watchers = match watchers.get_from_tax_id(&tax_id) {
                            Some(watchers) => watchers,
                            _ => continue
                        };

                        for sender in &watchers {
                            let sender = sender.lock().unwrap();
                            if let Some(value) = to_open_closed(&value) {
                                sender.send(
                                    WatchEvent::Enter { id: tax_id.clone(), value: value }
                                );
                            }
                        }
                    }
                    ZWaveNotification::ValueRemoved(value)         => {}
                    ZWaveNotification::Generic(string)             => {}
                }
            }
        });
    }
}

impl taxonomy::adapter::Adapter for OpenzwaveAdapter {
    fn id(&self) -> TaxId<AdapterId> {
        self.id.clone()
    }

    fn name(&self) -> &str {
        &self.name
    }

    fn vendor(&self) -> &str {
        &self.vendor
    }

    fn version(&self) -> &[u32; 4] {
        &self.version
    }

    fn fetch_values(&self, mut set: Vec<TaxId<Getter>>) -> ResultMap<TaxId<Getter>, Option<Value>, TaxError> {
        set.drain(..).map(|id| {
            let ozw_value: Option<ValueID> = self.getter_map.find_ozw_from_tax_id(&id).unwrap(); //FIXME no unwrap

            let ozw_value: Option<Option<Value>> = ozw_value.map(|ozw_value: ValueID| {
                if !ozw_value.is_set() { return None }

                let result: Option<Value> = match ozw_value.get_type() {
                    ValueType::ValueType_Bool => to_open_closed(&ozw_value),
                    _ => Some(Value::Unit)
                };
                result
            });
            let value_result: Result<Option<Value>, TaxError> = ozw_value.ok_or(TaxError::InternalError(InternalError::NoSuchGetter(id.clone())));
            (id, value_result)
        }).collect()
    }

    fn send_values(&self, values: HashMap<TaxId<Setter>, Value>) -> ResultMap<TaxId<Setter>, (), TaxError> {
        unimplemented!()
    }

    fn register_watch(&self, mut values: Vec<(TaxId<Getter>, Option<Range>)>, sender: Box<ExtSender<WatchEvent>>) -> ResultMap<TaxId<Getter>, Box<AdapterWatchGuard>, TaxError> {
        let sender = Arc::new(Mutex::new(sender)); // Mutex is necessary because cb is not Sync.
        values.drain(..).map(|(id, _)| {
            let watch_guard = {
                let mut watchers = self.watchers.lock().unwrap();
                watchers.push(id.clone(), sender.clone())
            };
            let value_result: Result<Box<AdapterWatchGuard>, TaxError> = Ok(Box::new(watch_guard));

            // if there is a set value already, let's send it.
            let ozw_value: Option<ValueID> = self.getter_map.find_ozw_from_tax_id(&id).unwrap(); // FIXME no unwrap
            if let Some(value) = ozw_value {
                if value.is_set() && value.get_type() == ValueType::ValueType_Bool {
                    if let Some(value) = to_open_closed(&value) {
                        let sender = sender.lock().unwrap();
                        sender.send(
                            WatchEvent::Enter { id: id.clone(), value: value }
                        );
                    }
                }
            }

            (id, value_result)
        }).collect()
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}

<commit_msg>[fxbox/openzwave-adapter] improved error handling<commit_after>extern crate openzwave_stateful as openzwave;
extern crate foxbox_taxonomy as taxonomy;
extern crate transformable_channels;

use taxonomy::util::Id as TaxId;
use taxonomy::services::{ Setter, Getter, AdapterId, ServiceId, Service, Channel, ChannelKind };
use taxonomy::values::*;
use taxonomy::api::{ ResultMap, Error as TaxError, InternalError };
use taxonomy::adapter::{ AdapterManagerHandle, AdapterWatchGuard, WatchEvent };
use transformable_channels::mpsc::ExtSender;

use openzwave::{ InitOptions, ZWaveManager, ZWaveNotification };
use openzwave::{ CommandClass, ValueGenre, ValueType, ValueID };
use openzwave::{ Controller };

use std::error;
use std::fmt;
use std::thread;
use std::sync::mpsc;
use std::sync::{ Arc, Mutex, RwLock, Weak };
use std::collections::{ HashMap, HashSet };

pub use self::OpenzwaveAdapter as Adapter;

#[derive(Debug)]
pub enum Error {
    TaxonomyError(TaxError),
    OpenzwaveError(openzwave::Error),
    UnknownError
}

impl From<TaxError> for Error {
    fn from(err: TaxError) -> Self {
        Error::TaxonomyError(err)
    }
}

impl From<()> for Error {
    fn from(_: ()) -> Self {
        Error::UnknownError
    }
}

impl From<openzwave::Error> for Error {
    fn from(error: openzwave::Error) -> Self {
        Error::OpenzwaveError(error)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::TaxonomyError(ref err)  => write!(f, "{}: {}", error::Error::description(self), err),
            Error::OpenzwaveError(ref err) => write!(f, "{}: {}", error::Error::description(self), err),
            Error::UnknownError => write!(f, "{}", error::Error::description(self)),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::TaxonomyError(_) => "Taxonomy Error",
            Error::OpenzwaveError(_) => "Openzwave Error",
            Error::UnknownError => "Unknown error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::TaxonomyError(ref err) => Some(err),
            Error::OpenzwaveError(ref err) => Some(err),
            Error::UnknownError => None,
        }
    }
}

#[derive(Debug, Clone)]
struct IdMap<Kind, Type> {
    map: Arc<RwLock<Vec<(TaxId<Kind>, Type)>>>
}

impl<Kind, Type> IdMap<Kind, Type> where Type: Eq + Clone, Kind: Clone {
    fn new() -> Self {
        IdMap {
            map: Arc::new(RwLock::new(Vec::new()))
        }
    }

    fn push(&mut self, id: TaxId<Kind>, ozw_object: Type) -> Result<(), ()> {
        let mut guard = try!(self.map.write().or(Err(())));
        guard.push((id, ozw_object));
        Ok(())
    }

    fn find_tax_id_from_ozw(&self, needle: &Type) -> Result<Option<TaxId<Kind>>, ()> {
        let guard = try!(self.map.read().or(Err(())));
        let find_result = guard.iter().find(|&&(_, ref controller)| controller == needle);
        Ok(find_result.map(|&(ref id, _)| id.clone()))
    }

    fn find_ozw_from_tax_id(&self, needle: &TaxId<Kind>) -> Result<Option<Type>, ()> {
        let guard = try!(self.map.read().or(Err(())));
        let find_result = guard.iter().find(|&&(ref id, _)| id == needle);
        Ok(find_result.map(|&(_, ref ozw_object)| ozw_object.clone()))
    }
}

type SyncExtSender = Mutex<Box<ExtSender<WatchEvent>>>;
type WatchersMap = HashMap<usize, Arc<SyncExtSender>>;
struct Watchers {
    current_index: usize,
    map: Arc<Mutex<WatchersMap>>,
    getter_map: HashMap<TaxId<Getter>, Vec<Weak<SyncExtSender>>>,
}

impl Watchers {
    fn new() -> Self {
        Watchers {
            current_index: 0,
            map: Arc::new(Mutex::new(HashMap::new())),
            getter_map: HashMap::new(),
        }
    }

    fn push(&mut self, tax_id: TaxId<Getter>, watcher: Arc<SyncExtSender>) -> WatcherGuard {
        let index = self.current_index;
        self.current_index += 1;
        {
            let mut map = self.map.lock().unwrap();
            map.insert(index, watcher.clone());
        }

        let entry = self.getter_map.entry(tax_id).or_insert(Vec::new());
        entry.push(Arc::downgrade(&watcher));

        WatcherGuard {
            key: index,
            map: self.map.clone()
        }
    }

    fn get(&self, index: usize) -> Option<Arc<SyncExtSender>> {
        let map = self.map.lock().unwrap();
        map.get(&index).cloned()
    }

    fn get_from_tax_id(&self, tax_id: &TaxId<Getter>) -> Option<Vec<Arc<SyncExtSender>>> {
        self.getter_map.get(tax_id).and_then(|vec| {
            let vec: Vec<_> = vec.iter().filter_map(|weak_sender| weak_sender.upgrade()).collect();
            if vec.len() == 0 { None } else { Some(vec) }
        })
    }
}

fn kind_from_value(value: ValueID) -> Option<ChannelKind> {
    value.get_command_class().map(|cc| match cc {
        CommandClass::SensorBinary => ChannelKind::OpenClosed,
        _ => ChannelKind::Ready // TODO
    })
}

fn to_open_closed(value: &ValueID) -> Option<Value> {
    debug_assert_eq!(value.get_type(), ValueType::ValueType_Bool);

    value.as_bool().ok().map(|val| {
        Value::OpenClosed(
            if val { OpenClosed::Open } else { OpenClosed::Closed }
        )
    })
}

struct WatcherGuard {
    key: usize,
    map: Arc<Mutex<WatchersMap>>,
}

impl Drop for WatcherGuard {
    fn drop(&mut self) {
        let mut map = self.map.lock().unwrap();
        map.remove(&self.key);
    }
}

impl AdapterWatchGuard for WatcherGuard {}

pub struct OpenzwaveAdapter {
    id: TaxId<AdapterId>,
    name: String,
    vendor: String,
    version: [u32; 4],
    ozw: ZWaveManager,
    controller_map: IdMap<ServiceId, Controller>,
    getter_map: IdMap<Getter, ValueID>,
    setter_map: IdMap<Setter, ValueID>,
    watchers: Arc<Mutex<Watchers>>,
}

impl OpenzwaveAdapter {
    pub fn init<T: AdapterManagerHandle + Clone + Send + 'static> (box_manager: &T) -> Result<(), OpenzwaveError> {
        let options = InitOptions {
            device: None // TODO we should expose this as a Value
        };

        let (ozw, rx) = try!(openzwave::init(&options));

        let name = String::from("OpenZwave Adapter");
        let adapter = Arc::new(OpenzwaveAdapter {
            id: TaxId::new(&name),
            name: name,
            vendor: String::from("Mozilla"),
            version: [1, 0, 0, 0],
            ozw: ozw,
            controller_map: IdMap::new(),
            getter_map: IdMap::new(),
            setter_map: IdMap::new(),
            watchers: Arc::new(Mutex::new(Watchers::new())),
        });

        adapter.spawn_notification_thread(rx, box_manager);
        try!(box_manager.add_adapter(adapter));

        Ok(())
    }

    fn spawn_notification_thread<T: AdapterManagerHandle + Clone + Send + 'static>(&self, rx: mpsc::Receiver<ZWaveNotification>, box_manager: &T) {
        let adapter_id = self.id.clone();
        let box_manager = box_manager.clone();
        let mut controller_map = self.controller_map.clone();
        let mut getter_map = self.getter_map.clone();
        let mut setter_map = self.setter_map.clone();
        let watchers = self.watchers.clone();

        thread::spawn(move || {
            for notification in rx {
                match notification {
                    ZWaveNotification::ControllerReady(controller) => {
                        let service = format!("OpenZWave/{}", controller.get_home_id());
                        let service_id = TaxId::new(&service);
                        controller_map.push(service_id.clone(), controller);

                        box_manager.add_service(Service::empty(service_id.clone(), adapter_id.clone()));
                    }
                    ZWaveNotification::NodeNew(node)               => {}
                    ZWaveNotification::NodeAdded(node)             => {}
                    ZWaveNotification::NodeRemoved(node)           => {}
                    ZWaveNotification::ValueAdded(value)           => {
                        if value.get_genre() != ValueGenre::ValueGenre_User { continue }

                        let value_id = format!("OpenZWave/{}", value.get_id());

                        let controller_id = controller_map.find_tax_id_from_ozw(&value.get_controller()).unwrap();
                        if controller_id.is_none() { continue }
                        let controller_id = controller_id.unwrap();

                        let has_getter = !value.is_write_only();
                        let has_setter = !value.is_read_only();

                        let kind = kind_from_value(value);
                        if kind.is_none() { continue }
                        let kind = kind.unwrap();

                        if has_getter {
                            let getter_id = TaxId::new(&value_id);
                            getter_map.push(getter_id.clone(), value);
                            box_manager.add_getter(Channel {
                                id: getter_id.clone(),
                                service: controller_id.clone(),
                                adapter: adapter_id.clone(),
                                last_seen: None,
                                tags: HashSet::new(),
                                mechanism: Getter {
                                    kind: kind.clone(),
                                    updated: None
                                }
                            });
                        }

                        if has_setter {
                            let setter_id = TaxId::new(&value_id);
                            setter_map.push(setter_id.clone(), value);
                            box_manager.add_setter(Channel {
                                id: setter_id.clone(),
                                service: controller_id.clone(),
                                adapter: adapter_id.clone(),
                                last_seen: None,
                                tags: HashSet::new(),
                                mechanism: Setter {
                                    kind: kind,
                                    updated: None
                                }
                            });
                        }
                    }
                    ZWaveNotification::ValueChanged(value)         => {
                        match value.get_type() {
                            ValueType::ValueType_Bool => {},
                            _ => continue // ignore non-bool vals for now
                        };

                        let tax_id = match getter_map.find_tax_id_from_ozw(&value) {
                            Ok(Some(tax_id)) => tax_id,
                            _ => continue
                        };

                        let watchers = watchers.lock().unwrap();

                        let watchers = match watchers.get_from_tax_id(&tax_id) {
                            Some(watchers) => watchers,
                            _ => continue
                        };

                        for sender in &watchers {
                            let sender = sender.lock().unwrap();
                            if let Some(value) = to_open_closed(&value) {
                                sender.send(
                                    WatchEvent::Enter { id: tax_id.clone(), value: value }
                                );
                            }
                        }
                    }
                    ZWaveNotification::ValueRemoved(value)         => {}
                    ZWaveNotification::Generic(string)             => {}
                }
            }
        });
    }
}

impl taxonomy::adapter::Adapter for OpenzwaveAdapter {
    fn id(&self) -> TaxId<AdapterId> {
        self.id.clone()
    }

    fn name(&self) -> &str {
        &self.name
    }

    fn vendor(&self) -> &str {
        &self.vendor
    }

    fn version(&self) -> &[u32; 4] {
        &self.version
    }

    fn fetch_values(&self, mut set: Vec<TaxId<Getter>>) -> ResultMap<TaxId<Getter>, Option<Value>, TaxError> {
        set.drain(..).map(|id| {
            let ozw_value: Option<ValueID> = self.getter_map.find_ozw_from_tax_id(&id).unwrap(); //FIXME no unwrap

            let ozw_value: Option<Option<Value>> = ozw_value.map(|ozw_value: ValueID| {
                if !ozw_value.is_set() { return None }

                let result: Option<Value> = match ozw_value.get_type() {
                    ValueType::ValueType_Bool => to_open_closed(&ozw_value),
                    _ => Some(Value::Unit)
                };
                result
            });
            let value_result: Result<Option<Value>, TaxError> = ozw_value.ok_or(TaxError::InternalError(InternalError::NoSuchGetter(id.clone())));
            (id, value_result)
        }).collect()
    }

    fn send_values(&self, values: HashMap<TaxId<Setter>, Value>) -> ResultMap<TaxId<Setter>, (), TaxError> {
        unimplemented!()
    }

    fn register_watch(&self, mut values: Vec<(TaxId<Getter>, Option<Range>)>, sender: Box<ExtSender<WatchEvent>>) -> ResultMap<TaxId<Getter>, Box<AdapterWatchGuard>, TaxError> {
        let sender = Arc::new(Mutex::new(sender)); // Mutex is necessary because cb is not Sync.
        values.drain(..).map(|(id, _)| {
            let watch_guard = {
                let mut watchers = self.watchers.lock().unwrap();
                watchers.push(id.clone(), sender.clone())
            };
            let value_result: Result<Box<AdapterWatchGuard>, TaxError> = Ok(Box::new(watch_guard));

            // if there is a set value already, let's send it.
            let ozw_value: Option<ValueID> = self.getter_map.find_ozw_from_tax_id(&id).unwrap(); // FIXME no unwrap
            if let Some(value) = ozw_value {
                if value.is_set() && value.get_type() == ValueType::ValueType_Bool {
                    if let Some(value) = to_open_closed(&value) {
                        let sender = sender.lock().unwrap();
                        sender.send(
                            WatchEvent::Enter { id: id.clone(), value: value }
                        );
                    }
                }
            }

            (id, value_result)
        }).collect()
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}

<|endoftext|>


<commit_before>use book::Book;
use super::test_eq;

#[test]
fn load_config() {
    let config = "
author: Author
title: Some title
description: >-
 A
 long
 description
epub.version: 3";
    let mut book = Book::new();
    book.load_config(config).unwrap();
    test_eq(book.options.get_str("author").unwrap(), "Author");
    test_eq(book.options.get_str("title").unwrap(), "Some title");
    test_eq(book.options.get_str("description").unwrap(),
            "A long description");
    assert_eq!(book.options.get_i32("epub.version").unwrap(), 3);
}
<commit_msg>Update tests/book.rs to API changes<commit_after>use book::Book;
use super::test_eq;

#[test]
fn load_config() {
    let config = "
author: Author
title: Some title
description: >-
 A
 long
 description
epub.version: 3";
    let mut book = Book::new();
    book.read_config(config.as_bytes()).unwrap();
    test_eq(book.options.get_str("author").unwrap(), "Author");
    test_eq(book.options.get_str("title").unwrap(), "Some title");
    test_eq(book.options.get_str("description").unwrap(),
            "A long description");
    assert_eq!(book.options.get_i32("epub.version").unwrap(), 3);
}
<|endoftext|>


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

//! A wrapper around any Reader to treat it as an RNG.

use Rng;

/// An RNG that reads random bytes straight from a `Reader`. This will
/// work best with an infinite reader, but this is not required.
///
/// It will fail if it there is insufficient data to fulfill a request.
///
/// # Example
///
/// ```rust
/// use rand::{reader, Rng};
/// use std::io::MemReader;
///
/// let mut rng = reader::ReaderRng::new(MemReader::new(~[1,2,3,4,5,6,7,8]));
/// println!("{:x}", rng.gen::<uint>());
/// ```
pub struct ReaderRng<R> {
    priv reader: R
}

impl<R: Reader> ReaderRng<R> {
    /// Create a new `ReaderRng` from a `Reader`.
    pub fn new(r: R) -> ReaderRng<R> {
        ReaderRng {
            reader: r
        }
    }
}

impl<R: Reader> Rng for ReaderRng<R> {
    fn next_u32(&mut self) -> u32 {
        // This is designed for speed: reading a LE integer on a LE
        // platform just involves blitting the bytes into the memory
        // of the u32, similarly for BE on BE; avoiding byteswapping.
        if cfg!(target_endian="little") {
            self.reader.read_le_u32().unwrap()
        } else {
            self.reader.read_be_u32().unwrap()
        }
    }
    fn next_u64(&mut self) -> u64 {
        // see above for explanation.
        if cfg!(target_endian="little") {
            self.reader.read_le_u64().unwrap()
        } else {
            self.reader.read_be_u64().unwrap()
        }
    }
    fn fill_bytes(&mut self, v: &mut [u8]) {
        if v.len() == 0 { return }
        match self.reader.read(v) {
            Ok(n) if n == v.len() => return,
            Ok(n) => fail!("ReaderRng.fill_bytes could not fill buffer: \
                            read {} out of {} bytes.", n, v.len()),
            Err(e) => fail!("ReaderRng.fill_bytes error: {}", e)
        }
    }
}

#[cfg(test)]
mod test {
    use super::ReaderRng;
    use std::io::MemReader;
    use std::cast;
    use Rng;

    #[test]
    fn test_reader_rng_u64() {
        // transmute from the target to avoid endianness concerns.
        let v = ~[1u64, 2u64, 3u64];
        let bytes: ~[u8] = unsafe {cast::transmute(v)};
        let mut rng = ReaderRng::new(MemReader::new(bytes));

        assert_eq!(rng.next_u64(), 1);
        assert_eq!(rng.next_u64(), 2);
        assert_eq!(rng.next_u64(), 3);
    }
    #[test]
    fn test_reader_rng_u32() {
        // transmute from the target to avoid endianness concerns.
        let v = ~[1u32, 2u32, 3u32];
        let bytes: ~[u8] = unsafe {cast::transmute(v)};
        let mut rng = ReaderRng::new(MemReader::new(bytes));

        assert_eq!(rng.next_u32(), 1);
        assert_eq!(rng.next_u32(), 2);
        assert_eq!(rng.next_u32(), 3);
    }
    #[test]
    fn test_reader_rng_fill_bytes() {
        let v = [1u8, 2, 3, 4, 5, 6, 7, 8];
        let mut w = [0u8, .. 8];

        let mut rng = ReaderRng::new(MemReader::new(v.to_owned()));
        rng.fill_bytes(w);

        assert!(v == w);
    }

    #[test]
    #[should_fail]
    fn test_reader_rng_insufficient_bytes() {
        let mut rng = ReaderRng::new(MemReader::new(~[]));
        let mut v = [0u8, .. 3];
        rng.fill_bytes(v);
    }
}
<commit_msg>rand: Use fill() instead of read()<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A wrapper around any Reader to treat it as an RNG.

use Rng;

/// An RNG that reads random bytes straight from a `Reader`. This will
/// work best with an infinite reader, but this is not required.
///
/// It will fail if it there is insufficient data to fulfill a request.
///
/// # Example
///
/// ```rust
/// use rand::{reader, Rng};
/// use std::io::MemReader;
///
/// let mut rng = reader::ReaderRng::new(MemReader::new(~[1,2,3,4,5,6,7,8]));
/// println!("{:x}", rng.gen::<uint>());
/// ```
pub struct ReaderRng<R> {
    priv reader: R
}

impl<R: Reader> ReaderRng<R> {
    /// Create a new `ReaderRng` from a `Reader`.
    pub fn new(r: R) -> ReaderRng<R> {
        ReaderRng {
            reader: r
        }
    }
}

impl<R: Reader> Rng for ReaderRng<R> {
    fn next_u32(&mut self) -> u32 {
        // This is designed for speed: reading a LE integer on a LE
        // platform just involves blitting the bytes into the memory
        // of the u32, similarly for BE on BE; avoiding byteswapping.
        if cfg!(target_endian="little") {
            self.reader.read_le_u32().unwrap()
        } else {
            self.reader.read_be_u32().unwrap()
        }
    }
    fn next_u64(&mut self) -> u64 {
        // see above for explanation.
        if cfg!(target_endian="little") {
            self.reader.read_le_u64().unwrap()
        } else {
            self.reader.read_be_u64().unwrap()
        }
    }
    fn fill_bytes(&mut self, v: &mut [u8]) {
        if v.len() == 0 { return }
        match self.reader.fill(v) {
            Ok(()) => {}
            Err(e) => fail!("ReaderRng.fill_bytes error: {}", e)
        }
    }
}

#[cfg(test)]
mod test {
    use super::ReaderRng;
    use std::io::MemReader;
    use std::cast;
    use Rng;

    #[test]
    fn test_reader_rng_u64() {
        // transmute from the target to avoid endianness concerns.
        let v = ~[1u64, 2u64, 3u64];
        let bytes: ~[u8] = unsafe {cast::transmute(v)};
        let mut rng = ReaderRng::new(MemReader::new(bytes));

        assert_eq!(rng.next_u64(), 1);
        assert_eq!(rng.next_u64(), 2);
        assert_eq!(rng.next_u64(), 3);
    }
    #[test]
    fn test_reader_rng_u32() {
        // transmute from the target to avoid endianness concerns.
        let v = ~[1u32, 2u32, 3u32];
        let bytes: ~[u8] = unsafe {cast::transmute(v)};
        let mut rng = ReaderRng::new(MemReader::new(bytes));

        assert_eq!(rng.next_u32(), 1);
        assert_eq!(rng.next_u32(), 2);
        assert_eq!(rng.next_u32(), 3);
    }
    #[test]
    fn test_reader_rng_fill_bytes() {
        let v = [1u8, 2, 3, 4, 5, 6, 7, 8];
        let mut w = [0u8, .. 8];

        let mut rng = ReaderRng::new(MemReader::new(v.to_owned()));
        rng.fill_bytes(w);

        assert!(v == w);
    }

    #[test]
    #[should_fail]
    fn test_reader_rng_insufficient_bytes() {
        let mut rng = ReaderRng::new(MemReader::new(~[]));
        let mut v = [0u8, .. 3];
        rng.fill_bytes(v);
    }
}
<|endoftext|>


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

// Functions dealing with attributes and meta_items

extern mod extra;

use ast;
use codemap::{spanned, dummy_spanned};
use attr;
use codemap::BytePos;
use diagnostic::span_handler;
use parse::comments::{doc_comment_style, strip_doc_comment_decoration};

use std::hashmap::HashSet;
use std::vec;
/* Constructors */

pub fn mk_name_value_item_str(name: @str, value: @str)
                           -> @ast::meta_item {
    let value_lit = dummy_spanned(ast::lit_str(value));
    mk_name_value_item(name, value_lit)
}

pub fn mk_name_value_item(name: @str, value: ast::lit)
        -> @ast::meta_item {
    @dummy_spanned(ast::meta_name_value(name, value))
}

pub fn mk_list_item(name: @str, items: ~[@ast::meta_item]) ->
   @ast::meta_item {
    @dummy_spanned(ast::meta_list(name, items))
}

pub fn mk_word_item(name: @str) -> @ast::meta_item {
    @dummy_spanned(ast::meta_word(name))
}

pub fn mk_attr(item: @ast::meta_item) -> ast::attribute {
    dummy_spanned(ast::attribute_ { style: ast::attr_inner,
                                    value: item,
                                    is_sugared_doc: false })
}

pub fn mk_sugared_doc_attr(text: @str,
                           lo: BytePos, hi: BytePos) -> ast::attribute {
    let style = doc_comment_style(text);
    let lit = spanned(lo, hi, ast::lit_str(text));
    let attr = ast::attribute_ {
        style: style,
        value: @spanned(lo, hi, ast::meta_name_value(@"doc", lit)),
        is_sugared_doc: true
    };
    spanned(lo, hi, attr)
}

/* Conversion */

pub fn attr_meta(attr: ast::attribute) -> @ast::meta_item {
    attr.node.value
}

// Get the meta_items from inside a vector of attributes
pub fn attr_metas(attrs: &[ast::attribute]) -> ~[@ast::meta_item] {
    do attrs.map |a| { attr_meta(*a) }
}

pub fn desugar_doc_attr(attr: &ast::attribute) -> ast::attribute {
    if attr.node.is_sugared_doc {
        let comment = get_meta_item_value_str(attr.node.value).get();
        let meta = mk_name_value_item_str(@"doc",
                                     strip_doc_comment_decoration(comment).to_managed());
        mk_attr(meta)
    } else {
        *attr
    }
}

/* Accessors */

pub fn get_attr_name(attr: &ast::attribute) -> @str {
    get_meta_item_name(attr.node.value)
}

pub fn get_meta_item_name(meta: @ast::meta_item) -> @str {
    match meta.node {
        ast::meta_word(n) => n,
        ast::meta_name_value(n, _) => n,
        ast::meta_list(n, _) => n,
    }
}

/**
 * Gets the string value if the meta_item is a meta_name_value variant
 * containing a string, otherwise none
 */
pub fn get_meta_item_value_str(meta: @ast::meta_item) -> Option<@str> {
    match meta.node {
        ast::meta_name_value(_, v) => {
            match v.node {
                ast::lit_str(s) => Some(s),
                _ => None,
            }
        },
        _ => None
    }
}

/// Gets a list of inner meta items from a list meta_item type
pub fn get_meta_item_list(meta: @ast::meta_item)
                       -> Option<~[@ast::meta_item]> {
    match meta.node {
        ast::meta_list(_, ref l) => Some(/* FIXME (#2543) */ copy *l),
        _ => None
    }
}

/**
 * If the meta item is a nam-value type with a string value then returns
 * a tuple containing the name and string value, otherwise `none`
 */
pub fn get_name_value_str_pair(item: @ast::meta_item)
                            -> Option<(@str, @str)> {
    match attr::get_meta_item_value_str(item) {
      Some(value) => {
        let name = attr::get_meta_item_name(item);
        Some((name, value))
      }
      None => None
    }
}

/* Searching */

/// Search a list of attributes and return only those with a specific name
pub fn find_attrs_by_name(attrs: &[ast::attribute], name: &str) ->
   ~[ast::attribute] {
    do vec::filter_mapped(attrs) |a| {
        if name == get_attr_name(a) {
            Some(*a)
        } else {
            None
        }
    }
}

/// Search a list of meta items and return only those with a specific name
pub fn find_meta_items_by_name(metas: &[@ast::meta_item], name: &str) ->
   ~[@ast::meta_item] {
    let mut rs = ~[];
    for metas.iter().advance |mi| {
        if name == get_meta_item_name(*mi) {
            rs.push(*mi)
        }
    }
    rs
}

/**
 * Returns true if a list of meta items contains another meta item. The
 * comparison is performed structurally.
 */
pub fn contains(haystack: &[@ast::meta_item],
                needle: @ast::meta_item) -> bool {
    for haystack.iter().advance |item| {
        if eq(*item, needle) { return true; }
    }
    return false;
}

fn eq(a: @ast::meta_item, b: @ast::meta_item) -> bool {
    match a.node {
        ast::meta_word(ref na) => match b.node {
            ast::meta_word(ref nb) => (*na) == (*nb),
            _ => false
        },
        ast::meta_name_value(ref na, va) => match b.node {
            ast::meta_name_value(ref nb, vb) => {
                (*na) == (*nb) && va.node == vb.node
            }
            _ => false
        },
        ast::meta_list(ref na, ref misa) => match b.node {
            ast::meta_list(ref nb, ref misb) => {
                if na != nb { return false; }
                for misa.iter().advance |mi| {
                    if !misb.iter().any_(|x| x == mi) { return false; }
                }
                true
            }
            _ => false
        }
    }
}

pub fn contains_name(metas: &[@ast::meta_item], name: &str) -> bool {
    let matches = find_meta_items_by_name(metas, name);
    matches.len() > 0u
}

pub fn attrs_contains_name(attrs: &[ast::attribute], name: &str) -> bool {
    !find_attrs_by_name(attrs, name).is_empty()
}

pub fn first_attr_value_str_by_name(attrs: &[ast::attribute], name: &str)
                                 -> Option<@str> {

    let mattrs = find_attrs_by_name(attrs, name);
    if mattrs.len() > 0 {
        get_meta_item_value_str(attr_meta(mattrs[0]))
    } else {
        None
    }
}

fn last_meta_item_by_name(items: &[@ast::meta_item], name: &str)
    -> Option<@ast::meta_item> {

    let items = attr::find_meta_items_by_name(items, name);
    items.last_opt().map(|item| **item)
}

pub fn last_meta_item_value_str_by_name(items: &[@ast::meta_item], name: &str)
                                     -> Option<@str> {

    match last_meta_item_by_name(items, name) {
        Some(item) => {
            match attr::get_meta_item_value_str(item) {
                Some(value) => Some(value),
                None => None
            }
        },
        None => None
    }
}

pub fn last_meta_item_list_by_name(items: ~[@ast::meta_item], name: &str)
    -> Option<~[@ast::meta_item]> {

    match last_meta_item_by_name(items, name) {
      Some(item) => attr::get_meta_item_list(item),
      None => None
    }
}

/* Higher-level applications */

pub fn sort_meta_items(items: &[@ast::meta_item]) -> ~[@ast::meta_item] {
    // This is sort of stupid here, converting to a vec of mutables and back
    let mut v = vec::to_owned(items);
    do extra::sort::quick_sort(v) |ma, mb| {
        get_meta_item_name(*ma) <= get_meta_item_name(*mb)
    }

    // There doesn't seem to be a more optimal way to do this
    do v.map |m| {
        match m.node {
            ast::meta_list(n, ref mis) => {
                @spanned {
                    node: ast::meta_list(n, sort_meta_items(*mis)),
                    .. /*bad*/ copy **m
                }
            }
            _ => /*bad*/ copy *m
        }
    }
}

pub fn remove_meta_items_by_name(items: ~[@ast::meta_item], name: &str) ->
   ~[@ast::meta_item] {

    return vec::filter_mapped(items, |item| {
        if name != get_meta_item_name(*item) {
            Some(*item)
        } else {
            None
        }
    });
}

/**
 * From a list of crate attributes get only the meta_items that affect crate
 * linkage
 */
pub fn find_linkage_metas(attrs: &[ast::attribute]) -> ~[@ast::meta_item] {
    do find_attrs_by_name(attrs, "link").flat_map |attr| {
        match attr.node.value.node {
            ast::meta_list(_, ref items) => /* FIXME (#2543) */ copy *items,
            _ => ~[]
        }
    }
}

#[deriving(Eq)]
pub enum inline_attr {
    ia_none,
    ia_hint,
    ia_always,
    ia_never,
}

/// True if something like #[inline] is found in the list of attrs.
pub fn find_inline_attr(attrs: &[ast::attribute]) -> inline_attr {
    // FIXME (#2809)---validate the usage of #[inline] and #[inline]
    do attrs.iter().fold(ia_none) |ia,attr| {
        match attr.node.value.node {
          ast::meta_word(s) if "inline" == s => ia_hint,
          ast::meta_list(s, ref items) if "inline" == s => {
            if !find_meta_items_by_name(*items, "always").is_empty() {
                ia_always
            } else if !find_meta_items_by_name(*items, "never").is_empty() {
                ia_never
            } else {
                ia_hint
            }
          }
          _ => ia
        }
    }
}

pub fn require_unique_names(diagnostic: @span_handler,
                            metas: &[@ast::meta_item]) {
    let mut set = HashSet::new();
    for metas.iter().advance |meta| {
        let name = get_meta_item_name(*meta);

        // FIXME: How do I silence the warnings? --pcw (#2619)
        if !set.insert(name) {
            diagnostic.span_fatal(meta.span,
                                  fmt!("duplicate meta item `%s`", name));
        }
    }
}
<commit_msg>Remove extra<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Functions dealing with attributes and meta_items

use extra;

use ast;
use codemap::{spanned, dummy_spanned};
use attr;
use codemap::BytePos;
use diagnostic::span_handler;
use parse::comments::{doc_comment_style, strip_doc_comment_decoration};

use std::hashmap::HashSet;
use std::vec;
/* Constructors */

pub fn mk_name_value_item_str(name: @str, value: @str)
                           -> @ast::meta_item {
    let value_lit = dummy_spanned(ast::lit_str(value));
    mk_name_value_item(name, value_lit)
}

pub fn mk_name_value_item(name: @str, value: ast::lit)
        -> @ast::meta_item {
    @dummy_spanned(ast::meta_name_value(name, value))
}

pub fn mk_list_item(name: @str, items: ~[@ast::meta_item]) ->
   @ast::meta_item {
    @dummy_spanned(ast::meta_list(name, items))
}

pub fn mk_word_item(name: @str) -> @ast::meta_item {
    @dummy_spanned(ast::meta_word(name))
}

pub fn mk_attr(item: @ast::meta_item) -> ast::attribute {
    dummy_spanned(ast::attribute_ { style: ast::attr_inner,
                                    value: item,
                                    is_sugared_doc: false })
}

pub fn mk_sugared_doc_attr(text: @str,
                           lo: BytePos, hi: BytePos) -> ast::attribute {
    let style = doc_comment_style(text);
    let lit = spanned(lo, hi, ast::lit_str(text));
    let attr = ast::attribute_ {
        style: style,
        value: @spanned(lo, hi, ast::meta_name_value(@"doc", lit)),
        is_sugared_doc: true
    };
    spanned(lo, hi, attr)
}

/* Conversion */

pub fn attr_meta(attr: ast::attribute) -> @ast::meta_item {
    attr.node.value
}

// Get the meta_items from inside a vector of attributes
pub fn attr_metas(attrs: &[ast::attribute]) -> ~[@ast::meta_item] {
    do attrs.map |a| { attr_meta(*a) }
}

pub fn desugar_doc_attr(attr: &ast::attribute) -> ast::attribute {
    if attr.node.is_sugared_doc {
        let comment = get_meta_item_value_str(attr.node.value).get();
        let meta = mk_name_value_item_str(@"doc",
                                     strip_doc_comment_decoration(comment).to_managed());
        mk_attr(meta)
    } else {
        *attr
    }
}

/* Accessors */

pub fn get_attr_name(attr: &ast::attribute) -> @str {
    get_meta_item_name(attr.node.value)
}

pub fn get_meta_item_name(meta: @ast::meta_item) -> @str {
    match meta.node {
        ast::meta_word(n) => n,
        ast::meta_name_value(n, _) => n,
        ast::meta_list(n, _) => n,
    }
}

/**
 * Gets the string value if the meta_item is a meta_name_value variant
 * containing a string, otherwise none
 */
pub fn get_meta_item_value_str(meta: @ast::meta_item) -> Option<@str> {
    match meta.node {
        ast::meta_name_value(_, v) => {
            match v.node {
                ast::lit_str(s) => Some(s),
                _ => None,
            }
        },
        _ => None
    }
}

/// Gets a list of inner meta items from a list meta_item type
pub fn get_meta_item_list(meta: @ast::meta_item)
                       -> Option<~[@ast::meta_item]> {
    match meta.node {
        ast::meta_list(_, ref l) => Some(/* FIXME (#2543) */ copy *l),
        _ => None
    }
}

/**
 * If the meta item is a nam-value type with a string value then returns
 * a tuple containing the name and string value, otherwise `none`
 */
pub fn get_name_value_str_pair(item: @ast::meta_item)
                            -> Option<(@str, @str)> {
    match attr::get_meta_item_value_str(item) {
      Some(value) => {
        let name = attr::get_meta_item_name(item);
        Some((name, value))
      }
      None => None
    }
}

/* Searching */

/// Search a list of attributes and return only those with a specific name
pub fn find_attrs_by_name(attrs: &[ast::attribute], name: &str) ->
   ~[ast::attribute] {
    do vec::filter_mapped(attrs) |a| {
        if name == get_attr_name(a) {
            Some(*a)
        } else {
            None
        }
    }
}

/// Search a list of meta items and return only those with a specific name
pub fn find_meta_items_by_name(metas: &[@ast::meta_item], name: &str) ->
   ~[@ast::meta_item] {
    let mut rs = ~[];
    for metas.iter().advance |mi| {
        if name == get_meta_item_name(*mi) {
            rs.push(*mi)
        }
    }
    rs
}

/**
 * Returns true if a list of meta items contains another meta item. The
 * comparison is performed structurally.
 */
pub fn contains(haystack: &[@ast::meta_item],
                needle: @ast::meta_item) -> bool {
    for haystack.iter().advance |item| {
        if eq(*item, needle) { return true; }
    }
    return false;
}

fn eq(a: @ast::meta_item, b: @ast::meta_item) -> bool {
    match a.node {
        ast::meta_word(ref na) => match b.node {
            ast::meta_word(ref nb) => (*na) == (*nb),
            _ => false
        },
        ast::meta_name_value(ref na, va) => match b.node {
            ast::meta_name_value(ref nb, vb) => {
                (*na) == (*nb) && va.node == vb.node
            }
            _ => false
        },
        ast::meta_list(ref na, ref misa) => match b.node {
            ast::meta_list(ref nb, ref misb) => {
                if na != nb { return false; }
                for misa.iter().advance |mi| {
                    if !misb.iter().any_(|x| x == mi) { return false; }
                }
                true
            }
            _ => false
        }
    }
}

pub fn contains_name(metas: &[@ast::meta_item], name: &str) -> bool {
    let matches = find_meta_items_by_name(metas, name);
    matches.len() > 0u
}

pub fn attrs_contains_name(attrs: &[ast::attribute], name: &str) -> bool {
    !find_attrs_by_name(attrs, name).is_empty()
}

pub fn first_attr_value_str_by_name(attrs: &[ast::attribute], name: &str)
                                 -> Option<@str> {

    let mattrs = find_attrs_by_name(attrs, name);
    if mattrs.len() > 0 {
        get_meta_item_value_str(attr_meta(mattrs[0]))
    } else {
        None
    }
}

fn last_meta_item_by_name(items: &[@ast::meta_item], name: &str)
    -> Option<@ast::meta_item> {

    let items = attr::find_meta_items_by_name(items, name);
    items.last_opt().map(|item| **item)
}

pub fn last_meta_item_value_str_by_name(items: &[@ast::meta_item], name: &str)
                                     -> Option<@str> {

    match last_meta_item_by_name(items, name) {
        Some(item) => {
            match attr::get_meta_item_value_str(item) {
                Some(value) => Some(value),
                None => None
            }
        },
        None => None
    }
}

pub fn last_meta_item_list_by_name(items: ~[@ast::meta_item], name: &str)
    -> Option<~[@ast::meta_item]> {

    match last_meta_item_by_name(items, name) {
      Some(item) => attr::get_meta_item_list(item),
      None => None
    }
}

/* Higher-level applications */

pub fn sort_meta_items(items: &[@ast::meta_item]) -> ~[@ast::meta_item] {
    // This is sort of stupid here, converting to a vec of mutables and back
    let mut v = vec::to_owned(items);
    do extra::sort::quick_sort(v) |ma, mb| {
        get_meta_item_name(*ma) <= get_meta_item_name(*mb)
    }

    // There doesn't seem to be a more optimal way to do this
    do v.map |m| {
        match m.node {
            ast::meta_list(n, ref mis) => {
                @spanned {
                    node: ast::meta_list(n, sort_meta_items(*mis)),
                    .. /*bad*/ copy **m
                }
            }
            _ => /*bad*/ copy *m
        }
    }
}

pub fn remove_meta_items_by_name(items: ~[@ast::meta_item], name: &str) ->
   ~[@ast::meta_item] {

    return vec::filter_mapped(items, |item| {
        if name != get_meta_item_name(*item) {
            Some(*item)
        } else {
            None
        }
    });
}

/**
 * From a list of crate attributes get only the meta_items that affect crate
 * linkage
 */
pub fn find_linkage_metas(attrs: &[ast::attribute]) -> ~[@ast::meta_item] {
    do find_attrs_by_name(attrs, "link").flat_map |attr| {
        match attr.node.value.node {
            ast::meta_list(_, ref items) => /* FIXME (#2543) */ copy *items,
            _ => ~[]
        }
    }
}

#[deriving(Eq)]
pub enum inline_attr {
    ia_none,
    ia_hint,
    ia_always,
    ia_never,
}

/// True if something like #[inline] is found in the list of attrs.
pub fn find_inline_attr(attrs: &[ast::attribute]) -> inline_attr {
    // FIXME (#2809)---validate the usage of #[inline] and #[inline]
    do attrs.iter().fold(ia_none) |ia,attr| {
        match attr.node.value.node {
          ast::meta_word(s) if "inline" == s => ia_hint,
          ast::meta_list(s, ref items) if "inline" == s => {
            if !find_meta_items_by_name(*items, "always").is_empty() {
                ia_always
            } else if !find_meta_items_by_name(*items, "never").is_empty() {
                ia_never
            } else {
                ia_hint
            }
          }
          _ => ia
        }
    }
}

pub fn require_unique_names(diagnostic: @span_handler,
                            metas: &[@ast::meta_item]) {
    let mut set = HashSet::new();
    for metas.iter().advance |meta| {
        let name = get_meta_item_name(*meta);

        // FIXME: How do I silence the warnings? --pcw (#2619)
        if !set.insert(name) {
            diagnostic.span_fatal(meta.span,
                                  fmt!("duplicate meta item `%s`", name));
        }
    }
}
<|endoftext|>