<commit_before>use ansi_term::Style;

use crate::fs::File;
use crate::info::filetype::FileExtensions;
use crate::output::file_name::FileStyle;

pub trait FileIcon {
    fn icon_file(&self, file: &File) -> Option<char>;
}

pub enum Icons {
    Audio,
    Image,
    Video,
}

impl Icons {
    pub fn value(&self) -> char {
        match *self {
            Icons::Audio => '\u{f001}',
            Icons::Image => '\u{f1c5}',
            Icons::Video => '\u{f03d}',
        }
    }
}

pub fn painted_icon(file: &File, style: &FileStyle) -> String {
    let file_icon = icon(&file).to_string();
    let painted = style.exts
            .colour_file(&file)
            .map_or(file_icon.to_string(), |c| {
                // Remove underline from icon
                if c.is_underline {
                    match c.foreground {
                        Some(color) => Style::from(color).paint(file_icon).to_string(),
                        None => Style::default().paint(file_icon).to_string(),
                    }
                } else {
                    c.paint(file_icon).to_string()
                }
            });
    format!("{}  ", painted)
}

fn icon(file: &File) -> char {
    let extensions = Box::new(FileExtensions);
    if file.is_directory() { '\u{f115}' }
    else if let Some(icon) = extensions.icon_file(file) { icon }
    else {
        if let Some(ext) = file.ext.as_ref() {
            match ext.as_str() {
                "ai"        => '\u{e7b4}',
                "android"   => '\u{e70e}',
                "apple"     => '\u{f179}',
                "avro"      => '\u{e60b}',
                "clj"       => '\u{e768}',
                "coffee"    => '\u{f0f4}',
                "cpp"       => '\u{e61d}',
                "hpp"       => '\u{e61d}',
                "c"         => '\u{e61e}',
                "h"         => '\u{e61e}',
                "cs"        => '\u{f81a}',
                "css"       => '\u{e749}',
                "d"         => '\u{e7af}',
                "dart"      => '\u{e798}',
                "db"        => '\u{f1c0}',
                "diff"      => '\u{f440}',
                "patch"     => '\u{f440}',
                "rtf"       => '\u{f1c2}',
                "doc"       => '\u{f1c2}',
                "docx"      => '\u{f1c2}',
                "odt"       => '\u{f1c2}',
                "ebook"     => '\u{e28b}',
                "env"       => '\u{f462}',
                "epub"      => '\u{e28a}',
                "erl"       => '\u{e7b1}',
                "font"      => '\u{f031}',
                "gform"     => '\u{f298}',
                "git"       => '\u{f1d3}',
                "go"        => '\u{e626}',
                "hs"        => '\u{e777}',
                "htm"       => '\u{f13b}',
                "html"      => '\u{f13b}',
                "xhtml"     => '\u{f13b}',
                "iml"       => '\u{e7b5}',
                "java"      => '\u{e204}',
                "js"        => '\u{e74e}',
                "mjs"       => '\u{e74e}',
                "json"      => '\u{e60b}',
                "jsx"       => '\u{e7ba}',
                "vue"       => '\u{fd42}',
                "node"      => '\u{f898}',
                "less"      => '\u{e758}',
                "log"       => '\u{f18d}',
                "lua"       => '\u{e620}',
                "md"        => '\u{f48a}',
                "markdown"  => '\u{f48a}',
                "mustache"  => '\u{e60f}',
                "npmignore" => '\u{e71e}',
                "pdf"       => '\u{f1c1}',
                "djvu"      => '\u{f02d}',
                "mobi"      => '\u{f02d}',
                "php"       => '\u{e73d}',
                "pl"        => '\u{e769}',
                "ppt"       => '\u{f1c4}',
                "pptx"      => '\u{f1c4}',
                "odp"       => '\u{f1c4}',
                "psd"       => '\u{e7b8}',
                "py"        => '\u{e606}',
                "r"         => '\u{f25d}',
                "rb"        => '\u{e21e}',
                "ru"        => '\u{e21e}',
                "erb"       => '\u{e21e}',
                "gem"       => '\u{e21e}',
                "rdb"       => '\u{e76d}',
                "rs"        => '\u{e7a8}',
                "rss"       => '\u{f09e}',
                "rubydoc"   => '\u{e73b}',
                "sass"      => '\u{e74b}',
                "stylus"    => '\u{e759}',
                "scala"     => '\u{e737}',
                "shell"     => '\u{f489}',
                "sqlite3"   => '\u{e7c4}',
                "styl"      => '\u{e600}',
                "latex"     => '\u{e600}',
                "tex"       => '\u{e600}',
                "ts"        => '\u{e628}',
                "tsx"       => '\u{e628}',
                "twig"      => '\u{e61c}',
                "txt"       => '\u{f15c}',
                "video"     => '\u{f03d}',
                "vim"       => '\u{e62b}',
                "xml"       => '\u{e619}',
                "yml"       => '\u{f481}',
                "yaml"      => '\u{f481}',
                "rar"       => '\u{f410}',
                "zip"       => '\u{f410}',
                "bz"        => '\u{f410}',
                "bz2"       => '\u{f410}',
                "xz"        => '\u{f410}',
                "taz"       => '\u{f410}',
                "tbz"       => '\u{f410}',
                "tbz2"      => '\u{f410}',
                "tz"        => '\u{f410}',
                "tar"       => '\u{f410}',
                "tzo"       => '\u{f410}',
                "lz"        => '\u{f410}',
                "lzh"       => '\u{f410}',
                "lzma"      => '\u{f410}',
                "lzo"       => '\u{f410}',
                "gz"        => '\u{f410}',
                "deb"       => '\u{e77d}',
                "rpm"       => '\u{e7bb}',
                "exe"       => '\u{e70f}',
                "msi"       => '\u{e70f}',
                "dll"       => '\u{e70f}',
                "cab"       => '\u{e70f}',
                "bat"       => '\u{e70f}',
                "cmd"       => '\u{e70f}',
                "sh"        => '\u{e795}',
                "bash"      => '\u{e795}',
                "zsh"       => '\u{e795}',
                "fish"      => '\u{e795}',
                "csh"       => '\u{e795}',
                "ini"       => '\u{e615}',
                "toml"      => '\u{e615}',
                "cfg"       => '\u{e615}',
                "conf"      => '\u{e615}',
                "apk"       => '\u{e70e}',
                "ttf"       => '\u{f031}',
                "woff"      => '\u{f031}',
                "woff2"     => '\u{f031}',
                "otf"       => '\u{f031}',
                "csv"       => '\u{f1c3}',
                "tsv"       => '\u{f1c3}',
                "xls"       => '\u{f1c3}',
                "xlsx"      => '\u{f1c3}',
                "ods"       => '\u{f1c3}',
                "so"        => '\u{f17c}',
                "sql"       => '\u{f1c0}',
                "jar"       => '\u{e256}',
                "jad"       => '\u{e256}',
                "class"     => '\u{e256}',
                "war"       => '\u{e256}',
                "groovy"    => '\u{e775}',
                "iso"       => '\u{e271}',
                "lock"      => '\u{f023}',
                _           => '\u{f15b}'
            }
        } else {
            '\u{f15b}'
        }
    }
}
<commit_msg>Updated filetype icons<commit_after>use ansi_term::Style;

use crate::fs::File;
use crate::info::filetype::FileExtensions;
use crate::output::file_name::FileStyle;

pub trait FileIcon {
    fn icon_file(&self, file: &File) -> Option<char>;
}

pub enum Icons {
    Audio,
    Image,
    Video,
}

impl Icons {
    pub fn value(&self) -> char {
        match *self {
            Icons::Audio => '\u{f001}',
            Icons::Image => '\u{f1c5}',
            Icons::Video => '\u{f03d}',
        }
    }
}

pub fn painted_icon(file: &File, style: &FileStyle) -> String {
    let file_icon = icon(&file).to_string();
    let painted = style.exts
            .colour_file(&file)
            .map_or(file_icon.to_string(), |c| {
                // Remove underline from icon
                if c.is_underline {
                    match c.foreground {
                        Some(color) => Style::from(color).paint(file_icon).to_string(),
                        None => Style::default().paint(file_icon).to_string(),
                    }
                } else {
                    c.paint(file_icon).to_string()
                }
            });
    format!("{}  ", painted)
}

