<commit_before>use std::num::ToPrimitive;

use serialize::json::Json;

use helpers::{HelperDef};
use template::{Helper};
use registry::{Registry};
use context::{Context, JsonRender};
use render::{Renderable, RenderContext, RenderError, render_error, EMPTY};

#[derive(Copy)]
pub struct LookupHelper;

impl HelperDef for LookupHelper {
    fn call(&self, c: &Context, h: &Helper, _: &Registry, rc: &mut RenderContext) -> Result<String, RenderError> {
        let value_param = h.params().get(0);
        let index_param = h.params().get(1);

        if value_param.is_none() {
            return Err(render_error("Param not found for helper \"lookup\""));
        }
        if index_param.is_none() {
            return Err(render_error("Insuffitient params for helper \"lookup\""));
        }

        let value = c.navigate(rc.get_path(), value_param.unwrap());
        match *value {
            Json::Array (ref l) => {
                let index_param_name = index_param.unwrap();
                let index = rc.get_local_var(index_param_name);
                match *index {
                    Json::U64(i) => {
                        match l.get(i.to_uint().unwrap()) {
                            Some(v) => Ok(v.render()),
                            None => Ok(EMPTY.to_string())
                        }
                    }
                    _ => {
                        Err(render_error("Invalid index name in \"lookup\""))
                    }
                }
            },

            _ => {
                Err(render_error("Cannot lookup value that is not an array"))
            }
        }
    }
}

pub static LOOKUP_HELPER: LookupHelper = LookupHelper;

#[cfg(test)]
mod test {
    use template::{Template};
    use registry::{Registry};

    use std::collections::BTreeMap;

    #[test]
    fn test_lookup() {
        let t0 = Template::compile("{{#each v1}}{{lookup ../v2 @index}}{{/each}}".to_string()).ok().unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);

        let mut m :BTreeMap<String, Vec<u16>> = BTreeMap::new();
        m.insert("v1".to_string(), vec![1u16, 2u16, 3u16]);
        m.insert("v2".to_string(), vec![9u16, 8u16, 7u16]);

        let r0 = handlebars.render("t0", &m);
        assert_eq!(r0.ok().unwrap(), "987".to_string());
    }
}
<commit_msg>(fix) rustup: to_uint -> to_usize<commit_after>use std::num::ToPrimitive;

use serialize::json::Json;

use helpers::{HelperDef};
use template::{Helper};
use registry::{Registry};
use context::{Context, JsonRender};
use render::{Renderable, RenderContext, RenderError, render_error, EMPTY};

#[derive(Copy)]
pub struct LookupHelper;

impl HelperDef for LookupHelper {
    fn call(&self, c: &Context, h: &Helper, _: &Registry, rc: &mut RenderContext) -> Result<String, RenderError> {
        let value_param = h.params().get(0);
        let index_param = h.params().get(1);

        if value_param.is_none() {
            return Err(render_error("Param not found for helper \"lookup\""));
        }
        if index_param.is_none() {
            return Err(render_error("Insuffitient params for helper \"lookup\""));
        }

        let value = c.navigate(rc.get_path(), value_param.unwrap());
        match *value {
            Json::Array (ref l) => {
                let index_param_name = index_param.unwrap();
                let index = rc.get_local_var(index_param_name);
                match *index {
                    Json::U64(i) => {
                        match l.get(i.to_usize().unwrap()) {
                            Some(v) => Ok(v.render()),
                            None => Ok(EMPTY.to_string())
                        }
                    }
                    _ => {
                        Err(render_error("Invalid index name in \"lookup\""))
                    }
                }
            },

            _ => {
                Err(render_error("Cannot lookup value that is not an array"))
            }
        }
    }
}

pub static LOOKUP_HELPER: LookupHelper = LookupHelper;

#[cfg(test)]
mod test {
    use template::{Template};
    use registry::{Registry};

    use std::collections::BTreeMap;

    #[test]
    fn test_lookup() {
        let t0 = Template::compile("{{#each v1}}{{lookup ../v2 @index}}{{/each}}".to_string()).ok().unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);

        let mut m :BTreeMap<String, Vec<u16>> = BTreeMap::new();
        m.insert("v1".to_string(), vec![1u16, 2u16, 3u16]);
        m.insert("v2".to_string(), vec![9u16, 8u16, 7u16]);

        let r0 = handlebars.render("t0", &m);
        assert_eq!(r0.ok().unwrap(), "987".to_string());
    }
}
<|endoftext|>


<commit_before>use std::env;

use crate::spec::{FramePointer, SplitDebuginfo, TargetOptions};

pub fn opts(os: &str) -> TargetOptions {
    // ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6
    // either the linker will complain if it is used or the binary will end up
    // segfaulting at runtime when run on 10.6. Rust by default supports macOS
    // 10.7+, but there is a standard environment variable,
    // MACOSX_DEPLOYMENT_TARGET, which is used to signal targeting older
    // versions of macOS. For example compiling on 10.10 with
    // MACOSX_DEPLOYMENT_TARGET set to 10.6 will cause the linker to generate
    // warnings about the usage of ELF TLS.
    //
    // Here we detect what version is being requested, defaulting to 10.7. ELF
    // TLS is flagged as enabled if it looks to be supported.
    let version = macos_deployment_target();

    TargetOptions {
        os: os.to_string(),
        vendor: "apple".to_string(),
        // macOS has -dead_strip, which doesn't rely on function_sections
        function_sections: false,
        dynamic_linking: true,
        linker_is_gnu: false,
        executables: true,
        families: vec!["unix".to_string()],
        is_like_osx: true,
        dwarf_version: Some(2),
        frame_pointer: FramePointer::Always,
        has_rpath: true,
        dll_suffix: ".dylib".to_string(),
        archive_format: "darwin".to_string(),
        has_elf_tls: version >= (10, 7),
        abi_return_struct_as_int: true,
        emit_debug_gdb_scripts: false,
        eh_frame_header: false,

        // The historical default for macOS targets is to run `dsymutil` which
        // generates a packed version of debuginfo split from the main file.
        split_debuginfo: SplitDebuginfo::Packed,

        // This environment variable is pretty magical but is intended for
        // producing deterministic builds. This was first discovered to be used
        // by the `ar` tool as a way to control whether or not mtime entries in
        // the archive headers were set to zero or not. It appears that
        // eventually the linker got updated to do the same thing and now reads
        // this environment variable too in recent versions.
        //
        // For some more info see the commentary on #47086
        link_env: vec![("ZERO_AR_DATE".to_string(), "1".to_string())],

        ..Default::default()
    }
}

fn deployment_target(var_name: &str) -> Option<(u32, u32)> {
    let deployment_target = env::var(var_name).ok();
    deployment_target
        .as_ref()
        .and_then(|s| s.split_once('.'))
        .and_then(|(a, b)| a.parse::<u32>().and_then(|a| b.parse::<u32>().map(|b| (a, b))).ok())
}

fn macos_deployment_target() -> (u32, u32) {
    deployment_target("MACOSX_DEPLOYMENT_TARGET").unwrap_or((10, 7))
}

pub fn macos_llvm_target(arch: &str) -> String {
    let (major, minor) = macos_deployment_target();
    format!("{}-apple-macosx{}.{}.0", arch, major, minor)
}

pub fn macos_link_env_remove() -> Vec<String> {
    let mut env_remove = Vec::with_capacity(2);
    // Remove the `SDKROOT` environment variable if it's clearly set for the wrong platform, which
    // may occur when we're linking a custom build script while targeting iOS for example.
    if let Ok(sdkroot) = env::var("SDKROOT") {
        if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("iPhoneSimulator.platform") {
            env_remove.push("SDKROOT".to_string())
        }
    }
    // Additionally, `IPHONEOS_DEPLOYMENT_TARGET` must not be set when using the Xcode linker at
    // "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld",
    // although this is apparently ignored when using the linker at "/usr/bin/ld".
    env_remove.push("IPHONEOS_DEPLOYMENT_TARGET".to_string());
    env_remove
}

