<commit_before>//! An interpreter implementation.

/// Instructions.
#[derive(PartialEq, Debug)]
pub enum Op {
    /// Treats the next instruction as a function call.
    Call,
    /// Treats the next instruction as argument path.
    Path,
    /// Treats the next instruction as function path.
    FnPath,
    /// A function reference.
    FnRef(usize),
    /// An instruction reference.
    OpRef(usize),
    /// End of instructions.
    End,
}

/// Evaluates a program.
pub fn eval(fns: &[Op], ops: &[Op], st: &mut Vec<Op>, calls: &mut Vec<usize>) {

}

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

    #[test]
    fn not() {
        let fns = vec![
            // bool,
            FnRef(0),                   // 0: bool
            End,
            // false,
            FnRef(2),                   // 2: false
            End,
            // true,
            FnRef(4),                   // 4: true
            End,
            // not(bool) -> bool
            FnRef(6),                   // 6: not
            FnRef(0),                   // 7: bool,
            OpRef(1),                   // 8: -> bool
            // not([true] true) -> [false] false
            FnRef(6),                   // 9: not
            Path,
            FnRef(4),                   // 11: true
            FnRef(4),                   // 12: true
            OpRef(5),                   // 13: -> [false] false,
        ];

        let ops = vec![
            // bool
            End,
            FnRef(0),                   // 1: bool
            // [false] false
            End,
            Path,
            FnRef(2),                   // 4: false
            FnRef(2),                   // 5: false
            // call not([true] true)
            End,
            Call,
            FnRef(6),                   // 8: not
            Path,
            FnRef(4),                   // 10: true
            FnRef(4),                   // 11: true
        ];

        let mut stack = vec![];
        let mut calls = vec![];

        eval(&fns, &ops, &mut stack, &mut calls);

        assert_eq!(&stack, &[
        ]);
    }
}
<commit_msg>Implemented simple interpreter<commit_after>//! An interpreter implementation.

/// Instructions.
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum Op {
    /// Treats the next instruction as a function call.
    Call,
    /// Treats the next instruction as argument path.
    Path,
    /// Treats the next instruction as function path.
    FnPath,
    /// A function reference.
    FnRef(usize),
    /// An instruction reference.
    OpRef(usize),
    /// End of instructions.
    End,
}

