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

// force-host

#![crate_type="dylib"]
#![feature(plugin_registrar, quote, rustc_private)]

extern crate syntax;
extern crate syntax_pos;
extern crate rustc;
extern crate rustc_plugin;

use syntax::parse::token::{self, str_to_ident, NtExpr, NtPat};
use syntax::ast::{Pat};
use syntax::tokenstream::{TokenTree};
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax::ext::build::AstBuilder;
use syntax::ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
use syntax::ext::tt::macro_parser::{Success, Failure, Error};
use syntax::ptr::P;
use syntax_pos::Span;
use rustc_plugin::Registry;

fn expand_mbe_matches(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
        -> Box<MacResult + 'static> {

    let mbe_matcher = quote_matcher!(cx, $matched:expr, $($pat:pat)|+);

    let mac_expr = match TokenTree::parse(cx, &mbe_matcher[..], args) {
        Success(map) => {
            match (&*map[&str_to_ident("matched").name], &*map[&str_to_ident("pat").name]) {
                (&MatchedNonterminal(NtExpr(ref matched_expr)),
                 &MatchedSeq(ref pats, seq_sp)) => {
                    let pats: Vec<P<Pat>> = pats.iter().map(|pat_nt|
                        if let &MatchedNonterminal(NtPat(ref pat)) = &**pat_nt {
                            pat.clone()
                        } else {
                            unreachable!()
                        }
                    ).collect();
                    let arm = cx.arm(seq_sp, pats, cx.expr_bool(seq_sp, true));

                    quote_expr!(cx,
                        match $matched_expr {
                            $arm
                            _ => false
                        }
                    )
                }
                _ => unreachable!()
            }
        }
        Failure(_, s) | Error(_, s) => {
            panic!("expected Success, but got Error/Failure: {}", s);
        }
    };

    MacEager::expr(mac_expr)
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("matches", expand_mbe_matches);
}
<commit_msg>Fix fallout in tests.<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// force-host

#![crate_type="dylib"]
#![feature(plugin_registrar, quote, rustc_private)]

extern crate syntax;
extern crate syntax_pos;
extern crate rustc;
extern crate rustc_plugin;

use syntax::parse::token::{self, str_to_ident, NtExpr, NtPat};
use syntax::ast::{Pat};
use syntax::tokenstream::{TokenTree};
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax::ext::build::AstBuilder;
use syntax::ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
use syntax::ext::tt::macro_parser::{Success, Failure, Error};
use syntax::ptr::P;
use syntax_pos::Span;
use rustc_plugin::Registry;

fn expand_mbe_matches(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
        -> Box<MacResult + 'static> {

    let mbe_matcher = quote_matcher!(cx, $matched:expr, $($pat:pat)|+);

    let mac_expr = match TokenTree::parse(cx, &mbe_matcher[..], args) {
        Success(map) => {
            match (&*map[&str_to_ident("matched")], &*map[&str_to_ident("pat")]) {
                (&MatchedNonterminal(NtExpr(ref matched_expr)),
                 &MatchedSeq(ref pats, seq_sp)) => {
                    let pats: Vec<P<Pat>> = pats.iter().map(|pat_nt|
                        if let &MatchedNonterminal(NtPat(ref pat)) = &**pat_nt {
                            pat.clone()
                        } else {
                            unreachable!()
                        }
                    ).collect();
                    let arm = cx.arm(seq_sp, pats, cx.expr_bool(seq_sp, true));

                    quote_expr!(cx,
                        match $matched_expr {
                            $arm
                            _ => false
                        }
                    )
                }
                _ => unreachable!()
            }
        }
        Failure(_, s) | Error(_, s) => {
            panic!("expected Success, but got Error/Failure: {}", s);
        }
    };

    MacEager::expr(mac_expr)
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("matches", expand_mbe_matches);
}
<|endoftext|>


<commit_before>
import option::none;
import option::some;
import util::orb;

export vbuf;

type vbuf = rustrt::vbuf;