fn icon(file: &File) -> char {
    let extensions = Box::new(FileExtensions);
    if file.is_directory() { '\u{f115}' }
    else if let Some(icon) = extensions.icon_file(file) { icon }
    else {
        if let Some(ext) = file.ext.as_ref() {
            match ext.as_str() {
                "ai"        => '\u{e7b4}',
                "android"   => '\u{e70e}',
                "apple"     => '\u{f179}',
                "avro"      => '\u{e60b}',
                "clj"       => '\u{e768}',
                "coffee"    => '\u{f0f4}',
                "cpp"       => '\u{e61d}',
                "hpp"       => '\u{e61d}',
                "c"         => '\u{e61e}',
                "h"         => '\u{e61e}',
                "cs"        => '\u{f81a}',
                "css"       => '\u{e749}',
                "d"         => '\u{e7af}',
                "dart"      => '\u{e798}',
                "db"        => '\u{f1c0}',
                "diff"      => '\u{f440}',
                "patch"     => '\u{f440}',
                "rtf"       => '\u{f1c2}',
                "doc"       => '\u{f1c2}',
                "docx"      => '\u{f1c2}',
                "odt"       => '\u{f1c2}',
                "ebook"     => '\u{e28b}',
                "env"       => '\u{f462}',
                "epub"      => '\u{e28a}',
                "erl"       => '\u{e7b1}',
                "font"      => '\u{f031}',
                "gform"     => '\u{f298}',
                "git"       => '\u{f1d3}',
                "go"        => '\u{e626}',
                "hs"        => '\u{e777}',
                "htm"       => '\u{f13b}',
                "html"      => '\u{f13b}',
                "xhtml"     => '\u{f13b}',
                "iml"       => '\u{e7b5}',
                "java"      => '\u{e204}',
                "js"        => '\u{e74e}',
                "mjs"       => '\u{e74e}',
                "json"      => '\u{e60b}',
                "jsx"       => '\u{e7ba}',
                "vue"       => '\u{fd42}',
                "node"      => '\u{f898}',
                "less"      => '\u{e758}',
                "log"       => '\u{f18d}',
                "lua"       => '\u{e620}',
                "md"        => '\u{f48a}',
                "markdown"  => '\u{f48a}',
                "mustache"  => '\u{e60f}',
                "npmignore" => '\u{e71e}',
                "pdf"       => '\u{f1c1}',
                "djvu"      => '\u{f02d}',
                "mobi"      => '\u{f02d}',
                "php"       => '\u{e73d}',
                "pl"        => '\u{e769}',
                "ppt"       => '\u{f1c4}',
                "pptx"      => '\u{f1c4}',
                "odp"       => '\u{f1c4}',
                "psd"       => '\u{e7b8}',
                "py"        => '\u{e606}',
                "r"         => '\u{f25d}',
                "rb"        => '\u{e21e}',
                "ru"        => '\u{e21e}',
                "erb"       => '\u{e21e}',
                "gem"       => '\u{e21e}',
                "rdb"       => '\u{e76d}',
                "rs"        => '\u{e7a8}',
                "rss"       => '\u{f09e}',
                "rubydoc"   => '\u{e73b}',
                "sass"      => '\u{e74b}',
                "stylus"    => '\u{e759}',
                "scala"     => '\u{e737}',
                "sh"        => '\u{f489}',
                "shell"     => '\u{f489}',
                "sqlite3"   => '\u{e7c4}',
                "styl"      => '\u{e600}',
                "latex"     => '\u{e600}',
                "tex"       => '\u{e600}',
                "ts"        => '\u{e628}',
                "tsx"       => '\u{e628}',
                "twig"      => '\u{e61c}',
                "txt"       => '\u{f15c}',
                "video"     => '\u{f03d}',
                "vim"       => '\u{e62b}',
                "xml"       => '\u{e619}',
                "yml"       => '\u{f481}',
                "yaml"      => '\u{f481}',
                "rar"       => '\u{f410}',
                "zip"       => '\u{f410}',
                "bz"        => '\u{f410}',
                "bz2"       => '\u{f410}',
                "xz"        => '\u{f410}',
                "taz"       => '\u{f410}',
                "tbz"       => '\u{f410}',
                "tbz2"      => '\u{f410}',
                "tz"        => '\u{f410}',
                "tar"       => '\u{f410}',
                "tzo"       => '\u{f410}',
                "lz"        => '\u{f410}',
                "lzh"       => '\u{f410}',
                "lzma"      => '\u{f410}',
                "lzo"       => '\u{f410}',
                "gz"        => '\u{f410}',
                "deb"       => '\u{e77d}',
                "rpm"       => '\u{e7bb}',
                "exe"       => '\u{e70f}',
                "msi"       => '\u{e70f}',
                "dll"       => '\u{e70f}',
                "cab"       => '\u{e70f}',
                "bat"       => '\u{e70f}',
                "cmd"       => '\u{e70f}',
                "sh"        => '\u{e795}',
                "bash"      => '\u{e795}',
                "zsh"       => '\u{e795}',
                "fish"      => '\u{e795}',
                "csh"       => '\u{e795}',
                "ini"       => '\u{e615}',
                "toml"      => '\u{e615}',
                "cfg"       => '\u{e615}',
                "conf"      => '\u{e615}',
                "apk"       => '\u{e70e}',
                "ttf"       => '\u{f031}',
                "woff"      => '\u{f031}',
                "woff2"     => '\u{f031}',
                "otf"       => '\u{f031}',
                "csv"       => '\u{f1c3}',
                "tsv"       => '\u{f1c3}',
                "xls"       => '\u{f1c3}',
                "xlsx"      => '\u{f1c3}',
                "ods"       => '\u{f1c3}',
                "so"        => '\u{f17c}',
                "sql"       => '\u{f1c0}',
                "jar"       => '\u{e256}',
                "jad"       => '\u{e256}',
                "class"     => '\u{e256}',
                "war"       => '\u{e256}',
                "groovy"    => '\u{e775}',
                "iso"       => '\u{e271}',
                "lock"      => '\u{f023}',
                _           => '\u{f15b}'
            }
        } else {
            '\u{f15b}'
        }
    }
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

extern crate devicemapper;
extern crate libstratis;
extern crate loopdev;
extern crate tempdir;

mod util;

use std::fs::OpenOptions;
use std::io::{Seek, Write, SeekFrom};
use std::path::{Path, PathBuf};

use devicemapper::Bytes;
use loopdev::{LoopControl, LoopDevice};
use tempdir::TempDir;

use libstratis::consts::IEC;

use util::simple_tests::test_force_flag_dirty;
use util::simple_tests::test_force_flag_stratis;
use util::simple_tests::test_linear_device;
use util::simple_tests::test_pool_blockdevs;
use util::simple_tests::test_thinpool_device;
use util::simple_tests::test_variable_length_metadata_times;

/// Setup count loop backed devices in dir.
/// Make sure each loop device is backed by a 1 GiB file.
fn get_devices(count: u8, dir: &TempDir) -> Vec<LoopDevice> {
    let lc = LoopControl::open().unwrap();
    let mut loop_devices = Vec::new();

    let length = Bytes(IEC::Gi as u64);
    for index in 0..count {
        let subdir = TempDir::new_in(dir, &index.to_string()).unwrap();
        let path = subdir.path().join("store");
        let mut f = OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();

        // the proper way to do this is fallocate, but nix doesn't implement yet.
        // TODO: see https://github.com/nix-rust/nix/issues/596
        f.seek(SeekFrom::Start(*length)).unwrap();
        f.write(&[0]).unwrap();
        f.flush().unwrap();

        let ld = lc.next_free().unwrap();
        ld.attach(path, 0).unwrap();
        loop_devices.push(ld);
    }
    loop_devices
}

/// Set up count loopbacked devices.
/// Then, run the designated test.
/// Then, take down the loop devices.
fn test_with_spec<F>(count: u8, test: F) -> ()
    where F: Fn(&[&Path]) -> ()
{
    let tmpdir = TempDir::new("stratis").unwrap();
    let loop_devices: Vec<LoopDevice> = get_devices(count, &tmpdir);
    let device_paths: Vec<PathBuf> = loop_devices.iter().map(|x| x.get_path().unwrap()).collect();
    let device_paths: Vec<&Path> = device_paths.iter().map(|x| x.as_path()).collect();

    test(&device_paths);

    for dev in loop_devices {
        dev.detach().unwrap();
    }
}

#[test]
pub fn loop_test_force_flag_stratis() {
    test_with_spec(2, test_force_flag_stratis);
    test_with_spec(3, test_force_flag_stratis);
}

#[test]
pub fn loop_test_linear_device() {
    test_with_spec(2, test_linear_device);
    test_with_spec(3, test_linear_device);
}

#[test]
pub fn loop_test_thinpool_device() {
    test_with_spec(3, test_thinpool_device);
}

#[test]
pub fn loop_test_pool_blockdevs() {
    test_with_spec(3, test_pool_blockdevs);
}

#[test]
pub fn loop_test_force_flag_dirty() {
    test_with_spec(3, test_force_flag_dirty);
}

#[test]
pub fn loop_test_variable_length_metadata_times() {
    test_with_spec(3, test_variable_length_metadata_times);
}
<commit_msg>Wipe the 1st 1 MiB of file backing loopbacked device<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

extern crate devicemapper;
extern crate libstratis;
extern crate loopdev;
extern crate tempdir;

mod util;

use std::fs::OpenOptions;
use std::io::{Seek, Write, SeekFrom};
use std::path::{Path, PathBuf};

use devicemapper::{Bytes, Sectors};
use loopdev::{LoopControl, LoopDevice};
use tempdir::TempDir;

use libstratis::consts::IEC;
use libstratis::engine::strat_engine::blockdev::wipe_sectors;

use util::simple_tests::test_force_flag_dirty;
use util::simple_tests::test_force_flag_stratis;
use util::simple_tests::test_linear_device;
use util::simple_tests::test_pool_blockdevs;
use util::simple_tests::test_thinpool_device;
use util::simple_tests::test_variable_length_metadata_times;

/// Setup count loop backed devices in dir.
/// Make sure each loop device is backed by a 1 GiB file.
/// Wipe the first 1 MiB of the file.
fn get_devices(count: u8, dir: &TempDir) -> Vec<LoopDevice> {
    let lc = LoopControl::open().unwrap();
    let mut loop_devices = Vec::new();

    let length = Bytes(IEC::Gi as u64);
    let wipe_length = Bytes(IEC::Mi as u64).sectors();
    for index in 0..count {
        let subdir = TempDir::new_in(dir, &index.to_string()).unwrap();
        let path = subdir.path().join("store");
        let mut f = OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();

        // the proper way to do this is fallocate, but nix doesn't implement yet.
        // TODO: see https://github.com/nix-rust/nix/issues/596
        f.seek(SeekFrom::Start(*length)).unwrap();
        f.write(&[0]).unwrap();
        f.flush().unwrap();

        // Wipe 1 MiB at the beginning, as data sits around on the files.
        OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();
        wipe_sectors(&path, Sectors(0), wipe_length).unwrap();

        let ld = lc.next_free().unwrap();
        ld.attach(path, 0).unwrap();
        loop_devices.push(ld);
    }
    loop_devices
}

/// Set up count loopbacked devices.
/// Then, run the designated test.
/// Then, take down the loop devices.
fn test_with_spec<F>(count: u8, test: F) -> ()
    where F: Fn(&[&Path]) -> ()
{
    let tmpdir = TempDir::new("stratis").unwrap();
    let loop_devices: Vec<LoopDevice> = get_devices(count, &tmpdir);
    let device_paths: Vec<PathBuf> = loop_devices.iter().map(|x| x.get_path().unwrap()).collect();
    let device_paths: Vec<&Path> = device_paths.iter().map(|x| x.as_path()).collect();

    test(&device_paths);

    for dev in loop_devices {
        dev.detach().unwrap();
    }
}

#[test]
pub fn loop_test_force_flag_stratis() {
    test_with_spec(2, test_force_flag_stratis);
    test_with_spec(3, test_force_flag_stratis);
}

#[test]
pub fn loop_test_linear_device() {
    test_with_spec(2, test_linear_device);
    test_with_spec(3, test_linear_device);
}

#[test]
pub fn loop_test_thinpool_device() {
    test_with_spec(3, test_thinpool_device);
}

#[test]
pub fn loop_test_pool_blockdevs() {
    test_with_spec(3, test_pool_blockdevs);
}

#[test]
pub fn loop_test_force_flag_dirty() {
    test_with_spec(3, test_force_flag_dirty);
}

#[test]
pub fn loop_test_variable_length_metadata_times() {
    test_with_spec(3, test_variable_length_metadata_times);
}
<|endoftext|>


<commit_before>//! way-cooler registry.

use std::ops::Deref;
use std::cmp::Eq;
use std::fmt::Display;
use std::hash::Hash;
use std::borrow::Borrow;
use std::collections::hash_map::{HashMap, Entry};
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};

use rustc_serialize::Decodable;
use rustc_serialize::json::{Json, ToJson, Decoder, DecoderError};

mod types;
mod commands;
pub use self::types::*; // Export constants too

#[cfg(test)]
mod tests;

pub type RegMap = HashMap<String, RegistryField>;

lazy_static! {
    /// Registry variable for the registry
    static ref REGISTRY: RwLock<RegMap> = RwLock::new(HashMap::new());
}

/// Error types that can happen
#[derive(Debug, PartialEq)]
pub enum RegistryError {
    /// The registry key was not found
    KeyNotFound,
    /// The registry key was of the wrong type
    WrongKeyType,
    /// Attempting to set a readonly value
    InvalidOperation,
    /// The object couldn't be converted to/from Json
    DecoderError(DecoderError)
}

/// Result type of gets/sets to the registry
pub type RegistryResult<T> = Result<T, RegistryError>;

/// Initialize the registry (register default commands)
pub fn init() {
    commands::register_defaults();
}

/// Acquires a read lock on the registry.
pub fn read_lock<'a>() -> RwLockReadGuard<'a, RegMap> {
    REGISTRY.read().expect("Unable to read from registry!")
}

/// Acquires a write lock on the registry.
pub fn write_lock<'a>() -> RwLockWriteGuard<'a, RegMap> {
    REGISTRY.write().expect("Unable to write to registry!")
}

/// Gets a RegistryField enum with the specified name
pub fn get_field<K>(name: &K) -> Option<RegistryField>
    where String: Borrow<K>, K: Hash + Eq + Display {
    // clone() will either clone an Arc or an Arc+AccessFlags
    let result = read_lock().get(name).map(|v| v.clone());
    trace!("get: {} => {:?}", name, &result);
    return result;
}

/// Attempts to get a command from the registry.
pub fn get_command<K>(name: &K) -> RegistryResult<CommandFn>
    where String: Borrow<K>, K: Hash + Eq + Display {
    get_field(name).ok_or(RegistryError::KeyNotFound)
        .and_then(|val| match val {
        RegistryField::Command(com) => Ok(com),
        _ => Err(RegistryError::WrongKeyType)
    })
}

/// Gets a data type from the registry, returning a reference to the property
/// method if the field is a property.
pub fn get_data<K>(name: &K) -> RegistryResult<RegistryGetData>
where String: Borrow<K>, K: Hash + Eq + Display {
    get_field(name).ok_or(RegistryError::KeyNotFound)
        .and_then(|val| match val {
            RegistryField::Object { flags, data } =>
                Ok(RegistryGetData::Object(flags, data)),
            RegistryField::Property { get: maybe_get, .. } =>
                match maybe_get {
                    Some(get) => Ok(RegistryGetData::Property(get)),
                    None => Err(RegistryError::InvalidOperation)
                },
            _ => Err(RegistryError::WrongKeyType)
        })
}

/// Get a Rust structure from the registry
#[allow(dead_code)]
pub fn get_struct<K, T>(name: &K) -> RegistryResult<(AccessFlags, T)>
where String: Borrow <K>, K: Hash + Eq + Display, T: Decodable {
    get_json(name).and_then(|(flags, json)|
        T::decode(&mut Decoder::new(json.deref().clone()))
                            .map_err(|e| RegistryError::DecoderError(e))
                            .map(|data| (flags, data)))
}

/// Get Json data from the registry, evaluating if a property was found.
pub fn get_json<K>(name: &K) -> RegistryResult<(AccessFlags, Arc<Json>)>
where String: Borrow<K>, K: Hash + Eq + Display {
    get_data(name).map(|val| val.resolve())
}

/// Set a value to the given registry field.
pub fn set_field(key: String, value: RegistryField)
                 -> RegistryResult<Option<RegistryField>> {
    let mut reg = write_lock();
    match reg.entry(key) {
        Entry::Occupied(mut entry) => {
            let first_type = entry.get().get_type();
            if first_type.can_set_from(value.get_type()) {
                Ok(Some(entry.insert(value)))
            }
            else {
                Err(RegistryError::WrongKeyType)
            }
        },
        Entry::Vacant(vacancy) => {
            vacancy.insert(value);
            Ok(None)
        }
    }
}

/// Set a command to the given Command
#[allow(dead_code)]
pub fn set_command(key: String, command: CommandFn)
                   -> RegistryResult<Option<CommandFn>> {
    set_field(key, RegistryField::Command(command))
        .map(|maybe_field|
              maybe_field.and_then(|field|
                                    field.get_command()))
}