/// Evaluates a program.
pub fn eval(fns: &[Op], ops: &[Op], st: &mut Vec<Op>, calls: &mut Vec<usize>) {
    let mut call = ops.len();
    'e: loop {
        let mut f = None;
        // Push instructions.
        for op in ops[0..call].iter().rev() {
            match op {
                &Op::End => {
                    // Continue previous call.
                    call = match calls.pop() {
                        None => { return; }
                        Some(call) => call,
                    };
                    continue 'e;
                }
                &Op::Call => {
                    // Call a function.
                    call -= 1;
                    f = match st.last() {
                        Some(&Op::FnRef(f)) => Some(f),
                        x => { panic!("Expected `FnRef`, found `{:?}`", x); }
                    };
                    break;
                }
                x => {
                    // Push instruction.
                    call -= 1;
                    st.push(*x);
                }
            }
        }

        if let Some(mut f) = f {
            // Pattern match function.
            'f: loop {
                let mut j = st.len();
                for (i, fi) in fns[f..].iter().enumerate() {
                    match fi {
                        &Op::End => {
                            panic!("Function does not return a value");
                        }
                        &Op::OpRef(o) => {
                            // Remove values and call function.
                            st.truncate(j);
                            calls.push(call);
                            call = o + 1;
                            continue 'e;
                        }
                        _ => {}
                    }
                    if j == 0 {
                        panic!("Stack is shorter than function signature");
                    }
                    j -= 1;
                    if fi != &st[j] {
                        if i == 0 {
                            panic!("No function matched (failed to match name)");
                        }
                        // Try next function.
                        for (k, fi) in fns[f + i..].iter().enumerate() {
                            match fi {
                                &Op::End | &Op::OpRef(_) => {
                                    f = f + i + k + 1;
                                    if f >= fns.len() {
                                        panic!("No function matched (end)");
                                    }
                                    continue 'f;
                                }
                                _ => {}
                            }
                        }
                    }
                }
            }
        }
    }
}

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

    #[test]
    fn not() {
        let fns = vec![
            // bool,
            FnRef(0),                   // 0: bool
            End,
            // false,
            FnRef(2),                   // 2: false
            End,
            // true,
            FnRef(4),                   // 4: true
            End,
            // not(bool) -> bool
            FnRef(6),                   // 6: not
            FnRef(0),                   // 7: bool,
            OpRef(1),                   // 8: -> bool
            // not([true] true) -> [false] false
            FnRef(6),                   // 9: not
            Path,
            FnRef(4),                   // 11: true
            FnRef(4),                   // 12: true
            OpRef(5),                   // 13: -> [false] false,
        ];

        let ops = vec![
            // bool
            End,
            FnRef(0),                   // 1: bool
            // [false] false
            End,
            Path,
            FnRef(2),                   // 4: false
            FnRef(2),                   // 5: false
            // call not([true] true)
            End,
            Call,
            FnRef(6),                   // 8: not
            Path,
            FnRef(4),                   // 10: true
            FnRef(4),                   // 11: true
        ];

        let mut stack = vec![];
        let mut calls = vec![];

        eval(&fns, &ops, &mut stack, &mut calls);

        assert_eq!(&stack, &[
            FnRef(2),
            FnRef(2),
            Path
        ]);
    }

    #[test]
    fn not_type() {
        let fns = vec![
            // bool,
            FnRef(0),                   // 0: bool
            End,
            // false,
            FnRef(2),                   // 2: false
            End,
            // true,
            FnRef(4),                   // 4: true
            End,
            // not(bool) -> bool
            FnRef(6),                   // 6: not
            FnRef(0),                   // 7: bool,
            OpRef(1),                   // 8: -> bool
            // not([true] true) -> [false] false
            FnRef(6),                   // 9: not
            Path,
            FnRef(4),                   // 11: true
            FnRef(4),                   // 12: true
            OpRef(5),                   // 13: -> [false] false,
        ];

        let ops = vec![
            // bool
            End,
            FnRef(0),                   // 1: bool
            // [false] false
            End,
            Path,
            FnRef(2),                   // 4: false
            FnRef(2),                   // 5: false
            // call not(bool)
            End,
            Call,
            FnRef(6),                   // 8: not
            FnRef(0),
        ];

        let mut stack = vec![];
        let mut calls = vec![];

        eval(&fns, &ops, &mut stack, &mut calls);

        assert_eq!(&stack, &[
            FnRef(0),
        ]);
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;

use bsdf::{BSDF, BxDF, FresnelSpecular, SpecularTransmission, SpecularReflection, Fresnel,
           MicrofacetReflection, MicrofacetTransmission, TrowbridgeReitzDistribution};
use interaction::SurfaceInteraction;
use material::{Material, TransportMode};
use spectrum::Spectrum;
use texture::{Texture, ConstantTexture};

pub struct GlassMaterial {
    kr: Arc<Texture<Spectrum> + Send + Sync>,
    kt: Arc<Texture<Spectrum> + Send + Sync>,
    u_roughness: Arc<Texture<f32> + Send + Sync>,
    v_roughness: Arc<Texture<f32> + Send + Sync>,
    index: Arc<Texture<f32> + Send + Sync>,
    remap_roughness: bool,
}

impl GlassMaterial {
    pub fn new() -> GlassMaterial {
        GlassMaterial {
            kr: Arc::new(ConstantTexture::new(Spectrum::white())),
            kt: Arc::new(ConstantTexture::new(Spectrum::white())),
            u_roughness: Arc::new(ConstantTexture::new(0.0)),
            v_roughness: Arc::new(ConstantTexture::new(0.0)),
            index: Arc::new(ConstantTexture::new(1.5)),
            remap_roughness: true,
        }
    }

    pub fn roughness(mut self, u_rough: f32, v_rough: f32) -> GlassMaterial {
        self.u_roughness = Arc::new(ConstantTexture::new(::na::clamp(u_rough, 0.0, 1.0)));
        self.v_roughness = Arc::new(ConstantTexture::new(::na::clamp(v_rough, 0.0, 1.0)));

        self
    }
}

impl Material for GlassMaterial {
    fn compute_scattering_functions(&self,
                                    isect: &mut SurfaceInteraction,
                                    mode: TransportMode,
                                    allow_multiple_lobes: bool) {
        let eta = self.index.evaluate(isect);
        let mut u_rough = self.u_roughness.evaluate(isect);
        let mut v_rough = self.v_roughness.evaluate(isect);
        let r = self.kr.evaluate(isect);
        let t = self.kt.evaluate(isect);

        let mut bxdfs: Vec<Box<BxDF + Send + Sync>> = Vec::new();

        if !r.is_black() || !t.is_black() {
            let is_specular = u_rough == 0.0 && v_rough == 0.0;
            if is_specular && allow_multiple_lobes {
                bxdfs.push(Box::new(FresnelSpecular::new()));
            } else {
                if self.remap_roughness {
                    u_rough = TrowbridgeReitzDistribution::roughness_to_alpha(u_rough);
                    v_rough = TrowbridgeReitzDistribution::roughness_to_alpha(v_rough);
                }
                if !r.is_black() {
                    let fresnel = Box::new(Fresnel::dielectric(1.0, eta));
                    if is_specular {
                        let bxdf = Box::new(SpecularReflection::new(r, fresnel));
                        bxdfs.push(bxdf);
                    } else {
                        let distrib = Box::new(TrowbridgeReitzDistribution::new(u_rough, v_rough));
                        let bxdf = Box::new(MicrofacetReflection::new(r, distrib, fresnel));
                    }
                }
                if !t.is_black() {
                    if is_specular {
                        let bxdf = Box::new(SpecularTransmission::new(t, 1.0, eta));
                        bxdfs.push(bxdf);
                    } else {
                        let distrib = Box::new(TrowbridgeReitzDistribution::new(u_rough, v_rough));
                        let bxdf = Box::new(MicrofacetTransmission::new(r, distrib, 1.0, eta));
                    }
                }
            }
        }

        isect.bsdf = Some(Arc::new(BSDF::new(isect, eta, bxdfs)));
    }
}
<commit_msg>oops, the BxDF wasn't added to the BSDF for rough glass...<commit_after>use std::sync::Arc;

use bsdf::{BSDF, BxDF, FresnelSpecular, SpecularTransmission, SpecularReflection, Fresnel,
           MicrofacetReflection, MicrofacetTransmission, TrowbridgeReitzDistribution};
use interaction::SurfaceInteraction;
use material::{Material, TransportMode};
use spectrum::Spectrum;
use texture::{Texture, ConstantTexture};

pub struct GlassMaterial {
    kr: Arc<Texture<Spectrum> + Send + Sync>,
    kt: Arc<Texture<Spectrum> + Send + Sync>,
    u_roughness: Arc<Texture<f32> + Send + Sync>,
    v_roughness: Arc<Texture<f32> + Send + Sync>,
    index: Arc<Texture<f32> + Send + Sync>,
    remap_roughness: bool,
}

impl GlassMaterial {
    pub fn new() -> GlassMaterial {
        GlassMaterial {
            kr: Arc::new(ConstantTexture::new(Spectrum::white())),
            kt: Arc::new(ConstantTexture::new(Spectrum::white())),
            u_roughness: Arc::new(ConstantTexture::new(0.0)),
            v_roughness: Arc::new(ConstantTexture::new(0.0)),
            index: Arc::new(ConstantTexture::new(1.5)),
            remap_roughness: true,
        }
    }

    pub fn roughness(mut self, u_rough: f32, v_rough: f32) -> GlassMaterial {
        self.u_roughness = Arc::new(ConstantTexture::new(::na::clamp(u_rough, 0.0, 1.0)));
        self.v_roughness = Arc::new(ConstantTexture::new(::na::clamp(v_rough, 0.0, 1.0)));

        self
    }
}

impl Material for GlassMaterial {
    fn compute_scattering_functions(&self,
                                    isect: &mut SurfaceInteraction,
                                    mode: TransportMode,
                                    allow_multiple_lobes: bool) {
        let eta = self.index.evaluate(isect);
        let mut u_rough = self.u_roughness.evaluate(isect);
        let mut v_rough = self.v_roughness.evaluate(isect);
        let r = self.kr.evaluate(isect);
        let t = self.kt.evaluate(isect);

        let mut bxdfs: Vec<Box<BxDF + Send + Sync>> = Vec::new();

        if !r.is_black() || !t.is_black() {
            let is_specular = u_rough == 0.0 && v_rough == 0.0;
            if is_specular && allow_multiple_lobes {
                bxdfs.push(Box::new(FresnelSpecular::new()));
            } else {
                if self.remap_roughness {
                    u_rough = TrowbridgeReitzDistribution::roughness_to_alpha(u_rough);
                    v_rough = TrowbridgeReitzDistribution::roughness_to_alpha(v_rough);
                }
                if !r.is_black() {
                    let fresnel = Box::new(Fresnel::dielectric(1.0, eta));
                    let bxdf: Box<BxDF + Send + Sync> = if is_specular {
                        Box::new(SpecularReflection::new(r, fresnel))
                    } else {
                        let distrib = Box::new(TrowbridgeReitzDistribution::new(u_rough, v_rough));
                        Box::new(MicrofacetReflection::new(r, distrib, fresnel))
                    };
                    bxdfs.push(bxdf);
                }
                if !t.is_black() {
                    let bxdf: Box<BxDF + Send + Sync> = if is_specular {
                        Box::new(SpecularTransmission::new(t, 1.0, eta))
                    } else {
                        let distrib = Box::new(TrowbridgeReitzDistribution::new(u_rough, v_rough));
                        Box::new(MicrofacetTransmission::new(r, distrib, 1.0, eta))
                    };
                    bxdfs.push(bxdf);
                }
            }
        }

        isect.bsdf = Some(Arc::new(BSDF::new(isect, eta, bxdfs)));
    }
}
<|endoftext|>


<commit_before>/*
Module: rand

Random number generation
*/
#[abi = "cdecl"]
native mod rustrt {
    type rctx;
    fn rand_new() -> rctx;
    fn rand_next(c: rctx) -> u32;
    fn rand_free(c: rctx);
}

/* Section: Types */

/*
Obj: rng

A random number generator
*/
type rng = obj {
    /*
    Method: next

    Return the next random integer
    */
    fn next() -> u32;

    /*
    Method: next_float

    Return the next random float
    */
    fn next_float() -> float;

    /*
    Method: gen_str

    Return a random string composed of A-Z, a-z, 0-9.
    */
    fn gen_str(len: uint) -> str;
};

resource rand_res(c: rustrt::rctx) { rustrt::rand_free(c); }

/* Section: Operations */

/*
Function: mk_rng

Create a random number generator
*/
fn mk_rng() -> rng {
    obj rt_rng(c: @rand_res) {
        fn next() -> u32 { ret rustrt::rand_next(**c); }
        fn next_float() -> float {
          let u1 = rustrt::rand_next(**c) as float;
          let u2 = rustrt::rand_next(**c) as float;
          let u3 = rustrt::rand_next(**c) as float;
          let scale = u32::max_value as float;
          ret ((u1 / scale + u2) / scale + u3) / scale;
        }
        fn gen_str(len: uint) -> str {
            let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
                          "abcdefghijklmnopqrstuvwxyz" +
                          "0123456789";
            let s = "";
            let i = 0u;
            while (i < len) {
                let n = rustrt::rand_next(**c) as uint %
                    str::char_len(charset);
                s = s + str::from_char(str::char_at(charset, n));
                i += 1u;
            }
            s
        }
    }
    ret rt_rng(@rand_res(rustrt::rand_new()));
}
// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>libstd: add a method to generate random bytestrings.<commit_after>/*
Module: rand

Random number generation
*/
#[abi = "cdecl"]
native mod rustrt {
    type rctx;
    fn rand_new() -> rctx;
    fn rand_next(c: rctx) -> u32;
    fn rand_free(c: rctx);
}

/* Section: Types */

/*
Obj: rng

A random number generator
*/
type rng = obj {
    /*
    Method: next

    Return the next random integer
    */
    fn next() -> u32;

    /*
    Method: next_float

    Return the next random float
    */
    fn next_float() -> float;

    /*
    Method: gen_str

    Return a random string composed of A-Z, a-z, 0-9.
    */
    fn gen_str(len: uint) -> str;

    /*
    Method: gen_bytes

    Return a random byte string.
    */
    fn gen_bytes(len: uint) -> [u8];
};

resource rand_res(c: rustrt::rctx) { rustrt::rand_free(c); }

/* Section: Operations */

/*
Function: mk_rng

Create a random number generator
*/
fn mk_rng() -> rng {
    obj rt_rng(c: @rand_res) {
        fn next() -> u32 { ret rustrt::rand_next(**c); }
        fn next_float() -> float {
          let u1 = rustrt::rand_next(**c) as float;
          let u2 = rustrt::rand_next(**c) as float;
          let u3 = rustrt::rand_next(**c) as float;
          let scale = u32::max_value as float;
          ret ((u1 / scale + u2) / scale + u3) / scale;
        }
        fn gen_str(len: uint) -> str {
            let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
                          "abcdefghijklmnopqrstuvwxyz" +
                          "0123456789";
            let s = "";
            let i = 0u;
            while (i < len) {
                let n = rustrt::rand_next(**c) as uint %
                    str::char_len(charset);
                s = s + str::from_char(str::char_at(charset, n));
                i += 1u;
            }
            s
        }
        fn gen_bytes(len: uint) -> [u8] {
            let v = [];
            let i = 0u;
            while i < len {
                let n = rustrt::rand_next(**c) as uint;
                v += [(n % (u8::max_value as uint)) as u8];
                i += 1u;
            }
            v
        }
    }
    ret rt_rng(@rand_res(rustrt::rand_new()));
}
// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>#[doc = "Sorting methods"];
import vec::len;

export merge_sort;
export quick_sort;
export quick_sort3;

type le<T> = fn(T, T) -> bool;

#[doc = "
Merge sort. Returns a new vector containing the sorted list.

Has worst case O(n log n) performance, best case O(n), but
is not space efficient. This is a stable sort.
"]
fn merge_sort<T: copy>(le: le<T>, v: [const T]) -> [T] {
    type slice = (uint, uint);

    ret merge_sort_(le, v, (0u, len(v)));

    fn merge_sort_<T: copy>(le: le<T>, v: [const T], slice: slice) -> [T] {
        let begin = tuple::first(slice);
        let end = tuple::second(slice);

        let v_len = end - begin;
        if v_len == 0u { ret []; }
        if v_len == 1u { ret [v[begin]]; }

        let mid = v_len / 2u + begin;
        let a = (begin, mid);
        let b = (mid, end);
        ret merge(le, merge_sort_(le, v, a), merge_sort_(le, v, b));
    }

    fn merge<T: copy>(le: le<T>, a: [T], b: [T]) -> [T] {
        let mut rs = [];
        vec::reserve(rs, len(a) + len(b));
        let a_len = len(a);
        let mut a_ix = 0u;
        let b_len = len(b);
        let mut b_ix = 0u;
        while a_ix < a_len && b_ix < b_len {
            if le(a[a_ix], b[b_ix]) {
                rs += [a[a_ix]];
                a_ix += 1u;
            } else { rs += [b[b_ix]]; b_ix += 1u; }
        }
        rs += vec::slice(a, a_ix, a_len);
        rs += vec::slice(b, b_ix, b_len);
        ret rs;
    }
}

fn part<T: copy>(compare_func: le<T>, arr: [mut T], left: uint,
                right: uint, pivot: uint) -> uint {
    let pivot_value = arr[pivot];
    arr[pivot] <-> arr[right];
    let mut storage_index: uint = left;
    let mut i: uint = left;
    while i < right {
        if compare_func(copy arr[i], pivot_value) {
            arr[i] <-> arr[storage_index];
            storage_index += 1u;
        }
        i += 1u;
    }
    arr[storage_index] <-> arr[right];
    ret storage_index;
}

fn qsort<T: copy>(compare_func: le<T>, arr: [mut T], left: uint,
             right: uint) {
    if right > left {
        let pivot = (left + right) / 2u;
        let new_pivot = part::<T>(compare_func, arr, left, right, pivot);
        if new_pivot != 0u {
            // Need to do this check before recursing due to overflow
            qsort::<T>(compare_func, arr, left, new_pivot - 1u);
        }
        qsort::<T>(compare_func, arr, new_pivot + 1u, right);
    }
}

#[doc = "
Quicksort. Sorts a mut vector in place.

Has worst case O(n^2) performance, average case O(n log n).
This is an unstable sort.
"]
fn quick_sort<T: copy>(compare_func: le<T>, arr: [mut T]) {
    if len::<T>(arr) == 0u { ret; }
    qsort::<T>(compare_func, arr, 0u, len::<T>(arr) - 1u);
}

fn qsort3<T: copy>(compare_func_lt: le<T>, compare_func_eq: le<T>,
                  arr: [mut T], left: int, right: int) {
    if right <= left { ret; }
    let v: T = arr[right];
    let mut i: int = left - 1;
    let mut j: int = right;
    let mut p: int = i;
    let mut q: int = j;
    loop {
        i += 1;
        while compare_func_lt(copy arr[i], v) { i += 1; }
        j -= 1;
        while compare_func_lt(v, copy arr[j]) {
            if j == left { break; }
            j -= 1;
        }
        if i >= j { break; }
        arr[i] <-> arr[j];
        if compare_func_eq(copy arr[i], v) {
            p += 1;
            arr[p] <-> arr[i];
        }
        if compare_func_eq(v, copy arr[j]) {
            q -= 1;
            arr[j] <-> arr[q];
        }
    }
    arr[i] <-> arr[right];
    j = i - 1;
    i += 1;
    let mut k: int = left;
    while k < p {
        arr[k] <-> arr[j];
        k += 1;
        j -= 1;
        if k == len::<T>(arr) as int { break; }
    }
    k = right - 1;
    while k > q {
        arr[i] <-> arr[k];
        k -= 1;
        i += 1;
        if k == 0 { break; }
    }
    qsort3::<T>(compare_func_lt, compare_func_eq, arr, left, j);
    qsort3::<T>(compare_func_lt, compare_func_eq, arr, i, right);
}

// FIXME: This should take lt and eq types
#[doc = "
Fancy quicksort. Sorts a mut vector in place.

Based on algorithm presented by [Sedgewick and Bentley]
(http://www.cs.princeton.edu/~rs/talks/QuicksortIsOptimal.pdf).
According to these slides this is the algorithm of choice for
'randomly ordered keys, abstract compare' & 'small number of key values'.

This is an unstable sort.
"]
fn quick_sort3<T: copy>(compare_func_lt: le<T>, compare_func_eq: le<T>,
                       arr: [mut T]) {
    if len::<T>(arr) == 0u { ret; }
    qsort3::<T>(compare_func_lt, compare_func_eq, arr, 0,
                (len::<T>(arr) as int) - 1);
}

#[cfg(test)]
mod test_qsort3 {
    fn check_sort(v1: [mut int], v2: [mut int]) {
        let len = vec::len::<int>(v1);
        fn lt(&&a: int, &&b: int) -> bool { ret a < b; }
        fn equal(&&a: int, &&b: int) -> bool { ret a == b; }
        let f1 = lt;
        let f2 = equal;
        quick_sort3::<int>(f1, f2, v1);
        let mut i = 0u;
        while i < len {
            log(debug, v2[i]);
            assert (v2[i] == v1[i]);
            i += 1u;
        }
    }

    #[test]
    fn test() {
        {
            let v1 = [mut 3, 7, 4, 5, 2, 9, 5, 8];
            let v2 = [mut 2, 3, 4, 5, 5, 7, 8, 9];
            check_sort(v1, v2);
        }
        {
            let v1 = [mut 1, 1, 1];
            let v2 = [mut 1, 1, 1];
            check_sort(v1, v2);
        }
        {
            let v1: [mut int] = [mut];
            let v2: [mut int] = [mut];
            check_sort(v1, v2);
        }
        { let v1 = [mut 9]; let v2 = [mut 9]; check_sort(v1, v2); }
        {
            let v1 = [mut 9, 3, 3, 3, 9];
            let v2 = [mut 3, 3, 3, 9, 9];
            check_sort(v1, v2);
        }
    }
}

#[cfg(test)]
mod test_qsort {
    fn check_sort(v1: [mut int], v2: [mut int]) {
        let len = vec::len::<int>(v1);
        fn leual(&&a: int, &&b: int) -> bool { ret a <= b; }
        let f = leual;
        quick_sort::<int>(f, v1);
        let mut i = 0u;
        while i < len {
            log(debug, v2[i]);
            assert (v2[i] == v1[i]);
            i += 1u;
        }
    }

    #[test]
    fn test() {
        {
            let v1 = [mut 3, 7, 4, 5, 2, 9, 5, 8];
            let v2 = [mut 2, 3, 4, 5, 5, 7, 8, 9];
            check_sort(v1, v2);
        }
        {
            let v1 = [mut 1, 1, 1];
            let v2 = [mut 1, 1, 1];
            check_sort(v1, v2);
        }
        {
            let v1: [mut int] = [mut];
            let v2: [mut int] = [mut];
            check_sort(v1, v2);
        }
        { let v1 = [mut 9]; let v2 = [mut 9]; check_sort(v1, v2); }
        {
            let v1 = [mut 9, 3, 3, 3, 9];
            let v2 = [mut 3, 3, 3, 9, 9];
            check_sort(v1, v2);
        }
    }

    // Regression test for #750
    #[test]
    fn test_simple() {
        let names = [mut 2, 1, 3];

        let expected = [1, 2, 3];

        fn le(&&a: int, &&b: int) -> bool { int::le(a, b) }
        sort::quick_sort(le, names);

        let immut_names = vec::from_mut(names);

        let pairs = vec::zip(expected, immut_names);
        for vec::each(pairs) {|p|
            let (a, b) = p;
            #debug("%d %d", a, b);
            assert (a == b);
        }
    }
}

#[cfg(test)]
mod tests {

    fn check_sort(v1: [int], v2: [int]) {
        let len = vec::len::<int>(v1);
        fn le(&&a: int, &&b: int) -> bool { ret a <= b; }
        let f = le;
        let v3 = merge_sort::<int>(f, v1);
        let mut i = 0u;
        while i < len {
            log(debug, v3[i]);
            assert (v3[i] == v2[i]);
            i += 1u;
        }
    }

    #[test]
    fn test() {
        {
            let v1 = [3, 7, 4, 5, 2, 9, 5, 8];
            let v2 = [2, 3, 4, 5, 5, 7, 8, 9];
            check_sort(v1, v2);
        }
        { let v1 = [1, 1, 1]; let v2 = [1, 1, 1]; check_sort(v1, v2); }
        { let v1: [int] = []; let v2: [int] = []; check_sort(v1, v2); }
        { let v1 = [9]; let v2 = [9]; check_sort(v1, v2); }
        {
            let v1 = [9, 3, 3, 3, 9];
            let v2 = [3, 3, 3, 9, 9];
            check_sort(v1, v2);
        }
    }

    #[test]
    fn test_merge_sort_mutable() {
        fn le(&&a: int, &&b: int) -> bool { ret a <= b; }
        let v1 = [mut 3, 2, 1];
        let v2 = merge_sort(le, v1);
        assert v2 == [1, 2, 3];
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>std: Export sort::le<commit_after>#[doc = "Sorting methods"];
import vec::len;

export le;
export merge_sort;
export quick_sort;
export quick_sort3;

type le<T> = fn(T, T) -> bool;

#[doc = "
Merge sort. Returns a new vector containing the sorted list.

Has worst case O(n log n) performance, best case O(n), but
is not space efficient. This is a stable sort.
"]
fn merge_sort<T: copy>(le: le<T>, v: [const T]) -> [T] {
    type slice = (uint, uint);

    ret merge_sort_(le, v, (0u, len(v)));

    fn merge_sort_<T: copy>(le: le<T>, v: [const T], slice: slice) -> [T] {
        let begin = tuple::first(slice);
        let end = tuple::second(slice);

        let v_len = end - begin;
        if v_len == 0u { ret []; }
        if v_len == 1u { ret [v[begin]]; }

        let mid = v_len / 2u + begin;
        let a = (begin, mid);
        let b = (mid, end);
        ret merge(le, merge_sort_(le, v, a), merge_sort_(le, v, b));
    }

    fn merge<T: copy>(le: le<T>, a: [T], b: [T]) -> [T] {
        let mut rs = [];
        vec::reserve(rs, len(a) + len(b));
        let a_len = len(a);
        let mut a_ix = 0u;
        let b_len = len(b);
        let mut b_ix = 0u;
        while a_ix < a_len && b_ix < b_len {
            if le(a[a_ix], b[b_ix]) {
                rs += [a[a_ix]];
                a_ix += 1u;
            } else { rs += [b[b_ix]]; b_ix += 1u; }
        }
        rs += vec::slice(a, a_ix, a_len);
        rs += vec::slice(b, b_ix, b_len);
        ret rs;
    }
}

fn part<T: copy>(compare_func: le<T>, arr: [mut T], left: uint,
                right: uint, pivot: uint) -> uint {
    let pivot_value = arr[pivot];
    arr[pivot] <-> arr[right];
    let mut storage_index: uint = left;
    let mut i: uint = left;
    while i < right {
        if compare_func(copy arr[i], pivot_value) {
            arr[i] <-> arr[storage_index];
            storage_index += 1u;
        }
        i += 1u;
    }
    arr[storage_index] <-> arr[right];
    ret storage_index;
}

fn qsort<T: copy>(compare_func: le<T>, arr: [mut T], left: uint,
             right: uint) {
    if right > left {
        let pivot = (left + right) / 2u;
        let new_pivot = part::<T>(compare_func, arr, left, right, pivot);
        if new_pivot != 0u {
            // Need to do this check before recursing due to overflow
            qsort::<T>(compare_func, arr, left, new_pivot - 1u);
        }
        qsort::<T>(compare_func, arr, new_pivot + 1u, right);
    }
}

#[doc = "
Quicksort. Sorts a mut vector in place.

Has worst case O(n^2) performance, average case O(n log n).
This is an unstable sort.
"]
fn quick_sort<T: copy>(compare_func: le<T>, arr: [mut T]) {
    if len::<T>(arr) == 0u { ret; }
    qsort::<T>(compare_func, arr, 0u, len::<T>(arr) - 1u);
}

fn qsort3<T: copy>(compare_func_lt: le<T>, compare_func_eq: le<T>,
                  arr: [mut T], left: int, right: int) {
    if right <= left { ret; }
    let v: T = arr[right];
    let mut i: int = left - 1;
    let mut j: int = right;
    let mut p: int = i;
    let mut q: int = j;
    loop {
        i += 1;
        while compare_func_lt(copy arr[i], v) { i += 1; }
        j -= 1;
        while compare_func_lt(v, copy arr[j]) {
            if j == left { break; }
            j -= 1;
        }
        if i >= j { break; }
        arr[i] <-> arr[j];
        if compare_func_eq(copy arr[i], v) {
            p += 1;
            arr[p] <-> arr[i];
        }
        if compare_func_eq(v, copy arr[j]) {
            q -= 1;
            arr[j] <-> arr[q];
        }
    }
    arr[i] <-> arr[right];
    j = i - 1;
    i += 1;
    let mut k: int = left;
    while k < p {
        arr[k] <-> arr[j];
        k += 1;
        j -= 1;
        if k == len::<T>(arr) as int { break; }
    }
    k = right - 1;
    while k > q {
        arr[i] <-> arr[k];
        k -= 1;
        i += 1;
        if k == 0 { break; }
    }
    qsort3::<T>(compare_func_lt, compare_func_eq, arr, left, j);
    qsort3::<T>(compare_func_lt, compare_func_eq, arr, i, right);
}

// FIXME: This should take lt and eq types
#[doc = "
Fancy quicksort. Sorts a mut vector in place.

Based on algorithm presented by [Sedgewick and Bentley]
(http://www.cs.princeton.edu/~rs/talks/QuicksortIsOptimal.pdf).
According to these slides this is the algorithm of choice for
'randomly ordered keys, abstract compare' & 'small number of key values'.

This is an unstable sort.
"]
fn quick_sort3<T: copy>(compare_func_lt: le<T>, compare_func_eq: le<T>,
                       arr: [mut T]) {
    if len::<T>(arr) == 0u { ret; }
    qsort3::<T>(compare_func_lt, compare_func_eq, arr, 0,
                (len::<T>(arr) as int) - 1);
}

#[cfg(test)]
mod test_qsort3 {
    fn check_sort(v1: [mut int], v2: [mut int]) {
        let len = vec::len::<int>(v1);
        fn lt(&&a: int, &&b: int) -> bool { ret a < b; }
        fn equal(&&a: int, &&b: int) -> bool { ret a == b; }
        let f1 = lt;
        let f2 = equal;
        quick_sort3::<int>(f1, f2, v1);
        let mut i = 0u;
        while i < len {
            log(debug, v2[i]);
            assert (v2[i] == v1[i]);
            i += 1u;
        }
    }

    #[test]
    fn test() {
        {
            let v1 = [mut 3, 7, 4, 5, 2, 9, 5, 8];
            let v2 = [mut 2, 3, 4, 5, 5, 7, 8, 9];
            check_sort(v1, v2);
        }
        {
            let v1 = [mut 1, 1, 1];
            let v2 = [mut 1, 1, 1];
            check_sort(v1, v2);
        }
        {
            let v1: [mut int] = [mut];
            let v2: [mut int] = [mut];
            check_sort(v1, v2);
        }
        { let v1 = [mut 9]; let v2 = [mut 9]; check_sort(v1, v2); }
        {
            let v1 = [mut 9, 3, 3, 3, 9];
            let v2 = [mut 3, 3, 3, 9, 9];
            check_sort(v1, v2);
        }
    }
}

#[cfg(test)]
mod test_qsort {
    fn check_sort(v1: [mut int], v2: [mut int]) {
        let len = vec::len::<int>(v1);
        fn leual(&&a: int, &&b: int) -> bool { ret a <= b; }
        let f = leual;
        quick_sort::<int>(f, v1);
        let mut i = 0u;
        while i < len {
            log(debug, v2[i]);
            assert (v2[i] == v1[i]);
            i += 1u;
        }
    }

    #[test]
    fn test() {
        {
            let v1 = [mut 3, 7, 4, 5, 2, 9, 5, 8];
            let v2 = [mut 2, 3, 4, 5, 5, 7, 8, 9];
            check_sort(v1, v2);
        }
        {
            let v1 = [mut 1, 1, 1];
            let v2 = [mut 1, 1, 1];
            check_sort(v1, v2);
        }
        {
            let v1: [mut int] = [mut];
            let v2: [mut int] = [mut];
            check_sort(v1, v2);
        }
        { let v1 = [mut 9]; let v2 = [mut 9]; check_sort(v1, v2); }
        {
            let v1 = [mut 9, 3, 3, 3, 9];
            let v2 = [mut 3, 3, 3, 9, 9];
            check_sort(v1, v2);
        }
    }

    // Regression test for #750
    #[test]
    fn test_simple() {
        let names = [mut 2, 1, 3];

        let expected = [1, 2, 3];

        fn le(&&a: int, &&b: int) -> bool { int::le(a, b) }
        sort::quick_sort(le, names);

        let immut_names = vec::from_mut(names);

        let pairs = vec::zip(expected, immut_names);
        for vec::each(pairs) {|p|
            let (a, b) = p;
            #debug("%d %d", a, b);
            assert (a == b);
        }
    }
}

#[cfg(test)]
mod tests {

    fn check_sort(v1: [int], v2: [int]) {
        let len = vec::len::<int>(v1);
        fn le(&&a: int, &&b: int) -> bool { ret a <= b; }
        let f = le;
        let v3 = merge_sort::<int>(f, v1);
        let mut i = 0u;
        while i < len {
            log(debug, v3[i]);
            assert (v3[i] == v2[i]);
            i += 1u;
        }
    }

    #[test]
    fn test() {
        {
            let v1 = [3, 7, 4, 5, 2, 9, 5, 8];
            let v2 = [2, 3, 4, 5, 5, 7, 8, 9];
            check_sort(v1, v2);
        }
        { let v1 = [1, 1, 1]; let v2 = [1, 1, 1]; check_sort(v1, v2); }
        { let v1: [int] = []; let v2: [int] = []; check_sort(v1, v2); }
        { let v1 = [9]; let v2 = [9]; check_sort(v1, v2); }
        {
            let v1 = [9, 3, 3, 3, 9];
            let v2 = [3, 3, 3, 9, 9];
            check_sort(v1, v2);
        }
    }

    #[test]
    fn test_merge_sort_mutable() {
        fn le(&&a: int, &&b: int) -> bool { ret a <= b; }
        let v1 = [mut 3, 2, 1];
        let v2 = merge_sort(le, v1);
        assert v2 == [1, 2, 3];
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>//! Support code for rustc's built in unit-test and micro-benchmarking
//! framework.
//!
//! Almost all user code will only be interested in `Bencher` and
//! `black_box`. All other interactions (such as writing tests and
//! benchmarks themselves) should be done via the `#[test]` and
//! `#[bench]` attributes.
//!
//! See the [Testing Chapter](../book/ch11-00-testing.html) of the book for more details.

#![crate_name = "test"]
#![unstable(feature = "test", issue = "27812")]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/",
       test(attr(deny(warnings))))]
#![feature(asm)]
#![feature(staged_api)]
#![feature(test)]

extern crate libtest;
pub use libtest::{test_main_static, TestDescAndFn, StaticTestFn, StaticBenchFn, Options};

/// A function that is opaque to the optimizer, to allow benchmarks to
/// pretend to use outputs to assist in avoiding dead-code
/// elimination.
///
/// This function is a no-op, and does not even read from `dummy`.
#[cfg(not(any(target_arch = "asmjs", target_arch = "wasm32")))]
pub fn black_box<T>(dummy: T) -> T {
    // we need to "use" the argument in some way LLVM can't
    // introspect.
    unsafe { asm!("" : : "r"(&dummy)) }
    dummy
}
#[cfg(any(target_arch = "asmjs", target_arch = "wasm32"))]
#[inline(never)]
pub fn black_box<T>(dummy: T) -> T {
    dummy
}
<commit_msg>Add missing explicit imports<commit_after>//! Support code for rustc's built in unit-test and micro-benchmarking
//! framework.
//!
//! Almost all user code will only be interested in `Bencher` and
//! `black_box`. All other interactions (such as writing tests and
//! benchmarks themselves) should be done via the `#[test]` and
//! `#[bench]` attributes.
//!
//! See the [Testing Chapter](../book/ch11-00-testing.html) of the book for more details.

#![crate_name = "test"]
#![unstable(feature = "test", issue = "27812")]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/",
       test(attr(deny(warnings))))]
#![feature(asm)]
#![feature(staged_api)]
#![feature(test)]

extern crate libtest;
pub use libtest::{
    assert_test_result, filter_tests, parse_opts, run_test, test_main, test_main_static,
    Bencher, DynTestFn, DynTestName, Metric, MetricMap, Options, RunIgnored, ShouldPanic,
    StaticBenchFn, StaticTestFn, StaticTestName, TestDesc, TestDescAndFn, TestName, TestOpts,
    TestResult, TrFailed, TrFailedMsg, TrIgnored, TrOk,
};

/// A function that is opaque to the optimizer, to allow benchmarks to
/// pretend to use outputs to assist in avoiding dead-code
/// elimination.
///
/// This function is a no-op, and does not even read from `dummy`.
#[cfg(not(any(target_arch = "asmjs", target_arch = "wasm32")))]
pub fn black_box<T>(dummy: T) -> T {
    // we need to "use" the argument in some way LLVM can't
    // introspect.
    unsafe { asm!("" : : "r"(&dummy)) }
    dummy
}
#[cfg(any(target_arch = "asmjs", target_arch = "wasm32"))]
#[inline(never)]
pub fn black_box<T>(dummy: T) -> T {
    dummy
}
<|endoftext|>


<commit_before>use serde_json::Value;

use std::collections::HashMap;
use std::fmt;

#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum AMQPType {
    Boolean,
    ShortShortInt,
    ShortShortUInt,
    ShortInt,
    ShortUInt,
    LongInt,
    LongUInt,
    LongLongInt,
    LongLongUInt,
    Float,
    Double,
    DecimalValue,
    ShortString,
    LongString,
    FieldArray,
    Timestamp,
    FieldTable,
    Void,
}

impl AMQPType {
    pub fn from_id(id: char) -> Option<AMQPType> {
        match id {
            't' => Some(AMQPType::Boolean),
            'b' => Some(AMQPType::ShortShortInt),
            'B' => Some(AMQPType::ShortShortUInt),
            'U' => Some(AMQPType::ShortInt),
            'u' => Some(AMQPType::ShortUInt),
            'I' => Some(AMQPType::LongInt),
            'i' => Some(AMQPType::LongUInt),
            'L' => Some(AMQPType::LongLongInt),
            'l' => Some(AMQPType::LongLongUInt),
            'f' => Some(AMQPType::Float),
            'd' => Some(AMQPType::Double),
            'D' => Some(AMQPType::DecimalValue),
            's' => Some(AMQPType::ShortString),
            'S' => Some(AMQPType::LongString),
            'A' => Some(AMQPType::FieldArray),
            'T' => Some(AMQPType::Timestamp),
            'F' => Some(AMQPType::FieldTable),
            'V' => Some(AMQPType::Void),
            _   => None,
        }
    }

    pub fn get_id(&self) -> char {
        match *self {
            AMQPType::Boolean => 't',
            AMQPType::ShortShortInt => 'b',
            AMQPType::ShortShortUInt => 'B',
            AMQPType::ShortInt => 'U',
            AMQPType::ShortUInt => 'u',
            AMQPType::LongInt => 'I',
            AMQPType::LongUInt => 'i',
            AMQPType::LongLongInt => 'L',
            AMQPType::LongLongUInt => 'l',
            AMQPType::Float => 'f',
            AMQPType::Double => 'd',
            AMQPType::DecimalValue => 'D',
            AMQPType::ShortString => 's',
            AMQPType::LongString => 'S',
            AMQPType::FieldArray => 'A',
            AMQPType::Timestamp => 'T',
            AMQPType::FieldTable => 'F',
            AMQPType::Void => 'V',
        }
    }

    pub fn to_string(&self) -> String {
        format!("{}", self)
    }
}

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

pub type Boolean        = bool;
pub type ShortShortInt  = i8;
pub type ShortShortUInt = u8;
pub type ShortInt       = i16;
pub type ShortUInt      = u16;
pub type LongInt        = i32;
pub type LongUInt       = u32;
pub type LongLongInt    = i64;
pub type LongLongUInt   = u64;
pub type Float          = f32;
pub type Double         = f64;
pub type ShortString    = String; /* TODO: don't allow size >= 255 */
pub type LongString     = String;
pub type FieldArray     = Vec<AMQPValue>;
pub type Timestamp      = LongLongUInt;
pub type FieldTable     = HashMap<ShortString, AMQPValue>;
pub type Void           = ();

#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct DecimalValue {
    pub scale: ShortShortUInt,
    pub value: LongUInt,
}

#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum AMQPValue {
    Boolean(Boolean),
    ShortShortInt(ShortShortInt),
    ShortShortUInt(ShortShortUInt),
    ShortInt(ShortInt),
    ShortUInt(ShortUInt),
    LongInt(LongInt),
    LongUInt(LongUInt),
    LongLongInt(LongLongInt),
    LongLongUInt(LongLongUInt),
    Float(Float),
    Double(Double),
    DecimalValue(DecimalValue),
    ShortString(ShortString),
    LongString(LongString),
    FieldArray(FieldArray),
    Timestamp(Timestamp),
    FieldTable(FieldTable),
    Void,
}