native "rust" mod rustrt {
    type vbuf;
    fn vec_buf[T](v: vec[T], offset: uint) -> vbuf;
    fn vec_len[T](v: vec[T]) -> uint;

    /**
     * Sometimes we modify the vec internal data via vec_buf and need to
     * update the vec's fill length accordingly.
     */
    fn vec_len_set[T](v: vec[T], n: uint);

    /**
     * The T in vec_alloc[T, U] is the type of the vec to allocate.  The
     * U is the type of an element in the vec.  So to allocate a vec[U] we
     * want to invoke this as vec_alloc[vec[U], U].
     */
    fn vec_alloc[T, U](n_elts: uint) -> vec[U];
    fn vec_alloc_mut[T, U](n_elts: uint) -> vec[mutable U];
    fn refcount[T](v: vec[T]) -> uint;
    fn vec_print_debug_info[T](v: vec[T]);
    fn vec_from_vbuf[T](v: vbuf, n_elts: uint) -> vec[T];
    fn unsafe_vec_to_mut[T](v: vec[T]) -> vec[mutable T];
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Don't export anything from std::vec<commit_after>
import option::none;
import option::some;
import util::orb;

export dummy;

type dummy = int;

native "rust" mod rustrt {
    type vbuf;
    fn vec_buf[T](v: vec[T], offset: uint) -> vbuf;
    fn vec_len[T](v: vec[T]) -> uint;

    /**
     * Sometimes we modify the vec internal data via vec_buf and need to
     * update the vec's fill length accordingly.
     */
    fn vec_len_set[T](v: vec[T], n: uint);

    /**
     * The T in vec_alloc[T, U] is the type of the vec to allocate.  The
     * U is the type of an element in the vec.  So to allocate a vec[U] we
     * want to invoke this as vec_alloc[vec[U], U].
     */
    fn vec_alloc[T, U](n_elts: uint) -> vec[U];
    fn vec_alloc_mut[T, U](n_elts: uint) -> vec[mutable U];
    fn refcount[T](v: vec[T]) -> uint;
    fn vec_print_debug_info[T](v: vec[T]);
    fn vec_from_vbuf[T](v: vbuf, n_elts: uint) -> vec[T];
    fn unsafe_vec_to_mut[T](v: vec[T]) -> vec[mutable T];
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>// Interior vector utility functions.

import option::{some, none};
import uint::next_power_of_two;
import ptr::addr_of;

native "rust-intrinsic" mod rusti {
    fn vec_len<T>(v: [T]) -> uint;
}

native "rust" mod rustrt {
    fn vec_reserve_shared<T>(&v: [mutable? T], n: uint);
    fn vec_from_buf_shared<T>(ptr: *T, count: uint) -> [T];
}

/// Reserves space for `n` elements in the given vector.
fn reserve<@T>(&v: [mutable? T], n: uint) {
    rustrt::vec_reserve_shared(v, n);
}

pure fn len<T>(v: [mutable? T]) -> uint { unchecked { rusti::vec_len(v) } }

type init_op<T> = fn(uint) -> T;

fn init_fn<@T>(op: init_op<T>, n_elts: uint) -> [T] {
    let v = [];
    reserve(v, n_elts);
    let i: uint = 0u;
    while i < n_elts { v += [op(i)]; i += 1u; }
    ret v;
}

// TODO: Remove me once we have slots.
fn init_fn_mut<@T>(op: init_op<T>, n_elts: uint) -> [mutable T] {
    let v = [mutable];
    reserve(v, n_elts);
    let i: uint = 0u;
    while i < n_elts { v += [mutable op(i)]; i += 1u; }
    ret v;
}

fn init_elt<@T>(t: T, n_elts: uint) -> [T] {
    let v = [];
    reserve(v, n_elts);
    let i: uint = 0u;
    while i < n_elts { v += [t]; i += 1u; }
    ret v;
}

// TODO: Remove me once we have slots.
fn init_elt_mut<@T>(t: T, n_elts: uint) -> [mutable T] {
    let v = [mutable];
    reserve(v, n_elts);
    let i: uint = 0u;
    while i < n_elts { v += [mutable t]; i += 1u; }
    ret v;
}

// FIXME: Possible typestate postcondition:
// len(result) == len(v) (needs issue #586)
fn to_mut<@T>(v: [T]) -> [mutable T] {
    let vres = [mutable];
    for t: T in v { vres += [mutable t]; }
    ret vres;
}

// Same comment as from_mut
fn from_mut<@T>(v: [mutable T]) -> [T] {
    let vres = [];
    for t: T in v { vres += [t]; }
    ret vres;
}

// Predicates
pure fn is_empty<T>(v: [mutable? T]) -> bool {
    // FIXME: This would be easier if we could just call len
    for t: T in v { ret false; }
    ret true;
}

pure fn is_not_empty<T>(v: [mutable? T]) -> bool { ret !is_empty(v); }

// Accessors

/// Returns the first element of a vector
fn head<@T>(v: [mutable? T]) : is_not_empty(v) -> T { ret v[0]; }

/// Returns all but the first element of a vector
fn tail<@T>(v: [mutable? T]) : is_not_empty(v) -> [mutable? T] {
    ret slice(v, 1u, len(v));
}

/// Returns the last element of `v`.
fn last<@T>(v: [mutable? T]) -> option::t<T> {
    if len(v) == 0u { ret none; }
    ret some(v[len(v) - 1u]);
}

/// Returns the last element of a non-empty vector `v`.
fn last_total<@T>(v: [mutable? T]) : is_not_empty(v) -> T {
    ret v[len(v) - 1u];
}

/// Returns a copy of the elements from [`start`..`end`) from `v`.
fn slice<@T>(v: [mutable? T], start: uint, end: uint) -> [T] {
    assert (start <= end);
    assert (end <= len(v));
    let result = [];
    reserve(result, end - start);
    let i = start;
    while i < end { result += [v[i]]; i += 1u; }
    ret result;
}

// TODO: Remove me once we have slots.
fn slice_mut<@T>(v: [mutable? T], start: uint, end: uint) -> [mutable T] {
    assert (start <= end);
    assert (end <= len(v));
    let result = [mutable];
    reserve(result, end - start);
    let i = start;
    while i < end { result += [mutable v[i]]; i += 1u; }
    ret result;
}

// Mutators

fn shift<@T>(&v: [mutable? T]) -> T {
    let ln = len::<T>(v);
    assert (ln > 0u);
    let e = v[0];
    v = slice::<T>(v, 1u, ln);
    ret e;
}

// TODO: Write this, unsafely, in a way that's not O(n).
fn pop<@T>(&v: [mutable? T]) -> T {
    let ln = len(v);
    assert (ln > 0u);
    ln -= 1u;
    let e = v[ln];
    v = slice(v, 0u, ln);
    ret e;
}

// TODO: More.

// Appending

/// Expands the given vector in-place by appending `n` copies of `initval`.
fn grow<@T>(&v: [T], n: uint, initval: T) {
    reserve(v, next_power_of_two(len(v) + n));
    let i: uint = 0u;
    while i < n { v += [initval]; i += 1u; }
}

// TODO: Remove me once we have slots.
fn grow_mut<@T>(&v: [mutable T], n: uint, initval: T) {
    reserve(v, next_power_of_two(len(v) + n));
    let i: uint = 0u;
    while i < n { v += [mutable initval]; i += 1u; }
}

/// Calls `f` `n` times and appends the results of these calls to the given
/// vector.
fn grow_fn<@T>(&v: [T], n: uint, init_fn: fn(uint) -> T) {
    reserve(v, next_power_of_two(len(v) + n));
    let i: uint = 0u;
    while i < n { v += [init_fn(i)]; i += 1u; }
}

/// Sets the element at position `index` to `val`. If `index` is past the end
/// of the vector, expands the vector by replicating `initval` to fill the
/// intervening space.
fn grow_set<@T>(&v: [mutable T], index: uint, initval: T, val: T) {
    if index >= len(v) { grow_mut(v, index - len(v) + 1u, initval); }
    v[index] = val;
}

// Functional utilities

fn map<@T, @U>(f: block(T) -> U, v: [mutable? T]) -> [U] {
    let result = [];
    reserve(result, len(v));
    for elem: T in v {
        let elem2 = elem; // satisfies alias checker
        result += [f(elem2)];
    }
    ret result;
}

fn map2<@T, @U, @V>(f: block(T, U) -> V, v0: [T], v1: [U]) -> [V] {
    let v0_len = len::<T>(v0);
    if v0_len != len::<U>(v1) { fail; }
    let u: [V] = [];
    let i = 0u;
    while i < v0_len { u += [f({ v0[i] }, { v1[i] })]; i += 1u; }
    ret u;
}

fn filter_map<@T, @U>(f: block(T) -> option::t<U>, v: [mutable? T]) -> [U] {
    let result = [];
    for elem: T in v {
        let elem2 = elem; // satisfies alias checker
        alt f(elem2) {
          none. {/* no-op */ }
          some(result_elem) { result += [result_elem]; }
        }
    }
    ret result;
}

fn filter<@T>(f: block(T) -> bool, v: [mutable? T]) -> [T] {
    let result = [];
    for elem: T in v {
        let elem2 = elem; // satisfies alias checker
        if f(elem2) {
            result += [elem2];
        }
    }
    ret result;
}

fn foldl<@T, @U>(p: block(U, T) -> U, z: U, v: [mutable? T]) -> U {
    let sz = len(v);
    if sz == 0u { ret z; }
    let first = v[0];
    let rest = slice(v, 1u, sz);
    ret p(foldl(p, z, rest), first);
}

fn any<T>(f: block(T) -> bool, v: [T]) -> bool {
    for elem: T in v { if f(elem) { ret true; } }
    ret false;
}

fn all<T>(f: block(T) -> bool, v: [T]) -> bool {
    for elem: T in v { if !f(elem) { ret false; } }
    ret true;
}

fn member<T>(x: T, v: [T]) -> bool {
    for elt: T in v { if x == elt { ret true; } }
    ret false;
}

fn count<T>(x: T, v: [mutable? T]) -> uint {
    let cnt = 0u;
    for elt: T in v { if x == elt { cnt += 1u; } }
    ret cnt;
}

fn find<@T>(f: block(T) -> bool, v: [T]) -> option::t<T> {
    for elt: T in v { if f(elt) { ret some(elt); } }
    ret none;
}

fn position<@T>(x: T, v: [T]) -> option::t<uint> {
    let i: uint = 0u;
    while i < len(v) { if x == v[i] { ret some::<uint>(i); } i += 1u; }
    ret none;
}

fn position_pred<T>(f: fn(T) -> bool, v: [T]) -> option::t<uint> {
    let i: uint = 0u;
    while i < len(v) { if f(v[i]) { ret some::<uint>(i); } i += 1u; }
    ret none;
}

pure fn same_length<T, U>(xs: [T], ys: [U]) -> bool {
    vec::len(xs) == vec::len(ys)
}

// FIXME: if issue #586 gets implemented, could have a postcondition
// saying the two result lists have the same length -- or, could
// return a nominal record with a constraint saying that, instead of
// returning a tuple (contingent on issue #869)
fn unzip<@T, @U>(v: [(T, U)]) -> ([T], [U]) {
    let as = [], bs = [];
    for (a, b) in v { as += [a]; bs += [b]; }
    ret (as, bs);
}

fn zip<@T, @U>(v: [T], u: [U]) : same_length(v, u) -> [(T, U)] {
    let zipped = [];
    let sz = len(v), i = 0u;
    assert (sz == len(u));
    while i < sz { zipped += [(v[i], u[i])]; i += 1u; }
    ret zipped;
}

// Swaps two elements in a vector
fn swap<@T>(v: [mutable T], a: uint, b: uint) {
    let t: T = v[a];
    v[a] = v[b];
    v[b] = t;
}

// In place vector reversal
fn reverse<@T>(v: [mutable T]) {
    let i: uint = 0u;
    let ln = len::<T>(v);
    while i < ln / 2u { swap(v, i, ln - i - 1u); i += 1u; }
}

// Functional vector reversal. Returns a reversed copy of v.
fn reversed<@T>(v: [T]) -> [T] {
    let rs: [T] = [];
    let i = len::<T>(v);
    if i == 0u { ret rs; } else { i -= 1u; }
    while i != 0u { rs += [v[i]]; i -= 1u; }
    rs += [v[0]];
    ret rs;
}

// Generating vecs.
fn enum_chars(start: u8, end: u8) : u8::le(start, end) -> [char] {
    let i = start;
    let r = [];
    while i <= end { r += [i as char]; i += 1u as u8; }
    ret r;
}

fn enum_uints(start: uint, end: uint) : uint::le(start, end) -> [uint] {
    let i = start;
    let r = [];
    while i <= end { r += [i]; i += 1u; }
    ret r;
}

// Iterate over a list with with the indexes
iter iter2<@T>(v: [T]) -> (uint, T) {
    let i = 0u;
    for x in v { put (i, x); i += 1u; }
}

mod unsafe {
    type vec_repr = {mutable fill: uint, mutable alloc: uint, data: u8};

    fn from_buf<@T>(ptr: *T, elts: uint) -> [T] {
        ret rustrt::vec_from_buf_shared(ptr, elts);
    }

    fn set_len<@T>(&v: [T], new_len: uint) {
        let repr: **vec_repr = ::unsafe::reinterpret_cast(addr_of(v));
        (**repr).fill = new_len * sys::size_of::<T>();
    }

    fn to_ptr<@T>(v: [T]) -> *T {
        let repr: **vec_repr = ::unsafe::reinterpret_cast(addr_of(v));
        ret ::unsafe::reinterpret_cast(addr_of((**repr).data));
    }
}

fn to_ptr<@T>(v: [T]) -> *T { ret unsafe::to_ptr(v); }

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>stdlib: Add vec::eachi to the standard library<commit_after>// Interior vector utility functions.

import option::{some, none};
import uint::next_power_of_two;
import ptr::addr_of;

native "rust-intrinsic" mod rusti {
    fn vec_len<T>(v: [T]) -> uint;
}

native "rust" mod rustrt {
    fn vec_reserve_shared<T>(&v: [mutable? T], n: uint);
    fn vec_from_buf_shared<T>(ptr: *T, count: uint) -> [T];
}

/// Reserves space for `n` elements in the given vector.
fn reserve<@T>(&v: [mutable? T], n: uint) {
    rustrt::vec_reserve_shared(v, n);
}

pure fn len<T>(v: [mutable? T]) -> uint { unchecked { rusti::vec_len(v) } }

type init_op<T> = fn(uint) -> T;

fn init_fn<@T>(op: init_op<T>, n_elts: uint) -> [T] {
    let v = [];
    reserve(v, n_elts);
    let i: uint = 0u;
    while i < n_elts { v += [op(i)]; i += 1u; }
    ret v;
}

// TODO: Remove me once we have slots.
fn init_fn_mut<@T>(op: init_op<T>, n_elts: uint) -> [mutable T] {
    let v = [mutable];
    reserve(v, n_elts);
    let i: uint = 0u;
    while i < n_elts { v += [mutable op(i)]; i += 1u; }
    ret v;
}

fn init_elt<@T>(t: T, n_elts: uint) -> [T] {
    let v = [];
    reserve(v, n_elts);
    let i: uint = 0u;
    while i < n_elts { v += [t]; i += 1u; }
    ret v;
}

// TODO: Remove me once we have slots.
fn init_elt_mut<@T>(t: T, n_elts: uint) -> [mutable T] {
    let v = [mutable];
    reserve(v, n_elts);
    let i: uint = 0u;
    while i < n_elts { v += [mutable t]; i += 1u; }
    ret v;
}

// FIXME: Possible typestate postcondition:
// len(result) == len(v) (needs issue #586)
fn to_mut<@T>(v: [T]) -> [mutable T] {
    let vres = [mutable];
    for t: T in v { vres += [mutable t]; }
    ret vres;
}

// Same comment as from_mut
fn from_mut<@T>(v: [mutable T]) -> [T] {
    let vres = [];
    for t: T in v { vres += [t]; }
    ret vres;
}

// Predicates
pure fn is_empty<T>(v: [mutable? T]) -> bool {
    // FIXME: This would be easier if we could just call len
    for t: T in v { ret false; }
    ret true;
}

pure fn is_not_empty<T>(v: [mutable? T]) -> bool { ret !is_empty(v); }

// Accessors

/// Returns the first element of a vector
fn head<@T>(v: [mutable? T]) : is_not_empty(v) -> T { ret v[0]; }

/// Returns all but the first element of a vector
fn tail<@T>(v: [mutable? T]) : is_not_empty(v) -> [mutable? T] {
    ret slice(v, 1u, len(v));
}

/// Returns the last element of `v`.
fn last<@T>(v: [mutable? T]) -> option::t<T> {
    if len(v) == 0u { ret none; }
    ret some(v[len(v) - 1u]);
}

/// Returns the last element of a non-empty vector `v`.
fn last_total<@T>(v: [mutable? T]) : is_not_empty(v) -> T {
    ret v[len(v) - 1u];
}

/// Returns a copy of the elements from [`start`..`end`) from `v`.
fn slice<@T>(v: [mutable? T], start: uint, end: uint) -> [T] {
    assert (start <= end);
    assert (end <= len(v));
    let result = [];
    reserve(result, end - start);
    let i = start;
    while i < end { result += [v[i]]; i += 1u; }
    ret result;
}

// TODO: Remove me once we have slots.
fn slice_mut<@T>(v: [mutable? T], start: uint, end: uint) -> [mutable T] {
    assert (start <= end);
    assert (end <= len(v));
    let result = [mutable];
    reserve(result, end - start);
    let i = start;
    while i < end { result += [mutable v[i]]; i += 1u; }
    ret result;
}

// Mutators

fn shift<@T>(&v: [mutable? T]) -> T {
    let ln = len::<T>(v);
    assert (ln > 0u);
    let e = v[0];
    v = slice::<T>(v, 1u, ln);
    ret e;
}

// TODO: Write this, unsafely, in a way that's not O(n).
fn pop<@T>(&v: [mutable? T]) -> T {
    let ln = len(v);
    assert (ln > 0u);
    ln -= 1u;
    let e = v[ln];
    v = slice(v, 0u, ln);
    ret e;
}

// TODO: More.

// Appending

/// Expands the given vector in-place by appending `n` copies of `initval`.
fn grow<@T>(&v: [T], n: uint, initval: T) {
    reserve(v, next_power_of_two(len(v) + n));
    let i: uint = 0u;
    while i < n { v += [initval]; i += 1u; }
}

// TODO: Remove me once we have slots.
fn grow_mut<@T>(&v: [mutable T], n: uint, initval: T) {
    reserve(v, next_power_of_two(len(v) + n));
    let i: uint = 0u;
    while i < n { v += [mutable initval]; i += 1u; }
}

/// Calls `f` `n` times and appends the results of these calls to the given
/// vector.
fn grow_fn<@T>(&v: [T], n: uint, init_fn: fn(uint) -> T) {
    reserve(v, next_power_of_two(len(v) + n));
    let i: uint = 0u;
    while i < n { v += [init_fn(i)]; i += 1u; }
}

/// Sets the element at position `index` to `val`. If `index` is past the end
/// of the vector, expands the vector by replicating `initval` to fill the
/// intervening space.
fn grow_set<@T>(&v: [mutable T], index: uint, initval: T, val: T) {
    if index >= len(v) { grow_mut(v, index - len(v) + 1u, initval); }
    v[index] = val;
}

// Functional utilities

fn map<@T, @U>(f: block(T) -> U, v: [mutable? T]) -> [U] {
    let result = [];
    reserve(result, len(v));
    for elem: T in v {
        let elem2 = elem; // satisfies alias checker
        result += [f(elem2)];
    }
    ret result;
}

fn map2<@T, @U, @V>(f: block(T, U) -> V, v0: [T], v1: [U]) -> [V] {
    let v0_len = len::<T>(v0);
    if v0_len != len::<U>(v1) { fail; }
    let u: [V] = [];
    let i = 0u;
    while i < v0_len { u += [f({ v0[i] }, { v1[i] })]; i += 1u; }
    ret u;
}

fn filter_map<@T, @U>(f: block(T) -> option::t<U>, v: [mutable? T]) -> [U] {
    let result = [];
    for elem: T in v {
        let elem2 = elem; // satisfies alias checker
        alt f(elem2) {
          none. {/* no-op */ }
          some(result_elem) { result += [result_elem]; }
        }
    }
    ret result;
}

fn filter<@T>(f: block(T) -> bool, v: [mutable? T]) -> [T] {
    let result = [];
    for elem: T in v {
        let elem2 = elem; // satisfies alias checker
        if f(elem2) {
            result += [elem2];
        }
    }
    ret result;
}

fn foldl<@T, @U>(p: block(U, T) -> U, z: U, v: [mutable? T]) -> U {
    let sz = len(v);
    if sz == 0u { ret z; }
    let first = v[0];
    let rest = slice(v, 1u, sz);
    ret p(foldl(p, z, rest), first);
}

fn any<T>(f: block(T) -> bool, v: [T]) -> bool {
    for elem: T in v { if f(elem) { ret true; } }
    ret false;
}

fn all<T>(f: block(T) -> bool, v: [T]) -> bool {
    for elem: T in v { if !f(elem) { ret false; } }
    ret true;
}

fn member<T>(x: T, v: [T]) -> bool {
    for elt: T in v { if x == elt { ret true; } }
    ret false;
}

fn count<T>(x: T, v: [mutable? T]) -> uint {
    let cnt = 0u;
    for elt: T in v { if x == elt { cnt += 1u; } }
    ret cnt;
}

fn find<@T>(f: block(T) -> bool, v: [T]) -> option::t<T> {
    for elt: T in v { if f(elt) { ret some(elt); } }
    ret none;
}

fn position<@T>(x: T, v: [T]) -> option::t<uint> {
    let i: uint = 0u;
    while i < len(v) { if x == v[i] { ret some::<uint>(i); } i += 1u; }
    ret none;
}

fn position_pred<T>(f: fn(T) -> bool, v: [T]) -> option::t<uint> {
    let i: uint = 0u;
    while i < len(v) { if f(v[i]) { ret some::<uint>(i); } i += 1u; }
    ret none;
}

pure fn same_length<T, U>(xs: [T], ys: [U]) -> bool {
    vec::len(xs) == vec::len(ys)
}

// FIXME: if issue #586 gets implemented, could have a postcondition
// saying the two result lists have the same length -- or, could
// return a nominal record with a constraint saying that, instead of
// returning a tuple (contingent on issue #869)
fn unzip<@T, @U>(v: [(T, U)]) -> ([T], [U]) {
    let as = [], bs = [];
    for (a, b) in v { as += [a]; bs += [b]; }
    ret (as, bs);
}

fn zip<@T, @U>(v: [T], u: [U]) : same_length(v, u) -> [(T, U)] {
    let zipped = [];
    let sz = len(v), i = 0u;
    assert (sz == len(u));
    while i < sz { zipped += [(v[i], u[i])]; i += 1u; }
    ret zipped;
}

// Swaps two elements in a vector
fn swap<@T>(v: [mutable T], a: uint, b: uint) {
    let t: T = v[a];
    v[a] = v[b];
    v[b] = t;
}

// In place vector reversal
fn reverse<@T>(v: [mutable T]) {
    let i: uint = 0u;
    let ln = len::<T>(v);
    while i < ln / 2u { swap(v, i, ln - i - 1u); i += 1u; }
}

// Functional vector reversal. Returns a reversed copy of v.
fn reversed<@T>(v: [T]) -> [T] {
    let rs: [T] = [];
    let i = len::<T>(v);
    if i == 0u { ret rs; } else { i -= 1u; }
    while i != 0u { rs += [v[i]]; i -= 1u; }
    rs += [v[0]];
    ret rs;
}

// Generating vecs.
fn enum_chars(start: u8, end: u8) : u8::le(start, end) -> [char] {
    let i = start;
    let r = [];
    while i <= end { r += [i as char]; i += 1u as u8; }
    ret r;
}

fn enum_uints(start: uint, end: uint) : uint::le(start, end) -> [uint] {
    let i = start;
    let r = [];
    while i <= end { r += [i]; i += 1u; }
    ret r;
}

fn eachi<@T>(f: block(T, uint) -> (), v: [mutable? T]) {
    let i = 0u;
    let l = len(v);
    while (i < l) {
        let elem = v[i];    // Satisfy alias checker
        f(elem, i);
        i += 1u;
    }
}

// Iterate over a list with with the indexes
iter iter2<@T>(v: [T]) -> (uint, T) {
    let i = 0u;
    for x in v { put (i, x); i += 1u; }
}

mod unsafe {
    type vec_repr = {mutable fill: uint, mutable alloc: uint, data: u8};

    fn from_buf<@T>(ptr: *T, elts: uint) -> [T] {
        ret rustrt::vec_from_buf_shared(ptr, elts);
    }

    fn set_len<@T>(&v: [T], new_len: uint) {
        let repr: **vec_repr = ::unsafe::reinterpret_cast(addr_of(v));
        (**repr).fill = new_len * sys::size_of::<T>();
    }

    fn to_ptr<@T>(v: [T]) -> *T {
        let repr: **vec_repr = ::unsafe::reinterpret_cast(addr_of(v));
        ret ::unsafe::reinterpret_cast(addr_of((**repr).data));
    }
}

fn to_ptr<@T>(v: [T]) -> *T { ret unsafe::to_ptr(v); }

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before><commit_msg>test: add compile-fail test for #[deriving(FromPrimitive)]<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::num::FromPrimitive;
use std::int;

#[deriving(FromPrimitive)]
struct A { x: int }
//~^^ ERROR `FromPrimitive` cannot be derived for structs
//~^^^ ERROR `FromPrimitive` cannot be derived for structs

#[deriving(FromPrimitive)]
struct B(int);
//~^^ ERROR `FromPrimitive` cannot be derived for structs
//~^^^ ERROR `FromPrimitive` cannot be derived for structs

#[deriving(FromPrimitive)]
enum C { Foo(int), Bar(uint) }
//~^^ ERROR `FromPrimitive` cannot be derived for enum variants with arguments
//~^^^ ERROR `FromPrimitive` cannot be derived for enum variants with arguments

#[deriving(FromPrimitive)]
enum D { Baz { x: int } }
//~^^ ERROR `FromPrimitive` cannot be derived for enums with struct variants
//~^^^ ERROR `FromPrimitive` cannot be derived for enums with struct variants

fn main() {}
<|endoftext|>


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

use cast;
use iterator::{Iterator,range};
use libc;
use ops::Drop;
use option::{Option, Some, None};
use ptr::RawPtr;
use ptr;
use str::StrSlice;
use vec::{ImmutableVector,CopyableVector};
use container::Container;

/// Resolution options for the `null_byte` condition
pub enum NullByteResolution {
    /// Truncate at the null byte
    Truncate,
    /// Use a replacement byte
    ReplaceWith(libc::c_char)
}

condition! {
    // this should be &[u8] but there's a lifetime issue
    null_byte: (~[u8]) -> super::NullByteResolution;
}

/// The representation of a C String.
///
/// This structure wraps a `*libc::c_char`, and will automatically free the
/// memory it is pointing to when it goes out of scope.
pub struct CString {
    priv buf: *libc::c_char,
    priv owns_buffer_: bool,
}

impl CString {
    /// Create a C String from a pointer.
    pub unsafe fn new(buf: *libc::c_char, owns_buffer: bool) -> CString {
        CString { buf: buf, owns_buffer_: owns_buffer }
    }

    /// Unwraps the wrapped `*libc::c_char` from the `CString` wrapper.
    /// Any ownership of the buffer by the `CString` wrapper is forgotten.
    pub unsafe fn unwrap(self) -> *libc::c_char {
        let mut c_str = self;
        c_str.owns_buffer_ = false;
        c_str.buf
    }

    /// Calls a closure with a reference to the underlying `*libc::c_char`.
    ///
    /// # Failure
    ///
    /// Fails if the CString is null.
    pub fn with_ref<T>(&self, f: &fn(*libc::c_char) -> T) -> T {
        if self.buf.is_null() { fail!("CString is null!"); }
        f(self.buf)
    }

    /// Calls a closure with a mutable reference to the underlying `*libc::c_char`.
    ///
    /// # Failure
    ///
    /// Fails if the CString is null.
    pub fn with_mut_ref<T>(&mut self, f: &fn(*mut libc::c_char) -> T) -> T {
        if self.buf.is_null() { fail!("CString is null!"); }
        f(unsafe { cast::transmute_mut_unsafe(self.buf) })
    }

    /// Returns true if the CString is a null.
    pub fn is_null(&self) -> bool {
        self.buf.is_null()
    }

    /// Returns true if the CString is not null.
    pub fn is_not_null(&self) -> bool {
        self.buf.is_not_null()
    }

    /// Returns whether or not the `CString` owns the buffer.
    pub fn owns_buffer(&self) -> bool {
        self.owns_buffer_
    }

    /// Converts the CString into a `&[u8]` without copying.
    ///
    /// # Failure
    ///
    /// Fails if the CString is null.
    pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
        if self.buf.is_null() { fail!("CString is null!"); }
        unsafe {
            let len = libc::strlen(self.buf) as uint;
            cast::transmute((self.buf, len + 1))
        }
    }

    /// Return a CString iterator.
    fn iter<'a>(&'a self) -> CStringIterator<'a> {
        CStringIterator {
            ptr: self.buf,
            lifetime: unsafe { cast::transmute(self.buf) },
        }
    }
}

