<commit_before>use codegen;
use cpu::global_pointers;
use cpu_context::CpuContext;
use jit::JitContext;
use prefix::{PREFIX_MASK_SEGMENT, SEG_PREFIX_ZERO};
use profiler;
use regs::{BP, BX, DI, SI};
use regs::{CS, DS, SS};
use regs::{EAX, EBP, EBX, ECX, EDI, EDX, ESI, ESP};

pub struct ModrmByte {
    segment: u32,
    first_reg: Option<u32>,
    second_reg: Option<u32>,
    shift: u8,
    immediate: i32,
    is_16: bool,
}
impl ModrmByte {
    pub fn is_nop(&self, reg: u32) -> bool {
        self.first_reg == Some(reg)
            && self.second_reg.is_none()
            && self.shift == 0
            && self.immediate == 0
            && !self.is_16
    }
}

pub fn decode(ctx: &mut CpuContext, modrm_byte: u8) -> ModrmByte {
    if ctx.asize_32() { decode32(ctx, modrm_byte) } else { decode16(ctx, modrm_byte) }
}

fn decode16(ctx: &mut CpuContext, modrm_byte: u8) -> ModrmByte {
    fn mk16(
        segment: u32,
        first_reg: Option<u32>,
        second_reg: Option<u32>,
        immediate: i32,
    ) -> ModrmByte {
        ModrmByte {
            segment,
            first_reg,
            second_reg,
            shift: 0,
            immediate,
            is_16: true,
        }
    }

    match modrm_byte & !0o070 {
        0o000 => mk16(DS, Some(BX), Some(SI), 0),
        0o001 => mk16(DS, Some(BX), Some(DI), 0),
        0o002 => mk16(SS, Some(BP), Some(SI), 0),
        0o003 => mk16(SS, Some(BP), Some(DI), 0),
        0o004 => mk16(DS, Some(SI), None, 0),
        0o005 => mk16(DS, Some(DI), None, 0),
        0o006 => mk16(DS, None, None, ctx.read_imm16() as i32),
        0o007 => mk16(DS, Some(BX), None, 0),

        0o100 => mk16(DS, Some(BX), Some(SI), ctx.read_imm8s() as i32),
        0o101 => mk16(DS, Some(BX), Some(DI), ctx.read_imm8s() as i32),
        0o102 => mk16(SS, Some(BP), Some(SI), ctx.read_imm8s() as i32),
        0o103 => mk16(SS, Some(BP), Some(DI), ctx.read_imm8s() as i32),
        0o104 => mk16(DS, Some(SI), None, ctx.read_imm8s() as i32),
        0o105 => mk16(DS, Some(DI), None, ctx.read_imm8s() as i32),
        0o106 => mk16(SS, Some(BP), None, ctx.read_imm8s() as i32),
        0o107 => mk16(DS, Some(BX), None, ctx.read_imm8s() as i32),

        0o200 => mk16(DS, Some(BX), Some(SI), ctx.read_imm16() as i32),
        0o201 => mk16(DS, Some(BX), Some(DI), ctx.read_imm16() as i32),
        0o202 => mk16(SS, Some(BP), Some(SI), ctx.read_imm16() as i32),
        0o203 => mk16(SS, Some(BP), Some(DI), ctx.read_imm16() as i32),
        0o204 => mk16(DS, Some(SI), None, ctx.read_imm16() as i32),
        0o205 => mk16(DS, Some(DI), None, ctx.read_imm16() as i32),
        0o206 => mk16(SS, Some(BP), None, ctx.read_imm16() as i32),
        0o207 => mk16(DS, Some(BX), None, ctx.read_imm16() as i32),

        _ => panic!("modrm byte >= 0xC0"),
    }
}

fn decode32(ctx: &mut CpuContext, modrm_byte: u8) -> ModrmByte {
    fn mk32(segment: u32, first_reg: Option<u32>, immediate: i32) -> ModrmByte {
        ModrmByte {
            segment,
            first_reg,
            second_reg: None,
            shift: 0,
            immediate,
            is_16: false,
        }
    }

    match modrm_byte & !0o070 {
        0o000 => mk32(DS, Some(EAX), 0),
        0o001 => mk32(DS, Some(ECX), 0),
        0o002 => mk32(DS, Some(EDX), 0),
        0o003 => mk32(DS, Some(EBX), 0),
        0o004 => decode_sib(ctx, Imm32::None),
        0o005 => mk32(DS, None, ctx.read_imm32() as i32),
        0o006 => mk32(DS, Some(ESI), 0),
        0o007 => mk32(DS, Some(EDI), 0),

        0o100 => mk32(DS, Some(EAX), ctx.read_imm8s() as i32),
        0o101 => mk32(DS, Some(ECX), ctx.read_imm8s() as i32),
        0o102 => mk32(DS, Some(EDX), ctx.read_imm8s() as i32),
        0o103 => mk32(DS, Some(EBX), ctx.read_imm8s() as i32),
        0o104 => decode_sib(ctx, Imm32::Imm8),
        0o105 => mk32(SS, Some(EBP), ctx.read_imm8s() as i32),
        0o106 => mk32(DS, Some(ESI), ctx.read_imm8s() as i32),
        0o107 => mk32(DS, Some(EDI), ctx.read_imm8s() as i32),

        0o200 => mk32(DS, Some(EAX), ctx.read_imm32() as i32),
        0o201 => mk32(DS, Some(ECX), ctx.read_imm32() as i32),
        0o202 => mk32(DS, Some(EDX), ctx.read_imm32() as i32),
        0o203 => mk32(DS, Some(EBX), ctx.read_imm32() as i32),
        0o204 => decode_sib(ctx, Imm32::Imm32),
        0o205 => mk32(SS, Some(EBP), ctx.read_imm32() as i32),
        0o206 => mk32(DS, Some(ESI), ctx.read_imm32() as i32),
        0o207 => mk32(DS, Some(EDI), ctx.read_imm32() as i32),

        _ => panic!("modrm byte >= 0xC0"),
    }
}

fn decode_sib(ctx: &mut CpuContext, immediate: Imm32) -> ModrmByte {
    let sib_byte = ctx.read_imm8();
    let r = sib_byte & 7;
    let m = sib_byte >> 3 & 7;
    let shift = sib_byte >> 6 & 3;

    let second_reg = if m == 4 { None } else { Some(m as u32) };

    let segment;
    let reg;

    if r == 4 {
        segment = SS;
        reg = ESP;
    }
    else if r == 5 {
        if immediate == Imm32::None {
            return ModrmByte {
                segment: DS,
                first_reg: None,
                second_reg,
                shift,
                immediate: ctx.read_imm32() as i32,
                is_16: false,
            };
        }
        else {
            segment = SS;
            reg = EBP;
        }
    }
    else {
        segment = DS;
        reg = r as u32;
    }

    let immediate = match immediate {
        Imm32::None => 0,
        Imm32::Imm8 => ctx.read_imm8s() as i32,
        Imm32::Imm32 => ctx.read_imm32() as i32,
    };

    ModrmByte {
        segment,
        first_reg: Some(reg),
        second_reg,
        shift,
        immediate,
        is_16: false,
    }
}

pub fn gen(ctx: &mut JitContext, modrm_byte: ModrmByte) {
    codegen::gen_profiler_stat_increment(
        ctx.builder,
        match modrm_byte {
            ModrmByte {
                first_reg: None,
                second_reg: None,
                ..
            } => profiler::stat::MODRM_SIMPLE_CONST_OFFSET,
            ModrmByte {
                first_reg: Some(_),
                second_reg: None,
                ..
            }
            | ModrmByte {
                first_reg: None,
                second_reg: Some(_),
                shift: 0,
                ..
            } => {
                if modrm_byte.immediate == 0 {
                    profiler::stat::MODRM_SIMPLE_REG
                }
                else {
                    profiler::stat::MODRM_SIMPLE_REG_WITH_OFFSET
                }
            },
            _ => profiler::stat::MODRM_COMPLEX,
        },
    );

    let mut have_something_on_stack = false;

    if let Some(reg) = modrm_byte.first_reg {
        codegen::gen_get_reg32(ctx, reg);
        have_something_on_stack = true;
    }

    if let Some(reg) = modrm_byte.second_reg {
        codegen::gen_get_reg32(ctx, reg);
        if modrm_byte.shift != 0 {
            ctx.builder.const_i32(modrm_byte.shift.into());
            ctx.builder.shl_i32();
        }
        if have_something_on_stack {
            ctx.builder.add_i32();
        }
        have_something_on_stack = true;
    }

    if modrm_byte.immediate != 0 || !have_something_on_stack {
        ctx.builder.const_i32(modrm_byte.immediate);
        if have_something_on_stack {
            ctx.builder.add_i32();
        }
    }

    if modrm_byte.is_16 {
        ctx.builder.const_i32(0xFFFF);
        ctx.builder.and_i32();
    }
    jit_add_seg_offset(ctx, modrm_byte.segment);
}

pub fn skip(ctx: &mut CpuContext, modrm_byte: u8) { let _ = decode(ctx, modrm_byte); }

#[derive(PartialEq)]
enum Imm32 {
    None,
    Imm8,
    Imm32,
}

fn can_optimize_get_seg(ctx: &mut JitContext, segment: u32) -> bool {
    (segment == DS || segment == SS) && ctx.cpu.has_flat_segmentation()
}

pub fn jit_add_seg_offset(ctx: &mut JitContext, default_segment: u32) {
    let prefix = ctx.cpu.prefixes & PREFIX_MASK_SEGMENT;
    let seg = if prefix != 0 { prefix - 1 } else { default_segment };

    if can_optimize_get_seg(ctx, seg) || prefix == SEG_PREFIX_ZERO {
        codegen::gen_profiler_stat_increment(ctx.builder, profiler::stat::SEG_OFFSET_OPTIMISED);
        return;
    }
    codegen::gen_profiler_stat_increment(ctx.builder, profiler::stat::SEG_OFFSET_NOT_OPTIMISED);

    if cfg!(debug_assertions) && seg != CS && seg != SS {
        ctx.builder.const_i32(seg as i32);
        ctx.builder.call_fn1("log_segment_null");
    }

    ctx.builder
        .load_fixed_u8(global_pointers::get_segment_is_null_offset(seg));
    ctx.builder.if_void();
    codegen::gen_trigger_gp(ctx, 0);
    ctx.builder.block_end();

    ctx.builder
        .load_fixed_i32(global_pointers::get_seg_offset(seg));
    ctx.builder.add_i32();
}
<commit_msg>Generate extra code only in profiling mode<commit_after>use codegen;
use cpu::global_pointers;
use cpu_context::CpuContext;
use jit::JitContext;
use prefix::{PREFIX_MASK_SEGMENT, SEG_PREFIX_ZERO};
use profiler;
use regs::{BP, BX, DI, SI};
use regs::{CS, DS, SS};
use regs::{EAX, EBP, EBX, ECX, EDI, EDX, ESI, ESP};

pub struct ModrmByte {
    segment: u32,
    first_reg: Option<u32>,
    second_reg: Option<u32>,
    shift: u8,
    immediate: i32,
    is_16: bool,
}
impl ModrmByte {
    pub fn is_nop(&self, reg: u32) -> bool {
        self.first_reg == Some(reg)
            && self.second_reg.is_none()
            && self.shift == 0
            && self.immediate == 0
            && !self.is_16
    }
}

pub fn decode(ctx: &mut CpuContext, modrm_byte: u8) -> ModrmByte {
    if ctx.asize_32() { decode32(ctx, modrm_byte) } else { decode16(ctx, modrm_byte) }
}

