<commit_before>use std::io::{Stream, IoResult, OtherIoError, IoError};
use client::request::RequestWriter;
use rfc2616::{CR, LF, SP};
use common::read_http_version;
use headers;
use status::Status;

use buffer::BufferedStream;
use server::request::{RequestBuffer};
use headers::{EndOfFile, EndOfHeaders, MalformedHeaderSyntax, MalformedHeaderValue};

pub struct ResponseReader<S> {
    stream: BufferedStream<S>,

    /// The request which this is a response to
    pub request: RequestWriter<S>,

    /// The HTTP version number; typically `(1, 1)` or, less commonly, `(1, 0)`.
    pub version: (uint, uint),

    /// The HTTP status indicated in the response.
    pub status: Status,

    /// The headers received in the response.
    pub headers: headers::response::HeaderCollection,
}

fn bad_response_err() -> IoError {
    // TODO: IoError isn't right
    IoError {
        kind: OtherIoError,
        desc: "Server returned malformed HTTP response",
        detail: None,
    }
}

impl<S: Stream> ResponseReader<S> {
    pub fn construct(mut stream: BufferedStream<S>, request: RequestWriter<S>)
            -> Result<ResponseReader<S>, (RequestWriter<S>, IoError)> {
        // TODO: raise condition at the points where Err is returned
        //let mut b = [0u8, ..4096];
        //let len = stream.read(b);
        //println!("{}", ::std::str::from_bytes(b.slice_to(len.unwrap())));
        let http_version = match read_http_version(&mut stream, |b| b == SP) {
            Ok(nums) => nums,
            Err(_) => return Err((request, bad_response_err())),
        };

        // Read the status code
        let mut digits = 0u8;
        let mut status_code = 0u16;
        loop {
            if digits == 4u8 {
                // Status code must be three digits long
                return Err((request, bad_response_err()));
            }
            match stream.read_byte() {
                Ok(b) if b >= b'0' && b <= b'9' => {
                    status_code = status_code * 10 + b as u16 - '0' as u16;
                },
                Ok(b) if b == SP => break,
                _ => return Err((request, bad_response_err())),
            }
            digits += 1;
        }

        // Read the status reason
        let mut reason = String::new();
        loop {
            match stream.read_byte() {
                Ok(b) if b == CR => {
                    if stream.read_byte() == Ok(LF) {
                        break;
                    } else {
                        // Response-Line has CR without LF. Not yet resilient; TODO.
                        return Err((request, bad_response_err()));
                    }
                }
                Ok(b) => {
                    reason.push_char(b as char);
                }
                Err(_) => return Err((request, bad_response_err())),
            }
        }

        // Now we sneakily slip back to server::RequestBuffer to avoid code duplication. This is
        // temporary, honest!
        //
        // You see, read_header and read_header_line will be replaced, as will this. The code will
        // not be shared between them as they will have ultra-smart parsers (probably using Ragel)
        // to provide fast loading of standard headers, and the set of defined headers is distinct
        // between a request and response.
        let headers = {
            let mut buffer = RequestBuffer::new(&mut stream);
            let mut headers = headers::response::HeaderCollection::new();
            loop {
                let xxx = buffer.read_header::<headers::response::Header>();
                info!("header = {:?}", xxx);
                match xxx {
                //match buffer.read_header::<headers::response::Header>() {
                    Err(EndOfFile) => {
                        //fail!("server disconnected, no more response to receive :-(");
                        return Err((request, bad_response_err()));
                    },
                    Err(EndOfHeaders) => break,
                    Err(MalformedHeaderSyntax) => {
                        return Err((request, bad_response_err()));
                    },
                    Err(MalformedHeaderValue) => {
                        println!("Bad header encountered. TODO: handle this better.");
                        // Now just ignore the header
                    },
                    Ok(header) => {
                        headers.insert(header);
                    },
                }
            }
            headers
        };

        Ok(ResponseReader {
            stream: stream,
            request: request,
            version: http_version,
            status: Status::from_code_and_reason(status_code, reason),
            headers: headers,
        })
    }
}

impl<S: Stream> Reader for ResponseReader<S> {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        self.stream.read(buf)
    }
}
<commit_msg>Print out an informative message for bad repsonses.<commit_after>use std::io::{Stream, IoResult, OtherIoError, IoError};
use client::request::RequestWriter;
use rfc2616::{CR, LF, SP};
use common::read_http_version;
use headers;
use status::Status;

use buffer::BufferedStream;
use server::request::{RequestBuffer};
use headers::{EndOfFile, EndOfHeaders, MalformedHeaderSyntax, MalformedHeaderValue};

pub struct ResponseReader<S> {
    stream: BufferedStream<S>,

    /// The request which this is a response to
    pub request: RequestWriter<S>,

    /// The HTTP version number; typically `(1, 1)` or, less commonly, `(1, 0)`.
    pub version: (uint, uint),

    /// The HTTP status indicated in the response.
    pub status: Status,

    /// The headers received in the response.
    pub headers: headers::response::HeaderCollection,
}

fn bad_response_err(msg: &str) -> IoError {
    // TODO: IoError isn't right
    println!("{}", msg); //FIXME remove when finisehd diagnosing https://github.com/servo/servo/issues/3596
    IoError {
        kind: OtherIoError,
        desc: "Server returned malformed HTTP response",
        detail: None,
    }
}

impl<S: Stream> ResponseReader<S> {
    pub fn construct(mut stream: BufferedStream<S>, request: RequestWriter<S>)
            -> Result<ResponseReader<S>, (RequestWriter<S>, IoError)> {
        // TODO: raise condition at the points where Err is returned
        //let mut b = [0u8, ..4096];
        //let len = stream.read(b);
        //println!("{}", ::std::str::from_bytes(b.slice_to(len.unwrap())));
        let http_version = match read_http_version(&mut stream, |b| b == SP) {
            Ok(nums) => nums,
            Err(_) => return Err((request, bad_response_err("invalid http version"))),
        };

        // Read the status code
        let mut digits = 0u8;
        let mut status_code = 0u16;
        loop {
            if digits == 4u8 {
                // Status code must be three digits long
                return Err((request, bad_response_err("status code > 3 digits long")));
            }
            match stream.read_byte() {
                Ok(b) if b >= b'0' && b <= b'9' => {
                    status_code = status_code * 10 + b as u16 - '0' as u16;
                },
                Ok(b) if b == SP => break,
                _ => return Err((request, bad_response_err("unknown error reading status code"))),
            }
            digits += 1;
        }

        // Read the status reason
        let mut reason = String::new();
        loop {
            match stream.read_byte() {
                Ok(b) if b == CR => {
                    if stream.read_byte() == Ok(LF) {
                        break;
                    } else {
                        // Response-Line has CR without LF. Not yet resilient; TODO.
                        return Err((request, bad_response_err("response-line has CR without LF")));
                    }
                }
                Ok(b) => {
                    reason.push_char(b as char);
                }
                Err(_) => return Err((request, bad_response_err("unknown error reading status reason"))),
            }
        }

        // Now we sneakily slip back to server::RequestBuffer to avoid code duplication. This is
        // temporary, honest!
        //
        // You see, read_header and read_header_line will be replaced, as will this. The code will
        // not be shared between them as they will have ultra-smart parsers (probably using Ragel)
        // to provide fast loading of standard headers, and the set of defined headers is distinct
        // between a request and response.
        let headers = {
            let mut buffer = RequestBuffer::new(&mut stream);
            let mut headers = headers::response::HeaderCollection::new();
            loop {
                let xxx = buffer.read_header::<headers::response::Header>();
                info!("header = {:?}", xxx);
                match xxx {
                //match buffer.read_header::<headers::response::Header>() {
                    Err(EndOfFile) => {
                        //fail!("server disconnected, no more response to receive :-(");
                        return Err((request, bad_response_err("eof while reading header")));
                    },
                    Err(EndOfHeaders) => break,
                    Err(MalformedHeaderSyntax) => {
                        return Err((request, bad_response_err("malformed header name")));
                    },
                    Err(MalformedHeaderValue) => {
                        println!("Bad header encountered. TODO: handle this better.");
                        // Now just ignore the header
                    },
                    Ok(header) => {
                        headers.insert(header);
                    },
                }
            }
            headers
        };

        Ok(ResponseReader {
            stream: stream,
            request: request,
            version: http_version,
            status: Status::from_code_and_reason(status_code, reason),
            headers: headers,
        })
    }
}

impl<S: Stream> Reader for ResponseReader<S> {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        self.stream.read(buf)
    }
}
<|endoftext|>


<commit_before>use super::common::Context;
use super::codegen::{CodeGenerator, GLOBAL_INIT_FN_NAME};
use super::lexer::lex;
use super::parser::parse;
use super::typecheck::typecheck;
use super::types::{Type, FunctionType};
use super::functions::{ExternalFunction, Function};
use super::issue::IssueTracker;

use llvm;
use llvm::ExecutionEngine;
use std::mem;

pub struct Compiler<'a> {
    ctxt: &'a Context<'a>,
    codegen: Option<CodeGenerator<'a>>,
    engine: Option<llvm::JitEngine<'a>>,
    stage: Stage,
}

#[derive(Debug, PartialEq)]
pub enum Stage {
    Lex,
    Parse,
    Typecheck,
    Codegen,
    Complete
}

impl<'a> Compiler<'a> {
    pub fn new(ctxt: &'a Context<'a>) -> Compiler<'a> {
        Compiler {
            ctxt: ctxt,
            codegen: None,
            engine: None,
            stage: Stage::Lex,
        }
    }

    pub fn compile(&mut self) -> Result<IssueTracker<'a>, IssueTracker<'a>> {
        // front end
        self.define_intrinsics();
        if !self.lex() {
            return Err(self.ctxt.issues.borrow().clone());
        }
        if !self.parse() {
            return Err(self.ctxt.issues.borrow().clone());
        }
        if !self.typecheck() {
            return Err(self.ctxt.issues.borrow().clone());
        }
        if !self.codegen() {
            return Err(self.ctxt.issues.borrow().clone());
        }
        Ok(self.ctxt.issues.borrow().clone())
    }

    pub fn lex(&mut self) -> bool {
        assert_eq!(self.stage, Stage::Lex);
        self.stage = Stage::Parse;
        lex(self.ctxt);
        return if self.ctxt.issues.borrow().has_errors() {
            false
        } else {
            self.stage = Stage::Parse;
            true
        }
    }
    pub fn parse(&mut self) -> bool {
        assert_eq!(self.stage, Stage::Parse);
        parse(self.ctxt);
        return if self.ctxt.issues.borrow().has_errors() {
            false
        } else {
            self.stage = Stage::Typecheck;
            true
        }
    }
    pub fn typecheck(&mut self) -> bool {
        assert_eq!(self.stage, Stage::Typecheck);
        typecheck(self.ctxt);
        return if self.ctxt.issues.borrow().has_errors() {
            false
        } else {
            self.stage = Stage::Codegen;
            true
        }
    }
    pub fn codegen(&mut self) -> bool {
        assert_eq!(self.stage, Stage::Codegen);
        let cg = CodeGenerator::new(self.ctxt);
        let cg_ptr: &'a CodeGenerator<'a> = unsafe { mem::transmute(&cg) };
        cg_ptr.codegen();
        self.engine = Some(llvm::JitEngine::new(&cg_ptr.module, llvm::JitOptions { opt_level: 3 }).unwrap());
        self.codegen = Some(cg);
        return if self.ctxt.issues.borrow().has_errors() {
            false
        } else {
            self.stage = Stage::Complete;
            true
        }
    }

    pub fn define_external_function(&self, name: &'static str, symbol: &'static str, ty: &FunctionType) {
        let id = self.ctxt.names.borrow_mut().new_id(name);
        let func = Function::External(ExternalFunction::new(symbol, ty.clone()));
        let ty = Type::Function(id);
        self.ctxt.functions.borrow_mut().insert(id, func);
        self.ctxt.types.borrow_mut().set_val(id, 0, ty);
    }

    pub fn define_intrinsics(&self) {
        let num_num_ty = &make_fn_ty!(self.ctxt, fn(x: Number) -> Number);
        let num_2num_ty = &make_fn_ty!(self.ctxt, fn(x: Number, y: Number) -> Number);

        self.define_external_function("sin", "llvm.sin.f64", num_num_ty);
        self.define_external_function("cos", "llvm.cos.f64", num_num_ty);
        self.define_external_function("log", "llvm.log.f64", num_num_ty);
        self.define_external_function("log10", "llvm.log10.f64", num_num_ty);
        self.define_external_function("log2", "llvm.log2.f64", num_num_ty);
        self.define_external_function("exp", "llvm.exp.f64", num_num_ty);
        self.define_external_function("exp2", "llvm.exp2.f64", num_num_ty);
        self.define_external_function("sqrt", "llvm.sqrt.f64", num_num_ty);
        self.define_external_function("abs", "llvm.fabs.f64", num_num_ty);
        self.define_external_function("floor", "llvm.floor.f64", num_num_ty);
        self.define_external_function("ceil", "llvm.ceil.f64", num_num_ty);
        self.define_external_function("trunc", "llvm.trunc.f64", num_num_ty);
        self.define_external_function("round", "llvm.round.f64", num_num_ty);

        self.define_external_function("pow", "llvm.pow.f64", num_2num_ty);
        self.define_external_function("min", "llvm.minnum.f64", num_2num_ty);
        self.define_external_function("max", "llvm.maxnum.f64", num_2num_ty);
    }

    /// Defines a function as externally accessible through get_fn after compilation
    pub fn define_entrypoint(&self, name: &'a str, ty: FunctionType) {
        // must be done before typecheck
        assert!(self.stage != Stage::Complete && self.stage != Stage::Codegen);
        let id = self.ctxt.names.borrow_mut().new_id(name);
        self.ctxt.entrypoints.borrow_mut().insert(id, ty);
    }

    pub unsafe fn get_fn<A, R>(&self, name: &'static str) -> Option<extern fn(A) -> R> {
        assert_eq!(self.stage, Stage::Complete);
        match self.codegen.as_ref().unwrap().module.get_function(name) {
            Some(f) => {
                Some(self.engine.as_ref().unwrap().get_function(f))
            },
            None => None,
        }
    }

    pub fn get_init_fn(&self) -> extern fn(()) {
        unsafe {
            self.get_fn(GLOBAL_INIT_FN_NAME).unwrap()
        }
    }
}
<commit_msg>Remove unnecessary limetime bound<commit_after>use super::common::Context;
use super::codegen::{CodeGenerator, GLOBAL_INIT_FN_NAME};
use super::lexer::lex;
use super::parser::parse;
use super::typecheck::typecheck;
use super::types::{Type, FunctionType};
use super::functions::{ExternalFunction, Function};
use super::issue::IssueTracker;