impl From<Value> for AMQPValue {
    fn from(v: Value) -> AMQPValue {
        From::from(&v)
    }
}

impl<'a> From<&'a Value> for AMQPValue {
    fn from(v: &Value) -> AMQPValue {
        match *v {
            Value::Bool(ref b)   => AMQPValue::Boolean(*b),
            Value::Number(ref n) => {
                if n.is_u64() {
                    AMQPValue::LongLongUInt(n.as_u64().unwrap())
                } else if n.is_i64() {
                    AMQPValue::LongLongInt(n.as_i64().unwrap())
                } else {
                    AMQPValue::Double(n.as_f64().unwrap())
                }
            },
            Value::String(ref s) => AMQPValue::LongString(s.clone()),
            Value::Array(ref v)  => AMQPValue::FieldArray(v.iter().map(From::from).collect()),
            Value::Object(ref o) => AMQPValue::FieldTable(o.iter().fold(FieldTable::new(), |mut table, (k, v)| {
                table.insert(k.clone(), From::from(v));
                table
            })),
            Value::Null          => AMQPValue::Void,
        }
    }
}
<commit_msg>types: add AMQPValue::get_type()<commit_after>use serde_json::Value;

use std::collections::HashMap;
use std::fmt;

#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum AMQPType {
    Boolean,
    ShortShortInt,
    ShortShortUInt,
    ShortInt,
    ShortUInt,
    LongInt,
    LongUInt,
    LongLongInt,
    LongLongUInt,
    Float,
    Double,
    DecimalValue,
    ShortString,
    LongString,
    FieldArray,
    Timestamp,
    FieldTable,
    Void,
}

