<commit_before>//! Multiboot v1 library
//!
//! # Additional documentation
//!   * https://www.gnu.org/software/grub/manual/multiboot/multiboot.html
//!   * http://git.savannah.gnu.org/cgit/grub.git/tree/doc/multiboot.texi?h=multiboot
//!

#![feature(no_std)]
#![feature(core)]
#![feature(raw)]
#![no_std]

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

extern crate core;

#[cfg(test)]
extern crate std;

use core::mem::{transmute};
use core::ops::FnMut;
use core::raw;
use core::str;

/// Value found in %rax after multiboot jumps to our entry point.
pub const SIGNATURE_RAX: u64 = 0x2BADB002;

/// Types that define if the memory is usable or not.
#[derive(Debug, PartialEq, Eq)]
pub enum MemType {
    RAM = 1,
    Unusable = 2,
}

pub type PAddr = u64;
pub type VAddr = usize;

/// Multiboot struct clients mainly interact with
/// To create this use Multiboot::new()
pub struct Multiboot<'a> {
    header: &'a MultibootInfo,
    paddr_to_vaddr: fn(PAddr) -> VAddr,
}

/// Representation of Multiboot header according to specification.
////
///<rawtext>
///         +-------------------+
/// 0       | flags             |    (required)
///         +-------------------+
/// 4       | mem_lower         |    (present if flags[0] is set)
/// 8       | mem_upper         |    (present if flags[0] is set)
///         +-------------------+
/// 12      | boot_device       |    (present if flags[1] is set)
///         +-------------------+
/// 16      | cmdline           |    (present if flags[2] is set)
///         +-------------------+
/// 20      | mods_count        |    (present if flags[3] is set)
/// 24      | mods_addr         |    (present if flags[3] is set)
///         +-------------------+
/// 28 - 40 | syms              |    (present if flags[4] or
///         |                   |                flags[5] is set)
///         +-------------------+
/// 44      | mmap_length       |    (present if flags[6] is set)
/// 48      | mmap_addr         |    (present if flags[6] is set)
///         +-------------------+
/// 52      | drives_length     |    (present if flags[7] is set)
/// 56      | drives_addr       |    (present if flags[7] is set)
///         +-------------------+
/// 60      | config_table      |    (present if flags[8] is set)
///         +-------------------+
/// 64      | boot_loader_name  |    (present if flags[9] is set)
///         +-------------------+
/// 68      | apm_table         |    (present if flags[10] is set)
///         +-------------------+
/// 72      | vbe_control_info  |    (present if flags[11] is set)
/// 76      | vbe_mode_info     |
/// 80      | vbe_mode          |
/// 82      | vbe_interface_seg |
/// 84      | vbe_interface_off |
/// 86      | vbe_interface_len |
///         +-------------------+
///</rawtext>
///
#[derive(Debug)]
#[repr(packed)]
struct MultibootInfo {
    flags: u32,

    /// Indicate the amount of lower memory in kilobytes.
    ///
    /// Lower memory starts at address 0. The maximum possible value for
    /// lower memory is 640 kilobytes.
    mem_lower: u32,

    /// Indicate the amount of upper memory in kilobytes.
    ///
    /// Upper memory starts at address 1 megabyte.
    /// The value returned for upper memory is maximally the address of
    /// the first upper memory hole minus 1 megabyte. It is not guaranteed
    /// to be this value.
    mem_upper: u32,

    boot_device: u32,
    cmdline: u32,

    mods_count: u32,
    mods_addr: u32,

    elf_symbols: ElfSymbols,

    mmap_length: u32,
    mmap_addr: u32,

    drives_length: u32,
    drives_addr: u32,

    config_table: u32,

    boot_loader_name: u32,

    apm_table: u32,

    vbe_control_info: u32,
    vbe_mode_info: u32,
    vbe_mode: u16,
    vbe_interface_off: u16,
    vbe_interface_len: u16
}

/// Multiboot format of the MMAP buffer.
///
/// Note that size is defined to be at -4 bytes in multiboot.
#[derive(Debug)]
#[repr(packed)]
struct MemEntry {
    size: u32,
    base_addr: u64,
    length: u64,
    mtype: u32
}

/// ELF Symbols
#[derive(Debug)]
#[repr(packed)]
struct ElfSymbols {
    num: u32,
    size: u32,
    addr: u32,
    shndx: u32,
}

/// Multiboot module representation
#[derive(Debug)]
#[repr(packed)]
struct Module {
    /// Start address of module in memory.
    start: u32,
    /// End address of module in memory.
    end: u32,
    /// Name of module.
    string: u32,
    /// Must be zero.
    reserved: u32
}

/// Convert a C string into a [u8 slice and from there into a &'static str.
/// This unsafe block builds on assumption that multiboot strings are sane.
fn convert_safe_c_string(cstring: *const u8) -> &'static str {
    unsafe {
        let mut iter = cstring;
        while *iter != 0 {
            iter = iter.offset(1);
        }

        let slice = raw::Slice { data: cstring, len: iter as usize - cstring as usize };
        let byte_array: &'static [u8] = transmute(slice);
        str::from_utf8_unchecked(byte_array)
    }
}

macro_rules! check_flag {
    ($doc:meta, $fun:ident, $bit:expr) => (
        #[$doc]
        pub fn $fun(&self) -> bool {
            //assert!($bit <= 31);
            (self.header.flags & (1 << $bit)) > 0
        }
    );

    // syms field is valid if bit 4 or 5 is set, wtf?
    ($doc:meta, $fun:ident, $bit1:expr, $bit2:expr) => (
        #[$doc]
        pub fn $fun(&self) -> bool {
            //assert!($bit1 <= 31);
            //assert!($bit2 <= 31);
            (self.header.flags & (1 << $bit1)) > 0 || (self.header.flags & (1 << $bit2)) > 0
        }
    );
}

impl<'a> Multiboot<'a> {

    /// Initializes the multiboot structure.
    ///
    /// # Arguments
    ///
    ///  * `mboot_ptr` - The physical address of the multiboot header. On qemu for example
    ///                  this is typically at 0x9500.
    ///  * `paddr_to_vaddr` - Translation of the physical addresses into kernel addresses.
    ///
    ///  `paddr_to_vaddr` translates physical it into a kernel accessible address.
    ///  The simplest paddr_to_vaddr function would for example be just the identity
    ///  function. But this may vary depending on how your page table layout looks like.
    ///
    pub fn new(mboot_ptr: u64, paddr_to_vaddr: fn(paddr: PAddr) -> VAddr) -> Multiboot<'a> {
        let header = paddr_to_vaddr(mboot_ptr);
        let mb: &MultibootInfo = unsafe { transmute::<VAddr, &MultibootInfo>(header) };

        Multiboot { header: mb, paddr_to_vaddr: paddr_to_vaddr }
    }

    check_flag!(doc = "If true, then the `mem_upper` and `mem_lower` fields are valid.",
               has_memory_bounds, 0);
    check_flag!(doc = "If true, then the `boot_device` field is valid.",
               has_boot_device, 1);
    check_flag!(doc = "If true, then the `cmdline` field is valid.",
               has_cmdline, 2);
    check_flag!(doc = "If true, then the `mods_addr` and `mods_count` fields are valid.",
               has_modules, 3);
    check_flag!(doc = "If true, then the `syms` field is valid.",
               has_symbols, 4, 5);
    check_flag!(doc = "If true, then the `mmap_addr` and `mmap_length` fields are valid.",
               has_memory_map, 6);
    check_flag!(doc = "If true, then the `drives_addr` and `drives_length` fields are valid.",
               has_drives, 7);
    check_flag!(doc = "If true, then the `config_table` field is valid.",
               has_config_table, 8);
    check_flag!(doc = "If true, then the `boot_loader_name` field is valid.",
               has_boot_loader_name, 9);
    check_flag!(doc = "If true, then the `apm_table` field is valid.",
               has_apm_table, 10);
    check_flag!(doc = "If true, then the `vbe_*` fields are valid.",
               has_vbe, 11);

    /// Discover all memory regions in the multiboot memory map.
    ///
    /// # Arguments
    ///
    ///  * `discovery_callback` - Function to notify your memory system about regions.
    ///
    pub fn find_memory<F: FnMut(u64, u64, MemType)>(&'a self, mut discovery_callback: F) {
        if !self.has_memory_map() {
            return
        }

        let paddr_to_vaddr = self.paddr_to_vaddr;

        let mut current = self.header.mmap_addr;
        let end = self.header.mmap_addr + self.header.mmap_length;
        while current < end
        {
            let memory_region: &MemEntry = unsafe { transmute::<VAddr, &MemEntry>(paddr_to_vaddr(current as u64)) };

            let mtype = match memory_region.mtype {
                1 => MemType::RAM,
                2 => MemType::Unusable,
                _ => MemType::Unusable
            };

            discovery_callback(memory_region.base_addr, memory_region.length, mtype);
            current += memory_region.size + 4;
        }
    }

    /// Discover all additional modules in multiboot.
    ///
    /// # Arguments
    ///
    ///  * `discovery_callback` - Function to notify your system about modules.
    ///
    pub fn find_modules<F: FnMut(&'static str, VAddr, VAddr)>(&'a self, mut discovery_callback: F) {
        if !self.has_modules() {
            return
        }

        let paddr_to_vaddr = self.paddr_to_vaddr;

        let module_start = paddr_to_vaddr(self.header.mods_addr as u64);
        let count: usize = self.header.mods_count as usize;
        for _ in 0..count {
            let current: &Module = unsafe { transmute::<VAddr, &Module>(module_start) };
            let path = unsafe { convert_safe_c_string(transmute::<VAddr, *const u8>(paddr_to_vaddr(current.string as u64))) };

            discovery_callback(path, paddr_to_vaddr(current.start as PAddr), paddr_to_vaddr(current.end as PAddr));
        }
    }
}
<commit_msg>Refactor code a bit, use more iterators.<commit_after>//! Multiboot v1 library
//!
//! # Additional documentation
//!   * https://www.gnu.org/software/grub/manual/multiboot/multiboot.html
//!   * http://git.savannah.gnu.org/cgit/grub.git/tree/doc/multiboot.texi?h=multiboot
//!

#![feature(core, core_prelude, prelude_import, no_std, raw)]
#![no_std]

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

extern crate core;

#[cfg(test)]
extern crate std;

use core::prelude::*;

use core::mem::{transmute};
use core::raw;
use core::str;
use core::slice;

/// Value found in %rax after multiboot jumps to our entry point.
pub const SIGNATURE_RAX: u64 = 0x2BADB002;

pub type PAddr = u64;
pub type VAddr = usize;

/// Multiboot struct clients mainly interact with
/// To create this use Multiboot::new()
pub struct Multiboot<'a> {
    header: &'a MultibootInfo,
    paddr_to_vaddr: fn(PAddr) -> VAddr,
}