use llvm;
use llvm::ExecutionEngine;
use std::mem;

pub struct Compiler<'a> {
    ctxt: &'a Context<'a>,
    codegen: Option<CodeGenerator<'a>>,
    engine: Option<llvm::JitEngine<'a>>,
    stage: Stage,
}

#[derive(Debug, PartialEq)]
pub enum Stage {
    Lex,
    Parse,
    Typecheck,
    Codegen,
    Complete
}

impl<'a> Compiler<'a> {
    pub fn new(ctxt: &'a Context<'a>) -> Compiler<'a> {
        Compiler {
            ctxt: ctxt,
            codegen: None,
            engine: None,
            stage: Stage::Lex,
        }
    }

    pub fn compile(&mut self) -> Result<IssueTracker<'a>, IssueTracker<'a>> {
        // front end
        self.define_intrinsics();
        if !self.lex() {
            return Err(self.ctxt.issues.borrow().clone());
        }
        if !self.parse() {
            return Err(self.ctxt.issues.borrow().clone());
        }
        if !self.typecheck() {
            return Err(self.ctxt.issues.borrow().clone());
        }
        if !self.codegen() {
            return Err(self.ctxt.issues.borrow().clone());
        }
        Ok(self.ctxt.issues.borrow().clone())
    }

    pub fn lex(&mut self) -> bool {
        assert_eq!(self.stage, Stage::Lex);
        self.stage = Stage::Parse;
        lex(self.ctxt);
        return if self.ctxt.issues.borrow().has_errors() {
            false
        } else {
            self.stage = Stage::Parse;
            true
        }
    }
    pub fn parse(&mut self) -> bool {
        assert_eq!(self.stage, Stage::Parse);
        parse(self.ctxt);
        return if self.ctxt.issues.borrow().has_errors() {
            false
        } else {
            self.stage = Stage::Typecheck;
            true
        }
    }
    pub fn typecheck(&mut self) -> bool {
        assert_eq!(self.stage, Stage::Typecheck);
        typecheck(self.ctxt);
        return if self.ctxt.issues.borrow().has_errors() {
            false
        } else {
            self.stage = Stage::Codegen;
            true
        }
    }
    pub fn codegen(&mut self) -> bool {
        assert_eq!(self.stage, Stage::Codegen);
        let cg = CodeGenerator::new(self.ctxt);
        let cg_ptr: &'a CodeGenerator<'a> = unsafe { mem::transmute(&cg) };
        cg_ptr.codegen();
        self.engine = Some(llvm::JitEngine::new(&cg_ptr.module, llvm::JitOptions { opt_level: 3 }).unwrap());
        self.codegen = Some(cg);
        return if self.ctxt.issues.borrow().has_errors() {
            false
        } else {
            self.stage = Stage::Complete;
            true
        }
    }

    pub fn define_external_function(&self, name: &'static str, symbol: &'static str, ty: &FunctionType) {
        let id = self.ctxt.names.borrow_mut().new_id(name);
        let func = Function::External(ExternalFunction::new(symbol, ty.clone()));
        let ty = Type::Function(id);
        self.ctxt.functions.borrow_mut().insert(id, func);
        self.ctxt.types.borrow_mut().set_val(id, 0, ty);
    }

    pub fn define_intrinsics(&self) {
        let num_num_ty = &make_fn_ty!(self.ctxt, fn(x: Number) -> Number);
        let num_2num_ty = &make_fn_ty!(self.ctxt, fn(x: Number, y: Number) -> Number);

        self.define_external_function("sin", "llvm.sin.f64", num_num_ty);
        self.define_external_function("cos", "llvm.cos.f64", num_num_ty);
        self.define_external_function("log", "llvm.log.f64", num_num_ty);
        self.define_external_function("log10", "llvm.log10.f64", num_num_ty);
        self.define_external_function("log2", "llvm.log2.f64", num_num_ty);
        self.define_external_function("exp", "llvm.exp.f64", num_num_ty);
        self.define_external_function("exp2", "llvm.exp2.f64", num_num_ty);
        self.define_external_function("sqrt", "llvm.sqrt.f64", num_num_ty);
        self.define_external_function("abs", "llvm.fabs.f64", num_num_ty);
        self.define_external_function("floor", "llvm.floor.f64", num_num_ty);
        self.define_external_function("ceil", "llvm.ceil.f64", num_num_ty);
        self.define_external_function("trunc", "llvm.trunc.f64", num_num_ty);
        self.define_external_function("round", "llvm.round.f64", num_num_ty);

        self.define_external_function("pow", "llvm.pow.f64", num_2num_ty);
        self.define_external_function("min", "llvm.minnum.f64", num_2num_ty);
        self.define_external_function("max", "llvm.maxnum.f64", num_2num_ty);
    }

    /// Defines a function as externally accessible through get_fn after compilation
    pub fn define_entrypoint(&self, name: &'a str, ty: FunctionType) {
        // must be done before typecheck
        assert!(self.stage != Stage::Complete && self.stage != Stage::Codegen);
        let id = self.ctxt.names.borrow_mut().new_id(name);
        self.ctxt.entrypoints.borrow_mut().insert(id, ty);
    }

    pub unsafe fn get_fn<A, R>(&self, name: &str) -> Option<extern fn(A) -> R> {
        assert_eq!(self.stage, Stage::Complete);
        match self.codegen.as_ref().unwrap().module.get_function(name) {
            Some(f) => {
                Some(self.engine.as_ref().unwrap().get_function(f))
            },
            None => None,
        }
    }

    pub fn get_init_fn(&self) -> extern fn(()) {
        unsafe {
            self.get_fn(GLOBAL_INIT_FN_NAME).unwrap()
        }
    }
}
<|endoftext|>


<commit_before>use std::mem::MaybeUninit;
use std::ptr::NonNull;

#[test]
fn unitialized_zero_size_box() {
    assert_eq!(
        &*Box::<()>::new_uninit() as *const _,
        NonNull::<MaybeUninit<()>>::dangling().as_ptr(),
    );
    assert_eq!(
        Box::<[()]>::new_uninit_slice(4).as_ptr(),
        NonNull::<MaybeUninit<()>>::dangling().as_ptr(),
    );
    assert_eq!(
        Box::<[String]>::new_uninit_slice(0).as_ptr(),
        NonNull::<MaybeUninit<String>>::dangling().as_ptr(),
    );
}

#[derive(Clone, PartialEq, Eq, Debug)]
struct Dummy {
    _data: u8,
}

#[test]
fn box_clone_and_clone_from_equivalence() {
    for size in (0..8).map(|i| 2usize.pow(i)) {
        let control = vec![Dummy { _data: 42 }; size].into_boxed_slice();
        let clone = control.clone();
        let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice();
        copy.clone_from(&control);
        assert_eq!(control, clone);
        assert_eq!(control, copy);
    }
}

#[test]
fn box_clone_from_ptr_stability() {
    for size in (0..8).map(|i| 2usize.pow(i)) {
        let control = vec![Dummy { _data: 42 }; size].into_boxed_slice();
        let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice();
        let copy_raw = copy.as_ptr() as usize;
        copy.clone_from(&control);
        assert_eq!(copy.as_ptr() as usize, copy_raw);
    }

    for size in (0..8).map(|i| 2usize.pow(i)) {
        let control = vec![Dummy { _data: 42 }; size].into_boxed_slice();
        let mut copy = vec![Dummy { _data: 84 }; size + 1].into_boxed_slice();
        let copy_raw = copy.as_ptr() as usize;
        copy.clone_from(&control);
        assert_ne!(copy.as_ptr() as usize, copy_raw);
    }
}
<commit_msg>Remove flaky test and document the other's flakiness<commit_after>use std::mem::MaybeUninit;
use std::ptr::NonNull;

#[test]
fn unitialized_zero_size_box() {
    assert_eq!(
        &*Box::<()>::new_uninit() as *const _,
        NonNull::<MaybeUninit<()>>::dangling().as_ptr(),
    );
    assert_eq!(
        Box::<[()]>::new_uninit_slice(4).as_ptr(),
        NonNull::<MaybeUninit<()>>::dangling().as_ptr(),
    );
    assert_eq!(
        Box::<[String]>::new_uninit_slice(0).as_ptr(),
        NonNull::<MaybeUninit<String>>::dangling().as_ptr(),
    );
}

#[derive(Clone, PartialEq, Eq, Debug)]
struct Dummy {
    _data: u8,
}

#[test]
fn box_clone_and_clone_from_equivalence() {
    for size in (0..8).map(|i| 2usize.pow(i)) {
        let control = vec![Dummy { _data: 42 }; size].into_boxed_slice();
        let clone = control.clone();
        let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice();
        copy.clone_from(&control);
        assert_eq!(control, clone);
        assert_eq!(control, copy);
    }
}

/// This test might give a false positive in case the box realocates, but the alocator keeps the
/// original pointer.
///
/// On the other hand it won't give a false negative, if it fails than the memory was definitly not
/// reused
#[test]
fn box_clone_from_ptr_stability() {
    for size in (0..8).map(|i| 2usize.pow(i)) {
        let control = vec![Dummy { _data: 42 }; size].into_boxed_slice();
        let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice();
        let copy_raw = copy.as_ptr() as usize;
        copy.clone_from(&control);
        assert_eq!(copy.as_ptr() as usize, copy_raw);
    }
}
<|endoftext|>


<commit_before>//! Integration crate to use heap::FirstFit as Uni.rs allocator

#![feature(no_std)]
#![feature(allocator)]
#![feature(const_fn)]

#![no_std]
#![allocator]

extern crate heap;
extern crate spin;

use heap::{Allocator, FirstFit};

use spin::Mutex as SpinLock;

static mut ALLOCATOR: SpinLock<Option<FirstFit>> = SpinLock::new(None);

pub unsafe fn init(region_start: usize, region_size: usize) {
    let mut guard = ALLOCATOR.lock();

    *guard = Some(FirstFit::new(region_start as *mut u8, region_size));
}

