<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.

/*
 * The compiler code necessary to support the fmt! extension. Eventually this
 * should all get sucked into either the standard library extfmt module or the
 * compiler syntax extension plugin interface.
 */

use ast;
use codemap::span;
use ext::base::*;
use ext::base;
use ext::build;
use ext::build::*;

use core::unstable::extfmt::ct::*;

pub fn expand_syntax_ext(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree])
    -> base::MacResult {
    let args = get_exprs_from_tts(cx, tts);
    if args.len() == 0 {
        cx.span_fatal(sp, "fmt! takes at least 1 argument.");
    }
    let fmt =
        expr_to_str(cx, args[0],
                    ~"first argument to fmt! must be a string literal.");
    let fmtspan = args[0].span;
    debug!("Format string: %s", fmt);
    fn parse_fmt_err_(cx: @ext_ctxt, sp: span, msg: &str) -> ! {
        cx.span_fatal(sp, msg);
    }
    let parse_fmt_err: @fn(&str) -> ! = |s| parse_fmt_err_(cx, fmtspan, s);
    let pieces = parse_fmt_string(fmt, parse_fmt_err);
    MRExpr(pieces_to_expr(cx, sp, pieces, args))
}

// FIXME (#2249): A lot of these functions for producing expressions can
// probably be factored out in common with other code that builds
// expressions.  Also: Cleanup the naming of these functions.
// Note: Moved many of the common ones to build.rs --kevina
fn pieces_to_expr(cx: @ext_ctxt, sp: span,
                  pieces: ~[Piece], args: ~[@ast::expr])
   -> @ast::expr {
    fn make_path_vec(cx: @ext_ctxt, ident: @~str) -> ~[ast::ident] {
        let intr = cx.parse_sess().interner;
        return ~[intr.intern(@~"unstable"), intr.intern(@~"extfmt"),
                 intr.intern(@~"rt"), intr.intern(ident)];
    }
    fn make_rt_path_expr(cx: @ext_ctxt, sp: span, nm: @~str) -> @ast::expr {
        let path = make_path_vec(cx, nm);
        return mk_path_global(cx, sp, path);
    }
    // Produces an AST expression that represents a RT::conv record,
    // which tells the RT::conv* functions how to perform the conversion

    fn make_rt_conv_expr(cx: @ext_ctxt, sp: span, cnv: &Conv) -> @ast::expr {
        fn make_flags(cx: @ext_ctxt, sp: span, flags: ~[Flag]) -> @ast::expr {
            let mut tmp_expr = make_rt_path_expr(cx, sp, @~"flag_none");
            for flags.each |f| {
                let fstr = match *f {
                  FlagLeftJustify => ~"flag_left_justify",
                  FlagLeftZeroPad => ~"flag_left_zero_pad",
                  FlagSpaceForSign => ~"flag_space_for_sign",
                  FlagSignAlways => ~"flag_sign_always",
                  FlagAlternate => ~"flag_alternate"
                };
                tmp_expr = mk_binary(cx, sp, ast::bitor, tmp_expr,
                                     make_rt_path_expr(cx, sp, @fstr));
            }
            return tmp_expr;
        }
        fn make_count(cx: @ext_ctxt, sp: span, cnt: Count) -> @ast::expr {
            match cnt {
              CountImplied => {
                return make_rt_path_expr(cx, sp, @~"CountImplied");
              }
              CountIs(c) => {
                let count_lit = mk_uint(cx, sp, c as uint);
                let count_is_path = make_path_vec(cx, @~"CountIs");
                let count_is_args = ~[count_lit];
                return mk_call_global(cx, sp, count_is_path, count_is_args);
              }
              _ => cx.span_unimpl(sp, ~"unimplemented fmt! conversion")
            }
        }
        fn make_ty(cx: @ext_ctxt, sp: span, t: Ty) -> @ast::expr {
            let rt_type;
            match t {
              TyHex(c) => match c {
                CaseUpper => rt_type = ~"TyHexUpper",
                CaseLower => rt_type = ~"TyHexLower"
              },
              TyBits => rt_type = ~"TyBits",
              TyOctal => rt_type = ~"TyOctal",
              _ => rt_type = ~"TyDefault"
            }
            return make_rt_path_expr(cx, sp, @rt_type);
        }
        fn make_conv_struct(cx: @ext_ctxt, sp: span, flags_expr: @ast::expr,
                         width_expr: @ast::expr, precision_expr: @ast::expr,
                         ty_expr: @ast::expr) -> @ast::expr {
            let intr = cx.parse_sess().interner;
            mk_global_struct_e(
                cx,
                sp,
                make_path_vec(cx, @~"Conv"),
                ~[
                    build::Field {
                        ident: intr.intern(@~"flags"), ex: flags_expr
                    },
                    build::Field {
                        ident: intr.intern(@~"width"), ex: width_expr
                    },
                    build::Field {
                        ident: intr.intern(@~"precision"), ex: precision_expr
                    },
                    build::Field {
                        ident: intr.intern(@~"ty"), ex: ty_expr
                    },
                ]
            )
        }
        let rt_conv_flags = make_flags(cx, sp, cnv.flags);
        let rt_conv_width = make_count(cx, sp, cnv.width);
        let rt_conv_precision = make_count(cx, sp, cnv.precision);
        let rt_conv_ty = make_ty(cx, sp, cnv.ty);
        make_conv_struct(cx, sp, rt_conv_flags, rt_conv_width,
                         rt_conv_precision, rt_conv_ty)
    }
    fn make_conv_call(cx: @ext_ctxt, sp: span, conv_type: &str, cnv: &Conv,
                      arg: @ast::expr, buf: @ast::expr) -> @ast::expr {
        let fname = ~"conv_" + conv_type;
        let path = make_path_vec(cx, @fname);
        let cnv_expr = make_rt_conv_expr(cx, sp, cnv);
        let args = ~[cnv_expr, arg, buf];
        return mk_call_global(cx, arg.span, path, args);
    }

    fn make_new_conv(cx: @ext_ctxt, sp: span, cnv: &Conv,
                     arg: @ast::expr, buf: @ast::expr) -> @ast::expr {
        fn is_signed_type(cnv: &Conv) -> bool {
            match cnv.ty {
              TyInt(s) => match s {
                Signed => return true,
                Unsigned => return false
              },
              TyFloat => return true,
              _ => return false
            }
        }
        let unsupported = ~"conversion not supported in fmt! string";
        match cnv.param {
          option::None => (),
          _ => cx.span_unimpl(sp, unsupported)
        }
        for cnv.flags.each |f| {
            match *f {
              FlagLeftJustify => (),
              FlagSignAlways => {
                if !is_signed_type(cnv) {
                    cx.span_fatal(sp,
                                  ~"+ flag only valid in " +
                                      ~"signed fmt! conversion");
                }
              }
              FlagSpaceForSign => {
                if !is_signed_type(cnv) {
                    cx.span_fatal(sp,
                                  ~"space flag only valid in " +
                                      ~"signed fmt! conversions");
                }
              }
              FlagLeftZeroPad => (),
              _ => cx.span_unimpl(sp, unsupported)
            }
        }
        match cnv.width {
          CountImplied => (),
          CountIs(_) => (),
          _ => cx.span_unimpl(sp, unsupported)
        }
        match cnv.precision {
          CountImplied => (),
          CountIs(_) => (),
          _ => cx.span_unimpl(sp, unsupported)
        }
        let (name, actual_arg) = match cnv.ty {
            TyStr => ("str", arg),
            TyInt(Signed) => ("int", arg),
            TyBool => ("bool", arg),
            TyChar => ("char", arg),
            TyBits | TyOctal | TyHex(_) | TyInt(Unsigned) => ("uint", arg),
            TyFloat => ("float", arg),
            TyPoly => ("poly", mk_addr_of(cx, sp, arg))
        };
        return make_conv_call(cx, arg.span, name, cnv, actual_arg,
                              mk_mut_addr_of(cx, arg.span, buf));
    }
    fn log_conv(c: &Conv) {
        debug!("Building conversion:");
        match c.param {
          Some(p) => { debug!("param: %s", p.to_str()); }
          _ => debug!("param: none")
        }
        for c.flags.each |f| {
            match *f {
              FlagLeftJustify => debug!("flag: left justify"),
              FlagLeftZeroPad => debug!("flag: left zero pad"),
              FlagSpaceForSign => debug!("flag: left space pad"),
              FlagSignAlways => debug!("flag: sign always"),
              FlagAlternate => debug!("flag: alternate")
            }
        }
        match c.width {
          CountIs(i) =>
              debug!("width: count is %s", i.to_str()),
          CountIsParam(i) =>
              debug!("width: count is param %s", i.to_str()),
          CountIsNextParam => debug!("width: count is next param"),
          CountImplied => debug!("width: count is implied")
        }
        match c.precision {
          CountIs(i) =>
              debug!("prec: count is %s", i.to_str()),
          CountIsParam(i) =>
              debug!("prec: count is param %s", i.to_str()),
          CountIsNextParam => debug!("prec: count is next param"),
          CountImplied => debug!("prec: count is implied")
        }
        match c.ty {
          TyBool => debug!("type: bool"),
          TyStr => debug!("type: str"),
          TyChar => debug!("type: char"),
          TyInt(s) => match s {
            Signed => debug!("type: signed"),
            Unsigned => debug!("type: unsigned")
          },
          TyBits => debug!("type: bits"),
          TyHex(cs) => match cs {
            CaseUpper => debug!("type: uhex"),
            CaseLower => debug!("type: lhex"),
          },
          TyOctal => debug!("type: octal"),
          TyFloat => debug!("type: float"),
          TyPoly => debug!("type: poly")
        }
    }

    let fmt_sp = args[0].span;
    let mut n = 0u;
    let nargs = args.len();

    /* 'ident' is the local buffer building up the result of fmt! */
    let ident = cx.parse_sess().interner.intern(@~"__fmtbuf");
    let buf = || mk_path(cx, fmt_sp, ~[ident]);
    let str_ident = cx.parse_sess().interner.intern(@~"str");
    let push_ident = cx.parse_sess().interner.intern(@~"push_str");
    let mut stms = ~[];

    /* Translate each piece (portion of the fmt expression) by invoking the
       corresponding function in core::unstable::extfmt. Each function takes a
       buffer to insert data into along with the data being formatted. */
    let npieces = pieces.len();
    do vec::consume(pieces) |i, pc| {
        match pc {
            /* Raw strings get appended via str::push_str */
            PieceString(s) => {
                let portion = mk_uniq_str(cx, fmt_sp, s);

                /* If this is the first portion, then initialize the local
                   buffer with it directly. If it's actually the only piece,
                   then there's no need for it to be mutable */
                if i == 0 {
                    stms.push(mk_local(cx, fmt_sp, npieces > 1, ident, portion));
                } else {
                    let args = ~[mk_mut_addr_of(cx, fmt_sp, buf()), portion];
                    let call = mk_call_global(cx,
                                              fmt_sp,
                                              ~[str_ident, push_ident],
                                              args);
                    stms.push(mk_stmt(cx, fmt_sp, call));
                }
            }

            /* Invoke the correct conv function in extfmt */
            PieceConv(ref conv) => {
                n += 1u;
                if n >= nargs {
                    cx.span_fatal(sp,
                                  ~"not enough arguments to fmt! " +
                                  ~"for the given format string");
                }

                log_conv(conv);
                /* If the first portion is a conversion, then the local buffer
                   must be initialized as an empty string */
                if i == 0 {
                    stms.push(mk_local(cx, fmt_sp, true, ident,
                                       mk_uniq_str(cx, fmt_sp, ~"")));
                }
                stms.push(mk_stmt(cx, fmt_sp,
                                  make_new_conv(cx, fmt_sp, conv,
                                                args[n], buf())));
            }
        }
    }

    let expected_nargs = n + 1u; // n conversions + the fmt string
    if expected_nargs < nargs {
        cx.span_fatal
            (sp, fmt!("too many arguments to fmt!. found %u, expected %u",
                           nargs, expected_nargs));
    }

    return mk_block(cx, fmt_sp, ~[], stms, Some(buf()));
}
<commit_msg>Avoid needless creation of unique strings in fmt!()<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.