/// Representation of Multiboot header according to specification.
////
///<rawtext>
///         +-------------------+
/// 0       | flags             |    (required)
///         +-------------------+
/// 4       | mem_lower         |    (present if flags[0] is set)
/// 8       | mem_upper         |    (present if flags[0] is set)
///         +-------------------+
/// 12      | boot_device       |    (present if flags[1] is set)
///         +-------------------+
/// 16      | cmdline           |    (present if flags[2] is set)
///         +-------------------+
/// 20      | mods_count        |    (present if flags[3] is set)
/// 24      | mods_addr         |    (present if flags[3] is set)
///         +-------------------+
/// 28 - 40 | syms              |    (present if flags[4] or
///         |                   |                flags[5] is set)
///         +-------------------+
/// 44      | mmap_length       |    (present if flags[6] is set)
/// 48      | mmap_addr         |    (present if flags[6] is set)
///         +-------------------+
/// 52      | drives_length     |    (present if flags[7] is set)
/// 56      | drives_addr       |    (present if flags[7] is set)
///         +-------------------+
/// 60      | config_table      |    (present if flags[8] is set)
///         +-------------------+
/// 64      | boot_loader_name  |    (present if flags[9] is set)
///         +-------------------+
/// 68      | apm_table         |    (present if flags[10] is set)
///         +-------------------+
/// 72      | vbe_control_info  |    (present if flags[11] is set)
/// 76      | vbe_mode_info     |
/// 80      | vbe_mode          |
/// 82      | vbe_interface_seg |
/// 84      | vbe_interface_off |
/// 86      | vbe_interface_len |
///         +-------------------+
///</rawtext>
///
#[derive(Debug)]
#[repr(C, packed)]
struct MultibootInfo {
    flags: u32,

    mem_lower: u32,
    mem_upper: u32,

    boot_device: BootDevice,

    /// The command line is a normal C-style zero-terminated string.
    cmdline: u32,

    mods_count: u32,
    mods_addr: u32,

    elf_symbols: ElfSymbols,

    mmap_length: u32,
    mmap_addr: u32,

    drives_length: u32,
    drives_addr: u32,

    config_table: u32,

    boot_loader_name: u32,

    apm_table: u32,

    vbe_control_info: u32,
    vbe_mode_info: u32,
    vbe_mode: u16,
    vbe_interface_off: u16,
    vbe_interface_len: u16
}

/// Convert a C string into a [u8 slice and from there into a &'static str.
/// This unsafe block builds on assumption that multiboot strings are sane.
fn convert_safe_c_string(cstring: *const u8) -> &'static str {
    unsafe {
        let mut iter = cstring;
        while *iter != 0 {
            iter = iter.offset(1);
        }

        let slice = raw::Slice { data: cstring, len: iter as usize - cstring as usize };
        let byte_array: &'static [u8] = transmute(slice);
        str::from_utf8_unchecked(byte_array)
    }
}

macro_rules! check_flag {
    ($doc:meta, $fun:ident, $bit:expr) => (
        #[$doc]
        pub fn $fun(&self) -> bool {
            //assert!($bit <= 31);
            (self.header.flags & (1 << $bit)) > 0
        }
    );

    // syms field is valid if bit 4 or 5 is set, wtf?
    ($doc:meta, $fun:ident, $bit1:expr, $bit2:expr) => (
        #[$doc]
        pub fn $fun(&self) -> bool {
            //assert!($bit1 <= 31);
            //assert!($bit2 <= 31);
            (self.header.flags & (1 << $bit1)) > 0 || (self.header.flags & (1 << $bit2)) > 0
        }
    );
}

/// Multiboot structure.
impl<'a> Multiboot<'a> {

    /// Initializes the multiboot structure.
    ///
    /// # Arguments
    ///
    ///  * `mboot_ptr` - The physical address of the multiboot header. On qemu for example
    ///                  this is typically at 0x9500.
    ///  * `paddr_to_vaddr` - Translation of the physical addresses into kernel addresses.
    ///
    ///  `paddr_to_vaddr` translates physical it into a kernel accessible address.
    ///  The simplest paddr_to_vaddr function would for example be just the identity
    ///  function. But this may vary depending on how your page table layout looks like.
    ///
    pub fn new(mboot_ptr: u64, paddr_to_vaddr: fn(paddr: PAddr) -> VAddr) -> Multiboot<'a> {
        let header = paddr_to_vaddr(mboot_ptr);
        let mb: &MultibootInfo = unsafe { transmute::<VAddr, &MultibootInfo>(header) };

        Multiboot { header: mb, paddr_to_vaddr: paddr_to_vaddr }
    }

    check_flag!(doc = "If true, then the `mem_upper` and `mem_lower` fields are valid.",
               has_memory_bounds, 0);
    check_flag!(doc = "If true, then the `boot_device` field is valid.",
               has_boot_device, 1);
    check_flag!(doc = "If true, then the `cmdline` field is valid.",
               has_cmdline, 2);
    check_flag!(doc = "If true, then the `mods_addr` and `mods_count` fields are valid.",
               has_modules, 3);
    check_flag!(doc = "If true, then the `syms` field is valid.",
               has_symbols, 4, 5);
    check_flag!(doc = "If true, then the `mmap_addr` and `mmap_length` fields are valid.",
               has_memory_map, 6);
    check_flag!(doc = "If true, then the `drives_addr` and `drives_length` fields are valid.",
               has_drives, 7);
    check_flag!(doc = "If true, then the `config_table` field is valid.",
               has_config_table, 8);
    check_flag!(doc = "If true, then the `boot_loader_name` field is valid.",
               has_boot_loader_name, 9);
    check_flag!(doc = "If true, then the `apm_table` field is valid.",
               has_apm_table, 10);
    check_flag!(doc = "If true, then the `vbe_*` fields are valid.",
               has_vbe, 11);

    /// Indicate the amount of lower memory in kilobytes.
    ///
    /// Lower memory starts at address 0. The maximum possible value for
    /// lower memory is 640 kilobytes.
    pub fn lower_memory_bound(&self) -> Option<u32> {
        match self.has_memory_bounds() {
            true => Some(self.header.mem_lower),
            false => None
        }
    }

    /// Indicate the amount of upper memory in kilobytes.
    ///
    /// Upper memory starts at address 1 megabyte.
    /// The value returned for upper memory is maximally the address of
    /// the first upper memory hole minus 1 megabyte. It is not guaranteed
    /// to be this value.
    pub fn upper_memory_bound(&self) -> Option<u32> {
        match self.has_memory_bounds() {
            true => Some(self.header.mem_upper),
            false => None
        }
    }

    /// Indicates which bios disk device the boot loader loaded the OS image from.
    ///
    /// If the OS image was not loaded from a bios disk, then this
    /// returns None.
    /// The operating system may use this field as a hint for determining its
    /// own root device, but is not required to.
    pub fn boot_device(&self) -> Option<BootDevice> {
        match self.has_boot_device() {
            true => Some(self.header.boot_device.clone()),
            false => None
        }
    }

    /// Command line to be passed to the kernel.
    pub fn command_line(&self) -> Option<&'static str> {
        let paddr_to_vaddr = self.paddr_to_vaddr;

        match self.has_cmdline() {
            true => {
                let command_line_str = unsafe {
                    let cstring = transmute(paddr_to_vaddr(self.header.cmdline as *const u8 as PAddr));
                    convert_safe_c_string(cstring)
                };
                Some(command_line_str)
            },
            false => None
        }
    }

    /// Discover all additional modules in multiboot.
    pub fn modules(&'a self) -> Option<ModuleIter> {
        match self.has_modules() {
            true => Some(ModuleIter { mb: self, current: 0 }),
            false => None
        }
    }

    /// Discover all memory regions in the multiboot memory map.
    pub fn memory_regions(&'a self) -> Option<MemoryMapIter> {
        match self.has_memory_map() {
            true => {
                let start = self.header.mmap_addr;
                let end = self.header.mmap_addr + self.header.mmap_length;
                Some(MemoryMapIter { current: start, end: end, mb: self })
            }
            false => None
        }
    }
}

/// The ‘boot_device’ field.
///
/// It is laid out as follows, each of the blocks is one byte:
///  +-------+-------+-------+-------+
///  | part3 | part2 | part1 | drive |
///  +-------+-------+-------+-------+
///
/// Partition numbers always start from zero. Unused partition
/// bytes must be set to 0xFF. For example, if the disk is partitioned
/// using a simple one-level DOS partitioning scheme, then
/// ‘part’ contains the DOS partition number, and ‘part2’ and ‘part3’
/// are both 0xFF. As another example, if a disk is partitioned first into
/// DOS partitions, and then one of those DOS partitions is subdivided
/// into several BSD partitions using BSD's disklabel strategy, then ‘part1’
/// contains the DOS partition number, ‘part2’ contains the BSD sub-partition
/// within that DOS partition, and ‘part3’ is 0xFF.
///
#[derive(Debug, Clone)]
#[repr(C, packed)]
pub struct BootDevice {
    /// Contains the bios drive number as understood by
    /// the bios INT 0x13 low-level disk interface: e.g. 0x00 for the
    /// first floppy disk or 0x80 for the first hard disk.
    pub drive: u8,
    /// Specifies the top-level partition number.
    pub partition1: u8,
    /// Specifies a sub-partition in the top-level partition
    pub partition2: u8,
    /// Specifies a sub-partition in the 2nd-level partition
    pub partition3: u8
}

impl BootDevice {

    /// Is partition1 a valid partition?
    pub fn partition1_is_valid(&self) -> bool {
        self.partition1 != 0xff
    }

    /// Is partition2 a valid partition?
    pub fn partition2_is_valid(&self) -> bool {
        self.partition2 != 0xff
    }

    /// Is partition3 a valid partition?
    pub fn partition3_is_valid(&self) -> bool {
        self.partition3 != 0xff
    }
}

/// Types that define if the memory is usable or not.
#[derive(Debug, PartialEq, Eq)]
pub enum MemoryType {
    RAM = 1,
    Unusable = 2,
}

/// Multiboot format of the MMAP buffer.
///
/// Note that size is defined to be at -4 bytes in multiboot.
#[derive(Debug)]
#[repr(C, packed)]
pub struct MemoryEntry {
    size: u32,
    base_addr: u64,
    length: u64,
    mtype: u32
}

impl MemoryEntry {

    /// Get base of memory region.
    pub fn base_address(&self) -> PAddr {
        self.base_addr as PAddr
    }

    /// Get size of the memory region.
    pub fn length(&self) -> u64 {
        self.length
    }

    /// Is the region type valid RAM?
    pub fn memory_type(&self) -> MemoryType {
        match self.mtype {
            1 => MemoryType::RAM,
            _ => MemoryType::Unusable
        }
    }
}

/// Used to iterate over all memory regions provided by multiboot.
pub struct MemoryMapIter<'a> {
    mb: &'a Multiboot<'a>,
    current: u32,
    end: u32,
}

impl<'a> Iterator for MemoryMapIter<'a> {
    type Item = &'a MemoryEntry;