#[no_mangle]
pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
    unsafe {
        ALLOCATOR.lock().as_mut()
            .expect("Use of uninitialized allocator").allocate(size, align)
    }
}

#[no_mangle]
pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize,
                                    align: usize) {
    unsafe {
        ALLOCATOR.lock().as_mut()
            .expect("Use of uninitialized allocator")
            .deallocate(ptr, old_size, align);
    }
}

#[no_mangle]
pub extern "C" fn __rust_reallocate(ptr: *mut u8, old_size: usize, size: usize,
                                    align: usize) -> *mut u8 {
    unsafe {
        ALLOCATOR.lock().as_mut()
            .expect("Use of uninitialized allocator")
            .reallocate(ptr, old_size, size, align)
    }
}

#[no_mangle]
pub extern "C" fn __rust_reallocate_inplace(_: *mut u8, old_size: usize,
                                            _: usize, _: usize) -> usize
{
    old_size
}

#[no_mangle]
pub extern "C" fn __rust_usable_size(size: usize, _: usize) -> usize {
    size
}
<commit_msg>liballoc_uni: Default allocator is now the buddy<commit_after>//! Integration crate to use heap::Buddy as Uni.rs allocator

#![feature(no_std)]
#![feature(allocator)]
#![feature(const_fn)]

#![no_std]
#![allocator]

extern crate heap;
extern crate spin;

use heap::{Allocator, Buddy};
use heap::buddy::FreeList;

use spin::Mutex as SpinLock;

static mut ALLOCATOR: SpinLock<Option<Buddy<'static>>> = SpinLock::new(None);

const MIN_BLOCK_SIZE: usize = 16;

// 1MB
const MAX_ORDER: u32 = 16;

// XXX: Not pretty
static mut FREE_LISTS: [FreeList; (MAX_ORDER + 1) as usize] =
[
    FreeList::new(),
    FreeList::new(),
    FreeList::new(),
    FreeList::new(),
    FreeList::new(),
    FreeList::new(),
    FreeList::new(),
    FreeList::new(),
    FreeList::new(),
    FreeList::new(),
    FreeList::new(),
    FreeList::new(),
    FreeList::new(),
    FreeList::new(),
    FreeList::new(),
    FreeList::new(),
    FreeList::new()
];

pub unsafe fn init(region_start: usize, region_size: usize) {
    let mut guard = ALLOCATOR.lock();

    *guard = Some(Buddy::new(region_start, region_size, MIN_BLOCK_SIZE,
                             MAX_ORDER, &mut FREE_LISTS[..]));
}

#[no_mangle]
pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
    unsafe {
        ALLOCATOR.lock().as_mut()
            .expect("Use of uninitialized allocator").allocate(size, align)
    }
}

#[no_mangle]
pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize,
                                    align: usize) {
    unsafe {
        ALLOCATOR.lock().as_mut()
            .expect("Use of uninitialized allocator")
            .deallocate(ptr, old_size, align);
    }
}

#[no_mangle]
pub extern "C" fn __rust_reallocate(ptr: *mut u8, old_size: usize, size: usize,
                                    align: usize) -> *mut u8 {
    unsafe {
        ALLOCATOR.lock().as_mut()
            .expect("Use of uninitialized allocator")
            .reallocate(ptr, old_size, size, align)
    }
}

#[no_mangle]
pub extern "C" fn __rust_reallocate_inplace(_: *mut u8, old_size: usize,
                                            _: usize, _: usize) -> usize
{
    old_size
}

#[no_mangle]
pub extern "C" fn __rust_usable_size(size: usize, _: usize) -> usize {
    size
}
<|endoftext|>


<commit_before>//! Shared settings module.
//!
//! This module defines data structures to access the settings defined in the meta language.
//!
//! Each settings group is translated to a `Flags` struct either in this module or in its
//! ISA-specific `settings` module. The struct provides individual getter methods for all of the
//! settings as well as computed predicate flags.
//!
//! The `Flags` struct is immutable once it has been created. A `Builder` instance is used to
//! create it.
//!
//! # Example
//! ```
//! use cretonne::settings::{self, Configurable};
//!
//! let mut b = settings::builder();
//! b.set("opt_level", "fastest");
//!
//! let f = settings::Flags::new(b);
//! assert_eq!(f.opt_level(), settings::OptLevel::Fastest);
//! ```

use std::fmt;
use std::result;

use constant_hash::simple_hash;

/// A string-based configurator for settings groups.
///
/// The `Configurable` protocol allows settings to be modified by name before a finished `Flags`
/// struct is created.
pub trait Configurable {
    /// Set the string value of any setting by name.
    ///
    /// This can set any type of setting whether it is numeric, boolean, or enumerated.
    fn set(&mut self, name: &str, value: &str) -> Result<()>;

    /// Set the value of a boolean setting by name.
    ///
    /// If the identified setting isn't a boolean, a `BadType` error is returned.
    fn set_bool(&mut self, name: &str, value: bool) -> Result<()>;
}

/// Collect settings values based on a template.
pub struct Builder {
    template: &'static detail::Template,
    bytes: Vec<u8>,
}

impl Builder {
    /// Create a new builder with defaults and names from the given template.
    pub fn new(tmpl: &'static detail::Template) -> Builder {
        Builder {
            template: tmpl,
            bytes: tmpl.defaults.into(),
        }
    }

    /// Extract contents of builder once everything is configured.
    pub fn finish(self, name: &str) -> Vec<u8> {
        assert_eq!(name, self.template.name);
        self.bytes
    }

    /// Set the value of a single bit.
    fn set_bit(&mut self, offset: usize, bit: u8, value: bool) {
        let byte = &mut self.bytes[offset];
        let mask = 1 << bit;
        if value {
            *byte |= mask;
        } else {
            *byte &= !mask;
        }
    }

    /// Look up a descriptor by name.
    fn lookup(&self, name: &str) -> Result<(usize, detail::Detail)> {
        let table = self.template.hash_table;
        let descs = self.template.descriptors;
        let mask = table.len() - 1;
        assert!((mask + 1).is_power_of_two());

        let mut idx = simple_hash(name) as usize;
        let mut step: usize = 0;

        loop {
            idx = idx & mask;
            let entry = table[idx] as usize;
            if entry >= descs.len() {
                return Err(Error::BadName);
            }
            let desc = &descs[entry];
            if desc.name == name {
                return Ok((desc.offset as usize, desc.detail));
            }
            step += 1;
            assert!(step <= mask);
            idx += step;
        }
    }
}

fn parse_bool_value(value: &str) -> Result<bool> {
    match value {
        "true" | "on" | "yes" | "1" => Ok(true),
        "false" | "off" | "no" | "0" => Ok(false),
        _ => Err(Error::BadValue),
    }
}

fn parse_enum_value(value: &str, choices: &[&str]) -> Result<u8> {
    match choices.iter().position(|&tag| tag == value) {
        Some(idx) => Ok(idx as u8),
        None => Err(Error::BadValue),
    }
}

impl Configurable for Builder {
    fn set_bool(&mut self, name: &str, value: bool) -> Result<()> {
        use self::detail::Detail;
        let (offset, detail) = try!(self.lookup(name));
        if let Detail::Bool { bit } = detail {
            self.set_bit(offset, bit, value);
            Ok(())
        } else {
            Err(Error::BadType)
        }
    }

    fn set(&mut self, name: &str, value: &str) -> Result<()> {
        use self::detail::Detail;
        let (offset, detail) = try!(self.lookup(name));
        match detail {
            Detail::Bool { bit } => {
                self.set_bit(offset, bit, try!(parse_bool_value(value)));
            }
            Detail::Num => {
                self.bytes[offset] = try!(value.parse().map_err(|_| Error::BadValue));
            }
            Detail::Enum { last, enumerators } => {
                self.bytes[offset] = try!(parse_enum_value(value,
                                                           self.template.enums(last, enumerators)));
            }
        }
        Ok(())
    }
}

/// An error produced when changing a setting.
#[derive(Debug, PartialEq, Eq)]
pub enum Error {
    /// No setting by this name exists.
    BadName,

    /// Type mismatch for setting (e.g., setting an enum setting as a bool).
    BadType,

    /// This is not a valid value for this setting.
    BadValue,
}

pub type Result<T> = result::Result<T, Error>;

/// Implementation details for generated code.
///
/// This module holds definitions that need to be public so the can be instantiated by generated
/// code in other modules.
pub mod detail {
    use std::fmt;

    /// An instruction group template.
    pub struct Template {
        pub name: &'static str,
        pub descriptors: &'static [Descriptor],
        pub enumerators: &'static [&'static str],
        pub hash_table: &'static [u16],
        pub defaults: &'static [u8],
    }

    impl Template {
        /// Get enumerators corresponding to a `Details::Enum`.
        pub fn enums(&self, last: u8, enumerators: u16) -> &[&'static str] {
            let from = enumerators as usize;
            let len = last as usize + 1;
            &self.enumerators[from..from + len]
        }

        /// Format a setting value as a TOML string. This is mostly for use by the generated
        /// `Display` implementation.
        pub fn format_toml_value(&self,
                                 detail: Detail,
                                 byte: u8,
                                 f: &mut fmt::Formatter)
                                 -> fmt::Result {
            match detail {
                Detail::Bool { bit } => write!(f, "{}", (byte & (1 << bit)) != 0),
                Detail::Num => write!(f, "{}", byte),
                Detail::Enum { last, enumerators } => {
                    if byte <= last {
                        let tags = self.enums(last, enumerators);
                        write!(f, "\"{}\"", tags[byte as usize])
                    } else {
                        write!(f, "{}", byte)
                    }
                }
            }
        }
    }

    /// A setting descriptor holds the information needed to generically set and print a setting.
    ///
    /// Each settings group will be represented as a constant DESCRIPTORS array.
    pub struct Descriptor {
        /// Lower snake-case name of setting as defined in meta.
        pub name: &'static str,

        /// Offset of byte containing this setting.
        pub offset: u32,

        /// Additional details, depending on the kind of setting.
        pub detail: Detail,
    }

    /// The different kind of settings along with descriptor bits that depend on the kind.
    #[derive(Clone, Copy)]
    pub enum Detail {
        /// A boolean setting only uses one bit, numbered from LSB.
        Bool {
            bit: u8,
        },

        /// A numerical setting uses the whole byte.
        Num,

        /// An Enum setting uses a range of enumerators.
        Enum {
            /// Numerical value of last enumerator, allowing for 1-256 enumerators.
            last: u8,

            /// First enumerator in the ENUMERATORS table.
            enumerators: u16,
        },
    }
}

// Include code generated by `meta/gen_settings.py`. This file contains a public `Flags` struct
// with an impl for all of the settings defined in `meta/cretonne/settings.py`.
include!(concat!(env!("OUT_DIR"), "/settings.rs"));

#[cfg(test)]
mod tests {
    use super::{builder, Flags};
    use super::Error::*;
    use super::Configurable;

    #[test]
    fn display_default() {
        let b = builder();
        let f = Flags::new(b);
        assert_eq!(f.to_string(),
                   "[shared]\n\
                    opt_level = \"default\"\n\
                    enable_simd = true\n");
        assert_eq!(f.opt_level(), super::OptLevel::Default);
        assert_eq!(f.enable_simd(), true);
    }

    #[test]
    fn modify_bool() {
        let mut b = builder();
        assert_eq!(b.set_bool("not_there", true), Err(BadName));
        assert_eq!(b.set_bool("enable_simd", true), Ok(()));
        assert_eq!(b.set_bool("enable_simd", false), Ok(()));

        let f = Flags::new(b);
        assert_eq!(f.enable_simd(), false);
    }

