<commit_before>// Copyright 2015 Keegan McAllister.
// Copyright 2016 Corey Farwell.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// See `LICENSE` in this repository.

use std::io::{self, Read};
use std::{panic, process};

/// Utility that reads a `Vec` of bytes from standard input (stdin)
/// and passes it to `closure`. All panics that occur within
/// `closure` will be treated as aborts. This is done so that
/// AFL considers a panic to be a crash.
///
/// # Examples
///
/// ```no_run
/// extern crate afl;
/// # struct Image;
/// # impl Image {
/// #     fn parse(_: &[u8]) {}
/// # }
///
/// fn main() {
///     afl::read_stdio_bytes(|read| {
///         Image::parse(&read)
///     })
/// }
/// ```
pub fn read_stdio_bytes<F>(closure: F)
where
    F: Fn(Vec<u8>) + panic::RefUnwindSafe,
{
    let mut input = vec![];
    let result = io::stdin().read_to_end(&mut input);
    if result.is_err() {
        return;
    }
    let was_panic = panic::catch_unwind(|| {
        closure(input);
    });
    if was_panic.is_err() {
        process::abort();
    }
}

/// Utility that reads a `String` from standard input (stdin) and
/// passes it to `closure`. If a `String` cannot be constructed from
/// the data provided by standard input, `closure` will _not_ be
/// called. All panics that occur within `closure` will be treated as
/// aborts. This is done so that AFL considers a panic to be a crash.
///
/// # Examples
///
/// ```no_run
/// extern crate afl;
/// # struct Url;
/// # impl Url {
/// #     fn parse(_: &str) {}
/// # }
///
/// fn main() {
///     afl::read_stdio_string(|string| {
///         Url::parse(&string)
///     })
/// }
/// ```
pub fn read_stdio_string<F>(closure: F)
where
    F: Fn(String) + panic::RefUnwindSafe,
{
    let mut input = String::new();
    let result = io::stdin().read_to_string(&mut input);
    if result.is_err() {
        return;
    }
    let was_panic = panic::catch_unwind(|| {
        closure(input);
    });
    if was_panic.is_err() {
        process::abort();
    }
}

// this function is provided by the afl-llvm-rt static library
extern "C" {
    fn __afl_persistent_loop(counter: usize) -> isize;
}

pub fn fuzz<F>(closure: F) where F: Fn(&[u8]) + std::panic::RefUnwindSafe {
    // this marker strings needs to be in the produced executable for
    // afl-fuzz to detect `persistent mode`
    static PERSIST_MARKER: &'static str = "##SIG_AFL_PERSISTENT##\0";

    // we now need a fake instruction to prevent the compiler from optimizing out
    // this marker string
    unsafe{std::ptr::read_volatile(&PERSIST_MARKER)}; // hack used in https://github.com/bluss/bencher for black_box()
    // unsafe { asm!("" : : "r"(&PERSIST_MARKER)) }; // hack used in nightly's back_box(), requires feature asm

    // sets panic hook to abort
    std::panic::set_hook(Box::new(|_| {
        std::process::abort();
    }));

    let mut input = vec![];

    while unsafe{__afl_persistent_loop(1000)} != 0 {
        // get buffer from AFL through stdin
        let result = io::stdin().read_to_end(&mut input);
        if result.is_err() {
            return;
        }

        // We still catch unwinding panics just in case the fuzzed code modifies
        // the panic hook.
        // If so, the fuzzer will be unable to tell different bugs appart and you will
        // only be able to find one bug at a time before fixing it to then find a new one.
        let did_panic = std::panic::catch_unwind(|| {
            closure(&input);
        }).is_err();

        if did_panic {
            // hopefully the custom panic hook will be called before and abort the
            // process before the stack frames are unwinded.
            std::process::abort();
        }
        input.clear();
    }
}

#[cfg(test)]
mod test {
    /*
    use std::path::PathBuf;
    use std::process::{Command, Stdio};
    use std::thread;
    use std::time;

    extern crate libc;
    extern crate tempdir;

    fn target_path() -> PathBuf {
        if PathBuf::from("../target/debug/cargo-afl-fuzz").exists() {
            PathBuf::from("../target/debug/")
        } else if PathBuf::from("target/debug/cargo-afl-fuzz").exists() {
            PathBuf::from("target/debug/")
        } else {
            panic!("Could not find cargo-afl-fuzz!");
        }
    }

    #[test]
    fn test_cargo_afl_fuzz() {
        let temp_dir = tempdir::TempDir::new("aflrs").expect("Could not create temporary directory");
        let temp_dir_path = temp_dir.path();
        let mut child = Command::new(target_path().join("cargo-afl-fuzz"))
            .stdout(Stdio::inherit())
            .stderr(Stdio::inherit())
            .arg("-i")
            .arg(".")
            .arg("-o")
            .arg(temp_dir_path)
            .arg(target_path().join("examples").join("hello"))
            .spawn()
            .expect("Could not run cargo-afl-fuzz");
        thread::sleep(time::Duration::from_secs(7));
        child.kill().unwrap();
        assert!(temp_dir_path.join("fuzzer_stats").is_file());
    }
    */
}
<commit_msg>Implement defered forkserver mode<commit_after>// Copyright 2015 Keegan McAllister.
// Copyright 2016 Corey Farwell.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// See `LICENSE` in this repository.

use std::io::{self, Read};
use std::{panic, process};

/// Utility that reads a `Vec` of bytes from standard input (stdin)
/// and passes it to `closure`. All panics that occur within
/// `closure` will be treated as aborts. This is done so that
/// AFL considers a panic to be a crash.
///
/// # Examples
///
/// ```no_run
/// extern crate afl;
/// # struct Image;
/// # impl Image {
/// #     fn parse(_: &[u8]) {}
/// # }
///
/// fn main() {
///     afl::read_stdio_bytes(|read| {
///         Image::parse(&read)
///     })
/// }
/// ```
pub fn read_stdio_bytes<F>(closure: F)
where
    F: Fn(Vec<u8>) + panic::RefUnwindSafe,
{
    let mut input = vec![];
    let result = io::stdin().read_to_end(&mut input);
    if result.is_err() {
        return;
    }
    let was_panic = panic::catch_unwind(|| {
        closure(input);
    });
    if was_panic.is_err() {
        process::abort();
    }
}

/// Utility that reads a `String` from standard input (stdin) and
/// passes it to `closure`. If a `String` cannot be constructed from
/// the data provided by standard input, `closure` will _not_ be
/// called. All panics that occur within `closure` will be treated as
/// aborts. This is done so that AFL considers a panic to be a crash.
///
/// # Examples
///
/// ```no_run
/// extern crate afl;
/// # struct Url;
/// # impl Url {
/// #     fn parse(_: &str) {}
/// # }
///
/// fn main() {
///     afl::read_stdio_string(|string| {
///         Url::parse(&string)
///     })
/// }
/// ```
pub fn read_stdio_string<F>(closure: F)
where
    F: Fn(String) + panic::RefUnwindSafe,
{
    let mut input = String::new();
    let result = io::stdin().read_to_string(&mut input);
    if result.is_err() {
        return;
    }
    let was_panic = panic::catch_unwind(|| {
        closure(input);
    });
    if was_panic.is_err() {
        process::abort();
    }
}

// those functions are provided by the afl-llvm-rt static library
extern "C" {
    fn __afl_persistent_loop(counter: usize) -> isize;
    fn __afl_manual_init();
}

pub fn fuzz<F>(closure: F) where F: Fn(&[u8]) + std::panic::RefUnwindSafe {
    // this marker strings needs to be in the produced executable for
    // afl-fuzz to detect `persistent mode` and `defered mode`
    static PERSIST_MARKER: &'static str = "##SIG_AFL_PERSISTENT##\0";
    static DEFERED_MARKER: &'static str = "##SIG_AFL_DEFER_FORKSRV##\0";

    // we now need a fake instruction to prevent the compiler from optimizing out
    // those marker strings
    unsafe{std::ptr::read_volatile(&PERSIST_MARKER)}; // hack used in https://github.com/bluss/bencher for black_box()
    unsafe{std::ptr::read_volatile(&DEFERED_MARKER)};
    // unsafe { asm!("" : : "r"(&PERSIST_MARKER)) }; // hack used in nightly's back_box(), requires feature asm
    // unsafe { asm!("" : : "r"(&DEFERED_MARKER)) };

    // sets panic hook to abort
    std::panic::set_hook(Box::new(|_| {
        std::process::abort();
    }));

    let mut input = vec![];

    // initialize forkserver there
    unsafe{__afl_manual_init()};

    while unsafe{__afl_persistent_loop(1000)} != 0 {
        // get buffer from AFL through stdin
        let result = io::stdin().read_to_end(&mut input);
        if result.is_err() {
            return;
        }

        // We still catch unwinding panics just in case the fuzzed code modifies
        // the panic hook.
        // If so, the fuzzer will be unable to tell different bugs appart and you will
        // only be able to find one bug at a time before fixing it to then find a new one.
        let did_panic = std::panic::catch_unwind(|| {
            closure(&input);
        }).is_err();

        if did_panic {
            // hopefully the custom panic hook will be called before and abort the
            // process before the stack frames are unwinded.
            std::process::abort();
        }
        input.clear();
    }
}

#[cfg(test)]
mod test {
    /*
    use std::path::PathBuf;
    use std::process::{Command, Stdio};
    use std::thread;
    use std::time;

    extern crate libc;
    extern crate tempdir;

    fn target_path() -> PathBuf {
        if PathBuf::from("../target/debug/cargo-afl-fuzz").exists() {
            PathBuf::from("../target/debug/")
        } else if PathBuf::from("target/debug/cargo-afl-fuzz").exists() {
            PathBuf::from("target/debug/")
        } else {
            panic!("Could not find cargo-afl-fuzz!");
        }
    }

    #[test]
    fn test_cargo_afl_fuzz() {
        let temp_dir = tempdir::TempDir::new("aflrs").expect("Could not create temporary directory");
        let temp_dir_path = temp_dir.path();
        let mut child = Command::new(target_path().join("cargo-afl-fuzz"))
            .stdout(Stdio::inherit())
            .stderr(Stdio::inherit())
            .arg("-i")
            .arg(".")
            .arg("-o")
            .arg(temp_dir_path)
            .arg(target_path().join("examples").join("hello"))
            .spawn()
            .expect("Could not run cargo-afl-fuzz");
        thread::sleep(time::Duration::from_secs(7));
        child.kill().unwrap();
        assert!(temp_dir_path.join("fuzzer_stats").is_file());
    }
    */
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]
#![feature(globs)]

extern crate "route-recognizer" as router;
extern crate conduit;

use std::collections::hash_map::{HashMap, Occupied, Vacant};
use std::fmt::Show;

use router::{Router, Match};
use conduit::{Method, Handler, Request, Response};

pub struct RouteBuilder {
    routers: HashMap<Method, Router<Box<Handler + Send + Sync>>>
}

impl RouteBuilder {
    pub fn new() -> RouteBuilder {
        RouteBuilder { routers: HashMap::new() }
    }

