<commit_before>
// Copyright 2017 The gltf Library Developers
//
// 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.

use json;

use Gltf;

pub use json::buffer::Target;

/// A buffer points to binary data representing geometry, animations, or skins.
#[derive(Clone, Debug)]
pub struct Buffer<'a> {
    /// The parent `Gltf` struct.
    gltf: &'a Gltf,

    /// The corresponding JSON index.
    index: usize,

    /// The corresponding JSON struct.
    json: &'a json::buffer::Buffer,
}

/// A view into a buffer generally representing a subset of the buffer.
#[derive(Clone, Debug)]
pub struct View<'a> {
    /// The parent `Gltf` struct.
    gltf: &'a Gltf,

    /// The corresponding JSON index.
    index: usize,

    /// The corresponding JSON struct.
    json: &'a json::buffer::View,

    /// The parent `Buffer`.
    parent: Buffer<'a>,
}

impl<'a> Buffer<'a> {
    /// Constructs a `Buffer`.
    pub(crate) fn new(
        gltf: &'a Gltf,
        index: usize,
        json: &'a json::buffer::Buffer,
    ) -> Self {
        Self {
            gltf: gltf,
            index: index,
            json: json,
        }
    }

    /// Returns the internal JSON index.
    pub fn index(&self) -> usize {
        self.index
    }

    /// Returns the internal JSON item.
    pub fn as_json(&self) ->  &json::buffer::Buffer {
        self.json
    }

    /// The length of the buffer in bytes.
    pub fn length(&self) -> usize {
        self.json.byte_length as usize
    }

    /// Optional user-defined name for this object.
    #[cfg(feature = "names")]
    pub fn name(&self) -> Option<&str> {
        self.json.name.as_ref().map(String::as_str)
    }

    /// Optional application specific data.
    pub fn extras(&self) -> &json::Extras {
        &self.json.extras
    }
}

impl<'a> View<'a> {
    /// Constructs a `View`.
    pub(crate) fn new(
        gltf: &'a Gltf,
        index: usize,
        json: &'a json::buffer::View,
    ) -> Self {
        let parent = gltf.buffers().nth(json.buffer.value()).unwrap();
        Self {
            gltf,
            index,
            json,
            parent,
        }
    }

    /// Returns the internal JSON index.
    pub fn index(&self) -> usize {
        self.index
    }

    /// Returns the internal JSON item.
    pub fn as_json(&self) ->  &json::buffer::View {
        self.json
    }

    /// Returns the parent `Buffer`.
    pub fn buffer(&self) -> Buffer<'a> {
        self.gltf.buffers().nth(self.json.buffer.value()).unwrap()
    }

    /// Returns the length of the buffer view in bytes.
    pub fn length(&self) -> usize {
        self.json.byte_length as usize
    }

    /// Returns the offset into the parent buffer in bytes.
    pub fn offset(&self) -> usize {
        self.json.byte_offset as usize
    }

    /// Returns the stride in bytes between vertex attributes or other interleavable
    /// data. When `None`, data is assumed to be tightly packed.
    pub fn stride(&self) -> Option<usize> {
        self.json.byte_stride.map(|x| x.0 as usize)
    }

    /// Optional user-defined name for this object.
    #[cfg(feature = "names")]
    pub fn name(&self) -> Option<&str> {
        self.json.name.as_ref().map(String::as_str)
    }

    /// Optional target the buffer should be bound to.
    pub fn target(&self) -> Option<Target> {
        self.json.target.map(|target| target.unwrap())
    }

    /// Optional application specific data.
    pub fn extras(&self) -> &json::Extras {
        &self.json.extras
    }
}
<commit_msg>Expose buffer URIs<commit_after>
// Copyright 2017 The gltf Library Developers
//
// 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.

use json;

use Gltf;

pub use json::buffer::Target;

/// A buffer points to binary data representing geometry, animations, or skins.
#[derive(Clone, Debug)]
pub struct Buffer<'a> {
    /// The parent `Gltf` struct.
    gltf: &'a Gltf,

    /// The corresponding JSON index.
    index: usize,

    /// The corresponding JSON struct.
    json: &'a json::buffer::Buffer,
}

/// A view into a buffer generally representing a subset of the buffer.
#[derive(Clone, Debug)]
pub struct View<'a> {
    /// The parent `Gltf` struct.
    gltf: &'a Gltf,

    /// The corresponding JSON index.
    index: usize,

    /// The corresponding JSON struct.
    json: &'a json::buffer::View,

    /// The parent `Buffer`.
    parent: Buffer<'a>,
}

impl<'a> Buffer<'a> {
    /// Constructs a `Buffer`.
    pub(crate) fn new(
        gltf: &'a Gltf,
        index: usize,
        json: &'a json::buffer::Buffer,
    ) -> Self {
        Self {
            gltf: gltf,
            index: index,
            json: json,
        }
    }

    /// Returns the internal JSON index.
    pub fn index(&self) -> usize {
        self.index
    }

    /// Returns the internal JSON item.
    pub fn as_json(&self) ->  &json::buffer::Buffer {
        self.json
    }

    /// Returns the uniform resource identifier for the buffer data.
    ///
    /// # Notes
    ///
    /// When the `glTF` comes from a .glb file and the .glb file has a BIN chunk,
    /// then this function will return `#bin` for the first buffer entry. This is not
    /// standard behaviour in the `glTF` schema.
    pub fn uri(&self) -> &str {
        self.json.uri.as_ref().map(String::as_str).unwrap_or("#bin")
    }

    /// The length of the buffer in bytes.
    pub fn length(&self) -> usize {
        self.json.byte_length as usize
    }

    /// Optional user-defined name for this object.
    #[cfg(feature = "names")]
    pub fn name(&self) -> Option<&str> {
        self.json.name.as_ref().map(String::as_str)
    }

    /// Optional application specific data.
    pub fn extras(&self) -> &json::Extras {
        &self.json.extras
    }
}

impl<'a> View<'a> {
    /// Constructs a `View`.
    pub(crate) fn new(
        gltf: &'a Gltf,
        index: usize,
        json: &'a json::buffer::View,
    ) -> Self {
        let parent = gltf.buffers().nth(json.buffer.value()).unwrap();
        Self {
            gltf,
            index,
            json,
            parent,
        }
    }

    /// Returns the internal JSON index.
    pub fn index(&self) -> usize {
        self.index
    }

    /// Returns the internal JSON item.
    pub fn as_json(&self) ->  &json::buffer::View {
        self.json
    }

    /// Returns the parent `Buffer`.
    pub fn buffer(&self) -> Buffer<'a> {
        self.gltf.buffers().nth(self.json.buffer.value()).unwrap()
    }

    /// Returns the length of the buffer view in bytes.
    pub fn length(&self) -> usize {
        self.json.byte_length as usize
    }

    /// Returns the offset into the parent buffer in bytes.
    pub fn offset(&self) -> usize {
        self.json.byte_offset as usize
    }

    /// Returns the stride in bytes between vertex attributes or other interleavable
    /// data. When `None`, data is assumed to be tightly packed.
    pub fn stride(&self) -> Option<usize> {
        self.json.byte_stride.map(|x| x.0 as usize)
    }

    /// Optional user-defined name for this object.
    #[cfg(feature = "names")]
    pub fn name(&self) -> Option<&str> {
        self.json.name.as_ref().map(String::as_str)
    }

    /// Optional target the buffer should be bound to.
    pub fn target(&self) -> Option<Target> {
        self.json.target.map(|target| target.unwrap())
    }

    /// Optional application specific data.
    pub fn extras(&self) -> &json::Extras {
        &self.json.extras
    }
}
<|endoftext|>


<commit_before>use rustc_serialize::hex::{ToHex, FromHex};
use rustc_serialize::base64::{ToBase64, FromBase64, STANDARD};
use std::str;
use std::io::BufWriter;
use std::fs::File;
use std::path::Path;
use std::io::prelude::*;
use std::cmp;
use std::fs::OpenOptions;
use std::fs;

enum WriteMethod { Truncate, Append }

pub struct CipherText(Vec<u8>);

impl CipherText {
    pub fn new(bytes: &[u8]) -> CipherText {
        CipherText(bytes.to_vec())
    }

    pub fn from_hex(hex: &str) -> Result<CipherText, Error> {
        let cipher_bytes: Vec<u8> = try!(hex.from_hex()
            .map_err(|e| Error::Hex(e.to_string())));
        Ok(CipherText(cipher_bytes))
    }

    pub fn to_hex(&self) -> String {
        let &CipherText(ref vec_bytes) = self;
        vec_bytes.to_hex()
    }

    pub fn from_b64<S: AsRef<str>>(b64: S) -> Result<CipherText, Error> {
        let cipher_bytes: Vec<u8> = try!(b64.as_ref().from_base64()
            .map_err(|e| Error::Base64(e.to_string())));
        Ok(CipherText(cipher_bytes))
    }

    pub fn to_b64(&self) -> String {
        let &CipherText(ref vec_bytes) = self;
        vec_bytes.to_base64(STANDARD)
    }

    fn from_file<P: AsRef<Path>>(path: P) -> Result<CipherText, Error> {
        buffer_file(path.as_ref()).and_then(CipherText::from_b64)
    }

    pub fn to_file<P: AsRef<Path>>(&self, path: P) -> Result<(), Error> {
        let text_b64 = self.to_b64();
        let mut file = try!(create_file(path.as_ref(), WriteMethod::Append));

        let mut i = 0;
        let mut j = cmp::min(text_b64.len(), 80);
        while i != j {
            try!(file.write_all(&text_b64[i..j].as_bytes())
                .map_err(|e| Error::File(e.to_string())));

            try!(file.write_all("\n".as_bytes()).map_err(|e| Error::File(e.to_string())));

            i = j;
            j = cmp::min(text_b64.len(), j + 80);
        }
        Ok(())
    }
}
pub struct PlainText(Vec<u8>);

impl PlainText {
    pub fn from_string<S: AsRef<str>>(string: S) -> PlainText {
        PlainText(string.as_ref().as_bytes().to_vec())
    }

    pub fn from_bytes(bytes: &[u8]) -> PlainText {
        PlainText(bytes.to_vec())
    }

    fn from_file<P: AsRef<Path>>(path: P) -> Result<PlainText, Error> {
        buffer_file(path.as_ref()).map(PlainText::from_string)
    }

    pub fn to_file<P: AsRef<Path>>(&self, path: P) -> Result<(), Error> {
        let &PlainText(ref vec_bytes) = self;
        let file = try!(create_file(path.as_ref(), WriteMethod::Truncate));
        let mut out_file = BufWriter::new(file);
        try!(out_file.write_all(&vec_bytes).map_err(|e| Error::File(e.to_string())));
        Ok(())
    }

    pub fn to_utf8(&self) -> Result<String, Error> {
        let &PlainText(ref vec_bytes) = self;
        let plain = try!(str::from_utf8(&vec_bytes).map_err(|e| Error::UTF8(e.to_string())));
        Ok(plain.to_string())
    }
}

fn buffer_file(path: &Path) -> Result<String, Error> {
    let mut file = try!(File::open(Path::new(path)).map_err(|e| Error::File(e.to_string())));
    let capacity = file.metadata().ok().map_or(0, |x| x.len());
    let mut buffer = String::with_capacity(capacity as usize);
    try!(file.read_to_string(&mut buffer).map_err(|e| Error::File(e.to_string())));
    Ok(buffer)
}