    #[test]
    fn modify_string() {
        let mut b = builder();
        assert_eq!(b.set("not_there", "true"), Err(BadName));
        assert_eq!(b.set("enable_simd", ""), Err(BadValue));
        assert_eq!(b.set("enable_simd", "best"), Err(BadValue));
        assert_eq!(b.set("opt_level", "true"), Err(BadValue));
        assert_eq!(b.set("opt_level", "best"), Ok(()));
        assert_eq!(b.set("enable_simd", "0"), Ok(()));

        let f = Flags::new(b);
        assert_eq!(f.enable_simd(), false);
        assert_eq!(f.opt_level(), super::OptLevel::Best);
    }
}
<commit_msg>Use shared quadratic probing for settings.<commit_after>//! Shared settings module.
//!
//! This module defines data structures to access the settings defined in the meta language.
//!
//! Each settings group is translated to a `Flags` struct either in this module or in its
//! ISA-specific `settings` module. The struct provides individual getter methods for all of the
//! settings as well as computed predicate flags.
//!
//! The `Flags` struct is immutable once it has been created. A `Builder` instance is used to
//! create it.
//!
//! # Example
//! ```
//! use cretonne::settings::{self, Configurable};
//!
//! let mut b = settings::builder();
//! b.set("opt_level", "fastest");
//!
//! let f = settings::Flags::new(b);
//! assert_eq!(f.opt_level(), settings::OptLevel::Fastest);
//! ```

use std::fmt;
use std::result;

use constant_hash::{probe, simple_hash};

/// A string-based configurator for settings groups.
///
/// The `Configurable` protocol allows settings to be modified by name before a finished `Flags`
/// struct is created.
pub trait Configurable {
    /// Set the string value of any setting by name.
    ///
    /// This can set any type of setting whether it is numeric, boolean, or enumerated.
    fn set(&mut self, name: &str, value: &str) -> Result<()>;

    /// Set the value of a boolean setting by name.
    ///
    /// If the identified setting isn't a boolean, a `BadType` error is returned.
    fn set_bool(&mut self, name: &str, value: bool) -> Result<()>;
}

/// Collect settings values based on a template.
pub struct Builder {
    template: &'static detail::Template,
    bytes: Vec<u8>,
}

impl Builder {
    /// Create a new builder with defaults and names from the given template.
    pub fn new(tmpl: &'static detail::Template) -> Builder {
        Builder {
            template: tmpl,
            bytes: tmpl.defaults.into(),
        }
    }

    /// Extract contents of builder once everything is configured.
    pub fn finish(self, name: &str) -> Vec<u8> {
        assert_eq!(name, self.template.name);
        self.bytes
    }

    /// Set the value of a single bit.
    fn set_bit(&mut self, offset: usize, bit: u8, value: bool) {
        let byte = &mut self.bytes[offset];
        let mask = 1 << bit;
        if value {
            *byte |= mask;
        } else {
            *byte &= !mask;
        }
    }

    /// Look up a descriptor by name.
    fn lookup(&self, name: &str) -> Result<(usize, detail::Detail)> {
        match probe(self.template, name, simple_hash(name)) {
            None => Err(Error::BadName),
            Some(entry) => {
                let d = &self.template.descriptors[self.template.hash_table[entry] as usize];
                Ok((d.offset as usize, d.detail))
            }
        }
    }
}

fn parse_bool_value(value: &str) -> Result<bool> {
    match value {
        "true" | "on" | "yes" | "1" => Ok(true),
        "false" | "off" | "no" | "0" => Ok(false),
        _ => Err(Error::BadValue),
    }
}

fn parse_enum_value(value: &str, choices: &[&str]) -> Result<u8> {
    match choices.iter().position(|&tag| tag == value) {
        Some(idx) => Ok(idx as u8),
        None => Err(Error::BadValue),
    }
}

impl Configurable for Builder {
    fn set_bool(&mut self, name: &str, value: bool) -> Result<()> {
        use self::detail::Detail;
        let (offset, detail) = try!(self.lookup(name));
        if let Detail::Bool { bit } = detail {
            self.set_bit(offset, bit, value);
            Ok(())
        } else {
            Err(Error::BadType)
        }
    }

    fn set(&mut self, name: &str, value: &str) -> Result<()> {
        use self::detail::Detail;
        let (offset, detail) = try!(self.lookup(name));
        match detail {
            Detail::Bool { bit } => {
                self.set_bit(offset, bit, try!(parse_bool_value(value)));
            }
            Detail::Num => {
                self.bytes[offset] = try!(value.parse().map_err(|_| Error::BadValue));
            }
            Detail::Enum { last, enumerators } => {
                self.bytes[offset] = try!(parse_enum_value(value,
                                                           self.template.enums(last, enumerators)));
            }
        }
        Ok(())
    }
}

/// An error produced when changing a setting.
#[derive(Debug, PartialEq, Eq)]
pub enum Error {
    /// No setting by this name exists.
    BadName,

    /// Type mismatch for setting (e.g., setting an enum setting as a bool).
    BadType,

    /// This is not a valid value for this setting.
    BadValue,
}

pub type Result<T> = result::Result<T, Error>;

/// Implementation details for generated code.
///
/// This module holds definitions that need to be public so the can be instantiated by generated
/// code in other modules.
pub mod detail {
    use std::fmt;
    use constant_hash;

    /// An instruction group template.
    pub struct Template {
        pub name: &'static str,
        pub descriptors: &'static [Descriptor],
        pub enumerators: &'static [&'static str],
        pub hash_table: &'static [u16],
        pub defaults: &'static [u8],
    }

    impl Template {
        /// Get enumerators corresponding to a `Details::Enum`.
        pub fn enums(&self, last: u8, enumerators: u16) -> &[&'static str] {
            let from = enumerators as usize;
            let len = last as usize + 1;
            &self.enumerators[from..from + len]
        }

        /// Format a setting value as a TOML string. This is mostly for use by the generated
        /// `Display` implementation.
        pub fn format_toml_value(&self,
                                 detail: Detail,
                                 byte: u8,
                                 f: &mut fmt::Formatter)
                                 -> fmt::Result {
            match detail {
                Detail::Bool { bit } => write!(f, "{}", (byte & (1 << bit)) != 0),
                Detail::Num => write!(f, "{}", byte),
                Detail::Enum { last, enumerators } => {
                    if byte <= last {
                        let tags = self.enums(last, enumerators);
                        write!(f, "\"{}\"", tags[byte as usize])
                    } else {
                        write!(f, "{}", byte)
                    }
                }
            }
        }
    }

    /// The template contains a hash table for by-name lookup.
    impl<'a> constant_hash::Table<&'a str> for Template {
        fn len(&self) -> usize {
            self.hash_table.len()
        }

        fn key(&self, idx: usize) -> Option<&'a str> {
            let e = self.hash_table[idx] as usize;
            if e < self.descriptors.len() {
                Some(self.descriptors[e].name)
            } else {
                None
            }
        }
    }

    /// A setting descriptor holds the information needed to generically set and print a setting.
    ///
    /// Each settings group will be represented as a constant DESCRIPTORS array.
    pub struct Descriptor {
        /// Lower snake-case name of setting as defined in meta.
        pub name: &'static str,

        /// Offset of byte containing this setting.
        pub offset: u32,

        /// Additional details, depending on the kind of setting.
        pub detail: Detail,
    }

    /// The different kind of settings along with descriptor bits that depend on the kind.
    #[derive(Clone, Copy)]
    pub enum Detail {
        /// A boolean setting only uses one bit, numbered from LSB.
        Bool {
            bit: u8,
        },

        /// A numerical setting uses the whole byte.
        Num,

        /// An Enum setting uses a range of enumerators.
        Enum {
            /// Numerical value of last enumerator, allowing for 1-256 enumerators.
            last: u8,

            /// First enumerator in the ENUMERATORS table.
            enumerators: u16,
        },
    }
}

// Include code generated by `meta/gen_settings.py`. This file contains a public `Flags` struct
// with an impl for all of the settings defined in `meta/cretonne/settings.py`.
include!(concat!(env!("OUT_DIR"), "/settings.rs"));

#[cfg(test)]
mod tests {
    use super::{builder, Flags};
    use super::Error::*;
    use super::Configurable;

    #[test]
    fn display_default() {
        let b = builder();
        let f = Flags::new(b);
        assert_eq!(f.to_string(),
                   "[shared]\n\
                    opt_level = \"default\"\n\
                    enable_simd = true\n");
        assert_eq!(f.opt_level(), super::OptLevel::Default);
        assert_eq!(f.enable_simd(), true);
    }

    #[test]
    fn modify_bool() {
        let mut b = builder();
        assert_eq!(b.set_bool("not_there", true), Err(BadName));
        assert_eq!(b.set_bool("enable_simd", true), Ok(()));
        assert_eq!(b.set_bool("enable_simd", false), Ok(()));

        let f = Flags::new(b);
        assert_eq!(f.enable_simd(), false);
    }

    #[test]
    fn modify_string() {
        let mut b = builder();
        assert_eq!(b.set("not_there", "true"), Err(BadName));
        assert_eq!(b.set("enable_simd", ""), Err(BadValue));
        assert_eq!(b.set("enable_simd", "best"), Err(BadValue));
        assert_eq!(b.set("opt_level", "true"), Err(BadValue));
        assert_eq!(b.set("opt_level", "best"), Ok(()));
        assert_eq!(b.set("enable_simd", "0"), Ok(()));

        let f = Flags::new(b);
        assert_eq!(f.enable_simd(), false);
        assert_eq!(f.opt_level(), super::OptLevel::Best);
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use solver::propagator::Propagator;
use solver::propagator::Status as PStatus;
use solver::variable::Variable;
use solver::dependencies::VarEventDependencies;
use solver::agenda::Agenda;
use solver::event::VarEvent;
use std::rc::Rc;
use std::cell::RefCell;
use std::fmt::{Formatter, Display, Error};
use std::result::fold;
use std::iter::range;

#[derive(Copy, Debug, PartialEq, Eq)]
pub enum Status {
  Satisfiable,
  Unsatisfiable,
  Unknown
}

pub trait Space {
  type Constraint;
  type Variable : Clone;
  type Domain;
  type Label;

  fn newvar(&mut self, dom: Self::Domain) -> Self::Variable;
  fn add(&mut self, c: Self::Constraint);
  fn solve(&mut self) -> Status;
  fn mark(&self) -> Self::Label;
  fn goto(&self, label: Self::Label) -> Self;
}

pub struct Solver<V: Variable, D, A> {
  propagators: Vec<Box<Propagator<SharedVar=Rc<RefCell<V>>, Event=<V as Variable>::Event> + 'static>>,
  variables: Vec<Rc<RefCell<V>>>,
  deps: D,
  agenda: A
}

impl<V, D, A> Space for Solver<V, D, A> where
 V: Variable+Clone,
 D: VarEventDependencies,
 A: Agenda
{
  type Constraint = Box<Propagator<SharedVar=Rc<RefCell<V>>, Event=<V as Variable>::Event> + 'static>;
  type Variable = Rc<RefCell<V>>;
  type Domain = <V as Variable>::Domain;
  type Label = Solver<V, D, A>;

  fn newvar(&mut self, dom: <Solver<V, D, A> as Space>::Domain) ->
   <Solver<V, D, A> as Space>::Variable {
    let var_idx = self.variables.len();
    self.variables.push(Rc::new(RefCell::new(Variable::new(var_idx as u32, dom))));
    self.variables[var_idx].clone()
  }

  fn add(&mut self, p: <Solver<V, D, A> as Space>::Constraint) {
    self.propagators.push(p);
  }

  fn solve(&mut self) -> Status {
    self.prepare();
    self.propagation_loop()
  }

  fn mark(&self) -> <Solver<V, D, A> as Space>::Label {
    let mut solver = Solver::new();
    solver.variables = self.variables.iter()
      .map(|v| Rc::new(RefCell::new(v.borrow().clone())))
      .collect();
    solver.propagators = self.propagators.iter()
      .map(|p| p.deep_clone(&solver.variables))
      .collect();
    solver
  }

  fn goto(&self, label: <Solver<V, D, A> as Space>::Label) -> Self
  {
    label
  }
}

impl<V, D, A> Solver<V, D, A> where
 V: Variable+Clone,
 D: VarEventDependencies,
 A: Agenda
{
  pub fn new() -> Solver<V, D, A> {
    Solver {
      propagators: vec![],
      variables: vec![],
      deps: VarEventDependencies::new(0,0),
      agenda: Agenda::new(0)
    }
  }

  fn prepare(&mut self) {
    self.init_deps();
    self.init_agenda();
  }

  fn init_deps(&mut self) {
    self.deps = VarEventDependencies::new(self.variables.len(), <<V as Variable>::Event as VarEvent>::size());
    for (p_idx, p) in self.propagators.iter().enumerate() {
      let p_deps: Vec<(u32, _)> = p.dependencies();
      for (v, ev) in p_deps.into_iter() {
        self.deps.subscribe(v as usize, ev, p_idx);
      }
    }
  }

  fn init_agenda(&mut self) {
    let num_props = self.propagators.len();
    self.agenda = Agenda::new(num_props);
    for p_idx in range(0, num_props) {
      self.agenda.schedule(p_idx);
    }
  }

  fn propagation_loop(&mut self) -> Status {
    let mut unsatisfiable = false;
    while let Some(p_idx) = self.agenda.pop() {
      unsatisfiable = !self.propagate_one(p_idx);
      if unsatisfiable { break; }
    }
    if unsatisfiable { Status::Unsatisfiable }
    else if self.deps.is_empty() { Status::Satisfiable }
    else { Status::Unknown }
  }

  fn propagate_one(&mut self, p_idx: usize) -> bool {
    let (events, status) = {
      let mut prop = &mut self.propagators[p_idx];
      if let Some(events) = prop.propagate() {
        (events, prop.status())
      } else {
        return false
      }
    };
    match status {
      PStatus::Disentailed => return false,
      PStatus::Entailed => self.unlink_prop(p_idx),
      PStatus::Unknown => self.reschedule_prop(&events, p_idx)
    };
    self.react(events);
    true
  }

  fn reschedule_prop(&mut self, events: &Vec<(u32, <V as Variable>::Event)>, p_idx: usize) {
    if !events.is_empty() {
      self.agenda.schedule(p_idx);
    }
  }

  fn react(&mut self, events: Vec<(u32, <V as Variable>::Event)>) {
    for (v, ev) in events.into_iter() {
      let reactions = self.deps.react(v as usize, ev);
      for p in reactions.into_iter() {
        self.agenda.schedule(p);
      }
    }
  }

  fn unlink_prop(&mut self, p_idx: usize) {
    self.agenda.unschedule(p_idx);
    let deps: Vec<(u32, _)> = self.propagators[p_idx].dependencies();
    for &(var, ev) in deps.iter() {
      self.deps.unsubscribe(var as usize, ev, p_idx)
    }
  }
}

impl<V, D, A> Display for Solver<V, D, A> where
 V: Variable+Display
{
  fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
    let format_vars =
      self.variables.iter()
      .map(|v| v.borrow())
      .map(|v| formatter.write_fmt(format_args!("{}\n", *v)));
    fold(format_vars, (), |a,_| a)
  }
}

#[cfg(test)]
mod test {
  use super::*;
  use solver::fd::var::*;
  use solver::fd::propagator::*;
  use solver::agenda::RelaxedFifoAgenda;
  use solver::dependencies::VarEventDepsVector;

