<commit_before>//! lzf-rs is a small wrapper around [LibLZF](http://software.schmorp.de/pkg/liblzf.html),
//! a very small data compression library.
//!
//! The compression algorithm is very, very fast, yet still written in portable C.
//!
//! This Rust library is a wrapper around the library from Marc Lehmann.
//!
//! # Basic Operation
//!
//! ```rust,no_run
//! # use lzf;
//! let data = "foobar";
//!
//! let compressed = lzf::compress(data.as_bytes()).unwrap();
//!
//! let decompressed = lzf::decompress(compressed.as_slice(), data.len()).unwrap();
//! ```

#![experimental]

extern crate libc;

use libc::{c_uint,c_void};

extern {
    fn lzf_compress(in_data: *const c_void, in_len: c_uint, out_data: *const c_void, out_len: c_uint) -> c_uint;
    fn lzf_decompress(in_data: *const c_void, in_len: c_uint, out_data: *const c_void, out_len: c_uint) -> c_uint;
}

#[deriving(PartialEq, Eq, Clone, Show)]
pub enum LzfError {
    BufferTooSmall,
    DataCorrupted,
    NoCompressionPossible,
    UnknownError(uint)
}
pub type LzfResult<T> = Result<T, LzfError>;

/// Compress the given data, if possible.
/// The return value will be set to the error if compression fails.
///
/// The buffer is always set to the same size as the input buffer.
/// If that is not enough to hold the lzf-compressed data,
/// an error will be returned.
///
/// Example:
///
/// ```rust
/// let data = "foobar";
/// let compressed = lzf::compress(data.as_bytes());
/// ```
pub fn compress(data: &[u8]) -> LzfResult<Vec<u8>> {
    let data_len = data.len();
    let mut out : Vec<u8> = Vec::with_capacity(data_len);

    let result = unsafe { lzf_compress(data.as_ptr() as *const c_void, data_len as c_uint,
                                       out.as_ptr() as *const c_void, data_len as c_uint) };

    match result {
        0 => Err(LzfError::NoCompressionPossible),
        _ => {
            unsafe { out.set_len(result as uint) };
            Ok(out)
        }
    }
}

/// Decompress the given data, if possible.
/// The return value will be set to the error if compression fails.
///
/// The length of the output buffer can be specified.
/// If the output buffer is not large enough to hold the decompressed data,
/// BufferTooSmall is returned.
/// Otherwise the number of decompressed bytes
/// (i.e. the original length of the data) is returned.
///
/// If an error in the compressed data is detected, DataCorrupted is returned.
///
/// Example:
///
/// ```rust,no_run
/// let data = "[your-compressed-data]";
/// let decompressed = lzf::decompress(data.as_bytes(), 10);
/// ```
pub fn decompress(data: &[u8], out_len: uint) -> LzfResult<Vec<u8>> {
    let mut out : Vec<u8> = Vec::with_capacity(out_len);

    let result = unsafe { lzf_decompress(data.as_ptr() as *const c_void, data.len() as c_uint,
                                         out.as_ptr() as *const c_void, out_len as c_uint) };
    match result {
        0 => {
            match std::os::errno() {
                7  => Err(LzfError::BufferTooSmall),
                22 => Err(LzfError::DataCorrupted),
                e  => Err(LzfError::UnknownError(e))
            }
        },
        _ => {
            unsafe { out.set_len(result as uint) };
            Ok(out)
        }
    }
}

#[test]
fn test_compress_skips_short() {
    match compress("foo".as_bytes()) {
        Ok(_) => panic!("Compression did _something_, with is wrong for 'foo'"),
        Err(err) => assert_eq!(LzfError::NoCompressionPossible, err)
    }
}

#[test]
fn test_compress_lorem() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    match compress(lorem.as_bytes()) {
        Ok(compressed) => {
            assert_eq!(272, compressed.len())
        }
        Err(err) => panic!("Compression failed with error {}", err)
    }
}

#[test]
fn test_compress_decompress_lorem_round() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    let compressed = match compress(lorem.as_bytes()) {
        Ok(c) => c,
        Err(err) => panic!("Compression failed with error {}", err)
    };

    match decompress(compressed.as_slice(), lorem.len()) {
        Ok(decompressed) => {
            assert_eq!(lorem.len(), decompressed.len());
            assert_eq!(lorem.as_bytes(), decompressed.as_slice());
        },
        Err(err) => panic!("Decompression failed with error {}", err)
    };
}

#[test]
fn test_decompress_fails_with_short_buffer() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    let compressed = match compress(lorem.as_bytes()) {
        Ok(c) => c,
        Err(err) => panic!("Compression failed with error {}", err)
    };

    match decompress(compressed.as_slice(), 10) {
        Ok(_) => panic!("Decompression worked. That should not happen"),
        Err(err) => assert_eq!(LzfError::BufferTooSmall, err)
    }
}

#[test]
fn test_decompress_fails_for_corrupted_data() {
    let lorem = "Lorem ipsum dolor sit amet";

    match decompress(lorem.as_bytes(), lorem.len()) {
        Ok(_) => panic!("Decompression worked. That should not happen"),
        Err(err) => assert_eq!(LzfError::DataCorrupted, err)
    }
}
<commit_msg>Derive copy as suggested by latest nightly<commit_after>//! lzf-rs is a small wrapper around [LibLZF](http://software.schmorp.de/pkg/liblzf.html),
//! a very small data compression library.
//!
//! The compression algorithm is very, very fast, yet still written in portable C.
//!
//! This Rust library is a wrapper around the library from Marc Lehmann.
//!
//! # Basic Operation
//!
//! ```rust,no_run
//! # use lzf;
//! let data = "foobar";
//!
//! let compressed = lzf::compress(data.as_bytes()).unwrap();
//!
//! let decompressed = lzf::decompress(compressed.as_slice(), data.len()).unwrap();
//! ```

#![experimental]

extern crate libc;

use libc::{c_uint,c_void};

extern {
    fn lzf_compress(in_data: *const c_void, in_len: c_uint, out_data: *const c_void, out_len: c_uint) -> c_uint;
    fn lzf_decompress(in_data: *const c_void, in_len: c_uint, out_data: *const c_void, out_len: c_uint) -> c_uint;
}

#[derive(PartialEq, Eq, Clone, Show, Copy)]
pub enum LzfError {
    BufferTooSmall,
    DataCorrupted,
    NoCompressionPossible,
    UnknownError(uint)
}
pub type LzfResult<T> = Result<T, LzfError>;

/// Compress the given data, if possible.
/// The return value will be set to the error if compression fails.
///
/// The buffer is always set to the same size as the input buffer.
/// If that is not enough to hold the lzf-compressed data,
/// an error will be returned.
///
/// Example:
///
/// ```rust
/// let data = "foobar";
/// let compressed = lzf::compress(data.as_bytes());
/// ```
pub fn compress(data: &[u8]) -> LzfResult<Vec<u8>> {
    let data_len = data.len();
    let mut out : Vec<u8> = Vec::with_capacity(data_len);

    let result = unsafe { lzf_compress(data.as_ptr() as *const c_void, data_len as c_uint,
                                       out.as_ptr() as *const c_void, data_len as c_uint) };

    match result {
        0 => Err(LzfError::NoCompressionPossible),
        _ => {
            unsafe { out.set_len(result as uint) };
            Ok(out)
        }
    }
}

/// Decompress the given data, if possible.
/// The return value will be set to the error if compression fails.
///
/// The length of the output buffer can be specified.
/// If the output buffer is not large enough to hold the decompressed data,
/// BufferTooSmall is returned.
/// Otherwise the number of decompressed bytes
/// (i.e. the original length of the data) is returned.
///
/// If an error in the compressed data is detected, DataCorrupted is returned.
///
/// Example:
///
/// ```rust,no_run
/// let data = "[your-compressed-data]";
/// let decompressed = lzf::decompress(data.as_bytes(), 10);
/// ```
pub fn decompress(data: &[u8], out_len: uint) -> LzfResult<Vec<u8>> {
    let mut out : Vec<u8> = Vec::with_capacity(out_len);

    let result = unsafe { lzf_decompress(data.as_ptr() as *const c_void, data.len() as c_uint,
                                         out.as_ptr() as *const c_void, out_len as c_uint) };
    match result {
        0 => {
            match std::os::errno() {
                7  => Err(LzfError::BufferTooSmall),
                22 => Err(LzfError::DataCorrupted),
                e  => Err(LzfError::UnknownError(e))
            }
        },
        _ => {
            unsafe { out.set_len(result as uint) };
            Ok(out)
        }
    }
}

#[test]
fn test_compress_skips_short() {
    match compress("foo".as_bytes()) {
        Ok(_) => panic!("Compression did _something_, with is wrong for 'foo'"),
        Err(err) => assert_eq!(LzfError::NoCompressionPossible, err)
    }
}

#[test]
fn test_compress_lorem() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    match compress(lorem.as_bytes()) {
        Ok(compressed) => {
            assert_eq!(272, compressed.len())
        }
        Err(err) => panic!("Compression failed with error {}", err)
    }
}

#[test]
fn test_compress_decompress_lorem_round() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    let compressed = match compress(lorem.as_bytes()) {
        Ok(c) => c,
        Err(err) => panic!("Compression failed with error {}", err)
    };

    match decompress(compressed.as_slice(), lorem.len()) {
        Ok(decompressed) => {
            assert_eq!(lorem.len(), decompressed.len());
            assert_eq!(lorem.as_bytes(), decompressed.as_slice());
        },
        Err(err) => panic!("Decompression failed with error {}", err)
    };
}

#[test]
fn test_decompress_fails_with_short_buffer() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    let compressed = match compress(lorem.as_bytes()) {
        Ok(c) => c,
        Err(err) => panic!("Compression failed with error {}", err)
    };

    match decompress(compressed.as_slice(), 10) {
        Ok(_) => panic!("Decompression worked. That should not happen"),
        Err(err) => assert_eq!(LzfError::BufferTooSmall, err)
    }
}

