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

#[allow(deprecated_mode)];

use json;
use sha1;
use serialize::{Encoder, Encodable, Decoder, Decodable};
use sort;

use core::cell::Cell;
use core::cmp;
use core::either::{Either, Left, Right};
use core::io;
use core::comm::{oneshot, PortOne, send_one};
use core::pipes::recv;
use core::prelude::*;
use core::result;
use core::run;
use core::hashmap::HashMap;
use core::task;
use core::to_bytes;

/**
*
* This is a loose clone of the fbuild build system, made a touch more
* generic (not wired to special cases on files) and much less metaprogram-y
* due to rust's comparative weakness there, relative to python.
*
* It's based around _imperative bulids_ that happen to have some function
* calls cached. That is, it's _just_ a mechanism for describing cached
* functions. This makes it much simpler and smaller than a "build system"
* that produces an IR and evaluates it. The evaluation order is normal
* function calls. Some of them just return really quickly.
*
* A cached function consumes and produces a set of _works_. A work has a
* name, a kind (that determines how the value is to be checked for
* freshness) and a value. Works must also be (de)serializable. Some
* examples of works:
*
*    kind   name    value
*   ------------------------
*    cfg    os      linux
*    file   foo.c   <sha1>
*    url    foo.com <etag>
*
* Works are conceptually single units, but we store them most of the time
* in maps of the form (type,name) => value. These are WorkMaps.
*
* A cached function divides the works it's interested up into inputs and
* outputs, and subdivides those into declared (input) works and
* discovered (input and output) works.
*
* A _declared_ input or is one that is given to the workcache before
* any work actually happens, in the "prep" phase. Even when a function's
* work-doing part (the "exec" phase) never gets called, it has declared
* inputs, which can be checked for freshness (and potentially
* used to determine that the function can be skipped).
*
* The workcache checks _all_ works for freshness, but uses the set of
* discovered outputs from the _previous_ exec (which it will re-discover
* and re-record each time the exec phase runs).
*
* Therefore the discovered works cached in the db might be a
* mis-approximation of the current discoverable works, but this is ok for
* the following reason: we assume that if an artifact A changed from
* depending on B,C,D to depending on B,C,D,E, then A itself changed (as
* part of the change-in-dependencies), so we will be ok.
*
* Each function has a single discriminated output work called its _result_.
* This is only different from other works in that it is returned, by value,
* from a call to the cacheable function; the other output works are used in
* passing to invalidate dependencies elsewhere in the cache, but do not
* otherwise escape from a function invocation. Most functions only have one
* output work anyways.
*
* A database (the central store of a workcache) stores a mappings:
*
* (fn_name,{declared_input}) => ({discovered_input},
*                                {discovered_output},result)
*
* (Note: fbuild, which workcache is based on, has the concept of a declared
* output as separate from a discovered output. This distinction exists only
* as an artifact of how fbuild works: via annotations on function types
* and metaprogramming, with explicit dependency declaration as a fallback.
* Workcache is more explicit about dependencies, and as such treats all
* outputs the same, as discovered-during-the-last-run.)
*
*/

#[deriving(Eq)]
#[auto_encode]
#[auto_decode]
struct WorkKey {
    kind: ~str,
    name: ~str
}

impl to_bytes::IterBytes for WorkKey {
    #[inline(always)]
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
        let mut flag = true;
        self.kind.iter_bytes(lsb0, |bytes| {flag = f(bytes); flag});
        if !flag { return; }
        self.name.iter_bytes(lsb0, f);
    }
}

impl cmp::Ord for WorkKey {
    fn lt(&self, other: &WorkKey) -> bool {
        self.kind < other.kind ||
            (self.kind == other.kind &&
             self.name < other.name)
    }
    fn le(&self, other: &WorkKey) -> bool {
        self.lt(other) || self.eq(other)
    }
    fn ge(&self, other: &WorkKey) -> bool {
        self.gt(other) || self.eq(other)
    }
    fn gt(&self, other: &WorkKey) -> bool {
        ! self.le(other)
    }
}

pub impl WorkKey {
    fn new(kind: &str, name: &str) -> WorkKey {
    WorkKey { kind: kind.to_owned(), name: name.to_owned() }
    }
}

struct WorkMap(HashMap<WorkKey, ~str>);

impl WorkMap {
    fn new() -> WorkMap { WorkMap(HashMap::new()) }
}

impl<S:Encoder> Encodable<S> for WorkMap {
    fn encode(&self, s: &S) {
        let mut d = ~[];
        for self.each |k, v| {
            d.push((copy *k, copy *v))
        }
        sort::tim_sort(d);
        d.encode(s)
    }
}

impl<D:Decoder> Decodable<D> for WorkMap {
    fn decode(d: &D) -> WorkMap {
        let v : ~[(WorkKey,~str)] = Decodable::decode(d);
        let mut w = WorkMap::new();
        for v.each |&(k, v)| {
            w.insert(copy k, copy v);
        }
        w
    }
}

struct Database {
    db_filename: Path,
    db_cache: HashMap<~str, ~str>,
    db_dirty: bool
}

pub impl Database {
    fn prepare(&mut self,
               fn_name: &str,
               declared_inputs: &WorkMap) -> Option<(WorkMap, WorkMap, ~str)>
    {
        let k = json_encode(&(fn_name, declared_inputs));
        match self.db_cache.find(&k) {
            None => None,
            Some(v) => Some(json_decode(*v))
        }
    }

    fn cache(&mut self,
             fn_name: &str,
             declared_inputs: &WorkMap,
             discovered_inputs: &WorkMap,
             discovered_outputs: &WorkMap,
             result: &str) {
        let k = json_encode(&(fn_name, declared_inputs));
        let v = json_encode(&(discovered_inputs,
                              discovered_outputs,
                              result));
        self.db_cache.insert(k,v);
        self.db_dirty = true
    }
}

struct Logger {
    // FIXME #4432: Fill in
    a: ()
}

pub impl Logger {
    fn info(&self, i: &str) {
        io::println(~"workcache: " + i.to_owned());
    }
}

struct Context {
    db: @mut Database,
    logger: @mut Logger,
    cfg: @json::Object,
    freshness: HashMap<~str,@fn(&str,&str)->bool>
}

struct Prep {
    ctxt: @Context,
    fn_name: ~str,
    declared_inputs: WorkMap,
}

struct Exec {
    discovered_inputs: WorkMap,
    discovered_outputs: WorkMap
}

struct Work<T> {
    prep: @mut Prep,
    res: Option<Either<T,PortOne<(Exec,T)>>>
}

fn json_encode<T:Encodable<json::Encoder>>(t: &T) -> ~str {
    do io::with_str_writer |wr| {
        t.encode(&json::Encoder(wr));
    }
}

// FIXME(#5121)
fn json_decode<T:Decodable<json::Decoder>>(s: &str) -> T {
    do io::with_str_reader(s) |rdr| {
        let j = result::unwrap(json::from_reader(rdr));
        Decodable::decode(&json::Decoder(j))
    }
}

fn digest<T:Encodable<json::Encoder>>(t: &T) -> ~str {
    let mut sha = sha1::sha1();
    sha.input_str(json_encode(t));
    sha.result_str()
}

fn digest_file(path: &Path) -> ~str {
    let mut sha = sha1::sha1();
    let s = io::read_whole_file_str(path);
    sha.input_str(*s.get_ref());
    sha.result_str()
}

pub impl Context {

    fn new(db: @mut Database,
                  lg: @mut Logger,
                  cfg: @json::Object) -> Context {
        Context {
            db: db,
            logger: lg,
            cfg: cfg,
            freshness: HashMap::new()
        }
    }

    fn prep<T:Owned +
              Encodable<json::Encoder> +
              Decodable<json::Decoder>>( // FIXME(#5121)
                  @self,
                  fn_name:&str,
                  blk: &fn(@mut Prep)->Work<T>) -> Work<T> {
        let p = @mut Prep {
            ctxt: self,
            fn_name: fn_name.to_owned(),
            declared_inputs: WorkMap::new()
        };
        blk(p)
    }
}

trait TPrep {
    fn declare_input(&mut self, kind:&str, name:&str, val:&str);
    fn is_fresh(&self, cat:&str, kind:&str, name:&str, val:&str) -> bool;
    fn all_fresh(&self, cat:&str, map:&WorkMap) -> bool;
    fn exec<T:Owned +
              Encodable<json::Encoder> +
              Decodable<json::Decoder>>( // FIXME(#5121)
        &self, blk: ~fn(&Exec) -> T) -> Work<T>;
}

impl TPrep for Prep {
    fn declare_input(&mut self, kind:&str, name:&str, val:&str) {
        self.declared_inputs.insert(WorkKey::new(kind, name),
                                 val.to_owned());
    }