/*
 * The compiler code necessary to support the fmt! extension. Eventually this
 * should all get sucked into either the standard library extfmt module or the
 * compiler syntax extension plugin interface.
 */

use ast;
use codemap::span;
use ext::base::*;
use ext::base;
use ext::build;
use ext::build::*;

use core::unstable::extfmt::ct::*;

pub fn expand_syntax_ext(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree])
    -> base::MacResult {
    let args = get_exprs_from_tts(cx, tts);
    if args.len() == 0 {
        cx.span_fatal(sp, "fmt! takes at least 1 argument.");
    }
    let fmt =
        expr_to_str(cx, args[0],
                    ~"first argument to fmt! must be a string literal.");
    let fmtspan = args[0].span;
    debug!("Format string: %s", fmt);
    fn parse_fmt_err_(cx: @ext_ctxt, sp: span, msg: &str) -> ! {
        cx.span_fatal(sp, msg);
    }
    let parse_fmt_err: @fn(&str) -> ! = |s| parse_fmt_err_(cx, fmtspan, s);
    let pieces = parse_fmt_string(fmt, parse_fmt_err);
    MRExpr(pieces_to_expr(cx, sp, pieces, args))
}

// FIXME (#2249): A lot of these functions for producing expressions can
// probably be factored out in common with other code that builds
// expressions.  Also: Cleanup the naming of these functions.
// Note: Moved many of the common ones to build.rs --kevina
fn pieces_to_expr(cx: @ext_ctxt, sp: span,
                  pieces: ~[Piece], args: ~[@ast::expr])
   -> @ast::expr {
    fn make_path_vec(cx: @ext_ctxt, ident: @~str) -> ~[ast::ident] {
        let intr = cx.parse_sess().interner;
        return ~[intr.intern(@~"unstable"), intr.intern(@~"extfmt"),
                 intr.intern(@~"rt"), intr.intern(ident)];
    }
    fn make_rt_path_expr(cx: @ext_ctxt, sp: span, nm: @~str) -> @ast::expr {
        let path = make_path_vec(cx, nm);
        return mk_path_global(cx, sp, path);
    }
    // Produces an AST expression that represents a RT::conv record,
    // which tells the RT::conv* functions how to perform the conversion

    fn make_rt_conv_expr(cx: @ext_ctxt, sp: span, cnv: &Conv) -> @ast::expr {
        fn make_flags(cx: @ext_ctxt, sp: span, flags: ~[Flag]) -> @ast::expr {
            let mut tmp_expr = make_rt_path_expr(cx, sp, @~"flag_none");
            for flags.each |f| {
                let fstr = match *f {
                  FlagLeftJustify => ~"flag_left_justify",
                  FlagLeftZeroPad => ~"flag_left_zero_pad",
                  FlagSpaceForSign => ~"flag_space_for_sign",
                  FlagSignAlways => ~"flag_sign_always",
                  FlagAlternate => ~"flag_alternate"
                };
                tmp_expr = mk_binary(cx, sp, ast::bitor, tmp_expr,
                                     make_rt_path_expr(cx, sp, @fstr));
            }
            return tmp_expr;
        }
        fn make_count(cx: @ext_ctxt, sp: span, cnt: Count) -> @ast::expr {
            match cnt {
              CountImplied => {
                return make_rt_path_expr(cx, sp, @~"CountImplied");
              }
              CountIs(c) => {
                let count_lit = mk_uint(cx, sp, c as uint);
                let count_is_path = make_path_vec(cx, @~"CountIs");
                let count_is_args = ~[count_lit];
                return mk_call_global(cx, sp, count_is_path, count_is_args);
              }
              _ => cx.span_unimpl(sp, ~"unimplemented fmt! conversion")
            }
        }
        fn make_ty(cx: @ext_ctxt, sp: span, t: Ty) -> @ast::expr {
            let rt_type;
            match t {
              TyHex(c) => match c {
                CaseUpper => rt_type = ~"TyHexUpper",
                CaseLower => rt_type = ~"TyHexLower"
              },
              TyBits => rt_type = ~"TyBits",
              TyOctal => rt_type = ~"TyOctal",
              _ => rt_type = ~"TyDefault"
            }
            return make_rt_path_expr(cx, sp, @rt_type);
        }
        fn make_conv_struct(cx: @ext_ctxt, sp: span, flags_expr: @ast::expr,
                         width_expr: @ast::expr, precision_expr: @ast::expr,
                         ty_expr: @ast::expr) -> @ast::expr {
            let intr = cx.parse_sess().interner;
            mk_global_struct_e(
                cx,
                sp,
                make_path_vec(cx, @~"Conv"),
                ~[
                    build::Field {
                        ident: intr.intern(@~"flags"), ex: flags_expr
                    },
                    build::Field {
                        ident: intr.intern(@~"width"), ex: width_expr
                    },
                    build::Field {
                        ident: intr.intern(@~"precision"), ex: precision_expr
                    },
                    build::Field {
                        ident: intr.intern(@~"ty"), ex: ty_expr
                    },
                ]
            )
        }
        let rt_conv_flags = make_flags(cx, sp, cnv.flags);
        let rt_conv_width = make_count(cx, sp, cnv.width);
        let rt_conv_precision = make_count(cx, sp, cnv.precision);
        let rt_conv_ty = make_ty(cx, sp, cnv.ty);
        make_conv_struct(cx, sp, rt_conv_flags, rt_conv_width,
                         rt_conv_precision, rt_conv_ty)
    }
    fn make_conv_call(cx: @ext_ctxt, sp: span, conv_type: &str, cnv: &Conv,
                      arg: @ast::expr, buf: @ast::expr) -> @ast::expr {
        let fname = ~"conv_" + conv_type;
        let path = make_path_vec(cx, @fname);
        let cnv_expr = make_rt_conv_expr(cx, sp, cnv);
        let args = ~[cnv_expr, arg, buf];
        return mk_call_global(cx, arg.span, path, args);
    }

    fn make_new_conv(cx: @ext_ctxt, sp: span, cnv: &Conv,
                     arg: @ast::expr, buf: @ast::expr) -> @ast::expr {
        fn is_signed_type(cnv: &Conv) -> bool {
            match cnv.ty {
              TyInt(s) => match s {
                Signed => return true,
                Unsigned => return false
              },
              TyFloat => return true,
              _ => return false
            }
        }
        let unsupported = ~"conversion not supported in fmt! string";
        match cnv.param {
          option::None => (),
          _ => cx.span_unimpl(sp, unsupported)
        }
        for cnv.flags.each |f| {
            match *f {
              FlagLeftJustify => (),
              FlagSignAlways => {
                if !is_signed_type(cnv) {
                    cx.span_fatal(sp,
                                  ~"+ flag only valid in " +
                                      ~"signed fmt! conversion");
                }
              }
              FlagSpaceForSign => {
                if !is_signed_type(cnv) {
                    cx.span_fatal(sp,
                                  ~"space flag only valid in " +
                                      ~"signed fmt! conversions");
                }
              }
              FlagLeftZeroPad => (),
              _ => cx.span_unimpl(sp, unsupported)
            }
        }
        match cnv.width {
          CountImplied => (),
          CountIs(_) => (),
          _ => cx.span_unimpl(sp, unsupported)
        }
        match cnv.precision {
          CountImplied => (),
          CountIs(_) => (),
          _ => cx.span_unimpl(sp, unsupported)
        }
        let (name, actual_arg) = match cnv.ty {
            TyStr => ("str", arg),
            TyInt(Signed) => ("int", arg),
            TyBool => ("bool", arg),
            TyChar => ("char", arg),
            TyBits | TyOctal | TyHex(_) | TyInt(Unsigned) => ("uint", arg),
            TyFloat => ("float", arg),
            TyPoly => ("poly", mk_addr_of(cx, sp, arg))
        };
        return make_conv_call(cx, arg.span, name, cnv, actual_arg,
                              mk_mut_addr_of(cx, arg.span, buf));
    }
    fn log_conv(c: &Conv) {
        debug!("Building conversion:");
        match c.param {
          Some(p) => { debug!("param: %s", p.to_str()); }
          _ => debug!("param: none")
        }
        for c.flags.each |f| {
            match *f {
              FlagLeftJustify => debug!("flag: left justify"),
              FlagLeftZeroPad => debug!("flag: left zero pad"),
              FlagSpaceForSign => debug!("flag: left space pad"),
              FlagSignAlways => debug!("flag: sign always"),
              FlagAlternate => debug!("flag: alternate")
            }
        }
        match c.width {
          CountIs(i) =>
              debug!("width: count is %s", i.to_str()),
          CountIsParam(i) =>
              debug!("width: count is param %s", i.to_str()),
          CountIsNextParam => debug!("width: count is next param"),
          CountImplied => debug!("width: count is implied")
        }
        match c.precision {
          CountIs(i) =>
              debug!("prec: count is %s", i.to_str()),
          CountIsParam(i) =>
              debug!("prec: count is param %s", i.to_str()),
          CountIsNextParam => debug!("prec: count is next param"),
          CountImplied => debug!("prec: count is implied")
        }
        match c.ty {
          TyBool => debug!("type: bool"),
          TyStr => debug!("type: str"),
          TyChar => debug!("type: char"),
          TyInt(s) => match s {
            Signed => debug!("type: signed"),
            Unsigned => debug!("type: unsigned")
          },
          TyBits => debug!("type: bits"),
          TyHex(cs) => match cs {
            CaseUpper => debug!("type: uhex"),
            CaseLower => debug!("type: lhex"),
          },
          TyOctal => debug!("type: octal"),
          TyFloat => debug!("type: float"),
          TyPoly => debug!("type: poly")
        }
    }

    let fmt_sp = args[0].span;
    let mut n = 0u;
    let nargs = args.len();

    /* 'ident' is the local buffer building up the result of fmt! */
    let ident = cx.parse_sess().interner.intern(@~"__fmtbuf");
    let buf = || mk_path(cx, fmt_sp, ~[ident]);
    let str_ident = cx.parse_sess().interner.intern(@~"str");
    let push_ident = cx.parse_sess().interner.intern(@~"push_str");
    let mut stms = ~[];

    /* Translate each piece (portion of the fmt expression) by invoking the
       corresponding function in core::unstable::extfmt. Each function takes a
       buffer to insert data into along with the data being formatted. */
    let npieces = pieces.len();
    do vec::consume(pieces) |i, pc| {
        match pc {
            /* Raw strings get appended via str::push_str */
            PieceString(s) => {
                /* If this is the first portion, then initialize the local
                   buffer with it directly. If it's actually the only piece,
                   then there's no need for it to be mutable */
                if i == 0 {
                    stms.push(mk_local(cx, fmt_sp, npieces > 1, ident, mk_uniq_str(cx, fmt_sp, s)));
                } else {
                    let args = ~[mk_mut_addr_of(cx, fmt_sp, buf()), mk_base_str(cx, fmt_sp, s)];
                    let call = mk_call_global(cx,
                                              fmt_sp,
                                              ~[str_ident, push_ident],
                                              args);
                    stms.push(mk_stmt(cx, fmt_sp, call));
                }
            }

            /* Invoke the correct conv function in extfmt */
            PieceConv(ref conv) => {
                n += 1u;
                if n >= nargs {
                    cx.span_fatal(sp,
                                  ~"not enough arguments to fmt! " +
                                  ~"for the given format string");
                }

                log_conv(conv);
                /* If the first portion is a conversion, then the local buffer
                   must be initialized as an empty string */
                if i == 0 {
                    stms.push(mk_local(cx, fmt_sp, true, ident,
                                       mk_uniq_str(cx, fmt_sp, ~"")));
                }
                stms.push(mk_stmt(cx, fmt_sp,
                                  make_new_conv(cx, fmt_sp, conv,
                                                args[n], buf())));
            }
        }
    }

    let expected_nargs = n + 1u; // n conversions + the fmt string
    if expected_nargs < nargs {
        cx.span_fatal
            (sp, fmt!("too many arguments to fmt!. found %u, expected %u",
                           nargs, expected_nargs));
    }

    return mk_block(cx, fmt_sp, ~[], stms, Some(buf()));
}
<|endoftext|>


