<commit_before>//! The simplest to use transport a `gready_stream`
//!
//! The transport agressively reads everything from input socket putting it
//! into the buffer. Similarly everything put into output buffer is just sent
//! back to the user.
//!
//! It's assumed that Protocol is able to keep up with the input rate. But if
//! it's not always the case you can always see input buffer size and drop
//! a connection. Currently you can't throttle neither reading end nor writer
//! (i.e. don't put everything to the output buffer at once)
//!
//! This is tradeoff to have super simple protocol and semantics. More
//! elaborate protocols will be implemented in the future.
//!
use std::io::{Read, Write, Error};
use std::marker::PhantomData;
use std::io::ErrorKind::{WouldBlock, Interrupted};

use mio::{EventSet, PollOpt, Evented};
use netbuf::Buf;

use super::StreamSocket as Socket;
use super::super::handler::EventMachine;
use super::accept::Init;

use {Scope, BaseMachine};

impl<T> Socket for T where T: Read, T: Write, T: Evented {}

struct Inner<S: Socket+Send> {
    sock: S,
    inbuf: Buf,
    outbuf: Buf,
    writable: bool,
    readable: bool,
}

pub struct Transport<'a> {
    inbuf: &'a mut Buf,
    outbuf: &'a mut Buf,
}

pub struct Stream<S: Socket+Send, P: Protocol<C>, C>(
    Inner<S>, P, PhantomData<*const C>);

unsafe impl<S: Socket+Send, P: Protocol<C>+Send, C> Send for Stream<S, P, C> {}

/// This trait you should implement to handle the protocol. Only data_received
/// handler is required, everything else may be left as is.
pub trait Protocol<C>: BaseMachine + Send + Sized {
    /// Returns new state machine in a state for new accepted connection
    // TODO(tailhook) should socket address be passed here?
    fn accepted(ctx: &mut C) -> Self;
    /// Some chunk of data has been received and placed into the buffer
    ///
    /// It's edge-triggered so be sure to read everything useful. But you
    /// can leave half-received packets in the buffer
    fn data_received(self, transport: &mut Transport, ctx: &mut C)
        -> Option<Self>;

    /// Eof received. State machine will shutdown unconditionally
    fn eof_received(self, _ctx: &mut C) {}

    /// Fatal error on connection happened, you may process error somehow, but
    /// statemachine will be destroyed anyway (note you receive self)
    ///
    /// Default action is to log error on the info level
    fn error_happened(self, e: Error, _ctx: &mut C) {
        info!("Error when handling connection: {}", e);
    }
}

impl<T, P, C> Init<T, C> for Stream<T, P, C>
    where T: Socket+Send, P: Protocol<C>
{
    fn accept<S>(conn: T, context: &mut C, _scope: &mut S)
        -> Self
        where S: Scope<Self>
    {
        Stream(Inner {
            sock: conn,
            inbuf: Buf::new(),
            outbuf: Buf::new(),
            readable: false,
            writable: true,   // Accepted socket is immediately writable
        }, Protocol::accepted(context), PhantomData)
    }
}
impl<T, P, Ctx> BaseMachine for Stream<T, P, Ctx>
    where T: Socket+Send, P: Protocol<Ctx>
{
    type Timeout = P::Timeout;
}

impl<T, P, Ctx> EventMachine<Ctx> for Stream<T, P, Ctx>
    where T: Socket+Send, P: Protocol<Ctx>
{
    fn ready<S>(self, evset: EventSet, context: &mut Ctx, _scope: &mut S)
        -> Option<Stream<T, P, Ctx>>
        where S: Scope<Self>
    {
        let Stream(mut stream, mut fsm, _) = self;
        if evset.is_writable() && stream.outbuf.len() > 0 {
            stream.writable = true;
            while stream.outbuf.len() > 0 {
                match stream.outbuf.write_to(&mut stream.sock) {
                    Ok(0) => { // Connection closed
                        fsm.eof_received(context);
                        return None;
                    }
                    Ok(_) => {}  // May notify application
                    Err(ref e) if e.kind() == WouldBlock => {
                        stream.writable = false;
                        break;
                    }
                    Err(ref e) if e.kind() == Interrupted =>  { continue; }
                    Err(e) => {
                        fsm.error_happened(e, context);
                        return None;
                    }
                }
            }
        }
        if evset.is_readable() {
            stream.readable = true;
            loop {
                match stream.inbuf.read_from(&mut stream.sock) {
                    Ok(0) => { // Connection closed
                        fsm.eof_received(context);
                        return None;
                    }
                    Ok(_) => {
                        fsm = match fsm.data_received(&mut Transport {
                            inbuf: &mut stream.inbuf,
                            outbuf: &mut stream.outbuf,
                        }, context) {
                            Some(fsm) => fsm,
                            None => return None,
                        };
                    }
                    Err(ref e) if e.kind() == WouldBlock => {
                        stream.readable = false;
                        break;
                    }
                    Err(ref e) if e.kind() == Interrupted =>  { continue; }
                    Err(e) => {
                        fsm.error_happened(e, context);
                        return None;
                    }
                }
            }
        }
        if stream.writable && stream.outbuf.len() > 0 {
            while stream.outbuf.len() > 0 {
                match stream.outbuf.write_to(&mut stream.sock) {
                    Ok(0) => { // Connection closed
                        fsm.eof_received(context);
                        return None;
                    }
                    Ok(_) => {}  // May notify application
                    Err(ref e) if e.kind() == WouldBlock => {
                        stream.writable = false;
                        break;
                    }
                    Err(ref e) if e.kind() == Interrupted =>  { continue; }
                    Err(e) => {
                        fsm.error_happened(e, context);
                        return None;
                    }
                }
            }
        }
        Some(Stream(stream, fsm, PhantomData))
    }

    fn register<S>(&mut self, scope: &mut S)
        -> Result<(), Error>
        where S: Scope<Self>
    {
        scope.register(&self.0.sock, EventSet::all(), PollOpt::edge())
    }
}

impl<'a> Transport<'a> {
    pub fn input<'x>(&'x mut self) -> &'x mut Buf {
        self.inbuf
    }
    pub fn output<'x>(&'x mut self) -> &'x mut Buf {
        self.outbuf
    }
}
<commit_msg>Pass socket to greedy_stream::Protocol::accepted<commit_after>//! The simplest to use transport a `gready_stream`
//!
//! The transport agressively reads everything from input socket putting it
//! into the buffer. Similarly everything put into output buffer is just sent
//! back to the user.
//!
//! It's assumed that Protocol is able to keep up with the input rate. But if
//! it's not always the case you can always see input buffer size and drop
//! a connection. Currently you can't throttle neither reading end nor writer
//! (i.e. don't put everything to the output buffer at once)
//!
//! This is tradeoff to have super simple protocol and semantics. More
//! elaborate protocols will be implemented in the future.
//!
use std::io::{Read, Write, Error};
use std::marker::PhantomData;
use std::io::ErrorKind::{WouldBlock, Interrupted};

use mio::{EventSet, PollOpt, Evented};
use netbuf::Buf;

use super::StreamSocket as Socket;
use super::super::handler::EventMachine;
use super::accept::Init;

use {Scope, BaseMachine};

impl<T> Socket for T where T: Read, T: Write, T: Evented {}

struct Inner<S: Socket+Send> {
    sock: S,
    inbuf: Buf,
    outbuf: Buf,
    writable: bool,
    readable: bool,
}

pub struct Transport<'a> {
    inbuf: &'a mut Buf,
    outbuf: &'a mut Buf,
}

pub struct Stream<S: Socket+Send, P: Protocol<S, C>, C>(
    Inner<S>, P, PhantomData<*const C>);

unsafe impl<S: Socket+Send, P: Protocol<S, C>+Send, C> Send for Stream<S, P, C> {}

/// This trait you should implement to handle the protocol. Only data_received
/// handler is required, everything else may be left as is.
pub trait Protocol<S, C>: BaseMachine + Send + Sized {
    /// Returns new state machine in a state for new accepted connection
    fn accepted(conn: &mut S, ctx: &mut C) -> Self;
    /// Some chunk of data has been received and placed into the buffer
    ///
    /// It's edge-triggered so be sure to read everything useful. But you
    /// can leave half-received packets in the buffer
    fn data_received(self, transport: &mut Transport, ctx: &mut C)
        -> Option<Self>;

    /// Eof received. State machine will shutdown unconditionally
    fn eof_received(self, _ctx: &mut C) {}

    /// Fatal error on connection happened, you may process error somehow, but
    /// statemachine will be destroyed anyway (note you receive self)
    ///
    /// Default action is to log error on the info level
    fn error_happened(self, e: Error, _ctx: &mut C) {
        info!("Error when handling connection: {}", e);
    }
}

impl<T, P, C> Init<T, C> for Stream<T, P, C>
    where T: Socket+Send, P: Protocol<T, C>
{
    fn accept<S>(mut conn: T, context: &mut C, _scope: &mut S)
        -> Self
        where S: Scope<Self>
    {
        let protocol = Protocol::accepted(&mut conn, context);

        Stream(Inner {
            sock: conn,
            inbuf: Buf::new(),
            outbuf: Buf::new(),
            readable: false,
            writable: true,   // Accepted socket is immediately writable
        }, protocol, PhantomData)
    }
}
impl<T, P, Ctx> BaseMachine for Stream<T, P, Ctx>
    where T: Socket+Send, P: Protocol<T, Ctx>
{
    type Timeout = P::Timeout;
}

impl<T, P, Ctx> EventMachine<Ctx> for Stream<T, P, Ctx>
    where T: Socket+Send, P: Protocol<T, Ctx>
{
    fn ready<S>(self, evset: EventSet, context: &mut Ctx, _scope: &mut S)
        -> Option<Stream<T, P, Ctx>>
        where S: Scope<Self>
    {
        let Stream(mut stream, mut fsm, _) = self;
        if evset.is_writable() && stream.outbuf.len() > 0 {
            stream.writable = true;
            while stream.outbuf.len() > 0 {
                match stream.outbuf.write_to(&mut stream.sock) {
                    Ok(0) => { // Connection closed
                        fsm.eof_received(context);
                        return None;
                    }
                    Ok(_) => {}  // May notify application
                    Err(ref e) if e.kind() == WouldBlock => {
                        stream.writable = false;
                        break;
                    }
                    Err(ref e) if e.kind() == Interrupted =>  { continue; }
                    Err(e) => {
                        fsm.error_happened(e, context);
                        return None;
                    }
                }
            }
        }
        if evset.is_readable() {
            stream.readable = true;
            loop {
                match stream.inbuf.read_from(&mut stream.sock) {
                    Ok(0) => { // Connection closed
                        fsm.eof_received(context);
                        return None;
                    }
                    Ok(_) => {
                        fsm = match fsm.data_received(&mut Transport {
                            inbuf: &mut stream.inbuf,
                            outbuf: &mut stream.outbuf,
                        }, context) {
                            Some(fsm) => fsm,
                            None => return None,
                        };
                    }
                    Err(ref e) if e.kind() == WouldBlock => {
                        stream.readable = false;
                        break;
                    }
                    Err(ref e) if e.kind() == Interrupted =>  { continue; }
                    Err(e) => {
                        fsm.error_happened(e, context);
                        return None;
                    }
                }
            }
        }
        if stream.writable && stream.outbuf.len() > 0 {
            while stream.outbuf.len() > 0 {
                match stream.outbuf.write_to(&mut stream.sock) {
                    Ok(0) => { // Connection closed
                        fsm.eof_received(context);
                        return None;
                    }
                    Ok(_) => {}  // May notify application
                    Err(ref e) if e.kind() == WouldBlock => {
                        stream.writable = false;
                        break;
                    }
                    Err(ref e) if e.kind() == Interrupted =>  { continue; }
                    Err(e) => {
                        fsm.error_happened(e, context);
                        return None;
                    }
                }
            }
        }
        Some(Stream(stream, fsm, PhantomData))
    }

    fn register<S>(&mut self, scope: &mut S)
        -> Result<(), Error>
        where S: Scope<Self>
    {
        scope.register(&self.0.sock, EventSet::all(), PollOpt::edge())
    }
}