    fn is_fresh(&self, cat: &str, kind: &str,
                name: &str, val: &str) -> bool {
        let k = kind.to_owned();
        let f = (*self.ctxt.freshness.get(&k))(name, val);
        let lg = self.ctxt.logger;
            if f {
                lg.info(fmt!("%s %s:%s is fresh",
                             cat, kind, name));
            } else {
                lg.info(fmt!("%s %s:%s is not fresh",
                             cat, kind, name))
            }
        f
    }

    fn all_fresh(&self, cat: &str, map: &WorkMap) -> bool {
        for map.each |k, v| {
            if ! self.is_fresh(cat, k.kind, k.name, *v) {
                return false;
            }
        }
        return true;
    }

    fn exec<T:Owned +
              Encodable<json::Encoder> +
              Decodable<json::Decoder>>( // FIXME(#5121)
            &self, blk: ~fn(&Exec) -> T) -> Work<T> {
        let mut bo = Some(blk);

        let cached = self.ctxt.db.prepare(self.fn_name, &self.declared_inputs);

        match cached {
            Some((ref disc_in, ref disc_out, ref res))
            if self.all_fresh("declared input",
                              &self.declared_inputs) &&
            self.all_fresh("discovered input", disc_in) &&
            self.all_fresh("discovered output", disc_out) => {
                Work::new(@mut *self, Left(json_decode(*res)))
            }

            _ => {
                let (chan, port) = oneshot::init();
                let mut blk = None;
                blk <-> bo;
                let blk = blk.unwrap();
                let chan = Cell(chan);

                do task::spawn || {
                    let exe = Exec {
                        discovered_inputs: WorkMap::new(),
                        discovered_outputs: WorkMap::new(),
                    };
                    let chan = chan.take();
                    let v = blk(&exe);
                    send_one(chan, (exe, v));
                }
                Work::new(@mut *self, Right(port))
            }
        }
    }
}

pub impl<T:Owned +
         Encodable<json::Encoder> +
         Decodable<json::Decoder>> Work<T> { // FIXME(#5121)
    fn new(p: @mut Prep, e: Either<T,PortOne<(Exec,T)>>) -> Work<T> {
        Work { prep: p, res: Some(e) }
    }
}

// FIXME (#3724): movable self. This should be in impl Work.
fn unwrap<T:Owned +
            Encodable<json::Encoder> +
            Decodable<json::Decoder>>( // FIXME(#5121)
        w: Work<T>) -> T {
    let mut ww = w;
    let mut s = None;

    ww.res <-> s;

    match s {
        None => fail!(),
        Some(Left(v)) => v,
        Some(Right(port)) => {
            let (exe, v) = match recv(port) {
                oneshot::send(data) => data
            };

            let s = json_encode(&v);

            let p = &*ww.prep;
            let db = p.ctxt.db;
            db.cache(p.fn_name,
                 &p.declared_inputs,
                 &exe.discovered_inputs,
                 &exe.discovered_outputs,
                 s);
            v
        }
    }
}

//#[test]
fn test() {
    use core::io::WriterUtil;

    let db = @mut Database { db_filename: Path("db.json"),
                             db_cache: HashMap::new(),
                             db_dirty: false };
    let lg = @mut Logger { a: () };
    let cfg = @HashMap::new();
    let cx = @Context::new(db, lg, cfg);
    let w:Work<~str> = do cx.prep("test1") |prep| {
        let pth = Path("foo.c");
        {
            let file = io::file_writer(&pth, [io::Create]).get();
            file.write_str("int main() { return 0; }");
        }

        prep.declare_input("file", pth.to_str(), digest_file(&pth));
        do prep.exec |_exe| {
            let out = Path("foo.o");
            run::run_program("gcc", [~"foo.c", ~"-o", out.to_str()]);
            out.to_str()
        }
    };
    let s = unwrap(w);
    io::println(s);
}
<commit_msg>Small typos, year date and URL of the fbuild system for reference.<commit_after>// Copyright 2012-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.

#[allow(deprecated_mode)];

use json;
use sha1;
use serialize::{Encoder, Encodable, Decoder, Decodable};
use sort;

use core::cell::Cell;
use core::cmp;
use core::either::{Either, Left, Right};
use core::io;
use core::comm::{oneshot, PortOne, send_one};
use core::pipes::recv;
use core::prelude::*;
use core::result;
use core::run;
use core::hashmap::HashMap;
use core::task;
use core::to_bytes;

/**
*
* This is a loose clone of the [fbuild build system](https://github.com/felix-lang/fbuild),
* made a touch more generic (not wired to special cases on files) and much
* less metaprogram-y due to rust's comparative weakness there, relative to
* python.
*
* It's based around _imperative builds_ that happen to have some function
* calls cached. That is, it's _just_ a mechanism for describing cached
* functions. This makes it much simpler and smaller than a "build system"
* that produces an IR and evaluates it. The evaluation order is normal
* function calls. Some of them just return really quickly.
*
* A cached function consumes and produces a set of _works_. A work has a
* name, a kind (that determines how the value is to be checked for
* freshness) and a value. Works must also be (de)serializable. Some
* examples of works:
*
*    kind   name    value
*   ------------------------
*    cfg    os      linux
*    file   foo.c   <sha1>
*    url    foo.com <etag>
*
* Works are conceptually single units, but we store them most of the time
* in maps of the form (type,name) => value. These are WorkMaps.
*
* A cached function divides the works it's interested in into inputs and
* outputs, and subdivides those into declared (input) works and
* discovered (input and output) works.
*
* A _declared_ input or is one that is given to the workcache before
* any work actually happens, in the "prep" phase. Even when a function's
* work-doing part (the "exec" phase) never gets called, it has declared
* inputs, which can be checked for freshness (and potentially
* used to determine that the function can be skipped).
*
* The workcache checks _all_ works for freshness, but uses the set of
* discovered outputs from the _previous_ exec (which it will re-discover
* and re-record each time the exec phase runs).
*
* Therefore the discovered works cached in the db might be a
* mis-approximation of the current discoverable works, but this is ok for
* the following reason: we assume that if an artifact A changed from
* depending on B,C,D to depending on B,C,D,E, then A itself changed (as
* part of the change-in-dependencies), so we will be ok.
*
* Each function has a single discriminated output work called its _result_.
* This is only different from other works in that it is returned, by value,
* from a call to the cacheable function; the other output works are used in
* passing to invalidate dependencies elsewhere in the cache, but do not
* otherwise escape from a function invocation. Most functions only have one
* output work anyways.
*
* A database (the central store of a workcache) stores a mappings:
*
* (fn_name,{declared_input}) => ({discovered_input},
*                                {discovered_output},result)
*
* (Note: fbuild, which workcache is based on, has the concept of a declared
* output as separate from a discovered output. This distinction exists only
* as an artifact of how fbuild works: via annotations on function types
* and metaprogramming, with explicit dependency declaration as a fallback.
* Workcache is more explicit about dependencies, and as such treats all
* outputs the same, as discovered-during-the-last-run.)
*
*/

#[deriving(Eq)]
#[auto_encode]
#[auto_decode]
struct WorkKey {
    kind: ~str,
    name: ~str
}

impl to_bytes::IterBytes for WorkKey {
    #[inline(always)]
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
        let mut flag = true;
        self.kind.iter_bytes(lsb0, |bytes| {flag = f(bytes); flag});
        if !flag { return; }
        self.name.iter_bytes(lsb0, f);
    }
}

impl cmp::Ord for WorkKey {
    fn lt(&self, other: &WorkKey) -> bool {
        self.kind < other.kind ||
            (self.kind == other.kind &&
             self.name < other.name)
    }
    fn le(&self, other: &WorkKey) -> bool {
        self.lt(other) || self.eq(other)
    }
    fn ge(&self, other: &WorkKey) -> bool {
        self.gt(other) || self.eq(other)
    }
    fn gt(&self, other: &WorkKey) -> bool {
        ! self.le(other)
    }
}

pub impl WorkKey {
    fn new(kind: &str, name: &str) -> WorkKey {
    WorkKey { kind: kind.to_owned(), name: name.to_owned() }
    }
}

struct WorkMap(HashMap<WorkKey, ~str>);

impl WorkMap {
    fn new() -> WorkMap { WorkMap(HashMap::new()) }
}

impl<S:Encoder> Encodable<S> for WorkMap {
    fn encode(&self, s: &S) {
        let mut d = ~[];
        for self.each |k, v| {
            d.push((copy *k, copy *v))
        }
        sort::tim_sort(d);
        d.encode(s)
    }
}

impl<D:Decoder> Decodable<D> for WorkMap {
    fn decode(d: &D) -> WorkMap {
        let v : ~[(WorkKey,~str)] = Decodable::decode(d);
        let mut w = WorkMap::new();
        for v.each |&(k, v)| {
            w.insert(copy k, copy v);
        }
        w
    }
}

struct Database {
    db_filename: Path,
    db_cache: HashMap<~str, ~str>,
    db_dirty: bool
}