    pub fn recognize<'a>(&'a self, method: &Method, path: &str)
                         -> Result<Match<&'a Box<Handler + Send + Sync>>, String>
    {
        match self.routers.get(method) {
            None => Err(format!("No router found for {}", method)),
            Some(router) => router.recognize(path)
        }
    }

    pub fn map<'a, H: Handler>(&'a mut self, method: Method, pattern: &str,
                               handler: H) -> &'a mut RouteBuilder {
        {
            let router = match self.routers.entry(method) {
                Occupied(e) => e.into_mut(),
                Vacant(e) => e.set(Router::new()),
            };
            router.add(pattern, box handler as Box<Handler + Send + Sync>);
        }
        self
    }

    pub fn get<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                               -> &'a mut RouteBuilder {
        self.map(conduit::Get, pattern, handler)
    }

    pub fn post<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                -> &'a mut RouteBuilder {
        self.map(conduit::Post, pattern, handler)
    }

    pub fn put<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                               -> &'a mut RouteBuilder {
        self.map(conduit::Put, pattern, handler)
    }

    pub fn delete<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                  -> &'a mut RouteBuilder {
        self.map(conduit::Delete, pattern, handler)
    }

    pub fn head<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                -> &'a mut RouteBuilder {
        self.map(conduit::Head, pattern, handler)
    }
}

impl conduit::Handler for RouteBuilder {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show + 'static>> {
        let m = {
            let method = request.method();
            let path = request.path();

            match self.recognize(&method, path) {
                Ok(m) => m,
                Err(e) => return Err(box e as Box<Show>)
            }
        };

        {
            let extensions = request.mut_extensions();
            extensions.insert(m.params.clone());
        }

        (*m.handler).call(request)
    }
}

pub trait RequestParams<'a> {
    fn params(self) -> &'a router::Params;
}

pub fn params<'a>(req: &'a Request) -> &'a router::Params {
    req.extensions().find::<router::Params>()
        .expect("Missing params")
}

impl<'a> RequestParams<'a> for &'a Request + 'a {
    fn params(self) -> &'a router::Params {
        params(self)
    }
}

#[cfg(test)]
mod tests {
    extern crate semver;
    use std::io::net::ip::IpAddr;
    use std::collections::HashMap;
    use std::io::MemReader;

    use {RouteBuilder, RequestParams};

    use conduit;
    use conduit::{Handler, Method, Scheme, Host, Headers, Extensions, TypeMap};

    struct RequestSentinel {
        method: Method,
        path: String,
        extensions: conduit::Extensions
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_string(),
                extensions: TypeMap::new(),
                method: method
            }
        }
    }

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version { unimplemented!() }
        fn conduit_version(&self) -> semver::Version { unimplemented!() }
        fn method(&self) -> Method { self.method }
        fn scheme(&self) -> Scheme { unimplemented!() }
        fn host<'a>(&'a self) -> Host<'a> { unimplemented!() }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn path<'a>(&'a self) -> &'a str {
            self.path.as_slice()
        }
        fn query_string<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn remote_ip(&self) -> IpAddr { unimplemented!() }
        fn content_length(&self) -> Option<uint> { unimplemented!() }
        fn headers<'a>(&'a self) -> &'a Headers { unimplemented!() }
        fn body<'a>(&'a mut self) -> &'a mut Reader { unimplemented!() }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    #[test]
    fn basic_get() {
        let router = test_router();
        let mut req = RequestSentinel::new(conduit::Get, "/posts/1");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        assert_eq!(res.body.read_to_string().unwrap(), "1, Get".to_string());
    }

    #[test]
    fn basic_post() {
        let router = test_router();
        let mut req = RequestSentinel::new(conduit::Post, "/posts/10");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        assert_eq!(res.body.read_to_string().unwrap(), "10, Post".to_string());
    }

    #[test]
    fn nonexistent_route() {
        let router = test_router();
        let mut req = RequestSentinel::new(conduit::Post, "/nonexistent");
        router.call(&mut req).err().expect("No response");
    }

    fn test_router() -> RouteBuilder {
        let mut router = RouteBuilder::new();
        router.post("/posts/:id", test_handler);
        router.get("/posts/:id", test_handler);
        router
    }

    fn test_handler(req: &mut conduit::Request) -> Result<conduit::Response, ()> {
        let mut res = vec!();
        res.push(req.params()["id"].clone());
        res.push(format!("{}", req.method()));

        Ok(conduit::Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: box MemReader::new(res.connect(", ").into_bytes())
        })
    }
}
<commit_msg>Update to rust master<commit_after>#![feature(macro_rules)]
#![feature(globs)]

extern crate "route-recognizer" as router;
extern crate conduit;

use std::collections::hash_map::{HashMap, Occupied, Vacant};
use std::fmt::Show;

use router::{Router, Match};
use conduit::{Method, Handler, Request, Response};

pub struct RouteBuilder {
    routers: HashMap<Method, Router<Box<Handler + Send + Sync>>>
}

impl RouteBuilder {
    pub fn new() -> RouteBuilder {
        RouteBuilder { routers: HashMap::new() }
    }

    pub fn recognize<'a>(&'a self, method: &Method, path: &str)
                         -> Result<Match<&'a Box<Handler + Send + Sync>>, String>
    {
        match self.routers.get(method) {
            None => Err(format!("No router found for {}", method)),
            Some(router) => router.recognize(path)
        }
    }

    pub fn map<'a, H: Handler>(&'a mut self, method: Method, pattern: &str,
                               handler: H) -> &'a mut RouteBuilder {
        {
            let router = match self.routers.entry(method) {
                Occupied(e) => e.into_mut(),
                Vacant(e) => e.set(Router::new()),
            };
            router.add(pattern, box handler as Box<Handler + Send + Sync>);
        }
        self
    }

    pub fn get<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                               -> &'a mut RouteBuilder {
        self.map(Method::Get, pattern, handler)
    }

    pub fn post<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                -> &'a mut RouteBuilder {
        self.map(Method::Post, pattern, handler)
    }

    pub fn put<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                               -> &'a mut RouteBuilder {
        self.map(Method::Put, pattern, handler)
    }

    pub fn delete<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                  -> &'a mut RouteBuilder {
        self.map(Method::Delete, pattern, handler)
    }

    pub fn head<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                -> &'a mut RouteBuilder {
        self.map(Method::Head, pattern, handler)
    }
}

impl conduit::Handler for RouteBuilder {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show + 'static>> {
        let m = {
            let method = request.method();
            let path = request.path();

            match self.recognize(&method, path) {
                Ok(m) => m,
                Err(e) => return Err(box e as Box<Show>)
            }
        };

        {
            let extensions = request.mut_extensions();
            extensions.insert(m.params.clone());
        }

        (*m.handler).call(request)
    }
}

pub trait RequestParams<'a> {
    fn params(self) -> &'a router::Params;
}

pub fn params<'a>(req: &'a Request) -> &'a router::Params {
    req.extensions().find::<router::Params>()
        .expect("Missing params")
}

impl<'a> RequestParams<'a> for &'a (Request + 'a) {
    fn params(self) -> &'a router::Params {
        params(self)
    }
}

#[cfg(test)]
mod tests {
    extern crate semver;
    use std::io::net::ip::IpAddr;
    use std::collections::HashMap;
    use std::io::MemReader;

    use {RouteBuilder, RequestParams};

    use conduit;
    use conduit::{Handler, Method, Scheme, Host, Headers, Extensions, TypeMap};

    struct RequestSentinel {
        method: Method,
        path: String,
        extensions: conduit::Extensions
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_string(),
                extensions: TypeMap::new(),
                method: method
            }
        }
    }

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version { unimplemented!() }
        fn conduit_version(&self) -> semver::Version { unimplemented!() }
        fn method(&self) -> Method { self.method }
        fn scheme(&self) -> Scheme { unimplemented!() }
        fn host<'a>(&'a self) -> Host<'a> { unimplemented!() }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn path<'a>(&'a self) -> &'a str {
            self.path.as_slice()
        }
        fn query_string<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn remote_ip(&self) -> IpAddr { unimplemented!() }
        fn content_length(&self) -> Option<uint> { unimplemented!() }
        fn headers<'a>(&'a self) -> &'a Headers { unimplemented!() }
        fn body<'a>(&'a mut self) -> &'a mut Reader { unimplemented!() }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    #[test]
    fn basic_get() {
        let router = test_router();
        let mut req = RequestSentinel::new(Method::Get, "/posts/1");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        assert_eq!(res.body.read_to_string().unwrap(), "1, Get".to_string());
    }

    #[test]
    fn basic_post() {
        let router = test_router();
        let mut req = RequestSentinel::new(Method::Post, "/posts/10");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        assert_eq!(res.body.read_to_string().unwrap(), "10, Post".to_string());
    }

    #[test]
    fn nonexistent_route() {
        let router = test_router();
        let mut req = RequestSentinel::new(Method::Post, "/nonexistent");
        router.call(&mut req).err().expect("No response");
    }

    fn test_router() -> RouteBuilder {
        let mut router = RouteBuilder::new();
        router.post("/posts/:id", test_handler);
        router.get("/posts/:id", test_handler);
        router
    }

    fn test_handler(req: &mut conduit::Request) -> Result<conduit::Response, ()> {
        let mut res = vec!();
        res.push(req.params()["id"].clone());
        res.push(format!("{}", req.method()));

        Ok(conduit::Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: box MemReader::new(res.connect(", ").into_bytes())
        })
    }
}
<|endoftext|>


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

#![crate_name = "lua"]
#![crate_type = "lib"]

#![feature(unsafe_destructor)]

extern crate libc;
#[macro_use]
extern crate bitflags;

pub use wrapper::state::{
  State,

  Number,
  Integer,
  Function,
  Continuation,
  Reader,
  Writer,
  Context,
  Allocator,
  Hook,
  Index,

  Arithmetic,
  Comparison,
  ThreadStatus,
  GcOption,
  Type,

  Reference,
  REFNIL, NOREF,

  HookMask,
  MASKCALL, MASKRET, MASKLINE, MASKCOUNT,

  MULTRET, REGISTRYINDEX,
  RIDX_MAINTHREAD, RIDX_GLOBALS
};

#[cfg(target_os="windows")]
mod windows {
  #[link(name="lua53")]
  extern {}
}

#[cfg(not(target_os="windows"))]
mod unix {
  #[link(name="lua")]
  extern {}
}

pub mod ffi;
pub mod wrapper;

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

#![crate_name = "lua"]
#![crate_type = "lib"]

#![feature(unsafe_destructor)]
#![feature(libc)]

extern crate libc;
#[macro_use]
extern crate bitflags;

pub use wrapper::state::{
  State,

  Number,
  Integer,
  Function,
  Continuation,
  Reader,
  Writer,
  Context,
  Allocator,
  Hook,
  Index,

  Arithmetic,
  Comparison,
  ThreadStatus,
  GcOption,
  Type,

  Reference,
  REFNIL, NOREF,

  HookMask,
  MASKCALL, MASKRET, MASKLINE, MASKCOUNT,

  MULTRET, REGISTRYINDEX,
  RIDX_MAINTHREAD, RIDX_GLOBALS
};

#[cfg(target_os="windows")]
mod windows {
  #[link(name="lua53")]
  extern {}
}

#[cfg(not(target_os="windows"))]
mod unix {
  #[link(name="lua")]
  extern {}
}

pub mod ffi;
pub mod wrapper;

<|endoftext|>


<commit_before>extern crate libc;

use std::os::raw;
use std::ffi::CString;
use std::mem::{transmute, size_of};