impl Drop for CString {
    fn drop(&self) {
        if self.owns_buffer_ {
            unsafe {
                libc::free(self.buf as *libc::c_void)
            }
        }
    }
}

/// A generic trait for converting a value to a CString.
pub trait ToCStr {
    /// Copy the receiver into a CString.
    ///
    /// # Failure
    ///
    /// Raises the `null_byte` condition if the receiver has an interior null.
    fn to_c_str(&self) -> CString;

    /// Unsafe variant of `to_c_str()` that doesn't check for nulls.
    unsafe fn to_c_str_unchecked(&self) -> CString;

    /// Work with a temporary CString constructed from the receiver.
    /// The provided `*libc::c_char` will be freed immediately upon return.
    ///
    /// # Example
    ///
    /// ~~~ {.rust}
    /// let s = "PATH".with_c_str(|path| libc::getenv(path))
    /// ~~~
    ///
    /// # Failure
    ///
    /// Raises the `null_byte` condition if the receiver has an interior null.
    #[inline]
    fn with_c_str<T>(&self, f: &fn(*libc::c_char) -> T) -> T {
        self.to_c_str().with_ref(f)
    }

    /// Unsafe variant of `with_c_str()` that doesn't check for nulls.
    #[inline]
    unsafe fn with_c_str_unchecked<T>(&self, f: &fn(*libc::c_char) -> T) -> T {
        self.to_c_str_unchecked().with_ref(f)
    }
}

impl<'self> ToCStr for &'self str {
    #[inline]
    fn to_c_str(&self) -> CString {
        self.as_bytes().to_c_str()
    }

    #[inline]
    unsafe fn to_c_str_unchecked(&self) -> CString {
        self.as_bytes().to_c_str_unchecked()
    }
}

impl<'self> ToCStr for &'self [u8] {
    fn to_c_str(&self) -> CString {
        let mut cs = unsafe { self.to_c_str_unchecked() };
        do cs.with_mut_ref |buf| {
            for i in range(0, self.len()) {
                unsafe {
                    let p = buf.offset_inbounds(i as int);
                    if *p == 0 {
                        match null_byte::cond.raise(self.to_owned()) {
                            Truncate => break,
                            ReplaceWith(c) => *p = c
                        }
                    }
                }
            }
        }
        cs
    }

    unsafe fn to_c_str_unchecked(&self) -> CString {
        do self.as_imm_buf |self_buf, self_len| {
            let buf = libc::malloc(self_len as libc::size_t + 1) as *mut u8;
            if buf.is_null() {
                fail!("failed to allocate memory!");
            }

            ptr::copy_memory(buf, self_buf, self_len);
            *ptr::mut_offset(buf, self_len as int) = 0;

            CString::new(buf as *libc::c_char, true)
        }
    }
}

/// External iterator for a CString's bytes.
///
/// Use with the `std::iterator` module.
pub struct CStringIterator<'self> {
    priv ptr: *libc::c_char,
    priv lifetime: &'self libc::c_char, // FIXME: #5922
}

