<commit_before>#![crate_name="orbclient"]
#![crate_type="lib"]
#![feature(associated_consts)]
#![feature(const_fn)]
#![feature(box_syntax)]
#![feature(deprecated)]

#![deny(warnings)]

extern crate core;

pub static FONT: &'static [u8] = include_bytes!("../res/unifont.font");

pub use bmp::BmpFile;
pub use color::Color;
pub use event::*;
pub use window::Window;

pub mod bmp;
pub mod color;
pub mod event;

#[cfg(target_os = "redox")]
#[path="orbital/window.rs"]
pub mod window;

#[cfg(not(target_os = "redox"))]
#[path="sdl2/window.rs"]
pub mod window;
<commit_msg>Remove the deprecated attribute<commit_after>#![crate_name="orbclient"]
#![crate_type="lib"]
#![feature(associated_consts)]
#![feature(const_fn)]
#![feature(box_syntax)]

#![deny(warnings)]

extern crate core;

pub static FONT: &'static [u8] = include_bytes!("../res/unifont.font");

pub use bmp::BmpFile;
pub use color::Color;
pub use event::*;
pub use window::Window;

pub mod bmp;
pub mod color;
pub mod event;

#[cfg(target_os = "redox")]
#[path="orbital/window.rs"]
pub mod window;

#[cfg(not(target_os = "redox"))]
#[path="sdl2/window.rs"]
pub mod window;
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;

use std::thread;
use std::sync::mpsc::{channel, Sender, Receiver, RecvError};

pub fn spawn_monitored_thread<F>(name: &str, sender: Sender<String>, f: F)
    where F: Send + 'static + FnOnce()
{
    let nam = name.to_string();
    thread::Builder::new().name(format!("{} thread", name)).spawn(move || {
        let _s = Sentinel::new(nam, sender);
        f();
    }).expect(&format!("cannot create {} thread", name));
}

pub struct ThreadMonitor {
    sender:   Sender<String>,
    receiver: Receiver<String>,
}

impl ThreadMonitor {
    pub fn new() -> Self {
        let (s,r) = channel();
        ThreadMonitor {
            sender:   s,
            receiver: r,
        }
    }

    pub fn sender(&self) -> Sender<String> {
        self.sender.clone()
    }

    pub fn run(&self) -> Result<String, RecvError> {
        self.receiver.recv()
    }

    pub fn spawn_monitored_thread<F>(&self, name: &str, f: F)
        where F: Send + 'static + FnOnce()
    {
        spawn_monitored_thread(name, self.sender.clone(), f);
    }
}

struct Sentinel {
    name:  String,
    sender: Sender<String>,
}

impl Sentinel {
    pub fn new(name: String, sender: Sender<String>) -> Self {
        Sentinel {
            name:   name,
            sender: sender,
        }
    }
}

impl Drop for Sentinel {
    fn drop(&mut self) {
        match self.sender.send(self.name.clone()) {
            Ok(()) => debug!("Sentinel exit: {}", self.name),
            Err(e) => error!("Sentinel exit: {} error: {:?}", self.name, e)
        }
    }
}
<commit_msg>add MonitoredThreadSpawner<commit_after>#[macro_use]
extern crate log;

use std::thread;
use std::sync::mpsc::{channel, Sender, Receiver, RecvError};

pub fn spawn_monitored_thread<F>(name: &str, sender: Sender<String>, f: F)
    where F: Send + 'static + FnOnce()
{
    let nam = name.to_string();
    thread::Builder::new().name(format!("{} thread", name)).spawn(move || {
        let _s = Sentinel::new(nam, sender);
        f();
    }).expect(&format!("cannot create {} thread", name));
}

pub struct ThreadMonitor {
    sender:   Sender<String>,
    receiver: Receiver<String>,
}

impl ThreadMonitor {
    pub fn new() -> Self {
        let (s,r) = channel();
        ThreadMonitor {
            sender:   s,
            receiver: r,
        }
    }

    pub fn spawner(&self) -> MonitoredThreadSpawner {
        MonitoredThreadSpawner {
            sender: self.sender.clone()
        }
    }

    pub fn sender(&self) -> Sender<String> {
        self.sender.clone()
    }

    pub fn run(&self) -> Result<String, RecvError> {
        self.receiver.recv()
    }

    pub fn spawn_monitored_thread<F>(&self, name: &str, f: F)
        where F: Send + 'static + FnOnce()
    {
        spawn_monitored_thread(name, self.sender.clone(), f);
    }
}

pub struct MonitoredThreadSpawner {
    sender: Sender<String>
}

impl MonitoredThreadSpawner {
    pub fn spawn_monitored_thread<F>(&self, name: &str, f: F)
        where F: Send + 'static + FnOnce()
    {
        spawn_monitored_thread(name, self.sender.clone(), f);
    }
}

struct Sentinel {
    name:  String,
    sender: Sender<String>,
}

impl Sentinel {
    pub fn new(name: String, sender: Sender<String>) -> Self {
        Sentinel {
            name:   name,
            sender: sender,
        }
    }
}

impl Drop for Sentinel {
    fn drop(&mut self) {
        match self.sender.send(self.name.clone()) {
            Ok(()) => debug!("Sentinel exit: {}", self.name),
            Err(e) => error!("Sentinel exit: {} error: {:?}", self.name, e)
        }
    }
}
<|endoftext|>


<commit_before>extern crate socket;

use socket::{AF_INET, Socket, SOCK_DGRAM, IP_MULTICAST_TTL, IPPROTO_IP};
use std::io::{Error, ErrorKind, Result};
use std::net::{IpAddr, SocketAddr};
use std::str::FromStr;
use std::sync::{Arc, mpsc};
use std::thread;
use std::time::Instant;

#[derive(Debug)]
/// `Discover` type
///
/// Used for discovering sonos devices in the local network via the simple service discovery protocol (ssdp).
/// The ssd-protocol works via udp sockets. First a certain search-message is sent to the multicast address (239.255.255.250:1900).
///
/// All answer from upnp (universal plug and play) ready devices are processed and filtered ("Sonos" is in the reply).
pub struct Discover {
    /// Multicast address in the local network
    multicast_addr: SocketAddr,
    /// Socket implementation
    /// INFO: The socket type will likely change in the future due to cross platform compatability
    socket: Arc<Socket>
}

impl Discover {
    /// Creates a new `Discovery`. Uses the default socket on the default ipv4 multicast address (239.255.255.250:1900).
    ///
    /// # Examples
    ///
    /// ```
    /// use sonos_discovery::Discovery;
    ///
    /// let discovery: Discovery = Discovery::new().unwrap();
    /// ```
    pub fn new() -> Result<Self> {
        let multicast_address = SocketAddr::from_str("239.255.255.250:1900")
            .map_err(|_|
                Error::new(ErrorKind::InvalidData, "Couldn't parse socket address"))?;

        Discover::with_address(multicast_address)
    }

    /// Creates a new `Discovery` with a custom multicast address.
    pub fn with_address(address: SocketAddr) -> Result<Self> {
        let socket = Discover::create_default_socket()?;
        Ok(Discover {
            multicast_addr: address,
            socket
        })
    }

    /// Create a default socket
    /// socket option: AF_INET - SOCK_DGRAM - 0 // Automatically discover the protocol (IPPROTO_UDP)
    /// socket option: IPPROTO_IP - IP_MULTICAST_TTL - 4 // UPnP 1.0 needs a TTL of 4
    fn create_default_socket() -> Result<Arc<Socket>> {
        let socket_family = AF_INET;
        let socket_level = SOCK_DGRAM;
        let protocol = 0; // auto discover
        let socket_options = vec![(IPPROTO_IP, IP_MULTICAST_TTL, 4)];

        Discover::create_socket(socket_family, socket_level, protocol, &socket_options)
    }

    fn create_socket(socket_family: i32, socket_type: i32, protocol: i32, socket_options: &[(i32, i32, i32)]) -> Result<Arc<Socket>> {
        let socket = Socket::new(socket_family, socket_type, protocol)?;
        for socket_option in socket_options {
            // TODO: Use result, allow to fail, panic or return a result?
            socket.setsockopt(socket_option.0, socket_option.1, socket_option.2)?
        }

        Ok(Arc::new(socket))
    }

    /// Sends the search message to the defined socket.
    /// Message can't have leading/trailing whitespaces (\s).
    ///
    /// # Message
    /// ```
    /// M-SEARCH * HTTP/1.1
    /// HOST: 239.255.255.250:1900
    /// MAN: "ssdp:discover"
    /// MX: 1
    /// ST: urn:schemas-upnp-org:device:ZonePlayer:1```
    fn send_search(&self) -> Result<usize> {
        let player_search = br#"M-SEARCH * HTTP/1.1
HOST: 239.255.255.250:1900
MAN: "ssdp:discover"
MX: 1
ST: urn:schemas-upnp-org:device:ZonePlayer:1"#;

        self.socket.sendto(player_search, 0, &self.multicast_addr)
    }

    /// Start discovering devices.
    ///
    /// # Examples
    /// In this example the search will stop if3 devices have been discovered or the default timeout (5s) is reached.
    /// This is useful if you know the amount of speakers you have and want to reduce the search time.
    ///
    /// ```
    /// use sonos_discovery::Discovery;
    ///
    /// let devices: Vec<IpAddr> = Discovery::new().unwrap().start(None, Some(3)).unwrap();
    /// ```
    pub fn start(&self, timeout: Option<u32>, device_count: Option<usize>) -> Result<Vec<IpAddr>> {
        let timeout = timeout.unwrap_or(5);
        let device_count = device_count.unwrap_or(std::u32::MAX as usize);

        let time = Instant::now();

        self.send_search()?;

        let mut devices: Vec<IpAddr> = Vec::new();
        while time.elapsed().as_secs() < u64::from(timeout) && devices.len() < device_count {
            let socket = Arc::clone(&self.socket);
            let (sender, receiver) = mpsc::channel();
            thread::spawn(move ||
                {
                    if let Ok((_addr, _data)) = socket.recvfrom(1024, 0) {
                        // TODO: Add logging, fail on multiple send errors?
                        sender.send((_addr, _data)).is_ok();
                    }
                }
            );

            // TODO: Add logging, change
            let timeout = std::time::Duration::new(0, 500_000_000);
            let (addr, data): (SocketAddr, Box<[u8]>) = match receiver.recv_timeout(timeout) {
                Ok((addr, data)) => (addr, data),
                Err(_) => continue
            };

            let needle: &[u8] = br"Sonos";
            if data.windows(needle.len()).position(|window| window == needle).is_some() {
                devices.push(addr.ip())
            }
        }

        Ok(devices)
    }
}
<commit_msg>Change option check<commit_after>extern crate socket;

