<commit_before>// Implement data structures for a Huffman encoding tree:
//   http://rosettacode.org/wiki/Huffman_coding

extern crate core;
use std::collections::HashMap;
use std::collections::priority_queue::PriorityQueue;

// Each HNode has a weight, representing the sum of the frequencies for all its
// children. It is either a leaf (containing a character), or a HTree
// (containing two children)
struct HNode {
    weight: int,
    item: HTreeOrHLeaf,
}

enum HTreeOrHLeaf {
    HTree(HTreeData),
    HLeaf(char),
}

struct HTreeData {
    left: Box<HNode>,
    right: Box<HNode>,
}

// Implementing comparison traits (Ord and all its dependencies) such that
// the HNode with the greatest weight is the smallest in a comparison. Basically
// reversing all the comparison operators.
impl Ord for HNode {
    fn cmp(&self, other: &HNode) -> Ordering {
        match self.weight.cmp(&other.weight) {
            Less    => Greater,
            Equal   => Equal,
            Greater => Less,
        }
    }
}

impl Eq for HNode {}
impl PartialEq for HNode {
    fn eq(&self, other: &HNode) -> bool {
        self.weight == other.weight
    }
}

impl PartialOrd for HNode {
    fn lt(&self, other: &HNode) -> bool {
        self.weight > other.weight
    }
}

// Takes a non-empty string (function will fail if string is empty) and computes
// the Huffman encoding tree for that string.
fn huffman_tree(input: &str) -> HNode {
    // 1. Loop through all the characters in that string, adding them to a HashMap
    //    of character to frequency.
    let mut freq = HashMap::new();
    for ch in input.chars() {
        freq.insert_or_update_with(ch, 1, |_k, v: &mut int| {*v += 1;});
    }

    // 2. For each (character, frequency) pair in the HashMap, add a Leaf to a
    //    PriorityQueue
    let mut queue = PriorityQueue::<HNode>::new();
    for (ch, freq) in freq.iter() {
        let new_node = HNode{
            weight: *freq,
            item: HLeaf(*ch),
        };
        queue.push(new_node);
    }

    // 3. Pop two items with the least weight from the queue, combine them into
    //    a tree as children. The parent node's weight is the sum of the
    //    children's weight. Continue until one item is left on the queue, and
    //    return that item.
    while queue.len() > 1 {
        let item1 = queue.pop().unwrap();
        let item2 = queue.pop().unwrap();
        let new_node = HNode {
            weight: item1.weight + item2.weight,
            item: HTree(HTreeData{
                left: box item1,
                right: box item2,
            }),
        };
        queue.push(new_node);
    }
    queue.pop().unwrap()
}

// Takes a Huffman Tree, traverse it and build a table with each character and
// its encoding string.
fn build_encoding_table(tree: &HNode,
                      table: &mut HashMap<char,String>,
                      startStr: &str) {
    match tree.item {
        HTree(ref data) => {
            build_encoding_table(data.left, table,
                               String::from_str(startStr).append("0").as_slice());
            build_encoding_table(data.right, table,
                               String::from_str(startStr).append("1").as_slice());
        },
        HLeaf(ch)   => {table.insert(ch, String::from_str(startStr));}
    };
}

// Attempts to construct a tree, and test that the construction is successful
//    7
//   ----
//  /    \
// 4:'4'  3
//      -----
//     /     \
//    2:'2'  1:'1'
#[test]
fn test_tree_construction() {
    let to_encode = "4444221";
    let tree = huffman_tree(to_encode);
    assert!(tree.weight == 7);
    let children = match tree.item {
        HTree(data) => data,
        HLeaf(_)    => fail!("Tree Missing Children!"),
    };
    let left  = &children.left;
    let right = &children.right;
    assert!(right.weight == 4);
    assert!(left.weight == 3);
    let right_char = match right.item {
        HTree(_)  => fail!("Node is not Leaf Node!"),
        HLeaf(ch) => ch,
    };
    assert!(right_char == '4');
    let children = match left.item {
        HTree(ref data) => data,
        HLeaf(_)    => fail!("Tree Missing Children!"),
    };
    let left  = &children.left;
    let right = &children.right;
    let left_char = match left.item {
        HTree(_)  => fail!("Node is not Leaf Node!"),
        HLeaf(ch) => ch,
    };
    let right_char = match right.item {
        HTree(_)  => fail!("Node is not Leaf Node!"),
        HLeaf(ch) => ch,
    };
    match (left.weight, right.weight) {
        (1, 2) => {
            assert!(left_char == '1');
            assert!(right_char == '2');
        },
        (2, 1) => {
            assert!(left_char == '2');
            assert!(right_char == '1');
        },
        (_, _) => {
            fail!("Incorrect Leaf Nodes");
        }
    };
}

#[test]
// Constructs a table:
//  '4': 1
//  '2': 01 OR 00
//  '1': 00    01
// And tests that the table was correctly constructed
fn test_table_construction() {
    let to_encode = "4444221";
    let tree = huffman_tree(to_encode);
    let mut table = HashMap::<char,String>::new();
    build_encoding_table(&tree, &mut table, "");
    let one  = table.get(&'1').as_slice();
    let two  = table.get(&'2').as_slice();
    let four = table.get(&'4').as_slice();
    assert!(four == "1");
    assert!((one == "01" && two == "00") ||
            (one == "00" && two == "01"));
}

#[cfg(not(test))]
fn main() {
    let to_encode = "this is an example for huffman encoding";
    let tree = huffman_tree(to_encode);
    let mut table = HashMap::<char,String>::new();
    build_encoding_table(&tree, &mut table, "");

    for (ch, encoding) in table.iter() {
        println!("{}: {}", *ch, encoding);
    }
}
<commit_msg>Fix huffman_coding<commit_after>// Implement data structures for a Huffman encoding tree:
//   http://rosettacode.org/wiki/Huffman_coding

extern crate core;
use std::collections::HashMap;
use std::collections::priority_queue::PriorityQueue;

// Each HNode has a weight, representing the sum of the frequencies for all its
// children. It is either a leaf (containing a character), or a HTree
// (containing two children)
struct HNode {
    weight: int,
    item: HTreeOrHLeaf,
}

enum HTreeOrHLeaf {
    HTree(HTreeData),
    HLeaf(char),
}

struct HTreeData {
    left: Box<HNode>,
    right: Box<HNode>,
}

// Implementing comparison traits (Ord and all its dependencies) such that
// the HNode with the greatest weight is the smallest in a comparison. Basically
// reversing all the comparison operators.
impl Ord for HNode {
    fn cmp(&self, other: &HNode) -> Ordering {
        match self.weight.cmp(&other.weight) {
            Less    => Greater,
            Equal   => Equal,
            Greater => Less,
        }
    }
}