/// Set a value to the given JSON value.
#[allow(dead_code)]
pub fn set_json(key: String, flags: AccessFlags, json: Json)
                -> RegistryResult<Option<(AccessFlags, Arc<Json>)>> {
    let func: SetFn;
    {
        let mut reg = write_lock();
        match reg.entry(key) {
            Entry::Vacant(vacancy) => {
                vacancy.insert(RegistryField::Object {
                    flags: flags, data: Arc::new(json)
                });
                return Ok(None);
            },
            Entry::Occupied(mut entry) => {
                let first_type = entry.get().get_type();
                if first_type == FieldType::Object {
                    return Ok(entry.insert(RegistryField::Object {
                        flags: flags, data: Arc::new(json)
                    }).as_object());
                }
                else if first_type == FieldType::Property {
                    match entry.get().clone().as_property_set() {
                        Some(fun) => func = fun,
                        None => return Err(RegistryError::InvalidOperation)
                    }
                }
                else {
                    return Err(RegistryError::WrongKeyType);
                }
            }
        }
    }
    func(json);
    return Ok(None);
}

/// Set an object/property in the registry to a value using a ToJson.
#[allow(dead_code)]
pub fn set_struct<T: ToJson>(key: String, flags: AccessFlags, value: T)
                             -> RegistryResult<Option<(AccessFlags, Arc<Json>)>> {
    set_json(key, flags, value.to_json())
}

/// Sets a value for a given Json value, optionally returning the associated property.
#[allow(dead_code)]
pub fn set_with_property(key: String, flags: AccessFlags, json: Json)
                         -> RegistryResult<Option<(Json, SetFn)>> {
    let mut reg = write_lock();
    match reg.entry(key) {
        Entry::Vacant(vacancy) => {
            vacancy.insert(RegistryField::Object {
                flags: flags, data: Arc::new(json)
            });
            Ok(None)
        },
        Entry::Occupied(mut entry) => {
            let first_type = entry.get().get_type();
            if first_type == FieldType::Object {
                entry.insert(RegistryField::Object {
                    flags: flags, data: Arc::new(json)
                });
                Ok(None)
            }
            else if first_type == FieldType::Property {
                Ok(Some((json, entry.get().clone().as_property_set()
                   .expect("set_json_property: checked value of field type"))))
            }
            else {
                Err(RegistryError::WrongKeyType)
            }
        }
    }
}

/// Binds properties to a field of the registry
#[allow(dead_code)]
pub fn set_property_field(key: String, get_fn: Option<GetFn>, set_fn: Option<SetFn>)
                          -> RegistryResult<Option<RegistryField>> {
    set_field(key, RegistryField::Property { get: get_fn, set: set_fn })
}

/// Whether this map contains a key of any type
#[allow(dead_code)]
pub fn contains_key<K>(key: &K) -> bool
where String: Borrow<K>, K: Hash + Eq + Display {
    trace!("contains_key: {}", *key);
    let read_reg = read_lock();
    read_reg.contains_key(key)
}

/// Whether the registry contains a key of some type:
/// None: no key
/// true: same type key
/// false: different type key
#[allow(dead_code)]
pub fn contains_key_of<K>(key: &K, field_type: FieldType) -> Option<bool>
where String: Borrow<K>, K: Hash + Eq + Display {
    let read_reg = read_lock();
    read_reg.get(key).map(|field| field.get_type() == field_type)
}
<commit_msg>Cleaned up set_json<commit_after>//! way-cooler registry.

use std::ops::Deref;
use std::cmp::Eq;
use std::fmt::Display;
use std::hash::Hash;
use std::borrow::Borrow;
use std::collections::hash_map::{HashMap, Entry};
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};

use rustc_serialize::Decodable;
use rustc_serialize::json::{Json, ToJson, Decoder, DecoderError};

mod types;
mod commands;
pub use self::types::*; // Export constants too

#[cfg(test)]
mod tests;

pub type RegMap = HashMap<String, RegistryField>;

lazy_static! {
    /// Registry variable for the registry
    static ref REGISTRY: RwLock<RegMap> = RwLock::new(HashMap::new());
}

/// Error types that can happen
#[derive(Debug, PartialEq)]
pub enum RegistryError {
    /// The registry key was not found
    KeyNotFound,
    /// The registry key was of the wrong type
    WrongKeyType,
    /// Attempting to set a readonly value
    InvalidOperation,
    /// The object couldn't be converted to/from Json
    DecoderError(DecoderError)
}

/// Result type of gets/sets to the registry
pub type RegistryResult<T> = Result<T, RegistryError>;

/// Initialize the registry (register default commands)
pub fn init() {
    commands::register_defaults();
}

/// Acquires a read lock on the registry.
pub fn read_lock<'a>() -> RwLockReadGuard<'a, RegMap> {
    REGISTRY.read().expect("Unable to read from registry!")
}

/// Acquires a write lock on the registry.
pub fn write_lock<'a>() -> RwLockWriteGuard<'a, RegMap> {
    REGISTRY.write().expect("Unable to write to registry!")
}

/// Gets a RegistryField enum with the specified name
pub fn get_field<K>(name: &K) -> Option<RegistryField>
    where String: Borrow<K>, K: Hash + Eq + Display {
    // clone() will either clone an Arc or an Arc+AccessFlags
    let result = read_lock().get(name).map(|v| v.clone());
    trace!("get: {} => {:?}", name, &result);
    return result;
}

/// Attempts to get a command from the registry.
pub fn get_command<K>(name: &K) -> RegistryResult<CommandFn>
    where String: Borrow<K>, K: Hash + Eq + Display {
    get_field(name).ok_or(RegistryError::KeyNotFound)
        .and_then(|val| match val {
        RegistryField::Command(com) => Ok(com),
        _ => Err(RegistryError::WrongKeyType)
    })
}

/// Gets a data type from the registry, returning a reference to the property
/// method if the field is a property.
pub fn get_data<K>(name: &K) -> RegistryResult<RegistryGetData>
where String: Borrow<K>, K: Hash + Eq + Display {
    get_field(name).ok_or(RegistryError::KeyNotFound)
        .and_then(|val| match val {
            RegistryField::Object { flags, data } =>
                Ok(RegistryGetData::Object(flags, data)),
            RegistryField::Property { get: maybe_get, .. } =>
                match maybe_get {
                    Some(get) => Ok(RegistryGetData::Property(get)),
                    None => Err(RegistryError::InvalidOperation)
                },
            _ => Err(RegistryError::WrongKeyType)
        })
}

/// Get a Rust structure from the registry
#[allow(dead_code)]
pub fn get_struct<K, T>(name: &K) -> RegistryResult<(AccessFlags, T)>
where String: Borrow <K>, K: Hash + Eq + Display, T: Decodable {
    get_json(name).and_then(|(flags, json)|
        T::decode(&mut Decoder::new(json.deref().clone()))
                            .map_err(|e| RegistryError::DecoderError(e))
                            .map(|data| (flags, data)))
}

/// Get Json data from the registry, evaluating if a property was found.
pub fn get_json<K>(name: &K) -> RegistryResult<(AccessFlags, Arc<Json>)>
where String: Borrow<K>, K: Hash + Eq + Display {
    get_data(name).map(|val| val.resolve())
}

/// Set a value to the given registry field.
pub fn set_field(key: String, value: RegistryField)
                 -> RegistryResult<Option<RegistryField>> {
    let mut reg = write_lock();
    match reg.entry(key) {
        Entry::Occupied(mut entry) => {
            let first_type = entry.get().get_type();
            if first_type.can_set_from(value.get_type()) {
                Ok(Some(entry.insert(value)))
            }
            else {
                Err(RegistryError::WrongKeyType)
            }
        },
        Entry::Vacant(vacancy) => {
            vacancy.insert(value);
            Ok(None)
        }
    }
}

/// Set a command to the given Command
#[allow(dead_code)]
pub fn set_command(key: String, command: CommandFn)
                   -> RegistryResult<Option<CommandFn>> {
    set_field(key, RegistryField::Command(command))
        .map(|maybe_field|
              maybe_field.and_then(|field|
                                    field.get_command()))
}

/// Set a value to the given JSON value.
#[allow(dead_code)]
pub fn set_json(key: String, flags: AccessFlags, json: Json)
                -> RegistryResult<Option<(AccessFlags, Arc<Json>)>> {
    let mut reg = write_lock();
    match reg.entry(key) {
        Entry::Vacant(vacancy) => {
            vacancy.insert(RegistryField::Object {
                flags: flags, data: Arc::new(json)
            });
            return Ok(None);
        },
        Entry::Occupied(mut entry) => {
            let first_type = entry.get().get_type();
            if first_type == FieldType::Object {
                return Ok(entry.insert(RegistryField::Object {
                    flags: flags, data: Arc::new(json)
                }).as_object());
            }
            else if first_type == FieldType::Property {
                match entry.get().clone().as_property_set() {
                    Some(func) => {
                        func(json);
                        return;
                    }
                    None => return Err(RegistryError::InvalidOperation)
                }
            }
            else {
                return Err(RegistryError::WrongKeyType);
            }
        }
    }
    return Ok(None);
}

/// Set an object/property in the registry to a value using a ToJson.
#[allow(dead_code)]
pub fn set_struct<T: ToJson>(key: String, flags: AccessFlags, value: T)
                             -> RegistryResult<Option<(AccessFlags, Arc<Json>)>> {
    set_json(key, flags, value.to_json())
}

/// Sets a value for a given Json value, optionally returning the associated property.
#[allow(dead_code)]
pub fn set_with_property(key: String, flags: AccessFlags, json: Json)
                         -> RegistryResult<Option<(Json, SetFn)>> {
    let mut reg = write_lock();
    match reg.entry(key) {
        Entry::Vacant(vacancy) => {
            vacancy.insert(RegistryField::Object {
                flags: flags, data: Arc::new(json)
            });
            Ok(None)
        },
        Entry::Occupied(mut entry) => {
            let first_type = entry.get().get_type();
            if first_type == FieldType::Object {
                entry.insert(RegistryField::Object {
                    flags: flags, data: Arc::new(json)
                });
                Ok(None)
            }
            else if first_type == FieldType::Property {
                Ok(Some((json, entry.get().clone().as_property_set()
                   .expect("set_json_property: checked value of field type"))))
            }
            else {
                Err(RegistryError::WrongKeyType)
            }
        }
    }
}

/// Binds properties to a field of the registry
#[allow(dead_code)]
pub fn set_property_field(key: String, get_fn: Option<GetFn>, set_fn: Option<SetFn>)
                          -> RegistryResult<Option<RegistryField>> {
    set_field(key, RegistryField::Property { get: get_fn, set: set_fn })
}

/// Whether this map contains a key of any type
#[allow(dead_code)]
pub fn contains_key<K>(key: &K) -> bool
where String: Borrow<K>, K: Hash + Eq + Display {
    trace!("contains_key: {}", *key);
    let read_reg = read_lock();
    read_reg.contains_key(key)
}

/// Whether the registry contains a key of some type:
/// None: no key
/// true: same type key
/// false: different type key
#[allow(dead_code)]
pub fn contains_key_of<K>(key: &K, field_type: FieldType) -> Option<bool>
where String: Borrow<K>, K: Hash + Eq + Display {
    let read_reg = read_lock();
    read_reg.get(key).map(|field| field.get_type() == field_type)
}
<|endoftext|>


<commit_before>// run-rustfix
#![allow(unreachable_code)]
#![allow(clippy::unnecessary_wraps)]

fn some_func(a: Option<u32>) -> Option<u32> {
    if a.is_none() {
        return None;
    }

    a
}

fn some_other_func(a: Option<u32>) -> Option<u32> {
    if a.is_none() {
        return None;
    } else {
        return Some(0);
    }
    unreachable!()
}

pub enum SeemsOption<T> {
    Some(T),
    None,
}

impl<T> SeemsOption<T> {
    pub fn is_none(&self) -> bool {
        match *self {
            SeemsOption::None => true,
            SeemsOption::Some(_) => false,
        }
    }
}

fn returns_something_similar_to_option(a: SeemsOption<u32>) -> SeemsOption<u32> {
    if a.is_none() {
        return SeemsOption::None;
    }

    a
}

pub struct CopyStruct {
    pub opt: Option<u32>,
}

impl CopyStruct {
    #[rustfmt::skip]
    pub fn func(&self) -> Option<u32> {
        if (self.opt).is_none() {
            return None;
        }

        if self.opt.is_none() {
            return None
        }

        let _ = if self.opt.is_none() {
            return None;
        } else {
            self.opt
        };

        let _ = if let Some(x) = self.opt {
            x
        } else {
            return None;
        };

        self.opt
    }
}

#[derive(Clone)]
pub struct MoveStruct {
    pub opt: Option<Vec<u32>>,
}

impl MoveStruct {
    pub fn ref_func(&self) -> Option<Vec<u32>> {
        if self.opt.is_none() {
            return None;
        }

        self.opt.clone()
    }