use socket::{AF_INET, Socket, SOCK_DGRAM, IP_MULTICAST_TTL, IPPROTO_IP};
use std::io::{Error, ErrorKind, Result};
use std::net::{IpAddr, SocketAddr};
use std::str::FromStr;
use std::sync::{Arc, mpsc};
use std::thread;
use std::time::Instant;

#[derive(Debug)]
/// `Discover` type
///
/// Used for discovering sonos devices in the local network via the simple service discovery protocol (ssdp).
/// The ssd-protocol works via udp sockets. First a certain search-message is sent to the multicast address (239.255.255.250:1900).
///
/// All answer from upnp (universal plug and play) ready devices are processed and filtered ("Sonos" is in the reply).
pub struct Discover {
    /// Multicast address in the local network
    multicast_addr: SocketAddr,
    /// Socket implementation
    /// INFO: The socket type will likely change in the future due to cross platform compatability
    socket: Arc<Socket>
}

impl Discover {
    /// Creates a new `Discovery`. Uses the default socket on the default ipv4 multicast address (239.255.255.250:1900).
    ///
    /// # Examples
    ///
    /// ```
    /// use sonos_discovery::Discovery;
    ///
    /// let discovery: Discovery = Discovery::new().unwrap();
    /// ```
    pub fn new() -> Result<Self> {
        let multicast_address = SocketAddr::from_str("239.255.255.250:1900")
            .map_err(|_|
                Error::new(ErrorKind::InvalidData, "Couldn't parse socket address"))?;

        Discover::with_address(multicast_address)
    }

    /// Creates a new `Discovery` with a custom multicast address.
    pub fn with_address(address: SocketAddr) -> Result<Self> {
        let socket = Discover::create_default_socket()?;
        Ok(Discover {
            multicast_addr: address,
            socket
        })
    }

    /// Create a default socket
    /// socket option: AF_INET - SOCK_DGRAM - 0 // Automatically discover the protocol (IPPROTO_UDP)
    /// socket option: IPPROTO_IP - IP_MULTICAST_TTL - 4 // UPnP 1.0 needs a TTL of 4
    fn create_default_socket() -> Result<Arc<Socket>> {
        let socket_family = AF_INET;
        let socket_level = SOCK_DGRAM;
        let protocol = 0; // auto discover
        let socket_options = vec![(IPPROTO_IP, IP_MULTICAST_TTL, 4)];

        Discover::create_socket(socket_family, socket_level, protocol, &socket_options)
    }

    fn create_socket(socket_family: i32, socket_type: i32, protocol: i32, socket_options: &[(i32, i32, i32)]) -> Result<Arc<Socket>> {
        let socket = Socket::new(socket_family, socket_type, protocol)?;
        for socket_option in socket_options {
            // TODO: Use result, allow to fail, panic or return a result?
            socket.setsockopt(socket_option.0, socket_option.1, socket_option.2)?
        }

        Ok(Arc::new(socket))
    }

    /// Sends the search message to the defined socket.
    /// Message can't have leading/trailing whitespaces (\s).
    ///
    /// # Message
    /// ```
    /// M-SEARCH * HTTP/1.1
    /// HOST: 239.255.255.250:1900
    /// MAN: "ssdp:discover"
    /// MX: 1
    /// ST: urn:schemas-upnp-org:device:ZonePlayer:1```
    fn send_search(&self) -> Result<usize> {
        let player_search = br#"M-SEARCH * HTTP/1.1
HOST: 239.255.255.250:1900
MAN: "ssdp:discover"
MX: 1
ST: urn:schemas-upnp-org:device:ZonePlayer:1"#;

        self.socket.sendto(player_search, 0, &self.multicast_addr)
    }

    /// Start discovering devices.
    ///
    /// # Examples
    /// In this example the search will stop if3 devices have been discovered or the default timeout (5s) is reached.
    /// This is useful if you know the amount of speakers you have and want to reduce the search time.
    ///
    /// ```
    /// use sonos_discovery::Discovery;
    ///
    /// let devices: Vec<IpAddr> = Discovery::new().unwrap().start(None, Some(3)).unwrap();
    /// ```
    pub fn start(&self, timeout: Option<u32>, device_count: Option<usize>) -> Result<Vec<IpAddr>> {
        let timeout = timeout.unwrap_or(5);
        let device_count = device_count.unwrap_or(std::u32::MAX as usize);

        let time = Instant::now();

        self.send_search()?;

        let mut devices: Vec<IpAddr> = Vec::new();
        while time.elapsed().as_secs() < u64::from(timeout) && devices.len() < device_count {
            let socket = Arc::clone(&self.socket);
            let (sender, receiver) = mpsc::channel();
            thread::spawn(move ||
                {
                    if let Ok((_addr, _data)) = socket.recvfrom(1024, 0) {
                        // TODO: Add logging, fail on multiple send errors?
                        sender.send((_addr, _data)).is_ok();
                    }
                }
            );

            // TODO: Add logging, change
            let timeout = std::time::Duration::new(0, 500_000_000);
            let (addr, data): (SocketAddr, Box<[u8]>) = match receiver.recv_timeout(timeout) {
                Ok((addr, data)) => (addr, data),
                Err(_) => continue
            };

            let needle: &[u8] = br"Sonos";
            data.windows(needle.len()).position(|window| window == needle)
                .map(|_|
                    devices.push(addr.ip())
                );
        }

        Ok(devices)
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Cesar Eduardo Barros
//
// 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.

//! A pure Rust implementation of BLAKE2 based on the draft RFC.

#![cfg_attr(all(feature = "bench", test), feature(test))]
#![cfg_attr(feature = "simd", feature(link_llvm_intrinsics, simd, simd_ffi))]
#![cfg_attr(feature = "simd_asm", feature(asm))]

extern crate constant_time_eq;

#[cfg(all(feature = "bench", test))] extern crate test;

#[cfg(feature = "simd")] extern crate simdty;

mod as_bytes;
mod bytes;
mod simd;

#[macro_use]
mod blake2;

pub mod blake2b;
pub mod blake2s;

/// Runs the self-test for both BLAKE2b and BLAKE2s.
pub fn selftest() {
    blake2b::selftest();
    blake2s::selftest();
}
<commit_msg>Minor layout tweak<commit_after>// Copyright (c) 2015 Cesar Eduardo Barros
//
// 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.

//! A pure Rust implementation of BLAKE2 based on the draft RFC.

#![cfg_attr(all(feature = "bench", test), feature(test))]
#![cfg_attr(feature = "simd", feature(link_llvm_intrinsics, simd, simd_ffi))]
#![cfg_attr(feature = "simd_asm", feature(asm))]

#[cfg(all(feature = "bench", test))] extern crate test;
#[cfg(feature = "simd")] extern crate simdty;

extern crate constant_time_eq;

mod as_bytes;
mod bytes;
mod simd;

#[macro_use]
mod blake2;

pub mod blake2b;
pub mod blake2s;

/// Runs the self-test for both BLAKE2b and BLAKE2s.
pub fn selftest() {
    blake2b::selftest();
    blake2s::selftest();
}
<|endoftext|>


<commit_before>extern crate ansi_term;
extern crate hyper;
extern crate pbr;
extern crate rayon;

use std::sync::{Arc, Mutex};

#[macro_use]
pub mod logs;

pub mod authorization;
pub mod bench;
pub mod cargo_helper;
pub mod client;
pub mod contentlength;
pub mod download;
pub mod filesize;
pub mod http_version;
pub mod response;
pub mod util;
pub mod write;

/// Represents a number of bytes, as `u64`.
pub type Bytes = u64;
/// Represents a 'chunk', which is just a piece of bytes.
type Chunk = Vec<u8>;
/// Represents a list of chunks
pub type Chunks = Vec<Chunk>;
/// Represents a shared mutable reference of chunks
pub type SChunks = Arc<Mutex<Chunks>>;
/// Represents an URL
pub type URL<'a> = &'a str;
/// MirrorsList is an alias that contain fast URLs to download the file
type MirrorsList<'a> = Vec<URL<'a>>;
<commit_msg>Manage OpenSSL client<commit_after>extern crate ansi_term;
extern crate hyper;
extern crate hyper_openssl;
extern crate pbr;
extern crate rayon;

use std::sync::{Arc, Mutex};

#[macro_use]
pub mod logs;

pub mod authorization;
pub mod bench;
pub mod cargo_helper;
pub mod client;
pub mod contentlength;
pub mod download;
pub mod filesize;
pub mod http_version;
pub mod response;
pub mod util;
pub mod write;

pub static mut SSL_SUPPORT: bool = false;

/// Represents a number of bytes, as `u64`.
pub type Bytes = u64;
/// Represents a 'chunk', which is just a piece of bytes.
type Chunk = Vec<u8>;
/// Represents a list of chunks
pub type Chunks = Vec<Chunk>;
/// Represents a shared mutable reference of chunks
pub type SChunks = Arc<Mutex<Chunks>>;
/// Represents an URL
pub type URL<'a> = &'a str;
/// MirrorsList is an alias that contain fast URLs to download the file
type MirrorsList<'a> = Vec<URL<'a>>;
<|endoftext|>


<commit_before>///! Copyright 2015 Philipp Korber
///!
///! 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.

//alloc is needed for BoxAny, witch willl most like be removed in the future
//this is not a problem because the methodes of BoxAny will the most like
//become part of Any so that this lib can be updated by removing the
//import and feature statement
#![feature(alloc)]
//this is needed 'cause Associated Types in combination with e.g. Index are not yet complety stable
#![feature(core)]
//for now it is unstable
#![unstable(feature="alloc,core")]

use std::rc::Rc;
use std::cell::RefCell;
use std::cell::RefMut;
use std::hash::Hash;

//import and reexport dyn_property
pub use dyn_property::DynProperty;
pub use dyn_property::UndefinedProperty;
pub use inner_dyn_object::InnerDynObject;

///!
///! InnerDynObject is a kind of dynamic objects witch allows
///! creating and deleting properties at runtime.
///! This includs runtime type checks over genereic functions
///! so that the rest of your programm don't has to care mutch
///! about. Neverless this has to backdrawings:
///!   1. Accessing the variables allways returns a Result
///!   2. it has to own the data
///!   3. it's slower. If you have a group of variables putng
///!      them into a POD rust object and then puting it into
///!      InnerDynObject might be preferable

mod dyn_property;
mod inner_dyn_object;

pub struct DynObject<Key> {
    inner: Rc<RefCell<InnerDynObject<Key>>>
}

impl<Key> DynObject<Key> where Key: Eq+Hash {

    pub fn new<T>() -> DynObject<T>
        where T: Eq + Hash
    {
        let x =  InnerDynObject::<T>::new();
        let cell = RefCell::new(x);
        let rc = Rc::new(cell);
        DynObject {
            inner: rc
        }
    }

    /// aquire the DynObject to perform operations on it
    ///
    /// # Panics
    /// if someone else aquired it and didn't relase it jet
    /// (by droping the returned RefMut, witch is often done
    /// implicitly)
    pub fn aquire(&mut self) -> RefMut<InnerDynObject<Key>> {
        self.inner.borrow_mut()
    }
}

impl<T> Clone for DynObject<T> where T: Eq+Hash {

    fn clone(&self) -> Self {
        DynObject {
            inner: self.inner.clone()
        }
    }
}

#[cfg(test)]
mod test_dyn_object {
    #![allow(unused_variables)]

    use super::DynObject;

    fn create_dummy() -> DynObject<&'static str> {
        DynObject::<&'static str>::new()
    }

    #[test]
    fn aquire_should_not_panic_if_only_on_instance_exists() {
        let mut x = create_dummy();
        let data = x.aquire();
    }

    #[test]
    #[should_fail]
    fn aquire_multiple_times_should_panic() {
        let mut x = create_dummy();
        let mut obj_ref_2 = x.clone();
        let data = x.aquire();
        let data2 = obj_ref_2.aquire();
    }

    #[test]
    fn aquire_multiple_times_after_relasing_each_should_not_fail() {
        let mut x = create_dummy();
        {
            let data = x.aquire();
        }
        let data2 = x.aquire();
    }

    fn set_data(mut target: DynObject<&'static str>, value: i32) {
        target.aquire().create_property(&"hallo", Box::new(value));
    }

    #[test]
    fn mutiple_cloned_dyn_object_should_share_the_same_core() {
        let value = 23i32;
        let mut obj1 = create_dummy();
        set_data(obj1.clone(), value);
        let obj = obj1.aquire();
        match obj["hallo"].as_ref::<i32>() {
            Some(data) => assert_eq!(data, &value),
            None => panic!("type mismatch, error in test or other class")
        }
    }
}
<commit_msg>fixed stupid build proplemn with inner documentation above inner (feature) attributes<commit_after>// Copyright 2015 Philipp Korber
//
// 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.

//alloc is needed for BoxAny, witch willl most like be removed in the future
//this is not a problem because the methodes of BoxAny will the most like
//become part of Any so that this lib can be updated by removing the
//import and feature statement
#![feature(alloc)]
//this is needed 'cause Associated Types in combination with e.g. Index are not yet complety stable
#![feature(core)]
//for now it is unstable
#![unstable(feature="alloc,core")]

use std::rc::Rc;
use std::cell::RefCell;
use std::cell::RefMut;
use std::hash::Hash;

//import and reexport dyn_property
pub use dyn_property::DynProperty;
pub use dyn_property::UndefinedProperty;
pub use inner_dyn_object::InnerDynObject;

///!
///! InnerDynObject is a kind of dynamic objects witch allows
///! creating and deleting properties at runtime.
///! This includs runtime type checks over genereic functions
///! so that the rest of your programm don't has to care mutch
///! about. Neverless this has to backdrawings:
///!   1. Accessing the variables allways returns a Result
///!   2. it has to own the data
///!   3. it's slower. If you have a group of variables putng
///!      them into a POD rust object and then puting it into
///!      InnerDynObject might be preferable

mod dyn_property;
mod inner_dyn_object;

pub struct DynObject<Key> {
    inner: Rc<RefCell<InnerDynObject<Key>>>
}

impl<Key> DynObject<Key> where Key: Eq+Hash {