impl<'self> Iterator<libc::c_char> for CStringIterator<'self> {
    fn next(&mut self) -> Option<libc::c_char> {
        let ch = unsafe { *self.ptr };
        if ch == 0 {
            None
        } else {
            self.ptr = ptr::offset(self.ptr, 1);
            Some(ch)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use libc;
    use ptr;
    use option::{Some, None};

    #[test]
    fn test_to_c_str() {
        do "".to_c_str().with_ref |buf| {
            unsafe {
                assert_eq!(*ptr::offset(buf, 0), 0);
            }
        }

        do "hello".to_c_str().with_ref |buf| {
            unsafe {
                assert_eq!(*ptr::offset(buf, 0), 'h' as libc::c_char);
                assert_eq!(*ptr::offset(buf, 1), 'e' as libc::c_char);
                assert_eq!(*ptr::offset(buf, 2), 'l' as libc::c_char);
                assert_eq!(*ptr::offset(buf, 3), 'l' as libc::c_char);
                assert_eq!(*ptr::offset(buf, 4), 'o' as libc::c_char);
                assert_eq!(*ptr::offset(buf, 5), 0);
            }
        }
    }

    #[test]
    fn test_is_null() {
        let c_str = unsafe { CString::new(ptr::null(), false) };
        assert!(c_str.is_null());
        assert!(!c_str.is_not_null());
    }

    #[test]
    fn test_unwrap() {
        let c_str = "hello".to_c_str();
        unsafe { libc::free(c_str.unwrap() as *libc::c_void) }
    }

    #[test]
    fn test_with_ref() {
        let c_str = "hello".to_c_str();
        let len = unsafe { c_str.with_ref(|buf| libc::strlen(buf)) };
        assert!(!c_str.is_null());
        assert!(c_str.is_not_null());
        assert_eq!(len, 5);
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn test_with_ref_empty_fail() {
        let c_str = unsafe { CString::new(ptr::null(), false) };
        c_str.with_ref(|_| ());
    }

    #[test]
    fn test_iterator() {
        let c_str = "".to_c_str();
        let mut iter = c_str.iter();
        assert_eq!(iter.next(), None);

        let c_str = "hello".to_c_str();
        let mut iter = c_str.iter();
        assert_eq!(iter.next(), Some('h' as libc::c_char));
        assert_eq!(iter.next(), Some('e' as libc::c_char));
        assert_eq!(iter.next(), Some('l' as libc::c_char));
        assert_eq!(iter.next(), Some('l' as libc::c_char));
        assert_eq!(iter.next(), Some('o' as libc::c_char));
        assert_eq!(iter.next(), None);
    }

    #[test]
    #[ignore(cfg(windows))]
    fn test_to_c_str_fail() {
        use c_str::null_byte::cond;

        let mut error_happened = false;
        do cond.trap(|err| {
            assert_eq!(err, bytes!("he", 0, "llo").to_owned())
            error_happened = true;
            Truncate
        }).inside {
            "he\x00llo".to_c_str()
        };
        assert!(error_happened);

        do cond.trap(|_| {
            ReplaceWith('?' as libc::c_char)
        }).inside(|| "he\x00llo".to_c_str()).with_ref |buf| {
            unsafe {
                assert_eq!(*buf.offset(0), 'h' as libc::c_char);
                assert_eq!(*buf.offset(1), 'e' as libc::c_char);
                assert_eq!(*buf.offset(2), '?' as libc::c_char);
                assert_eq!(*buf.offset(3), 'l' as libc::c_char);
                assert_eq!(*buf.offset(4), 'l' as libc::c_char);
                assert_eq!(*buf.offset(5), 'o' as libc::c_char);
                assert_eq!(*buf.offset(6), 0);
            }
        }
    }

    #[test]
    fn test_to_c_str_unchecked() {
        unsafe {
            do "he\x00llo".to_c_str_unchecked().with_ref |buf| {
                assert_eq!(*buf.offset(0), 'h' as libc::c_char);
                assert_eq!(*buf.offset(1), 'e' as libc::c_char);
                assert_eq!(*buf.offset(2), 0);
                assert_eq!(*buf.offset(3), 'l' as libc::c_char);
                assert_eq!(*buf.offset(4), 'l' as libc::c_char);
                assert_eq!(*buf.offset(5), 'o' as libc::c_char);
                assert_eq!(*buf.offset(6), 0);
            }
        }
    }
}
<commit_msg>Make CString.iter() public<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use cast;
use iterator::{Iterator,range};
use libc;
use ops::Drop;
use option::{Option, Some, None};
use ptr::RawPtr;
use ptr;
use str::StrSlice;
use vec::{ImmutableVector,CopyableVector};
use container::Container;

/// Resolution options for the `null_byte` condition
pub enum NullByteResolution {
    /// Truncate at the null byte
    Truncate,
    /// Use a replacement byte
    ReplaceWith(libc::c_char)
}

condition! {
    // this should be &[u8] but there's a lifetime issue
    null_byte: (~[u8]) -> super::NullByteResolution;
}

/// The representation of a C String.
///
/// This structure wraps a `*libc::c_char`, and will automatically free the
/// memory it is pointing to when it goes out of scope.
pub struct CString {
    priv buf: *libc::c_char,
    priv owns_buffer_: bool,
}

impl CString {
    /// Create a C String from a pointer.
    pub unsafe fn new(buf: *libc::c_char, owns_buffer: bool) -> CString {
        CString { buf: buf, owns_buffer_: owns_buffer }
    }

    /// Unwraps the wrapped `*libc::c_char` from the `CString` wrapper.
    /// Any ownership of the buffer by the `CString` wrapper is forgotten.
    pub unsafe fn unwrap(self) -> *libc::c_char {
        let mut c_str = self;
        c_str.owns_buffer_ = false;
        c_str.buf
    }

    /// Calls a closure with a reference to the underlying `*libc::c_char`.
    ///
    /// # Failure
    ///
    /// Fails if the CString is null.
    pub fn with_ref<T>(&self, f: &fn(*libc::c_char) -> T) -> T {
        if self.buf.is_null() { fail!("CString is null!"); }
        f(self.buf)
    }

    /// Calls a closure with a mutable reference to the underlying `*libc::c_char`.
    ///
    /// # Failure
    ///
    /// Fails if the CString is null.
    pub fn with_mut_ref<T>(&mut self, f: &fn(*mut libc::c_char) -> T) -> T {
        if self.buf.is_null() { fail!("CString is null!"); }
        f(unsafe { cast::transmute_mut_unsafe(self.buf) })
    }

    /// Returns true if the CString is a null.
    pub fn is_null(&self) -> bool {
        self.buf.is_null()
    }

    /// Returns true if the CString is not null.
    pub fn is_not_null(&self) -> bool {
        self.buf.is_not_null()
    }

    /// Returns whether or not the `CString` owns the buffer.
    pub fn owns_buffer(&self) -> bool {
        self.owns_buffer_
    }

    /// Converts the CString into a `&[u8]` without copying.
    ///
    /// # Failure
    ///
    /// Fails if the CString is null.
    pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
        if self.buf.is_null() { fail!("CString is null!"); }
        unsafe {
            let len = libc::strlen(self.buf) as uint;
            cast::transmute((self.buf, len + 1))
        }
    }

    /// Return a CString iterator.
    pub fn iter<'a>(&'a self) -> CStringIterator<'a> {
        CStringIterator {
            ptr: self.buf,
            lifetime: unsafe { cast::transmute(self.buf) },
        }
    }
}

impl Drop for CString {
    fn drop(&self) {
        if self.owns_buffer_ {
            unsafe {
                libc::free(self.buf as *libc::c_void)
            }
        }
    }
}

/// A generic trait for converting a value to a CString.
pub trait ToCStr {
    /// Copy the receiver into a CString.
    ///
    /// # Failure
    ///
    /// Raises the `null_byte` condition if the receiver has an interior null.
    fn to_c_str(&self) -> CString;

    /// Unsafe variant of `to_c_str()` that doesn't check for nulls.
    unsafe fn to_c_str_unchecked(&self) -> CString;

    /// Work with a temporary CString constructed from the receiver.
    /// The provided `*libc::c_char` will be freed immediately upon return.
    ///
    /// # Example
    ///
    /// ~~~ {.rust}
    /// let s = "PATH".with_c_str(|path| libc::getenv(path))
    /// ~~~
    ///
    /// # Failure
    ///
    /// Raises the `null_byte` condition if the receiver has an interior null.
    #[inline]
    fn with_c_str<T>(&self, f: &fn(*libc::c_char) -> T) -> T {
        self.to_c_str().with_ref(f)
    }

    /// Unsafe variant of `with_c_str()` that doesn't check for nulls.
    #[inline]
    unsafe fn with_c_str_unchecked<T>(&self, f: &fn(*libc::c_char) -> T) -> T {
        self.to_c_str_unchecked().with_ref(f)
    }
}

impl<'self> ToCStr for &'self str {
    #[inline]
    fn to_c_str(&self) -> CString {
        self.as_bytes().to_c_str()
    }

    #[inline]
    unsafe fn to_c_str_unchecked(&self) -> CString {
        self.as_bytes().to_c_str_unchecked()
    }
}

impl<'self> ToCStr for &'self [u8] {
    fn to_c_str(&self) -> CString {
        let mut cs = unsafe { self.to_c_str_unchecked() };
        do cs.with_mut_ref |buf| {
            for i in range(0, self.len()) {
                unsafe {
                    let p = buf.offset_inbounds(i as int);
                    if *p == 0 {
                        match null_byte::cond.raise(self.to_owned()) {
                            Truncate => break,
                            ReplaceWith(c) => *p = c
                        }
                    }
                }
            }
        }
        cs
    }

    unsafe fn to_c_str_unchecked(&self) -> CString {
        do self.as_imm_buf |self_buf, self_len| {
            let buf = libc::malloc(self_len as libc::size_t + 1) as *mut u8;
            if buf.is_null() {
                fail!("failed to allocate memory!");
            }

            ptr::copy_memory(buf, self_buf, self_len);
            *ptr::mut_offset(buf, self_len as int) = 0;

            CString::new(buf as *libc::c_char, true)
        }
    }
}

/// External iterator for a CString's bytes.
///
/// Use with the `std::iterator` module.
pub struct CStringIterator<'self> {
    priv ptr: *libc::c_char,
    priv lifetime: &'self libc::c_char, // FIXME: #5922
}