    pub fn mov_func_reuse(self) -> Option<Vec<u32>> {
        if self.opt.is_none() {
            return None;
        }

        self.opt
    }

    pub fn mov_func_no_use(self) -> Option<Vec<u32>> {
        if self.opt.is_none() {
            return None;
        }
        Some(Vec::new())
    }

    pub fn if_let_ref_func(self) -> Option<Vec<u32>> {
        let v: &Vec<_> = if let Some(ref v) = self.opt {
            v
        } else {
            return None;
        };

        Some(v.clone())
    }

    pub fn if_let_mov_func(self) -> Option<Vec<u32>> {
        let v = if let Some(v) = self.opt {
            v
        } else {
            return None;
        };

        Some(v)
    }
}

fn func() -> Option<i32> {
    fn f() -> Option<String> {
        Some(String::new())
    }

    if f().is_none() {
        return None;
    }

    Some(0)
}

fn result_func(x: Result<i32, &str>) -> Result<i32, &str> {
    let _ = if let Ok(x) = x { x } else { return x };

    if x.is_err() {
        return x;
    }

    // No warning
    let y = if let Ok(x) = x {
        x
    } else {
        return Err("some error");
    };

    Ok(y)
}

fn main() {
    some_func(Some(42));
    some_func(None);
    some_other_func(Some(42));

    let copy_struct = CopyStruct { opt: Some(54) };
    copy_struct.func();

    let move_struct = MoveStruct {
        opt: Some(vec![42, 1337]),
    };
    move_struct.ref_func();
    move_struct.clone().mov_func_reuse();
    move_struct.mov_func_no_use();

    let so = SeemsOption::Some(45);
    returns_something_similar_to_option(so);

    func();

    let _ = result_func(Ok(42));
}
<commit_msg>Add #7859 FP test case for `question_mark`<commit_after>// run-rustfix
#![allow(unreachable_code)]
#![allow(clippy::unnecessary_wraps)]

use std::env;
use std::path::PathBuf;

fn some_func(a: Option<u32>) -> Option<u32> {
    if a.is_none() {
        return None;
    }

    a
}

fn some_other_func(a: Option<u32>) -> Option<u32> {
    if a.is_none() {
        return None;
    } else {
        return Some(0);
    }
    unreachable!()
}

pub enum SeemsOption<T> {
    Some(T),
    None,
}

impl<T> SeemsOption<T> {
    pub fn is_none(&self) -> bool {
        match *self {
            SeemsOption::None => true,
            SeemsOption::Some(_) => false,
        }
    }
}

fn returns_something_similar_to_option(a: SeemsOption<u32>) -> SeemsOption<u32> {
    if a.is_none() {
        return SeemsOption::None;
    }

    a
}

pub struct CopyStruct {
    pub opt: Option<u32>,
}

impl CopyStruct {
    #[rustfmt::skip]
    pub fn func(&self) -> Option<u32> {
        if (self.opt).is_none() {
            return None;
        }

        if self.opt.is_none() {
            return None
        }

        let _ = if self.opt.is_none() {
            return None;
        } else {
            self.opt
        };

        let _ = if let Some(x) = self.opt {
            x
        } else {
            return None;
        };

        self.opt
    }
}

#[derive(Clone)]
pub struct MoveStruct {
    pub opt: Option<Vec<u32>>,
}

impl MoveStruct {
    pub fn ref_func(&self) -> Option<Vec<u32>> {
        if self.opt.is_none() {
            return None;
        }

        self.opt.clone()
    }

    pub fn mov_func_reuse(self) -> Option<Vec<u32>> {
        if self.opt.is_none() {
            return None;
        }

        self.opt
    }

    pub fn mov_func_no_use(self) -> Option<Vec<u32>> {
        if self.opt.is_none() {
            return None;
        }
        Some(Vec::new())
    }

    pub fn if_let_ref_func(self) -> Option<Vec<u32>> {
        let v: &Vec<_> = if let Some(ref v) = self.opt {
            v
        } else {
            return None;
        };

        Some(v.clone())
    }

    pub fn if_let_mov_func(self) -> Option<Vec<u32>> {
        let v = if let Some(v) = self.opt {
            v
        } else {
            return None;
        };

        Some(v)
    }
}

fn func() -> Option<i32> {
    fn f() -> Option<String> {
        Some(String::new())
    }

    if f().is_none() {
        return None;
    }

    Some(0)
}

fn func_returning_result() -> Result<i32, String> {
    Ok(1)
}

fn result_func(x: Result<i32, String>) -> Result<i32, String> {
    let _ = if let Ok(x) = x { x } else { return x };

    if x.is_err() {
        return x;
    }

    // No warning
    let y = if let Ok(x) = x {
        x
    } else {
        return Err("some error".to_string());
    };

    // issue #7859
    // no warning
    let _ = if let Ok(x) = func_returning_result() {
        x
    } else {
        return Err("some error".to_string());
    };

    if func_returning_result().is_err() {
        return func_returning_result();
    }

    Ok(y)
}

fn main() {
    some_func(Some(42));
    some_func(None);
    some_other_func(Some(42));

    let copy_struct = CopyStruct { opt: Some(54) };
    copy_struct.func();

    let move_struct = MoveStruct {
        opt: Some(vec![42, 1337]),
    };
    move_struct.ref_func();
    move_struct.clone().mov_func_reuse();
    move_struct.mov_func_no_use();

    let so = SeemsOption::Some(45);
    returns_something_similar_to_option(so);

    func();

    let _ = result_func(Ok(42));
}
<|endoftext|>


<commit_before>pub const RUNTIME: &'static str = r#"
#include "ruby.h"
#include <stdbool.h>

static VALUE escape_html(VALUE value) {
    VALUE cgi = rb_const_get(rb_cObject, rb_intern("CGI"));
    return rb_funcall(cgi, rb_intern("escapeHTML"), 1, value);
}

static VALUE fetch(VALUE context, VALUE key) {
    switch (rb_type(context)) {
        case T_HASH:
            return rb_hash_aref(context, key);
        case T_STRUCT:
            // TODO Check rb_struct_members to avoid name error.
            return rb_struct_aref(context, key);
        case T_OBJECT:
            // TODO Prevent undefined method error and check arity.
            return rb_funcall(context, rb_to_id(key), 0);
        default:
            return Qundef;
    }
}

static VALUE context_fetch(VALUE stack, VALUE key) {
    for (long i = RARRAY_LEN(stack) - 1; i >= 0; i--) {
        VALUE context = rb_ary_entry(stack, i);
        VALUE value = fetch(context, key);
        if (value != Qundef) {
            return value;
        }
    }
    return Qnil;
}

static VALUE fetch_path(VALUE stack, VALUE path) {
    VALUE value = context_fetch(stack, rb_ary_entry(path, 0));
    if (value == Qnil) {
        return Qnil;
    }
    for (long i = 1; i < RARRAY_LEN(path); i++) {
        value = fetch(value, rb_ary_entry(path, i));
        if (value == Qundef) {
            return Qnil;
        }
    }
    return value;
}

static void append_value(VALUE buf, VALUE stack, VALUE path, bool escape) {
    VALUE value = fetch_path(stack, path);
    switch (rb_type(value)) {
        case T_STRING:
            if (escape) {
                value = escape_html(value);
            }
            rb_str_buf_append(buf, value);
            break;
        case T_NIL:
        case T_UNDEF:
            break;
        default:
            value = rb_any_to_s(value);
            rb_str_buf_append(buf, value);
            break;
    }
}

static void section(VALUE buf, VALUE stack, VALUE path, void (*block)(VALUE, VALUE)) {
    VALUE value = context_fetch(stack, path);
    switch (rb_type(value)) {
        case T_ARRAY:
            for (long i = 0; i < RARRAY_LEN(value); i++) {
                rb_ary_push(stack, rb_ary_entry(value, i));
                block(buf, stack);
                rb_ary_pop(stack);
            }
            break;
        case T_OBJECT:
        case T_STRUCT:
            rb_ary_push(stack, value);
            block(buf, stack);
            rb_ary_pop(stack);
            break;
        case T_NIL:
        case T_UNDEF:
        case T_FALSE:
            break;
        default:
            block(buf, stack);
            break;
    }
}

static void inverted(VALUE buf, VALUE stack, VALUE path, void (*block)(VALUE, VALUE)) {
    VALUE value = context_fetch(stack, path);
    switch (rb_type(value)) {
        case T_ARRAY:
            if (RARRAY_LEN(value) == 0) {
                block(buf, stack);
            }
            break;
        case T_NIL:
        case T_UNDEF:
        case T_FALSE:
            block(buf, stack);
            break;
    }
}
"#;
<commit_msg>Call to_s to convert to String values<commit_after>pub const RUNTIME: &'static str = r#"
#include "ruby.h"
#include <stdbool.h>

static VALUE escape_html(VALUE value) {
    VALUE cgi = rb_const_get(rb_cObject, rb_intern("CGI"));
    return rb_funcall(cgi, rb_intern("escapeHTML"), 1, value);
}

static VALUE fetch(VALUE context, VALUE key) {
    switch (rb_type(context)) {
        case T_HASH:
            return rb_hash_aref(context, key);
        case T_STRUCT:
            // TODO Check rb_struct_members to avoid name error.
            return rb_struct_aref(context, key);
        case T_OBJECT:
            // TODO Prevent undefined method error and check arity.
            return rb_funcall(context, rb_to_id(key), 0);
        default:
            return Qundef;
    }
}

static VALUE context_fetch(VALUE stack, VALUE key) {
    for (long i = RARRAY_LEN(stack) - 1; i >= 0; i--) {
        VALUE context = rb_ary_entry(stack, i);
        VALUE value = fetch(context, key);
        if (value != Qundef) {
            return value;
        }
    }
    return Qnil;
}

static VALUE fetch_path(VALUE stack, VALUE path) {
    VALUE value = context_fetch(stack, rb_ary_entry(path, 0));
    if (value == Qnil) {
        return Qnil;
    }
    for (long i = 1; i < RARRAY_LEN(path); i++) {
        value = fetch(value, rb_ary_entry(path, i));
        if (value == Qundef) {
            return Qnil;
        }
    }
    return value;
}

static void append_value(VALUE buf, VALUE stack, VALUE path, bool escape) {
    VALUE value = fetch_path(stack, path);
    switch (rb_type(value)) {
        case T_NIL:
        case T_UNDEF:
            return;
        case T_STRING:
            break;
        default:
            value = rb_funcall(value, rb_intern("to_s"), 0);
            break;
    }
    rb_str_buf_append(buf, escape ? escape_html(value) : value);
}

static void section(VALUE buf, VALUE stack, VALUE path, void (*block)(VALUE, VALUE)) {
    VALUE value = context_fetch(stack, path);
    switch (rb_type(value)) {
        case T_ARRAY:
            for (long i = 0; i < RARRAY_LEN(value); i++) {
                rb_ary_push(stack, rb_ary_entry(value, i));
                block(buf, stack);
                rb_ary_pop(stack);
            }
            break;
        case T_OBJECT:
        case T_STRUCT:
            rb_ary_push(stack, value);
            block(buf, stack);
            rb_ary_pop(stack);
            break;
        case T_NIL:
        case T_UNDEF:
        case T_FALSE:
            break;
        default:
            block(buf, stack);
            break;
    }
}

static void inverted(VALUE buf, VALUE stack, VALUE path, void (*block)(VALUE, VALUE)) {
    VALUE value = context_fetch(stack, path);
    switch (rb_type(value)) {
        case T_ARRAY:
            if (RARRAY_LEN(value) == 0) {
                block(buf, stack);
            }
            break;
        case T_NIL:
        case T_UNDEF:
        case T_FALSE:
            block(buf, stack);
            break;
    }
}
"#;
<|endoftext|>


<commit_before>export fold;
export fold_crate, fold_mod, fold_fn;
export default_seq_fold;
export default_seq_fold_crate;
export default_seq_fold_item;
export default_seq_fold_mod;
export default_seq_fold_fn;
export default_seq_fold_const;
export default_seq_fold_enum;
export default_seq_fold_res;
export default_seq_fold_iface;
export default_seq_fold_impl;
export default_seq_fold_type;
export default_par_fold;
export default_par_fold_mod;
export default_any_fold;
export default_any_fold_mod;

enum fold<T> = t<T>;

