<commit_before>#![allow(non_camel_case_types)]
#![allow(dead_code)]

#[derive(Copy,Clone)]
pub enum PartitionType {
    PARTITION_NONE,
    PARTITION_HORZ,
    PARTITION_VERT,
    PARTITION_SPLIT
}

#[derive(Copy,Clone)]
pub enum BlockSize {
    BLOCK_4X4,
    BLOCK_4X8,
    BLOCK_8X4,
    BLOCK_8X8,
    BLOCK_8X16,
    BLOCK_16X8,
    BLOCK_16X16,
    BLOCK_16X32,
    BLOCK_32X16,
    BLOCK_32X32,
    BLOCK_32X64,
    BLOCK_64X32,
    BLOCK_64X64,
    BLOCK_4X16,
    BLOCK_16X4,
    BLOCK_8X32,
    BLOCK_32X8
}

pub const TX_SIZES: usize = 4;
pub const TX_SIZES_ALL: usize = 14;

#[derive(Copy,Clone,PartialEq,PartialOrd)]
pub enum TxSize {
    TX_4X4,
    TX_8X8,
    TX_16X16,
    TX_32X32,
    TX_4X8,
    TX_8X4,
    TX_8X16,
    TX_16X8,
    TX_16X32,
    TX_32X16,
    TX_4X16,
    TX_16X4,
    TX_8X32,
    TX_32X8,
}

pub const TX_TYPES: usize = 16;

#[derive(Copy,Clone)]
#[repr(C)]
pub enum TxType {
    DCT_DCT = 0,    // DCT  in both horizontal and vertical
    ADST_DCT = 1,   // ADST in vertical, DCT in horizontal
    DCT_ADST = 2,   // DCT  in vertical, ADST in horizontal
    ADST_ADST = 3,  // ADST in both directions
    FLIPADST_DCT = 4,
    DCT_FLIPADST = 5,
    FLIPADST_FLIPADST = 6,
    ADST_FLIPADST = 7,
    FLIPADST_ADST = 8,
    IDTX = 9,
    V_DCT = 10,
    H_DCT = 11,
    V_ADST = 12,
    H_ADST = 13,
    V_FLIPADST = 14,
    H_FLIPADST = 15,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum PredictionMode {
  DC_PRED,    // Average of above and left pixels
  V_PRED,     // Vertical
  H_PRED,     // Horizontal
  D45_PRED,   // Directional 45  deg = round(arctan(1/1) * 180/pi)
  D135_PRED,  // Directional 135 deg = 180 - 45
  D117_PRED,  // Directional 117 deg = 180 - 63
  D153_PRED,  // Directional 153 deg = 180 - 27
  D207_PRED,  // Directional 207 deg = 180 + 27
  D63_PRED,   // Directional 63  deg = round(arctan(2/1) * 180/pi)
  SMOOTH_PRED,  // Combination of horizontal and vertical interpolation
  TM_PRED,        // True-motion
  NEARESTMV,
  NEARMV,
  ZEROMV,
  NEWMV,
  // Compound ref compound modes
  NEAREST_NEARESTMV,
  NEAR_NEARMV,
  NEAREST_NEWMV,
  NEW_NEARESTMV,
  NEAR_NEWMV,
  NEW_NEARMV,
  ZERO_ZEROMV,
  NEW_NEWMV,
}

use plane::*;
use predict::*;

fn setup_left(left: &mut [u16; 4], rec: &PlaneMutSlice) {
    let left_slice = rec.go_left(1);
    for i in 0..4 {
        left[i] = left_slice.p(0, i);
    }
}

impl PredictionMode {
    pub fn predict_4x4<'a>(&self, dst: &'a mut PlaneMutSlice<'a>) {
        let mut above = [127u16; 4];
        let mut left = [129u16; 4];
        let stride = dst.plane.cfg.stride;
        let x = dst.x;
        let y = dst.y;

        if (self == &PredictionMode::V_PRED ||
            self == &PredictionMode::DC_PRED) && x != 0 {
            above.copy_from_slice(&dst.go_up(1).as_slice()[..4]);
        }

        if (self == &PredictionMode::H_PRED ||
            self == &PredictionMode::DC_PRED) && y != 0 {
            setup_left(&mut left, dst);
        }

        let slice = dst.as_mut_slice();

        match *self {
            PredictionMode::DC_PRED => {
                match (x, y) {
                    (0, 0) =>
                        pred_dc_128(slice, stride),
                    (_, 0) => {
                        pred_dc_left_4x4(slice, stride, &above[..4], &left[..4]);
                    },
                    (0, _) => {
                        pred_dc_top_4x4(slice, stride, &above[..4], &left[..4])
                    },
                    _ => {
                        pred_dc(slice, stride, &above[..4], &left[..4]);
                    }
                }
            },
            PredictionMode::H_PRED => {
                pred_h(slice, stride, &left[..4], 4);
            },
            PredictionMode::V_PRED => {
                pred_v(slice, stride, &above[..4], 4);
            },
            _ => unimplemented!(),
        }
    }
}

#[derive(Copy,Clone)]
pub enum TxSetType {
    // DCT only
    EXT_TX_SET_DCTONLY = 0,
    // DCT + Identity only
    EXT_TX_SET_DCT_IDTX = 1,
    // Discrete Trig transforms w/o flip (4) + Identity (1)
    EXT_TX_SET_DTT4_IDTX = 2,
    // Discrete Trig transforms w/o flip (4) + Identity (1) + 1D Hor/vert DCT (2)
    EXT_TX_SET_DTT4_IDTX_1DDCT = 3,
    // Discrete Trig transforms w/ flip (9) + Identity (1) + 1D Hor/Ver DCT (2)
    EXT_TX_SET_DTT9_IDTX_1DDCT = 4,
    // Discrete Trig transforms w/ flip (9) + Identity (1) + 1D Hor/Ver (6)
    EXT_TX_SET_ALL16 = 5,
    EXT_TX_SET_TYPES
}
<commit_msg>Fix incorrect prediction introduced in 0df1e6ed.<commit_after>#![allow(non_camel_case_types)]
#![allow(dead_code)]

#[derive(Copy,Clone)]
pub enum PartitionType {
    PARTITION_NONE,
    PARTITION_HORZ,
    PARTITION_VERT,
    PARTITION_SPLIT
}

#[derive(Copy,Clone)]
pub enum BlockSize {
    BLOCK_4X4,
    BLOCK_4X8,
    BLOCK_8X4,
    BLOCK_8X8,
    BLOCK_8X16,
    BLOCK_16X8,
    BLOCK_16X16,
    BLOCK_16X32,
    BLOCK_32X16,
    BLOCK_32X32,
    BLOCK_32X64,
    BLOCK_64X32,
    BLOCK_64X64,
    BLOCK_4X16,
    BLOCK_16X4,
    BLOCK_8X32,
    BLOCK_32X8
}

pub const TX_SIZES: usize = 4;
pub const TX_SIZES_ALL: usize = 14;

#[derive(Copy,Clone,PartialEq,PartialOrd)]
pub enum TxSize {
    TX_4X4,
    TX_8X8,
    TX_16X16,
    TX_32X32,
    TX_4X8,
    TX_8X4,
    TX_8X16,
    TX_16X8,
    TX_16X32,
    TX_32X16,
    TX_4X16,
    TX_16X4,
    TX_8X32,
    TX_32X8,
}

pub const TX_TYPES: usize = 16;

#[derive(Copy,Clone)]
#[repr(C)]
pub enum TxType {
    DCT_DCT = 0,    // DCT  in both horizontal and vertical
    ADST_DCT = 1,   // ADST in vertical, DCT in horizontal
    DCT_ADST = 2,   // DCT  in vertical, ADST in horizontal
    ADST_ADST = 3,  // ADST in both directions
    FLIPADST_DCT = 4,
    DCT_FLIPADST = 5,
    FLIPADST_FLIPADST = 6,
    ADST_FLIPADST = 7,
    FLIPADST_ADST = 8,
    IDTX = 9,
    V_DCT = 10,
    H_DCT = 11,
    V_ADST = 12,
    H_ADST = 13,
    V_FLIPADST = 14,
    H_FLIPADST = 15,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum PredictionMode {
  DC_PRED,    // Average of above and left pixels
  V_PRED,     // Vertical
  H_PRED,     // Horizontal
  D45_PRED,   // Directional 45  deg = round(arctan(1/1) * 180/pi)
  D135_PRED,  // Directional 135 deg = 180 - 45
  D117_PRED,  // Directional 117 deg = 180 - 63
  D153_PRED,  // Directional 153 deg = 180 - 27
  D207_PRED,  // Directional 207 deg = 180 + 27
  D63_PRED,   // Directional 63  deg = round(arctan(2/1) * 180/pi)
  SMOOTH_PRED,  // Combination of horizontal and vertical interpolation
  TM_PRED,        // True-motion
  NEARESTMV,
  NEARMV,
  ZEROMV,
  NEWMV,
  // Compound ref compound modes
  NEAREST_NEARESTMV,
  NEAR_NEARMV,
  NEAREST_NEWMV,
  NEW_NEARESTMV,
  NEAR_NEWMV,
  NEW_NEARMV,
  ZERO_ZEROMV,
  NEW_NEWMV,
}

use plane::*;
use predict::*;

fn setup_left(left: &mut [u16; 4], rec: &PlaneMutSlice) {
    let left_slice = rec.go_up(1);
    for i in 0..4 {
        left[i] = left_slice.p(0, i);
    }
}

impl PredictionMode {
    pub fn predict_4x4<'a>(&self, dst: &'a mut PlaneMutSlice<'a>) {
        let mut above = [127u16; 4];
        let mut left = [129u16; 4];
        let stride = dst.plane.cfg.stride;
        let x = dst.x;
        let y = dst.y;

        if (self == &PredictionMode::V_PRED ||
            self == &PredictionMode::DC_PRED) && y != 0 {
            above.copy_from_slice(&dst.go_left(1).as_slice()[..4]);
        }

        if (self == &PredictionMode::H_PRED ||
            self == &PredictionMode::DC_PRED) && x != 0 {
            setup_left(&mut left, dst);
        }

        let slice = dst.as_mut_slice();

        match *self {
            PredictionMode::DC_PRED => {
                match (x, y) {
                    (0, 0) =>
                        pred_dc_128(slice, stride),
                    (_, 0) => {
                        pred_dc_left_4x4(slice, stride, &above[..4], &left[..4]);
                    },
                    (0, _) => {
                        pred_dc_top_4x4(slice, stride, &above[..4], &left[..4])
                    },
                    _ => {
                        pred_dc(slice, stride, &above[..4], &left[..4]);
                    }
                }
            },
            PredictionMode::H_PRED => {
                pred_h(slice, stride, &left[..4], 4);
            },
            PredictionMode::V_PRED => {
                pred_v(slice, stride, &above[..4], 4);
            },
            _ => unimplemented!(),
        }
    }
}

#[derive(Copy,Clone)]
pub enum TxSetType {
    // DCT only
    EXT_TX_SET_DCTONLY = 0,
    // DCT + Identity only
    EXT_TX_SET_DCT_IDTX = 1,
    // Discrete Trig transforms w/o flip (4) + Identity (1)
    EXT_TX_SET_DTT4_IDTX = 2,
    // Discrete Trig transforms w/o flip (4) + Identity (1) + 1D Hor/vert DCT (2)
    EXT_TX_SET_DTT4_IDTX_1DDCT = 3,
    // Discrete Trig transforms w/ flip (9) + Identity (1) + 1D Hor/Ver DCT (2)
    EXT_TX_SET_DTT9_IDTX_1DDCT = 4,
    // Discrete Trig transforms w/ flip (9) + Identity (1) + 1D Hor/Ver (6)
    EXT_TX_SET_ALL16 = 5,
    EXT_TX_SET_TYPES
}
<|endoftext|>