fn create_file(path: &Path, method: WriteMethod) -> Result<File, Error> {
    if path.exists() {
        try!(fs::remove_file(path).map_err(|e| Error::File(e.to_string())));
    }

    match method {
        WriteMethod::Append => {
            OpenOptions::new()
                .write(true)
                .append(true)
                .create(true)
                .open(path)
                .map_err(|e| Error::File(e.to_string()))
        },
        WriteMethod::Truncate => {
            OpenOptions::new()
                .write(true)
                .truncate(true)
                .create(true)
                .open(path)
                .map_err(|e| Error::File(e.to_string()))
        }
    }

}

pub fn encrypt(text: &PlainText, key: &str) -> CipherText {
    let &PlainText(ref bytes) = text;
    let xored: Vec<u8> = repeating_xor(bytes, key.as_bytes());
    CipherText::new(&xored)
}

pub fn decrypt(cipher_text: &CipherText, key: &str) -> Result<PlainText, Error> {
    let &CipherText(ref bytes) = cipher_text;
    let xored: Vec<u8> = repeating_xor(bytes, key.as_bytes());
    Ok(PlainText::from_bytes(&xored))
}

pub fn decrypt_file(input_path: &str, output_path: &str, key: &str) -> Result<(), Error> {
    let cipher = try!(CipherText::from_file(input_path));
    let plain = try!(decrypt(&cipher, key));
    try!(plain.to_file(output_path));
    Ok(())
}

pub fn encrypt_file(input_path: &str, output_path: &str, key: &str) -> Result<(), Error> {
    let plain = try!(PlainText::from_file(input_path));
    let cipher = encrypt(&plain, key);
    try!(cipher.to_file(output_path));
    Ok(())
}

#[derive(Debug)]
pub enum Error {
    Hex(String),
    Base64(String),
    UTF8(String),
    File(String),
}

fn repeating_xor(input: &[u8], key: &[u8]) -> Vec<u8> {
    let mut out: Vec<u8> = Vec::with_capacity(input.len());
    unsafe {
        out.set_len(input.len());
    }
    for (i, in_val) in input.iter().enumerate() {
        out[i] = in_val ^ key[i % key.len()];
    }
    out
}

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

    #[test]
    fn test_encrypt_and_decrypt() {
        check_text("This is the plain text\n");
        check_text("123, 456");
        check_text("!£$%^&*@~:");
        check_text("日本語");
    }

    #[test]
    fn test_encrypt_and_decrypt_files() {
        check_text_file("This is the plain text\n");
        check_text_file("123, 456");
        check_text_file("!£$%^&*@~:");
        check_text_file("日本語");
        check_text_file("This is the plain text\nThis is the plain text\nThis is the plain text\n");
    }

    #[test]
    fn test_wrong_key() {
        let text = "This is the plain text";
        let plain_text = PlainText::from_string(text);
        let key: &str = "toy";
        let decoded_text = decrypt(&encrypt(&plain_text, key), "wrong_key").unwrap();
        assert!(text != decoded_text.to_utf8().unwrap());
    }

    fn check_text(text: &str) {
        let plain_text = PlainText::from_string(text);
        let key: &str = "toy";
        let decoded_text = decrypt(&encrypt(&plain_text, key), key).unwrap();
        assert_eq!(text, decoded_text.to_utf8().unwrap());
    }

    fn check_text_file(text: &str) {
        let plain_text = PlainText::from_string(text);
        let key: &str = "toy";
        let plain_path = "./target/test-plain.txt";
        let cipher_path = "./target/test-cipher.txt";
        let decoded_path = "./target/test-decoded.txt";

        plain_text.to_file(plain_path).unwrap();
        encrypt_file(plain_path, cipher_path, key).unwrap();
        decrypt_file(cipher_path, decoded_path, key).unwrap();
        let decoded_text = PlainText::from_file(decoded_path).unwrap();

        assert_eq!(text, decoded_text.to_utf8().unwrap());
    }
}
<commit_msg>Added feedback from reddit<commit_after>use rustc_serialize::hex::{ToHex, FromHex, FromHexError};
use rustc_serialize::base64::{FromBase64Error, ToBase64, FromBase64, STANDARD};
use std::str;
use std::io;
use std::io::BufWriter;
use std::fs::File;
use std::path::Path;
use std::io::prelude::*;
use std::cmp;
use std::fs::OpenOptions;
use std::fs;

enum WriteMethod {
    Truncate,
    Append,
}

pub struct CipherText(Vec<u8>);

impl CipherText {
    pub fn new(bytes: &[u8]) -> CipherText {
        CipherText(bytes.to_vec())
    }

    pub fn from_hex(hex: &str) -> Result<CipherText, Error> {
        let cipher_bytes: Vec<u8> = try!(hex.from_hex());
        Ok(CipherText(cipher_bytes))
    }

    pub fn to_hex(&self) -> String {
        let &CipherText(ref vec_bytes) = self;
        vec_bytes.to_hex()
    }

    pub fn from_b64<S: AsRef<str>>(b64: S) -> Result<CipherText, Error> {
        let cipher_bytes: Vec<u8> = try!(b64.as_ref().from_base64());
        Ok(CipherText(cipher_bytes))
    }

    pub fn to_b64(&self) -> String {
        let &CipherText(ref vec_bytes) = self;
        vec_bytes.to_base64(STANDARD)
    }

    fn from_file<P: AsRef<Path>>(path: P) -> Result<CipherText, Error> {
        buffer_file(path.as_ref()).and_then(CipherText::from_b64)
    }

    pub fn to_file<P: AsRef<Path>>(&self, path: P) -> Result<(), Error> {
        let text_b64 = self.to_b64();
        let mut file = try!(create_file(path.as_ref(), WriteMethod::Append));

        let mut i = 0;
        let mut j = cmp::min(text_b64.len(), 80);
        while i != j {
            try!(file.write_all(&text_b64[i..j].as_bytes()));
            try!(file.write_all("\n".as_bytes()));

            i = j;
            j = cmp::min(text_b64.len(), j + 80);
        }
        Ok(())
    }
}
pub struct PlainText(Vec<u8>);

impl PlainText {
    pub fn from_string<S: AsRef<str>>(string: S) -> PlainText {
        PlainText(string.as_ref().as_bytes().to_vec())
    }

    pub fn from_bytes(bytes: &[u8]) -> PlainText {
        PlainText(bytes.to_vec())
    }

    fn from_file<P: AsRef<Path>>(path: P) -> Result<PlainText, Error> {
        buffer_file(path.as_ref()).map(PlainText::from_string)
    }

    pub fn to_file<P: AsRef<Path>>(&self, path: P) -> Result<(), Error> {
        let &PlainText(ref vec_bytes) = self;
        let file = try!(create_file(path.as_ref(), WriteMethod::Truncate));
        let mut out_file = BufWriter::new(file);
        try!(out_file.write_all(&vec_bytes));
        Ok(())
    }

    pub fn to_utf8(&self) -> Result<String, Error> {
        let &PlainText(ref vec_bytes) = self;
        let plain = try!(str::from_utf8(&vec_bytes));
        Ok(plain.to_string())
    }
}

fn buffer_file(path: &Path) -> Result<String, Error> {
    let mut file = try!(File::open(Path::new(path)));
    let capacity = file.metadata().ok().map_or(0, |x| x.len());
    let mut buffer = String::with_capacity(capacity as usize);
    try!(file.read_to_string(&mut buffer));
    Ok(buffer)
}

fn create_file(path: &Path, method: WriteMethod) -> Result<File, Error> {
    if path.exists() {
        try!(fs::remove_file(path));
    }

    match method {
        WriteMethod::Append => {
            OpenOptions::new()
                .write(true)
                .append(true)
                .create(true)
                .open(path)
                .map_err(|e| Error::from(e))
        }
        WriteMethod::Truncate => {
            OpenOptions::new()
                .write(true)
                .truncate(true)
                .create(true)
                .open(path)
                .map_err(|e| Error::from(e))
        }
    }

}

pub fn encrypt(text: &PlainText, key: &str) -> CipherText {
    let &PlainText(ref bytes) = text;
    let xored: Vec<u8> = repeating_xor(bytes, key.as_bytes());
    CipherText::new(&xored)
}

pub fn decrypt(cipher_text: &CipherText, key: &str) -> Result<PlainText, Error> {
    let &CipherText(ref bytes) = cipher_text;
    let xored: Vec<u8> = repeating_xor(bytes, key.as_bytes());
    Ok(PlainText::from_bytes(&xored))
}

pub fn decrypt_file(input_path: &str, output_path: &str, key: &str) -> Result<(), Error> {
    let cipher = try!(CipherText::from_file(input_path));
    let plain = try!(decrypt(&cipher, key));
    try!(plain.to_file(output_path));
    Ok(())
}

pub fn encrypt_file(input_path: &str, output_path: &str, key: &str) -> Result<(), Error> {
    let plain = try!(PlainText::from_file(input_path));
    let cipher = encrypt(&plain, key);
    try!(cipher.to_file(output_path));
    Ok(())
}

#[derive(Debug)]
pub enum Error {
    Hex(String),
    Base64(String),
    UTF8(String),
    File(String),
}

impl From<FromBase64Error> for Error {
    fn from(err: FromBase64Error) -> Error {
        Error::Base64(err.to_string())
    }
}

impl From<FromHexError> for Error {
    fn from(err: FromHexError) -> Error {
        Error::Hex(err.to_string())
    }
}

impl From<str::Utf8Error> for Error {
    fn from(err: str::Utf8Error) -> Error {
        Error::UTF8(err.to_string())
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::File(err.to_string())
    }
}