impl<'self> Iterator<libc::c_char> for CStringIterator<'self> {
    fn next(&mut self) -> Option<libc::c_char> {
        let ch = unsafe { *self.ptr };
        if ch == 0 {
            None
        } else {
            self.ptr = ptr::offset(self.ptr, 1);
            Some(ch)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use libc;
    use ptr;
    use option::{Some, None};

    #[test]
    fn test_to_c_str() {
        do "".to_c_str().with_ref |buf| {
            unsafe {
                assert_eq!(*ptr::offset(buf, 0), 0);
            }
        }

        do "hello".to_c_str().with_ref |buf| {
            unsafe {
                assert_eq!(*ptr::offset(buf, 0), 'h' as libc::c_char);
                assert_eq!(*ptr::offset(buf, 1), 'e' as libc::c_char);
                assert_eq!(*ptr::offset(buf, 2), 'l' as libc::c_char);
                assert_eq!(*ptr::offset(buf, 3), 'l' as libc::c_char);
                assert_eq!(*ptr::offset(buf, 4), 'o' as libc::c_char);
                assert_eq!(*ptr::offset(buf, 5), 0);
            }
        }
    }

    #[test]
    fn test_is_null() {
        let c_str = unsafe { CString::new(ptr::null(), false) };
        assert!(c_str.is_null());
        assert!(!c_str.is_not_null());
    }

    #[test]
    fn test_unwrap() {
        let c_str = "hello".to_c_str();
        unsafe { libc::free(c_str.unwrap() as *libc::c_void) }
    }

    #[test]
    fn test_with_ref() {
        let c_str = "hello".to_c_str();
        let len = unsafe { c_str.with_ref(|buf| libc::strlen(buf)) };
        assert!(!c_str.is_null());
        assert!(c_str.is_not_null());
        assert_eq!(len, 5);
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn test_with_ref_empty_fail() {
        let c_str = unsafe { CString::new(ptr::null(), false) };
        c_str.with_ref(|_| ());
    }

    #[test]
    fn test_iterator() {
        let c_str = "".to_c_str();
        let mut iter = c_str.iter();
        assert_eq!(iter.next(), None);

        let c_str = "hello".to_c_str();
        let mut iter = c_str.iter();
        assert_eq!(iter.next(), Some('h' as libc::c_char));
        assert_eq!(iter.next(), Some('e' as libc::c_char));
        assert_eq!(iter.next(), Some('l' as libc::c_char));
        assert_eq!(iter.next(), Some('l' as libc::c_char));
        assert_eq!(iter.next(), Some('o' as libc::c_char));
        assert_eq!(iter.next(), None);
    }

    #[test]
    #[ignore(cfg(windows))]
    fn test_to_c_str_fail() {
        use c_str::null_byte::cond;

        let mut error_happened = false;
        do cond.trap(|err| {
            assert_eq!(err, bytes!("he", 0, "llo").to_owned())
            error_happened = true;
            Truncate
        }).inside {
            "he\x00llo".to_c_str()
        };
        assert!(error_happened);

        do cond.trap(|_| {
            ReplaceWith('?' as libc::c_char)
        }).inside(|| "he\x00llo".to_c_str()).with_ref |buf| {
            unsafe {
                assert_eq!(*buf.offset(0), 'h' as libc::c_char);
                assert_eq!(*buf.offset(1), 'e' as libc::c_char);
                assert_eq!(*buf.offset(2), '?' as libc::c_char);
                assert_eq!(*buf.offset(3), 'l' as libc::c_char);
                assert_eq!(*buf.offset(4), 'l' as libc::c_char);
                assert_eq!(*buf.offset(5), 'o' as libc::c_char);
                assert_eq!(*buf.offset(6), 0);
            }
        }
    }

    #[test]
    fn test_to_c_str_unchecked() {
        unsafe {
            do "he\x00llo".to_c_str_unchecked().with_ref |buf| {
                assert_eq!(*buf.offset(0), 'h' as libc::c_char);
                assert_eq!(*buf.offset(1), 'e' as libc::c_char);
                assert_eq!(*buf.offset(2), 0);
                assert_eq!(*buf.offset(3), 'l' as libc::c_char);
                assert_eq!(*buf.offset(4), 'l' as libc::c_char);
                assert_eq!(*buf.offset(5), 'o' as libc::c_char);
                assert_eq!(*buf.offset(6), 0);
            }
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>"(6 kyu) Square Digits Sequence" solved in RS<commit_after><|endoftext|>


<commit_before><commit_msg>added parse.rs<commit_after><|endoftext|>


<commit_before><commit_msg>Add ptrie data-structure<commit_after>
/* Compiled representation of our Trie
struct PTrie
{
  nb_succ : int,
  key_len : int,
  word_stop : int,
  freq : int
  key     : [char],
  succ    : [int]
}
*/

struct PTrie
{
  key       : ~str,
  freq      : int,
  word_stop : bool,
  succ      : ~[Ptrie]
}
<|endoftext|>


<commit_before>pub fn escape(code: &str) -> String {
    let mut s = String::new();

    for c in code.chars() {
        match c {
            c@'!' => s.push_char(c),
            c@'.' => s.push_char(c),
            c@'0'..'9' => s.push_char(c),
            c@'A'..'Z' => s.push_char(c),
            c@'a'..'z' => s.push_char(c),
            c => s.push_str(format!("%{:02X}", c as u32).as_slice()),
        }
    }

    s
}

pub fn link(source: &str) -> String {
    format!("http://playtest.rust-lang.org/?code={}&run=1", escape(source))
}
<commit_msg>the playpen now lives in play.rust-lang.org<commit_after>pub fn escape(code: &str) -> String {
    let mut s = String::new();

    for c in code.chars() {
        match c {
            c@'!' => s.push_char(c),
            c@'.' => s.push_char(c),
            c@'0'..'9' => s.push_char(c),
            c@'A'..'Z' => s.push_char(c),
            c@'a'..'z' => s.push_char(c),
            c => s.push_str(format!("%{:02X}", c as u32).as_slice()),
        }
    }

    s
}

pub fn link(source: &str) -> String {
    format!("http://play.rust-lang.org/?code={}&run=1", escape(source))
}
<|endoftext|>


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

// Test that destructors for rvalue temporaries run either at end of
// statement or end of block, as appropriate given the temporary
// lifetime rules.

#[feature(macro_rules)];

use std::ops::Drop;

static mut FLAGS: u64 = 0;

struct Box<T> { f: T }
struct AddFlags { bits: u64 }

fn AddFlags(bits: u64) -> AddFlags {
    AddFlags { bits: bits }
}

fn arg(exp: u64, _x: &AddFlags) {
    check_flags(exp);
}

fn pass<T>(v: T) -> T {
    v
}

fn check_flags(exp: u64) {
    unsafe {
        let x = FLAGS;
        FLAGS = 0;
        println!("flags {}, expected {}", x, exp);
        assert_eq!(x, exp);
    }
}

impl AddFlags {
    fn check_flags<'a>(&'a self, exp: u64) -> &'a AddFlags {
        check_flags(exp);
        self
    }

    fn bits(&self) -> u64 {
        self.bits
    }
}

impl Drop for AddFlags {
    fn drop(&mut self) {
        unsafe {
            FLAGS = FLAGS + self.bits;
        }
    }
}

macro_rules! end_of_block(
    ($pat:pat, $expr:expr) => (
        {
            println!("end_of_block({})", stringify!({let $pat = $expr;}));

            {
                // Destructor here does not run until exit from the block,
                // because value is assigned to.
                let $pat = $expr;
                check_flags(0);
            }
            check_flags(1);
        }
    )
)

macro_rules! end_of_stmt(
    ($pat:pat, $expr:expr) => (
        {
            println!("end_of_stmt({})", stringify!($expr));

            {
                // Destructor here does not run until exit from the block,
                // because value is assigned to.
                let $pat = $expr;
                check_flags(1);
            }

            check_flags(0);
        }
    )
)

pub fn main() {

    // In all these cases, we trip over the rules designed to cover
    // the case where we are taking addr of rvalue and storing that
    // addr into a stack slot, either via `let ref` or via a `&` in
    // the initializer.

    end_of_block!(_x, AddFlags(1));
    end_of_block!(_x, &AddFlags(1));
    end_of_block!(_x, & &AddFlags(1));
    end_of_block!(_x, Box { f: AddFlags(1) });
    end_of_block!(_x, Box { f: &AddFlags(1) });
    end_of_block!(_x, Box { f: &AddFlags(1) });
    end_of_block!(_x, pass(AddFlags(1)));
    end_of_block!(ref _x, AddFlags(1));
    end_of_block!(AddFlags { bits: ref _x }, AddFlags(1));
    end_of_block!(&AddFlags { bits }, &AddFlags(1));
    end_of_block!((_, ref _y), (AddFlags(1), 22));
    end_of_block!(~ref _x, ~AddFlags(1));
    end_of_block!(~_x, ~AddFlags(1));
    end_of_block!(_, { { check_flags(0); &AddFlags(1) } });
    end_of_block!(_, &((Box { f: AddFlags(1) }).f));
    end_of_block!(_, &(([AddFlags(1)])[0]));
    end_of_block!(_, &((&~[AddFlags(1)])[0]));

    // LHS does not create a ref binding, so temporary lives as long
    // as statement, and we do not move the AddFlags out:
    end_of_stmt!(_, AddFlags(1));
    end_of_stmt!((_, _), (AddFlags(1), 22));

    // `&` operator appears inside an arg to a function,
    // so it is not prolonged:
    end_of_stmt!(ref _x, arg(0, &AddFlags(1)));

    // autoref occurs inside receiver, so temp lifetime is not
    // prolonged:
    end_of_stmt!(ref _x, AddFlags(1).check_flags(0).bits());

    // No reference is created on LHS, thus RHS is moved into
    // a temporary that lives just as long as the statement.
    end_of_stmt!(AddFlags { bits }, AddFlags(1));
}
<commit_msg>Adjust comments in test case<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Test that destructors for rvalue temporaries run either at end of
// statement or end of block, as appropriate given the temporary
// lifetime rules.

#[feature(macro_rules)];

use std::ops::Drop;

static mut FLAGS: u64 = 0;

struct Box<T> { f: T }
struct AddFlags { bits: u64 }

fn AddFlags(bits: u64) -> AddFlags {
    AddFlags { bits: bits }
}

fn arg(exp: u64, _x: &AddFlags) {
    check_flags(exp);
}

fn pass<T>(v: T) -> T {
    v
}

fn check_flags(exp: u64) {
    unsafe {
        let x = FLAGS;
        FLAGS = 0;
        println!("flags {}, expected {}", x, exp);
        assert_eq!(x, exp);
    }
}

impl AddFlags {
    fn check_flags<'a>(&'a self, exp: u64) -> &'a AddFlags {
        check_flags(exp);
        self
    }

    fn bits(&self) -> u64 {
        self.bits
    }
}

impl Drop for AddFlags {
    fn drop(&mut self) {
        unsafe {
            FLAGS = FLAGS + self.bits;
        }
    }
}

macro_rules! end_of_block(
    ($pat:pat, $expr:expr) => (
        {
            println!("end_of_block({})", stringify!({let $pat = $expr;}));

            {
                // Destructor here does not run until exit from the block.
                let $pat = $expr;
                check_flags(0);
            }
            check_flags(1);
        }
    )
)

macro_rules! end_of_stmt(
    ($pat:pat, $expr:expr) => (
        {
            println!("end_of_stmt({})", stringify!($expr));

            {
                // Destructor here run after `let` statement
                // terminates.
                let $pat = $expr;
                check_flags(1);
            }

            check_flags(0);
        }
    )
)

pub fn main() {

    // In all these cases, we trip over the rules designed to cover
    // the case where we are taking addr of rvalue and storing that
    // addr into a stack slot, either via `let ref` or via a `&` in
    // the initializer.

    end_of_block!(_x, AddFlags(1));
    end_of_block!(_x, &AddFlags(1));
    end_of_block!(_x, & &AddFlags(1));
    end_of_block!(_x, Box { f: AddFlags(1) });
    end_of_block!(_x, Box { f: &AddFlags(1) });
    end_of_block!(_x, Box { f: &AddFlags(1) });
    end_of_block!(_x, pass(AddFlags(1)));
    end_of_block!(ref _x, AddFlags(1));
    end_of_block!(AddFlags { bits: ref _x }, AddFlags(1));
    end_of_block!(&AddFlags { bits }, &AddFlags(1));
    end_of_block!((_, ref _y), (AddFlags(1), 22));
    end_of_block!(~ref _x, ~AddFlags(1));
    end_of_block!(~_x, ~AddFlags(1));
    end_of_block!(_, { { check_flags(0); &AddFlags(1) } });
    end_of_block!(_, &((Box { f: AddFlags(1) }).f));
    end_of_block!(_, &(([AddFlags(1)])[0]));
    end_of_block!(_, &((&~[AddFlags(1)])[0]));

    // LHS does not create a ref binding, so temporary lives as long
    // as statement, and we do not move the AddFlags out:
    end_of_stmt!(_, AddFlags(1));
    end_of_stmt!((_, _), (AddFlags(1), 22));

    // `&` operator appears inside an arg to a function,
    // so it is not prolonged:
    end_of_stmt!(ref _x, arg(0, &AddFlags(1)));

    // autoref occurs inside receiver, so temp lifetime is not
    // prolonged:
    end_of_stmt!(ref _x, AddFlags(1).check_flags(0).bits());

    // No reference is created on LHS, thus RHS is moved into
    // a temporary that lives just as long as the statement.
    end_of_stmt!(AddFlags { bits }, AddFlags(1));
}
<|endoftext|>


<commit_before><commit_msg>Fix the bug parsing char literals containing multi bytes.<commit_after><|endoftext|>


<commit_before><commit_msg>Adds groups clearing<commit_after><|endoftext|>


<commit_before><commit_msg>Chore(trash): fix import warnings<commit_after><|endoftext|>


<commit_before><commit_msg>Add comment for blank lines<commit_after><|endoftext|>


<commit_before><commit_msg>update to latest nightly<commit_after><|endoftext|>


<commit_before>use context::CommandContext;
use version::Version;
use version::Api;
use gl;

use std::mem;

use texture::any::TextureAny;
use TextureExt;

/// Error that can happen when retrieving the internal format of a texture.
#[derive(Copy, Clone, Debug)]
pub enum GetFormatError {
    /// The backend doesn't support retrieving the internal format.
    NotSupported,
}

/// Internal format of a texture.
///
/// The actual format of a texture is not necessarly one of the predefined ones, so we have
/// to use a very generic description.
// TODO: change bits to be u16 for consistency with the rest of the library
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum InternalFormat {
    /// The format has one component.
    OneComponent {
        /// Type of the first component of the format.
        ty1: InternalFormatType,
        /// Number of bits of the first component.
        bits1: usize,
    },

    /// The format has two components.
    TwoComponents {
        /// Type of the first component of the format.
        ty1: InternalFormatType,
        /// Number of bits of the first component.
        bits1: usize,
        /// Type of the second component.
        ty2: InternalFormatType,
        /// Number of bits of the second component.
        bits2: usize,
    },

    /// The format has three components.
    ThreeComponents {
        /// Type of the first component of the format.
        ty1: InternalFormatType,
        /// Number of bits of the first component.
        bits1: usize,
        /// Type of the second component.
        ty2: InternalFormatType,
        /// Number of bits of the second component.
        bits2: usize,
        /// Type of the third component.
        ty3: InternalFormatType,
        /// Number of bits of the third component.
        bits3: usize,
    },

    /// The format has four components.
    FourComponents {
        /// Type of the first component of the format.
        ty1: InternalFormatType,
        /// Number of bits of the first component.
        bits1: usize,
        /// Type of the second component.
        ty2: InternalFormatType,
        /// Number of bits of the second component.
        bits2: usize,
        /// Type of the third component.
        ty3: InternalFormatType,
        /// Number of bits of the third component.
        bits3: usize,
        /// Type of the fourth component.
        ty4: InternalFormatType,
        /// Number of bits of the fourth component.
        bits4: usize,
    },
}

impl InternalFormat {
    /// Returns the total number of bits of this format.
    #[inline]
    pub fn get_total_bits(&self) -> usize {
        match self {
            &InternalFormat::OneComponent { bits1, .. } => bits1,
            &InternalFormat::TwoComponents { bits1, bits2, .. } => bits1 + bits2,
            &InternalFormat::ThreeComponents { bits1, bits2, bits3, .. } => bits1 + bits2 + bits3,
            &InternalFormat::FourComponents { bits1, bits2, bits3, bits4, .. } =>
                                                                    bits1 + bits2 + bits3 + bits4,
        }
    }
}

/// Format of a component of an internal format.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum InternalFormatType {
    /// Floating point texture with signed components.
    SignedNormalized,
    /// Floating point texture with unsigned components.
    UnsignedNormalized,
    /// Floating point texture with floats.
    Float,
    /// Integral texture.
    Int,
    /// Unsigned texture.
    UnsignedInt,
}

impl InternalFormatType {
    /// Builds the `InternalFormatType` of the GLenum. Panics if the value is not recognized.
    #[inline]
    fn from_glenum(val: gl::types::GLenum) -> InternalFormatType {
        match val {
            gl::SIGNED_NORMALIZED => InternalFormatType::SignedNormalized,
            gl::UNSIGNED_NORMALIZED => InternalFormatType::UnsignedNormalized,
            gl::FLOAT => InternalFormatType::Float,
            gl::INT => InternalFormatType::Int,
            gl::UNSIGNED_INT => InternalFormatType::UnsignedInt,
            gl::NONE => unreachable!(),     // separating this case for easier debugging
            _ => unreachable!(),
        }
    }
}

/// Determines the format of a texture.
///
/// A `TextureAny` is guaranteed to have the same format for each mipmap.
pub fn get_format(ctxt: &mut CommandContext, texture: &TextureAny)
                  -> Result<InternalFormat, GetFormatError>
{
    if ctxt.version >= &Version(Api::Gl, 3, 0) || ctxt.version >= &Version(Api::GlEs, 3, 0) {
        let (red_sz, red_ty, green_sz, green_ty, blue_sz, blue_ty,
             alpha_sz, alpha_ty, depth_sz, depth_ty) = unsafe
        {
            // TODO: use DSA if available

            let bind_point = texture.bind_to_current(ctxt);

            let mut red_sz = mem::uninitialized();
            ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_RED_SIZE, &mut red_sz);

            let mut red_ty = mem::uninitialized();
            ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_RED_TYPE, &mut red_ty);

            let mut green_sz = mem::uninitialized();
            ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_GREEN_SIZE, &mut green_sz);