#[test]
fn test_decompress_fails_for_corrupted_data() {
    let lorem = "Lorem ipsum dolor sit amet";

    match decompress(lorem.as_bytes(), lorem.len()) {
        Ok(_) => panic!("Decompression worked. That should not happen"),
        Err(err) => assert_eq!(LzfError::DataCorrupted, err)
    }
}
<|endoftext|>


<commit_before>mod crypt;

use std::path::Path;

extern crate rustc_serialize;
use rustc_serialize::json;

extern crate uuid;
use uuid::Uuid;

use std::io::prelude::*;
use std::fs::File;

#[derive(RustcDecodable, RustcEncodable)]
struct StorableKey {
    key: Box<[u8]>,
    iv: Box<[u8]>
}

#[derive(RustcDecodable, RustcEncodable)]
struct StorableData {
    ciphertext: Box<Vec<u8>>
}

struct StorableMap {
    external_id: Uuid,
    key_id: Uuid,
    data_id: Uuid
}

pub fn dump(external_id: String, data: Vec<u8>) -> Result<(), &'static str>  {

    let data_path = "/home/andrey/Documents/storages/data".to_string();
    let keys_path = "/home/andrey/Documents/storages/keys".to_string();
    let maps_path = "/home/andrey/Documents/storages/maps".to_string();

    let result = crypt::encrypt(&external_id.into_bytes(), &data);

    let key_id = store_key(keys_path, StorableKey { key: result.key.key, iv: result.key.iv });
    let data_id = store_data(data_path, StorableData { ciphertext: result.ciphertext });
    store_map(maps_path, StorableMap { external_id: Uuid::parse_str(external_id).unwrap(), key_id: key_id, data_id: data_id})
}

fn store_data(path_prefix: String, storable: StorableData) -> Result<Uuid, &'static str> {
    let id = Uuid::new_v4();
    let encoded_storable = json::encode(&storable).unwrap();

    let mut file = File::create(Path::new(&format!("{}/{}.json", path_prefix, id.to_string()))).ok().expect("Cannot create file");
    match file.write_all(encoded_storable.as_bytes()) {
        Ok(_) => id,
        Err(error) => Err("fucked")
    }
}

fn store_key(path_prefix: String, storable: StorableKey) -> Result<Uuid, &'static str> {
    let id = Uuid::new_v4();
    let encoded_storable = json::encode(&storable).unwrap();

    let mut file = File::create(Path::new(&format!("{}/{}.json", path_prefix, id.to_string()))).ok().expect("Cannot create file");
    match file.write_all(encoded_storable.as_bytes()) {
        Ok(_) => id,
        Err(error) => Err("fucked")
    }
}

fn store_map(path_prefix: String, storable: StorableMap) -> Result<(), &'static str> {
    let id = Uuid::new_v4();
    let encoded_storable = json::encode(&storable).unwrap();

    let mut file = File::create(Path::new(&format!("{}/{}.json", path_prefix, id.to_string()))).ok().expect("Cannot create file");
    match file.write_all(encoded_storable.as_bytes()) {
        Ok(_) => id,
        Err(error) => Err("fucked")
    }
}

pub struct LoadResult {
    pub data: Vec<u8>
}

trait FakeLoadResult {
    fn new(data: &'static str) -> Self;
    fn data(&self) -> Vec<u8> { self.data() }
}

impl FakeLoadResult for LoadResult {
    fn new(data: &'static str) -> LoadResult {
        LoadResult { data: data.to_string().into_bytes() }
    }
}

pub fn load(external_id: &String) -> LoadResult {
    LoadResult::new("fakevalue")
}
<commit_msg>Now works like a charm but looks very ugly.<commit_after>mod crypt;

use std::path::Path;

extern crate rustc_serialize;
use rustc_serialize::json;

extern crate uuid;
use uuid::Uuid;

use std::io::prelude::*;
use std::fs::File;

#[derive(RustcDecodable, RustcEncodable)]
struct StorableKey {
    key: Box<[u8]>,
    iv: Box<[u8]>
}

#[derive(RustcDecodable, RustcEncodable)]
struct StorableData {
    ciphertext: Box<Vec<u8>>
}

#[derive(RustcDecodable, RustcEncodable)]
struct StorableMap {
    external_id: Uuid,
    key_id: Uuid,
    data_id: Uuid
}

pub fn dump(external_id: String, data: Vec<u8>) -> Result<(), &'static str>  {

    let data_path = "/home/andrey/Documents/storages/data".to_string();
    let keys_path = "/home/andrey/Documents/storages/keys".to_string();
    let maps_path = "/home/andrey/Documents/storages/maps".to_string();

    let result = crypt::encrypt(external_id.as_bytes(), &data);

    let key_id = store_key(keys_path, StorableKey { key: result.key.key, iv: result.key.iv }).unwrap();
    let data_id = store_data(data_path, StorableData { ciphertext: result.ciphertext }).unwrap();
    store_map(maps_path, StorableMap { external_id: Uuid::parse_str(&external_id).unwrap(), key_id: key_id, data_id: data_id})
}

fn store_data(path_prefix: String, storable: StorableData) -> Result<Uuid, &'static str> {
    let id = Uuid::new_v4();
    let encoded_storable = json::encode(&storable).unwrap();

    let mut file = File::create(Path::new(&format!("{}/{}.json", path_prefix, id.to_string()))).ok().expect("Cannot create file");
    match file.write_all(encoded_storable.as_bytes()) {
        Ok(_) => Ok(id),
        Err(error) => Err("fucked")
    }
}

fn store_key(path_prefix: String, storable: StorableKey) -> Result<Uuid, &'static str> {
    let id = Uuid::new_v4();
    let encoded_storable = json::encode(&storable).unwrap();

    let mut file = File::create(Path::new(&format!("{}/{}.json", path_prefix, id.to_string()))).ok().expect("Cannot create file");
    match file.write_all(encoded_storable.as_bytes()) {
        Ok(_) => Ok(id),
        Err(error) => Err("fucked")
    }
}

fn store_map(path_prefix: String, storable: StorableMap) -> Result<(), &'static str> {
    let id = Uuid::new_v4();
    let encoded_storable = json::encode(&storable).unwrap();

    let mut file = File::create(Path::new(&format!("{}/{}.json", path_prefix, id.to_string()))).ok().expect("Cannot create file");
    match file.write_all(encoded_storable.as_bytes()) {
        Ok(_) => Ok(()),
        Err(error) => Err("fucked")
    }
}

pub struct LoadResult {
    pub data: Vec<u8>
}

trait FakeLoadResult {
    fn new(data: &'static str) -> Self;
    fn data(&self) -> Vec<u8> { self.data() }
}

impl FakeLoadResult for LoadResult {
    fn new(data: &'static str) -> LoadResult {
        LoadResult { data: data.to_string().into_bytes() }
    }
}

pub fn load(external_id: &String) -> LoadResult {
    LoadResult::new("fakevalue")
}
<|endoftext|>


<commit_before>//! Hardware specific implementation for V4L2 cameras
//!
//!

use super::{Camera, CameraConfig, CameraError, CameraType};
pub use rscam::Camera as CameraBackend;
use rscam::Config;
use std::{fs, io::Write};

pub struct VLCamera {
    backend: CameraBackend,
    meta: CameraType,
}

impl VLCamera {
    /// Bind a new camera with a path on the FS
    pub fn new(path: &str, meta: CameraType) -> Result<VLCamera, CameraError> {
        let mut backend = match CameraBackend::new(path) {
            Ok(c) => c,
            Err(e) => {
                return Err(CameraError::ReceiverNotFound(format!(
                    "Failed to allocate '{}': {:?}",
                    path, e
                )))
            }
        };

        backend
            .start(&Config {
                interval: (1, 30), // 30 fps.
                resolution: (1280, 720),
                format: b"MJPG",
                ..Default::default()
            }).unwrap();

        Ok(VLCamera { backend, meta })
    }
}

impl Camera for VLCamera {
    fn auto_config(&mut self, cfg: Option<CameraConfig>) -> Result<(), CameraError> {
        unimplemented!()
    }

    fn capture_image(&self) -> Result<(), CameraError> {
        let frame = self.backend.capture().unwrap();
        let mut file = fs::File::create(&format!("static/img/frame-{}.jpg", self.meta)).unwrap();
        file.write_all(&frame[..]).unwrap();
        Ok(())
    }

    fn capture_video(&self, fps: u32, time: u32) -> Result<(), CameraError> {
        unimplemented!()
    }

    fn start_liveview(&self, fps: u32) -> Result<(), CameraError> {
        unimplemented!()
    }

    fn stop_liveview(&self) -> Result<(), CameraError> {
        unimplemented!()
    }

    fn get_liveview_chunk(&self) {
        unimplemented!()
    }
}
<commit_msg>Adjusting camera resolution<commit_after>//! Hardware specific implementation for V4L2 cameras
//!
//!

use super::{Camera, CameraConfig, CameraError, CameraType};
pub use rscam::Camera as CameraBackend;
use rscam::Config;
use std::{fs, io::Write};

pub struct VLCamera {
    backend: CameraBackend,
    meta: CameraType,
}

impl VLCamera {
    /// Bind a new camera with a path on the FS
    pub fn new(path: &str, meta: CameraType) -> Result<VLCamera, CameraError> {
        let mut backend = match CameraBackend::new(path) {
            Ok(c) => c,
            Err(e) => {
                return Err(CameraError::ReceiverNotFound(format!(
                    "Failed to allocate '{}': {:?}",
                    path, e
                )))
            }
        };

        backend
            .start(&Config {
                interval: (1, 30), // 30 fps.
                resolution: (4224, 3156),
                format: b"MJPG",
                ..Default::default()
            }).unwrap();

        Ok(VLCamera { backend, meta })
    }
}

impl Camera for VLCamera {
    fn auto_config(&mut self, cfg: Option<CameraConfig>) -> Result<(), CameraError> {
        unimplemented!()
    }

    fn capture_image(&self) -> Result<(), CameraError> {
        let frame = self.backend.capture().unwrap();
        let mut file = fs::File::create(&format!("static/img/frame-{}.jpg", self.meta)).unwrap();
        file.write_all(&frame[..]).unwrap();
        Ok(())
    }