fn repeating_xor(input: &[u8], key: &[u8]) -> Vec<u8> {
    let mut out: Vec<u8> = Vec::with_capacity(input.len());
    for (i, in_val) in input.iter().enumerate() {
        out.push(in_val ^ key[i % key.len()]);
    }
    out
}

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

    #[test]
    fn test_encrypt_and_decrypt() {
        check_text("This is the plain text\n");
        check_text("123, 456");
        check_text("!£$%^&*@~:");
        check_text("日本語");
    }

    #[test]
    fn test_encrypt_and_decrypt_files() {
        check_text_file("This is the plain text\n");
        check_text_file("123, 456");
        check_text_file("!£$%^&*@~:");
        check_text_file("日本語");
        check_text_file("This is the plain text\nThis is the plain text\nThis is the plain text\n");
        check_text_file("dsklfshdfsfsdfsdfsdfsdfsgfssssssssssssssssssssssfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
    }

    #[test]
    fn test_file_storage() {
        check_to_from_file("This is the plain text\n");
        check_to_from_file("123, 456");
        check_to_from_file("!£$%^&*@~:");
        check_to_from_file("日本語");
        check_to_from_file("This is the plain text\nThis is the plain text\nThis is the plain \
                            text\n");
        check_to_from_file("dsklfshdfsfsdfsdfsdfsdfsgfssssssssssssssssssssssfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
    }

    #[test]
    fn test_wrong_key() {
        let text = "This is the plain text";
        let plain_text = PlainText::from_string(text);
        let key: &str = "toy";
        let decoded_text = decrypt(&encrypt(&plain_text, key), "wrong_key").unwrap();
        assert!(text != decoded_text.to_utf8().unwrap());
    }

    fn check_to_from_file(text: &str) {
        let plain_text = PlainText::from_string(text);
        let key: &str = "toy";
        let cipher_text = encrypt(&plain_text, key);
        let path = "./target/debug/test.txt";

        plain_text.to_file(&path).unwrap();
        let rec_plain = PlainText::from_file(&path).unwrap();
        assert_eq!(plain_text.to_utf8().unwrap(), rec_plain.to_utf8().unwrap());

        cipher_text.to_file(&path).unwrap();
        let rec_cipher = CipherText::from_file(&path).unwrap();
        assert_eq!(cipher_text.to_b64(), rec_cipher.to_b64());

    }

    fn check_text(text: &str) {
        let plain_text = PlainText::from_string(text);
        let key: &str = "toy";
        let decoded_text = decrypt(&encrypt(&plain_text, key), key).unwrap();
        assert_eq!(text, decoded_text.to_utf8().unwrap());
    }

    fn check_text_file(text: &str) {
        let plain_text = PlainText::from_string(text);
        let key: &str = "toy";
        let plain_path = "./target/test-plain.txt";
        let cipher_path = "./target/test-cipher.txt";
        let decoded_path = "./target/test-decoded.txt";

        plain_text.to_file(plain_path).unwrap();
        encrypt_file(plain_path, cipher_path, key).unwrap();
        decrypt_file(cipher_path, decoded_path, key).unwrap();
        let decoded_text = PlainText::from_file(decoded_path).unwrap();

        assert_eq!(text, decoded_text.to_utf8().unwrap());
    }
}
<|endoftext|>


<commit_before>//! This module contains the main client code, including the `Rocket` type.
use interpolation::*;
use track::*;

use std;
use std::io::Cursor;
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
use std::io::prelude::*;
use std::net::TcpStream;

#[derive(Copy, Clone, Debug)]
/// The `RocketErr` Type. This is the main error type.
pub struct RocketErr {}

#[derive(Debug)]
enum RocketState {
    New,
    Incomplete(usize),
    Complete,
}

#[derive(Debug, Copy, Clone)]
/// The `Event` Type. These are the various events from the tracker.
pub enum Event {
    /// The tracker changes row.
    SetRow(u32),
    /// The tracker pauses or unpauses.
    Pause(bool),
    /// The tracker asks us to save our track data.
    SaveTracks,
}

enum ReceiveResult {
    Some(Event),
    None,
    Incomplete,
}

#[derive(Debug)]
/// The `Rocket` type. This contains the connected socket and other fields.
pub struct Rocket {
    stream: TcpStream,
    state: RocketState,
    cmd: Vec<u8>,
    tracks: Vec<Track>,
}

impl Rocket {
    /// Construct a new Rocket.
    ///
    /// This constructs a new rocket and connect to localhost on port 1338.
    ///
    /// # Errors
    ///
    /// If a connection cannot be established, or if the handshake fails.
    /// This will raise a `RocketErr`.
    ///
    /// # Examples
    ///
    /// ```
    /// use rocket::Rocket;
    ///
    /// let mut rocket = Rocket::new();
    /// ```
    pub fn new() -> Result<Rocket, RocketErr> {
        Rocket::connect("localhost", 1338)
    }

    /// Construct a new Rocket.
    ///
    /// This constructs a new rocket and connects to a specified host and port.
    ///
    /// # Errors
    ///
    /// If a connection cannot be established, or if the handshake fails.
    /// This will raise a `RocketErr`.
    ///
    /// # Examples
    ///
    /// ```
    /// use rocket::Rocket;
    ///
    /// let mut rocket = Rocket::connect("localhost", 1338);
    /// ```
    pub fn connect(host: &str, port: u16) -> Result<Rocket, RocketErr> {
        let stream = TcpStream::connect((host, port)).expect("Failed to connect");

        let mut rocket = Rocket {
            stream: stream,
            state: RocketState::New,
            cmd: Vec::new(),
            tracks: Vec::new(),
        };

        rocket.handshake().expect("Failed to handshake");

        rocket.stream.set_nonblocking(true).expect("Failed to set nonblocking mode");

        Ok(rocket)
    }

    /// Get a track by name.
    ///
    /// If the track does not yet exist it will be created.
    ///
    /// # Examples
    ///
    /// ```
    /// let track = rocket.get_track("namespace:track");
    /// track.get_value(3.5);
    /// ```
    pub fn get_track(&mut self, name: &str) -> &Track {
        if !self.tracks.iter().any(|t| t.get_name() == name) {

            // Send GET_TRACK message
            let mut buf = vec![2];
            buf.write_u32::<BigEndian>(name.len() as u32).unwrap();
            buf.extend_from_slice(&name.as_bytes());
            self.stream.write_all(&buf).unwrap();

            self.tracks.push(Track::new(name));
        }
        self.tracks.iter().find(|t| t.get_name() == name).unwrap()
    }

    /// Send a SetRow message.
    ///
    /// This changes the current row on the tracker side.
    pub fn set_row(&mut self, row: u32) {
        // Send SET_ROW message
        let mut buf = vec![3];
        buf.write_u32::<BigEndian>(row).unwrap();
        self.stream.write_all(&buf).unwrap();
    }

    /// Poll for new events from the tracker.
    ///
    /// This polls from events from the tracker.
    /// You should call this fairly often your main loop.
    /// It is recommended to keep calling this as long as your receive
    /// Some(Event).
    ///
    /// # Examples
    ///
    /// ```
    ///  while let Some(Event) = rocket.poll_events() {
    ///      match event {
    ///          // Do something with the various events.
    ///          _ => (),
    ///      }
    ///  }
    /// ```
    pub fn poll_events(&mut self) -> Option<Event> {
        loop {
            let result = self.poll_event();
            match result {
                ReceiveResult::None => return None,
                ReceiveResult::Incomplete => (),
                ReceiveResult::Some(event) => return Some(event),
            }
        }
    }

    fn poll_event(&mut self) -> ReceiveResult {
        match self.state {
            RocketState::New => {
                let mut buf = [0; 1];
                if self.stream.read_exact(&mut buf).is_ok() {
                    self.cmd.extend_from_slice(&buf);
                    match self.cmd[0] {
                        0 => self.state = RocketState::Incomplete(4 + 4 + 4 + 1), //SET_KEY
                        1 => self.state = RocketState::Incomplete(4 + 4), //DELETE_KEY
                        3 => self.state = RocketState::Incomplete(4), //SET_ROW
                        4 => self.state = RocketState::Incomplete(1), //PAUSE
                        5 => self.state = RocketState::Complete, //SAVE_TRACKS
                        _ => self.state = RocketState::Complete, // Error / Unknown
                    }
                    ReceiveResult::Incomplete
                } else {
                    ReceiveResult::None
                }
            }
            RocketState::Incomplete(bytes) => {
                let mut buf = vec![0;bytes];
                if let Ok(bytes_read) = self.stream.read(&mut buf) {
                    self.cmd.extend_from_slice(&buf);
                    if bytes - bytes_read > 0 {
                        self.state = RocketState::Incomplete(bytes - bytes_read);
                    } else {
                        self.state = RocketState::Complete;
                    }
                    ReceiveResult::Incomplete
                } else {
                    ReceiveResult::None
                }
            }
            RocketState::Complete => {
                let mut result = ReceiveResult::None;
                {
                    let mut cursor = Cursor::new(&self.cmd);
                    let cmd = cursor.read_u8().unwrap();
                    match cmd {
                        0 => {
                            let mut track = &mut self.tracks[cursor.read_u32::<BigEndian>().unwrap() as
                                                 usize];
                            let row = cursor.read_u32::<BigEndian>().unwrap();
                            let value = cursor.read_f32::<BigEndian>().unwrap();
                            let interpolation = Interpolation::from(cursor.read_u8().unwrap());
                            let key = Key::new(row, value, interpolation);

                            track.set_key(key);

                        }
                        1 => {
                            let mut track = &mut self.tracks[cursor.read_u32::<BigEndian>().unwrap() as
                                                 usize];
                            let row = cursor.read_u32::<BigEndian>().unwrap();

                            track.delete_key(row);
                        }
                        3 => {
                            let row = cursor.read_u32::<BigEndian>().unwrap();
                            result = ReceiveResult::Some(Event::SetRow(row));
                        }
                        4 => {
                            let flag = cursor.read_u8().unwrap() == 1;
                            result = ReceiveResult::Some(Event::Pause(flag));
                        }
                        5 => {
                            result = ReceiveResult::Some(Event::SaveTracks);
                        }
                        _ => println!("Unknown {:?}", cmd),
                    }
                }

                self.cmd.clear();
                self.state = RocketState::New;

                result
            }
        }
    }

    fn handshake(&mut self) -> Result<(), RocketErr> {
        let client_greeting = "hello, synctracker!";
        let server_greeting = "hello, demo!";

        self.stream.write_all(client_greeting.as_bytes()).expect("Failed to write client greeting");
        let mut buf = [0; 12];
        self.stream.read_exact(&mut buf).expect("Failed to read server greeting");
        let read_greeting = std::str::from_utf8(&buf).expect("Failed to convert buf to utf8");
        if read_greeting == server_greeting {
            Ok(())
        } else {
            Err(RocketErr {})
        }
    }
}
<commit_msg>Add get_track_mut<commit_after>//! This module contains the main client code, including the `Rocket` type.
use interpolation::*;
use track::*;

use std;
use std::io::Cursor;
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
use std::io::prelude::*;
use std::net::TcpStream;

#[derive(Copy, Clone, Debug)]
/// The `RocketErr` Type. This is the main error type.
pub struct RocketErr {}

#[derive(Debug)]
enum RocketState {
    New,
    Incomplete(usize),
    Complete,
}

#[derive(Debug, Copy, Clone)]
/// The `Event` Type. These are the various events from the tracker.
pub enum Event {
    /// The tracker changes row.
    SetRow(u32),
    /// The tracker pauses or unpauses.
    Pause(bool),
    /// The tracker asks us to save our track data.
    SaveTracks,
}

enum ReceiveResult {
    Some(Event),
    None,
    Incomplete,
}

#[derive(Debug)]
/// The `Rocket` type. This contains the connected socket and other fields.
pub struct Rocket {
    stream: TcpStream,
    state: RocketState,
    cmd: Vec<u8>,
    tracks: Vec<Track>,
}

impl Rocket {
    /// Construct a new Rocket.
    ///
    /// This constructs a new rocket and connect to localhost on port 1338.
    ///
    /// # Errors
    ///
    /// If a connection cannot be established, or if the handshake fails.
    /// This will raise a `RocketErr`.
    ///
    /// # Examples
    ///
    /// ```
    /// use rocket::Rocket;
    ///
    /// let mut rocket = Rocket::new();
    /// ```
    pub fn new() -> Result<Rocket, RocketErr> {
        Rocket::connect("localhost", 1338)
    }

    /// Construct a new Rocket.
    ///
    /// This constructs a new rocket and connects to a specified host and port.
    ///
    /// # Errors
    ///
    /// If a connection cannot be established, or if the handshake fails.
    /// This will raise a `RocketErr`.
    ///
    /// # Examples
    ///
    /// ```
    /// use rocket::Rocket;
    ///
    /// let mut rocket = Rocket::connect("localhost", 1338);
    /// ```
    pub fn connect(host: &str, port: u16) -> Result<Rocket, RocketErr> {
        let stream = TcpStream::connect((host, port)).expect("Failed to connect");

        let mut rocket = Rocket {
            stream: stream,
            state: RocketState::New,
            cmd: Vec::new(),
            tracks: Vec::new(),
        };

        rocket.handshake().expect("Failed to handshake");

        rocket.stream.set_nonblocking(true).expect("Failed to set nonblocking mode");

        Ok(rocket)
    }

    /// Get a track by name.
    ///
    /// If the track does not yet exist it will be created.
    ///
    /// # Examples
    ///
    /// ```
    /// let track = rocket.get_track_mut("namespace:track");
    /// track.get_value(3.5);
    /// ```
    pub fn get_track_mut(&mut self, name: &str) -> &Track {
        if !self.tracks.iter().any(|t| t.get_name() == name) {

            // Send GET_TRACK message
            let mut buf = vec![2];
            buf.write_u32::<BigEndian>(name.len() as u32).unwrap();
            buf.extend_from_slice(&name.as_bytes());
            self.stream.write_all(&buf).unwrap();

            self.tracks.push(Track::new(name));
        }
        self.tracks.iter().find(|t| t.get_name() == name).unwrap()
    }

    /// Get Track by name.
    ///
    /// If it does not exist, it will panic.
    /// You should use `get_track_mut` instead.
    pub fn get_track(&self, name: &str) -> &Track {
        self.tracks.iter().find(|t| t.get_name() == name).unwrap()
    }

    /// Send a SetRow message.
    ///
    /// This changes the current row on the tracker side.
    pub fn set_row(&mut self, row: u32) {
        // Send SET_ROW message
        let mut buf = vec![3];
        buf.write_u32::<BigEndian>(row).unwrap();
        self.stream.write_all(&buf).unwrap();
    }

    /// Poll for new events from the tracker.
    ///
    /// This polls from events from the tracker.
    /// You should call this fairly often your main loop.
    /// It is recommended to keep calling this as long as your receive
    /// Some(Event).
    ///
    /// # Examples
    ///
    /// ```
    ///  while let Some(Event) = rocket.poll_events() {
    ///      match event {
    ///          // Do something with the various events.
    ///          _ => (),
    ///      }
    ///  }
    /// ```
    pub fn poll_events(&mut self) -> Option<Event> {
        loop {
            let result = self.poll_event();
            match result {
                ReceiveResult::None => return None,
                ReceiveResult::Incomplete => (),
                ReceiveResult::Some(event) => return Some(event),
            }
        }
    }

    fn poll_event(&mut self) -> ReceiveResult {
        match self.state {
            RocketState::New => {
                let mut buf = [0; 1];
                if self.stream.read_exact(&mut buf).is_ok() {
                    self.cmd.extend_from_slice(&buf);
                    match self.cmd[0] {
                        0 => self.state = RocketState::Incomplete(4 + 4 + 4 + 1), //SET_KEY
                        1 => self.state = RocketState::Incomplete(4 + 4), //DELETE_KEY
                        3 => self.state = RocketState::Incomplete(4), //SET_ROW
                        4 => self.state = RocketState::Incomplete(1), //PAUSE
                        5 => self.state = RocketState::Complete, //SAVE_TRACKS
                        _ => self.state = RocketState::Complete, // Error / Unknown
                    }
                    ReceiveResult::Incomplete
                } else {
                    ReceiveResult::None
                }
            }
            RocketState::Incomplete(bytes) => {
                let mut buf = vec![0;bytes];
                if let Ok(bytes_read) = self.stream.read(&mut buf) {
                    self.cmd.extend_from_slice(&buf);
                    if bytes - bytes_read > 0 {
                        self.state = RocketState::Incomplete(bytes - bytes_read);
                    } else {
                        self.state = RocketState::Complete;
                    }
                    ReceiveResult::Incomplete
                } else {
                    ReceiveResult::None
                }
            }
            RocketState::Complete => {
                let mut result = ReceiveResult::None;
                {
                    let mut cursor = Cursor::new(&self.cmd);
                    let cmd = cursor.read_u8().unwrap();
                    match cmd {
                        0 => {
                            let mut track = &mut self.tracks[cursor.read_u32::<BigEndian>().unwrap() as
                                                 usize];
                            let row = cursor.read_u32::<BigEndian>().unwrap();
                            let value = cursor.read_f32::<BigEndian>().unwrap();
                            let interpolation = Interpolation::from(cursor.read_u8().unwrap());
                            let key = Key::new(row, value, interpolation);

                            track.set_key(key);

                        }
                        1 => {
                            let mut track = &mut self.tracks[cursor.read_u32::<BigEndian>().unwrap() as
                                                 usize];
                            let row = cursor.read_u32::<BigEndian>().unwrap();

                            track.delete_key(row);
                        }
                        3 => {
                            let row = cursor.read_u32::<BigEndian>().unwrap();
                            result = ReceiveResult::Some(Event::SetRow(row));
                        }
                        4 => {
                            let flag = cursor.read_u8().unwrap() == 1;
                            result = ReceiveResult::Some(Event::Pause(flag));
                        }
                        5 => {
                            result = ReceiveResult::Some(Event::SaveTracks);
                        }
                        _ => println!("Unknown {:?}", cmd),
                    }
                }

                self.cmd.clear();
                self.state = RocketState::New;

                result
            }
        }
    }

    fn handshake(&mut self) -> Result<(), RocketErr> {
        let client_greeting = "hello, synctracker!";
        let server_greeting = "hello, demo!";

        self.stream.write_all(client_greeting.as_bytes()).expect("Failed to write client greeting");
        let mut buf = [0; 12];
        self.stream.read_exact(&mut buf).expect("Failed to read server greeting");
        let read_greeting = std::str::from_utf8(&buf).expect("Failed to convert buf to utf8");
        if read_greeting == server_greeting {
            Ok(())
        } else {
            Err(RocketErr {})
        }
    }
}
<|endoftext|>


<commit_before>use connection::{ConnectionInfo, IntoConnectionInfo, Connection, connect,
                 PubSub, connect_pubsub, ConnectionLike};
use types::{RedisResult, Value};

/// The client type.
pub struct Client {
    connection_info: ConnectionInfo,
}

/// The client acts as connector to the redis server.  By itself it does not
/// do much other than providing a convenient way to fetch a connection from
/// it.  In the future the plan is to provide a connection pool in the client.
///
/// When opening a client a URL in the following format should be used:
///
/// ```plain
/// redis://host:port/db
/// ```
///
/// Example usage::
///
/// ```rust,no_run
/// let client = redis::Client::open("redis://127.0.0.1/").unwrap();
/// let con = client.get_connection().unwrap();
/// ```
impl Client {

    /// Connects to a redis server and returns a client.  This does not
    /// actually open a connection yet but it does perform some basic
    /// checks on the URL that might make the operation fail.
    pub fn open<T: IntoConnectionInfo>(params: T) -> RedisResult<Client> {
        Ok(Client {
            connection_info: try!(params.into_connection_info())
        })
    }

    /// Instructs the client to actually connect to redis and returns a
    /// connection object.  The connection object can be used to send
    /// commands to the server.  This can fail with a variety of errors
    /// (like unreachable host) so it's important that you handle those
    /// errors.
    pub fn get_connection(&self) -> RedisResult<Connection> {
        Ok(try!(connect(&self.connection_info)))
    }

    /// Returns a PubSub connection.  A pubsub connection can be used to
    /// listen to messages coming in through the redis publish/subscribe
    /// system.
    ///
    /// Note that redis' pubsub operates across all databases.
    pub fn get_pubsub(&self) -> RedisResult<PubSub> {
        Ok(try!(connect_pubsub(&self.connection_info)))
    }
}

impl ConnectionLike for Client {

    fn req_packed_command(&self, cmd: &[u8]) -> RedisResult<Value> {
        (try!(self.get_connection())).req_packed_command(cmd)
    }

    fn req_packed_commands(&self, cmd: &[u8],
        offset: uint, count: uint) -> RedisResult<Vec<Value>> {
        (try!(self.get_connection())).req_packed_commands(cmd, offset, count)
    }

    fn get_db(&self) -> i64 {
        self.connection_info.db
    }
}
<commit_msg>Removed some now unnecessary parentheses<commit_after>use connection::{ConnectionInfo, IntoConnectionInfo, Connection, connect,
                 PubSub, connect_pubsub, ConnectionLike};
use types::{RedisResult, Value};

/// The client type.
pub struct Client {
    connection_info: ConnectionInfo,
}

/// The client acts as connector to the redis server.  By itself it does not
/// do much other than providing a convenient way to fetch a connection from
/// it.  In the future the plan is to provide a connection pool in the client.
///
/// When opening a client a URL in the following format should be used:
///
/// ```plain
/// redis://host:port/db
/// ```
///
/// Example usage::
///
/// ```rust,no_run
/// let client = redis::Client::open("redis://127.0.0.1/").unwrap();
/// let con = client.get_connection().unwrap();
/// ```
impl Client {

    /// Connects to a redis server and returns a client.  This does not
    /// actually open a connection yet but it does perform some basic
    /// checks on the URL that might make the operation fail.
    pub fn open<T: IntoConnectionInfo>(params: T) -> RedisResult<Client> {
        Ok(Client {
            connection_info: try!(params.into_connection_info())
        })
    }

    /// Instructs the client to actually connect to redis and returns a
    /// connection object.  The connection object can be used to send
    /// commands to the server.  This can fail with a variety of errors
    /// (like unreachable host) so it's important that you handle those
    /// errors.
    pub fn get_connection(&self) -> RedisResult<Connection> {
        Ok(try!(connect(&self.connection_info)))
    }

    /// Returns a PubSub connection.  A pubsub connection can be used to
    /// listen to messages coming in through the redis publish/subscribe
    /// system.
    ///
    /// Note that redis' pubsub operates across all databases.
    pub fn get_pubsub(&self) -> RedisResult<PubSub> {
        Ok(try!(connect_pubsub(&self.connection_info)))
    }
}

impl ConnectionLike for Client {

    fn req_packed_command(&self, cmd: &[u8]) -> RedisResult<Value> {
        try!(self.get_connection()).req_packed_command(cmd)
    }

    fn req_packed_commands(&self, cmd: &[u8],
        offset: uint, count: uint) -> RedisResult<Vec<Value>> {
        try!(self.get_connection()).req_packed_commands(cmd, offset, count)
    }

    fn get_db(&self) -> i64 {
        self.connection_info.db
    }
}
<|endoftext|>


<commit_before>use addressable::Addressable;

struct Memory<'self, ADDR> {
	getfn: &'self fn(ADDR) -> u8,
	setfn: &'self fn(ADDR, u8),
}