<commit_before><commit_msg>Add missing file<commit_after>use std::str::FromStr;
use std::string::ToString;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum EdgeOp {
    Dup,
    Split,
    Loop,
    Merge,
    Next,
    Parent,
    Reverse,
    Save,
    Restore,
}

impl ToString for EdgeOp {
    fn to_string(&self) -> String {
        match *self {
            EdgeOp::Dup => "Dup".to_string(),
            EdgeOp::Split => "Split".to_string(),
            EdgeOp::Loop => "Loop".to_string(),
            EdgeOp::Merge => "Merge".to_string(),
            EdgeOp::Next => "Next".to_string(),
            EdgeOp::Parent => "Parent".to_string(),
            EdgeOp::Reverse => "Reverse".to_string(),
            EdgeOp::Save => "Save".to_string(),
            EdgeOp::Restore => "Restore".to_string(),
        }
    }
}

impl FromStr for EdgeOp {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "Dup" => Ok(EdgeOp::Dup),
            "Split" => Ok(EdgeOp::Split),
            "Loop" => Ok(EdgeOp::Loop),
            "Merge" => Ok(EdgeOp::Merge),
            "Next" => Ok(EdgeOp::Next),
            "Parent" => Ok(EdgeOp::Parent),
            "Reverse" => Ok(EdgeOp::Reverse),
            "Save" => Ok(EdgeOp::Save),
            "Restore" => Ok(EdgeOp::Restore),
            _ => Err(format!("Invalid opcode: {}", s)),
        }
    }
}
<|endoftext|>


<commit_before>// -*- rust -*-

import front.parser;
import front.token;
import middle.trans;
import middle.resolve;
import middle.typeck;
import util.common;

import std.option;
import std.option.some;
import std.option.none;
import std._str;
import std._vec;

impure fn parse_input(session.session sess,
                      parser.parser p,
                      str input) -> @front.ast.crate {
    if (_str.ends_with(input, ".rc")) {
        ret parser.parse_crate_from_crate_file(p);
    } else if (_str.ends_with(input, ".rs")) {
        ret parser.parse_crate_from_source_file(p);
    }
    sess.err("unknown unput file type: " + input);
    fail;
}

impure fn compile_input(session.session sess, str input, str output,
                        bool shared) {
    auto p = parser.new_parser(sess, 0, input);
    auto crate = parse_input(sess, p, input);
    crate = resolve.resolve_crate(sess, crate);
    crate = typeck.check_crate(sess, crate);
    trans.trans_crate(sess, crate, output, shared);
}

fn warn_wrong_compiler() {
    log "This is the rust 'self-hosted' compiler.";
    log "The one written in rust.";
    log "It is currently incomplete.";
    log "You may want rustboot insteaad, the compiler next door.";
}

fn usage(session.session sess, str argv0) {
    log #fmt("usage: %s [options] <input>", argv0);
    log "options:";
    log "";
    log "    -o <filename>      write output to <filename>";
    log "    -nowarn            suppress wrong-compiler warning";
    log "    -shared            compile a shared-library crate";
    log "    -h                 display this message";
    log "";
    log "";
}

fn get_os() -> session.os {
    auto s = std.os.target_os();
    if (_str.eq(s, "win32")) { ret session.os_win32; }
    if (_str.eq(s, "macos")) { ret session.os_macos; }
    if (_str.eq(s, "linux")) { ret session.os_linux; }
}

impure fn main(vec[str] args) {

    // FIXME: don't hard-wire this.
    auto target_cfg = rec(os = get_os(),
                          arch = session.arch_x86,
                          int_type = common.ty_i32,
                          uint_type = common.ty_u32,
                          float_type = common.ty_f64 );

    auto sess = session.session(target_cfg);
    let option.t[str] input_file = none[str];
    let option.t[str] output_file = none[str];
    let bool do_warn = true;
    let bool shared = false;

    auto i = 1u;
    auto len = _vec.len[str](args);

    // FIXME: a getopt module would be nice.
    while (i < len) {
        auto arg = args.(i);
        if (_str.byte_len(arg) > 0u && arg.(0) == '-' as u8) {
            if (_str.eq(arg, "-nowarn")) {
                do_warn = false;
            } else if (_str.eq(arg, "-shared")) {
                shared = true;
            } else {
                // FIXME: rust could use an elif construct.
                if (_str.eq(arg, "-o")) {
                    if (i+1u < len) {
                        output_file = some(args.(i+1u));
                        i += 1u;
                    } else {
                        usage(sess, args.(0));
                        sess.err("-o requires an argument");
                    }
                } else {
                    if (_str.eq(arg, "-h")) {
                        usage(sess, args.(0));
                    } else {
                        usage(sess, args.(0));
                        sess.err("unrecognized option: " + arg);
                    }
                }
            }
        } else {
            alt (input_file) {
                case (some[str](_)) {
                    usage(sess, args.(0));
                    sess.err("multiple inputs provided");
                }
                case (none[str]) {
                    input_file = some[str](arg);
                }
            }
            // FIXME: dummy node to work around typestate mis-wiring bug.
            i = i;
        }
        i += 1u;
    }

    if (do_warn) {
        warn_wrong_compiler();
    }

    alt (input_file) {
        case (none[str]) {
            usage(sess, args.(0));
            sess.err("no input filename");
        }
        case (some[str](?ifile)) {
            alt (output_file) {
                case (none[str]) {
                    let vec[str] parts = _str.split(ifile, '.' as u8);
                    parts = _vec.pop[str](parts);
                    parts += ".bc";
                    auto ofile = _str.concat(parts);
                    compile_input(sess, ifile, ofile, shared);
                }
                case (some[str](?ofile)) {
                    compile_input(sess, ifile, ofile, shared);
                }
            }
        }
    }
}

// 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 ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Fix typo in comment.<commit_after>// -*- rust -*-

import front.parser;
import front.token;
import middle.trans;
import middle.resolve;
import middle.typeck;
import util.common;

import std.option;
import std.option.some;
import std.option.none;
import std._str;
import std._vec;

impure fn parse_input(session.session sess,
                      parser.parser p,
                      str input) -> @front.ast.crate {
    if (_str.ends_with(input, ".rc")) {
        ret parser.parse_crate_from_crate_file(p);
    } else if (_str.ends_with(input, ".rs")) {
        ret parser.parse_crate_from_source_file(p);
    }
    sess.err("unknown unput file type: " + input);
    fail;
}

impure fn compile_input(session.session sess, str input, str output,
                        bool shared) {
    auto p = parser.new_parser(sess, 0, input);
    auto crate = parse_input(sess, p, input);
    crate = resolve.resolve_crate(sess, crate);
    crate = typeck.check_crate(sess, crate);
    trans.trans_crate(sess, crate, output, shared);
}

fn warn_wrong_compiler() {
    log "This is the rust 'self-hosted' compiler.";
    log "The one written in rust.";
    log "It is currently incomplete.";
    log "You may want rustboot instead, the compiler next door.";
}

fn usage(session.session sess, str argv0) {
    log #fmt("usage: %s [options] <input>", argv0);
    log "options:";
    log "";
    log "    -o <filename>      write output to <filename>";
    log "    -nowarn            suppress wrong-compiler warning";
    log "    -shared            compile a shared-library crate";
    log "    -h                 display this message";
    log "";
    log "";
}

fn get_os() -> session.os {
    auto s = std.os.target_os();
    if (_str.eq(s, "win32")) { ret session.os_win32; }
    if (_str.eq(s, "macos")) { ret session.os_macos; }
    if (_str.eq(s, "linux")) { ret session.os_linux; }
}

impure fn main(vec[str] args) {

    // FIXME: don't hard-wire this.
    auto target_cfg = rec(os = get_os(),
                          arch = session.arch_x86,
                          int_type = common.ty_i32,
                          uint_type = common.ty_u32,
                          float_type = common.ty_f64 );

    auto sess = session.session(target_cfg);
    let option.t[str] input_file = none[str];
    let option.t[str] output_file = none[str];
    let bool do_warn = true;
    let bool shared = false;

    auto i = 1u;
    auto len = _vec.len[str](args);

    // FIXME: a getopt module would be nice.
    while (i < len) {
        auto arg = args.(i);
        if (_str.byte_len(arg) > 0u && arg.(0) == '-' as u8) {
            if (_str.eq(arg, "-nowarn")) {
                do_warn = false;
            } else if (_str.eq(arg, "-shared")) {
                shared = true;
            } else {
                // FIXME: rust could use an elif construct.
                if (_str.eq(arg, "-o")) {
                    if (i+1u < len) {
                        output_file = some(args.(i+1u));
                        i += 1u;
                    } else {
                        usage(sess, args.(0));
                        sess.err("-o requires an argument");
                    }
                } else {
                    if (_str.eq(arg, "-h")) {
                        usage(sess, args.(0));
                    } else {
                        usage(sess, args.(0));
                        sess.err("unrecognized option: " + arg);
                    }
                }
            }
        } else {
            alt (input_file) {
                case (some[str](_)) {
                    usage(sess, args.(0));
                    sess.err("multiple inputs provided");
                }
                case (none[str]) {
                    input_file = some[str](arg);
                }
            }
            // FIXME: dummy node to work around typestate mis-wiring bug.
            i = i;
        }
        i += 1u;
    }

    if (do_warn) {
        warn_wrong_compiler();
    }

    alt (input_file) {
        case (none[str]) {
            usage(sess, args.(0));
            sess.err("no input filename");
        }
        case (some[str](?ifile)) {
            alt (output_file) {
                case (none[str]) {
                    let vec[str] parts = _str.split(ifile, '.' as u8);
                    parts = _vec.pop[str](parts);
                    parts += ".bc";
                    auto ofile = _str.concat(parts);
                    compile_input(sess, ifile, ofile, shared);
                }
                case (some[str](?ofile)) {
                    compile_input(sess, ifile, ofile, shared);
                }
            }
        }
    }
}