type fold_crate<T> = fn~(fold: fold<T>, doc: doc::cratedoc) -> doc::cratedoc;
type fold_item<T> = fn~(fold: fold<T>, doc: doc::itemdoc) -> doc::itemdoc;
type fold_mod<T> = fn~(fold: fold<T>, doc: doc::moddoc) -> doc::moddoc;
type fold_fn<T> = fn~(fold: fold<T>, doc: doc::fndoc) -> doc::fndoc;
type fold_const<T> = fn~(fold: fold<T>, doc: doc::constdoc) -> doc::constdoc;
type fold_enum<T> = fn~(fold: fold<T>, doc: doc::enumdoc) -> doc::enumdoc;
type fold_res<T> = fn~(fold: fold<T>, doc: doc::resdoc) -> doc::resdoc;
type fold_iface<T> = fn~(fold: fold<T>, doc: doc::ifacedoc) -> doc::ifacedoc;
type fold_impl<T> = fn~(fold: fold<T>, doc: doc::impldoc) -> doc::impldoc;
type fold_type<T> = fn~(fold: fold<T>, doc: doc::tydoc) -> doc::tydoc;

type t<T> = {
    ctxt: T,
    fold_crate: fold_crate<T>,
    fold_item: fold_item<T>,
    fold_mod: fold_mod<T>,
    fold_fn: fold_fn<T>,
    fold_const: fold_const<T>,
    fold_enum: fold_enum<T>,
    fold_res: fold_res<T>,
    fold_iface: fold_iface<T>,
    fold_impl: fold_impl<T>,
    fold_type: fold_type<T>
};

// This exists because fn types don't infer correctly as record
// initializers, but they do as function arguments
fn mk_fold<T:copy>(
    ctxt: T,
    fold_crate: fold_crate<T>,
    fold_item: fold_item<T>,
    fold_mod: fold_mod<T>,
    fold_fn: fold_fn<T>,
    fold_const: fold_const<T>,
    fold_enum: fold_enum<T>,
    fold_res: fold_res<T>,
    fold_iface: fold_iface<T>,
    fold_impl: fold_impl<T>,
    fold_type: fold_type<T>
) -> fold<T> {
    fold({
        ctxt: ctxt,
        fold_crate: fold_crate,
        fold_item: fold_item,
        fold_mod: fold_mod,
        fold_fn: fold_fn,
        fold_const: fold_const,
        fold_enum: fold_enum,
        fold_res: fold_res,
        fold_iface: fold_iface,
        fold_impl: fold_impl,
        fold_type: fold_type
    })
}

fn default_seq_fold<T:copy>(ctxt: T) -> fold<T> {
    mk_fold(
        ctxt,
        {|f, d| default_seq_fold_crate(f, d)},
        {|f, d| default_seq_fold_item(f, d)},
        {|f, d| default_seq_fold_mod(f, d)},
        {|f, d| default_seq_fold_fn(f, d)},
        {|f, d| default_seq_fold_const(f, d)},
        {|f, d| default_seq_fold_enum(f, d)},
        {|f, d| default_seq_fold_res(f, d)},
        {|f, d| default_seq_fold_iface(f, d)},
        {|f, d| default_seq_fold_impl(f, d)},
        {|f, d| default_seq_fold_type(f, d)}
    )
}

fn default_par_fold<T:send>(ctxt: T) -> fold<T> {
    mk_fold(
        ctxt,
        {|f, d| default_seq_fold_crate(f, d)},
        {|f, d| default_seq_fold_item(f, d)},
        {|f, d| default_par_fold_mod(f, d)},
        {|f, d| default_seq_fold_fn(f, d)},
        {|f, d| default_seq_fold_const(f, d)},
        {|f, d| default_seq_fold_enum(f, d)},
        {|f, d| default_seq_fold_res(f, d)},
        {|f, d| default_seq_fold_iface(f, d)},
        {|f, d| default_seq_fold_impl(f, d)},
        {|f, d| default_seq_fold_type(f, d)}
    )
}

// Just a convenient wrapper to convert back and forth between
// parallel and sequential folds for perf testing
fn default_any_fold<T:send>(ctxt: T) -> fold<T> {
    default_par_fold(ctxt)
}

fn default_seq_fold_crate<T>(
    fold: fold<T>,
    doc: doc::cratedoc
) -> doc::cratedoc {
    {
        topmod: fold.fold_mod(fold, doc.topmod)
    }
}

fn default_seq_fold_item<T>(
    _fold: fold<T>,
    doc: doc::itemdoc
) -> doc::itemdoc {
    doc
}

fn default_seq_fold_mod<T>(
    fold: fold<T>,
    doc: doc::moddoc
) -> doc::moddoc {
    {
        item: fold.fold_item(fold, doc.item),
        items: ~vec::map(*doc.items) {|itemtag|
            fold_itemtag(fold, itemtag)
        }
        with doc
    }
}

fn default_par_fold_mod<T:send>(
    fold: fold<T>,
    doc: doc::moddoc
) -> doc::moddoc {
    {
        item: fold.fold_item(fold, doc.item),
        items: ~util::parmap(*doc.items) {|itemtag|
            fold_itemtag(fold, itemtag)
        }
        with doc
    }
}

fn default_any_fold_mod<T:send>(
    fold: fold<T>,
    doc: doc::moddoc
) -> doc::moddoc {
    default_par_fold_mod(fold, doc)
}

fn fold_itemtag<T>(fold: fold<T>, doc: doc::itemtag) -> doc::itemtag {
    alt doc {
      doc::modtag(moddoc) {
        doc::modtag(fold.fold_mod(fold, moddoc))
      }
      doc::fntag(fndoc) {
        doc::fntag(fold.fold_fn(fold, fndoc))
      }
      doc::consttag(constdoc) {
        doc::consttag(fold.fold_const(fold, constdoc))
      }
      doc::enumtag(enumdoc) {
        doc::enumtag(fold.fold_enum(fold, enumdoc))
      }
      doc::restag(resdoc) {
        doc::restag(fold.fold_res(fold, resdoc))
      }
      doc::ifacetag(ifacedoc) {
        doc::ifacetag(fold.fold_iface(fold, ifacedoc))
      }
      doc::impltag(impldoc) {
        doc::impltag(fold.fold_impl(fold, impldoc))
      }
      doc::tytag(tydoc) {
        doc::tytag(fold.fold_type(fold, tydoc))
      }
    }
}

fn default_seq_fold_fn<T>(
    fold: fold<T>,
    doc: doc::fndoc
) -> doc::fndoc {
    {
        item: fold.fold_item(fold, doc.item)
        with doc
    }
}

fn default_seq_fold_const<T>(
    fold: fold<T>,
    doc: doc::constdoc
) -> doc::constdoc {
    {
        item: fold.fold_item(fold, doc.item)
        with doc
    }
}

fn default_seq_fold_enum<T>(
    fold: fold<T>,
    doc: doc::enumdoc
) -> doc::enumdoc {
    {
        item: fold.fold_item(fold, doc.item)
        with doc
    }
}

fn default_seq_fold_res<T>(
    fold: fold<T>,
    doc: doc::resdoc
) -> doc::resdoc {
    {
        item: fold.fold_item(fold, doc.item)
        with doc
    }
}

fn default_seq_fold_iface<T>(
    fold: fold<T>,
    doc: doc::ifacedoc
) -> doc::ifacedoc {
    {
        item: fold.fold_item(fold, doc.item)
        with doc
    }
}

fn default_seq_fold_impl<T>(
    fold: fold<T>,
    doc: doc::impldoc
) -> doc::impldoc {
    {
        item: fold.fold_item(fold, doc.item)
        with doc
    }
}

fn default_seq_fold_type<T>(
    fold: fold<T>,
    doc: doc::tydoc
) -> doc::tydoc {
    {
        item: fold.fold_item(fold, doc.item)
        with doc
    }
}

#[test]
fn default_fold_should_produce_same_doc() {
    let source = "mod a { fn b() { } mod c { fn d() { } } }";
    let ast = parse::from_str(source);
    let doc = extract::extract(ast, "");
    let fld = default_seq_fold(());
    let folded = fld.fold_crate(fld, doc);
    assert doc == folded;
}

#[test]
fn default_fold_should_produce_same_consts() {
    let source = "const a: int = 0;";
    let ast = parse::from_str(source);
    let doc = extract::extract(ast, "");
    let fld = default_seq_fold(());
    let folded = fld.fold_crate(fld, doc);
    assert doc == folded;
}

#[test]
fn default_fold_should_produce_same_enums() {
    let source = "enum a { b }";
    let ast = parse::from_str(source);
    let doc = extract::extract(ast, "");
    let fld = default_seq_fold(());
    let folded = fld.fold_crate(fld, doc);
    assert doc == folded;
}

#[test]
fn default_parallel_fold_should_produce_same_doc() {
    let source = "mod a { fn b() { } mod c { fn d() { } } }";
    let ast = parse::from_str(source);
    let doc = extract::extract(ast, "");
    let fld = default_par_fold(());
    let folded = fld.fold_crate(fld, doc);
    assert doc == folded;
}
<commit_msg>rustdoc: Turn off parallel folding until I figure out what's wrong on OS X<commit_after>export fold;
export fold_crate, fold_mod, fold_fn;
export default_seq_fold;
export default_seq_fold_crate;
export default_seq_fold_item;
export default_seq_fold_mod;
export default_seq_fold_fn;
export default_seq_fold_const;
export default_seq_fold_enum;
export default_seq_fold_res;
export default_seq_fold_iface;
export default_seq_fold_impl;
export default_seq_fold_type;
export default_par_fold;
export default_par_fold_mod;
export default_any_fold;
export default_any_fold_mod;

enum fold<T> = t<T>;

type fold_crate<T> = fn~(fold: fold<T>, doc: doc::cratedoc) -> doc::cratedoc;
type fold_item<T> = fn~(fold: fold<T>, doc: doc::itemdoc) -> doc::itemdoc;
type fold_mod<T> = fn~(fold: fold<T>, doc: doc::moddoc) -> doc::moddoc;
type fold_fn<T> = fn~(fold: fold<T>, doc: doc::fndoc) -> doc::fndoc;
type fold_const<T> = fn~(fold: fold<T>, doc: doc::constdoc) -> doc::constdoc;
type fold_enum<T> = fn~(fold: fold<T>, doc: doc::enumdoc) -> doc::enumdoc;
type fold_res<T> = fn~(fold: fold<T>, doc: doc::resdoc) -> doc::resdoc;
type fold_iface<T> = fn~(fold: fold<T>, doc: doc::ifacedoc) -> doc::ifacedoc;
type fold_impl<T> = fn~(fold: fold<T>, doc: doc::impldoc) -> doc::impldoc;
type fold_type<T> = fn~(fold: fold<T>, doc: doc::tydoc) -> doc::tydoc;

type t<T> = {
    ctxt: T,
    fold_crate: fold_crate<T>,
    fold_item: fold_item<T>,
    fold_mod: fold_mod<T>,
    fold_fn: fold_fn<T>,
    fold_const: fold_const<T>,
    fold_enum: fold_enum<T>,
    fold_res: fold_res<T>,
    fold_iface: fold_iface<T>,
    fold_impl: fold_impl<T>,
    fold_type: fold_type<T>
};

// This exists because fn types don't infer correctly as record
// initializers, but they do as function arguments
fn mk_fold<T:copy>(
    ctxt: T,
    fold_crate: fold_crate<T>,
    fold_item: fold_item<T>,
    fold_mod: fold_mod<T>,
    fold_fn: fold_fn<T>,
    fold_const: fold_const<T>,
    fold_enum: fold_enum<T>,
    fold_res: fold_res<T>,
    fold_iface: fold_iface<T>,
    fold_impl: fold_impl<T>,
    fold_type: fold_type<T>
) -> fold<T> {
    fold({
        ctxt: ctxt,
        fold_crate: fold_crate,
        fold_item: fold_item,
        fold_mod: fold_mod,
        fold_fn: fold_fn,
        fold_const: fold_const,
        fold_enum: fold_enum,
        fold_res: fold_res,
        fold_iface: fold_iface,
        fold_impl: fold_impl,
        fold_type: fold_type
    })
}

fn default_seq_fold<T:copy>(ctxt: T) -> fold<T> {
    mk_fold(
        ctxt,
        {|f, d| default_seq_fold_crate(f, d)},
        {|f, d| default_seq_fold_item(f, d)},
        {|f, d| default_seq_fold_mod(f, d)},
        {|f, d| default_seq_fold_fn(f, d)},
        {|f, d| default_seq_fold_const(f, d)},
        {|f, d| default_seq_fold_enum(f, d)},
        {|f, d| default_seq_fold_res(f, d)},
        {|f, d| default_seq_fold_iface(f, d)},
        {|f, d| default_seq_fold_impl(f, d)},
        {|f, d| default_seq_fold_type(f, d)}
    )
}

fn default_par_fold<T:send>(ctxt: T) -> fold<T> {
    mk_fold(
        ctxt,
        {|f, d| default_seq_fold_crate(f, d)},
        {|f, d| default_seq_fold_item(f, d)},
        {|f, d| default_par_fold_mod(f, d)},
        {|f, d| default_seq_fold_fn(f, d)},
        {|f, d| default_seq_fold_const(f, d)},
        {|f, d| default_seq_fold_enum(f, d)},
        {|f, d| default_seq_fold_res(f, d)},
        {|f, d| default_seq_fold_iface(f, d)},
        {|f, d| default_seq_fold_impl(f, d)},
        {|f, d| default_seq_fold_type(f, d)}
    )
}