impl<'self, ADDR> Memory<'self, ADDR> {
	pub fn new (getfn: &'self fn(ADDR) -> u8, setfn: &'self fn(ADDR, u8)) -> Memory<'self, ADDR> {
		Memory { getfn: getfn, setfn: setfn }
	}
}

impl<'self, ADDR: Int> Addressable<ADDR> for Memory<'self, ADDR> {
	pub fn get (&self, addr: ADDR) -> u8 {
		(self.getfn)(addr)
	}

	pub fn set (&mut self, addr: ADDR, data: u8) {
		(self.setfn)(addr, data);
	}
}

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

	#[test]
	fn test_get_set () {
		let mut ram: Ram<u16> = Ram::new_sized(0x0400);
		let mut mem = Memory::new(|addr| { ram.get(addr) }, |addr, data| { ram.set(addr, data); });
		mem.set(0x0200, 123);
		assert_eq!(mem.get(0x0200), 123);
		assert_eq!(ram.get(0x0200), 123);
		ram.set(0x0200, 234);
		assert_eq!(mem.get(0x0200), 234);
		assert_eq!(ram.get(0x0200), 234);
	}
}
<commit_msg>Corrected lifetime specifiers in constructor function<commit_after>use addressable::Addressable;

struct Memory<'self, ADDR> {
	getfn: &'self fn(ADDR) -> u8,
	setfn: &'self fn(ADDR, u8),
}