fn ios_deployment_target() -> (u32, u32) {
    deployment_target("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
}

pub fn ios_llvm_target(arch: &str) -> String {
    let (major, minor) = ios_deployment_target();
    format!("{}-apple-ios{}.{}.0", arch, major, minor)
}

pub fn ios_sim_llvm_target(arch: &str) -> String {
    let (major, minor) = ios_deployment_target();
    format!("{}-apple-ios{}.{}.0-simulator", arch, major, minor)
}
<commit_msg>Mach-O (Macos/ios/...) LLD flavor is always LD64.<commit_after>use std::env;

use crate::spec::{FramePointer, LldFlavor, SplitDebuginfo, TargetOptions};

pub fn opts(os: &str) -> TargetOptions {
    // ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6
    // either the linker will complain if it is used or the binary will end up
    // segfaulting at runtime when run on 10.6. Rust by default supports macOS
    // 10.7+, but there is a standard environment variable,
    // MACOSX_DEPLOYMENT_TARGET, which is used to signal targeting older
    // versions of macOS. For example compiling on 10.10 with
    // MACOSX_DEPLOYMENT_TARGET set to 10.6 will cause the linker to generate
    // warnings about the usage of ELF TLS.
    //
    // Here we detect what version is being requested, defaulting to 10.7. ELF
    // TLS is flagged as enabled if it looks to be supported.
    let version = macos_deployment_target();

    TargetOptions {
        os: os.to_string(),
        vendor: "apple".to_string(),
        // macOS has -dead_strip, which doesn't rely on function_sections
        function_sections: false,
        dynamic_linking: true,
        linker_is_gnu: false,
        executables: true,
        families: vec!["unix".to_string()],
        is_like_osx: true,
        dwarf_version: Some(2),
        frame_pointer: FramePointer::Always,
        has_rpath: true,
        dll_suffix: ".dylib".to_string(),
        archive_format: "darwin".to_string(),
        has_elf_tls: version >= (10, 7),
        abi_return_struct_as_int: true,
        emit_debug_gdb_scripts: false,
        eh_frame_header: false,
        lld_flavor: LldFlavor::Ld64,

        // The historical default for macOS targets is to run `dsymutil` which
        // generates a packed version of debuginfo split from the main file.
        split_debuginfo: SplitDebuginfo::Packed,

        // This environment variable is pretty magical but is intended for
        // producing deterministic builds. This was first discovered to be used
        // by the `ar` tool as a way to control whether or not mtime entries in
        // the archive headers were set to zero or not. It appears that
        // eventually the linker got updated to do the same thing and now reads
        // this environment variable too in recent versions.
        //
        // For some more info see the commentary on #47086
        link_env: vec![("ZERO_AR_DATE".to_string(), "1".to_string())],

        ..Default::default()
    }
}

fn deployment_target(var_name: &str) -> Option<(u32, u32)> {
    let deployment_target = env::var(var_name).ok();
    deployment_target
        .as_ref()
        .and_then(|s| s.split_once('.'))
        .and_then(|(a, b)| a.parse::<u32>().and_then(|a| b.parse::<u32>().map(|b| (a, b))).ok())
}

fn macos_deployment_target() -> (u32, u32) {
    deployment_target("MACOSX_DEPLOYMENT_TARGET").unwrap_or((10, 7))
}

pub fn macos_llvm_target(arch: &str) -> String {
    let (major, minor) = macos_deployment_target();
    format!("{}-apple-macosx{}.{}.0", arch, major, minor)
}

pub fn macos_link_env_remove() -> Vec<String> {
    let mut env_remove = Vec::with_capacity(2);
    // Remove the `SDKROOT` environment variable if it's clearly set for the wrong platform, which
    // may occur when we're linking a custom build script while targeting iOS for example.
    if let Ok(sdkroot) = env::var("SDKROOT") {
        if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("iPhoneSimulator.platform") {
            env_remove.push("SDKROOT".to_string())
        }
    }
    // Additionally, `IPHONEOS_DEPLOYMENT_TARGET` must not be set when using the Xcode linker at
    // "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld",
    // although this is apparently ignored when using the linker at "/usr/bin/ld".
    env_remove.push("IPHONEOS_DEPLOYMENT_TARGET".to_string());
    env_remove
}

fn ios_deployment_target() -> (u32, u32) {
    deployment_target("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
}

pub fn ios_llvm_target(arch: &str) -> String {
    let (major, minor) = ios_deployment_target();
    format!("{}-apple-ios{}.{}.0", arch, major, minor)
}

pub fn ios_sim_llvm_target(arch: &str) -> String {
    let (major, minor) = ios_deployment_target();
    format!("{}-apple-ios{}.{}.0-simulator", arch, major, minor)
}
<|endoftext|>


<commit_before>/// Breadth First Search
pub mod bfs {

    use hex2d::Coordinate;

    use std;
    use std::hash;
    use std::num::{SignedInt, FromPrimitive};
    use num::integer::{Integer};
    use std::collections::ring_buf::RingBuf;
    use std::collections::HashMap;
    use std::collections::hash_map::Entry::{Occupied,Vacant};

    struct Visited<I = i32>
        where I : SignedInt+hash::Hash<std::collections::hash_map::Hasher> {
        prev : Coordinate<I>,
        dist : u32,
    }

    /// Breadth First Search
    ///
    /// Use BFS to find closest (in walk steps) Coordinates that satisfy `is_dest` and can be
    /// reached with a walk through coordinates for which `can_pass` returns true.
    pub struct Traverser<FCanPass, FIsDest, I = i32> where
        I : SignedInt+hash::Hash<std::collections::hash_map::Hasher>,
        FCanPass : Fn(Coordinate<I>) -> bool,
        FIsDest : Fn(Coordinate<I>) -> bool
    {
        visited : HashMap<Coordinate<I>, Visited<I>>,
        to_traverse : RingBuf<Coordinate<I>>,
        can_pass : FCanPass,
        is_dest : FIsDest,
        start : Coordinate<I>,
    }

    impl<FCanPass, FIsDest, I> Traverser<FCanPass, FIsDest, I> where
        I : SignedInt+FromPrimitive+Integer+hash::Hash<std::collections::hash_map::Hasher>,
        FCanPass : Fn(Coordinate<I>) -> bool,
        FIsDest : Fn(Coordinate<I>) -> bool
    {

        /// Create a Traverser instance with initial conditions
        pub fn new(can_pass : FCanPass, is_dest : FIsDest, start: Coordinate<I>) -> Traverser<FCanPass, FIsDest, I> {
            let mut to_traverse = RingBuf::new();
            to_traverse.push_back(start);

            let mut visited = HashMap::new();
            visited.insert(start, Visited{prev: start, dist: 0});

            Traverser {
                visited: visited,
                to_traverse: to_traverse,
                can_pass: can_pass,
                is_dest: is_dest,
                start: start,
            }
        }

        /// Find next closest coordinate.
        ///
        /// Can be called multiple times, each time returning next coordinate
        pub fn find(&mut self) -> Option<Coordinate<I>> {

            loop {
                let pos = match self.to_traverse.pop_front() {
                    None => return None,
                    Some(coord) => coord,
                };

                // Traverse before returning, so `find` can be call subsequently
                // for more than just first answer
                if (self.can_pass)(pos) {

                    let &Visited{dist, ..} = self.visited.get(&pos).expect("BFS: Should have been visited already");

                    let dist = dist + 1;

                    for &npos in pos.neighbors().iter() {
                        match self.visited.entry(npos) {
                            Occupied(_) => { /* already visited */ }
                            Vacant(entry) => {
                                entry.insert(Visited{prev: pos, dist: dist});
                                self.to_traverse.push_back(npos);
                            }
                        }
                    }
                }

                if (self.is_dest)(pos) {
                    return Some(pos);
                }
            }
        }

        /// Return neighbor Coordinate to `pos` that is one step closer to
        /// `start` from initial conditions.
        ///
        /// Useful for finding whole path to a Coordinate returned by `find`.
        ///
        /// Returns `None` for Coordinates that were not yet visited.
        /// Returns `start` for `start` (from initial conditions)
        pub fn backtrace(&self, pos : Coordinate<I>) -> Option<Coordinate<I>> {
            self.visited.get(&pos).map(|entry| entry.prev)
        }

        /// Perform a recursive `backtrace` walk to find a neighbor of `start` that leads to the
        /// Coordinate returned by `find()`.
        ///
        /// Returns `None` for Coordinates that were not yet visited.
        /// Returns `start` for `start` (from initial conditions)
        pub fn backtrace_last(&self, mut pos : Coordinate<I>) -> Option<Coordinate<I>> {
            loop {
                pos = match self.visited.get(&pos) {
                    None => return None,
                    Some(entry) => {
                        if entry.prev == self.start {
                            return Some(pos);
                        } else {
                            entry.prev
                        }
                    }
                }
            }
        }
    }
}

/// Very tricky, but (hopefully) good enough, recursive LoS algorithm
pub mod los {
    use hex2d::Angle::{Left,Right};
    use hex2d::Direction;
    use hex2d::Coordinate;
    use std::num::{SignedInt, FromPrimitive};
    use num::integer::{Integer};

    fn los_rec<FOpaqueness, FVisible, I=i32>(
        opaqueness : &FOpaqueness,
        visible : &mut FVisible,
        light: I,
        p : Coordinate<I>,
        main_dir : Direction,
        dir : Option<Direction>,
        pdir : Option<Direction>,
    ) where
        I : SignedInt+FromPrimitive+Integer,
        FOpaqueness : Fn(Coordinate<I>) -> I,
        FVisible : FnMut(Coordinate<I>, I)
        {
            visible(p, light);

            let mut light = light;
            let opaq = opaqueness(p);

            if opaq >= light {
                return;
            } else {
                light = light - opaq;
            }

            let neighbors = match (dir, pdir) {
                (Some(dir), Some(pdir)) => {

                    if main_dir == dir {
                        visible(p + (main_dir + Right), light);
                        visible(p + (main_dir + Left), light);
                    }

                    if dir == pdir {
                        vec!(dir)
                    } else {
                        vec!(dir, pdir)
                    }
                },
                (Some(dir), None) => {
                    if main_dir == dir {
                        visible(p + (main_dir + Right), light);
                        visible(p + (main_dir + Left), light);
                        vec!(dir, dir + Left, dir + Right)
                    } else {
                        visible((p + main_dir), light);
                        vec!(dir, main_dir)
                    }
                },
                _ => {
                    visible(p + main_dir, light);
                    visible(p + (main_dir + Left), light);
                    visible(p + (main_dir + Right), light);
                    vec!(main_dir, main_dir + Left, main_dir + Right)
                }
            };

            for &d in neighbors.iter() {
                let n = p + d;
                match dir {
                    Some(_) => los_rec::<FOpaqueness, FVisible, I>(opaqueness, visible, light, n, d, Some(d), dir),
                    None => los_rec::<FOpaqueness, FVisible, I>(opaqueness, visible, light, n, main_dir, Some(d), dir),
                }
            }
        }

    /// Starting from `pos` in direction `dir`, call `visible` for each visible Coordinate.
    ///
    /// Use `light` as starting range of the LoS. For each visible Coordinate, the value returned
    /// by `opaqueness` will be subtracted from `light` to check if the LoS should finish due to
    /// "lack of visibility". `opaqueness` should typically return 1 for fully transparent
    /// Coordinates, and anything bigger than initial `light` for fully opaque Coordinates.
    pub fn los<FOpaqueness, FVisible, I=i32>(
        opaqueness : &FOpaqueness,
        visible : &mut FVisible,
        light: I,
        pos : Coordinate<I>,
        dirs : &[Direction],
    ) where
        I : SignedInt+FromPrimitive+Integer,
        FOpaqueness : Fn(Coordinate<I>) -> I,
        FVisible : FnMut(Coordinate<I>, I)
        {
            for dir in dirs.iter() {
                los_rec::<FOpaqueness, FVisible, I>(opaqueness, visible, light, pos, *dir, None, None);
            }
        }
}
<commit_msg>LoS improvement.<commit_after>/// Breadth First Search
pub mod bfs {

    use hex2d::Coordinate;

    use std;
    use std::hash;
    use std::num::{SignedInt, FromPrimitive};
    use num::integer::{Integer};
    use std::collections::ring_buf::RingBuf;
    use std::collections::HashMap;
    use std::collections::hash_map::Entry::{Occupied,Vacant};

    struct Visited<I = i32>
        where I : SignedInt+hash::Hash<std::collections::hash_map::Hasher> {
        prev : Coordinate<I>,
        dist : u32,
    }

    /// Breadth First Search
    ///
    /// Use BFS to find closest (in walk steps) Coordinates that satisfy `is_dest` and can be
    /// reached with a walk through coordinates for which `can_pass` returns true.
    pub struct Traverser<FCanPass, FIsDest, I = i32> where
        I : SignedInt+hash::Hash<std::collections::hash_map::Hasher>,
        FCanPass : Fn(Coordinate<I>) -> bool,
        FIsDest : Fn(Coordinate<I>) -> bool
    {
        visited : HashMap<Coordinate<I>, Visited<I>>,
        to_traverse : RingBuf<Coordinate<I>>,
        can_pass : FCanPass,
        is_dest : FIsDest,
        start : Coordinate<I>,
    }

    impl<FCanPass, FIsDest, I> Traverser<FCanPass, FIsDest, I> where
        I : SignedInt+FromPrimitive+Integer+hash::Hash<std::collections::hash_map::Hasher>,
        FCanPass : Fn(Coordinate<I>) -> bool,
        FIsDest : Fn(Coordinate<I>) -> bool
    {

        /// Create a Traverser instance with initial conditions
        pub fn new(can_pass : FCanPass, is_dest : FIsDest, start: Coordinate<I>) -> Traverser<FCanPass, FIsDest, I> {
            let mut to_traverse = RingBuf::new();
            to_traverse.push_back(start);

            let mut visited = HashMap::new();
            visited.insert(start, Visited{prev: start, dist: 0});

            Traverser {
                visited: visited,
                to_traverse: to_traverse,
                can_pass: can_pass,
                is_dest: is_dest,
                start: start,
            }
        }

        /// Find next closest coordinate.
        ///
        /// Can be called multiple times, each time returning next coordinate
        pub fn find(&mut self) -> Option<Coordinate<I>> {

            loop {
                let pos = match self.to_traverse.pop_front() {
                    None => return None,
                    Some(coord) => coord,
                };

                // Traverse before returning, so `find` can be call subsequently
                // for more than just first answer
                if (self.can_pass)(pos) {

                    let &Visited{dist, ..} = self.visited.get(&pos).expect("BFS: Should have been visited already");

                    let dist = dist + 1;

                    for &npos in pos.neighbors().iter() {
                        match self.visited.entry(npos) {
                            Occupied(_) => { /* already visited */ }
                            Vacant(entry) => {
                                entry.insert(Visited{prev: pos, dist: dist});
                                self.to_traverse.push_back(npos);
                            }
                        }
                    }
                }

                if (self.is_dest)(pos) {
                    return Some(pos);
                }
            }
        }

        /// Return neighbor Coordinate to `pos` that is one step closer to
        /// `start` from initial conditions.
        ///
        /// Useful for finding whole path to a Coordinate returned by `find`.
        ///
        /// Returns `None` for Coordinates that were not yet visited.
        /// Returns `start` for `start` (from initial conditions)
        pub fn backtrace(&self, pos : Coordinate<I>) -> Option<Coordinate<I>> {
            self.visited.get(&pos).map(|entry| entry.prev)
        }

        /// Perform a recursive `backtrace` walk to find a neighbor of `start` that leads to the
        /// Coordinate returned by `find()`.
        ///
        /// Returns `None` for Coordinates that were not yet visited.
        /// Returns `start` for `start` (from initial conditions)
        pub fn backtrace_last(&self, mut pos : Coordinate<I>) -> Option<Coordinate<I>> {
            loop {
                pos = match self.visited.get(&pos) {
                    None => return None,
                    Some(entry) => {
                        if entry.prev == self.start {
                            return Some(pos);
                        } else {
                            entry.prev
                        }
                    }
                }
            }
        }
    }
}

/// Very tricky, but (hopefully) good enough, recursive LoS algorithm
pub mod los {
    use hex2d::Angle::{Left,Right};
    use hex2d::Direction;
    use hex2d::Coordinate;
    use std::num::{SignedInt, FromPrimitive};
    use num::integer::{Integer};

    fn los_rec<FOpaqueness, FVisible, I=i32>(
        opaqueness : &FOpaqueness,
        visible : &mut FVisible,
        light: I,
        pos : Coordinate<I>,
        start_dir : Direction,
        main_dir : Direction,
        dir : Option<Direction>,
        pdir : Option<Direction>,
    ) where
        I : SignedInt+FromPrimitive+Integer,
        FOpaqueness : Fn(Coordinate<I>) -> I,
        FVisible : FnMut(Coordinate<I>, I)
        {
            visible(pos, light);

            let mut light = light;
            let opaq = opaqueness(pos);

            if opaq >= light {
                return;
            } else {
                light = light - opaq;
            }

            // Handle long corridors a bit better
            if main_dir + Left == start_dir || main_dir == start_dir {
                visible(pos + (main_dir + Left), light);
            }
            if main_dir + Right == start_dir || main_dir == start_dir {
                visible(pos + (main_dir + Right), light);
            }

            let neighbors = match (dir, pdir) {
                (Some(dir), Some(pdir)) => {
                    if dir == pdir {
                        vec!(dir)
                    } else {
                        vec!(dir, pdir)
                    }
                },
                (Some(dir), None) => {
                    if main_dir == dir {
                        vec!(dir, dir + Left, dir + Right)
                    } else {
                        vec!(dir, main_dir)
                    }
                },
                _ => {
                    vec!(main_dir, main_dir + Left, main_dir + Right)
                }
            };

            for &d in neighbors.iter() {
                let npos = pos + d;
                match dir {
                    Some(_) => los_rec::<FOpaqueness, FVisible, I>(opaqueness, visible, light, npos, start_dir, d, Some(d), dir),
                    None => los_rec::<FOpaqueness, FVisible, I>(opaqueness, visible, light, npos, start_dir, main_dir, Some(d), dir),
                }
            }
        }

    /// Starting from `pos` in direction `dir`, call `visible` for each visible Coordinate.
    ///
    /// Use `light` as starting range of the LoS. For each visible Coordinate, the value returned
    /// by `opaqueness` will be subtracted from `light` to check if the LoS should finish due to
    /// "lack of visibility". `opaqueness` should typically return 1 for fully transparent
    /// Coordinates, and anything bigger than initial `light` for fully opaque Coordinates.
    pub fn los<FOpaqueness, FVisible, I=i32>(
        opaqueness : &FOpaqueness,
        visible : &mut FVisible,
        light: I,
        pos : Coordinate<I>,
        dirs : &[Direction],
    ) where
        I : SignedInt+FromPrimitive+Integer,
        FOpaqueness : Fn(Coordinate<I>) -> I,
        FVisible : FnMut(Coordinate<I>, I)
        {
            for dir in dirs.iter() {
                los_rec::<FOpaqueness, FVisible, I>(opaqueness, visible, light, pos, *dir, *dir, None, None);
            }
        }
}
<|endoftext|>


<commit_before>//! # C API for rav1e
//!
//! [rav1e](https://github.com/xiph/rav1e/) is an [AV1](https://aomediacodec.github.io/av1-spec/)
//! encoder written in [Rust](https://rust-lang.org)
//!
//! This is the C-compatible API

extern crate rav1e;
extern crate libc;

use std::slice;
use std::sync::Arc;

use std::ffi::CStr;
use std::os::raw::c_char;
use std::os::raw::c_int;

use libc::size_t;
use libc::ptrdiff_t;

/// Raw video Frame
///
/// It can be allocated throught rav1e_frame_new(), populated using rav1e_frame_fill_plane()
/// and freed using rav1e_frame_unref().
pub struct Frame(Arc<rav1e::Frame>);

type EncoderStatus=rav1e::EncoderStatus;

/// Encoder configuration
///
/// Instantiate it using rav1e_config_default() and fine-tune it using
/// rav1e_config_parse().
///
/// Use rav1e_config_unref() to free its memory.
pub struct Config {
    cfg: rav1e::Config,
    last_err: Option<EncoderStatus>,
}

/// Encoder context
///
/// Contains the encoding state, it is created by rav1e_context_new() using an
/// Encoder configuration.
///
/// Use rav1e_context_unref() to free its memory.
pub struct Context {
    ctx: rav1e::Context,
    last_err: Option<EncoderStatus>,
}

type FrameType = rav1e::FrameType;

/// Encoded Packet
///
/// The encoded packets are retrieved using rav1e_receive_packet().
///
/// Use rav1e_packet_unref() to free its memory.
#[repr(C)]
pub struct Packet {
    /// Encoded data buffer
    pub data: *const u8,
    /// Encoded data buffer size
    pub len: size_t,
    /// Frame sequence number
    pub number: u64,
    /// Frame type
    pub frame_type: FrameType,
}

type ChromaSamplePosition=rav1e::ChromaSamplePosition;
type ChromaSampling=rav1e::ChromaSampling;
type MatrixCoefficients=rav1e::MatrixCoefficients;
type ColorPrimaries=rav1e::ColorPrimaries;
type TransferCharacteristics=rav1e::TransferCharacteristics;
type Rational=rav1e::Rational;

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_default(
    width: u32,
    height: u32,
    bit_depth: u8,
    chroma_sampling: ChromaSampling,
    chroma_sample_position: ChromaSamplePosition,
    timebase: Rational,
) -> *mut Config {
    let cfg = rav1e::Config {
        frame_info: rav1e::FrameInfo {
            width: width as usize,
            height: height as usize,
            bit_depth: bit_depth as usize,
            chroma_sampling,
            chroma_sample_position,
        },
        timebase,
        enc: Default::default(),
    };

    let c = Box::new(Config {
        cfg,
        last_err: None,
    });

    Box::into_raw(c)
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_set_color_description(cfg: *mut Config,
                                                            matrix: MatrixCoefficients,
                                                            primaries: ColorPrimaries,
                                                            transfer: TransferCharacteristics)
{
    (*cfg).cfg.enc.color_description = Some(rav1e::ColorDescription {
        matrix_coefficients: matrix,
        color_primaries: primaries,
        transfer_characteristics: transfer,
    });
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_unref(cfg: *mut Config) {
    let _ = Box::from_raw(cfg);
}

/// Set a configuration parameter using its key and value
///
/// Available keys and values
/// - "quantizer": 0-255, default 100
/// - "speed": 0-10, default 3
/// - "tune": "psnr"-"psychovisual", default "psnr"
///
/// Returns a negative value on non-zero.
#[no_mangle]
pub unsafe extern "C" fn rav1e_config_parse(
    cfg: *mut Config,
    key: *const c_char,
    value: *const c_char,
) -> c_int {
    let key = CStr::from_ptr(key).to_string_lossy();
    let value = CStr::from_ptr(value).to_string_lossy();

    (*cfg)
        .cfg
        .parse(&key, &value)
        .map(|_v| {
            (*cfg).last_err = None;
            0
        }).map_err(|e| (*cfg).last_err = Some(e))
        .unwrap_or(-1)
}

/// Generate a new encoding context from a populated encoder configuration
///
/// Multiple contexts can be generated through it.
#[no_mangle]
pub unsafe extern "C" fn rav1e_context_new(cfg: *const Config) -> *mut Context {
    let ctx = Context {
        ctx: (*cfg).cfg.new_context(),
        last_err: None,
    };

    Box::into_raw(Box::new(ctx))
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_context_unref(ctx: *mut Context) {
    let _ = Box::from_raw(ctx);
}

/// Produce a new frame from the encoding context
///
/// It must be populated using rav1e_frame_fill_plane().
///
/// The frame is reference counted and must be released passing it to rav1e_frame_unref(),
/// see rav1e_send_frame().
#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_new(ctx: *const Context) -> *mut Frame {
    let f = (*ctx).ctx.new_frame();
    let frame = Box::new(Frame(f));

    Box::into_raw(frame)
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_unref(frame: *mut Frame) {
    let _ = Arc::from_raw(frame);
}

/// Send the frame for encoding
///
/// The function increases the frame internal reference count and it can be passed multiple
/// times to different rav1e_send_frame().
#[no_mangle]
pub unsafe extern "C" fn rav1e_send_frame(ctx: *mut Context, frame: *const Frame) -> c_int {
    let frame = if frame.is_null() {
        None
    } else {
        Some((*frame).0.clone())
    };

    (*ctx)
        .ctx
        .send_frame(frame)
        .map(|_v| {
            (*ctx).last_err = None;
            0
        }).map_err(|e| (*ctx).last_err = Some(e))
        .unwrap_or(-1)
}

/// Receive encoded data
#[no_mangle]
pub unsafe extern "C" fn rav1e_receive_packet(
    ctx: *mut Context,
    pkt: *mut *mut Packet,
) -> c_int {
    (*ctx)
        .ctx
        .receive_packet()
        .map(|p| {
            (*ctx).last_err = None;
            let packet = Packet {
                data: p.data.as_ptr(),
                len: p.data.len(),
                number: p.number,
                frame_type: p.frame_type,
            };
            *pkt = Box::into_raw(Box::new(packet));
            0
        }).map_err(|e| (*ctx).last_err = Some(e))
        .unwrap_or(-1)
}

#[no_mangle]
pub unsafe extern fn rav1e_packet_unref(pkt: *mut Packet) {
    let _ = Box::from_raw(pkt);
}

/// Produce a sequence header matching the current encoding context
///
/// Its format is compatible with the AV1 Matroska and ISOBMFF specification.
///
/// Use rav1e_container_sequence_header_unref() to free it.
#[no_mangle]
pub unsafe extern fn rav1e_container_sequence_header(ctx: *mut Context, buf_size: *mut size_t) -> *mut u8 {
    let buf = (*ctx).ctx.container_sequence_header();

    *buf_size = buf.len();
    Box::into_raw(buf.into_boxed_slice()) as *mut u8
}

#[no_mangle]
pub unsafe extern fn rav1e_container_sequence_header_unref(sequence: *mut u8) {
    let _ = Box::from_raw(sequence);
}

/// Fill a frame plane
///
/// Currently the frame contains 3 planes, the first is luminance followed by
/// chrominance.
///
/// The data is copied and this function has to be called for each plane.
///
/// frame: A frame provided by rav1e_frame_new()
/// plane: The index of the plane starting from 0
/// data: The data to be copied
/// data_len: Lenght of the buffer
/// stride: Plane line in bytes, including padding
/// bytewidth: Number of bytes per component, either 1 or 2
#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_fill_plane(
    frame: *mut Frame,
    plane: c_int,
    data: *const u8,
    data_len: size_t,
    stride: ptrdiff_t,
    bytewidth: c_int,
) {
    let input = Arc::get_mut(&mut (*frame).0).unwrap();
    let data_slice = slice::from_raw_parts(data, data_len as usize);

    input.planes[plane as usize].copy_from_raw_u8(data_slice, stride as usize, bytewidth as usize);
}
<commit_msg>crav1e: Update to the current rav1e API<commit_after>//! # C API for rav1e
//!
//! [rav1e](https://github.com/xiph/rav1e/) is an [AV1](https://aomediacodec.github.io/av1-spec/)
//! encoder written in [Rust](https://rust-lang.org)
//!
//! This is the C-compatible API

extern crate rav1e;
extern crate libc;

use std::slice;
use std::sync::Arc;

use std::ffi::CStr;
use std::os::raw::c_char;
use std::os::raw::c_int;

use libc::size_t;
use libc::ptrdiff_t;

/// Raw video Frame
///
/// It can be allocated throught rav1e_frame_new(), populated using rav1e_frame_fill_plane()
/// and freed using rav1e_frame_unref().
pub struct Frame(Arc<rav1e::Frame>);

type EncoderStatus=rav1e::EncoderStatus;

/// Encoder configuration
///
/// Instantiate it using rav1e_config_default() and fine-tune it using
/// rav1e_config_parse().
///
/// Use rav1e_config_unref() to free its memory.
pub struct Config {
    cfg: rav1e::Config,
    last_err: Option<EncoderStatus>,
}

/// Encoder context
///
/// Contains the encoding state, it is created by rav1e_context_new() using an
/// Encoder configuration.
///
/// Use rav1e_context_unref() to free its memory.
pub struct Context {
    ctx: rav1e::Context,
    last_err: Option<EncoderStatus>,
}

type FrameType = rav1e::FrameType;

/// Encoded Packet
///
/// The encoded packets are retrieved using rav1e_receive_packet().
///
/// Use rav1e_packet_unref() to free its memory.
#[repr(C)]
pub struct Packet {
    /// Encoded data buffer
    pub data: *const u8,
    /// Encoded data buffer size
    pub len: size_t,
    /// Frame sequence number
    pub number: u64,
    /// Frame type
    pub frame_type: FrameType,
}

type ChromaSamplePosition=rav1e::ChromaSamplePosition;
type ChromaSampling=rav1e::ChromaSampling;
type MatrixCoefficients=rav1e::MatrixCoefficients;
type ColorPrimaries=rav1e::ColorPrimaries;
type TransferCharacteristics=rav1e::TransferCharacteristics;
type Rational=rav1e::Rational;

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_default(
    width: u32,
    height: u32,
    bit_depth: u8,
    chroma_sampling: ChromaSampling,
    chroma_sample_position: ChromaSamplePosition,
    timebase: Rational,
) -> *mut Config {
    let cfg = rav1e::Config {
        video_info: rav1e::VideoDetails {
            width: width as usize,
            height: height as usize,
            bit_depth: bit_depth as usize,
            chroma_sampling,
            chroma_sample_position,
            mono: false,
            time_base: timebase,
        },
        enc: Default::default(),
    };

    let c = Box::new(Config {
        cfg,
        last_err: None,
    });

    Box::into_raw(c)
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_set_color_description(cfg: *mut Config,
                                                            matrix: MatrixCoefficients,
                                                            primaries: ColorPrimaries,
                                                            transfer: TransferCharacteristics)
{
    (*cfg).cfg.enc.color_description = Some(rav1e::ColorDescription {
        matrix_coefficients: matrix,
        color_primaries: primaries,
        transfer_characteristics: transfer,
    });
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_unref(cfg: *mut Config) {
    let _ = Box::from_raw(cfg);
}

/// Set a configuration parameter using its key and value
///
/// Available keys and values
/// - "quantizer": 0-255, default 100
/// - "speed": 0-10, default 3
/// - "tune": "psnr"-"psychovisual", default "psnr"
///
/// Returns a negative value on non-zero.
#[no_mangle]
pub unsafe extern "C" fn rav1e_config_parse(
    cfg: *mut Config,
    key: *const c_char,
    value: *const c_char,
) -> c_int {
    let key = CStr::from_ptr(key).to_string_lossy();
    let value = CStr::from_ptr(value).to_string_lossy();

    (*cfg)
        .cfg
        .parse(&key, &value)
        .map(|_v| {
            (*cfg).last_err = None;
            0
        }).map_err(|e| (*cfg).last_err = Some(e))
        .unwrap_or(-1)
}

/// Generate a new encoding context from a populated encoder configuration
///
/// Multiple contexts can be generated through it.
#[no_mangle]
pub unsafe extern "C" fn rav1e_context_new(cfg: *const Config) -> *mut Context {
    let ctx = Context {
        ctx: (*cfg).cfg.new_context(),
        last_err: None,
    };

    Box::into_raw(Box::new(ctx))
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_context_unref(ctx: *mut Context) {
    let _ = Box::from_raw(ctx);
}

/// Produce a new frame from the encoding context
///
/// It must be populated using rav1e_frame_fill_plane().
///
/// The frame is reference counted and must be released passing it to rav1e_frame_unref(),
/// see rav1e_send_frame().
#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_new(ctx: *const Context) -> *mut Frame {
    let f = (*ctx).ctx.new_frame();
    let frame = Box::new(Frame(f));

    Box::into_raw(frame)
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_unref(frame: *mut Frame) {
    let _ = Arc::from_raw(frame);
}

/// Send the frame for encoding
///
/// The function increases the frame internal reference count and it can be passed multiple
/// times to different rav1e_send_frame().
#[no_mangle]
pub unsafe extern "C" fn rav1e_send_frame(ctx: *mut Context, frame: *const Frame) -> c_int {
    let frame = if frame.is_null() {
        None
    } else {
        Some((*frame).0.clone())
    };

    (*ctx)
        .ctx
        .send_frame(frame)
        .map(|_v| {
            (*ctx).last_err = None;
            0
        }).map_err(|e| (*ctx).last_err = Some(e))
        .unwrap_or(-1)
}

/// Receive encoded data
#[no_mangle]
pub unsafe extern "C" fn rav1e_receive_packet(
    ctx: *mut Context,
    pkt: *mut *mut Packet,
) -> c_int {
    (*ctx)
        .ctx
        .receive_packet()
        .map(|p| {
            (*ctx).last_err = None;
            let packet = Packet {
                data: p.data.as_ptr(),
                len: p.data.len(),
                number: p.number,
                frame_type: p.frame_type,
            };
            *pkt = Box::into_raw(Box::new(packet));
            0
        }).map_err(|e| (*ctx).last_err = Some(e))
        .unwrap_or(-1)
}

#[no_mangle]
pub unsafe extern fn rav1e_packet_unref(pkt: *mut Packet) {
    let _ = Box::from_raw(pkt);
}

/// Produce a sequence header matching the current encoding context
///
/// Its format is compatible with the AV1 Matroska and ISOBMFF specification.
///
/// Use rav1e_container_sequence_header_unref() to free it.
#[no_mangle]
pub unsafe extern fn rav1e_container_sequence_header(ctx: *mut Context, buf_size: *mut size_t) -> *mut u8 {
    let buf = (*ctx).ctx.container_sequence_header();

    *buf_size = buf.len();
    Box::into_raw(buf.into_boxed_slice()) as *mut u8
}

#[no_mangle]
pub unsafe extern fn rav1e_container_sequence_header_unref(sequence: *mut u8) {
    let _ = Box::from_raw(sequence);
}

/// Fill a frame plane
///
/// Currently the frame contains 3 planes, the first is luminance followed by
/// chrominance.
///
/// The data is copied and this function has to be called for each plane.
///
/// frame: A frame provided by rav1e_frame_new()
/// plane: The index of the plane starting from 0
/// data: The data to be copied
/// data_len: Lenght of the buffer
/// stride: Plane line in bytes, including padding
/// bytewidth: Number of bytes per component, either 1 or 2
#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_fill_plane(
    frame: *mut Frame,
    plane: c_int,
    data: *const u8,
    data_len: size_t,
    stride: ptrdiff_t,
    bytewidth: c_int,
) {
    let input = Arc::get_mut(&mut (*frame).0).unwrap();
    let data_slice = slice::from_raw_parts(data, data_len as usize);

    input.planes[plane as usize].copy_from_raw_u8(data_slice, stride as usize, bytewidth as usize);
}
<|endoftext|>


<commit_before>use chrono::{DateTime, Duration, TimeZone, UTC};
use std::fmt;
use std::str::FromStr;

use {Error, Result};

#[derive(Clone, Debug, PartialEq)]
pub struct Date {
    inner: DateTime<UTC>,
}

impl Date {
    #[doc(hidden)]
    pub fn from_seconds_since_plist_epoch(timestamp: f64) -> Result<Date> {
        // Seconds since 1/1/2001 00:00:00.

        let millis = timestamp * 1_000.0;
        // Chrono's Duration can only millisecond values between ::std::i64::MIN and
        // ::std::i64::MAX.
        if millis > ::std::i64::MAX as f64 || millis < ::std::i64::MIN as f64 {
            return Err(Error::InvalidData);
        }

        let whole_millis = millis.floor();
        let submilli_nanos = ((millis - whole_millis) * 1_000_000.0).floor();

        let dur = Duration::milliseconds(whole_millis as i64);
        let dur = dur + Duration::nanoseconds(submilli_nanos as i64);

        let plist_epoch = UTC.ymd(2001, 1, 1).and_hms(0, 0, 0);
        let date = plist_epoch.checked_add_signed(dur).ok_or(Error::InvalidData)?;

        Ok(Date { inner: date })
    }
}

impl From<DateTime<UTC>> for Date {
    fn from(date: DateTime<UTC>) -> Self {
        Date { inner: date }
    }
}

impl Into<DateTime<UTC>> for Date {
    fn into(self) -> DateTime<UTC> {
        self.inner
    }
}

impl fmt::Display for Date {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.inner)
    }
}

impl FromStr for Date {
    type Err = ();

    fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
        let date = DateTime::parse_from_rfc3339(&s).map_err(|_| ())?;
        Ok(Date { inner: date.with_timezone(&UTC) })
    }
}

#[cfg(feature = "serde")]
pub mod serde_impls {
    use serde_base::de::{Deserialize, Deserializer, Error, Visitor, Unexpected};
    use serde_base::ser::{Serialize, Serializer};
    use std::fmt;
    use std::str::FromStr;

    use Date;

    pub const DATE_NEWTYPE_STRUCT_NAME: &'static str = "PLIST-DATE";

    impl Serialize for Date {
        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
            where S: Serializer
        {
            let date_str = self.to_string();
            serializer.serialize_newtype_struct(DATE_NEWTYPE_STRUCT_NAME, &date_str)
        }
    }

    struct DateNewtypeVisitor;

    impl<'de> Visitor<'de> for DateNewtypeVisitor {
        type Value = Date;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a plist date newtype")
        }

        fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
            where D: Deserializer<'de>
        {
            deserializer.deserialize_str(DateStrVisitor)
        }
    }

    struct DateStrVisitor;

    impl<'de> Visitor<'de> for DateStrVisitor {
        type Value = Date;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a plist date string")
        }

        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where E: Error
        {
            Date::from_str(v).map_err(|_| E::invalid_value(Unexpected::Str(v), &self))
        }
    }

    impl<'de> Deserialize<'de> for Date {
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
            where D: Deserializer<'de>
        {
            deserializer.deserialize_newtype_struct(DATE_NEWTYPE_STRUCT_NAME, DateNewtypeVisitor)
        }
    }
}
<commit_msg>Add brief overview of the new Date type.<commit_after>use chrono::{DateTime, Duration, TimeZone, UTC};
use std::fmt;
use std::str::FromStr;

use {Error, Result};

/// A UTC timestamp. Used for serialization to and from the plist date type.
#[derive(Clone, Debug, PartialEq)]
pub struct Date {
    inner: DateTime<UTC>,
}

impl Date {
    #[doc(hidden)]
    pub fn from_seconds_since_plist_epoch(timestamp: f64) -> Result<Date> {
        // Seconds since 1/1/2001 00:00:00.

        let millis = timestamp * 1_000.0;
        // Chrono's Duration can only millisecond values between ::std::i64::MIN and
        // ::std::i64::MAX.
        if millis > ::std::i64::MAX as f64 || millis < ::std::i64::MIN as f64 {
            return Err(Error::InvalidData);
        }

        let whole_millis = millis.floor();
        let submilli_nanos = ((millis - whole_millis) * 1_000_000.0).floor();

        let dur = Duration::milliseconds(whole_millis as i64);
        let dur = dur + Duration::nanoseconds(submilli_nanos as i64);

        let plist_epoch = UTC.ymd(2001, 1, 1).and_hms(0, 0, 0);
        let date = plist_epoch.checked_add_signed(dur).ok_or(Error::InvalidData)?;

        Ok(Date { inner: date })
    }
}

impl From<DateTime<UTC>> for Date {
    fn from(date: DateTime<UTC>) -> Self {
        Date { inner: date }
    }
}

impl Into<DateTime<UTC>> for Date {
    fn into(self) -> DateTime<UTC> {
        self.inner
    }
}

impl fmt::Display for Date {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.inner)
    }
}