#[link(name = "kleeRuntest")]
extern {
    fn klee_make_symbolic(data: *const raw::c_void, length: libc::size_t, name: *const raw::c_char);
    fn klee_set_forking(state: bool);
}

pub unsafe fn any(data: *const raw::c_void, length: usize, name: &str) {
    klee_make_symbolic(data, length as libc::size_t, CString::new(name).unwrap().as_ptr());
}

pub fn set_forking(state: bool) {
    unsafe { klee_set_forking(state); }
}

pub fn some<T>(name: &str) -> T {
    let new_symbol : T;
    symbol(&new_symbol, name);
    return new_symbol;
}

pub fn symbol<T>(data: &T, name: &str) {
    unsafe{ any(transmute(data as *const T), size_of::<T>(), name); }
}
<commit_msg>Update lib.rs<commit_after>extern crate libc;

use std::os::raw;
use std::ffi::CString;
use std::mem::{transmute, size_of};

#[link(name = "kleeRuntest")]
extern {
    fn klee_make_symbolic(data: *const raw::c_void, length: libc::size_t, name: *const raw::c_char);
    fn klee_set_forking(state: bool);
}

pub unsafe fn any(data: *const raw::c_void, length: usize, name: &str) {
    klee_make_symbolic(data, length as libc::size_t, CString::new(name).unwrap().as_ptr());
}

pub fn set_forking(state: bool) {
    unsafe { klee_set_forking(state); }
}

pub fn some<T>(initial: T, name: &str) -> T {
    unsafe {
        let new_symbol : T = initial;
        symbol(&new_symbol, name);
        return new_symbol;
    }
}

pub fn symbol<T>(data: &T, name: &str) {
    unsafe{ any(transmute(data as *const T), size_of::<T>(), name); }
}
<|endoftext|>


<commit_before>//! Minimal wrapper around internal Perl API.

use std::ptr;
use std::mem;
use std::os::raw::{ c_int, c_char };
use perl_sys::funcs::*;

pub use perl_sys::types::*;
pub use perl_sys::consts::*;

pub type Stack = OuroborosStack;

#[derive(Copy, Clone)]
pub struct Interpreter (PerlThreadContext);

impl Interpreter {
    pub unsafe fn new(pthx: PerlThreadContext) -> Interpreter { Interpreter(pthx) }
}

// Contains result of failed JMPENV_PUSH() while propagating through Rust.
struct Xcpt(c_int);

// Wrapper to safely call potentially dying perl functions (which is pretty much all of them because
// magic and ties).
//
// Put actual call into Perl inside a closure. `ouroboros_xcpt_try()` will call the closure while
// capturing Perl exceptions, so they don't skip Rust code except the closure itself, which should
// be fine, since closure is FnMut and has no destructors.
//
// If it returns zero, we assume that closure did not die and `v` was assigned to, making it safe to
// return, otherwise we panic and possibly incorrect value of `v` is not revealed.
//
// This only works with POD return types and non-panicing $body, which should always be the case for
// Perl API.
macro_rules! xcpt_try {
    ( $pthx:expr, $( $body:stmt )* ) => {{
        let mut v = mem::zeroed();
        {
            let mut callback: &mut FnMut() = &mut || ptr::write(&mut v, { $( $body )* });
            let rc = ouroboros_xcpt_try($pthx,
                                        mem::transmute(xcpt_bouncer as extern "C" fn(_)),
                                        mem::transmute(&mut callback));
            if rc != 0 {
                panic!(Xcpt(rc));
            }
        }
        v
    }}
}

// Helper function for calling Rust closure from C.
extern "C" fn xcpt_bouncer(closure: &mut &mut FnMut()) {
    (*closure)();
}

macro_rules! method {
    (
        fn $name:ident ( $( $pname:ident : $ptype:ty ),* ) = $imp:ident
    ) => (
        method! { fn $name ( $( $pname : $ptype ),* ) -> () = $imp }
    );

    (
        fn $name:ident ( $( $pname:ident : $ptype:ty ),* ) -> $rtype:ty = $imp:ident
    ) => (
        pub unsafe fn $name ( &self, $( $pname : $ptype ),* ) -> $rtype {
            xcpt_try! { self.0, $imp( self.0, $( $pname ),* ) }
        }
    );
}

impl Interpreter {
    method! { fn stack_init(arg0: *mut Stack) = ouroboros_stack_init }
    method! { fn stack_items(arg0: *mut Stack) -> c_int = ouroboros_stack_items }
    method! { fn stack_prepush(arg0: *mut Stack) = ouroboros_stack_prepush }
    method! { fn stack_putback(arg0: *mut Stack) = ouroboros_stack_putback }
    method! { fn stack_fetch(arg0: *mut Stack, arg1: SSize_t) -> *mut SV = ouroboros_stack_fetch }
    method! { fn stack_store(arg0: *mut Stack, arg1: SSize_t, arg2: *mut SV) = ouroboros_stack_store }
    method! { fn stack_extend(arg0: *mut Stack, arg1: SSize_t) = ouroboros_stack_extend }
    method! { fn stack_pushmark(arg0: *mut Stack) = ouroboros_stack_pushmark }
    method! { fn stack_spagain(arg0: *mut Stack) = ouroboros_stack_spagain }
    method! { fn stack_xpush_sv(arg0: *mut Stack, arg1: *mut SV) = ouroboros_stack_xpush_sv }
    method! { fn stack_xpush_sv_mortal(arg0: *mut Stack, arg1: *mut SV) = ouroboros_stack_xpush_sv_mortal }
    method! { fn stack_xpush_iv(arg0: *mut Stack, arg1: IV) = ouroboros_stack_xpush_iv }
    method! { fn stack_xpush_uv(arg0: *mut Stack, arg1: UV) = ouroboros_stack_xpush_uv }
    method! { fn stack_xpush_nv(arg0: *mut Stack, arg1: NV) = ouroboros_stack_xpush_nv }
    method! { fn stack_xpush_pv(arg0: *mut Stack, arg1: *const c_char, arg2: STRLEN) = ouroboros_stack_xpush_pv }
    method! { fn stack_push_sv(arg0: *mut Stack, arg1: *mut SV) = ouroboros_stack_push_sv }
    method! { fn stack_push_sv_mortal(arg0: *mut Stack, arg1: *mut SV) = ouroboros_stack_push_sv_mortal }
    method! { fn stack_push_iv(arg0: *mut Stack, arg1: IV) = ouroboros_stack_push_iv }
    method! { fn stack_push_uv(arg0: *mut Stack, arg1: UV) = ouroboros_stack_push_uv }
    method! { fn stack_push_nv(arg0: *mut Stack, arg1: NV) = ouroboros_stack_push_nv }
    method! { fn stack_push_pv(arg0: *mut Stack, arg1: *const c_char, arg2: STRLEN) = ouroboros_stack_push_pv }
    method! { fn sv_iv(arg0: *mut SV) -> IV = ouroboros_sv_iv }
    method! { fn sv_uv(arg0: *mut SV) -> UV = ouroboros_sv_uv }
    method! { fn sv_nv(arg0: *mut SV) -> NV = ouroboros_sv_nv }
    method! { fn sv_pv(arg0: *mut SV, arg1: *mut STRLEN) -> *const c_char = ouroboros_sv_pv }
    method! { fn sv_pv_nolen(arg0: *mut SV) -> *const c_char = ouroboros_sv_pv_nolen }
    method! { fn sv_rok(arg0: *mut SV) -> U32 = ouroboros_sv_rok }
    method! { fn sv_rv(arg0: *mut SV) -> *mut SV = ouroboros_sv_rv }
    method! { fn sv_type(arg0: *mut SV) -> IV = ouroboros_sv_type }
    method! { fn gv_sv(arg0: *mut GV) -> *mut SV = ouroboros_gv_sv }
    method! { fn gv_av(arg0: *mut GV) -> *mut AV = ouroboros_gv_av }
    method! { fn gv_hv(arg0: *mut GV) -> *mut HV = ouroboros_gv_hv }
    method! { fn gv_cv(arg0: *mut CV) -> *mut CV = ouroboros_gv_cv }
    method! { fn sv_refcnt(arg0: *mut SV) -> U32 = ouroboros_sv_refcnt }
    method! { fn sv_refcnt_inc(arg0: *mut SV) -> *mut SV = ouroboros_sv_refcnt_inc }
    method! { fn sv_refcnt_inc_nn(arg0: *mut SV) -> *mut SV = ouroboros_sv_refcnt_inc_nn }
    method! { fn sv_refcnt_inc_void(arg0: *mut SV) = ouroboros_sv_refcnt_inc_void }
    method! { fn sv_refcnt_inc_void_nn(arg0: *mut SV) = ouroboros_sv_refcnt_inc_void_nn }
    method! { fn sv_refcnt_dec(arg0: *mut SV) = ouroboros_sv_refcnt_dec }
    method! { fn sv_refcnt_dec_nn(arg0: *mut SV) = ouroboros_sv_refcnt_dec_nn }
    method! { fn enter() = ouroboros_enter }
    method! { fn leave() = ouroboros_leave }
    method! { fn savetmps() = ouroboros_savetmps }
    method! { fn freetmps() = ouroboros_freetmps }

    method! { fn av_clear(av: *mut AV) = Perl_av_clear }
    method! { fn av_delete(av: *mut AV, key: SSize_t, flags: I32) -> *mut SV = Perl_av_delete }
    method! { fn av_exists(av: *mut AV, key: SSize_t) -> c_bool = Perl_av_exists }
    method! { fn av_extend(av: *mut AV, key: SSize_t) = Perl_av_extend }
    method! { fn av_fetch(av: *mut AV, key: SSize_t, flags: I32) -> *mut *mut SV = Perl_av_fetch }
    method! { fn av_fill(av: *mut AV, fill: SSize_t) = Perl_av_fill }
    method! { fn av_len(av: *mut AV) -> SSize_t = Perl_av_len }
    method! { fn av_make(size: SSize_t, strp: *mut *mut SV) -> *mut AV = Perl_av_make }
    method! { fn av_pop(av: *mut AV) -> *mut SV = Perl_av_pop }
    method! { fn av_push(av: *mut AV, val: *mut SV) = Perl_av_push }
    method! { fn av_shift(av: *mut AV) -> *mut SV = Perl_av_shift }
    method! { fn av_store(av: *mut AV, key: SSize_t, sv: *mut SV) -> *mut *mut SV = Perl_av_store }
    method! { fn av_undef(av: *mut AV) = Perl_av_undef }
    method! { fn av_unshift(av: *mut AV, num: SSize_t) = Perl_av_unshift }

    method! { fn call_pv(name: *const i8, flags: I32) -> I32 = Perl_call_pv }

    method! { fn new_xs(name: *const i8, func: XSUBADDR_t, file: *const i8) -> *mut CV = Perl_newXS }
    method! { fn new_sv(len: STRLEN) -> *mut SV = Perl_newSV }
    method! { fn new_sv_iv(val: IV) -> *mut SV = Perl_newSViv }
    method! { fn new_sv_uv(val: UV) -> *mut SV = Perl_newSVuv }
    method! { fn new_sv_nv(val: NV) -> *mut SV = Perl_newSVnv }
    method! { fn new_sv_pvn(val: *const i8, len: STRLEN, flags: U32) -> *mut SV = Perl_newSVpvn_flags }