impl<'self, ADDR> Memory<'self, ADDR> {
	pub fn new<'r> (getfn: &'r fn(ADDR) -> u8, setfn: &'r fn(ADDR, u8)) -> Memory<'r, ADDR> {
		Memory { getfn: getfn, setfn: setfn }
	}
}

impl<'self, ADDR: Int> Addressable<ADDR> for Memory<'self, ADDR> {
	pub fn get (&self, addr: ADDR) -> u8 {
		(self.getfn)(addr)
	}

	pub fn set (&mut self, addr: ADDR, data: u8) {
		(self.setfn)(addr, data);
	}
}

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

	#[test]
	fn test_get_set () {
		let mut ram: Ram<u16> = Ram::new_sized(0x0400);
		let mut mem = Memory::new(|addr| { ram.get(addr) }, |addr, data| { ram.set(addr, data); });
		mem.set(0x0200, 123);
		assert_eq!(mem.get(0x0200), 123);
		assert_eq!(ram.get(0x0200), 123);
		ram.set(0x0200, 234);
		assert_eq!(mem.get(0x0200), 234);
		assert_eq!(ram.get(0x0200), 234);
	}
}
<|endoftext|>


<commit_before>use std::process::{Command, Output};
use errors::*;

pub trait Config {
  fn get(&self, name: &str) -> Result<String>;
  fn set(&self, name: &str, value: &str) -> Result<()>;
}

pub struct GitConfig {
  pub namespace: String,
}

impl GitConfig {
  fn output(&self, args: &[&str]) -> Result<Output> {
    Command::new("git")
      .arg("config")
      .args(args)
      .output()
      .chain_err(|| "failed to execute `git config`")
      .and_then(|output| {
        if output.status.success() {
          Ok(output)
        } else {
          Err(ErrorKind::GitConfig(output).into())
        }
      })
  }
}

impl Config for GitConfig {
  fn get(&self, name: &str) -> Result<String> {
    let name = format!("{}.{}", self.namespace, name);
    let output = try!(self.output(&[&name]));
    let stdout = String::from_utf8_lossy(&output.stdout);
    Ok(stdout.trim().into())
  }

  fn set(&self, name: &str, value: &str) -> Result<()> {
    let name = format!("{}.{}", self.namespace, name);
    self.output(&[&name, &value]).and(Ok(()))
  }
}
<commit_msg>remove unnecessary deref<commit_after>use std::process::{Command, Output};
use errors::*;

pub trait Config {
  fn get(&self, name: &str) -> Result<String>;
  fn set(&self, name: &str, value: &str) -> Result<()>;
}

pub struct GitConfig {
  pub namespace: String,
}

impl GitConfig {
  fn output(&self, args: &[&str]) -> Result<Output> {
    Command::new("git")
      .arg("config")
      .args(args)
      .output()
      .chain_err(|| "failed to execute `git config`")
      .and_then(|output| {
        if output.status.success() {
          Ok(output)
        } else {
          Err(ErrorKind::GitConfig(output).into())
        }
      })
  }
}

impl Config for GitConfig {
  fn get(&self, name: &str) -> Result<String> {
    let name = format!("{}.{}", self.namespace, name);
    let output = try!(self.output(&[&name]));
    let stdout = String::from_utf8_lossy(&output.stdout);
    Ok(stdout.trim().into())
  }

  fn set(&self, name: &str, value: &str) -> Result<()> {
    let name = format!("{}.{}", self.namespace, name);
    self.output(&[&name, value]).and(Ok(()))
  }
}
<|endoftext|>


<commit_before>//! This module implements config access.
use std::io;
use std::fs;
use std::env;
use std::path::{Path, PathBuf};

use dotenv;
use log;
use java_properties;
use clap::ArgMatches;
use url::Url;
use ini::Ini;

use prelude::*;
use constants::{DEFAULT_URL, VERSION, PROTOCOL_VERSION};

/// Represents the auth information
#[derive(Debug, Clone)]
pub enum Auth {
    Key(String),
    Token(String),
}

/// Represents a DSN
#[derive(Debug, Clone)]
pub struct Dsn {
    pub host: String,
    pub protocol: String,
    pub port: u16,
    pub client_id: String,
    pub secret: String,
    pub project_id: u64,
}

impl Dsn {
    /// Parses a Dsn from a given string.
    fn from_str(dsn: &str) -> Result<Dsn> {
        let url = Url::parse(dsn)?;
        let project_id = if let Some(component_iter) = url.path_segments() {
            let components: Vec<_> = component_iter.collect();
            if components.len() != 1 {
                fail!("invalid dsn: invalid project ID");
            }
            components[0].parse().or(Err("invalid dsn: invalid project id"))?
        } else {
            fail!("invalid dsn: missing project ID");
        };
        if !(url.scheme() == "http" || url.scheme() == "https") {
            fail!(format!("invalid dsn: unknown protocol '{}'", url.scheme()));
        }

        if url.username() == "" {
            fail!("invalid dsn: missing client id");
        }

        Ok(Dsn {
            protocol: url.scheme().into(),
            host: url.host_str().ok_or("invalid dsn: missing host")?.into(),
            port: url.port_or_known_default().unwrap(),
            client_id: url.username().into(),
            secret: url.password().ok_or("invalid dsn: missing secret")?.into(),
            project_id: project_id,
        })
    }

    /// Returns the URL where events should be sent.
    pub fn get_submit_url(&self) -> String {
        format!("{}://{}:{}/api/{}/store/",
                self.protocol,
                self.host,
                self.port,
                self.project_id)
    }

    /// Returns the given auth header (ts is the timestamp of the event)
    pub fn get_auth_header(&self, ts: f64) -> String {
        format!("Sentry \
            sentry_timestamp={}, \
            sentry_client=sentry-cli/{}, \
            sentry_version={}, \
            sentry_key={}, \
            sentry_secret={}",
                ts,
                VERSION,
                PROTOCOL_VERSION,
                self.client_id,
                self.secret)
    }
}

pub fn prepare_environment() {
    dotenv::dotenv().ok();
}

/// Represents the `sentry-cli` config.
#[derive(Clone)]
pub struct Config {
    pub filename: PathBuf,
    pub auth: Option<Auth>,
    pub url: String,
    pub log_level: log::LogLevelFilter,
    pub ini: Ini,
}

impl Config {
    /// Loads the CLI config from the default location and returns it.
    pub fn from_cli_config() -> Result<Config> {
        let (filename, ini) = load_cli_config()?;
        Ok(Config {
            filename: filename,
            auth: get_default_auth(&ini),
            url: get_default_url(&ini),
            log_level: get_default_log_level(&ini)?,
            ini: ini,
        })
    }

    /// Load config values from a java style .properties file.
    pub fn load_java_properties<P: AsRef<Path>>(&mut self, p: P) -> Result<bool> {
        let f = match fs::File::open(p) {
            Ok(f) => f,
            Err(err) => {
                if err.kind() == io::ErrorKind::NotFound {
                    return Ok(false);
                }
                return Err(err.into());
            }
        };

        let props = match java_properties::read(f) {
            Ok(props) => props,
            Err(err) => {
                return Err(Error::from(format!(
                    "Could not load java style properties file: {}", err)));
            }
        };

        for (key, value) in props {
            let mut iter = key.rsplitn(2, '.');
            if let Some(key) = iter.next() {
                let section = iter.next();
                self.ini.set_to(section, key.to_string(), value);
            }
        }

        Ok(true)
    }

    /// Update the environment based on the config
    pub fn configure_environment(&self) {
        if !env::var("http_proxy").is_ok() {
            if let Some(proxy) = self.get_proxy_url() {
                env::set_var("http_proxy", proxy);
            }
        }
        #[cfg(not(windows))]
        {
            use openssl_probe::init_ssl_cert_env_vars;
            init_ssl_cert_env_vars();
        }
    }

    /// Indicates whether keepalive support should be enabled.  This
    /// mostly corresponds to an ini config but also has some sensible
    /// default handling.
    pub fn allow_keepalive(&self) -> bool {
        let val = self.ini.get_from(Some("http"), "keepalive");
        match val {
            // keepalive is broken on our dev server.  Since this makes local development
            // quite frustrating we disable keepalive (handle reuse) when we connect to
            // unprotected servers where it does not matter that much.
            None => !self.has_insecure_server(),
            Some(val) => val == "true",
        }
    }

    /// Returns the proxy URL if defined.
    fn get_proxy_url(&self) -> Option<&str> {
        self.ini.get_from(Some("http"), "proxy_url")
    }

    /// Returns the proxy username if defined.
    pub fn get_proxy_username(&self) -> Option<&str> {
        self.ini.get_from(Some("http"), "proxy_username")
    }

    /// Returns the proxy password if defined.
    pub fn get_proxy_password(&self) -> Option<&str> {
        self.ini.get_from(Some("http"), "proxy_password")
    }

    /// Indicates if SSL is enabled or disabled for the server.
    pub fn has_insecure_server(&self) -> bool {
        self.url.starts_with("http://")
    }

    /// Indicates whether SSL verification should be on or off.
    pub fn should_verify_ssl(&self) -> bool {
        let val = self.ini.get_from(Some("http"), "verify_ssl");
        match val {
            None => true,
            Some(val) => val == "true",
        }
    }

    /// Controls the SSL revocation check on windows.  This can be used as a
    /// workaround for misconfigured local SSL proxies.
    pub fn disable_ssl_revocation_check(&self) -> bool {
        let val = self.ini.get_from(Some("http"), "check_ssl_revoke");
        match val {
            None => true,
            Some(val) => val == "true",
        }
    }

    /// Given a match object from clap, this returns the org from it.
    pub fn get_org(&self, matches: &ArgMatches) -> Result<String> {
        Ok(matches.value_of("org")
               .map(|x| x.to_owned())
               .or_else(|| env::var("SENTRY_ORG").ok())
               .or_else(|| self.ini.get_from(Some("defaults"), "org").map(|x| x.to_owned()))
               .ok_or("An organization slug is required (provide with --org)")?)
    }

    /// Given a match object from clap, this returns a tuple in the
    /// form `(org, project)` which can either come from the match
    /// object or some defaults (envvar, ini etc.).
    pub fn get_org_and_project(&self, matches: &ArgMatches) -> Result<(String, String)> {
        let org = self.get_org(matches)?;
        let project = if let Some(project) = matches.value_of("project") {
            project.to_owned()
        } else {
            self.get_project_default()?
        };
        Ok((org, project))
    }

    /// Return the default value for a project.
    pub fn get_project_default(&self) -> Result<String> {
        Ok(env::var("SENTRY_PROJECT").ok()
            .or_else(|| self.ini.get_from(Some("defaults"), "project").map(|x| x.to_owned()))
            .ok_or("A project slug is required")?)
    }