pub impl Database {
    fn prepare(&mut self,
               fn_name: &str,
               declared_inputs: &WorkMap) -> Option<(WorkMap, WorkMap, ~str)>
    {
        let k = json_encode(&(fn_name, declared_inputs));
        match self.db_cache.find(&k) {
            None => None,
            Some(v) => Some(json_decode(*v))
        }
    }

    fn cache(&mut self,
             fn_name: &str,
             declared_inputs: &WorkMap,
             discovered_inputs: &WorkMap,
             discovered_outputs: &WorkMap,
             result: &str) {
        let k = json_encode(&(fn_name, declared_inputs));
        let v = json_encode(&(discovered_inputs,
                              discovered_outputs,
                              result));
        self.db_cache.insert(k,v);
        self.db_dirty = true
    }
}

struct Logger {
    // FIXME #4432: Fill in
    a: ()
}

pub impl Logger {
    fn info(&self, i: &str) {
        io::println(~"workcache: " + i.to_owned());
    }
}

struct Context {
    db: @mut Database,
    logger: @mut Logger,
    cfg: @json::Object,
    freshness: HashMap<~str,@fn(&str,&str)->bool>
}

struct Prep {
    ctxt: @Context,
    fn_name: ~str,
    declared_inputs: WorkMap,
}

struct Exec {
    discovered_inputs: WorkMap,
    discovered_outputs: WorkMap
}

struct Work<T> {
    prep: @mut Prep,
    res: Option<Either<T,PortOne<(Exec,T)>>>
}

fn json_encode<T:Encodable<json::Encoder>>(t: &T) -> ~str {
    do io::with_str_writer |wr| {
        t.encode(&json::Encoder(wr));
    }
}

// FIXME(#5121)
fn json_decode<T:Decodable<json::Decoder>>(s: &str) -> T {
    do io::with_str_reader(s) |rdr| {
        let j = result::unwrap(json::from_reader(rdr));
        Decodable::decode(&json::Decoder(j))
    }
}

fn digest<T:Encodable<json::Encoder>>(t: &T) -> ~str {
    let mut sha = sha1::sha1();
    sha.input_str(json_encode(t));
    sha.result_str()
}

fn digest_file(path: &Path) -> ~str {
    let mut sha = sha1::sha1();
    let s = io::read_whole_file_str(path);
    sha.input_str(*s.get_ref());
    sha.result_str()
}

pub impl Context {

    fn new(db: @mut Database,
                  lg: @mut Logger,
                  cfg: @json::Object) -> Context {
        Context {
            db: db,
            logger: lg,
            cfg: cfg,
            freshness: HashMap::new()
        }
    }

    fn prep<T:Owned +
              Encodable<json::Encoder> +
              Decodable<json::Decoder>>( // FIXME(#5121)
                  @self,
                  fn_name:&str,
                  blk: &fn(@mut Prep)->Work<T>) -> Work<T> {
        let p = @mut Prep {
            ctxt: self,
            fn_name: fn_name.to_owned(),
            declared_inputs: WorkMap::new()
        };
        blk(p)
    }
}

trait TPrep {
    fn declare_input(&mut self, kind:&str, name:&str, val:&str);
    fn is_fresh(&self, cat:&str, kind:&str, name:&str, val:&str) -> bool;
    fn all_fresh(&self, cat:&str, map:&WorkMap) -> bool;
    fn exec<T:Owned +
              Encodable<json::Encoder> +
              Decodable<json::Decoder>>( // FIXME(#5121)
        &self, blk: ~fn(&Exec) -> T) -> Work<T>;
}

impl TPrep for Prep {
    fn declare_input(&mut self, kind:&str, name:&str, val:&str) {
        self.declared_inputs.insert(WorkKey::new(kind, name),
                                 val.to_owned());
    }

    fn is_fresh(&self, cat: &str, kind: &str,
                name: &str, val: &str) -> bool {
        let k = kind.to_owned();
        let f = (*self.ctxt.freshness.get(&k))(name, val);
        let lg = self.ctxt.logger;
            if f {
                lg.info(fmt!("%s %s:%s is fresh",
                             cat, kind, name));
            } else {
                lg.info(fmt!("%s %s:%s is not fresh",
                             cat, kind, name))
            }
        f
    }

    fn all_fresh(&self, cat: &str, map: &WorkMap) -> bool {
        for map.each |k, v| {
            if ! self.is_fresh(cat, k.kind, k.name, *v) {
                return false;
            }
        }
        return true;
    }

    fn exec<T:Owned +
              Encodable<json::Encoder> +
              Decodable<json::Decoder>>( // FIXME(#5121)
            &self, blk: ~fn(&Exec) -> T) -> Work<T> {
        let mut bo = Some(blk);

        let cached = self.ctxt.db.prepare(self.fn_name, &self.declared_inputs);

        match cached {
            Some((ref disc_in, ref disc_out, ref res))
            if self.all_fresh("declared input",
                              &self.declared_inputs) &&
            self.all_fresh("discovered input", disc_in) &&
            self.all_fresh("discovered output", disc_out) => {
                Work::new(@mut *self, Left(json_decode(*res)))
            }

            _ => {
                let (chan, port) = oneshot::init();
                let mut blk = None;
                blk <-> bo;
                let blk = blk.unwrap();
                let chan = Cell(chan);

                do task::spawn || {
                    let exe = Exec {
                        discovered_inputs: WorkMap::new(),
                        discovered_outputs: WorkMap::new(),
                    };
                    let chan = chan.take();
                    let v = blk(&exe);
                    send_one(chan, (exe, v));
                }
                Work::new(@mut *self, Right(port))
            }
        }
    }
}

pub impl<T:Owned +
         Encodable<json::Encoder> +
         Decodable<json::Decoder>> Work<T> { // FIXME(#5121)
    fn new(p: @mut Prep, e: Either<T,PortOne<(Exec,T)>>) -> Work<T> {
        Work { prep: p, res: Some(e) }
    }
}

// FIXME (#3724): movable self. This should be in impl Work.
fn unwrap<T:Owned +
            Encodable<json::Encoder> +
            Decodable<json::Decoder>>( // FIXME(#5121)
        w: Work<T>) -> T {
    let mut ww = w;
    let mut s = None;

    ww.res <-> s;

    match s {
        None => fail!(),
        Some(Left(v)) => v,
        Some(Right(port)) => {
            let (exe, v) = match recv(port) {
                oneshot::send(data) => data
            };

            let s = json_encode(&v);

            let p = &*ww.prep;
            let db = p.ctxt.db;
            db.cache(p.fn_name,
                 &p.declared_inputs,
                 &exe.discovered_inputs,
                 &exe.discovered_outputs,
                 s);
            v
        }
    }
}

//#[test]
fn test() {
    use core::io::WriterUtil;

    let db = @mut Database { db_filename: Path("db.json"),
                             db_cache: HashMap::new(),
                             db_dirty: false };
    let lg = @mut Logger { a: () };
    let cfg = @HashMap::new();
    let cx = @Context::new(db, lg, cfg);
    let w:Work<~str> = do cx.prep("test1") |prep| {
        let pth = Path("foo.c");
        {
            let file = io::file_writer(&pth, [io::Create]).get();
            file.write_str("int main() { return 0; }");
        }

        prep.declare_input("file", pth.to_str(), digest_file(&pth));
        do prep.exec |_exe| {
            let out = Path("foo.o");
            run::run_program("gcc", [~"foo.c", ~"-o", out.to_str()]);
            out.to_str()
        }
    };
    let s = unwrap(w);
    io::println(s);
}
<|endoftext|>


<commit_before><commit_msg>Rearrange the tests so the bitmap has a chance of being seen<commit_after><|endoftext|>


<commit_before><commit_msg>Started adding some tests and benchs.<commit_after>#[feature(globs)];

extern mod lua;
extern mod extra;

use lua::state::State;
use lua::status::*;

#[test]
fn test_file_loading()
{
    let state = State::new();
    match state.load_file("sample.lua")
    {
        LuaOk => {}
        LuaErr(_) => fail!("Failed to load file: sample.lua"),
    }

    match state.load_file("inexistant.lua")
    {
        LuaOk => fail!("Successed to load file: inexistant.lua, but it shouldn't as the file shouldn't exists."),
        LuaErr(_) => {},
    }
}

#[test]
fn test_str_loading()
{
    let state = State::new();
    match state.load_str("a = 2")
    {
        LuaOk => {}
        LuaErr(_) => fail!(),
    }

    match state.load_str("fail fail fail fail")
    {
        LuaOk => fail!(),
        LuaErr(_) => {}
    }
}

#[bench]
fn bench_load_str(b: &mut extra::test::BenchHarness)
{
    let state = State::new();
    do b.iter
    {
        state.load_str("a = 2");
    }
}
<|endoftext|>


<commit_before>//! Module that parses arguments and initializes radeco
use errors::ArgError;
use std::io::Read;
use std::process::Command;