    method! { fn get_av(name: *const i8, flags: I32) -> *mut AV = Perl_get_av }
}
<commit_msg>Add HE and HV methods.<commit_after>//! Minimal wrapper around internal Perl API.

use std::ptr;
use std::mem;
use std::os::raw::{ c_int, c_char };
use perl_sys::funcs::*;

pub use perl_sys::types::*;
pub use perl_sys::consts::*;

pub type Stack = OuroborosStack;

#[derive(Copy, Clone)]
pub struct Interpreter (PerlThreadContext);

impl Interpreter {
    pub unsafe fn new(pthx: PerlThreadContext) -> Interpreter { Interpreter(pthx) }
}

// Contains result of failed JMPENV_PUSH() while propagating through Rust.
struct Xcpt(c_int);

// Wrapper to safely call potentially dying perl functions (which is pretty much all of them because
// magic and ties).
//
// Put actual call into Perl inside a closure. `ouroboros_xcpt_try()` will call the closure while
// capturing Perl exceptions, so they don't skip Rust code except the closure itself, which should
// be fine, since closure is FnMut and has no destructors.
//
// If it returns zero, we assume that closure did not die and `v` was assigned to, making it safe to
// return, otherwise we panic and possibly incorrect value of `v` is not revealed.
//
// This only works with POD return types and non-panicing $body, which should always be the case for
// Perl API.
macro_rules! xcpt_try {
    ( $pthx:expr, $( $body:stmt )* ) => {{
        let mut v = mem::zeroed();
        {
            let mut callback: &mut FnMut() = &mut || ptr::write(&mut v, { $( $body )* });
            let rc = ouroboros_xcpt_try($pthx,
                                        mem::transmute(xcpt_bouncer as extern "C" fn(_)),
                                        mem::transmute(&mut callback));
            if rc != 0 {
                panic!(Xcpt(rc));
            }
        }
        v
    }}
}

// Helper function for calling Rust closure from C.
extern "C" fn xcpt_bouncer(closure: &mut &mut FnMut()) {
    (*closure)();
}

macro_rules! method {
    (
        fn $name:ident ( $( $pname:ident : $ptype:ty ),* ) = $imp:ident
    ) => (
        method! { fn $name ( $( $pname : $ptype ),* ) -> () = $imp }
    );

    (
        fn $name:ident ( $( $pname:ident : $ptype:ty ),* ) -> $rtype:ty = $imp:ident
    ) => (
        pub unsafe fn $name ( &self, $( $pname : $ptype ),* ) -> $rtype {
            xcpt_try! { self.0, $imp( self.0, $( $pname ),* ) }
        }
    );
}

impl Interpreter {
    method! { fn stack_init(arg0: *mut Stack) = ouroboros_stack_init }
    method! { fn stack_items(arg0: *mut Stack) -> c_int = ouroboros_stack_items }
    method! { fn stack_prepush(arg0: *mut Stack) = ouroboros_stack_prepush }
    method! { fn stack_putback(arg0: *mut Stack) = ouroboros_stack_putback }
    method! { fn stack_fetch(arg0: *mut Stack, arg1: SSize_t) -> *mut SV = ouroboros_stack_fetch }
    method! { fn stack_store(arg0: *mut Stack, arg1: SSize_t, arg2: *mut SV) = ouroboros_stack_store }
    method! { fn stack_extend(arg0: *mut Stack, arg1: SSize_t) = ouroboros_stack_extend }
    method! { fn stack_pushmark(arg0: *mut Stack) = ouroboros_stack_pushmark }
    method! { fn stack_spagain(arg0: *mut Stack) = ouroboros_stack_spagain }
    method! { fn stack_xpush_sv(arg0: *mut Stack, arg1: *mut SV) = ouroboros_stack_xpush_sv }
    method! { fn stack_xpush_sv_mortal(arg0: *mut Stack, arg1: *mut SV) = ouroboros_stack_xpush_sv_mortal }
    method! { fn stack_xpush_iv(arg0: *mut Stack, arg1: IV) = ouroboros_stack_xpush_iv }
    method! { fn stack_xpush_uv(arg0: *mut Stack, arg1: UV) = ouroboros_stack_xpush_uv }
    method! { fn stack_xpush_nv(arg0: *mut Stack, arg1: NV) = ouroboros_stack_xpush_nv }
    method! { fn stack_xpush_pv(arg0: *mut Stack, arg1: *const c_char, arg2: STRLEN) = ouroboros_stack_xpush_pv }
    method! { fn stack_push_sv(arg0: *mut Stack, arg1: *mut SV) = ouroboros_stack_push_sv }
    method! { fn stack_push_sv_mortal(arg0: *mut Stack, arg1: *mut SV) = ouroboros_stack_push_sv_mortal }
    method! { fn stack_push_iv(arg0: *mut Stack, arg1: IV) = ouroboros_stack_push_iv }
    method! { fn stack_push_uv(arg0: *mut Stack, arg1: UV) = ouroboros_stack_push_uv }
    method! { fn stack_push_nv(arg0: *mut Stack, arg1: NV) = ouroboros_stack_push_nv }
    method! { fn stack_push_pv(arg0: *mut Stack, arg1: *const c_char, arg2: STRLEN) = ouroboros_stack_push_pv }
    method! { fn sv_iv(arg0: *mut SV) -> IV = ouroboros_sv_iv }
    method! { fn sv_uv(arg0: *mut SV) -> UV = ouroboros_sv_uv }
    method! { fn sv_nv(arg0: *mut SV) -> NV = ouroboros_sv_nv }
    method! { fn sv_pv(arg0: *mut SV, arg1: *mut STRLEN) -> *const c_char = ouroboros_sv_pv }
    method! { fn sv_pv_nolen(arg0: *mut SV) -> *const c_char = ouroboros_sv_pv_nolen }
    method! { fn sv_rok(arg0: *mut SV) -> U32 = ouroboros_sv_rok }
    method! { fn sv_rv(arg0: *mut SV) -> *mut SV = ouroboros_sv_rv }
    method! { fn sv_type(arg0: *mut SV) -> IV = ouroboros_sv_type }
    method! { fn gv_sv(arg0: *mut GV) -> *mut SV = ouroboros_gv_sv }
    method! { fn gv_av(arg0: *mut GV) -> *mut AV = ouroboros_gv_av }
    method! { fn gv_hv(arg0: *mut GV) -> *mut HV = ouroboros_gv_hv }
    method! { fn gv_cv(arg0: *mut CV) -> *mut CV = ouroboros_gv_cv }
    method! { fn sv_refcnt(arg0: *mut SV) -> U32 = ouroboros_sv_refcnt }
    method! { fn sv_refcnt_inc(arg0: *mut SV) -> *mut SV = ouroboros_sv_refcnt_inc }
    method! { fn sv_refcnt_inc_nn(arg0: *mut SV) -> *mut SV = ouroboros_sv_refcnt_inc_nn }
    method! { fn sv_refcnt_inc_void(arg0: *mut SV) = ouroboros_sv_refcnt_inc_void }
    method! { fn sv_refcnt_inc_void_nn(arg0: *mut SV) = ouroboros_sv_refcnt_inc_void_nn }
    method! { fn sv_refcnt_dec(arg0: *mut SV) = ouroboros_sv_refcnt_dec }
    method! { fn sv_refcnt_dec_nn(arg0: *mut SV) = ouroboros_sv_refcnt_dec_nn }
    method! { fn enter() = ouroboros_enter }
    method! { fn leave() = ouroboros_leave }
    method! { fn savetmps() = ouroboros_savetmps }
    method! { fn freetmps() = ouroboros_freetmps }
    method! { fn he_hash(arg0: *mut HE) -> U32 = ouroboros_he_hash }
    method! { fn he_pv(arg0: *mut HE, arg1: *mut STRLEN) -> *const c_char = ouroboros_he_pv }
    method! { fn he_svkey(arg0: *mut HE) -> *mut SV = ouroboros_he_svkey }
    method! { fn he_svkey_force(arg0: *mut HE) -> *mut SV = ouroboros_he_svkey_force }
    method! { fn he_svkey_set(arg0: *mut HE, arg1: *mut SV) -> *mut SV = ouroboros_he_svkey_set }
    method! { fn he_val(arg0: *mut HE) -> *mut SV = ouroboros_he_val }

    method! { fn av_clear(av: *mut AV) = Perl_av_clear }
    method! { fn av_delete(av: *mut AV, key: SSize_t, flags: I32) -> *mut SV = Perl_av_delete }
    method! { fn av_exists(av: *mut AV, key: SSize_t) -> c_bool = Perl_av_exists }
    method! { fn av_extend(av: *mut AV, key: SSize_t) = Perl_av_extend }
    method! { fn av_fetch(av: *mut AV, key: SSize_t, flags: I32) -> *mut *mut SV = Perl_av_fetch }
    method! { fn av_fill(av: *mut AV, fill: SSize_t) = Perl_av_fill }
    method! { fn av_len(av: *mut AV) -> SSize_t = Perl_av_len }
    method! { fn av_make(size: SSize_t, strp: *mut *mut SV) -> *mut AV = Perl_av_make }
    method! { fn av_pop(av: *mut AV) -> *mut SV = Perl_av_pop }
    method! { fn av_push(av: *mut AV, val: *mut SV) = Perl_av_push }
    method! { fn av_shift(av: *mut AV) -> *mut SV = Perl_av_shift }
    method! { fn av_store(av: *mut AV, key: SSize_t, sv: *mut SV) -> *mut *mut SV = Perl_av_store }
    method! { fn av_undef(av: *mut AV) = Perl_av_undef }
    method! { fn av_unshift(av: *mut AV, num: SSize_t) = Perl_av_unshift }

    method! { fn hv_fetch(hv: *mut HV, key: *const c_char, klen: I32, lval: I32) -> *mut *mut SV = Perl_hv_fetch }
    method! { fn hv_fetch_ent(hv: *mut HV, keysv: *mut SV, lval: I32, hash: U32) -> *mut HE = Perl_hv_fetch_ent }
    method! { fn hv_fill(hv: *mut HV) -> STRLEN = Perl_hv_fill }
    method! { fn hv_iterinit(hv: *mut HV) -> I32 = Perl_hv_iterinit }
    method! { fn hv_iterkey(entry: *mut HE, retlen: *mut I32) -> *mut c_char = Perl_hv_iterkey }
    method! { fn hv_iterkeysv(entry: *mut HE) -> *mut SV = Perl_hv_iterkeysv }
    method! { fn hv_iternext(hv: *mut HV) -> *mut HE = Perl_hv_iternext }
    method! { fn hv_iternextsv(hv: *mut HV, key: *mut *mut c_char, retlen: *mut I32) -> *mut SV = Perl_hv_iternextsv }
    method! { fn hv_iterval(hv: *mut HV, entry: *mut HE) -> *mut SV = Perl_hv_iterval }
    method! { fn hv_magic(hv: *mut HV, gv: *mut GV, how: c_int) = Perl_hv_magic }
    method! { fn hv_scalar(hv: *mut HV) -> *mut SV = Perl_hv_scalar }
    method! { fn hv_store(hv: *mut HV, key: *const c_char, klen: I32, val: *mut SV, hash: U32) -> *mut *mut SV = Perl_hv_store }
    method! { fn hv_store_ent(hv: *mut HV, key: *mut SV, val: *mut SV, hash: U32) -> *mut HE = Perl_hv_store_ent }