    pub fn new<T>() -> DynObject<T>
        where T: Eq + Hash
    {
        let x =  InnerDynObject::<T>::new();
        let cell = RefCell::new(x);
        let rc = Rc::new(cell);
        DynObject {
            inner: rc
        }
    }

    /// aquire the DynObject to perform operations on it
    ///
    /// # Panics
    /// if someone else aquired it and didn't relase it jet
    /// (by droping the returned RefMut, witch is often done
    /// implicitly)
    pub fn aquire(&mut self) -> RefMut<InnerDynObject<Key>> {
        self.inner.borrow_mut()
    }
}

impl<T> Clone for DynObject<T> where T: Eq+Hash {

    fn clone(&self) -> Self {
        DynObject {
            inner: self.inner.clone()
        }
    }
}

#[cfg(test)]
mod test_dyn_object {
    #![allow(unused_variables)]

    use super::DynObject;

    fn create_dummy() -> DynObject<&'static str> {
        DynObject::<&'static str>::new()
    }

    #[test]
    fn aquire_should_not_panic_if_only_on_instance_exists() {
        let mut x = create_dummy();
        let data = x.aquire();
    }

    #[test]
    #[should_fail]
    fn aquire_multiple_times_should_panic() {
        let mut x = create_dummy();
        let mut obj_ref_2 = x.clone();
        let data = x.aquire();
        let data2 = obj_ref_2.aquire();
    }

    #[test]
    fn aquire_multiple_times_after_relasing_each_should_not_fail() {
        let mut x = create_dummy();
        {
            let data = x.aquire();
        }
        let data2 = x.aquire();
    }

    fn set_data(mut target: DynObject<&'static str>, value: i32) {
        target.aquire().create_property(&"hallo", Box::new(value));
    }

    #[test]
    fn mutiple_cloned_dyn_object_should_share_the_same_core() {
        let value = 23i32;
        let mut obj1 = create_dummy();
        set_data(obj1.clone(), value);
        let obj = obj1.aquire();
        match obj["hallo"].as_ref::<i32>() {
            Some(data) => assert_eq!(data, &value),
            None => panic!("type mismatch, error in test or other class")
        }
    }
}
<|endoftext|>


<commit_before>#![no_std]

extern crate num;

pub mod create;
pub use create::*;

pub mod set;
pub use set::*;

pub mod add;
pub use add::*;

pub mod sub;
pub use sub::*;

pub mod mul;
pub use mul::*;

pub mod div;
pub use div::*;

pub mod length;
pub use length::*;

pub mod misc;
pub use misc::*;

pub mod transform;
pub use transform::*;
<commit_msg>dont export mods<commit_after>#![no_std]

extern crate num;

mod create;
pub use create::*;

mod set;
pub use set::*;

mod add;
pub use add::*;

mod sub;
pub use sub::*;

mod mul;
pub use mul::*;

mod div;
pub use div::*;

mod length;
pub use length::*;

mod misc;
pub use misc::*;

mod transform;
pub use transform::*;
<|endoftext|>


<commit_before>#![cfg_attr(test, feature(plugin))]
#![cfg_attr(test, plugin(quickcheck_macros))]

extern crate num;

#[cfg(test)] extern crate quickcheck;

use num::{Float, Num, NumCast, Signed, Zero, cast};
use std::f64::consts::PI;
use std::fmt::{Display, Formatter, Error};
use std::ops::{Add, Div, Mul, Neg, Sub};

/// An angle.
///
/// Might be a value in degrees or in radians.
#[derive(Copy, Clone, Debug)]
pub enum Angle<T=f64> {
    Radians(T),
    Degrees(T)
}

impl<T: NumCast> Angle<T> {
    /// Yield the value encoded in radians.
    pub fn in_radians(self) -> T {
        match self {
            Radians(v) => v,
            Degrees(v) => cast(cast::<T, f64>(v).unwrap() / 180.0 * PI).unwrap()
        }
    }

    /// Yield the value encoded in degrees.
    pub fn in_degrees(self) -> T {
        match self {
            Radians(v) => cast(cast::<T, f64>(v).unwrap() / PI * 180.0).unwrap(),
            Degrees(v) => v
        }
    }
}

impl<T: Copy + Num + NumCast + PartialOrd> Angle<T> {
    /// Create a new angle by normalizing the value into the range of
    /// [0, 2π) rad.
    pub fn normalized(self) -> Angle<T> {
        let (v, upper) = match self {
            Radians(v) => (v, cast(2.0 * PI).unwrap()),
            Degrees(v) => (v, cast(360.0).unwrap())
        };

        let normalized = if v < upper && v >= Zero::zero() {
            v
        } else {
            let v = v % upper;

            if v >= Zero::zero() {
                v
            } else {
                v + upper
            }
        };

        match self {
            Radians(_) => Radians(normalized),
            Degrees(_) => Degrees(normalized)
        }
    }
}

impl<T: Signed> Angle<T> {
    /// Compute the absolute angle.
    pub fn abs(self) -> Angle<T> {
        match self {
            Radians(v) => Radians(v.abs()),
            Degrees(v) => Degrees(v.abs())
        }
    }
}

impl<T: Float + NumCast> Angle<T> {
    /// Compute the sine of the angle.
    pub fn sin(self) -> T {
        self.in_radians().sin()
    }

    /// Compute the cosine of the angle.
    pub fn cos(self) -> T {
        self.in_radians().cos()
    }

    /// Compute the tangent of the angle.
    pub fn tan(self) -> T {
        self.in_radians().tan()
    }

    /// Simultaneously compute the sine and cosine of the number, `x`.
    /// Return `(sin(x), cos(x))`.
    pub fn sin_cos(self) -> (T, T) {
        self.in_radians().sin_cos()
    }

    /*
    /// Computes the approximate mean of a set of angles by averaging the
    /// Cartesian coordinates of the angles on the unit circle.
    pub fn mean(angles: &[Angle<T>]) -> Angle<T> {
        let mut x: T = Zero::zero();
        let mut y: T = Zero::zero();

        for angle in angles.iter() {
            let radian = angle.as_radian();
            x = x + radian.cos();
            y = y + radian.sin();
        }

        let n = cast(angles.len()).unwrap();
        let a = (y/n).atan2(x/n);

        Radian(a).normalize()
    }

    /// Computes the minimal unsigned distance between two normalized angles.
    pub fn distance(&self, other: Angle<T>) -> Angle<T> {
        // FIXME: Once associated types are implemented fix this nightmares of casts #17841
        let pi: T = cast(f64::consts::PI).unwrap();
        let pi2: T = pi * cast(2.0).unwrap();
        let d = (self.as_radian() - other.as_radian()).abs();
        Radian(pi - ((d % (pi2)) - pi).abs())
    }*/
}