  type FDSolver = Solver<FDVar, VarEventDepsVector, RelaxedFifoAgenda>;

  #[test]
  fn basic_test() {
    let mut solver: FDSolver = Solver::new();
    let var1 = solver.newvar(Interval::new(1,4));
    let var2 = solver.newvar(Interval::new(1,4));
    let var3 = solver.newvar(Interval::new(1,1));

    solver.add(Box::new(XLessThanY::new(var1.clone(), var2)));
    assert_eq!(solver.solve(), Status::Unknown);

    solver.add(Box::new(XEqualY::new(var1, var3)));
    assert_eq!(solver.solve(), Status::Satisfiable);
  }

  #[test]
  fn example_nqueens() {
    nqueens(1, Status::Satisfiable);
    nqueens(2, Status::Unknown);
    nqueens(3, Status::Unknown);
    nqueens(4, Status::Unknown);
  }

  fn nqueens(n: usize, expect: Status) {
    let mut solver: FDSolver = Solver::new();
    let mut queens = vec![];
    // 2 queens can't share the same line.
    for _ in range(0,n) {
      queens.push(solver.newvar((1, n as i32).to_interval()));
    }
    for i in range(0usize,n-1) {
      for j in range(i + 1, n) {
        // 2 queens can't share the same diagonal.
        let q1 = (i + 1) as i32;
        let q2 = (j + 1) as i32;
        // Xi + i != Xj + j
        solver.add(Box::new(XNotEqualYPlusC::new(queens[i].clone(), queens[j].clone(), q2 - q1)));
        // Xi - i != Xj - j
        solver.add(Box::new(XNotEqualYPlusC::new(queens[i].clone(), queens[j].clone(), -q2 + q1)));
      }
    }
    // 2 queens can't share the same column.
    solver.add(Box::new(Distinct::new(queens)));
    assert_eq!(solver.solve(), expect);
  }
}
<commit_msg>Add some tests in the solver. Related to #3.<commit_after>// Copyright 2015 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use solver::propagator::Propagator;
use solver::propagator::Status as PStatus;
use solver::variable::Variable;
use solver::dependencies::VarEventDependencies;
use solver::agenda::Agenda;
use solver::event::VarEvent;
use std::rc::Rc;
use std::cell::RefCell;
use std::fmt::{Formatter, Display, Error};
use std::result::fold;
use std::iter::range;

#[derive(Copy, Debug, PartialEq, Eq)]
pub enum Status {
  Satisfiable,
  Unsatisfiable,
  Unknown
}

pub trait Space {
  type Constraint;
  type Variable : Clone;
  type Domain;
  type Label;

  fn newvar(&mut self, dom: Self::Domain) -> Self::Variable;
  fn add(&mut self, c: Self::Constraint);
  fn solve(&mut self) -> Status;
  fn mark(&self) -> Self::Label;
  fn goto(&self, label: Self::Label) -> Self;
}

pub struct Solver<V: Variable, D, A> {
  propagators: Vec<Box<Propagator<SharedVar=Rc<RefCell<V>>, Event=<V as Variable>::Event> + 'static>>,
  variables: Vec<Rc<RefCell<V>>>,
  deps: D,
  agenda: A
}

impl<V, D, A> Space for Solver<V, D, A> where
 V: Variable+Clone,
 D: VarEventDependencies,
 A: Agenda
{
  type Constraint = Box<Propagator<SharedVar=Rc<RefCell<V>>, Event=<V as Variable>::Event> + 'static>;
  type Variable = Rc<RefCell<V>>;
  type Domain = <V as Variable>::Domain;
  type Label = Solver<V, D, A>;

  fn newvar(&mut self, dom: <Solver<V, D, A> as Space>::Domain) ->
   <Solver<V, D, A> as Space>::Variable {
    let var_idx = self.variables.len();
    self.variables.push(Rc::new(RefCell::new(Variable::new(var_idx as u32, dom))));
    self.variables[var_idx].clone()
  }

  fn add(&mut self, p: <Solver<V, D, A> as Space>::Constraint) {
    self.propagators.push(p);
  }

  fn solve(&mut self) -> Status {
    self.prepare();
    self.propagation_loop()
  }

  fn mark(&self) -> <Solver<V, D, A> as Space>::Label {
    let mut solver = Solver::new();
    solver.variables = self.variables.iter()
      .map(|v| Rc::new(RefCell::new(v.borrow().clone())))
      .collect();
    solver.propagators = self.propagators.iter()
      .map(|p| p.deep_clone(&solver.variables))
      .collect();
    solver
  }

  fn goto(&self, label: <Solver<V, D, A> as Space>::Label) -> Self
  {
    label
  }
}

impl<V, D, A> Solver<V, D, A> where
 V: Variable+Clone,
 D: VarEventDependencies,
 A: Agenda
{
  pub fn new() -> Solver<V, D, A> {
    Solver {
      propagators: vec![],
      variables: vec![],
      deps: VarEventDependencies::new(0,0),
      agenda: Agenda::new(0)
    }
  }

  fn prepare(&mut self) {
    self.init_deps();
    self.init_agenda();
  }

  fn init_deps(&mut self) {
    self.deps = VarEventDependencies::new(self.variables.len(), <<V as Variable>::Event as VarEvent>::size());
    for (p_idx, p) in self.propagators.iter().enumerate() {
      let p_deps: Vec<(u32, _)> = p.dependencies();
      for (v, ev) in p_deps.into_iter() {
        self.deps.subscribe(v as usize, ev, p_idx);
      }
    }
  }

  fn init_agenda(&mut self) {
    let num_props = self.propagators.len();
    self.agenda = Agenda::new(num_props);
    for p_idx in range(0, num_props) {
      self.agenda.schedule(p_idx);
    }
  }

  fn propagation_loop(&mut self) -> Status {
    let mut unsatisfiable = false;
    while let Some(p_idx) = self.agenda.pop() {
      unsatisfiable = !self.propagate_one(p_idx);
      if unsatisfiable { break; }
    }
    if unsatisfiable { Status::Unsatisfiable }
    else if self.deps.is_empty() { Status::Satisfiable }
    else { Status::Unknown }
  }

  fn propagate_one(&mut self, p_idx: usize) -> bool {
    let (events, status) = {
      let mut prop = &mut self.propagators[p_idx];
      if let Some(events) = prop.propagate() {
        (events, prop.status())
      } else {
        return false
      }
    };
    match status {
      PStatus::Disentailed => return false,
      PStatus::Entailed => self.unlink_prop(p_idx),
      PStatus::Unknown => self.reschedule_prop(&events, p_idx)
    };
    self.react(events);
    true
  }

  fn reschedule_prop(&mut self, events: &Vec<(u32, <V as Variable>::Event)>, p_idx: usize) {
    if !events.is_empty() {
      self.agenda.schedule(p_idx);
    }
  }

  fn react(&mut self, events: Vec<(u32, <V as Variable>::Event)>) {
    for (v, ev) in events.into_iter() {
      let reactions = self.deps.react(v as usize, ev);
      for p in reactions.into_iter() {
        self.agenda.schedule(p);
      }
    }
  }

  fn unlink_prop(&mut self, p_idx: usize) {
    self.agenda.unschedule(p_idx);
    let deps: Vec<(u32, _)> = self.propagators[p_idx].dependencies();
    for &(var, ev) in deps.iter() {
      self.deps.unsubscribe(var as usize, ev, p_idx)
    }
  }
}

impl<V, D, A> Display for Solver<V, D, A> where
 V: Variable+Display
{
  fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
    let format_vars =
      self.variables.iter()
      .map(|v| v.borrow())
      .map(|v| formatter.write_fmt(format_args!("{}\n", *v)));
    fold(format_vars, (), |a,_| a)
  }
}

#[cfg(test)]
mod test {
  use super::*;
  use solver::fd::var::*;
  use solver::fd::propagator::*;
  use solver::agenda::RelaxedFifoAgenda;
  use solver::dependencies::VarEventDepsVector;

  type FDSolver = Solver<FDVar, VarEventDepsVector, RelaxedFifoAgenda>;

  #[test]
  fn basic_test() {
    let mut solver: FDSolver = Solver::new();

    assert_eq!(solver.solve(), Status::Satisfiable);

    let var1 = solver.newvar(Interval::new(1,4));
    let var2 = solver.newvar(Interval::new(1,4));
    let var3 = solver.newvar(Interval::new(1,1));

    assert_eq!(solver.solve(), Status::Satisfiable);

    solver.add(Box::new(XLessThanY::new(var1.clone(), var2)));
    assert_eq!(solver.solve(), Status::Unknown);

    solver.add(Box::new(XEqualY::new(var1, var3)));
    assert_eq!(solver.solve(), Status::Satisfiable);
  }

  fn chained_lt(n: usize, expect: Status) {
    // X1 < X2 < X3 < ... < XN, all in dom [1, 10]

    let mut solver: FDSolver = Solver::new();
    let mut vars = vec![];
    for _ in range(0,n) {
      vars.push(solver.newvar(Interval::new(1,10)));
    }
    for i in range(0,n-1) {
      solver.add(Box::new(XLessThanY::new(vars[i].clone(), vars[i+1].clone())));
    }
    assert_eq!(solver.solve(), expect);
  }

  #[test]
  fn chained_lt_tests() {
    chained_lt(1, Status::Satisfiable);
    chained_lt(2, Status::Unknown);
    chained_lt(5, Status::Unknown);
    chained_lt(9, Status::Unknown);
    chained_lt(10, Status::Satisfiable);
    chained_lt(11, Status::Unsatisfiable);
  }

  #[test]
  fn example_nqueens() {
    nqueens(1, Status::Satisfiable);
    nqueens(2, Status::Unknown);
    nqueens(3, Status::Unknown);
    nqueens(4, Status::Unknown);
  }