    method! { fn call_pv(name: *const i8, flags: I32) -> I32 = Perl_call_pv }

    method! { fn new_xs(name: *const i8, func: XSUBADDR_t, file: *const i8) -> *mut CV = Perl_newXS }
    method! { fn new_sv(len: STRLEN) -> *mut SV = Perl_newSV }
    method! { fn new_sv_iv(val: IV) -> *mut SV = Perl_newSViv }
    method! { fn new_sv_uv(val: UV) -> *mut SV = Perl_newSVuv }
    method! { fn new_sv_nv(val: NV) -> *mut SV = Perl_newSVnv }
    method! { fn new_sv_pvn(val: *const i8, len: STRLEN, flags: U32) -> *mut SV = Perl_newSVpvn_flags }

    method! { fn get_av(name: *const i8, flags: I32) -> *mut AV = Perl_get_av }
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate openexr_sys;

use std::{mem, ptr, error, fmt};
use std::path::Path;
use std::ffi::{CString, CStr};
use std::marker::PhantomData;

use libc::{c_char, c_int};

use openexr_sys::*;

pub use openexr_sys::CEXR_PixelType as PixelType;
pub use openexr_sys::CEXR_LineOrder as LineOrder;
pub use openexr_sys::CEXR_Compression as Compression;
pub use openexr_sys::CEXR_Box2i as Box2i;

#[derive(Debug, Clone)]
pub enum Error {
    Generic(String),
}

impl error::Error for Error {
    fn description(&self) -> &str {
        use self::Error::*;
        match *self {
            Generic(ref x) => x,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;
        match *self {
            Generic(ref x) => f.pad(x),
        }
    }
}

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

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

/// Types used by OpenEXR to represent a value held by a particular channel at
/// a particular point, suitable for being to directly by the decoder.
pub unsafe trait ChannelData: Copy + Into<f64> {
    fn pixel_type() -> PixelType;
}

unsafe impl ChannelData for u32 {
    fn pixel_type() -> PixelType {
        PixelType::UINT
    }
}

unsafe impl ChannelData for f32 {
    fn pixel_type() -> PixelType {
        PixelType::FLOAT
    }
}

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

/// Types that represent the values of an arbitrary collection of channels at
/// a particular point, suitable for being written to directly by the decoder.
pub unsafe trait PixelStruct: Copy {
    /// Returns an array of the types and byte offsets of the channels in the data
    fn channels() -> &'static [(PixelType, usize)];
}

unsafe impl PixelStruct for (f32, f32) {
    fn channels() -> &'static [(PixelType, usize)] {
        static TYPES: [(PixelType, usize); 2] = [(PixelType::FLOAT, 0), (PixelType::FLOAT, 4)];
        &TYPES
    }
}

unsafe impl PixelStruct for (f32, f32, f32) {
    fn channels() -> &'static [(PixelType, usize)] {
        static TYPES: [(PixelType, usize); 3] = [(PixelType::FLOAT, 0),
                                                 (PixelType::FLOAT, 4),
                                                 (PixelType::FLOAT, 8)];
        &TYPES
    }
}

unsafe impl PixelStruct for (f32, f32, f32, f32) {
    fn channels() -> &'static [(PixelType, usize)] {
        static TYPES: [(PixelType, usize); 4] = [(PixelType::FLOAT, 0),
                                                 (PixelType::FLOAT, 4),
                                                 (PixelType::FLOAT, 8),
                                                 (PixelType::FLOAT, 12)];
        &TYPES
    }
}

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

pub struct IStream<'a> {
    handle: *mut CEXR_IStream,
    _phantom: PhantomData<&'a ()>,
}

impl<'a> IStream<'a> {
    pub fn from_slice(slice: &[u8]) -> Self {
        IStream {
            handle: unsafe {
                CEXR_IStream_from_memory(b"in-memory data\0".as_ptr() as *const c_char,
                                         slice.as_ptr() as *mut u8 as *mut c_char,
                                         slice.len())
            },
            _phantom: PhantomData,
        }
    }
}

impl<'a> Drop for IStream<'a> {
    fn drop(&mut self) {
        unsafe { CEXR_IStream_delete(self.handle) };
    }
}

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

pub struct InputFile<'a> {
    handle: *mut CEXR_InputFile,
    _phantom: PhantomData<&'a ()>,
}

impl<'a> InputFile<'a> {
    pub fn from_file(path: &Path) -> Result<InputFile<'static>> {
        let c_path = CString::new(path.to_str()
                                      .expect("non-unicode path handling is unimplemented")
                                      .as_bytes())
                .unwrap();
        let mut error_out = ptr::null();
        let mut out = ptr::null_mut();
        let error =
            unsafe { CEXR_InputFile_from_file(c_path.as_ptr(), 1, &mut out, &mut error_out) };
        if error != 0 {
            let msg = unsafe { CStr::from_ptr(error_out) };
            Err(Error::Generic(msg.to_string_lossy().into_owned()))
        } else {
            Ok(InputFile {
                   handle: out,
                   _phantom: PhantomData,
               })
        }
    }

    pub fn from_stream(stream: &'a IStream) -> Result<InputFile<'a>> {
        let mut error_out = ptr::null();
        let mut out = ptr::null_mut();
        let error =
            unsafe { CEXR_InputFile_from_stream(stream.handle, 1, &mut out, &mut error_out) };
        if error != 0 {
            let msg = unsafe { CStr::from_ptr(error_out) };
            Err(Error::Generic(msg.to_string_lossy().into_owned()))
        } else {
            Ok(InputFile {
                   handle: out,
                   _phantom: PhantomData,
               })
        }
    }

    pub fn read_pixels(&self, framebuffer: &mut FrameBuffer) -> Result<()> {
        let w = self.data_window();
        if (w.max.x - w.min.x) as usize != framebuffer.dimensions.0 - 1 ||
           (w.max.y - w.min.y) as usize != framebuffer.dimensions.1 - 1 {
            panic!("framebuffer size {}x{} does not match input file dimensions {}x{}",
                   framebuffer.dimensions.0,
                   framebuffer.dimensions.1,
                   w.max.x - w.min.x,
                   w.max.y - w.min.y)
        }
        unsafe { CEXR_InputFile_set_framebuffer(self.handle, framebuffer.handle) };
        let mut error_out = ptr::null();
        let error =
            unsafe { CEXR_InputFile_read_pixels(self.handle, w.min.y, w.max.y, &mut error_out) };
        if error != 0 {
            let msg = unsafe { CStr::from_ptr(error_out) };
            Err(Error::Generic(msg.to_string_lossy().into_owned()))
        } else {
            Ok(())
        }
    }

    pub fn data_window(&self) -> &Box2i {
        unsafe { &*CEXR_Header_data_window(CEXR_InputFile_header(self.handle)) }
    }

    pub fn display_window(&self) -> &Box2i {
        unsafe { &*CEXR_Header_display_window(CEXR_InputFile_header(self.handle)) }
    }
}

impl<'a> Drop for InputFile<'a> {
    fn drop(&mut self) {
        unsafe { CEXR_InputFile_delete(self.handle) };
    }
}

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

pub struct OutputFile<'a> {
    handle: *mut CEXR_OutputFile,
    header_handle: *mut CEXR_Header,
    _phantom: PhantomData<&'a ()>,
}

impl<'a> OutputFile<'a> {
    pub fn from_file(path: &Path,
                     resolution: (u32, u32),
                     channels: &[(&str, PixelType)],
                     compression: Compression)
                     -> Result<OutputFile<'static>> {
        // Create header
        let header = {
            let display_window = Box2i {
                min: CEXR_V2i { x: 0, y: 0 },
                max: CEXR_V2i {
                    x: resolution.0 as i32 - 1,
                    y: resolution.1 as i32 - 1,
                },
            };
            let data_window = display_window;
            let pixel_aspect_ratio = 1.0;
            let screen_window_center = CEXR_V2f { x: 0.0, y: 0.0 };
            let screen_window_width = 1.0;
            let line_order = LineOrder::INCREASING_Y;
            let header = unsafe {
                CEXR_Header_new(&display_window,
                                &data_window,
                                pixel_aspect_ratio,
                                &screen_window_center,
                                screen_window_width,
                                line_order,
                                compression)
            };
            for &(name, pixel_type) in channels.iter() {
                let channel_description = CEXR_Channel {
                    pixel_type: pixel_type,
                    x_sampling: 1,
                    y_sampling: 1,
                    p_linear: true,
                };
                let cname = CString::new(name.as_bytes()).unwrap();
                unsafe { CEXR_Header_insert_channel(header, cname.as_ptr(), channel_description) };
            }
            header
        };

        // Create file
        let c_path = CString::new(path.to_str()
                                      .expect("non-unicode path handling is unimplemented")
                                      .as_bytes())
                .unwrap();
        let mut error_out = ptr::null();
        let mut out = ptr::null_mut();
        let error = unsafe {
            CEXR_OutputFile_from_file(c_path.as_ptr(), header, 1, &mut out, &mut error_out)
        };
        if error != 0 {
            let msg = unsafe { CStr::from_ptr(error_out) };
            Err(Error::Generic(msg.to_string_lossy().into_owned()))
        } else {
            Ok(OutputFile {
                   handle: out,
                   header_handle: header,
                   _phantom: PhantomData,
               })
        }
    }

    pub fn write_pixels(&self, framebuffer: &mut FrameBuffer) -> Result<()> {
        let w = self.data_window();
        if (w.max.x - w.min.x) as usize != framebuffer.dimensions.0 - 1 ||
           (w.max.y - w.min.y) as usize != framebuffer.dimensions.1 - 1 {
            panic!("framebuffer size {}x{} does not match output file dimensions {}x{}",
                   framebuffer.dimensions.0,
                   framebuffer.dimensions.1,
                   w.max.x - w.min.x,
                   w.max.y - w.min.y)
        }
        unsafe { CEXR_OutputFile_set_framebuffer(self.handle, framebuffer.handle) };
        let mut error_out = ptr::null();
        let error = unsafe {
            CEXR_OutputFile_write_pixels(self.handle,
                                         framebuffer.dimensions.1 as i32,
                                         &mut error_out)
        };
        if error != 0 {
            let msg = unsafe { CStr::from_ptr(error_out) };
            Err(Error::Generic(msg.to_string_lossy().into_owned()))
        } else {
            Ok(())
        }
    }

    pub fn data_window(&self) -> &Box2i {
        unsafe { &*CEXR_Header_data_window(CEXR_OutputFile_header(self.handle)) }
    }

    pub fn display_window(&self) -> &Box2i {
        unsafe { &*CEXR_Header_display_window(CEXR_OutputFile_header(self.handle)) }
    }
}

impl<'a> Drop for OutputFile<'a> {
    fn drop(&mut self) {
        unsafe { CEXR_OutputFile_delete(self.handle) };
        unsafe { CEXR_Header_delete(self.header_handle) };
    }
}

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

pub struct FrameBuffer<'a> {
    handle: *mut CEXR_FrameBuffer,
    dimensions: (usize, usize),
    _phantom: PhantomData<&'a mut ()>,
}

impl<'a> FrameBuffer<'a> {
    pub fn new(width: usize, height: usize) -> Self {
        FrameBuffer {
            handle: unsafe { CEXR_FrameBuffer_new() },
            dimensions: (width, height),
            _phantom: PhantomData,
        }
    }