impl<T: Float> Angle<T> {
    /// Compute the arcsine of a number. Return value is in the range of
    /// [-π/2, π/2] rad or `None` if the number is outside the range [-1, 1].
    pub fn asin(value: T) -> Option<Angle<T>> {
        let value = value.asin();
        if value.is_nan() {
            None
        } else {
            Some(Radians(value))
        }
    }

    /// Compute the arccosine of a number. Return value is in the range of
    /// [0, π] rad or `None` if the number is outside the range [-1, 1].
    pub fn acos(value: T) -> Option<Angle<T>> {
        let value = value.acos();
        if value.is_nan() {
            None
        } else {
            Some(Radians(value))
        }
    }

    /// Compute the arctangent of a number. Return value is in the range of
    /// [-π/2, π/2] rad.
    pub fn atan(value: T) -> Angle<T> {
        Radians(value.atan())
    }

    // Computes the four quadrant arctangent of `y` and `x`.
    pub fn atan2(y: T, x: T) -> Angle<T> {
        Radians(y.atan2(x))
    }
}

impl<T: Zero + Copy + NumCast> Zero for Angle<T> {
    fn zero() -> Self {
        Radians(T::zero())
    }

    fn is_zero(&self) -> bool {
        match self {
            &Radians(ref v) => v.is_zero(),
            &Degrees(ref v) => v.is_zero()
        }
    }
}

impl<T: PartialEq + Copy + NumCast> PartialEq for Angle<T> {
    fn eq(&self, other: &Angle<T>) -> bool {
        if let (Degrees(a), Degrees(b)) = (*self, *other) {
            a == b
        } else {
            self.in_radians() == other.in_radians()
        }
    }
}

macro_rules! math_additive(
    ($bound:ident, $func:ident) => (
        impl<T: $bound + Copy + NumCast> $bound for Angle<T> {
            type Output = Angle<T::Output>;
            fn $func(self, rhs: Angle<T>) -> Self::Output {
                if let (Degrees(a), Degrees(b)) = (self, rhs) {
                    Degrees(a.$func(b))
                } else {
                    Radians(self.in_radians().$func(rhs.in_radians()))
                }
            }
        }
    );
);

math_additive!(Add, add);
math_additive!(Sub, sub);

macro_rules! math_multiplicative(
    ($bound:ident, $func:ident, $($t:ident),*) => (
        impl<T: $bound> $bound<T> for Angle<T> {
            type Output = Angle<T::Output>;
            fn $func(self, rhs: T) -> Self::Output {
                match self {
                    Radians(v) => Radians(v.$func(rhs)),
                    Degrees(v) => Degrees(v.$func(rhs))
                }
            }
        }

        $(
            impl $bound<Angle<$t>> for $t {
                type Output = Angle<$t>;
                fn $func(self, rhs: Angle<$t>) -> Self::Output {
                    match rhs {
                        Radians(v) => Radians(self.$func(v)),
                        Degrees(v) => Degrees(self.$func(v))
                    }
                }
            }
        )*
    );
);

math_multiplicative!(Mul, mul, u8, u16, u32, u64, i8, i16, i32, i64, usize, isize, f32, f64);
math_multiplicative!(Div, div, u8, u16, u32, u64, i8, i16, i32, i64, usize, isize, f32, f64);

impl<T: Neg> Neg for Angle<T> {
    type Output = Angle<T::Output>;
    fn neg(self) -> Self::Output {
        match self {
            Radians(v) => Radians(-v),
            Degrees(v) => Degrees(-v)
        }
    }
}

impl<T: Display> Display for Angle<T> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        match *self {
            Radians(ref v) => write!(f, "{}rad", v),
            Degrees(ref v) => write!(f, "{}°", v)
        }
    }
}

unsafe impl<T: Send> Send for Angle<T> {  }

/*
impl<T: Encodable + Float + NumCast> Encodable for Angle<T> {
    fn encode<S: Encoder>(&self,  s: &mut S) -> Result<(), S::Error> {
        self.as_radian().encode(s)
    }
}

impl<T: Decodable + Float + NumCast> Decodable for Angle<T> {
    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
        let t = try!(T::decode(d));
        Ok(Angle::Radian(t))
    }
}
*/

// re-exports
pub use Angle::{Radians, Degrees};

#[cfg(test)]
mod tests {
    use num::{Float, cast};
    use quickcheck::{Arbitrary, Gen};
    use std::f64::consts::PI;
    use super::{Angle, Radians, Degrees};

    #[quickcheck]
    fn test_angle_conversions(angle: Angle<f64>) -> bool {
        are_close(angle.in_radians(), Degrees(angle.in_degrees()).in_radians())
    }

    #[quickcheck]
    fn test_angle_math_multiplicative(a: Angle<f64>, x: f64) -> bool {
        match a {
            Radians(v) => (a * x).in_radians() == v * x &&
                          (a / x).in_radians() == v / x,
            Degrees(v) => (a * x).in_degrees() == v * x &&
                          (a / x).in_degrees() == v / x
        }
    }

    #[quickcheck]
    fn test_angle_math_additive(a: Angle, b: Angle) -> bool {
        if let (Radians(x), Radians(y)) = (a, b) {
            (a + b).in_radians() == x + y &&
            (a - b).in_radians() == x - y
        } else if let (Degrees(x), Degrees(y)) = (a, b) {
            (a + b).in_degrees() == x + y &&
            (a - b).in_degrees() == x - y
        } else {
            (a + b).in_radians() == a.in_radians() + b.in_radians()
        }
    }

    #[quickcheck]
    fn test_angle_normalization(angle: Angle) -> bool {
        let v = angle.normalized();
        let rad = v.in_radians();
        let deg = v.in_degrees();

        0.0 <= rad && rad < 2.0 * PI &&
        0.0 <= deg && deg < 360.0 &&
        are_close(rad.cos(), angle.cos())
    }

    fn are_close<T: Float>(a: T, b: T) -> bool {
        (a - b).abs() < cast(1.0e-10).unwrap()
    }

    impl<T: Arbitrary> Arbitrary for Angle<T> {
        fn arbitrary<G: Gen>(g: &mut G) -> Self {
            let v = Arbitrary::arbitrary(g);
            if bool::arbitrary(g) {
                Radians(v)
            } else {
                Degrees(v)
            }
        }
    }
}
<commit_msg>Stylistic improvements<commit_after>#![cfg_attr(test, feature(plugin))]
#![cfg_attr(test, plugin(quickcheck_macros))]

extern crate num;

#[cfg(test)] extern crate quickcheck;

use num::{Float, Num, NumCast, Signed, Zero, cast};
use std::f64::consts::PI;
use std::fmt::{Display, Formatter, Error};
use std::ops::{Add, Div, Mul, Neg, Sub};

/// An angle.
///
/// Might be a value in degrees or in radians.
#[derive(Copy, Clone, Debug)]
pub enum Angle<T=f64> {
    Radians(T),
    Degrees(T)
}

impl<T: NumCast> Angle<T> {
    /// Yield the value encoded in radians.
    pub fn in_radians(self) -> T {
        match self {
            Radians(v) => v,
            Degrees(v) => cast(cast::<T, f64>(v).unwrap() / 180.0 * PI).unwrap()
        }
    }

    /// Yield the value encoded in degrees.
    pub fn in_degrees(self) -> T {
        match self {
            Radians(v) => cast(cast::<T, f64>(v).unwrap() / PI * 180.0).unwrap(),
            Degrees(v) => v
        }
    }
}

impl<T: Copy + Num + NumCast + PartialOrd> Angle<T> {
    /// Create a new angle by normalizing the value into the range of
    /// [0, 2π) rad.
    pub fn normalized(self) -> Self {
        let (v, upper) = match self {
            Radians(v) => (v, cast(2.0 * PI).unwrap()),
            Degrees(v) => (v, cast(360.0).unwrap())
        };

        let normalized = if v < upper && v >= Zero::zero() {
            v
        } else {
            let v = v % upper;

            if v >= Zero::zero() {
                v
            } else {
                v + upper
            }
        };

        match self {
            Radians(_) => Radians(normalized),
            Degrees(_) => Degrees(normalized)
        }
    }
}

impl<T: Signed> Angle<T> {
    /// Compute the absolute angle.
    pub fn abs(self) -> Self {
        match self {
            Radians(v) => Radians(v.abs()),
            Degrees(v) => Degrees(v.abs())
        }
    }
}

impl<T: Float + NumCast> Angle<T> {
    /// Compute the sine of the angle.
    pub fn sin(self) -> T {
        self.in_radians().sin()
    }

    /// Compute the cosine of the angle.
    pub fn cos(self) -> T {
        self.in_radians().cos()
    }

    /// Compute the tangent of the angle.
    pub fn tan(self) -> T {
        self.in_radians().tan()
    }

    /// Simultaneously compute the sine and cosine of the number, `x`.
    /// Return `(sin(x), cos(x))`.
    pub fn sin_cos(self) -> (T, T) {
        self.in_radians().sin_cos()
    }

    /*
    /// Computes the approximate mean of a set of angles by averaging the
    /// Cartesian coordinates of the angles on the unit circle.
    pub fn mean(angles: &[Angle<T>]) -> Angle<T> {
        let mut x: T = Zero::zero();
        let mut y: T = Zero::zero();

        for angle in angles.iter() {
            let radian = angle.as_radian();
            x = x + radian.cos();
            y = y + radian.sin();
        }

        let n = cast(angles.len()).unwrap();
        let a = (y/n).atan2(x/n);

        Radian(a).normalize()
    }

    /// Computes the minimal unsigned distance between two normalized angles.
    pub fn distance(&self, other: Angle<T>) -> Angle<T> {
        // FIXME: Once associated types are implemented fix this nightmares of casts #17841
        let pi: T = cast(f64::consts::PI).unwrap();
        let pi2: T = pi * cast(2.0).unwrap();
        let d = (self.as_radian() - other.as_radian()).abs();
        Radian(pi - ((d % (pi2)) - pi).abs())
    }*/
}

impl<T: Float> Angle<T> {
    /// Compute the arcsine of a number. Return value is in the range of
    /// [-π/2, π/2] rad or `None` if the number is outside the range [-1, 1].
    pub fn asin(value: T) -> Option<Self> {
        let value = value.asin();
        if value.is_nan() {
            None
        } else {
            Some(Radians(value))
        }
    }