impl PartialOrd for HNode {
    fn partial_cmp(&self, other: &HNode) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Eq for HNode {}
impl PartialEq for HNode {
    fn eq(&self, other: &HNode) -> bool {
        self.weight == other.weight
    }
}

// Takes a non-empty string (function will fail if string is empty) and computes
// the Huffman encoding tree for that string.
fn huffman_tree(input: &str) -> HNode {
    // 1. Loop through all the characters in that string, adding them to a HashMap
    //    of character to frequency.
    let mut freq = HashMap::new();
    for ch in input.chars() {
        freq.insert_or_update_with(ch, 1, |_k, v: &mut int| {*v += 1;});
    }

    // 2. For each (character, frequency) pair in the HashMap, add a Leaf to a
    //    PriorityQueue
    let mut queue = PriorityQueue::<HNode>::new();
    for (ch, freq) in freq.iter() {
        let new_node = HNode{
            weight: *freq,
            item: HLeaf(*ch),
        };
        queue.push(new_node);
    }

    // 3. Pop two items with the least weight from the queue, combine them into
    //    a tree as children. The parent node's weight is the sum of the
    //    children's weight. Continue until one item is left on the queue, and
    //    return that item.
    while queue.len() > 1 {
        let item1 = queue.pop().unwrap();
        let item2 = queue.pop().unwrap();
        let new_node = HNode {
            weight: item1.weight + item2.weight,
            item: HTree(HTreeData{
                left: box item1,
                right: box item2,
            }),
        };
        queue.push(new_node);
    }
    queue.pop().unwrap()
}

// Takes a Huffman Tree, traverse it and build a table with each character and
// its encoding string.
fn build_encoding_table(tree: &HNode,
                      table: &mut HashMap<char,String>,
                      startStr: &str) {
    match tree.item {
        HTree(ref data) => {
            build_encoding_table(data.left, table,
                               String::from_str(startStr).append("0").as_slice());
            build_encoding_table(data.right, table,
                               String::from_str(startStr).append("1").as_slice());
        },
        HLeaf(ch)   => {table.insert(ch, String::from_str(startStr));}
    };
}

// Attempts to construct a tree, and test that the construction is successful
//    7
//   ----
//  /    \
// 4:'4'  3
//      -----
//     /     \
//    2:'2'  1:'1'
#[test]
fn test_tree_construction() {
    let to_encode = "4444221";
    let tree = huffman_tree(to_encode);
    assert!(tree.weight == 7);
    let children = match tree.item {
        HTree(data) => data,
        HLeaf(_)    => fail!("Tree Missing Children!"),
    };
    let left  = &children.left;
    let right = &children.right;
    assert!(right.weight == 4);
    assert!(left.weight == 3);
    let right_char = match right.item {
        HTree(_)  => fail!("Node is not Leaf Node!"),
        HLeaf(ch) => ch,
    };
    assert!(right_char == '4');
    let children = match left.item {
        HTree(ref data) => data,
        HLeaf(_)    => fail!("Tree Missing Children!"),
    };
    let left  = &children.left;
    let right = &children.right;
    let left_char = match left.item {
        HTree(_)  => fail!("Node is not Leaf Node!"),
        HLeaf(ch) => ch,
    };
    let right_char = match right.item {
        HTree(_)  => fail!("Node is not Leaf Node!"),
        HLeaf(ch) => ch,
    };
    match (left.weight, right.weight) {
        (1, 2) => {
            assert!(left_char == '1');
            assert!(right_char == '2');
        },
        (2, 1) => {
            assert!(left_char == '2');
            assert!(right_char == '1');
        },
        (_, _) => {
            fail!("Incorrect Leaf Nodes");
        }
    };
}

#[test]
// Constructs a table:
//  '4': 1
//  '2': 01 OR 00
//  '1': 00    01
// And tests that the table was correctly constructed
fn test_table_construction() {
    let to_encode = "4444221";
    let tree = huffman_tree(to_encode);
    let mut table = HashMap::<char,String>::new();
    build_encoding_table(&tree, &mut table, "");
    let one  = table.get(&'1').as_slice();
    let two  = table.get(&'2').as_slice();
    let four = table.get(&'4').as_slice();
    assert!(four == "1");
    assert!((one == "01" && two == "00") ||
            (one == "00" && two == "01"));
}

#[cfg(not(test))]
fn main() {
    let to_encode = "this is an example for huffman encoding";
    let tree = huffman_tree(to_encode);
    let mut table = HashMap::<char,String>::new();
    build_encoding_table(&tree, &mut table, "");

    for (ch, encoding) in table.iter() {
        println!("{}: {}", *ch, encoding);
    }
}
<|endoftext|>


<commit_before>//extern crate llvm_sys as llvm;
//extern crate libffi;
//extern crate libc;
extern crate libcobra;
extern crate docopt;
extern crate rustc_serialize;

use std::fs::File;
use std::path::{Path, PathBuf};
use std::process::exit;
//use codegen::{CodeGenOptions, codegen, link, llvm_init};
use docopt::Docopt;
use libcobra::parser::{ParserOptions, parse_file};
use libcobra::typechecker::{type_check_module};
use libcobra::bytecode::{compile_to_byte_code, run_byte_code, debug_byte_code, optimize_module, ByteCodeModule, OptimizationLevel};
use libcobra::compileerror::{CompileResult, CompileError};

static USAGE: &'static str =  "
Usage: cobra [options] <input-file>
       cobra --help

options:
  --help                                       Show this message.
  -D <dump>, --dump=<dump>                     Dump internal compiler state for debug purposes. Argument can be all, ast, bytecode or ir.
                                               A comma separated list of these values is also supported.
  -O, --optimize                               Optimize the code.
  -I <imports>, --imports=<imports>            Directory to look for imports, use a comma separated list for more then one.
  -o <output-file>, --output=<output-file>     Name of binary to create (by default input-file without the extensions).
  -t <binary-type>, --type=<binary-type>       Binary type, allowed values: bytecode or elf
  -i --interpret                               Execute the code in the interpreter.
  -d --debug                                   Run the interpreter in debug mode.
";

#[derive(RustcDecodable, Debug)]
struct Args
{
    flag_dump: Option<String>,
    flag_optimize: Option<bool>,
    arg_input_file: Option<String>,
    flag_output: Option<String>,
    flag_type: Option<String>,
    flag_imports: Option<String>,
    flag_interpret: Option<bool>,
    flag_debug: Option<bool>,
}

fn default_output_file(input_file: &str) -> String
{
    Path::new(&input_file)
        .file_stem()
        .expect("Invalid input file")
        .to_str()
        .expect("Invalid input file")
        .into()
}

fn dump_byte_code(bc_mod: &ByteCodeModule, dump_flags: &str)
{
    if dump_flags.contains("bytecode") || dump_flags.contains("all") {
        println!("bytecode:");
        println!("------\n");
        println!("{}", bc_mod);
        println!("------\n");
    }
}

fn parse(parser_options: &ParserOptions, input_file: &str, dump_flags: &str, optimize: bool) -> CompileResult<ByteCodeModule>
{
    let bc_mod = if input_file.ends_with(".byte")
    {
        let mut file = File::open(input_file)?;
        ByteCodeModule::load(&mut file)
            .map_err(|err| CompileError::Other(err))?
    }
    else
    {
        let mut module = parse_file(&parser_options, input_file)?;
        type_check_module(&mut module)?;

        if dump_flags.contains("ast") || dump_flags.contains("all") {
            println!("AST:");
            println!("------\n");
            use libcobra::ast::TreePrinter;
            module.print(0);
            println!("------\n");
        }

        let mut bc_mod = compile_to_byte_code(&module);
        if optimize {
            optimize_module(&mut bc_mod, OptimizationLevel::Normal);
        } else {
            optimize_module(&mut bc_mod, OptimizationLevel::Minimal);
        }

        bc_mod
    };

    dump_byte_code(&bc_mod, &dump_flags);
    Ok(bc_mod)

}

fn run() -> CompileResult<i32>
{
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    let input_file = args.arg_input_file.expect("Missing input file argument");
    let run_interpreter = args.flag_interpret.unwrap_or(false);
    let run_debugger = args.flag_debug.unwrap_or(false);
    let optimize = args.flag_optimize.unwrap_or(false);
    let output_file = args.flag_output.unwrap_or_else(|| default_output_file(&input_file));
    let binary_type = args.flag_type.unwrap_or("bytecode".into());
    let dump_flags = args.flag_dump.unwrap_or_default();

    let parser_options = ParserOptions{
        import_dirs: args.flag_imports
            .map(|dirs| dirs.split(',').map(PathBuf::from).collect())
            .unwrap_or_else(Vec::new),
    };

    /*
        let opts = CodeGenOptions{
            dump_ir: dump_flags.contains("ir") || dump_flags.contains("all"),
            build_dir: "build".into(),
            program_name: output_file,
            optimize: args.flag_optimize.unwrap_or(false),
        };
    */

    let bc_mod = parse(&parser_options, &input_file, &dump_flags, optimize)?;
    if !run_debugger && !run_interpreter {

        match &binary_type[..]
        {
            "bytecode" => {
                println!("Generating bytecode binary {}.byte", output_file);
                let mut file = File::create(&format!("{}.byte", output_file))?;
                match bc_mod.save(&mut file)
                {
                    Ok(()) => Ok(0),
                    Err(msg) => {
                        println!("Failed to save {}: {}", output_file, msg);
                        Ok(-1)
                    }
                }
            },

            "elf" => {
                /*
                llvm_init();
                let mut ctx = codegen(&bc_mod)?;
                link(&mut ctx, &opts)
                */
                panic!("NYI");
            }

            _ => {
                println!("Unknown binary type {}", binary_type);
                Ok(1)
            }
        }

    } else {

    }
}

fn main()
{
    match run()
    {
        Ok(ret) => exit(ret),
        Err(e) => {
            e.print();
            exit(-1);
        },
    }
}
<commit_msg>Make cobrac build again<commit_after>//extern crate llvm_sys as llvm;
//extern crate libffi;
//extern crate libc;
extern crate libcobra;
extern crate docopt;
extern crate rustc_serialize;

use std::fs::File;
use std::path::{Path, PathBuf};
use std::process::exit;
//use codegen::{CodeGenOptions, codegen, link, llvm_init};
use docopt::Docopt;
use libcobra::parser::{ParserOptions, parse_file};
use libcobra::typechecker::{type_check_module};
use libcobra::bytecode::{compile_to_byte_code, optimize_module, ByteCodeModule, OptimizationLevel};
use libcobra::compileerror::{CompileResult};

static USAGE: &'static str =  "
Usage: cobra [options] <input-file>
       cobra --help

options:
  --help                                       Show this message.
  -D <dump>, --dump=<dump>                     Dump internal compiler state for debug purposes. Argument can be all, ast, bytecode or ir.
                                               A comma separated list of these values is also supported.
  -O, --optimize                               Optimize the code.
  -I <imports>, --imports=<imports>            Directory to look for imports, use a comma separated list for more then one.
  -o <output-file>, --output=<output-file>     Name of binary to create (by default input-file without the extensions).
  -t <binary-type>, --type=<binary-type>       Binary type, allowed values: bytecode or exe
";

#[derive(RustcDecodable, Debug)]
struct Args
{
    flag_dump: Option<String>,
    flag_optimize: Option<bool>,
    arg_input_file: Option<String>,
    flag_output: Option<String>,
    flag_type: Option<String>,
    flag_imports: Option<String>,
}

fn default_output_file(input_file: &str) -> String
{
    Path::new(&input_file)
        .file_stem()
        .expect("Invalid input file")
        .to_str()
        .expect("Invalid input file")
        .into()
}

fn dump_byte_code(bc_mod: &ByteCodeModule, dump_flags: &str)
{
    if dump_flags.contains("bytecode") || dump_flags.contains("all") {
        println!("bytecode:");
        println!("------\n");
        println!("{}", bc_mod);
        println!("------\n");
    }
}

fn parse(parser_options: &ParserOptions, input_file: &str, dump_flags: &str, optimize: bool) -> CompileResult<ByteCodeModule>
{
    let mut module = parse_file(&parser_options, input_file)?;
    type_check_module(&mut module)?;

    if dump_flags.contains("ast") || dump_flags.contains("all") {
        println!("AST:");
        println!("------\n");
        use libcobra::ast::TreePrinter;
        module.print(0);
        println!("------\n");
    }

    let mut bc_mod = compile_to_byte_code(&module);
    if optimize {
        optimize_module(&mut bc_mod, OptimizationLevel::Normal);
    } else {
        optimize_module(&mut bc_mod, OptimizationLevel::Minimal);
    }

    dump_byte_code(&bc_mod, &dump_flags);
    Ok(bc_mod)
}

fn run() -> CompileResult<i32>
{
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    let input_file = args.arg_input_file.expect("Missing input file argument");
    let optimize = args.flag_optimize.unwrap_or(false);
    let output_file = args.flag_output.unwrap_or_else(|| default_output_file(&input_file));
    let binary_type = args.flag_type.unwrap_or("bytecode".into());
    let dump_flags = args.flag_dump.unwrap_or_default();

    let parser_options = ParserOptions{
        import_dirs: args.flag_imports
            .map(|dirs| dirs.split(',').map(PathBuf::from).collect())
            .unwrap_or_else(Vec::new),
    };

    let bc_mod = parse(&parser_options, &input_file, &dump_flags, optimize)?;
    match &binary_type[..]
    {
        "bytecode" => {
            println!("Generating bytecode binary {}.byte", output_file);
            let mut file = File::create(&format!("{}.byte", output_file))?;
            match bc_mod.save(&mut file)
            {
                Ok(()) => Ok(0),
                Err(msg) => {
                    println!("Failed to save {}: {}", output_file, msg);
                    Ok(-1)
                }
            }
        },

        "exe" => {
            /*
            let opts = CodeGenOptions{
                dump_ir: dump_flags.contains("ir") || dump_flags.contains("all"),
                build_dir: "build".into(),
                program_name: output_file,
                optimize: args.flag_optimize.unwrap_or(false),
            };

            llvm_init();
            let mut ctx = codegen(&bc_mod)?;
            link(&mut ctx, &opts)
            */
            panic!("NYI");
        }

        _ => {
            println!("Unknown binary type {}", binary_type);
            Ok(1)
        }
    }
}

fn main()
{
    match run()
    {
        Ok(ret) => exit(ret),
        Err(e) => {
            e.print();
            exit(-1);
        },
    }
}
<|endoftext|>


<commit_before>use autograd::{Function, FuncIntf, FuncDelegate, FIWrap};
use tensor::{OptTensorKindList, TensorKindList};

#[derive(Clone)]
pub struct ViewArgs {
    pub dims: Vec<isize>,
}

impl_func_args_other!(View, ViewArgs);
impl FuncIntf for View {
    fn forward(&mut self, input_list: &mut TensorKindList) -> TensorKindList {
        let mut input = input_list.remove(0);
        self.saved_trvalue.push(input.size().into());
        let output = input.view(self.args.dims.clone());
        // XXX mark shared?
        vec![output]
    }
    fn backward(&mut self, grad_output: &mut OptTensorKindList) -> OptTensorKindList {
        let mut grad_output = grad_output.remove(0).unwrap();
        let dims: Vec<isize> = self.saved_trvalue.remove(0).into();
        vec![grad_output.contiguous().view(dims).into(), None]
    }
}
<commit_msg>make sure to save vec as isize in View, add mostly complete implementation of MaskedFill<commit_after>use autograd::{Function, FuncIntf, FuncDelegate, FIWrap};
use tensor::{OptTensorKindList, TensorKindList};

#[derive(Clone)]
pub struct ViewArgs {
    pub dims: Vec<isize>,
}

impl_func_args_other!(View, ViewArgs);
impl FuncIntf for View {
    fn forward(&mut self, input_list: &mut TensorKindList) -> TensorKindList {
        let mut input = input_list.remove(0);
        let dims : Vec<isize> = input.size().iter().map(|v| *v as isize).collect();
        self.saved_trvalue.push(dims.into());
        let output = input.view(self.args.dims.clone());
        // XXX mark shared?
        vec![output]
    }
    fn backward(&mut self, grad_output: &mut OptTensorKindList) -> OptTensorKindList {
        let mut grad_output = grad_output.remove(0).unwrap();
        let dims: Vec<isize> = self.saved_trvalue.remove(0).into();
        println!("View backward");
        vec![grad_output.contiguous().view(dims).into(), None]
    }
}
#[derive(Clone)]
pub struct MaskedFillArgs {
    value: f64,
    inplace: bool,
}

impl_func_args_other!(MaskedFill, MaskedFillArgs);
impl FuncIntf for MaskedFill {
    fn forward(&mut self, input_list: &mut TensorKindList) -> TensorKindList {
        let (mut input, mut mask) = (input_list.remove(0), input_list.remove(0));

        self.saved_trvalue.push(input.size().into());
        let mut tensor = if self.args.inplace {
            self.mark_dirty(&vec![input.clone()]);
            input.clone()
        } else {
            input.copy()
        };
        self.save_for_backward(&vec![mask.clone()]);
        tensor.masked_fill_(mask.into(), self.args.value);
        vec![tensor]
    }
    fn backward(&mut self, grad_output: &mut OptTensorKindList) -> OptTensorKindList {
        unimplemented!();
        let mut grad_output = grad_output.remove(0).unwrap();
        let dims: Vec<isize> = self.saved_trvalue.remove(0).into();
        println!("MaskedFill backward");
        vec![grad_output.contiguous().view(dims).into(), None]
    }
}<|endoftext|>


<commit_before>use x86::segmentation::{self, SegmentSelector};

pub struct Idt([Entry; 16]);

impl Idt {
    pub fn new() -> Idt {
        Idt([Entry::missing(); 16])
    }