            let mut green_ty = mem::uninitialized();
            ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_GREEN_TYPE, &mut green_ty);

            let mut blue_sz = mem::uninitialized();
            ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_BLUE_SIZE, &mut blue_sz);

            let mut blue_ty = mem::uninitialized();
            ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_BLUE_TYPE, &mut blue_ty);

            let mut alpha_sz = mem::uninitialized();
            ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_ALPHA_SIZE, &mut alpha_sz);

            let mut alpha_ty = mem::uninitialized();
            ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_ALPHA_TYPE, &mut alpha_ty);

            let mut depth_sz = mem::uninitialized();
            ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_DEPTH_SIZE, &mut depth_sz);

            let mut depth_ty = mem::uninitialized();
            ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_DEPTH_TYPE, &mut depth_ty);

            (red_sz as gl::types::GLenum, red_ty as gl::types::GLenum,
             green_sz as gl::types::GLenum, green_ty as gl::types::GLenum,
             blue_sz as gl::types::GLenum, blue_ty as gl::types::GLenum,
             alpha_sz as gl::types::GLenum, alpha_ty as gl::types::GLenum,
             depth_sz as gl::types::GLenum, depth_ty as gl::types::GLenum)
        };

        Ok(match (red_sz, red_ty, green_sz, green_ty, blue_sz, blue_ty,
               alpha_sz, alpha_ty, depth_sz, depth_ty)
        {
            (_, gl::NONE, _, _, _, _, _, _, sz1, ty1) => InternalFormat::OneComponent {
                ty1: InternalFormatType::from_glenum(ty1),
                bits1: sz1 as usize,
            },
            (sz1, ty1, _, gl::NONE, _, _, _, _, _, _) => InternalFormat::OneComponent {
                ty1: InternalFormatType::from_glenum(ty1),
                bits1: sz1 as usize,
            },
            (sz1, ty1, sz2, ty2, _, gl::NONE, _, _, _, _) => InternalFormat::TwoComponents {
                ty1: InternalFormatType::from_glenum(ty1),
                bits1: sz1 as usize,
                ty2: InternalFormatType::from_glenum(ty2),
                bits2: sz2 as usize,
            },
            (sz1, ty1, sz2, ty2, sz3, ty3, _, gl::NONE, _, _) => InternalFormat::ThreeComponents {
                ty1: InternalFormatType::from_glenum(ty1),
                bits1: sz1 as usize,
                ty2: InternalFormatType::from_glenum(ty2),
                bits2: sz2 as usize,
                ty3: InternalFormatType::from_glenum(ty3),
                bits3: sz3 as usize,
            },
            (sz1, ty1, sz2, ty2, sz3, ty3, sz4, ty4, _, gl::NONE) => InternalFormat::FourComponents {
                ty1: InternalFormatType::from_glenum(ty1),
                bits1: sz1 as usize,
                ty2: InternalFormatType::from_glenum(ty2),
                bits2: sz2 as usize,
                ty3: InternalFormatType::from_glenum(ty3),
                bits3: sz3 as usize,
                ty4: InternalFormatType::from_glenum(ty4),
                bits4: sz4 as usize,
            },
            _ => unreachable!()
        })

    } else {
        // FIXME: GL2
        Err(GetFormatError::NotSupported)
    }
}
<commit_msg>Use DSA in texture/get_format<commit_after>use context::CommandContext;
use version::Version;
use version::Api;
use gl;

use std::mem;

use texture::any::TextureAny;
use TextureExt;
use GlObject;

/// Error that can happen when retrieving the internal format of a texture.
#[derive(Copy, Clone, Debug)]
pub enum GetFormatError {
    /// The backend doesn't support retrieving the internal format.
    NotSupported,
}

/// Internal format of a texture.
///
/// The actual format of a texture is not necessarly one of the predefined ones, so we have
/// to use a very generic description.
// TODO: change bits to be u16 for consistency with the rest of the library
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum InternalFormat {
    /// The format has one component.
    OneComponent {
        /// Type of the first component of the format.
        ty1: InternalFormatType,
        /// Number of bits of the first component.
        bits1: usize,
    },

    /// The format has two components.
    TwoComponents {
        /// Type of the first component of the format.
        ty1: InternalFormatType,
        /// Number of bits of the first component.
        bits1: usize,
        /// Type of the second component.
        ty2: InternalFormatType,
        /// Number of bits of the second component.
        bits2: usize,
    },

    /// The format has three components.
    ThreeComponents {
        /// Type of the first component of the format.
        ty1: InternalFormatType,
        /// Number of bits of the first component.
        bits1: usize,
        /// Type of the second component.
        ty2: InternalFormatType,
        /// Number of bits of the second component.
        bits2: usize,
        /// Type of the third component.
        ty3: InternalFormatType,
        /// Number of bits of the third component.
        bits3: usize,
    },

    /// The format has four components.
    FourComponents {
        /// Type of the first component of the format.
        ty1: InternalFormatType,
        /// Number of bits of the first component.
        bits1: usize,
        /// Type of the second component.
        ty2: InternalFormatType,
        /// Number of bits of the second component.
        bits2: usize,
        /// Type of the third component.
        ty3: InternalFormatType,
        /// Number of bits of the third component.
        bits3: usize,
        /// Type of the fourth component.
        ty4: InternalFormatType,
        /// Number of bits of the fourth component.
        bits4: usize,
    },
}

impl InternalFormat {
    /// Returns the total number of bits of this format.
    #[inline]
    pub fn get_total_bits(&self) -> usize {
        match self {
            &InternalFormat::OneComponent { bits1, .. } => bits1,
            &InternalFormat::TwoComponents { bits1, bits2, .. } => bits1 + bits2,
            &InternalFormat::ThreeComponents { bits1, bits2, bits3, .. } => bits1 + bits2 + bits3,
            &InternalFormat::FourComponents { bits1, bits2, bits3, bits4, .. } =>
                                                                    bits1 + bits2 + bits3 + bits4,
        }
    }
}

/// Format of a component of an internal format.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum InternalFormatType {
    /// Floating point texture with signed components.
    SignedNormalized,
    /// Floating point texture with unsigned components.
    UnsignedNormalized,
    /// Floating point texture with floats.
    Float,
    /// Integral texture.
    Int,
    /// Unsigned texture.
    UnsignedInt,
}

impl InternalFormatType {
    /// Builds the `InternalFormatType` of the GLenum. Panics if the value is not recognized.
    #[inline]
    fn from_glenum(val: gl::types::GLenum) -> InternalFormatType {
        match val {
            gl::SIGNED_NORMALIZED => InternalFormatType::SignedNormalized,
            gl::UNSIGNED_NORMALIZED => InternalFormatType::UnsignedNormalized,
            gl::FLOAT => InternalFormatType::Float,
            gl::INT => InternalFormatType::Int,
            gl::UNSIGNED_INT => InternalFormatType::UnsignedInt,
            gl::NONE => unreachable!(),     // separating this case for easier debugging
            _ => unreachable!(),
        }
    }
}