use docopt::Docopt;
use radeco_lib;
use structs;

static USAGE: &'static str = "
radeco. The radare2 decompiler.
Usage:
  radeco <file>
  radeco [options] [<file>]
  radeco run [options] [<file>]

Options:
  --config <json_file>     Run decompilation using json rules file.
  --make-config <file>     Wizard to make the JSON config.
  -a --address=<addr>      Address of function to decompile.
  -e --esil=<esil_expr>    Evaluate given esil expression.
  -o --output=<output>     Specify output directory.
  -p --pipeline=<pipe>     Stages in the pipeline. Comma separated values.
                           Prefix the string with '=' (such as =ssa)
                           to obtain the output the stage.
                           Valid values: c,r2,ssa,cfg,const,dce,verify,svg,png
  -q --quiet               Display silent output.
  -s --shell               Run interactive prompt.
  -v --version             Show version.
  -h --help                Show this screen.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_esil_expr: Option<Vec<String>>,
    arg_file: Option<String>,
    cmd_run: bool,
    flag_address: Option<String>,
    flag_config: Option<String>,
    flag_help: bool,
    flag_make_config: bool,
    flag_shell: bool,
    flag_quiet: bool,
    flag_version: bool,
    flag_output: Option<String>,
    flag_esil: Option<Vec<String>>,
    flag_pipeline: Option<String>,
}

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

pub type ArgResult<T> = Option<Result<T, ArgError>>;

fn make_config() -> structs::Input {
    structs::input_builder()
}

#[allow(dead_code)]
pub struct Radeco {
    bin_name: Option<String>,
    esil: Option<Vec<String>>,
    addr: String,
    name: Option<String>,
    outpath: String,
    stages: Vec<usize>,
    quiet: bool,
    runner: Option<radeco_lib::utils::Runner>,
    outmodes: Option<Vec<u16>>,
    post_runner: Option<Vec<PostRunner>>,
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum PostRunner {
    Genpng,
    Gensvg,
}

macro_rules! radeco_out {
	($x: expr, $b: expr) => {
		if $b {
			println!("{}", $x);
		}
	}
}

impl Radeco {
    pub fn new(input: structs::Input, post: Option<Vec<PostRunner>>) -> ArgResult<Radeco> {
        let runner = input.validate();
        if runner.is_err() {
            return Some(Err(runner.err().unwrap()));
        }

        let radeco = Radeco {
            bin_name: input.bin_name.clone(),
            esil: input.esil.clone(),
            addr: input.addr.clone().unwrap(),
            name: input.name.clone(),
            outpath: input.outpath.clone().unwrap(),
            stages: input.stages.clone(),
            quiet: input.quiet.clone().unwrap(),
            runner: runner.ok(),
            outmodes: input.outmodes.clone(),
            post_runner: post,
        };

        Some(Ok(radeco))
    }

    pub fn init() -> ArgResult<Radeco> {
        let args: Args = Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit());

        if args.flag_version {
            println!("Version: {:?}", VERSION);
            return None;
        } else if args.flag_help {
            println!("{}", USAGE);
            return None;
        }

        let mut post_runner = Vec::<PostRunner>::new();
        // Make config file and run radeco with it
        if args.flag_make_config {
            let input = make_config();
            input.spew_json();
            // TODO: populate post_runner
            return Radeco::new(input, Some(post_runner));
        }

        // Run from a predefined configuration file
        if args.flag_config.is_some() {
            let filename = args.flag_config.clone().unwrap();
            let input = structs::Input::from_config(filename);
            if input.is_err() {
                return Some(Err(input.err().unwrap()));
            }
            return Radeco::new(input.unwrap(), Some(post_runner));
        }

        let mut input = structs::Input::defaults();

        if args.arg_file.is_some() {
            input.bin_name = args.arg_file;
        }
        if args.flag_address.is_some() {
            input.addr = args.flag_address;
        }
        if args.flag_esil.is_some() {
            input.esil = args.flag_esil;
        }
        input.quiet = Some(!args.flag_quiet);
        if args.flag_output.is_some() {
            input.outpath = args.flag_output;
        }

        if args.flag_pipeline.is_some() {
            let pipe = args.flag_pipeline.unwrap();
            let mut _tmp_stages = Vec::<usize>::new();
            let mut exclude = Vec::<u16>::new();
            for (i, stage) in pipe.split(',').enumerate() {
                let j = match stage.chars().nth(0).unwrap() {
                    '-' => {
                        exclude.push(i as u16);
                        1
                    }
                    '+' => 1,
                    _ => 0,
                };

                // Try and match with post runner stages
                match &stage[j..] {
                    "png" => {
                        post_runner.push(PostRunner::Genpng);
                        continue;
                    }
                    "svg" => {
                        post_runner.push(PostRunner::Gensvg);
                        continue;
                    }
                    _ => (),
                }

                let n = match &stage[j..] {
                    "r2" => 0,
                    "esil" => 1,
                    "cfg" => 2,
                    "ssa" => 3,
                    "const" => 4,
                    "dce" => 5,
                    "verify" => 6,
                    "c" => 7,
                    _ => {
                        let e = ArgError::InvalidArgument(stage[j..].to_owned());
                        return Some(Err(e));
                    }
                };
                _tmp_stages.push(n);
            }

            let mut _tmp_out = Vec::<u16>::new();
            for i in (0..(pipe.len() - 1) as u16) {
                if exclude.contains(&i) {
                    continue;
                }
                _tmp_out.push(i);
            }
            input.stages = _tmp_stages;
            input.outmodes = Some(_tmp_out);
        }

        Radeco::new(input, Some(post_runner))
    }

    pub fn run(&mut self) -> Result<(), String> {
        match self.runner.as_mut() {
            Some(ref mut runner) => {
                radeco_out!("[*] Starting radeco with config: ", runner.is_verbose());
                radeco_out!(runner, runner.is_verbose());
                runner.run()
            }
            None => panic!("Uninitialized instance of radeco!"),
        }
        Ok(())
    }

    pub fn output(&mut self) {
        match self.runner.as_mut() {
            Some(ref mut runner) => {
                radeco_out!("[*] Writing output", runner.is_verbose());
                runner.output(self.outmodes.clone());
            }
            None => panic!("Uninitialized instance of radeco!"),
        }

        // Post processing phases defined in radeco
        // These can be generation of svg, png etc
        for phase in self.post_runner.as_ref().unwrap() {
            match *phase {
                PostRunner::Genpng | PostRunner::Gensvg => {
                    let format = if *phase == PostRunner::Genpng {
                        "png"
                    } else {
                        "svg"
                    };
                    radeco_out!("[*] Generating svg",
                                self.runner.as_ref().unwrap().is_verbose());
                    let mut cmd = String::new();
                    let mut target = self.outpath.clone();
                    target.push_str("/");
                    target.push_str(&self.name.as_ref().unwrap());
                    target.push_str("/*.dot");
                    cmd.push_str(&format!("dot -T{} -O ", format));
                    cmd.push_str(&target);

                    let _ = Command::new("sh").arg("-c").arg(cmd).output().unwrap();
                }
            }
        }
    }
}
<commit_msg>Remove unnecessary parenthesis<commit_after>//! Module that parses arguments and initializes radeco
use errors::ArgError;
use std::io::Read;
use std::process::Command;

use docopt::Docopt;
use radeco_lib;
use structs;

static USAGE: &'static str = "
radeco. The radare2 decompiler.
Usage:
  radeco <file>
  radeco [options] [<file>]
  radeco run [options] [<file>]

Options:
  --config <json_file>     Run decompilation using json rules file.
  --make-config <file>     Wizard to make the JSON config.
  -a --address=<addr>      Address of function to decompile.
  -e --esil=<esil_expr>    Evaluate given esil expression.
  -o --output=<output>     Specify output directory.
  -p --pipeline=<pipe>     Stages in the pipeline. Comma separated values.
                           Prefix the string with '=' (such as =ssa)
                           to obtain the output the stage.
                           Valid values: c,r2,ssa,cfg,const,dce,verify,svg,png
  -q --quiet               Display silent output.
  -s --shell               Run interactive prompt.
  -v --version             Show version.
  -h --help                Show this screen.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_esil_expr: Option<Vec<String>>,
    arg_file: Option<String>,
    cmd_run: bool,
    flag_address: Option<String>,
    flag_config: Option<String>,
    flag_help: bool,
    flag_make_config: bool,
    flag_shell: bool,
    flag_quiet: bool,
    flag_version: bool,
    flag_output: Option<String>,
    flag_esil: Option<Vec<String>>,
    flag_pipeline: Option<String>,
}

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

pub type ArgResult<T> = Option<Result<T, ArgError>>;

fn make_config() -> structs::Input {
    structs::input_builder()
}