// 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 ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before><commit_msg>Convenience method to parser darwin xml from Read instance.<commit_after><|endoftext|>


<commit_before>// 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.

//! Readers and Writers for in-memory buffers
//!
//! # XXX
//!
//! * Should probably have something like this for strings.
//! * Should they implement Closable? Would take extra state.

use cmp::min;
use prelude::*;
use super::*;
use vec;

/// Writes to an owned, growable byte vector
pub struct MemWriter {
    buf: ~[u8]
}

impl MemWriter {
    pub fn new() -> MemWriter { MemWriter { buf: vec::with_capacity(128) } }
}

impl Writer for MemWriter {
    fn write(&mut self, buf: &[u8]) {
        self.buf.push_all(buf)
    }

    fn flush(&mut self) { /* no-op */ }
}

impl Seek for MemWriter {
    fn tell(&self) -> u64 { self.buf.len() as u64 }

    fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
}

impl Decorator<~[u8]> for MemWriter {

    fn inner(self) -> ~[u8] {
        match self {
            MemWriter { buf: buf } => buf
        }
    }

    fn inner_ref<'a>(&'a self) -> &'a ~[u8] {
        match *self {
            MemWriter { buf: ref buf } => buf
        }
    }

    fn inner_mut_ref<'a>(&'a mut self) -> &'a mut ~[u8] {
        match *self {
            MemWriter { buf: ref mut buf } => buf
        }
    }
}

/// Reads from an owned byte vector
pub struct MemReader {
    buf: ~[u8],
    pos: uint
}

impl MemReader {
    pub fn new(buf: ~[u8]) -> MemReader {
        MemReader {
            buf: buf,
            pos: 0
        }
    }
}

impl Reader for MemReader {
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
        { if self.eof() { return None; } }

        let write_len = min(buf.len(), self.buf.len() - self.pos);
        {
            let input = self.buf.slice(self.pos, self.pos + write_len);
            let output = buf.mut_slice(0, write_len);
            assert_eq!(input.len(), output.len());
            vec::bytes::copy_memory(output, input, write_len);
        }
        self.pos += write_len;
        assert!(self.pos <= self.buf.len());

        return Some(write_len);
    }

    fn eof(&mut self) -> bool { self.pos == self.buf.len() }
}

impl Seek for MemReader {
    fn tell(&self) -> u64 { self.pos as u64 }

    fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
}

impl Decorator<~[u8]> for MemReader {

    fn inner(self) -> ~[u8] {
        match self {
            MemReader { buf: buf, _ } => buf
        }
    }

    fn inner_ref<'a>(&'a self) -> &'a ~[u8] {
        match *self {
            MemReader { buf: ref buf, _ } => buf
        }
    }

    fn inner_mut_ref<'a>(&'a mut self) -> &'a mut ~[u8] {
        match *self {
            MemReader { buf: ref mut buf, _ } => buf
        }
    }
}

/// Writes to a fixed-size byte slice
struct BufWriter<'self> {
    buf: &'self mut [u8],
    pos: uint
}

impl<'self> BufWriter<'self> {
    pub fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> {
        BufWriter {
            buf: buf,
            pos: 0
        }
    }
}

impl<'self> Writer for BufWriter<'self> {
    fn write(&mut self, _buf: &[u8]) { fail!() }

    fn flush(&mut self) { fail!() }
}

impl<'self> Seek for BufWriter<'self> {
    fn tell(&self) -> u64 { fail!() }

    fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
}

/// Reads from a fixed-size byte slice
struct BufReader<'self> {
    buf: &'self [u8],
    pos: uint
}

impl<'self> BufReader<'self> {
    pub fn new<'a>(buf: &'a [u8]) -> BufReader<'a> {
        BufReader {
            buf: buf,
            pos: 0
        }
    }
}

impl<'self> Reader for BufReader<'self> {
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
        { if self.eof() { return None; } }

        let write_len = min(buf.len(), self.buf.len() - self.pos);
        {
            let input = self.buf.slice(self.pos, self.pos + write_len);
            let output = buf.mut_slice(0, write_len);
            assert_eq!(input.len(), output.len());
            vec::bytes::copy_memory(output, input, write_len);
        }
        self.pos += write_len;
        assert!(self.pos <= self.buf.len());

        return Some(write_len);
     }

    fn eof(&mut self) -> bool { self.pos == self.buf.len() }
}

impl<'self> Seek for BufReader<'self> {
    fn tell(&self) -> u64 { self.pos as u64 }

    fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
}

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

    #[test]
    fn test_mem_writer() {
        let mut writer = MemWriter::new();
        assert_eq!(writer.tell(), 0);
        writer.write([0]);
        assert_eq!(writer.tell(), 1);
        writer.write([1, 2, 3]);
        writer.write([4, 5, 6, 7]);
        assert_eq!(writer.tell(), 8);
        assert_eq!(writer.inner(), ~[0, 1, 2, 3, 4, 5 , 6, 7]);
    }

    #[test]
    fn test_mem_reader() {
        let mut reader = MemReader::new(~[0, 1, 2, 3, 4, 5, 6, 7]);
        let mut buf = [];
        assert_eq!(reader.read(buf), Some(0));
        assert_eq!(reader.tell(), 0);
        let mut buf = [0];
        assert_eq!(reader.read(buf), Some(1));
        assert_eq!(reader.tell(), 1);
        assert_eq!(buf, [0]);
        let mut buf = [0, ..4];
        assert_eq!(reader.read(buf), Some(4));
        assert_eq!(reader.tell(), 5);
        assert_eq!(buf, [1, 2, 3, 4]);
        assert_eq!(reader.read(buf), Some(3));
        assert_eq!(buf.slice(0, 3), [5, 6, 7]);
        assert!(reader.eof());
        assert_eq!(reader.read(buf), None);
        assert!(reader.eof());
    }

    #[test]
    fn test_buf_reader() {
        let in_buf = ~[0, 1, 2, 3, 4, 5, 6, 7];
        let mut reader = BufReader::new(in_buf);
        let mut buf = [];
        assert_eq!(reader.read(buf), Some(0));
        assert_eq!(reader.tell(), 0);
        let mut buf = [0];
        assert_eq!(reader.read(buf), Some(1));
        assert_eq!(reader.tell(), 1);
        assert_eq!(buf, [0]);
        let mut buf = [0, ..4];
        assert_eq!(reader.read(buf), Some(4));
        assert_eq!(reader.tell(), 5);
        assert_eq!(buf, [1, 2, 3, 4]);
        assert_eq!(reader.read(buf), Some(3));
        assert_eq!(buf.slice(0, 3), [5, 6, 7]);
        assert!(reader.eof());
        assert_eq!(reader.read(buf), None);
        assert!(reader.eof());
    }
}
<commit_msg>Add with_mem_writer to std::rt::io::mem.<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.

//! Readers and Writers for in-memory buffers
//!
//! # XXX
//!
//! * Should probably have something like this for strings.
//! * Should they implement Closable? Would take extra state.

use cmp::min;
use prelude::*;
use super::*;
use vec;

/// Writes to an owned, growable byte vector
pub struct MemWriter {
    buf: ~[u8]
}

impl MemWriter {
    pub fn new() -> MemWriter { MemWriter { buf: vec::with_capacity(128) } }
}

impl Writer for MemWriter {
    fn write(&mut self, buf: &[u8]) {
        self.buf.push_all(buf)
    }

    fn flush(&mut self) { /* no-op */ }
}

impl Seek for MemWriter {
    fn tell(&self) -> u64 { self.buf.len() as u64 }

    fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
}

impl Decorator<~[u8]> for MemWriter {

    fn inner(self) -> ~[u8] {
        match self {
            MemWriter { buf: buf } => buf
        }
    }

    fn inner_ref<'a>(&'a self) -> &'a ~[u8] {
        match *self {
            MemWriter { buf: ref buf } => buf
        }
    }

    fn inner_mut_ref<'a>(&'a mut self) -> &'a mut ~[u8] {
        match *self {
            MemWriter { buf: ref mut buf } => buf
        }
    }
}

/// Reads from an owned byte vector
pub struct MemReader {
    buf: ~[u8],
    pos: uint
}

impl MemReader {
    pub fn new(buf: ~[u8]) -> MemReader {
        MemReader {
            buf: buf,
            pos: 0
        }
    }
}

impl Reader for MemReader {
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
        { if self.eof() { return None; } }

        let write_len = min(buf.len(), self.buf.len() - self.pos);
        {
            let input = self.buf.slice(self.pos, self.pos + write_len);
            let output = buf.mut_slice(0, write_len);
            assert_eq!(input.len(), output.len());
            vec::bytes::copy_memory(output, input, write_len);
        }
        self.pos += write_len;
        assert!(self.pos <= self.buf.len());

        return Some(write_len);
    }

    fn eof(&mut self) -> bool { self.pos == self.buf.len() }
}

impl Seek for MemReader {
    fn tell(&self) -> u64 { self.pos as u64 }

    fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
}

impl Decorator<~[u8]> for MemReader {

    fn inner(self) -> ~[u8] {
        match self {
            MemReader { buf: buf, _ } => buf
        }
    }

    fn inner_ref<'a>(&'a self) -> &'a ~[u8] {
        match *self {
            MemReader { buf: ref buf, _ } => buf
        }
    }

    fn inner_mut_ref<'a>(&'a mut self) -> &'a mut ~[u8] {
        match *self {
            MemReader { buf: ref mut buf, _ } => buf
        }
    }
}

/// Writes to a fixed-size byte slice
struct BufWriter<'self> {
    buf: &'self mut [u8],
    pos: uint
}

impl<'self> BufWriter<'self> {
    pub fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> {
        BufWriter {
            buf: buf,
            pos: 0
        }
    }
}

impl<'self> Writer for BufWriter<'self> {
    fn write(&mut self, _buf: &[u8]) { fail!() }

    fn flush(&mut self) { fail!() }
}

impl<'self> Seek for BufWriter<'self> {
    fn tell(&self) -> u64 { fail!() }

    fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
}

/// Reads from a fixed-size byte slice
struct BufReader<'self> {
    buf: &'self [u8],
    pos: uint
}

impl<'self> BufReader<'self> {
    pub fn new<'a>(buf: &'a [u8]) -> BufReader<'a> {
        BufReader {
            buf: buf,
            pos: 0
        }
    }
}

impl<'self> Reader for BufReader<'self> {
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
        { if self.eof() { return None; } }

        let write_len = min(buf.len(), self.buf.len() - self.pos);
        {
            let input = self.buf.slice(self.pos, self.pos + write_len);
            let output = buf.mut_slice(0, write_len);
            assert_eq!(input.len(), output.len());
            vec::bytes::copy_memory(output, input, write_len);
        }
        self.pos += write_len;
        assert!(self.pos <= self.buf.len());

        return Some(write_len);
     }

    fn eof(&mut self) -> bool { self.pos == self.buf.len() }
}