/// Determines the format of a texture.
///
/// A `TextureAny` is guaranteed to have the same format for each mipmap.
pub fn get_format(ctxt: &mut CommandContext, texture: &TextureAny)
                  -> Result<InternalFormat, GetFormatError>
{
    if ctxt.version >= &Version(Api::Gl, 3, 0) || ctxt.version >= &Version(Api::GlEs, 3, 0) {
        let (red_sz, red_ty, green_sz, green_ty, blue_sz, blue_ty,
             alpha_sz, alpha_ty, depth_sz, depth_ty) = unsafe
        {
            let mut red_sz = mem::uninitialized();
            let mut red_ty = mem::uninitialized();
            let mut green_sz = mem::uninitialized();
            let mut green_ty = mem::uninitialized();
            let mut blue_sz = mem::uninitialized();
            let mut blue_ty = mem::uninitialized();
            let mut alpha_sz = mem::uninitialized();
            let mut alpha_ty = mem::uninitialized();
            let mut depth_sz = mem::uninitialized();
            let mut depth_ty = mem::uninitialized();

            if ctxt.version >= &Version(Api::Gl, 4, 5) ||
               ctxt.extensions.gl_arb_direct_state_access
            {
                let id = texture.get_id();
                ctxt.gl.GetTextureLevelParameteriv(id, 0, gl::TEXTURE_RED_SIZE, &mut red_sz);
                ctxt.gl.GetTextureLevelParameteriv(id, 0, gl::TEXTURE_RED_TYPE, &mut red_ty);
                ctxt.gl.GetTextureLevelParameteriv(id, 0, gl::TEXTURE_GREEN_SIZE, &mut green_sz);
                ctxt.gl.GetTextureLevelParameteriv(id, 0, gl::TEXTURE_GREEN_TYPE, &mut green_ty);
                ctxt.gl.GetTextureLevelParameteriv(id, 0, gl::TEXTURE_BLUE_SIZE, &mut blue_sz);
                ctxt.gl.GetTextureLevelParameteriv(id, 0, gl::TEXTURE_BLUE_TYPE, &mut blue_ty);
                ctxt.gl.GetTextureLevelParameteriv(id, 0, gl::TEXTURE_ALPHA_SIZE, &mut alpha_sz);
                ctxt.gl.GetTextureLevelParameteriv(id, 0, gl::TEXTURE_ALPHA_TYPE, &mut alpha_ty);
                ctxt.gl.GetTextureLevelParameteriv(id, 0, gl::TEXTURE_DEPTH_SIZE, &mut depth_sz);
                ctxt.gl.GetTextureLevelParameteriv(id, 0, gl::TEXTURE_DEPTH_TYPE, &mut depth_ty);

            } else if ctxt.extensions.gl_ext_direct_state_access {
                let id = texture.get_id();
                let bind_point = texture.get_bind_point();

                ctxt.gl.GetTextureLevelParameterivEXT(id, bind_point, 0, gl::TEXTURE_RED_SIZE,
                                                      &mut red_sz);
                ctxt.gl.GetTextureLevelParameterivEXT(id, bind_point, 0, gl::TEXTURE_RED_TYPE,
                                                      &mut red_ty);
                ctxt.gl.GetTextureLevelParameterivEXT(id, bind_point, 0, gl::TEXTURE_GREEN_SIZE,
                                                      &mut green_sz);
                ctxt.gl.GetTextureLevelParameterivEXT(id, bind_point, 0, gl::TEXTURE_GREEN_TYPE,
                                                      &mut green_ty);
                ctxt.gl.GetTextureLevelParameterivEXT(id, bind_point, 0, gl::TEXTURE_BLUE_SIZE,
                                                      &mut blue_sz);
                ctxt.gl.GetTextureLevelParameterivEXT(id, bind_point, 0, gl::TEXTURE_BLUE_TYPE,
                                                      &mut blue_ty);
                ctxt.gl.GetTextureLevelParameterivEXT(id, bind_point, 0, gl::TEXTURE_ALPHA_SIZE,
                                                      &mut alpha_sz);
                ctxt.gl.GetTextureLevelParameterivEXT(id, bind_point, 0, gl::TEXTURE_ALPHA_TYPE,
                                                      &mut alpha_ty);
                ctxt.gl.GetTextureLevelParameterivEXT(id, bind_point, 0, gl::TEXTURE_DEPTH_SIZE,
                                                      &mut depth_sz);
                ctxt.gl.GetTextureLevelParameterivEXT(id, bind_point, 0, gl::TEXTURE_DEPTH_TYPE,
                                                      &mut depth_ty);

            } else {
                let bind_point = texture.bind_to_current(ctxt);
                ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_RED_SIZE, &mut red_sz);
                ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_RED_TYPE, &mut red_ty);
                ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_GREEN_SIZE,
                                               &mut green_sz);
                ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_GREEN_TYPE,
                                               &mut green_ty);
                ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_BLUE_SIZE, &mut blue_sz);
                ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_BLUE_TYPE, &mut blue_ty);
                ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_ALPHA_SIZE,
                                               &mut alpha_sz);
                ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_ALPHA_TYPE,
                                               &mut alpha_ty);
                ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_DEPTH_SIZE,
                                               &mut depth_sz);
                ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_DEPTH_TYPE,
                                               &mut depth_ty);
            }

            (red_sz as gl::types::GLenum, red_ty as gl::types::GLenum,
             green_sz as gl::types::GLenum, green_ty as gl::types::GLenum,
             blue_sz as gl::types::GLenum, blue_ty as gl::types::GLenum,
             alpha_sz as gl::types::GLenum, alpha_ty as gl::types::GLenum,
             depth_sz as gl::types::GLenum, depth_ty as gl::types::GLenum)
        };

        Ok(match (red_sz, red_ty, green_sz, green_ty, blue_sz, blue_ty,
               alpha_sz, alpha_ty, depth_sz, depth_ty)
        {
            (_, gl::NONE, _, _, _, _, _, _, sz1, ty1) => InternalFormat::OneComponent {
                ty1: InternalFormatType::from_glenum(ty1),
                bits1: sz1 as usize,
            },
            (sz1, ty1, _, gl::NONE, _, _, _, _, _, _) => InternalFormat::OneComponent {
                ty1: InternalFormatType::from_glenum(ty1),
                bits1: sz1 as usize,
            },
            (sz1, ty1, sz2, ty2, _, gl::NONE, _, _, _, _) => InternalFormat::TwoComponents {
                ty1: InternalFormatType::from_glenum(ty1),
                bits1: sz1 as usize,
                ty2: InternalFormatType::from_glenum(ty2),
                bits2: sz2 as usize,
            },
            (sz1, ty1, sz2, ty2, sz3, ty3, _, gl::NONE, _, _) => InternalFormat::ThreeComponents {
                ty1: InternalFormatType::from_glenum(ty1),
                bits1: sz1 as usize,
                ty2: InternalFormatType::from_glenum(ty2),
                bits2: sz2 as usize,
                ty3: InternalFormatType::from_glenum(ty3),
                bits3: sz3 as usize,
            },
            (sz1, ty1, sz2, ty2, sz3, ty3, sz4, ty4, _, gl::NONE) => InternalFormat::FourComponents {
                ty1: InternalFormatType::from_glenum(ty1),
                bits1: sz1 as usize,
                ty2: InternalFormatType::from_glenum(ty2),
                bits2: sz2 as usize,
                ty3: InternalFormatType::from_glenum(ty3),
                bits3: sz3 as usize,
                ty4: InternalFormatType::from_glenum(ty4),
                bits4: sz4 as usize,
            },
            _ => unreachable!()
        })

    } else {
        // FIXME: GL2
        Err(GetFormatError::NotSupported)
    }
}
<|endoftext|>


<commit_before><commit_msg>:hammer: Fix the type of id<commit_after><|endoftext|>


<commit_before><commit_msg>Fix: Do not use deprecated StoreId::exists() function<commit_after><|endoftext|>


<commit_before><commit_msg>tests: add tests for `mpm` binary<commit_after><|endoftext|>


<commit_before>extern mod std;

use libc::c_char;
use libc::c_int;
use libc::size_t;
use libc::c_ulong;
use libc::c_void;
use ptr::null;
use ptr::addr_of;
use ptr::mut_addr_of;
use ptr::to_mut_unsafe_ptr;
use str::as_c_str;

struct mpz_struct {
  _mp_alloc: c_int,
  _mp_size: c_int,
  _mp_d: *c_void
}

type mpz_srcptr = *const mpz_struct;
type mpz_ptr = *mut mpz_struct;

extern mod gmp {
  fn __gmpz_init(x: mpz_ptr);
  fn __gmpz_init_set_str(rop: mpz_ptr, str: *c_char, base: c_int) -> c_int;
  fn __gmpz_clear(x: mpz_ptr);
  fn __gmpz_set_str(rop: mpz_ptr, str: *c_char, base: c_int) -> c_int;
  fn __gmpz_get_str(str: *c_char, base: c_int, op: mpz_srcptr) -> *c_char;
  pure fn __gmpz_sizeinbase(op: mpz_srcptr, base: c_int) -> size_t;
  pure fn __gmpz_cmp(op: mpz_srcptr, op2: mpz_srcptr) -> c_int;
  pure fn __gmpz_cmp_ui(op1: mpz_srcptr, op2: c_ulong) -> c_int;
  fn __gmpz_add(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr);
  fn __gmpz_sub(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr);
  fn __gmpz_mul(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr);
  fn __gmpz_neg(rop: mpz_ptr, op: mpz_srcptr);
  fn __gmpz_tdiv_q(r: mpz_ptr, n: mpz_srcptr, d: mpz_srcptr);
  fn __gmpz_mod(r: mpz_ptr, n: mpz_srcptr, d: mpz_srcptr);
}

use gmp::*;

pub struct Mpz {
  priv mpz: mpz_struct,

  drop {
    __gmpz_clear(mut_addr_of(&self.mpz));
  }
}

impl Mpz {
  fn set_str(&mut self, s: &str, base: int) -> bool {
    let mpz = to_mut_unsafe_ptr(&mut self.mpz);
    let r = as_c_str(s, { |s| __gmpz_set_str(mpz, s, base as c_int) });
    r == 0
  }

  pure fn size_in_base(&self, base: int) -> uint {
    __gmpz_sizeinbase(addr_of(&self.mpz), base as c_int) as uint
  }
}

impl Mpz: cmp::Eq {
  pure fn eq(other: &Mpz) -> bool {
    __gmpz_cmp(addr_of(&self.mpz), addr_of(&other.mpz)) == 0
  }
  pure fn ne(other: &Mpz) -> bool {
    __gmpz_cmp(addr_of(&self.mpz), addr_of(&other.mpz)) != 0
  }
}

impl Mpz: cmp::Ord {
  pure fn lt(other: &Mpz) -> bool {
    __gmpz_cmp(addr_of(&self.mpz), addr_of(&other.mpz)) < 0
  }
  pure fn le(other: &Mpz) -> bool {
    __gmpz_cmp(addr_of(&self.mpz), addr_of(&other.mpz)) <= 0
  }
  pure fn gt(other: &Mpz) -> bool {
    __gmpz_cmp(addr_of(&self.mpz), addr_of(&other.mpz)) > 0
  }
  pure fn ge(other: &Mpz) -> bool {
    __gmpz_cmp(addr_of(&self.mpz), addr_of(&other.mpz)) >= 0
  }
}

impl Mpz: num::Num {
  pure fn add(other: &Mpz) -> Mpz unsafe {
    let res = init();
    __gmpz_add(mut_addr_of(&res.mpz), addr_of(&self.mpz), addr_of(&other.mpz));
    res
  }
  pure fn sub(other: &Mpz) -> Mpz unsafe {
    let res = init();
    __gmpz_sub(mut_addr_of(&res.mpz), addr_of(&self.mpz), addr_of(&other.mpz));
    res
  }
  pure fn mul(other: &Mpz) -> Mpz unsafe {
    let res = init();
    __gmpz_mul(mut_addr_of(&res.mpz), addr_of(&self.mpz), addr_of(&other.mpz));
    res
  }
  pure fn div(other: &Mpz) -> Mpz unsafe {
    if __gmpz_cmp_ui(addr_of(&self.mpz), 0) == 0 {
      fail ~"divide by zero";
    }

    let res = init();
    __gmpz_tdiv_q(mut_addr_of(&res.mpz), addr_of(&self.mpz), addr_of(&other.mpz));
    res
  }
  pure fn modulo(other: &Mpz) -> Mpz unsafe {
    if __gmpz_cmp_ui(addr_of(&self.mpz), 0) == 0 {
      fail ~"divide by zero";
    }

    let res = init();
    __gmpz_mod(mut_addr_of(&res.mpz), addr_of(&self.mpz), addr_of(&other.mpz));
    res
  }
  pure fn neg() -> Mpz unsafe {
    let res = init();
    __gmpz_neg(mut_addr_of(&res.mpz), addr_of(&self.mpz));
    res
  }
  pure fn to_int() -> int {
    fail ~"not implemented";
  }
  static pure fn from_int(other: int) -> Mpz {
    // the gmp functions dealing with longs aren't usable here - long is only
    // guaranteed to be at least 32-bit
    option::unwrap(from_str(other.to_str()))
  }
}