impl FromStr for Date {
    type Err = ();

    fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
        let date = DateTime::parse_from_rfc3339(&s).map_err(|_| ())?;
        Ok(Date { inner: date.with_timezone(&UTC) })
    }
}

#[cfg(feature = "serde")]
pub mod serde_impls {
    use serde_base::de::{Deserialize, Deserializer, Error, Visitor, Unexpected};
    use serde_base::ser::{Serialize, Serializer};
    use std::fmt;
    use std::str::FromStr;

    use Date;

    pub const DATE_NEWTYPE_STRUCT_NAME: &'static str = "PLIST-DATE";

    impl Serialize for Date {
        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
            where S: Serializer
        {
            let date_str = self.to_string();
            serializer.serialize_newtype_struct(DATE_NEWTYPE_STRUCT_NAME, &date_str)
        }
    }

    struct DateNewtypeVisitor;

    impl<'de> Visitor<'de> for DateNewtypeVisitor {
        type Value = Date;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a plist date newtype")
        }

        fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
            where D: Deserializer<'de>
        {
            deserializer.deserialize_str(DateStrVisitor)
        }
    }

    struct DateStrVisitor;

    impl<'de> Visitor<'de> for DateStrVisitor {
        type Value = Date;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a plist date string")
        }

        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where E: Error
        {
            Date::from_str(v).map_err(|_| E::invalid_value(Unexpected::Str(v), &self))
        }
    }

    impl<'de> Deserialize<'de> for Date {
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
            where D: Deserializer<'de>
        {
            deserializer.deserialize_newtype_struct(DATE_NEWTYPE_STRUCT_NAME, DateNewtypeVisitor)
        }
    }
}
<|endoftext|>