fn decode16(ctx: &mut CpuContext, modrm_byte: u8) -> ModrmByte {
    fn mk16(
        segment: u32,
        first_reg: Option<u32>,
        second_reg: Option<u32>,
        immediate: i32,
    ) -> ModrmByte {
        ModrmByte {
            segment,
            first_reg,
            second_reg,
            shift: 0,
            immediate,
            is_16: true,
        }
    }

    match modrm_byte & !0o070 {
        0o000 => mk16(DS, Some(BX), Some(SI), 0),
        0o001 => mk16(DS, Some(BX), Some(DI), 0),
        0o002 => mk16(SS, Some(BP), Some(SI), 0),
        0o003 => mk16(SS, Some(BP), Some(DI), 0),
        0o004 => mk16(DS, Some(SI), None, 0),
        0o005 => mk16(DS, Some(DI), None, 0),
        0o006 => mk16(DS, None, None, ctx.read_imm16() as i32),
        0o007 => mk16(DS, Some(BX), None, 0),

        0o100 => mk16(DS, Some(BX), Some(SI), ctx.read_imm8s() as i32),
        0o101 => mk16(DS, Some(BX), Some(DI), ctx.read_imm8s() as i32),
        0o102 => mk16(SS, Some(BP), Some(SI), ctx.read_imm8s() as i32),
        0o103 => mk16(SS, Some(BP), Some(DI), ctx.read_imm8s() as i32),
        0o104 => mk16(DS, Some(SI), None, ctx.read_imm8s() as i32),
        0o105 => mk16(DS, Some(DI), None, ctx.read_imm8s() as i32),
        0o106 => mk16(SS, Some(BP), None, ctx.read_imm8s() as i32),
        0o107 => mk16(DS, Some(BX), None, ctx.read_imm8s() as i32),

        0o200 => mk16(DS, Some(BX), Some(SI), ctx.read_imm16() as i32),
        0o201 => mk16(DS, Some(BX), Some(DI), ctx.read_imm16() as i32),
        0o202 => mk16(SS, Some(BP), Some(SI), ctx.read_imm16() as i32),
        0o203 => mk16(SS, Some(BP), Some(DI), ctx.read_imm16() as i32),
        0o204 => mk16(DS, Some(SI), None, ctx.read_imm16() as i32),
        0o205 => mk16(DS, Some(DI), None, ctx.read_imm16() as i32),
        0o206 => mk16(SS, Some(BP), None, ctx.read_imm16() as i32),
        0o207 => mk16(DS, Some(BX), None, ctx.read_imm16() as i32),

        _ => panic!("modrm byte >= 0xC0"),
    }
}

fn decode32(ctx: &mut CpuContext, modrm_byte: u8) -> ModrmByte {
    fn mk32(segment: u32, first_reg: Option<u32>, immediate: i32) -> ModrmByte {
        ModrmByte {
            segment,
            first_reg,
            second_reg: None,
            shift: 0,
            immediate,
            is_16: false,
        }
    }

    match modrm_byte & !0o070 {
        0o000 => mk32(DS, Some(EAX), 0),
        0o001 => mk32(DS, Some(ECX), 0),
        0o002 => mk32(DS, Some(EDX), 0),
        0o003 => mk32(DS, Some(EBX), 0),
        0o004 => decode_sib(ctx, Imm32::None),
        0o005 => mk32(DS, None, ctx.read_imm32() as i32),
        0o006 => mk32(DS, Some(ESI), 0),
        0o007 => mk32(DS, Some(EDI), 0),

        0o100 => mk32(DS, Some(EAX), ctx.read_imm8s() as i32),
        0o101 => mk32(DS, Some(ECX), ctx.read_imm8s() as i32),
        0o102 => mk32(DS, Some(EDX), ctx.read_imm8s() as i32),
        0o103 => mk32(DS, Some(EBX), ctx.read_imm8s() as i32),
        0o104 => decode_sib(ctx, Imm32::Imm8),
        0o105 => mk32(SS, Some(EBP), ctx.read_imm8s() as i32),
        0o106 => mk32(DS, Some(ESI), ctx.read_imm8s() as i32),
        0o107 => mk32(DS, Some(EDI), ctx.read_imm8s() as i32),

        0o200 => mk32(DS, Some(EAX), ctx.read_imm32() as i32),
        0o201 => mk32(DS, Some(ECX), ctx.read_imm32() as i32),
        0o202 => mk32(DS, Some(EDX), ctx.read_imm32() as i32),
        0o203 => mk32(DS, Some(EBX), ctx.read_imm32() as i32),
        0o204 => decode_sib(ctx, Imm32::Imm32),
        0o205 => mk32(SS, Some(EBP), ctx.read_imm32() as i32),
        0o206 => mk32(DS, Some(ESI), ctx.read_imm32() as i32),
        0o207 => mk32(DS, Some(EDI), ctx.read_imm32() as i32),

        _ => panic!("modrm byte >= 0xC0"),
    }
}

fn decode_sib(ctx: &mut CpuContext, immediate: Imm32) -> ModrmByte {
    let sib_byte = ctx.read_imm8();
    let r = sib_byte & 7;
    let m = sib_byte >> 3 & 7;
    let shift = sib_byte >> 6 & 3;

    let second_reg = if m == 4 { None } else { Some(m as u32) };

    let segment;
    let reg;

    if r == 4 {
        segment = SS;
        reg = ESP;
    }
    else if r == 5 {
        if immediate == Imm32::None {
            return ModrmByte {
                segment: DS,
                first_reg: None,
                second_reg,
                shift,
                immediate: ctx.read_imm32() as i32,
                is_16: false,
            };
        }
        else {
            segment = SS;
            reg = EBP;
        }
    }
    else {
        segment = DS;
        reg = r as u32;
    }

    let immediate = match immediate {
        Imm32::None => 0,
        Imm32::Imm8 => ctx.read_imm8s() as i32,
        Imm32::Imm32 => ctx.read_imm32() as i32,
    };

    ModrmByte {
        segment,
        first_reg: Some(reg),
        second_reg,
        shift,
        immediate,
        is_16: false,
    }
}

pub fn gen(ctx: &mut JitContext, modrm_byte: ModrmByte) {
    codegen::gen_profiler_stat_increment(
        ctx.builder,
        match modrm_byte {
            ModrmByte {
                first_reg: None,
                second_reg: None,
                ..
            } => profiler::stat::MODRM_SIMPLE_CONST_OFFSET,
            ModrmByte {
                first_reg: Some(_),
                second_reg: None,
                ..
            }
            | ModrmByte {
                first_reg: None,
                second_reg: Some(_),
                shift: 0,
                ..
            } => {
                if modrm_byte.immediate == 0 {
                    profiler::stat::MODRM_SIMPLE_REG
                }
                else {
                    profiler::stat::MODRM_SIMPLE_REG_WITH_OFFSET
                }
            },
            _ => profiler::stat::MODRM_COMPLEX,
        },
    );

    let mut have_something_on_stack = false;

    if let Some(reg) = modrm_byte.first_reg {
        codegen::gen_get_reg32(ctx, reg);
        have_something_on_stack = true;
    }

    if let Some(reg) = modrm_byte.second_reg {
        codegen::gen_get_reg32(ctx, reg);
        if modrm_byte.shift != 0 {
            ctx.builder.const_i32(modrm_byte.shift.into());
            ctx.builder.shl_i32();
        }
        if have_something_on_stack {
            ctx.builder.add_i32();
        }
        have_something_on_stack = true;
    }

    if modrm_byte.immediate != 0 || !have_something_on_stack {
        ctx.builder.const_i32(modrm_byte.immediate);
        if have_something_on_stack {
            ctx.builder.add_i32();
        }
    }

    if modrm_byte.is_16 {
        ctx.builder.const_i32(0xFFFF);
        ctx.builder.and_i32();
    }
    jit_add_seg_offset(ctx, modrm_byte.segment);
}

pub fn skip(ctx: &mut CpuContext, modrm_byte: u8) { let _ = decode(ctx, modrm_byte); }

#[derive(PartialEq)]
enum Imm32 {
    None,
    Imm8,
    Imm32,
}

fn can_optimize_get_seg(ctx: &mut JitContext, segment: u32) -> bool {
    (segment == DS || segment == SS) && ctx.cpu.has_flat_segmentation()
}

pub fn jit_add_seg_offset(ctx: &mut JitContext, default_segment: u32) {
    let prefix = ctx.cpu.prefixes & PREFIX_MASK_SEGMENT;
    let seg = if prefix != 0 { prefix - 1 } else { default_segment };

    if can_optimize_get_seg(ctx, seg) || prefix == SEG_PREFIX_ZERO {
        codegen::gen_profiler_stat_increment(ctx.builder, profiler::stat::SEG_OFFSET_OPTIMISED);
        return;
    }
    codegen::gen_profiler_stat_increment(ctx.builder, profiler::stat::SEG_OFFSET_NOT_OPTIMISED);

    if cfg!(feature = "profiler") && seg != CS && seg != SS {
        ctx.builder.const_i32(seg as i32);
        ctx.builder.call_fn1("log_segment_null");
    }

    ctx.builder
        .load_fixed_u8(global_pointers::get_segment_is_null_offset(seg));
    ctx.builder.if_void();
    codegen::gen_trigger_gp(ctx, 0);
    ctx.builder.block_end();

    ctx.builder
        .load_fixed_i32(global_pointers::get_seg_offset(seg));
    ctx.builder.add_i32();
}
<|endoftext|>


<commit_before>//! HTTP Server
//!
//! A `Server` is created to listen on a port, parse HTTP requests, and hand
//! them off to a `Handler`.
use std::fmt;
use std::net::SocketAddr;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;

use rotor::mio::{EventSet, PollOpt};
use rotor::{self, Scope};

pub use self::request::Request;
pub use self::response::Response;

use http::{self, Next};

pub use net::{Accept, HttpListener, HttpsListener};
use net::{SslServer, Transport};

mod request;
mod response;
mod message;

/// A configured `Server` ready to run.
pub struct ServerLoop<A, H> where A: Accept, H: HandlerFactory<A::Output> {
    inner: Option<(rotor::Loop<ServerFsm<A, H>>, Context<H>)>,
}

impl<A: Accept, H: HandlerFactory<A::Output>> fmt::Debug for ServerLoop<A, H> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("ServerLoop")
    }
}

/// A Server that can accept incoming network requests.
#[derive(Debug)]
pub struct Server<T: Accept> {
    listener: T,
    keep_alive: bool,
    idle_timeout: Duration,
    max_sockets: usize,
}

impl<T> Server<T> where T: Accept, T::Output: Transport {
    /// Creates a new server with the provided Listener.
    #[inline]
    pub fn new(listener: T) -> Server<T> {
        Server {
            listener: listener,
            keep_alive: true,
            idle_timeout: Duration::from_secs(10),
            max_sockets: 4096,
        }
    }

    /// Enables or disables HTTP keep-alive.
    ///
    /// Default is true.
    pub fn keep_alive(mut self, val: bool) -> Server<T> {
        self.keep_alive = val;
        self
    }

    /// Sets how long an idle connection will be kept before closing.
    ///
    /// Default is 10 seconds.
    pub fn idle_timeout(mut self, val: Duration) -> Server<T> {
        self.idle_timeout = val;
        self
    }