    pub unsafe fn insert_raw(&mut self,
                             name: &str,
                             type_: PixelType,
                             base: *mut c_char,
                             stride: (usize, usize),
                             sampling: (c_int, c_int),
                             fill_value: f64,
                             tile_coords: (bool, bool)) {
        let c_name = CString::new(name).unwrap();
        CEXR_FrameBuffer_insert(self.handle,
                                c_name.as_ptr(),
                                type_,
                                base,
                                stride.0,
                                stride.1,
                                sampling.0,
                                sampling.1,
                                fill_value,
                                tile_coords.0 as c_int,
                                tile_coords.1 as c_int);
    }

    pub fn insert_channel<T: ChannelData>(&mut self, name: &str, fill: f64, data: &'a mut [T]) {
        if data.len() != self.dimensions.0 * self.dimensions.1 {
            panic!("data size of {} elements cannot back {}x{} framebuffer",
                   data.len(),
                   self.dimensions.0,
                   self.dimensions.1);
        }
        let width = self.dimensions.0;
        unsafe {
            self.insert_raw(name,
                            T::pixel_type(),
                            data.as_mut_ptr() as *mut c_char,
                            (mem::size_of::<T>(), width * mem::size_of::<T>()),
                            (1, 1),
                            fill,
                            (false, false))
        };
    }

    pub fn insert_pixels<'b, T: PixelStruct>(&mut self,
                                             channels: &[(&'b str, f64)],
                                             data: &'a mut [T]) {
        if data.len() != self.dimensions.0 * self.dimensions.1 {
            panic!("data size of {} elements cannot back {}x{} framebuffer",
                   data.len(),
                   self.dimensions.0,
                   self.dimensions.1);
        }
        let width = self.dimensions.0;
        for (&(name, fill), &(ty, offset)) in channels.iter().zip(T::channels()) {
            unsafe {
                self.insert_raw(name,
                                ty,
                                (data.as_mut_ptr() as *mut c_char).offset(offset as isize),
                                (mem::size_of::<T>(), width * mem::size_of::<T>()),
                                (1, 1),
                                fill,
                                (false, false))
            };
        }
    }
}

impl<'a> Drop for FrameBuffer<'a> {
    fn drop(&mut self) {
        unsafe { CEXR_FrameBuffer_delete(self.handle) };
    }
}
<commit_msg>Cleaning up some lifetime stuff and adding PhantomData for things.<commit_after>extern crate libc;
extern crate openexr_sys;

use std::{mem, ptr, error, fmt};
use std::path::Path;
use std::ffi::{CString, CStr};
use std::marker::PhantomData;

use libc::{c_char, c_int};

use openexr_sys::*;

pub use openexr_sys::CEXR_PixelType as PixelType;
pub use openexr_sys::CEXR_LineOrder as LineOrder;
pub use openexr_sys::CEXR_Compression as Compression;
pub use openexr_sys::CEXR_Box2i as Box2i;

#[derive(Debug, Clone)]
pub enum Error {
    Generic(String),
}

impl error::Error for Error {
    fn description(&self) -> &str {
        use self::Error::*;
        match *self {
            Generic(ref x) => x,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;
        match *self {
            Generic(ref x) => f.pad(x),
        }
    }
}

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

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

/// Types used by OpenEXR to represent a value held by a particular channel at
/// a particular point, suitable for being to directly by the decoder.
pub unsafe trait ChannelData: Copy + Into<f64> {
    fn pixel_type() -> PixelType;
}

unsafe impl ChannelData for u32 {
    fn pixel_type() -> PixelType {
        PixelType::UINT
    }
}

unsafe impl ChannelData for f32 {
    fn pixel_type() -> PixelType {
        PixelType::FLOAT
    }
}

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

/// Types that represent the values of an arbitrary collection of channels at
/// a particular point, suitable for being written to directly by the decoder.
pub unsafe trait PixelStruct: Copy {
    /// Returns an array of the types and byte offsets of the channels in the data
    fn channels() -> &'static [(PixelType, usize)];
}

unsafe impl PixelStruct for (f32, f32) {
    fn channels() -> &'static [(PixelType, usize)] {
        static TYPES: [(PixelType, usize); 2] = [(PixelType::FLOAT, 0), (PixelType::FLOAT, 4)];
        &TYPES
    }
}

unsafe impl PixelStruct for (f32, f32, f32) {
    fn channels() -> &'static [(PixelType, usize)] {
        static TYPES: [(PixelType, usize); 3] = [(PixelType::FLOAT, 0),
                                                 (PixelType::FLOAT, 4),
                                                 (PixelType::FLOAT, 8)];
        &TYPES
    }
}

unsafe impl PixelStruct for (f32, f32, f32, f32) {
    fn channels() -> &'static [(PixelType, usize)] {
        static TYPES: [(PixelType, usize); 4] = [(PixelType::FLOAT, 0),
                                                 (PixelType::FLOAT, 4),
                                                 (PixelType::FLOAT, 8),
                                                 (PixelType::FLOAT, 12)];
        &TYPES
    }
}

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

pub struct IStream<'a> {
    handle: *mut CEXR_IStream,
    _phantom: PhantomData<&'a ()>,
}

impl<'a> IStream<'a> {
    pub fn from_slice<'b>(slice: &'b [u8]) -> IStream<'b> {
        IStream {
            handle: unsafe {
                CEXR_IStream_from_memory(b"in-memory data\0".as_ptr() as *const c_char,
                                         slice.as_ptr() as *mut u8 as *mut c_char,
                                         slice.len())
            },
            _phantom: PhantomData,
        }
    }
}

impl<'a> Drop for IStream<'a> {
    fn drop(&mut self) {
        unsafe { CEXR_IStream_delete(self.handle) };
    }
}

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

pub struct InputFile<'a> {
    handle: *mut CEXR_InputFile,
    _phantom_1: PhantomData<CEXR_InputFile>,
    _phantom_2: PhantomData<&'a IStream<'a>>,
}

impl<'a> InputFile<'a> {
    pub fn from_file(path: &Path) -> Result<InputFile<'static>> {
        let c_path = CString::new(path.to_str()
                                      .expect("non-unicode path handling is unimplemented")
                                      .as_bytes())
                .unwrap();
        let mut error_out = ptr::null();
        let mut out = ptr::null_mut();
        let error =
            unsafe { CEXR_InputFile_from_file(c_path.as_ptr(), 1, &mut out, &mut error_out) };
        if error != 0 {
            let msg = unsafe { CStr::from_ptr(error_out) };
            Err(Error::Generic(msg.to_string_lossy().into_owned()))
        } else {
            Ok(InputFile {
                   handle: out,
                   _phantom_1: PhantomData,
                   _phantom_2: PhantomData,
               })
        }
    }

    pub fn from_stream(stream: &'a IStream) -> Result<InputFile<'a>> {
        let mut error_out = ptr::null();
        let mut out = ptr::null_mut();
        let error =
            unsafe { CEXR_InputFile_from_stream(stream.handle, 1, &mut out, &mut error_out) };
        if error != 0 {
            let msg = unsafe { CStr::from_ptr(error_out) };
            Err(Error::Generic(msg.to_string_lossy().into_owned()))
        } else {
            Ok(InputFile {
                   handle: out,
                   _phantom_1: PhantomData,
                   _phantom_2: PhantomData,
               })
        }
    }

    pub fn read_pixels(&self, framebuffer: &mut FrameBuffer) -> Result<()> {
        let w = self.data_window();
        if (w.max.x - w.min.x) as usize != framebuffer.dimensions.0 - 1 ||
           (w.max.y - w.min.y) as usize != framebuffer.dimensions.1 - 1 {
            panic!("framebuffer size {}x{} does not match input file dimensions {}x{}",
                   framebuffer.dimensions.0,
                   framebuffer.dimensions.1,
                   w.max.x - w.min.x,
                   w.max.y - w.min.y)
        }
        unsafe { CEXR_InputFile_set_framebuffer(self.handle, framebuffer.handle) };
        let mut error_out = ptr::null();
        let error =
            unsafe { CEXR_InputFile_read_pixels(self.handle, w.min.y, w.max.y, &mut error_out) };
        if error != 0 {
            let msg = unsafe { CStr::from_ptr(error_out) };
            Err(Error::Generic(msg.to_string_lossy().into_owned()))
        } else {
            Ok(())
        }
    }

    pub fn data_window(&self) -> &Box2i {
        unsafe { &*CEXR_Header_data_window(CEXR_InputFile_header(self.handle)) }
    }

    pub fn display_window(&self) -> &Box2i {
        unsafe { &*CEXR_Header_display_window(CEXR_InputFile_header(self.handle)) }
    }
}

impl<'a> Drop for InputFile<'a> {
    fn drop(&mut self) {
        unsafe { CEXR_InputFile_delete(self.handle) };
    }
}

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

pub struct OutputFile {
    handle: *mut CEXR_OutputFile,
    header_handle: *mut CEXR_Header,
    _phantom_1: PhantomData<CEXR_OutputFile>,
    _phantom_2: PhantomData<CEXR_Header>,
}

impl OutputFile {
    pub fn from_file(path: &Path,
                     resolution: (u32, u32),
                     channels: &[(&str, PixelType)],
                     compression: Compression)
                     -> Result<OutputFile> {
        // Create header
        let header = {
            let display_window = Box2i {
                min: CEXR_V2i { x: 0, y: 0 },
                max: CEXR_V2i {
                    x: resolution.0 as i32 - 1,
                    y: resolution.1 as i32 - 1,
                },
            };
            let data_window = display_window;
            let pixel_aspect_ratio = 1.0;
            let screen_window_center = CEXR_V2f { x: 0.0, y: 0.0 };
            let screen_window_width = 1.0;
            let line_order = LineOrder::INCREASING_Y;
            let header = unsafe {
                CEXR_Header_new(&display_window,
                                &data_window,
                                pixel_aspect_ratio,
                                &screen_window_center,
                                screen_window_width,
                                line_order,
                                compression)
            };
            for &(name, pixel_type) in channels.iter() {
                let channel_description = CEXR_Channel {
                    pixel_type: pixel_type,
                    x_sampling: 1,
                    y_sampling: 1,
                    p_linear: true,
                };
                let cname = CString::new(name.as_bytes()).unwrap();
                unsafe { CEXR_Header_insert_channel(header, cname.as_ptr(), channel_description) };
            }
            header
        };

        // Create file
        let c_path = CString::new(path.to_str()
                                      .expect("non-unicode path handling is unimplemented")
                                      .as_bytes())
                .unwrap();
        let mut error_out = ptr::null();
        let mut out = ptr::null_mut();
        let error = unsafe {
            CEXR_OutputFile_from_file(c_path.as_ptr(), header, 1, &mut out, &mut error_out)
        };
        if error != 0 {
            let msg = unsafe { CStr::from_ptr(error_out) };
            Err(Error::Generic(msg.to_string_lossy().into_owned()))
        } else {
            Ok(OutputFile {
                   handle: out,
                   header_handle: header,
                   _phantom_1: PhantomData,
                   _phantom_2: PhantomData,
               })
        }
    }