<commit_before>//! "Diff"ing iterators for caching elements to sequential collections without requiring the new
//! elements' iterator to be `Clone`.
//!
//! - [**Diff**](./enum.Diff.html) (produced by the [**diff**](./fn.diff.html) and
//! [**diff_by_ref**](./fn.diff_by_ref.html) functions) describes the difference between two
//! non-`Clone` iterators `a` and `b` after breaking ASAP from a comparison with enough data to
//! update `a`'s collection.
//! - [**copy_on_diff**](./fn.copy_on_diff.html) is an application of [**diff**] that compares two
//! iterators `a` and `b`, borrowing the source of `a` if they are the same or creating a new owned
//! collection with `b`'s elements if they are different.

use adaptors::PutBack;

/// A type returned by the [`diff`](./fn.diff.html) function.
///
/// `Diff` represents the way in which the elements yielded by the iterator `I` differ to some
/// iterator `J`.
pub enum Diff<I, J>
    where I: Iterator,
          J: Iterator,
{
    /// The index of the first non-matching element along with both iterator's remaining elements
    /// starting with the first mis-match.
    FirstMismatch(usize, PutBack<I>, PutBack<J>),
    /// The total number of elements that were in `J` along with the remaining elements of `I`.
    Shorter(usize, PutBack<I>),
    /// The total number of elements that were in `I` along with the remaining elements of `J`.
    Longer(usize, PutBack<J>),
}