impl<'a> Transport<'a> {
    pub fn input<'x>(&'x mut self) -> &'x mut Buf {
        self.inbuf
    }
    pub fn output<'x>(&'x mut self) -> &'x mut Buf {
        self.outbuf
    }
}
<|endoftext|>


<commit_before>use find_interval;

#[derive(Debug)]
pub struct Distribution1D {
    pub func: Vec<f32>,
    cdf: Vec<f32>,
    pub func_int: f32,
}

impl Distribution1D {
    pub fn new(f: &[f32]) -> Distribution1D {
        let n = f.len();
        let func = Vec::from(f);
        let mut cdf = vec![0.0; n + 1];
        // compute integral of step function at xi
        cdf[0] = 0.0;
        for i in 1..(n + 1) {
            cdf[i] = cdf[i - 1] + func[i - 1] / n as f32;
        }
        // transform step function integral into CDF
        let func_int = cdf[n];
        if func_int == 0.0 {
            for i in 1..(n + 1) {
                cdf[i] = i as f32 / n as f32;
            }
        } else {
            for i in 1..(n + 1) {
                cdf[i] /= func_int;
            }
        }

        Distribution1D {
            cdf: cdf,
            func: func,
            func_int: func_int,
        }
    }

    pub fn count(&self) -> usize {
        self.func.len()
    }

    pub fn sample_continuous(&self, u: f32) -> (f32, f32, usize) {
        // Find surrounding CDF segments and offset
        let offset = find_interval(self.cdf.len(), |i| self.cdf[i] <= u);
        // compute offset along CDF segment
        let mut du = u - self.cdf[offset];
        if self.cdf[offset + 1] - self.cdf[offset] > 0.0 {
            du /= self.cdf[offset + 1] - self.cdf[offset];
        }
        // compute PDF for sampled offset
        let pdf = self.func[offset] / self.func_int;

        // return x ∈ [0,1) corresponding to sample
        let x = (offset as f32 + du) / self.count() as f32;

        (x, pdf, offset)
    }

    pub fn sample_discrete(&self, u: f32) -> (usize, f32) {
        let offset = find_interval(self.cdf.len(), |i| self.cdf[i] <= u);
        let pdf = if self.func_int > 0.0 {
            self.func[offset] / (self.func_int * self.count() as f32)
        } else {
            0.0
        };

        (offset, pdf)
    }

    // TODO pdf_discrete
}

#[test]
fn test_discrete() {
    let func = [0.0, 1.0, 0.0, 3.0];
    let distrib = Distribution1D::new(&func[..]);

    assert_eq!(4, distrib.count());

    assert_eq!((1, 0.25), distrib.sample_discrete(0.0));
    assert_eq!((1, 0.25), distrib.sample_discrete(0.125));
    assert_eq!((1, 0.25), distrib.sample_discrete(0.24999));
    assert_eq!((3, 0.75), distrib.sample_discrete(0.250001));
    assert_eq!((3, 0.75), distrib.sample_discrete(0.625));
    assert_eq!((3, 0.75), distrib.sample_discrete(::ONE_MINUS_EPSILON));
    assert_eq!((3, 0.75), distrib.sample_discrete(1.0));
}
<commit_msg>Tiny fix in Distribution1D<commit_after>use find_interval;

#[derive(Debug)]
pub struct Distribution1D {
    pub func: Vec<f32>,
    cdf: Vec<f32>,
    pub func_int: f32,
}

impl Distribution1D {
    pub fn new(f: &[f32]) -> Distribution1D {
        let n = f.len();
        let func = Vec::from(f);
        let mut cdf = vec![0.0; n + 1];
        // compute integral of step function at xi
        cdf[0] = 0.0;
        for i in 1..(n + 1) {
            cdf[i] = cdf[i - 1] + func[i - 1] / n as f32;
        }
        // transform step function integral into CDF
        let func_int = cdf[n];
        if func_int == 0.0 {
            for i in 1..(n + 1) {
                cdf[i] = i as f32 / n as f32;
            }
        } else {
            for i in 1..(n + 1) {
                cdf[i] /= func_int;
            }
        }

        Distribution1D {
            cdf: cdf,
            func: func,
            func_int: func_int,
        }
    }

    pub fn count(&self) -> usize {
        self.func.len()
    }

    pub fn sample_continuous(&self, u: f32) -> (f32, f32, usize) {
        // Find surrounding CDF segments and offset
        let offset = find_interval(self.cdf.len(), |i| self.cdf[i] <= u);
        // compute offset along CDF segment
        let mut du = u - self.cdf[offset];
        if self.cdf[offset + 1] - self.cdf[offset] > 0.0 {
            assert!(self.cdf[offset + 1] > self.cdf[offset]);
            du /= self.cdf[offset + 1] - self.cdf[offset];
        }
        // compute PDF for sampled offset
        let pdf = if self.func_int > 0.0 {
            self.func[offset] / self.func_int
        } else {
            0.0
        };

        // return x ∈ [0,1) corresponding to sample
        let x = (offset as f32 + du) / self.count() as f32;

        (x, pdf, offset)
    }

    pub fn sample_discrete(&self, u: f32) -> (usize, f32) {
        let offset = find_interval(self.cdf.len(), |i| self.cdf[i] <= u);
        let pdf = if self.func_int > 0.0 {
            self.func[offset] / (self.func_int * self.count() as f32)
        } else {
            0.0
        };

        (offset, pdf)
    }

    // TODO pdf_discrete
}

#[test]
fn test_discrete() {
    let func = [0.0, 1.0, 0.0, 3.0];
    let distrib = Distribution1D::new(&func[..]);

    assert_eq!(4, distrib.count());

    assert_eq!((1, 0.25), distrib.sample_discrete(0.0));
    assert_eq!((1, 0.25), distrib.sample_discrete(0.125));
    assert_eq!((1, 0.25), distrib.sample_discrete(0.24999));
    assert_eq!((3, 0.75), distrib.sample_discrete(0.250001));
    assert_eq!((3, 0.75), distrib.sample_discrete(0.625));
    assert_eq!((3, 0.75), distrib.sample_discrete(::ONE_MINUS_EPSILON));
    assert_eq!((3, 0.75), distrib.sample_discrete(1.0));
}
<|endoftext|>


<commit_before>use piston::window::WindowSettings;
use piston_window;
use piston_window::{PistonWindow, UpdateArgs, Event, OpenGL, TextureSettings, Flip};
use gfx_device_gl::Resources;
use glutin;
use audio_private;
use audio::Dj;
use input_private;
use input::Input;
use game_object::GameObject;
use game_object;
use texture::Texture;
use texture;
use transform::Transform;
use transform;
use camera::Camera;
use nphysics2d::world::World;
use rodio;
use rodio::Decoder;
use rodio::source::Buffered;
use rodio::Source;
use std::collections::HashMap;
use std::fs::File;
use std::io::BufReader;
use std::path::PathBuf;
use std::f32;

type BufferedAudioFile = Buffered<Decoder<BufReader<File>>>;

pub struct App {
    window: PistonWindow,
    game_objects: HashMap<u64, Box<GameObject>>,
    next_game_object_id: u64,
    pub input: Input,
    sound_cache: HashMap<String, Box<BufferedAudioFile>>,
    pub camera: Camera,
    pub world: World<f32>,
}

impl App {
    pub fn new(name: &str) -> App {
        let opengl = OpenGL::V3_2;
        let (width, height) = glutin::get_primary_monitor().get_dimensions();
        App {
            next_game_object_id: 0,
            game_objects: HashMap::new(),
            input: Input::new(),
            sound_cache: HashMap::new(),
            window: WindowSettings::new(name, [width, height])
                .opengl(opengl)
                .exit_on_esc(true)
                .fullscreen(false)
                .build()
                .unwrap(),
            camera: Camera { transform: Transform::new() },
            world: World::new(),
        }
    }

    fn render(&mut self, e: &Event) {
        // This should never be false.
        // The only reason I didn't request the render_args in the signature is the Piston API
        // requires the event object.
        if let Event::Render(render_args) = *e {
            use graphics::*;
            const GREY: [f32; 4] = [0.9, 0.9, 0.9, 1.0];
            let game_objs = &self.game_objects;
            let camera_transform = self.camera.transform;
            self.window.draw_2d(e, |c, gl| {
                // Clear the screen.
                clear(GREY, gl);
                for game_obj in game_objs.values() {
                    let mut render_transform = game_obj.transform;
                    *render_transform.mut_x() -= *camera_transform.x() -
                                                 (render_args.draw_width / 2) as f32;
                    *render_transform.mut_y() -= *camera_transform.y() -
                                                 (render_args.draw_height / 2) as f32;
                    *render_transform.mut_rotation() -= *camera_transform.rotation();
                    let (tex_width, tex_height) = texture::get_raw(&game_obj.texture).get_size();
                    image(texture::get_raw(&game_obj.texture),
                          c.transform
                              .append_transform(transform::get_raw(&render_transform))
                              .trans(-(tex_width as f64) / 2.0, -(tex_height as f64) / 2.0),
                          gl);
                }
            });
        } else {
            panic!("Render should never be called with an event that isn't Event::Render.");
        }
    }

    fn update(&mut self, args: &UpdateArgs) {
        for mut game_object in self.game_objects.values_mut() {
            game_object::copy_to_physics(game_object);
        }
        self.world.step(args.dt as f32);
        for mut game_object in self.game_objects.values_mut() {
            game_object::copy_from_physics(game_object);
        }
        let keys = self.game_objects.keys().map(|x| *x).collect::<Vec<u64>>();
        for key in keys {
            if let Some(mut game_object) = self.game_objects.remove(&key) {
                game_object.update(self, args.dt as f32);
                *game_object.transform.mut_rotation() %= 2.0 * f32::consts::PI;
                self.game_objects.insert(game_object.get_id(), game_object);
            }
        }
        input_private::input::shift_frame(&mut self.input);
    }

    pub fn run(&mut self) {
        while let Some(e) = self.window.next() {
            match e {
                Event::Render(..) => {
                    self.render(&e);
                }
                Event::AfterRender(..) => {}
                Event::Update(update_args) => self.update(&update_args),
                Event::Idle(..) => {}
                Event::Input(input_event) => {
                    input_private::input::process_event(&mut self.input, input_event);
                }
            }
        }
    }

    pub fn play_sound(&mut self, path: &str, volume: f32) {
        let mut sink = rodio::Sink::new(&rodio::get_default_endpoint().unwrap());
        sink.set_volume(volume);
        sink.append(fetch_sound(self, path));
        sink.detach();
    }

    pub fn hire_dj(&mut self) -> Dj {
        let sink = rodio::Sink::new(&rodio::get_default_endpoint().unwrap());
        audio_private::dj::new_dj(sink)
    }