impl AMQPType {
    pub fn from_id(id: char) -> Option<AMQPType> {
        match id {
            't' => Some(AMQPType::Boolean),
            'b' => Some(AMQPType::ShortShortInt),
            'B' => Some(AMQPType::ShortShortUInt),
            'U' => Some(AMQPType::ShortInt),
            'u' => Some(AMQPType::ShortUInt),
            'I' => Some(AMQPType::LongInt),
            'i' => Some(AMQPType::LongUInt),
            'L' => Some(AMQPType::LongLongInt),
            'l' => Some(AMQPType::LongLongUInt),
            'f' => Some(AMQPType::Float),
            'd' => Some(AMQPType::Double),
            'D' => Some(AMQPType::DecimalValue),
            's' => Some(AMQPType::ShortString),
            'S' => Some(AMQPType::LongString),
            'A' => Some(AMQPType::FieldArray),
            'T' => Some(AMQPType::Timestamp),
            'F' => Some(AMQPType::FieldTable),
            'V' => Some(AMQPType::Void),
            _   => None,
        }
    }

    pub fn get_id(&self) -> char {
        match *self {
            AMQPType::Boolean => 't',
            AMQPType::ShortShortInt => 'b',
            AMQPType::ShortShortUInt => 'B',
            AMQPType::ShortInt => 'U',
            AMQPType::ShortUInt => 'u',
            AMQPType::LongInt => 'I',
            AMQPType::LongUInt => 'i',
            AMQPType::LongLongInt => 'L',
            AMQPType::LongLongUInt => 'l',
            AMQPType::Float => 'f',
            AMQPType::Double => 'd',
            AMQPType::DecimalValue => 'D',
            AMQPType::ShortString => 's',
            AMQPType::LongString => 'S',
            AMQPType::FieldArray => 'A',
            AMQPType::Timestamp => 'T',
            AMQPType::FieldTable => 'F',
            AMQPType::Void => 'V',
        }
    }