pub pure fn from_str_radix(s: &str, base: int) -> Option<Mpz> unsafe {
  let mpz = mpz_struct { _mp_alloc: 0, _mp_size: 0, _mp_d: null() };
  let mpz_ptr = mut_addr_of(&mpz);
  let r = as_c_str(s, { |s| __gmpz_init_set_str(mpz_ptr, s, base as c_int) });
  if r == 0 {
    Some(Mpz { mpz: mpz })
  } else {
    __gmpz_clear(mpz_ptr);
    None
  }
}

pub pure fn from_str(s: &str) -> Option<Mpz> {
  from_str_radix(s, 10)
}

impl Mpz : from_str::FromStr {
  static fn from_str(s: &str) -> Option<Mpz> {
    from_str(s)
  }
}

impl Mpz : to_str::ToStr {
  pure fn to_str() -> ~str unsafe {
    let length = self.size_in_base(10) + 2;
    let dst = vec::to_mut(vec::from_elem(length, '0'));
    let pdst = vec::raw::to_ptr(dst);

    str::raw::from_c_str(__gmpz_get_str(pdst as *c_char, 10, addr_of(&self.mpz)))
  }
}

pub pure fn init() -> Mpz unsafe {
  let mpz = mpz_struct { _mp_alloc: 0, _mp_size: 0, _mp_d: null() };
  __gmpz_init(mut_addr_of(&mpz));
  Mpz { mpz: mpz }
}

#[cfg(test)]
mod tests {
  #[test]
  fn size_in_base() {
    let x = option::unwrap(from_str("150000"));
    assert(x.size_in_base(10) == 6);
  }

  #[test]
  fn eq() {
    let x = option::unwrap(from_str("4242142195"));
    let y = option::unwrap(from_str("4242142195"));
    let z = option::unwrap(from_str("4242142196"));

    assert(x == y);
    assert(x != z);
    assert(y != z);
  }

  #[test]
  fn ord() {
    let x = option::unwrap(from_str("40000000000000000000000"));
    let y = option::unwrap(from_str("45000000000000000000000"));
    let z = option::unwrap(from_str("50000000000000000000000"));

    assert(x < y && x < z && y < z);
    assert(x <= x && x <= y && x <= z && y <= z);
    assert(z > y && z > x && y > x);
    assert(z >= z && z >= y && z >= x && y >= x);
  }

  #[test]
  #[should_fail]
  fn div_zero() {
    let x = init();
    x / x;
  }

  #[test]
  #[should_fail]
  fn modulo_zero() {
    let x = init();
    x % x;
  }

  #[test]
  fn test_div_round() {
    let mut x = init();
    let mut y = init();
    let mut z: Mpz;

    x.set_str("2", 10);
    y.set_str("3", 10);
    z = x / y;
    assert(__gmpz_cmp_ui(addr_of(&z.mpz), 2 / 3) == 0);

    x.set_str("2", 10);
    y.set_str("-3", 10);
    z = x / y;
    assert(__gmpz_cmp_ui(addr_of(&z.mpz), 2 / -3) == 0);
  }

  #[test]
  fn to_str() {
    let x = option::unwrap(from_str("1234567890"));
    assert(x.to_str() == ~"1234567890");
  }

  #[test]
  fn invalid_str() {
    assert(from_str("foobar").is_none());
  }
}
<commit_msg>add to_str_radix method<commit_after>extern mod std;

use libc::c_char;
use libc::c_int;
use libc::size_t;
use libc::c_ulong;
use libc::c_void;
use ptr::null;
use ptr::addr_of;
use ptr::mut_addr_of;
use ptr::to_mut_unsafe_ptr;
use str::as_c_str;

struct mpz_struct {
  _mp_alloc: c_int,
  _mp_size: c_int,
  _mp_d: *c_void
}

type mpz_srcptr = *const mpz_struct;
type mpz_ptr = *mut mpz_struct;

extern mod gmp {
  fn __gmpz_init(x: mpz_ptr);
  fn __gmpz_init_set_str(rop: mpz_ptr, str: *c_char, base: c_int) -> c_int;
  fn __gmpz_clear(x: mpz_ptr);
  fn __gmpz_set_str(rop: mpz_ptr, str: *c_char, base: c_int) -> c_int;
  fn __gmpz_get_str(str: *c_char, base: c_int, op: mpz_srcptr) -> *c_char;
  pure fn __gmpz_sizeinbase(op: mpz_srcptr, base: c_int) -> size_t;
  pure fn __gmpz_cmp(op: mpz_srcptr, op2: mpz_srcptr) -> c_int;
  pure fn __gmpz_cmp_ui(op1: mpz_srcptr, op2: c_ulong) -> c_int;
  fn __gmpz_add(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr);
  fn __gmpz_sub(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr);
  fn __gmpz_mul(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr);
  fn __gmpz_neg(rop: mpz_ptr, op: mpz_srcptr);
  fn __gmpz_tdiv_q(r: mpz_ptr, n: mpz_srcptr, d: mpz_srcptr);
  fn __gmpz_mod(r: mpz_ptr, n: mpz_srcptr, d: mpz_srcptr);
}

use gmp::*;

pub struct Mpz {
  priv mpz: mpz_struct,

  drop {
    __gmpz_clear(mut_addr_of(&self.mpz));
  }
}

impl Mpz {
  fn set_str(&mut self, s: &str, base: int) -> bool {
    let mpz = to_mut_unsafe_ptr(&mut self.mpz);
    let r = as_c_str(s, { |s| __gmpz_set_str(mpz, s, base as c_int) });
    r == 0
  }

  pure fn to_str_radix(&self, base: int) -> ~str unsafe {
    let length = self.size_in_base(10) + 2;
    let dst = vec::to_mut(vec::from_elem(length, '0'));
    let pdst = vec::raw::to_ptr(dst);

    str::raw::from_c_str(__gmpz_get_str(pdst as *c_char, base as c_int,
                         addr_of(&self.mpz)))
  }

  pure fn size_in_base(&self, base: int) -> uint {
    __gmpz_sizeinbase(addr_of(&self.mpz), base as c_int) as uint
  }
}

impl Mpz: cmp::Eq {
  pure fn eq(other: &Mpz) -> bool {
    __gmpz_cmp(addr_of(&self.mpz), addr_of(&other.mpz)) == 0
  }
  pure fn ne(other: &Mpz) -> bool {
    __gmpz_cmp(addr_of(&self.mpz), addr_of(&other.mpz)) != 0
  }
}

impl Mpz: cmp::Ord {
  pure fn lt(other: &Mpz) -> bool {
    __gmpz_cmp(addr_of(&self.mpz), addr_of(&other.mpz)) < 0
  }
  pure fn le(other: &Mpz) -> bool {
    __gmpz_cmp(addr_of(&self.mpz), addr_of(&other.mpz)) <= 0
  }
  pure fn gt(other: &Mpz) -> bool {
    __gmpz_cmp(addr_of(&self.mpz), addr_of(&other.mpz)) > 0
  }
  pure fn ge(other: &Mpz) -> bool {
    __gmpz_cmp(addr_of(&self.mpz), addr_of(&other.mpz)) >= 0
  }
}

impl Mpz: num::Num {
  pure fn add(other: &Mpz) -> Mpz unsafe {
    let res = init();
    __gmpz_add(mut_addr_of(&res.mpz), addr_of(&self.mpz), addr_of(&other.mpz));
    res
  }
  pure fn sub(other: &Mpz) -> Mpz unsafe {
    let res = init();
    __gmpz_sub(mut_addr_of(&res.mpz), addr_of(&self.mpz), addr_of(&other.mpz));
    res
  }
  pure fn mul(other: &Mpz) -> Mpz unsafe {
    let res = init();
    __gmpz_mul(mut_addr_of(&res.mpz), addr_of(&self.mpz), addr_of(&other.mpz));
    res
  }
  pure fn div(other: &Mpz) -> Mpz unsafe {
    if __gmpz_cmp_ui(addr_of(&self.mpz), 0) == 0 {
      fail ~"divide by zero";
    }

    let res = init();
    __gmpz_tdiv_q(mut_addr_of(&res.mpz), addr_of(&self.mpz), addr_of(&other.mpz));
    res
  }
  pure fn modulo(other: &Mpz) -> Mpz unsafe {
    if __gmpz_cmp_ui(addr_of(&self.mpz), 0) == 0 {
      fail ~"divide by zero";
    }

    let res = init();
    __gmpz_mod(mut_addr_of(&res.mpz), addr_of(&self.mpz), addr_of(&other.mpz));
    res
  }
  pure fn neg() -> Mpz unsafe {
    let res = init();
    __gmpz_neg(mut_addr_of(&res.mpz), addr_of(&self.mpz));
    res
  }
  pure fn to_int() -> int {
    fail ~"not implemented";
  }
  static pure fn from_int(other: int) -> Mpz {
    // the gmp functions dealing with longs aren't usable here - long is only
    // guaranteed to be at least 32-bit
    option::unwrap(from_str(other.to_str()))
  }
}

pub pure fn from_str_radix(s: &str, base: int) -> Option<Mpz> unsafe {
  let mpz = mpz_struct { _mp_alloc: 0, _mp_size: 0, _mp_d: null() };
  let mpz_ptr = mut_addr_of(&mpz);
  let r = as_c_str(s, { |s| __gmpz_init_set_str(mpz_ptr, s, base as c_int) });
  if r == 0 {
    Some(Mpz { mpz: mpz })
  } else {
    __gmpz_clear(mpz_ptr);
    None
  }
}

pub pure fn from_str(s: &str) -> Option<Mpz> {
  from_str_radix(s, 10)
}

impl Mpz : from_str::FromStr {
  static fn from_str(s: &str) -> Option<Mpz> {
    from_str(s)
  }
}

impl Mpz : to_str::ToStr {
  pure fn to_str() -> ~str unsafe {
    self.to_str_radix(10)
  }
}

pub pure fn init() -> Mpz unsafe {
  let mpz = mpz_struct { _mp_alloc: 0, _mp_size: 0, _mp_d: null() };
  __gmpz_init(mut_addr_of(&mpz));
  Mpz { mpz: mpz }
}

#[cfg(test)]
mod tests {
  #[test]
  fn size_in_base() {
    let x = option::unwrap(from_str("150000"));
    assert(x.size_in_base(10) == 6);
  }

  #[test]
  fn eq() {
    let x = option::unwrap(from_str("4242142195"));
    let y = option::unwrap(from_str("4242142195"));
    let z = option::unwrap(from_str("4242142196"));

    assert(x == y);
    assert(x != z);
    assert(y != z);
  }

  #[test]
  fn ord() {
    let x = option::unwrap(from_str("40000000000000000000000"));
    let y = option::unwrap(from_str("45000000000000000000000"));
    let z = option::unwrap(from_str("50000000000000000000000"));

    assert(x < y && x < z && y < z);
    assert(x <= x && x <= y && x <= z && y <= z);
    assert(z > y && z > x && y > x);
    assert(z >= z && z >= y && z >= x && y >= x);
  }

  #[test]
  #[should_fail]
  fn div_zero() {
    let x = init();
    x / x;
  }

  #[test]
  #[should_fail]
  fn modulo_zero() {
    let x = init();
    x % x;
  }

  #[test]
  fn test_div_round() {
    let mut x = init();
    let mut y = init();
    let mut z: Mpz;

    x.set_str("2", 10);
    y.set_str("3", 10);
    z = x / y;
    assert(__gmpz_cmp_ui(addr_of(&z.mpz), 2 / 3) == 0);

    x.set_str("2", 10);
    y.set_str("-3", 10);
    z = x / y;
    assert(__gmpz_cmp_ui(addr_of(&z.mpz), 2 / -3) == 0);
  }

  #[test]
  fn to_str_radix() {
    let x = option::unwrap(from_str("255"));
    assert(x.to_str_radix(16) == ~"ff");
  }

  #[test]
  fn to_str() {
    let x = option::unwrap(from_str("1234567890"));
    assert(x.to_str() == ~"1234567890");
  }

  #[test]
  fn invalid_str() {
    assert(from_str("foobar").is_none());
  }
}
<|endoftext|>