#[allow(dead_code)]
pub struct Radeco {
    bin_name: Option<String>,
    esil: Option<Vec<String>>,
    addr: String,
    name: Option<String>,
    outpath: String,
    stages: Vec<usize>,
    quiet: bool,
    runner: Option<radeco_lib::utils::Runner>,
    outmodes: Option<Vec<u16>>,
    post_runner: Option<Vec<PostRunner>>,
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum PostRunner {
    Genpng,
    Gensvg,
}

macro_rules! radeco_out {
	($x: expr, $b: expr) => {
		if $b {
			println!("{}", $x);
		}
	}
}

impl Radeco {
    pub fn new(input: structs::Input, post: Option<Vec<PostRunner>>) -> ArgResult<Radeco> {
        let runner = input.validate();
        if runner.is_err() {
            return Some(Err(runner.err().unwrap()));
        }

        let radeco = Radeco {
            bin_name: input.bin_name.clone(),
            esil: input.esil.clone(),
            addr: input.addr.clone().unwrap(),
            name: input.name.clone(),
            outpath: input.outpath.clone().unwrap(),
            stages: input.stages.clone(),
            quiet: input.quiet.clone().unwrap(),
            runner: runner.ok(),
            outmodes: input.outmodes.clone(),
            post_runner: post,
        };

        Some(Ok(radeco))
    }

    pub fn init() -> ArgResult<Radeco> {
        let args: Args = Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit());

        if args.flag_version {
            println!("Version: {:?}", VERSION);
            return None;
        } else if args.flag_help {
            println!("{}", USAGE);
            return None;
        }

        let mut post_runner = Vec::<PostRunner>::new();
        // Make config file and run radeco with it
        if args.flag_make_config {
            let input = make_config();
            input.spew_json();
            // TODO: populate post_runner
            return Radeco::new(input, Some(post_runner));
        }

        // Run from a predefined configuration file
        if args.flag_config.is_some() {
            let filename = args.flag_config.clone().unwrap();
            let input = structs::Input::from_config(filename);
            if input.is_err() {
                return Some(Err(input.err().unwrap()));
            }
            return Radeco::new(input.unwrap(), Some(post_runner));
        }

        let mut input = structs::Input::defaults();

        if args.arg_file.is_some() {
            input.bin_name = args.arg_file;
        }
        if args.flag_address.is_some() {
            input.addr = args.flag_address;
        }
        if args.flag_esil.is_some() {
            input.esil = args.flag_esil;
        }
        input.quiet = Some(!args.flag_quiet);
        if args.flag_output.is_some() {
            input.outpath = args.flag_output;
        }

        if args.flag_pipeline.is_some() {
            let pipe = args.flag_pipeline.unwrap();
            let mut _tmp_stages = Vec::<usize>::new();
            let mut exclude = Vec::<u16>::new();
            for (i, stage) in pipe.split(',').enumerate() {
                let j = match stage.chars().nth(0).unwrap() {
                    '-' => {
                        exclude.push(i as u16);
                        1
                    }
                    '+' => 1,
                    _ => 0,
                };

                // Try and match with post runner stages
                match &stage[j..] {
                    "png" => {
                        post_runner.push(PostRunner::Genpng);
                        continue;
                    }
                    "svg" => {
                        post_runner.push(PostRunner::Gensvg);
                        continue;
                    }
                    _ => (),
                }

                let n = match &stage[j..] {
                    "r2" => 0,
                    "esil" => 1,
                    "cfg" => 2,
                    "ssa" => 3,
                    "const" => 4,
                    "dce" => 5,
                    "verify" => 6,
                    "c" => 7,
                    _ => {
                        let e = ArgError::InvalidArgument(stage[j..].to_owned());
                        return Some(Err(e));
                    }
                };
                _tmp_stages.push(n);
            }

            let mut _tmp_out = Vec::<u16>::new();
            for i in 0..(pipe.len() - 1) as u16 {
                if exclude.contains(&i) {
                    continue;
                }
                _tmp_out.push(i);
            }
            input.stages = _tmp_stages;
            input.outmodes = Some(_tmp_out);
        }

        Radeco::new(input, Some(post_runner))
    }

    pub fn run(&mut self) -> Result<(), String> {
        match self.runner.as_mut() {
            Some(ref mut runner) => {
                radeco_out!("[*] Starting radeco with config: ", runner.is_verbose());
                radeco_out!(runner, runner.is_verbose());
                runner.run()
            }
            None => panic!("Uninitialized instance of radeco!"),
        }
        Ok(())
    }

    pub fn output(&mut self) {
        match self.runner.as_mut() {
            Some(ref mut runner) => {
                radeco_out!("[*] Writing output", runner.is_verbose());
                runner.output(self.outmodes.clone());
            }
            None => panic!("Uninitialized instance of radeco!"),
        }

        // Post processing phases defined in radeco
        // These can be generation of svg, png etc
        for phase in self.post_runner.as_ref().unwrap() {
            match *phase {
                PostRunner::Genpng | PostRunner::Gensvg => {
                    let format = if *phase == PostRunner::Genpng {
                        "png"
                    } else {
                        "svg"
                    };
                    radeco_out!("[*] Generating svg",
                                self.runner.as_ref().unwrap().is_verbose());
                    let mut cmd = String::new();
                    let mut target = self.outpath.clone();
                    target.push_str("/");
                    target.push_str(&self.name.as_ref().unwrap());
                    target.push_str("/*.dot");
                    cmd.push_str(&format!("dot -T{} -O ", format));
                    cmd.push_str(&target);

                    let _ = Command::new("sh").arg("-c").arg(cmd).output().unwrap();
                }
            }
        }
    }
}
<|endoftext|>


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

//! OS-based thread local storage
//!
//! This module provides an implementation of OS-based thread local storage,
//! using the native OS-provided facilities (think `TlsAlloc` or
//! `pthread_setspecific`). The interface of this differs from the other types
//! of thread-local-storage provided in this crate in that OS-based TLS can only
//! get/set pointers,
//!
//! This module also provides two flavors of TLS. One is intended for static
//! initialization, and does not contain a `Drop` implementation to deallocate
//! the OS-TLS key. The other is a type which does implement `Drop` and hence
//! has a safe interface.
//!
//! # Usage
//!
//! This module should likely not be used directly unless other primitives are
//! being built on. types such as `thread_local::scoped::Key` are likely much
//! more useful in practice than this OS-based version which likely requires
//! unsafe code to interoperate with.
//!
//! # Example
//!
//! Using a dynamically allocated TLS key. Note that this key can be shared
//! among many threads via an `Arc`.
//!
//! ```rust,ignore
//! let key = Key::new(None);
//! assert!(key.get().is_null());
//! key.set(1 as *mut u8);
//! assert!(!key.get().is_null());
//!
//! drop(key); // deallocate this TLS slot.
//! ```
//!
//! Sometimes a statically allocated key is either required or easier to work
//! with, however.
//!
//! ```rust,ignore
//! static KEY: StaticKey = INIT;
//!
//! unsafe {
//!     assert!(KEY.get().is_null());
//!     KEY.set(1 as *mut u8);
//! }
//! ```

#![allow(non_camel_case_types)]

use prelude::*;

use kinds::marker;
use mem;
use rustrt::exclusive::Exclusive;
use rustrt;
use sync::atomic::{mod, AtomicUint};
use sync::{Once, ONCE_INIT};

use sys::thread_local as imp;

/// A type for TLS keys that are statically allocated.
///
/// This type is entirely `unsafe` to use as it does not protect against
/// use-after-deallocation or use-during-deallocation.
///
/// The actual OS-TLS key is lazily allocated when this is used for the first
/// time. The key is also deallocated when the Rust runtime exits or `destroy`
/// is called, whichever comes first.
///
/// # Example
///
/// ```ignore
/// use tls::os::{StaticKey, INIT};
///
/// static KEY: StaticKey = INIT;
///
/// unsafe {
///     assert!(KEY.get().is_null());
///     KEY.set(1 as *mut u8);
/// }
/// ```
pub struct StaticKey {
    /// Inner static TLS key (internals), created with by `INIT_INNER` in this
    /// module.
    pub inner: StaticKeyInner,
    /// Destructor for the TLS value.
    ///
    /// See `Key::new` for information about when the destructor runs and how
    /// it runs.
    pub dtor: Option<unsafe extern fn(*mut u8)>,
}

/// Inner contents of `StaticKey`, created by the `INIT_INNER` constant.
pub struct StaticKeyInner {
    key: AtomicUint,
    nc: marker::NoCopy,
}

/// A type for a safely managed OS-based TLS slot.
///
/// This type allocates an OS TLS key when it is initialized and will deallocate
/// the key when it falls out of scope. When compared with `StaticKey`, this
/// type is entirely safe to use.
///
/// Implementations will likely, however, contain unsafe code as this type only
/// operates on `*mut u8`, an unsafe pointer.
///
/// # Example
///
/// ```rust,ignore
/// use tls::os::Key;
///
/// let key = Key::new(None);
/// assert!(key.get().is_null());
/// key.set(1 as *mut u8);
/// assert!(!key.get().is_null());
///
/// drop(key); // deallocate this TLS slot.
/// ```
pub struct Key {
    key: imp::Key,
}