    pub fn write_pixels(&self, framebuffer: &mut FrameBuffer) -> Result<()> {
        let w = self.data_window();
        if (w.max.x - w.min.x) as usize != framebuffer.dimensions.0 - 1 ||
           (w.max.y - w.min.y) as usize != framebuffer.dimensions.1 - 1 {
            panic!("framebuffer size {}x{} does not match output file dimensions {}x{}",
                   framebuffer.dimensions.0,
                   framebuffer.dimensions.1,
                   w.max.x - w.min.x,
                   w.max.y - w.min.y)
        }
        unsafe { CEXR_OutputFile_set_framebuffer(self.handle, framebuffer.handle) };
        let mut error_out = ptr::null();
        let error = unsafe {
            CEXR_OutputFile_write_pixels(self.handle,
                                         framebuffer.dimensions.1 as i32,
                                         &mut error_out)
        };
        if error != 0 {
            let msg = unsafe { CStr::from_ptr(error_out) };
            Err(Error::Generic(msg.to_string_lossy().into_owned()))
        } else {
            Ok(())
        }
    }

    pub fn data_window(&self) -> &Box2i {
        unsafe { &*CEXR_Header_data_window(CEXR_OutputFile_header(self.handle)) }
    }

    pub fn display_window(&self) -> &Box2i {
        unsafe { &*CEXR_Header_display_window(CEXR_OutputFile_header(self.handle)) }
    }
}

impl Drop for OutputFile {
    fn drop(&mut self) {
        unsafe { CEXR_OutputFile_delete(self.handle) };
        unsafe { CEXR_Header_delete(self.header_handle) };
    }
}

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

pub struct FrameBuffer<'a> {
    handle: *mut CEXR_FrameBuffer,
    dimensions: (usize, usize),
    _phantom_1: PhantomData<CEXR_FrameBuffer>,
    _phantom_2: PhantomData<&'a mut ()>,
}

impl<'a> FrameBuffer<'a> {
    pub fn new(width: usize, height: usize) -> Self {
        FrameBuffer {
            handle: unsafe { CEXR_FrameBuffer_new() },
            dimensions: (width, height),
            _phantom_1: PhantomData,
            _phantom_2: PhantomData,
        }
    }

    pub unsafe fn insert_raw(&mut self,
                             name: &str,
                             type_: PixelType,
                             base: *mut c_char,
                             stride: (usize, usize),
                             sampling: (c_int, c_int),
                             fill_value: f64,
                             tile_coords: (bool, bool)) {
        let c_name = CString::new(name).unwrap();
        CEXR_FrameBuffer_insert(self.handle,
                                c_name.as_ptr(),
                                type_,
                                base,
                                stride.0,
                                stride.1,
                                sampling.0,
                                sampling.1,
                                fill_value,
                                tile_coords.0 as c_int,
                                tile_coords.1 as c_int);
    }

    pub fn insert_channel<T: ChannelData>(&mut self, name: &str, fill: f64, data: &'a mut [T]) {
        if data.len() != self.dimensions.0 * self.dimensions.1 {
            panic!("data size of {} elements cannot back {}x{} framebuffer",
                   data.len(),
                   self.dimensions.0,
                   self.dimensions.1);
        }
        let width = self.dimensions.0;
        unsafe {
            self.insert_raw(name,
                            T::pixel_type(),
                            data.as_mut_ptr() as *mut c_char,
                            (mem::size_of::<T>(), width * mem::size_of::<T>()),
                            (1, 1),
                            fill,
                            (false, false))
        };
    }

    pub fn insert_pixels<T: PixelStruct>(&mut self, channels: &[(&str, f64)], data: &'a mut [T]) {
        if data.len() != self.dimensions.0 * self.dimensions.1 {
            panic!("data size of {} elements cannot back {}x{} framebuffer",
                   data.len(),
                   self.dimensions.0,
                   self.dimensions.1);
        }
        let width = self.dimensions.0;
        for (&(name, fill), &(ty, offset)) in channels.iter().zip(T::channels()) {
            unsafe {
                self.insert_raw(name,
                                ty,
                                (data.as_mut_ptr() as *mut c_char).offset(offset as isize),
                                (mem::size_of::<T>(), width * mem::size_of::<T>()),
                                (1, 1),
                                fill,
                                (false, false))
            };
        }
    }
}

impl<'a> Drop for FrameBuffer<'a> {
    fn drop(&mut self) {
        unsafe { CEXR_FrameBuffer_delete(self.handle) };
    }
}
<|endoftext|>


<commit_before>extern crate chrono;
#[macro_use] extern crate log;
extern crate rusqlite;

use rusqlite::Connection;
use rusqlite::types::{ToSql, ToSqlOutput};
use std::fmt;
use std::path::{Path, PathBuf};

#[derive(Debug)]
pub enum Error {
    Io(std::io::Error),
    Sqlite(rusqlite::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::Sqlite(e) => write!(f, "SQLite error: {}", e),
            Error::Io(e) => write!(f, "I/O error: {}", e),
        }
    }
}

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

impl From<rusqlite::Error> for Error {
    fn from(e: rusqlite::Error) -> Error {
        Error::Sqlite(e)
    }
}

impl From<std::io::Error> for Error {
    fn from(e: std::io::Error) -> Error {
        Error::Io(e)
    }
}

#[derive(Debug, PartialEq, Eq)]
pub struct HashDigest([u8; 20]);

impl ToSql for HashDigest {
    fn to_sql(&self) -> Result<ToSqlOutput, rusqlite::Error> {
        unimplemented!()
    }
}

const SCHEMA: &'static str = "
    CREATE TABLE version(
        name VARCHAR(8) NOT NULL,
        version VARCHAR(16) NOT NULL
    );
    INSERT INTO version(name, version) VALUES('rs-sync', '0.1');

    CREATE TABLE files(
        file_id INTEGER NOT NULL PRIMARY KEY,
        name VARCHAR(512) NOT NULL,
        modified DATETIME NOT NULL
    );
    CREATE INDEX idx_files_name ON files(name);

    CREATE TABLE blocks(
        hash VARCHAR(40) NOT NULL,
        file_id INTEGER NOT NULL,
        offset INTEGER NOT NULL,
        PRIMARY KEY(file_id, offset)
    );
    CREATE INDEX idx_blocks_hash ON blocks(hash);
    CREATE INDEX idx_blocks_file ON blocks(file_id);
    CREATE INDEX idx_blocks_file_offset ON blocks(file_id, offset);
";

pub struct Index {
    db: Connection,
}

impl Index {
    pub fn open(filename: &Path) -> Result<Index, Error> {
        let exists = filename.exists();
        let db = Connection::open(filename)?;
        if !exists {
            warn!("Database doesn't exist, creating tables...");
            db.execute_batch(SCHEMA)?;
        }
        Ok(Index { db })
    }

    pub fn add_file(
        &mut self,
        name: &Path,
        modified: chrono::NaiveDateTime,
    ) -> Result<u32, Error>
    {
        let modified = modified.format("%Y-%m-%d %H:%M:%S").to_string();
        let mut stmt = self.db.prepare(
            "
            SELECT file_id FROM files
            WHERE name = ?;
            ",
        )?;
        let mut rows = stmt.query(&[name.to_str().expect("encoding")])?;
        if let Some(row) = rows.next() {
            let file_id: u32 = row?.get(0);
            self.db.execute(
                "
                UPDATE files SET modified = ? WHERE file_id = ?;
                ",
                &[&file_id as &dyn ToSql, &modified],
            )?;
            Ok(file_id)
        } else {
            self.db.execute(
                "
                INSERT INTO files(name, modified)
                VALUES(?, ?);
                ",
                &[name.to_str().expect("encoding"), &modified],
            )?;
            let file_id = self.db.last_insert_rowid();
            Ok(file_id as u32)
        }
    }

    pub fn remove_file(
        &mut self,
        name: &Path,
    ) -> Result<(), Error>
    {
        self.db.execute(
            "
            DELETE FROM blocks WHERE file_id = (
                SELECT file_id FROM files
                WHERE name = ?
            );
            ",
            &[name.to_str().expect("encoding")],
        )?;
        self.db.execute(
            "
            DELETE FROM files WHERE name = ?;
            ",
            &[name.to_str().expect("encoding")],
        )?;
        Ok(())
    }

    pub fn add_block(
        &mut self,
        hash: HashDigest,
        file_id: u32,
        offset: usize,
    ) -> Result<(), Error>
    {
        self.db.execute(
            "
            INSERT INTO blocks(hash, file_id, offset)
            VALUES(?, ?, ?);
            ",
            &[&hash as &dyn ToSql, &file_id, &(offset as i64)],
        )?;
        Ok(())
    }

    pub fn get_block(
        &self,
        hash: HashDigest,
    ) -> Result<Option<(PathBuf, usize)>, Error>
    {
        let mut stmt = self.db.prepare(
            "
            SELECT blocks.file_id, blocks.offset
            FROM blocks
            INNER JOIN files ON blocks.file_id = files.file_id
            WHERE blocks.hash = ?;
            ",
        )?;
        let mut rows = stmt.query(&[&hash as &dyn ToSql])?;
        if let Some(row) = rows.next() {
            let row = row?;
            let path: String = row.get(0);
            let path: PathBuf = path.into();
            let offset: i64 = row.get(1);
            let offset = offset as usize;
            Ok(Some((path, offset)))
        } else {
            Ok(None)
        }
    }
}
<commit_msg>Add doc<commit_after>extern crate chrono;
#[macro_use] extern crate log;
extern crate rusqlite;

use rusqlite::Connection;
use rusqlite::types::{ToSql, ToSqlOutput};
use std::fmt;
use std::path::{Path, PathBuf};

#[derive(Debug)]
pub enum Error {
    Io(std::io::Error),
    Sqlite(rusqlite::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::Sqlite(e) => write!(f, "SQLite error: {}", e),
            Error::Io(e) => write!(f, "I/O error: {}", e),
        }
    }
}

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

impl From<rusqlite::Error> for Error {
    fn from(e: rusqlite::Error) -> Error {
        Error::Sqlite(e)
    }
}

impl From<std::io::Error> for Error {
    fn from(e: std::io::Error) -> Error {
        Error::Io(e)
    }
}

/// Type for the hashes
#[derive(Debug, PartialEq, Eq)]
pub struct HashDigest([u8; 20]);

impl ToSql for HashDigest {
    fn to_sql(&self) -> Result<ToSqlOutput, rusqlite::Error> {
        unimplemented!()
    }
}

const SCHEMA: &'static str = "
    CREATE TABLE version(
        name VARCHAR(8) NOT NULL,
        version VARCHAR(16) NOT NULL
    );
    INSERT INTO version(name, version) VALUES('rs-sync', '0.1');

    CREATE TABLE files(
        file_id INTEGER NOT NULL PRIMARY KEY,
        name VARCHAR(512) NOT NULL,
        modified DATETIME NOT NULL
    );
    CREATE INDEX idx_files_name ON files(name);

    CREATE TABLE blocks(
        hash VARCHAR(40) NOT NULL,
        file_id INTEGER NOT NULL,
        offset INTEGER NOT NULL,
        PRIMARY KEY(file_id, offset)
    );
    CREATE INDEX idx_blocks_hash ON blocks(hash);
    CREATE INDEX idx_blocks_file ON blocks(file_id);
    CREATE INDEX idx_blocks_file_offset ON blocks(file_id, offset);
";