    pub fn set_handler(&mut self, entry: u8, handler: HandlerFunc) -> &mut EntryOptions {
        self.0[entry as usize] = Entry::new(segmentation::cs(), handler);
        &mut self.0[entry as usize].options
    }

    pub fn load(&'static self) {
        use x86::dtables::{DescriptorTablePointer, lidt};
        use core::mem::size_of;

        let ptr = DescriptorTablePointer {
            base: self as *const _ as u64,
            limit: (size_of::<Self>() - 1) as u16,
        };

        unsafe { lidt(&ptr) };
    }
}

#[derive(Debug, Clone, Copy)]
#[repr(C, packed)]
pub struct Entry {
    pointer_low: u16,
    gdt_selector: SegmentSelector,
    options: EntryOptions,
    pointer_middle: u16,
    pointer_high: u32,
    reserved: u32,
}

type HandlerFunc = extern "C" fn() -> !;

impl Entry {
    fn new(gdt_selector: SegmentSelector, handler: HandlerFunc) -> Self {
        let pointer = handler as u64;
        Entry {
            gdt_selector: gdt_selector,
            pointer_low: pointer as u16,
            pointer_middle: (pointer >> 16) as u16,
            pointer_high: (pointer >> 32) as u32,
            options: EntryOptions::new(),
            reserved: 0,
        }
    }

    fn missing() -> Self {
        Entry {
            gdt_selector: SegmentSelector::new(0),
            pointer_low: 0,
            pointer_middle: 0,
            pointer_high: 0,
            options: EntryOptions::minimal(),
            reserved: 0,
        }
    }
}

use bit_field::BitField;

#[derive(Debug, Clone, Copy)]
pub struct EntryOptions(BitField<u16>);

impl EntryOptions {
    fn minimal() -> Self {
        let mut options = BitField::new(0);
        options.set_range(9..12, 0b111); // 'must-be-one' bits
        EntryOptions(options)
    }

    fn new() -> Self {
        let mut options = Self::minimal();
        options.set_present(true).disable_interrupts(true);
        options
    }

    fn set_present(&mut self, present: bool) -> &mut Self {
        self.0.set_bit(15, present);
        self
    }

    fn disable_interrupts(&mut self, disable: bool) -> &mut Self {
        self.0.set_bit(8, !disable);
        self
    }

    fn set_privilege_level(&mut self, dpl: u16) -> &mut Self {
        self.0.set_range(13..15, dpl);
        self
    }

    fn set_stack_index(&mut self, index: u16) -> &mut Self {
        self.0.set_range(0..3, index);
        self
    }
}
<commit_msg>Make HandlerFunc public, because it is part of a public interface<commit_after>use x86::segmentation::{self, SegmentSelector};

pub struct Idt([Entry; 16]);

impl Idt {
    pub fn new() -> Idt {
        Idt([Entry::missing(); 16])
    }

    pub fn set_handler(&mut self, entry: u8, handler: HandlerFunc) -> &mut EntryOptions {
        self.0[entry as usize] = Entry::new(segmentation::cs(), handler);
        &mut self.0[entry as usize].options
    }

    pub fn load(&'static self) {
        use x86::dtables::{DescriptorTablePointer, lidt};
        use core::mem::size_of;

        let ptr = DescriptorTablePointer {
            base: self as *const _ as u64,
            limit: (size_of::<Self>() - 1) as u16,
        };

        unsafe { lidt(&ptr) };
    }
}

#[derive(Debug, Clone, Copy)]
#[repr(C, packed)]
pub struct Entry {
    pointer_low: u16,
    gdt_selector: SegmentSelector,
    options: EntryOptions,
    pointer_middle: u16,
    pointer_high: u32,
    reserved: u32,
}

pub type HandlerFunc = extern "C" fn() -> !;

impl Entry {
    fn new(gdt_selector: SegmentSelector, handler: HandlerFunc) -> Self {
        let pointer = handler as u64;
        Entry {
            gdt_selector: gdt_selector,
            pointer_low: pointer as u16,
            pointer_middle: (pointer >> 16) as u16,
            pointer_high: (pointer >> 32) as u32,
            options: EntryOptions::new(),
            reserved: 0,
        }
    }

    fn missing() -> Self {
        Entry {
            gdt_selector: SegmentSelector::new(0),
            pointer_low: 0,
            pointer_middle: 0,
            pointer_high: 0,
            options: EntryOptions::minimal(),
            reserved: 0,
        }
    }
}

use bit_field::BitField;

#[derive(Debug, Clone, Copy)]
pub struct EntryOptions(BitField<u16>);

impl EntryOptions {
    fn minimal() -> Self {
        let mut options = BitField::new(0);
        options.set_range(9..12, 0b111); // 'must-be-one' bits
        EntryOptions(options)
    }

    fn new() -> Self {
        let mut options = Self::minimal();
        options.set_present(true).disable_interrupts(true);
        options
    }

    fn set_present(&mut self, present: bool) -> &mut Self {
        self.0.set_bit(15, present);
        self
    }

    fn disable_interrupts(&mut self, disable: bool) -> &mut Self {
        self.0.set_bit(8, !disable);
        self
    }

    fn set_privilege_level(&mut self, dpl: u16) -> &mut Self {
        self.0.set_range(13..15, dpl);
        self
    }