/// Compares every element yielded by both `i` and `j` with the given function in lock-step and
/// returns a `Diff` which describes how `j` differs from `i`.
///
/// If the number of elements yielded by `j` is less than the number of elements yielded by `i`,
/// the number of `j` elements yielded will be returned along with `i`'s remaining elements as
/// `Diff::Shorter`.
///
/// If the two elements of a step differ, the index of those elements along with the remaining
/// elements of both `i` and `j` are returned as `Diff::FirstMismatch`.
///
/// If `i` becomes exhausted before `j` becomes exhausted, the number of elements in `i` along with
/// the remaining `j` elements will be returned as `Diff::Longer`.
pub fn diff_with<I, J, F>(i: I, j: J, is_diff: F) -> Option<Diff<I::IntoIter, J::IntoIter>>
    where I: IntoIterator,
          J: IntoIterator,
          F: Fn(&I::Item, &J::Item) -> bool,
{
    let mut i = i.into_iter();
    let mut j = j.into_iter();
    let mut idx = 0;
    while let Some(i_elem) = i.next() {
        match j.next() {
            None => return Some(Diff::Shorter(idx, PutBack::with_value(i_elem, i))),
            Some(j_elem) => if is_diff(&i_elem, &j_elem) {
                let remaining_i = PutBack::with_value(i_elem, i);
                let remaining_j = PutBack::with_value(j_elem, j);
                return Some(Diff::FirstMismatch(idx, remaining_i, remaining_j));
            },
        }
        idx += 1;
    }
    j.next().map(|j_elem| Diff::Longer(idx, PutBack::with_value(j_elem, j)))
}
<commit_msg>Updated docs to latest changes.<commit_after>//! "Diff"ing iterators for caching elements to sequential collections without requiring the new
//! elements' iterator to be `Clone`.
//!
//! - [**Diff**](./enum.Diff.html) (produced by the [**diff_with**](./fn.diff_with.html) function)
//! describes the difference between two non-`Clone` iterators `I` and `J` after breaking ASAP from
//! a lock-step comparison.