    /// Returns the defaults for org and project.
    pub fn get_org_and_project_defaults(&self) -> (Option<String>, Option<String>) {
        (env::var("SENTRY_ORG")
             .ok()
             .or_else(|| self.ini.get_from(Some("defaults"), "org").map(|x| x.to_owned())),
         env::var("SENTRY_PROJECT")
             .ok()
             .or_else(|| self.ini.get_from(Some("defaults"), "project").map(|x| x.to_owned())))
    }

    /// Return the DSN
    pub fn get_dsn(&self) -> Result<Dsn> {
        if let Some(ref val) = env::var("SENTRY_DSN").ok() {
            Dsn::from_str(val)
        } else if let Some(val) = self.ini.get_from(Some("auth"), "dsn") {
            Dsn::from_str(val)
        } else {
            fail!("No DSN provided");
        }
    }
}

fn find_project_config_file() -> Option<PathBuf> {
    env::current_dir().ok().and_then(|mut path| {
        loop {
            path.push(".sentryclirc");
            if path.exists() {
                return Some(path);
            }
            path.pop();
            if !path.pop() {
                return None;
            }
        }
    })
}

fn load_cli_config() -> Result<(PathBuf, Ini)> {
    let mut home_fn = env::home_dir().ok_or("Could not find home dir")?;
    home_fn.push(".sentryclirc");

    let mut rv = match fs::File::open(&home_fn) {
        Ok(mut file) => Ini::read_from(&mut file)?,
        Err(err) => {
            if err.kind() == io::ErrorKind::NotFound {
                Ini::new()
            } else {
                fail!(err);
            }
        }
    };

    if let Some(project_config_path) = find_project_config_file() {
        let ini = Ini::read_from(&mut fs::File::open(&project_config_path)?)?;
        for (section, props) in ini.iter() {
            for (key, value) in props {
                rv.set_to(section.clone(), key.clone(), value.to_owned());
            }
        }
        Ok((project_config_path, rv))
    } else {
        Ok((home_fn, rv))
    }
}

fn get_default_auth(ini: &Ini) -> Option<Auth> {
    if let Some(ref val) = env::var("SENTRY_AUTH_TOKEN").ok() {
        Some(Auth::Token(val.to_owned()))
    } else if let Some(ref val) = env::var("SENTRY_API_KEY").ok() {
        Some(Auth::Key(val.to_owned()))
    } else if let Some(val) = ini.get_from(Some("auth"), "token") {
        Some(Auth::Token(val.to_owned()))
    } else if let Some(val) = ini.get_from(Some("auth"), "api_key") {
        Some(Auth::Key(val.to_owned()))
    } else {
        None
    }
}

fn get_default_url(ini: &Ini) -> String {
    if let Some(ref val) = env::var("SENTRY_URL").ok() {
        val.to_owned()
    } else if let Some(val) = ini.get_from(Some("defaults"), "url") {
        val.to_owned()
    } else {
        DEFAULT_URL.to_owned()
    }
}

fn get_default_log_level(ini: &Ini) -> Result<log::LogLevelFilter> {
    if let Ok(level_str) = env::var("SENTRY_LOG_LEVEL") {
        if let Ok(level) = level_str.parse() {
            return Ok(level);
        }
    }

    if let Some(level_str) = ini.get_from(Some("log"), "level") {
        if let Ok(level) = level_str.parse() {
            return Ok(level);
        }
    }

    Ok(log::LogLevelFilter::Warn)
}
<commit_msg>Consider a sentrycli.ini<commit_after>//! This module implements config access.
use std::io;
use std::fs;
use std::env;
use std::path::{Path, PathBuf};

use dotenv;
use log;
use java_properties;
use clap::ArgMatches;
use url::Url;
use ini::Ini;

use prelude::*;
use constants::{DEFAULT_URL, VERSION, PROTOCOL_VERSION};

/// Represents the auth information
#[derive(Debug, Clone)]
pub enum Auth {
    Key(String),
    Token(String),
}

/// Represents a DSN
#[derive(Debug, Clone)]
pub struct Dsn {
    pub host: String,
    pub protocol: String,
    pub port: u16,
    pub client_id: String,
    pub secret: String,
    pub project_id: u64,
}

impl Dsn {
    /// Parses a Dsn from a given string.
    fn from_str(dsn: &str) -> Result<Dsn> {
        let url = Url::parse(dsn)?;
        let project_id = if let Some(component_iter) = url.path_segments() {
            let components: Vec<_> = component_iter.collect();
            if components.len() != 1 {
                fail!("invalid dsn: invalid project ID");
            }
            components[0].parse().or(Err("invalid dsn: invalid project id"))?
        } else {
            fail!("invalid dsn: missing project ID");
        };
        if !(url.scheme() == "http" || url.scheme() == "https") {
            fail!(format!("invalid dsn: unknown protocol '{}'", url.scheme()));
        }

        if url.username() == "" {
            fail!("invalid dsn: missing client id");
        }

        Ok(Dsn {
            protocol: url.scheme().into(),
            host: url.host_str().ok_or("invalid dsn: missing host")?.into(),
            port: url.port_or_known_default().unwrap(),
            client_id: url.username().into(),
            secret: url.password().ok_or("invalid dsn: missing secret")?.into(),
            project_id: project_id,
        })
    }

    /// Returns the URL where events should be sent.
    pub fn get_submit_url(&self) -> String {
        format!("{}://{}:{}/api/{}/store/",
                self.protocol,
                self.host,
                self.port,
                self.project_id)
    }

    /// Returns the given auth header (ts is the timestamp of the event)
    pub fn get_auth_header(&self, ts: f64) -> String {
        format!("Sentry \
            sentry_timestamp={}, \
            sentry_client=sentry-cli/{}, \
            sentry_version={}, \
            sentry_key={}, \
            sentry_secret={}",
                ts,
                VERSION,
                PROTOCOL_VERSION,
                self.client_id,
                self.secret)
    }
}

pub fn prepare_environment() {
    dotenv::dotenv().ok();
}

/// Represents the `sentry-cli` config.
#[derive(Clone)]
pub struct Config {
    pub filename: PathBuf,
    pub auth: Option<Auth>,
    pub url: String,
    pub log_level: log::LogLevelFilter,
    pub ini: Ini,
}

impl Config {
    /// Loads the CLI config from the default location and returns it.
    pub fn from_cli_config() -> Result<Config> {
        let (filename, ini) = load_cli_config()?;
        Ok(Config {
            filename: filename,
            auth: get_default_auth(&ini),
            url: get_default_url(&ini),
            log_level: get_default_log_level(&ini)?,
            ini: ini,
        })
    }

    /// Load config values from a java style .properties file.
    pub fn load_java_properties<P: AsRef<Path>>(&mut self, p: P) -> Result<bool> {
        let f = match fs::File::open(p) {
            Ok(f) => f,
            Err(err) => {
                if err.kind() == io::ErrorKind::NotFound {
                    return Ok(false);
                }
                return Err(err.into());
            }
        };

        let props = match java_properties::read(f) {
            Ok(props) => props,
            Err(err) => {
                return Err(Error::from(format!(
                    "Could not load java style properties file: {}", err)));
            }
        };

        for (key, value) in props {
            let mut iter = key.rsplitn(2, '.');
            if let Some(key) = iter.next() {
                let section = iter.next();
                self.ini.set_to(section, key.to_string(), value);
            }
        }

        Ok(true)
    }

    /// Update the environment based on the config
    pub fn configure_environment(&self) {
        if !env::var("http_proxy").is_ok() {
            if let Some(proxy) = self.get_proxy_url() {
                env::set_var("http_proxy", proxy);
            }
        }
        #[cfg(not(windows))]
        {
            use openssl_probe::init_ssl_cert_env_vars;
            init_ssl_cert_env_vars();
        }
    }

    /// Indicates whether keepalive support should be enabled.  This
    /// mostly corresponds to an ini config but also has some sensible
    /// default handling.
    pub fn allow_keepalive(&self) -> bool {
        let val = self.ini.get_from(Some("http"), "keepalive");
        match val {
            // keepalive is broken on our dev server.  Since this makes local development
            // quite frustrating we disable keepalive (handle reuse) when we connect to
            // unprotected servers where it does not matter that much.
            None => !self.has_insecure_server(),
            Some(val) => val == "true",
        }
    }

    /// Returns the proxy URL if defined.
    fn get_proxy_url(&self) -> Option<&str> {
        self.ini.get_from(Some("http"), "proxy_url")
    }

    /// Returns the proxy username if defined.
    pub fn get_proxy_username(&self) -> Option<&str> {
        self.ini.get_from(Some("http"), "proxy_username")
    }

    /// Returns the proxy password if defined.
    pub fn get_proxy_password(&self) -> Option<&str> {
        self.ini.get_from(Some("http"), "proxy_password")
    }

    /// Indicates if SSL is enabled or disabled for the server.
    pub fn has_insecure_server(&self) -> bool {
        self.url.starts_with("http://")
    }

    /// Indicates whether SSL verification should be on or off.
    pub fn should_verify_ssl(&self) -> bool {
        let val = self.ini.get_from(Some("http"), "verify_ssl");
        match val {
            None => true,
            Some(val) => val == "true",
        }
    }

    /// Controls the SSL revocation check on windows.  This can be used as a
    /// workaround for misconfigured local SSL proxies.
    pub fn disable_ssl_revocation_check(&self) -> bool {
        let val = self.ini.get_from(Some("http"), "check_ssl_revoke");
        match val {
            None => true,
            Some(val) => val == "true",
        }
    }

    /// Given a match object from clap, this returns the org from it.
    pub fn get_org(&self, matches: &ArgMatches) -> Result<String> {
        Ok(matches.value_of("org")
               .map(|x| x.to_owned())
               .or_else(|| env::var("SENTRY_ORG").ok())
               .or_else(|| self.ini.get_from(Some("defaults"), "org").map(|x| x.to_owned()))
               .ok_or("An organization slug is required (provide with --org)")?)
    }

    /// Given a match object from clap, this returns a tuple in the
    /// form `(org, project)` which can either come from the match
    /// object or some defaults (envvar, ini etc.).
    pub fn get_org_and_project(&self, matches: &ArgMatches) -> Result<(String, String)> {
        let org = self.get_org(matches)?;
        let project = if let Some(project) = matches.value_of("project") {
            project.to_owned()
        } else {
            self.get_project_default()?
        };
        Ok((org, project))
    }

    /// Return the default value for a project.
    pub fn get_project_default(&self) -> Result<String> {
        Ok(env::var("SENTRY_PROJECT").ok()
            .or_else(|| self.ini.get_from(Some("defaults"), "project").map(|x| x.to_owned()))
            .ok_or("A project slug is required")?)
    }

    /// Returns the defaults for org and project.
    pub fn get_org_and_project_defaults(&self) -> (Option<String>, Option<String>) {
        (env::var("SENTRY_ORG")
             .ok()
             .or_else(|| self.ini.get_from(Some("defaults"), "org").map(|x| x.to_owned())),
         env::var("SENTRY_PROJECT")
             .ok()
             .or_else(|| self.ini.get_from(Some("defaults"), "project").map(|x| x.to_owned())))
    }