    fn capture_video(&self, fps: u32, time: u32) -> Result<(), CameraError> {
        unimplemented!()
    }

    fn start_liveview(&self, fps: u32) -> Result<(), CameraError> {
        unimplemented!()
    }

    fn stop_liveview(&self) -> Result<(), CameraError> {
        unimplemented!()
    }

    fn get_liveview_chunk(&self) {
        unimplemented!()
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]
#![feature(hash)]

//! A library for range addressing

/// A representation of a range
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct Range {
    /// The range offset
    pub offset: usize,
    /// The range length
    pub length: usize
}

impl Range {
    /// Creates a new `Range`
    pub fn new(offset: usize, length: usize) -> Range {
        Range {
            offset: offset,
            length: length,
        }
    }

    /// Creates an empty range with an offset.
    pub fn empty(offset: usize) -> Range {
        Range {
            offset: offset,
            length: 0,
        }
    }

    /// Returns true if range is empty
    pub fn is_empty(&self) -> bool {
        self.length == 0
    }

    /// Returns the next offset
    pub fn next_offset(&self) -> usize {
        self.offset + self.length
    }

    /// Returns a range iterator.
    pub fn iter(&self) -> std::ops::Range<usize> {
        self.offset..self.offset + self.length
    }
}

<commit_msg>Added `shrink` functions<commit_after>#![deny(missing_docs)]
#![feature(hash)]

//! A library for range addressing

/// A representation of a range
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct Range {
    /// The range offset
    pub offset: usize,
    /// The range length
    pub length: usize
}

impl Range {
    /// Creates a new `Range`
    pub fn new(offset: usize, length: usize) -> Range {
        Range {
            offset: offset,
            length: length,
        }
    }

    /// Creates an empty range with an offset.
    pub fn empty(offset: usize) -> Range {
        Range {
            offset: offset,
            length: 0,
        }
    }

    /// Returns true if range is empty
    pub fn is_empty(&self) -> bool {
        self.length == 0
    }

    /// Returns the next offset
    pub fn next_offset(&self) -> usize {
        self.offset + self.length
    }

    /// Returns a range iterator.
    pub fn iter(&self) -> std::ops::Range<usize> {
        self.offset..self.offset + self.length
    }

    /// Shrinks range at both ends with `n` items.
    pub fn shrink_n(&self, n: usize) -> Option<Range> {
        if self.length < 2 * n {
            None
        } else {
            Some(Range::new(self.offset + n, self.length - 2 * n))
        }
    }

    /// Shrinks range at both ends with 1 item.
    pub fn shrink(&self) -> Option<Range> {
        self.shrink_n(1)
    }
}

<|endoftext|>


<commit_before>//! Providing the features between "full" and "derive" of syn.
//!
//! This crate provides the following two unique data structures.
//!
//! * [`syn_mid::ItemFn`] -- A function whose body is not parsed.
//!
//!   ```text
//!   fn process(n: usize) -> Result<()> { ... }
//!   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^     ^
//!   ```
//!
//! * [`syn_mid::Block`] -- A block whose body is not parsed.
//!
//!   ```text
//!   { ... }
//!   ^     ^
//!   ```
//!
//! Other data structures are the same as data structures of [syn]. These are
//! defined in this crate because they cannot be used in [syn] without "full"
//! feature.
//!
//! # Optional features
//!
//! * **`clone-impls`** — Clone impls for all syntax tree types.
//!
//! [`syn_mid::ItemFn`]: ItemFn
//! [`syn_mid::Block`]: Block
//! [syn]: https://github.com/dtolnay/syn

#![doc(test(
    no_crate_inject,
    attr(
        deny(warnings, rust_2018_idioms, single_use_lifetimes),
        allow(dead_code, unused_variables)
    )
))]
#![forbid(unsafe_code)]
#![warn(future_incompatible, rust_2018_idioms, single_use_lifetimes, unreachable_pub)]
#![warn(clippy::default_trait_access, clippy::wildcard_imports)]
#![allow(clippy::eval_order_dependence, clippy::large_enum_variant)]

// Many of the code contained in this crate are copies from https://github.com/dtolnay/syn.

#[macro_use]
mod macros;

mod func;
mod pat;
mod path;

pub use crate::{
    func::{Block, FnArg, ItemFn, Receiver, Signature},
    pat::{
        FieldPat, Pat, PatIdent, PatPath, PatReference, PatStruct, PatTuple, PatTupleStruct,
        PatType, PatWild,
    },
};
<commit_msg>Unify unordered list symbol in markdown<commit_after>//! Providing the features between "full" and "derive" of syn.
//!
//! This crate provides the following two unique data structures.
//!
//! - [`syn_mid::ItemFn`] -- A function whose body is not parsed.
//!
//!   ```text
//!   fn process(n: usize) -> Result<()> { ... }
//!   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^     ^
//!   ```
//!
//! - [`syn_mid::Block`] -- A block whose body is not parsed.
//!
//!   ```text
//!   { ... }
//!   ^     ^
//!   ```
//!
//! Other data structures are the same as data structures of [syn]. These are
//! defined in this crate because they cannot be used in [syn] without "full"
//! feature.
//!
//! # Optional features
//!
//! - **`clone-impls`** — Clone impls for all syntax tree types.
//!
//! [`syn_mid::ItemFn`]: ItemFn
//! [`syn_mid::Block`]: Block
//! [syn]: https://github.com/dtolnay/syn

#![doc(test(
    no_crate_inject,
    attr(
        deny(warnings, rust_2018_idioms, single_use_lifetimes),
        allow(dead_code, unused_variables)
    )
))]
#![forbid(unsafe_code)]
#![warn(future_incompatible, rust_2018_idioms, single_use_lifetimes, unreachable_pub)]
#![warn(clippy::default_trait_access, clippy::wildcard_imports)]
#![allow(clippy::eval_order_dependence, clippy::large_enum_variant)]

// Many of the code contained in this crate are copies from https://github.com/dtolnay/syn.

#[macro_use]
mod macros;

mod func;
mod pat;
mod path;

pub use crate::{
    func::{Block, FnArg, ItemFn, Receiver, Signature},
    pat::{
        FieldPat, Pat, PatIdent, PatPath, PatReference, PatStruct, PatTuple, PatTupleStruct,
        PatType, PatWild,
    },
};
<|endoftext|>


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

extern crate num_traits;

pub mod checkers;
pub mod types;
mod float_impl;

pub mod prelude {
    pub use types::*;

    pub use num_traits::{Float, Num};
    pub use num_traits::cast::{ToPrimitive, NumCast};
    pub use num_traits::identities::{Zero, One};
}

use std::marker::PhantomData;
use std::fmt;
use num_traits::Float;

//FIXME add doc comments
//FIXME proofread rustdocs, make sure the impls from float_impl are included

pub trait FloatChecker<F> {
    fn assert(value: F);
    fn check(value: F) -> bool;
}

pub struct NoisyFloat<F: Float, C: FloatChecker<F>> {
    value: F,
    checker: PhantomData<C>
}

//note: not implementing From<F>, because From conversion is never supposed to fail, according to the docs
impl<F: Float, C: FloatChecker<F>> NoisyFloat<F, C> {
    #[inline]
    pub fn new(value: F) -> NoisyFloat<F, C> {
        C::assert(value);
        Self::unchecked_new(value)
    }

    #[inline]
    fn unchecked_new(value: F) -> NoisyFloat<F, C> {
        NoisyFloat {
            value: value,
            checker: PhantomData
        }
    }

    #[inline]
    pub fn try_new(value: F) -> Option<NoisyFloat<F, C>> {
        if C::check(value) {
            Some(NoisyFloat {
                value: value,
                checker: PhantomData
            })
        } else {
            None
        }
    }

    #[inline]
    pub fn raw(self) -> F {
        self.value
    }
}

impl<C: FloatChecker<f32>> Into<f32> for NoisyFloat<f32, C> {
    #[inline]
    fn into(self) -> f32 {
        self.value
    }
}

impl<C: FloatChecker<f64>> Into<f64> for NoisyFloat<f64, C> {
    #[inline]
    fn into(self) -> f64 {
        self.value
    }
}

impl<F: Float + fmt::Debug, C: FloatChecker<F>> fmt::Debug for NoisyFloat<F, C> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt::Debug::fmt(&self.value, f)
    }
}

impl<F: Float + fmt::Display, C: FloatChecker<F>> fmt::Display for NoisyFloat<F, C> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt::Display::fmt(&self.value, f)
    }
}

impl<F: Float + fmt::LowerExp, C: FloatChecker<F>> fmt::LowerExp for NoisyFloat<F, C> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt::LowerExp::fmt(&self.value, f)
    }
}

impl<F: Float + fmt::UpperExp, C: FloatChecker<F>> fmt::UpperExp for NoisyFloat<F, C> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt::UpperExp::fmt(&self.value, f)
    }
}

#[cfg(test)]
mod tests {
    use prelude::*;
    use std::f32;
    use std::f64::{self, consts};

    #[test]
    fn smoke_test() {
        assert!(n64(1.0) + n64(2.0) == n64(3.0));
        assert!(n64(3.0) != n64(2.9));
        assert!(r64(1.0) < r64(2.0));
        let mut value = n64(18.0);
        value %= n64(5.0);
        assert!(-value == n64(-3.0));
        assert!(R64::one().exp() == r64(consts::E));
        assert!((N64::try_new(1.0).unwrap() / N64::infinity()).is_zero());
        assert!(NumCast::from(f32::INFINITY) == N64::try_new(f64::INFINITY));
        assert!(R64::try_new(f64::NEG_INFINITY) == None);
        assert!(N64::try_new(f64::NAN) == None);
        assert!(R64::try_new(f64::NAN) == None);
    }

    #[test]
    #[should_panic]
    fn n64_nan() {
        n64(0.0) / n64(0.0);
    }

    #[test]
    #[should_panic]
    fn r64_nan() {
        r64(0.0) / r64(0.0);
    }