// Just a convenient wrapper to convert back and forth between
// parallel and sequential folds for perf testing
fn default_any_fold<T:send>(ctxt: T) -> fold<T> {
    default_seq_fold(ctxt)
}

fn default_seq_fold_crate<T>(
    fold: fold<T>,
    doc: doc::cratedoc
) -> doc::cratedoc {
    {
        topmod: fold.fold_mod(fold, doc.topmod)
    }
}

fn default_seq_fold_item<T>(
    _fold: fold<T>,
    doc: doc::itemdoc
) -> doc::itemdoc {
    doc
}

fn default_seq_fold_mod<T>(
    fold: fold<T>,
    doc: doc::moddoc
) -> doc::moddoc {
    {
        item: fold.fold_item(fold, doc.item),
        items: ~vec::map(*doc.items) {|itemtag|
            fold_itemtag(fold, itemtag)
        }
        with doc
    }
}

fn default_par_fold_mod<T:send>(
    fold: fold<T>,
    doc: doc::moddoc
) -> doc::moddoc {
    {
        item: fold.fold_item(fold, doc.item),
        items: ~util::parmap(*doc.items) {|itemtag|
            fold_itemtag(fold, itemtag)
        }
        with doc
    }
}

fn default_any_fold_mod<T:send>(
    fold: fold<T>,
    doc: doc::moddoc
) -> doc::moddoc {
    default_seq_fold_mod(fold, doc)
}

fn fold_itemtag<T>(fold: fold<T>, doc: doc::itemtag) -> doc::itemtag {
    alt doc {
      doc::modtag(moddoc) {
        doc::modtag(fold.fold_mod(fold, moddoc))
      }
      doc::fntag(fndoc) {
        doc::fntag(fold.fold_fn(fold, fndoc))
      }
      doc::consttag(constdoc) {
        doc::consttag(fold.fold_const(fold, constdoc))
      }
      doc::enumtag(enumdoc) {
        doc::enumtag(fold.fold_enum(fold, enumdoc))
      }
      doc::restag(resdoc) {
        doc::restag(fold.fold_res(fold, resdoc))
      }
      doc::ifacetag(ifacedoc) {
        doc::ifacetag(fold.fold_iface(fold, ifacedoc))
      }
      doc::impltag(impldoc) {
        doc::impltag(fold.fold_impl(fold, impldoc))
      }
      doc::tytag(tydoc) {
        doc::tytag(fold.fold_type(fold, tydoc))
      }
    }
}

fn default_seq_fold_fn<T>(
    fold: fold<T>,
    doc: doc::fndoc
) -> doc::fndoc {
    {
        item: fold.fold_item(fold, doc.item)
        with doc
    }
}

fn default_seq_fold_const<T>(
    fold: fold<T>,
    doc: doc::constdoc
) -> doc::constdoc {
    {
        item: fold.fold_item(fold, doc.item)
        with doc
    }
}

fn default_seq_fold_enum<T>(
    fold: fold<T>,
    doc: doc::enumdoc
) -> doc::enumdoc {
    {
        item: fold.fold_item(fold, doc.item)
        with doc
    }
}

fn default_seq_fold_res<T>(
    fold: fold<T>,
    doc: doc::resdoc
) -> doc::resdoc {
    {
        item: fold.fold_item(fold, doc.item)
        with doc
    }
}

fn default_seq_fold_iface<T>(
    fold: fold<T>,
    doc: doc::ifacedoc
) -> doc::ifacedoc {
    {
        item: fold.fold_item(fold, doc.item)
        with doc
    }
}

fn default_seq_fold_impl<T>(
    fold: fold<T>,
    doc: doc::impldoc
) -> doc::impldoc {
    {
        item: fold.fold_item(fold, doc.item)
        with doc
    }
}

fn default_seq_fold_type<T>(
    fold: fold<T>,
    doc: doc::tydoc
) -> doc::tydoc {
    {
        item: fold.fold_item(fold, doc.item)
        with doc
    }
}

#[test]
fn default_fold_should_produce_same_doc() {
    let source = "mod a { fn b() { } mod c { fn d() { } } }";
    let ast = parse::from_str(source);
    let doc = extract::extract(ast, "");
    let fld = default_seq_fold(());
    let folded = fld.fold_crate(fld, doc);
    assert doc == folded;
}

#[test]
fn default_fold_should_produce_same_consts() {
    let source = "const a: int = 0;";
    let ast = parse::from_str(source);
    let doc = extract::extract(ast, "");
    let fld = default_seq_fold(());
    let folded = fld.fold_crate(fld, doc);
    assert doc == folded;
}

#[test]
fn default_fold_should_produce_same_enums() {
    let source = "enum a { b }";
    let ast = parse::from_str(source);
    let doc = extract::extract(ast, "");
    let fld = default_seq_fold(());
    let folded = fld.fold_crate(fld, doc);
    assert doc == folded;
}

#[test]
fn default_parallel_fold_should_produce_same_doc() {
    let source = "mod a { fn b() { } mod c { fn d() { } } }";
    let ast = parse::from_str(source);
    let doc = extract::extract(ast, "");
    let fld = default_par_fold(());
    let folded = fld.fold_crate(fld, doc);
    assert doc == folded;
}
<|endoftext|>


<commit_before>// FIXME: Random import to solve the mystery resolve bug
import std;

export fold;
export fold_crate, fold_mod, fold_fn, fold_modlist, fold_fnlist;
export default_seq_fold;
export default_seq_fold_crate;
export default_seq_fold_mod;
export default_seq_fold_fn;
export default_seq_fold_const;
export default_seq_fold_fnlist;

enum fold<T> = t<T>;

type fold_crate<T> = fn~(fold: fold<T>, doc: doc::cratedoc) -> doc::cratedoc;
type fold_mod<T> = fn~(fold: fold<T>, doc: doc::moddoc) -> doc::moddoc;
type fold_fn<T> = fn~(fold: fold<T>, doc: doc::fndoc) -> doc::fndoc;
type fold_const<T> = fn~(fold: fold<T>, doc: doc::constdoc) -> doc::constdoc;
type fold_modlist<T> = fn~(fold: fold<T>, list: doc::modlist) -> doc::modlist;
type fold_fnlist<T> = fn~(fold: fold<T>, list: doc::fnlist) -> doc::fnlist;
type fold_constlist<T> = fn~(
    fold: fold<T>,
    list: doc::constlist
) -> doc::constlist;

type t<T> = {
    ctxt: T,
    fold_crate: fold_crate<T>,
    fold_mod: fold_mod<T>,
    fold_fn: fold_fn<T>,
    fold_const: fold_const<T>,
    fold_modlist: fold_modlist<T>,
    fold_fnlist: fold_fnlist<T>,
    fold_constlist: fold_constlist<T>
};

// This exists because fn types don't infer correctly as record
// initializers, but they do as function arguments
fn mk_fold<T:copy>(
    ctxt: T,
    fold_crate: fold_crate<T>,
    fold_mod: fold_mod<T>,
    fold_fn: fold_fn<T>,
    fold_const: fold_const<T>,
    fold_modlist: fold_modlist<T>,
    fold_fnlist: fold_fnlist<T>,
    fold_constlist: fold_constlist<T>
) -> fold<T> {
    fold({
        ctxt: ctxt,
        fold_crate: fold_crate,
        fold_mod: fold_mod,
        fold_fn: fold_fn,
        fold_const: fold_const,
        fold_modlist: fold_modlist,
        fold_fnlist: fold_fnlist,
        fold_constlist: fold_constlist
    })
}

fn default_seq_fold<T:copy>(ctxt: T) -> fold<T> {
    mk_fold(
        ctxt,
        {|f, d| default_seq_fold_crate(f, d)},
        {|f, d| default_seq_fold_mod(f, d)},
        {|f, d| default_seq_fold_fn(f, d)},
        {|f, d| default_seq_fold_const(f, d)},
        {|f, d| default_seq_fold_modlist(f, d)},
        {|f, d| default_seq_fold_fnlist(f, d)},
        {|f, d| default_seq_fold_constlist(f, d)}
    )
}

fn default_seq_fold_crate<T>(
    fold: fold<T>,
    doc: doc::cratedoc
) -> doc::cratedoc {
    ~{
        topmod: fold.fold_mod(fold, doc.topmod)
    }
}

fn default_seq_fold_mod<T>(
    fold: fold<T>,
    doc: doc::moddoc
) -> doc::moddoc {
    ~{
        mods: fold.fold_modlist(fold, doc.mods),
        fns: fold.fold_fnlist(fold, doc.fns),
        consts: fold.fold_constlist(fold, doc.consts)
        with *doc
    }
}

fn default_seq_fold_fn<T>(
    _fold: fold<T>,
    doc: doc::fndoc
) -> doc::fndoc {
    doc
}

fn default_seq_fold_const<T>(
    _fold: fold<T>,
    doc: doc::constdoc
) -> doc::constdoc {
    doc
}

fn default_seq_fold_modlist<T>(
    fold: fold<T>,
    list: doc::modlist
) -> doc::modlist {
    doc::modlist(vec::map(*list) {|doc|
        fold.fold_mod(fold, doc)
    })
}

fn default_seq_fold_fnlist<T>(
    fold: fold<T>,
    list: doc::fnlist
) -> doc::fnlist {
    doc::fnlist(vec::map(*list) {|doc|
        fold.fold_fn(fold, doc)
    })
}

fn default_seq_fold_constlist<T>(
    fold: fold<T>,
    list: doc::constlist
) -> doc::constlist {
    doc::constlist(vec::map(*list) {|doc|
        fold.fold_const(fold, doc)
    })
}

#[test]
fn default_fold_should_produce_same_doc() {
    let source = "mod a { fn b() { } mod c { fn d() { } } }";
    let ast = parse::from_str(source);
    let doc = extract::extract(ast, "");
    let fld = default_seq_fold(());
    let folded = fld.fold_crate(fld, doc);
    assert doc == folded;
}

#[test]
fn default_fold_should_produce_same_consts() {
    let source = "const a: int = 0;";
    let ast = parse::from_str(source);
    let doc = extract::extract(ast, "");
    let fld = default_seq_fold(());
    let folded = fld.fold_crate(fld, doc);
    assert doc == folded;
}<commit_msg>rustdoc: Add enum folding<commit_after>// FIXME: Random import to solve the mystery resolve bug
import std;

export fold;
export fold_crate, fold_mod, fold_fn, fold_modlist, fold_fnlist;
export default_seq_fold;
export default_seq_fold_crate;
export default_seq_fold_mod;
export default_seq_fold_fn;
export default_seq_fold_const;
export default_seq_fold_fnlist;

enum fold<T> = t<T>;

type fold_crate<T> = fn~(fold: fold<T>, doc: doc::cratedoc) -> doc::cratedoc;
type fold_mod<T> = fn~(fold: fold<T>, doc: doc::moddoc) -> doc::moddoc;
type fold_fn<T> = fn~(fold: fold<T>, doc: doc::fndoc) -> doc::fndoc;
type fold_const<T> = fn~(fold: fold<T>, doc: doc::constdoc) -> doc::constdoc;
type fold_enum<T> = fn~(fold: fold<T>, doc: doc::enumdoc) -> doc::enumdoc;
type fold_modlist<T> = fn~(fold: fold<T>, list: doc::modlist) -> doc::modlist;
type fold_fnlist<T> = fn~(fold: fold<T>, list: doc::fnlist) -> doc::fnlist;
type fold_constlist<T> = fn~(
    fold: fold<T>, list: doc::constlist) -> doc::constlist;
type fold_enumlist<T> = fn~(
    fold: fold<T>, list: doc::enumlist) -> doc::enumlist;

type t<T> = {
    ctxt: T,
    fold_crate: fold_crate<T>,
    fold_mod: fold_mod<T>,
    fold_fn: fold_fn<T>,
    fold_const: fold_const<T>,
    fold_enum: fold_enum<T>,
    fold_modlist: fold_modlist<T>,
    fold_fnlist: fold_fnlist<T>,
    fold_constlist: fold_constlist<T>,
    fold_enumlist: fold_enumlist<T>
};