use adaptors::PutBack;

/// A type returned by the [`diff_with`](./fn.diff_with.html) function.
///
/// `Diff` represents the way in which the elements yielded by the iterator `I` differ to some
/// iterator `J`.
pub enum Diff<I, J>
    where I: Iterator,
          J: Iterator,
{
    /// The index of the first non-matching element along with both iterator's remaining elements
    /// starting with the first mis-match.
    FirstMismatch(usize, PutBack<I>, PutBack<J>),
    /// The total number of elements that were in `J` along with the remaining elements of `I`.
    Shorter(usize, PutBack<I>),
    /// The total number of elements that were in `I` along with the remaining elements of `J`.
    Longer(usize, PutBack<J>),
}

/// Compares every element yielded by both `i` and `j` with the given function in lock-step and
/// returns a `Diff` which describes how `j` differs from `i`.
///
/// If the number of elements yielded by `j` is less than the number of elements yielded by `i`,
/// the number of `j` elements yielded will be returned along with `i`'s remaining elements as
/// `Diff::Shorter`.
///
/// If the two elements of a step differ, the index of those elements along with the remaining
/// elements of both `i` and `j` are returned as `Diff::FirstMismatch`.
///
/// If `i` becomes exhausted before `j` becomes exhausted, the number of elements in `i` along with
/// the remaining `j` elements will be returned as `Diff::Longer`.
pub fn diff_with<I, J, F>(i: I, j: J, is_diff: F) -> Option<Diff<I::IntoIter, J::IntoIter>>
    where I: IntoIterator,
          J: IntoIterator,
          F: Fn(&I::Item, &J::Item) -> bool,
{
    let mut i = i.into_iter();
    let mut j = j.into_iter();
    let mut idx = 0;
    while let Some(i_elem) = i.next() {
        match j.next() {
            None => return Some(Diff::Shorter(idx, PutBack::with_value(i_elem, i))),
            Some(j_elem) => if is_diff(&i_elem, &j_elem) {
                let remaining_i = PutBack::with_value(i_elem, i);
                let remaining_j = PutBack::with_value(j_elem, j);
                return Some(Diff::FirstMismatch(idx, remaining_i, remaining_j));
            },
        }
        idx += 1;
    }
    j.next().map(|j_elem| Diff::Longer(idx, PutBack::with_value(j_elem, j)))
}
<|endoftext|>


<commit_before>extern crate sdl2;
extern crate native;

//use sdl2;
use sdl2::video::{Window, PosCentered, OpenGL};
use sdl2::timer::{delay};

#[start]
fn start(argc: int, argv: **u8) -> int {
    native::start(argc, argv, main)
}

#[main]
fn main() {
    sdl2::init(sdl2::InitVideo);

    // Create a window

    let window = match Window::new("eg01", PosCentered, PosCentered, 640, 480, OpenGL) {
        Ok(window) => window,
        Err(err)   => fail!(format!("failed to create window: {}", err))
    };

    // Display the window for 3 seconds

    window.show();
    delay(3000);

    // then quit

    sdl2::quit();
}

<commit_msg>comment cleanup<commit_after>extern crate sdl2;
extern crate native;

use sdl2::video::{Window, PosCentered, OpenGL};
use sdl2::timer::{delay};

#[start]
fn start(argc: int, argv: **u8) -> int {
    native::start(argc, argv, main)
}

#[main]
fn main() {
    // start sdl2

    sdl2::init(sdl2::InitVideo);

    // Create a window

    let window = match Window::new("eg01", PosCentered, PosCentered, 640, 480, OpenGL) {
        Ok(window) => window,
        Err(err)   => fail!(format!("failed to create window: {}", err))
    };

    // Display the window for 3 seconds

    window.show();
    delay(3000);

    // then quit

    sdl2::quit();
}

<|endoftext|>


<commit_before>use ffi::h5::{hsize_t, hbool_t};
use ffi::h5i::{hid_t, H5I_INVALID_HID};
use ffi::h5p::{H5Pcreate, H5Pset_userblock};
use ffi::h5f::{H5F_ACC_RDONLY, H5F_ACC_RDWR, H5F_ACC_EXCL, H5F_ACC_TRUNC,
               H5Fopen, H5Fcreate, H5Fget_filesize, H5Fget_intent,
               H5Fget_access_plist, H5Fget_create_plist, H5Fget_freespace};
use ffi::h5fd::{H5Pset_fapl_sec2, H5Pset_fapl_stdio, H5Pset_fapl_core};

use globals::{H5P_FILE_CREATE, H5P_FILE_ACCESS};

use container::Container;
use error::Result;
use location::Location;
use object::{Handle, Object};
use plist::PropertyList;
use util::to_cstring;

use std::path::Path;
use std::process::Command;

use libc::{size_t, c_uint};

#[derive(Clone)]
pub struct File {
    handle: Handle,
}

impl Object for File {
    fn id(&self) -> hid_t {
        self.handle.id()
    }

    fn from_id(id: hid_t) -> File {
        File { handle: Handle::new(id) }
    }
}

impl Location for File {}

impl Container for File {}

impl File {
    /// Create a new file object.
    ///
    /// | `mode`    | File access mode
    /// |-----------|-----------------
    /// | `r`       | Read-only, file must exist
    /// | `r+`      | Read/write, file must exist
    /// | `w`       | Create file, truncate if exists
    /// | `w-`, `x` | Create file, fail if exists
    /// | `a`       | Read/write if exists, create otherwise
    pub fn open<P: AsRef<Path>, S: Into<String>>(filename: P, mode: S) -> Result<File> {
        FileBuilder::new().mode(mode).open(filename)
    }

    /// Returns the file size in bytes.
    pub fn size(&self) -> u64 {
        unsafe {
            let size: *mut hsize_t = &mut 0;
            h5lock_s!(H5Fget_filesize(self.id(), size));
            if *size > 0 { *size as u64 } else { 0 }
        }
    }

    /// Returns the free space in the file in bytes.
    pub fn free_space(&self) -> u64 {
        match h5call!(H5Fget_freespace(self.id())) {
            Ok(size) => size as u64,
            _        => 0,
        }
    }

    /// Returns true if the file was opened in a read-only mode.
    pub fn is_read_only(&self) -> bool {
        unsafe {
            let mode: *mut c_uint = &mut 0;
            h5lock_s!(H5Fget_intent(self.id(), mode));
            *mode != H5F_ACC_RDWR
        }
    }

    #[allow(dead_code)]
    fn fapl(&self) -> PropertyList {
        PropertyList::from_id(h5call!(H5Fget_access_plist(self.id())).unwrap_or(H5I_INVALID_HID))
    }

    #[allow(dead_code)]
    fn fcpl(&self) -> PropertyList {
        PropertyList::from_id(h5call!(H5Fget_create_plist(self.id())).unwrap_or(H5I_INVALID_HID))
    }

    /// Returns the output of the `h5dump` tool. Note that this wouldn't work with core driver.
    pub fn dump(&self) -> Option<String> {
        self.flush(true).ok().and(Command::new("h5dump").arg(self.filename()).output().ok()
                                  .map(|out| String::from_utf8_lossy(&out.stdout).to_string()))
    }
}

pub struct FileBuilder {
    driver: String,
    mode: String,
    userblock: size_t,
    filebacked: bool,
    increment: size_t,
}

impl FileBuilder {
    pub fn new() -> FileBuilder {
        FileBuilder {
            driver: "sec2".to_string(),
            mode: "r".to_string(),
            userblock: 0,
            filebacked: false,
            increment: 64 * 1024 * 1024,
        }
    }

    pub fn driver<S: Into<String>>(&mut self, driver: S) -> &mut FileBuilder {
        self.driver = driver.into(); self
    }

    pub fn mode<S: Into<String>>(&mut self, mode: S) -> &mut FileBuilder {
        self.mode = mode.into(); self
    }

    pub fn userblock(&mut self, userblock: size_t) -> &mut FileBuilder {
        self.userblock = userblock; self
    }

    pub fn filebacked(&mut self, filebacked: bool) -> &mut FileBuilder {
        self.filebacked = filebacked; self
    }

    pub fn increment(&mut self, increment: size_t) -> &mut FileBuilder {
        self.increment = increment; self
    }

    fn make_fapl(&self) -> Result<PropertyList> {
        h5lock_s!({
            let fapl = PropertyList::from_id(h5try!(H5Pcreate(*H5P_FILE_ACCESS)));
            match self.driver.as_ref() {
                "sec2"  => h5try!(H5Pset_fapl_sec2(fapl.id())),
                "stdio" => h5try!(H5Pset_fapl_stdio(fapl.id())),
                "core"  => h5try!(H5Pset_fapl_core(fapl.id(), self.increment,
                                                   self.filebacked as hbool_t)),
                _       => fail!(format!("Invalid file driver: {}", self.driver)),
            };
            Ok(fapl)
        })
    }

    fn open_file<P: AsRef<Path>>(&self, filename: P, write: bool) -> Result<File> {
        ensure!(self.userblock == 0, "Cannot specify userblock when opening a file");
        h5lock_s!({
            let fapl = try!(self.make_fapl());
            let flags = if write { H5F_ACC_RDWR } else { H5F_ACC_RDONLY };
            let filename = filename.as_ref();
            match filename.to_str() {
                Some(filename) => {
                    let c_filename = to_cstring(filename).as_ptr();
                    let file = File::from_id(h5try!(H5Fopen(c_filename, flags, fapl.id())));
                    ensure!(file.is_valid(), "Invalid id for opened file");
                    Ok(file)
                },
                None          => fail!("Invalid UTF-8 in file name: {:?}", filename)
            }
        })
    }

    fn create_file<P: AsRef<Path>>(&self, filename: P, exclusive: bool) -> Result<File> {
        h5lock_s!({
            let fcpl = PropertyList::from_id(h5try!(H5Pcreate(*H5P_FILE_CREATE)));
            h5try!(H5Pset_userblock(fcpl.id(), self.userblock));
            let fapl = try!(self.make_fapl());
            let flags = if exclusive { H5F_ACC_EXCL } else { H5F_ACC_TRUNC };
            let filename = filename.as_ref();
            match filename.to_str() {
                Some(filename) => {
                    let c_filename = to_cstring(filename).as_ptr();
                    let file = File::from_id(h5try!(H5Fcreate(c_filename, flags,
                                                              fcpl.id(), fapl.id())));
                    ensure!(file.is_valid(), "Invalid id for created file");
                    Ok(file)
                },
                None          => fail!("Invalid UTF-8 in file name: {:?}", filename)
            }
        })
    }