    #[test]
    #[should_panic]
    fn r64_infinity() {
        r64(1.0) / r64(0.0);
    }
}
<commit_msg>reduced prelude a little<commit_after>// Copyright 2016 Matthew D. Michelotti
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate num_traits;

pub mod checkers;
pub mod types;
mod float_impl;

pub mod prelude {
    pub use types::*;

    pub use num_traits::Float;
    pub use num_traits::cast::{ToPrimitive, NumCast};
}

use std::marker::PhantomData;
use std::fmt;
use num_traits::Float;

//FIXME add doc comments
//FIXME proofread rustdocs, make sure the impls from float_impl are included

pub trait FloatChecker<F> {
    fn assert(value: F);
    fn check(value: F) -> bool;
}

pub struct NoisyFloat<F: Float, C: FloatChecker<F>> {
    value: F,
    checker: PhantomData<C>
}

//note: not implementing From<F>, because From conversion is never supposed to fail, according to the docs
impl<F: Float, C: FloatChecker<F>> NoisyFloat<F, C> {
    #[inline]
    pub fn new(value: F) -> NoisyFloat<F, C> {
        C::assert(value);
        Self::unchecked_new(value)
    }

    #[inline]
    fn unchecked_new(value: F) -> NoisyFloat<F, C> {
        NoisyFloat {
            value: value,
            checker: PhantomData
        }
    }

    #[inline]
    pub fn try_new(value: F) -> Option<NoisyFloat<F, C>> {
        if C::check(value) {
            Some(NoisyFloat {
                value: value,
                checker: PhantomData
            })
        } else {
            None
        }
    }

    #[inline]
    pub fn raw(self) -> F {
        self.value
    }
}

impl<C: FloatChecker<f32>> Into<f32> for NoisyFloat<f32, C> {
    #[inline]
    fn into(self) -> f32 {
        self.value
    }
}

impl<C: FloatChecker<f64>> Into<f64> for NoisyFloat<f64, C> {
    #[inline]
    fn into(self) -> f64 {
        self.value
    }
}

impl<F: Float + fmt::Debug, C: FloatChecker<F>> fmt::Debug for NoisyFloat<F, C> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt::Debug::fmt(&self.value, f)
    }
}

impl<F: Float + fmt::Display, C: FloatChecker<F>> fmt::Display for NoisyFloat<F, C> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt::Display::fmt(&self.value, f)
    }
}

impl<F: Float + fmt::LowerExp, C: FloatChecker<F>> fmt::LowerExp for NoisyFloat<F, C> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt::LowerExp::fmt(&self.value, f)
    }
}

impl<F: Float + fmt::UpperExp, C: FloatChecker<F>> fmt::UpperExp for NoisyFloat<F, C> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt::UpperExp::fmt(&self.value, f)
    }
}

#[cfg(test)]
mod tests {
    use prelude::*;
    use std::f32;
    use std::f64::{self, consts};

    #[test]
    fn smoke_test() {
        assert!(n64(1.0) + n64(2.0) == n64(3.0));
        assert!(n64(3.0) != n64(2.9));
        assert!(r64(1.0) < r64(2.0));
        let mut value = n64(18.0);
        value %= n64(5.0);
        assert!(-value == n64(-3.0));
        assert!(r64(1.0).exp() == r64(consts::E));
        assert!((N64::try_new(1.0).unwrap() / N64::infinity()) == n64(0.0));
        assert!(NumCast::from(f32::INFINITY) == N64::try_new(f64::INFINITY));
        assert!(R64::try_new(f64::NEG_INFINITY) == None);
        assert!(N64::try_new(f64::NAN) == None);
        assert!(R64::try_new(f64::NAN) == None);
    }

    #[test]
    #[should_panic]
    fn n64_nan() {
        n64(0.0) / n64(0.0);
    }

    #[test]
    #[should_panic]
    fn r64_nan() {
        r64(0.0) / r64(0.0);
    }

    #[test]
    #[should_panic]
    fn r64_infinity() {
        r64(1.0) / r64(0.0);
    }
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate notify;
extern crate libloading;
extern crate tempdir;

use libloading::Library;
use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::sync::mpsc::{channel, Receiver, Sender};
use notify::{RecommendedWatcher, Watcher, Event};
use tempdir::TempDir;
use std::time::Duration;
use std::thread;
use std::fs;
use std::env;
use std::fmt::Write;

/// Formats dll name on Windows ("test_foo" -> "test_foo.dll")
#[cfg(target_os="windows")]
fn get_dynamiclib_name(name: &str) -> String {
    format!("{}.dll", name)
}

/// Formats dll name on Mac ("test_foo" -> "libtest_foo.dylib")
#[cfg(target_os="macos")]
fn get_dynamiclib_name(name: &str) -> String {
    format!("lib{}.dylib", name)
}

/// Formats dll name on *nix ("test_foo" -> "libtest_foo.so")
#[cfg(any(target_os="linux",
          target_os="freebsd",
          target_os="dragonfly",
          target_os="netbsd",
          target_os="openbsd"))]
fn get_dynamiclib_name(name: &str) -> String {
    format!("lib{}.so", name)
}

pub struct Lib {
    pub lib: Library,
    pub loaded_path: PathBuf,
    pub original_path: Option<PathBuf>,
}

pub struct DynamicReload {
    _libs: Vec<Lib>,
    _watcher: Option<RecommendedWatcher>,
    shadow_dir: Option<TempDir>,
    search_paths: Vec<&'static str>,
    _watch_recv: Receiver<Event>,
}

pub enum Search {
    Default,
    Backwards,
}

#[derive(PartialEq)]
pub enum UsePlatformName {
    No,
    Yes
}

// Test

impl DynamicReload {

    ///
    ///
    pub fn new(search_paths: Option<Vec<&'static str>>, shadow_dir: Option<&'static str>, _search: Search) -> DynamicReload {
        let (tx, rx) = channel();
        DynamicReload {
            _libs: Vec::new(),
            _watcher: Self::get_watcher(tx),
            shadow_dir: Self::get_temp_dir(shadow_dir),
            _watch_recv: rx,
            search_paths: Self::get_search_paths(search_paths),
        }
    }

    ///
    /// Add a library to be loaded and to be reloaded once updated.
    /// If UsePlatformName is set to Yes the input name will be formatted according
    /// to the standard way libraries looks on that platform examples:
    ///
    /// ```ignore
    /// Windows: foobar -> foobar.dll
    /// Linux:   foobar -> libfoobar.so
    /// Mac:     foobar -> libfoobar.dylib
    /// ````
    ///
    /// If set to no the given inputname will be used as is. This function
    /// will also search for the file in this priority order
    ///
    ///
    /// ```ignore
    /// 1. Current directory
    /// 2. In the search paths (relative to currect directory)
    /// 3. Currect directory of the executable
    /// 4. Serach backwards from executable if Backwards has been set in [new](struct.DynamicReload.html#method.new)
    /// ```
    ///
    pub fn add_library(&mut self, name: &str, name_format: UsePlatformName) -> Result<Rc<Lib>, String> {
        if let Some(path) = Self::search_dirs(self, name, name_format) {
            Self::load_library(self, &path)
        } else {
            let mut t = "Unable to find ".to_string();
            t.push_str(name);
            Err(t)
        }
    }

    ///
    /// Update the will check if a dynamic library needs to be reloaded and if that is the case
    /// then the supplied callback functions will be called
    ///
    /// First the before_reload code. This allows the calling application to performe actions
    /// before the dynamic library is unloaded. This can for example be to save some internal
    /// state that needs to be restorted when relodaded
    ///
    /// After the reloading is comple the post_reload function will be called giving the host
    /// application the possibility to restore any potentially saved state
    ///
    /// If no callbacks are needed use the regular [update](struct.DynamicReload.html#method.update) call instead
    ///
    pub fn update_with_callback<F, T>(&self, _before_update: F, _after_update: F, _data: T) where F : Fn(T, Rc<Lib>) {

    }

    ///
    /// Updates the DynamicReload handler and reloads the dynamic libraries if needed
    ///
    ///
    pub fn update(&self) {
        /*
           match self.watch_recv.try_recv() {
           Ok(file) => {
           plugin_handler.reload_plugin(file.path.as_ref().unwrap());
           }
           _ => (),
           }
           */
    }

    fn load_library(&mut self, full_path: &PathBuf) -> Result<Rc<Lib>, String> {
        let path;
        let original_path;

        if let Some(sd) = self.shadow_dir.as_ref() {
            path = sd.path().join(full_path.file_name().unwrap());
            if !Self::try_copy(&full_path, &path) {
                let mut error = "".to_string();
                write!(error, "Unable to copy {:?} to {:?}", full_path, path).unwrap();
                return Err(error);
            }
            original_path = Some(full_path.clone());
        } else {
            original_path = None;
            path = full_path.clone();
        }

        Self::init_library(original_path, path)
    }

    fn init_library(org_path: Option<PathBuf>, path: PathBuf) -> Result<Rc<Lib>, String> {
        match Library::new(&path) {
            Ok(l) => Ok(Rc::new(Lib {
                original_path: org_path,
                loaded_path: path,
                lib: l
            })),
            Err(e) => {
                let mut error = "".to_string();
                write!(error, "Unable to load library {:?}", e).unwrap();
                Err(error)
            }
        }
    }

    fn search_dirs(&self, name: &str, name_format: UsePlatformName) -> Option<PathBuf> {
        let lib_name = Self::get_library_name(name, name_format);

        // 1. Serach the current directory
        if let Some(path) = Self::search_current_dir(&lib_name) {
            return Some(path);
        }

        // 2. search the relative paths
        if let Some(path) = Self::search_relative_paths(self, &lib_name) {
            return Some(path);
        }

        // 3. searches in the executable dir and then backwards
        Self::search_backwards_from_exe(&lib_name)
    }

    fn search_current_dir(name: &String) -> Option<PathBuf> {
        Self::is_file(&Path::new(name).to_path_buf())
    }