// This exists because fn types don't infer correctly as record
// initializers, but they do as function arguments
fn mk_fold<T:copy>(
    ctxt: T,
    fold_crate: fold_crate<T>,
    fold_mod: fold_mod<T>,
    fold_fn: fold_fn<T>,
    fold_const: fold_const<T>,
    fold_enum: fold_enum<T>,
    fold_modlist: fold_modlist<T>,
    fold_fnlist: fold_fnlist<T>,
    fold_constlist: fold_constlist<T>,
    fold_enumlist: fold_enumlist<T>
) -> fold<T> {
    fold({
        ctxt: ctxt,
        fold_crate: fold_crate,
        fold_mod: fold_mod,
        fold_fn: fold_fn,
        fold_const: fold_const,
        fold_enum: fold_enum,
        fold_modlist: fold_modlist,
        fold_fnlist: fold_fnlist,
        fold_constlist: fold_constlist,
        fold_enumlist: fold_enumlist
    })
}

fn default_seq_fold<T:copy>(ctxt: T) -> fold<T> {
    mk_fold(
        ctxt,
        {|f, d| default_seq_fold_crate(f, d)},
        {|f, d| default_seq_fold_mod(f, d)},
        {|f, d| default_seq_fold_fn(f, d)},
        {|f, d| default_seq_fold_const(f, d)},
        {|f, d| default_seq_fold_enum(f, d)},
        {|f, d| default_seq_fold_modlist(f, d)},
        {|f, d| default_seq_fold_fnlist(f, d)},
        {|f, d| default_seq_fold_constlist(f, d)},
        {|f, d| default_seq_fold_enumlist(f, d)}
    )
}

fn default_seq_fold_crate<T>(
    fold: fold<T>,
    doc: doc::cratedoc
) -> doc::cratedoc {
    ~{
        topmod: fold.fold_mod(fold, doc.topmod)
    }
}

fn default_seq_fold_mod<T>(
    fold: fold<T>,
    doc: doc::moddoc
) -> doc::moddoc {
    ~{
        mods: fold.fold_modlist(fold, doc.mods),
        fns: fold.fold_fnlist(fold, doc.fns),
        consts: fold.fold_constlist(fold, doc.consts)
        with *doc
    }
}

fn default_seq_fold_fn<T>(
    _fold: fold<T>,
    doc: doc::fndoc
) -> doc::fndoc {
    doc
}

fn default_seq_fold_const<T>(
    _fold: fold<T>,
    doc: doc::constdoc
) -> doc::constdoc {
    doc
}

fn default_seq_fold_enum<T>(
    _fold: fold<T>,
    doc: doc::enumdoc
) -> doc::enumdoc {
    doc
}

fn default_seq_fold_modlist<T>(
    fold: fold<T>,
    list: doc::modlist
) -> doc::modlist {
    doc::modlist(vec::map(*list) {|doc|
        fold.fold_mod(fold, doc)
    })
}

fn default_seq_fold_fnlist<T>(
    fold: fold<T>,
    list: doc::fnlist
) -> doc::fnlist {
    doc::fnlist(vec::map(*list) {|doc|
        fold.fold_fn(fold, doc)
    })
}

fn default_seq_fold_constlist<T>(
    fold: fold<T>,
    list: doc::constlist
) -> doc::constlist {
    doc::constlist(vec::map(*list) {|doc|
        fold.fold_const(fold, doc)
    })
}

fn default_seq_fold_enumlist<T>(
    fold: fold<T>,
    list: doc::enumlist
) -> doc::enumlist {
    doc::enumlist(vec::map(*list) {|doc|
        fold.fold_enum(fold, doc)
    })
}

#[test]
fn default_fold_should_produce_same_doc() {
    let source = "mod a { fn b() { } mod c { fn d() { } } }";
    let ast = parse::from_str(source);
    let doc = extract::extract(ast, "");
    let fld = default_seq_fold(());
    let folded = fld.fold_crate(fld, doc);
    assert doc == folded;
}

#[test]
fn default_fold_should_produce_same_consts() {
    let source = "const a: int = 0;";
    let ast = parse::from_str(source);
    let doc = extract::extract(ast, "");
    let fld = default_seq_fold(());
    let folded = fld.fold_crate(fld, doc);
    assert doc == folded;
}

#[test]
fn default_fold_should_produce_same_enums() {
    let source = "enum a { b }";
    let ast = parse::from_str(source);
    let doc = extract::extract(ast, "");
    let fld = default_seq_fold(());
    let folded = fld.fold_crate(fld, doc);
    assert doc == folded;
}<|endoftext|>


<commit_before>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Terminfo database interface.

use std::collections::HashMap;
use std::env;
use std::error::Error as ErrorTrait;
use std::fmt;
use std::fs::File;
use std::io::prelude::*;
use std::io;
use std::path::Path;

use Attr;
use color;
use Terminal;
use UnwrappableTerminal;
use self::searcher::get_dbpath_for_term;
use self::parser::compiled::{parse, msys_terminfo};
use self::parm::{expand, Variables, Param};

/// A parsed terminfo database entry.
#[derive(Debug)]
pub struct TermInfo {
    /// Names for the terminal
    pub names: Vec<String> ,
    /// Map of capability name to boolean value
    pub bools: HashMap<String, bool>,
    /// Map of capability name to numeric value
    pub numbers: HashMap<String, u16>,
    /// Map of capability name to raw (unexpanded) string
    pub strings: HashMap<String, Vec<u8> >
}

/// A terminfo creation error.
pub enum Error {
    /// TermUnset Indicates that the environment doesn't include enough information to find
    /// the terminfo entry.
    TermUnset,
    /// MalformedTerminfo indicates that parsing the terminfo entry failed.
    MalformedTerminfo(String),
    /// io::Error forwards any io::Errors encountered when finding or reading the terminfo entry.
    IoError(io::Error),
}

impl ErrorTrait for Error {
    fn description(&self) -> &str { "failed to create TermInfo" }

    fn cause(&self) -> Option<&ErrorTrait> {
        use self::Error::*;
        match self {
            &IoError(ref e) => Some(e),
            _ => None,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;
        match self {
            &TermUnset => Ok(()),
            &MalformedTerminfo(ref e) => e.fmt(f),
            &IoError(ref e) => e.fmt(f),
        }
    }
}

impl TermInfo {
    /// Create a TermInfo based on current environment.
    pub fn from_env() -> Result<TermInfo, Error> {
        let term = match env::var("TERM") {
            Ok(name) => TermInfo::from_name(&name),
            Err(..) => return Err(Error::TermUnset),
        };

        if term.is_err() && env::var("MSYSCON").ok().map_or(false, |s| "mintty.exe" == s) {
            // msys terminal
            Ok(msys_terminfo())
        } else {
            term
        }
    }

    /// Create a TermInfo for the named terminal.
    pub fn from_name(name: &str) -> Result<TermInfo, Error> {
        get_dbpath_for_term(name).ok_or_else(|| {
            Error::IoError(io::Error::new(io::ErrorKind::FileNotFound, "terminfo file not found", None))
        }).and_then(|p| {
            TermInfo::from_path(&p)
        })
    }

    /// Parse the given TermInfo.
    pub fn from_path(path: &Path) -> Result<TermInfo, Error> {
        File::open(path).map_err(|e| {
            Error::IoError(e)
        }).and_then(|ref mut file| {
            parse(file, false).map_err(|e| {
                Error::MalformedTerminfo(e)
            })
        })
    }
}

pub mod searcher;

/// TermInfo format parsing.
pub mod parser {
    //! ncurses-compatible compiled terminfo format parsing (term(5))
    pub mod compiled;
}
pub mod parm;

fn cap_for_attr(attr: Attr) -> &'static str {
    match attr {
        Attr::Bold               => "bold",
        Attr::Dim                => "dim",
        Attr::Italic(true)       => "sitm",
        Attr::Italic(false)      => "ritm",
        Attr::Underline(true)    => "smul",
        Attr::Underline(false)   => "rmul",
        Attr::Blink              => "blink",
        Attr::Standout(true)     => "smso",
        Attr::Standout(false)    => "rmso",
        Attr::Reverse            => "rev",
        Attr::Secure             => "invis",
        Attr::ForegroundColor(_) => "setaf",
        Attr::BackgroundColor(_) => "setab"
    }
}

/// A Terminal that knows how many colors it supports, with a reference to its
/// parsed Terminfo database record.
pub struct TerminfoTerminal<T> {
    num_colors: u16,
    out: T,
    ti: TermInfo,
}

impl<T: Write+Send> Terminal<T> for TerminfoTerminal<T> {
    fn fg(&mut self, color: color::Color) -> io::Result<bool> {
        let color = self.dim_if_necessary(color);
        if self.num_colors > color {
            return self.apply_cap("setaf", &[Param::Number(color as i16)]);
        }
        Ok(false)
    }

    fn bg(&mut self, color: color::Color) -> io::Result<bool> {
        let color = self.dim_if_necessary(color);
        if self.num_colors > color {
            return self.apply_cap("setab", &[Param::Number(color as i16)]);
        }
        Ok(false)
    }

    fn attr(&mut self, attr: Attr) -> io::Result<bool> {
        match attr {
            Attr::ForegroundColor(c) => self.fg(c),
            Attr::BackgroundColor(c) => self.bg(c),
            _ => self.apply_cap(cap_for_attr(attr), &[]),
        }
    }

    fn supports_attr(&self, attr: Attr) -> bool {
        match attr {
            Attr::ForegroundColor(_) | Attr::BackgroundColor(_) => {
                self.num_colors > 0
            }
            _ => {
                let cap = cap_for_attr(attr);
                self.ti.strings.get(cap).is_some()
            }
        }
    }

    fn reset(&mut self) -> io::Result<bool> {
        // are there any terminals that have color/attrs and not sgr0?
        // Try falling back to sgr, then op
        let cmd = match [
            "sg0", "sgr", "op"
        ].iter().filter_map(|cap| {
            self.ti.strings.get(*cap)
        }).next() {
            Some(op) => match expand(&op, &[], &mut Variables::new()) {
                Ok(cmd) => cmd,
                Err(_) => return Ok(false),
            },
            None => return Ok(false),
        };

        self.out.write_all(&cmd).map(|_|true)
    }

    fn get_ref<'a>(&'a self) -> &'a T { &self.out }

    fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.out }
}

impl<T: Write+Send> UnwrappableTerminal<T> for TerminfoTerminal<T> {
    fn unwrap(self) -> T { self.out }
}

impl<T: Write+Send> TerminfoTerminal<T> {
    /// Create a new TerminfoTerminal with the given TermInfo and Write.
    pub fn new_with_terminfo(out: T, terminfo: TermInfo) -> TerminfoTerminal<T> {
        let nc = if terminfo.strings.contains_key("setaf")
                 && terminfo.strings.contains_key("setab") {
                     terminfo.numbers.get("colors").map_or(0, |&n| n)
                 } else { 0 };

        TerminfoTerminal {
            out: out,
            ti: terminfo,
            num_colors: nc,
        }
    }

    /// Create a new TerminfoTerminal for the current environment with the given Write.
    ///
    /// Returns `None` when the terminfo cannot be found or parsed.
    pub fn new(out: T) -> Option<TerminfoTerminal<T>> {
        TermInfo::from_env().map(move |ti| TerminfoTerminal::new_with_terminfo(out, ti)).ok()
    }

    fn dim_if_necessary(&self, color: color::Color) -> color::Color {
        if color >= self.num_colors && color >= 8 && color < 16 {
            color-8
        } else { color }
    }

    fn apply_cap(&mut self, cmd: &str, params: &[Param]) -> io::Result<bool> {
        if let Some(cmd) = self.ti.strings.get(cmd) {
            if let Ok(s) = expand(&cmd, params, &mut Variables::new()) {
                try!(self.out.write_all(&s));
                return Ok(true)
            }
        }
        Ok(false)
    }
}

impl<T: Write> Write for TerminfoTerminal<T> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.out.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.out.flush()
    }
}
<commit_msg>Upgrade to rustc 1.0.0-dev (7f53b943f 2015-03-19)<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Terminfo database interface.

use std::collections::HashMap;
use std::env;
use std::error::Error as ErrorTrait;
use std::fmt;
use std::fs::File;
use std::io::prelude::*;
use std::io;
use std::path::Path;

use Attr;
use color;
use Terminal;
use UnwrappableTerminal;
use self::searcher::get_dbpath_for_term;
use self::parser::compiled::{parse, msys_terminfo};
use self::parm::{expand, Variables, Param};

/// A parsed terminfo database entry.
#[derive(Debug)]
pub struct TermInfo {
    /// Names for the terminal
    pub names: Vec<String> ,
    /// Map of capability name to boolean value
    pub bools: HashMap<String, bool>,
    /// Map of capability name to numeric value
    pub numbers: HashMap<String, u16>,
    /// Map of capability name to raw (unexpanded) string
    pub strings: HashMap<String, Vec<u8> >
}

/// A terminfo creation error.
pub enum Error {
    /// TermUnset Indicates that the environment doesn't include enough information to find
    /// the terminfo entry.
    TermUnset,
    /// MalformedTerminfo indicates that parsing the terminfo entry failed.
    MalformedTerminfo(String),
    /// io::Error forwards any io::Errors encountered when finding or reading the terminfo entry.
    IoError(io::Error),
}