    pub fn to_string(&self) -> String {
        format!("{}", self)
    }
}

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

pub type Boolean        = bool;
pub type ShortShortInt  = i8;
pub type ShortShortUInt = u8;
pub type ShortInt       = i16;
pub type ShortUInt      = u16;
pub type LongInt        = i32;
pub type LongUInt       = u32;
pub type LongLongInt    = i64;
pub type LongLongUInt   = u64;
pub type Float          = f32;
pub type Double         = f64;
pub type ShortString    = String; /* TODO: don't allow size >= 255 */
pub type LongString     = String;
pub type FieldArray     = Vec<AMQPValue>;
pub type Timestamp      = LongLongUInt;
pub type FieldTable     = HashMap<ShortString, AMQPValue>;
pub type Void           = ();

#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct DecimalValue {
    pub scale: ShortShortUInt,
    pub value: LongUInt,
}

#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum AMQPValue {
    Boolean(Boolean),
    ShortShortInt(ShortShortInt),
    ShortShortUInt(ShortShortUInt),
    ShortInt(ShortInt),
    ShortUInt(ShortUInt),
    LongInt(LongInt),
    LongUInt(LongUInt),
    LongLongInt(LongLongInt),
    LongLongUInt(LongLongUInt),
    Float(Float),
    Double(Double),
    DecimalValue(DecimalValue),
    ShortString(ShortString),
    LongString(LongString),
    FieldArray(FieldArray),
    Timestamp(Timestamp),
    FieldTable(FieldTable),
    Void,
}

impl AMQPValue {
    pub fn get_type(&self) -> AMQPType {
        match *self {
            AMQPValue::Boolean(_)        => AMQPType::Boolean,
            AMQPValue::ShortShortInt(_)  => AMQPType::ShortShortInt,
            AMQPValue::ShortShortUInt(_) => AMQPType::ShortShortUInt,
            AMQPValue::ShortInt(_)       => AMQPType::ShortInt,
            AMQPValue::ShortUInt(_)      => AMQPType::ShortUInt,
            AMQPValue::LongInt(_)        => AMQPType::LongInt,
            AMQPValue::LongUInt(_)       => AMQPType::LongUInt,
            AMQPValue::LongLongInt(_)    => AMQPType::LongLongInt,
            AMQPValue::LongLongUInt(_)   => AMQPType::LongLongUInt,
            AMQPValue::Float(_)          => AMQPType::Float,
            AMQPValue::Double(_)         => AMQPType::Double,
            AMQPValue::DecimalValue(_)   => AMQPType::DecimalValue,
            AMQPValue::ShortString(_)    => AMQPType::ShortString,
            AMQPValue::LongString(_)     => AMQPType::LongString,
            AMQPValue::FieldArray(_)     => AMQPType::FieldArray,
            AMQPValue::Timestamp(_)      => AMQPType::Timestamp,
            AMQPValue::FieldTable(_)     => AMQPType::FieldTable,
            AMQPValue::Void              => AMQPType::Void,
        }
    }
}

impl From<Value> for AMQPValue {
    fn from(v: Value) -> AMQPValue {
        From::from(&v)
    }
}

impl<'a> From<&'a Value> for AMQPValue {
    fn from(v: &Value) -> AMQPValue {
        match *v {
            Value::Bool(ref b)   => AMQPValue::Boolean(*b),
            Value::Number(ref n) => {
                if n.is_u64() {
                    AMQPValue::LongLongUInt(n.as_u64().unwrap())
                } else if n.is_i64() {
                    AMQPValue::LongLongInt(n.as_i64().unwrap())
                } else {
                    AMQPValue::Double(n.as_f64().unwrap())
                }
            },
            Value::String(ref s) => AMQPValue::LongString(s.clone()),
            Value::Array(ref v)  => AMQPValue::FieldArray(v.iter().map(From::from).collect()),
            Value::Object(ref o) => AMQPValue::FieldTable(o.iter().fold(FieldTable::new(), |mut table, (k, v)| {
                table.insert(k.clone(), From::from(v));
                table
            })),
            Value::Null          => AMQPValue::Void,
        }
    }
}
<|endoftext|>


<commit_before>#![allow(unused_variables, dead_code)]

use std::ffi::{OsStr, OsString};

pub type ShortArg = u8;
pub type LongArg = &'static str;

#[derive(PartialEq, Debug)]
pub enum Flag {
    Short(ShortArg),
    Long(LongArg),
}

#[derive(PartialEq, Debug)]
pub enum Strictness {
    ComplainAboutRedundantArguments,
    UseLastArguments,
}

#[derive(Copy, Clone, PartialEq, Debug)]
pub enum TakesValue {
    Necessary,
    Forbidden,
}

#[derive(PartialEq, Debug)]
pub struct Arg {
    short: Option<ShortArg>,
    long: LongArg,
    takes_value: TakesValue,
}

#[derive(PartialEq, Debug)]
pub struct Args(&'static [Arg]);

impl Args {
    fn lookup_short<'a>(&self, short: ShortArg) -> Result<&Arg, ParseError<'a>> {
        match self.0.into_iter().find(|arg| arg.short == Some(short)) {
            Some(arg)  => Ok(arg),
            None       => Err(ParseError::UnknownShortArgument { attempt: short })
        }
    }

    fn lookup_long<'a>(&self, long: &'a OsStr) -> Result<&Arg, ParseError<'a>> {
        match self.0.into_iter().find(|arg| arg.long == long) {
            Some(arg)  => Ok(arg),
            None       => Err(ParseError::UnknownArgument { attempt: long })
        }
    }
}

#[derive(PartialEq, Debug)]
pub struct Matches<'a> {
    /// Long and short arguments need to be kept in the same vector, because
    /// we usually want the one nearest the end to count.
    flags: Vec<(Flag, Option<&'a OsStr>)>,
    frees: Vec<&'a OsStr>,
}

#[derive(PartialEq, Debug)]
pub enum ParseError<'a> {
    NeedsValue { flag: Flag },
    ForbiddenValue { flag: Flag },
    UnknownShortArgument { attempt: ShortArg },
    UnknownArgument { attempt: &'a OsStr },
}

fn parse<'a>(args: Args, inputs: &'a [OsString]) -> Result<Matches<'a>, ParseError<'a>> {
    use std::os::unix::ffi::OsStrExt;
    use self::TakesValue::*;

    let mut parsing = true;

    let mut results = Matches {
        flags: Vec::new(),
        frees: Vec::new(),
    };

    let mut iter = inputs.iter();
    while let Some(arg) = iter.next() {
        let bytes = arg.as_bytes();

        if !parsing {
            results.frees.push(arg)
        }
        else if arg == "--" {
            parsing = false;
        }
        else if bytes.starts_with(b"--") {
            let long_arg_name = OsStr::from_bytes(&bytes[2..]);

            if let Some((before, after)) = split_on_equals(long_arg_name) {
                let arg = args.lookup_long(before)?;
                let flag = Flag::Long(arg.long);
                match arg.takes_value {
                    Necessary  => results.flags.push((flag, Some(after))),
                    Forbidden  => return Err(ParseError::ForbiddenValue { flag })
                }
            }
            else {
                let arg = args.lookup_long(long_arg_name)?;
                let flag = Flag::Long(arg.long);
                match arg.takes_value {
                    Forbidden  => results.flags.push((flag, None)),
                    Necessary  => {
                        if let Some(next_arg) = iter.next() {
                            results.flags.push((flag, Some(next_arg)));
                        }
                        else {
                            return Err(ParseError::NeedsValue { flag })
                        }
                    }
                }
            }
        }
        else if bytes.starts_with(b"-") && arg != "-" {
            let short_arg = OsStr::from_bytes(&bytes[1..]);
            if let Some((before, after)) = split_on_equals(short_arg) {
                let (arg_with_value, other_args) = before.as_bytes().split_last().unwrap();

                for byte in other_args {
                    let arg = args.lookup_short(*byte)?;
                    let flag = Flag::Short(*byte);
                    match arg.takes_value {
                        Forbidden  => results.flags.push((flag, None)),
                        Necessary  => return Err(ParseError::NeedsValue { flag })
                    }
                }

                let arg = args.lookup_short(*before.as_bytes().last().unwrap())?;
                let flag = Flag::Short(arg.short.unwrap());
                match arg.takes_value {
                    Necessary  => results.flags.push((flag, Some(after))),
                    Forbidden  => return Err(ParseError::ForbiddenValue { flag })
                }
            }
            else {
                for (index, byte) in bytes.into_iter().enumerate().skip(1) {
                    let arg = args.lookup_short(*byte)?;
                    let flag = Flag::Short(*byte);
                    match arg.takes_value {
                        Forbidden  => results.flags.push((flag, None)),
                        Necessary  => {
                            if index < bytes.len() - 1 {
                                let remnants = &bytes[index+1 ..];
                                results.flags.push((flag, Some(OsStr::from_bytes(remnants))));
                                break;
                            }
                            else if let Some(next_arg) = iter.next() {
                                results.flags.push((flag, Some(next_arg)));
                            }
                            else {
                                return Err(ParseError::NeedsValue { flag })
                            }
                        }
                    }
                }
            }
        }
        else {
            results.frees.push(arg)
        }
    }

    Ok(results)
}

/// Splits a string on its `=` character, returning the two substrings on
/// either side. Returns `None` if there’s no equals or a string is missing.
fn split_on_equals(input: &OsStr) -> Option<(&OsStr, &OsStr)> {
    use std::os::unix::ffi::OsStrExt;

    if let Some(index) = input.as_bytes().iter().position(|elem| *elem == b'=') {
        let (before, after) = input.as_bytes().split_at(index);

        // The after string contains the = that we need to remove.
        if before.len() >= 1 && after.len() >= 2 {
            return Some((OsStr::from_bytes(before),
                         OsStr::from_bytes(&after[1..])))
        }
    }

    None
}

/// Creates an `OSString` (used in tests)
#[cfg(test)]
fn os(input: &'static str) -> OsString {
    let mut os = OsString::new();
    os.push(input);
    os
}

#[cfg(test)]
mod split_test {
    use super::{split_on_equals, os};

    macro_rules! test_split {
        ($name:ident: $input:expr => None) => {
            #[test]
            fn $name() {
                assert_eq!(split_on_equals(&os($input)),
                           None);
            }
        };

        ($name:ident: $input:expr => $before:expr, $after:expr) => {
            #[test]
            fn $name() {
                assert_eq!(split_on_equals(&os($input)),
                           Some((&*os($before), &*os($after))));
            }
        };
    }

    test_split!(empty:   ""   => None);
    test_split!(letter:  "a"  => None);

    test_split!(just:      "="    => None);
    test_split!(intro:     "=bbb" => None);
    test_split!(denou:  "aaa="    => None);
    test_split!(equals: "aaa=bbb" => "aaa", "bbb");