/// Constant initialization value for static TLS keys.
///
/// This value specifies no destructor by default.
pub const INIT: StaticKey = StaticKey {
    inner: INIT_INNER,
    dtor: None,
};

/// Constant initialization value for the inner part of static TLS keys.
///
/// This value allows specific configuration of the destructor for a TLS key.
pub const INIT_INNER: StaticKeyInner = StaticKeyInner {
    key: atomic::INIT_ATOMIC_UINT,
    nc: marker::NoCopy,
};

static INIT_KEYS: Once = ONCE_INIT;
static mut KEYS: *mut Exclusive<Vec<imp::Key>> = 0 as *mut _;

impl StaticKey {
    /// Gets the value associated with this TLS key
    ///
    /// This will lazily allocate a TLS key from the OS if one has not already
    /// been allocated.
    #[inline]
    pub unsafe fn get(&self) -> *mut u8 { imp::get(self.key()) }

    /// Sets this TLS key to a new value.
    ///
    /// This will lazily allocate a TLS key from the OS if one has not already
    /// been allocated.
    #[inline]
    pub unsafe fn set(&self, val: *mut u8) { imp::set(self.key(), val) }

    /// Deallocates this OS TLS key.
    ///
    /// This function is unsafe as there is no guarantee that the key is not
    /// currently in use by other threads or will not ever be used again.
    ///
    /// Note that this does *not* run the user-provided destructor if one was
    /// specified at definition time. Doing so must be done manually.
    pub unsafe fn destroy(&self) {
        match self.inner.key.swap(0, atomic::SeqCst) {
            0 => {}
            n => { unregister_key(n as imp::Key); imp::destroy(n as imp::Key) }
        }
    }

    #[inline]
    unsafe fn key(&self) -> imp::Key {
        match self.inner.key.load(atomic::Relaxed) {
            0 => self.lazy_init() as imp::Key,
            n => n as imp::Key
        }
    }

    unsafe fn lazy_init(&self) -> uint {
        let key = imp::create(self.dtor);
        assert!(key != 0);
        match self.inner.key.compare_and_swap(0, key as uint, atomic::SeqCst) {
            // The CAS succeeded, so we've created the actual key
            0 => {
                register_key(key);
                key as uint
            }
            // If someone beat us to the punch, use their key instead
            n => { imp::destroy(key); n }
        }
    }
}

impl Key {
    /// Create a new managed OS TLS key.
    ///
    /// This key will be deallocated when the key falls out of scope.
    ///
    /// The argument provided is an optionally-specified destructor for the
    /// value of this TLS key. When a thread exits and the value for this key
    /// is non-null the destructor will be invoked. The TLS value will be reset
    /// to null before the destructor is invoked.
    ///
    /// Note that the destructor will not be run when the `Key` goes out of
    /// scope.
    #[inline]
    pub fn new(dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
        Key { key: unsafe { imp::create(dtor) } }
    }

    /// See StaticKey::get
    #[inline]
    pub fn get(&self) -> *mut u8 {
        unsafe { imp::get(self.key) }
    }

    /// See StaticKey::set
    #[inline]
    pub fn set(&self, val: *mut u8) {
        unsafe { imp::set(self.key, val) }
    }
}

impl Drop for Key {
    fn drop(&mut self) {
        unsafe { imp::destroy(self.key) }
    }
}

fn init_keys() {
    let keys = box Exclusive::new(Vec::<imp::Key>::new());
    unsafe {
        KEYS = mem::transmute(keys);
    }

    rustrt::at_exit(proc() unsafe {
        let keys: Box<Exclusive<Vec<imp::Key>>> = mem::transmute(KEYS);
        KEYS = 0 as *mut _;
        let keys = keys.lock();
        for key in keys.iter() {
            imp::destroy(*key);
        }
    });
}

fn register_key(key: imp::Key) {
    INIT_KEYS.doit(init_keys);
    let mut keys = unsafe { (*KEYS).lock() };
    keys.push(key);
}

fn unregister_key(key: imp::Key) {
    INIT_KEYS.doit(init_keys);
    let mut keys = unsafe { (*KEYS).lock() };
    keys.retain(|k| *k != key);
}

#[cfg(test)]
mod tests {
    use prelude::*;
    use super::{Key, StaticKey, INIT_INNER};

    fn assert_sync<T: Sync>() {}
    fn assert_send<T: Send>() {}

    #[test]
    fn smoke() {
        assert_sync::<Key>();
        assert_send::<Key>();

        let k1 = Key::new(None);
        let k2 = Key::new(None);
        assert!(k1.get().is_null());
        assert!(k2.get().is_null());
        k1.set(1 as *mut _);
        k2.set(2 as *mut _);
        assert_eq!(k1.get() as uint, 1);
        assert_eq!(k2.get() as uint, 2);
    }

    #[test]
    fn statik() {
        static K1: StaticKey = StaticKey { inner: INIT_INNER, dtor: None };
        static K2: StaticKey = StaticKey { inner: INIT_INNER, dtor: None };

        unsafe {
            assert!(K1.get().is_null());
            assert!(K2.get().is_null());
            K1.set(1 as *mut _);
            K2.set(2 as *mut _);
            assert_eq!(K1.get() as uint, 1);
            assert_eq!(K2.get() as uint, 2);
        }
    }
}

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

//! OS-based thread local storage
//!
//! This module provides an implementation of OS-based thread local storage,
//! using the native OS-provided facilities (think `TlsAlloc` or
//! `pthread_setspecific`). The interface of this differs from the other types
//! of thread-local-storage provided in this crate in that OS-based TLS can only
//! get/set pointers,
//!
//! This module also provides two flavors of TLS. One is intended for static
//! initialization, and does not contain a `Drop` implementation to deallocate
//! the OS-TLS key. The other is a type which does implement `Drop` and hence
//! has a safe interface.
//!
//! # Usage
//!
//! This module should likely not be used directly unless other primitives are
//! being built on. types such as `thread_local::scoped::Key` are likely much
//! more useful in practice than this OS-based version which likely requires
//! unsafe code to interoperate with.
//!
//! # Example
//!
//! Using a dynamically allocated TLS key. Note that this key can be shared
//! among many threads via an `Arc`.
//!
//! ```rust,ignore
//! let key = Key::new(None);
//! assert!(key.get().is_null());
//! key.set(1 as *mut u8);
//! assert!(!key.get().is_null());
//!
//! drop(key); // deallocate this TLS slot.
//! ```
//!
//! Sometimes a statically allocated key is either required or easier to work
//! with, however.
//!
//! ```rust,ignore
//! static KEY: StaticKey = INIT;
//!
//! unsafe {
//!     assert!(KEY.get().is_null());
//!     KEY.set(1 as *mut u8);
//! }
//! ```

#![allow(non_camel_case_types)]

use prelude::*;

use kinds::marker;
use rustrt::exclusive::Exclusive;
use sync::atomic::{mod, AtomicUint};
use sync::{Once, ONCE_INIT};

use sys::thread_local as imp;

/// A type for TLS keys that are statically allocated.
///
/// This type is entirely `unsafe` to use as it does not protect against
/// use-after-deallocation or use-during-deallocation.
///
/// The actual OS-TLS key is lazily allocated when this is used for the first
/// time. The key is also deallocated when the Rust runtime exits or `destroy`
/// is called, whichever comes first.
///
/// # Example
///
/// ```ignore
/// use tls::os::{StaticKey, INIT};
///
/// static KEY: StaticKey = INIT;
///
/// unsafe {
///     assert!(KEY.get().is_null());
///     KEY.set(1 as *mut u8);
/// }
/// ```
pub struct StaticKey {
    /// Inner static TLS key (internals), created with by `INIT_INNER` in this
    /// module.
    pub inner: StaticKeyInner,
    /// Destructor for the TLS value.
    ///
    /// See `Key::new` for information about when the destructor runs and how
    /// it runs.
    pub dtor: Option<unsafe extern fn(*mut u8)>,
}

/// Inner contents of `StaticKey`, created by the `INIT_INNER` constant.
pub struct StaticKeyInner {
    key: AtomicUint,
    nc: marker::NoCopy,
}

/// A type for a safely managed OS-based TLS slot.
///
/// This type allocates an OS TLS key when it is initialized and will deallocate
/// the key when it falls out of scope. When compared with `StaticKey`, this
/// type is entirely safe to use.
///
/// Implementations will likely, however, contain unsafe code as this type only
/// operates on `*mut u8`, an unsafe pointer.
///
/// # Example
///
/// ```rust,ignore
/// use tls::os::Key;
///
/// let key = Key::new(None);
/// assert!(key.get().is_null());
/// key.set(1 as *mut u8);
/// assert!(!key.get().is_null());
///
/// drop(key); // deallocate this TLS slot.
/// ```
pub struct Key {
    key: imp::Key,
}