/// Index of files and blocks
pub struct Index {
    db: Connection,
}

impl Index {
    /// Open an index from a file
    pub fn open(filename: &Path) -> Result<Index, Error> {
        let exists = filename.exists();
        let db = Connection::open(filename)?;
        if !exists {
            warn!("Database doesn't exist, creating tables...");
            db.execute_batch(SCHEMA)?;
        }
        Ok(Index { db })
    }

    /// Add a file to the index
    ///
    /// This returns a tuple `(file_id, up_to_date)` where `file_id` can be
    /// used to insert blocks, and `up_to_date` indicates whether the file's
    /// modification date has changed and it should be re-indexed.
    pub fn add_file(
        &mut self,
        name: &Path,
        modified: chrono::NaiveDateTime,
    ) -> Result<u32, Error>
    {
        let modified = modified.format("%Y-%m-%d %H:%M:%S").to_string();
        let mut stmt = self.db.prepare(
            "
            SELECT file_id FROM files
            WHERE name = ?;
            ",
        )?;
        let mut rows = stmt.query(&[name.to_str().expect("encoding")])?;
        if let Some(row) = rows.next() {
            let file_id: u32 = row?.get(0);
            self.db.execute(
                "
                UPDATE files SET modified = ? WHERE file_id = ?;
                ",
                &[&file_id as &dyn ToSql, &modified],
            )?;
            Ok(file_id)
        } else {
            self.db.execute(
                "
                INSERT INTO files(name, modified)
                VALUES(?, ?);
                ",
                &[name.to_str().expect("encoding"), &modified],
            )?;
            let file_id = self.db.last_insert_rowid();
            Ok(file_id as u32)
        }
    }

    /// Remove a file and all its blocks from the index
    pub fn remove_file(
        &mut self,
        name: &Path,
    ) -> Result<(), Error>
    {
        self.db.execute(
            "
            DELETE FROM blocks WHERE file_id = (
                SELECT file_id FROM files
                WHERE name = ?
            );
            ",
            &[name.to_str().expect("encoding")],
        )?;
        self.db.execute(
            "
            DELETE FROM files WHERE name = ?;
            ",
            &[name.to_str().expect("encoding")],
        )?;
        Ok(())
    }

    /// Add a block to the index
    pub fn add_block(
        &mut self,
        hash: HashDigest,
        file_id: u32,
        offset: usize,
    ) -> Result<(), Error>
    {
        self.db.execute(
            "
            INSERT INTO blocks(hash, file_id, offset)
            VALUES(?, ?, ?);
            ",
            &[&hash as &dyn ToSql, &file_id, &(offset as i64)],
        )?;
        Ok(())
    }

    /// Try to find a block in the indexed files
    pub fn get_block(
        &self,
        hash: HashDigest,
    ) -> Result<Option<(PathBuf, usize)>, Error>
    {
        let mut stmt = self.db.prepare(
            "
            SELECT blocks.file_id, blocks.offset
            FROM blocks
            INNER JOIN files ON blocks.file_id = files.file_id
            WHERE blocks.hash = ?;
            ",
        )?;
        let mut rows = stmt.query(&[&hash as &dyn ToSql])?;
        if let Some(row) = rows.next() {
            let row = row?;
            let path: String = row.get(0);
            let path: PathBuf = path.into();
            let offset: i64 = row.get(1);
            let offset = offset as usize;
            Ok(Some((path, offset)))
        } else {
            Ok(None)
        }
    }
}
<|endoftext|>


<commit_before>#![feature(plugin_registrar, box_syntax)]
#![feature(rustc_private, collections)]
#![allow(unused_imports)]

#[macro_use]
extern crate syntax;
#[macro_use]
extern crate rustc;

// Only for the compile time checking of paths
extern crate collections;

use rustc::plugin::Registry;
use rustc::lint::LintPassObject;

#[macro_use]
pub mod utils;
pub mod types;
pub mod misc;
pub mod eq_op;
pub mod bit_mask;
pub mod ptr_arg;
pub mod needless_bool;
pub mod approx_const;
pub mod eta_reduction;
pub mod identity_op;
pub mod mut_mut;
pub mod len_zero;
pub mod attrs;
pub mod collapsible_if;
pub mod unicode;
pub mod strings;
pub mod methods;
pub mod returns;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_lint_pass(box types::TypePass as LintPassObject);
    reg.register_lint_pass(box misc::MiscPass as LintPassObject);
    reg.register_lint_pass(box misc::TopLevelRefPass as LintPassObject);
    reg.register_lint_pass(box misc::CmpNan as LintPassObject);
    reg.register_lint_pass(box eq_op::EqOp as LintPassObject);
    reg.register_lint_pass(box bit_mask::BitMask as LintPassObject);
    reg.register_lint_pass(box ptr_arg::PtrArg as LintPassObject);
    reg.register_lint_pass(box needless_bool::NeedlessBool as LintPassObject);
    reg.register_lint_pass(box approx_const::ApproxConstant as LintPassObject);
    reg.register_lint_pass(box misc::FloatCmp as LintPassObject);
    reg.register_lint_pass(box misc::Precedence as LintPassObject);
    reg.register_lint_pass(box eta_reduction::EtaPass as LintPassObject);
    reg.register_lint_pass(box identity_op::IdentityOp as LintPassObject);
    reg.register_lint_pass(box mut_mut::MutMut as LintPassObject);
    reg.register_lint_pass(box len_zero::LenZero as LintPassObject);
    reg.register_lint_pass(box misc::CmpOwned as LintPassObject);
    reg.register_lint_pass(box attrs::AttrPass as LintPassObject);
    reg.register_lint_pass(box collapsible_if::CollapsibleIf as LintPassObject);
    reg.register_lint_pass(box misc::ModuloOne as LintPassObject);
    reg.register_lint_pass(box unicode::Unicode as LintPassObject);
    reg.register_lint_pass(box strings::StringAdd as LintPassObject);
    reg.register_lint_pass(box returns::ReturnPass as LintPassObject);
    reg.register_lint_pass(box methods::MethodsPass as LintPassObject);

    reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST,
                                           misc::SINGLE_MATCH,
                                           misc::TOPLEVEL_REF_ARG, eq_op::EQ_OP,
                                           bit_mask::BAD_BIT_MASK,
                                           bit_mask::INEFFECTIVE_BIT_MASK,
                                           ptr_arg::PTR_ARG,
                                           needless_bool::NEEDLESS_BOOL,
                                           approx_const::APPROX_CONSTANT,
                                           misc::CMP_NAN, misc::FLOAT_CMP,
                                           misc::PRECEDENCE, misc::CMP_OWNED,
                                           eta_reduction::REDUNDANT_CLOSURE,
                                           identity_op::IDENTITY_OP,
                                           mut_mut::MUT_MUT,
                                           len_zero::LEN_ZERO,
                                           len_zero::LEN_WITHOUT_IS_EMPTY,
                                           attrs::INLINE_ALWAYS,
                                           collapsible_if::COLLAPSIBLE_IF,
                                           unicode::ZERO_WIDTH_SPACE,
                                           strings::STRING_ADD_ASSIGN,
                                           returns::NEEDLESS_RETURN,
                                           misc::MODULO_ONE,
                                           methods::OPTION_UNWRAP_USED,
                                           methods::RESULT_UNWRAP_USED,
                                           methods::STR_TO_STRING,
                                           ]);
}
<commit_msg>added `string_add` to `clippy` lint group<commit_after>#![feature(plugin_registrar, box_syntax)]
#![feature(rustc_private, collections)]
#![allow(unused_imports)]

#[macro_use]
extern crate syntax;
#[macro_use]
extern crate rustc;

// Only for the compile time checking of paths
extern crate collections;

use rustc::plugin::Registry;
use rustc::lint::LintPassObject;

#[macro_use]
pub mod utils;
pub mod types;
pub mod misc;
pub mod eq_op;
pub mod bit_mask;
pub mod ptr_arg;
pub mod needless_bool;
pub mod approx_const;
pub mod eta_reduction;
pub mod identity_op;
pub mod mut_mut;
pub mod len_zero;
pub mod attrs;
pub mod collapsible_if;
pub mod unicode;
pub mod strings;
pub mod methods;
pub mod returns;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_lint_pass(box types::TypePass as LintPassObject);
    reg.register_lint_pass(box misc::MiscPass as LintPassObject);
    reg.register_lint_pass(box misc::TopLevelRefPass as LintPassObject);
    reg.register_lint_pass(box misc::CmpNan as LintPassObject);
    reg.register_lint_pass(box eq_op::EqOp as LintPassObject);
    reg.register_lint_pass(box bit_mask::BitMask as LintPassObject);
    reg.register_lint_pass(box ptr_arg::PtrArg as LintPassObject);
    reg.register_lint_pass(box needless_bool::NeedlessBool as LintPassObject);
    reg.register_lint_pass(box approx_const::ApproxConstant as LintPassObject);
    reg.register_lint_pass(box misc::FloatCmp as LintPassObject);
    reg.register_lint_pass(box misc::Precedence as LintPassObject);
    reg.register_lint_pass(box eta_reduction::EtaPass as LintPassObject);
    reg.register_lint_pass(box identity_op::IdentityOp as LintPassObject);
    reg.register_lint_pass(box mut_mut::MutMut as LintPassObject);
    reg.register_lint_pass(box len_zero::LenZero as LintPassObject);
    reg.register_lint_pass(box misc::CmpOwned as LintPassObject);
    reg.register_lint_pass(box attrs::AttrPass as LintPassObject);
    reg.register_lint_pass(box collapsible_if::CollapsibleIf as LintPassObject);
    reg.register_lint_pass(box misc::ModuloOne as LintPassObject);
    reg.register_lint_pass(box unicode::Unicode as LintPassObject);
    reg.register_lint_pass(box strings::StringAdd as LintPassObject);
    reg.register_lint_pass(box returns::ReturnPass as LintPassObject);
    reg.register_lint_pass(box methods::MethodsPass as LintPassObject);

    reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST,
                                           misc::SINGLE_MATCH,
                                           misc::TOPLEVEL_REF_ARG, eq_op::EQ_OP,
                                           bit_mask::BAD_BIT_MASK,
                                           bit_mask::INEFFECTIVE_BIT_MASK,
                                           ptr_arg::PTR_ARG,
                                           needless_bool::NEEDLESS_BOOL,
                                           approx_const::APPROX_CONSTANT,
                                           misc::CMP_NAN, misc::FLOAT_CMP,
                                           misc::PRECEDENCE, misc::CMP_OWNED,
                                           eta_reduction::REDUNDANT_CLOSURE,
                                           identity_op::IDENTITY_OP,
                                           mut_mut::MUT_MUT,
                                           len_zero::LEN_ZERO,
                                           len_zero::LEN_WITHOUT_IS_EMPTY,
                                           attrs::INLINE_ALWAYS,
                                           collapsible_if::COLLAPSIBLE_IF,
                                           unicode::ZERO_WIDTH_SPACE,
                                           strings::STRING_ADD_ASSIGN,
                                           strings::STRING_ADD,
                                           returns::NEEDLESS_RETURN,
                                           misc::MODULO_ONE,
                                           methods::OPTION_UNWRAP_USED,
                                           methods::RESULT_UNWRAP_USED,
                                           methods::STR_TO_STRING,
                                           ]);
}
<|endoftext|>