    /// Sets the maximum open sockets for this Server.
    ///
    /// Default is 4096, but most servers can handle much more than this.
    pub fn max_sockets(mut self, val: usize) -> Server<T> {
        self.max_sockets = val;
        self
    }
}

impl Server<HttpListener> { //<H: HandlerFactory<<HttpListener as Accept>::Output>> Server<HttpListener, H> {
    /// Creates a new HTTP server config listening on the provided address.
    pub fn http(addr: &SocketAddr) -> ::Result<Server<HttpListener>> {
        use ::rotor::mio::tcp::TcpListener;
        TcpListener::bind(addr)
            .map(HttpListener)
            .map(Server::new)
            .map_err(From::from)
    }
}

impl<S: SslServer> Server<HttpsListener<S>> {
    /// Creates a new server config that will handle `HttpStream`s over SSL.
    ///
    /// You can use any SSL implementation, as long as it implements `hyper::net::Ssl`.
    pub fn https(addr: &SocketAddr, ssl: S) -> ::Result<Server<HttpsListener<S>>> {
        HttpsListener::new(addr, ssl)
            .map(Server::new)
            .map_err(From::from)
    }
}

impl<A: Accept> Server<A> where A::Output: Transport  {
    /// Binds to a socket and starts handling connections.
    pub fn handle<H>(self, factory: H) -> ::Result<(Listening, ServerLoop<A, H>)>
    where H: HandlerFactory<A::Output> {
        let addr = try!(self.listener.local_addr());
        let shutdown = Arc::new(AtomicBool::new(false));
        let shutdown_rx = shutdown.clone();

        let mut config = rotor::Config::new();
        config.slab_capacity(self.max_sockets);
        config.mio().notify_capacity(self.max_sockets);
        let keep_alive = self.keep_alive;
        let mut loop_ = rotor::Loop::new(&config).unwrap();
        let mut notifier = None;
        {
            let notifier = &mut notifier;
            loop_.add_machine_with(move |scope| {
                *notifier = Some(scope.notifier());
                rotor_try!(scope.register(&self.listener, EventSet::readable(), PollOpt::level()));
                rotor::Response::ok(ServerFsm::Listener::<A, H>(self.listener, shutdown_rx))
            }).unwrap();
        }
        let notifier = notifier.expect("loop.add_machine failed");

        let listening = Listening {
            addr: addr,
            shutdown: (shutdown, notifier),
        };
        let server = ServerLoop {
            inner: Some((loop_, Context {
                keep_alive: keep_alive,
                factory: factory
            }))
        };
        Ok((listening, server))
    }
}

impl<A: Accept, H: HandlerFactory<A::Output>> ServerLoop<A, H> {
    /// Runs the server forever in this loop.
    ///
    /// This will block the current thread.
    pub fn run(self) {
        // drop will take care of it.
    }
}

impl<A: Accept, H: HandlerFactory<A::Output>> Drop for ServerLoop<A, H> {
    fn drop(&mut self) {
        self.inner.take().map(|(loop_, ctx)| {
            let _ = loop_.run(ctx);
        });
    }
}

struct Context<F> {
    keep_alive: bool,
    factory: F,
}

impl<F: HandlerFactory<T>, T: Transport> http::MessageHandlerFactory<(), T> for Context<F> {
    type Output = message::Message<F::Output, T>;

    fn create(&mut self, seed: http::Seed<()>) -> Option<Self::Output> {
        Some(message::Message::new(self.factory.create(seed.control())))
    }

    fn keep_alive_interest(&self) -> Next {
        Next::read()
    }
}

enum ServerFsm<A, H>
where A: Accept,
      A::Output: Transport,
      H: HandlerFactory<A::Output> {
    Listener(A, Arc<AtomicBool>),
    Conn(http::Conn<(), A::Output, message::Message<H::Output, A::Output>>)
}

impl<A, H> rotor::Machine for ServerFsm<A, H>
where A: Accept,
      A::Output: Transport,
      H: HandlerFactory<A::Output> {
    type Context = Context<H>;
    type Seed = A::Output;

    fn create(seed: Self::Seed, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, rotor::Void> {
        rotor_try!(scope.register(&seed, EventSet::readable(), PollOpt::level()));
        rotor::Response::ok(
            ServerFsm::Conn(
                http::Conn::new((), seed, Next::read(), scope.notifier())
                    .keep_alive(scope.keep_alive)
            )
        )
    }

    fn ready(self, events: EventSet, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, Self::Seed> {
        match self {
            ServerFsm::Listener(listener, rx) => {
                match listener.accept() {
                    Ok(Some(conn)) => {
                        rotor::Response::spawn(ServerFsm::Listener(listener, rx), conn)
                    },
                    Ok(None) => rotor::Response::ok(ServerFsm::Listener(listener, rx)),
                    Err(e) => {
                        error!("listener accept error {}", e);
                        // usually fine, just keep listening
                        rotor::Response::ok(ServerFsm::Listener(listener, rx))
                    }
                }
            },
            ServerFsm::Conn(conn) => {
                match conn.ready(events, scope) {
                    Some((conn, None)) => rotor::Response::ok(ServerFsm::Conn(conn)),
                    Some((conn, Some(dur))) => {
                        rotor::Response::ok(ServerFsm::Conn(conn))
                            .deadline(scope.now() + dur)
                    }
                    None => rotor::Response::done()
                }
            }
        }
    }

    fn spawned(self, _scope: &mut Scope<Self::Context>) -> rotor::Response<Self, Self::Seed> {
        match self {
            ServerFsm::Listener(listener, rx) => {
                match listener.accept() {
                    Ok(Some(conn)) => {
                        rotor::Response::spawn(ServerFsm::Listener(listener, rx), conn)
                    },
                    Ok(None) => rotor::Response::ok(ServerFsm::Listener(listener, rx)),
                    Err(e) => {
                        error!("listener accept error {}", e);
                        // usually fine, just keep listening
                        rotor::Response::ok(ServerFsm::Listener(listener, rx))
                    }
                }
            },
            sock => rotor::Response::ok(sock)
        }

    }

    fn timeout(self, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, Self::Seed> {
        match self {
            ServerFsm::Listener(..) => unreachable!("Listener cannot timeout"),
            ServerFsm::Conn(conn) => {
                match conn.timeout(scope) {
                    Some((conn, None)) => rotor::Response::ok(ServerFsm::Conn(conn)),
                    Some((conn, Some(dur))) => {
                        rotor::Response::ok(ServerFsm::Conn(conn))
                            .deadline(scope.now() + dur)
                    }
                    None => rotor::Response::done()
                }
            }
        }
    }

    fn wakeup(self, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, Self::Seed> {
        match self {
            ServerFsm::Listener(lst, shutdown) => {
                if shutdown.load(Ordering::Acquire) {
                    let _ = scope.deregister(&lst);
                    scope.shutdown_loop();
                    rotor::Response::done()
                } else {
                    rotor::Response::ok(ServerFsm::Listener(lst, shutdown))
                }
            },
            ServerFsm::Conn(conn) => match conn.wakeup(scope) {
                Some((conn, None)) => rotor::Response::ok(ServerFsm::Conn(conn)),
                Some((conn, Some(dur))) => {
                    rotor::Response::ok(ServerFsm::Conn(conn))
                        .deadline(scope.now() + dur)
                }
                None => rotor::Response::done()
            }
        }
    }
}

/// A handle of the running server.
pub struct Listening {
    addr: SocketAddr,
    shutdown: (Arc<AtomicBool>, rotor::Notifier),
}

impl fmt::Debug for Listening {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Listening")
            .field("addr", &self.addr)
            .field("closed", &self.shutdown.0.load(Ordering::Relaxed))
            .finish()
    }
}

impl fmt::Display for Listening {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.addr, f)
    }
}

impl Listening {
    /// The address this server is listening on.
    pub fn addr(&self) -> &SocketAddr {
        &self.addr
    }

    /// Stop the server from listening to its socket address.
    pub fn close(self) {
        debug!("closing server {}", self);
        self.shutdown.0.store(true, Ordering::Release);
        self.shutdown.1.wakeup().unwrap();
    }
}

/// A trait to react to server events that happen for each message.
///
/// Each event handler returns its desired `Next` action.
pub trait Handler<T: Transport> {
    /// This event occurs first, triggering when a `Request` has been parsed.
    fn on_request(&mut self, request: Request<T>) -> Next;
    /// This event occurs each time the `Request` is ready to be read from.
    fn on_request_readable(&mut self, request: &mut http::Decoder<T>) -> Next;
    /// This event occurs after the first time this handled signals `Next::write()`.
    fn on_response(&mut self, response: &mut Response) -> Next;
    /// This event occurs each time the `Response` is ready to be written to.
    fn on_response_writable(&mut self, response: &mut http::Encoder<T>) -> Next;

    /// This event occurs whenever an `Error` occurs outside of the other events.
    ///
    /// This could IO errors while waiting for events, or a timeout, etc.
    fn on_error(&mut self, err: ::Error) -> Next where Self: Sized {
        debug!("default Handler.on_error({:?})", err);
        http::Next::remove()
    }

    /// This event occurs when this Handler has requested to remove the Transport.
    fn on_remove(self, _transport: T) where Self: Sized {
        debug!("default Handler.on_remove");
    }
}

/// Used to create a `Handler` when a new message is received by the server.
pub trait HandlerFactory<T: Transport> {
    /// The `Handler` to use for the incoming message.
    type Output: Handler<T>;
    /// Creates the associated `Handler`.
    fn create(&mut self, ctrl: http::Control) -> Self::Output;
}

impl<F, H, T> HandlerFactory<T> for F
where F: FnMut(http::Control) -> H, H: Handler<T>, T: Transport {
    type Output = H;
    fn create(&mut self, ctrl: http::Control) -> H {
        self(ctrl)
    }
}

#[cfg(test)]
mod tests {

}
<commit_msg>feat(server): add idle_timeout to Server<commit_after>//! HTTP Server
//!
//! A `Server` is created to listen on a port, parse HTTP requests, and hand
//! them off to a `Handler`.
use std::fmt;
use std::net::SocketAddr;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;

use rotor::mio::{EventSet, PollOpt};
use rotor::{self, Scope};

pub use self::request::Request;
pub use self::response::Response;

use http::{self, Next};

pub use net::{Accept, HttpListener, HttpsListener};
use net::{SslServer, Transport};

mod request;
mod response;
mod message;

/// A configured `Server` ready to run.
pub struct ServerLoop<A, H> where A: Accept, H: HandlerFactory<A::Output> {
    inner: Option<(rotor::Loop<ServerFsm<A, H>>, Context<H>)>,
}

impl<A: Accept, H: HandlerFactory<A::Output>> fmt::Debug for ServerLoop<A, H> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("ServerLoop")
    }
}

/// A Server that can accept incoming network requests.
#[derive(Debug)]
pub struct Server<T: Accept> {
    listener: T,
    keep_alive: bool,
    idle_timeout: Duration,
    max_sockets: usize,
}

impl<T> Server<T> where T: Accept, T::Output: Transport {
    /// Creates a new server with the provided Listener.
    #[inline]
    pub fn new(listener: T) -> Server<T> {
        Server {
            listener: listener,
            keep_alive: true,
            idle_timeout: Duration::from_secs(10),
            max_sockets: 4096,
        }
    }

    /// Enables or disables HTTP keep-alive.
    ///
    /// Default is true.
    pub fn keep_alive(mut self, val: bool) -> Server<T> {
        self.keep_alive = val;
        self
    }