    test_split!(sort: "--sort=size"     => "--sort", "size");
    test_split!(more: "this=that=other" => "this",   "that=other");
}

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

    macro_rules! test {
        ($name:ident: $input:expr => $result:expr) => {
            #[test]
            fn $name() {
                let bits = $input;
                let results = parse(Args(TEST_ARGS), &bits);
                assert_eq!(results, $result);
            }
        };
    }

    static TEST_ARGS: &'static [Arg] = &[
        Arg { short: Some(b'l'), long: "long",     takes_value: TakesValue::Forbidden },
        Arg { short: Some(b'v'), long: "verbose",  takes_value: TakesValue::Forbidden },
        Arg { short: Some(b'c'), long: "count",    takes_value: TakesValue::Necessary }
    ];

    // Just filenames
    test!(empty:       []           => Ok(Matches { frees: vec![], flags: vec![] }));
    test!(one_arg:     [os("exa")]  => Ok(Matches { frees: vec![ os("exa").as_os_str() ], flags: vec![] }));

    // Dashes and double dashes
    test!(one_dash:    [os("-")]                 => Ok(Matches { frees: vec![ os("-").as_os_str() ],      flags: vec![] }));
    test!(two_dashes:  [os("--")]                => Ok(Matches { frees: vec![],                           flags: vec![] }));
    test!(two_file:    [os("--"), os("file")]    => Ok(Matches { frees: vec![ os("file").as_os_str() ],   flags: vec![] }));
    test!(two_arg_l:   [os("--"), os("--long")]  => Ok(Matches { frees: vec![ os("--long").as_os_str() ], flags: vec![] }));
    test!(two_arg_s:   [os("--"), os("-l")]      => Ok(Matches { frees: vec![ os("-l").as_os_str() ],     flags: vec![] }));

    // Long args
    test!(long:        [os("--long")]                  => Ok(Matches { frees: vec![],                      flags: vec![ (Flag::Long("long"), None) ] }));
    test!(long_then:   [os("--long"), os("4")]         => Ok(Matches { frees: vec![ os("4").as_os_str() ], flags: vec![ (Flag::Long("long"), None) ] }));
    test!(long_two:    [os("--long"), os("--verbose")] => Ok(Matches { frees: vec![],                      flags: vec![ (Flag::Long("long"), None), (Flag::Long("verbose"), None) ] }));

    // Long args with values
    test!(bad_equals:  [os("--long=equals")]    => Err(ParseError::ForbiddenValue { flag: Flag::Long("long") }));
    test!(no_arg:      [os("--count")]          => Err(ParseError::NeedsValue     { flag: Flag::Long("count") }));
    test!(arg_equals:  [os("--count=4")]        => Ok(Matches { frees: vec![], flags: vec![ (Flag::Long("count"), Some(os("4").as_os_str())) ] }));
    test!(arg_then:    [os("--count"), os("4")] => Ok(Matches { frees: vec![], flags: vec![ (Flag::Long("count"), Some(os("4").as_os_str())) ] }));

    // Short args
    test!(short:       [os("-l")]                  => Ok(Matches { frees: vec![],                      flags: vec![ (Flag::Short(b'l'), None) ] }));
    test!(short_then:  [os("-l"), os("4")]         => Ok(Matches { frees: vec![ os("4").as_os_str() ], flags: vec![ (Flag::Short(b'l'), None) ] }));
    test!(short_two:   [os("-lv")]                 => Ok(Matches { frees: vec![],                      flags: vec![ (Flag::Short(b'l'), None), (Flag::Short(b'v'), None) ] }));
    test!(mixed:       [os("-v"), os("--long")]    => Ok(Matches { frees: vec![],                      flags: vec![ (Flag::Short(b'v'), None), (Flag::Long("long"), None) ] }));

    // Short args with values
    test!(bad_short:          [os("-l=equals")]       => Err(ParseError::ForbiddenValue { flag: Flag::Short(b'l') }));
    test!(short_none:         [os("-c")]              => Err(ParseError::NeedsValue     { flag: Flag::Short(b'c') }));
    test!(short_arg_eq:       [os("-c=4")]            => Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'c'), Some(os("4").as_os_str())) ] }));
    test!(short_arg_then:     [os("-c"), os("4")]     => Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'c'), Some(os("4").as_os_str())) ] }));
    test!(short_two_together: [os("-lctwo")]          => Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'l'), None), (Flag::Short(b'c'), Some(os("two").as_os_str())) ] }));
    test!(short_two_equals:   [os("-lc=two")]         => Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'l'), None), (Flag::Short(b'c'), Some(os("two").as_os_str())) ] }));
    test!(short_two_next:     [os("-lc"), os("two")]  => Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'l'), None), (Flag::Short(b'c'), Some(os("two").as_os_str())) ] }));

    // Unknown args
    test!(unknown_long:          [os("--quiet")]      => Err(ParseError::UnknownArgument      { attempt: os("quiet").as_os_str() }));
    test!(unknown_long_eq:       [os("--quiet=shhh")] => Err(ParseError::UnknownArgument      { attempt: os("quiet").as_os_str() }));
    test!(unknown_short:         [os("-q")]           => Err(ParseError::UnknownShortArgument { attempt: b'q' }));
    test!(unknown_short_2nd:     [os("-lq")]          => Err(ParseError::UnknownShortArgument { attempt: b'q' }));
    test!(unknown_short_eq:      [os("-q=shhh")]      => Err(ParseError::UnknownShortArgument { attempt: b'q' }));
    test!(unknown_short_2nd_eq:  [os("-lq=shhh")]     => Err(ParseError::UnknownShortArgument { attempt: b'q' }));
}
<commit_msg>Search for long options through matches<commit_after>#![allow(unused_variables, dead_code)]

use std::ffi::{OsStr, OsString};

pub type ShortArg = u8;
pub type LongArg = &'static str;

#[derive(PartialEq, Debug)]
pub enum Flag {
    Short(ShortArg),
    Long(LongArg),
}

impl Flag {
    fn matches(&self, arg: &Arg) -> bool {
        match *self {
            Flag::Short(short)  => arg.short == Some(short),
            Flag::Long(long)    => arg.long == long,
        }
    }
}

#[derive(PartialEq, Debug)]
pub enum Strictness {
    ComplainAboutRedundantArguments,
    UseLastArguments,
}

#[derive(Copy, Clone, PartialEq, Debug)]
pub enum TakesValue {
    Necessary,
    Forbidden,
}

#[derive(PartialEq, Debug)]
pub struct Arg {
    short: Option<ShortArg>,
    long: LongArg,
    takes_value: TakesValue,
}

#[derive(PartialEq, Debug)]
pub struct Args(&'static [&'static Arg]);

impl Args {
    fn lookup_short<'a>(&self, short: ShortArg) -> Result<&Arg, ParseError<'a>> {
        match self.0.into_iter().find(|arg| arg.short == Some(short)) {
            Some(arg)  => Ok(arg),
            None       => Err(ParseError::UnknownShortArgument { attempt: short })
        }
    }

    fn lookup_long<'a>(&self, long: &'a OsStr) -> Result<&Arg, ParseError<'a>> {
        match self.0.into_iter().find(|arg| arg.long == long) {
            Some(arg)  => Ok(arg),
            None       => Err(ParseError::UnknownArgument { attempt: long })
        }
    }
}

#[derive(PartialEq, Debug)]
pub struct Matches<'a> {
    /// Long and short arguments need to be kept in the same vector, because
    /// we usually want the one nearest the end to count.
    flags: Vec<(Flag, Option<&'a OsStr>)>,
    frees: Vec<&'a OsStr>,
}

impl<'a> Matches<'a> {
    fn has(&self, arg: &Arg) -> bool {
        self.flags.iter().rev()
            .find(|tuple| tuple.1.is_none() && tuple.0.matches(arg))
            .is_some()
    }

    fn get(&self, arg: &Arg) -> Option<&OsStr> {
        self.flags.iter().rev()
            .find(|tuple| tuple.1.is_some() && tuple.0.matches(arg))
            .map(|tuple| tuple.1.unwrap())
    }
}

#[derive(PartialEq, Debug)]
pub enum ParseError<'a> {
    NeedsValue { flag: Flag },
    ForbiddenValue { flag: Flag },
    UnknownShortArgument { attempt: ShortArg },
    UnknownArgument { attempt: &'a OsStr },
}

fn parse<'a>(args: Args, inputs: &'a [OsString]) -> Result<Matches<'a>, ParseError<'a>> {
    use std::os::unix::ffi::OsStrExt;
    use self::TakesValue::*;

    let mut parsing = true;

    let mut results = Matches {
        flags: Vec::new(),
        frees: Vec::new(),
    };

    let mut iter = inputs.iter();
    while let Some(arg) = iter.next() {
        let bytes = arg.as_bytes();

        if !parsing {
            results.frees.push(arg)
        }
        else if arg == "--" {
            parsing = false;
        }
        else if bytes.starts_with(b"--") {
            let long_arg_name = OsStr::from_bytes(&bytes[2..]);

            if let Some((before, after)) = split_on_equals(long_arg_name) {
                let arg = args.lookup_long(before)?;
                let flag = Flag::Long(arg.long);
                match arg.takes_value {
                    Necessary  => results.flags.push((flag, Some(after))),
                    Forbidden  => return Err(ParseError::ForbiddenValue { flag })
                }
            }
            else {
                let arg = args.lookup_long(long_arg_name)?;
                let flag = Flag::Long(arg.long);
                match arg.takes_value {
                    Forbidden  => results.flags.push((flag, None)),
                    Necessary  => {
                        if let Some(next_arg) = iter.next() {
                            results.flags.push((flag, Some(next_arg)));
                        }
                        else {
                            return Err(ParseError::NeedsValue { flag })
                        }
                    }
                }
            }
        }
        else if bytes.starts_with(b"-") && arg != "-" {
            let short_arg = OsStr::from_bytes(&bytes[1..]);
            if let Some((before, after)) = split_on_equals(short_arg) {
                let (arg_with_value, other_args) = before.as_bytes().split_last().unwrap();

                for byte in other_args {
                    let arg = args.lookup_short(*byte)?;
                    let flag = Flag::Short(*byte);
                    match arg.takes_value {
                        Forbidden  => results.flags.push((flag, None)),
                        Necessary  => return Err(ParseError::NeedsValue { flag })
                    }
                }

                let arg = args.lookup_short(*before.as_bytes().last().unwrap())?;
                let flag = Flag::Short(arg.short.unwrap());
                match arg.takes_value {
                    Necessary  => results.flags.push((flag, Some(after))),
                    Forbidden  => return Err(ParseError::ForbiddenValue { flag })
                }
            }
            else {
                for (index, byte) in bytes.into_iter().enumerate().skip(1) {
                    let arg = args.lookup_short(*byte)?;
                    let flag = Flag::Short(*byte);
                    match arg.takes_value {
                        Forbidden  => results.flags.push((flag, None)),
                        Necessary  => {
                            if index < bytes.len() - 1 {
                                let remnants = &bytes[index+1 ..];
                                results.flags.push((flag, Some(OsStr::from_bytes(remnants))));
                                break;
                            }
                            else if let Some(next_arg) = iter.next() {
                                results.flags.push((flag, Some(next_arg)));
                            }
                            else {
                                return Err(ParseError::NeedsValue { flag })
                            }
                        }
                    }
                }
            }
        }
        else {
            results.frees.push(arg)
        }
    }

    Ok(results)
}

/// Splits a string on its `=` character, returning the two substrings on
/// either side. Returns `None` if there’s no equals or a string is missing.
fn split_on_equals(input: &OsStr) -> Option<(&OsStr, &OsStr)> {
    use std::os::unix::ffi::OsStrExt;

    if let Some(index) = input.as_bytes().iter().position(|elem| *elem == b'=') {
        let (before, after) = input.as_bytes().split_at(index);

        // The after string contains the = that we need to remove.
        if before.len() >= 1 && after.len() >= 2 {
            return Some((OsStr::from_bytes(before),
                         OsStr::from_bytes(&after[1..])))
        }
    }

    None
}