impl<'self> Seek for BufReader<'self> {
    fn tell(&self) -> u64 { self.pos as u64 }

    fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
}

///Calls a function with a MemWriter and returns
///the writer's stored vector.
pub fn with_mem_writer(writeFn:&fn(&mut MemWriter)) -> ~[u8] {
  let mut writer = MemWriter::new();
  writeFn(&mut writer);
  writer.inner()
}

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

    #[test]
    fn test_mem_writer() {
        let mut writer = MemWriter::new();
        assert_eq!(writer.tell(), 0);
        writer.write([0]);
        assert_eq!(writer.tell(), 1);
        writer.write([1, 2, 3]);
        writer.write([4, 5, 6, 7]);
        assert_eq!(writer.tell(), 8);
        assert_eq!(writer.inner(), ~[0, 1, 2, 3, 4, 5 , 6, 7]);
    }

    #[test]
    fn test_mem_reader() {
        let mut reader = MemReader::new(~[0, 1, 2, 3, 4, 5, 6, 7]);
        let mut buf = [];
        assert_eq!(reader.read(buf), Some(0));
        assert_eq!(reader.tell(), 0);
        let mut buf = [0];
        assert_eq!(reader.read(buf), Some(1));
        assert_eq!(reader.tell(), 1);
        assert_eq!(buf, [0]);
        let mut buf = [0, ..4];
        assert_eq!(reader.read(buf), Some(4));
        assert_eq!(reader.tell(), 5);
        assert_eq!(buf, [1, 2, 3, 4]);
        assert_eq!(reader.read(buf), Some(3));
        assert_eq!(buf.slice(0, 3), [5, 6, 7]);
        assert!(reader.eof());
        assert_eq!(reader.read(buf), None);
        assert!(reader.eof());
    }

    #[test]
    fn test_buf_reader() {
        let in_buf = ~[0, 1, 2, 3, 4, 5, 6, 7];
        let mut reader = BufReader::new(in_buf);
        let mut buf = [];
        assert_eq!(reader.read(buf), Some(0));
        assert_eq!(reader.tell(), 0);
        let mut buf = [0];
        assert_eq!(reader.read(buf), Some(1));
        assert_eq!(reader.tell(), 1);
        assert_eq!(buf, [0]);
        let mut buf = [0, ..4];
        assert_eq!(reader.read(buf), Some(4));
        assert_eq!(reader.tell(), 5);
        assert_eq!(buf, [1, 2, 3, 4]);
        assert_eq!(reader.read(buf), Some(3));
        assert_eq!(buf.slice(0, 3), [5, 6, 7]);
        assert!(reader.eof());
        assert_eq!(reader.read(buf), None);
        assert!(reader.eof());
    }

    #[test]
    fn test_with_mem_writer() {
        let buf = with_mem_writer(|wr| wr.write([1,2,3,4,5,6,7]));
        assert_eq!(buf, ~[1,2,3,4,5,6,7]);
    }
}
<|endoftext|>


<commit_before><commit_msg>e2e_tests: Add vsock tests<commit_after>// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Testing vsock.

pub mod fixture;

use std::process::Command;
use std::process::Stdio;
use std::thread;
use std::time::Duration;

use fixture::Config;
use fixture::TestVm;

const HOST_CID: u64 = 2;
const GUEST_CID: u64 = 5;
const VSOCK_COM_PORT: u64 = 11111;

const SERVER_TIMEOUT_IN_SEC: u64 = 3;
const CLIENT_WAIT_DURATION: Duration = Duration::from_millis(1000);

const MESSAGE_TO_HOST: &str = "Connection from the host is successfully established";
const MESSAGE_TO_GUEST: &str = "Connection from the guest is successfully established";

#[test]
fn host_to_guest_connection() {
    let config = Config::new().extra_args(vec!["--cid".to_string(), GUEST_CID.to_string()]);
    let mut vm = TestVm::new(config).unwrap();

    let handle_guest = thread::spawn(move || {
        let cmd = format!(
            "echo {MESSAGE_TO_HOST} | timeout {SERVER_TIMEOUT_IN_SEC}s ncat -l --vsock {VSOCK_COM_PORT}",
        );
        vm.exec_in_guest(&cmd).unwrap();
    });

    // wait until the server is ready
    thread::sleep(CLIENT_WAIT_DURATION);

    let output = Command::new("ncat")
        .args(["--idle-timeout", "1"])
        .args([
            "--vsock",
            &GUEST_CID.to_string(),
            &VSOCK_COM_PORT.to_string(),
        ])
        .output()
        .expect("failed to execute process");
    let host_stdout = std::str::from_utf8(&output.stdout).unwrap();

    handle_guest.join().unwrap();

    assert_eq!(host_stdout.trim(), MESSAGE_TO_HOST);
}

#[test]
fn guest_to_host_connection() {
    let config = Config::new().extra_args(vec!["--cid".to_string(), GUEST_CID.to_string()]);
    let mut vm = TestVm::new(config).unwrap();

    let echo = Command::new("echo")
        .arg(MESSAGE_TO_GUEST)
        .stdout(Stdio::piped())
        .spawn()
        .unwrap();
    let mut handle_host = Command::new("timeout")
        .arg(format!("{SERVER_TIMEOUT_IN_SEC}s"))
        .arg("ncat")
        .arg("-l")
        .args(["--vsock", &VSOCK_COM_PORT.to_string()])
        .stdin(echo.stdout.unwrap())
        .spawn()
        .expect("failed to execute process");

    // wait until the server is ready
    thread::sleep(CLIENT_WAIT_DURATION);

    let cmd = format!("ncat --idle-timeout 1 --vsock {HOST_CID} {VSOCK_COM_PORT}");
    let guest_stdout = vm.exec_in_guest(&cmd).unwrap();

    handle_host.wait().unwrap();

    assert_eq!(guest_stdout.trim(), MESSAGE_TO_GUEST);
}
<|endoftext|>


<commit_before><commit_msg>implemented history internal command.<commit_after><|endoftext|>


<commit_before><commit_msg>Regression test for #8468.<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.

trait Foo {
    fn m(&self, _:int) { }
}

fn main() { }
<|endoftext|>


<commit_before><commit_msg>Tree structure<commit_after>use tokens::*;

pub struct Tree<'a>
{
	pub root: Node<'a>,
}

pub struct Node<'a>
{
	pub token: Token<'a>,
	pub children: Vec<Node<'a>>
}

impl<'a> Node<'a>
{
	fn has_children(&self) -> bool
	{
		self.children.len() > 0
	}

	fn add_child(&mut self, child: Node<'a>)
	{
		self.children.push(child);
	}

	fn value(&self) -> String
	{
		self.token.value.clone()
	}
}
<|endoftext|>


<commit_before><commit_msg>Make sure #47772 does not regress<commit_after>// Copyright 2017 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.

// no-system-llvm
// compile-flags: -O
#![crate_type = "lib"]

fn search<T: Ord + Eq>(arr: &mut [T], a: &T) -> Result<usize, ()> {
    match arr.iter().position(|x| x == a) {
        Some(p) => {
            Ok(p)
        },
        None => Err(()),
    }
}

// CHECK-LABEL: @position_no_bounds_check
#[no_mangle]
pub fn position_no_bounds_check(y: &mut [u32], x: &u32, z: &u32) -> bool {
    // This contains "call assume" so we cannot just rule out all calls
    // CHECK-NOT: panic
    if let Ok(p) = search(y, x) {
      y[p] == *z
    } else {
      false
    }
}
<|endoftext|>


<commit_before>#![feature(if_let)]

use time::get_time;
use time::Timespec;

use std::sync::Mutex;

use ewma::EWMA;
use metric::Metric;

const WINDOW: [f64, ..3] = [1f64, 5f64, 15f64];

// A MeterSnapshot
pub struct MeterSnapshot {
    count: i64,
    rates: [f64, ..3],
    mean: f64
}

// A StdMeter struct
pub struct StdMeter {
    data: Mutex<MeterSnapshot>,
    ewma: [EWMA, ..3],
    start: Timespec
}

// A Meter trait
pub trait Meter : Metric {
    fn snapshot(&self) -> MeterSnapshot;

    fn mark(&self, n: i64);

    fn tick(&mut self);

    fn rate(&self, rate: f64) -> f64;

    fn mean(&self) -> f64;

    fn count(&self) -> i64;
}

impl Meter for StdMeter {
    fn snapshot(&self) -> MeterSnapshot {
        let s = self.data.lock();

        MeterSnapshot {
            count: s.count,
            rates: s.rates,
            mean: s.mean
        }
    }

    fn mark(&self, n: i64) {
        let mut s = self.data.lock();

        s.count += n;

        for i in range(0, WINDOW.len()) {
            self.ewma[i].update(n as uint);
        }

        self.update_snapshot(*s);
    }

    fn tick(&mut self) {
        let s = self.data.lock();

        for i in range(0, WINDOW.len()) {
            self.ewma[i].tick();
        }

        self.update_snapshot(*s);
    }

    // Return the given EWMA for a rate like 1, 5, 15 minutes
    #[experimental]
    fn rate(&self, rate: f64) -> f64 {
        let s = self.data.lock();

        if let Some(pos) = WINDOW.position_elem(&rate) {
            let r: f64 = s.rates[pos];
            return r;
        }
        0f64
    }

    // Return the mean rate
    fn mean(&self) -> f64 {
        let s = self.data.lock();
        s.mean
    }

    fn count(&self) -> i64 {
        let s = self.data.lock();
        s.count
    }
}

impl Metric for StdMeter {
}

impl StdMeter {
    fn update_snapshot(&self, mut s: MeterSnapshot) {
        for i in range(0, WINDOW.len()) {
            s.rates[i] = self.ewma[i].rate();
        }

        let diff = get_time() - self.start;
        s.mean = s.count as f64 / diff.num_seconds() as f64;
    }

    pub fn new() -> StdMeter {
        let data: MeterSnapshot = MeterSnapshot{
            count: 0i64,
            rates: [0f64, 0f64, 0f64],
            mean: 0f64
        };

        let ewma: [EWMA, ..3] = [EWMA::new(1f64), EWMA::new(5f64), EWMA::new(15f64)];

        StdMeter {
            data: Mutex::new(data),
            ewma: ewma,
            start: get_time()
        }
    }

}

#[cfg(test)]
mod test {
    use meter::{Meter,MeterSnapshot,StdMeter};

    #[test]
    fn zero() {
        let m: StdMeter = StdMeter::new();
        let s: MeterSnapshot = m.snapshot();
        assert_eq!(s.count, 0);
    }

    #[test]
    fn non_zero() {
        let m: StdMeter = StdMeter::new();
        m.mark(3);
        let s: MeterSnapshot = m.snapshot();
        assert_eq!(s.count, 3);
    }

    #[test]
    fn snapshot() {
        let m: StdMeter = StdMeter::new();
        m.mark(1);
        m.mark(1);

        let s = m.snapshot();

        m.mark(1);

        assert_eq!(s.count, 2);
        assert_eq!(m.snapshot().count, 3);
    }