    fn search_relative_paths(&self, name: &String) -> Option<PathBuf> {
        for p in self.search_paths.iter() {
            let path = Path::new(p).join(name);
            if let Some(file) = Self::is_file(&path) {
                return Some(file);
            }
        }

        None
    }

    fn get_parent_dir(path: &PathBuf) -> Option<PathBuf> {
        match path.parent() {
            Some(p) => Some(p.to_path_buf()),
            _ => None,
        }
    }

    fn search_backwards_from_file(path: &PathBuf, lib_name: &String) -> Option<PathBuf> {
        match Self::get_parent_dir(path) {
            Some(p) => {
                let new_path = Path::new(&p).join(lib_name);
                if Self::is_file(&new_path).is_some() {
                    return Some(new_path);
                }
                Self::search_backwards_from_file(&p, lib_name)
            },
            _ => None,
        }
    }

    fn search_backwards_from_exe(lib_name: &String) -> Option<PathBuf> {
        let exe_path = env::current_exe().unwrap_or(PathBuf::new());
        Self::search_backwards_from_file(&exe_path, lib_name)
    }

    fn get_temp_dir(shadow_dir: Option<&str>) -> Option<TempDir> {
        match shadow_dir {
            Some(dir) => {
                match TempDir::new_in(dir, "shadow_libs") {
                    Ok(td) => Some(td),
                    Err(er) => {
                        println!("Unable to create tempdir {}", er);
                        None
                    }
                }
            }
            _ => None,
        }
    }

    fn is_file(path: &PathBuf) -> Option<PathBuf> {
        match fs::metadata(path) {
            Ok(md) => {
                if md.is_file() {
                    Some(path.clone())
                } else {
                    None
                }
            }
            _ => None,
        }
    }

    //
    // In some cases when a file has been set that it's reloaded it's actually not possible
    // to read from it directly so this code does some testing first to ensure we
    // can actually read from it (by using metadata which does a stat on the file)
    // If we can't read from it we wait for 100 ms before we try again, if we can't
    // do it with in 1 sec we give up
    //
    fn try_copy(src: &Path, dest: &Path) -> bool {
        for _ in 0..10 {
            match fs::metadata(src) {
                Ok(file) => {
                    let len = file.len();
                    if len > 0 {
                        fs::copy(&src, &dest).unwrap();
                        //println!("Copy from {} {}", src.to_str().unwrap(), dest.to_str().unwrap());
                        return true;
                    }
                }
                _ => (),
            }

            thread::sleep(Duration::from_millis(100));
        }

        false
    }

    fn get_watcher(tx: Sender<Event>) -> Option<RecommendedWatcher> {
        match Watcher::new(tx) {
            Ok(watcher) => Some(watcher),
            Err(e) => {
                println!("Unable to create file watcher, no dynamic reloading will be done, error: {:?}", e);
                None
            }
        }
    }

    pub fn get_search_paths(search_paths: Option<Vec<&'static str>>) -> Vec<&'static str> {
        match search_paths {
            Some(paths) => {
                paths.clone()
            },
            None => Vec::new(),
        }
    }

    fn get_library_name(name: &str, name_format: UsePlatformName) -> String {
        if name_format == UsePlatformName::Yes  {
            get_dynamiclib_name(name)
        } else {
            name.to_string()
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::sync::mpsc::channel;
    use std::path::Path;
    use std::env;

    #[test]
    fn test_search_paths_none() {
        assert_eq!(DynamicReload::get_search_paths(None).len(), 0);
    }

    #[test]
    fn test_search_paths_some() {
        assert_eq!(DynamicReload::get_search_paths(Some(vec!["test", "test"])).len(), 2);
    }

    #[test]
    fn test_get_watcher() {
        let (tx, _) = channel();
        // We expect this to always work
        assert!(DynamicReload::get_watcher(tx).is_some());
    }

    #[test]
    fn test_get_temp_dir_fail() {
        assert!(DynamicReload::get_temp_dir(Some("_no_such_dir")).is_none());
    }

    #[test]
    fn test_get_temp_dir_none() {
        assert!(DynamicReload::get_temp_dir(None).is_none());
    }

    #[test]
    fn test_get_temp_dir_ok() {
        assert!(DynamicReload::get_temp_dir(Some("")).is_some());
    }

    #[test]
    fn test_is_file_fail() {
        assert!(DynamicReload::is_file(&Path::new("haz_no_file_with_this_name").to_path_buf()).is_none());
    }

    #[test]
    fn test_is_file_ok() {
        assert!(DynamicReload::is_file(&env::current_exe().unwrap()).is_some());
    }

    #[test]
    #[cfg(target_os="macos")]
    fn test_get_library_name_mac() {
        assert_eq!(DynamicReload::get_library_name("foobar", UsePlatformName::Yes), "libfoobar.dylib");
    }

    #[test]
    fn test_get_library_name() {
        assert_eq!(DynamicReload::get_library_name("foobar", UsePlatformName::No), "foobar");
    }

    #[test]
    fn test_search_backwards_from_file_ok() {
        // While this rely on that we have a Cargo project it should be fine
        assert!(DynamicReload::search_backwards_from_exe(&"Cargo.toml".to_string()).is_some());
    }

    #[test]
    fn test_search_backwards_from_file_fail() {
        assert!(DynamicReload::search_backwards_from_exe(&"_no_such_file".to_string()).is_none());
    }
}
<commit_msg>WIP - Doesn't compile<commit_after>extern crate libc;
extern crate notify;
extern crate libloading;
extern crate tempdir;

use libloading::Library;
use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::sync::mpsc::{channel, Receiver, Sender};
use notify::{RecommendedWatcher, Watcher, Event};
use tempdir::TempDir;
use std::time::Duration;
use std::thread;
use std::fs;
use std::env;
use std::fmt::Write;

/// Formats dll name on Windows ("test_foo" -> "test_foo.dll")
#[cfg(target_os="windows")]
fn get_dynamiclib_name(name: &str) -> String {
    format!("{}.dll", name)
}

/// Formats dll name on Mac ("test_foo" -> "libtest_foo.dylib")
#[cfg(target_os="macos")]
fn get_dynamiclib_name(name: &str) -> String {
    format!("lib{}.dylib", name)
}

/// Formats dll name on *nix ("test_foo" -> "libtest_foo.so")
#[cfg(any(target_os="linux",
          target_os="freebsd",
          target_os="dragonfly",
          target_os="netbsd",
          target_os="openbsd"))]
fn get_dynamiclib_name(name: &str) -> String {
    format!("lib{}.so", name)
}

pub struct Lib {
    pub lib: Library,
    pub loaded_path: PathBuf,
    pub original_path: Option<PathBuf>,
}

pub struct DynamicReload {
    libs: Vec<Rc<Lib>>,
    watcher: Option<RecommendedWatcher>,
    shadow_dir: Option<TempDir>,
    search_paths: Vec<&'static str>,
    watch_recv: Receiver<Event>,
}

pub enum Search {
    Default,
    Backwards,
}

#[derive(PartialEq)]
pub enum UsePlatformName {
    No,
    Yes
}

// Test

impl DynamicReload {

    ///
    ///
    pub fn new(search_paths: Option<Vec<&'static str>>, shadow_dir: Option<&'static str>, _search: Search) -> DynamicReload {
        let (tx, rx) = channel();
        DynamicReload {
            libs: Vec::new(),
            watcher: Self::get_watcher(tx),
            shadow_dir: Self::get_temp_dir(shadow_dir),
            watch_recv: rx,
            search_paths: Self::get_search_paths(search_paths),
        }
    }

    ///
    /// Add a library to be loaded and to be reloaded once updated.
    /// If UsePlatformName is set to Yes the input name will be formatted according
    /// to the standard way libraries looks on that platform examples:
    ///
    /// ```ignore
    /// Windows: foobar -> foobar.dll
    /// Linux:   foobar -> libfoobar.so
    /// Mac:     foobar -> libfoobar.dylib
    /// ````
    ///
    /// If set to no the given inputname will be used as is. This function
    /// will also search for the file in this priority order
    ///
    ///
    /// ```ignore
    /// 1. Current directory
    /// 2. In the search paths (relative to currect directory)
    /// 3. Currect directory of the executable
    /// 4. Serach backwards from executable if Backwards has been set in [new](struct.DynamicReload.html#method.new)
    /// ```
    ///
    pub fn add_library(&mut self, name: &str, name_format: UsePlatformName) -> Result<Rc<Lib>, String> {
        match Self::try_load_library(self, name, name_format) {
            Ok(lib) => {
                if let Some(w) = self.watcher.as_mut() {
                    if let Some(path) = lib.original_path.as_ref() {
                        let _ = w.watch(path);
                    }
                }
                // Bump the ref here as we keep one around to keep track of files that needs to be reloaded
                self.libs.push(lib.clone());
                Ok(lib)
            }
            Err(e) => Err(e),
        }
    }

    ///
    /// Update the will check if a dynamic library needs to be reloaded and if that is the case
    /// then the supplied callback functions will be called
    ///
    /// First the before_reload code. This allows the calling application to performe actions
    /// before the dynamic library is unloaded. This can for example be to save some internal
    /// state that needs to be restorted when relodaded
    ///
    /// After the reloading is comple the post_reload function will be called giving the host
    /// application the possibility to restore any potentially saved state
    ///
    /// If no callbacks are needed use the regular [update](struct.DynamicReload.html#method.update) call instead
    ///
    pub fn update_with_callback<F, T>(&mut self, before_update: F, after_update: F, data: T) where F : Fn(T, &Rc<Lib>) {
        match self.watch_recv.try_recv() {
            Ok(file) => Self::reload_libs(self, file.path.as_ref().unwrap(), before_update, after_update, data),
            _ => (),
        }
    }

    ///
    /// Updates the DynamicReload handler and reloads the dynamic libraries if needed
    ///
    ///
    pub fn update(&self) {
    }

    fn reload_libs<F, T>(&mut self, file_path: &PathBuf, before_update: F, after_update: F, data: T) where F : Fn(T, &Rc<Lib>) {
        let len = self.libs.len();
        for i in (0..len).rev() {
            if Self::should_reload(file_path, &self.libs[i]) {
                Self::reload_lib(self, i, file_path, before_update, after_update, data);
            }
        }
    }