/// Creates an `OSString` (used in tests)
#[cfg(test)]
fn os(input: &'static str) -> OsString {
    let mut os = OsString::new();
    os.push(input);
    os
}

#[cfg(test)]
mod split_test {
    use super::{split_on_equals, os};

    macro_rules! test_split {
        ($name:ident: $input:expr => None) => {
            #[test]
            fn $name() {
                assert_eq!(split_on_equals(&os($input)),
                           None);
            }
        };

        ($name:ident: $input:expr => $before:expr, $after:expr) => {
            #[test]
            fn $name() {
                assert_eq!(split_on_equals(&os($input)),
                           Some((&*os($before), &*os($after))));
            }
        };
    }

    test_split!(empty:   ""   => None);
    test_split!(letter:  "a"  => None);

    test_split!(just:      "="    => None);
    test_split!(intro:     "=bbb" => None);
    test_split!(denou:  "aaa="    => None);
    test_split!(equals: "aaa=bbb" => "aaa", "bbb");

    test_split!(sort: "--sort=size"     => "--sort", "size");
    test_split!(more: "this=that=other" => "this",   "that=other");
}

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

    macro_rules! test {
        ($name:ident: $input:expr => $result:expr) => {
            #[test]
            fn $name() {
                let bits = $input;
                let results = parse(Args(TEST_ARGS), &bits);
                assert_eq!(results, $result);
            }
        };
    }

    static TEST_ARGS: &[&Arg] = &[
        &Arg { short: Some(b'l'), long: "long",     takes_value: TakesValue::Forbidden },
        &Arg { short: Some(b'v'), long: "verbose",  takes_value: TakesValue::Forbidden },
        &Arg { short: Some(b'c'), long: "count",    takes_value: TakesValue::Necessary }
    ];

    // Just filenames
    test!(empty:       []           => Ok(Matches { frees: vec![], flags: vec![] }));
    test!(one_arg:     [os("exa")]  => Ok(Matches { frees: vec![ os("exa").as_os_str() ], flags: vec![] }));

    // Dashes and double dashes
    test!(one_dash:    [os("-")]                 => Ok(Matches { frees: vec![ os("-").as_os_str() ],      flags: vec![] }));
    test!(two_dashes:  [os("--")]                => Ok(Matches { frees: vec![],                           flags: vec![] }));
    test!(two_file:    [os("--"), os("file")]    => Ok(Matches { frees: vec![ os("file").as_os_str() ],   flags: vec![] }));
    test!(two_arg_l:   [os("--"), os("--long")]  => Ok(Matches { frees: vec![ os("--long").as_os_str() ], flags: vec![] }));
    test!(two_arg_s:   [os("--"), os("-l")]      => Ok(Matches { frees: vec![ os("-l").as_os_str() ],     flags: vec![] }));

    // Long args
    test!(long:        [os("--long")]                  => Ok(Matches { frees: vec![],                      flags: vec![ (Flag::Long("long"), None) ] }));
    test!(long_then:   [os("--long"), os("4")]         => Ok(Matches { frees: vec![ os("4").as_os_str() ], flags: vec![ (Flag::Long("long"), None) ] }));
    test!(long_two:    [os("--long"), os("--verbose")] => Ok(Matches { frees: vec![],                      flags: vec![ (Flag::Long("long"), None), (Flag::Long("verbose"), None) ] }));

    // Long args with values
    test!(bad_equals:  [os("--long=equals")]    => Err(ParseError::ForbiddenValue { flag: Flag::Long("long") }));
    test!(no_arg:      [os("--count")]          => Err(ParseError::NeedsValue     { flag: Flag::Long("count") }));
    test!(arg_equals:  [os("--count=4")]        => Ok(Matches { frees: vec![], flags: vec![ (Flag::Long("count"), Some(os("4").as_os_str())) ] }));
    test!(arg_then:    [os("--count"), os("4")] => Ok(Matches { frees: vec![], flags: vec![ (Flag::Long("count"), Some(os("4").as_os_str())) ] }));

    // Short args
    test!(short:       [os("-l")]                  => Ok(Matches { frees: vec![],                      flags: vec![ (Flag::Short(b'l'), None) ] }));
    test!(short_then:  [os("-l"), os("4")]         => Ok(Matches { frees: vec![ os("4").as_os_str() ], flags: vec![ (Flag::Short(b'l'), None) ] }));
    test!(short_two:   [os("-lv")]                 => Ok(Matches { frees: vec![],                      flags: vec![ (Flag::Short(b'l'), None), (Flag::Short(b'v'), None) ] }));
    test!(mixed:       [os("-v"), os("--long")]    => Ok(Matches { frees: vec![],                      flags: vec![ (Flag::Short(b'v'), None), (Flag::Long("long"), None) ] }));

    // Short args with values
    test!(bad_short:          [os("-l=equals")]       => Err(ParseError::ForbiddenValue { flag: Flag::Short(b'l') }));
    test!(short_none:         [os("-c")]              => Err(ParseError::NeedsValue     { flag: Flag::Short(b'c') }));
    test!(short_arg_eq:       [os("-c=4")]            => Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'c'), Some(os("4").as_os_str())) ] }));
    test!(short_arg_then:     [os("-c"), os("4")]     => Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'c'), Some(os("4").as_os_str())) ] }));
    test!(short_two_together: [os("-lctwo")]          => Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'l'), None), (Flag::Short(b'c'), Some(os("two").as_os_str())) ] }));
    test!(short_two_equals:   [os("-lc=two")]         => Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'l'), None), (Flag::Short(b'c'), Some(os("two").as_os_str())) ] }));
    test!(short_two_next:     [os("-lc"), os("two")]  => Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'l'), None), (Flag::Short(b'c'), Some(os("two").as_os_str())) ] }));

    // Unknown args
    test!(unknown_long:          [os("--quiet")]      => Err(ParseError::UnknownArgument      { attempt: os("quiet").as_os_str() }));
    test!(unknown_long_eq:       [os("--quiet=shhh")] => Err(ParseError::UnknownArgument      { attempt: os("quiet").as_os_str() }));
    test!(unknown_short:         [os("-q")]           => Err(ParseError::UnknownShortArgument { attempt: b'q' }));
    test!(unknown_short_2nd:     [os("-lq")]          => Err(ParseError::UnknownShortArgument { attempt: b'q' }));
    test!(unknown_short_eq:      [os("-q=shhh")]      => Err(ParseError::UnknownShortArgument { attempt: b'q' }));
    test!(unknown_short_2nd_eq:  [os("-lq=shhh")]     => Err(ParseError::UnknownShortArgument { attempt: b'q' }));
}

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

    static LONG:    Arg = Arg { short: Some(b'l'), long: "long",     takes_value: TakesValue::Forbidden };
    static VERBOSE: Arg = Arg { short: Some(b'v'), long: "verbose",  takes_value: TakesValue::Forbidden };
    static COUNT:   Arg = Arg { short: Some(b'c'), long: "count",    takes_value: TakesValue::Necessary };
    static TEST_ARGS: &[&Arg] = &[ &LONG, &VERBOSE, &COUNT ];

    #[test]
    fn has_long() {
        let matches = Matches {
            frees: Vec::new(),
            flags: vec![ (Flag::Short(b'l'), None) ],
        };

        assert!(matches.has(&LONG));
    }

    #[test]
    fn has_long_twice() {
        let matches = Matches {
            frees: Vec::new(),
            flags: vec![ (Flag::Short(b'l'), None),
                         (Flag::Short(b'l'), None) ],
        };

        assert!(matches.has(&LONG));
    }

    #[test]
    fn no_long() {
        let matches = Matches {
            frees: Vec::new(),
            flags: Vec::new(),
        };

        assert!(!matches.has(&LONG));
    }

    #[test]
    fn only_count() {
        let everything = os("everything");

        let matches = Matches {
            frees: Vec::new(),
            flags: vec![ (Flag::Short(b'c'), Some(&*everything)) ],
        };

        assert_eq!(matches.get(&COUNT), Some(&*everything));
    }

    #[test]
    fn rightmost_count() {
        let everything = os("everything");
        let nothing    = os("nothing");

        let matches = Matches {
            frees: Vec::new(),
            flags: vec![ (Flag::Short(b'c'), Some(&*everything)),
                         (Flag::Short(b'c'), Some(&*nothing)) ],
        };

        assert_eq!(matches.get(&COUNT), Some(&*nothing));
    }

    #[test]
    fn no_count() {
        let matches = Matches {
            frees: Vec::new(),
            flags: Vec::new(),
        };

        assert!(!matches.has(&COUNT));
    }
}
<|endoftext|>


<commit_before>use std::os::raw::c_int;

/// Perform lazy binding.
///
/// Relocations shall be performed at an implementation-defined time, ranging from the time
/// of the [`Library::open`] call until the first reference to a given symbol occurs.
/// Specifying `RTLD_LAZY` should improve performance on implementations supporting dynamic
/// symbol binding since a process might not reference all of the symbols in an executable
/// object file. And, for systems supporting dynamic symbol resolution for normal process
/// execution, this behaviour mimics the normal handling of process execution.
///
/// Conflicts with [`RTLD_NOW`].
///
/// [`Library::open`]: crate::os::unix::Library::open
pub const RTLD_LAZY: c_int = posix::RTLD_LAZY;

/// Perform eager binding.
///
/// All necessary relocations shall be performed when the executable object file is first
/// loaded. This may waste some processing if relocations are performed for symbols
/// that are never referenced. This behaviour may be useful for applications that need to
/// know that all symbols referenced during execution will be available before
/// [`Library::open`] returns.
///
/// Conflicts with [`RTLD_LAZY`].
///
/// [`Library::open`]: crate::os::unix::Library::open
pub const RTLD_NOW: c_int = posix::RTLD_NOW;

/// Make loaded symbols available for resolution globally.
///
/// The executable object file's symbols shall be made available for relocation processing of any
/// other executable object file. In addition, calls to [`Library::get`] on `Library` obtained from
/// [`Library::this`] allows executable object files loaded with this mode to be searched.
///
/// [`Library::this`]: crate::os::unix::Library::this
/// [`Library::get`]: crate::os::unix::Library::get
pub const RTLD_GLOBAL: c_int = posix::RTLD_GLOBAL;

/// Load symbols into an isolated namespace.
///
/// The executable object file's symbols shall not be made available for relocation processing of
/// any other executable object file. This mode of operation is most appropriate for e.g. plugins.
pub const RTLD_LOCAL: c_int = posix::RTLD_LOCAL;

#[cfg(all(libloading_docs, not(unix)))]
mod posix {
    use super::c_int;
    pub(super) const RTLD_LAZY: c_int = !0;
    pub(super) const RTLD_NOW: c_int = !0;
    pub(super) const RTLD_GLOBAL: c_int = !0;
    pub(super) const RTLD_LOCAL: c_int = !0;
}

#[cfg(any(not(libloading_docs), unix))]
mod posix {
    extern crate cfg_if;
    use self::cfg_if::cfg_if;
    use super::c_int;
    cfg_if! {
        if #[cfg(target_os = "haiku")] {
            pub(super) const RTLD_LAZY: c_int = 0;
        } else if #[cfg(any(
            target_os = "linux",
            target_os = "android",
            target_os = "emscripten",

            target_os = "macos",
            target_os = "ios",
            target_os = "freebsd",
            target_os = "dragonfly",
            target_os = "openbsd",
            target_os = "netbsd",

            target_os = "solaris",
            target_os = "illumos",

            target_env = "uclibc",
            target_env = "newlib",