    // Test that decay works correctly
    #[test]
    fn decay() {
        let mut m: StdMeter = StdMeter::new();

        m.tick();
    }
}
<commit_msg>remove if-let warning<commit_after>use time::get_time;
use time::Timespec;

use std::sync::Mutex;

use ewma::EWMA;
use metric::Metric;

const WINDOW: [f64, ..3] = [1f64, 5f64, 15f64];

// A MeterSnapshot
pub struct MeterSnapshot {
    count: i64,
    rates: [f64, ..3],
    mean: f64
}

// A StdMeter struct
pub struct StdMeter {
    data: Mutex<MeterSnapshot>,
    ewma: [EWMA, ..3],
    start: Timespec
}

// A Meter trait
pub trait Meter : Metric {
    fn snapshot(&self) -> MeterSnapshot;

    fn mark(&self, n: i64);

    fn tick(&mut self);

    fn rate(&self, rate: f64) -> f64;

    fn mean(&self) -> f64;

    fn count(&self) -> i64;
}

impl Meter for StdMeter {
    fn snapshot(&self) -> MeterSnapshot {
        let s = self.data.lock();

        MeterSnapshot {
            count: s.count,
            rates: s.rates,
            mean: s.mean
        }
    }

    fn mark(&self, n: i64) {
        let mut s = self.data.lock();

        s.count += n;

        for i in range(0, WINDOW.len()) {
            self.ewma[i].update(n as uint);
        }

        self.update_snapshot(*s);
    }

    fn tick(&mut self) {
        let s = self.data.lock();

        for i in range(0, WINDOW.len()) {
            self.ewma[i].tick();
        }

        self.update_snapshot(*s);
    }

    // Return the given EWMA for a rate like 1, 5, 15 minutes
    #[experimental]
    fn rate(&self, rate: f64) -> f64 {
        let s = self.data.lock();

        if let Some(pos) = WINDOW.position_elem(&rate) {
            let r: f64 = s.rates[pos];
            return r;
        }
        0f64
    }

    // Return the mean rate
    fn mean(&self) -> f64 {
        let s = self.data.lock();
        s.mean
    }

    fn count(&self) -> i64 {
        let s = self.data.lock();
        s.count
    }
}

impl Metric for StdMeter {
}

impl StdMeter {
    fn update_snapshot(&self, mut s: MeterSnapshot) {
        for i in range(0, WINDOW.len()) {
            s.rates[i] = self.ewma[i].rate();
        }

        let diff = get_time() - self.start;
        s.mean = s.count as f64 / diff.num_seconds() as f64;
    }

    pub fn new() -> StdMeter {
        let data: MeterSnapshot = MeterSnapshot{
            count: 0i64,
            rates: [0f64, 0f64, 0f64],
            mean: 0f64
        };

        let ewma: [EWMA, ..3] = [EWMA::new(1f64), EWMA::new(5f64), EWMA::new(15f64)];

        StdMeter {
            data: Mutex::new(data),
            ewma: ewma,
            start: get_time()
        }
    }

}

#[cfg(test)]
mod test {
    use meter::{Meter,MeterSnapshot,StdMeter};

    #[test]
    fn zero() {
        let m: StdMeter = StdMeter::new();
        let s: MeterSnapshot = m.snapshot();
        assert_eq!(s.count, 0);
    }

    #[test]
    fn non_zero() {
        let m: StdMeter = StdMeter::new();
        m.mark(3);
        let s: MeterSnapshot = m.snapshot();
        assert_eq!(s.count, 3);
    }

    #[test]
    fn snapshot() {
        let m: StdMeter = StdMeter::new();
        m.mark(1);
        m.mark(1);

        let s = m.snapshot();

        m.mark(1);

        assert_eq!(s.count, 2);
        assert_eq!(m.snapshot().count, 3);
    }