    fn reload_lib<F, T>(&mut self, index: usize, file_path: &PathBuf, before_update: F, after_update: F, data: T)
        where F : Fn(T, &Rc<Lib>) {
        before_update(data, &self.libs[index]);
        self.libs.swap_remove(index);

        match Self::load_library(self, file_path) {
            Ok(lib) => {
                self.libs.push(lib.clone());
                after_update(data, &lib);
            }

            // What should we really do here?
            Err(err) => {
                println!("Unable to reload lib {:?} err {:?}", file_path, err);
            }
        }
    }

    fn try_load_library(&self, name: &str, name_format: UsePlatformName) -> Result<Rc<Lib>, String> {
        if let Some(path) = Self::search_dirs(self, name, name_format) {
            Self::load_library(self, &path)
        } else {
            let mut t = "Unable to find ".to_string();
            t.push_str(name);
            Err(t)
        }
    }

    fn load_library(&self, full_path: &PathBuf) -> Result<Rc<Lib>, String> {
        let path;
        let original_path;

        if let Some(sd) = self.shadow_dir.as_ref() {
            path = sd.path().join(full_path.file_name().unwrap());
            if !Self::try_copy(&full_path, &path) {
                let mut error = "".to_string();
                write!(error, "Unable to copy {:?} to {:?}", full_path, path).unwrap();
                return Err(error);
            }
            original_path = Some(full_path.clone());
        } else {
            original_path = None;
            path = full_path.clone();
        }

        Self::init_library(original_path, path)
    }

    fn init_library(org_path: Option<PathBuf>, path: PathBuf) -> Result<Rc<Lib>, String> {
        match Library::new(&path) {
            Ok(l) => Ok(Rc::new(Lib {
                original_path: org_path,
                loaded_path: path,
                lib: l
            })),
            Err(e) => {
                let mut error = "".to_string();
                write!(error, "Unable to load library {:?}", e).unwrap();
                Err(error)
            }
        }
    }

    fn should_reload(reload_path: &PathBuf, lib: &Lib) -> bool {
        if let Some(p) = lib.original_path.as_ref() {
            if reload_path.to_str().unwrap().contains(p.to_str().unwrap()) {
                return true;
            }
        }

        false
    }

    fn remove_library(&mut self, path: &PathBuf) {

    }

    fn search_dirs(&self, name: &str, name_format: UsePlatformName) -> Option<PathBuf> {
        let lib_name = Self::get_library_name(name, name_format);

        // 1. Serach the current directory
        if let Some(path) = Self::search_current_dir(&lib_name) {
            return Some(path);
        }

        // 2. search the relative paths
        if let Some(path) = Self::search_relative_paths(self, &lib_name) {
            return Some(path);
        }

        // 3. searches in the executable dir and then backwards
        Self::search_backwards_from_exe(&lib_name)
    }

    fn search_current_dir(name: &String) -> Option<PathBuf> {
        Self::is_file(&Path::new(name).to_path_buf())
    }

    fn search_relative_paths(&self, name: &String) -> Option<PathBuf> {
        for p in self.search_paths.iter() {
            let path = Path::new(p).join(name);
            if let Some(file) = Self::is_file(&path) {
                return Some(file);
            }
        }

        None
    }

    fn get_parent_dir(path: &PathBuf) -> Option<PathBuf> {
        match path.parent() {
            Some(p) => Some(p.to_path_buf()),
            _ => None,
        }
    }

    fn search_backwards_from_file(path: &PathBuf, lib_name: &String) -> Option<PathBuf> {
        match Self::get_parent_dir(path) {
            Some(p) => {
                let new_path = Path::new(&p).join(lib_name);
                if Self::is_file(&new_path).is_some() {
                    return Some(new_path);
                }
                Self::search_backwards_from_file(&p, lib_name)
            },
            _ => None,
        }
    }

    fn search_backwards_from_exe(lib_name: &String) -> Option<PathBuf> {
        let exe_path = env::current_exe().unwrap_or(PathBuf::new());
        Self::search_backwards_from_file(&exe_path, lib_name)
    }

    fn get_temp_dir(shadow_dir: Option<&str>) -> Option<TempDir> {
        match shadow_dir {
            Some(dir) => {
                match TempDir::new_in(dir, "shadow_libs") {
                    Ok(td) => Some(td),
                    Err(er) => {
                        println!("Unable to create tempdir {}", er);
                        None
                    }
                }
            }
            _ => None,
        }
    }

    fn is_file(path: &PathBuf) -> Option<PathBuf> {
        match fs::metadata(path) {
            Ok(md) => {
                if md.is_file() {
                    Some(path.clone())
                } else {
                    None
                }
            }
            _ => None,
        }
    }

    //
    // In some cases when a file has been set that it's reloaded it's actually not possible
    // to read from it directly so this code does some testing first to ensure we
    // can actually read from it (by using metadata which does a stat on the file)
    // If we can't read from it we wait for 100 ms before we try again, if we can't
    // do it with in 1 sec we give up
    //
    fn try_copy(src: &Path, dest: &Path) -> bool {
        for _ in 0..10 {
            match fs::metadata(src) {
                Ok(file) => {
                    let len = file.len();
                    if len > 0 {
                        fs::copy(&src, &dest).unwrap();
                        //println!("Copy from {} {}", src.to_str().unwrap(), dest.to_str().unwrap());
                        return true;
                    }
                }
                _ => (),
            }

            thread::sleep(Duration::from_millis(100));
        }

        false
    }

    fn get_watcher(tx: Sender<Event>) -> Option<RecommendedWatcher> {
        match Watcher::new(tx) {
            Ok(watcher) => Some(watcher),
            Err(e) => {
                println!("Unable to create file watcher, no dynamic reloading will be done, error: {:?}", e);
                None
            }
        }
    }

    pub fn get_search_paths(search_paths: Option<Vec<&'static str>>) -> Vec<&'static str> {
        match search_paths {
            Some(paths) => {
                paths.clone()
            },
            None => Vec::new(),
        }
    }

    fn get_library_name(name: &str, name_format: UsePlatformName) -> String {
        if name_format == UsePlatformName::Yes  {
            get_dynamiclib_name(name)
        } else {
            name.to_string()
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::sync::mpsc::channel;
    use std::path::Path;
    use std::env;

    #[test]
    fn test_search_paths_none() {
        assert_eq!(DynamicReload::get_search_paths(None).len(), 0);
    }

    #[test]
    fn test_search_paths_some() {
        assert_eq!(DynamicReload::get_search_paths(Some(vec!["test", "test"])).len(), 2);
    }

    #[test]
    fn test_get_watcher() {
        let (tx, _) = channel();
        // We expect this to always work
        assert!(DynamicReload::get_watcher(tx).is_some());
    }

    #[test]
    fn test_get_temp_dir_fail() {
        assert!(DynamicReload::get_temp_dir(Some("_no_such_dir")).is_none());
    }

    #[test]
    fn test_get_temp_dir_none() {
        assert!(DynamicReload::get_temp_dir(None).is_none());
    }

    #[test]
    fn test_get_temp_dir_ok() {
        assert!(DynamicReload::get_temp_dir(Some("")).is_some());
    }

    #[test]
    fn test_is_file_fail() {
        assert!(DynamicReload::is_file(&Path::new("haz_no_file_with_this_name").to_path_buf()).is_none());
    }

    #[test]
    fn test_is_file_ok() {
        assert!(DynamicReload::is_file(&env::current_exe().unwrap()).is_some());
    }

    #[test]
    #[cfg(target_os="macos")]
    fn test_get_library_name_mac() {
        assert_eq!(DynamicReload::get_library_name("foobar", UsePlatformName::Yes), "libfoobar.dylib");
    }

    #[test]
    fn test_get_library_name() {
        assert_eq!(DynamicReload::get_library_name("foobar", UsePlatformName::No), "foobar");
    }

    #[test]
    fn test_search_backwards_from_file_ok() {
        // While this rely on that we have a Cargo project it should be fine
        assert!(DynamicReload::search_backwards_from_exe(&"Cargo.toml".to_string()).is_some());
    }

    #[test]
    fn test_search_backwards_from_file_fail() {
        assert!(DynamicReload::search_backwards_from_exe(&"_no_such_file".to_string()).is_none());
    }
}
<|endoftext|>


<commit_before>//! Implementation of a basic linear space trait.
//!
//! The main interface is `Lin` with an implementation for a vector of real
//! numbers: `Rn<F>`.
//!
//! ```rust
//! use linear_space::lin::{Lin,Rn};
//!
//! let x = Rn::new(vec![1.,2.]);
//! let y = Rn::new(vec![2.,-3.]);
//!
//! assert_eq!(x.dot(&y), -4.);
//! assert_eq!(Rn::new(vec![3., -1.]), x.clone() + y);
//! assert_eq!(Rn::new(vec![2., 4.]), x * 2.);
//! ```
use num::{Zero, One, Float};
use std::ops::{Add, Mul, Deref, DerefMut};
use std::iter::repeat;

/// Trait defining basic operations for an element of a linear space.
///
/// The focus is on operations _in place_: methods that return a `Lin` object
/// modify the object in place.
pub trait Lin {
    /// Scalars for this linear space.
    type F: Float;

    /// Dot product (inner product).
    fn dot(&self, other: &Self) -> Self::F;

    /// Multiplication by a constant.
    fn scale(&mut self, a: Self::F) -> &mut Self;

    /// Adds a vector multiplied by a constant to this vector.
    fn ray_to(&mut self, other: &Self, t: Self::F) -> &mut Self;

    /// Return the origin of the vector space to which self belongs too.
    fn origin(&self) -> Self;

    /// Norm of the vector.
    fn norm(&self) -> Self::F {
        self.norm_squared().sqrt()
    }

    /// Square of the norm.
    fn norm_squared(&self) -> Self::F {
        self.dot(self)
    }

    /// Scale the vector so that it has a norm one.
    ///
    /// If norm is zero, causes division by zero.
    fn normalize(&mut self) -> &mut Self {
        let norm = self.norm();
        self.scale(Self::F::one() / norm)
    }

    /// Distance between two vectors.
    ///
    /// Default implementation uses
    /// `|x - v| = sqrt(x.x - 2 x.y + y.y)`
    /// to avoid copying.
    /// Therefore it is recommended to reimplement this method.
    fn dist(&self, other: &Self) -> Self::F {
        (self.norm_squared() + other.norm_squared()
            - (Self::F::one() + Self::F::one()) * self.dot(other)).sqrt()
    }

    /// Adds a vector to this vector.
    fn add_mut(&mut self, other: &Self) -> &mut Self {
        self.ray_to(other, Self::F::one())
    }

    /// Creates a linear combination.
    fn combine(&mut self,  a: Self::F, other: &Self, b: Self::F) -> &mut Self {
        self.scale(a).ray_to(other,b)
    }

    /// Project on a line given by a given direction.
    ///
    /// `dir` does not have to be normalized, but must be nonzero.
    fn project_on(&mut self, dir: &Self) -> &mut Self {
        let a = self.dot(dir) / dir.norm_squared();
        self.combine(Self::F::zero(), dir, a)
    }

    /// Project on a plane orthogonal to the given direction.
    ///
    /// `dir` does not have to be normalized, but must be nonzero.
    fn project_ortho(&mut self, dir: &Self) -> &mut Self {
        let a = self.dot(dir) / dir.norm_squared();
        self.combine(Self::F::one(), dir, -a)
    }
}

/// An implementation of the Lin trait: an n-dimensional real vector.
///
/// Backed by a `Vec<F>`, where `F` is `Float`.
#[derive(Clone,Debug,PartialEq)]
pub struct Rn<F: Float> {
    vec: Vec<F>,
}

impl<F: Float> Rn<F> {
    pub fn new(v: Vec<F>) -> Self {
        Rn {vec: v}
    }
}

impl<F: Float> Deref for Rn<F> {
    type Target = Vec<F>;

    fn deref<'a>(&'a self) -> &'a Vec<F> {
        &self.vec
    }
}

impl<F: Float> DerefMut for Rn<F> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut Vec<F> {
        &mut self.vec
    }
}