    fn set_stack_index(&mut self, index: u16) -> &mut Self {
        self.0.set_range(0..3, index);
        self
    }
}
<|endoftext|>


<commit_before>#![allow(missing_docs, nonstandard_style)]

use crate::ffi::{OsStr, OsString};
use crate::io::ErrorKind;
use crate::os::windows::ffi::{OsStrExt, OsStringExt};
use crate::path::PathBuf;
use crate::time::Duration;

pub use self::rand::hashmap_random_keys;
pub use libc::strlen;

#[macro_use]
pub mod compat;

pub mod alloc;
pub mod args;
pub mod c;
pub mod cmath;
pub mod condvar;
pub mod env;
pub mod fs;
pub mod handle;
pub mod io;
pub mod memchr;
pub mod mutex;
pub mod net;
pub mod os;
pub mod os_str;
pub mod path;
pub mod pipe;
pub mod process;
pub mod rand;
pub mod rwlock;
pub mod thread;
pub mod thread_local_dtor;
pub mod thread_local_key;
pub mod thread_parker;
pub mod time;
cfg_if::cfg_if! {
    if #[cfg(not(target_vendor = "uwp"))] {
        pub mod stdio;
        pub mod stack_overflow;
    } else {
        pub mod stdio_uwp;
        pub mod stack_overflow_uwp;
        pub use self::stdio_uwp as stdio;
        pub use self::stack_overflow_uwp as stack_overflow;
    }
}

// SAFETY: must be called only once during runtime initialization.
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
    stack_overflow::init();
}

// SAFETY: must be called only once during runtime cleanup.
// NOTE: this is not guaranteed to run, for example when the program aborts.
pub unsafe fn cleanup() {
    net::cleanup();
}

pub fn decode_error_kind(errno: i32) -> ErrorKind {
    use ErrorKind::*;

    match errno as c::DWORD {
        c::ERROR_ACCESS_DENIED => return PermissionDenied,
        c::ERROR_ALREADY_EXISTS => return AlreadyExists,
        c::ERROR_FILE_EXISTS => return AlreadyExists,
        c::ERROR_BROKEN_PIPE => return BrokenPipe,
        c::ERROR_FILE_NOT_FOUND => return NotFound,
        c::ERROR_PATH_NOT_FOUND => return NotFound,
        c::ERROR_NO_DATA => return BrokenPipe,
        c::ERROR_INVALID_PARAMETER => return InvalidInput,
        c::ERROR_NOT_ENOUGH_MEMORY | c::ERROR_OUTOFMEMORY => return OutOfMemory,
        c::ERROR_SEM_TIMEOUT
        | c::WAIT_TIMEOUT
        | c::ERROR_DRIVER_CANCEL_TIMEOUT
        | c::ERROR_OPERATION_ABORTED
        | c::ERROR_SERVICE_REQUEST_TIMEOUT
        | c::ERROR_COUNTER_TIMEOUT
        | c::ERROR_TIMEOUT
        | c::ERROR_RESOURCE_CALL_TIMED_OUT
        | c::ERROR_CTX_MODEM_RESPONSE_TIMEOUT
        | c::ERROR_CTX_CLIENT_QUERY_TIMEOUT
        | c::FRS_ERR_SYSVOL_POPULATE_TIMEOUT
        | c::ERROR_DS_TIMELIMIT_EXCEEDED
        | c::DNS_ERROR_RECORD_TIMED_OUT
        | c::ERROR_IPSEC_IKE_TIMED_OUT
        | c::ERROR_RUNLEVEL_SWITCH_TIMEOUT
        | c::ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT => return TimedOut,
        c::ERROR_CALL_NOT_IMPLEMENTED => return Unsupported,
        | c::ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT => return TimedOut,
        c::ERROR_CALL_NOT_IMPLEMENTED => return Unsupported,
        c::ERROR_HOST_UNREACHABLE => return HostUnreachable,
        c::ERROR_NETWORK_UNREACHABLE => return NetworkUnreachable,
        c::ERROR_DIRECTORY => return NotADirectory,
        c::ERROR_DIRECTORY_NOT_SUPPORTED => return IsADirectory,
        c::ERROR_DIR_NOT_EMPTY => return DirectoryNotEmpty,
        c::ERROR_WRITE_PROTECT => return ReadOnlyFilesystem,
        c::ERROR_DISK_FULL
        | c::ERROR_HANDLE_DISK_FULL => return StorageFull,
        c::ERROR_SEEK_ON_DEVICE => return NotSeekable,
        c::ERROR_DISK_QUOTA_EXCEEDED => return FilesystemQuotaExceeded,
        c::ERROR_FILE_TOO_LARGE => return FileTooLarge,
        c::ERROR_BUSY => return ResourceBusy,
        c::ERROR_POSSIBLE_DEADLOCK => return Deadlock,
        c::ERROR_NOT_SAME_DEVICE => return CrossesDevices,
        c::ERROR_TOO_MANY_LINKS => return TooManyLinks,
        c::ERROR_FILENAME_EXCED_RANGE => return FilenameTooLong,
        _ => {}
    }

    match errno {
        c::WSAEACCES => PermissionDenied,
        c::WSAEADDRINUSE => AddrInUse,
        c::WSAEADDRNOTAVAIL => AddrNotAvailable,
        c::WSAECONNABORTED => ConnectionAborted,
        c::WSAECONNREFUSED => ConnectionRefused,
        c::WSAECONNRESET => ConnectionReset,
        c::WSAEINVAL => InvalidInput,
        c::WSAENOTCONN => NotConnected,
        c::WSAEWOULDBLOCK => WouldBlock,
        c::WSAETIMEDOUT => TimedOut,
        c::WSAEHOSTUNREACH => HostUnreachable,
        c::WSAENETDOWN => NetworkDown,
        c::WSAENETUNREACH => NetworkUnreachable,

        _ => Uncategorized,
    }
}

pub fn unrolled_find_u16s(needle: u16, haystack: &[u16]) -> Option<usize> {
    let ptr = haystack.as_ptr();
    let mut start = &haystack[..];

    // For performance reasons unfold the loop eight times.
    while start.len() >= 8 {
        macro_rules! if_return {
            ($($n:literal,)+) => {
                $(
                    if start[$n] == needle {
                        return Some((&start[$n] as *const u16 as usize - ptr as usize) / 2);
                    }
                )+
            }
        }

        if_return!(0, 1, 2, 3, 4, 5, 6, 7,);

        start = &start[8..];
    }

    for c in start {
        if *c == needle {
            return Some((c as *const u16 as usize - ptr as usize) / 2);
        }
    }
    None
}

pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> crate::io::Result<Vec<u16>> {
    fn inner(s: &OsStr) -> crate::io::Result<Vec<u16>> {
        let mut maybe_result: Vec<u16> = s.encode_wide().collect();
        if unrolled_find_u16s(0, &maybe_result).is_some() {
            return Err(crate::io::Error::new_const(
                ErrorKind::InvalidInput,
                &"strings passed to WinAPI cannot contain NULs",
            ));
        }
        maybe_result.push(0);
        Ok(maybe_result)
    }
    inner(s.as_ref())
}

// Many Windows APIs follow a pattern of where we hand a buffer and then they
// will report back to us how large the buffer should be or how many bytes
// currently reside in the buffer. This function is an abstraction over these
// functions by making them easier to call.
//
// The first callback, `f1`, is yielded a (pointer, len) pair which can be
// passed to a syscall. The `ptr` is valid for `len` items (u16 in this case).
// The closure is expected to return what the syscall returns which will be
// interpreted by this function to determine if the syscall needs to be invoked
// again (with more buffer space).
//
// Once the syscall has completed (errors bail out early) the second closure is
// yielded the data which has been read from the syscall. The return value
// from this closure is then the return value of the function.
fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> crate::io::Result<T>
where
    F1: FnMut(*mut u16, c::DWORD) -> c::DWORD,
    F2: FnOnce(&[u16]) -> T,
{
    // Start off with a stack buf but then spill over to the heap if we end up
    // needing more space.
    let mut stack_buf = [0u16; 512];
    let mut heap_buf = Vec::new();
    unsafe {
        let mut n = stack_buf.len();
        loop {
            let buf = if n <= stack_buf.len() {
                &mut stack_buf[..]
            } else {
                let extra = n - heap_buf.len();
                heap_buf.reserve(extra);
                heap_buf.set_len(n);
                &mut heap_buf[..]
            };

            // This function is typically called on windows API functions which
            // will return the correct length of the string, but these functions
            // also return the `0` on error. In some cases, however, the
            // returned "correct length" may actually be 0!
            //
            // To handle this case we call `SetLastError` to reset it to 0 and
            // then check it again if we get the "0 error value". If the "last
            // error" is still 0 then we interpret it as a 0 length buffer and
            // not an actual error.
            c::SetLastError(0);
            let k = match f1(buf.as_mut_ptr(), n as c::DWORD) {
                0 if c::GetLastError() == 0 => 0,
                0 => return Err(crate::io::Error::last_os_error()),
                n => n,
            } as usize;
            if k == n && c::GetLastError() == c::ERROR_INSUFFICIENT_BUFFER {
                n *= 2;
            } else if k >= n {
                n = k;
            } else {
                return Ok(f2(&buf[..k]));
            }
        }
    }
}

fn os2path(s: &[u16]) -> PathBuf {
    PathBuf::from(OsString::from_wide(s))
}

pub fn truncate_utf16_at_nul(v: &[u16]) -> &[u16] {
    match unrolled_find_u16s(0, v) {
        // don't include the 0
        Some(i) => &v[..i],
        None => v,
    }
}

pub trait IsZero {
    fn is_zero(&self) -> bool;
}

macro_rules! impl_is_zero {
    ($($t:ident)*) => ($(impl IsZero for $t {
        fn is_zero(&self) -> bool {
            *self == 0
        }
    })*)
}

impl_is_zero! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }

pub fn cvt<I: IsZero>(i: I) -> crate::io::Result<I> {
    if i.is_zero() { Err(crate::io::Error::last_os_error()) } else { Ok(i) }
}