    // Test that decay works correctly
    #[test]
    fn decay() {
        let mut m: StdMeter = StdMeter::new();

        m.tick();
    }
}
<|endoftext|>


<commit_before><commit_msg>add msgsend.rs to benchmarks<commit_after>// A port of the simplistic benchmark from
//
//    http://github.com/PaulKeeble/ScalaVErlangAgents
//
// I *think* it's the same, more or less.

use std;
import std::io::writer;
import std::io::writer_util;

enum request {
    get_count,
    bytes(uint),
    stop
}

fn server(requests: comm::port<request>, responses: comm::chan<uint>) {
    let count = 0u;
    let done = false;
    while !done {
        alt comm::recv(requests) {
          get_count { comm::send(responses, copy count); }
          bytes(b) { count += b; }
          stop { done = true; }
        }
    }
    comm::send(responses, count);
}

fn run(args: [str]) {
    let server = task::spawn_connected(server);
    let size = uint::from_str(args[1]);
    let workers = uint::from_str(args[2]);
    let start = std::time::precise_time_s();
    let to_child = server.to_child;
    let worker_tasks = [];
    uint::range(0u, workers) {|_i|
        worker_tasks += [task::spawn_joinable {||
            uint::range(0u, size / workers) {|_i|
                comm::send(to_child, bytes(100u));
            }
        }];
    }
    vec::iter(worker_tasks) {|t| task::join(t); }
    comm::send(server.to_child, stop);
    let result = comm::recv(server.from_child);
    let end = std::time::precise_time_s();
    let elapsed = end - start;
    std::io::stdout().write_str(#fmt("Count is %?\n", result));
    std::io::stdout().write_str(#fmt("Test took %? seconds\n", elapsed));
    let thruput = (size / workers * workers as float) / (elapsed as float);
    std::io::stdout().write_str(#fmt("Throughput=%f per sec\n", thruput));
}

fn main(args: [str]) {
    let args1 = if vec::len(args) <= 1u { ["", "10000", "4"] } else { args };
    #debug("%?", args1);
    run(args1);
}

<|endoftext|>


<commit_before><commit_msg>Move reopen check to flush.<commit_after><|endoftext|>


<commit_before><commit_msg>First example: hell world.<commit_after>fn main() {
    println!("Hello, world!")
}
<|endoftext|>


<commit_before>// Copyright 2013-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.

#![allow(missing_docs)]

pub use self::ExponentFormat::*;
pub use self::SignificantDigits::*;
pub use self::SignFormat::*;

use char;
use char::Char;
use fmt;
use iter::{range, DoubleEndedIteratorExt};
use num::{Float, FPNaN, FPInfinite, ToPrimitive};
use num::cast;
use result::Result::Ok;
use slice::{mod, SlicePrelude};
use str::StrPrelude;

/// A flag that specifies whether to use exponential (scientific) notation.
pub enum ExponentFormat {
    /// Do not use exponential notation.
    ExpNone,
    /// Use exponential notation with the exponent having a base of 10 and the
    /// exponent sign being `e` or `E`. For example, 1000 would be printed
    /// 1e3.
    ExpDec
}

/// The number of digits used for emitting the fractional part of a number, if
/// any.
pub enum SignificantDigits {
    /// At most the given number of digits will be printed, truncating any
    /// trailing zeroes.
    DigMax(uint),

    /// Precisely the given number of digits will be printed.
    DigExact(uint)
}

/// How to emit the sign of a number.
pub enum SignFormat {
    /// `-` will be printed for negative values, but no sign will be emitted
    /// for positive numbers.
    SignNeg
}

static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u;

/// Converts a number to its string representation as a byte vector.
/// This is meant to be a common base implementation for all numeric string
/// conversion functions like `to_string()` or `to_str_radix()`.
///
/// # Arguments
///
/// - `num`           - The number to convert. Accepts any number that
///                     implements the numeric traits.
/// - `radix`         - Base to use. Accepts only the values 2-36. If the exponential notation
///                     is used, then this base is only used for the significand. The exponent
///                     itself always printed using a base of 10.
/// - `negative_zero` - Whether to treat the special value `-0` as
///                     `-0` or as `+0`.
/// - `sign`          - How to emit the sign. See `SignFormat`.
/// - `digits`        - The amount of digits to use for emitting the fractional
///                     part, if any. See `SignificantDigits`.
/// - `exp_format`   - Whether or not to use the exponential (scientific) notation.
///                    See `ExponentFormat`.
/// - `exp_capital`   - Whether or not to use a capital letter for the exponent sign, if
///                     exponential notation is desired.
/// - `f`             - A closure to invoke with the bytes representing the
///                     float.
///
/// # Panics
///
/// - Panics if `radix` < 2 or `radix` > 36.
/// - Panics if `radix` > 14 and `exp_format` is `ExpDec` due to conflict
///   between digit and exponent sign `'e'`.
/// - Panics if `radix` > 25 and `exp_format` is `ExpBin` due to conflict
///   between digit and exponent sign `'p'`.
pub fn float_to_str_bytes_common<T: Float, U>(
    num: T,
    radix: uint,
    negative_zero: bool,
    sign: SignFormat,
    digits: SignificantDigits,
    exp_format: ExponentFormat,
    exp_upper: bool,
    f: |&[u8]| -> U
) -> U {
    assert!(2 <= radix && radix <= 36);
    match exp_format {
        ExpDec if radix >= DIGIT_E_RADIX       // decimal exponent 'e'
          => panic!("float_to_str_bytes_common: radix {} incompatible with \
                    use of 'e' as decimal exponent", radix),
        _ => ()
    }

    let _0: T = Float::zero();
    let _1: T = Float::one();

    match num.classify() {
        FPNaN => return f("NaN".as_bytes()),
        FPInfinite if num > _0 => {
            return f("inf".as_bytes());
        }
        FPInfinite if num < _0 => {
            return f("-inf".as_bytes());
        }
        _ => {}
    }

    let neg = num < _0 || (negative_zero && _1 / num == Float::neg_infinity());
    // For an f64 the exponent is in the range of [-1022, 1023] for base 2, so
    // we may have up to that many digits. Give ourselves some extra wiggle room
    // otherwise as well.
    let mut buf = [0u8, ..1536];
    let mut end = 0;
    let radix_gen: T = cast(radix as int).unwrap();

    let (num, exp) = match exp_format {
        ExpNone => (num, 0i32),
        ExpDec if num == _0 => (num, 0i32),
        ExpDec => {
            let (exp, exp_base) = match exp_format {
                ExpDec => (num.abs().log10().floor(), cast::<f64, T>(10.0f64).unwrap()),
                ExpNone => panic!("unreachable"),
            };

            (num / exp_base.powf(exp), cast::<T, i32>(exp).unwrap())
        }
    };

    // First emit the non-fractional part, looping at least once to make
    // sure at least a `0` gets emitted.
    let mut deccum = num.trunc();
    loop {
        // Calculate the absolute value of each digit instead of only
        // doing it once for the whole number because a
        // representable negative number doesn't necessary have an
        // representable additive inverse of the same type
        // (See twos complement). But we assume that for the
        // numbers [-35 .. 0] we always have [0 .. 35].
        let current_digit = (deccum % radix_gen).abs();

        // Decrease the deccumulator one digit at a time
        deccum = deccum / radix_gen;
        deccum = deccum.trunc();

        let c = char::from_digit(current_digit.to_int().unwrap() as uint, radix);
        buf[end] = c.unwrap() as u8;
        end += 1;

        // No more digits to calculate for the non-fractional part -> break
        if deccum == _0 { break; }
    }

    // If limited digits, calculate one digit more for rounding.
    let (limit_digits, digit_count, exact) = match digits {
        DigMax(count)   => (true, count + 1, false),
        DigExact(count) => (true, count + 1, true)
    };

    // Decide what sign to put in front
    match sign {
        SignNeg if neg => {
            buf[end] = b'-';
            end += 1;
        }
        _ => ()
    }

    buf[mut ..end].reverse();

    // Remember start of the fractional digits.
    // Points one beyond end of buf if none get generated,
    // or at the '.' otherwise.
    let start_fractional_digits = end;

    // Now emit the fractional part, if any
    deccum = num.fract();
    if deccum != _0 || (limit_digits && exact && digit_count > 0) {
        buf[end] = b'.';
        end += 1;
        let mut dig = 0u;

        // calculate new digits while
        // - there is no limit and there are digits left
        // - or there is a limit, it's not reached yet and
        //   - it's exact
        //   - or it's a maximum, and there are still digits left
        while (!limit_digits && deccum != _0)
           || (limit_digits && dig < digit_count && (
                   exact
                || (!exact && deccum != _0)
              )
        ) {
            // Shift first fractional digit into the integer part
            deccum = deccum * radix_gen;

            // Calculate the absolute value of each digit.
            // See note in first loop.
            let current_digit = deccum.trunc().abs();

            let c = char::from_digit(current_digit.to_int().unwrap() as uint,
                                     radix);
            buf[end] = c.unwrap() as u8;
            end += 1;

            // Decrease the deccumulator one fractional digit at a time
            deccum = deccum.fract();
            dig += 1u;
        }

        // If digits are limited, and that limit has been reached,
        // cut off the one extra digit, and depending on its value
        // round the remaining ones.
        if limit_digits && dig == digit_count {
            let ascii2value = |chr: u8| {
                (chr as char).to_digit(radix).unwrap()
            };
            let value2ascii = |val: uint| {
                char::from_digit(val, radix).unwrap() as u8
            };

            let extra_digit = ascii2value(buf[end - 1]);
            end -= 1;
            if extra_digit >= radix / 2 { // -> need to round
                let mut i: int = end as int - 1;
                loop {
                    // If reached left end of number, have to
                    // insert additional digit:
                    if i < 0
                    || buf[i as uint] == b'-'
                    || buf[i as uint] == b'+' {
                        for j in range(i as uint + 1, end).rev() {
                            buf[j + 1] = buf[j];
                        }
                        buf[(i + 1) as uint] = value2ascii(1);
                        end += 1;
                        break;
                    }

                    // Skip the '.'
                    if buf[i as uint] == b'.' { i -= 1; continue; }

                    // Either increment the digit,
                    // or set to 0 if max and carry the 1.
                    let current_digit = ascii2value(buf[i as uint]);
                    if current_digit < (radix - 1) {
                        buf[i as uint] = value2ascii(current_digit+1);
                        break;
                    } else {
                        buf[i as uint] = value2ascii(0);
                        i -= 1;
                    }
                }
            }
        }
    }

    // if number of digits is not exact, remove all trailing '0's up to
    // and including the '.'
    if !exact {
        let buf_max_i = end - 1;

        // index to truncate from
        let mut i = buf_max_i;

        // discover trailing zeros of fractional part
        while i > start_fractional_digits && buf[i] == b'0' {
            i -= 1;
        }

        // Only attempt to truncate digits if buf has fractional digits
        if i >= start_fractional_digits {
            // If buf ends with '.', cut that too.
            if buf[i] == b'.' { i -= 1 }

            // only resize buf if we actually remove digits
            if i < buf_max_i {
                end = i + 1;
            }
        }
    } // If exact and trailing '.', just cut that
    else {
        let max_i = end - 1;
        if buf[max_i] == b'.' {
            end = max_i;
        }
    }

    match exp_format {
        ExpNone => {},
        _ => {
            buf[end] = match exp_format {
                ExpDec if exp_upper => 'E',
                ExpDec if !exp_upper => 'e',
                _ => panic!("unreachable"),
            } as u8;
            end += 1;

            struct Filler<'a> {
                buf: &'a mut [u8],
                end: &'a mut uint,
            }

            impl<'a> fmt::FormatWriter for Filler<'a> {
                fn write(&mut self, bytes: &[u8]) -> fmt::Result {
                    slice::bytes::copy_memory(self.buf[mut *self.end..],
                                              bytes);
                    *self.end += bytes.len();
                    Ok(())
                }
            }

            let mut filler = Filler { buf: &mut buf, end: &mut end };
            match sign {
                SignNeg => {
                    let _ = format_args!(|args| {
                        fmt::write(&mut filler, args)
                    }, "{:-}", exp);
                }
            }
        }
    }

    f(buf[..end])
}
<commit_msg>libcore: use unboxed closures in `float_to_str_bytes_common`<commit_after>// Copyright 2013-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.

#![allow(missing_docs)]

pub use self::ExponentFormat::*;
pub use self::SignificantDigits::*;
pub use self::SignFormat::*;

use char;
use char::Char;
use fmt;
use iter::{range, DoubleEndedIteratorExt};
use num::{Float, FPNaN, FPInfinite, ToPrimitive};
use num::cast;
use ops::FnOnce;
use result::Result::Ok;
use slice::{mod, SlicePrelude};
use str::StrPrelude;

/// A flag that specifies whether to use exponential (scientific) notation.
pub enum ExponentFormat {
    /// Do not use exponential notation.
    ExpNone,
    /// Use exponential notation with the exponent having a base of 10 and the
    /// exponent sign being `e` or `E`. For example, 1000 would be printed
    /// 1e3.
    ExpDec
}

/// The number of digits used for emitting the fractional part of a number, if
/// any.
pub enum SignificantDigits {
    /// At most the given number of digits will be printed, truncating any
    /// trailing zeroes.
    DigMax(uint),

    /// Precisely the given number of digits will be printed.
    DigExact(uint)
}

/// How to emit the sign of a number.
pub enum SignFormat {
    /// `-` will be printed for negative values, but no sign will be emitted
    /// for positive numbers.
    SignNeg
}

static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u;

/// Converts a number to its string representation as a byte vector.
/// This is meant to be a common base implementation for all numeric string
/// conversion functions like `to_string()` or `to_str_radix()`.
///
/// # Arguments
///
/// - `num`           - The number to convert. Accepts any number that
///                     implements the numeric traits.
/// - `radix`         - Base to use. Accepts only the values 2-36. If the exponential notation
///                     is used, then this base is only used for the significand. The exponent
///                     itself always printed using a base of 10.
/// - `negative_zero` - Whether to treat the special value `-0` as
///                     `-0` or as `+0`.
/// - `sign`          - How to emit the sign. See `SignFormat`.
/// - `digits`        - The amount of digits to use for emitting the fractional
///                     part, if any. See `SignificantDigits`.
/// - `exp_format`   - Whether or not to use the exponential (scientific) notation.
///                    See `ExponentFormat`.
/// - `exp_capital`   - Whether or not to use a capital letter for the exponent sign, if
///                     exponential notation is desired.
/// - `f`             - A closure to invoke with the bytes representing the
///                     float.
///
/// # Panics
///
/// - Panics if `radix` < 2 or `radix` > 36.
/// - Panics if `radix` > 14 and `exp_format` is `ExpDec` due to conflict
///   between digit and exponent sign `'e'`.
/// - Panics if `radix` > 25 and `exp_format` is `ExpBin` due to conflict
///   between digit and exponent sign `'p'`.
pub fn float_to_str_bytes_common<T: Float, U, F>(
    num: T,
    radix: uint,
    negative_zero: bool,
    sign: SignFormat,
    digits: SignificantDigits,
    exp_format: ExponentFormat,
    exp_upper: bool,
    f: F
) -> U where
    F: FnOnce(&[u8]) -> U,
{
    assert!(2 <= radix && radix <= 36);
    match exp_format {
        ExpDec if radix >= DIGIT_E_RADIX       // decimal exponent 'e'
          => panic!("float_to_str_bytes_common: radix {} incompatible with \
                    use of 'e' as decimal exponent", radix),
        _ => ()
    }

    let _0: T = Float::zero();
    let _1: T = Float::one();

    match num.classify() {
        FPNaN => return f("NaN".as_bytes()),
        FPInfinite if num > _0 => {
            return f("inf".as_bytes());
        }
        FPInfinite if num < _0 => {
            return f("-inf".as_bytes());
        }
        _ => {}
    }

    let neg = num < _0 || (negative_zero && _1 / num == Float::neg_infinity());
    // For an f64 the exponent is in the range of [-1022, 1023] for base 2, so
    // we may have up to that many digits. Give ourselves some extra wiggle room
    // otherwise as well.
    let mut buf = [0u8, ..1536];
    let mut end = 0;
    let radix_gen: T = cast(radix as int).unwrap();

    let (num, exp) = match exp_format {
        ExpNone => (num, 0i32),
        ExpDec if num == _0 => (num, 0i32),
        ExpDec => {
            let (exp, exp_base) = match exp_format {
                ExpDec => (num.abs().log10().floor(), cast::<f64, T>(10.0f64).unwrap()),
                ExpNone => panic!("unreachable"),
            };

            (num / exp_base.powf(exp), cast::<T, i32>(exp).unwrap())
        }
    };

    // First emit the non-fractional part, looping at least once to make
    // sure at least a `0` gets emitted.
    let mut deccum = num.trunc();
    loop {
        // Calculate the absolute value of each digit instead of only
        // doing it once for the whole number because a
        // representable negative number doesn't necessary have an
        // representable additive inverse of the same type
        // (See twos complement). But we assume that for the
        // numbers [-35 .. 0] we always have [0 .. 35].
        let current_digit = (deccum % radix_gen).abs();

        // Decrease the deccumulator one digit at a time
        deccum = deccum / radix_gen;
        deccum = deccum.trunc();

        let c = char::from_digit(current_digit.to_int().unwrap() as uint, radix);
        buf[end] = c.unwrap() as u8;
        end += 1;

        // No more digits to calculate for the non-fractional part -> break
        if deccum == _0 { break; }
    }

    // If limited digits, calculate one digit more for rounding.
    let (limit_digits, digit_count, exact) = match digits {
        DigMax(count)   => (true, count + 1, false),
        DigExact(count) => (true, count + 1, true)
    };

    // Decide what sign to put in front
    match sign {
        SignNeg if neg => {
            buf[end] = b'-';
            end += 1;
        }
        _ => ()
    }

    buf[mut ..end].reverse();

    // Remember start of the fractional digits.
    // Points one beyond end of buf if none get generated,
    // or at the '.' otherwise.
    let start_fractional_digits = end;

    // Now emit the fractional part, if any
    deccum = num.fract();
    if deccum != _0 || (limit_digits && exact && digit_count > 0) {
        buf[end] = b'.';
        end += 1;
        let mut dig = 0u;

        // calculate new digits while
        // - there is no limit and there are digits left
        // - or there is a limit, it's not reached yet and
        //   - it's exact
        //   - or it's a maximum, and there are still digits left
        while (!limit_digits && deccum != _0)
           || (limit_digits && dig < digit_count && (
                   exact
                || (!exact && deccum != _0)
              )
        ) {
            // Shift first fractional digit into the integer part
            deccum = deccum * radix_gen;

            // Calculate the absolute value of each digit.
            // See note in first loop.
            let current_digit = deccum.trunc().abs();

            let c = char::from_digit(current_digit.to_int().unwrap() as uint,
                                     radix);
            buf[end] = c.unwrap() as u8;
            end += 1;

            // Decrease the deccumulator one fractional digit at a time
            deccum = deccum.fract();
            dig += 1u;
        }

        // If digits are limited, and that limit has been reached,
        // cut off the one extra digit, and depending on its value
        // round the remaining ones.
        if limit_digits && dig == digit_count {
            let ascii2value = |chr: u8| {
                (chr as char).to_digit(radix).unwrap()
            };
            let value2ascii = |val: uint| {
                char::from_digit(val, radix).unwrap() as u8
            };

            let extra_digit = ascii2value(buf[end - 1]);
            end -= 1;
            if extra_digit >= radix / 2 { // -> need to round
                let mut i: int = end as int - 1;
                loop {
                    // If reached left end of number, have to
                    // insert additional digit:
                    if i < 0
                    || buf[i as uint] == b'-'
                    || buf[i as uint] == b'+' {
                        for j in range(i as uint + 1, end).rev() {
                            buf[j + 1] = buf[j];
                        }
                        buf[(i + 1) as uint] = value2ascii(1);
                        end += 1;
                        break;
                    }

                    // Skip the '.'
                    if buf[i as uint] == b'.' { i -= 1; continue; }

                    // Either increment the digit,
                    // or set to 0 if max and carry the 1.
                    let current_digit = ascii2value(buf[i as uint]);
                    if current_digit < (radix - 1) {
                        buf[i as uint] = value2ascii(current_digit+1);
                        break;
                    } else {
                        buf[i as uint] = value2ascii(0);
                        i -= 1;
                    }
                }
            }
        }
    }

    // if number of digits is not exact, remove all trailing '0's up to
    // and including the '.'
    if !exact {
        let buf_max_i = end - 1;

        // index to truncate from
        let mut i = buf_max_i;

        // discover trailing zeros of fractional part
        while i > start_fractional_digits && buf[i] == b'0' {
            i -= 1;
        }

        // Only attempt to truncate digits if buf has fractional digits
        if i >= start_fractional_digits {
            // If buf ends with '.', cut that too.
            if buf[i] == b'.' { i -= 1 }

            // only resize buf if we actually remove digits
            if i < buf_max_i {
                end = i + 1;
            }
        }
    } // If exact and trailing '.', just cut that
    else {
        let max_i = end - 1;
        if buf[max_i] == b'.' {
            end = max_i;
        }
    }

    match exp_format {
        ExpNone => {},
        _ => {
            buf[end] = match exp_format {
                ExpDec if exp_upper => 'E',
                ExpDec if !exp_upper => 'e',
                _ => panic!("unreachable"),
            } as u8;
            end += 1;

            struct Filler<'a> {
                buf: &'a mut [u8],
                end: &'a mut uint,
            }

            impl<'a> fmt::FormatWriter for Filler<'a> {
                fn write(&mut self, bytes: &[u8]) -> fmt::Result {
                    slice::bytes::copy_memory(self.buf[mut *self.end..],
                                              bytes);
                    *self.end += bytes.len();
                    Ok(())
                }
            }

            let mut filler = Filler { buf: &mut buf, end: &mut end };
            match sign {
                SignNeg => {
                    let _ = format_args!(|args| {
                        fmt::write(&mut filler, args)
                    }, "{:-}", exp);
                }
            }
        }
    }

    f(buf[..end])
}
<|endoftext|>


<commit_before>/*
Module: generic_os

Some miscellaneous platform functions.

These should be rolled into another module.
*/

import core::option;

// Wow, this is an ugly way to write doc comments

#[cfg(bogus)]
#[doc = "Get the value of an environment variable"]
fn getenv(n: str) -> option<str> { }

#[cfg(bogus)]
#[doc = "Set the value of an environment variable"]
fn setenv(n: str, v: str) { }

fn env() -> [(str,str)] {
    let pairs = [];
    for p in os::rustrt::rust_env_pairs() {
        let vs = str::split(p, '=' as u8);
        assert vec::len(vs) == 2u;
        pairs += [(vs[0], vs[1])];
    }
    ret pairs;
}

#[cfg(target_os = "linux")]
#[cfg(target_os = "macos")]
#[cfg(target_os = "freebsd")]
fn getenv(n: str) -> option<str> unsafe {
    let s = str::as_buf(n, {|buf| os::libc::getenv(buf) });
    ret if unsafe::reinterpret_cast(s) == 0 {
            option::none::<str>
        } else {
            let s = unsafe::reinterpret_cast(s);
            option::some::<str>(str::from_cstr(s))
        };
}

#[cfg(target_os = "linux")]
#[cfg(target_os = "macos")]
#[cfg(target_os = "freebsd")]
fn setenv(n: str, v: str) {
    // FIXME (868)
    str::as_buf(
        n,
        // FIXME (868)
        {|nbuf|
            str::as_buf(
                v,
                {|vbuf|
                    os::libc::setenv(nbuf, vbuf, 1i32)})});
}

#[cfg(target_os = "win32")]
fn getenv(n: str) -> option<str> {
    let nsize = 256u;
    while true {
        let v: [u8] = [];
        vec::reserve(v, nsize);
        let res =
            str::as_buf(n,
                        {|nbuf|
                            unsafe {
                            let vbuf = vec::to_ptr(v);
                            os::kernel32::GetEnvironmentVariableA(nbuf, vbuf,
                                                                  nsize)
                        }
                        });
        if res == 0u {
            ret option::none;
        } else if res < nsize {
            unsafe {
                vec::unsafe::set_len(v, res);
            }
            ret option::some(str::from_bytes(v)); // UTF-8 or fail
        } else { nsize = res; }
    }
    fail;
}

#[cfg(target_os = "win32")]
fn setenv(n: str, v: str) {
    // FIXME (868)
    let _: () =
        str::as_buf(n, {|nbuf|
            let _: () =
                str::as_buf(v, {|vbuf|
                    os::kernel32::SetEnvironmentVariableA(nbuf, vbuf);
                });
        });
}

#[cfg(test)]
mod tests {

    #[test]
    #[ignore(reason = "fails periodically on mac")]
    fn test_setenv() {
        // NB: Each test of setenv needs to use different variable names or
        // the tests will not be threadsafe
        setenv("NAME1", "VALUE");
        assert (getenv("NAME1") == option::some("VALUE"));
    }

    #[test]
    #[ignore(reason = "fails periodically on mac")]
    fn test_setenv_overwrite() {
        setenv("NAME2", "1");
        setenv("NAME2", "2");
        assert (getenv("NAME2") == option::some("2"));
    }

    // Windows GetEnvironmentVariable requires some extra work to make sure
    // the buffer the variable is copied into is the right size
    #[test]
    #[ignore(reason = "fails periodically on mac")]
    fn test_getenv_big() {
        let s = "";
        let i = 0;
        while i < 100 { s += "aaaaaaaaaa"; i += 1; }
        setenv("test_getenv_big", s);
        log(debug, s);
        assert (getenv("test_getenv_big") == option::some(s));
    }

    #[test]
    fn test_get_exe_path() {
        let path = os::get_exe_path();
        assert option::is_some(path);
        let path = option::get(path);
        log(debug, path);

        // Hard to test this function
        if os::target_os() != "win32" {
            assert str::starts_with(path, fs::path_sep());
        } else {
            assert path[1] == ':' as u8;
        }
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>std: Use correct split function in generic_os::env<commit_after>/*
Module: generic_os

Some miscellaneous platform functions.

These should be rolled into another module.
*/

import core::option;

// Wow, this is an ugly way to write doc comments

#[cfg(bogus)]
#[doc = "Get the value of an environment variable"]
fn getenv(n: str) -> option<str> { }

#[cfg(bogus)]
#[doc = "Set the value of an environment variable"]
fn setenv(n: str, v: str) { }

fn env() -> [(str,str)] {
    let pairs = [];
    for p in os::rustrt::rust_env_pairs() {
        let vs = str::split_char(p, '=');
        assert vec::len(vs) == 2u;
        pairs += [(vs[0], vs[1])];
    }
    ret pairs;
}

#[cfg(target_os = "linux")]
#[cfg(target_os = "macos")]
#[cfg(target_os = "freebsd")]
fn getenv(n: str) -> option<str> unsafe {
    let s = str::as_buf(n, {|buf| os::libc::getenv(buf) });
    ret if unsafe::reinterpret_cast(s) == 0 {
            option::none::<str>
        } else {
            let s = unsafe::reinterpret_cast(s);
            option::some::<str>(str::from_cstr(s))
        };
}

#[cfg(target_os = "linux")]
#[cfg(target_os = "macos")]
#[cfg(target_os = "freebsd")]
fn setenv(n: str, v: str) {
    // FIXME (868)
    str::as_buf(
        n,
        // FIXME (868)
        {|nbuf|
            str::as_buf(
                v,
                {|vbuf|
                    os::libc::setenv(nbuf, vbuf, 1i32)})});
}

#[cfg(target_os = "win32")]
fn getenv(n: str) -> option<str> {
    let nsize = 256u;
    while true {
        let v: [u8] = [];
        vec::reserve(v, nsize);
        let res =
            str::as_buf(n,
                        {|nbuf|
                            unsafe {
                            let vbuf = vec::to_ptr(v);
                            os::kernel32::GetEnvironmentVariableA(nbuf, vbuf,
                                                                  nsize)
                        }
                        });
        if res == 0u {
            ret option::none;
        } else if res < nsize {
            unsafe {
                vec::unsafe::set_len(v, res);
            }
            ret option::some(str::from_bytes(v)); // UTF-8 or fail
        } else { nsize = res; }
    }
    fail;
}

#[cfg(target_os = "win32")]
fn setenv(n: str, v: str) {
    // FIXME (868)
    let _: () =
        str::as_buf(n, {|nbuf|
            let _: () =
                str::as_buf(v, {|vbuf|
                    os::kernel32::SetEnvironmentVariableA(nbuf, vbuf);
                });
        });
}

#[cfg(test)]
mod tests {

    #[test]
    #[ignore(reason = "fails periodically on mac")]
    fn test_setenv() {
        // NB: Each test of setenv needs to use different variable names or
        // the tests will not be threadsafe
        setenv("NAME1", "VALUE");
        assert (getenv("NAME1") == option::some("VALUE"));
    }

    #[test]
    #[ignore(reason = "fails periodically on mac")]
    fn test_setenv_overwrite() {
        setenv("NAME2", "1");
        setenv("NAME2", "2");
        assert (getenv("NAME2") == option::some("2"));
    }

    // Windows GetEnvironmentVariable requires some extra work to make sure
    // the buffer the variable is copied into is the right size
    #[test]
    #[ignore(reason = "fails periodically on mac")]
    fn test_getenv_big() {
        let s = "";
        let i = 0;
        while i < 100 { s += "aaaaaaaaaa"; i += 1; }
        setenv("test_getenv_big", s);
        log(debug, s);
        assert (getenv("test_getenv_big") == option::some(s));
    }

    #[test]
    fn test_get_exe_path() {
        let path = os::get_exe_path();
        assert option::is_some(path);
        let path = option::get(path);
        log(debug, path);

        // Hard to test this function
        if os::target_os() != "win32" {
            assert str::starts_with(path, fs::path_sep());
        } else {
            assert path[1] == ':' as u8;
        }
    }
}

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