    /// Compute the arccosine of a number. Return value is in the range of
    /// [0, π] rad or `None` if the number is outside the range [-1, 1].
    pub fn acos(value: T) -> Option<Self> {
        let value = value.acos();
        if value.is_nan() {
            None
        } else {
            Some(Radians(value))
        }
    }

    /// Compute the arctangent of a number. Return value is in the range of
    /// [-π/2, π/2] rad.
    pub fn atan(value: T) -> Self {
        Radians(value.atan())
    }

    /// Compute the four quadrant arctangent of `y` and `x`.
    pub fn atan2(y: T, x: T) -> Self {
        Radians(y.atan2(x))
    }
}

impl<T: Zero + Copy + NumCast> Zero for Angle<T> {
    fn zero() -> Self {
        Radians(T::zero())
    }

    fn is_zero(&self) -> bool {
        match self {
            &Radians(ref v) => v.is_zero(),
            &Degrees(ref v) => v.is_zero()
        }
    }
}

impl<T: PartialEq + Copy + NumCast> PartialEq for Angle<T> {
    fn eq(&self, other: &Angle<T>) -> bool {
        if let (Degrees(a), Degrees(b)) = (*self, *other) {
            a == b
        } else {
            self.in_radians() == other.in_radians()
        }
    }
}

macro_rules! math_additive(
    ($bound:ident, $func:ident) => (
        impl<T: $bound + Copy + NumCast> $bound for Angle<T> {
            type Output = Angle<T::Output>;
            fn $func(self, rhs: Angle<T>) -> Self::Output {
                if let (Degrees(a), Degrees(b)) = (self, rhs) {
                    Degrees(a.$func(b))
                } else {
                    Radians(self.in_radians().$func(rhs.in_radians()))
                }
            }
        }
    );
);

math_additive!(Add, add);
math_additive!(Sub, sub);

macro_rules! math_multiplicative(
    ($bound:ident, $func:ident, $($t:ident),*) => (
        impl<T: $bound> $bound<T> for Angle<T> {
            type Output = Angle<T::Output>;
            fn $func(self, rhs: T) -> Self::Output {
                match self {
                    Radians(v) => Radians(v.$func(rhs)),
                    Degrees(v) => Degrees(v.$func(rhs))
                }
            }
        }

        $(
            impl $bound<Angle<$t>> for $t {
                type Output = Angle<$t>;
                fn $func(self, rhs: Angle<$t>) -> Self::Output {
                    match rhs {
                        Radians(v) => Radians(self.$func(v)),
                        Degrees(v) => Degrees(self.$func(v))
                    }
                }
            }
        )*
    );
);

math_multiplicative!(Mul, mul, u8, u16, u32, u64, i8, i16, i32, i64, usize, isize, f32, f64);
math_multiplicative!(Div, div, u8, u16, u32, u64, i8, i16, i32, i64, usize, isize, f32, f64);

impl<T: Neg> Neg for Angle<T> {
    type Output = Angle<T::Output>;
    fn neg(self) -> Self::Output {
        match self {
            Radians(v) => Radians(-v),
            Degrees(v) => Degrees(-v)
        }
    }
}

impl<T: Display> Display for Angle<T> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        match *self {
            Radians(ref v) => write!(f, "{}rad", v),
            Degrees(ref v) => write!(f, "{}°", v)
        }
    }
}

unsafe impl<T: Send> Send for Angle<T> {  }

/*
impl<T: Encodable + Float + NumCast> Encodable for Angle<T> {
    fn encode<S: Encoder>(&self,  s: &mut S) -> Result<(), S::Error> {
        self.as_radian().encode(s)
    }
}

impl<T: Decodable + Float + NumCast> Decodable for Angle<T> {
    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
        let t = try!(T::decode(d));
        Ok(Angle::Radian(t))
    }
}
*/

// re-exports
pub use Angle::{Radians, Degrees};

#[cfg(test)]
mod tests {
    use num::{Float, cast};
    use quickcheck::{Arbitrary, Gen};
    use std::f64::consts::PI;
    use super::{Angle, Radians, Degrees};

    #[quickcheck]
    fn test_angle_conversions(angle: Angle<f64>) -> bool {
        are_close(angle.in_radians(), Degrees(angle.in_degrees()).in_radians())
    }

    #[quickcheck]
    fn test_angle_math_multiplicative(a: Angle<f64>, x: f64) -> bool {
        match a {
            Radians(v) => (a * x).in_radians() == v * x &&
                          (a / x).in_radians() == v / x,
            Degrees(v) => (a * x).in_degrees() == v * x &&
                          (a / x).in_degrees() == v / x
        }
    }

    #[quickcheck]
    fn test_angle_math_additive(a: Angle, b: Angle) -> bool {
        if let (Radians(x), Radians(y)) = (a, b) {
            (a + b).in_radians() == x + y &&
            (a - b).in_radians() == x - y
        } else if let (Degrees(x), Degrees(y)) = (a, b) {
            (a + b).in_degrees() == x + y &&
            (a - b).in_degrees() == x - y
        } else {
            (a + b).in_radians() == a.in_radians() + b.in_radians()
        }
    }

    #[quickcheck]
    fn test_angle_normalization(angle: Angle) -> bool {
        let v = angle.normalized();
        let rad = v.in_radians();
        let deg = v.in_degrees();

        0.0 <= rad && rad < 2.0 * PI &&
        0.0 <= deg && deg < 360.0 &&
        are_close(rad.cos(), angle.cos())
    }

    fn are_close<T: Float>(a: T, b: T) -> bool {
        (a - b).abs() < cast(1.0e-10).unwrap()
    }

    impl<T: Arbitrary> Arbitrary for Angle<T> {
        fn arbitrary<G: Gen>(g: &mut G) -> Self {
            let v = Arbitrary::arbitrary(g);
            if bool::arbitrary(g) {
                Radians(v)
            } else {
                Degrees(v)
            }
        }
    }
}
<|endoftext|>


<commit_before>use serial::{Serial, SerialCallback};
use timer::Timer;
use keypad::Keypad;
use gpu::GPU;
use sound::Sound;
use gbmode::{GbMode, GbSpeed};
use std::path;

const WRAM_SIZE: usize = 0x8000;
const ZRAM_SIZE: usize = 0x7F;

#[derive(PartialEq)]
enum DMAType {
    NoDMA,
    GDMA,
    HDMA,
}

pub struct MMU<'a> {
    wram: [u8; WRAM_SIZE],
    zram: [u8; ZRAM_SIZE],
    hdma: [u8; 4],
    pub inte: u8,
    pub intf: u8,
    pub serial: Serial<'a>,
    pub timer: Timer,
    pub keypad: Keypad,
    pub gpu: GPU,
    pub sound: Option<Sound>,
    hdma_status: DMAType,
    hdma_src: u16,
    hdma_dst: u16,
    hdma_len: u8,
    wrambank: usize,
    mbc: Box<::mbc::MBC+'static>,
    gbmode: GbMode,
    gbspeed: GbSpeed,
    speed_switch_req: bool,
}