pub fn dur2timeout(dur: Duration) -> c::DWORD {
    // Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the
    // timeouts in windows APIs are typically u32 milliseconds. To translate, we
    // have two pieces to take care of:
    //
    // * Nanosecond precision is rounded up
    // * Greater than u32::MAX milliseconds (50 days) is rounded up to INFINITE
    //   (never time out).
    dur.as_secs()
        .checked_mul(1000)
        .and_then(|ms| ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000))
        .and_then(|ms| ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 { 1 } else { 0 }))
        .map(|ms| if ms > <c::DWORD>::MAX as u64 { c::INFINITE } else { ms as c::DWORD })
        .unwrap_or(c::INFINITE)
}

/// Use `__fastfail` to abort the process
///
/// This is the same implementation as in libpanic_abort's `__rust_start_panic`. See
/// that function for more information on `__fastfail`
#[allow(unreachable_code)]
pub fn abort_internal() -> ! {
    const FAST_FAIL_FATAL_APP_EXIT: usize = 7;
    unsafe {
        cfg_if::cfg_if! {
            if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
                asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT);
                crate::intrinsics::unreachable();
            } else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] {
                asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT);
                crate::intrinsics::unreachable();
            } else if #[cfg(target_arch = "aarch64")] {
                asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT);
                crate::intrinsics::unreachable();
            }
        }
    }
    crate::intrinsics::abort();
}
<commit_msg>ErrorKind: Windows: Fix botched rebase<commit_after>#![allow(missing_docs, nonstandard_style)]

use crate::ffi::{OsStr, OsString};
use crate::io::ErrorKind;
use crate::os::windows::ffi::{OsStrExt, OsStringExt};
use crate::path::PathBuf;
use crate::time::Duration;

pub use self::rand::hashmap_random_keys;
pub use libc::strlen;

#[macro_use]
pub mod compat;

pub mod alloc;
pub mod args;
pub mod c;
pub mod cmath;
pub mod condvar;
pub mod env;
pub mod fs;
pub mod handle;
pub mod io;
pub mod memchr;
pub mod mutex;
pub mod net;
pub mod os;
pub mod os_str;
pub mod path;
pub mod pipe;
pub mod process;
pub mod rand;
pub mod rwlock;
pub mod thread;
pub mod thread_local_dtor;
pub mod thread_local_key;
pub mod thread_parker;
pub mod time;
cfg_if::cfg_if! {
    if #[cfg(not(target_vendor = "uwp"))] {
        pub mod stdio;
        pub mod stack_overflow;
    } else {
        pub mod stdio_uwp;
        pub mod stack_overflow_uwp;
        pub use self::stdio_uwp as stdio;
        pub use self::stack_overflow_uwp as stack_overflow;
    }
}

// SAFETY: must be called only once during runtime initialization.
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
    stack_overflow::init();
}

// SAFETY: must be called only once during runtime cleanup.
// NOTE: this is not guaranteed to run, for example when the program aborts.
pub unsafe fn cleanup() {
    net::cleanup();
}

pub fn decode_error_kind(errno: i32) -> ErrorKind {
    use ErrorKind::*;

    match errno as c::DWORD {
        c::ERROR_ACCESS_DENIED => return PermissionDenied,
        c::ERROR_ALREADY_EXISTS => return AlreadyExists,
        c::ERROR_FILE_EXISTS => return AlreadyExists,
        c::ERROR_BROKEN_PIPE => return BrokenPipe,
        c::ERROR_FILE_NOT_FOUND => return NotFound,
        c::ERROR_PATH_NOT_FOUND => return NotFound,
        c::ERROR_NO_DATA => return BrokenPipe,
        c::ERROR_INVALID_PARAMETER => return InvalidInput,
        c::ERROR_NOT_ENOUGH_MEMORY | c::ERROR_OUTOFMEMORY => return OutOfMemory,
        c::ERROR_SEM_TIMEOUT
        | c::WAIT_TIMEOUT
        | c::ERROR_DRIVER_CANCEL_TIMEOUT
        | c::ERROR_OPERATION_ABORTED
        | c::ERROR_SERVICE_REQUEST_TIMEOUT
        | c::ERROR_COUNTER_TIMEOUT
        | c::ERROR_TIMEOUT
        | c::ERROR_RESOURCE_CALL_TIMED_OUT
        | c::ERROR_CTX_MODEM_RESPONSE_TIMEOUT
        | c::ERROR_CTX_CLIENT_QUERY_TIMEOUT
        | c::FRS_ERR_SYSVOL_POPULATE_TIMEOUT
        | c::ERROR_DS_TIMELIMIT_EXCEEDED
        | c::DNS_ERROR_RECORD_TIMED_OUT
        | c::ERROR_IPSEC_IKE_TIMED_OUT
        | c::ERROR_RUNLEVEL_SWITCH_TIMEOUT
        | c::ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT => return TimedOut,
        c::ERROR_CALL_NOT_IMPLEMENTED => return Unsupported,
        c::ERROR_HOST_UNREACHABLE => return HostUnreachable,
        c::ERROR_NETWORK_UNREACHABLE => return NetworkUnreachable,
        c::ERROR_DIRECTORY => return NotADirectory,
        c::ERROR_DIRECTORY_NOT_SUPPORTED => return IsADirectory,
        c::ERROR_DIR_NOT_EMPTY => return DirectoryNotEmpty,
        c::ERROR_WRITE_PROTECT => return ReadOnlyFilesystem,
        c::ERROR_DISK_FULL
        | c::ERROR_HANDLE_DISK_FULL => return StorageFull,
        c::ERROR_SEEK_ON_DEVICE => return NotSeekable,
        c::ERROR_DISK_QUOTA_EXCEEDED => return FilesystemQuotaExceeded,
        c::ERROR_FILE_TOO_LARGE => return FileTooLarge,
        c::ERROR_BUSY => return ResourceBusy,
        c::ERROR_POSSIBLE_DEADLOCK => return Deadlock,
        c::ERROR_NOT_SAME_DEVICE => return CrossesDevices,
        c::ERROR_TOO_MANY_LINKS => return TooManyLinks,
        c::ERROR_FILENAME_EXCED_RANGE => return FilenameTooLong,
        _ => {}
    }

    match errno {
        c::WSAEACCES => PermissionDenied,
        c::WSAEADDRINUSE => AddrInUse,
        c::WSAEADDRNOTAVAIL => AddrNotAvailable,
        c::WSAECONNABORTED => ConnectionAborted,
        c::WSAECONNREFUSED => ConnectionRefused,
        c::WSAECONNRESET => ConnectionReset,
        c::WSAEINVAL => InvalidInput,
        c::WSAENOTCONN => NotConnected,
        c::WSAEWOULDBLOCK => WouldBlock,
        c::WSAETIMEDOUT => TimedOut,
        c::WSAEHOSTUNREACH => HostUnreachable,
        c::WSAENETDOWN => NetworkDown,
        c::WSAENETUNREACH => NetworkUnreachable,

        _ => Uncategorized,
    }
}

pub fn unrolled_find_u16s(needle: u16, haystack: &[u16]) -> Option<usize> {
    let ptr = haystack.as_ptr();
    let mut start = &haystack[..];

    // For performance reasons unfold the loop eight times.
    while start.len() >= 8 {
        macro_rules! if_return {
            ($($n:literal,)+) => {
                $(
                    if start[$n] == needle {
                        return Some((&start[$n] as *const u16 as usize - ptr as usize) / 2);
                    }
                )+
            }
        }

        if_return!(0, 1, 2, 3, 4, 5, 6, 7,);

        start = &start[8..];
    }

    for c in start {
        if *c == needle {
            return Some((c as *const u16 as usize - ptr as usize) / 2);
        }
    }
    None
}

pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> crate::io::Result<Vec<u16>> {
    fn inner(s: &OsStr) -> crate::io::Result<Vec<u16>> {
        let mut maybe_result: Vec<u16> = s.encode_wide().collect();
        if unrolled_find_u16s(0, &maybe_result).is_some() {
            return Err(crate::io::Error::new_const(
                ErrorKind::InvalidInput,
                &"strings passed to WinAPI cannot contain NULs",
            ));
        }
        maybe_result.push(0);
        Ok(maybe_result)
    }
    inner(s.as_ref())
}

// Many Windows APIs follow a pattern of where we hand a buffer and then they
// will report back to us how large the buffer should be or how many bytes
// currently reside in the buffer. This function is an abstraction over these
// functions by making them easier to call.
//
// The first callback, `f1`, is yielded a (pointer, len) pair which can be
// passed to a syscall. The `ptr` is valid for `len` items (u16 in this case).
// The closure is expected to return what the syscall returns which will be
// interpreted by this function to determine if the syscall needs to be invoked
// again (with more buffer space).
//
// Once the syscall has completed (errors bail out early) the second closure is
// yielded the data which has been read from the syscall. The return value
// from this closure is then the return value of the function.
fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> crate::io::Result<T>
where
    F1: FnMut(*mut u16, c::DWORD) -> c::DWORD,
    F2: FnOnce(&[u16]) -> T,
{
    // Start off with a stack buf but then spill over to the heap if we end up
    // needing more space.
    let mut stack_buf = [0u16; 512];
    let mut heap_buf = Vec::new();
    unsafe {
        let mut n = stack_buf.len();
        loop {
            let buf = if n <= stack_buf.len() {
                &mut stack_buf[..]
            } else {
                let extra = n - heap_buf.len();
                heap_buf.reserve(extra);
                heap_buf.set_len(n);
                &mut heap_buf[..]
            };

            // This function is typically called on windows API functions which
            // will return the correct length of the string, but these functions
            // also return the `0` on error. In some cases, however, the
            // returned "correct length" may actually be 0!
            //
            // To handle this case we call `SetLastError` to reset it to 0 and
            // then check it again if we get the "0 error value". If the "last
            // error" is still 0 then we interpret it as a 0 length buffer and
            // not an actual error.
            c::SetLastError(0);
            let k = match f1(buf.as_mut_ptr(), n as c::DWORD) {
                0 if c::GetLastError() == 0 => 0,
                0 => return Err(crate::io::Error::last_os_error()),
                n => n,
            } as usize;
            if k == n && c::GetLastError() == c::ERROR_INSUFFICIENT_BUFFER {
                n *= 2;
            } else if k >= n {
                n = k;
            } else {
                return Ok(f2(&buf[..k]));
            }
        }
    }
}