    // Load a sound into the cache if it's not already there.
    pub fn load_sound(&mut self, path: &str) {
        if !self.sound_cache.contains_key(path) {
            let mut sound_path = PathBuf::from("assets");
            sound_path.push("sounds");
            sound_path.push(path);
            let file = File::open(sound_path).unwrap();
            let new_source =
                Box::new(rodio::Decoder::new(BufReader::new(file)).unwrap().buffered());
            self.sound_cache.insert(path.to_owned(), new_source);
        }
    }

    pub fn unload_sound(&mut self, path: &str) {
        self.sound_cache.remove(path);
    }

    pub fn new_gameobject<F>(&mut self, f: F) where F: FnOnce(&mut App, &mut GameObject) {
        let mut game_object = Box::new(game_object::new(self));
        f(self, &mut game_object);
        let id = game_object.get_id();
        self.game_objects.insert(id, game_object);
    }

    pub fn game_object_by_id(&self, id: u64) -> Option<&GameObject> {
        if let Some(boxxed) = self.game_objects.get(&id) {
            Some(boxxed.as_ref())
        }
        else {
            None
        }
    }

    pub fn game_object_mut_by_id(&mut self, id: u64) -> Option<&mut GameObject> {
        use std::borrow::BorrowMut;
        if let Some(boxxed) = self.game_objects.get_mut(&id) {
            Some(boxxed.borrow_mut())
        }
        else {
            None
        }
    }

    pub fn empty_raw_texture(&mut self) -> piston_window::Texture<Resources> {
        piston_window::Texture::empty(&mut self.window.factory)
            .expect("Getting empty texture failed. 0_o")
    }

    pub fn fetch_texture(&mut self, texture_name: &str) -> Texture {
        let mut texture_path = PathBuf::from("assets");
        texture_path.push("textures");
        texture_path.push(texture_name);
        let result = piston_window::Texture::from_path(&mut self.window.factory,
                                                       texture_path,
                                                       Flip::None,
                                                       &TextureSettings::new());
        let mut return_value = Texture::empty(self);
        match result {
            Ok(texture) => {
                texture::set_raw_texture(&mut return_value, texture);
            }
            Err(err) => {
                println!("Unable to load texture, {} Error: {:?}", texture_name, err);
            }
        }
        return_value
    }
}

// This function will never return 0.  0 can now be used as a null value.
pub fn next_game_object_id(app: &mut App) -> u64 {
    app.next_game_object_id += 1;
    app.next_game_object_id
}

// Fetches sound from cache if present, otherwise loads it from the filesystem.
pub fn fetch_sound(app: &mut App, path: &str) -> BufferedAudioFile {
    if !app.sound_cache.contains_key(path) {
        let mut sound_path = PathBuf::from("assets");
        sound_path.push("sounds");
        sound_path.push(path);
        let file = File::open(sound_path).unwrap();
        let new_source = rodio::Decoder::new(BufReader::new(file)).unwrap().buffered();
        app.sound_cache.insert(path.to_owned(), Box::new(new_source.clone()));
        return new_source;
    }
    (**app.sound_cache.get(path).unwrap()).clone()
}
<commit_msg>Modified app<commit_after>use piston::window::WindowSettings;
use piston_window;
use piston_window::{PistonWindow, UpdateArgs, Event, OpenGL, TextureSettings, Flip};
use gfx_device_gl::Resources;
use glutin;
use audio_private;
use audio::Dj;
use input_private;
use input::Input;
use game_object::GameObject;
use game_object;
use texture::Texture;
use texture;
use transform::Transform;
use transform;
use camera::Camera;
use nphysics2d::world::World;
use rodio;
use rodio::Decoder;
use rodio::source::Buffered;
use rodio::Source;
use std::collections::HashMap;
use std::fs::File;
use std::io::BufReader;
use std::path::PathBuf;
use std::f32;

type BufferedAudioFile = Buffered<Decoder<BufReader<File>>>;

pub struct App {
    window: PistonWindow,
    game_objects: HashMap<u64, Box<GameObject>>,
    next_game_object_id: u64,
    pub input: Input,
    sound_cache: HashMap<String, Box<BufferedAudioFile>>,
    pub camera: Camera,
    pub world: World<f32>,
}

impl App {
    pub fn new(name: &str) -> App {
        let opengl = OpenGL::V3_2;
        let (width, height) = glutin::get_primary_monitor().get_dimensions();
        App {
            next_game_object_id: 0,
            game_objects: HashMap::new(),
            input: Input::new(),
            sound_cache: HashMap::new(),
            window: WindowSettings::new(name, [width, height])
                .opengl(opengl)
                .exit_on_esc(true)
                .fullscreen(false)
                .build()
                .unwrap(),
            camera: Camera { transform: Transform::new() },
            world: World::new(),
        }
    }

    fn render(&mut self, e: &Event) {
        // This should never be false.
        // The only reason I didn't request the render_args in the signature is the Piston API
        // requires the event object.
        if let Event::Render(render_args) = *e {
            use graphics::*;
            const GREY: [f32; 4] = [0.9, 0.9, 0.9, 1.0];
            let game_objs = &self.game_objects;
            let camera_transform = self.camera.transform;
            self.window.draw_2d(e, |c, gl| {
                // Clear the screen.
                clear(GREY, gl);
                for game_obj in game_objs.values() {
                    let mut render_transform = game_obj.transform;
                    *render_transform.mut_x() -= *camera_transform.x() -
                                                 (render_args.draw_width / 2) as f32;
                    *render_transform.mut_y() -= *camera_transform.y() -
                                                 (render_args.draw_height / 2) as f32;
                    *render_transform.mut_rotation() -= *camera_transform.rotation();
                    let (tex_width, tex_height) = texture::get_raw(&game_obj.texture).get_size();
                    image(texture::get_raw(&game_obj.texture),
                          c.transform
                              .append_transform(transform::get_raw(&render_transform))
                              .trans(-(tex_width as f64) / 2.0, -(tex_height as f64) / 2.0),
                          gl);
                }
            });
        } else {
            panic!("Render should never be called with an event that isn't Event::Render.");
        }
    }

    fn update(&mut self, args: &UpdateArgs) {
        for mut game_object in self.game_objects.values_mut() {
            game_object::copy_to_physics(game_object);
        }
        self.world.step(args.dt as f32);
        for mut game_object in self.game_objects.values_mut() {
            game_object::copy_from_physics(game_object);
        }
        let keys = self.game_objects.keys().map(|x| *x).collect::<Vec<u64>>();
        for key in keys {
            if let Some(mut game_object) = self.game_objects.remove(&key) {
                game_object.update(self, args.dt as f32);
                *game_object.transform.mut_rotation() %= 2.0 * f32::consts::PI;
                self.game_objects.insert(game_object.get_id(), game_object);
            }
        }
        input_private::input::shift_frame(&mut self.input);
    }

    pub fn run(&mut self) {
        while let Some(e) = self.window.next() {
            match e {
                Event::Render(..) => {
                    self.render(&e);
                }
                Event::AfterRender(..) => {}
                Event::Update(update_args) => self.update(&update_args),
                Event::Idle(..) => {}
                Event::Input(input_event) => {
                    input_private::input::process_event(&mut self.input, input_event);
                }
            }
        }
    }

    pub fn play_sound(&mut self, path: &str, volume: f32) {
        let mut sink = rodio::Sink::new(&rodio::get_default_endpoint().unwrap());
        sink.set_volume(volume);
        sink.append(fetch_sound(self, path));
        sink.detach();
    }

    pub fn hire_dj(&mut self) -> Dj {
        let sink = rodio::Sink::new(&rodio::get_default_endpoint().unwrap());
        audio_private::dj::new_dj(sink)
    }

    // Load a sound into the cache if it's not already there.
    pub fn load_sound(&mut self, path: &str) {
        if !self.sound_cache.contains_key(path) {
            let mut sound_path = PathBuf::from("assets");
            sound_path.push("sounds");
            sound_path.push(path);
            let file = File::open(sound_path).unwrap();
            let new_source =
                Box::new(rodio::Decoder::new(BufReader::new(file)).unwrap().buffered());
            self.sound_cache.insert(path.to_owned(), new_source);
        }
    }

    pub fn unload_sound(&mut self, path: &str) {
        self.sound_cache.remove(path);
    }

    pub fn new_gameobject<F>(&mut self, f: F)
        where F: FnOnce(&mut App, &mut GameObject)
    {
        let mut game_object = Box::new(game_object::new(self));
        f(self, &mut game_object);
        let id = game_object.get_id();
        self.game_objects.insert(id, game_object);
    }

    pub fn game_object_by_id(&self, id: u64) -> Option<&GameObject> {
        if let Some(boxxed) = self.game_objects.get(&id) {
            Some(boxxed.as_ref())
        } else {
            None
        }
    }

    pub fn game_object_by_id_mut(&mut self, id: u64) -> Option<&mut GameObject> {
        use std::borrow::BorrowMut;
        if let Some(boxxed) = self.game_objects.get_mut(&id) {
            Some(boxxed.borrow_mut())
        } else {
            None
        }
    }

    pub fn empty_raw_texture(&mut self) -> piston_window::Texture<Resources> {
        piston_window::Texture::empty(&mut self.window.factory)
            .expect("Getting empty texture failed. 0_o")
    }

    pub fn fetch_texture(&mut self, texture_name: &str) -> Texture {
        let mut texture_path = PathBuf::from("assets");
        texture_path.push("textures");
        texture_path.push(texture_name);
        let result = piston_window::Texture::from_path(&mut self.window.factory,
                                                       texture_path,
                                                       Flip::None,
                                                       &TextureSettings::new());
        let mut return_value = Texture::empty(self);
        match result {
            Ok(texture) => {
                texture::set_raw_texture(&mut return_value, texture);
            }
            Err(err) => {
                println!("Unable to load texture, {} Error: {:?}", texture_name, err);
            }
        }
        return_value
    }
}

// This function will never return 0.  0 can now be used as a null value.
pub fn next_game_object_id(app: &mut App) -> u64 {
    app.next_game_object_id += 1;
    app.next_game_object_id
}

// Fetches sound from cache if present, otherwise loads it from the filesystem.
pub fn fetch_sound(app: &mut App, path: &str) -> BufferedAudioFile {
    if !app.sound_cache.contains_key(path) {
        let mut sound_path = PathBuf::from("assets");
        sound_path.push("sounds");
        sound_path.push(path);
        let file = File::open(sound_path).unwrap();
        let new_source = rodio::Decoder::new(BufReader::new(file)).unwrap().buffered();
        app.sound_cache.insert(path.to_owned(), Box::new(new_source.clone()));
        return new_source;
    }
    (**app.sound_cache.get(path).unwrap()).clone()
}
<|endoftext|>


<commit_before>use futures::{Future, Async, Poll};
use super::cpu_relax;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::cell::UnsafeCell;
use std::ops::{Deref, DerefMut};

#[derive(Clone)]
pub struct RwLock<T: ?Sized> {
    inner: Arc<RwLockInner<T>>
}

struct RwLockInner<T: ?Sized> {
    raw: RwLockRaw,
    data: UnsafeCell<T>
}

struct RwLockRaw {
    state: AtomicUsize
}

#[derive(Clone)]
pub struct AsyncRwLockReadGuard<T: ?Sized> {
    lock: Arc<RwLockInner<T>>
}