impl ErrorTrait for Error {
    fn description(&self) -> &str { "failed to create TermInfo" }

    fn cause(&self) -> Option<&ErrorTrait> {
        use self::Error::*;
        match self {
            &IoError(ref e) => Some(e),
            _ => None,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;
        match self {
            &TermUnset => Ok(()),
            &MalformedTerminfo(ref e) => e.fmt(f),
            &IoError(ref e) => e.fmt(f),
        }
    }
}

impl TermInfo {
    /// Create a TermInfo based on current environment.
    pub fn from_env() -> Result<TermInfo, Error> {
        let term = match env::var("TERM") {
            Ok(name) => TermInfo::from_name(&name),
            Err(..) => return Err(Error::TermUnset),
        };

        if term.is_err() && env::var("MSYSCON").ok().map_or(false, |s| "mintty.exe" == s) {
            // msys terminal
            Ok(msys_terminfo())
        } else {
            term
        }
    }

    /// Create a TermInfo for the named terminal.
    pub fn from_name(name: &str) -> Result<TermInfo, Error> {
        get_dbpath_for_term(name).ok_or_else(|| {
            Error::IoError(io::Error::new(io::ErrorKind::NotFound, "terminfo file not found", None))
        }).and_then(|p| {
            TermInfo::from_path(&p)
        })
    }

    /// Parse the given TermInfo.
    pub fn from_path(path: &Path) -> Result<TermInfo, Error> {
        File::open(path).map_err(|e| {
            Error::IoError(e)
        }).and_then(|ref mut file| {
            parse(file, false).map_err(|e| {
                Error::MalformedTerminfo(e)
            })
        })
    }
}

pub mod searcher;

/// TermInfo format parsing.
pub mod parser {
    //! ncurses-compatible compiled terminfo format parsing (term(5))
    pub mod compiled;
}
pub mod parm;

fn cap_for_attr(attr: Attr) -> &'static str {
    match attr {
        Attr::Bold               => "bold",
        Attr::Dim                => "dim",
        Attr::Italic(true)       => "sitm",
        Attr::Italic(false)      => "ritm",
        Attr::Underline(true)    => "smul",
        Attr::Underline(false)   => "rmul",
        Attr::Blink              => "blink",
        Attr::Standout(true)     => "smso",
        Attr::Standout(false)    => "rmso",
        Attr::Reverse            => "rev",
        Attr::Secure             => "invis",
        Attr::ForegroundColor(_) => "setaf",
        Attr::BackgroundColor(_) => "setab"
    }
}

/// A Terminal that knows how many colors it supports, with a reference to its
/// parsed Terminfo database record.
pub struct TerminfoTerminal<T> {
    num_colors: u16,
    out: T,
    ti: TermInfo,
}

impl<T: Write+Send> Terminal<T> for TerminfoTerminal<T> {
    fn fg(&mut self, color: color::Color) -> io::Result<bool> {
        let color = self.dim_if_necessary(color);
        if self.num_colors > color {
            return self.apply_cap("setaf", &[Param::Number(color as i16)]);
        }
        Ok(false)
    }

    fn bg(&mut self, color: color::Color) -> io::Result<bool> {
        let color = self.dim_if_necessary(color);
        if self.num_colors > color {
            return self.apply_cap("setab", &[Param::Number(color as i16)]);
        }
        Ok(false)
    }

    fn attr(&mut self, attr: Attr) -> io::Result<bool> {
        match attr {
            Attr::ForegroundColor(c) => self.fg(c),
            Attr::BackgroundColor(c) => self.bg(c),
            _ => self.apply_cap(cap_for_attr(attr), &[]),
        }
    }

    fn supports_attr(&self, attr: Attr) -> bool {
        match attr {
            Attr::ForegroundColor(_) | Attr::BackgroundColor(_) => {
                self.num_colors > 0
            }
            _ => {
                let cap = cap_for_attr(attr);
                self.ti.strings.get(cap).is_some()
            }
        }
    }

    fn reset(&mut self) -> io::Result<bool> {
        // are there any terminals that have color/attrs and not sgr0?
        // Try falling back to sgr, then op
        let cmd = match [
            "sg0", "sgr", "op"
        ].iter().filter_map(|cap| {
            self.ti.strings.get(*cap)
        }).next() {
            Some(op) => match expand(&op, &[], &mut Variables::new()) {
                Ok(cmd) => cmd,
                Err(_) => return Ok(false),
            },
            None => return Ok(false),
        };

        self.out.write_all(&cmd).map(|_|true)
    }

    fn get_ref<'a>(&'a self) -> &'a T { &self.out }

    fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.out }
}

impl<T: Write+Send> UnwrappableTerminal<T> for TerminfoTerminal<T> {
    fn unwrap(self) -> T { self.out }
}

impl<T: Write+Send> TerminfoTerminal<T> {
    /// Create a new TerminfoTerminal with the given TermInfo and Write.
    pub fn new_with_terminfo(out: T, terminfo: TermInfo) -> TerminfoTerminal<T> {
        let nc = if terminfo.strings.contains_key("setaf")
                 && terminfo.strings.contains_key("setab") {
                     terminfo.numbers.get("colors").map_or(0, |&n| n)
                 } else { 0 };

        TerminfoTerminal {
            out: out,
            ti: terminfo,
            num_colors: nc,
        }
    }

    /// Create a new TerminfoTerminal for the current environment with the given Write.
    ///
    /// Returns `None` when the terminfo cannot be found or parsed.
    pub fn new(out: T) -> Option<TerminfoTerminal<T>> {
        TermInfo::from_env().map(move |ti| TerminfoTerminal::new_with_terminfo(out, ti)).ok()
    }

    fn dim_if_necessary(&self, color: color::Color) -> color::Color {
        if color >= self.num_colors && color >= 8 && color < 16 {
            color-8
        } else { color }
    }

    fn apply_cap(&mut self, cmd: &str, params: &[Param]) -> io::Result<bool> {
        if let Some(cmd) = self.ti.strings.get(cmd) {
            if let Ok(s) = expand(&cmd, params, &mut Variables::new()) {
                try!(self.out.write_all(&s));
                return Ok(true)
            }
        }
        Ok(false)
    }
}

impl<T: Write> Write for TerminfoTerminal<T> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.out.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.out.flush()
    }
}
<|endoftext|>


<commit_before>use std::ptr::null;
use libc::c_int;
use utils::_string;
use vector::{ogr, Dataset, Feature, Geometry};

pub struct Layer<'a> {
    _dataset: &'a Dataset,
    c_layer: *const (),
}

impl<'a> Layer<'a> {
    pub unsafe fn _with_dataset(dataset: &'a Dataset, c_layer: *const ()) -> Layer<'a> {
        return Layer{_dataset: dataset, c_layer: c_layer};
    }

    pub fn fields(&'a self) -> FieldIterator<'a> {
        let c_feature_defn = unsafe { ogr::OGR_L_GetLayerDefn(self.c_layer) };
        let total = unsafe { ogr::OGR_FD_GetFieldCount(c_feature_defn) } as isize;
        return FieldIterator{
            layer: self,
            c_feature_defn: c_feature_defn,
            next_id: 0,
            total: total
        };
    }

    pub fn features(&'a self) -> FeatureIterator<'a> {
        return FeatureIterator::_with_layer(self);
    }

    pub fn set_spatial_filter(&'a self, geometry: &Geometry) {
        unsafe { ogr::OGR_L_SetSpatialFilter(self.c_layer, geometry.c_geometry()) };
    }

    pub fn clear_spatial_filter(&'a self) {
        unsafe { ogr::OGR_L_SetSpatialFilter(self.c_layer, null()) };
    }
}

pub struct FieldIterator<'a> {
    layer: &'a Layer<'a>,
    c_feature_defn: *const (),
    next_id: isize,
    total: isize,
}

impl<'a> Iterator for FieldIterator<'a> {
    type Item = Field<'a>;

    #[inline]
    fn next(&mut self) -> Option<Field<'a>> {
        if self.next_id == self.total {
            return None;
        }
        let field = Field{
            _layer: self.layer,
            c_field_defn: unsafe { ogr::OGR_FD_GetFieldDefn(
                self.c_feature_defn,
                self.next_id as c_int
            ) }
        };
        self.next_id += 1;
        return Some(field);
    }
}

pub struct Field<'a> {
    _layer: &'a Layer<'a>,
    c_field_defn: *const (),
}

impl<'a> Field<'a> {
    pub fn name(&'a self) -> String {
        let rv = unsafe { ogr::OGR_Fld_GetNameRef(self.c_field_defn) };
        return _string(rv);
    }
}

pub struct FeatureIterator<'a> {
    layer: &'a Layer<'a>,
}

impl<'a> Iterator for FeatureIterator<'a> {
    type Item = Feature<'a>;

    #[inline]
    fn next(&mut self) -> Option<Feature<'a>> {
        let c_feature = unsafe { ogr::OGR_L_GetNextFeature(self.layer.c_layer) };
        return match c_feature.is_null() {
            true  => None,
            false => Some(unsafe { Feature::_with_layer(self.layer, c_feature) }),
        };
    }
}

impl<'a> FeatureIterator<'a> {
    pub fn _with_layer(layer: &'a Layer<'a>) -> FeatureIterator<'a> {
        return FeatureIterator{layer: layer};
    }
}
<commit_msg>docs for layer<commit_after>use std::ptr::null;
use libc::c_int;
use utils::_string;
use vector::{ogr, Dataset, Feature, Geometry};

/// Layer in a vector dataset
///
/// ```
/// use std::path::Path;
/// use gdal::vector::Dataset;
///
/// let dataset = Dataset::open(Path::new("fixtures/roads.geojson")).unwrap();
/// let layer = dataset.layer(0).unwrap();
/// for feature in layer.features() {
///     // do something with each feature
/// }
/// ```
pub struct Layer<'a> {
    _dataset: &'a Dataset,
    c_layer: *const (),
}

impl<'a> Layer<'a> {
    pub unsafe fn _with_dataset(dataset: &'a Dataset, c_layer: *const ()) -> Layer<'a> {
        return Layer{_dataset: dataset, c_layer: c_layer};
    }

    /// Iterate over the field schema of this layer.
    pub fn fields(&'a self) -> FieldIterator<'a> {
        let c_feature_defn = unsafe { ogr::OGR_L_GetLayerDefn(self.c_layer) };
        let total = unsafe { ogr::OGR_FD_GetFieldCount(c_feature_defn) } as isize;
        return FieldIterator{
            layer: self,
            c_feature_defn: c_feature_defn,
            next_id: 0,
            total: total
        };
    }

    /// Iterate over all features in this layer.
    pub fn features(&'a self) -> FeatureIterator<'a> {
        return FeatureIterator::_with_layer(self);
    }

    pub fn set_spatial_filter(&'a self, geometry: &Geometry) {
        unsafe { ogr::OGR_L_SetSpatialFilter(self.c_layer, geometry.c_geometry()) };
    }

    pub fn clear_spatial_filter(&'a self) {
        unsafe { ogr::OGR_L_SetSpatialFilter(self.c_layer, null()) };
    }
}

pub struct FieldIterator<'a> {
    layer: &'a Layer<'a>,
    c_feature_defn: *const (),
    next_id: isize,
    total: isize,
}

impl<'a> Iterator for FieldIterator<'a> {
    type Item = Field<'a>;

    #[inline]
    fn next(&mut self) -> Option<Field<'a>> {
        if self.next_id == self.total {
            return None;
        }
        let field = Field{
            _layer: self.layer,
            c_field_defn: unsafe { ogr::OGR_FD_GetFieldDefn(
                self.c_feature_defn,
                self.next_id as c_int
            ) }
        };
        self.next_id += 1;
        return Some(field);
    }
}

pub struct Field<'a> {
    _layer: &'a Layer<'a>,
    c_field_defn: *const (),
}

impl<'a> Field<'a> {
    /// Get the name of this field.
    pub fn name(&'a self) -> String {
        let rv = unsafe { ogr::OGR_Fld_GetNameRef(self.c_field_defn) };
        return _string(rv);
    }
}

pub struct FeatureIterator<'a> {
    layer: &'a Layer<'a>,
}

impl<'a> Iterator for FeatureIterator<'a> {
    type Item = Feature<'a>;

    #[inline]
    fn next(&mut self) -> Option<Feature<'a>> {
        let c_feature = unsafe { ogr::OGR_L_GetNextFeature(self.layer.c_layer) };
        return match c_feature.is_null() {
            true  => None,
            false => Some(unsafe { Feature::_with_layer(self.layer, c_feature) }),
        };
    }
}

impl<'a> FeatureIterator<'a> {
    pub fn _with_layer(layer: &'a Layer<'a>) -> FeatureIterator<'a> {
        return FeatureIterator{layer: layer};
    }
}
<|endoftext|>