fn os2path(s: &[u16]) -> PathBuf {
    PathBuf::from(OsString::from_wide(s))
}

pub fn truncate_utf16_at_nul(v: &[u16]) -> &[u16] {
    match unrolled_find_u16s(0, v) {
        // don't include the 0
        Some(i) => &v[..i],
        None => v,
    }
}

pub trait IsZero {
    fn is_zero(&self) -> bool;
}

macro_rules! impl_is_zero {
    ($($t:ident)*) => ($(impl IsZero for $t {
        fn is_zero(&self) -> bool {
            *self == 0
        }
    })*)
}

impl_is_zero! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }

pub fn cvt<I: IsZero>(i: I) -> crate::io::Result<I> {
    if i.is_zero() { Err(crate::io::Error::last_os_error()) } else { Ok(i) }
}

pub fn dur2timeout(dur: Duration) -> c::DWORD {
    // Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the
    // timeouts in windows APIs are typically u32 milliseconds. To translate, we
    // have two pieces to take care of:
    //
    // * Nanosecond precision is rounded up
    // * Greater than u32::MAX milliseconds (50 days) is rounded up to INFINITE
    //   (never time out).
    dur.as_secs()
        .checked_mul(1000)
        .and_then(|ms| ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000))
        .and_then(|ms| ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 { 1 } else { 0 }))
        .map(|ms| if ms > <c::DWORD>::MAX as u64 { c::INFINITE } else { ms as c::DWORD })
        .unwrap_or(c::INFINITE)
}

/// Use `__fastfail` to abort the process
///
/// This is the same implementation as in libpanic_abort's `__rust_start_panic`. See
/// that function for more information on `__fastfail`
#[allow(unreachable_code)]
pub fn abort_internal() -> ! {
    const FAST_FAIL_FATAL_APP_EXIT: usize = 7;
    unsafe {
        cfg_if::cfg_if! {
            if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
                asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT);
                crate::intrinsics::unreachable();
            } else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] {
                asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT);
                crate::intrinsics::unreachable();
            } else if #[cfg(target_arch = "aarch64")] {
                asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT);
                crate::intrinsics::unreachable();
            }
        }
    }
    crate::intrinsics::abort();
}
<|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/. */

use resource_task::{Metadata, Payload, Done, LoadResponse, LoaderTask, start_sending};

use std::vec;
use extra::url::Url;
use http::client::RequestWriter;
use http::method::Get;
use http::headers::HeaderEnum;
use std::io::Reader;
use servo_util::task::spawn_named;

pub fn factory() -> LoaderTask {
    let f: LoaderTask = proc(url, start_chan) {
        spawn_named("http_loader", proc() load(url, start_chan))
    };
    f
}

fn load(mut url: Url, start_chan: Chan<LoadResponse>) {
    // Loop to handle redirects.
    loop {
        assert!("http" == url.scheme);

        info!("requesting {:s}", url.to_str());

        let request = ~RequestWriter::new(Get, url.clone());
        let mut response = match request.read_response() {
            Ok(r) => r,
            Err(_) => {
                start_sending(start_chan, Metadata::default(url)).send(Done(Err(())));
                return;
            }
        };

        // Dump headers, but only do the iteration if info!() is enabled.
        info!("got HTTP response {:s}, headers:", response.status.to_str());
        info!("{:?}",
            for header in response.headers.iter() {
                info!(" - {:s}: {:s}", header.header_name(), header.header_value());
            });

        // FIXME: detect redirect loops
        if 3 == (response.status.code() / 100) {
            match response.headers.location {
                Some(new_url) => {
                    info!("redirecting to {:s}", new_url.to_str());
                    url = new_url;
                    continue;
                }
                None => ()
            }
        }

        let mut metadata = Metadata::default(url);
        metadata.set_content_type(&response.headers.content_type);

        let progress_chan = start_sending(start_chan, metadata);
        loop {
            let mut buf = vec::with_capacity(1024);

            unsafe { buf.set_len(1024); }
            match response.read(buf) {
                Some(len) => {
                    unsafe { buf.set_len(len); }
                    progress_chan.send(Payload(buf));
                }
                None => {
                    progress_chan.send(Done(Ok(())));
                    break;
                }
            }
        }

        // We didn't get redirected.
        break;
    }
}
<commit_msg>Added bound to number of HTTP redirects, and prevented redirect loops.<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/. */

use resource_task::{Metadata, Payload, Done, LoadResponse, LoaderTask, start_sending};

use std::vec;
use std::hashmap::HashSet;
use extra::url::Url;
use http::client::RequestWriter;
use http::method::Get;
use http::headers::HeaderEnum;
use std::io::Reader;
use servo_util::task::spawn_named;

pub fn factory() -> LoaderTask {
    let f: LoaderTask = proc(url, start_chan) {
        spawn_named("http_loader", proc() load(url, start_chan))
    };
    f
}

fn send_error(url: Url, start_chan: Chan<LoadResponse>) {
    start_sending(start_chan, Metadata::default(url)).send(Done(Err(())));
}

fn load(mut url: Url, start_chan: Chan<LoadResponse>) {
    // FIXME: At the time of writing this FIXME, servo didn't have any central
    //        location for configuration. If you're reading this and such a
    //        repository DOES exist, please update this constant to use it.
    let max_redirects = 50u;
    let mut iters = 0u;

    let mut redirected_to = HashSet::new();

    // Loop to handle redirects.
    loop {
        iters = iters + 1;

        if iters > max_redirects {
            info!("too many redirects");
            send_error(url, start_chan);
            return;
        }

        if redirected_to.contains(&url) {
            info!("redirect loop");
            send_error(url, start_chan);
            return;
        }

        redirected_to.insert(url.clone());

        assert!("http" == url.scheme);

        info!("requesting {:s}", url.to_str());

        let request = ~RequestWriter::new(Get, url.clone());
        let mut response = match request.read_response() {
            Ok(r) => r,
            Err(_) => {
                send_error(url, start_chan);
                return;
            }
        };

        // Dump headers, but only do the iteration if info!() is enabled.
        info!("got HTTP response {:s}, headers:", response.status.to_str());
        info!("{:?}",
            for header in response.headers.iter() {
                info!(" - {:s}: {:s}", header.header_name(), header.header_value());
            });

        if 3 == (response.status.code() / 100) {
            match response.headers.location {
                Some(new_url) => {
                    info!("redirecting to {:s}", new_url.to_str());
                    url = new_url;
                    continue;
                }
                None => ()
            }
        }

        let mut metadata = Metadata::default(url);
        metadata.set_content_type(&response.headers.content_type);

        let progress_chan = start_sending(start_chan, metadata);
        loop {
            let mut buf = vec::with_capacity(1024);

            unsafe { buf.set_len(1024); }
            match response.read(buf) {
                Some(len) => {
                    unsafe { buf.set_len(len); }
                    progress_chan.send(Payload(buf));
                }
                None => {
                    progress_chan.send(Done(Ok(())));
                    break;
                }
            }
        }

        // We didn't get redirected.
        break;
    }
}
<|endoftext|>


<commit_before>/*
Module: ctypes

Definitions useful for C interop
*/

/*
FIXME: Add a test that uses some native code to verify these sizes,
which are not obviously correct for all potential platforms.
*/

// PORT adapt to architecture

/*
Type: c_int

A signed integer with the same size as a C `int`
*/
type c_int = i32;

/*
Type: c_uint

An unsigned integer with the same size as a C `unsigned int`
*/
type c_uint = u32;

/*
Type: long

A signed integer with the same size as a C `long`
*/
type long = int;

/*
Type: longlong

A signed integer with the same size as a C `long long`
*/
type longlong = i64;

/*
Type: unsigned

An unsigned integer with the same size as a C `unsigned int`
*/
type unsigned = u32;

/*
Type: ulong

An unsigned integer with the same size as a C `unsigned long`
*/
type ulong = uint;

/*
Type: ulonglong

An unsigned integer with the same size as a C `unsigned long long`
*/
type ulonglong = u64;

/*
Type: intptr_t

A signed integer with the same size as a pointer. This is
guaranteed to always be the same type as a Rust `int`
*/
type intptr_t = uint; // FIXME: int

/*
Type: uintptr_t

An unsigned integer with the same size as a pointer. This is
guaranteed to always be the same type as a Rust `uint`.
*/
type uintptr_t = uint;
type uint32_t = u32;

/*
Type: void

A type, a pointer to which can be used as C `void *`

Note that this does not directly correspond to the C `void` type,
which is an incomplete type. Using pointers to this type
when interoperating with C void pointers can help in documentation.
*/
type void = int;

/*
Type: c_float

A float value with the same size as a C `float`
*/
type c_float = f32;

/*
Type: c_float

A float value with the same size as a C `double`
*/
type c_double = f64;

/*
Type: size_t

An unsigned integer corresponding to the C `size_t`
*/
type size_t = uint;

/*
Type: ssize_t

A signed integer correpsonding to the C `ssize_t`
*/
type ssize_t = int;

/*
Type: off_t

An unsigned integer corresponding to the C `off_t`
*/
type off_t = uint;

/*
Type: fd_t

A type that can be used for C file descriptors
*/
type fd_t = i32;      // not actually a C type, but should be.

/*
Type: pid_t

A type for representing process ID's, corresponding to C `pid_t`
*/
type pid_t = i32;

// enum is implementation-defined, but is 32-bits in practice
/*
Type: enum

An unsigned integer with the same size as a C enum
*/
type enum = u32;