    /// Sets how long an idle connection will be kept before closing.
    ///
    /// Default is 10 seconds.
    pub fn idle_timeout(mut self, val: Duration) -> Server<T> {
        self.idle_timeout = val;
        self
    }

    /// Sets the maximum open sockets for this Server.
    ///
    /// Default is 4096, but most servers can handle much more than this.
    pub fn max_sockets(mut self, val: usize) -> Server<T> {
        self.max_sockets = val;
        self
    }
}

impl Server<HttpListener> { //<H: HandlerFactory<<HttpListener as Accept>::Output>> Server<HttpListener, H> {
    /// Creates a new HTTP server config listening on the provided address.
    pub fn http(addr: &SocketAddr) -> ::Result<Server<HttpListener>> {
        use ::rotor::mio::tcp::TcpListener;
        TcpListener::bind(addr)
            .map(HttpListener)
            .map(Server::new)
            .map_err(From::from)
    }
}

impl<S: SslServer> Server<HttpsListener<S>> {
    /// Creates a new server config that will handle `HttpStream`s over SSL.
    ///
    /// You can use any SSL implementation, as long as it implements `hyper::net::Ssl`.
    pub fn https(addr: &SocketAddr, ssl: S) -> ::Result<Server<HttpsListener<S>>> {
        HttpsListener::new(addr, ssl)
            .map(Server::new)
            .map_err(From::from)
    }
}

impl<A: Accept> Server<A> where A::Output: Transport  {
    /// Binds to a socket and starts handling connections.
    pub fn handle<H>(self, factory: H) -> ::Result<(Listening, ServerLoop<A, H>)>
    where H: HandlerFactory<A::Output> {
        let addr = try!(self.listener.local_addr());
        let shutdown = Arc::new(AtomicBool::new(false));
        let shutdown_rx = shutdown.clone();

        let mut config = rotor::Config::new();
        config.slab_capacity(self.max_sockets);
        config.mio().notify_capacity(self.max_sockets);
        let keep_alive = self.keep_alive;
        let idle_timeout = self.idle_timeout;
        let mut loop_ = rotor::Loop::new(&config).unwrap();
        let mut notifier = None;
        {
            let notifier = &mut notifier;
            loop_.add_machine_with(move |scope| {
                *notifier = Some(scope.notifier());
                rotor_try!(scope.register(&self.listener, EventSet::readable(), PollOpt::level()));
                rotor::Response::ok(ServerFsm::Listener::<A, H>(self.listener, shutdown_rx))
            }).unwrap();
        }
        let notifier = notifier.expect("loop.add_machine failed");

        let listening = Listening {
            addr: addr,
            shutdown: (shutdown, notifier),
        };
        let server = ServerLoop {
            inner: Some((loop_, Context {
                factory: factory,
                idle_timeout: idle_timeout,
                keep_alive: keep_alive,
            }))
        };
        Ok((listening, server))
    }
}

impl<A: Accept, H: HandlerFactory<A::Output>> ServerLoop<A, H> {
    /// Runs the server forever in this loop.
    ///
    /// This will block the current thread.
    pub fn run(self) {
        // drop will take care of it.
    }
}

impl<A: Accept, H: HandlerFactory<A::Output>> Drop for ServerLoop<A, H> {
    fn drop(&mut self) {
        self.inner.take().map(|(loop_, ctx)| {
            let _ = loop_.run(ctx);
        });
    }
}

struct Context<F> {
    factory: F,
    idle_timeout: Option<Duration>,
    keep_alive: bool,
}

impl<F: HandlerFactory<T>, T: Transport> http::MessageHandlerFactory<(), T> for Context<F> {
    type Output = message::Message<F::Output, T>;

    fn create(&mut self, seed: http::Seed<()>) -> Option<Self::Output> {
        Some(message::Message::new(self.factory.create(seed.control())))
    }

    fn keep_alive_interest(&self) -> Next {
        if let Some(dur) = self.idle_timeout {
            Next::read().timeout(dur)
        } else {
            Next::read()
        }
    }
}

enum ServerFsm<A, H>
where A: Accept,
      A::Output: Transport,
      H: HandlerFactory<A::Output> {
    Listener(A, Arc<AtomicBool>),
    Conn(http::Conn<(), A::Output, message::Message<H::Output, A::Output>>)
}