impl<F: Float> Mul<F> for Rn<F> {
    type Output = Rn<F>;

    fn mul(mut self, other: F) -> Self {
        self.scale(other);
        self
    }
}

impl<F: Float> Add for Rn<F> {
    type Output = Rn<F>;

    fn add(mut self, other: Self) -> Self {
        self.add_mut(&other);
        self
    }
}

impl<F: Float> Lin for Rn<F> {
    type F = F;

    fn dist(&self, other: &Self) -> Self::F {
        assert_eq!(self.len(), other.len());
        self.iter().zip(other.iter())
            .fold(Self::F::zero(),
                |sum, (&x, &y)| sum + (x - y).powi(2))
            .sqrt()
    }

    fn dot(&self, other: &Self) -> Self::F {
        assert_eq!(self.len(), other.len());
        self.iter().zip(other.iter())
            .fold(Self::F::zero(), |sum, (&x, &y)| sum + x * y)
    }

    fn scale(&mut self, a: Self::F) -> &mut Self {
        for x in self.iter_mut() {
            *x = *x * a;
        }
        self
    }

    fn combine(&mut self,  a: Self::F, other: &Self, b: Self::F) -> &mut Self {
        assert_eq!(self.len(), other.len());
        for (x, y) in self.iter_mut().zip(other.iter()) {
            *x = *x * a + *y * b;
        }
        self
    }

    fn ray_to(&mut self,  other: &Self, b: Self::F) -> &mut Self {
        assert_eq!(self.len(), other.len());
        for (x, y) in self.iter_mut().zip(other.iter()) {
            *x = *x + *y * b;
        }
        self
    }

    fn origin(&self) -> Self {
        Rn::new(repeat(Self::F::zero()).take(self.len()).collect())
    }
}

// Trivial implementation of `Lin` for any `num::Float` as an element of a
// linear space over scalars `num::Float`.
impl<F: Float> Lin for F {
    type F = F;

    fn dot(&self, other: &Self) -> Self::F {
        *self * *other
    }

    fn scale(&mut self, a: Self::F) -> &mut Self {
        *self = *self * a;
        self
    }

    fn combine(&mut self,  a: Self::F, other: &Self, b: Self::F) -> &mut Self {
        *self = *self * a + *other * b;
        self
    }

    fn ray_to(&mut self,  other: &Self, b: Self::F) -> &mut Self {
        *self = *self + *other * b;
        self
    }

    fn origin(&self) -> Self {
        F::zero()
    }

    fn dist(&self, other: &Self) -> Self::F {
        (*self - *other).abs()
    }

    fn norm(&self) -> Self::F {
        self.abs()
    }
}

#[cfg(test)]
mod test {
    extern crate quickcheck;

    use super::Lin;
    use super::Rn;
    use std::cmp::min;
    use num::Float;
    use self::quickcheck::quickcheck;

    // relative error: this shouldn't be to small
    const EPS: f64 = 1e-10;

    fn eps_eq(a: f64, b: f64) -> bool {
        let m = a.abs() + b.abs();
        (a - b).abs() <= EPS * m
    }

    fn trunc<T: Float>(v: Vec<T>, w: Vec<T>) -> (Rn<T>, Rn<T>) {
            let mut v = Rn::new(v);
            let mut w = Rn::new(w);
            let l = min(v.len(), w.len());
            v.truncate(l);
            w.truncate(l);
            (v, w)
    }

    #[test]
    fn test_lin_f64() {
        fn prop(a: f64, b: f64, c: f64) -> bool {
            let mut d = a;
            d.ray_to(&b,c);
            eps_eq(a.norm(), a.dist(&a.origin())) &&
                eps_eq(d.dot(&a), a.norm_squared() + c * a * b)

        }

        quickcheck(prop as fn(f64, f64, f64) -> bool);
        let mut a = 1.;
        a.combine(2.,&3.,4.);
        assert_eq!(a.norm(), 1. * 2. + 3. * 4.);
    }

    #[test]
    fn scale_norm_zero() {
        fn prop(v: Vec<f64>) -> bool {
            let mut v = Rn::new(v);
            eps_eq(0., v.scale(0.).norm())
        }
        quickcheck(prop as fn(Vec<f64>) -> bool);
    }

    #[test]
    fn dot_equal_norm_squared() {
        fn prop(v: Vec<f64>) -> bool {
            let v = Rn::new(v);
            eps_eq(v.dot(&v), v.norm().powi(2))
        }
        quickcheck(prop as fn(Vec<f64>) -> bool);
    }

    #[test]
    fn origin() {
        fn prop(v: Vec<f64>) -> bool {
            let v = Rn::new(v);
            let o = v.origin();
            eps_eq(o.norm(), 0.) && o.len() == v.len()
        }
        quickcheck(prop as fn(Vec<f64>) -> bool);
    }

    #[test]
    fn dist_norm() {
        fn prop(v: Vec<f64>, w: Vec<f64>) -> bool {
            let (mut v, w) = trunc(v, w);

            let d = v.dist(&w);
            v.ray_to(&w, -1.);

            eps_eq(d, v.norm())
        }
        quickcheck(prop as fn(Vec<f64>, Vec<f64>) -> bool);
    }

    #[test]
    fn combine_ray_to() {
        fn prop(v: Vec<f64>, w: Vec<f64>, a: f64) -> bool {
            let (mut v, w) = trunc(v, w);

            let mut v1 = v.clone();
            v.combine(1., &w, a);
            v1.ray_to(&w, a);

            eps_eq(v.dist(&v1), 0.)
        }
        quickcheck(prop as fn(Vec<f64>, Vec<f64>, f64) -> bool);
    }

    #[test]
    fn combine_dot() {
        fn prop(v: Vec<f64>, w: Vec<f64>, z: Vec<f64>, a: f64) -> bool {
            let mut v = Rn::new(v);
            let mut w = Rn::new(w);
            let mut z = Rn::new(z);
            let l = min(v.len(), min(w.len(), z.len()));
            v.truncate(l);
            w.truncate(l);
            z.truncate(l);

            let b = 3.5;

            let dv = v.dot(&z);
            let dw = w.dot(&z);

            v.combine(a, &w, b);

            let dvw = v.dot(&z);
            eps_eq(a * dv + b * dw, dvw)
        }
        quickcheck(prop as fn(Vec<f64>, Vec<f64>, Vec<f64>, f64) -> bool);
    }

    #[test]
    fn project_pythagoras() {
        fn prop(v: Vec<f64>, w: Vec<f64>) -> bool {
            let (v, w) = trunc(v, w);

            let mut p = v.clone();
            let mut perp = v.clone();

            p.project_on(&w);
            perp.project_ortho(&w);
            eps_eq(p.norm_squared() + perp.norm_squared(), v.norm_squared())
        }
        quickcheck(prop as fn(Vec<f64>, Vec<f64>) -> bool);
    }

}
<commit_msg>Specialize Lin definitions for f32 and f64<commit_after>//! Implementation of a basic linear space trait.
//!
//! The main interface is `Lin` with an implementation for a vector of real
//! numbers: `Rn<F>`.
//!
//! ```rust
//! use linear_space::lin::{Lin,Rn};
//!
//! let x = Rn::new(vec![1.,2.]);
//! let y = Rn::new(vec![2.,-3.]);
//!
//! assert_eq!(x.dot(&y), -4.);
//! assert_eq!(Rn::new(vec![3., -1.]), x.clone() + y);
//! assert_eq!(Rn::new(vec![2., 4.]), x * 2.);
//! ```
use num::{Zero, One, Float};
use std::ops::{Add, Mul, Deref, DerefMut};
use std::iter::repeat;

/// Trait defining basic operations for an element of a linear space.
///
/// The focus is on operations _in place_: methods that return a `Lin` object
/// modify the object in place.
pub trait Lin {
    /// Scalars for this linear space.
    type F: Float;

    /// Dot product (inner product).
    fn dot(&self, other: &Self) -> Self::F;