<commit_msg>libcore: Make ctypes::void an unconstructable, undestructurable tag<commit_after>/*
Module: ctypes

Definitions useful for C interop
*/

/*
FIXME: Add a test that uses some native code to verify these sizes,
which are not obviously correct for all potential platforms.
*/

export c_int, c_uint, long, longlong, unsigned, ulong, ulonglong;
export intptr_t, uintptr_t;
export uint32_t;
export void;
export c_float, c_double;
export size_t, ssize_t;
export off_t, fd_t, pid_t;
export enum;

// PORT adapt to architecture

/*
Type: c_int

A signed integer with the same size as a C `int`
*/
type c_int = i32;

/*
Type: c_uint

An unsigned integer with the same size as a C `unsigned int`
*/
type c_uint = u32;

/*
Type: long

A signed integer with the same size as a C `long`
*/
type long = int;

/*
Type: longlong

A signed integer with the same size as a C `long long`
*/
type longlong = i64;

/*
Type: unsigned

An unsigned integer with the same size as a C `unsigned int`
*/
type unsigned = u32;

/*
Type: ulong

An unsigned integer with the same size as a C `unsigned long`
*/
type ulong = uint;

/*
Type: ulonglong

An unsigned integer with the same size as a C `unsigned long long`
*/
type ulonglong = u64;

/*
Type: intptr_t

A signed integer with the same size as a pointer. This is
guaranteed to always be the same type as a Rust `int`
*/
type intptr_t = uint; // FIXME: int

/*
Type: uintptr_t

An unsigned integer with the same size as a pointer. This is
guaranteed to always be the same type as a Rust `uint`.
*/
type uintptr_t = uint;
type uint32_t = u32;

/*
Type: void

A type, a pointer to which can be used as C `void *`.

The void type cannot be constructed or destructured, but using
pointers to this type when interoperating with C void pointers can
help in documentation.
*/
tag void {
    // Making the only variant reference itself makes it impossible to
    // construct. Not exporting it makes it impossible to destructure.
    void_private(@void);
    // FIXME: #881
    void_private2(@void);
}

/*
Type: c_float

A float value with the same size as a C `float`
*/
type c_float = f32;

/*
Type: c_float

A float value with the same size as a C `double`
*/
type c_double = f64;

/*
Type: size_t

An unsigned integer corresponding to the C `size_t`
*/
type size_t = uint;

/*
Type: ssize_t

A signed integer correpsonding to the C `ssize_t`
*/
type ssize_t = int;

/*
Type: off_t

An unsigned integer corresponding to the C `off_t`
*/
type off_t = uint;

/*
Type: fd_t

A type that can be used for C file descriptors
*/
type fd_t = i32;      // not actually a C type, but should be.

/*
Type: pid_t

A type for representing process ID's, corresponding to C `pid_t`
*/
type pid_t = i32;

// enum is implementation-defined, but is 32-bits in practice
/*
Type: enum

An unsigned integer with the same size as a C enum
*/
type enum = u32;

<|endoftext|>


<commit_before>#[doc = "A type representing either success or failure"];

import either::either;

#[doc = "The result type"]
enum result<T, U> {
    #[doc = "Contains the successful result value"]
    ok(T),
    #[doc = "Contains the error value"]
    err(U)
}

#[doc = "
Get the value out of a successful result

# Failure