/// Constant initialization value for static TLS keys.
///
/// This value specifies no destructor by default.
pub const INIT: StaticKey = StaticKey {
    inner: INIT_INNER,
    dtor: None,
};

/// Constant initialization value for the inner part of static TLS keys.
///
/// This value allows specific configuration of the destructor for a TLS key.
pub const INIT_INNER: StaticKeyInner = StaticKeyInner {
    key: atomic::INIT_ATOMIC_UINT,
    nc: marker::NoCopy,
};

static INIT_KEYS: Once = ONCE_INIT;
static mut KEYS: *mut Exclusive<Vec<imp::Key>> = 0 as *mut _;

impl StaticKey {
    /// Gets the value associated with this TLS key
    ///
    /// This will lazily allocate a TLS key from the OS if one has not already
    /// been allocated.
    #[inline]
    pub unsafe fn get(&self) -> *mut u8 { imp::get(self.key()) }

    /// Sets this TLS key to a new value.
    ///
    /// This will lazily allocate a TLS key from the OS if one has not already
    /// been allocated.
    #[inline]
    pub unsafe fn set(&self, val: *mut u8) { imp::set(self.key(), val) }

    /// Deallocates this OS TLS key.
    ///
    /// This function is unsafe as there is no guarantee that the key is not
    /// currently in use by other threads or will not ever be used again.
    ///
    /// Note that this does *not* run the user-provided destructor if one was
    /// specified at definition time. Doing so must be done manually.
    pub unsafe fn destroy(&self) {
        match self.inner.key.swap(0, atomic::SeqCst) {
            0 => {}
            n => { imp::destroy(n as imp::Key) }
        }
    }

    #[inline]
    unsafe fn key(&self) -> imp::Key {
        match self.inner.key.load(atomic::Relaxed) {
            0 => self.lazy_init() as imp::Key,
            n => n as imp::Key
        }
    }

    unsafe fn lazy_init(&self) -> uint {
        let key = imp::create(self.dtor);
        assert!(key != 0);
        match self.inner.key.compare_and_swap(0, key as uint, atomic::SeqCst) {
            // The CAS succeeded, so we've created the actual key
            0 => key as uint,
            // If someone beat us to the punch, use their key instead
            n => { imp::destroy(key); n }
        }
    }
}

impl Key {
    /// Create a new managed OS TLS key.
    ///
    /// This key will be deallocated when the key falls out of scope.
    ///
    /// The argument provided is an optionally-specified destructor for the
    /// value of this TLS key. When a thread exits and the value for this key
    /// is non-null the destructor will be invoked. The TLS value will be reset
    /// to null before the destructor is invoked.
    ///
    /// Note that the destructor will not be run when the `Key` goes out of
    /// scope.
    #[inline]
    pub fn new(dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
        Key { key: unsafe { imp::create(dtor) } }
    }

    /// See StaticKey::get
    #[inline]
    pub fn get(&self) -> *mut u8 {
        unsafe { imp::get(self.key) }
    }

    /// See StaticKey::set
    #[inline]
    pub fn set(&self, val: *mut u8) {
        unsafe { imp::set(self.key, val) }
    }
}

impl Drop for Key {
    fn drop(&mut self) {
        unsafe { imp::destroy(self.key) }
    }
}

#[cfg(test)]
mod tests {
    use prelude::*;
    use super::{Key, StaticKey, INIT_INNER};

    fn assert_sync<T: Sync>() {}
    fn assert_send<T: Send>() {}

    #[test]
    fn smoke() {
        assert_sync::<Key>();
        assert_send::<Key>();

        let k1 = Key::new(None);
        let k2 = Key::new(None);
        assert!(k1.get().is_null());
        assert!(k2.get().is_null());
        k1.set(1 as *mut _);
        k2.set(2 as *mut _);
        assert_eq!(k1.get() as uint, 1);
        assert_eq!(k2.get() as uint, 2);
    }

    #[test]
    fn statik() {
        static K1: StaticKey = StaticKey { inner: INIT_INNER, dtor: None };
        static K2: StaticKey = StaticKey { inner: INIT_INNER, dtor: None };

        unsafe {
            assert!(K1.get().is_null());
            assert!(K2.get().is_null());
            K1.set(1 as *mut _);
            K2.set(2 as *mut _);
            assert_eq!(K1.get() as uint, 1);
            assert_eq!(K2.get() as uint, 2);
        }
    }
}

<|endoftext|>


<commit_before><commit_msg>sevice lane<commit_after>use std::io;
use std::io::prelude::*;

fn main() {
    let mut stdin = io::stdin();

    //don't need it
    let n_t_line = stdin.lock().lines().next().unwrap().unwrap();

    let segment_widths: Vec<u32> =
        stdin.lock().lines()    //Iterator over lines in stdin()
        .next().unwrap().unwrap()   //String represents next line
        .trim().split(' ')  //Splitted string(Vec<&str>)
        .map(|x| x.parse::<u32>().unwrap()).collect();  //Parse each value as u32 and collect in Vec

    for line in stdin.lock().lines() {
        let start_stop: Vec<usize> = line.unwrap().trim().split(' ').map(|x| x.parse::<usize>().unwrap()).collect();
        let mut min: u32 = *((segment_widths[start_stop[0]..start_stop[1]].iter()).min().unwrap());
        min = if min > 3 {3} else {min};
        println!("{:?}", min);
    }
}<|endoftext|>


<commit_before><commit_msg>Forgot a file.<commit_after>pub struct StringPool {
  name: String,
  strings: Vec<String>
}

impl StringPool {
  pub fn with_size(name: &str, number_of_strings: u32) -> StringPool {
    let strings : Vec<String> =
      (0..number_of_strings)
      .map(|_| String::new())
      .collect();
    debug!("Creating StringPool '{}' with {} strings.", name, number_of_strings);
    StringPool {
      name: name.to_string(),
      strings: strings
    }
  }

  pub fn get(&mut self) -> String {
    let string = match self.strings.pop() {
      Some(s) => {
        debug!("Pulling from '{}', size now: {}", self.name, self.size());
        s
      },
      None => {
        debug!("'{}' empty, creating a new string.", self.name);
        String::new()
      }
    };
    string
  }

  pub fn string_from(&mut self, s: &str) -> String {
    let mut string = self.get();
    string.push_str(s);
    debug!("String acquired from '{}' is '{}'", self.name, s);
    string
  }

  pub fn put(&mut self, mut s: String) {
    debug!("Returning string '{}' to pool '{}'", s, self.name);
    s.clear();
    self.strings.push(s);
    debug!("'{}' size now {}", self.name, self.size());
  }

  pub fn size(&self) -> usize {
    self.strings.len()
  }
}
<|endoftext|>


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

//! # Translation of inline assembly.

use llvm;
use trans::build::*;
use trans::callee;
use trans::common::*;
use trans::cleanup;
use trans::cleanup::CleanupMethods;
use trans::expr;
use trans::type_of;
use trans::type_::Type;

use syntax::ast;
use std::ffi::CString;
use libc::{c_uint, c_char};