    /// Multiplication by a constant.
    fn scale(&mut self, a: Self::F) -> &mut Self;

    /// Adds a vector multiplied by a constant to this vector.
    fn ray_to(&mut self, other: &Self, t: Self::F) -> &mut Self;

    /// Return the origin of the vector space to which self belongs too.
    fn origin(&self) -> Self;

    /// Norm of the vector.
    fn norm(&self) -> Self::F {
        self.norm_squared().sqrt()
    }

    /// Square of the norm.
    fn norm_squared(&self) -> Self::F {
        self.dot(self)
    }

    /// Scale the vector so that it has a norm one.
    ///
    /// If norm is zero, causes division by zero.
    fn normalize(&mut self) -> &mut Self {
        let norm = self.norm();
        self.scale(Self::F::one() / norm)
    }

    /// Distance between two vectors.
    ///
    /// Default implementation uses
    /// `|x - v| = sqrt(x.x - 2 x.y + y.y)`
    /// to avoid copying.
    /// Therefore it is recommended to reimplement this method.
    fn dist(&self, other: &Self) -> Self::F {
        (self.norm_squared() + other.norm_squared()
            - (Self::F::one() + Self::F::one()) * self.dot(other)).sqrt()
    }

    /// Adds a vector to this vector.
    fn add_mut(&mut self, other: &Self) -> &mut Self {
        self.ray_to(other, Self::F::one())
    }

    /// Creates a linear combination.
    fn combine(&mut self,  a: Self::F, other: &Self, b: Self::F) -> &mut Self {
        self.scale(a).ray_to(other,b)
    }

    /// Project on a line given by a given direction.
    ///
    /// `dir` does not have to be normalized, but must be nonzero.
    fn project_on(&mut self, dir: &Self) -> &mut Self {
        let a = self.dot(dir) / dir.norm_squared();
        self.combine(Self::F::zero(), dir, a)
    }

    /// Project on a plane orthogonal to the given direction.
    ///
    /// `dir` does not have to be normalized, but must be nonzero.
    fn project_ortho(&mut self, dir: &Self) -> &mut Self {
        let a = self.dot(dir) / dir.norm_squared();
        self.combine(Self::F::one(), dir, -a)
    }
}

/// An implementation of the Lin trait: an n-dimensional real vector.
///
/// Backed by a `Vec<F>`, where `F` is `Float`.
#[derive(Clone,Debug,PartialEq)]
pub struct Rn<F: Float> {
    vec: Vec<F>,
}

impl<F: Float> Rn<F> {
    pub fn new(v: Vec<F>) -> Self {
        Rn {vec: v}
    }
}

impl<F: Float> Deref for Rn<F> {
    type Target = Vec<F>;

    fn deref<'a>(&'a self) -> &'a Vec<F> {
        &self.vec
    }
}

impl<F: Float> DerefMut for Rn<F> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut Vec<F> {
        &mut self.vec
    }
}

impl<F: Float> Mul<F> for Rn<F> {
    type Output = Rn<F>;

    fn mul(mut self, other: F) -> Self {
        self.scale(other);
        self
    }
}

impl<F: Float> Add for Rn<F> {
    type Output = Rn<F>;

    fn add(mut self, other: Self) -> Self {
        self.add_mut(&other);
        self
    }
}

impl<F: Float> Lin for Rn<F> {
    type F = F;

    fn dist(&self, other: &Self) -> Self::F {
        assert_eq!(self.len(), other.len());
        self.iter().zip(other.iter())
            .fold(Self::F::zero(),
                |sum, (&x, &y)| sum + (x - y).powi(2))
            .sqrt()
    }

    fn dot(&self, other: &Self) -> Self::F {
        assert_eq!(self.len(), other.len());
        self.iter().zip(other.iter())
            .fold(Self::F::zero(), |sum, (&x, &y)| sum + x * y)
    }

    fn scale(&mut self, a: Self::F) -> &mut Self {
        for x in self.iter_mut() {
            *x = *x * a;
        }
        self
    }

    fn combine(&mut self,  a: Self::F, other: &Self, b: Self::F) -> &mut Self {
        assert_eq!(self.len(), other.len());
        for (x, y) in self.iter_mut().zip(other.iter()) {
            *x = *x * a + *y * b;
        }
        self
    }

    fn ray_to(&mut self,  other: &Self, b: Self::F) -> &mut Self {
        assert_eq!(self.len(), other.len());
        for (x, y) in self.iter_mut().zip(other.iter()) {
            *x = *x + *y * b;
        }
        self
    }

    fn origin(&self) -> Self {
        Rn::new(repeat(Self::F::zero()).take(self.len()).collect())
    }
}

// Trivial implementation of `Lin` for `f32` and `f64 as an element of a
// linear space over scalars of the same type.
// This cannot be done directly using
//
// ```
// impl<F: Float> Lin for F {
// ...
// ```
//
// since I am hitting
//
// ```
// error: conflicting implementations for trait `Lin` [E0119]
// ```
macro_rules! lin_float_impl {
    ($T:ident) => (
        impl Lin for $T {
            type F = $T;

            fn dot(&self, other: &Self) -> Self::F {
                *self * *other
            }

            fn scale(&mut self, a: Self::F) -> &mut Self {
                *self = *self * a;
                self
            }

            fn combine(&mut self,  a: Self::F, other: &Self, b: Self::F) -> &mut Self {
                *self = *self * a + *other * b;
                self
            }

            fn ray_to(&mut self,  other: &Self, b: Self::F) -> &mut Self {
                *self = *self + *other * b;
                self
            }

            fn origin(&self) -> Self {
                Self::F::zero()
            }

            fn dist(&self, other: &Self) -> Self::F {
                (*self - *other).abs()
            }

            fn norm(&self) -> Self::F {
                self.abs()
            }
        }
    )
}

lin_float_impl!(f32);
lin_float_impl!(f64);

#[cfg(test)]
mod test {
    extern crate quickcheck;

    use super::Lin;
    use super::Rn;
    use std::cmp::min;
    use num::Float;
    use self::quickcheck::quickcheck;

    // relative error: this shouldn't be to small
    const EPS: f64 = 1e-10;

    fn eps_eq(a: f64, b: f64) -> bool {
        let m = a.abs() + b.abs();
        (a - b).abs() <= EPS * m
    }

    fn trunc<T: Float>(v: Vec<T>, w: Vec<T>) -> (Rn<T>, Rn<T>) {
            let mut v = Rn::new(v);
            let mut w = Rn::new(w);
            let l = min(v.len(), w.len());
            v.truncate(l);
            w.truncate(l);
            (v, w)
    }

    #[test]
    fn test_lin_f64() {
        fn prop(a: f64, b: f64, c: f64) -> bool {
            let mut d = a;
            d.ray_to(&b,c);
            eps_eq(a.norm(), a.dist(&a.origin())) &&
                eps_eq(d.dot(&a), a.norm_squared() + c * a * b)

        }

        quickcheck(prop as fn(f64, f64, f64) -> bool);
        let mut a = 1.;
        a.combine(2.,&3.,4.);
        assert_eq!(a.norm(), 1. * 2. + 3. * 4.);
    }

    #[test]
    fn scale_norm_zero() {
        fn prop(v: Vec<f64>) -> bool {
            let mut v = Rn::new(v);
            eps_eq(0., v.scale(0.).norm())
        }
        quickcheck(prop as fn(Vec<f64>) -> bool);
    }

    #[test]
    fn dot_equal_norm_squared() {
        fn prop(v: Vec<f64>) -> bool {
            let v = Rn::new(v);
            eps_eq(v.dot(&v), v.norm().powi(2))
        }
        quickcheck(prop as fn(Vec<f64>) -> bool);
    }

    #[test]
    fn origin() {
        fn prop(v: Vec<f64>) -> bool {
            let v = Rn::new(v);
            let o = v.origin();
            eps_eq(o.norm(), 0.) && o.len() == v.len()
        }
        quickcheck(prop as fn(Vec<f64>) -> bool);
    }

    #[test]
    fn dist_norm() {
        fn prop(v: Vec<f64>, w: Vec<f64>) -> bool {
            let (mut v, w) = trunc(v, w);

            let d = v.dist(&w);
            v.ray_to(&w, -1.);

            eps_eq(d, v.norm())
        }
        quickcheck(prop as fn(Vec<f64>, Vec<f64>) -> bool);
    }

    #[test]
    fn combine_ray_to() {
        fn prop(v: Vec<f64>, w: Vec<f64>, a: f64) -> bool {
            let (mut v, w) = trunc(v, w);

            let mut v1 = v.clone();
            v.combine(1., &w, a);
            v1.ray_to(&w, a);

            eps_eq(v.dist(&v1), 0.)
        }
        quickcheck(prop as fn(Vec<f64>, Vec<f64>, f64) -> bool);
    }

    #[test]
    fn combine_dot() {
        fn prop(v: Vec<f64>, w: Vec<f64>, z: Vec<f64>, a: f64) -> bool {
            let mut v = Rn::new(v);
            let mut w = Rn::new(w);
            let mut z = Rn::new(z);
            let l = min(v.len(), min(w.len(), z.len()));
            v.truncate(l);
            w.truncate(l);
            z.truncate(l);

            let b = 3.5;

            let dv = v.dot(&z);
            let dw = w.dot(&z);

            v.combine(a, &w, b);

            let dvw = v.dot(&z);
            eps_eq(a * dv + b * dw, dvw)
        }
        quickcheck(prop as fn(Vec<f64>, Vec<f64>, Vec<f64>, f64) -> bool);
    }

    #[test]
    fn project_pythagoras() {
        fn prop(v: Vec<f64>, w: Vec<f64>) -> bool {
            let (v, w) = trunc(v, w);

            let mut p = v.clone();
            let mut perp = v.clone();

            p.project_on(&w);
            perp.project_ortho(&w);
            eps_eq(p.norm_squared() + perp.norm_squared(), v.norm_squared())
        }
        quickcheck(prop as fn(Vec<f64>, Vec<f64>) -> bool);
    }

}
<|endoftext|>