If the result is an error
"]
pure fn get<T: copy, U>(res: result<T, U>) -> T {
    alt res {
      ok(t) { t }
      err(the_err) {
        unchecked{ fail #fmt("get called on error result: %?", the_err); }
      }
    }
}

#[doc = "
Get the value out of an error result

# Failure

If the result is not an error
"]
pure fn get_err<T, U: copy>(res: result<T, U>) -> U {
    alt res {
      err(u) { u }
      ok(_) {
        fail "get_error called on ok result";
      }
    }
}

#[doc = "Returns true if the result is `ok`"]
pure fn is_success<T, U>(res: result<T, U>) -> bool {
    alt res {
      ok(_) { true }
      err(_) { false }
    }
}

#[doc = "Returns true if the result is `error`"]
pure fn is_failure<T, U>(res: result<T, U>) -> bool {
    !is_success(res)
}

#[doc = "
Convert to the `either` type

`ok` result variants are converted to `either::right` variants, `err`
result variants are converted to `either::left`.
"]
pure fn to_either<T: copy, U: copy>(res: result<U, T>) -> either<T, U> {
    alt res {
      ok(res) { either::right(res) }
      err(fail_) { either::left(fail_) }
    }
}

#[doc = "
Call a function based on a previous result

If `res` is `ok` then the value is extracted and passed to `op` whereupon
`op`s result is returned. if `res` is `err` then it is immediately returned.
This function can be used to compose the results of two functions.

Example:

    let res = chain(read_file(file)) { |buf|
        ok(parse_buf(buf))
    }
"]
fn chain<T, U: copy, V: copy>(res: result<T, V>, op: fn(T) -> result<U, V>)
    -> result<U, V> {
    alt res {
      ok(t) { op(t) }
      err(e) { err(e) }
    }
}

#[doc = "
Call a function based on a previous result

If `res` is `err` then the value is extracted and passed to `op`
whereupon `op`s result is returned. if `res` is `ok` then it is
immediately returned.  This function can be used to pass through a
successful result while handling an error.
"]
fn chain_err<T: copy, U: copy, V: copy>(
    res: result<T, V>,
    op: fn(V) -> result<T, U>)
    -> result<T, U> {
    alt res {
      ok(t) { ok(t) }
      err(v) { op(v) }
    }
}

impl extensions<T:copy, E:copy> for result<T,E> {
    fn get() -> T { get(self) }

    fn get_err() -> E { get_err(self) }

    fn is_success() -> bool { is_success(self) }

    fn is_failure() -> bool { is_failure(self) }

    fn chain<U:copy>(op: fn(T) -> result<U,E>) -> result<U,E> {
        chain(self, op)
    }

    fn chain_err<F:copy>(op: fn(E) -> result<T,F>) -> result<T,F> {
        chain_err(self, op)
    }
}

#[doc = "
Maps each element in the vector `ts` using the operation `op`.  Should an
error occur, no further mappings are performed and the error is returned.
Should no error occur, a vector containing the result of each map is
returned.

Here is an example which increments every integer in a vector,
checking for overflow:

    fn inc_conditionally(x: uint) -> result<uint,str> {
        if x == uint::max_value { ret err(\"overflow\"); }
        else { ret ok(x+1u); }
    }
    map([1u, 2u, 3u], inc_conditionally).chain {|incd|
        assert incd == [2u, 3u, 4u];
    }
"]
fn map_vec<T,U:copy,V:copy>(
    ts: [T], op: fn(T) -> result<V,U>) -> result<[V],U> {

    let mut vs: [V] = [];
    vec::reserve(vs, vec::len(ts));
    for vec::each(ts) {|t|
        alt op(t) {
          ok(v) { vs += [v]; }
          err(u) { ret err(u); }
        }
    }
    ret ok(vs);
}

fn map_opt<T,U:copy,V:copy>(
    o_t: option<T>, op: fn(T) -> result<V,U>) -> result<option<V>,U> {

    alt o_t {
      none { ok(none) }
      some(t) {
        alt op(t) {
          ok(v) { ok(some(v)) }
          err(e) { err(e) }
        }
      }
    }
}

#[doc = "Same as map, but it operates over two parallel vectors.

A precondition is used here to ensure that the vectors are the same
length.  While we do not often use preconditions in the standard
library, a precondition is used here because result::t is generally
used in 'careful' code contexts where it is both appropriate and easy
to accommodate an error like the vectors being of different lengths."]
fn map_vec2<S,T,U:copy,V:copy>(ss: [S], ts: [T], op: fn(S,T) -> result<V,U>)
    : vec::same_length(ss, ts) -> result<[V],U> {

    let n = vec::len(ts);
    let mut vs = [];
    vec::reserve(vs, n);
    let mut i = 0u;
    while i < n {
        alt op(ss[i],ts[i]) {
          ok(v) { vs += [v]; }
          err(u) { ret err(u); }
        }
        i += 1u;
    }
    ret ok(vs);
}

#[doc = "
Applies op to the pairwise elements from `ss` and `ts`, aborting on
error.  This could be implemented using `map2()` but it is more efficient
on its own as no result vector is built.
"]
fn iter_vec2<S,T,U:copy>(ss: [S], ts: [T],
                         op: fn(S,T) -> result<(),U>)
    : vec::same_length(ss, ts)
    -> result<(),U> {

    let n = vec::len(ts);
    let mut i = 0u;
    while i < n {
        alt op(ss[i],ts[i]) {
          ok(()) { }
          err(u) { ret err(u); }
        }
        i += 1u;
    }
    ret ok(());
}

#[doc="
Unwraps a result, assuming it is an `ok(T)`
"]
fn unwrap<T, U>(-res: result<T, U>) -> T unsafe {
    let addr = alt res {
      ok(x) { ptr::addr_of(x) }
      err(_) { fail "error result" }
    };
    let liberated_value = unsafe::reinterpret_cast(*addr);
    unsafe::forget(res);
    ret liberated_value;
}

#[cfg(test)]
mod tests {
    fn op1() -> result::result<int, str> { result::ok(666) }

    fn op2(&&i: int) -> result::result<uint, str> {
        result::ok(i as uint + 1u)
    }

    fn op3() -> result::result<int, str> { result::err("sadface") }

    #[test]
    fn chain_success() {
        assert get(chain(op1(), op2)) == 667u;
    }

    #[test]
    fn chain_failure() {
        assert get_err(chain(op3(), op2)) == "sadface";
    }
}
<commit_msg>Add methods iter, iter_err, map, map_err to the result type.<commit_after>#[doc = "A type representing either success or failure"];

import either::either;

#[doc = "The result type"]
enum result<T, U> {
    #[doc = "Contains the successful result value"]
    ok(T),
    #[doc = "Contains the error value"]
    err(U)
}

#[doc = "
Get the value out of a successful result

# Failure

If the result is an error
"]
pure fn get<T: copy, U>(res: result<T, U>) -> T {
    alt res {
      ok(t) { t }
      err(the_err) {
        unchecked{ fail #fmt("get called on error result: %?", the_err); }
      }
    }
}

#[doc = "
Get the value out of an error result

# Failure

If the result is not an error
"]
pure fn get_err<T, U: copy>(res: result<T, U>) -> U {
    alt res {
      err(u) { u }
      ok(_) {
        fail "get_error called on ok result";
      }
    }
}

#[doc = "Returns true if the result is `ok`"]
pure fn is_success<T, U>(res: result<T, U>) -> bool {
    alt res {
      ok(_) { true }
      err(_) { false }
    }
}

#[doc = "Returns true if the result is `error`"]
pure fn is_failure<T, U>(res: result<T, U>) -> bool {
    !is_success(res)
}

#[doc = "
Convert to the `either` type

`ok` result variants are converted to `either::right` variants, `err`
result variants are converted to `either::left`.
"]
pure fn to_either<T: copy, U: copy>(res: result<U, T>) -> either<T, U> {
    alt res {
      ok(res) { either::right(res) }
      err(fail_) { either::left(fail_) }
    }
}

#[doc = "
Call a function based on a previous result

If `res` is `ok` then the value is extracted and passed to `op` whereupon
`op`s result is returned. if `res` is `err` then it is immediately returned.
This function can be used to compose the results of two functions.

Example:

    let res = chain(read_file(file)) { |buf|
        ok(parse_buf(buf))
    }
"]
fn chain<T, U: copy, V: copy>(res: result<T, V>, op: fn(T) -> result<U, V>)
    -> result<U, V> {
    alt res {
      ok(t) { op(t) }
      err(e) { err(e) }
    }
}

#[doc = "
Call a function based on a previous result

If `res` is `err` then the value is extracted and passed to `op`
whereupon `op`s result is returned. if `res` is `ok` then it is
immediately returned.  This function can be used to pass through a
successful result while handling an error.
"]
fn chain_err<T: copy, U: copy, V: copy>(
    res: result<T, V>,
    op: fn(V) -> result<T, U>)
    -> result<T, U> {
    alt res {
      ok(t) { ok(t) }
      err(v) { op(v) }
    }
}

#[doc = "
Call a function based on a previous result

If `res` is `ok` then the value is extracted and passed to `op` whereupon
`op`s result is returned. if `res` is `err` then it is immediately returned.
This function can be used to compose the results of two functions.

Example:

    iter(read_file(file)) { |buf|
        print_buf(buf)
    }
"]
fn iter<T, E>(res: result<T, E>, f: fn(T)) {
    alt res {
      ok(t) { f(t) }
      err(_) { }
    }
}

#[doc = "
Call a function based on a previous result

If `res` is `err` then the value is extracted and passed to `op` whereupon
`op`s result is returned. if `res` is `ok` then it is immediately returned.
This function can be used to pass through a successful result while handling
an error.
"]
fn iter_err<T, E>(res: result<T, E>, f: fn(E)) {
    alt res {
      ok(_) { }
      err(e) { f(e) }
    }
}

#[doc = "
Call a function based on a previous result

If `res` is `ok` then the value is extracted and passed to `op` whereupon
`op`s result is wrapped in `ok` and returned. if `res` is `err` then it is
immediately returned.  This function can be used to compose the results of two
functions.

Example:

    let res = map(read_file(file)) { |buf|
        parse_buf(buf)
    }
"]
fn map<T, E: copy, U: copy>(res: result<T, E>, op: fn(T) -> U)
  -> result<U, E> {
    alt res {
      ok(t) { ok(op(t)) }
      err(e) { err(e) }
    }
}

#[doc = "
Call a function based on a previous result

If `res` is `err` then the value is extracted and passed to `op` whereupon
`op`s result is wrapped in an `err` and returned. if `res` is `ok` then it is
immediately returned.  This function can be used to pass through a successful
result while handling an error.
"]
fn map_err<T: copy, E, F: copy>(res: result<T, E>, op: fn(E) -> F)
  -> result<T, F> {
    alt res {
      ok(t) { ok(t) }
      err(e) { err(op(e)) }
    }
}

impl extensions<T:copy, E:copy> for result<T,E> {
    fn get() -> T { get(self) }

    fn get_err() -> E { get_err(self) }

    fn is_success() -> bool { is_success(self) }

    fn is_failure() -> bool { is_failure(self) }

    fn chain<U:copy>(op: fn(T) -> result<U,E>) -> result<U,E> {
        chain(self, op)
    }

    fn chain_err<F:copy>(op: fn(E) -> result<T,F>) -> result<T,F> {
        chain_err(self, op)
    }

    fn iter(f: fn(T)) {
        alt self {
          ok(t) { f(t) }
          err(_) { }
        }
    }

    fn iter_err(f: fn(E)) {
        alt self {
          ok(_) { }
          err(e) { f(e) }
        }
    }

    fn map<U:copy>(op: fn(T) -> U) -> result<U,E> {
        alt self {
          ok(t) { ok(op(t)) }
          err(e) { err(e) }
        }
    }

    fn map_err<F:copy>(op: fn(E) -> F) -> result<T,F> {
        alt self {
          ok(t) { ok(t) }
          err(e) { err(op(e)) }
        }
    }
}

#[doc = "
Maps each element in the vector `ts` using the operation `op`.  Should an
error occur, no further mappings are performed and the error is returned.
Should no error occur, a vector containing the result of each map is
returned.

Here is an example which increments every integer in a vector,
checking for overflow:

    fn inc_conditionally(x: uint) -> result<uint,str> {
        if x == uint::max_value { ret err(\"overflow\"); }
        else { ret ok(x+1u); }
    }
    map([1u, 2u, 3u], inc_conditionally).chain {|incd|
        assert incd == [2u, 3u, 4u];
    }
"]
fn map_vec<T,U:copy,V:copy>(
    ts: [T], op: fn(T) -> result<V,U>) -> result<[V],U> {

    let mut vs: [V] = [];
    vec::reserve(vs, vec::len(ts));
    for vec::each(ts) {|t|
        alt op(t) {
          ok(v) { vs += [v]; }
          err(u) { ret err(u); }
        }
    }
    ret ok(vs);
}

fn map_opt<T,U:copy,V:copy>(
    o_t: option<T>, op: fn(T) -> result<V,U>) -> result<option<V>,U> {

    alt o_t {
      none { ok(none) }
      some(t) {
        alt op(t) {
          ok(v) { ok(some(v)) }
          err(e) { err(e) }
        }
      }
    }
}

#[doc = "Same as map, but it operates over two parallel vectors.

A precondition is used here to ensure that the vectors are the same
length.  While we do not often use preconditions in the standard
library, a precondition is used here because result::t is generally
used in 'careful' code contexts where it is both appropriate and easy
to accommodate an error like the vectors being of different lengths."]
fn map_vec2<S,T,U:copy,V:copy>(ss: [S], ts: [T], op: fn(S,T) -> result<V,U>)
    : vec::same_length(ss, ts) -> result<[V],U> {

    let n = vec::len(ts);
    let mut vs = [];
    vec::reserve(vs, n);
    let mut i = 0u;
    while i < n {
        alt op(ss[i],ts[i]) {
          ok(v) { vs += [v]; }
          err(u) { ret err(u); }
        }
        i += 1u;
    }
    ret ok(vs);
}

#[doc = "
Applies op to the pairwise elements from `ss` and `ts`, aborting on
error.  This could be implemented using `map2()` but it is more efficient
on its own as no result vector is built.
"]
fn iter_vec2<S,T,U:copy>(ss: [S], ts: [T],
                         op: fn(S,T) -> result<(),U>)
    : vec::same_length(ss, ts)
    -> result<(),U> {

    let n = vec::len(ts);
    let mut i = 0u;
    while i < n {
        alt op(ss[i],ts[i]) {
          ok(()) { }
          err(u) { ret err(u); }
        }
        i += 1u;
    }
    ret ok(());
}

#[doc="
Unwraps a result, assuming it is an `ok(T)`
"]
fn unwrap<T, U>(-res: result<T, U>) -> T unsafe {
    let addr = alt res {
      ok(x) { ptr::addr_of(x) }
      err(_) { fail "error result" }
    };
    let liberated_value = unsafe::reinterpret_cast(*addr);
    unsafe::forget(res);
    ret liberated_value;
}

#[cfg(test)]
mod tests {
    fn op1() -> result::result<int, str> { result::ok(666) }

    fn op2(&&i: int) -> result::result<uint, str> {
        result::ok(i as uint + 1u)
    }

    fn op3() -> result::result<int, str> { result::err("sadface") }

    #[test]
    fn chain_success() {
        assert get(chain(op1(), op2)) == 667u;
    }

    #[test]
    fn chain_failure() {
        assert get_err(chain(op3(), op2)) == "sadface";
    }

    #[test]
    fn test_impl_iter() {
        let mut valid = false;
        ok::<str, str>("a").iter { |_x| valid = true; };
        assert valid;

        err::<str, str>("b").iter { |_x| valid = false; };
        assert valid;
    }

    #[test]
    fn test_impl_iter_err() {
        let mut valid = true;
        ok::<str, str>("a").iter_err { |_x| valid = false; };
        assert valid;

        valid = false;
        err::<str, str>("b").iter_err { |_x| valid = true; };
        assert valid;
    }

    #[test]
    fn test_impl_map() {
        assert ok::<str, str>("a").map { |_x| "b" } == ok("b");
        assert err::<str, str>("a").map { |_x| "b" } == err("a");
    }

    #[test]
    fn test_impl_map_err() {
        assert ok::<str, str>("a").map_err { |_x| "b" } == ok("a");
        assert err::<str, str>("a").map_err { |_x| "b" } == err("b");
    }
}
<|endoftext|>