    #[inline]
    fn next(&mut self) -> Option<&'a MemoryEntry> {
        let paddr_to_vaddr = self.mb.paddr_to_vaddr;

        if self.current < self.end {
            let memory_region: &MemoryEntry = unsafe {
                transmute::<VAddr, &MemoryEntry>(paddr_to_vaddr(self.current as PAddr))
            };

            self.current += memory_region.size + 4;
            return Some(memory_region);
        }

        return None
    }
}

/// Multiboot format to information about module
#[derive(Debug)]
#[repr(packed)]
struct MBModule {
    /// Start address of module in memory.
    start: u32,

    /// End address of module in memory.
    end: u32,

    /// The `string` field provides an arbitrary string to be associated
    /// with that particular boot module.
    ///
    /// It is a zero-terminated ASCII string, just like the kernel command line.
    /// The `string` field may be 0 if there is no string associated with the module.
    /// Typically the string might be a command line (e.g. if the operating system
    /// treats boot modules as executable programs), or a pathname
    /// (e.g. if the operating system treats boot modules as files in a file system),
    /// but its exact use is specific to the operating system.
    string: u32,

    /// Must be zero.
    reserved: u32
}

pub struct Module {
    /// Start address of module in kernel addressable memory.
    pub start: VAddr,
    /// End address of module in kernel addressable memory.
    pub end: VAddr,
    /// Name of the module.
    pub string: &'static str
}

impl Module {
    fn new(start: VAddr, end: VAddr, name: &'static str) -> Module {
        Module{start: start, end: end, string: name}
    }
}

/// Used to iterate over all modules in multiboot.
pub struct ModuleIter<'a> {
    mb: &'a Multiboot<'a>,
    current: usize,
}

impl<'a> Iterator for ModuleIter<'a> {
    type Item = Module;

    #[inline]
    fn next(&mut self) -> Option<Module> {
        let paddr_to_vaddr = self.mb.paddr_to_vaddr;
        let modules = unsafe {
            slice::from_raw_parts(
                transmute::<VAddr, &MBModule>(
                    paddr_to_vaddr(self.mb.header.mods_addr as PAddr)),
                    self.mb.header.mods_count as usize)
        };

        if self.current < self.mb.header.mods_count as usize {
            let ref m = modules[self.current];
            let cstring = paddr_to_vaddr(m.string as *const u8 as PAddr);
            let module = Module::new(
                paddr_to_vaddr(m.start as PAddr),
                paddr_to_vaddr(m.end as PAddr),
                convert_safe_c_string(cstring as *const u8)
            );
            self.current += 1;
            return Some(module);
        }

        None
    }
}

/// Multiboot format for ELF Symbols
#[derive(Debug)]
#[repr(C, packed)]
struct ElfSymbols {
    num: u32,
    size: u32,
    addr: u32,
    shndx: u32,
}<|endoftext|>


<commit_before>use std::ops::*;

extern crate cgmath;

use cgmath::num_traits::*;
use cgmath::*;

use std::num::FpCategory;

#[derive(Copy, Clone, PartialEq, Debug)]
pub struct F64Err {
    val: f64,
    err: f64,
}

impl F64Err {
    pub fn new_errorfree(val: f64) -> F64Err {
        F64Err {
            val: val,
            err: 0.
        }
    }

    pub fn new(val: f64) -> F64Err {
        F64Err {
            val: val,
            err: val
        }
    }

    pub fn new_exact(val: f64, err: f64) -> F64Err {
        F64Err {
            val: val,
            err: err
        }
    }

    pub fn val(&self) -> f64 {
        self.val
    }

    pub fn err(&self) -> f64 {
        self.err
    }

    pub fn err_times_eps(&self) -> f64 {
        self.err * ::std::f64::EPSILON
    }
}

impl Mul for F64Err {
    type Output = F64Err;
    fn mul(self, rhs: Self) -> Self::Output {
        F64Err {
            val: self.val * rhs.val,
            err: self.val.abs() * rhs.err + rhs.val.abs() * self.err
        }
    }
}

impl MulAssign for F64Err {
    fn mul_assign(&mut self, rhs: Self) {
        *self = *self * rhs
    }
}

impl Div for F64Err {
    type Output = F64Err;
    fn div(self, rhs: Self) -> Self::Output {
        F64Err {
            val: self.val / rhs.val,
            err: self.err / rhs.val.abs() + rhs.err * self.val / (rhs.val * rhs.val)
        }
    }
}

impl DivAssign for F64Err {
    fn div_assign(&mut self, rhs: Self) {
        *self = *self / rhs
    }
}

impl Add for F64Err {
    type Output = Self;
    fn add(self, rhs: Self) -> Self::Output {
        F64Err {
            val: self.val + rhs.val,
            err: self.val.abs().max(rhs.val.abs()) + self.err + rhs.err
        }
    }
}

impl AddAssign for F64Err {
    fn add_assign(&mut self, rhs: Self) {
        *self = *self + rhs
    }
}

impl Sub for F64Err {
    type Output = Self;
    fn sub(self, rhs: Self) -> Self::Output {
        F64Err {
            val: self.val - rhs.val,
            err: self.val.abs().max(rhs.val.abs()) + self.err + rhs.err
        }
    }
}

impl SubAssign for F64Err {
    fn sub_assign(&mut self, rhs: Self) {
        *self = *self - rhs
    }
}

impl Rem for F64Err {
    type Output = Self;
    fn rem(self, rhs: Self) -> Self::Output {
        unimplemented!();
    }
}

impl RemAssign for F64Err {
    fn rem_assign(&mut self, rhs: Self) {
        *self = *self % rhs
    }
}

impl PartialOrd for F64Err {
    fn partial_min(self, other: Self) -> Self {
        if self.val < other.val {
            self
        } else {
            other
        }
    }
    fn partial_max(self, other: Self) -> Self {
        if self.val > other.val {
            self
        } else {
            other
        }
    }
}

impl ::std::cmp::PartialOrd for F64Err {
    fn partial_cmp(&self, other: &Self) -> Option<::std::cmp::Ordering> {
        self.val.partial_cmp(&other.val)
    }
}

impl Zero for F64Err {
    fn zero() -> Self {
        Self::new_errorfree(0.)
    }

    fn is_zero(&self) -> bool {
        self.val.is_zero()
    }
}

impl One for F64Err {
    fn one() -> Self {
        Self::new_errorfree(1.)
    }
}

impl ToPrimitive for F64Err {
    /// Converts the value of `self` to an `isize`.
    #[inline]
    fn to_isize(&self) -> Option<isize> {
        self.val.to_isize()
    }

    /// Converts the value of `self` to an `i8`.
    #[inline]
    fn to_i8(&self) -> Option<i8> {
        self.val.to_i8()
    }

    /// Converts the value of `self` to an `i16`.
    #[inline]
    fn to_i16(&self) -> Option<i16> {
        self.val.to_i16()
    }

    /// Converts the value of `self` to an `i32`.
    #[inline]
    fn to_i32(&self) -> Option<i32> {
        self.val.to_i32()
    }

    #[inline]
    fn to_i64(&self) -> Option<i64> {
        self.val.to_i64()
    }

    /// Converts the value of `self` to a `usize`.
    #[inline]
    fn to_usize(&self) -> Option<usize> {
        self.val.to_usize()
    }

    /// Converts the value of `self` to an `u8`.
    #[inline]
    fn to_u8(&self) -> Option<u8> {
        self.val.to_u8()
    }

    /// Converts the value of `self` to an `u16`.
    #[inline]
    fn to_u16(&self) -> Option<u16> {
        self.val.to_u16()
    }

    /// Converts the value of `self` to an `u32`.
    #[inline]
    fn to_u32(&self) -> Option<u32> {
        self.val.to_u32()
    }

    /// Converts the value of `self` to an `u32`.
    #[inline]
    fn to_u64(&self) -> Option<u64> {
        self.val.to_u64()
    }

    /// Converts the value of `self` to an `f32`.
    #[inline]
    fn to_f32(&self) -> Option<f32> {
        self.val.to_f32()
    }

    /// Converts the value of `self` to an `f64`.
    #[inline]
    fn to_f64(&self) -> Option<f64> {
        self.val.to_f64()
    }
}

impl NumCast for F64Err {
    fn from<T>(t: T) -> Option<Self> {
        unimplemented!();
    }
}

impl Num for F64Err {
    type FromStrRadixErr = ParseFloatError;
    fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseFloatError> {
        unimplemented!();
    }
}

impl BaseNum for F64Err {}

impl ApproxEq for F64Err {
    type Epsilon = Self;
    fn default_epsilon() -> Self::Epsilon {
        unimplemented!()
    }

    fn default_max_relative() -> Self::Epsilon {
        unimplemented!()
    }

    fn default_max_ulps() -> u32 {
        unimplemented!()
    }

    fn relative_eq(&self, other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon) -> bool {
        unimplemented!()
    }

    fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
        unimplemented!()
    }
}

impl Neg for F64Err {
    type Output = Self;
    fn neg(self) -> Self::Output {
        unimplemented!()
    }
}

impl Float for F64Err {
    fn nan() -> Self {
        unimplemented!()
    }

    fn infinity() -> Self {
        unimplemented!()
    }

    fn neg_infinity() -> Self {
        unimplemented!()
    }

    fn neg_zero() -> Self {
        unimplemented!()
    }

    fn min_value() -> Self {
        unimplemented!()
    }

    fn min_positive_value() -> Self {
        unimplemented!()
    }

    fn max_value() -> Self {
        unimplemented!()
    }

    fn is_nan(self) -> bool {
        unimplemented!()
    }

    fn is_infinite(self) -> bool {
        unimplemented!()
    }

    fn is_finite(self) -> bool {
        unimplemented!()
    }

    fn is_normal(self) -> bool {
        unimplemented!()
    }

    fn classify(self) -> FpCategory {
        unimplemented!()
    }

    fn floor(self) -> Self {
        unimplemented!()
    }

    fn ceil(self) -> Self {
        unimplemented!()
    }

    fn round(self) -> Self {
        unimplemented!()
    }

    fn trunc(self) -> Self {
        unimplemented!()
    }

    fn fract(self) -> Self {
        unimplemented!()
    }

    fn abs(self) -> Self {
        unimplemented!()
    }

    fn signum(self) -> Self {
        unimplemented!()
    }

    fn is_sign_positive(self) -> bool {
        unimplemented!()
    }

    fn is_sign_negative(self) -> bool {
        unimplemented!()
    }

    fn mul_add(self, a: Self, b: Self) -> Self {
        unimplemented!()
    }

    fn recip(self) -> Self {
        unimplemented!()
    }

    fn powi(self, n: i32) -> Self {
        unimplemented!()
    }

    fn powf(self, n: Self) -> Self {
        unimplemented!()
    }

    fn sqrt(self) -> Self {
        unimplemented!()
    }

    fn exp(self) -> Self {
        unimplemented!()
    }

    fn exp2(self) -> Self {
        unimplemented!()
    }