#[derive(Clone)]
pub struct AsyncRwLockWriteGuard<T: ?Sized> {
    lock: Arc<RwLockInner<T>>
}

#[derive(Clone)]
pub struct RwLockReadGuard<T: ?Sized> {
    lock: Arc<RwLockInner<T>>
}

#[derive(Clone)]
pub struct RwLockWriteGuard<T: ?Sized> {
    lock: Arc<RwLockInner<T>>
}

unsafe impl<T: Send> Send for RwLock<T> {}
unsafe impl<T: Send> Sync for RwLock<T> {}

unsafe impl<T: Send> Send for RwLockInner<T> {}
unsafe impl<T: Send> Sync for RwLockInner<T> {}

impl <T: ?Sized> Future for AsyncRwLockReadGuard<T> {
    type Item = RwLockReadGuard<T>;
    type Error = ();

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        if self.lock.raw.try_read() {
            Ok(Async::Ready(RwLockReadGuard {
                lock: self.lock.clone()
            }))
        } else {
            Ok(Async::NotReady)
        }
    }
}

impl <T> Future for AsyncRwLockWriteGuard<T> {
    type Item = RwLockWriteGuard<T>;
    type Error = ();

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        if self.lock.raw.try_write() {
            Ok(Async::Ready(RwLockWriteGuard {
                lock: self.lock.clone()
            }))
        } else {
            Ok(Async::NotReady)
        }
    }
}

impl <T> RwLock <T> {
    pub fn new(val: T) -> RwLock<T> {
        RwLock {
            inner: RwLockInner::new(val)
        }
    }
    pub fn read_async(&self) -> AsyncRwLockReadGuard<T> {
        AsyncRwLockReadGuard {
            lock: self.inner.clone()
        }
    }
    pub fn write_async(&self) -> AsyncRwLockWriteGuard<T> {
        AsyncRwLockWriteGuard {
            lock: self.inner.clone()
        }
    }
    pub fn read(&self) -> RwLockReadGuard<T> {
        while !self.inner.raw.try_read() {
            cpu_relax()
        }
        RwLockReadGuard {
            lock: self.inner.clone()
        }
    }
    pub fn write(&self) -> RwLockWriteGuard<T> {
        while !self.inner.raw.try_write() {
            cpu_relax()
        }
        RwLockWriteGuard {
            lock: self.inner.clone()
        }
    }
}

impl <T> RwLockInner<T> {
    pub fn new(val: T) -> Arc<RwLockInner<T>> {
        Arc::new(RwLockInner {
            raw: RwLockRaw::new(),
            data: UnsafeCell::new(val)
        })
    }
}

impl RwLockRaw {
    fn new() -> RwLockRaw {
        RwLockRaw {
          state: AtomicUsize::new(0)
        }
    }
    fn try_read(&self) -> bool  {
        let lc = self.state.load(Ordering::Relaxed);
        if lc == 1 {
            // write locked
            return false;
        } else {
            let next_count = if lc == 0 { 2 } else { lc + 1 };
            return self.state.compare_and_swap(lc, next_count, Ordering::Relaxed) == lc;
        }
    }
    fn try_write(&self) -> bool {
        self.state.compare_and_swap(0, 1, Ordering::Relaxed) == 0
    }
    fn unlock_read(&self) {
        loop {
            let lc = self.state.load(Ordering::Relaxed);
            let next_count = if lc == 2 { 0 } else { lc - 1 };
            assert!(lc > 1);
            if self.state.compare_and_swap(lc, next_count, Ordering::Relaxed) == lc {
                return;
            } else {
                cpu_relax();
            }
        }
    }
    fn unlock_write(&self) {
        assert_eq!(self.state.compare_and_swap(1, 0, Ordering::Relaxed), 1);
    }
}

impl <T> Deref for RwLockReadGuard<T> {
    type Target = T;
    #[inline]
    fn deref(&self) -> &Self::Target {
        unsafe {
            &*self.lock.data.get()
        }
    }
}

impl <T> Deref for RwLockWriteGuard<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        #[inline]
        unsafe {
            &*self.lock.data.get()
        }
    }
}

impl <T> DerefMut for RwLockWriteGuard<T> {
    #[inline]
    fn deref_mut(&mut self) -> &mut T {
        self.mutate()
    }
}

impl <T> RwLockWriteGuard<T> {
    #[inline]
    pub fn mutate(&self) -> &mut T {
        unsafe { &mut *self.lock.data.get() }
    }
}

impl <T: ?Sized> Drop for RwLockReadGuard<T> {
    #[inline]
    fn drop(&mut self) {
        self.lock.raw.unlock_read()
    }
}

impl <T: ?Sized> Drop for RwLockWriteGuard<T> {
    #[inline]
    fn drop(&mut self) {
        self.lock.raw.unlock_write()
    }
}

#[cfg(test)]
mod tests {
    extern crate rand;
    use self::rand::Rng;
    use std::sync::mpsc::channel;
    use std::thread;
    use std::sync::Arc;
    use std::sync::atomic::{AtomicUsize, Ordering};
    use std::time::Duration;
    use super::*;

    #[derive(Eq, PartialEq, Debug)]
    struct NonCopy(i32);

    #[test]
    fn smoke() {
        let l = RwLock::new(());
        drop(l.read());
        drop(l.write());
        drop((l.read(), l.read()));
        drop(l.write());
    }

    #[test]
    fn frob() {
        const N: u32 = 10;
        const M: u32 = 1000;

        let r = Arc::new(RwLock::new(()));

        let (tx, rx) = channel::<()>();
        for _ in 0..N {
            let tx = tx.clone();
            let r = r.clone();
            thread::spawn(move || {
                let mut rng = rand::thread_rng();
                for _ in 0..M {
                    if rng.gen_weighted_bool(N) {
                        drop(r.write());
                    } else {
                        drop(r.read());
                    }
                }
                drop(tx);
            });
        }
        drop(tx);
        let _ = rx.recv();
    }

    #[test]
    fn test_rw_arc_no_poison_wr() {
        let arc = Arc::new(RwLock::new(1));
        let arc2 = arc.clone();
        thread::spawn(move || {
            thread::sleep(Duration::from_millis(10));
            let _lock = arc2.write();
            panic!();
        });
        let lock = arc.read();
        assert_eq!(*lock, 1);
    }

    #[test]
    fn test_rw_arc_no_poison_ww() {
        let arc = Arc::new(RwLock::new(1));
        let arc2 = arc.clone();
        thread::spawn(move || {
            thread::sleep(Duration::from_millis(10));
            let _lock = arc2.write();
            panic!();
        });
        let lock = arc.write();
        assert_eq!(*lock, 1);
    }

    #[test]
    fn test_rw_arc() {
        let arc = Arc::new(RwLock::new(0));
        let arc2 = arc.clone();
        let (tx, rx) = channel();

        thread::spawn(move || {
            let mut lock = arc2.write();
            for _ in 0..10 {
                let tmp = *lock;
                *lock = -1;
                thread::yield_now();
                *lock = tmp + 1;
            }
            tx.send(()).unwrap();
        });

        // Readers try to catch the writer in the act
        let mut children = Vec::new();
        for _ in 0..5 {
            let arc3 = arc.clone();
            children.push(thread::spawn(move || {
                let lock = arc3.read();
                assert!(*lock >= 0);
            }));
        }

        // Wait for children to pass their asserts
        for r in children {
            assert!(r.join().is_ok());
        }

        // Wait for writer to finish
        rx.recv().unwrap();
        let lock = arc.read();
        assert_eq!(*lock, 10);
    }
}<commit_msg>fix misplaced inline tag<commit_after>use futures::{Future, Async, Poll};
use super::cpu_relax;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::cell::UnsafeCell;
use std::ops::{Deref, DerefMut};

#[derive(Clone)]
pub struct RwLock<T: ?Sized> {
    inner: Arc<RwLockInner<T>>
}

struct RwLockInner<T: ?Sized> {
    raw: RwLockRaw,
    data: UnsafeCell<T>
}

struct RwLockRaw {
    state: AtomicUsize
}

#[derive(Clone)]
pub struct AsyncRwLockReadGuard<T: ?Sized> {
    lock: Arc<RwLockInner<T>>
}

#[derive(Clone)]
pub struct AsyncRwLockWriteGuard<T: ?Sized> {
    lock: Arc<RwLockInner<T>>
}

#[derive(Clone)]
pub struct RwLockReadGuard<T: ?Sized> {
    lock: Arc<RwLockInner<T>>
}

#[derive(Clone)]
pub struct RwLockWriteGuard<T: ?Sized> {
    lock: Arc<RwLockInner<T>>
}

unsafe impl<T: Send> Send for RwLock<T> {}
unsafe impl<T: Send> Sync for RwLock<T> {}

unsafe impl<T: Send> Send for RwLockInner<T> {}
unsafe impl<T: Send> Sync for RwLockInner<T> {}

impl <T: ?Sized> Future for AsyncRwLockReadGuard<T> {
    type Item = RwLockReadGuard<T>;
    type Error = ();

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        if self.lock.raw.try_read() {
            Ok(Async::Ready(RwLockReadGuard {
                lock: self.lock.clone()
            }))
        } else {
            Ok(Async::NotReady)
        }
    }
}

impl <T> Future for AsyncRwLockWriteGuard<T> {
    type Item = RwLockWriteGuard<T>;
    type Error = ();

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        if self.lock.raw.try_write() {
            Ok(Async::Ready(RwLockWriteGuard {
                lock: self.lock.clone()
            }))
        } else {
            Ok(Async::NotReady)
        }
    }
}

impl <T> RwLock <T> {
    pub fn new(val: T) -> RwLock<T> {
        RwLock {
            inner: RwLockInner::new(val)
        }
    }
    pub fn read_async(&self) -> AsyncRwLockReadGuard<T> {
        AsyncRwLockReadGuard {
            lock: self.inner.clone()
        }
    }
    pub fn write_async(&self) -> AsyncRwLockWriteGuard<T> {
        AsyncRwLockWriteGuard {
            lock: self.inner.clone()
        }
    }
    pub fn read(&self) -> RwLockReadGuard<T> {
        while !self.inner.raw.try_read() {
            cpu_relax()
        }
        RwLockReadGuard {
            lock: self.inner.clone()
        }
    }
    pub fn write(&self) -> RwLockWriteGuard<T> {
        while !self.inner.raw.try_write() {
            cpu_relax()
        }
        RwLockWriteGuard {
            lock: self.inner.clone()
        }
    }
}

impl <T> RwLockInner<T> {
    pub fn new(val: T) -> Arc<RwLockInner<T>> {
        Arc::new(RwLockInner {
            raw: RwLockRaw::new(),
            data: UnsafeCell::new(val)
        })
    }
}

impl RwLockRaw {
    fn new() -> RwLockRaw {
        RwLockRaw {
          state: AtomicUsize::new(0)
        }
    }
    fn try_read(&self) -> bool  {
        let lc = self.state.load(Ordering::Relaxed);
        if lc == 1 {
            // write locked
            return false;
        } else {
            let next_count = if lc == 0 { 2 } else { lc + 1 };
            return self.state.compare_and_swap(lc, next_count, Ordering::Relaxed) == lc;
        }
    }
    fn try_write(&self) -> bool {
        self.state.compare_and_swap(0, 1, Ordering::Relaxed) == 0
    }
    fn unlock_read(&self) {
        loop {
            let lc = self.state.load(Ordering::Relaxed);
            let next_count = if lc == 2 { 0 } else { lc - 1 };
            assert!(lc > 1);
            if self.state.compare_and_swap(lc, next_count, Ordering::Relaxed) == lc {
                return;
            } else {
                cpu_relax();
            }
        }
    }
    fn unlock_write(&self) {
        assert_eq!(self.state.compare_and_swap(1, 0, Ordering::Relaxed), 1);
    }
}