impl<'a> MMU<'a> {
    pub fn new(romname: &str, serial_callback: Option<SerialCallback<'a>>) -> ::StrResult<MMU<'a>> {
        let mmu_mbc = try!(::mbc::get_mbc(path::PathBuf::from(romname)));
        let serial = match serial_callback {
            Some(cb) => Serial::new_with_callback(cb),
            None => Serial::new(),
        };
        let mut res = MMU {
            wram: [0; WRAM_SIZE],
            zram: [0; ZRAM_SIZE],
            hdma: [0; 4],
            wrambank: 1,
            inte: 0,
            intf: 0,
            serial: serial,
            timer: Timer::new(),
            keypad: Keypad::new(),
            gpu: GPU::new(),
            sound: None,
            mbc: mmu_mbc,
            gbmode: GbMode::Classic,
            gbspeed: GbSpeed::Single,
            speed_switch_req: false,
            hdma_src: 0,
            hdma_dst: 0,
            hdma_status: DMAType::NoDMA,
            hdma_len: 0xFF,
        };
        if res.rb(0x0143) == 0xC0 {
            return Err("This game does not work in Classic mode");
        }
        res.set_initial();
        Ok(res)
    }

    pub fn new_cgb(romname: &str, serial_callback: Option<SerialCallback<'a>>) -> ::StrResult<MMU<'a>> {
        let mmu_mbc = try!(::mbc::get_mbc(path::PathBuf::from(romname)));
        let serial = match serial_callback {
            Some(cb) => Serial::new_with_callback(cb),
            None => Serial::new(),
        };
        let mut res = MMU {
            wram: [0; WRAM_SIZE],
            zram: [0; ZRAM_SIZE],
            wrambank: 1,
            hdma: [0; 4],
            inte: 0,
            intf: 0,
            serial: serial,
            timer: Timer::new(),
            keypad: Keypad::new(),
            gpu: GPU::new_cgb(),
            sound: None,
            mbc: mmu_mbc,
            gbmode: GbMode::Color,
            gbspeed: GbSpeed::Single,
            speed_switch_req: false,
            hdma_src: 0,
            hdma_dst: 0,
            hdma_status: DMAType::NoDMA,
            hdma_len: 0xFF,
        };
        res.determine_mode();
        res.set_initial();
        Ok(res)
    }

    fn set_initial(&mut self) {
        self.wb(0xFF05, 0);
        self.wb(0xFF06, 0);
        self.wb(0xFF07, 0);
        self.wb(0xFF10, 0x80);
        self.wb(0xFF11, 0xBF);
        self.wb(0xFF12, 0xF3);
        self.wb(0xFF14, 0xBF);
        self.wb(0xFF16, 0x3F);
        self.wb(0xFF16, 0x3F);
        self.wb(0xFF17, 0);
        self.wb(0xFF19, 0xBF);
        self.wb(0xFF1A, 0x7F);
        self.wb(0xFF1B, 0xFF);
        self.wb(0xFF1C, 0x9F);
        self.wb(0xFF1E, 0xFF);
        self.wb(0xFF20, 0xFF);
        self.wb(0xFF21, 0);
        self.wb(0xFF22, 0);
        self.wb(0xFF23, 0xBF);
        self.wb(0xFF24, 0x77);
        self.wb(0xFF25, 0xF3);
        self.wb(0xFF26, 0xF1);
        self.wb(0xFF40, 0x91);
        self.wb(0xFF42, 0);
        self.wb(0xFF43, 0);
        self.wb(0xFF45, 0);
        self.wb(0xFF47, 0xFC);
        self.wb(0xFF48, 0xFF);
        self.wb(0xFF49, 0xFF);
        self.wb(0xFF4A, 0);
        self.wb(0xFF4B, 0);
    }

    fn determine_mode(&mut self) {
        let mode = match self.rb(0x0143) & 0x80 {
            0x80 => GbMode::Color,
            _ => GbMode::ColorAsClassic,
        };
        self.gbmode = mode;
        self.gpu.gbmode = mode;
    }

    pub fn do_cycle(&mut self, cputicks: u32) -> u32 {
        let cpudivider = match self.gbspeed {
            GbSpeed::Single => 1,
            GbSpeed::Double => 2,
        };
        let ticks = cputicks / cpudivider;
        let gputicks = ticks + self.perform_vramdma();

        self.timer.do_cycle(ticks);
        self.intf |= self.timer.interrupt;
        self.timer.interrupt = 0;

        self.intf |= self.keypad.interrupt;
        self.keypad.interrupt = 0;

        self.gpu.do_cycle(gputicks);
        self.intf |= self.gpu.interrupt;
        self.gpu.interrupt = 0;

        self.sound.as_mut().map_or((), |s| s.do_cycle(gputicks));

        return gputicks;
    }

    pub fn rb(&mut self, address: u16) -> u8 {
        match address {
            0x0000 ... 0x7FFF => self.mbc.readrom(address),
            0x8000 ... 0x9FFF => self.gpu.rb(address),
            0xA000 ... 0xBFFF => self.mbc.readram(address),
            0xC000 ... 0xCFFF | 0xE000 ... 0xEFFF => self.wram[address as usize & 0x0FFF],
            0xD000 ... 0xDFFF | 0xF000 ... 0xFDFF => self.wram[(self.wrambank * 0x1000) | address as usize & 0x0FFF],
            0xFE00 ... 0xFE9F => self.gpu.rb(address),
            0xFF00 => self.keypad.rb(),
            0xFF01 ... 0xFF02 => self.serial.rb(address),
            0xFF04 ... 0xFF07 => self.timer.rb(address),
            0xFF0F => self.intf,
            0xFF10 ... 0xFF3F => self.sound.as_mut().map_or(0, |s| s.rb(address)),
            0xFF4D => (if self.gbspeed == GbSpeed::Double { 0x80 } else { 0 }) | (if self.speed_switch_req { 1 } else { 0 }),
            0xFF40 ... 0xFF4F => self.gpu.rb(address),
            0xFF51 ... 0xFF55 => self.hdma_read(address),
            0xFF68 ... 0xFF6B => self.gpu.rb(address),
            0xFF70 => self.wrambank as u8,
            0xFF80 ... 0xFFFE => self.zram[address as usize & 0x007F],
            0xFFFF => self.inte,
            _ => 0,
        }
    }

    pub fn rw(&mut self, address: u16) -> u16 {
        (self.rb(address) as u16) | ((self.rb(address + 1) as u16) << 8)
    }

    pub fn wb(&mut self, address: u16, value: u8) {
        match address {
            0x0000 ... 0x7FFF => self.mbc.writerom(address, value),
            0x8000 ... 0x9FFF => self.gpu.wb(address, value),
            0xA000 ... 0xBFFF => self.mbc.writeram(address, value),
            0xC000 ... 0xCFFF | 0xE000 ... 0xEFFF => self.wram[address as usize & 0x0FFF] = value,
            0xD000 ... 0xDFFF | 0xF000 ... 0xFDFF => self.wram[(self.wrambank * 0x1000) | (address as usize & 0x0FFF)] = value,
            0xFE00 ... 0xFE9F => self.gpu.wb(address, value),
            0xFF00 => self.keypad.wb(value),
            0xFF01 ... 0xFF02 => self.serial.wb(address, value),
            0xFF04 ... 0xFF07 => self.timer.wb(address, value),
            0xFF10 ... 0xFF3F => self.sound.as_mut().map_or((), |s| s.wb(address, value)),
            0xFF46 => self.oamdma(value),
            0xFF4D => if value & 0x1 == 0x1 { self.speed_switch_req = true; },
            0xFF40 ... 0xFF4F => self.gpu.wb(address, value),
            0xFF51 ... 0xFF55 => self.hdma_write(address, value),
            0xFF68 ... 0xFF6B => self.gpu.wb(address, value),
            0xFF0F => self.intf = value,
            0xFF70 => { self.wrambank = match value & 0x7 { 0 => 1, n => n as usize }; },
            0xFF80 ... 0xFFFE => self.zram[address as usize & 0x007F] = value,
            0xFFFF => self.inte = value,
            _ => {},
        };
    }

    pub fn ww(&mut self, address: u16, value: u16) {
        self.wb(address, (value & 0xFF) as u8);
        self.wb(address + 1, (value >> 8) as u8);
    }

    pub fn switch_speed(&mut self) {
        if self.speed_switch_req {
            if self.gbspeed == GbSpeed::Double {
                self.gbspeed = GbSpeed::Single;
            } else {
                self.gbspeed = GbSpeed::Double;
            }
        }
        self.speed_switch_req = false;
    }

    fn oamdma(&mut self, value: u8) {
        let base = (value as u16) << 8;
        for i in (0u16 .. 0xA0) {
            let b = self.rb(base + i);
            self.wb(0xFE00 + i, b);
        }
    }

    fn hdma_read(&self, a: u16) -> u8 {
        match a {
            0xFF51 ... 0xFF54 => { self.hdma[(a - 0xFF51) as usize] },
            0xFF55 => self.hdma_len | if self.hdma_status == DMAType::NoDMA { 0x80 } else { 0 },
            _ => panic!("The address {:04X} should not be handled by hdma_read", a),
        }
    }

    fn hdma_write(&mut self, a: u16, v: u8) {
        match a {
            0xFF51 => self.hdma[0] = v,
            0xFF52 => self.hdma[1] = v & 0xF0,
            0xFF53 => self.hdma[2] = v & 0x1F,
            0xFF54 => self.hdma[3] = v & 0xF0,
            0xFF55 => {
                if self.hdma_status == DMAType::HDMA {
                    if v & 0x80 == 0 { self.hdma_status = DMAType::NoDMA; };
                    return;
                }
                let src = ((self.hdma[0] as u16) << 8) | (self.hdma[1] as u16);
                let dst = ((self.hdma[2] as u16) << 8) | (self.hdma[3] as u16) | 0x8000;
                if !(src <= 0x7FF0 || (src >= 0xA000 && src <= 0xDFF0)) { panic!("HDMA transfer with illegal start address {:04X}", src); }

                self.hdma_src = src;
                self.hdma_dst = dst;
                self.hdma_len = v & 0x7F;

                self.hdma_status =
                    if v & 0x80 == 0x80 { DMAType::HDMA }
                    else { DMAType::GDMA };
            },
            _ => panic!("The address {:04X} should not be handled by hdma_write", a),
        };
    }

    fn perform_vramdma(&mut self) -> u32 {
        match self.hdma_status {
            DMAType::NoDMA => 0,
            DMAType::GDMA => self.perform_gdma(),
            DMAType::HDMA => self.perform_hdma(),
        }
    }

    fn perform_hdma(&mut self) -> u32 {
        if self.gpu.may_hdma() == false {
            return 0;
        }

        self.perform_vramdma_row();
        if self.hdma_len == 0x7F { self.hdma_status = DMAType::NoDMA; }

        return 8;
    }

    fn perform_gdma(&mut self) -> u32 {
        let len = self.hdma_len as u32 + 1;
        for _i in (0 .. len) {
            self.perform_vramdma_row();
        }

        self.hdma_status = DMAType::NoDMA;
        return len * 8;
    }

    fn perform_vramdma_row(&mut self) {
        let mmu_src = self.hdma_src;
        for j in (0u16 .. 0x10) {
            let b: u8 = self.rb(mmu_src + j);
            self.gpu.wb(self.hdma_dst + j, b);
        }
        self.hdma_src += 0x10;
        self.hdma_dst += 0x10;

        if self.hdma_len == 0 {
            self.hdma_len = 0x7F;
        }
        else {
            self.hdma_len -= 1;
        }
    }
}
<commit_msg>Fix timer running to slow in double speed mode<commit_after>use serial::{Serial, SerialCallback};
use timer::Timer;
use keypad::Keypad;
use gpu::GPU;
use sound::Sound;
use gbmode::{GbMode, GbSpeed};
use std::path;

const WRAM_SIZE: usize = 0x8000;
const ZRAM_SIZE: usize = 0x7F;

#[derive(PartialEq)]
enum DMAType {
    NoDMA,
    GDMA,
    HDMA,
}

pub struct MMU<'a> {
    wram: [u8; WRAM_SIZE],
    zram: [u8; ZRAM_SIZE],
    hdma: [u8; 4],
    pub inte: u8,
    pub intf: u8,
    pub serial: Serial<'a>,
    pub timer: Timer,
    pub keypad: Keypad,
    pub gpu: GPU,
    pub sound: Option<Sound>,
    hdma_status: DMAType,
    hdma_src: u16,
    hdma_dst: u16,
    hdma_len: u8,
    wrambank: usize,
    mbc: Box<::mbc::MBC+'static>,
    gbmode: GbMode,
    gbspeed: GbSpeed,
    speed_switch_req: bool,
}

impl<'a> MMU<'a> {
    pub fn new(romname: &str, serial_callback: Option<SerialCallback<'a>>) -> ::StrResult<MMU<'a>> {
        let mmu_mbc = try!(::mbc::get_mbc(path::PathBuf::from(romname)));
        let serial = match serial_callback {
            Some(cb) => Serial::new_with_callback(cb),
            None => Serial::new(),
        };
        let mut res = MMU {
            wram: [0; WRAM_SIZE],
            zram: [0; ZRAM_SIZE],
            hdma: [0; 4],
            wrambank: 1,
            inte: 0,
            intf: 0,
            serial: serial,
            timer: Timer::new(),
            keypad: Keypad::new(),
            gpu: GPU::new(),
            sound: None,
            mbc: mmu_mbc,
            gbmode: GbMode::Classic,
            gbspeed: GbSpeed::Single,
            speed_switch_req: false,
            hdma_src: 0,
            hdma_dst: 0,
            hdma_status: DMAType::NoDMA,
            hdma_len: 0xFF,
        };
        if res.rb(0x0143) == 0xC0 {
            return Err("This game does not work in Classic mode");
        }
        res.set_initial();
        Ok(res)
    }

    pub fn new_cgb(romname: &str, serial_callback: Option<SerialCallback<'a>>) -> ::StrResult<MMU<'a>> {
        let mmu_mbc = try!(::mbc::get_mbc(path::PathBuf::from(romname)));
        let serial = match serial_callback {
            Some(cb) => Serial::new_with_callback(cb),
            None => Serial::new(),
        };
        let mut res = MMU {
            wram: [0; WRAM_SIZE],
            zram: [0; ZRAM_SIZE],
            wrambank: 1,
            hdma: [0; 4],
            inte: 0,
            intf: 0,
            serial: serial,
            timer: Timer::new(),
            keypad: Keypad::new(),
            gpu: GPU::new_cgb(),
            sound: None,
            mbc: mmu_mbc,
            gbmode: GbMode::Color,
            gbspeed: GbSpeed::Single,
            speed_switch_req: false,
            hdma_src: 0,
            hdma_dst: 0,
            hdma_status: DMAType::NoDMA,
            hdma_len: 0xFF,
        };
        res.determine_mode();
        res.set_initial();
        Ok(res)
    }

    fn set_initial(&mut self) {
        self.wb(0xFF05, 0);
        self.wb(0xFF06, 0);
        self.wb(0xFF07, 0);
        self.wb(0xFF10, 0x80);
        self.wb(0xFF11, 0xBF);
        self.wb(0xFF12, 0xF3);
        self.wb(0xFF14, 0xBF);
        self.wb(0xFF16, 0x3F);
        self.wb(0xFF16, 0x3F);
        self.wb(0xFF17, 0);
        self.wb(0xFF19, 0xBF);
        self.wb(0xFF1A, 0x7F);
        self.wb(0xFF1B, 0xFF);
        self.wb(0xFF1C, 0x9F);
        self.wb(0xFF1E, 0xFF);
        self.wb(0xFF20, 0xFF);
        self.wb(0xFF21, 0);
        self.wb(0xFF22, 0);
        self.wb(0xFF23, 0xBF);
        self.wb(0xFF24, 0x77);
        self.wb(0xFF25, 0xF3);
        self.wb(0xFF26, 0xF1);
        self.wb(0xFF40, 0x91);
        self.wb(0xFF42, 0);
        self.wb(0xFF43, 0);
        self.wb(0xFF45, 0);
        self.wb(0xFF47, 0xFC);
        self.wb(0xFF48, 0xFF);
        self.wb(0xFF49, 0xFF);
        self.wb(0xFF4A, 0);
        self.wb(0xFF4B, 0);
    }

    fn determine_mode(&mut self) {
        let mode = match self.rb(0x0143) & 0x80 {
            0x80 => GbMode::Color,
            _ => GbMode::ColorAsClassic,
        };
        self.gbmode = mode;
        self.gpu.gbmode = mode;
    }

    pub fn do_cycle(&mut self, ticks: u32) -> u32 {
        let cpudivider = match self.gbspeed {
            GbSpeed::Single => 1,
            GbSpeed::Double => 2,
        };
        let vramticks = self.perform_vramdma();
        let gputicks = ticks / cpudivider + vramticks;
        let cputicks = ticks + vramticks * cpudivider;

        self.timer.do_cycle(cputicks);
        self.intf |= self.timer.interrupt;
        self.timer.interrupt = 0;

        self.intf |= self.keypad.interrupt;
        self.keypad.interrupt = 0;

        self.gpu.do_cycle(gputicks);
        self.intf |= self.gpu.interrupt;
        self.gpu.interrupt = 0;

        self.sound.as_mut().map_or((), |s| s.do_cycle(gputicks));

        return gputicks;
    }

    pub fn rb(&mut self, address: u16) -> u8 {
        match address {
            0x0000 ... 0x7FFF => self.mbc.readrom(address),
            0x8000 ... 0x9FFF => self.gpu.rb(address),
            0xA000 ... 0xBFFF => self.mbc.readram(address),
            0xC000 ... 0xCFFF | 0xE000 ... 0xEFFF => self.wram[address as usize & 0x0FFF],
            0xD000 ... 0xDFFF | 0xF000 ... 0xFDFF => self.wram[(self.wrambank * 0x1000) | address as usize & 0x0FFF],
            0xFE00 ... 0xFE9F => self.gpu.rb(address),
            0xFF00 => self.keypad.rb(),
            0xFF01 ... 0xFF02 => self.serial.rb(address),
            0xFF04 ... 0xFF07 => self.timer.rb(address),
            0xFF0F => self.intf,
            0xFF10 ... 0xFF3F => self.sound.as_mut().map_or(0, |s| s.rb(address)),
            0xFF4D => (if self.gbspeed == GbSpeed::Double { 0x80 } else { 0 }) | (if self.speed_switch_req { 1 } else { 0 }),
            0xFF40 ... 0xFF4F => self.gpu.rb(address),
            0xFF51 ... 0xFF55 => self.hdma_read(address),
            0xFF68 ... 0xFF6B => self.gpu.rb(address),
            0xFF70 => self.wrambank as u8,
            0xFF80 ... 0xFFFE => self.zram[address as usize & 0x007F],
            0xFFFF => self.inte,
            _ => 0,
        }
    }

    pub fn rw(&mut self, address: u16) -> u16 {
        (self.rb(address) as u16) | ((self.rb(address + 1) as u16) << 8)
    }

    pub fn wb(&mut self, address: u16, value: u8) {
        match address {
            0x0000 ... 0x7FFF => self.mbc.writerom(address, value),
            0x8000 ... 0x9FFF => self.gpu.wb(address, value),
            0xA000 ... 0xBFFF => self.mbc.writeram(address, value),
            0xC000 ... 0xCFFF | 0xE000 ... 0xEFFF => self.wram[address as usize & 0x0FFF] = value,
            0xD000 ... 0xDFFF | 0xF000 ... 0xFDFF => self.wram[(self.wrambank * 0x1000) | (address as usize & 0x0FFF)] = value,
            0xFE00 ... 0xFE9F => self.gpu.wb(address, value),
            0xFF00 => self.keypad.wb(value),
            0xFF01 ... 0xFF02 => self.serial.wb(address, value),
            0xFF04 ... 0xFF07 => self.timer.wb(address, value),
            0xFF10 ... 0xFF3F => self.sound.as_mut().map_or((), |s| s.wb(address, value)),
            0xFF46 => self.oamdma(value),
            0xFF4D => if value & 0x1 == 0x1 { self.speed_switch_req = true; },
            0xFF40 ... 0xFF4F => self.gpu.wb(address, value),
            0xFF51 ... 0xFF55 => self.hdma_write(address, value),
            0xFF68 ... 0xFF6B => self.gpu.wb(address, value),
            0xFF0F => self.intf = value,
            0xFF70 => { self.wrambank = match value & 0x7 { 0 => 1, n => n as usize }; },
            0xFF80 ... 0xFFFE => self.zram[address as usize & 0x007F] = value,
            0xFFFF => self.inte = value,
            _ => {},
        };
    }

    pub fn ww(&mut self, address: u16, value: u16) {
        self.wb(address, (value & 0xFF) as u8);
        self.wb(address + 1, (value >> 8) as u8);
    }

    pub fn switch_speed(&mut self) {
        if self.speed_switch_req {
            if self.gbspeed == GbSpeed::Double {
                self.gbspeed = GbSpeed::Single;
            } else {
                self.gbspeed = GbSpeed::Double;
            }
        }
        self.speed_switch_req = false;
    }

    fn oamdma(&mut self, value: u8) {
        let base = (value as u16) << 8;
        for i in (0u16 .. 0xA0) {
            let b = self.rb(base + i);
            self.wb(0xFE00 + i, b);
        }
    }

    fn hdma_read(&self, a: u16) -> u8 {
        match a {
            0xFF51 ... 0xFF54 => { self.hdma[(a - 0xFF51) as usize] },
            0xFF55 => self.hdma_len | if self.hdma_status == DMAType::NoDMA { 0x80 } else { 0 },
            _ => panic!("The address {:04X} should not be handled by hdma_read", a),
        }
    }

    fn hdma_write(&mut self, a: u16, v: u8) {
        match a {
            0xFF51 => self.hdma[0] = v,
            0xFF52 => self.hdma[1] = v & 0xF0,
            0xFF53 => self.hdma[2] = v & 0x1F,
            0xFF54 => self.hdma[3] = v & 0xF0,
            0xFF55 => {
                if self.hdma_status == DMAType::HDMA {
                    if v & 0x80 == 0 { self.hdma_status = DMAType::NoDMA; };
                    return;
                }
                let src = ((self.hdma[0] as u16) << 8) | (self.hdma[1] as u16);
                let dst = ((self.hdma[2] as u16) << 8) | (self.hdma[3] as u16) | 0x8000;
                if !(src <= 0x7FF0 || (src >= 0xA000 && src <= 0xDFF0)) { panic!("HDMA transfer with illegal start address {:04X}", src); }

                self.hdma_src = src;
                self.hdma_dst = dst;
                self.hdma_len = v & 0x7F;

                self.hdma_status =
                    if v & 0x80 == 0x80 { DMAType::HDMA }
                    else { DMAType::GDMA };
            },
            _ => panic!("The address {:04X} should not be handled by hdma_write", a),
        };
    }

    fn perform_vramdma(&mut self) -> u32 {
        match self.hdma_status {
            DMAType::NoDMA => 0,
            DMAType::GDMA => self.perform_gdma(),
            DMAType::HDMA => self.perform_hdma(),
        }
    }

    fn perform_hdma(&mut self) -> u32 {
        if self.gpu.may_hdma() == false {
            return 0;
        }

        self.perform_vramdma_row();
        if self.hdma_len == 0x7F { self.hdma_status = DMAType::NoDMA; }

        return 8;
    }

    fn perform_gdma(&mut self) -> u32 {
        let len = self.hdma_len as u32 + 1;
        for _i in (0 .. len) {
            self.perform_vramdma_row();
        }

        self.hdma_status = DMAType::NoDMA;
        return len * 8;
    }

    fn perform_vramdma_row(&mut self) {
        let mmu_src = self.hdma_src;
        for j in (0u16 .. 0x10) {
            let b: u8 = self.rb(mmu_src + j);
            self.gpu.wb(self.hdma_dst + j, b);
        }
        self.hdma_src += 0x10;
        self.hdma_dst += 0x10;

        if self.hdma_len == 0 {
            self.hdma_len = 0x7F;
        }
        else {
            self.hdma_len -= 1;
        }
    }
}
<|endoftext|>


<commit_before>//! SRT-format subtitle support.

use std::io::File;
use std::num::Float;

use err::Result as MyResult;
use err::ParseError;

/// Format seconds using the standard SRT time format.
pub fn format_time(time: f32) -> String {
    let (h, rem) = ((time / 3600.0).trunc(), time % 3600.0);
    let (m, s) = ((rem / 60.0).trunc(), rem % 60.0);
    (format!("{:02f}:{:02f}:{:0>6.3f}", h, m, s)).replace(".", ",")
}

/// A single SRT-format subtitle, minus some of the optional fields used in
/// various versions of the file format.
#[deriving(Show, PartialEq, Clone)]
pub struct Subtitle {
    /// The index of this subtitle.  We should normalize these to start
    /// with 1 on output.
    pub index: uint,

    /// The start time of this subtitle, in seconds.
    pub begin: f32,

    /// The end time of this subtitle, in seconds.
    pub end: f32,

    /// The lines of text in this subtitle.
    pub lines: Vec<String>
}

impl Subtitle {
    /// Return a string representation of this subtitle.
    pub fn to_string(&self) -> String {
        format!("{}\n{} --> {}\n{}\n", self.index,
                format_time(self.begin),
                format_time(self.end),
                self.lines.connect("\n"))
    }
}

/// The contents of an SRT-format subtitle file.
#[deriving(Show, PartialEq)]
pub struct SubtitleFile {
    /// The subtitles in this file.
    pub subtitles: Vec<Subtitle>
}

impl SubtitleFile {
    /// Parse raw subtitle text into an appropriate structure.
    pub fn from_str(data: &str) -> MyResult<SubtitleFile> {
        match grammar::subtitle_file(data) {
            Ok(file) => Ok(file),
            Err(msg) => Err(ParseError(msg))
        }
    }

    /// Parse the subtitle file found at the specified path.
    pub fn from_path(path: &Path) -> MyResult<SubtitleFile> {
        let mut file = try!(File::open(path));
        let data = try!(file.read_to_string());
        SubtitleFile::from_str(data.as_slice())
    }

    /// Convert subtitles to a string.
    pub fn to_string(&self) -> String {
        let subs: Vec<String> =
            self.subtitles.iter().map(|s| s.to_string()).collect();
        subs.connect("\n")
    }
}

#[cfg(test)]
mod test {
    use srt::{SubtitleFile,Subtitle};

    #[test]
    fn subtitle_file_from_path() {
        let path = Path::new("fixtures/sample.es.srt");
        let srt = SubtitleFile::from_path(&path).unwrap();
        assert_eq!(5, srt.subtitles.len());

        let sub = &srt.subtitles[0];
        assert_eq!(16, sub.index);
        assert_eq!(62.328, sub.begin);
        assert_eq!(64.664, sub.end);
        assert_eq!(vec!("¡Si! ¡Aang ha vuelto!".to_string()), sub.lines);

        let sub2 = &srt.subtitles[2];
        assert_eq!(vec!("Tu diste la señal a la armada".to_string(),
                        "del fuego con la bengala,".to_string()),
                   sub2.lines);
    }

    #[test]
    fn subtitle_to_string() {
        let sub = Subtitle{index: 4, begin: 61.5, end: 63.75,
                           lines: vec!("Line 1".to_string(),
                                       "Line 2".to_string())};
        let expected = r"4
00:01:01,500 --> 00:01:03,750
Line 1
Line 2
".to_string();
        assert_eq!(expected, sub.to_string());
    }

    #[test]
    fn subtitle_file_to_string() {
        let data = r"16
00:01:02,328 --> 00:01:04,664
Line 1.1

17
00:01:12,839 --> 00:01:13,839
Line 2.1
";
        let srt = SubtitleFile::from_str(data).unwrap();
        assert_eq!(data, srt.to_string().as_slice());
    }
}

// Our parser expression grammar.  We'd like to move this to another file.
peg! grammar(r#"
use srt::{Subtitle,SubtitleFile};

#[pub]
subtitle_file -> SubtitleFile
    = blank_lines? result:subtitles blank_lines? {
        SubtitleFile{subtitles: result}
    }

subtitles -> Vec<Subtitle>
    = subs:subtitle ** blank_lines { subs }

subtitle -> Subtitle
    = index:digits newline t:times newline l:lines {
        let (b, e) = t;
        Subtitle{index: index, begin: b, end: e, lines: l}
    }

times -> (f32, f32)
    = begin:time " --> " end:time { (begin, end) }

time -> f32
    = hh:digits ":" mm:digits ":" ss:comma_float {
        (hh as f32)*3600.0 + (mm as f32)*60.0 + ss
    }

lines -> Vec<String>
    = lines:line ** newline { lines }

line -> String
    = [^\r\n]+ { match_str.to_string() }

digits -> uint
    = [0-9]+ { from_str::<uint>(match_str).unwrap() }

comma_float -> f32
    = [0-9]+ "," [0-9]+ {
        let fixed: String = match_str.replace(",", ".");
        from_str::<f32>(fixed.as_slice()).unwrap()
    }

newline
    = "\r"? "\n"

blank_lines
    = newline+

"#)
<commit_msg>Handle optional UTF-8 BOM on input files<commit_after>//! SRT-format subtitle support.

use std::io::File;
use std::num::Float;

use err::Result as MyResult;
use err::ParseError;

/// Format seconds using the standard SRT time format.
pub fn format_time(time: f32) -> String {
    let (h, rem) = ((time / 3600.0).trunc(), time % 3600.0);
    let (m, s) = ((rem / 60.0).trunc(), rem % 60.0);
    (format!("{:02f}:{:02f}:{:0>6.3f}", h, m, s)).replace(".", ",")
}

/// A single SRT-format subtitle, minus some of the optional fields used in
/// various versions of the file format.
#[deriving(Show, PartialEq, Clone)]
pub struct Subtitle {
    /// The index of this subtitle.  We should normalize these to start
    /// with 1 on output.
    pub index: uint,

    /// The start time of this subtitle, in seconds.
    pub begin: f32,

    /// The end time of this subtitle, in seconds.
    pub end: f32,

    /// The lines of text in this subtitle.
    pub lines: Vec<String>
}

impl Subtitle {
    /// Return a string representation of this subtitle.
    pub fn to_string(&self) -> String {
        format!("{}\n{} --> {}\n{}\n", self.index,
                format_time(self.begin),
                format_time(self.end),
                self.lines.connect("\n"))
    }
}

/// The contents of an SRT-format subtitle file.
#[deriving(Show, PartialEq)]
pub struct SubtitleFile {
    /// The subtitles in this file.
    pub subtitles: Vec<Subtitle>
}

impl SubtitleFile {
    /// Parse raw subtitle text into an appropriate structure.
    pub fn from_str(data: &str) -> MyResult<SubtitleFile> {
        match grammar::subtitle_file(data) {
            Ok(file) => Ok(file),
            Err(msg) => Err(ParseError(msg))
        }
    }

    /// Parse the subtitle file found at the specified path.
    pub fn from_path(path: &Path) -> MyResult<SubtitleFile> {
        let mut file = try!(File::open(path));
        let data = try!(file.read_to_string());
        SubtitleFile::from_str(data.as_slice())
    }

    /// Convert subtitles to a string.
    pub fn to_string(&self) -> String {
        let subs: Vec<String> =
            self.subtitles.iter().map(|s| s.to_string()).collect();
        subs.connect("\n")
    }
}

#[cfg(test)]
mod test {
    use srt::{SubtitleFile,Subtitle};

    #[test]
    fn subtitle_file_from_path() {
        let path = Path::new("fixtures/sample.es.srt");
        let srt = SubtitleFile::from_path(&path).unwrap();
        assert_eq!(5, srt.subtitles.len());

        let sub = &srt.subtitles[0];
        assert_eq!(16, sub.index);
        assert_eq!(62.328, sub.begin);
        assert_eq!(64.664, sub.end);
        assert_eq!(vec!("¡Si! ¡Aang ha vuelto!".to_string()), sub.lines);

        let sub2 = &srt.subtitles[2];
        assert_eq!(vec!("Tu diste la señal a la armada".to_string(),
                        "del fuego con la bengala,".to_string()),
                   sub2.lines);
    }

    #[test]
    fn subtitle_to_string() {
        let sub = Subtitle{index: 4, begin: 61.5, end: 63.75,
                           lines: vec!("Line 1".to_string(),
                                       "Line 2".to_string())};
        let expected = r"4
00:01:01,500 --> 00:01:03,750
Line 1
Line 2
".to_string();
        assert_eq!(expected, sub.to_string());
    }

    #[test]
    fn subtitle_file_to_string() {
        let data = r"16
00:01:02,328 --> 00:01:04,664
Line 1.1

17
00:01:12,839 --> 00:01:13,839
Line 2.1
";
        let srt = SubtitleFile::from_str(data).unwrap();
        assert_eq!(data, srt.to_string().as_slice());
    }
}

// Our parser expression grammar.  We'd like to move this to another file.
peg! grammar(r#"
use srt::{Subtitle,SubtitleFile};

#[pub]
subtitle_file -> SubtitleFile
    = bom? blank_lines? result:subtitles blank_lines? {
        SubtitleFile{subtitles: result}
    }

subtitles -> Vec<Subtitle>
    = subs:subtitle ** blank_lines { subs }

subtitle -> Subtitle
    = index:digits newline t:times newline l:lines {
        let (b, e) = t;
        Subtitle{index: index, begin: b, end: e, lines: l}
    }

times -> (f32, f32)
    = begin:time " --> " end:time { (begin, end) }

time -> f32
    = hh:digits ":" mm:digits ":" ss:comma_float {
        (hh as f32)*3600.0 + (mm as f32)*60.0 + ss
    }

lines -> Vec<String>
    = lines:line ** newline { lines }

line -> String
    = [^\r\n]+ { match_str.to_string() }

digits -> uint
    = [0-9]+ { from_str::<uint>(match_str).unwrap() }

comma_float -> f32
    = [0-9]+ "," [0-9]+ {
        let fixed: String = match_str.replace(",", ".");
        from_str::<f32>(fixed.as_slice()).unwrap()
    }

bom
    = "\uFEFF"

newline
    = "\r"? "\n"

blank_lines
    = newline+

"#)
<|endoftext|>