            target_os = "fuchsia",
            target_os = "redox",
        ))] {
            pub(super) const RTLD_LAZY: c_int = 1;
        } else {
            compile_error!(
                "Target has no known `RTLD_LAZY` value. Please submit an issue or PR adding it."
            );
        }
    }

    cfg_if! {
        if #[cfg(target_os = "haiku")] {
            pub(super) const RTLD_NOW: c_int = 1;
        } else if #[cfg(any(
            target_os = "linux",
            all(target_os = "android", target_pointer_width = "64"),
            target_os = "emscripten",

            target_os = "macos",
            target_os = "ios",
            target_os = "freebsd",
            target_os = "dragonfly",
            target_os = "openbsd",
            target_os = "netbsd",

            target_os = "solaris",
            target_os = "illumos",

            target_env = "uclibc",
            target_env = "newlib",

            target_os = "fuchsia",
            target_os = "redox",
        ))] {
            pub(super) const RTLD_NOW: c_int = 2;
        } else if #[cfg(all(target_os = "android",target_pointer_width = "32"))] {
            pub(super) const RTLD_NOW: c_int = 0;
        } else {
            compile_error!(
                "Target has no known `RTLD_NOW` value. Please submit an issue or PR adding it."
            );
        }
    }

    cfg_if! {
        if #[cfg(any(
            target_os = "haiku",
            all(target_os = "android",target_pointer_width = "32"),
        ))] {
            pub(super) const RTLD_GLOBAL: c_int = 2;
        } else if #[cfg(any(
            target_env = "uclibc",
            all(target_os = "linux", target_arch = "mips"),
            all(target_os = "linux", target_arch = "mips64"),
        ))] {
            pub(super) const RTLD_GLOBAL: c_int = 4;
        } else if #[cfg(any(
            target_os = "macos",
            target_os = "ios",
        ))] {
            pub(super) const RTLD_GLOBAL: c_int = 8;
        } else if #[cfg(any(
            target_os = "linux",
            all(target_os = "android", target_pointer_width = "64"),
            target_os = "emscripten",

            target_os = "freebsd",
            target_os = "dragonfly",
            target_os = "openbsd",
            target_os = "netbsd",

            target_os = "solaris",
            target_os = "illumos",

            target_env = "newlib",

            target_os = "fuchsia",
            target_os = "redox",
        ))] {
            pub(super) const RTLD_GLOBAL: c_int = 0x100;
        } else {
            compile_error!(
                "Target has no known `RTLD_GLOBAL` value. Please submit an issue or PR adding it."
            );
        }
    }

    cfg_if! {
        if #[cfg(target_os = "netbsd")] {
            pub(super) const RTLD_LOCAL: c_int = 0x200;
        } else if #[cfg(any(
            target_os = "macos",
            target_os = "ios",
        ))] {
            pub(super) const RTLD_LOCAL: c_int = 4;
        } else if #[cfg(any(
            target_os = "linux",
            target_os = "android",
            target_os = "emscripten",

            target_os = "freebsd",
            target_os = "dragonfly",
            target_os = "openbsd",

            target_os = "haiku",

            target_os = "solaris",
            target_os = "illumos",

            target_env = "uclibc",
            target_env = "newlib",

            target_os = "fuchsia",
            target_os = "redox",
        ))] {
            pub(super) const RTLD_LOCAL: c_int = 0;
        } else {
            compile_error!(
                "Target has no known `RTLD_LOCAL` value. Please submit an issue or PR adding it."
            );
        }
    }
}

// Other constants that exist but are not bound because they are platform-specific (non-posix)
// extensions. Some of these constants are only relevant to `dlsym` or `dlmopen` calls.
//
// RTLD_CONFGEN
// RTLD_DEFAULT
// RTLD_DI_CONFIGADDR
// RTLD_DI_LINKMAP
// RTLD_DI_LMID
// RTLD_DI_ORIGIN
// RTLD_DI_PROFILENAME
// RTLD_DI_PROFILEOUT
// RTLD_DI_SERINFO
// RTLD_DI_SERINFOSIZE
// RTLD_DI_TLS_DATA
// RTLD_DI_TLS_MODID
// RTLD_FIRST
// RTLD_GROUP
// RTLD_NEXT
// RTLD_PARENT
// RTLD_PROBE
// RTLD_SELF
// RTLD_WORLD
// RTLD_NODELETE
// RTLD_NOLOAD
// RTLD_DEEPBIND
<commit_msg>Support AIX dyld constants<commit_after>use std::os::raw::c_int;

/// Perform lazy binding.
///
/// Relocations shall be performed at an implementation-defined time, ranging from the time
/// of the [`Library::open`] call until the first reference to a given symbol occurs.
/// Specifying `RTLD_LAZY` should improve performance on implementations supporting dynamic
/// symbol binding since a process might not reference all of the symbols in an executable
/// object file. And, for systems supporting dynamic symbol resolution for normal process
/// execution, this behaviour mimics the normal handling of process execution.
///
/// Conflicts with [`RTLD_NOW`].
///
/// [`Library::open`]: crate::os::unix::Library::open
pub const RTLD_LAZY: c_int = posix::RTLD_LAZY;

/// Perform eager binding.
///
/// All necessary relocations shall be performed when the executable object file is first
/// loaded. This may waste some processing if relocations are performed for symbols
/// that are never referenced. This behaviour may be useful for applications that need to
/// know that all symbols referenced during execution will be available before
/// [`Library::open`] returns.
///
/// Conflicts with [`RTLD_LAZY`].
///
/// [`Library::open`]: crate::os::unix::Library::open
pub const RTLD_NOW: c_int = posix::RTLD_NOW;

/// Make loaded symbols available for resolution globally.
///
/// The executable object file's symbols shall be made available for relocation processing of any
/// other executable object file. In addition, calls to [`Library::get`] on `Library` obtained from
/// [`Library::this`] allows executable object files loaded with this mode to be searched.
///
/// [`Library::this`]: crate::os::unix::Library::this
/// [`Library::get`]: crate::os::unix::Library::get
pub const RTLD_GLOBAL: c_int = posix::RTLD_GLOBAL;

/// Load symbols into an isolated namespace.
///
/// The executable object file's symbols shall not be made available for relocation processing of
/// any other executable object file. This mode of operation is most appropriate for e.g. plugins.
pub const RTLD_LOCAL: c_int = posix::RTLD_LOCAL;

#[cfg(all(libloading_docs, not(unix)))]
mod posix {
    use super::c_int;
    pub(super) const RTLD_LAZY: c_int = !0;
    pub(super) const RTLD_NOW: c_int = !0;
    pub(super) const RTLD_GLOBAL: c_int = !0;
    pub(super) const RTLD_LOCAL: c_int = !0;
}

#[cfg(any(not(libloading_docs), unix))]
mod posix {
    extern crate cfg_if;
    use self::cfg_if::cfg_if;
    use super::c_int;
    cfg_if! {
        if #[cfg(target_os = "haiku")] {
            pub(super) const RTLD_LAZY: c_int = 0;
        } else if #[cfg(target_os = "aix")] {
            pub(super) const RTLD_LAZY: c_int = 4;
        } else if #[cfg(any(
            target_os = "linux",
            target_os = "android",
            target_os = "emscripten",

            target_os = "macos",
            target_os = "ios",
            target_os = "freebsd",
            target_os = "dragonfly",
            target_os = "openbsd",
            target_os = "netbsd",

            target_os = "solaris",
            target_os = "illumos",

            target_env = "uclibc",
            target_env = "newlib",

            target_os = "fuchsia",
            target_os = "redox",
        ))] {
            pub(super) const RTLD_LAZY: c_int = 1;
        } else {
            compile_error!(
                "Target has no known `RTLD_LAZY` value. Please submit an issue or PR adding it."
            );
        }
    }

    cfg_if! {
        if #[cfg(target_os = "haiku")] {
            pub(super) const RTLD_NOW: c_int = 1;
        } else if #[cfg(any(
            target_os = "linux",
            all(target_os = "android", target_pointer_width = "64"),
            target_os = "emscripten",

            target_os = "macos",
            target_os = "ios",
            target_os = "freebsd",
            target_os = "dragonfly",
            target_os = "openbsd",
            target_os = "netbsd",

            target_os = "aix",
            target_os = "solaris",
            target_os = "illumos",

            target_env = "uclibc",
            target_env = "newlib",

            target_os = "fuchsia",
            target_os = "redox",
        ))] {
            pub(super) const RTLD_NOW: c_int = 2;
        } else if #[cfg(all(target_os = "android",target_pointer_width = "32"))] {
            pub(super) const RTLD_NOW: c_int = 0;
        } else {
            compile_error!(
                "Target has no known `RTLD_NOW` value. Please submit an issue or PR adding it."
            );
        }
    }

    cfg_if! {
        if #[cfg(any(
            target_os = "haiku",
            all(target_os = "android",target_pointer_width = "32"),
        ))] {
            pub(super) const RTLD_GLOBAL: c_int = 2;
        } else if #[cfg(target_os = "aix")] {
            pub(super) const RTLD_GLOBAL: c_int = 0x10000;
        } else if #[cfg(any(
            target_env = "uclibc",
            all(target_os = "linux", target_arch = "mips"),
            all(target_os = "linux", target_arch = "mips64"),
        ))] {
            pub(super) const RTLD_GLOBAL: c_int = 4;
        } else if #[cfg(any(
            target_os = "macos",
            target_os = "ios",
        ))] {
            pub(super) const RTLD_GLOBAL: c_int = 8;
        } else if #[cfg(any(
            target_os = "linux",
            all(target_os = "android", target_pointer_width = "64"),
            target_os = "emscripten",

            target_os = "freebsd",
            target_os = "dragonfly",
            target_os = "openbsd",
            target_os = "netbsd",

            target_os = "solaris",
            target_os = "illumos",

            target_env = "newlib",

            target_os = "fuchsia",
            target_os = "redox",
        ))] {
            pub(super) const RTLD_GLOBAL: c_int = 0x100;
        } else {
            compile_error!(
                "Target has no known `RTLD_GLOBAL` value. Please submit an issue or PR adding it."
            );
        }
    }

    cfg_if! {
        if #[cfg(target_os = "netbsd")] {
            pub(super) const RTLD_LOCAL: c_int = 0x200;
        } else if #[cfg(target_os = "aix")] {
            pub(super) const RTLD_LOCAL: c_int = 0x80000;
        } else if #[cfg(any(
            target_os = "macos",
            target_os = "ios",
        ))] {
            pub(super) const RTLD_LOCAL: c_int = 4;
        } else if #[cfg(any(
            target_os = "linux",
            target_os = "android",
            target_os = "emscripten",

            target_os = "freebsd",
            target_os = "dragonfly",
            target_os = "openbsd",

            target_os = "haiku",

            target_os = "solaris",
            target_os = "illumos",

            target_env = "uclibc",
            target_env = "newlib",

            target_os = "fuchsia",
            target_os = "redox",
        ))] {
            pub(super) const RTLD_LOCAL: c_int = 0;
        } else {
            compile_error!(
                "Target has no known `RTLD_LOCAL` value. Please submit an issue or PR adding it."
            );
        }
    }
}

// Other constants that exist but are not bound because they are platform-specific (non-posix)
// extensions. Some of these constants are only relevant to `dlsym` or `dlmopen` calls.
//
// RTLD_CONFGEN
// RTLD_DEFAULT
// RTLD_DI_CONFIGADDR
// RTLD_DI_LINKMAP
// RTLD_DI_LMID
// RTLD_DI_ORIGIN
// RTLD_DI_PROFILENAME
// RTLD_DI_PROFILEOUT
// RTLD_DI_SERINFO
// RTLD_DI_SERINFOSIZE
// RTLD_DI_TLS_DATA
// RTLD_DI_TLS_MODID
// RTLD_FIRST
// RTLD_GROUP
// RTLD_NEXT
// RTLD_PARENT
// RTLD_PROBE
// RTLD_SELF
// RTLD_WORLD
// RTLD_NODELETE
// RTLD_NOLOAD
// RTLD_DEEPBIND
<|endoftext|>