impl <T> Deref for RwLockReadGuard<T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &Self::Target {
        unsafe {
            &*self.lock.data.get()
        }
    }
}

impl <T> Deref for RwLockWriteGuard<T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &Self::Target {
        unsafe {
            &*self.lock.data.get()
        }
    }
}

impl <T> DerefMut for RwLockWriteGuard<T> {
    #[inline]
    fn deref_mut(&mut self) -> &mut T {
        self.mutate()
    }
}

impl <T> RwLockWriteGuard<T> {
    #[inline]
    pub fn mutate(&self) -> &mut T {
        unsafe { &mut *self.lock.data.get() }
    }
}

impl <T: ?Sized> Drop for RwLockReadGuard<T> {
    #[inline]
    fn drop(&mut self) {
        self.lock.raw.unlock_read()
    }
}

impl <T: ?Sized> Drop for RwLockWriteGuard<T> {
    #[inline]
    fn drop(&mut self) {
        self.lock.raw.unlock_write()
    }
}

#[cfg(test)]
mod tests {
    extern crate rand;
    use self::rand::Rng;
    use std::sync::mpsc::channel;
    use std::thread;
    use std::sync::Arc;
    use std::sync::atomic::{AtomicUsize, Ordering};
    use std::time::Duration;
    use super::*;

    #[derive(Eq, PartialEq, Debug)]
    struct NonCopy(i32);

    #[test]
    fn smoke() {
        let l = RwLock::new(());
        drop(l.read());
        drop(l.write());
        drop((l.read(), l.read()));
        drop(l.write());
    }

    #[test]
    fn frob() {
        const N: u32 = 10;
        const M: u32 = 1000;

        let r = Arc::new(RwLock::new(()));

        let (tx, rx) = channel::<()>();
        for _ in 0..N {
            let tx = tx.clone();
            let r = r.clone();
            thread::spawn(move || {
                let mut rng = rand::thread_rng();
                for _ in 0..M {
                    if rng.gen_weighted_bool(N) {
                        drop(r.write());
                    } else {
                        drop(r.read());
                    }
                }
                drop(tx);
            });
        }
        drop(tx);
        let _ = rx.recv();
    }

    #[test]
    fn test_rw_arc_no_poison_wr() {
        let arc = Arc::new(RwLock::new(1));
        let arc2 = arc.clone();
        thread::spawn(move || {
            thread::sleep(Duration::from_millis(10));
            let _lock = arc2.write();
            panic!();
        });
        let lock = arc.read();
        assert_eq!(*lock, 1);
    }

    #[test]
    fn test_rw_arc_no_poison_ww() {
        let arc = Arc::new(RwLock::new(1));
        let arc2 = arc.clone();
        thread::spawn(move || {
            thread::sleep(Duration::from_millis(10));
            let _lock = arc2.write();
            panic!();
        });
        let lock = arc.write();
        assert_eq!(*lock, 1);
    }

    #[test]
    fn test_rw_arc() {
        let arc = Arc::new(RwLock::new(0));
        let arc2 = arc.clone();
        let (tx, rx) = channel();

        thread::spawn(move || {
            let mut lock = arc2.write();
            for _ in 0..10 {
                let tmp = *lock;
                *lock = -1;
                thread::yield_now();
                *lock = tmp + 1;
            }
            tx.send(()).unwrap();
        });

        // Readers try to catch the writer in the act
        let mut children = Vec::new();
        for _ in 0..5 {
            let arc3 = arc.clone();
            children.push(thread::spawn(move || {
                let lock = arc3.read();
                assert!(*lock >= 0);
            }));
        }

        // Wait for children to pass their asserts
        for r in children {
            assert!(r.join().is_ok());
        }

        // Wait for writer to finish
        rx.recv().unwrap();
        let lock = arc.read();
        assert_eq!(*lock, 10);
    }
}<|endoftext|>


<commit_before>
use syntax::codemap::{Span, respan, dummy_spanned, DUMMY_SP};

use syntax::ptr::P;

use syntax::ast::{TokenTree, Name, Delimited, SyntaxContext, Ident,
                  StrStyle, LitKind, Item, Visibility, Mod,
                  ItemKind, Generics, EnumDef, VariantData, Variant_,
                  Path, PathSegment, PathParameters, DUMMY_NODE_ID};

use syntax::ext::base::{ExtCtxt, MacResult, MacEager};
use syntax::ext::build::AstBuilder;

use syntax::parse::parser::{Parser, PathParsingMode};
use syntax::parse::token::{Token, DelimToken, Lit,
                           intern, intern_and_get_ident};
use syntax::parse::token::keywords::Keyword;

use syntax::util::small_vector::SmallVector;

use nametable::name_hash;

struct MyLiteralArray<T>(Vec<T>);
struct MyLiteralString(String);
struct MyLiteralTuple2<T1,T2>(T1,T2);

use quasi::ToTokens;
use std::rc::Rc;
impl<T: ToTokens> ToTokens for MyLiteralArray<T> {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        let mut r = vec![];
        let mut r_inner = vec![];
        for item in self.0.iter() {
            r_inner.append(&mut item.to_tokens(_cx));
            r_inner.push(TokenTree::Token(DUMMY_SP, Token::Comma));
        }
        r.push(TokenTree::Delimited(DUMMY_SP, Rc::new(Delimited {
            delim: DelimToken::Bracket,
            open_span: DUMMY_SP,
            tts: r_inner,
            close_span: DUMMY_SP,
        })));
        r
    }
}

impl ToTokens for MyLiteralString {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
		let lit = LitKind::Str(
			intern_and_get_ident(&self.0), StrStyle::Cooked);
        dummy_spanned(lit).to_tokens(_cx)
	}
}

impl<T1: ToTokens, T2: ToTokens> ToTokens for MyLiteralTuple2<T1, T2> {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        let mut r = vec![];
        let mut r_inner = vec![];
        r_inner.append(&mut self.0.to_tokens(_cx));
        r_inner.push(TokenTree::Token(DUMMY_SP, Token::Comma));
        r_inner.append(&mut self.1.to_tokens(_cx));
        r.push(TokenTree::Delimited(DUMMY_SP, Rc::new(Delimited {
            delim: DelimToken::Paren,
            open_span: DUMMY_SP,
            tts: r_inner,
            close_span: DUMMY_SP,
        })));
        r
    }
}

fn to_pub_item(mut item: Item) -> Item {
    item.vis = Visibility::Public;
    item
}

fn to_pub_item_ptr(item: P<Item>) -> P<Item> {
    item.map(to_pub_item)
}

fn add_suffix_to_path(prefix: &Path, suffix: Ident) -> Path {
    let mut result = prefix.clone();
    result.segments.push(
        PathSegment {
            identifier: suffix,
            parameters: PathParameters::none(),
        }
    );
    result
}

fn add_prefix_to_path(prefix: Ident, suffix: &Path) -> Path {
    let mut result = suffix.clone();
    result.segments.insert(0,
        PathSegment {
            identifier: prefix,
            parameters: PathParameters::none(),
        }
    );
    result
}