<commit_before>extern crate crossbeam;
#[macro_use] extern crate version;
extern crate walkdir;

use std::env;
use std::process::exit;
use std::process::Command;
use std::process::Stdio;
use std::io::ErrorKind;

use walkdir::WalkDir;
use crossbeam::*;

fn help(cmds: Vec<String>) {
    println!(r#"

     _
    (_)_ __ ___   __ _  __ _
    | | '_ \` _ \/ _\`|/ _\`|
    | | | | | | | (_| | (_| |
    |_|_| |_| |_|\__,_|\__, |
                       |___/
    -------------------------

    Usage: imag [--version | --versions | -h | --help] <command> <args...>

    imag - the personal information management suite for the commandline

    imag is a PIM suite for the commandline. It consists of several commands,
    called "modules". Each module implements one PIM aspect and all of these
    modules can be used independently.

    Available commands:
    "#);

    for cmd in cmds.iter() {
        println!("\t{}", cmd);
    }

    println!(r#"

    Call a command with 'imag <command> <args>'
    Each command can be called with "--help" to get the respective helptext.

    Please visit https://github.com/matthiasbeyer/imag to view the source code,
    follow the development of imag or maybe even contribute to imag.

    imag is free software. It is released under the terms of LGPLv2.1

    (c) 2016 Matthias Beyer and contributors"#);
}

fn get_commands() -> Vec<String> {
    let path = env::var("PATH");
    if path.is_err() {
        println!("PATH error: {:?}", path);
        exit(1);
    }
    let pathelements = path.unwrap();
    let pathelements = pathelements.split(":");

    let joinhandles : Vec<ScopedJoinHandle<Vec<String>>> = pathelements
        .map(|elem| {
            crossbeam::scope(|scope| {
                scope.spawn(|| {
                    WalkDir::new(elem)
                        .max_depth(1)
                        .into_iter()
                        .filter(|path| {
                            match path {
                                &Ok(ref path) => path.path().starts_with(format!("{}/imag-", elem)),
                                &Err(_)   => false,
                            }
                        })
                        .filter_map(|x| x.ok())
                        .map(|path| {
                            path.path()
                                .to_str()
                                .map(String::from)
                        })
                        .filter_map(|x| x)
                        .collect()
                })
            })
        })
        .collect();

    let mut execs = vec![];
    for joinhandle in joinhandles.into_iter() {
        let mut v = joinhandle.join();
        execs.append(&mut v);
    }

    execs
}

fn main() {
    let commands  = get_commands();
    let mut args  = env::args();
    let _         = args.next();
    let first_arg = match args.next() {
        Some(s) => s,
        None    => {
            help(commands);
            exit(0);
        },
    };

    match &first_arg[..] {
        "--help" | "-h" => {
            help(commands);
            exit(0);
        },

        "--version"  => println!("imag {}", &version!()[..]),

        "--versions" => {
            let mut result = vec![];
            for command in commands.iter() {
                result.push(crossbeam::scope(|scope| {
                    scope.spawn(|| {
                        let v = Command::new(command).arg("--version").output();
                        match v {
                            Ok(v) => match String::from_utf8(v.stdout) {
                                Ok(s) => format!("{} -> {}", command, s),
                                Err(e) => format!("Failed calling {} -> {:?}", command, e),
                            },
                            Err(e) => format!("Failed calling {} -> {:?}", command, e),
                        }
                    })
                }))
            }

            for versionstring in result.into_iter().map(|handle| handle.join()) {
                println!("{}", versionstring);
            }
        },

        s => {
            match Command::new(format!("imag-{}", s))
                .stdin(Stdio::inherit())
                .stdout(Stdio::inherit())
                .stderr(Stdio::inherit())
                .spawn()
                .and_then(|mut handle| handle.wait())
            {
                Ok(exit_status) => {
                    if !exit_status.success() {
                        println!("{} exited with non-zero exit code", s);
                        exit(exit_status.code().unwrap_or(42));
                    }
                },

                Err(e) => {
                    match e.kind() {
                        ErrorKind::NotFound => {
                            println!("No such command: 'imag-{}'", s);
                            exit(2);
                        },
                        ErrorKind::PermissionDenied => {
                            println!("No permission to execute: 'imag-{}'", s);
                            exit(1);
                        },
                        _ => {
                            println!("Error spawning: {:?}", e);
                            exit(1337);
                        }
                    }
                }
            }

        },
    }
}
<commit_msg>Add command finder helper function<commit_after>extern crate crossbeam;
#[macro_use] extern crate version;
extern crate walkdir;

use std::env;
use std::process::exit;
use std::process::Command;
use std::process::Stdio;
use std::io::ErrorKind;

use walkdir::WalkDir;
use crossbeam::*;

fn help(cmds: Vec<String>) {
    println!(r#"

     _
    (_)_ __ ___   __ _  __ _
    | | '_ \` _ \/ _\`|/ _\`|
    | | | | | | | (_| | (_| |
    |_|_| |_| |_|\__,_|\__, |
                       |___/
    -------------------------

    Usage: imag [--version | --versions | -h | --help] <command> <args...>

    imag - the personal information management suite for the commandline

    imag is a PIM suite for the commandline. It consists of several commands,
    called "modules". Each module implements one PIM aspect and all of these
    modules can be used independently.

    Available commands:
    "#);

    for cmd in cmds.iter() {
        println!("\t{}", cmd);
    }

    println!(r#"

    Call a command with 'imag <command> <args>'
    Each command can be called with "--help" to get the respective helptext.

    Please visit https://github.com/matthiasbeyer/imag to view the source code,
    follow the development of imag or maybe even contribute to imag.

    imag is free software. It is released under the terms of LGPLv2.1

    (c) 2016 Matthias Beyer and contributors"#);
}

fn get_commands() -> Vec<String> {
    let path = env::var("PATH");
    if path.is_err() {
        println!("PATH error: {:?}", path);
        exit(1);
    }
    let pathelements = path.unwrap();
    let pathelements = pathelements.split(":");

    let joinhandles : Vec<ScopedJoinHandle<Vec<String>>> = pathelements
        .map(|elem| {
            crossbeam::scope(|scope| {
                scope.spawn(|| {
                    WalkDir::new(elem)
                        .max_depth(1)
                        .into_iter()
                        .filter(|path| {
                            match path {
                                &Ok(ref path) => path.path().starts_with(format!("{}/imag-", elem)),
                                &Err(_)   => false,
                            }
                        })
                        .filter_map(|x| x.ok())
                        .map(|path| {
                            path.path()
                                .to_str()
                                .map(String::from)
                        })
                        .filter_map(|x| x)
                        .collect()
                })
            })
        })
        .collect();

    let mut execs = vec![];
    for joinhandle in joinhandles.into_iter() {
        let mut v = joinhandle.join();
        execs.append(&mut v);
    }

    execs
}

fn find_command() -> Option<String> {
    env::args().skip(1).filter(|x| !x.starts_with("-")).next()
}

fn main() {
    let commands  = get_commands();
    let mut args  = env::args();
    let _         = args.next();
    let first_arg = match find_command() {
        Some(s) => s,
        None    => {
            help(commands);
            exit(0);
        },
    };

    match &first_arg[..] {
        "--help" | "-h" => {
            help(commands);
            exit(0);
        },

        "--version"  => println!("imag {}", &version!()[..]),

        "--versions" => {
            let mut result = vec![];
            for command in commands.iter() {
                result.push(crossbeam::scope(|scope| {
                    scope.spawn(|| {
                        let v = Command::new(command).arg("--version").output();
                        match v {
                            Ok(v) => match String::from_utf8(v.stdout) {
                                Ok(s) => format!("{} -> {}", command, s),
                                Err(e) => format!("Failed calling {} -> {:?}", command, e),
                            },
                            Err(e) => format!("Failed calling {} -> {:?}", command, e),
                        }
                    })
                }))
            }

            for versionstring in result.into_iter().map(|handle| handle.join()) {
                println!("{}", versionstring);
            }
        },

        s => {
            match Command::new(format!("imag-{}", s))
                .stdin(Stdio::inherit())
                .stdout(Stdio::inherit())
                .stderr(Stdio::inherit())
                .spawn()
                .and_then(|mut handle| handle.wait())
            {
                Ok(exit_status) => {
                    if !exit_status.success() {
                        println!("{} exited with non-zero exit code", s);
                        exit(exit_status.code().unwrap_or(42));
                    }
                },

                Err(e) => {
                    match e.kind() {
                        ErrorKind::NotFound => {
                            println!("No such command: 'imag-{}'", s);
                            exit(2);
                        },
                        ErrorKind::PermissionDenied => {
                            println!("No permission to execute: 'imag-{}'", s);
                            exit(1);
                        },
                        _ => {
                            println!("Error spawning: {:?}", e);
                            exit(1337);
                        }
                    }
                }
            }

        },
    }
}
<|endoftext|>


<commit_before>use ::color::FloatColor;
use ::color::Color;

struct HistColor {
    color: FloatColor,
    count: usize,
}

struct QuantizerNode {
    histogram: Vec<HistColor>,
    avg: FloatColor,
    vdif: f64,
    split: usize,
}

impl QuantizerNode {
    fn new(mut histogram: Vec<HistColor>) -> QuantizerNode {
        let mut n = 0usize;
        let mut fsum = FloatColor::default();
        let mut fsum2 = FloatColor::default();

        for entry in &histogram {
            n += entry.count;
            fsum += entry.color * entry.count as f64;
            fsum2 += entry.color * entry.color * entry.count as f64;
        }

        if n == 0 {
            return QuantizerNode {
                histogram: histogram,
                avg: FloatColor::default(),
                vdif: 0.0,
                split: 0,
            };
        }

        let avg = fsum * (1.0 / n as f64);
        let vc = fsum2 - fsum * avg;
        let v = vc.r + vc.g + vc.b + vc.a;

        if vc.r > vc.g && vc.r > vc.b && vc.r > vc.a {
            histogram.sort_by(|a, b| a.color.r.partial_cmp(&b.color.r).unwrap());
        } else if vc.g > vc.b && vc.g > vc.a {
            histogram.sort_by(|a, b| a.color.g.partial_cmp(&b.color.g).unwrap());
        } else if vc.b > vc.a {
            histogram.sort_by(|a, b| a.color.b.partial_cmp(&b.color.b).unwrap());
        } else {
            histogram.sort_by(|a, b| a.color.a.partial_cmp(&b.color.a).unwrap());
        }

        let mut dir = FloatColor::default();
        for entry in &histogram {
            let mut tmp = (entry.color - avg) * entry.count as f64;
            if tmp.dot(&tmp) < 0.0 {
                tmp *= -1.0;
            }
            dir += tmp;
        }

        dir *= {
            let s = dir.dot(&dir).sqrt();
            if s < 0.000000001 { 1.0 } else { 1.0 / s }
        };

        histogram.sort_by(|a, b| a.color.dot(&dir).partial_cmp(&b.color.dot(&dir)).unwrap());

        let mut sum = FloatColor::default();
        let mut sum2 = FloatColor::default();
        let mut vdif = -v;
        let mut n2 = 0;
        let mut split = 0usize;
        let mut i = 0;
        for entry in &histogram {
            n2 += entry.count;
            sum += entry.color * entry.count as f64;
            sum2 += entry.color * entry.color * entry.count as f64;

            if n2 < n {
                let tmp = sum2 - sum * sum * (1.0 / n2 as f64);
                let dif_sum = fsum - sum;
                let tmp2 = (fsum2 - sum2) - dif_sum * dif_sum * (1.0 / (n - n2) as f64);
                let nv = tmp.r + tmp.g + tmp.b + tmp.a + tmp2.r + tmp2.g + tmp2.b + tmp2.a;
                if -nv > vdif {
                    vdif = -nv;
                    split = i;
                }
            }

            i += 1;
        }

        QuantizerNode {
            histogram: histogram,
            avg: avg,
            vdif: vdif + v,
            split: split,
        }
    }
}

pub fn create_palette(histogram: &::histogram::Histogram, num_colors: usize) -> Vec<Color> {
    let hist: Vec<_> = histogram.data
        .iter()
        .map(|(color, count)| {
            HistColor {
                color: color.into(),
                count: *count,
            }
        })
        .collect();

    let mut nodes = vec![QuantizerNode::new(hist)];

    while nodes.len() < num_colors {
        let (new_node1, new_node2) = {
            let node = {
                let mut best_i = 0;
                let mut best_e = 0.0;
                for i in 1..nodes.len() - 1 {
                    if nodes[i].vdif >= best_e {
                        best_e = nodes[i].vdif;
                        best_i = i;
                    }
                }
                nodes.swap_remove(best_i)
            };
            let mut colors1 = node.histogram;
            let colors2 = colors1.split_off(node.split);
            (QuantizerNode::new(colors1), QuantizerNode::new(colors2))
        };
        nodes.push(new_node1);
        nodes.push(new_node2);
    }

    nodes.iter().map(|n| n.avg.into()).collect()
}
<commit_msg>fix basic quantizer<commit_after>use ::color::FloatColor;
use ::color::Color;

struct HistColor {
    color: FloatColor,
    count: usize,
}

struct QuantizerNode {
    histogram: Vec<HistColor>, // a histogram of the colors represented by this node
    avg: FloatColor, // the average color of this node
    vdif: f64, // the improvement to the total variance when splitting this node
    split: usize, // the best index to split this node at
}

impl QuantizerNode {
    fn new(mut histogram: Vec<HistColor>) -> QuantizerNode {
        // First calculate the color average and variance over the histogram
        let mut n = 0usize;
        let mut fsum = FloatColor::default();
        let mut fsum2 = FloatColor::default();

        for entry in &histogram {
            n += entry.count;
            fsum += entry.color * entry.count as f64;
            fsum2 += entry.color * entry.color * entry.count as f64;
        }

        if n == 0 {
            return QuantizerNode {
                histogram: histogram,
                avg: FloatColor::default(),
                vdif: 0.0,
                split: 0,
            };
        }

        let avg = fsum * (1.0 / n as f64);
        let vc = fsum2 - fsum * avg;
        let v = vc.r + vc.g + vc.b + vc.a;

        // Next sort histogram by the channel with the largest variance
        if vc.r > vc.g && vc.r > vc.b && vc.r > vc.a {
            histogram.sort_by(|a, b| a.color.r.partial_cmp(&b.color.r).unwrap());
        } else if vc.g > vc.b && vc.g > vc.a {
            histogram.sort_by(|a, b| a.color.g.partial_cmp(&b.color.g).unwrap());
        } else if vc.b > vc.a {
            histogram.sort_by(|a, b| a.color.b.partial_cmp(&b.color.b).unwrap());
        } else {
            histogram.sort_by(|a, b| a.color.a.partial_cmp(&b.color.a).unwrap());
        }

        // Determine primary vector of distribution in the histogram
        let mut dir = FloatColor::default();
        for entry in &histogram {
            let mut tmp = (entry.color - avg) * entry.count as f64;
            if tmp.dot(&dir) < 0.0 {
                tmp *= -1.0;
            }
            dir += tmp;
        }

        dir *= {
            let s = dir.dot(&dir).sqrt();
            if s < 0.000000001 {
                1.0
            } else {
                1.0 / s
            }
        };

        // Now sort histogram by primary vector
        histogram.sort_by(|a, b| a.color.dot(&dir).partial_cmp(&b.color.dot(&dir)).unwrap());

        // Find split index that results in lowest total variance
        let mut sum = FloatColor::default();
        let mut sum2 = FloatColor::default();
        let mut vdif = -v;
        let mut n2 = 0;
        let mut split = 0usize;
        let mut i = 0;
        for entry in &histogram {
            n2 += entry.count;
            sum += entry.color * entry.count as f64;
            sum2 += entry.color * entry.color * entry.count as f64;

            if n2 < n {
                let tmp = sum2 - sum * sum * (1.0 / n2 as f64);
                let dif_sum = fsum - sum;
                let tmp2 = (fsum2 - sum2) - dif_sum * dif_sum * (1.0 / (n - n2) as f64);
                let nv = tmp.r + tmp.g + tmp.b + tmp.a + tmp2.r + tmp2.g + tmp2.b + tmp2.a;
                if -nv > vdif {
                    vdif = -nv;
                    split = i + 1;
                }
            }

            i += 1;
        }

        QuantizerNode {
            histogram: histogram,
            avg: avg,
            vdif: vdif + v,
            split: split,
        }
    }
}

pub fn create_palette(histogram: &::histogram::Histogram, num_colors: usize) -> Vec<Color> {
    let hist: Vec<_> = histogram.data
        .iter()
        .map(|(color, count)| {
            HistColor {
                color: color.into(),
                count: *count,
            }
        })
        .collect();

    let mut nodes = vec![QuantizerNode::new(hist)];

    while nodes.len() < num_colors {
        let (new_node1, new_node2) = {
            let node = {
                let mut best_i = 0;
                let mut best_e = 0.0;
                for i in 0..nodes.len() {
                    if nodes[i].vdif >= best_e {
                        best_e = nodes[i].vdif;
                        best_i = i;
                    }
                }
                nodes.swap_remove(best_i)
            };
            let mut colors1 = node.histogram;
            let colors2 = colors1.split_off(node.split);
            (QuantizerNode::new(colors1), QuantizerNode::new(colors2))
        };
        nodes.push(new_node1);
        nodes.push(new_node2);
    }

    nodes.iter().map(|n| n.avg.into()).collect()
}
<|endoftext|>


<commit_before>
use qvariant::*;
use types::*;
use qurl::*;

extern "C" {
    fn dos_qapplication_create();
    fn dos_qapplication_exec();
    fn dos_qapplication_quit();
    fn dos_qapplication_delete();

    fn dos_qqmlapplicationengine_create() -> DosQmlApplicationEngine;
    fn dos_qqmlapplicationengine_load(vptr: DosQmlApplicationEngine, filename: DosCStr);
    fn dos_qqmlapplicationengine_load_url(vptr: DosQmlApplicationEngine, url: DosQUrl);
    fn dos_qqmlapplicationengine_load_data(vptr: DosQmlApplicationEngine, data: DosCStr);
    // fn dos_qqmlapplicationengine_add_import_path(vptr: *mut DosQQmlApplicationEngine, const char *path);
    fn dos_qqmlapplicationengine_context(vptr: DosQmlApplicationEngine) -> DosQQmlContext;
    fn dos_qqmlapplicationengine_delete(vptr: DosQmlApplicationEngine);

    fn dos_qqmlcontext_setcontextproperty(vptr: DosQQmlContext,
                                          name: DosCStr,
                                          value: DosQVariant);

}

/// Provides an entry point for building QML applications from Rust
pub struct QmlEngine {
    ptr: DosQmlApplicationEngine,
    stored: Vec<QVariant>,
}

impl QmlEngine {
    /// Creates a QML context of a non-headless application
    pub fn new() -> Self {
        unsafe {
            dos_qapplication_create();
            QmlEngine {
                ptr: dos_qqmlapplicationengine_create(),
                stored: Vec::new(),
            }
        }
    }

    /// Loads a file as a qml file
    pub fn load_file(&mut self, path: &str) {
        let path_raw = ::std::env::current_dir().unwrap().join(path);
        let path = if cfg!(windows) {
            format!("file:///{}", path_raw.display())
        } else {
            format!("file://{}", path_raw.display())
        };
        unsafe { dos_qqmlapplicationengine_load_url(self.ptr, construct_qurl(&path)) }
    }

    /// Loads qml from a specified url (`file://`, `qrc://`, `http://`)
    pub fn load_url(&mut self, uri: &str) {
        unsafe { dos_qqmlapplicationengine_load_url(self.ptr, construct_qurl(uri)) }
    }

    /// Loads a string as a qml file
    pub fn load_data(&mut self, data: &str) {
        unsafe { dos_qqmlapplicationengine_load_data(self.ptr, stoptr(data)) }
    }

    /// Launches the application
    pub fn exec(&mut self) {
        unsafe {
            dos_qapplication_exec();
        }
    }
    /// Closes the application
    pub fn quit(&mut self) {
        unsafe {
            dos_qapplication_quit();
        }
    }

    /// Sets a property for this QML context
    ///
    /// This variant stores qvariant, so it is removed, only when this QmlEngine is removed.
    pub fn set_and_store_property<T: Into<QVariant>>(&mut self, name: &str, value: T) {
        let val = value.into();
        unsafe {
            let context = dos_qqmlapplicationengine_context(self.ptr);
            dos_qqmlcontext_setcontextproperty(context, stoptr(name), get_private_variant(&val));
        }
        self.stored.push(val);
    }

    /// Sets a property for this QML context
    pub fn set_property(&mut self, name: &str, value: &QVariant) {
        unsafe {
            let context = dos_qqmlapplicationengine_context(self.ptr);
            dos_qqmlcontext_setcontextproperty(context, stoptr(name), get_private_variant(value));
        }
    }
}

use utils::*;

impl Default for QmlEngine {
    fn default() -> Self {
        Self::new()
    }
}

impl Drop for QmlEngine {
    fn drop(&mut self) {
        unsafe {
            dos_qapplication_quit();
            dos_qqmlapplicationengine_delete(self.ptr);
            dos_qapplication_delete();
        }
    }
}
<commit_msg>added QmlEngine::add_import_path()<commit_after>
use qvariant::*;
use types::*;
use qurl::*;

extern "C" {
    fn dos_qapplication_create();
    fn dos_qapplication_exec();
    fn dos_qapplication_quit();
    fn dos_qapplication_delete();

    fn dos_qqmlapplicationengine_create() -> DosQmlApplicationEngine;
    fn dos_qqmlapplicationengine_load(vptr: DosQmlApplicationEngine, filename: DosCStr);
    fn dos_qqmlapplicationengine_load_url(vptr: DosQmlApplicationEngine, url: DosQUrl);
    fn dos_qqmlapplicationengine_load_data(vptr: DosQmlApplicationEngine, data: DosCStr);
    fn dos_qqmlapplicationengine_add_import_path(vptr: DosQmlApplicationEngine, path: DosCStr);
    fn dos_qqmlapplicationengine_context(vptr: DosQmlApplicationEngine) -> DosQQmlContext;
    fn dos_qqmlapplicationengine_delete(vptr: DosQmlApplicationEngine);

    fn dos_qqmlcontext_setcontextproperty(vptr: DosQQmlContext,
                                          name: DosCStr,
                                          value: DosQVariant);

}

/// Provides an entry point for building QML applications from Rust
pub struct QmlEngine {
    ptr: DosQmlApplicationEngine,
    stored: Vec<QVariant>,
}

impl QmlEngine {
    /// Creates a QML context of a non-headless application
    pub fn new() -> Self {
        unsafe {
            dos_qapplication_create();
            QmlEngine {
                ptr: dos_qqmlapplicationengine_create(),
                stored: Vec::new(),
            }
        }
    }

    /// Loads a file as a qml file
    pub fn load_file(&mut self, path: &str) {
        let path_raw = ::std::env::current_dir().unwrap().join(path);
        let path = if cfg!(windows) {
            format!("file:///{}", path_raw.display())
        } else {
            format!("file://{}", path_raw.display())
        };
        unsafe { dos_qqmlapplicationengine_load_url(self.ptr, construct_qurl(&path)) }
    }

    /// Loads qml from a specified url (`file://`, `qrc://`, `http://`)
    pub fn load_url(&mut self, uri: &str) {
        unsafe { dos_qqmlapplicationengine_load_url(self.ptr, construct_qurl(uri)) }
    }

    /// Adds a path to the QML import path
    /// On an "import ModuleName" call QML will additionally search this path for the matching module.
    pub fn add_import_path(&mut self, path: &str) {
        unsafe { dos_qqmlapplicationengine_add_import_path(self.ptr, stoptr(path)) }
    }

    /// Loads a string as a qml file
    pub fn load_data(&mut self, data: &str) {
        unsafe { dos_qqmlapplicationengine_load_data(self.ptr, stoptr(data)) }
    }

    /// Launches the application
    pub fn exec(&mut self) {
        unsafe {
            dos_qapplication_exec();
        }
    }
    /// Closes the application
    pub fn quit(&mut self) {
        unsafe {
            dos_qapplication_quit();
        }
    }

    /// Sets a property for this QML context
    ///
    /// This variant stores qvariant, so it is removed, only when this QmlEngine is removed.
    pub fn set_and_store_property<T: Into<QVariant>>(&mut self, name: &str, value: T) {
        let val = value.into();
        unsafe {
            let context = dos_qqmlapplicationengine_context(self.ptr);
            dos_qqmlcontext_setcontextproperty(context, stoptr(name), get_private_variant(&val));
        }
        self.stored.push(val);
    }

    /// Sets a property for this QML context
    pub fn set_property(&mut self, name: &str, value: &QVariant) {
        unsafe {
            let context = dos_qqmlapplicationengine_context(self.ptr);
            dos_qqmlcontext_setcontextproperty(context, stoptr(name), get_private_variant(value));
        }
    }
}

use utils::*;

impl Default for QmlEngine {
    fn default() -> Self {
        Self::new()
    }
}

impl Drop for QmlEngine {
    fn drop(&mut self) {
        unsafe {
            dos_qapplication_quit();
            dos_qqmlapplicationengine_delete(self.ptr);
            dos_qapplication_delete();
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2104 Michael Dvorkin
// Ante is an esoteric programming language where all you've got is a deck of cards.
//
// This is Ante implementation in Rust.

extern crate regex;
extern crate num;

use std::io::File;
use std::collections::HashMap;

use regex::Regex;
use num::bigint::BigInt;

static A: u32 = 65;
static J: u32 = 74;
static Q: u32 = 81;
static K: u32 = 75;

struct Card {
    rank: u32,
    suit: u32
}

struct Ante {
    pc:     uint,                   // Program counter (index within ante.code)
    line:   uint,                   // Current line number.
    code:   Vec<Card>,              // Array of cards.
    vars:   HashMap<char, uint>,    // Four registers hashed by suit.
    labels: HashMap<uint, uint>,    // Labels for ante.pc to jump to.
}

impl Ante {
    fn new(filename: &str) -> Ante {
        let mut vars = HashMap::new();
        vars.insert('♦', 0);
        vars.insert('♥', 0);
        vars.insert('♠', 0);
        vars.insert('♣', 0);

        let code = Ante::parse(filename);
        let labels = Ante::resolve(&code);

        Ante {
            pc:     0,
            line:   0,
            code:   code,
            vars:   vars,
            labels: labels
        }
    }

    fn run(&mut self) -> &Ante {
        while self.pc < self.code.len() {
            let card = self.code[self.pc];
            self.pc += 1;
            match card.rank {
                0  => self.newline(card),
                K  => self.jump(card),
                Q  => continue,
                J  => self.dump(card, true),
                10 => self.dump(card, false),
                _  => self.assign(card)
            };
        }
        self
    }

    // Turn source file into array of cards.
    fn parse(filename: &str) -> Vec<Card> {
        let mut file = File::open(&Path::new(filename));
        let program = file.read_to_string().unwrap();
        println!("file: {}", program);

        // Split program blob into lines getting rid of comments and whitespaces.
        let comments = Regex::new(r"#.*$").unwrap();
        let lines: Vec<String> = program.as_slice().lines().map( |line|
            comments.replace_all(line, "").as_slice().trim().to_string()
        ).collect();

        //\\ DEBUG //\\
        for i in range(0, lines.len()) {
            println!("{:2}) parsing: /{}/", i, lines[i]);
        }

        // Turn source file into array of cards. Each card a struct of rank and suit.
        let mut code: Vec<Card> = vec![];
        let card = Regex::new(r"(10|[2-9JQKA])([♦♥♠♣])").unwrap();
        for (i, line) in lines.iter().enumerate() {
            // Line number cards have zero rank.
            code.push(Card { rank: 0, suit: i as u32 + 1 });

            // Parse cards using regural expression. Card rank and suit characters get saved
            // as u32 runes (to cast u32 back to char use std::char::from_u32(ch).unwrap()).
            for caps in card.captures_iter(line.as_slice()) {
                let rank = caps.at(1).char_at(0);
                let suit = caps.at(2).char_at(0);
                let card = match rank {
                   '1'       => Card { rank: 10, suit: suit as u32 },
                   '2'...'9' => Card { rank: rank as u32 - 48, suit: suit as u32 },
                   _         => Card { rank: rank as u32, suit: suit as u32 }
                };
                code.push(card);
            }
        }

        //\\ DEBUG //\\
        for i in range(0, code.len()) {
            println!("{:2}) code: /{}:{}/", i, code[i].rank, code[i].suit);
        }
        code
    }

    // Extra pass to set up jump labels.
    fn resolve(code: &Vec<Card>) -> HashMap<uint, uint> {
        let mut pc = 0u;
        let mut labels: HashMap<uint, uint> = HashMap::new();

        while pc < code.len() - 1 {
            let card = code[pc];
            pc += 1;
            if card.rank == Q {
                let mut queen = card.suit as uint;
                while pc < code.len() && code[pc].rank == Q && code[pc].suit == card.suit {
                    queen += card.suit as uint;
                    pc += 1;
                }
                labels.insert(queen, pc);
            }
        }

        //\\ DEBUG //\\
        for (k,v) in labels.iter() {
            println!("label: /{} => {}/", k, v);
        }
        labels
    }

    fn newline(&mut self, card: Card) -> &Ante {
        //println!("newline {}:{}", card.rank, card.suit);
        self.line = card.suit as uint;
        self
    }

    fn jump(&self, card: Card) -> &Ante {
        //println!("jump {}:{}", card.rank, card.suit);
        self
    }

    fn assign(&mut self, card: Card) -> &Ante {
        //println!("assign {}:{}", card.rank, card.suit);
        let operands = self.remaining(card);
        self.expression(operands)
    }

    fn dump(&self, card: Card, as_character: bool) -> &Ante {
        //println!("dump {}:{} as character {}", card.rank, card.suit, as_character);
        let value = self.vars[std::char::from_u32(card.suit).unwrap()];
        if as_character {
            if value >= 0 as uint && value <= 255 as uint {
                print!("{}", std::char::from_u32(value as u32).unwrap());
            } else {
                self.exception(format!("character code {} is out of 0..255 range", value).as_slice());
            }
        } else {
            print!("{}", value);
        }
        self
    }

    fn remaining(&mut self, card: Card) -> Vec<Card> {
        let mut operands: Vec<Card> = vec![card];

        while self.pc < self.code.len() {
            let card = self.code[self.pc];
            if card.rank == 0 || card.rank == K || card.rank == Q || card.rank == J {
                break;
            }
            operands.push(card);
            self.pc += 1;
        }
        operands
    }

    fn expression(&mut self, operands: Vec<Card>) -> &Ante {
        let mut initial = operands[0].rank;
        let target = std::char::from_u32(operands[0].suit).unwrap();

        if initial == A {
            initial = self.vars[target] as u32;
        }

        for i in range(1, operands.len()) {
            let mut rank = operands[i].rank;
            let suit = std::char::from_u32(operands[i].suit).unwrap();

            if rank == A {
                rank = self.vars[suit] as u32;
            }
            match suit {
                '♦' => initial += rank,
                '♥' => initial *= rank,
                '♠' => initial -= rank,
                '♣' => if rank != 0 {
                            initial /= rank;
                        } else {
                            self.exception("division by zero");
                        },
                _ => continue
            }
        }

        *self.vars.get_mut(&target) = initial as uint;
        self
    }

    // NOTE: fail! got renamed to panic!
    fn exception(&self, message: &str) {
        fail!("Ante exception: {} on line {} (pc:{})\n", message, self.line, self.pc)
    }
}

fn main() {
    println!("usage: ante filename.ante");
    Ante::new("hello.ante".as_slice()).run();
}
<commit_msg>Complete implementation without BigInt<commit_after>// Copyright (c) 2013-2104 Michael Dvorkin
// Ante is an esoteric programming language where all you've got is a deck of cards.
//
// This is Ante implementation in Rust.

extern crate regex;
extern crate num;

use std::io::File;
use std::collections::HashMap;

use regex::Regex;
use num::bigint::BigInt;

static A: u32 = 65;
static J: u32 = 74;
static Q: u32 = 81;
static K: u32 = 75;

struct Card {
    rank: u32,
    suit: u32
}

struct Ante {
    pc:     uint,                   // Program counter (index within ante.code)
    line:   uint,                   // Current line number.
    code:   Vec<Card>,              // Array of cards.
    vars:   HashMap<char, uint>,    // Four registers hashed by suit.
    labels: HashMap<uint, uint>,    // Labels for ante.pc to jump to.
}

impl Ante {
    fn new(filename: &str) -> Ante {
        let mut vars = HashMap::new();
        vars.insert('♦', 0);
        vars.insert('♥', 0);
        vars.insert('♠', 0);
        vars.insert('♣', 0);

        let code = Ante::parse(filename);
        let labels = Ante::resolve(&code);

        Ante {
            pc:     0,
            line:   0,
            code:   code,
            vars:   vars,
            labels: labels
        }
    }

    fn run(&mut self) -> &Ante {
        while self.pc < self.code.len() {
            let card = self.code[self.pc];
            self.pc += 1;
            match card.rank {
                0  => self.newline(card),
                K  => self.jump(card),
                Q  => continue,
                J  => self.dump(card, true),
                10 => self.dump(card, false),
                _  => self.assign(card)
            };
        }
        self
    }

    // Turn source file into array of cards.
    fn parse(filename: &str) -> Vec<Card> {
        let mut file = File::open(&Path::new(filename));
        let program = file.read_to_string().unwrap();
        println!("file: {}", program);

        // Split program blob into lines getting rid of comments and whitespaces.
        let comments = Regex::new(r"#.*$").unwrap();
        let lines: Vec<String> = program.as_slice().lines().map( |line|
            comments.replace_all(line, "").as_slice().trim().to_string()
        ).collect();

        //\\ DEBUG //\\
        for i in range(0, lines.len()) {
            println!("{:2}) parsing: /{}/", i, lines[i]);
        }

        // Turn source file into array of cards. Each card a struct of rank and suit.
        let mut code: Vec<Card> = vec![];
        let card = Regex::new(r"(10|[2-9JQKA])([♦♥♠♣])").unwrap();
        for (i, line) in lines.iter().enumerate() {
            // Line number cards have zero rank.
            code.push(Card { rank: 0, suit: i as u32 + 1 });

            // Parse cards using regural expression. Card rank and suit characters get saved
            // as u32 runes (to cast u32 back to char use std::char::from_u32(ch).unwrap()).
            for caps in card.captures_iter(line.as_slice()) {
                let rank = caps.at(1).char_at(0);
                let suit = caps.at(2).char_at(0);
                let card = match rank {
                   '1'       => Card { rank: 10, suit: suit as u32 },
                   '2'...'9' => Card { rank: rank as u32 - 48, suit: suit as u32 },
                   _         => Card { rank: rank as u32, suit: suit as u32 }
                };
                code.push(card);
            }
        }

        //\\ DEBUG //\\
        for i in range(0, code.len()) {
            println!("{:2}) code: /{}:{}/", i, code[i].rank, code[i].suit);
        }
        code
    }

    // Extra pass to set up jump labels.
    fn resolve(code: &Vec<Card>) -> HashMap<uint, uint> {
        let mut pc = 0u;
        let mut labels: HashMap<uint, uint> = HashMap::new();

        while pc < code.len() - 1 {
            let card = code[pc];
            pc += 1;
            if card.rank == Q {
                let mut queen = card.suit as uint;
                while pc < code.len() && code[pc].rank == Q && code[pc].suit == card.suit {
                    queen += card.suit as uint;
                    pc += 1;
                }
                labels.insert(queen, pc);
            }
        }

        //\\ DEBUG //\\
        for (k,v) in labels.iter() {
            println!("label: /{} => {}/", k, v);
        }
        labels
    }

    fn newline(&mut self, card: Card) -> &Ante {
        //println!("newline {}:{}", card.rank, card.suit);
        self.line = card.suit as uint;
        self
    }

    fn jump(&mut self, card: Card) -> &Ante {
        //println!("jump {}:{}", card.rank, card.suit);
        let mut suit = card.suit;
        while self.pc < self.code.len() && self.code[self.pc].rank == K && self.code[self.pc].suit == card.suit {
            suit += card.suit;
            self.pc += 1;
        }

        if self.vars[std::char::from_u32(card.suit).unwrap()] != 0 {
            let label: uint = suit as uint;
            if self.labels.contains_key(&label) {
                self.pc = self.labels[label];
            } else {
                self.exception("can't find the label...");
            }
        }
        self
    }

    fn assign(&mut self, card: Card) -> &Ante {
        //println!("assign {}:{}", card.rank, card.suit);
        let operands = self.remaining(card);
        self.expression(operands)
    }

    fn dump(&self, card: Card, as_character: bool) -> &Ante {
        //println!("dump {}:{} as character {}", card.rank, card.suit, as_character);
        let value = self.vars[std::char::from_u32(card.suit).unwrap()];
        if as_character {
            if value >= 0 as uint && value <= 255 as uint {
                print!("{}", std::char::from_u32(value as u32).unwrap());
            } else {
                self.exception(format!("character code {} is out of 0..255 range", value).as_slice());
            }
        } else {
            print!("{}", value);
        }
        self
    }

    fn remaining(&mut self, card: Card) -> Vec<Card> {
        let mut operands: Vec<Card> = vec![card];

        while self.pc < self.code.len() {
            let card = self.code[self.pc];
            if card.rank == 0 || card.rank == K || card.rank == Q || card.rank == J {
                break;
            }
            operands.push(card);
            self.pc += 1;
        }
        operands
    }

    fn expression(&mut self, operands: Vec<Card>) -> &Ante {
        let mut initial = operands[0].rank;
        let target = std::char::from_u32(operands[0].suit).unwrap();

        if initial == A {
            initial = self.vars[target] as u32;
        }

        for i in range(1, operands.len()) {
            let mut rank = operands[i].rank;
            let suit = std::char::from_u32(operands[i].suit).unwrap();

            if rank == A {
                rank = self.vars[suit] as u32;
            }
            match suit {
                '♦' => initial += rank,
                '♥' => initial *= rank,
                '♠' => initial -= rank,
                '♣' => if rank != 0 {
                            initial /= rank;
                        } else {
                            self.exception("division by zero");
                        },
                _ => continue
            }
        }

        *self.vars.get_mut(&target) = initial as uint;
        self
    }

    // NOTE: fail! got renamed to panic!
    fn exception(&self, message: &str) {
        fail!("Ante exception: {} on line {} (pc:{})\n", message, self.line, self.pc)
    }
}

fn main() {
    println!("usage: ante filename.ante");
    Ante::new("numbers.ante".as_slice()).run();
}
<|endoftext|>


<commit_before>//! [β-reduction](https://en.wikipedia.org/wiki/Beta_normal_form) for lambda `Term`s

use term::{Term, TermError};
use term::Term::*;
use std::fmt;
use std::mem;
pub use self::Order::*;

/// The [evaluation order](http://www.cs.cornell.edu/courses/cs6110/2014sp/Handouts/Sestoft.pdf) of
/// β-reductions. The default is `NOR` (normal order).
///
/// They don't always yield the same result:
///
/// - The `NOR`, `HNO`, `APP` and `HAP` orders reduce expressions to their normal forms
/// - The `APP` order will fail to fully reduce expressions containing functions without a normal
/// form, e.g. the `Y` combinator (they will expand forever)
/// - The `CBN` order reduces to weak head normal form
/// - The `CBV` order reduces to weak normal form
/// - The `HSP` order reduces to head normal form
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Order {
    /// Normal - leftmost outermost; the most popular lambda calculus reduction strategy
    NOR,
    /// Call-by-name - leftmost outermost, but no reductions inside abstractions
    CBN,
    /// Head spine - leftmost outermost, but abstractions reduced only in head position
    HSP,
    /// Hybrid normal - a hybrid between `HSP` (head spine) and `NOR` (normal) strategies
    HNO,
    /// Applicative - leftmost innermost; the most eager strategy; unfit for recursion combinators
    APP,
    /// Call-by-value - leftmost innermost, but no reductions inside abstractions
    CBV,
    /// Hybrid applicative - a hybrid between `CBV` (call-by-value) and `APP` (applicative)
    /// strategies; usually the fastest-reducing normalizing strategy
    HAP
}

/// Applies two `Term`s with substitution and variable update, consuming the first one in the
/// process.
///
/// # Example
/// ```
/// use lambda_calculus::reduction::apply;
/// use lambda_calculus::*;
///
/// // these are valid terms, but be careful with unwraps in your code
/// let lhs    = parse(&"λλ42(λ13)", DeBruijn).unwrap();
/// let rhs    = parse(&"λ51", DeBruijn).unwrap();
/// let result = parse(&"λ3(λ61)(λ1(λ71))", DeBruijn).unwrap();
///
/// assert_eq!(apply(lhs, &rhs), Ok(result));
/// ```
/// # Errors
///
/// The function will return an error if the `lhs` term is not an `Abs`traction.
pub fn apply(mut lhs: Term, rhs: &Term) -> Result<Term, TermError> {
    if lhs.unabs_ref().is_err() { return Err(TermError::NotAbs) }

    _apply(&mut lhs, rhs, 0);

    lhs.unabs()
}

fn _apply(lhs: &mut Term, rhs: &Term, depth: usize) {
    match *lhs {
        Var(i) => if i == depth {
            *lhs = rhs.to_owned(); // substitute a top-level variable from lhs with rhs
            update_free_variables(lhs, depth - 1, 0); // update indices of free variables from rhs
        } else if i > depth {
            *lhs = Var(i - 1) // decrement a free variable's index
        },
        Abs(ref mut abstracted) => {
            _apply(abstracted, rhs, depth + 1)
        },
        App(ref mut lhs_lhs, ref mut lhs_rhs) => {
            _apply(lhs_lhs, rhs, depth);
            _apply(lhs_rhs, rhs, depth)
        }
    }
}

fn update_free_variables(term: &mut Term, added_depth: usize, own_depth: usize) {
    match *term {
        Var(ref mut i) => if *i > own_depth {
            *i += added_depth
        },
        Abs(ref mut abstracted) => {
            update_free_variables(abstracted, added_depth, own_depth + 1)
        },
        App(ref mut lhs, ref mut rhs) => {
            update_free_variables(lhs, added_depth, own_depth);
            update_free_variables(rhs, added_depth, own_depth)
        }
    }
}

/// Performs β-reduction on a `Term` with the specified evaluation `Order` and an optional limit on
/// the number of reductions (`0` means no limit) and returns the number of performed reductions.
///
/// # Example
///
/// ```
/// use lambda_calculus::*;
///
/// let expression = parse(&"(λa.λb.λc.a (λd.λe.e (d b)) (λd.c) (λd.d)) (λa.λb.a b)", Classic);
/// let reduced    = parse(&"λa.λb.b", Classic);
///
/// assert!(expression.is_ok());
/// assert!(reduced.is_ok());
/// assert_eq!(beta(expression.unwrap(), NOR, 0), reduced.unwrap());
/// ```
pub fn beta(mut term: Term, order: Order, limit: usize) -> Term {
    term.beta(order, limit);
    term
}

/// For a given `Term` and a set of β-reduction `Order`s it returns a vector of pairs containing
/// the `Order`s and their corresponding numbers of reductions required for the `Term` to reach its
/// fully reduced form (which, depending on the reduction strategy, might not be the normal form).
///
/// # Example
///
/// ```
/// use lambda_calculus::reduction::compare;
/// use lambda_calculus::church::numerals::fac;
/// use lambda_calculus::*;
///
/// let expr = app(fac(), 3.into()); // a Church-encoded factorial of 3
///
/// assert_eq!(
///     compare(&expr, &[NOR, APP, HNO, HAP]),
///     vec![(NOR, 35), (APP, 36), (HNO, 35), (HAP, 30)]
/// );
/// ```
pub fn compare(term: &Term, orders: &[Order]) -> Vec<(Order, usize)> {
    let mut ret = Vec::with_capacity(orders.len());

    for order in orders {
        ret.push((order.to_owned(), term.to_owned().beta(*order, 0)));
    }

    ret
}

impl Term {
    /// Applies `self` to another `Term` and performs substitution, consuming `self` in the process.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::parser::*;
    ///
    /// let lhs    = parse(&"λλ42(λ13)", DeBruijn).unwrap();
    /// let rhs    = parse(&"λ51", DeBruijn).unwrap();
    /// let result = parse(&"λ3(λ61)(λ1(λ71))", DeBruijn).unwrap();
    ///
    /// assert_eq!(lhs.apply(&rhs), Ok(result));
    /// ```
    /// # Errors
    ///
    /// The function will return an error if `self` is not an `Abs`traction.
    pub fn apply(self, rhs: &Term) -> Result<Term, TermError> {
        apply(self, rhs)
    }

    /// Reduces an `App`lication by substitution and variable update.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::*;
    /// use lambda_calculus::combinators::I;
    ///
    /// assert_eq!(app(I(), Var(1)).eval(), Ok(Var(1)));
    /// ```
    /// # Errors
    ///
    /// The function will return an error if `self` is not an `App`lication or if its left hand
    /// side term is not an `Abs`traction.
    pub fn eval(self) -> Result<Term, TermError> {
        let (lhs, rhs) = self.unapp()?;

        apply(lhs, &rhs)
    }

    fn _eval(&mut self, count: &mut usize) {
        let mut to_eval = mem::replace(self, Var(0)); // replace self with a dummy
        to_eval = to_eval.eval().unwrap(); // safe; only called in reduction sites
        mem::replace(self, to_eval); // move self back to its place

        *count += 1;
    }

    fn is_reducible(&self, limit: usize, count: &usize) -> bool {
        self.lhs_ref().and_then(|t| t.unabs_ref()).is_ok() && (limit == 0 || *count < limit )
    }

    /// Performs β-reduction on a `Term` with the specified evaluation `Order` and an optional limit
    /// on the number of reductions (`0` means no limit) and returns the number of performed
    /// reductions.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::*;
    ///
    /// let expression = parse(&"(λa.λb.λc.b (a b c)) (λa.λb.b)", Classic);
    /// let reduced    = parse(&"λa.λb.a b", Classic);
    ///
    /// assert!(expression.is_ok());
    /// assert!(reduced.is_ok());
    ///
    /// let mut expression = expression.unwrap();
    /// expression.beta(NOR, 0);
    ///
    /// assert_eq!(expression, reduced.unwrap());
    /// ```
    pub fn beta(&mut self, order: Order, limit: usize) -> usize {
        let mut count = 0;

        match order {
            CBN => self.beta_cbn(0, limit, &mut count),
            NOR => self.beta_nor(0, limit, &mut count),
            CBV => self.beta_cbv(0, limit, &mut count),
            APP => self.beta_app(0, limit, &mut count),
            HSP => self.beta_hsp(0, limit, &mut count),
            HNO => self.beta_hno(0, limit, &mut count),
            HAP => self.beta_hap(0, limit, &mut count)
        }

        count
    }

    fn beta_cbn(&mut self, depth: u32, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        if let App(_, _) = *self {
            self.lhs_mut().unwrap().beta_cbn(depth, limit, count);

            if self.is_reducible(limit, count) {
                self._eval(count);
                self.beta_cbn(depth, limit, count);
            }
        }
    }

    fn beta_nor(&mut self, depth: u32, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        match *self {
            Abs(ref mut abstracted) => abstracted.beta_nor(depth + 1, limit, count),
            App(_, _) => {
                self.lhs_mut().unwrap().beta_cbn(depth, limit, count);

                if self.is_reducible(limit, count) {
                    self._eval(count);
                    self.beta_nor(depth, limit, count);
                } else {
                    self.lhs_mut().unwrap().beta_nor(depth, limit, count);
                    self.rhs_mut().unwrap().beta_nor(depth, limit, count);
                }
            },
            _ => ()
        }
    }

    fn beta_cbv(&mut self, depth: u32, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        if let App(_, _) = *self {
            self.lhs_mut().unwrap().beta_cbv(depth, limit, count);
            self.rhs_mut().unwrap().beta_cbv(depth, limit, count);

            if self.is_reducible(limit, count) {
                self._eval(count);
                self.beta_cbv(depth, limit, count);
            }
        }
    }

    fn beta_app(&mut self, depth: u32, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        match *self {
            Abs(ref mut abstracted) => abstracted.beta_app(depth + 1, limit, count),
            App(_, _) => {
                self.lhs_mut().unwrap().beta_app(depth, limit, count);
                self.rhs_mut().unwrap().beta_app(depth, limit, count);

                if self.is_reducible(limit, count) {
                    self._eval(count);
                    self.beta_app(depth, limit, count);
                }
            },
            _ => ()
        }
    }

    fn beta_hap(&mut self, depth: u32, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        match *self {
            Abs(ref mut abstracted) => abstracted.beta_hap(depth + 1, limit, count),
            App(_, _) => {
                self.lhs_mut().unwrap().beta_cbv(depth, limit, count);
                self.rhs_mut().unwrap().beta_hap(depth, limit, count);

                if self.is_reducible(limit, count) {
                    self._eval(count);
                    self.beta_hap(depth, limit, count);
                } else {
                    self.lhs_mut().unwrap().beta_hap(depth, limit, count);
                }
            },
            _ => ()
        }
    }

    fn beta_hsp(&mut self, depth: u32, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        match *self {
            Abs(ref mut abstracted) => abstracted.beta_hsp(depth + 1, limit, count),
            App(_, _) => {
                self.lhs_mut().unwrap().beta_hsp(depth, limit, count);

                if self.is_reducible(limit, count) {
                    self._eval(count);
                    self.beta_hsp(depth, limit, count)
                }
            },
            _ => ()
        }
    }

    fn beta_hno(&mut self, depth: u32, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        match *self {
            Abs(ref mut abstracted) => abstracted.beta_hno(depth + 1, limit, count),
            App(_, _) => {
                self.lhs_mut().unwrap().beta_hsp(depth, limit, count);

                if self.is_reducible(limit, count) {
                    self._eval(count);
                    self.beta_hno(depth, limit, count)
                } else {
                    self.lhs_mut().unwrap().beta_hno(depth, limit, count);
                    self.rhs_mut().unwrap().beta_hno(depth, limit, count);
                }
            },
            _ => ()
        }
    }
}

impl fmt::Display for Order {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            NOR => "normal",
            CBN => "call-by-name",
            HSP => "head spine",
            HNO => "hybrid normal",
            APP => "applicative",
            CBV => "call-by-value",
            HAP => "hybrid applicative"
        })
    }
}
<commit_msg>fix non-church travis builds<commit_after>//! [β-reduction](https://en.wikipedia.org/wiki/Beta_normal_form) for lambda `Term`s

use term::{Term, TermError};
use term::Term::*;
use std::fmt;
use std::mem;
pub use self::Order::*;

/// The [evaluation order](http://www.cs.cornell.edu/courses/cs6110/2014sp/Handouts/Sestoft.pdf) of
/// β-reductions. The default is `NOR` (normal order).
///
/// They don't always yield the same result:
///
/// - The `NOR`, `HNO`, `APP` and `HAP` orders reduce expressions to their normal forms
/// - The `APP` order will fail to fully reduce expressions containing functions without a normal
/// form, e.g. the `Y` combinator (they will expand forever)
/// - The `CBN` order reduces to weak head normal form
/// - The `CBV` order reduces to weak normal form
/// - The `HSP` order reduces to head normal form
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Order {
    /// Normal - leftmost outermost; the most popular lambda calculus reduction strategy
    NOR,
    /// Call-by-name - leftmost outermost, but no reductions inside abstractions
    CBN,
    /// Head spine - leftmost outermost, but abstractions reduced only in head position
    HSP,
    /// Hybrid normal - a hybrid between `HSP` (head spine) and `NOR` (normal) strategies
    HNO,
    /// Applicative - leftmost innermost; the most eager strategy; unfit for recursion combinators
    APP,
    /// Call-by-value - leftmost innermost, but no reductions inside abstractions
    CBV,
    /// Hybrid applicative - a hybrid between `CBV` (call-by-value) and `APP` (applicative)
    /// strategies; usually the fastest-reducing normalizing strategy
    HAP
}

/// Applies two `Term`s with substitution and variable update, consuming the first one in the
/// process.
///
/// # Example
/// ```
/// use lambda_calculus::reduction::apply;
/// use lambda_calculus::*;
///
/// // these are valid terms, but be careful with unwraps in your code
/// let lhs    = parse(&"λλ42(λ13)", DeBruijn).unwrap();
/// let rhs    = parse(&"λ51", DeBruijn).unwrap();
/// let result = parse(&"λ3(λ61)(λ1(λ71))", DeBruijn).unwrap();
///
/// assert_eq!(apply(lhs, &rhs), Ok(result));
/// ```
/// # Errors
///
/// The function will return an error if the `lhs` term is not an `Abs`traction.
pub fn apply(mut lhs: Term, rhs: &Term) -> Result<Term, TermError> {
    if lhs.unabs_ref().is_err() { return Err(TermError::NotAbs) }

    _apply(&mut lhs, rhs, 0);

    lhs.unabs()
}

fn _apply(lhs: &mut Term, rhs: &Term, depth: usize) {
    match *lhs {
        Var(i) => if i == depth {
            *lhs = rhs.to_owned(); // substitute a top-level variable from lhs with rhs
            update_free_variables(lhs, depth - 1, 0); // update indices of free variables from rhs
        } else if i > depth {
            *lhs = Var(i - 1) // decrement a free variable's index
        },
        Abs(ref mut abstracted) => {
            _apply(abstracted, rhs, depth + 1)
        },
        App(ref mut lhs_lhs, ref mut lhs_rhs) => {
            _apply(lhs_lhs, rhs, depth);
            _apply(lhs_rhs, rhs, depth)
        }
    }
}

fn update_free_variables(term: &mut Term, added_depth: usize, own_depth: usize) {
    match *term {
        Var(ref mut i) => if *i > own_depth {
            *i += added_depth
        },
        Abs(ref mut abstracted) => {
            update_free_variables(abstracted, added_depth, own_depth + 1)
        },
        App(ref mut lhs, ref mut rhs) => {
            update_free_variables(lhs, added_depth, own_depth);
            update_free_variables(rhs, added_depth, own_depth)
        }
    }
}

/// Performs β-reduction on a `Term` with the specified evaluation `Order` and an optional limit on
/// the number of reductions (`0` means no limit) and returns the number of performed reductions.
///
/// # Example
///
/// ```
/// use lambda_calculus::*;
///
/// let expression = parse(&"(λa.λb.λc.a (λd.λe.e (d b)) (λd.c) (λd.d)) (λa.λb.a b)", Classic);
/// let reduced    = parse(&"λa.λb.b", Classic);
///
/// assert!(expression.is_ok());
/// assert!(reduced.is_ok());
/// assert_eq!(beta(expression.unwrap(), NOR, 0), reduced.unwrap());
/// ```
pub fn beta(mut term: Term, order: Order, limit: usize) -> Term {
    term.beta(order, limit);
    term
}

/// For a given `Term` and a set of β-reduction `Order`s it returns a vector of pairs containing
/// the `Order`s and their corresponding numbers of reductions required for the `Term` to reach its
/// fully reduced form (which, depending on the reduction strategy, might not be the normal form).
///
/// # Example
///
/// ```
/// use lambda_calculus::reduction::compare;
/// use lambda_calculus::*;
///
/// let factorial_3 = parse(&"(λa.a (λb.λc.λd.b (λe.c (d e)) (λe.λf.e (d e f))) (λb.λc.b)\
///     (λb.λc.b c) (λb.λc.b c)) (λa.λb.a (a (a b)))", Classic).unwrap();
///
/// assert_eq!(
///     compare(&factorial_3, &[NOR, APP, HNO, HAP]),
///     vec![(NOR, 35), (APP, 36), (HNO, 35), (HAP, 30)]
/// );
/// ```
pub fn compare(term: &Term, orders: &[Order]) -> Vec<(Order, usize)> {
    let mut ret = Vec::with_capacity(orders.len());

    for order in orders {
        ret.push((order.to_owned(), term.to_owned().beta(*order, 0)));
    }

    ret
}

impl Term {
    /// Applies `self` to another `Term` and performs substitution, consuming `self` in the process.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::parser::*;
    ///
    /// let lhs    = parse(&"λλ42(λ13)", DeBruijn).unwrap();
    /// let rhs    = parse(&"λ51", DeBruijn).unwrap();
    /// let result = parse(&"λ3(λ61)(λ1(λ71))", DeBruijn).unwrap();
    ///
    /// assert_eq!(lhs.apply(&rhs), Ok(result));
    /// ```
    /// # Errors
    ///
    /// The function will return an error if `self` is not an `Abs`traction.
    pub fn apply(self, rhs: &Term) -> Result<Term, TermError> {
        apply(self, rhs)
    }

    /// Reduces an `App`lication by substitution and variable update.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::*;
    /// use lambda_calculus::combinators::I;
    ///
    /// assert_eq!(app(I(), Var(1)).eval(), Ok(Var(1)));
    /// ```
    /// # Errors
    ///
    /// The function will return an error if `self` is not an `App`lication or if its left hand
    /// side term is not an `Abs`traction.
    pub fn eval(self) -> Result<Term, TermError> {
        let (lhs, rhs) = self.unapp()?;

        apply(lhs, &rhs)
    }

    fn _eval(&mut self, count: &mut usize) {
        let mut to_eval = mem::replace(self, Var(0)); // replace self with a dummy
        to_eval = to_eval.eval().unwrap(); // safe; only called in reduction sites
        mem::replace(self, to_eval); // move self back to its place

        *count += 1;
    }

    fn is_reducible(&self, limit: usize, count: &usize) -> bool {
        self.lhs_ref().and_then(|t| t.unabs_ref()).is_ok() && (limit == 0 || *count < limit )
    }

    /// Performs β-reduction on a `Term` with the specified evaluation `Order` and an optional limit
    /// on the number of reductions (`0` means no limit) and returns the number of performed
    /// reductions.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::*;
    ///
    /// let expression = parse(&"(λa.λb.λc.b (a b c)) (λa.λb.b)", Classic);
    /// let reduced    = parse(&"λa.λb.a b", Classic);
    ///
    /// assert!(expression.is_ok());
    /// assert!(reduced.is_ok());
    ///
    /// let mut expression = expression.unwrap();
    /// expression.beta(NOR, 0);
    ///
    /// assert_eq!(expression, reduced.unwrap());
    /// ```
    pub fn beta(&mut self, order: Order, limit: usize) -> usize {
        let mut count = 0;

        match order {
            CBN => self.beta_cbn(0, limit, &mut count),
            NOR => self.beta_nor(0, limit, &mut count),
            CBV => self.beta_cbv(0, limit, &mut count),
            APP => self.beta_app(0, limit, &mut count),
            HSP => self.beta_hsp(0, limit, &mut count),
            HNO => self.beta_hno(0, limit, &mut count),
            HAP => self.beta_hap(0, limit, &mut count)
        }

        count
    }

    fn beta_cbn(&mut self, depth: u32, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        if let App(_, _) = *self {
            self.lhs_mut().unwrap().beta_cbn(depth, limit, count);

            if self.is_reducible(limit, count) {
                self._eval(count);
                self.beta_cbn(depth, limit, count);
            }
        }
    }

    fn beta_nor(&mut self, depth: u32, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        match *self {
            Abs(ref mut abstracted) => abstracted.beta_nor(depth + 1, limit, count),
            App(_, _) => {
                self.lhs_mut().unwrap().beta_cbn(depth, limit, count);

                if self.is_reducible(limit, count) {
                    self._eval(count);
                    self.beta_nor(depth, limit, count);
                } else {
                    self.lhs_mut().unwrap().beta_nor(depth, limit, count);
                    self.rhs_mut().unwrap().beta_nor(depth, limit, count);
                }
            },
            _ => ()
        }
    }

    fn beta_cbv(&mut self, depth: u32, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        if let App(_, _) = *self {
            self.lhs_mut().unwrap().beta_cbv(depth, limit, count);
            self.rhs_mut().unwrap().beta_cbv(depth, limit, count);

            if self.is_reducible(limit, count) {
                self._eval(count);
                self.beta_cbv(depth, limit, count);
            }
        }
    }

    fn beta_app(&mut self, depth: u32, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        match *self {
            Abs(ref mut abstracted) => abstracted.beta_app(depth + 1, limit, count),
            App(_, _) => {
                self.lhs_mut().unwrap().beta_app(depth, limit, count);
                self.rhs_mut().unwrap().beta_app(depth, limit, count);

                if self.is_reducible(limit, count) {
                    self._eval(count);
                    self.beta_app(depth, limit, count);
                }
            },
            _ => ()
        }
    }

    fn beta_hap(&mut self, depth: u32, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        match *self {
            Abs(ref mut abstracted) => abstracted.beta_hap(depth + 1, limit, count),
            App(_, _) => {
                self.lhs_mut().unwrap().beta_cbv(depth, limit, count);
                self.rhs_mut().unwrap().beta_hap(depth, limit, count);

                if self.is_reducible(limit, count) {
                    self._eval(count);
                    self.beta_hap(depth, limit, count);
                } else {
                    self.lhs_mut().unwrap().beta_hap(depth, limit, count);
                }
            },
            _ => ()
        }
    }

    fn beta_hsp(&mut self, depth: u32, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        match *self {
            Abs(ref mut abstracted) => abstracted.beta_hsp(depth + 1, limit, count),
            App(_, _) => {
                self.lhs_mut().unwrap().beta_hsp(depth, limit, count);

                if self.is_reducible(limit, count) {
                    self._eval(count);
                    self.beta_hsp(depth, limit, count)
                }
            },
            _ => ()
        }
    }

    fn beta_hno(&mut self, depth: u32, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        match *self {
            Abs(ref mut abstracted) => abstracted.beta_hno(depth + 1, limit, count),
            App(_, _) => {
                self.lhs_mut().unwrap().beta_hsp(depth, limit, count);

                if self.is_reducible(limit, count) {
                    self._eval(count);
                    self.beta_hno(depth, limit, count)
                } else {
                    self.lhs_mut().unwrap().beta_hno(depth, limit, count);
                    self.rhs_mut().unwrap().beta_hno(depth, limit, count);
                }
            },
            _ => ()
        }
    }
}

impl fmt::Display for Order {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            NOR => "normal",
            CBN => "call-by-name",
            HSP => "head spine",
            HNO => "hybrid normal",
            APP => "applicative",
            CBV => "call-by-value",
            HAP => "hybrid applicative"
        })
    }
}
<|endoftext|>


<commit_before>use std::any::Any;
use std::ops::Deref;
use std::path::PathBuf;

use input::Input;
use output::Output;
use service::ServiceAccess;
use service::StaticServices;

use hyper::server::request::Request as HyperRequest;
use hyper::server::response::Response as HyperResponse;
use hyper::uri::RequestUri as HyperRequestUri;
use hyper::method::Method as HyperMethod;

pub struct Route {
    pub url: Pattern,
    pub method: MethodsMask,
    pub handler: Box<Handler + Send + Sync>,
}

impl Route {
    /// Returns the route parameters, or `Err` if this route can't handle the given request.
    pub fn matches(&self, request: &HyperRequest) -> Result<Box<Any>, ()> {
        if !self.method.matches(&request.method) {
            return Err(());
        }

        match request.uri {
            HyperRequestUri::AbsolutePath(ref p) => self.url.parse(p),
            _ => Err(())
        }
    }
}

/// Represents a URL pattern.
///
/// Contains a function that will return the route parameters, or `Err` if it doesn't match the
/// request's URL.
pub struct Pattern(pub Box<Fn(&str) -> Result<Box<Any>, ()> + Send + Sync>);

impl Pattern {
    /// Return `Err` if this pattern doesn't match the given URL, otherwise returns the
    /// route parameters.
    pub fn parse(&self, url: &str) -> Result<Box<Any>, ()> {
        (self.0)(url)
    }
}

/// Describes which methods must be used by the request for a route to be used.
pub struct MethodsMask {
    /// True if the `GET` method matches this mask.
    pub get: bool,
    /// True if the `POST` method matches this mask.
    pub post: bool,
    /// True if the `PUT` method matches this mask.
    pub put: bool,
    /// True if the `DELETE` method matches this mask.
    pub delete: bool,
}

impl MethodsMask {
    /// Parses from a string of the `route!` macro.
    pub fn parse(_: &str) -> MethodsMask {
        // FIXME:
        MethodsMask {
            get: true,
            post: false,
            put: false,
            delete: false,
        }
    }

    /// Returns true if the mask contains the specified method.
    pub fn matches(&self, method: &HyperMethod) -> bool {
        match method {
            &HyperMethod::Get => self.get,
            &HyperMethod::Post => self.post,
            &HyperMethod::Put => self.put,
            &HyperMethod::Delete => self.delete,
            _ => false
        }
    }
}

pub struct Router {
    /// List of the routes to try to match. They will be tried in this order.
    pub routes: Vec<Route>,
}

/// Describes types that can process a route.
pub trait Handler {
    /// Handles a request.
    fn call(&self, HyperRequest, HyperResponse, &StaticServices, route_params: &Box<Any>);
}

macro_rules! impl_handler {
    ($($p:ident),*) => (
        impl<'a, I, O $(, $p)*> Handler for fn(I $(, $p)*) -> O
                                            where I: Input, O: Output $(, $p: ServiceAccess<'a>)*
        {
            #[allow(non_snake_case)]
            fn call(&self, request: HyperRequest, response: HyperResponse,
                    services: &StaticServices, route_params: &Box<Any>)
            {
                let input = match I::process(request) {
                    Ok(i) => i,
                    Err(_) => return        // TODO: handle properly
                };

                // TODO: Properly handling lifetimes here would require HKTs which are not
                //       supported by Rust. Considering that services are never destroyed, it's
                //       ok to cast their lifetime to whatever we want ; however there is a danger
                //       with route parameters and this should be fixed.
                $(
                    let $p = $p::load(unsafe { ::std::mem::transmute(services) },
                                      unsafe { ::std::mem::transmute(route_params) });
                )*

                let output = (*self)(input $(, $p)*);
                output.send(response, services);
            }
        }

        impl<'a, I, O $(, $p)*> Handler for Box<Fn(I $(, $p)*) -> O>
                                            where I: Input, O: Output $(, $p: ServiceAccess<'a>)*
        {
            #[allow(non_snake_case)]
            fn call(&self, request: HyperRequest, response: HyperResponse,
                    services: &StaticServices, route_params: &Box<Any>)
            {
                let input = match I::process(request) {
                    Ok(i) => i,
                    Err(_) => return        // TODO: handle properly
                };

                // TODO: Properly handling lifetimes here would require HKTs which are not
                //       supported by Rust. Considering that services are never destroyed, it's
                //       ok to cast their lifetime to whatever we want ; however there is a danger
                //       with route parameters and this should be fixed.
                $(
                    let $p = $p::load(unsafe { ::std::mem::transmute(services) },
                                      unsafe { ::std::mem::transmute(route_params) });
                )*

                let output = (*self)(input $(, $p)*);
                output.send(response, services);
            }
        }
    );
}

impl_handler!();
impl_handler!(S1);
impl_handler!(S1, S2);
impl_handler!(S1, S2, S3);
impl_handler!(S1, S2, S3, S4);
impl_handler!(S1, S2, S3, S4, S5);
impl_handler!(S1, S2, S3, S4, S5, S6);
impl_handler!(S1, S2, S3, S4, S5, S6, S7);
impl_handler!(S1, S2, S3, S4, S5, S6, S7, S8);
impl_handler!(S1, S2, S3, S4, S5, S6, S7, S8, S9);
impl_handler!(S1, S2, S3, S4, S5, S6, S7, S8, S9, S10);
impl_handler!(S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11);

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Params<'a, T: 'a>(&'a T);

impl<'a, T: 'a> ServiceAccess<'a> for Params<'a, T> where T: Any {
    fn load(_: &'a StaticServices, params: &'a Box<Any>) -> Params<'a, T> {
        Params(params.downcast_ref().unwrap())      // TODO: don't panic
    }
}

impl<'a, T> Deref for Params<'a, T> {
    type Target = T;

    fn deref(&self) -> &T {
        self.0
    }
}

// TODO: fix the trailing '/' problem

#[macro_export]
macro_rules! router {
    ($($t:tt)+) => (
        {
            let mut routes = Vec::new();
            router_impl!(__parse_route routes [] $($t)+);
            $crate::route::Router { routes: routes }
        }
    );
}

#[macro_export]
macro_rules! router_impl {
    (__parse_route $routes:ident [$($ex:tt)*] / $($t:tt)+) => (
        {
            let method = router_impl!(__parse_method $($ex)*);
            router_impl!(__parse_route2 $routes method [/] $($t)+)
        }
    );

    (__parse_route $routes:ident [$($ex:tt)*] $f:tt $($t:tt)*) => (
        router_impl!(__parse_route $routes [$($ex)* $f] $($t)*)
    );

    (__parse_route $routes:ident []) => ();

    (__parse_route2 $routes:ident $method:ident [$($ex:tt)*] => $handler:expr, $($t:tt)*) => (
        {
            let pattern = router_impl!(__parse_pattern $($ex)*);
            let handler = Box::new($handler) as Box<$crate::route::Handler + Send + Sync>;
            $routes.push($crate::route::Route {
                url: pattern,
                method: $method,
                handler: handler,
            });

            router_impl!(__parse_route $routes [] $($t)*);
        }
    );

    (__parse_route2 $routes:ident $method:ident [$($ex:tt)*] => $handler:expr) => (
        router_impl!(__parse_route2 $routes $method [$($ex)*] => $handler,)
    );

    (__parse_route2 $routes:ident $method:ident [$($ex:tt)*] $f:tt $($t:tt)*) => (
        router_impl!(__parse_route2 $routes $method [$($ex)* $f] $($t)*)
    );

    (__parse_pattern $($t:tt)*) => (
        $crate::route::Pattern(Box::new(move |input| {
            router_impl!(__parse_pattern_inner (input.trim_right_matches('/')) () $($t)*)
        }))
    );

    (__parse_pattern_inner ($input:expr) () [ $s:ident ]) => (
        {
            if $input.len() != 0 {
                return Err(());
            }

            Ok(Box::new($s))
        }
    );

    (__parse_pattern_inner ($input:expr) ($(, $mem:ident:$val:expr)+) [ $s:ident ]) => (
        {
            if $input.len() != 0 {
                return Err(());
            }

            Ok(Box::new($s {
                $(
                    $mem: match $val.parse() {
                        Ok(r) => r,
                        Err(_) => return Err(())
                    },
                )*
            }))
        }
    );

    (__parse_pattern_inner ($input:expr) ()) => (
        {
            if $input.len() != 0 {
                return Err(());
            }

            Ok(Box::new(()))
        }
    );

    (__parse_pattern_inner ($input:expr) ($($t:tt)*) / [ $s:ident ]) => (
        router_impl!(__parse_pattern_inner ($input) ($($t)*) [$s])
    );

    (__parse_pattern_inner ($input:expr) ($($t:tt)*) /) => (
        router_impl!(__parse_pattern_inner ($($t)*) ($input))
    );

    (__parse_pattern_inner ($input:expr) ($($e:tt)*) / { $val:ident } $($t:tt)*) => (
        {
            if !$input.starts_with('/') {
                return Err(());
            }

            let end = $input[1 ..].find('/').map(|p| p + 1).unwrap_or($input.len());
            let matched = &$input[1 .. end];

            router_impl!(__parse_pattern_inner (&$input[end ..]) ($($e)* , $val: matched) $($t)*)
        }
    );

    (__parse_pattern_inner ($input:expr) ($($e:tt)*) / $val:ident $($t:tt)*) => (
        {
            let s = concat!("/", stringify!($val));
            if !$input.starts_with(s) {
                return Err(());
            }

            router_impl!(__parse_pattern_inner (&$input[s.len() ..]) ($($e)*) $($t)*)
        }
    );

    (__parse_method $($t:tt)*) => (
        // TODO:
        $crate::route::MethodsMask { get: true, post: false, put: false, delete: false }
    );
}
<commit_msg>Various fixes to router!<commit_after>use std::any::Any;
use std::ops::Deref;
use std::path::PathBuf;

use input::Input;
use output::Output;
use service::ServiceAccess;
use service::StaticServices;

use hyper::server::request::Request as HyperRequest;
use hyper::server::response::Response as HyperResponse;
use hyper::uri::RequestUri as HyperRequestUri;
use hyper::method::Method as HyperMethod;

pub struct Route {
    pub url: Pattern,
    pub method: MethodsMask,
    pub handler: Box<Handler + Send + Sync>,
}

impl Route {
    /// Returns the route parameters, or `Err` if this route can't handle the given request.
    pub fn matches(&self, request: &HyperRequest) -> Result<Box<Any>, ()> {
        if !self.method.matches(&request.method) {
            return Err(());
        }

        match request.uri {
            HyperRequestUri::AbsolutePath(ref p) => self.url.parse(p),
            _ => Err(())
        }
    }
}

/// Represents a URL pattern.
///
/// Contains a function that will return the route parameters, or `Err` if it doesn't match the
/// request's URL.
pub struct Pattern(pub Box<Fn(&str) -> Result<Box<Any>, ()> + Send + Sync>);

impl Pattern {
    /// Return `Err` if this pattern doesn't match the given URL, otherwise returns the
    /// route parameters.
    pub fn parse(&self, url: &str) -> Result<Box<Any>, ()> {
        (self.0)(url)
    }
}

/// Describes which methods must be used by the request for a route to be used.
pub struct MethodsMask {
    /// True if the `GET` method matches this mask.
    pub get: bool,
    /// True if the `POST` method matches this mask.
    pub post: bool,
    /// True if the `PUT` method matches this mask.
    pub put: bool,
    /// True if the `DELETE` method matches this mask.
    pub delete: bool,
}

impl MethodsMask {
    /// Parses from a string of the `route!` macro.
    pub fn parse(_: &str) -> MethodsMask {
        // FIXME:
        MethodsMask {
            get: true,
            post: false,
            put: false,
            delete: false,
        }
    }

    /// Returns true if the mask contains the specified method.
    pub fn matches(&self, method: &HyperMethod) -> bool {
        match method {
            &HyperMethod::Get => self.get,
            &HyperMethod::Post => self.post,
            &HyperMethod::Put => self.put,
            &HyperMethod::Delete => self.delete,
            _ => false
        }
    }
}

pub struct Router {
    /// List of the routes to try to match. They will be tried in this order.
    pub routes: Vec<Route>,
}

/// Describes types that can process a route.
pub trait Handler {
    /// Handles a request.
    fn call(&self, HyperRequest, HyperResponse, &StaticServices, route_params: &Box<Any>);
}

macro_rules! impl_handler {
    ($($p:ident),*) => (
        impl<'a, I, O $(, $p)*> Handler for fn(I $(, $p)*) -> O
                                            where I: Input, O: Output $(, $p: ServiceAccess<'a>)*
        {
            #[allow(non_snake_case)]
            fn call(&self, request: HyperRequest, response: HyperResponse,
                    services: &StaticServices, route_params: &Box<Any>)
            {
                let input = match I::process(request) {
                    Ok(i) => i,
                    Err(_) => return        // TODO: handle properly
                };

                // TODO: Properly handling lifetimes here would require HKTs which are not
                //       supported by Rust. Considering that services are never destroyed, it's
                //       ok to cast their lifetime to whatever we want ; however there is a danger
                //       with route parameters and this should be fixed.
                $(
                    let $p = $p::load(unsafe { ::std::mem::transmute(services) },
                                      unsafe { ::std::mem::transmute(route_params) });
                )*

                let output = (*self)(input $(, $p)*);
                output.send(response, services);
            }
        }

        impl<'a, I, O $(, $p)*> Handler for Box<Fn(I $(, $p)*) -> O>
                                            where I: Input, O: Output $(, $p: ServiceAccess<'a>)*
        {
            #[allow(non_snake_case)]
            fn call(&self, request: HyperRequest, response: HyperResponse,
                    services: &StaticServices, route_params: &Box<Any>)
            {
                let input = match I::process(request) {
                    Ok(i) => i,
                    Err(_) => return        // TODO: handle properly
                };

                // TODO: Properly handling lifetimes here would require HKTs which are not
                //       supported by Rust. Considering that services are never destroyed, it's
                //       ok to cast their lifetime to whatever we want ; however there is a danger
                //       with route parameters and this should be fixed.
                $(
                    let $p = $p::load(unsafe { ::std::mem::transmute(services) },
                                      unsafe { ::std::mem::transmute(route_params) });
                )*

                let output = (*self)(input $(, $p)*);
                output.send(response, services);
            }
        }
    );
}

impl_handler!();
impl_handler!(S1);
impl_handler!(S1, S2);
impl_handler!(S1, S2, S3);
impl_handler!(S1, S2, S3, S4);
impl_handler!(S1, S2, S3, S4, S5);
impl_handler!(S1, S2, S3, S4, S5, S6);
impl_handler!(S1, S2, S3, S4, S5, S6, S7);
impl_handler!(S1, S2, S3, S4, S5, S6, S7, S8);
impl_handler!(S1, S2, S3, S4, S5, S6, S7, S8, S9);
impl_handler!(S1, S2, S3, S4, S5, S6, S7, S8, S9, S10);
impl_handler!(S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11);

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Params<'a, T: 'a>(&'a T);

impl<'a, T: 'a> ServiceAccess<'a> for Params<'a, T> where T: Any {
    fn load(_: &'a StaticServices, params: &'a Box<Any>) -> Params<'a, T> {
        Params(params.downcast_ref().unwrap())      // TODO: don't panic
    }
}

impl<'a, T> Deref for Params<'a, T> {
    type Target = T;

    fn deref(&self) -> &T {
        self.0
    }
}

// TODO: fix the trailing '/' problem

#[macro_export]
macro_rules! router {
    ($($t:tt)+) => (
        {
            let mut routes = Vec::new();
            router_impl!(__parse_route routes [] $($t)+);
            $crate::route::Router { routes: routes }
        }
    );
}

#[macro_export]
macro_rules! router_impl {
    (__parse_route $routes:ident [$($method:tt)*] / $($pattern:tt)+) => (
        {
            let method = router_impl!(__parse_method $($method)*);
            router_impl!(__parse_route2 $routes method [/] $($pattern)+)
        }
    );

    (__parse_route $routes:ident [$($method:tt)*] $method_next:tt $($rest:tt)*) => (
        router_impl!(__parse_route $routes [$($method)* $method_next] $($rest)*)
    );

    (__parse_route $routes:ident []) => ();

    (__parse_route2 $routes:ident $method:ident [$($pattern:tt)*] => $handler:expr, $($other_routes:tt)*) => (
        {
            router_impl!(__parse_route2 $routes $method [$($pattern)*] => $handler);
            router_impl!(__parse_route $routes [] $($other_routes)*);
        }
    );

    (__parse_route2 $routes:ident $method:ident [$($pattern:tt)*] => $handler:expr) => (
        {
            let pattern = router_impl!(__parse_pattern $($pattern)*);
            let handler = Box::new($handler) as Box<$crate::route::Handler + Send + Sync>;
            $routes.push($crate::route::Route {
                url: pattern,
                method: $method,
                handler: handler,
            });
        }
    );

    (__parse_route2 $routes:ident $method:ident [$($pattern:tt)*] $pattern_next:tt $($rest:tt)*) => (
        router_impl!(__parse_route2 $routes $method [$($pattern)* $pattern_next] $($rest)*)
    );

    (__parse_pattern $($pat:tt)*) => (
        $crate::route::Pattern(Box::new(move |input| {
            router_impl!(__parse_pattern_inner (input.trim_right_matches('/')) () $($pat)*)
        }))
    );

    (__parse_pattern_inner ($input:expr) () [ $($s:ident)::+ ]) => (
        {
            if $input.len() != 0 {
                return Err(());
            }

            Ok(Box::new($($s)::+))
        }
    );

    (__parse_pattern_inner ($input:expr) ($(, $mem:ident:$val:expr)+) [ $($s:ident)::+ ]) => (
        {
            if $input.len() != 0 {
                return Err(());
            }

            Ok(Box::new($($s)::+ {
                $(
                    $mem: match $val.parse() {
                        Ok(r) => r,
                        Err(_) => return Err(())
                    },
                )*
            }))
        }
    );

    (__parse_pattern_inner ($input:expr) ()) => (
        {
            if $input.len() != 0 {
                return Err(());
            }

            Ok(Box::new(()))
        }
    );

    (__parse_pattern_inner ($input:expr) ($(, $mem:ident:$val:expr)+)) => (
        {
            use found_pattern_without_struct_to_match_see_documentation;
            Err(())
        }
    );

    (__parse_pattern_inner ($input:expr) ($($t:tt)*) / [ $s:ty ]) => (
        router_impl!(__parse_pattern_inner ($input) ($($t)*) [$s])
    );

    (__parse_pattern_inner ($input:expr) ($($t:tt)*) /) => (
        router_impl!(__parse_pattern_inner ($input) ($($t)*))
    );

    (__parse_pattern_inner ($input:expr) ($($e:tt)*) / { $val:ident } $($rest:tt)*) => (
        {
            if !$input.starts_with('/') {
                return Err(());
            }

            let end = $input[1 ..].find('/').map(|p| p + 1).unwrap_or($input.len());
            let matched = &$input[1 .. end];

            router_impl!(__parse_pattern_inner (&$input[end ..]) ($($e)*, $val:matched) $($rest)*)
        }
    );

    (__parse_pattern_inner ($input:expr) ($($e:tt)*) / $val:ident $($t:tt)*) => (
        {
            let s = concat!("/", stringify!($val));
            if !$input.starts_with(s) {
                return Err(());
            }

            router_impl!(__parse_pattern_inner (&$input[s.len() ..]) ($($e)*) $($t)*)
        }
    );

    (__parse_method $($t:tt)*) => (
        // TODO:
        $crate::route::MethodsMask { get: true, post: false, put: false, delete: false }
    );
}
<|endoftext|>