    fn ln(self) -> Self {
        unimplemented!()
    }

    fn log(self, base: Self) -> Self {
        unimplemented!()
    }

    fn log2(self) -> Self {
        unimplemented!()
    }

    fn log10(self) -> Self {
        unimplemented!()
    }

    fn max(self, other: Self) -> Self {
        unimplemented!()
    }

    fn min(self, other: Self) -> Self {
        unimplemented!()
    }

    fn abs_sub(self, other: Self) -> Self {
        unimplemented!()
    }

    fn cbrt(self) -> Self {
        unimplemented!()
    }

    fn hypot(self, other: Self) -> Self {
        unimplemented!()
    }

    fn sin(self) -> Self {
        unimplemented!()
    }

    fn cos(self) -> Self {
        unimplemented!()
    }

    fn tan(self) -> Self {
        unimplemented!()
    }

    fn asin(self) -> Self {
        unimplemented!()
    }

    fn acos(self) -> Self {
        unimplemented!()
    }

    fn atan(self) -> Self {
        unimplemented!()
    }

    fn atan2(self, other: Self) -> Self {
        unimplemented!()
    }

    fn sin_cos(self) -> (Self, Self) {
        unimplemented!()
    }

    fn exp_m1(self) -> Self {
        unimplemented!()
    }

    fn ln_1p(self) -> Self {
        unimplemented!()
    }

    fn sinh(self) -> Self {
        unimplemented!()
    }

    fn cosh(self) -> Self {
        unimplemented!()
    }

    fn tanh(self) -> Self {
        unimplemented!()
    }

    fn asinh(self) -> Self {
        unimplemented!()
    }

    fn acosh(self) -> Self {
        unimplemented!()
    }

    fn atanh(self) -> Self {
        unimplemented!()
    }

    fn integer_decode(self) -> (u64, i16, i8) {
        unimplemented!()
    }
}

impl BaseFloat for F64Err {}

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

    #[test]
    fn multiplication_error() {
        let left = F64Err::new_errorfree(2.);
        let right = F64Err::new_errorfree(2.);

        let res = left * right;

        assert_eq!(4., res.val());
        assert_eq!(0., res.err());
    }

    #[test]
    fn addition_error() {
        let left = F64Err::new_errorfree(2.);
        let right = F64Err::new_errorfree(3.);

        let res = left + right;

        assert_eq!(5., res.val());
        assert_eq!(3., res.err());
    }

    #[test]
    fn addition_then_multipl() {
        let left = F64Err::new_errorfree(2.);
        let right = F64Err::new_errorfree(3.);

        let res_add = left + right;
        let res_mul = res_add * left;

        assert_eq!(10., res_mul.val());
        assert_eq!(3. * 2., res_mul.err());

        let res_mul = res_mul * res_mul;

        assert_eq!(100., res_mul.val());
        assert_eq!((3. * 2.) * 10. + (3. * 2.) * 10., res_mul.err());
    }

    #[test]
    fn subtract_error() {
        let left = F64Err::new_errorfree(2.);
        let right = F64Err::new_errorfree(3.);

        let res = left - right;

        assert_eq!(-1., res.val());
        assert_eq!(3., res.err());

        let res = res - right;

        assert_eq!(-4., res.val());
        assert_eq!(6., res.err());
    }

    #[test]
    fn can_use_cgmath_stuff() {
        type Point2 = ::cgmath::Point2<F64Err>;

        let a = Point2::new(F64Err::new(1.), F64Err::new(0.));
        let b = Point2::new(F64Err::new(1.), F64Err::new(0.));

        let det = ::cgmath::Matrix2::new(a.x, a.y,
                               b.x, b.y).determinant();
    }
}
<commit_msg>Added missing inline specifier to all thefunctions<commit_after>use std::ops::*;

extern crate cgmath;

use cgmath::num_traits::*;
use cgmath::*;

use std::num::FpCategory;

#[derive(Copy, Clone, PartialEq, Debug)]
pub struct F64Err {
    val: f64,
    err: f64,
}

impl F64Err {
    #[inline]
    pub fn new_errorfree(val: f64) -> F64Err {
        F64Err {
            val: val,
            err: 0.
        }
    }

    #[inline]
    pub fn new(val: f64) -> F64Err {
        F64Err {
            val: val,
            err: val
        }
    }

    #[inline]
    pub fn new_exact(val: f64, err: f64) -> F64Err {
        F64Err {
            val: val,
            err: err
        }
    }

    #[inline]
    pub fn val(&self) -> f64 {
        self.val
    }

    #[inline]
    pub fn err(&self) -> f64 {
        self.err
    }

    #[inline]
    pub fn err_times_eps(&self) -> f64 {
        self.err * ::std::f64::EPSILON
    }
}

impl Mul for F64Err {
    type Output = F64Err;
    #[inline]
    fn mul(self, rhs: Self) -> Self::Output {
        F64Err {
            val: self.val * rhs.val,
            err: self.val.abs() * rhs.err + rhs.val.abs() * self.err
        }
    }
}

impl MulAssign for F64Err {
    #[inline]
    fn mul_assign(&mut self, rhs: Self) {
        *self = *self * rhs
    }
}

impl Div for F64Err {
    type Output = F64Err;
    #[inline]
    fn div(self, rhs: Self) -> Self::Output {
        F64Err {
            val: self.val / rhs.val,
            err: self.err / rhs.val.abs() + rhs.err * self.val / (rhs.val * rhs.val)
        }
    }
}

impl DivAssign for F64Err {
    #[inline]
    fn div_assign(&mut self, rhs: Self) {
        *self = *self / rhs
    }
}

impl Add for F64Err {
    type Output = Self;
    #[inline]
    fn add(self, rhs: Self) -> Self::Output {
        F64Err {
            val: self.val + rhs.val,
            err: self.val.abs().max(rhs.val.abs()) + self.err + rhs.err
        }
    }
}

impl AddAssign for F64Err {
    #[inline]
    fn add_assign(&mut self, rhs: Self) {
        *self = *self + rhs
    }
}

impl Sub for F64Err {
    type Output = Self;
    #[inline]
    fn sub(self, rhs: Self) -> Self::Output {
        F64Err {
            val: self.val - rhs.val,
            err: self.val.abs().max(rhs.val.abs()) + self.err + rhs.err
        }
    }
}

impl SubAssign for F64Err {
    #[inline]
    fn sub_assign(&mut self, rhs: Self) {
        *self = *self - rhs
    }
}

impl Rem for F64Err {
    type Output = Self;
    #[inline]
    fn rem(self, rhs: Self) -> Self::Output {
        unimplemented!();
    }
}

impl RemAssign for F64Err {
    #[inline]
    fn rem_assign(&mut self, rhs: Self) {
        *self = *self % rhs
    }
}

impl PartialOrd for F64Err {
    #[inline]
    fn partial_min(self, other: Self) -> Self {
        if self.val < other.val {
            self
        } else {
            other
        }
    }
    #[inline]
    fn partial_max(self, other: Self) -> Self {
        if self.val > other.val {
            self
        } else {
            other
        }
    }
}

impl ::std::cmp::PartialOrd for F64Err {
    #[inline]
    fn partial_cmp(&self, other: &Self) -> Option<::std::cmp::Ordering> {
        self.val.partial_cmp(&other.val)
    }
}

impl Zero for F64Err {
    #[inline]
    fn zero() -> Self {
        Self::new_errorfree(0.)
    }

    #[inline]
    fn is_zero(&self) -> bool {
        self.val.is_zero()
    }
}

impl One for F64Err {
    #[inline]
    fn one() -> Self {
        Self::new_errorfree(1.)
    }
}

impl ToPrimitive for F64Err {
    /// Converts the value of `self` to an `isize`.
    #[inline]
    fn to_isize(&self) -> Option<isize> {
        self.val.to_isize()
    }

    /// Converts the value of `self` to an `i8`.
    #[inline]
    fn to_i8(&self) -> Option<i8> {
        self.val.to_i8()
    }

    /// Converts the value of `self` to an `i16`.
    #[inline]
    fn to_i16(&self) -> Option<i16> {
        self.val.to_i16()
    }

    /// Converts the value of `self` to an `i32`.
    #[inline]
    fn to_i32(&self) -> Option<i32> {
        self.val.to_i32()
    }

    #[inline]
    fn to_i64(&self) -> Option<i64> {
        self.val.to_i64()
    }

    /// Converts the value of `self` to a `usize`.
    #[inline]
    fn to_usize(&self) -> Option<usize> {
        self.val.to_usize()
    }

    /// Converts the value of `self` to an `u8`.
    #[inline]
    fn to_u8(&self) -> Option<u8> {
        self.val.to_u8()
    }

    /// Converts the value of `self` to an `u16`.
    #[inline]
    fn to_u16(&self) -> Option<u16> {
        self.val.to_u16()
    }

    /// Converts the value of `self` to an `u32`.
    #[inline]
    fn to_u32(&self) -> Option<u32> {
        self.val.to_u32()
    }

    /// Converts the value of `self` to an `u32`.
    #[inline]
    fn to_u64(&self) -> Option<u64> {
        self.val.to_u64()
    }

    /// Converts the value of `self` to an `f32`.
    #[inline]
    fn to_f32(&self) -> Option<f32> {
        self.val.to_f32()
    }

    /// Converts the value of `self` to an `f64`.
    #[inline]
    fn to_f64(&self) -> Option<f64> {
        self.val.to_f64()
    }
}

impl NumCast for F64Err {
    #[inline]
    fn from<T>(t: T) -> Option<Self> {
        unimplemented!();
    }
}

impl Num for F64Err {
    type FromStrRadixErr = ParseFloatError;
    #[inline]
    fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseFloatError> {
        unimplemented!();
    }
}

impl BaseNum for F64Err {}

impl ApproxEq for F64Err {
    type Epsilon = Self;
    #[inline]
    fn default_epsilon() -> Self::Epsilon {
        unimplemented!()
    }

    #[inline]
    fn default_max_relative() -> Self::Epsilon {
        unimplemented!()
    }

    #[inline]
    fn default_max_ulps() -> u32 {
        unimplemented!()
    }

    #[inline]
    fn relative_eq(&self, other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon) -> bool {
        unimplemented!()
    }

    #[inline]
    fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
        unimplemented!()
    }
}

impl Neg for F64Err {
    type Output = Self;
    #[inline]
    fn neg(self) -> Self::Output {
        unimplemented!()
    }
}

impl Float for F64Err {
    #[inline]
    fn nan() -> Self {
        unimplemented!()
    }

    #[inline]
    fn infinity() -> Self {
        unimplemented!()
    }

    #[inline]
    fn neg_infinity() -> Self {
        unimplemented!()
    }

    #[inline]
    fn neg_zero() -> Self {
        unimplemented!()
    }

    #[inline]
    fn min_value() -> Self {
        unimplemented!()
    }

    #[inline]
    fn min_positive_value() -> Self {
        unimplemented!()
    }