fn generate_nametable_item<'cx>(
    cx: &'cx mut ExtCtxt,
    sp: Span,
    sc: SyntaxContext,
    artifact_name: Name,
    base_artifact_path: Option<Path>,
    artifact_items: Vec<(Name, Name)>) -> P<Item> {

    let mut mod_attributes = Vec::new();
    let mut mod_items = Vec::new();

    let base_artifact_path = base_artifact_path.map(
        |path: Path| if path.global {
            path
        } else {
            add_prefix_to_path(Ident::new(intern("super"), sc), &path)
        }
    );

    {
        // use
        mod_items.push(quote_item!(
            cx,
            use ::nametable::{
                NameTable, StaticNameTable, DynamicNameTable,
                StaticHashedNameTable, NameTableIdx};).unwrap());
    }

    {
        // const INITIAL
        if let Some(ref path) = base_artifact_path {
            mod_items.push(cx.item_use_simple(DUMMY_SP, Visibility::Inherited, path.clone()));
            let base_artifact_initial = add_suffix_to_path(path, Ident::new(intern("INITIAL"), sc));
            let base_artifact_count = add_suffix_to_path(path, Ident::new(intern("COUNT"), sc));
            mod_items.push(quote_item!(cx, pub const INITIAL : usize = $base_artifact_initial + $base_artifact_count; ).unwrap());
        } else {
            mod_items.push(quote_item!(cx, pub const INITIAL : usize = 0usize; ).unwrap());
    }

        let count = artifact_items.len();
        mod_items.push(quote_item!(cx, pub const COUNT : usize = $count; ).unwrap());
    }

    {
        // enum Names
        let ident_names = Ident::new(intern("Names"), sc);

        let mut enumdef = EnumDef { variants: Vec::new() };
        for (idx,&(key, _)) in artifact_items.iter().enumerate() {
            let ident_key = Ident::new(key, sc);
            enumdef.variants.push(respan(sp, Variant_ {
                name: ident_key,
                attrs: Vec::new(),
                data: VariantData::Unit(DUMMY_NODE_ID),
                disr_expr: Some(quote_expr!(cx, INITIAL + $idx)),
            }));
        }

        let repr_attribute = cx.attribute(
            sp, cx.meta_list(sp, intern_and_get_ident("repr"),
                             vec!(cx.meta_word(sp, intern_and_get_ident("usize")))));

        let derive_attribute = cx.attribute(
            sp, cx.meta_list(sp, intern_and_get_ident("derive"),
                             vec!(cx.meta_word(sp, intern_and_get_ident("Copy")),
                                  cx.meta_word(sp, intern_and_get_ident("Clone")))));
        mod_items.push(to_pub_item_ptr(
            cx.item(sp, ident_names,
                    vec!(repr_attribute, derive_attribute),
                    ItemKind::Enum(enumdef, Generics::default()))));
    }

    {
        // impl
        mod_items.push(quote_item!(
            cx,
            impl NameTableIdx for Names {
                fn to_index(&self) -> usize() { *self as usize }
            }
        ).unwrap());
    }

    {
        //data
        let mut name_data : MyLiteralString = MyLiteralString(String::new());
        let mut index_data : MyLiteralArray<usize> = MyLiteralArray(vec!(0));
        let mut hash_data : MyLiteralArray<MyLiteralTuple2<u64,usize>> = MyLiteralArray(vec!());
        for (idx,&(_, value)) in artifact_items.iter().enumerate() {
            name_data.0.push_str(&*value.as_str());
            index_data.0.push(name_data.0.len());
            hash_data.0.push(MyLiteralTuple2(name_hash(&*value.as_str()),idx));
        }
        hash_data.0.sort_by(|&MyLiteralTuple2(a, _), &MyLiteralTuple2(b, _)| a.cmp(&b));

        fn detect_collision<T: PartialOrd + Copy>(arr: &[MyLiteralTuple2<T, usize>]) -> Option<(usize, usize)> {
            if arr.len() == 0 {
                return None;
            }
            let mut old_val = arr.get(0).unwrap().0;
            for i in 1..arr.len() {
                if arr.get(i).unwrap().0 == old_val {
                    return Some((arr.get(i-1).unwrap().1, arr.get(i).unwrap().1));
                }
                old_val = arr.get(i).unwrap().0;
            }
            return None
        }

        match detect_collision(&hash_data.0) {
            Some((a, b)) => {
                println!(
                    "nametable_macros: Hash collision happened between item index {:} and {:} for table `{:}'",
                    a, b, &*artifact_name.as_str());
                hash_data.0 = vec!();
            },
            None => ()
        }

        mod_items.push(quote_item!(
            cx,
            const NAME_DATA : &'static str = $name_data;
        ).unwrap());
        mod_items.push(quote_item!(
            cx,
            const INDEX_DATA : &'static [usize] = &$index_data;
        ).unwrap());

        mod_items.push(quote_item!(
            cx,
            const HASH_DATA : &'static [(u64,usize)] = &$hash_data;
        ).unwrap());

    }

    {
        //functions
        match base_artifact_path {
            Some(ref path) => {
                let base_artifact_new = add_suffix_to_path(&path, Ident::new(intern("new"), sc));
                mod_items.push(
                    quote_item!(
                        cx,
                        pub fn new<'x>() -> StaticHashedNameTable<'x> {
                            StaticHashedNameTable::new_upon(NAME_DATA, INDEX_DATA, HASH_DATA, $base_artifact_new())
                        }).unwrap());

                mod_items.push(quote_item!(
                    cx,
                    pub fn new_dynamic<'x>() -> DynamicNameTable<'x> {
                        DynamicNameTable::new_upon(
                            StaticHashedNameTable::new_upon(NAME_DATA, INDEX_DATA, HASH_DATA, $base_artifact_new()))
                    }
                ).unwrap());

                mod_items.push(quote_item!(
                    cx,
                    pub fn new_plain_<'x>() -> StaticNameTable<'x> {
                        StaticNameTable::new_upon(NAME_DATA, INDEX_DATA, $base_artifact_new())
                    }
                ).unwrap());

                mod_items.push(quote_item!(
                    cx,
                    pub fn new_dynamic_plain<'x>() -> DynamicNameTable<'x> {
                        DynamicNameTable::new_upon(
                            StaticNameTable::new_upon(NAME_DATA, INDEX_DATA, $base_artifact_new()))
                    }
                ).unwrap());

            }
            None => {
                mod_items.push(quote_item!(
                        cx,
                        pub fn new<'x>() -> StaticHashedNameTable<'x> {
                            StaticHashedNameTable::new(NAME_DATA, INDEX_DATA, HASH_DATA)
                        }
                ).unwrap());

                mod_items.push(quote_item!(
                    cx,
                    pub fn new_dynamic<'x>() -> DynamicNameTable<'x> {
                        DynamicNameTable::new_upon(
                            StaticHashedNameTable::new(NAME_DATA, INDEX_DATA, HASH_DATA))
                    }
                ).unwrap());

                mod_items.push(quote_item!(
                    cx,
                    pub fn new_plain_<'x>() -> StaticNameTable<'x> {
                        StaticNameTable::new(NAME_DATA, INDEX_DATA)
                    }
                ).unwrap());

                mod_items.push(quote_item!(
                    cx,
                    pub fn new_dynamic_plain<'x>() -> DynamicNameTable<'x> {
                        DynamicNameTable::new_upon(
                            StaticNameTable::new(NAME_DATA, INDEX_DATA))
                    }
                ).unwrap());
            }
        }
    }

      {
          let allow_unused_attribute = cx.attribute(
            sp, cx.meta_list(sp, intern_and_get_ident("allow"),
                             vec!(cx.meta_word(sp, intern_and_get_ident("dead_code")))));

        let allow_unused_imports_attribute = cx.attribute(
            sp, cx.meta_list(sp, intern_and_get_ident("allow"),
                             vec!(cx.meta_word(sp, intern_and_get_ident("unused_imports")))));

            mod_attributes.push(allow_unused_attribute);
            mod_attributes.push(allow_unused_imports_attribute);
      }

    P(Item {
        ident: Ident::new(artifact_name, sc),
        attrs: mod_attributes,
        id: DUMMY_NODE_ID,
        node: ItemKind::Mod(Mod {
            inner: sp,
            items: mod_items,
        }),
        vis: Visibility::Public,
        span: sp,
    })
}

fn process_nametables<'cx>(cx: &'cx mut ExtCtxt, sp: Span, mut parser: Parser) -> SmallVector<P<Item>> {
    let mut result : Vec<P<Item>> = Vec::new();

    while &parser.token != &Token::Eof {
        let syntax_ctx = if let Token::Ident(nt_keyword, _) = parser.token {
            if nt_keyword.name.as_str() != "nametable" {
                cx.span_fatal(parser.span, "expected keyword `nametable' here.");
            }
            let _ = parser.bump();
            nt_keyword.ctxt
        }
        else {
            cx.span_fatal(parser.span, "expected keyword `nametable' here.");
        };

        let artifact_name = if let Token::Ident(artifact_name, _) = parser.token {
            let _ = parser.bump();
            artifact_name.name
        }
        else {
            cx.span_fatal(parser.span, "expected nametable name here.");
        };

        let base_artifact_path = if parser.eat(&Token::Colon) {
            let result = parser.parse_path(PathParsingMode::NoTypesAllowed);
            match result{
                Ok(path) => Some(path),
                _ => cx.span_fatal(parser.span, "expected base nametable name here."),
            }
            } else {
            None
        };

        if !parser.eat(&Token::OpenDelim(DelimToken::Brace)) {
            cx.span_fatal(parser.span, "expected open brace here.");
        }

        let mut artifact_items : Vec<(Name, Name)> = Vec::new();

        while let Token::Ident(item_name, _) = parser.token {
            let _ = parser.bump();
            let item_string = if parser.token.is_keyword(Keyword::For) {
                let _ = parser.bump();
                if let Token::Literal(Lit::Str_(item_string_name), _) = parser.token {
                    let _ = parser.bump();
                    item_string_name
                } else {
                    cx.span_fatal(parser.span, "expected string literal here.");
                }
            } else {
                item_name.name
            };

            artifact_items.push((item_name.name,item_string));

            if !parser.eat(&Token::Comma) {
                break;
            }
        }

        if !parser.eat(&Token::CloseDelim(DelimToken::Brace)) {
            cx.span_fatal(parser.span, "expected close brace here.");
        }

        result.push(generate_nametable_item(cx, sp, syntax_ctx, artifact_name, base_artifact_path, artifact_items));
    }

    if &parser.token != &Token::Eof {
        cx.span_fatal(parser.span, "expected end of `nametable!` macro invocation");
    }

    match result.len() {
        0 => SmallVector::zero(),
        1 => SmallVector::one(result.pop().unwrap()),
        _ => SmallVector::many(result),
    }
}

pub fn expand<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult + 'cx> {
    let parser = cx.new_parser_from_tts(tts);

    MacEager::items(process_nametables(cx, sp, parser))
}

<commit_msg>Add extra level of super only when path starts with self or super<commit_after>
use syntax::codemap::{Span, respan, dummy_spanned, DUMMY_SP};

use syntax::ptr::P;

use syntax::ast::{TokenTree, Name, Delimited, SyntaxContext, Ident,
                  StrStyle, LitKind, Item, Visibility, Mod,
                  ItemKind, Generics, EnumDef, VariantData, Variant_,
                  Path, PathSegment, PathParameters, DUMMY_NODE_ID};

use syntax::ext::base::{ExtCtxt, MacResult, MacEager};
use syntax::ext::build::AstBuilder;

use syntax::parse::parser::{Parser, PathParsingMode};
use syntax::parse::token::{Token, DelimToken, Lit,
                           intern, intern_and_get_ident};
use syntax::parse::token::keywords::Keyword;

use syntax::util::small_vector::SmallVector;

use nametable::name_hash;

struct MyLiteralArray<T>(Vec<T>);
struct MyLiteralString(String);
struct MyLiteralTuple2<T1,T2>(T1,T2);

use quasi::ToTokens;
use std::rc::Rc;
impl<T: ToTokens> ToTokens for MyLiteralArray<T> {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        let mut r = vec![];
        let mut r_inner = vec![];
        for item in self.0.iter() {
            r_inner.append(&mut item.to_tokens(_cx));
            r_inner.push(TokenTree::Token(DUMMY_SP, Token::Comma));
        }
        r.push(TokenTree::Delimited(DUMMY_SP, Rc::new(Delimited {
            delim: DelimToken::Bracket,
            open_span: DUMMY_SP,
            tts: r_inner,
            close_span: DUMMY_SP,
        })));
        r
    }
}

impl ToTokens for MyLiteralString {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
		let lit = LitKind::Str(
			intern_and_get_ident(&self.0), StrStyle::Cooked);
        dummy_spanned(lit).to_tokens(_cx)
	}
}

impl<T1: ToTokens, T2: ToTokens> ToTokens for MyLiteralTuple2<T1, T2> {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        let mut r = vec![];
        let mut r_inner = vec![];
        r_inner.append(&mut self.0.to_tokens(_cx));
        r_inner.push(TokenTree::Token(DUMMY_SP, Token::Comma));
        r_inner.append(&mut self.1.to_tokens(_cx));
        r.push(TokenTree::Delimited(DUMMY_SP, Rc::new(Delimited {
            delim: DelimToken::Paren,
            open_span: DUMMY_SP,
            tts: r_inner,
            close_span: DUMMY_SP,
        })));
        r
    }
}

fn to_pub_item(mut item: Item) -> Item {
    item.vis = Visibility::Public;
    item
}

fn to_pub_item_ptr(item: P<Item>) -> P<Item> {
    item.map(to_pub_item)
}

fn add_suffix_to_path(prefix: &Path, suffix: Ident) -> Path {
    let mut result = prefix.clone();
    result.segments.push(
        PathSegment {
            identifier: suffix,
            parameters: PathParameters::none(),
        }
    );
    result
}

fn add_prefix_to_path(prefix: Ident, suffix: &Path) -> Path {
    let mut result = suffix.clone();
    result.segments.insert(0,
        PathSegment {
            identifier: prefix,
            parameters: PathParameters::none(),
        }
    );
    result
}