    /// Return the DSN
    pub fn get_dsn(&self) -> Result<Dsn> {
        if let Some(ref val) = env::var("SENTRY_DSN").ok() {
            Dsn::from_str(val)
        } else if let Some(val) = self.ini.get_from(Some("auth"), "dsn") {
            Dsn::from_str(val)
        } else {
            fail!("No DSN provided");
        }
    }
}

fn find_project_config_file() -> Option<PathBuf> {
    env::current_dir().ok().and_then(|mut path| {
        loop {
            path.push(".sentryclirc");
            if path.exists() {
                return Some(path);
            }
            path.set_file_name("sentrycli.ini");
            if path.exists() {
                return Some(path);
            }
            path.pop();
            if !path.pop() {
                return None;
            }
        }
    })
}

fn load_cli_config() -> Result<(PathBuf, Ini)> {
    let mut home_fn = env::home_dir().ok_or("Could not find home dir")?;
    home_fn.push(".sentryclirc");

    let mut rv = match fs::File::open(&home_fn) {
        Ok(mut file) => Ini::read_from(&mut file)?,
        Err(err) => {
            if err.kind() == io::ErrorKind::NotFound {
                Ini::new()
            } else {
                fail!(err);
            }
        }
    };

    if let Some(project_config_path) = find_project_config_file() {
        let ini = Ini::read_from(&mut fs::File::open(&project_config_path)?)?;
        for (section, props) in ini.iter() {
            for (key, value) in props {
                rv.set_to(section.clone(), key.clone(), value.to_owned());
            }
        }
        Ok((project_config_path, rv))
    } else {
        Ok((home_fn, rv))
    }
}

fn get_default_auth(ini: &Ini) -> Option<Auth> {
    if let Some(ref val) = env::var("SENTRY_AUTH_TOKEN").ok() {
        Some(Auth::Token(val.to_owned()))
    } else if let Some(ref val) = env::var("SENTRY_API_KEY").ok() {
        Some(Auth::Key(val.to_owned()))
    } else if let Some(val) = ini.get_from(Some("auth"), "token") {
        Some(Auth::Token(val.to_owned()))
    } else if let Some(val) = ini.get_from(Some("auth"), "api_key") {
        Some(Auth::Key(val.to_owned()))
    } else {
        None
    }
}

fn get_default_url(ini: &Ini) -> String {
    if let Some(ref val) = env::var("SENTRY_URL").ok() {
        val.to_owned()
    } else if let Some(val) = ini.get_from(Some("defaults"), "url") {
        val.to_owned()
    } else {
        DEFAULT_URL.to_owned()
    }
}

fn get_default_log_level(ini: &Ini) -> Result<log::LogLevelFilter> {
    if let Ok(level_str) = env::var("SENTRY_LOG_LEVEL") {
        if let Ok(level) = level_str.parse() {
            return Ok(level);
        }
    }

    if let Some(level_str) = ini.get_from(Some("log"), "level") {
        if let Ok(level) = level_str.parse() {
            return Ok(level);
        }
    }

    Ok(log::LogLevelFilter::Warn)
}
<|endoftext|>


<commit_before>use clap::{App, Arg};
use log::info;
use regex::Regex;
use std::ffi::OsStr;
use std::path::Path;

use inkwell::context::Context;
use inkwell::memory_buffer::MemoryBuffer;
use inkwell::module::Linkage;
use inkwell::module::Module;
use inkwell::types::{AnyType, FunctionType};
use inkwell::values::{AnyValue, BasicValue, BasicValueEnum};
use inkwell::values::{FunctionValue, GlobalValue, PointerValue};
use inkwell::AddressSpace;

fn main() {
    // Command line argument parsing (using clap)
    let matches = App::new("Test inkwell")
        // .version("0.1.0")
        // .author("")
        // .about("")
        .arg(
            Arg::with_name("initializers")
                .long("initializers")
                .short("i")
                .long("initializers")
                .help("Call initializers from main"),
        )
        .arg(
            Arg::with_name("seahorn")
                .long("seahorn")
                .short("s")
                .long("seahorn")
                .conflicts_with("initializers")
                .help("SeaHorn preparation (conflicts with --initializers)"),
        )
        .arg(
            Arg::with_name("verbosity")
                .short("v")
                .long("verbosity")
                .multiple(true)
                .help("Increase message verbosity"),
        )
        .arg(
            Arg::with_name("INPUT")
                .help("Input file name")
                .required(true)
                .index(1),
        )
        .arg(
            Arg::with_name("OUTPUT")
                .help("Output file name")
                .short("o")
                .long("output")
                .takes_value(true)
                .default_value("out"),
        )
        .get_matches();

    stderrlog::new()
        .verbosity(matches.occurrences_of("verbosity") as usize)
        .init()
        .unwrap();

    let path_in = matches
        .value_of("INPUT")
        .expect("ERROR: missing input file name argument.");
    let path_in = Path::new(path_in);

    let path_out = matches
        .value_of("OUTPUT")
        .expect("ERROR: missing output file name argument.");
    let path_out = Path::new(path_out);

    // Read the input file
    info!("Reading input from {}", path_in.to_str().unwrap());
    let memory_buffer =
        MemoryBuffer::create_from_file(path_in).expect("ERROR: failed to open file.");

    let context = Context::create();
    let mut module = context
        .create_module_from_ir(memory_buffer)
        .expect("ERROR: failed to create module.");

    if matches.is_present("initializers") {
        handle_initializers(&context, &mut module);
    }

    if matches.is_present("seahorn") {
        handle_main(&module);

        handle_panic(&module);

        replace_def_with_dec(
            &module,
            &Regex::new(r"^_ZN3std2io5stdio7_eprint17h[a-f0-9]{16}E$").unwrap(),
        );
        replace_def_with_dec(
            &module,
            &Regex::new(r"^_ZN3std2io5stdio6_print17h[a-f0-9]{16}E$").unwrap(),
        );
    }

    // Write output file
    info!("Writing output to {}", path_out.to_str().unwrap());
    if path_out.extension() == Some(OsStr::new("bc")) {
        // output bitcode
        // TODO: this function returns bool but the doc doesn't say anything about it.
        module.write_bitcode_to_path(path_out);
    } else {
        // output disassembled bitcode
        module
            .print_to_file(path_out)
            .expect("ERROR: failed to write to file.");
    }
}

////////////////////////////////////////////////////////////////
// Transformations associated with initializers
////////////////////////////////////////////////////////////////

fn handle_initializers(context: &Context, module: &mut Module) {
    if let Some(initializer) = collect_initializers(context, module, ".init_array", "__init_function") {
        info!("Combined .init_array* initializers into '{}'", initializer.get_name().to_str().unwrap());

        let main = module.get_function("main").expect("Unable to find 'main' function");
        let mut args = get_fn_args(main);
        assert!(args.len() == 2); // We expect "i32 @main(i32 %0, i8** %1)"
        let i8_type = context.i8_type();
        let pi8_type = i8_type.ptr_type(AddressSpace::Generic);
        let ppi8_type = pi8_type.ptr_type(AddressSpace::Generic);
        args.push(ppi8_type.const_null().as_basic_value_enum());
        insert_call_at_head(context, initializer, args, main);
        info!("Inserted call to '{}' into 'main'", initializer.get_name().to_str().unwrap())
    } else {
        info!("No initializers to handle")
    }
}

/// Collect all the initializers in a section (whose name starts with 'prefix')
/// into a single function that calls all the initializers.
fn collect_initializers<'a>(context: &Context, module: &mut Module<'a>, prefix: &str, nm: &str) -> Option<FunctionValue<'a>> {
    let vs = collect_variables_in_section(module, prefix);
    for v in &vs {
        info!("Found initializer {:?}", v.get_name().to_str().unwrap());
    }

    let fps : Vec<PointerValue> = vs.iter().map(get_initializer_function).collect();

    if ! fps.is_empty() {
        let fp = fps[0];

        // dereference the pointer type
        let fp_type = fp.get_type().get_element_type().into_function_type();
        info!("Initializer type {:?}", fp_type.print_to_string());

        Some(build_fanout(context, module, nm, fp_type, fps))
    } else {
        None
    }
}

/// Collect variables that are assigned to a section whose name matches prefix
fn collect_variables_in_section<'a>(module: &Module<'a>, prefix: &str) -> Vec<GlobalValue<'a>> {
    let mut vs = Vec::new();
    // todo: should implement an iterator for global values so that the following loop
    // becomes just iter().filter_map().filter_map().filter()
    let mut og = module.get_first_global();
    while let Some(g) = og {
        if let Some(s) = g.get_section() {
            if let Ok(s) = s.to_str() {
                if s.starts_with(prefix) {
                    vs.push(g)
                }
            }
        }
        og = g.get_next_global();
    }
    vs
}

/// Convert the contents of an initializer section to a function pointer.
///
/// Initializer sections contain structs where the first field is a function pointer cast to
/// some other type.
fn get_initializer_function<'a>(v: &GlobalValue<'a>) -> PointerValue<'a> {
        let i = v.get_initializer().unwrap().into_struct_value();
        assert!(i.get_num_operands() == 2); // expecting two fields in struct
        let i = i.get_operand(0).unwrap();
        assert!(i.get_num_operands() == 1); // expecting bitcast
        let fp = i.get_operand(0).unwrap();
        fp.into_pointer_value()
}

/// Given a list of functions of type 'ty', build a function that calls each function in order
///
/// Assumes (without checking) that return type is void
///
///     define void @fanout(i32 %0, i32 %1) {
///     entry:
///       call void @f1(i32 %0, i32 %1)
///       call void @f2(i32 %0, i32 %1)
///       call void @f3(i32 %0, i32 %1)
///       ret void
///     }
///
fn build_fanout<'a>(context: &Context, module: &mut Module<'a>, nm: &str, ty: FunctionType<'a>, fps: Vec<PointerValue<'a>>) -> FunctionValue<'a> {
    let function = module.add_function(nm, ty, None);
    let args = get_fn_args(function);
    let basic_block = context.append_basic_block(function, "entry");
    let builder = context.create_builder();
    builder.position_at_end(basic_block);

    for fp in fps {
        builder.build_call(fp, &args, "");
        builder.build_return(None);
        // println!("Built function {:?}", function)
    }

    function
}

fn get_fn_args<'a>(function: FunctionValue<'a>) -> Vec<BasicValueEnum<'a>> {
    (0 .. function.count_params()).map(|i| function.get_nth_param(i).unwrap()).collect()
}

fn insert_call_at_head<'a>(context: &Context, f: FunctionValue<'a>, args: Vec<BasicValueEnum<'a>>, insertee: FunctionValue<'a>) {
    let bb = insertee.get_first_basic_block().expect("Unable to find function to insert function call into");
    let first_instruction = bb.get_first_instruction().expect("Unable to find where to insert function call into function");
    let builder = context.create_builder();
    builder.position_before(&first_instruction);
    builder.build_call(f, &args, "");
}

////////////////////////////////////////////////////////////////
// Transformations associated with SeaHorn
////////////////////////////////////////////////////////////////

fn handle_main(module: &Module) {
    // Remove the main function rustc generates.
    if let Some(main) = module.get_function("main") {
        unsafe { main.delete(); }
        info!("Deleted 'main' (was added by rustc).");
    }

    // Change the linkage of mangled main function from internal to external.
    if let Some(main) = get_function(module, &Regex::new(r"4main17h[a-f0-9]{16}E$").unwrap()) {
        // main.set_linkage(Linkage::External);
        println!("MAIN: {}", main.get_name().to_str().unwrap());
    }
}