  fn nqueens(n: usize, expect: Status) {
    let mut solver: FDSolver = Solver::new();
    let mut queens = vec![];
    // 2 queens can't share the same line.
    for _ in range(0,n) {
      queens.push(solver.newvar((1, n as i32).to_interval()));
    }
    for i in range(0usize,n-1) {
      for j in range(i + 1, n) {
        // 2 queens can't share the same diagonal.
        let q1 = (i + 1) as i32;
        let q2 = (j + 1) as i32;
        // Xi + i != Xj + j
        solver.add(Box::new(XNotEqualYPlusC::new(queens[i].clone(), queens[j].clone(), q2 - q1)));
        // Xi - i != Xj - j
        solver.add(Box::new(XNotEqualYPlusC::new(queens[i].clone(), queens[j].clone(), -q2 + q1)));
      }
    }
    // 2 queens can't share the same column.
    solver.add(Box::new(Distinct::new(queens)));
    assert_eq!(solver.solve(), expect);
  }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate modparse_derive;
#[macro_use]
extern crate derive_builder;
#[macro_use]
extern crate torchrs;
#[macro_use]
extern crate clap;

use torchrs::autograd::{Variable, VariableArgs, VarAccess};
use torchrs::optim;
use torchrs::optim::OptimVal;
use torchrs::nn;
use torchrs::nn::{InitModuleStruct, GetFieldStruct, ModIntf, ModDelegate, Module};
use torchrs::nn::functional as F;
use torchrs::utils::data as D;
use torchrs::utils::torchvision::{datasets, transforms};
use torchrs::tensor;

use clap::{Arg, App};
#[derive(Clone, Builder)]
struct NetArgs {
    #[builder(default="64")]
    batch_size: usize,
    #[builder(default="1000")]
    test_batch_size: usize,
    #[builder(default="10")]
    epochs: u32,
    #[builder(default="0.01")]
    lr: f32,
    #[builder(default="0.5")]
    momentum: f32,
    #[builder(default="false")]
    cuda: bool,
    #[builder(default="1")]
    seed: usize,
    #[builder(default="10")]
    log_interval: usize,
}

impl Default for NetArgs {
    fn default() -> Self {
        NetArgsBuilder::default().build().unwrap()
    }
}

fn parse_args() -> NetArgs {
    let mut args = NetArgs::default();
    let matches = App::new("Torch.rs MNIST Example")
        .version("0.1")
        .author("Some Guy")
        .about("recognize handwritten digits")
        .arg(Arg::with_name("batch-size").takes_value(true))
        .arg(Arg::with_name("test-batch-size").takes_value(true))
        .arg(Arg::with_name("epochs").takes_value(true))
        .arg(Arg::with_name("lr").takes_value(true))
        .arg(Arg::with_name("momentum").takes_value(true))
        .arg(Arg::with_name("no-cuda").takes_value(false))
        .arg(Arg::with_name("seed").takes_value(true))
        .arg(Arg::with_name("log-interval").takes_value(true))
        .get_matches();
    let (b_size, tb_size, epochs, lr, momentum, seed, log_int) =
        (value_t!(matches.value_of("batch-size"), usize).ok(),
         value_t!(matches.value_of("test-batch-size"), usize).ok(),
         value_t!(matches.value_of("epochs"), u32).ok(),
         value_t!(matches.value_of("lr"), f32).ok(),
         value_t!(matches.value_of("momentum"), f32).ok(),
         value_t!(matches.value_of("seed"), usize).ok(),
         value_t!(matches.value_of("log-interval"), usize).ok());
    if let Some(b_size) = b_size {
        args.batch_size = b_size
    }
    if let Some(tb_size) = tb_size {
        args.test_batch_size = tb_size
    }
    if let Some(epochs) = epochs {
        args.epochs = epochs
    }
    if let Some(lr) = lr {
        args.lr = lr
    }
    if let Some(momentum) = momentum {
        args.momentum = momentum
    }
    if let Some(seed) = seed {
        args.seed = seed
    }
    if let Some(log_int) = log_int {
        args.log_interval = log_int
    }
    //XXX CUDA?
    args
}

#[derive(ModParse)]
struct Net<T: tensor::NumLimits> {
    delegate: nn::Module<T>,
    conv1: nn::Conv2d<T>,
    conv2: nn::Conv2d<T>,
    fc1: nn::Linear<T>,
    fc2: nn::Linear<T>,
}

impl<T: tensor::NumLimits> Net<T> {
    pub fn new() -> Net<T> {
        Net {
                delegate: nn::Module::new(),
                conv1: nn::Conv2d::build(1, 10, (5, 5)).done(),
                conv2: nn::Conv2d::build(10, 20, (5, 5)).done(),
                fc1: nn::Linear::build(320, 50).done(),
                fc2: nn::Linear::build(50, 10).done(),
            }
            .init_module()
    }
}
impl_mod_delegate!(Net);

// The forward operations could take on one of two implementations.
// The first supporting a near verbatim version of the python
// implementation, and the second supporting a slightly more
// idiomatic to Rust method chaining.

// a) as a near verbatim implementation of the python version
impl<T: tensor::NumLimits> ModIntf<T> for Net<T> {
    fn forward(&mut self, args: &mut Variable<T>) -> Variable<T> {
        let pool_val = F::MaxPool2dArgs::default();
        let mut dropout_val = F::DropoutArgs::default();
        dropout_val.training = self.delegate.training;
        let mut x = F::relu(F::max_pool2d(self.conv1.f(args.clone()), (2, 2), &pool_val));
        x = F::relu(F::max_pool2d(F::dropout2d(self.conv2.f(x), &dropout_val),
                                  (2, 2),
                                  &pool_val));
        x = x.view([-1, 320]);
        x = F::relu(self.fc1.f(x));
        x = F::dropout(x, &dropout_val);
        x = self.fc2.f(x);
        F::log_softmax(x)
    }
}

fn train(model: &mut Net<f32>,
         args: &NetArgs,
         train_loader: &D::BatchLoader<f32, i64>,
         epoch: u32,
         optimizer: &mut optim::OptIntf<f32>) {
    model.train();
    for (batch_idx, (ref data, ref target)) in train_loader.iter().enumerate() {
        let (mut data, target) = if args.cuda {
            (Variable::new(data.cuda(None).clone()), Variable::new(target.cuda(None).clone()))
        } else {
            (Variable::new(data.clone()), Variable::new(target.clone()))
        };
        optimizer.zero_grad(model);
        let output = model.f(data.clone());
        let mut loss = F::nll_loss(output, target, &F::NLLLossArgs::default());
        loss.backward();
        optimizer.step(model);
        model.free_graph();
        if batch_idx % args.log_interval == 0 {
            println!("Train Epoch: {} [{}/{} ({:.0}%)]\tLoss: {:.6}",
                     epoch,
                     batch_idx * data.data().len(),
                     train_loader.dataset.len(),
                     100. * (batch_idx as f32) / train_loader.len() as f32,
                     loss.data()[0]);
        }
    }
}

fn test(model: &mut Net<f32>, args: &NetArgs, test_loader: &D::BatchLoader<f32, i64>) {
    model.eval();
    let mut test_loss = 0.;
    let mut correct = 0;
    for (ref data, ref target) in test_loader.iter() {
        let varargs = VariableArgs {
            volatile: true,
            ..Default::default()
        };
        let (data, mut target) = if args.cuda {
            (Variable::new_args(data.cuda(None).clone(), &varargs),
             Variable::new(target.cuda(None).clone()))
        } else {
            (Variable::new_args(data.clone(), &varargs), Variable::new(target.clone()))
        };
        let mut output = model.f(data);
        test_loss += F::nll_loss(output.clone(), target.clone(), &F::NLLLossArgs::default());
        let pred = output.data().max_reduce(1).1;
        correct += pred.eq_tensor(&*target.data()).cpu().sum() as u32;
    }
    test_loss /= test_loader.len() as f32;
    println!("\nTest set: Average loss: {:.4}, Accuracy: {}/{} ({:.0}%)\n",
             test_loss,
             correct,
             test_loader.dataset.len(),
             100. * (correct as f32) / (test_loader.dataset.len() as f32))

}

fn main() {
    let args = parse_args();
    let train_loader: D::BatchLoader<f32, i64> = D::DataLoader::build()
        .batch_size(args.batch_size)
        .done(datasets::MNIST::<f32>::build("../data")
                  .download(false)
                  .done(None));

    let test_loader: D::BatchLoader<f32, i64> = D::DataLoader::build()
        .batch_size(args.batch_size)
        .done(datasets::MNIST::<f32>::build("../data")
                  .train(false)
                  .done(None));
    let mut model = Net::new();
    let mut optimizer = optim::SGD::new(map_opt!{"lr" => args.lr, "momentum" => args.momentum});
    for epoch in 1..args.epochs + 1 {
        train(&mut model, &args, &train_loader, epoch, &mut optimizer);
        test(&mut model, &args, &test_loader);
    }
}
<commit_msg>remove stale comments<commit_after>#[macro_use]
extern crate modparse_derive;
#[macro_use]
extern crate derive_builder;
#[macro_use]
extern crate torchrs;
#[macro_use]
extern crate clap;

use torchrs::autograd::{Variable, VariableArgs, VarAccess};
use torchrs::optim;
use torchrs::optim::OptimVal;
use torchrs::nn;
use torchrs::nn::{InitModuleStruct, GetFieldStruct, ModIntf, ModDelegate, Module};
use torchrs::nn::functional as F;
use torchrs::utils::data as D;
use torchrs::utils::torchvision::{datasets, transforms};
use torchrs::tensor;

use clap::{Arg, App};
#[derive(Clone, Builder)]
struct NetArgs {
    #[builder(default="64")]
    batch_size: usize,
    #[builder(default="1000")]
    test_batch_size: usize,
    #[builder(default="10")]
    epochs: u32,
    #[builder(default="0.01")]
    lr: f32,
    #[builder(default="0.5")]
    momentum: f32,
    #[builder(default="false")]
    cuda: bool,
    #[builder(default="1")]
    seed: usize,
    #[builder(default="10")]
    log_interval: usize,
}

impl Default for NetArgs {
    fn default() -> Self {
        NetArgsBuilder::default().build().unwrap()
    }
}

fn parse_args() -> NetArgs {
    let mut args = NetArgs::default();
    let matches = App::new("Torch.rs MNIST Example")
        .version("0.1")
        .author("Some Guy")
        .about("recognize handwritten digits")
        .arg(Arg::with_name("batch-size").takes_value(true))
        .arg(Arg::with_name("test-batch-size").takes_value(true))
        .arg(Arg::with_name("epochs").takes_value(true))
        .arg(Arg::with_name("lr").takes_value(true))
        .arg(Arg::with_name("momentum").takes_value(true))
        .arg(Arg::with_name("no-cuda").takes_value(false))
        .arg(Arg::with_name("seed").takes_value(true))
        .arg(Arg::with_name("log-interval").takes_value(true))
        .get_matches();
    let (b_size, tb_size, epochs, lr, momentum, seed, log_int) =
        (value_t!(matches.value_of("batch-size"), usize).ok(),
         value_t!(matches.value_of("test-batch-size"), usize).ok(),
         value_t!(matches.value_of("epochs"), u32).ok(),
         value_t!(matches.value_of("lr"), f32).ok(),
         value_t!(matches.value_of("momentum"), f32).ok(),
         value_t!(matches.value_of("seed"), usize).ok(),
         value_t!(matches.value_of("log-interval"), usize).ok());
    if let Some(b_size) = b_size {
        args.batch_size = b_size
    }
    if let Some(tb_size) = tb_size {
        args.test_batch_size = tb_size
    }
    if let Some(epochs) = epochs {
        args.epochs = epochs
    }
    if let Some(lr) = lr {
        args.lr = lr
    }
    if let Some(momentum) = momentum {
        args.momentum = momentum
    }
    if let Some(seed) = seed {
        args.seed = seed
    }
    if let Some(log_int) = log_int {
        args.log_interval = log_int
    }
    //XXX CUDA?
    args
}

#[derive(ModParse)]
struct Net<T: tensor::NumLimits> {
    delegate: nn::Module<T>,
    conv1: nn::Conv2d<T>,
    conv2: nn::Conv2d<T>,
    fc1: nn::Linear<T>,
    fc2: nn::Linear<T>,
}

impl<T: tensor::NumLimits> Net<T> {
    pub fn new() -> Net<T> {
        Net {
                delegate: nn::Module::new(),
                conv1: nn::Conv2d::build(1, 10, (5, 5)).done(),
                conv2: nn::Conv2d::build(10, 20, (5, 5)).done(),
                fc1: nn::Linear::build(320, 50).done(),
                fc2: nn::Linear::build(50, 10).done(),
            }
            .init_module()
    }
}
impl_mod_delegate!(Net);

impl<T: tensor::NumLimits> ModIntf<T> for Net<T> {
    fn forward(&mut self, args: &mut Variable<T>) -> Variable<T> {
        let pool_val = F::MaxPool2dArgs::default();
        let mut dropout_val = F::DropoutArgs::default();
        dropout_val.training = self.delegate.training;
        let mut x = F::relu(F::max_pool2d(self.conv1.f(args.clone()), (2, 2), &pool_val));
        x = F::relu(F::max_pool2d(F::dropout2d(self.conv2.f(x), &dropout_val),
                                  (2, 2),
                                  &pool_val));
        x = x.view([-1, 320]);
        x = F::relu(self.fc1.f(x));
        x = F::dropout(x, &dropout_val);
        x = self.fc2.f(x);
        F::log_softmax(x)
    }
}

fn train(model: &mut Net<f32>,
         args: &NetArgs,
         train_loader: &D::BatchLoader<f32, i64>,
         epoch: u32,
         optimizer: &mut optim::OptIntf<f32>) {
    model.train();
    for (batch_idx, (ref data, ref target)) in train_loader.iter().enumerate() {
        let (mut data, target) = if args.cuda {
            (Variable::new(data.cuda(None).clone()), Variable::new(target.cuda(None).clone()))
        } else {
            (Variable::new(data.clone()), Variable::new(target.clone()))
        };
        optimizer.zero_grad(model);
        let output = model.f(data.clone());
        let mut loss = F::nll_loss(output, target, &F::NLLLossArgs::default());
        loss.backward();
        optimizer.step(model);
        model.free_graph();
        if batch_idx % args.log_interval == 0 {
            println!("Train Epoch: {} [{}/{} ({:.0}%)]\tLoss: {:.6}",
                     epoch,
                     batch_idx * data.data().len(),
                     train_loader.dataset.len(),
                     100. * (batch_idx as f32) / train_loader.len() as f32,
                     loss.data()[0]);
        }
    }
}

fn test(model: &mut Net<f32>, args: &NetArgs, test_loader: &D::BatchLoader<f32, i64>) {
    model.eval();
    let mut test_loss = 0.;
    let mut correct = 0;
    for (ref data, ref target) in test_loader.iter() {
        let varargs = VariableArgs {
            volatile: true,
            ..Default::default()
        };
        let (data, mut target) = if args.cuda {
            (Variable::new_args(data.cuda(None).clone(), &varargs),
             Variable::new(target.cuda(None).clone()))
        } else {
            (Variable::new_args(data.clone(), &varargs), Variable::new(target.clone()))
        };
        let mut output = model.f(data);
        test_loss += F::nll_loss(output.clone(), target.clone(), &F::NLLLossArgs::default());
        let pred = output.data().max_reduce(1).1;
        correct += pred.eq_tensor(&*target.data()).cpu().sum() as u32;
    }
    test_loss /= test_loader.len() as f32;
    println!("\nTest set: Average loss: {:.4}, Accuracy: {}/{} ({:.0}%)\n",
             test_loss,
             correct,
             test_loader.dataset.len(),
             100. * (correct as f32) / (test_loader.dataset.len() as f32))

}

fn main() {
    let args = parse_args();
    let train_loader: D::BatchLoader<f32, i64> = D::DataLoader::build()
        .batch_size(args.batch_size)
        .done(datasets::MNIST::<f32>::build("../data")
                  .download(false)
                  .done(None));

    let test_loader: D::BatchLoader<f32, i64> = D::DataLoader::build()
        .batch_size(args.batch_size)
        .done(datasets::MNIST::<f32>::build("../data")
                  .train(false)
                  .done(None));
    let mut model = Net::new();
    let mut optimizer = optim::SGD::new(map_opt!{"lr" => args.lr, "momentum" => args.momentum});
    for epoch in 1..args.epochs + 1 {
        train(&mut model, &args, &train_loader, epoch, &mut optimizer);
        test(&mut model, &args, &test_loader);
    }
}
<|endoftext|>


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

use core::prelude::*;

use middle::pat_util;
use middle::ty;
use middle::ty::{CopyValue, MoveValue, ReadValue, ValueMode, ctxt};
use middle::typeck::{method_map, method_map_entry};

use core::vec;
use std::map::HashMap;
use syntax::ast::{bind_infer, box, by_copy, by_move, by_ref, by_val, crate};
use syntax::ast::{deref, expr, expr_addr_of, expr_assign, expr_assign_op};
use syntax::ast::{expr_binary, expr_call, expr_copy, expr_field, expr_index};
use syntax::ast::{expr_match, expr_method_call, expr_paren, expr_path};
use syntax::ast::{expr_swap, expr_unary, neg, node_id, not, pat, pat_ident};
use syntax::ast::{sty_uniq, sty_value, uniq};
use syntax::ast::{fn_decl, blk};
use syntax::visit;
use syntax::visit::{fn_kind, vt};
use syntax::print::pprust;
use syntax::codemap::span;

struct VisitContext {
    tcx: ctxt,
    method_map: HashMap<node_id,method_map_entry>,
    mode: ValueMode,
}

fn compute_modes_for_fn(fk: fn_kind,
                        decl: fn_decl,
                        body: blk,
                        sp: span,
                        id: node_id,
                        &&cx: VisitContext,
                        v: vt<VisitContext>) {
    let body_cx = VisitContext { mode: MoveValue, ..cx };
    visit::visit_fn(fk, decl, body, sp, id, body_cx, v);
}

fn compute_modes_for_fn_args(callee_id: node_id,
                             args: &[@expr],
                             last_arg_is_block: bool,
                             &&cx: VisitContext,
                             v: vt<VisitContext>) {
    let arg_tys = ty::ty_fn_args(ty::node_id_to_type(cx.tcx, callee_id));
    let mut i = 0;
    for vec::each2(args, arg_tys) |arg, arg_ty| {
        if last_arg_is_block && i == args.len() - 1 {
            let block_cx = VisitContext { mode: MoveValue, ..cx };
            compute_modes_for_expr(*arg, block_cx, v);
        } else {
            match ty::resolved_mode(cx.tcx, arg_ty.mode) {
                by_ref => {
                    let arg_cx = VisitContext { mode: ReadValue, ..cx };
                    compute_modes_for_expr(*arg, arg_cx, v);
                }
                by_val | by_move | by_copy => {
                    compute_modes_for_expr(*arg, cx, v);
                }
            }
        }
        i += 1;
    }
}

fn record_mode_for_expr(expr: @expr, &&cx: VisitContext) {
    match cx.mode {
        ReadValue | CopyValue => {
            cx.tcx.value_modes.insert(expr.id, cx.mode);
        }
        MoveValue => {
            // This is, contextually, a move, but if this expression
            // is implicitly copyable it's cheaper to copy.
            let e_ty = ty::expr_ty(cx.tcx, expr);
            if ty::type_implicitly_moves(cx.tcx, e_ty) {
                cx.tcx.value_modes.insert(expr.id, MoveValue);
            } else {
                cx.tcx.value_modes.insert(expr.id, CopyValue);
            }
        }
    }
}

fn compute_modes_for_expr(expr: @expr,
                          &&cx: VisitContext,
                          v: vt<VisitContext>) {
    debug!("compute_modes_for_expr(expr=%?/%s, mode=%?)",
           expr.id, pprust::expr_to_str(expr, cx.tcx.sess.intr()),
           cx.mode);

    // Adjust the mode if there was an implicit reference here.
    let cx = match cx.tcx.adjustments.find(expr.id) {
        None => cx,
        Some(adjustment) => {
            if adjustment.autoref.is_some() {
                VisitContext { mode: ReadValue, ..cx }
            } else {
                cx
            }
        }
    };

    match copy expr.node {
        expr_call(callee, args, is_block) => {
            let callee_cx = VisitContext { mode: ReadValue, ..cx };
            compute_modes_for_expr(callee, callee_cx, v);
            compute_modes_for_fn_args(callee.id, args, is_block, cx, v);
        }
        expr_path(*) => {
            record_mode_for_expr(expr, cx);
        }
        expr_copy(expr) => {
            let callee_cx = VisitContext { mode: CopyValue, ..cx };
            compute_modes_for_expr(expr, callee_cx, v);
        }
        expr_method_call(callee, _, _, args, is_block) => {
            // The LHS of the dot may or may not result in a move, depending
            // on the method map entry.
            let callee_mode;
            match cx.method_map.find(expr.id) {
                Some(ref method_map_entry) => {
                    match method_map_entry.explicit_self {
                        sty_uniq(_) | sty_value => callee_mode = MoveValue,
                        _ => callee_mode = ReadValue
                    }
                }
                None => {
                    cx.tcx.sess.span_bug(expr.span, ~"no method map entry");
                }
            }

            let callee_cx = VisitContext { mode: callee_mode, ..cx };
            compute_modes_for_expr(callee, callee_cx, v);

            compute_modes_for_fn_args(expr.callee_id, args, is_block, cx, v);
        }
        expr_binary(_, lhs, rhs) | expr_assign_op(_, lhs, rhs) => {
            // The signatures of these take their arguments by-ref, so they
            // don't copy or move.
            let arg_cx = VisitContext { mode: ReadValue, ..cx };
            compute_modes_for_expr(lhs, arg_cx, v);
            compute_modes_for_expr(rhs, arg_cx, v);
        }
        expr_addr_of(_, arg) => {
            // Takes its argument by-ref, so it doesn't copy or move.
            let arg_cx = VisitContext { mode: ReadValue, ..cx };
            compute_modes_for_expr(arg, arg_cx, v);
        }
        expr_unary(unop, arg) => {
            match unop {
                deref => {
                    // Derefs function as reads.
                    let arg_cx = VisitContext { mode: ReadValue, ..cx };
                    compute_modes_for_expr(arg, arg_cx, v);

                    // This is an lvalue, so it needs a value mode recorded
                    // for it.
                    record_mode_for_expr(expr, cx);
                }
                box(_) | uniq(_) => {
                    let arg_cx = VisitContext { mode: MoveValue, ..cx };
                    compute_modes_for_expr(arg, arg_cx, v);
                }
                not | neg => {
                    // Takes its argument by ref.
                    let arg_cx = VisitContext { mode: ReadValue, ..cx };
                    compute_modes_for_expr(arg, arg_cx, v);
                }
            }
        }
        expr_field(arg, _, _) => {
            let arg_cx = VisitContext { mode: ReadValue, ..cx };
            compute_modes_for_expr(arg, arg_cx, v);

            record_mode_for_expr(expr, cx);
        }
        expr_assign(lhs, rhs) => {
            // The signatures of these take their arguments by-ref, so they
            // don't copy or move.
            let arg_cx = VisitContext { mode: ReadValue, ..cx };
            compute_modes_for_expr(lhs, arg_cx, v);
            compute_modes_for_expr(rhs, cx, v);
        }
        expr_swap(lhs, rhs) => {
            let arg_cx = VisitContext { mode: ReadValue, ..cx };
            compute_modes_for_expr(lhs, arg_cx, v);
            compute_modes_for_expr(rhs, arg_cx, v);
        }
        expr_index(lhs, rhs) => {
            let lhs_cx = VisitContext { mode: ReadValue, ..cx };
            compute_modes_for_expr(lhs, lhs_cx, v);
            let rhs_cx = VisitContext { mode: MoveValue, ..cx };
            compute_modes_for_expr(rhs, rhs_cx, v);

            record_mode_for_expr(expr, cx);
        }
        expr_paren(arg) => {
            compute_modes_for_expr(arg, cx, v);
            record_mode_for_expr(expr, cx);
        }
        expr_match(head, ref arms) => {
            // We must do this first so that `arms_have_by_move_bindings`
            // below knows which bindings are moves.
            for arms.each |arm| {
                (v.visit_arm)(*arm, cx, v);
            }

            let by_move_bindings_present =
                pat_util::arms_have_by_move_bindings(cx.tcx, *arms);
            if by_move_bindings_present {
                // Propagate the current mode flag downward.
                visit::visit_expr(expr, cx, v);
            } else {
                // We aren't moving into any pattern, so this is just a read.
                let head_cx = VisitContext { mode: ReadValue, ..cx };
                compute_modes_for_expr(head, head_cx, v);
            }
        }
        _ => {
            // XXX: Spell out every expression above so when we add them we
            // don't forget to update this file.
            visit::visit_expr(expr, cx, v)
        }
    }
}

fn compute_modes_for_pat(pat: @pat,
                         &&cx: VisitContext,
                         v: vt<VisitContext>) {
    match pat.node {
        pat_ident(bind_infer, _, _)
                if pat_util::pat_is_binding(cx.tcx.def_map, pat) => {
            if ty::type_implicitly_moves(cx.tcx, ty::pat_ty(cx.tcx, pat)) {
                cx.tcx.value_modes.insert(pat.id, MoveValue);
            } else {
                cx.tcx.value_modes.insert(pat.id, CopyValue);
            }
        }
        _ => {}
    }

    visit::visit_pat(pat, cx, v);
}

pub fn compute_modes(tcx: ctxt, method_map: method_map, crate: @crate) {
    let visitor = visit::mk_vt(@visit::Visitor {
        visit_fn: compute_modes_for_fn,
        visit_expr: compute_modes_for_expr,
        visit_pat: compute_modes_for_pat,
        .. *visit::default_visitor()
    });
    let callee_cx = VisitContext {
        tcx: tcx,
        method_map: method_map,
        mode: MoveValue
    };
    visit::visit_crate(*crate, callee_cx, visitor);
}

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

use core::prelude::*;

use middle::pat_util;
use middle::ty;
use middle::ty::{CopyValue, MoveValue, ReadValue, ValueMode, ctxt};
use middle::typeck::{method_map, method_map_entry};

use core::vec;
use std::map::HashMap;
use syntax::ast::{bind_infer, box, by_copy, by_move, by_ref, by_val, crate};
use syntax::ast::{deref, expr, expr_addr_of, expr_assign, expr_assign_op};
use syntax::ast::{expr_binary, expr_call, expr_copy, expr_field, expr_index};
use syntax::ast::{expr_match, expr_method_call, expr_paren, expr_path};
use syntax::ast::{expr_swap, expr_unary, neg, node_id, not, pat, pat_ident};
use syntax::ast::{expr_vstore, expr_vec, expr_rec, expr_tup, expr_lit};
use syntax::ast::{expr_cast, expr_if, expr_while, expr_loop, expr_fn};
use syntax::ast::{expr_fn_block, expr_loop_body, expr_do_body, expr_block};
use syntax::ast::{expr_unary_move, expr_fail, expr_break, expr_again};
use syntax::ast::{expr_ret, expr_log, expr_assert, expr_mac, expr_struct};
use syntax::ast::{expr_repeat};
use syntax::ast::{sty_uniq, sty_value, uniq};
use syntax::ast::{fn_decl, blk};
use syntax::visit;
use syntax::visit::{fn_kind, vt};
use syntax::print::pprust;
use syntax::codemap::span;

struct VisitContext {
    tcx: ctxt,
    method_map: HashMap<node_id,method_map_entry>,
    mode: ValueMode,
}

fn compute_modes_for_fn(fk: fn_kind,
                        decl: fn_decl,
                        body: blk,
                        sp: span,
                        id: node_id,
                        &&cx: VisitContext,
                        v: vt<VisitContext>) {
    let body_cx = VisitContext { mode: MoveValue, ..cx };
    visit::visit_fn(fk, decl, body, sp, id, body_cx, v);
}

fn compute_modes_for_fn_args(callee_id: node_id,
                             args: &[@expr],
                             last_arg_is_block: bool,
                             &&cx: VisitContext,
                             v: vt<VisitContext>) {
    let arg_tys = ty::ty_fn_args(ty::node_id_to_type(cx.tcx, callee_id));
    let mut i = 0;
    for vec::each2(args, arg_tys) |arg, arg_ty| {
        if last_arg_is_block && i == args.len() - 1 {
            let block_cx = VisitContext { mode: MoveValue, ..cx };
            compute_modes_for_expr(*arg, block_cx, v);
        } else {
            match ty::resolved_mode(cx.tcx, arg_ty.mode) {
                by_ref => {
                    let arg_cx = VisitContext { mode: ReadValue, ..cx };
                    compute_modes_for_expr(*arg, arg_cx, v);
                }
                by_val | by_move | by_copy => {
                    compute_modes_for_expr(*arg, cx, v);
                }
            }
        }
        i += 1;
    }
}

fn record_mode_for_expr(expr: @expr, &&cx: VisitContext) {
    match cx.mode {
        ReadValue | CopyValue => {
            cx.tcx.value_modes.insert(expr.id, cx.mode);
        }
        MoveValue => {
            // This is, contextually, a move, but if this expression
            // is implicitly copyable it's cheaper to copy.
            let e_ty = ty::expr_ty(cx.tcx, expr);
            if ty::type_implicitly_moves(cx.tcx, e_ty) {
                cx.tcx.value_modes.insert(expr.id, MoveValue);
            } else {
                cx.tcx.value_modes.insert(expr.id, CopyValue);
            }
        }
    }
}

fn compute_modes_for_expr(expr: @expr,
                          &&cx: VisitContext,
                          v: vt<VisitContext>) {
    debug!("compute_modes_for_expr(expr=%?/%s, mode=%?)",
           expr.id, pprust::expr_to_str(expr, cx.tcx.sess.intr()),
           cx.mode);

    // Adjust the mode if there was an implicit reference here.
    let cx = match cx.tcx.adjustments.find(expr.id) {
        None => cx,
        Some(adjustment) => {
            if adjustment.autoref.is_some() {
                VisitContext { mode: ReadValue, ..cx }
            } else {
                cx
            }
        }
    };

    match copy expr.node {
        expr_call(callee, args, is_block) => {
            let callee_cx = VisitContext { mode: ReadValue, ..cx };
            compute_modes_for_expr(callee, callee_cx, v);
            compute_modes_for_fn_args(callee.id, args, is_block, cx, v);
        }
        expr_path(*) => {
            record_mode_for_expr(expr, cx);
        }
        expr_copy(expr) => {
            let callee_cx = VisitContext { mode: CopyValue, ..cx };
            compute_modes_for_expr(expr, callee_cx, v);
        }
        expr_method_call(callee, _, _, args, is_block) => {
            // The LHS of the dot may or may not result in a move, depending
            // on the method map entry.
            let callee_mode;
            match cx.method_map.find(expr.id) {
                Some(ref method_map_entry) => {
                    match method_map_entry.explicit_self {
                        sty_uniq(_) | sty_value => callee_mode = MoveValue,
                        _ => callee_mode = ReadValue
                    }
                }
                None => {
                    cx.tcx.sess.span_bug(expr.span, ~"no method map entry");
                }
            }

            let callee_cx = VisitContext { mode: callee_mode, ..cx };
            compute_modes_for_expr(callee, callee_cx, v);

            compute_modes_for_fn_args(expr.callee_id, args, is_block, cx, v);
        }
        expr_binary(_, lhs, rhs) | expr_assign_op(_, lhs, rhs) => {
            // The signatures of these take their arguments by-ref, so they
            // don't copy or move.
            let arg_cx = VisitContext { mode: ReadValue, ..cx };
            compute_modes_for_expr(lhs, arg_cx, v);
            compute_modes_for_expr(rhs, arg_cx, v);
        }
        expr_addr_of(_, arg) => {
            // Takes its argument by-ref, so it doesn't copy or move.
            let arg_cx = VisitContext { mode: ReadValue, ..cx };
            compute_modes_for_expr(arg, arg_cx, v);
        }
        expr_unary(unop, arg) => {
            match unop {
                deref => {
                    // Derefs function as reads.
                    let arg_cx = VisitContext { mode: ReadValue, ..cx };
                    compute_modes_for_expr(arg, arg_cx, v);

                    // This is an lvalue, so it needs a value mode recorded
                    // for it.
                    record_mode_for_expr(expr, cx);
                }
                box(_) | uniq(_) => {
                    let arg_cx = VisitContext { mode: MoveValue, ..cx };
                    compute_modes_for_expr(arg, arg_cx, v);
                }
                not | neg => {
                    // Takes its argument by ref.
                    let arg_cx = VisitContext { mode: ReadValue, ..cx };
                    compute_modes_for_expr(arg, arg_cx, v);
                }
            }
        }
        expr_field(arg, _, _) => {
            let arg_cx = VisitContext { mode: ReadValue, ..cx };
            compute_modes_for_expr(arg, arg_cx, v);

            record_mode_for_expr(expr, cx);
        }
        expr_assign(lhs, rhs) => {
            // The signatures of these take their arguments by-ref, so they
            // don't copy or move.
            let arg_cx = VisitContext { mode: ReadValue, ..cx };
            compute_modes_for_expr(lhs, arg_cx, v);
            compute_modes_for_expr(rhs, cx, v);
        }
        expr_swap(lhs, rhs) => {
            let arg_cx = VisitContext { mode: ReadValue, ..cx };
            compute_modes_for_expr(lhs, arg_cx, v);
            compute_modes_for_expr(rhs, arg_cx, v);
        }
        expr_index(lhs, rhs) => {
            let lhs_cx = VisitContext { mode: ReadValue, ..cx };
            compute_modes_for_expr(lhs, lhs_cx, v);
            let rhs_cx = VisitContext { mode: MoveValue, ..cx };
            compute_modes_for_expr(rhs, rhs_cx, v);

            record_mode_for_expr(expr, cx);
        }
        expr_paren(arg) => {
            compute_modes_for_expr(arg, cx, v);
            record_mode_for_expr(expr, cx);
        }
        expr_match(head, ref arms) => {
            // We must do this first so that `arms_have_by_move_bindings`
            // below knows which bindings are moves.
            for arms.each |arm| {
                (v.visit_arm)(*arm, cx, v);
            }

            let by_move_bindings_present =
                pat_util::arms_have_by_move_bindings(cx.tcx, *arms);
            if by_move_bindings_present {
                // Propagate the current mode flag downward.
                visit::visit_expr(expr, cx, v);
            } else {
                // We aren't moving into any pattern, so this is just a read.
                let head_cx = VisitContext { mode: ReadValue, ..cx };
                compute_modes_for_expr(head, head_cx, v);
            }
        }
        // Spell out every remaining expression so we don't forget to
        // update this code if we add a new variant.
        // (Maybe a macro to do this would be nice...)
        expr_vstore(*) | expr_vec(*) | expr_rec(*) | expr_tup(*) |
            expr_lit(*) | expr_cast(*) | expr_if(*) | expr_while(*) |
            expr_loop(*) | expr_fn(*) | expr_fn_block(*) |
            expr_loop_body(*) | expr_do_body(*) | expr_block(*) |
            expr_unary_move(*) | expr_fail(*) | expr_break(*) |
            expr_again(*) | expr_ret(*) | expr_log(*) | expr_assert(*) |
            expr_mac(*) | expr_struct(*) | expr_repeat(*) => {
            visit::visit_expr(expr, cx, v)
        }
    }
}

fn compute_modes_for_pat(pat: @pat,
                         &&cx: VisitContext,
                         v: vt<VisitContext>) {
    match pat.node {
        pat_ident(bind_infer, _, _)
                if pat_util::pat_is_binding(cx.tcx.def_map, pat) => {
            if ty::type_implicitly_moves(cx.tcx, ty::pat_ty(cx.tcx, pat)) {
                cx.tcx.value_modes.insert(pat.id, MoveValue);
            } else {
                cx.tcx.value_modes.insert(pat.id, CopyValue);
            }
        }
        _ => {}
    }

    visit::visit_pat(pat, cx, v);
}

pub fn compute_modes(tcx: ctxt, method_map: method_map, crate: @crate) {
    let visitor = visit::mk_vt(@visit::Visitor {
        visit_fn: compute_modes_for_fn,
        visit_expr: compute_modes_for_expr,
        visit_pat: compute_modes_for_pat,
        .. *visit::default_visitor()
    });
    let callee_cx = VisitContext {
        tcx: tcx,
        method_map: method_map,
        mode: MoveValue
    };
    visit::visit_crate(*crate, callee_cx, visitor);
}

<|endoftext|>