fn generate_nametable_item<'cx>(
    cx: &'cx mut ExtCtxt,
    sp: Span,
    sc: SyntaxContext,
    artifact_name: Name,
    base_artifact_path: Option<Path>,
    artifact_items: Vec<(Name, Name)>) -> P<Item> {

    let mut mod_attributes = Vec::new();
    let mut mod_items = Vec::new();

    let base_artifact_path = base_artifact_path.map(
        |path: Path|
        if path.segments.len() > 0 {
            let initial_segment_name =
                path.segments[0].identifier.name.as_str();
            if initial_segment_name == "self" ||
                initial_segment_name == "super" {
                    add_prefix_to_path(Ident::new(intern("super"), sc), &path)
                } else {
                    path
                }
        } else {
            path
        }
    );

    {
        // use
        mod_items.push(quote_item!(
            cx,
            use ::nametable::{
                NameTable, StaticNameTable, DynamicNameTable,
                StaticHashedNameTable, NameTableIdx};).unwrap());
    }

    {
        // const INITIAL
        if let Some(ref path) = base_artifact_path {
            mod_items.push(cx.item_use_simple(DUMMY_SP, Visibility::Inherited, path.clone()));
            let base_artifact_initial = add_suffix_to_path(path, Ident::new(intern("INITIAL"), sc));
            let base_artifact_count = add_suffix_to_path(path, Ident::new(intern("COUNT"), sc));
            mod_items.push(quote_item!(cx, pub const INITIAL : usize = $base_artifact_initial + $base_artifact_count; ).unwrap());
        } else {
            mod_items.push(quote_item!(cx, pub const INITIAL : usize = 0usize; ).unwrap());
    }

        let count = artifact_items.len();
        mod_items.push(quote_item!(cx, pub const COUNT : usize = $count; ).unwrap());
    }

    {
        // enum Names
        let ident_names = Ident::new(intern("Names"), sc);

        let mut enumdef = EnumDef { variants: Vec::new() };
        for (idx,&(key, _)) in artifact_items.iter().enumerate() {
            let ident_key = Ident::new(key, sc);
            enumdef.variants.push(respan(sp, Variant_ {
                name: ident_key,
                attrs: Vec::new(),
                data: VariantData::Unit(DUMMY_NODE_ID),
                disr_expr: Some(quote_expr!(cx, INITIAL + $idx)),
            }));
        }

        let repr_attribute = cx.attribute(
            sp, cx.meta_list(sp, intern_and_get_ident("repr"),
                             vec!(cx.meta_word(sp, intern_and_get_ident("usize")))));

        let derive_attribute = cx.attribute(
            sp, cx.meta_list(sp, intern_and_get_ident("derive"),
                             vec!(cx.meta_word(sp, intern_and_get_ident("Copy")),
                                  cx.meta_word(sp, intern_and_get_ident("Clone")))));
        mod_items.push(to_pub_item_ptr(
            cx.item(sp, ident_names,
                    vec!(repr_attribute, derive_attribute),
                    ItemKind::Enum(enumdef, Generics::default()))));
    }

    {
        // impl
        mod_items.push(quote_item!(
            cx,
            impl NameTableIdx for Names {
                fn to_index(&self) -> usize() { *self as usize }
            }
        ).unwrap());
    }

    {
        //data
        let mut name_data : MyLiteralString = MyLiteralString(String::new());
        let mut index_data : MyLiteralArray<usize> = MyLiteralArray(vec!(0));
        let mut hash_data : MyLiteralArray<MyLiteralTuple2<u64,usize>> = MyLiteralArray(vec!());
        for (idx,&(_, value)) in artifact_items.iter().enumerate() {
            name_data.0.push_str(&*value.as_str());
            index_data.0.push(name_data.0.len());
            hash_data.0.push(MyLiteralTuple2(name_hash(&*value.as_str()),idx));
        }
        hash_data.0.sort_by(|&MyLiteralTuple2(a, _), &MyLiteralTuple2(b, _)| a.cmp(&b));

        fn detect_collision<T: PartialOrd + Copy>(arr: &[MyLiteralTuple2<T, usize>]) -> Option<(usize, usize)> {
            if arr.len() == 0 {
                return None;
            }
            let mut old_val = arr.get(0).unwrap().0;
            for i in 1..arr.len() {
                if arr.get(i).unwrap().0 == old_val {
                    return Some((arr.get(i-1).unwrap().1, arr.get(i).unwrap().1));
                }
                old_val = arr.get(i).unwrap().0;
            }
            return None
        }

        match detect_collision(&hash_data.0) {
            Some((a, b)) => {
                println!(
                    "nametable_macros: Hash collision happened between item index {:} and {:} for table `{:}'",
                    a, b, &*artifact_name.as_str());
                hash_data.0 = vec!();
            },
            None => ()
        }

        mod_items.push(quote_item!(
            cx,
            const NAME_DATA : &'static str = $name_data;
        ).unwrap());
        mod_items.push(quote_item!(
            cx,
            const INDEX_DATA : &'static [usize] = &$index_data;
        ).unwrap());

        mod_items.push(quote_item!(
            cx,
            const HASH_DATA : &'static [(u64,usize)] = &$hash_data;
        ).unwrap());

    }

    {
        //functions
        match base_artifact_path {
            Some(ref path) => {
                let base_artifact_new = add_suffix_to_path(&path, Ident::new(intern("new"), sc));
                mod_items.push(
                    quote_item!(
                        cx,
                        pub fn new<'x>() -> StaticHashedNameTable<'x> {
                            StaticHashedNameTable::new_upon(NAME_DATA, INDEX_DATA, HASH_DATA, $base_artifact_new())
                        }).unwrap());

                mod_items.push(quote_item!(
                    cx,
                    pub fn new_dynamic<'x>() -> DynamicNameTable<'x> {
                        DynamicNameTable::new_upon(
                            StaticHashedNameTable::new_upon(NAME_DATA, INDEX_DATA, HASH_DATA, $base_artifact_new()))
                    }
                ).unwrap());

                mod_items.push(quote_item!(
                    cx,
                    pub fn new_plain_<'x>() -> StaticNameTable<'x> {
                        StaticNameTable::new_upon(NAME_DATA, INDEX_DATA, $base_artifact_new())
                    }
                ).unwrap());

                mod_items.push(quote_item!(
                    cx,
                    pub fn new_dynamic_plain<'x>() -> DynamicNameTable<'x> {
                        DynamicNameTable::new_upon(
                            StaticNameTable::new_upon(NAME_DATA, INDEX_DATA, $base_artifact_new()))
                    }
                ).unwrap());

            }
            None => {
                mod_items.push(quote_item!(
                        cx,
                        pub fn new<'x>() -> StaticHashedNameTable<'x> {
                            StaticHashedNameTable::new(NAME_DATA, INDEX_DATA, HASH_DATA)
                        }
                ).unwrap());

                mod_items.push(quote_item!(
                    cx,
                    pub fn new_dynamic<'x>() -> DynamicNameTable<'x> {
                        DynamicNameTable::new_upon(
                            StaticHashedNameTable::new(NAME_DATA, INDEX_DATA, HASH_DATA))
                    }
                ).unwrap());

                mod_items.push(quote_item!(
                    cx,
                    pub fn new_plain_<'x>() -> StaticNameTable<'x> {
                        StaticNameTable::new(NAME_DATA, INDEX_DATA)
                    }
                ).unwrap());

                mod_items.push(quote_item!(
                    cx,
                    pub fn new_dynamic_plain<'x>() -> DynamicNameTable<'x> {
                        DynamicNameTable::new_upon(
                            StaticNameTable::new(NAME_DATA, INDEX_DATA))
                    }
                ).unwrap());
            }
        }
    }

      {
          let allow_unused_attribute = cx.attribute(
            sp, cx.meta_list(sp, intern_and_get_ident("allow"),
                             vec!(cx.meta_word(sp, intern_and_get_ident("dead_code")))));

        let allow_unused_imports_attribute = cx.attribute(
            sp, cx.meta_list(sp, intern_and_get_ident("allow"),
                             vec!(cx.meta_word(sp, intern_and_get_ident("unused_imports")))));

            mod_attributes.push(allow_unused_attribute);
            mod_attributes.push(allow_unused_imports_attribute);
      }

    P(Item {
        ident: Ident::new(artifact_name, sc),
        attrs: mod_attributes,
        id: DUMMY_NODE_ID,
        node: ItemKind::Mod(Mod {
            inner: sp,
            items: mod_items,
        }),
        vis: Visibility::Public,
        span: sp,
    })
}

fn process_nametables<'cx>(cx: &'cx mut ExtCtxt, sp: Span, mut parser: Parser) -> SmallVector<P<Item>> {
    let mut result : Vec<P<Item>> = Vec::new();

    while &parser.token != &Token::Eof {
        let syntax_ctx = if let Token::Ident(nt_keyword, _) = parser.token {
            if nt_keyword.name.as_str() != "nametable" {
                cx.span_fatal(parser.span, "expected keyword `nametable' here.");
            }
            let _ = parser.bump();
            nt_keyword.ctxt
        }
        else {
            cx.span_fatal(parser.span, "expected keyword `nametable' here.");
        };

        let artifact_name = if let Token::Ident(artifact_name, _) = parser.token {
            let _ = parser.bump();
            artifact_name.name
        }
        else {
            cx.span_fatal(parser.span, "expected nametable name here.");
        };

        let base_artifact_path = if parser.eat(&Token::Colon) {
            let result = parser.parse_path(PathParsingMode::NoTypesAllowed);
            match result{
                Ok(path) => Some(path),
                _ => cx.span_fatal(parser.span, "expected base nametable name here."),
            }
            } else {
            None
        };

        if !parser.eat(&Token::OpenDelim(DelimToken::Brace)) {
            cx.span_fatal(parser.span, "expected open brace here.");
        }

        let mut artifact_items : Vec<(Name, Name)> = Vec::new();

        while let Token::Ident(item_name, _) = parser.token {
            let _ = parser.bump();
            let item_string = if parser.token.is_keyword(Keyword::For) {
                let _ = parser.bump();
                if let Token::Literal(Lit::Str_(item_string_name), _) = parser.token {
                    let _ = parser.bump();
                    item_string_name
                } else {
                    cx.span_fatal(parser.span, "expected string literal here.");
                }
            } else {
                item_name.name
            };

            artifact_items.push((item_name.name,item_string));

            if !parser.eat(&Token::Comma) {
                break;
            }
        }

        if !parser.eat(&Token::CloseDelim(DelimToken::Brace)) {
            cx.span_fatal(parser.span, "expected close brace here.");
        }

        result.push(generate_nametable_item(cx, sp, syntax_ctx, artifact_name, base_artifact_path, artifact_items));
    }

    if &parser.token != &Token::Eof {
        cx.span_fatal(parser.span, "expected end of `nametable!` macro invocation");
    }

    match result.len() {
        0 => SmallVector::zero(),
        1 => SmallVector::one(result.pop().unwrap()),
        _ => SmallVector::many(result),
    }
}

pub fn expand<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult + 'cx> {
    let parser = cx.new_parser_from_tts(tts);

    MacEager::items(process_nametables(cx, sp, parser))
}

<|endoftext|>


<commit_before>use std::path::PathBuf;

use xshell::pushd;

use crate::{cmd, Metadata, Result};

const MSRV: &str = "1.45";

/// Task to run CI tests.
pub struct CiTask {
    /// Which version of Rust to test against.
    version: Option<String>,

    /// The root of the workspace.
    project_root: PathBuf,
}

impl CiTask {
    pub(crate) fn new(version: Option<String>) -> Result<Self> {
        let project_root = Metadata::load()?.workspace_root;
        Ok(Self { version, project_root })
    }

    pub(crate) fn run(self) -> Result<()> {
        let _p = pushd(&self.project_root)?;

        match self.version.as_deref() {
            Some("msrv") => self.build_msrv()?,
            Some("stable") => self.build_stable()?,
            Some("nightly") => self.build_nightly()?,
            Some(_) => return Err("Wrong Rust version specified.".into()),
            None => {
                self.build_msrv().and(self.build_stable()).and(self.build_nightly())?;
            }
        }

        Ok(())
    }

    fn build_msrv(&self) -> xshell::Result<()> {
        let _p = pushd("crates/ruma")?;
        cmd!("rustup run {MSRV} cargo build --features full").run()
    }

    fn build_stable(&self) -> xshell::Result<()> {
        // 1. Make sure everything compiles
        cmd!("rustup run stable cargo check --workspace --all-features").run()?;
        cmd!("rustup run stable cargo check -p ruma-client --no-default-features").run()?;
        cmd!("rustup run stable cargo check -p ruma-identifiers --no-default-features").run()?;

        // 2. Run tests
        cmd!("rustup run stable cargo test --workspace").run()
    }