fn get_function<'ctx>(module: &'ctx Module, re: &Regex) -> Option<FunctionValue<'ctx>> {
    let mut op_fun = module.get_first_function();
    while let Some(fun) = op_fun {
        if re.is_match(fun.get_name().to_str()
                       .expect("ERROR: function name is not in valid UTF-8")) {
            return Some(fun);
        }
        op_fun = fun.get_next_function();
    }
    None
}

fn handle_panic(module: &Module) {
    // TODO: make "spanic" a CL arg.
    if let Some(spanic) = module.get_function("spanic") {
        if let Some(unwind) = module.get_function("rust_begin_unwind") {
            unwind.replace_all_uses_with(spanic);
            info!("Replaced panic handling ('rust_begin_unwind') with 'spanic'.");
        }
    }
}

fn replace_def_with_dec(module: &Module, re: &Regex) {
    if let Some(fun) = get_function(module, re) {
        for bb in fun.get_basic_blocks() {
            unsafe { bb.delete().unwrap(); }
        }
        fun.remove_personality_function();
        fun.set_linkage(Linkage::External);
        info!("Removed the implementation of '{}'.", fun.get_name().to_str().unwrap());
    }
}

////////////////////////////////////////////////////////////////
// End
////////////////////////////////////////////////////////////////
<commit_msg>Patch-LLVM: cargo-fmt part 2<commit_after>use clap::{App, Arg};
use log::info;
use regex::Regex;
use std::ffi::OsStr;
use std::path::Path;

use inkwell::context::Context;
use inkwell::memory_buffer::MemoryBuffer;
use inkwell::module::Linkage;
use inkwell::module::Module;
use inkwell::types::{AnyType, FunctionType};
use inkwell::values::{AnyValue, BasicValue, BasicValueEnum};
use inkwell::values::{FunctionValue, GlobalValue, PointerValue};
use inkwell::AddressSpace;

fn main() {
    // Command line argument parsing (using clap)
    let matches = App::new("Test inkwell")
        // .version("0.1.0")
        // .author("")
        // .about("")
        .arg(
            Arg::with_name("initializers")
                .long("initializers")
                .short("i")
                .long("initializers")
                .help("Call initializers from main"),
        )
        .arg(
            Arg::with_name("seahorn")
                .long("seahorn")
                .short("s")
                .long("seahorn")
                .conflicts_with("initializers")
                .help("SeaHorn preparation (conflicts with --initializers)"),
        )
        .arg(
            Arg::with_name("verbosity")
                .short("v")
                .long("verbosity")
                .multiple(true)
                .help("Increase message verbosity"),
        )
        .arg(
            Arg::with_name("INPUT")
                .help("Input file name")
                .required(true)
                .index(1),
        )
        .arg(
            Arg::with_name("OUTPUT")
                .help("Output file name")
                .short("o")
                .long("output")
                .takes_value(true)
                .default_value("out"),
        )
        .get_matches();

    stderrlog::new()
        .verbosity(matches.occurrences_of("verbosity") as usize)
        .init()
        .unwrap();

    let path_in = matches
        .value_of("INPUT")
        .expect("ERROR: missing input file name argument.");
    let path_in = Path::new(path_in);

    let path_out = matches
        .value_of("OUTPUT")
        .expect("ERROR: missing output file name argument.");
    let path_out = Path::new(path_out);

    // Read the input file
    info!("Reading input from {}", path_in.to_str().unwrap());
    let memory_buffer =
        MemoryBuffer::create_from_file(path_in).expect("ERROR: failed to open file.");

    let context = Context::create();
    let mut module = context
        .create_module_from_ir(memory_buffer)
        .expect("ERROR: failed to create module.");

    if matches.is_present("initializers") {
        handle_initializers(&context, &mut module);
    }

    if matches.is_present("seahorn") {
        handle_main(&module);

        handle_panic(&module);

        replace_def_with_dec(
            &module,
            &Regex::new(r"^_ZN3std2io5stdio7_eprint17h[a-f0-9]{16}E$").unwrap(),
        );
        replace_def_with_dec(
            &module,
            &Regex::new(r"^_ZN3std2io5stdio6_print17h[a-f0-9]{16}E$").unwrap(),
        );
    }

    // Write output file
    info!("Writing output to {}", path_out.to_str().unwrap());
    if path_out.extension() == Some(OsStr::new("bc")) {
        // output bitcode
        // TODO: this function returns bool but the doc doesn't say anything about it.
        module.write_bitcode_to_path(path_out);
    } else {
        // output disassembled bitcode
        module
            .print_to_file(path_out)
            .expect("ERROR: failed to write to file.");
    }
}

////////////////////////////////////////////////////////////////
// Transformations associated with initializers
////////////////////////////////////////////////////////////////

fn handle_initializers(context: &Context, module: &mut Module) {
    if let Some(initializer) =
        collect_initializers(context, module, ".init_array", "__init_function")
    {
        info!(
            "Combined .init_array* initializers into '{}'",
            initializer.get_name().to_str().unwrap()
        );

        let main = module
            .get_function("main")
            .expect("Unable to find 'main' function");
        let mut args = get_fn_args(main);
        assert!(args.len() == 2); // We expect "i32 @main(i32 %0, i8** %1)"
        let i8_type = context.i8_type();
        let pi8_type = i8_type.ptr_type(AddressSpace::Generic);
        let ppi8_type = pi8_type.ptr_type(AddressSpace::Generic);
        args.push(ppi8_type.const_null().as_basic_value_enum());
        insert_call_at_head(context, initializer, args, main);
        info!(
            "Inserted call to '{}' into 'main'",
            initializer.get_name().to_str().unwrap()
        )
    } else {
        info!("No initializers to handle")
    }
}

/// Collect all the initializers in a section (whose name starts with 'prefix')
/// into a single function that calls all the initializers.
fn collect_initializers<'a>(
    context: &Context,
    module: &mut Module<'a>,
    prefix: &str,
    nm: &str,
) -> Option<FunctionValue<'a>> {
    let vs = collect_variables_in_section(module, prefix);
    for v in &vs {
        info!("Found initializer {:?}", v.get_name().to_str().unwrap());
    }

    let fps: Vec<PointerValue> = vs.iter().map(get_initializer_function).collect();

    if !fps.is_empty() {
        let fp = fps[0];

        // dereference the pointer type
        let fp_type = fp.get_type().get_element_type().into_function_type();
        info!("Initializer type {:?}", fp_type.print_to_string());

        Some(build_fanout(context, module, nm, fp_type, fps))
    } else {
        None
    }
}

/// Collect variables that are assigned to a section whose name matches prefix
fn collect_variables_in_section<'a>(module: &Module<'a>, prefix: &str) -> Vec<GlobalValue<'a>> {
    let mut vs = Vec::new();
    // todo: should implement an iterator for global values so that the following loop
    // becomes just iter().filter_map().filter_map().filter()
    let mut og = module.get_first_global();
    while let Some(g) = og {
        if let Some(s) = g.get_section() {
            if let Ok(s) = s.to_str() {
                if s.starts_with(prefix) {
                    vs.push(g)
                }
            }
        }
        og = g.get_next_global();
    }
    vs
}

/// Convert the contents of an initializer section to a function pointer.
///
/// Initializer sections contain structs where the first field is a function pointer cast to
/// some other type.
fn get_initializer_function<'a>(v: &GlobalValue<'a>) -> PointerValue<'a> {
    let i = v.get_initializer().unwrap().into_struct_value();
    assert!(i.get_num_operands() == 2); // expecting two fields in struct
    let i = i.get_operand(0).unwrap();
    assert!(i.get_num_operands() == 1); // expecting bitcast
    let fp = i.get_operand(0).unwrap();
    fp.into_pointer_value()
}

/// Given a list of functions of type 'ty', build a function that calls each function in order
///
/// Assumes (without checking) that return type is void
///
///     define void @fanout(i32 %0, i32 %1) {
///     entry:
///       call void @f1(i32 %0, i32 %1)
///       call void @f2(i32 %0, i32 %1)
///       call void @f3(i32 %0, i32 %1)
///       ret void
///     }
///
fn build_fanout<'a>(
    context: &Context,
    module: &mut Module<'a>,
    nm: &str,
    ty: FunctionType<'a>,
    fps: Vec<PointerValue<'a>>,
) -> FunctionValue<'a> {
    let function = module.add_function(nm, ty, None);
    let args = get_fn_args(function);
    let basic_block = context.append_basic_block(function, "entry");
    let builder = context.create_builder();
    builder.position_at_end(basic_block);

    for fp in fps {
        builder.build_call(fp, &args, "");
        builder.build_return(None);
        // println!("Built function {:?}", function)
    }

    function
}

fn get_fn_args<'a>(function: FunctionValue<'a>) -> Vec<BasicValueEnum<'a>> {
    (0..function.count_params())
        .map(|i| function.get_nth_param(i).unwrap())
        .collect()
}

fn insert_call_at_head<'a>(
    context: &Context,
    f: FunctionValue<'a>,
    args: Vec<BasicValueEnum<'a>>,
    insertee: FunctionValue<'a>,
) {
    let bb = insertee
        .get_first_basic_block()
        .expect("Unable to find function to insert function call into");
    let first_instruction = bb
        .get_first_instruction()
        .expect("Unable to find where to insert function call into function");
    let builder = context.create_builder();
    builder.position_before(&first_instruction);
    builder.build_call(f, &args, "");
}

////////////////////////////////////////////////////////////////
// Transformations associated with SeaHorn
////////////////////////////////////////////////////////////////

fn handle_main(module: &Module) {
    // Remove the main function rustc generates.
    if let Some(main) = module.get_function("main") {
        unsafe { main.delete(); }
        info!("Deleted 'main' (was added by rustc).");
    }

    // Change the linkage of mangled main function from internal to external.
    if let Some(main) = get_function(module, &Regex::new(r"4main17h[a-f0-9]{16}E$").unwrap()) {
        // main.set_linkage(Linkage::External);
        println!("MAIN: {}", main.get_name().to_str().unwrap());
    }
}

fn get_function<'ctx>(module: &'ctx Module, re: &Regex) -> Option<FunctionValue<'ctx>> {
    let mut op_fun = module.get_first_function();
    while let Some(fun) = op_fun {
        if re.is_match(fun.get_name().to_str()
                       .expect("ERROR: function name is not in valid UTF-8")) {
            return Some(fun);
        }
        op_fun = fun.get_next_function();
    }
    None
}

fn handle_panic(module: &Module) {
    // TODO: make "spanic" a CL arg.
    if let Some(spanic) = module.get_function("spanic") {
        if let Some(unwind) = module.get_function("rust_begin_unwind") {
            unwind.replace_all_uses_with(spanic);
            info!("Replaced panic handling ('rust_begin_unwind') with 'spanic'.");
        }
    }
}

fn replace_def_with_dec(module: &Module, re: &Regex) {
    if let Some(fun) = get_function(module, re) {
        for bb in fun.get_basic_blocks() {
            unsafe { bb.delete().unwrap(); }
        }
        fun.remove_personality_function();
        fun.set_linkage(Linkage::External);
        info!("Removed the implementation of '{}'.", fun.get_name().to_str().unwrap());
    }
}

////////////////////////////////////////////////////////////////
// End
////////////////////////////////////////////////////////////////
<|endoftext|>