    #[inline]
    fn max_value() -> Self {
        unimplemented!()
    }

    #[inline]
    fn is_nan(self) -> bool {
        unimplemented!()
    }

    #[inline]
    fn is_infinite(self) -> bool {
        unimplemented!()
    }

    #[inline]
    fn is_finite(self) -> bool {
        unimplemented!()
    }

    #[inline]
    fn is_normal(self) -> bool {
        unimplemented!()
    }

    #[inline]
    fn classify(self) -> FpCategory {
        unimplemented!()
    }

    #[inline]
    fn floor(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn ceil(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn round(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn trunc(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn fract(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn abs(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn signum(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn is_sign_positive(self) -> bool {
        unimplemented!()
    }

    #[inline]
    fn is_sign_negative(self) -> bool {
        unimplemented!()
    }

    #[inline]
    fn mul_add(self, a: Self, b: Self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn recip(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn powi(self, n: i32) -> Self {
        unimplemented!()
    }

    #[inline]
    fn powf(self, n: Self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn sqrt(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn exp(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn exp2(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn ln(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn log(self, base: Self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn log2(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn log10(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn max(self, other: Self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn min(self, other: Self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn abs_sub(self, other: Self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn cbrt(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn hypot(self, other: Self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn sin(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn cos(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn tan(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn asin(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn acos(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn atan(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn atan2(self, other: Self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn sin_cos(self) -> (Self, Self) {
        unimplemented!()
    }

    #[inline]
    fn exp_m1(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn ln_1p(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn sinh(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn cosh(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn tanh(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn asinh(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn acosh(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn atanh(self) -> Self {
        unimplemented!()
    }

    #[inline]
    fn integer_decode(self) -> (u64, i16, i8) {
        unimplemented!()
    }
}

impl BaseFloat for F64Err {}

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

    #[test]
    fn multiplication_error() {
        let left = F64Err::new_errorfree(2.);
        let right = F64Err::new_errorfree(2.);

        let res = left * right;

        assert_eq!(4., res.val());
        assert_eq!(0., res.err());
    }

    #[test]
    fn addition_error() {
        let left = F64Err::new_errorfree(2.);
        let right = F64Err::new_errorfree(3.);

        let res = left + right;

        assert_eq!(5., res.val());
        assert_eq!(3., res.err());
    }

    #[test]
    fn addition_then_multipl() {
        let left = F64Err::new_errorfree(2.);
        let right = F64Err::new_errorfree(3.);

        let res_add = left + right;
        let res_mul = res_add * left;

        assert_eq!(10., res_mul.val());
        assert_eq!(3. * 2., res_mul.err());

        let res_mul = res_mul * res_mul;

        assert_eq!(100., res_mul.val());
        assert_eq!((3. * 2.) * 10. + (3. * 2.) * 10., res_mul.err());
    }

    #[test]
    fn subtract_error() {
        let left = F64Err::new_errorfree(2.);
        let right = F64Err::new_errorfree(3.);

        let res = left - right;

        assert_eq!(-1., res.val());
        assert_eq!(3., res.err());

        let res = res - right;

        assert_eq!(-4., res.val());
        assert_eq!(6., res.err());
    }

    #[test]
    fn can_use_cgmath_stuff() {
        type Point2 = ::cgmath::Point2<F64Err>;

        let a = Point2::new(F64Err::new(1.), F64Err::new(0.));
        let b = Point2::new(F64Err::new(1.), F64Err::new(0.));

        let det = ::cgmath::Matrix2::new(a.x, a.y,
                                         b.x, b.y).determinant();
    }
}
<|endoftext|>


<commit_before>use std::os;
use std::io::fs::PathExtensions;

/// Probe the system for the directory in which CA certificates should likely be
/// found.
///
/// This will only search known system locations.
pub fn find_certs_dirs() -> Vec<Path> {
    // see http://gagravarr.org/writing/openssl-certs/others.shtml
    [
        "/var/ssl",
        "/usr/share/ssl",
        "/usr/local/ssl",
        "/usr/local/openssl",
        "/usr/local/share",
        "/usr/lib/ssl",
        "/usr/ssl",
        "/etc/openssl",
        "/etc/pki/tls",
        "/etc/ssl",
    ].iter().map(|s| Path::new(*s)).filter(|p| {
        p.exists()
    }).collect()
}

pub fn init_ssl_cert_env_vars() {
    for certs_dir in find_certs_dirs().iter() {
        // cert.pem looks to be an openssl 1.0.1 thing, while
        // certs/ca-certificates.crt appears to be a 0.9.8 thing
        try("SSL_CERT_FILE", certs_dir.join("cert.pem"));
        try("SSL_CERT_FILE", certs_dir.join("certs/ca-certificates.crt"));
        try("SSL_CERT_FILE", certs_dir.join("certs/ca-root-nss.crt"));

        try("SSL_CERT_DIR", certs_dir.join("certs"));
    }
}

fn try(var: &str, val: Path) {
    if !val.exists() { return }
    match os::getenv(var) {
        // Someone else has already got this, they probably know what
        // they're doing more than we do
        Some(..) => {},
        None => os::setenv(var, val),
    }
}
<commit_msg>Add the programmatic result of a probe<commit_after>use std::os;
use std::io::fs::PathExtensions;

pub struct ProbeResult {
    pub cert_file: Option<Path>,
    pub cert_dir: Option<Path>,
}

/// Probe the system for the directory in which CA certificates should likely be
/// found.
///
/// This will only search known system locations.
pub fn find_certs_dirs() -> Vec<Path> {
    // see http://gagravarr.org/writing/openssl-certs/others.shtml
    [
        "/var/ssl",
        "/usr/share/ssl",
        "/usr/local/ssl",
        "/usr/local/openssl",
        "/usr/local/share",
        "/usr/lib/ssl",
        "/usr/ssl",
        "/etc/openssl",
        "/etc/pki/tls",
        "/etc/ssl",
    ].iter().map(|s| Path::new(*s)).filter(|p| {
        p.exists()
    }).collect()
}

pub fn init_ssl_cert_env_vars() {
    let ProbeResult { cert_file, cert_dir } = probe();
    match cert_file {
        Some(path) => put("SSL_CERT_FILE", path),
        None => {}
    }
    match cert_dir {
        Some(path) => put("SSL_CERT_DIR", path),
        None => {}
    }

    fn put(var: &str, path: Path) {
        // Don't stomp over what anyone else has set
        match os::getenv(var) {
            Some(..) => {}
            None => os::setenv(var, path),
        }
    }
}

pub fn probe() -> ProbeResult {
    let mut result = ProbeResult {
        cert_file: os::getenv("SSL_CERT_FILE").map(Path::new),
        cert_dir: os::getenv("SSL_CERT_DIR").map(Path::new),
    };
    for certs_dir in find_certs_dirs().iter() {
        // cert.pem looks to be an openssl 1.0.1 thing, while
        // certs/ca-certificates.crt appears to be a 0.9.8 thing
        try(&mut result.cert_file, certs_dir.join("cert.pem"));
        try(&mut result.cert_file, certs_dir.join("certs/ca-certificates.crt"));
        try(&mut result.cert_file, certs_dir.join("certs/ca-root-nss.crt"));

        try(&mut result.cert_dir, certs_dir.join("certs"));
    }
    result
}

fn try(dst: &mut Option<Path>, val: Path) {
    if dst.is_none() && val.exists() {
        *dst = Some(val);
    }
}
<|endoftext|>


<commit_before>#![feature(libc)]
extern crate libc;
use libc::*;
use std::ffi;
use std::str;

use std::env;
use std::fs::File;
use std::path::PathBuf;

#[link(name = "spotify")]
extern {
    fn sp_build_id() -> *const c_char;
}

/// Return the libspotify build ID
///
/// This might be useful to have available for display somewhere in your user interface.
///
/// # Examples
/// ```
/// use spotify::*;
///
/// println!("{}", build_info);
///
/// // 12.1.51.g86c92b43 Release Linux-x86_64
/// ```
pub fn build_id() -> String {
    unsafe {
        let slice = ffi::CStr::from_ptr(sp_build_id());
        str::from_utf8(slice.to_bytes()).unwrap().to_string()
    }
}

/// Gets the cache directory used for storing the cache handled by libspotify.
fn get_cache_dir() -> PathBuf {
    let mut dir = env::temp_dir();
    dir.push("rusty-spot");
    dir
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn test_build_id() {
        println!("{}", build_id());
        assert!(!build_id().is_empty());
    }

    #[test]
    #[cfg(target_os = "linux")]
    fn cache_dir() {
        let dir = super::get_cache_dir();
        assert_eq!("/tmp/rusty-spot", dir.into_os_string().into_string().unwrap());
    }
}
<commit_msg>Fixed example in docs<commit_after>#![feature(libc)]
extern crate libc;
use libc::*;
use std::ffi;
use std::str;

use std::env;
use std::fs::File;
use std::path::PathBuf;

#[link(name = "spotify")]
extern {
    fn sp_build_id() -> *const c_char;
}

/// Return the libspotify build ID
///
/// This might be useful to have available for display somewhere in your user interface.
///
/// # Examples
/// ```
/// use spotify;
///
/// println!("{}", spotify::build_id());
///
/// // 12.1.51.g86c92b43 Release Linux-x86_64
/// ```
pub fn build_id() -> String {
    unsafe {
        let slice = ffi::CStr::from_ptr(sp_build_id());
        str::from_utf8(slice.to_bytes()).unwrap().to_string()
    }
}

/// Gets the cache directory used for storing the cache handled by libspotify.
fn get_cache_dir() -> PathBuf {
    let mut dir = env::temp_dir();
    dir.push("rusty-spot");
    dir
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn test_build_id() {
        println!("{}", build_id());
        assert!(!build_id().is_empty());
    }

    #[test]
    #[cfg(target_os = "linux")]
    fn cache_dir() {
        let dir = super::get_cache_dir();
        assert_eq!("/tmp/rusty-spot", dir.into_os_string().into_string().unwrap());
    }
}
<|endoftext|>


<commit_before>extern crate unicode_segmentation;
use unicode_segmentation::UnicodeSegmentation;

use std::rc::Rc;

const SPLIT_LEN: usize = 10;
const JOIN_LEN: usize = 5;
const REBALANCE_RATIO: f32 = 1.2;

/// A "base" segment of a Rope.
/// Usually a String, but could in principle be a large file buffer or similar.
trait RopeSegment {
    /// Returns the number of unicode grapheme clusters in this segment
    fn grapheme_len(&self) -> usize;
    /// Return Rc pointers to segments before and after the grapheme cluster specified by the `index` parameter
    fn split(&self, index: usize) -> (Rc<RopeSegment>, Rc<RopeSegment>);

}

enum RopeNode {
    Leaf(String),
    Node { len: usize, left: Rc<RopeNode>, right: Rc<RopeNode> },
}

impl RopeNode {
    pub fn new_leaf(value: String) -> RopeNode {
        RopeNode::Leaf(value).adjust()
    }
    pub fn push_str(self, value: String) -> RopeNode {
        let l = self.len() + value.len();
        RopeNode::Node { len: l, left: Rc::new(self), right: Rc::new(RopeNode::new_leaf(value)) }
    }
    fn split(&self, index: usize) -> (RopeNode, RopeNode) {
        use RopeNode::*;

        match *self {
            Leaf(ref s) => {
                let len = s.len();
                let left = s[..len].to_string();
                let right = s[len..].to_string();
                (RopeNode::new_leaf(left), RopeNode::new_leaf(right))
            },
            Node { len, ref left, ref right } => {
                let left_len = left.len();
                let right_len = right.len();
                if index < left_len {
                    let (a, b) = left.split(index);
                    (a, RopeNode::join(Rc::new(b), right.clone()))
                } else {
                    let (b, c) = right.split(index-left_len);
                    (RopeNode::join(left.clone(), Rc::new(b)), c)
                }
            }
        }

    }
    fn join(left: Rc<RopeNode>, right: Rc<RopeNode>) -> RopeNode {
        RopeNode::Node { len: left.len() + right.len(), left: left.clone(), right: right.clone() }
    }
    fn adjust(self) -> RopeNode {
        use RopeNode::*;

        let l = self.len();
        match self {
            Leaf(s) => {
                if l > SPLIT_LEN {
                    let split = l / 2;
                    let left = s[0..split].to_string();
                    let right = s[split..].to_string();
                    Node { len: l,
                           left: Rc::new(RopeNode::new_leaf(left).adjust()),
                           right: Rc::new(RopeNode::new_leaf(right).adjust()) }
                } else {
                    Leaf(s)
                }
            },
            Node { len, left, right } => {
                if len < JOIN_LEN {
                    let mut s = String::with_capacity(len);
                    left.append_to(&mut s);
                    right.append_to(&mut s);
                    Leaf(s)
                } else {
                    Node { len: len, left: left, right: right }
                }
            },
        }
    }
    fn append_to(&self, buffer: &mut String) {
        match *self {
            RopeNode::Leaf(ref s) => {
                buffer.push_str(s);
            },
            RopeNode::Node { len, ref left, ref right } => {
                left.append_to(buffer);
                right.append_to(buffer);
            }
        }
    }
    pub fn len(&self) -> usize {
        match *self {
            RopeNode::Leaf(ref s) => s.len(),
            RopeNode::Node{ len, .. } => len
        }
    }
    pub fn to_string(&self) -> String {
        let mut buffer = String::with_capacity(self.len());
        self.append_to(&mut buffer);
        buffer
    }
}

fn walk(depth: usize, rope: &RopeNode) {
    for i in 0..depth*2 {
        print!(" ");
    }
    match *rope {
        RopeNode::Leaf(ref s) => println!(" Leaf ({}): {:?}", s.len(), s),
        RopeNode::Node { len, ref left, ref right } => {
            println!(" Node ({}):", len);
            walk(depth+1, &*left);
            walk(depth+1, &*right);
        }
    }
}

#[test]
fn it_works() {
    let base = "the quick brown fox jumped over the lazy dog.";

    let rope = RopeNode::new_leaf(base.to_string());
    assert_eq!(rope.to_string(), base.to_string());

    println!("---");
    println!("{}", rope.to_string());
    walk(0, &rope);

    let rope = rope.adjust();
    println!("---");
    println!("{}", rope.to_string());
    walk(0, &rope);

    assert_eq!(rope.to_string(), base.to_string());

    let rope = rope.push_str("  Foo bar baz baz bar foo.".to_string());
    println!("---");
    println!("{}", rope.to_string());
    walk(0, &rope);

}
<commit_msg>Implement basic construction, split, join, and insertion operations.<commit_after>#![feature(collections,vec_push_all)]

extern crate unicode_segmentation;
use unicode_segmentation::UnicodeSegmentation;

use std::rc::Rc;

const SPLIT_LEN: usize = 10;
const JOIN_LEN: usize = 5;
const REBALANCE_RATIO: f32 = 1.2;

struct Leaf {
    base: Rc<String>,
    start: usize,
    end: usize,
    graphemes: usize,
}
impl Leaf {
    /// Create a new Leaf from a String
    fn from_string(base: &str) -> Leaf {
        let base = String::from_str(base);
        let (start, end) = (0, base.len());
        Leaf::new(Rc::new(base), start, end)
    }
    /// Create a new Leaf
    /// This works like a Slice of the base String; base[start..end]
    fn new(base: Rc<String>, start: usize, end: usize) -> Leaf {
        let graphemes = UnicodeSegmentation::graphemes(&base[start..end], true).collect::<Vec<&str>>().len();
        Leaf { base: base, start: start, end: end, graphemes: graphemes }
    }
    /// Split a Leaf after the nth grapheme
    /// Panics if the grapheme index is out of range
    fn split(&self, grapheme_index: usize) -> (Rope, Rope) {
        let byte_index = UnicodeSegmentation::grapheme_indices(&self.base[self.start..self.end], true)
            .nth(grapheme_index).unwrap().0;
        let left = Leaf::new(self.base.clone(), self.start, self.start + byte_index);
        let right = Leaf::new(self.base.clone(), self.start + byte_index, self.end);
        (Rope::Leaf(left), Rope::Leaf(right))
    }
    /// Gets the number of Unicode grapheme clusters in this leaf
    fn num_graphemes(&self) -> usize {
        self.graphemes
    }
    /// Returns a &str of this Leafs contents
    fn to_str(&self) -> &str {
        &self.base[self.start..self.end]
    }
}
impl Clone for Leaf {
    fn clone(&self) -> Leaf {
        Leaf { base: self.base.clone(),
               start: self.start,
               end: self.end,
               graphemes: self.graphemes }
    }
}

struct Concat {
    left: Rope,
    right: Rope,
    graphemes: usize,
}
impl Concat {
    /// Join two Ropes
    fn new(left: &Rope, right: &Rope) -> Concat {
        let graphemes = left.num_graphemes() + right.num_graphemes();
        Concat { left: left.clone(), right: right.clone(), graphemes: graphemes }
    }

    /// Split a Rope after the nth grapheme
    fn split(&self, grapheme_index: usize) -> (Rope, Rope) {
        // if self is (a, b)
        // find out if the index is in the left or right child
        if self.left.num_graphemes() >= grapheme_index {
            // split a into (a1, a2), return ( a1, concat(a2, b) )
            let (a1, a2) = self.left.split(grapheme_index);
            return (a1, Rope::Concat(Rc::new(Concat::new(&a2, &self.right))));
        } else {
            // split b into (b1, b2), return ( concat(a, b1), b2 )
            let (b1, b2) = self.right.split(grapheme_index - self.left.num_graphemes());
            return (Rope::Concat(Rc::new(Concat::new(&self.left, &b1))), b2);
        }
    }

    /// Gets the number of Unicode grapheme clusters in the children of this node
    fn num_graphemes(&self) -> usize {
        self.graphemes
    }
}
impl Clone for Concat {
    fn clone(&self) -> Concat {
        Concat { left: self.left.clone(),
                 right: self.right.clone(),
                 graphemes: self.graphemes }
    }
}

enum Rope {
    Leaf(Leaf),
    Concat(Rc<Concat>),
}
impl Rope {
    /// Create a new Rope
    fn from_string(base: &str) -> Rope {
        Rope::Leaf(Leaf::from_string(base))
    }
    /// Gets the number of Unicode grapheme clusters in the children of this node
    fn num_graphemes(&self) -> usize {
        match *self {
            Rope::Leaf(ref leaf) => leaf.num_graphemes(),
            Rope::Concat(ref concat) => concat.num_graphemes(),
        }
    }
    /// Split a Rope after the nth grapheme
    fn split(&self, grapheme_index: usize) -> (Rope, Rope) {
        match *self {
            Rope::Leaf(ref leaf) => leaf.split(grapheme_index),
            Rope::Concat(ref concat) => concat.split(grapheme_index),
        }
    }
    /// Collect the pieces of this Rope into a continuous String
    fn to_string(&self) -> String {
        let mut buf = String::with_capacity(self.num_graphemes());

        fn str_parts<'a>(root: &'a Rope) -> Vec<&'a str> {
            let mut v = vec![];
            match *root {
                Rope::Leaf(ref leaf) => {
                    v.push(leaf.to_str());
                },
                Rope::Concat(ref concat) => {
                    v.push_all(&str_parts(&concat.left));
                    v.push_all(&str_parts(&concat.right));
                },
            }
            v
        }
        for part in str_parts(self).iter() {
            buf.push_str(part);
        }

        buf
    }
    /// Join two pieces into a Rope
    fn join(left: &Rope, right: &Rope) -> Rope {
        Rope::Concat(Rc::new(Concat::new(left, right)))
    }
    /// Insert a string into a Rope by splitting and joining nodes
    /// Returns a new Rope, leaving the original unchanged
    fn insert(&self, grapheme_index: usize, value: &str) -> Rope {
        let (left, right) = self.split(grapheme_index);
        let left = Rope::join(&left, &Rope::from_string(value));
        Rope::join(&left, &right)
    }

}
impl Clone for Rope {
    fn clone(&self) -> Rope {
        match *self {
            Rope::Leaf(ref leaf) => Rope::Leaf(leaf.clone()),
            Rope::Concat(ref concat) => Rope::Concat(concat.clone()),
        }
    }
}

/// Count the number of unicode extended grapheme clusters in a string
/// This is O(n)
fn count_clusters(s: &str) -> usize {
    UnicodeSegmentation::graphemes(s, true).collect::<Vec<&str>>().len()
}

#[test]
fn test_count_clusters() {
    // 11 bytes, 3 grapheme clusters
    let s = "a̐éö̲";
    assert_eq!(s.len(), 11);
    assert_eq!(count_clusters(s), 3);
}

#[test]
fn test_create_leaf() {
    let base = "a̐éö̲";
    let leaf = Leaf::from_string(base);
    assert_eq!(leaf.num_graphemes(), 3);
}

#[test]
fn test_split_leaf() {
    let base = "a̐éö̲a̐éö̲";
    let leaf = Leaf::from_string(base);
    let (left, right) = leaf.split(3);
    assert_eq!(left.num_graphemes(), right.num_graphemes());
    assert_eq!(left.to_string(), "a̐éö̲");
}

#[test]
fn test_create_rope() {
    let rope = Rope::from_string("The quick brown fox jumps over the lazy dog.");

    assert_eq!(rope.num_graphemes(), 44);
    assert_eq!(rope.to_string(), "The quick brown fox jumps over the lazy dog.");
}

#[test]
fn test_rope_operations() {
    let rope = Rope::from_string("The quick brown fox jumps over the lazy dog.");

    let (left, right) = rope.split(22);
    assert_eq!(left.to_string(), "The quick brown fox ju");
    assert_eq!(right.to_string(), "mps over the lazy dog.");

    let rope = Rope::join(&left, &Rope::from_string("mps over the tiny wooden fence!"));
    assert_eq!(rope.to_string(), "The quick brown fox jumps over the tiny wooden fence!");

    let rope2 = rope.insert(10, "(and really very clever) ");
    assert_eq!(rope2.to_string(), "The quick (and really very clever) brown fox jumps over the tiny wooden fence!");
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]
#![warn(dead_code)]

//! A user friendly game engine written in Rust.

#[cfg(feature = "include_gfx")]
extern crate libc;
#[cfg(feature = "include_gfx")]
extern crate gfx;
#[cfg(feature = "include_gfx")]
extern crate gfx_device_gl;
#[cfg(feature = "include_gfx")]
extern crate gfx_graphics;
#[cfg(feature = "include_opengl")]
extern crate opengl_graphics;
#[cfg(feature = "include_sdl2")]
extern crate sdl2;
#[cfg(feature = "include_sdl2")]
extern crate sdl2_window;
#[cfg(feature = "include_glfw")]
extern crate glfw;
#[cfg(feature = "include_glfw")]
extern crate glfw_window;
#[cfg(feature = "include_glutin")]
extern crate glutin;
#[cfg(feature = "include_glutin")]
extern crate glutin_window;
extern crate graphics;
extern crate fps_counter;
extern crate current;
extern crate shader_version;

extern crate piston;

#[cfg(feature = "include_sdl2")]
pub use sdl2_window::Sdl2Window as WindowBackEnd;
#[cfg(feature = "include_glfw")]
pub use glfw_window::GlfwWindow as WindowBackEnd;
#[cfg(feature = "include_glutin")]
pub use glutin_window::GlutinWindow as WindowBackEnd;

#[cfg(feature = "include_gfx")]
use gfx_graphics::Gfx2d;
#[cfg(feature = "include_gfx")]
use gfx_device_gl::{ Device, Resources };
#[cfg(feature = "include_gfx")]
use gfx_device_gl::CommandBuffer;

#[cfg(feature = "include_opengl")]
use opengl_graphics::GlGraphics;
use fps_counter::FPSCounter;

use std::rc::Rc;
use std::cell::RefCell;

use piston::window::WindowSettings;
use current::{ Current, CurrentGuard };

fn start_window<F>(
    opengl: shader_version::OpenGL,
    window_settings: WindowSettings,
    mut f: F
)
    where
        F: FnMut()
{
    let mut window = Rc::new(RefCell::new(WindowBackEnd::new(
        opengl,
        window_settings,
    )));
    let mut fps_counter = Rc::new(RefCell::new(FPSCounter::new()));

    #[cfg(feature = "include_sdl2")]
    fn disable_vsync() { sdl2::video::gl_set_swap_interval(0); }

    #[cfg(not(feature = "include_sdl2"))]
    fn disable_vsync() {}

    disable_vsync();

    let window_guard = CurrentGuard::new(&mut window);
    let fps_counter_guard = CurrentGuard::new(&mut fps_counter);

    f();

    drop(window_guard);
    drop(fps_counter_guard);
}

#[cfg(feature = "include_opengl")]
fn start_opengl<F>(opengl: shader_version::OpenGL, mut f: F)
    where
        F: FnMut()
{
    let mut gl = Rc::new(RefCell::new(GlGraphics::new(opengl)));

    let gl_guard = CurrentGuard::new(&mut gl);

    f();

    drop(gl_guard);
}

#[cfg(not(feature = "include_opengl"))]
fn start_opengl<F>(_opengl: shader_version::OpenGL, mut f: F)
    where
        F: FnMut()
{
    f();
}

#[cfg(feature = "include_gfx")]
fn start_gfx<F>(mut f: F)
    where
        F: FnMut()
{
    use piston::window::Window;
    use gfx::render::ext::factory::RenderFactory;

    let window = current_window();

    let (device, mut factory) = gfx_device_gl::create(|s| {
        #[cfg(feature = "include_sdl2")]
        fn get_proc_address(_: &WindowBackEnd, s: &str) ->
            *const libc::types::common::c95::c_void {
            unsafe { std::mem::transmute(sdl2::video::gl_get_proc_address(s)) }
        }

        #[cfg(feature = "include_glfw")]
        fn get_proc_address(window: &mut WindowBackEnd, s: &str) ->
            *const libc::types::common::c95::c_void {
            window.window.get_proc_address(s)
        }

        #[cfg(feature = "include_glutin")]
        fn get_proc_address(window: &WindowBackEnd, s: &str) ->
            *const libc::types::common::c95::c_void {
            window.window.get_proc_address(s)
        }

        get_proc_address(&mut *window.borrow_mut(), s)
    });
    let mut renderer: Rc<RefCell<
        gfx::Renderer<gfx_device_gl::Resources,
        <gfx_device_gl::Device as gfx::Device>::CommandBuffer
    >>> =
        Rc::new(RefCell::new(factory.create_renderer()));
    let mut device = Rc::new(RefCell::new(device));
    let factory = Rc::new(RefCell::new(factory));
    let mut g2d = Rc::new(RefCell::new(Gfx2d::new(&mut *device.borrow_mut(), &mut *factory.borrow_mut())));
    let size = window.borrow().size();
    let mut frame = Rc::new(RefCell::new(gfx::Frame::<Resources>::new(
        size.width as u16, size.height as u16)));

    let device_guard = CurrentGuard::new(&mut device);
    let g2d_guard = CurrentGuard::new(&mut g2d);
    let renderer_guard = CurrentGuard::new(&mut renderer);
    let frame_guard = CurrentGuard::new(&mut frame);

    f();

    drop(g2d_guard);
    drop(renderer_guard);
    drop(frame_guard);
    drop(device_guard);
}

#[cfg(not(feature = "include_gfx"))]
fn start_gfx<F>(mut f: F)
    where
        F: FnMut()
{
    f();
}

/// Initializes window and sets up current objects.
pub fn start<F>(
    opengl: shader_version::OpenGL,
    window_settings: WindowSettings,
    mut f: F
)
    where
        F: FnMut()
{
    start_window(opengl, window_settings, || {
        start_opengl(opengl, || {
            if cfg!(feature = "include_gfx") {
                start_gfx(|| f());
            } else {
                f();
            }
        })
    });
}

/// The current window
pub fn current_window() -> Rc<RefCell<WindowBackEnd>> {
    unsafe {
        Current::<Rc<RefCell<WindowBackEnd>>>::new().clone()
    }
}
/// The current Gfx device
#[cfg(feature = "include_gfx")]
pub fn current_gfx_device() -> Rc<RefCell<Device>> {
    unsafe {
        Current::<Rc<RefCell<Device>>>::new().clone()
    }
}
/// The current opengl_graphics back-end
#[cfg(feature = "include_opengl")]
pub fn current_gl() -> Rc<RefCell<GlGraphics>> {
    unsafe {
        Current::<Rc<RefCell<GlGraphics>>>::new().clone()
    }
}
/// The current gfx_graphics back-end
#[cfg(feature = "include_gfx")]
pub fn current_g2d() -> Rc<RefCell<Gfx2d<Resources>>> {
    unsafe {
        Current::<Rc<RefCell<Gfx2d<Resources>>>>::new().clone()
    }
}
/// The current Gfx renderer
#[cfg(feature = "include_gfx")]
pub fn current_renderer() -> Rc<RefCell<gfx::Renderer<Resources, CommandBuffer>>> {
    unsafe {
        Current::<Rc<RefCell<gfx::Renderer<Resources, CommandBuffer>>>>::new().clone()
    }
}
/// The current Gfx frame
#[cfg(feature = "include_gfx")]
pub fn current_frame() -> Rc<RefCell<gfx::Frame<Resources>>> {
    unsafe {
        Current::<Rc<RefCell<gfx::Frame<Resources>>>>::new().clone()
    }
}
/// The current FPS counter
pub fn current_fps_counter() -> Rc<RefCell<FPSCounter>> {
    unsafe {
        Current::<Rc<RefCell<FPSCounter>>>::new().clone()
    }
}

/// Returns an event iterator for the event loop
pub fn events() -> piston::event::events::Events<WindowBackEnd, piston::event::Event> {
    use piston::event::Events;

    current_window().events()
}

/// Updates the FPS counter and gets the frames per second.
pub fn fps_tick() -> usize {
    let fps_counter = current_fps_counter();
    let mut fps_counter = fps_counter.borrow_mut();
    fps_counter.tick()
}

/// Sets title of the current window.
pub fn set_title(text: String) {
    use piston::window::AdvancedWindow;

    let window = current_window();
    let mut window = window.borrow_mut();
    window.set_title(text);
}

/// Returns true if the current window should be closed.
pub fn should_close() -> bool {
    use piston::window::Window;

    let window = current_window();
    let window = window.borrow();
    window.should_close()
}

/// Renders 2D graphics using Gfx.
#[cfg(feature = "include_gfx")]
pub fn render_2d_gfx<F>(
    bg_color: Option<[f32; 4]>,
    mut f: F
)
    where
        F: FnMut(graphics::Context,
            &mut gfx_graphics::GfxGraphics<Resources, CommandBuffer>)
{
    use gfx::Device;
    use piston::window::Window;
    use graphics::Viewport;

    let window = current_window();
    let window = window.borrow();
    let size = window.size();
    let draw_size = window.draw_size();
    let renderer = current_renderer();
    let mut renderer = renderer.borrow_mut();
    let renderer = &mut *renderer;
    let gfx = current_g2d();
    let mut gfx = gfx.borrow_mut();
    let frame = current_frame();
    let frame = frame.borrow();
    gfx.draw(
        renderer,
        &*frame,
        Viewport {
            rect: [0, 0, draw_size.width as i32, draw_size.height as i32],
            draw_size: [draw_size.width, draw_size.height],
            window_size: [size.width, size.height],
        },
        |c, g| {
            if let Some(bg_color) = bg_color {
                graphics::clear(bg_color, g);
            }
            f(c, g);
        });
    let gfx_device = current_gfx_device();
    let mut gfx_device = gfx_device.borrow_mut();
    gfx_device.submit(renderer.as_buffer());
    renderer.reset();
}

/// Renders 2D graphics using OpenGL.
///
/// Panics if called nested within the closure
/// to prevent mutable aliases to the graphics back-end.
#[cfg(feature = "include_opengl")]
pub fn render_2d_opengl<F>(
    bg_color: Option<[f32; 4]>,
    mut f: F
)
    where
        F: FnMut(graphics::Context, &mut opengl_graphics::Gl)
{
    use piston::window::Window;
    use graphics::Viewport;

    let window = current_window();
    let window = window.borrow();
    let size = window.size();
    let draw_size = window.draw_size();
    let gl = current_gl();
    let mut gl = gl.borrow_mut();
    gl.draw(Viewport {
        rect: [0, 0, draw_size.width as i32, draw_size.height as i32],
        draw_size: [draw_size.width, draw_size.height],
        window_size: [size.width, size.height]
    }, |c, g| {
        use graphics::*;
        if let Some(bg_color) = bg_color {
            graphics::clear(bg_color, g);
        }
        f(c, g);
    });
}

<commit_msg>Upgraded to latest Gfx<commit_after>#![deny(missing_docs)]
#![warn(dead_code)]

//! A user friendly game engine written in Rust.

#[cfg(feature = "include_gfx")]
extern crate libc;
#[cfg(feature = "include_gfx")]
extern crate gfx;
#[cfg(feature = "include_gfx")]
extern crate gfx_device_gl;
#[cfg(feature = "include_gfx")]
extern crate gfx_graphics;
#[cfg(feature = "include_opengl")]
extern crate opengl_graphics;
#[cfg(feature = "include_sdl2")]
extern crate sdl2;
#[cfg(feature = "include_sdl2")]
extern crate sdl2_window;
#[cfg(feature = "include_glfw")]
extern crate glfw;
#[cfg(feature = "include_glfw")]
extern crate glfw_window;
#[cfg(feature = "include_glutin")]
extern crate glutin;
#[cfg(feature = "include_glutin")]
extern crate glutin_window;
extern crate graphics;
extern crate fps_counter;
extern crate current;
extern crate shader_version;

extern crate piston;

#[cfg(feature = "include_sdl2")]
pub use sdl2_window::Sdl2Window as WindowBackEnd;
#[cfg(feature = "include_glfw")]
pub use glfw_window::GlfwWindow as WindowBackEnd;
#[cfg(feature = "include_glutin")]
pub use glutin_window::GlutinWindow as WindowBackEnd;

#[cfg(feature = "include_gfx")]
use gfx_graphics::Gfx2d;
#[cfg(feature = "include_gfx")]
use gfx_device_gl::{ Device, Resources, CommandBuffer, Output };

#[cfg(feature = "include_opengl")]
use opengl_graphics::GlGraphics;
use fps_counter::FPSCounter;

use std::rc::Rc;
use std::cell::RefCell;

use piston::window::WindowSettings;
use current::{ Current, CurrentGuard };

fn start_window<F>(
    opengl: shader_version::OpenGL,
    window_settings: WindowSettings,
    mut f: F
)
    where
        F: FnMut()
{
    let mut window = Rc::new(RefCell::new(WindowBackEnd::new(
        opengl,
        window_settings,
    )));
    let mut fps_counter = Rc::new(RefCell::new(FPSCounter::new()));

    #[cfg(feature = "include_sdl2")]
    fn disable_vsync() { sdl2::video::gl_set_swap_interval(0); }

    #[cfg(not(feature = "include_sdl2"))]
    fn disable_vsync() {}

    disable_vsync();

    let window_guard = CurrentGuard::new(&mut window);
    let fps_counter_guard = CurrentGuard::new(&mut fps_counter);

    f();

    drop(window_guard);
    drop(fps_counter_guard);
}

#[cfg(feature = "include_opengl")]
fn start_opengl<F>(opengl: shader_version::OpenGL, mut f: F)
    where
        F: FnMut()
{
    let mut gl = Rc::new(RefCell::new(GlGraphics::new(opengl)));

    let gl_guard = CurrentGuard::new(&mut gl);

    f();

    drop(gl_guard);
}

#[cfg(not(feature = "include_opengl"))]
fn start_opengl<F>(_opengl: shader_version::OpenGL, mut f: F)
    where
        F: FnMut()
{
    f();
}

#[cfg(feature = "include_gfx")]
fn start_gfx<F>(mut f: F)
    where
        F: FnMut()
{
    use piston::window::Window;
    use gfx::render::RenderFactory;

    let window = current_window();

    let (device, mut factory) = gfx_device_gl::create(|s| {
        #[cfg(feature = "include_sdl2")]
        fn get_proc_address(_: &WindowBackEnd, s: &str) ->
            *const libc::types::common::c95::c_void {
            unsafe { std::mem::transmute(sdl2::video::gl_get_proc_address(s)) }
        }

        #[cfg(feature = "include_glfw")]
        fn get_proc_address(window: &mut WindowBackEnd, s: &str) ->
            *const libc::types::common::c95::c_void {
            window.window.get_proc_address(s)
        }

        #[cfg(feature = "include_glutin")]
        fn get_proc_address(window: &WindowBackEnd, s: &str) ->
            *const libc::types::common::c95::c_void {
            window.window.get_proc_address(s)
        }

        get_proc_address(&mut *window.borrow_mut(), s)
    });
    let mut renderer: Rc<RefCell<
        gfx::Renderer<gfx_device_gl::Resources,
        <gfx_device_gl::Device as gfx::Device>::CommandBuffer
    >>> =
        Rc::new(RefCell::new(factory.create_renderer()));
    let mut device = Rc::new(RefCell::new(device));
    let factory = Rc::new(RefCell::new(factory));
    let mut g2d = Rc::new(RefCell::new(Gfx2d::new(&mut *device.borrow_mut(), &mut *factory.borrow_mut())));
    let size = window.borrow().size();
    let mut output = Rc::new(RefCell::new(factory.borrow_mut().make_fake_output(
        size.width as u16, size.height as u16)));

    let device_guard = CurrentGuard::new(&mut device);
    let g2d_guard = CurrentGuard::new(&mut g2d);
    let renderer_guard = CurrentGuard::new(&mut renderer);
    let output_guard = CurrentGuard::new(&mut output);

    f();

    drop(g2d_guard);
    drop(renderer_guard);
    drop(output_guard);
    drop(device_guard);
}

#[cfg(not(feature = "include_gfx"))]
fn start_gfx<F>(mut f: F)
    where
        F: FnMut()
{
    f();
}

/// Initializes window and sets up current objects.
pub fn start<F>(
    opengl: shader_version::OpenGL,
    window_settings: WindowSettings,
    mut f: F
)
    where
        F: FnMut()
{
    start_window(opengl, window_settings, || {
        start_opengl(opengl, || {
            if cfg!(feature = "include_gfx") {
                start_gfx(|| f());
            } else {
                f();
            }
        })
    });
}

/// The current window
pub fn current_window() -> Rc<RefCell<WindowBackEnd>> {
    unsafe {
        Current::<Rc<RefCell<WindowBackEnd>>>::new().clone()
    }
}
/// The current Gfx device
#[cfg(feature = "include_gfx")]
pub fn current_gfx_device() -> Rc<RefCell<Device>> {
    unsafe {
        Current::<Rc<RefCell<Device>>>::new().clone()
    }
}
/// The current opengl_graphics back-end
#[cfg(feature = "include_opengl")]
pub fn current_gl() -> Rc<RefCell<GlGraphics>> {
    unsafe {
        Current::<Rc<RefCell<GlGraphics>>>::new().clone()
    }
}
/// The current gfx_graphics back-end
#[cfg(feature = "include_gfx")]
pub fn current_g2d() -> Rc<RefCell<Gfx2d<Resources>>> {
    unsafe {
        Current::<Rc<RefCell<Gfx2d<Resources>>>>::new().clone()
    }
}
/// The current Gfx renderer
#[cfg(feature = "include_gfx")]
pub fn current_renderer() -> Rc<RefCell<gfx::Renderer<Resources, CommandBuffer>>> {
    unsafe {
        Current::<Rc<RefCell<gfx::Renderer<Resources, CommandBuffer>>>>::new().clone()
    }
}
/// The current Gfx frame
#[cfg(feature = "include_gfx")]
pub fn current_output() -> Rc<RefCell<Output>> {
    unsafe {
        Current::<Rc<RefCell<Output>>>::new().clone()
    }
}
/// The current FPS counter
pub fn current_fps_counter() -> Rc<RefCell<FPSCounter>> {
    unsafe {
        Current::<Rc<RefCell<FPSCounter>>>::new().clone()
    }
}

/// Returns an event iterator for the event loop
pub fn events() -> piston::event::events::Events<WindowBackEnd, piston::event::Event> {
    use piston::event::Events;

    current_window().events()
}

/// Updates the FPS counter and gets the frames per second.
pub fn fps_tick() -> usize {
    let fps_counter = current_fps_counter();
    let mut fps_counter = fps_counter.borrow_mut();
    fps_counter.tick()
}

/// Sets title of the current window.
pub fn set_title(text: String) {
    use piston::window::AdvancedWindow;

    let window = current_window();
    let mut window = window.borrow_mut();
    window.set_title(text);
}

/// Returns true if the current window should be closed.
pub fn should_close() -> bool {
    use piston::window::Window;

    let window = current_window();
    let window = window.borrow();
    window.should_close()
}

/// Renders 2D graphics using Gfx.
#[cfg(feature = "include_gfx")]
pub fn render_2d_gfx<F>(
    bg_color: Option<[f32; 4]>,
    mut f: F
)
    where
        F: FnMut(graphics::Context,
            &mut gfx_graphics::GfxGraphics<Resources, CommandBuffer, Output>)
{
    use gfx::Device;
    use piston::window::Window;
    use graphics::Viewport;

    let window = current_window();
    let window = window.borrow();
    let size = window.size();
    let draw_size = window.draw_size();
    let renderer = current_renderer();
    let mut renderer = renderer.borrow_mut();
    let renderer = &mut *renderer;
    let gfx = current_g2d();
    let mut gfx = gfx.borrow_mut();
    let output = current_output();
    let output = output.borrow();
    gfx.draw(
        renderer,
        &*output,
        Viewport {
            rect: [0, 0, draw_size.width as i32, draw_size.height as i32],
            draw_size: [draw_size.width, draw_size.height],
            window_size: [size.width, size.height],
        },
        |c, g| {
            if let Some(bg_color) = bg_color {
                graphics::clear(bg_color, g);
            }
            f(c, g);
        });
    let gfx_device = current_gfx_device();
    let mut gfx_device = gfx_device.borrow_mut();
    gfx_device.submit(renderer.as_buffer());
    renderer.reset();
}

/// Renders 2D graphics using OpenGL.
///
/// Panics if called nested within the closure
/// to prevent mutable aliases to the graphics back-end.
#[cfg(feature = "include_opengl")]
pub fn render_2d_opengl<F>(
    bg_color: Option<[f32; 4]>,
    mut f: F
)
    where
        F: FnMut(graphics::Context, &mut opengl_graphics::GlGraphics)
{
    use piston::window::Window;
    use graphics::Viewport;

    let window = current_window();
    let window = window.borrow();
    let size = window.size();
    let draw_size = window.draw_size();
    let gl = current_gl();
    let mut gl = gl.borrow_mut();
    gl.draw(Viewport {
        rect: [0, 0, draw_size.width as i32, draw_size.height as i32],
        draw_size: [draw_size.width, draw_size.height],
        window_size: [size.width, size.height]
    }, |c, g| {
        use graphics::*;
        if let Some(bg_color) = bg_color {
            graphics::clear(bg_color, g);
        }
        f(c, g);
    });
}

<|endoftext|>