impl<A, H> rotor::Machine for ServerFsm<A, H>
where A: Accept,
      A::Output: Transport,
      H: HandlerFactory<A::Output> {
    type Context = Context<H>;
    type Seed = A::Output;

    fn create(seed: Self::Seed, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, rotor::Void> {
        rotor_try!(scope.register(&seed, EventSet::readable(), PollOpt::level()));
        rotor::Response::ok(
            ServerFsm::Conn(
                http::Conn::new((), seed, Next::read(), scope.notifier())
                    .keep_alive(scope.keep_alive)
            )
        )
    }

    fn ready(self, events: EventSet, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, Self::Seed> {
        match self {
            ServerFsm::Listener(listener, rx) => {
                match listener.accept() {
                    Ok(Some(conn)) => {
                        rotor::Response::spawn(ServerFsm::Listener(listener, rx), conn)
                    },
                    Ok(None) => rotor::Response::ok(ServerFsm::Listener(listener, rx)),
                    Err(e) => {
                        error!("listener accept error {}", e);
                        // usually fine, just keep listening
                        rotor::Response::ok(ServerFsm::Listener(listener, rx))
                    }
                }
            },
            ServerFsm::Conn(conn) => {
                match conn.ready(events, scope) {
                    Some((conn, None)) => rotor::Response::ok(ServerFsm::Conn(conn)),
                    Some((conn, Some(dur))) => {
                        rotor::Response::ok(ServerFsm::Conn(conn))
                            .deadline(scope.now() + dur)
                    }
                    None => rotor::Response::done()
                }
            }
        }
    }

    fn spawned(self, _scope: &mut Scope<Self::Context>) -> rotor::Response<Self, Self::Seed> {
        match self {
            ServerFsm::Listener(listener, rx) => {
                match listener.accept() {
                    Ok(Some(conn)) => {
                        rotor::Response::spawn(ServerFsm::Listener(listener, rx), conn)
                    },
                    Ok(None) => rotor::Response::ok(ServerFsm::Listener(listener, rx)),
                    Err(e) => {
                        error!("listener accept error {}", e);
                        // usually fine, just keep listening
                        rotor::Response::ok(ServerFsm::Listener(listener, rx))
                    }
                }
            },
            sock => rotor::Response::ok(sock)
        }

    }

    fn timeout(self, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, Self::Seed> {
        match self {
            ServerFsm::Listener(..) => unreachable!("Listener cannot timeout"),
            ServerFsm::Conn(conn) => {
                match conn.timeout(scope) {
                    Some((conn, None)) => rotor::Response::ok(ServerFsm::Conn(conn)),
                    Some((conn, Some(dur))) => {
                        rotor::Response::ok(ServerFsm::Conn(conn))
                            .deadline(scope.now() + dur)
                    }
                    None => rotor::Response::done()
                }
            }
        }
    }

    fn wakeup(self, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, Self::Seed> {
        match self {
            ServerFsm::Listener(lst, shutdown) => {
                if shutdown.load(Ordering::Acquire) {
                    let _ = scope.deregister(&lst);
                    scope.shutdown_loop();
                    rotor::Response::done()
                } else {
                    rotor::Response::ok(ServerFsm::Listener(lst, shutdown))
                }
            },
            ServerFsm::Conn(conn) => match conn.wakeup(scope) {
                Some((conn, None)) => rotor::Response::ok(ServerFsm::Conn(conn)),
                Some((conn, Some(dur))) => {
                    rotor::Response::ok(ServerFsm::Conn(conn))
                        .deadline(scope.now() + dur)
                }
                None => rotor::Response::done()
            }
        }
    }
}

/// A handle of the running server.
pub struct Listening {
    addr: SocketAddr,
    shutdown: (Arc<AtomicBool>, rotor::Notifier),
}

impl fmt::Debug for Listening {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Listening")
            .field("addr", &self.addr)
            .field("closed", &self.shutdown.0.load(Ordering::Relaxed))
            .finish()
    }
}

impl fmt::Display for Listening {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.addr, f)
    }
}

impl Listening {
    /// The address this server is listening on.
    pub fn addr(&self) -> &SocketAddr {
        &self.addr
    }

    /// Stop the server from listening to its socket address.
    pub fn close(self) {
        debug!("closing server {}", self);
        self.shutdown.0.store(true, Ordering::Release);
        self.shutdown.1.wakeup().unwrap();
    }
}

/// A trait to react to server events that happen for each message.
///
/// Each event handler returns its desired `Next` action.
pub trait Handler<T: Transport> {
    /// This event occurs first, triggering when a `Request` has been parsed.
    fn on_request(&mut self, request: Request<T>) -> Next;
    /// This event occurs each time the `Request` is ready to be read from.
    fn on_request_readable(&mut self, request: &mut http::Decoder<T>) -> Next;
    /// This event occurs after the first time this handled signals `Next::write()`.
    fn on_response(&mut self, response: &mut Response) -> Next;
    /// This event occurs each time the `Response` is ready to be written to.
    fn on_response_writable(&mut self, response: &mut http::Encoder<T>) -> Next;

    /// This event occurs whenever an `Error` occurs outside of the other events.
    ///
    /// This could IO errors while waiting for events, or a timeout, etc.
    fn on_error(&mut self, err: ::Error) -> Next where Self: Sized {
        debug!("default Handler.on_error({:?})", err);
        http::Next::remove()
    }

    /// This event occurs when this Handler has requested to remove the Transport.
    fn on_remove(self, _transport: T) where Self: Sized {
        debug!("default Handler.on_remove");
    }
}

/// Used to create a `Handler` when a new message is received by the server.
pub trait HandlerFactory<T: Transport> {
    /// The `Handler` to use for the incoming message.
    type Output: Handler<T>;
    /// Creates the associated `Handler`.
    fn create(&mut self, ctrl: http::Control) -> Self::Output;
}

impl<F, H, T> HandlerFactory<T> for F
where F: FnMut(http::Control) -> H, H: Handler<T>, T: Transport {
    type Output = H;
    fn create(&mut self, ctrl: http::Control) -> H {
        self(ctrl)
    }
}

#[cfg(test)]
mod tests {

}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use blockdev::BlockDevs;

use engine::Engine;

use engine::Pool;

use std::path::Path;
use std::collections::BTreeMap;
use std::iter::FromIterator;

use types::StratisResult;

#[derive(Debug)]
pub struct SimEngine {
    pub pools: BTreeMap<String, Box<Pool>>,
}

impl SimEngine {
    pub fn new() -> SimEngine {
        SimEngine { pools: BTreeMap::new() }
    }
}

impl Engine for SimEngine {
    fn create_pool(&mut self,
                   name: &str,
                   blockdev_paths: &[&Path],
                   raid_level: u16)
                   -> StratisResult<()> {

        let pool = SimPool::new_pool(name, blockdev_paths, raid_level);

        self.pools.insert(name.to_owned(), pool);

        Ok(())
    }

    fn destroy_pool(&mut self, name: &str) -> StratisResult<()> {

        self.pools.remove(name);

        Ok(())
    }

    fn list_pools(&self) -> StratisResult<BTreeMap<String, Box<Pool>>> {

        Ok(BTreeMap::from_iter(self.pools.iter().map(|x| (x.0.clone(), x.1.copy()))))

    }
}

#[derive(Debug)]
pub struct SimPool {
    pub name: String,
    pub block_devs: BlockDevs,
    pub raid_level: u16,
    pub online: bool,
    pub checking: bool,
}

impl SimPool {
    pub fn new_pool(name: &str, blockdev_paths: &[&Path], raid_level: u16) -> Box<Pool> {

        let status = BlockDevs::new(blockdev_paths);

        let block_devs = status.unwrap();

        let new_pool = SimPool {
            name: name.to_owned(),
            block_devs: block_devs.to_owned(),
            raid_level: raid_level,
            online: true,
            checking: false,
        };

        Box::new(new_pool)
    }
}

impl Pool for SimPool {
    fn add_blockdev(&mut self, path: &str) -> StratisResult<()> {
        println!("sim: pool::add_blockdev");
        Ok(())
    }

    fn add_cachedev(&mut self, path: &str) -> StratisResult<()> {
        println!("sim: pool::add_cachedev");
        Ok(())
    }

    fn destroy(&mut self) -> StratisResult<()> {
        println!("sim: pool::destroy");
        Ok(())
    }

    fn get_name(&mut self) -> String {
        self.name.clone()
    }
    fn copy(&self) -> Box<Pool> {
        let pool_copy = SimPool {
            name: self.name.clone(),
            block_devs: self.block_devs.clone(),
            raid_level: self.raid_level.clone(),
            online: true,
            checking: false,
        };
        Box::new(pool_copy)
    }
}
<commit_msg>Silenced compiler warning by adding an "_" before un-used variables.<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use blockdev::BlockDevs;

use engine::Engine;

use engine::Pool;

use std::path::Path;
use std::collections::BTreeMap;
use std::iter::FromIterator;

use types::StratisResult;

#[derive(Debug)]
pub struct SimEngine {
    pub pools: BTreeMap<String, Box<Pool>>,
}

impl SimEngine {
    pub fn new() -> SimEngine {
        SimEngine { pools: BTreeMap::new() }
    }
}

impl Engine for SimEngine {
    fn create_pool(&mut self,
                   name: &str,
                   blockdev_paths: &[&Path],
                   raid_level: u16)
                   -> StratisResult<()> {

        let pool = SimPool::new_pool(name, blockdev_paths, raid_level);

        self.pools.insert(name.to_owned(), pool);

        Ok(())
    }

    fn destroy_pool(&mut self, name: &str) -> StratisResult<()> {

        self.pools.remove(name);

        Ok(())
    }

    fn list_pools(&self) -> StratisResult<BTreeMap<String, Box<Pool>>> {

        Ok(BTreeMap::from_iter(self.pools.iter().map(|x| (x.0.clone(), x.1.copy()))))

    }
}

#[derive(Debug)]
pub struct SimPool {
    pub name: String,
    pub block_devs: BlockDevs,
    pub raid_level: u16,
    pub online: bool,
    pub checking: bool,
}

impl SimPool {
    pub fn new_pool(name: &str, blockdev_paths: &[&Path], raid_level: u16) -> Box<Pool> {

        let status = BlockDevs::new(blockdev_paths);

        let block_devs = status.unwrap();

        let new_pool = SimPool {
            name: name.to_owned(),
            block_devs: block_devs.to_owned(),
            raid_level: raid_level,
            online: true,
            checking: false,
        };

        Box::new(new_pool)
    }
}

impl Pool for SimPool {
    fn add_blockdev(&mut self, _path: &str) -> StratisResult<()> {
        println!("sim: pool::add_blockdev");
        Ok(())
    }

    fn add_cachedev(&mut self, _path: &str) -> StratisResult<()> {
        println!("sim: pool::add_cachedev");
        Ok(())
    }

    fn destroy(&mut self) -> StratisResult<()> {
        println!("sim: pool::destroy");
        Ok(())
    }

    fn get_name(&mut self) -> String {
        self.name.clone()
    }
    fn copy(&self) -> Box<Pool> {
        let pool_copy = SimPool {
            name: self.name.clone(),
            block_devs: self.block_devs.clone(),
            raid_level: self.raid_level.clone(),
            online: true,
            checking: false,
        };
        Box::new(pool_copy)
    }
}
<|endoftext|>


<commit_before>extern crate sdl2;

use sdl2::audio::{AudioCallback, AudioSpecDesired};
use std::time::Duration;

fn gen_wave(bytes_to_write: i32) -> Vec<i16> {
    // Generate a square wave
    let tone_volume = 1000i16;
    let period = 48000 / 256;
    let sample_count = bytes_to_write;
    let mut result = Vec::new();

    for x in 0..sample_count {
        result.push(
            if (x / period) % 2 == 0 {
                tone_volume
            }
            else {
                -tone_volume
            }
        );
    }
    result
}

fn main() {
    let sdl_context = sdl2::init().unwrap();
    let audio_subsystem = sdl_context.audio().unwrap();

    let desired_spec = AudioSpecDesired {
        freq: Some(48000),
        channels: Some(2),  // mono
        samples: Some(4)    // default sample size
    };

    let device = audio_subsystem.open_queue::<i16>(None, &desired_spec).unwrap();

    let target_bytes = 48000 * 4;
    let wave = gen_wave(target_bytes);
    device.queue(&wave);

    // Start playback
    device.resume();

    // Play for 2 seconds
    std::thread::sleep(Duration::from_millis(2000));

    // Device is automatically closed when dropped
}
<commit_msg>removed example code temporarily<commit_after><|endoftext|>


<commit_before>#[phase(link, plugin)]
extern crate input;

pub static CFFFormatTag: u32 = 0x4F54544F;

pub struct OffsetTable {
    pub tag: u32,
    pub table_count: u16,
    pub search_range: u16,
    pub entry_selector: u16,
    pub range_shift: u16,
}

implement_loader!(OffsetTable,
    tag as le_u32,
    table_count as be_u16,
    search_range as be_u16,
    entry_selector as be_u16,
    range_shift as be_u16
)

pub struct TableRecord {
    pub tag: u32,
    pub check_sum: u32,
    pub offset: u32,
    pub length: u32,
}

implement_loader!(TableRecord,
    tag as le_u32,
    check_sum as be_u32,
    offset as be_u32,
    length as be_u32
)
<commit_msg>Renamed check_sum into checksum<commit_after>#[phase(link, plugin)]
extern crate input;

pub static CFFFormatTag: u32 = 0x4F54544F;

pub struct OffsetTable {
    pub tag: u32,
    pub table_count: u16,
    pub search_range: u16,
    pub entry_selector: u16,
    pub range_shift: u16,
}

implement_loader!(OffsetTable,
    tag as le_u32,
    table_count as be_u16,
    search_range as be_u16,
    entry_selector as be_u16,
    range_shift as be_u16
)

pub struct TableRecord {
    pub tag: u32,
    pub checksum: u32,
    pub offset: u32,
    pub length: u32,
}

implement_loader!(TableRecord,
    tag as le_u32,
    checksum as be_u32,
    offset as be_u32,
    length as be_u32
)
<|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.

// Code that generates a test runner to run all the tests in a crate

use driver::session;
use front::config;

use std::vec;
use syntax::ast_util::*;
use syntax::attr::AttrMetaMethods;
use syntax::attr;
use syntax::codemap::{dummy_sp, Span, ExpnInfo, NameAndSpan, MacroAttribute};
use syntax::codemap;
use syntax::ext::base::ExtCtxt;
use syntax::fold::ast_fold;
use syntax::fold;
use syntax::opt_vec;
use syntax::print::pprust;
use syntax::{ast, ast_util};
use syntax::util::small_vector::SmallVector;

struct Test {
    span: Span,
    path: ~[ast::Ident],
    bench: bool,
    ignore: bool,
    should_fail: bool
}

struct TestCtxt {
    sess: session::Session,
    path: ~[ast::Ident],
    ext_cx: @ExtCtxt,
    testfns: ~[Test],
    is_extra: bool,
    config: ast::CrateConfig,
}

// Traverse the crate, collecting all the test functions, eliding any
// existing main functions, and synthesizing a main test harness
pub fn modify_for_testing(sess: session::Session,
                          crate: ast::Crate) -> ast::Crate {
    // We generate the test harness when building in the 'test'
    // configuration, either with the '--test' or '--cfg test'
    // command line options.
    let should_test = attr::contains_name(crate.config, "test");

    if should_test {
        generate_test_harness(sess, crate)
    } else {
        strip_test_functions(crate)
    }
}

struct TestHarnessGenerator {
    cx: @mut TestCtxt,
}

impl fold::ast_fold for TestHarnessGenerator {
    fn fold_crate(&self, c: ast::Crate) -> ast::Crate {
        let folded = fold::noop_fold_crate(c, self);

        // Add a special __test module to the crate that will contain code
        // generated for the test harness
        ast::Crate {
            module: add_test_module(self.cx, &folded.module),
            .. folded
        }
    }

    fn fold_item(&self, i: @ast::item) -> SmallVector<@ast::item> {
        self.cx.path.push(i.ident);
        debug!("current path: {}",
               ast_util::path_name_i(self.cx.path.clone()));

        if is_test_fn(self.cx, i) || is_bench_fn(i) {
            match i.node {
                ast::item_fn(_, purity, _, _, _)
                    if purity == ast::unsafe_fn => {
                    let sess = self.cx.sess;
                    sess.span_fatal(i.span,
                                    "unsafe functions cannot be used for \
                                     tests");
                }
                _ => {
                    debug!("this is a test function");
                    let test = Test {
                        span: i.span,
                        path: self.cx.path.clone(),
                        bench: is_bench_fn(i),
                        ignore: is_ignored(self.cx, i),
                        should_fail: should_fail(i)
                    };
                    self.cx.testfns.push(test);
                    // debug!("have {} test/bench functions",
                    //        cx.testfns.len());
                }
            }
        }

        let res = fold::noop_fold_item(i, self);
        self.cx.path.pop();
        res
    }

    fn fold_mod(&self, m: &ast::_mod) -> ast::_mod {
        // Remove any #[main] from the AST so it doesn't clash with
        // the one we're going to add. Only if compiling an executable.

        fn nomain(cx: @mut TestCtxt, item: @ast::item) -> @ast::item {
            if !*cx.sess.building_library {
                @ast::item {
                    attrs: item.attrs.iter().filter_map(|attr| {
                        if "main" != attr.name() {
                            Some(*attr)
                        } else {
                            None
                        }
                    }).collect(),
                    .. (*item).clone()
                }
            } else {
                item
            }
        }

        let mod_nomain = ast::_mod {
            view_items: m.view_items.clone(),
            items: m.items.iter().map(|i| nomain(self.cx, *i)).collect(),
        };

        fold::noop_fold_mod(&mod_nomain, self)
    }
}

fn generate_test_harness(sess: session::Session, crate: ast::Crate)
                         -> ast::Crate {
    let cx: @mut TestCtxt = @mut TestCtxt {
        sess: sess,
        ext_cx: ExtCtxt::new(sess.parse_sess, sess.opts.cfg.clone()),
        path: ~[],
        testfns: ~[],
        is_extra: is_extra(&crate),
        config: crate.config.clone(),
    };

    let ext_cx = cx.ext_cx;
    ext_cx.bt_push(ExpnInfo {
        call_site: dummy_sp(),
        callee: NameAndSpan {
            name: @"test",
            format: MacroAttribute,
            span: None
        }
    });

    let fold = TestHarnessGenerator {
        cx: cx
    };
    let res = fold.fold_crate(crate);
    ext_cx.bt_pop();
    return res;
}

fn strip_test_functions(crate: ast::Crate) -> ast::Crate {
    // When not compiling with --test we should not compile the
    // #[test] functions
    config::strip_items(crate, |attrs| {
        !attr::contains_name(attrs, "test") &&
        !attr::contains_name(attrs, "bench")
    })
}

fn is_test_fn(cx: @mut TestCtxt, i: @ast::item) -> bool {
    let has_test_attr = attr::contains_name(i.attrs, "test");

    fn has_test_signature(i: @ast::item) -> bool {
        match &i.node {
          &ast::item_fn(ref decl, _, _, ref generics, _) => {
            let no_output = match decl.output.node {
                ast::ty_nil => true,
                _ => false
            };
            decl.inputs.is_empty()
                && no_output
                && !generics.is_parameterized()
          }
          _ => false
        }
    }

    if has_test_attr && !has_test_signature(i) {
        let sess = cx.sess;
        sess.span_err(
            i.span,
            "functions used as tests must have signature fn() -> ()."
        );
    }

    return has_test_attr && has_test_signature(i);
}

fn is_bench_fn(i: @ast::item) -> bool {
    let has_bench_attr = attr::contains_name(i.attrs, "bench");

    fn has_test_signature(i: @ast::item) -> bool {
        match i.node {
            ast::item_fn(ref decl, _, _, ref generics, _) => {
                let input_cnt = decl.inputs.len();
                let no_output = match decl.output.node {
                    ast::ty_nil => true,
                    _ => false
                };
                let tparm_cnt = generics.ty_params.len();
                // NB: inadequate check, but we're running
                // well before resolve, can't get too deep.
                input_cnt == 1u
                    && no_output && tparm_cnt == 0u
            }
          _ => false
        }
    }

    return has_bench_attr && has_test_signature(i);
}

fn is_ignored(cx: @mut TestCtxt, i: @ast::item) -> bool {
    i.attrs.iter().any(|attr| {
        // check ignore(cfg(foo, bar))
        "ignore" == attr.name() && match attr.meta_item_list() {
            Some(ref cfgs) => attr::test_cfg(cx.config, cfgs.iter().map(|x| *x)),
            None => true
        }
    })
}

fn should_fail(i: @ast::item) -> bool {
    attr::contains_name(i.attrs, "should_fail")
}

fn add_test_module(cx: &TestCtxt, m: &ast::_mod) -> ast::_mod {
    let testmod = mk_test_module(cx);
    ast::_mod {
        items: vec::append_one(m.items.clone(), testmod),
        ..(*m).clone()
    }
}

/*

We're going to be building a module that looks more or less like:

mod __test {
  #[!resolve_unexported]
  extern mod extra (name = "extra", vers = "...");
  fn main() {
    #[main];
    extra::test::test_main_static(::os::args(), tests)
  }

  static tests : &'static [extra::test::TestDescAndFn] = &[
    ... the list of tests in the crate ...
  ];
}

*/

fn mk_std(cx: &TestCtxt) -> ast::view_item {
    let id_extra = cx.sess.ident_of("extra");
    let vi = if cx.is_extra {
        ast::view_item_use(
            ~[@nospan(ast::view_path_simple(id_extra,
                                            path_node(~[id_extra]),
                                            ast::DUMMY_NODE_ID))])
    } else {
        let mi = attr::mk_name_value_item_str(@"vers", @"0.9-pre");
        ast::view_item_extern_mod(id_extra, None, ~[mi], ast::DUMMY_NODE_ID)
    };
    ast::view_item {
        node: vi,
        attrs: ~[],
        vis: ast::public,
        span: dummy_sp()
    }
}

fn mk_test_module(cx: &TestCtxt) -> @ast::item {

    // Link to extra
    let view_items = ~[mk_std(cx)];

    // A constant vector of test descriptors.
    let tests = mk_tests(cx);

    // The synthesized main function which will call the console test runner
    // with our list of tests
    let mainfn = (quote_item!(cx.ext_cx,
        pub fn main() {
            #[main];
            extra::test::test_main_static(::std::os::args(), TESTS);
        }
    )).unwrap();

    let testmod = ast::_mod {
        view_items: view_items,
        items: ~[mainfn, tests],
    };
    let item_ = ast::item_mod(testmod);

    // This attribute tells resolve to let us call unexported functions
    let resolve_unexported_attr =
        attr::mk_attr(attr::mk_word_item(@"!resolve_unexported"));

    let item = ast::item {
        ident: cx.sess.ident_of("__test"),
        attrs: ~[resolve_unexported_attr],
        id: ast::DUMMY_NODE_ID,
        node: item_,
        vis: ast::public,
        span: dummy_sp(),
     };

    debug!("Synthetic test module:\n{}\n",
           pprust::item_to_str(&item, cx.sess.intr()));

    return @item;
}

fn nospan<T>(t: T) -> codemap::Spanned<T> {
    codemap::Spanned { node: t, span: dummy_sp() }
}

fn path_node(ids: ~[ast::Ident]) -> ast::Path {
    ast::Path {
        span: dummy_sp(),
        global: false,
        segments: ids.move_iter().map(|identifier| ast::PathSegment {
            identifier: identifier,
            lifetimes: opt_vec::Empty,
            types: opt_vec::Empty,
        }).collect()
    }
}

fn path_node_global(ids: ~[ast::Ident]) -> ast::Path {
    ast::Path {
        span: dummy_sp(),
        global: true,
        segments: ids.move_iter().map(|identifier| ast::PathSegment {
            identifier: identifier,
            lifetimes: opt_vec::Empty,
            types: opt_vec::Empty,
        }).collect()
    }
}

fn mk_tests(cx: &TestCtxt) -> @ast::item {
    // The vector of test_descs for this crate
    let test_descs = mk_test_descs(cx);

    (quote_item!(cx.ext_cx,
        pub static TESTS : &'static [self::extra::test::TestDescAndFn] =
            $test_descs
        ;
    )).unwrap()
}

fn is_extra(crate: &ast::Crate) -> bool {
    match attr::find_pkgid(crate.attrs) {
        Some(ref s) if "extra" == s.name => true,
        _ => false
    }
}

fn mk_test_descs(cx: &TestCtxt) -> @ast::Expr {
    debug!("building test vector from {} tests", cx.testfns.len());
    let mut descs = ~[];
    for test in cx.testfns.iter() {
        descs.push(mk_test_desc_and_fn_rec(cx, test));
    }

    let inner_expr = @ast::Expr {
        id: ast::DUMMY_NODE_ID,
        node: ast::ExprVec(descs, ast::MutImmutable),
        span: dummy_sp(),
    };

    @ast::Expr {
        id: ast::DUMMY_NODE_ID,
        node: ast::ExprVstore(inner_expr, ast::ExprVstoreSlice),
        span: dummy_sp(),
    }
}

fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> @ast::Expr {
    let span = test.span;
    let path = test.path.clone();

    debug!("encoding {}", ast_util::path_name_i(path));

    let name_lit: ast::lit =
        nospan(ast::lit_str(ast_util::path_name_i(path).to_managed(), ast::CookedStr));

    let name_expr = @ast::Expr {
          id: ast::DUMMY_NODE_ID,
          node: ast::ExprLit(@name_lit),
          span: span
    };

    let fn_path = path_node_global(path);

    let fn_expr = @ast::Expr {
        id: ast::DUMMY_NODE_ID,
        node: ast::ExprPath(fn_path),
        span: span,
    };

    let t_expr = if test.bench {
        quote_expr!(cx.ext_cx, self::extra::test::StaticBenchFn($fn_expr) )
    } else {
        quote_expr!(cx.ext_cx, self::extra::test::StaticTestFn($fn_expr) )
    };

    let ignore_expr = if test.ignore {
        quote_expr!(cx.ext_cx, true )
    } else {
        quote_expr!(cx.ext_cx, false )
    };

    let fail_expr = if test.should_fail {
        quote_expr!(cx.ext_cx, true )
    } else {
        quote_expr!(cx.ext_cx, false )
    };

    let e = quote_expr!(cx.ext_cx,
        self::extra::test::TestDescAndFn {
            desc: self::extra::test::TestDesc {
                name: self::extra::test::StaticTestName($name_expr),
                ignore: $ignore_expr,
                should_fail: $fail_expr
            },
            testfn: $t_expr,
        }
    );
    e
}
<commit_msg>librustc: De-`@mut` `TestCtxt::path`<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.

// Code that generates a test runner to run all the tests in a crate

use driver::session;
use front::config;

use std::cell::RefCell;
use std::vec;
use syntax::ast_util::*;
use syntax::attr::AttrMetaMethods;
use syntax::attr;
use syntax::codemap::{dummy_sp, Span, ExpnInfo, NameAndSpan, MacroAttribute};
use syntax::codemap;
use syntax::ext::base::ExtCtxt;
use syntax::fold::ast_fold;
use syntax::fold;
use syntax::opt_vec;
use syntax::print::pprust;
use syntax::{ast, ast_util};
use syntax::util::small_vector::SmallVector;

struct Test {
    span: Span,
    path: ~[ast::Ident],
    bench: bool,
    ignore: bool,
    should_fail: bool
}

struct TestCtxt {
    sess: session::Session,
    path: RefCell<~[ast::Ident]>,
    ext_cx: @ExtCtxt,
    testfns: ~[Test],
    is_extra: bool,
    config: ast::CrateConfig,
}

// Traverse the crate, collecting all the test functions, eliding any
// existing main functions, and synthesizing a main test harness
pub fn modify_for_testing(sess: session::Session,
                          crate: ast::Crate) -> ast::Crate {
    // We generate the test harness when building in the 'test'
    // configuration, either with the '--test' or '--cfg test'
    // command line options.
    let should_test = attr::contains_name(crate.config, "test");

    if should_test {
        generate_test_harness(sess, crate)
    } else {
        strip_test_functions(crate)
    }
}

struct TestHarnessGenerator {
    cx: @mut TestCtxt,
}

impl fold::ast_fold for TestHarnessGenerator {
    fn fold_crate(&self, c: ast::Crate) -> ast::Crate {
        let folded = fold::noop_fold_crate(c, self);

        // Add a special __test module to the crate that will contain code
        // generated for the test harness
        ast::Crate {
            module: add_test_module(self.cx, &folded.module),
            .. folded
        }
    }

    fn fold_item(&self, i: @ast::item) -> SmallVector<@ast::item> {
        {
            let mut path = self.cx.path.borrow_mut();
            path.get().push(i.ident);
        }
        debug!("current path: {}",
               ast_util::path_name_i(self.cx.path.get()));

        if is_test_fn(self.cx, i) || is_bench_fn(i) {
            match i.node {
                ast::item_fn(_, purity, _, _, _)
                    if purity == ast::unsafe_fn => {
                    let sess = self.cx.sess;
                    sess.span_fatal(i.span,
                                    "unsafe functions cannot be used for \
                                     tests");
                }
                _ => {
                    debug!("this is a test function");
                    let test = Test {
                        span: i.span,
                        path: self.cx.path.get(),
                        bench: is_bench_fn(i),
                        ignore: is_ignored(self.cx, i),
                        should_fail: should_fail(i)
                    };
                    self.cx.testfns.push(test);
                    // debug!("have {} test/bench functions",
                    //        cx.testfns.len());
                }
            }
        }

        let res = fold::noop_fold_item(i, self);
        {
            let mut path = self.cx.path.borrow_mut();
            path.get().pop();
        }
        res
    }

    fn fold_mod(&self, m: &ast::_mod) -> ast::_mod {
        // Remove any #[main] from the AST so it doesn't clash with
        // the one we're going to add. Only if compiling an executable.

        fn nomain(cx: @mut TestCtxt, item: @ast::item) -> @ast::item {
            if !*cx.sess.building_library {
                @ast::item {
                    attrs: item.attrs.iter().filter_map(|attr| {
                        if "main" != attr.name() {
                            Some(*attr)
                        } else {
                            None
                        }
                    }).collect(),
                    .. (*item).clone()
                }
            } else {
                item
            }
        }

        let mod_nomain = ast::_mod {
            view_items: m.view_items.clone(),
            items: m.items.iter().map(|i| nomain(self.cx, *i)).collect(),
        };

        fold::noop_fold_mod(&mod_nomain, self)
    }
}

fn generate_test_harness(sess: session::Session, crate: ast::Crate)
                         -> ast::Crate {
    let cx: @mut TestCtxt = @mut TestCtxt {
        sess: sess,
        ext_cx: ExtCtxt::new(sess.parse_sess, sess.opts.cfg.clone()),
        path: RefCell::new(~[]),
        testfns: ~[],
        is_extra: is_extra(&crate),
        config: crate.config.clone(),
    };

    let ext_cx = cx.ext_cx;
    ext_cx.bt_push(ExpnInfo {
        call_site: dummy_sp(),
        callee: NameAndSpan {
            name: @"test",
            format: MacroAttribute,
            span: None
        }
    });

    let fold = TestHarnessGenerator {
        cx: cx
    };
    let res = fold.fold_crate(crate);
    ext_cx.bt_pop();
    return res;
}

fn strip_test_functions(crate: ast::Crate) -> ast::Crate {
    // When not compiling with --test we should not compile the
    // #[test] functions
    config::strip_items(crate, |attrs| {
        !attr::contains_name(attrs, "test") &&
        !attr::contains_name(attrs, "bench")
    })
}

fn is_test_fn(cx: @mut TestCtxt, i: @ast::item) -> bool {
    let has_test_attr = attr::contains_name(i.attrs, "test");

    fn has_test_signature(i: @ast::item) -> bool {
        match &i.node {
          &ast::item_fn(ref decl, _, _, ref generics, _) => {
            let no_output = match decl.output.node {
                ast::ty_nil => true,
                _ => false
            };
            decl.inputs.is_empty()
                && no_output
                && !generics.is_parameterized()
          }
          _ => false
        }
    }

    if has_test_attr && !has_test_signature(i) {
        let sess = cx.sess;
        sess.span_err(
            i.span,
            "functions used as tests must have signature fn() -> ()."
        );
    }

    return has_test_attr && has_test_signature(i);
}

fn is_bench_fn(i: @ast::item) -> bool {
    let has_bench_attr = attr::contains_name(i.attrs, "bench");

    fn has_test_signature(i: @ast::item) -> bool {
        match i.node {
            ast::item_fn(ref decl, _, _, ref generics, _) => {
                let input_cnt = decl.inputs.len();
                let no_output = match decl.output.node {
                    ast::ty_nil => true,
                    _ => false
                };
                let tparm_cnt = generics.ty_params.len();
                // NB: inadequate check, but we're running
                // well before resolve, can't get too deep.
                input_cnt == 1u
                    && no_output && tparm_cnt == 0u
            }
          _ => false
        }
    }

    return has_bench_attr && has_test_signature(i);
}

fn is_ignored(cx: @mut TestCtxt, i: @ast::item) -> bool {
    i.attrs.iter().any(|attr| {
        // check ignore(cfg(foo, bar))
        "ignore" == attr.name() && match attr.meta_item_list() {
            Some(ref cfgs) => attr::test_cfg(cx.config, cfgs.iter().map(|x| *x)),
            None => true
        }
    })
}

fn should_fail(i: @ast::item) -> bool {
    attr::contains_name(i.attrs, "should_fail")
}

fn add_test_module(cx: &TestCtxt, m: &ast::_mod) -> ast::_mod {
    let testmod = mk_test_module(cx);
    ast::_mod {
        items: vec::append_one(m.items.clone(), testmod),
        ..(*m).clone()
    }
}

/*

We're going to be building a module that looks more or less like:

mod __test {
  #[!resolve_unexported]
  extern mod extra (name = "extra", vers = "...");
  fn main() {
    #[main];
    extra::test::test_main_static(::os::args(), tests)
  }

  static tests : &'static [extra::test::TestDescAndFn] = &[
    ... the list of tests in the crate ...
  ];
}

*/

fn mk_std(cx: &TestCtxt) -> ast::view_item {
    let id_extra = cx.sess.ident_of("extra");
    let vi = if cx.is_extra {
        ast::view_item_use(
            ~[@nospan(ast::view_path_simple(id_extra,
                                            path_node(~[id_extra]),
                                            ast::DUMMY_NODE_ID))])
    } else {
        let mi = attr::mk_name_value_item_str(@"vers", @"0.9-pre");
        ast::view_item_extern_mod(id_extra, None, ~[mi], ast::DUMMY_NODE_ID)
    };
    ast::view_item {
        node: vi,
        attrs: ~[],
        vis: ast::public,
        span: dummy_sp()
    }
}

fn mk_test_module(cx: &TestCtxt) -> @ast::item {

    // Link to extra
    let view_items = ~[mk_std(cx)];

    // A constant vector of test descriptors.
    let tests = mk_tests(cx);

    // The synthesized main function which will call the console test runner
    // with our list of tests
    let mainfn = (quote_item!(cx.ext_cx,
        pub fn main() {
            #[main];
            extra::test::test_main_static(::std::os::args(), TESTS);
        }
    )).unwrap();

    let testmod = ast::_mod {
        view_items: view_items,
        items: ~[mainfn, tests],
    };
    let item_ = ast::item_mod(testmod);

    // This attribute tells resolve to let us call unexported functions
    let resolve_unexported_attr =
        attr::mk_attr(attr::mk_word_item(@"!resolve_unexported"));

    let item = ast::item {
        ident: cx.sess.ident_of("__test"),
        attrs: ~[resolve_unexported_attr],
        id: ast::DUMMY_NODE_ID,
        node: item_,
        vis: ast::public,
        span: dummy_sp(),
     };

    debug!("Synthetic test module:\n{}\n",
           pprust::item_to_str(&item, cx.sess.intr()));

    return @item;
}

fn nospan<T>(t: T) -> codemap::Spanned<T> {
    codemap::Spanned { node: t, span: dummy_sp() }
}

fn path_node(ids: ~[ast::Ident]) -> ast::Path {
    ast::Path {
        span: dummy_sp(),
        global: false,
        segments: ids.move_iter().map(|identifier| ast::PathSegment {
            identifier: identifier,
            lifetimes: opt_vec::Empty,
            types: opt_vec::Empty,
        }).collect()
    }
}

fn path_node_global(ids: ~[ast::Ident]) -> ast::Path {
    ast::Path {
        span: dummy_sp(),
        global: true,
        segments: ids.move_iter().map(|identifier| ast::PathSegment {
            identifier: identifier,
            lifetimes: opt_vec::Empty,
            types: opt_vec::Empty,
        }).collect()
    }
}

fn mk_tests(cx: &TestCtxt) -> @ast::item {
    // The vector of test_descs for this crate
    let test_descs = mk_test_descs(cx);

    (quote_item!(cx.ext_cx,
        pub static TESTS : &'static [self::extra::test::TestDescAndFn] =
            $test_descs
        ;
    )).unwrap()
}

fn is_extra(crate: &ast::Crate) -> bool {
    match attr::find_pkgid(crate.attrs) {
        Some(ref s) if "extra" == s.name => true,
        _ => false
    }
}

fn mk_test_descs(cx: &TestCtxt) -> @ast::Expr {
    debug!("building test vector from {} tests", cx.testfns.len());
    let mut descs = ~[];
    for test in cx.testfns.iter() {
        descs.push(mk_test_desc_and_fn_rec(cx, test));
    }

    let inner_expr = @ast::Expr {
        id: ast::DUMMY_NODE_ID,
        node: ast::ExprVec(descs, ast::MutImmutable),
        span: dummy_sp(),
    };

    @ast::Expr {
        id: ast::DUMMY_NODE_ID,
        node: ast::ExprVstore(inner_expr, ast::ExprVstoreSlice),
        span: dummy_sp(),
    }
}

fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> @ast::Expr {
    let span = test.span;
    let path = test.path.clone();

    debug!("encoding {}", ast_util::path_name_i(path));

    let name_lit: ast::lit =
        nospan(ast::lit_str(ast_util::path_name_i(path).to_managed(), ast::CookedStr));

    let name_expr = @ast::Expr {
          id: ast::DUMMY_NODE_ID,
          node: ast::ExprLit(@name_lit),
          span: span
    };

    let fn_path = path_node_global(path);

    let fn_expr = @ast::Expr {
        id: ast::DUMMY_NODE_ID,
        node: ast::ExprPath(fn_path),
        span: span,
    };

    let t_expr = if test.bench {
        quote_expr!(cx.ext_cx, self::extra::test::StaticBenchFn($fn_expr) )
    } else {
        quote_expr!(cx.ext_cx, self::extra::test::StaticTestFn($fn_expr) )
    };

    let ignore_expr = if test.ignore {
        quote_expr!(cx.ext_cx, true )
    } else {
        quote_expr!(cx.ext_cx, false )
    };

    let fail_expr = if test.should_fail {
        quote_expr!(cx.ext_cx, true )
    } else {
        quote_expr!(cx.ext_cx, false )
    };

    let e = quote_expr!(cx.ext_cx,
        self::extra::test::TestDescAndFn {
            desc: self::extra::test::TestDesc {
                name: self::extra::test::StaticTestName($name_expr),
                ignore: $ignore_expr,
                should_fail: $fail_expr
            },
            testfn: $t_expr,
        }
    );
    e
}
<|endoftext|>


<commit_before>use std::io::{Cursor};

use byteorder::{LittleEndian, WriteBytesExt, ReadBytesExt};

use mul_reader::{simple_from_vecs};
use art::{ArtReader, TileOrStatic, Art, Tile, Static, RunPair, STATIC_OFFSET};

#[test]
fn test_load_tile() {
    let mut data = Cursor::new(vec![]);
    data.write_u32::<LittleEndian>(0).unwrap();  // Header
    for _i in 0..1022 {
        data.write_u16::<LittleEndian>(0xFFFF).unwrap();
    }

    let mul_reader = simple_from_vecs(vec![
        data.into_inner(),
    ]);
    let mut reader = ArtReader::from_mul(mul_reader);
    match reader.read(0) {
        Ok(TileOrStatic::Tile(tile)) => {
            assert_eq!(tile.header, 0);
            assert_eq!(tile.image_data[0], 0xFFFF);
        },
        Ok(_) => {
            panic!("Got Static instead of Tile");
        },
        Err(err) => panic!("{}", err)
    };
}

#[test]
fn test_tile_to_32bit() {
    let tile = Tile {
        header: 0,
        image_data: [0xFFFF; 1022]
    };
    let (width, height, data) = tile.to_32bit();
    assert_eq!(width, 44);
    assert_eq!(height, 44);
    assert_eq!(data.len(), 44 * 44);

    // Check the first row
    for i in 0..44 {
        if i == 21 || i == 22 {
            assert_eq!(data[i], 0xFFFFFFFF);
        } else {
            assert_eq!(data[i], 0);
        }
    }

    // Check the middle row
    for i in 0..44 {
        assert_eq!(data[i + (22 * 44)], 0xFFFFFFFF);
    }
}

#[test]
#[cfg(feature = "use-sdl2")]
fn test_tile_to_surface() {
    let tile = Tile {
        header: 0,
        image_data: [0xFFFF; 1022]
    };
    let surface = tile.to_surface();
    assert_eq!(surface.width(), 44);
    assert_eq!(surface.height(), 44);
    let data = surface.without_lock().unwrap();
    assert_eq!(data.len(), 44 * 44 * 4);

    // Check the first row
    for i in 0..44 {
        if i == 21 || i == 22 {
            assert_eq!(data[(i * 4)], 0xFF);
            assert_eq!(data[(i * 4) + 1], 0xFF);
            assert_eq!(data[(i * 4) + 2], 0xFF);
            assert_eq!(data[(i * 4) + 3], 0xFF);
        } else {
            assert_eq!(data[(i * 4)], 0);
            assert_eq!(data[(i * 4) + 1], 0);
            assert_eq!(data[(i * 4) + 2], 0);
            assert_eq!(data[(i * 4) + 3], 0);
        }
    }

    // Check the middle row
    for i in 0..44 {
        assert_eq!(data[((i + (22 * 44)) * 4)], 0xFF);
        assert_eq!(data[((i + (22 * 44)) * 4) + 1], 0xFF);
        assert_eq!(data[((i + (22 * 44)) * 4) + 2], 0xFF);
        assert_eq!(data[((i + (22 * 44)) * 4) + 3], 0xFF);
    }
}

#[test]
fn test_load_static() {
    let mut data = Cursor::new(vec![]);

    data.write_u16::<LittleEndian>(0).unwrap();  //Size, unused
    data.write_u16::<LittleEndian>(1).unwrap();  //Trigger, unknown
    data.write_u16::<LittleEndian>(3).unwrap();  //Width in pixels
    data.write_u16::<LittleEndian>(3).unwrap();  //Height in pixels

    data.write_u16::<LittleEndian>(0).unwrap();  //Row 1 offset
    data.write_u16::<LittleEndian>(5).unwrap();  //Row 2 offset
    data.write_u16::<LittleEndian>(12).unwrap();  //Row 3 offset

    data.write_u16::<LittleEndian>(1).unwrap();  //Row 1, run 1 spacer
    data.write_u16::<LittleEndian>(1).unwrap();  //Row 1, run 1 number of pixels
    data.write_u16::<LittleEndian>(0xFFFF).unwrap();  //Row 1, run 1 data
    data.write_u32::<LittleEndian>(0).unwrap();  //Row 1 EOL

    data.write_u16::<LittleEndian>(0).unwrap();  //Row 2, run 1 spacer
    data.write_u16::<LittleEndian>(3).unwrap();  //Row 2, run 1 number of pixels
    data.write_u16::<LittleEndian>(0xFFFF).unwrap();  //Row 2, run 1 data
    data.write_u16::<LittleEndian>(0xFFFF).unwrap();  //Row 2, run 1 data
    data.write_u16::<LittleEndian>(0xFFFF).unwrap();  //Row 2, run 1 data
    data.write_u32::<LittleEndian>(0).unwrap();  //Row 2 EOL

    data.write_u16::<LittleEndian>(1).unwrap();  //Row 1, run 1 spacer
    data.write_u16::<LittleEndian>(1).unwrap();  //Row 1, run 1 number of pixels
    data.write_u16::<LittleEndian>(0xFFFF).unwrap();  //Row 1, run 1 data
    data.write_u32::<LittleEndian>(0).unwrap();  //Row 2 EOL

    let mut padded = vec![];
    for _i in 0..STATIC_OFFSET {
        padded.push(vec![]);
    }
    padded.push(data.into_inner());

    let mul_reader = simple_from_vecs(padded);
    let mut reader = ArtReader::from_mul(mul_reader);

    match reader.read(STATIC_OFFSET) {
        Ok(TileOrStatic::Static(stat)) => {
        },
        Ok(_) => {
            panic!("Got Tile instead of Static");
        },
        Err(err) => panic!("{}", err)
    };
}

/*#[test]
fn dump_art() {
    use mul_reader::MulWriter;
    use art::{Art, Tile};
    use std::io::FileMode;
    let dummy_tile = Tile {header: 0, image_data: [0xFFFF, ..1022]};
    let mut mul_writer = MulWriter::new(&Path::new("./testdata/test_art.idx"), &Path::new("./testdata/test_art.mul"), FileMode::Truncate).ok().expect("Can't open files for writing");

    let serialized = dummy_tile.serialize();

    for i in range(0, 0x4000u32) {
        mul_writer.append(&serialized, None, None).ok().expect("Can't write white tile");
    }
}*/
<commit_msg>Test image unpacking shape<commit_after>use std::io::{Cursor};

use byteorder::{LittleEndian, WriteBytesExt, ReadBytesExt};

use mul_reader::{simple_from_vecs};
use art::{ArtReader, TileOrStatic, Art, Tile, Static, RunPair, STATIC_OFFSET};

#[test]
fn test_load_tile() {
    let mut data = Cursor::new(vec![]);
    data.write_u32::<LittleEndian>(0).unwrap();  // Header
    for _i in 0..1022 {
        data.write_u16::<LittleEndian>(0xFFFF).unwrap();
    }

    let mul_reader = simple_from_vecs(vec![
        data.into_inner(),
    ]);
    let mut reader = ArtReader::from_mul(mul_reader);
    match reader.read(0) {
        Ok(TileOrStatic::Tile(tile)) => {
            assert_eq!(tile.header, 0);
            assert_eq!(tile.image_data[0], 0xFFFF);
        },
        Ok(_) => {
            panic!("Got Static instead of Tile");
        },
        Err(err) => panic!("{}", err)
    };
}

#[test]
fn test_tile_to_32bit() {
    let tile = Tile {
        header: 0,
        image_data: [0xFFFF; 1022]
    };
    let (width, height, data) = tile.to_32bit();
    assert_eq!(width, 44);
    assert_eq!(height, 44);
    assert_eq!(data.len(), 44 * 44);

    // Check the first row
    for i in 0..44 {
        if i == 21 || i == 22 {
            assert_eq!(data[i], 0xFFFFFFFF);
        } else {
            assert_eq!(data[i], 0);
        }
    }

    // Check the middle row
    for i in 0..44 {
        assert_eq!(data[i + (22 * 44)], 0xFFFFFFFF);
    }
}

#[test]
#[cfg(feature = "use-sdl2")]
fn test_tile_to_surface() {
    let tile = Tile {
        header: 0,
        image_data: [0xFFFF; 1022]
    };
    let surface = tile.to_surface();
    assert_eq!(surface.width(), 44);
    assert_eq!(surface.height(), 44);
    let data = surface.without_lock().unwrap();
    assert_eq!(data.len(), 44 * 44 * 4);

    // Check the first row
    for i in 0..44 {
        if i == 21 || i == 22 {
            assert_eq!(data[(i * 4)], 0xFF);
            assert_eq!(data[(i * 4) + 1], 0xFF);
            assert_eq!(data[(i * 4) + 2], 0xFF);
            assert_eq!(data[(i * 4) + 3], 0xFF);
        } else {
            assert_eq!(data[(i * 4)], 0);
            assert_eq!(data[(i * 4) + 1], 0);
            assert_eq!(data[(i * 4) + 2], 0);
            assert_eq!(data[(i * 4) + 3], 0);
        }
    }

    // Check the middle row
    for i in 0..44 {
        assert_eq!(data[((i + (22 * 44)) * 4)], 0xFF);
        assert_eq!(data[((i + (22 * 44)) * 4) + 1], 0xFF);
        assert_eq!(data[((i + (22 * 44)) * 4) + 2], 0xFF);
        assert_eq!(data[((i + (22 * 44)) * 4) + 3], 0xFF);
    }
}

#[test]
fn test_load_static() {
    let mut data = Cursor::new(vec![]);

    data.write_u16::<LittleEndian>(0).unwrap();  //Size, unused
    data.write_u16::<LittleEndian>(1).unwrap();  //Trigger, unknown
    data.write_u16::<LittleEndian>(3).unwrap();  //Width in pixels
    data.write_u16::<LittleEndian>(3).unwrap();  //Height in pixels

    data.write_u16::<LittleEndian>(0).unwrap();  //Row 1 offset
    data.write_u16::<LittleEndian>(5).unwrap();  //Row 2 offset
    data.write_u16::<LittleEndian>(12).unwrap();  //Row 3 offset

    data.write_u16::<LittleEndian>(1).unwrap();  //Row 1, run 1 spacer
    data.write_u16::<LittleEndian>(1).unwrap();  //Row 1, run 1 number of pixels
    data.write_u16::<LittleEndian>(0xFFFF).unwrap();  //Row 1, run 1 data
    data.write_u32::<LittleEndian>(0).unwrap();  //Row 1 EOL

    data.write_u16::<LittleEndian>(0).unwrap();  //Row 2, run 1 spacer
    data.write_u16::<LittleEndian>(3).unwrap();  //Row 2, run 1 number of pixels
    data.write_u16::<LittleEndian>(0xFFFF).unwrap();  //Row 2, run 1 data
    data.write_u16::<LittleEndian>(0xFFFF).unwrap();  //Row 2, run 1 data
    data.write_u16::<LittleEndian>(0xFFFF).unwrap();  //Row 2, run 1 data
    data.write_u32::<LittleEndian>(0).unwrap();  //Row 2 EOL

    data.write_u16::<LittleEndian>(1).unwrap();  //Row 1, run 1 spacer
    data.write_u16::<LittleEndian>(1).unwrap();  //Row 1, run 1 number of pixels
    data.write_u16::<LittleEndian>(0xFFFF).unwrap();  //Row 1, run 1 data
    data.write_u32::<LittleEndian>(0).unwrap();  //Row 2 EOL

    let mut padded = vec![];
    for _i in 0..STATIC_OFFSET {
        padded.push(vec![]);
    }
    padded.push(data.into_inner());

    let mul_reader = simple_from_vecs(padded);
    let mut reader = ArtReader::from_mul(mul_reader);

    match reader.read(STATIC_OFFSET) {
        Ok(TileOrStatic::Static(stat)) => {
            assert_eq!(stat.size, 0);
            assert_eq!(stat.trigger, 1);
            assert_eq!(stat.width, 3);
            assert_eq!(stat.height, 3);
            let (width, height, data) = stat.to_32bit();
            assert_eq!(stat.width, width as u16);
            assert_eq!(stat.height, height as u16);
            assert_eq!(data, vec![
                0, 0xFFFFFFFF, 0,
                0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
                0, 0xFFFFFFFF, 0
            ]);
        },
        Ok(_) => {
            panic!("Got Tile instead of Static");
        },
        Err(err) => panic!("{}", err)
    };
}

/*#[test]
fn dump_art() {
    use mul_reader::MulWriter;
    use art::{Art, Tile};
    use std::io::FileMode;
    let dummy_tile = Tile {header: 0, image_data: [0xFFFF, ..1022]};
    let mut mul_writer = MulWriter::new(&Path::new("./testdata/test_art.idx"), &Path::new("./testdata/test_art.mul"), FileMode::Truncate).ok().expect("Can't open files for writing");

    let serialized = dummy_tile.serialize();

    for i in range(0, 0x4000u32) {
        mul_writer.append(&serialized, None, None).ok().expect("Can't write white tile");
    }
}*/
<|endoftext|>