    fn build_nightly(&self) -> xshell::Result<()> {
        let fmt_res = cmd!("rustup run nightly cargo fmt -- --check").run();
        let clippy_res = cmd!("rustup run nightly cargo ruma-clippy -D warnings").run();
        fmt_res.or(clippy_res)
    }
}
<commit_msg>ci: Fix nightly return status<commit_after>use std::path::PathBuf;

use xshell::pushd;

use crate::{cmd, Metadata, Result};

const MSRV: &str = "1.45";

/// Task to run CI tests.
pub struct CiTask {
    /// Which version of Rust to test against.
    version: Option<String>,

    /// The root of the workspace.
    project_root: PathBuf,
}

impl CiTask {
    pub(crate) fn new(version: Option<String>) -> Result<Self> {
        let project_root = Metadata::load()?.workspace_root;
        Ok(Self { version, project_root })
    }

    pub(crate) fn run(self) -> Result<()> {
        let _p = pushd(&self.project_root)?;

        match self.version.as_deref() {
            Some("msrv") => self.build_msrv()?,
            Some("stable") => self.build_stable()?,
            Some("nightly") => self.build_nightly()?,
            Some(_) => return Err("Wrong Rust version specified.".into()),
            None => {
                self.build_msrv().and(self.build_stable()).and(self.build_nightly())?;
            }
        }

        Ok(())
    }

    fn build_msrv(&self) -> xshell::Result<()> {
        let _p = pushd("crates/ruma")?;
        cmd!("rustup run {MSRV} cargo build --features full").run()
    }

    fn build_stable(&self) -> xshell::Result<()> {
        // 1. Make sure everything compiles
        cmd!("rustup run stable cargo check --workspace --all-features").run()?;
        cmd!("rustup run stable cargo check -p ruma-client --no-default-features").run()?;
        cmd!("rustup run stable cargo check -p ruma-identifiers --no-default-features").run()?;

        // 2. Run tests
        cmd!("rustup run stable cargo test --workspace").run()
    }

    fn build_nightly(&self) -> xshell::Result<()> {
        let fmt_res = cmd!("rustup run nightly cargo fmt -- --check").run();
        let clippy_res = cmd!("rustup run nightly cargo ruma-clippy -D warnings").run();
        fmt_res.and(clippy_res)
    }
}
<|endoftext|>


<commit_before>use crate::mir::operand::OperandRef;
use crate::traits::*;
use rustc::mir;
use rustc::mir::interpret::{ConstValue, ErrorHandled};
use rustc::ty::layout::{self, HasTyCtxt};
use rustc::ty::{self, Ty};
use rustc_index::vec::Idx;
use rustc_span::source_map::Span;

use super::FunctionCx;

impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
    pub fn eval_mir_constant_to_operand(
        &mut self,
        bx: &mut Bx,
        constant: &mir::Constant<'tcx>,
    ) -> Result<OperandRef<'tcx, Bx::Value>, ErrorHandled> {
        match constant.literal.val {
            // Special case unevaluated statics, because statics have an identity and thus should
            // use `get_static` to get at their id.
            // FIXME(oli-obk): can we unify this somehow, maybe by making const eval of statics
            // always produce `&STATIC`. This may also simplify how const eval works with statics.
            ty::ConstKind::Unevaluated(def_id, substs, None) if self.cx.tcx().is_static(def_id) => {
                assert!(substs.is_empty(), "we don't support generic statics yet");
                let static_ = bx.get_static(def_id);
                // we treat operands referring to statics as if they were `&STATIC` instead
                let ptr_ty = self.cx.tcx().mk_mut_ptr(self.monomorphize(&constant.literal.ty));
                let layout = bx.layout_of(ptr_ty);
                Ok(OperandRef::from_immediate_or_packed_pair(bx, static_, layout))
            }
            _ => {
                let val = self.eval_mir_constant(constant)?;
                let ty = self.monomorphize(&constant.literal.ty);
                Ok(OperandRef::from_const(bx, val, ty))
            }
        }
    }

    pub fn eval_mir_constant(
        &mut self,
        constant: &mir::Constant<'tcx>,
    ) -> Result<ConstValue<'tcx>, ErrorHandled> {
        let const_ = match constant.literal.val {
            ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
                let substs = self.monomorphize(&substs);
                ty::ConstKind::Unevaluated(def_id, substs, promoted)
            }
            ty::ConstKind::Value(value) => ty::ConstKind::Value(value),
            ty::ConstKind::Param(_) => self.monomorphize(&constant.literal).val,
            _ => span_bug!(constant.span, "encountered bad Const in codegen: {:?}", constant),
        };

        match const_ {
            ty::ConstKind::Unevaluated(def_id, substs, promoted) => self
                .cx
                .tcx()
                .const_eval_resolve(ty::ParamEnv::reveal_all(), def_id, substs, promoted, None)
                .map_err(|err| {
                    if promoted.is_none() {
                        self.cx
                            .tcx()
                            .sess
                            .span_err(constant.span, "erroneous constant encountered");
                    }
                    err
                }),
            ty::ConstKind::Value(value) => Ok(value),
            _ => span_bug!(
                constant.span,
                "encountered bad ConstKind after monomorphizing: {:?}",
                const_
            ),
        }
    }

    /// process constant containing SIMD shuffle indices
    pub fn simd_shuffle_indices(
        &mut self,
        bx: &Bx,
        span: Span,
        ty: Ty<'tcx>,
        constant: Result<ConstValue<'tcx>, ErrorHandled>,
    ) -> (Bx::Value, Ty<'tcx>) {
        constant
            .map(|val| {
                let field_ty = ty.builtin_index().unwrap();
                let fields = match ty.kind {
                    ty::Array(_, n) => n.eval_usize(bx.tcx(), ty::ParamEnv::reveal_all()),
                    _ => bug!("invalid simd shuffle type: {}", ty),
                };
                let c = ty::Const::from_value(bx.tcx(), val, ty);
                let values: Vec<_> = (0..fields)
                    .map(|field| {
                        let field = bx.tcx().const_field(
                            ty::ParamEnv::reveal_all().and((&c, mir::Field::new(field as usize))),
                        );
                        if let Some(prim) = field.try_to_scalar() {
                            let layout = bx.layout_of(field_ty);
                            let scalar = match layout.abi {
                                layout::Abi::Scalar(ref x) => x,
                                _ => bug!("from_const: invalid ByVal layout: {:#?}", layout),
                            };
                            bx.scalar_to_backend(prim, scalar, bx.immediate_backend_type(layout))
                        } else {
                            bug!("simd shuffle field {:?}", field)
                        }
                    })
                    .collect();
                let llval = bx.const_struct(&values, false);
                (llval, c.ty)
            })
            .unwrap_or_else(|_| {
                bx.tcx().sess.span_err(span, "could not evaluate shuffle_indices at compile time");
                // We've errored, so we don't have to produce working code.
                let ty = self.monomorphize(&ty);
                let llty = bx.backend_type(bx.layout_of(ty));
                (bx.const_undef(llty), ty)
            })
    }
}
<commit_msg>simplify eval_mir_constant<commit_after>use crate::mir::operand::OperandRef;
use crate::traits::*;
use rustc::mir;
use rustc::mir::interpret::{ConstValue, ErrorHandled};
use rustc::ty::layout::{self, HasTyCtxt};
use rustc::ty::{self, Ty};
use rustc_index::vec::Idx;
use rustc_span::source_map::Span;

use super::FunctionCx;

impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
    pub fn eval_mir_constant_to_operand(
        &mut self,
        bx: &mut Bx,
        constant: &mir::Constant<'tcx>,
    ) -> Result<OperandRef<'tcx, Bx::Value>, ErrorHandled> {
        match constant.literal.val {
            // Special case unevaluated statics, because statics have an identity and thus should
            // use `get_static` to get at their id.
            // FIXME(oli-obk): can we unify this somehow, maybe by making const eval of statics
            // always produce `&STATIC`. This may also simplify how const eval works with statics.
            ty::ConstKind::Unevaluated(def_id, substs, None) if self.cx.tcx().is_static(def_id) => {
                assert!(substs.is_empty(), "we don't support generic statics yet");
                let static_ = bx.get_static(def_id);
                // we treat operands referring to statics as if they were `&STATIC` instead
                let ptr_ty = self.cx.tcx().mk_mut_ptr(self.monomorphize(&constant.literal.ty));
                let layout = bx.layout_of(ptr_ty);
                Ok(OperandRef::from_immediate_or_packed_pair(bx, static_, layout))
            }
            _ => {
                let val = self.eval_mir_constant(constant)?;
                let ty = self.monomorphize(&constant.literal.ty);
                Ok(OperandRef::from_const(bx, val, ty))
            }
        }
    }

    pub fn eval_mir_constant(
        &mut self,
        constant: &mir::Constant<'tcx>,
    ) -> Result<ConstValue<'tcx>, ErrorHandled> {
        match self.monomorphize(&constant.literal).val {
            ty::ConstKind::Unevaluated(def_id, substs, promoted) => self
                .cx
                .tcx()
                .const_eval_resolve(ty::ParamEnv::reveal_all(), def_id, substs, promoted, None)
                .map_err(|err| {
                    if promoted.is_none() {
                        self.cx
                            .tcx()
                            .sess
                            .span_err(constant.span, "erroneous constant encountered");
                    }
                    err
                }),
            ty::ConstKind::Value(value) => Ok(value),
            err => span_bug!(
                constant.span,
                "encountered bad ConstKind after monomorphizing: {:?}",
                err
            ),
        }
    }

    /// process constant containing SIMD shuffle indices
    pub fn simd_shuffle_indices(
        &mut self,
        bx: &Bx,
        span: Span,
        ty: Ty<'tcx>,
        constant: Result<ConstValue<'tcx>, ErrorHandled>,
    ) -> (Bx::Value, Ty<'tcx>) {
        constant
            .map(|val| {
                let field_ty = ty.builtin_index().unwrap();
                let fields = match ty.kind {
                    ty::Array(_, n) => n.eval_usize(bx.tcx(), ty::ParamEnv::reveal_all()),
                    _ => bug!("invalid simd shuffle type: {}", ty),
                };
                let c = ty::Const::from_value(bx.tcx(), val, ty);
                let values: Vec<_> = (0..fields)
                    .map(|field| {
                        let field = bx.tcx().const_field(
                            ty::ParamEnv::reveal_all().and((&c, mir::Field::new(field as usize))),
                        );
                        if let Some(prim) = field.try_to_scalar() {
                            let layout = bx.layout_of(field_ty);
                            let scalar = match layout.abi {
                                layout::Abi::Scalar(ref x) => x,
                                _ => bug!("from_const: invalid ByVal layout: {:#?}", layout),
                            };
                            bx.scalar_to_backend(prim, scalar, bx.immediate_backend_type(layout))
                        } else {
                            bug!("simd shuffle field {:?}", field)
                        }
                    })
                    .collect();
                let llval = bx.const_struct(&values, false);
                (llval, c.ty)
            })
            .unwrap_or_else(|_| {
                bx.tcx().sess.span_err(span, "could not evaluate shuffle_indices at compile time");
                // We've errored, so we don't have to produce working code.
                let ty = self.monomorphize(&ty);
                let llty = bx.backend_type(bx.layout_of(ty));
                (bx.const_undef(llty), ty)
            })
    }
}
<|endoftext|>