// Take an inline assembly expression and splat it out via LLVM
pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
                                    -> Block<'blk, 'tcx> {
    let fcx = bcx.fcx;
    let mut bcx = bcx;
    let mut constraints = Vec::new();
    let mut output_types = Vec::new();

    let temp_scope = fcx.push_custom_cleanup_scope();

    let mut ext_inputs = Vec::new();
    let mut ext_constraints = Vec::new();

    // Prepare the output operands
    let outputs = ia.outputs.iter().enumerate().map(|(i, &(ref c, ref out, is_rw))| {
        constraints.push((*c).clone());

        let out_datum = unpack_datum!(bcx, expr::trans(bcx, &**out));
        output_types.push(type_of::type_of(bcx.ccx(), out_datum.ty));
        let val = out_datum.val;
        if is_rw {
            ext_inputs.push(unpack_result!(bcx, {
                callee::trans_arg_datum(bcx,
                                       expr_ty(bcx, &**out),
                                       out_datum,
                                       cleanup::CustomScope(temp_scope),
                                       callee::DontAutorefArg)
            }));
            ext_constraints.push(i.to_string());
        }
        val

    }).collect::<Vec<_>>();

    // Now the input operands
    let mut inputs = ia.inputs.iter().map(|&(ref c, ref input)| {
        constraints.push((*c).clone());

        let in_datum = unpack_datum!(bcx, expr::trans(bcx, &**input));
        unpack_result!(bcx, {
            callee::trans_arg_datum(bcx,
                                    expr_ty(bcx, &**input),
                                    in_datum,
                                    cleanup::CustomScope(temp_scope),
                                    callee::DontAutorefArg)
        })
    }).collect::<Vec<_>>();
    inputs.push_all(&ext_inputs[]);

    // no failure occurred preparing operands, no need to cleanup
    fcx.pop_custom_cleanup_scope(temp_scope);

    let mut constraints = constraints.iter()
                                     .map(|s| s.get().to_string())
                                     .chain(ext_constraints.into_iter())
                                     .collect::<Vec<String>>()
                                     .connect(",");

    let mut clobbers = ia.clobbers.iter()
                                  .map(|s| format!("~{{{}}}", s.get()))
                                  .collect::<Vec<String>>()
                                  .connect(",");
    let more_clobbers = get_clobbers();
    if !more_clobbers.is_empty() {
        if !clobbers.is_empty() {
            clobbers.push(',');
        }
        clobbers.push_str(&more_clobbers[]);
    }

    // Add the clobbers to our constraints list
    if clobbers.len() != 0 && constraints.len() != 0 {
        constraints.push(',');
        constraints.push_str(&clobbers[]);
    } else {
        constraints.push_str(&clobbers[]);
    }

    debug!("Asm Constraints: {}", &constraints[]);

    let num_outputs = outputs.len();

    // Depending on how many outputs we have, the return type is different
    let output_type = if num_outputs == 0 {
        Type::void(bcx.ccx())
    } else if num_outputs == 1 {
        output_types[0]
    } else {
        Type::struct_(bcx.ccx(), &output_types[], false)
    };

    let dialect = match ia.dialect {
        ast::AsmAtt   => llvm::AD_ATT,
        ast::AsmIntel => llvm::AD_Intel
    };

    let asm = CString::from_slice(ia.asm.get().as_bytes());
    let constraints = CString::from_slice(constraints.as_bytes());
    let r = InlineAsmCall(bcx,
                          asm.as_ptr(),
                          constraints.as_ptr(),
                          inputs.as_slice(),
                          output_type,
                          ia.volatile,
                          ia.alignstack,
                          dialect);

    // Again, based on how many outputs we have
    if num_outputs == 1 {
        Store(bcx, r, outputs[0]);
    } else {
        for (i, o) in outputs.iter().enumerate() {
            let v = ExtractValue(bcx, r, i);
            Store(bcx, v, *o);
        }
    }

    // Store expn_id in a metadata node so we can map LLVM errors
    // back to source locations.  See #17552.
    unsafe {
        let key = "srcloc";
        let kind = llvm::LLVMGetMDKindIDInContext(bcx.ccx().llcx(),
            key.as_ptr() as *const c_char, key.len() as c_uint);

        let val: llvm::ValueRef = C_i32(bcx.ccx(), ia.expn_id.to_llvm_cookie());

        llvm::LLVMSetMetadata(r, kind,
            llvm::LLVMMDNodeInContext(bcx.ccx().llcx(), &val, 1));
    }

    return bcx;

}

// Default per-arch clobbers
// Basically what clang does

#[cfg(any(target_arch = "arm",
          target_arch = "aarch64",
          target_arch = "mips",
          target_arch = "mipsel",
          target_arch = "powerpc"))]
fn get_clobbers() -> String {
    "".to_string()
}

#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn get_clobbers() -> String {
    "~{dirflag},~{fpsr},~{flags}".to_string()
}
<commit_msg>Clean up conditions for clobbers<commit_after>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! # Translation of inline assembly.

use llvm;
use trans::build::*;
use trans::callee;
use trans::common::*;
use trans::cleanup;
use trans::cleanup::CleanupMethods;
use trans::expr;
use trans::type_of;
use trans::type_::Type;

use syntax::ast;
use std::ffi::CString;
use libc::{c_uint, c_char};

// Take an inline assembly expression and splat it out via LLVM
pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
                                    -> Block<'blk, 'tcx> {
    let fcx = bcx.fcx;
    let mut bcx = bcx;
    let mut constraints = Vec::new();
    let mut output_types = Vec::new();

    let temp_scope = fcx.push_custom_cleanup_scope();

    let mut ext_inputs = Vec::new();
    let mut ext_constraints = Vec::new();

    // Prepare the output operands
    let outputs = ia.outputs.iter().enumerate().map(|(i, &(ref c, ref out, is_rw))| {
        constraints.push((*c).clone());

        let out_datum = unpack_datum!(bcx, expr::trans(bcx, &**out));
        output_types.push(type_of::type_of(bcx.ccx(), out_datum.ty));
        let val = out_datum.val;
        if is_rw {
            ext_inputs.push(unpack_result!(bcx, {
                callee::trans_arg_datum(bcx,
                                       expr_ty(bcx, &**out),
                                       out_datum,
                                       cleanup::CustomScope(temp_scope),
                                       callee::DontAutorefArg)
            }));
            ext_constraints.push(i.to_string());
        }
        val

    }).collect::<Vec<_>>();

    // Now the input operands
    let mut inputs = ia.inputs.iter().map(|&(ref c, ref input)| {
        constraints.push((*c).clone());

        let in_datum = unpack_datum!(bcx, expr::trans(bcx, &**input));
        unpack_result!(bcx, {
            callee::trans_arg_datum(bcx,
                                    expr_ty(bcx, &**input),
                                    in_datum,
                                    cleanup::CustomScope(temp_scope),
                                    callee::DontAutorefArg)
        })
    }).collect::<Vec<_>>();
    inputs.push_all(&ext_inputs[]);

    // no failure occurred preparing operands, no need to cleanup
    fcx.pop_custom_cleanup_scope(temp_scope);

    let mut constraints = constraints.iter()
                                     .map(|s| s.get().to_string())
                                     .chain(ext_constraints.into_iter())
                                     .collect::<Vec<String>>()
                                     .connect(",");

    let mut clobbers = ia.clobbers.iter()
                                  .map(|s| format!("~{{{}}}", s.get()))
                                  .collect::<Vec<String>>()
                                  .connect(",");
    let more_clobbers = get_clobbers();
    if !more_clobbers.is_empty() {
        if !clobbers.is_empty() {
            clobbers.push(',');
        }
        clobbers.push_str(&more_clobbers[]);
    }

    // Add the clobbers to our constraints list
    if clobbers.len() != 0 && constraints.len() != 0 {
        constraints.push(',');
        constraints.push_str(&clobbers[]);
    } else {
        constraints.push_str(&clobbers[]);
    }

    debug!("Asm Constraints: {}", &constraints[]);

    let num_outputs = outputs.len();

    // Depending on how many outputs we have, the return type is different
    let output_type = if num_outputs == 0 {
        Type::void(bcx.ccx())
    } else if num_outputs == 1 {
        output_types[0]
    } else {
        Type::struct_(bcx.ccx(), &output_types[], false)
    };

    let dialect = match ia.dialect {
        ast::AsmAtt   => llvm::AD_ATT,
        ast::AsmIntel => llvm::AD_Intel
    };

    let asm = CString::from_slice(ia.asm.get().as_bytes());
    let constraints = CString::from_slice(constraints.as_bytes());
    let r = InlineAsmCall(bcx,
                          asm.as_ptr(),
                          constraints.as_ptr(),
                          inputs.as_slice(),
                          output_type,
                          ia.volatile,
                          ia.alignstack,
                          dialect);

    // Again, based on how many outputs we have
    if num_outputs == 1 {
        Store(bcx, r, outputs[0]);
    } else {
        for (i, o) in outputs.iter().enumerate() {
            let v = ExtractValue(bcx, r, i);
            Store(bcx, v, *o);
        }
    }

    // Store expn_id in a metadata node so we can map LLVM errors
    // back to source locations.  See #17552.
    unsafe {
        let key = "srcloc";
        let kind = llvm::LLVMGetMDKindIDInContext(bcx.ccx().llcx(),
            key.as_ptr() as *const c_char, key.len() as c_uint);

        let val: llvm::ValueRef = C_i32(bcx.ccx(), ia.expn_id.to_llvm_cookie());

        llvm::LLVMSetMetadata(r, kind,
            llvm::LLVMMDNodeInContext(bcx.ccx().llcx(), &val, 1));
    }

    return bcx;

}

// Default per-arch clobbers
// Basically what clang does

#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
fn get_clobbers() -> String {
    "".to_string()
}

#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn get_clobbers() -> String {
    "~{dirflag},~{fpsr},~{flags}".to_string()
}
<|endoftext|>


<commit_before><commit_msg>Add a simple test<commit_after>use std::thread::spawn;

extern crate session_types;
use session_types::*;

fn client(n: u64, c: Chan<(), Send<u64, Eps>>) {
    c.send(n).close()
}

#[test]
fn main() {
    let n = 42;
    let (c1, c2) = session_channel();
    spawn(move || client(n, c1));

    let (c, n_) = c2.recv();
    c.close();
    assert_eq!(n, n_);
}
<|endoftext|>


<commit_before><commit_msg>Fix a bug<commit_after><|endoftext|>