    pub fn open<P: AsRef<Path>>(&self, filename: P) -> Result<File> {
        match self.mode.as_ref() {
            "r"        => self.open_file(&filename, false),
            "r+"       => self.open_file(&filename, true),
            "w"        => self.create_file(&filename, false),
            "w-" | "x" => self.create_file(&filename, true),
            "a"        => match self.open_file(&filename, true) {
                            Ok(file) => Ok(file),
                            _        => self.create_file(&filename, true),
                          },
            _          => fail!("Invalid file access mode, expected r|r+|w|w-|x|a"),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::File;
    use std::fs;
    use std::io::Write;
    use test::{with_tmp_dir, with_tmp_path};
    use error::silence_errors;

    #[test]
    pub fn test_invalid_mode() {
        silence_errors();
        with_tmp_dir(|dir| {
            assert_err!(File::open(&dir, "foo"), "Invalid file access mode");
        })
    }

    #[test]
    pub fn test_non_hdf5_file() {
        silence_errors();
        with_tmp_path("foo.h5", |path| {
            fs::File::create(&path).unwrap().write_all(b"foo").unwrap();
            assert!(fs::metadata(&path).is_ok());
            assert_err!(File::open(&path, "r"), "unable to open file");
        })
    }

    #[test]
    pub fn test_is_read_only() {
        silence_errors();
        with_tmp_path("foo.h5", |path| {
            assert!(!File::open(&path, "w").unwrap().is_read_only());
            assert!(File::open(&path, "r").unwrap().is_read_only());
            assert!(!File::open(&path, "r+").unwrap().is_read_only());
            assert!(!File::open(&path, "a").unwrap().is_read_only());
        });
        with_tmp_path("foo.h5", |path| {
            assert!(!File::open(&path, "a").unwrap().is_read_only());
        });
        with_tmp_path("foo.h5", |path| {
            assert!(!File::open(&path, "x").unwrap().is_read_only());
        });
    }

    #[test]
    pub fn test_unable_to_open() {
        silence_errors();
        with_tmp_dir(|dir| {
            assert_err!(File::open(&dir, "r"), "unable to open file");
            assert_err!(File::open(&dir, "r+"), "unable to open file");
            assert_err!(File::open(&dir, "x"), "unable to create file");
            assert_err!(File::open(&dir, "w-"), "unable to create file");
            assert_err!(File::open(&dir, "w"), "unable to create file");
            assert_err!(File::open(&dir, "a"), "unable to create file");
        });
    }
}
<commit_msg>Added File::userblock() -- extract userblock size from fcpl<commit_after>use ffi::h5::{hsize_t, hbool_t};
use ffi::h5i::{hid_t, H5I_INVALID_HID};
use ffi::h5p::{H5Pcreate, H5Pset_userblock, H5Pget_userblock};
use ffi::h5f::{H5F_ACC_RDONLY, H5F_ACC_RDWR, H5F_ACC_EXCL, H5F_ACC_TRUNC,
               H5Fopen, H5Fcreate, H5Fget_filesize, H5Fget_intent,
               H5Fget_access_plist, H5Fget_create_plist, H5Fget_freespace};
use ffi::h5fd::{H5Pset_fapl_sec2, H5Pset_fapl_stdio, H5Pset_fapl_core};

use globals::{H5P_FILE_CREATE, H5P_FILE_ACCESS};

use container::Container;
use error::Result;
use location::Location;
use object::{Handle, Object};
use plist::PropertyList;
use util::to_cstring;

use std::path::Path;
use std::process::Command;

use libc::{size_t, c_uint};

#[derive(Clone)]
pub struct File {
    handle: Handle,
}

impl Object for File {
    fn id(&self) -> hid_t {
        self.handle.id()
    }

    fn from_id(id: hid_t) -> File {
        File { handle: Handle::new(id) }
    }
}

impl Location for File {}

impl Container for File {}

impl File {
    /// Create a new file object.
    ///
    /// | `mode`    | File access mode
    /// |-----------|-----------------
    /// | `r`       | Read-only, file must exist
    /// | `r+`      | Read/write, file must exist
    /// | `w`       | Create file, truncate if exists
    /// | `w-`, `x` | Create file, fail if exists
    /// | `a`       | Read/write if exists, create otherwise
    pub fn open<P: AsRef<Path>, S: Into<String>>(filename: P, mode: S) -> Result<File> {
        FileBuilder::new().mode(mode).open(filename)
    }

    /// Returns the file size in bytes (or 0 if the file handle is invalid).
    pub fn size(&self) -> u64 {
        unsafe {
            let size: *mut hsize_t = &mut 0;
            h5lock_s!(H5Fget_filesize(self.id(), size));
            if *size > 0 { *size as u64 } else { 0 }
        }
    }

    /// Returns the free space in the file in bytes (or 0 if the file handle is invalid).
    pub fn free_space(&self) -> u64 {
        match h5call!(H5Fget_freespace(self.id())) {
            Ok(size) => size as u64,
            _        => 0,
        }
    }

    /// Returns true if the file was opened in a read-only mode.
    pub fn is_read_only(&self) -> bool {
        unsafe {
            let mode: *mut c_uint = &mut 0;
            h5lock_s!(H5Fget_intent(self.id(), mode));
            *mode != H5F_ACC_RDWR
        }
    }

    #[allow(dead_code)]
    fn fapl(&self) -> PropertyList {
        PropertyList::from_id(h5call!(H5Fget_access_plist(self.id())).unwrap_or(H5I_INVALID_HID))
    }

    fn fcpl(&self) -> PropertyList {
        PropertyList::from_id(h5call!(H5Fget_create_plist(self.id())).unwrap_or(H5I_INVALID_HID))
    }

    /// Returns the output of the `h5dump` tool. Note that this wouldn't work with core driver.
    pub fn dump(&self) -> Option<String> {
        self.flush(true).ok().and(Command::new("h5dump").arg(self.filename()).output().ok()
                                  .map(|out| String::from_utf8_lossy(&out.stdout).to_string()))
    }

    /// Returns the userblock size in bytes (or 0 if the file handle is invalid).
    pub fn userblock(&self) -> size_t {
        unsafe {
            let userblock: *mut hsize_t = &mut 0;
            h5lock_s!(H5Pget_userblock(self.fcpl().id(), userblock));
            *userblock as size_t
        }
    }
}

pub struct FileBuilder {
    driver: String,
    mode: String,
    userblock: size_t,
    filebacked: bool,
    increment: size_t,
}

impl FileBuilder {
    pub fn new() -> FileBuilder {
        FileBuilder {
            driver: "sec2".to_string(),
            mode: "r".to_string(),
            userblock: 0,
            filebacked: false,
            increment: 64 * 1024 * 1024,
        }
    }

    pub fn driver<S: Into<String>>(&mut self, driver: S) -> &mut FileBuilder {
        self.driver = driver.into(); self
    }

    pub fn mode<S: Into<String>>(&mut self, mode: S) -> &mut FileBuilder {
        self.mode = mode.into(); self
    }

    pub fn userblock(&mut self, userblock: size_t) -> &mut FileBuilder {
        self.userblock = userblock; self
    }

    pub fn filebacked(&mut self, filebacked: bool) -> &mut FileBuilder {
        self.filebacked = filebacked; self
    }

    pub fn increment(&mut self, increment: size_t) -> &mut FileBuilder {
        self.increment = increment; self
    }

    fn make_fapl(&self) -> Result<PropertyList> {
        h5lock_s!({
            let fapl = PropertyList::from_id(h5try!(H5Pcreate(*H5P_FILE_ACCESS)));
            match self.driver.as_ref() {
                "sec2"  => h5try!(H5Pset_fapl_sec2(fapl.id())),
                "stdio" => h5try!(H5Pset_fapl_stdio(fapl.id())),
                "core"  => h5try!(H5Pset_fapl_core(fapl.id(), self.increment,
                                                   self.filebacked as hbool_t)),
                _       => fail!(format!("Invalid file driver: {}", self.driver)),
            };
            Ok(fapl)
        })
    }

    fn open_file<P: AsRef<Path>>(&self, filename: P, write: bool) -> Result<File> {
        ensure!(self.userblock == 0, "Cannot specify userblock when opening a file");
        h5lock_s!({
            let fapl = try!(self.make_fapl());
            let flags = if write { H5F_ACC_RDWR } else { H5F_ACC_RDONLY };
            let filename = filename.as_ref();
            match filename.to_str() {
                Some(filename) => {
                    let c_filename = to_cstring(filename).as_ptr();
                    let file = File::from_id(h5try!(H5Fopen(c_filename, flags, fapl.id())));
                    ensure!(file.is_valid(), "Invalid id for opened file");
                    Ok(file)
                },
                None          => fail!("Invalid UTF-8 in file name: {:?}", filename)
            }
        })
    }

    fn create_file<P: AsRef<Path>>(&self, filename: P, exclusive: bool) -> Result<File> {
        h5lock_s!({
            let fcpl = PropertyList::from_id(h5try!(H5Pcreate(*H5P_FILE_CREATE)));
            h5try!(H5Pset_userblock(fcpl.id(), self.userblock));
            let fapl = try!(self.make_fapl());
            let flags = if exclusive { H5F_ACC_EXCL } else { H5F_ACC_TRUNC };
            let filename = filename.as_ref();
            match filename.to_str() {
                Some(filename) => {
                    let c_filename = to_cstring(filename).as_ptr();
                    let file = File::from_id(h5try!(H5Fcreate(c_filename, flags,
                                                              fcpl.id(), fapl.id())));
                    ensure!(file.is_valid(), "Invalid id for created file");
                    Ok(file)
                },
                None          => fail!("Invalid UTF-8 in file name: {:?}", filename)
            }
        })
    }

    pub fn open<P: AsRef<Path>>(&self, filename: P) -> Result<File> {
        match self.mode.as_ref() {
            "r"        => self.open_file(&filename, false),
            "r+"       => self.open_file(&filename, true),
            "w"        => self.create_file(&filename, false),
            "w-" | "x" => self.create_file(&filename, true),
            "a"        => match self.open_file(&filename, true) {
                            Ok(file) => Ok(file),
                            _        => self.create_file(&filename, true),
                          },
            _          => fail!("Invalid file access mode, expected r|r+|w|w-|x|a"),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::File;
    use std::fs;
    use std::io::Write;
    use test::{with_tmp_dir, with_tmp_path};
    use error::silence_errors;

    #[test]
    pub fn test_invalid_mode() {
        silence_errors();
        with_tmp_dir(|dir| {
            assert_err!(File::open(&dir, "foo"), "Invalid file access mode");
        })
    }

    #[test]
    pub fn test_non_hdf5_file() {
        silence_errors();
        with_tmp_path("foo.h5", |path| {
            fs::File::create(&path).unwrap().write_all(b"foo").unwrap();
            assert!(fs::metadata(&path).is_ok());
            assert_err!(File::open(&path, "r"), "unable to open file");
        })
    }

    #[test]
    pub fn test_is_read_only() {
        silence_errors();
        with_tmp_path("foo.h5", |path| {
            assert!(!File::open(&path, "w").unwrap().is_read_only());
            assert!(File::open(&path, "r").unwrap().is_read_only());
            assert!(!File::open(&path, "r+").unwrap().is_read_only());
            assert!(!File::open(&path, "a").unwrap().is_read_only());
        });
        with_tmp_path("foo.h5", |path| {
            assert!(!File::open(&path, "a").unwrap().is_read_only());
        });
        with_tmp_path("foo.h5", |path| {
            assert!(!File::open(&path, "x").unwrap().is_read_only());
        });
    }

    #[test]
    pub fn test_unable_to_open() {
        silence_errors();
        with_tmp_dir(|dir| {
            assert_err!(File::open(&dir, "r"), "unable to open file");
            assert_err!(File::open(&dir, "r+"), "unable to open file");
            assert_err!(File::open(&dir, "x"), "unable to create file");
            assert_err!(File::open(&dir, "w-"), "unable to create file");
            assert_err!(File::open(&dir, "w"), "unable to create file");
            assert_err!(File::open(&dir, "a"), "unable to create file");
        });
    }
}
<|endoftext|>


<commit_before>use postscript;
use postscript::compact::FontSet;
use std::io::{Read, Seek};
use truetype::{self, Result, Tag, Tape};
use truetype::{
    CharMapping,
    FontHeader,
    GlyphData,
    GlyphMapping,
    HorizontalHeader,
    HorizontalMetrics,
    MaximumProfile,
    NamingTable,
    PostScript,
    WindowsMetrics,
};
use truetype::offset_table::{OffsetTable, Record};

use {GlyphPositioning, GlyphSubstitution};

/// A font.
pub struct Font {
    /// The offset table.
    pub offset_table: OffsetTable,
}

macro_rules! find_check_jump(
    ($this:ident, $tape:ident, $tag:expr, $process:expr) => (
        match $this.find(Tag(*$tag)) {
            Some(record) => {
                if !try!(record.checksum($tape, $process)) {
                    raise!("found a malformed font table");
                }
                try!(Tape::jump($tape, record.offset as u64));
            },
            _ => return Ok(None),
        }
    );
    ($record:ident, $tape:ident, $tag:expr) => (
        find_check_jump!($record, $tape, $tag, |_, word| word);
    );
);

macro_rules! read {
    ($(#[$doc:meta] $tag:expr => $method:ident => $kind:ident($($dependency:ident),+),)+) => (
        $(
            #[$doc]
            pub fn $method<'l, T>(&self, tape: &mut T, dependency: ($(&'l $dependency),+))
                                  -> Result<Option<$kind>> where T: Read + Seek {

                find_check_jump!(self, tape, $tag);
                Ok(Some(try!(Tape::take_given(tape, dependency))))
            }
        )+
    );
    ($(#[$doc:meta] $tag:expr => $method:ident => $kind:ident,)+) => (
        $(
            #[$doc]
            pub fn $method<T>(&self, tape: &mut T) -> Result<Option<$kind>> where T: Read + Seek {
                find_check_jump!(self, tape, $tag);
                Ok(Some(try!(Tape::take(tape))))
            }
        )+
    );
}

impl Font {
    /// Read a font.
    pub fn read<T>(tape: &mut T) -> Result<Font> where T: Read + Seek {
        Ok(Font { offset_table: try!(truetype::Value::read(tape)) })
    }

    /// Read the font header (`head`).
    pub fn font_header<T>(&self, tape: &mut T) -> Result<Option<FontHeader>> where T: Read + Seek {
        find_check_jump!(self, tape, b"head", |i, word| if i == 2 { 0 } else { word });
        Ok(Some(try!(Tape::take(tape))))
    }

    /// Read the compact font set (`CFF `).
    pub fn font_set<T>(&self, tape: &mut T) -> Result<Option<FontSet>> where T: Read + Seek {
        find_check_jump!(self, tape, b"CFF ");
        Ok(Some(try!(postscript::Tape::take(tape))))
    }

    read! {
        #[doc = "Read the glyph-positioning table (`GPOS`)."]
        b"GPOS" => glyph_positioning => GlyphPositioning,
        #[doc = "Read the glyph-substitution table (`GSUB`)."]
        b"GSUB" => glyph_substitution => GlyphSubstitution,
        #[doc = "Read the OS/2 and Windows information (`OS/2`)."]
        b"OS/2" => windows_metrics => WindowsMetrics,
        #[doc = "Read the char-to-glyph mapping (`cmap`)."]
        b"cmap" => char_mapping => CharMapping,
        #[doc = "Read the horizontal header (`hhea`)."]
        b"hhea" => horizontal_header => HorizontalHeader,
        #[doc = "Read the maximum profile (`maxp`)."]
        b"maxp" => maximum_profile => MaximumProfile,
        #[doc = "Read the naming table (`name`)."]
        b"name" => naming_table => NamingTable,
        #[doc = "Read the PostScript information (`post`)."]
        b"post" => postscript => PostScript,
    }

    read! {
        #[doc = "Read the glyph data (`glyf`)."]
        b"glyf" => glyph_data => GlyphData(GlyphMapping),
        #[doc = "Read the horizontal metrics (`hmtx`)."]
        b"hmtx" => horizontal_metrics => HorizontalMetrics(HorizontalHeader, MaximumProfile),
        #[doc = "Read the glyph-to-location mapping (`loca`)."]
        b"loca" => glyph_mapping => GlyphMapping(FontHeader, MaximumProfile),
    }

    fn find(&self, tag: Tag) -> Option<&Record> {
        for record in &self.offset_table.records {
            if record.tag == tag {
                return Some(record);
            }
        }
        None
    }
}
<commit_msg>Rename dependency into parameter<commit_after>use postscript;
use postscript::compact::FontSet;
use std::io::{Read, Seek};
use truetype::{self, Result, Tag, Tape};
use truetype::{
    CharMapping,
    FontHeader,
    GlyphData,
    GlyphMapping,
    HorizontalHeader,
    HorizontalMetrics,
    MaximumProfile,
    NamingTable,
    PostScript,
    WindowsMetrics,
};
use truetype::offset_table::{OffsetTable, Record};

use {GlyphPositioning, GlyphSubstitution};

/// A font.
pub struct Font {
    /// The offset table.
    pub offset_table: OffsetTable,
}

macro_rules! find_check_jump(
    ($this:ident, $tape:ident, $tag:expr, $process:expr) => (
        match $this.find(Tag(*$tag)) {
            Some(record) => {
                if !try!(record.checksum($tape, $process)) {
                    raise!("found a malformed font table");
                }
                try!(Tape::jump($tape, record.offset as u64));
            },
            _ => return Ok(None),
        }
    );
    ($record:ident, $tape:ident, $tag:expr) => (
        find_check_jump!($record, $tape, $tag, |_, word| word);
    );
);

macro_rules! read {
    ($(#[$doc:meta] $tag:expr => $method:ident => $kind:ident($($parameter:ident),+),)+) => (
        $(
            #[$doc]
            pub fn $method<'l, T>(&self, tape: &mut T, parameter: ($(&'l $parameter),+))
                                  -> Result<Option<$kind>> where T: Read + Seek {

                find_check_jump!(self, tape, $tag);
                Ok(Some(try!(Tape::take_given(tape, parameter))))
            }
        )+
    );
    ($(#[$doc:meta] $tag:expr => $method:ident => $kind:ident,)+) => (
        $(
            #[$doc]
            pub fn $method<T>(&self, tape: &mut T) -> Result<Option<$kind>> where T: Read + Seek {
                find_check_jump!(self, tape, $tag);
                Ok(Some(try!(Tape::take(tape))))
            }
        )+
    );
}

impl Font {
    /// Read a font.
    pub fn read<T>(tape: &mut T) -> Result<Font> where T: Read + Seek {
        Ok(Font { offset_table: try!(truetype::Value::read(tape)) })
    }

    /// Read the font header (`head`).
    pub fn font_header<T>(&self, tape: &mut T) -> Result<Option<FontHeader>> where T: Read + Seek {
        find_check_jump!(self, tape, b"head", |i, word| if i == 2 { 0 } else { word });
        Ok(Some(try!(Tape::take(tape))))
    }

    /// Read the compact font set (`CFF `).
    pub fn font_set<T>(&self, tape: &mut T) -> Result<Option<FontSet>> where T: Read + Seek {
        find_check_jump!(self, tape, b"CFF ");
        Ok(Some(try!(postscript::Tape::take(tape))))
    }

    read! {
        #[doc = "Read the glyph-positioning table (`GPOS`)."]
        b"GPOS" => glyph_positioning => GlyphPositioning,
        #[doc = "Read the glyph-substitution table (`GSUB`)."]
        b"GSUB" => glyph_substitution => GlyphSubstitution,
        #[doc = "Read the OS/2 and Windows information (`OS/2`)."]
        b"OS/2" => windows_metrics => WindowsMetrics,
        #[doc = "Read the char-to-glyph mapping (`cmap`)."]
        b"cmap" => char_mapping => CharMapping,
        #[doc = "Read the horizontal header (`hhea`)."]
        b"hhea" => horizontal_header => HorizontalHeader,
        #[doc = "Read the maximum profile (`maxp`)."]
        b"maxp" => maximum_profile => MaximumProfile,
        #[doc = "Read the naming table (`name`)."]
        b"name" => naming_table => NamingTable,
        #[doc = "Read the PostScript information (`post`)."]
        b"post" => postscript => PostScript,
    }

    read! {
        #[doc = "Read the glyph data (`glyf`)."]
        b"glyf" => glyph_data => GlyphData(GlyphMapping),
        #[doc = "Read the horizontal metrics (`hmtx`)."]
        b"hmtx" => horizontal_metrics => HorizontalMetrics(HorizontalHeader, MaximumProfile),
        #[doc = "Read the glyph-to-location mapping (`loca`)."]
        b"loca" => glyph_mapping => GlyphMapping(FontHeader, MaximumProfile),
    }

    fn find(&self, tag: Tag) -> Option<&Record> {
        for record in &self.offset_table.records {
            if record.tag == tag {
                return Some(record);
            }
        }
        None
    }
}
<|endoftext|>