<commit_before>use types::NumPlies;

use super::color::{White, Black};
use super::piece::{Piece, WK, WR, BK, BR, Pawn};
use super::square::{Square,File,Rank};
use super::moves::Move;
use super::pos::Position;
use super::castle::{Kingside,Queenside};

pub fn make_move(p: &mut Position, m: &Move) {
    let from = m.from();
    let to = m.to();
    let curr_piece = p.at(from).unwrap();

    if m.capture_normal().is_some() || m.is_en_passant() || curr_piece.piece_type() == Pawn {
        p.set_ply_count(NumPlies(0));
    } else {
        let NumPlies(temp) = p.ply_count();
        p.set_ply_count(NumPlies(temp+1));
    }

    if m.castle().is_some() {

        //no en passant
        p.set_en_passant(None);

        let castle_color = match from.rank() {
            Rank(0) => White,
            Rank(7) => Black,
            _ => panic!(),
        };
        let castle_side = match to.file() {
            File(2) => Queenside,
            File(6) => Kingside,
            _ => panic!(),
        };

        let (rook_from, rook_to) = match (castle_color, castle_side) {
            (White, Kingside ) => (Square::new(File(7),Rank(0)), Square::new(File(5),Rank(0))),
            (White, Queenside) => (Square::new(File(0),Rank(0)), Square::new(File(3),Rank(0))),
            (Black, Kingside ) => (Square::new(File(7),Rank(7)), Square::new(File(5),Rank(7))),
            (Black, Queenside) => (Square::new(File(0),Rank(7)), Square::new(File(3),Rank(7))),
        };

        p.remove_at(from, curr_piece);
        p.set_at(to, curr_piece);
        let curr_rook = p.at(rook_from).unwrap();
        p.remove_at(rook_from, curr_rook);
        p.set_at(rook_to, curr_rook);

    } else if m.is_en_passant() {

        //no en passant after this
        p.set_en_passant(None);

        let captured = Square::new(to.file(), from.rank());
        let captured_piece = Piece::new(p.side_to_move().invert(), Pawn);

        p.remove_at(captured, captured_piece);
        p.remove_at(from, curr_piece);
        p.set_at(to, curr_piece);

    } else if m.promote().is_some() {
        //no en passant
        p.set_en_passant(None);

        //change the board and promote
        if let Some(captured_piece) = m.capture_normal() {
            p.remove_at(to, captured_piece);
        }
        p.remove_at(from, curr_piece);
        p.set_at(to, Piece::new(curr_piece.color(), m.promote().unwrap()));
    } else {

        if m.is_pawn_double_move() {
            p.set_en_passant(Some(to.file()));
        } else {
            p.set_en_passant(None);
        }

        //change the board
        if let Some(captured_piece) = m.capture_normal() {
            p.remove_at(to, captured_piece);
        }
        p.remove_at(from, curr_piece);
        p.set_at(to, curr_piece);
    }

    //castling
    if p.at(Square::new(File(4),Rank(0))) != Some(WK) {
        p.set_castle(Queenside, White, false);
        p.set_castle(Kingside , White, false);
    }
    if p.at(Square::new(File(0),Rank(0))) != Some(WR) {
        p.set_castle(Queenside, White, false);
    }
    if p.at(Square::new(File(7),Rank(0))) != Some(WR) {
        p.set_castle(Kingside , White, false);
    }
    if p.at(Square::new(File(4),Rank(7))) != Some(BK) {
        p.set_castle(Queenside, Black, false);
        p.set_castle(Kingside , Black, false);
    }
    if p.at(Square::new(File(0),Rank(7))) != Some(BR) {
        p.set_castle(Queenside, Black, false);
    }
    if p.at(Square::new(File(7),Rank(7))) != Some(BR) {
        p.set_castle(Kingside , Black, false);
    }

    p.swap_side_to_move();
}
<commit_msg>Clean up make_move()<commit_after>use types::NumPlies;

use super::color::{White, Black};
use super::piece::{Piece, WK, WR, BK, BR, Pawn};
use super::square::{Square,File,Rank};
use super::moves::Move;
use super::pos::Position;
use super::castle::{Kingside,Queenside};

pub fn make_move(p: &mut Position, m: &Move) {
    let from = m.from();
    let to = m.to();
    let curr_piece = p.at(from).unwrap();
    let curr_color = p.side_to_move();

    if m.capture_normal().is_some() || m.is_en_passant() || curr_piece.piece_type() == Pawn {
        p.set_ply_count(NumPlies(0));
    } else {
        let NumPlies(temp) = p.ply_count();
        p.set_ply_count(NumPlies(temp+1));
    }

    if let Some(castle_side) = m.castle() {

        //no en passant
        p.set_en_passant(None);

        let (rook_from, rook_to) = match (curr_color, castle_side) {
            (White, Kingside ) => (Square::new(File(7),Rank(0)), Square::new(File(5),Rank(0))),
            (White, Queenside) => (Square::new(File(0),Rank(0)), Square::new(File(3),Rank(0))),
            (Black, Kingside ) => (Square::new(File(7),Rank(7)), Square::new(File(5),Rank(7))),
            (Black, Queenside) => (Square::new(File(0),Rank(7)), Square::new(File(3),Rank(7))),
        };

        p.remove_at(from, curr_piece);
        p.set_at(to, curr_piece);
        let curr_rook = p.at(rook_from).unwrap();
        p.remove_at(rook_from, curr_rook);
        p.set_at(rook_to, curr_rook);

    } else if m.is_en_passant() {

        //no en passant after this
        p.set_en_passant(None);

        let captured = Square::new(to.file(), from.rank());
        let captured_piece = Piece::new(p.side_to_move().invert(), Pawn);

        p.remove_at(captured, captured_piece);
        p.remove_at(from, curr_piece);
        p.set_at(to, curr_piece);

    } else if let Some(promote_piece) = m.promote() {
        //no en passant
        p.set_en_passant(None);

        //change the board and promote
        if let Some(captured_piece) = m.capture_normal() {
            p.remove_at(to, captured_piece);
        }
        p.remove_at(from, curr_piece);
        p.set_at(to, Piece::new(curr_color, promote_piece));
    } else {

        if m.is_pawn_double_move() {
            p.set_en_passant(Some(to.file()));
        } else {
            p.set_en_passant(None);
        }

        //change the board
        if let Some(captured_piece) = m.capture_normal() {
            p.remove_at(to, captured_piece);
        }
        p.remove_at(from, curr_piece);
        p.set_at(to, curr_piece);
    }

    //castling
    if p.at(Square::new(File(4),Rank(0))) != Some(WK) {
        p.set_castle(Queenside, White, false);
        p.set_castle(Kingside , White, false);
    }
    if p.at(Square::new(File(0),Rank(0))) != Some(WR) {
        p.set_castle(Queenside, White, false);
    }
    if p.at(Square::new(File(7),Rank(0))) != Some(WR) {
        p.set_castle(Kingside , White, false);
    }
    if p.at(Square::new(File(4),Rank(7))) != Some(BK) {
        p.set_castle(Queenside, Black, false);
        p.set_castle(Kingside , Black, false);
    }
    if p.at(Square::new(File(0),Rank(7))) != Some(BR) {
        p.set_castle(Queenside, Black, false);
    }
    if p.at(Square::new(File(7),Rank(7))) != Some(BR) {
        p.set_castle(Kingside , Black, false);
    }

    p.swap_side_to_move();
}
<|endoftext|>


<commit_before>use std::sync::mpsc::{Sender, Receiver, channel};
use ::gameboy::cpu::interrupts::{InterruptLine, Interrupt};

//pub type SerialCallback = (FnMut(u8) -> u8) + Send;

pub struct Serial {
	// Callback that is called when a byte is shifted through the serial port using the internal clock.
	// If an external clock is used to drive the serial port, this callback function will not be called.
	// The parameter is the byte that was shifted out of the serial port.
	// The return value is the byte to be shifted in.
	// removed in favor of using channels to handle serial communication.
	//callback: Option<Box<SerialCallback>>,

	/// Serial Data register ($FF01).
	/// When a transfer is active, the value in this register will be shifted out bit by bit, and on every
	/// shift a new bit will also be shifted in from the other end. (for performance reasons, the new data will only be loaded after all 8bits have been shifted out)
	sb: u8,

	/// Serial Control register ($FF02).
	/// Bit 7 - Transfer Status
	///     0: No transfer in progress
	///     1: Start transfer
	/// Bit 1 - Clock Speed (CGB only)
	///     0: Normal
	///     1: Fast
	/// Bit 0 - Internal/External Clock
	///     0: External Clock
	///     1: Internal Clock
	sc: u8,

	/// Counts how many 4MHz cycles since the last bit has been shifted out
	current_bit_cycles: usize,

	/// Counts how many bits have been shifted during the current transfer (0...8)
	bits_shifted: u8,

	/// Stores bits shifted out during the current transfer so they can all be sent at once.
	data_out: u8,

	channels: Option<(Sender<u8>, Receiver<u8>)>
}

impl Serial {
	pub fn new() -> Serial {
		Serial {
			channels: None,
			sb: 0xFF,
			sc: 0,
			current_bit_cycles: 0,
			bits_shifted: 0,
			data_out: 0
		}
	}

	pub fn reset(&mut self) {
		self.sb = 0xFF;
		self.sc = 0;
		self.current_bit_cycles = 0;
		self.bits_shifted = 0;
		self.data_out = 0;
	}

	/// Read a byte from the serial data register ($FF01).
	pub fn read_sb(&self) -> u8 {
		self.sb
	}

	/// Read a byte from the serial control register ($FF02).
	/// Unused bits are probably all 1 (TODO: confirm this).
	pub fn read_sc(&self) -> u8 {
		self.sc | 0x7C
	}

	/// Write a byte to the serial data register ($FF01).
	/// TODO: what happens if you write to sb during a transfer?
	pub fn write_sb(&mut self, value: u8) {
		self.sb = value;
	}

	/// Write a byte to the serial control register ($FF02).
	/// TODO: what happens when you set bit 7 when there is already an active transfer? Does it restart?
	/// TODO: what happens when you change the value of bit 1 (clock speed) in the middle of a transfer that is using the internal clock.
	pub fn write_sc(&mut self, value: u8) {
		self.sc = value & 0x83;
		if value & 0x80 == 0x80 {
			self.current_bit_cycles = 0;
			self.bits_shifted = 0;
			self.data_out = 0;
		}
	}

	/// Create channels to handle async serial transfers.
	/// When the remote device wants to shift a byte over the serial port, send the byte using the sender, and then then a corresponding response will be sent to the reciever channel.
	/// When the local device wants to shift a byte out during a transfer driven by the internal clock, it will send the byte and block until a byte is recieved in response.
	/// If one of the channels returned by this function is dropped, then it is assumed that the external device has been disconnected.
	pub fn create_channels(&mut self) -> (Sender<u8>, Receiver<u8>) {
		let input: (Sender<u8>, Receiver<u8>) = channel();
		let output: (Sender<u8>, Receiver<u8>) = channel();
		let (input_send, input_recv) = input;
		let (output_send, output_recv) = output;
		self.channels = Some((output_send, input_recv));
		(input_send, output_recv)
	}

	/// Emulate the serial port behaviour for 1 cycle.
	/// TODO: different transfer speeds for CGB mode.
	pub fn emulate_hardware(&mut self, interrupt_line: &mut InterruptLine) {
		if let Some((ref mut sender, ref mut reciever)) = self.channels {
			// handle externaly driven transfers
			if let Ok(byte) = reciever.try_recv() {
				if self.sc & 1 == 0 {
					//externally driven transfer
					let out = self.sb;
					self.sb = byte;
					self.bits_shifted += 8;
					// if bits_shifted >= 8 and bit 7 of sc is set an interrupt needs to be requested and bit 7 needs to be cleared.
					if self.sc & 0x80 == 0x80 {
						interrupt_line.request_interrupt(Interrupt::Serial);
						self.sc &= 0x7F;
						self.bits_shifted = 0;
					}
					sender.send(out);
				}
				else {
					//internally driven transfer -> ignore
					let out = if self.sb & 0x80 == 0x80 {
						0xFF
					}
					else {
						0
					};
					sender.send(out);
				}
			}
		}
		if self.sc & 0x80 == 0x80 {
			// transfer active
			if self.sc & 1 == 1 {
				//internal clock
				if self.current_bit_cycles >= 64 {
					//shift bit out
					self.data_out |= self.sb & (0x80 >> (self.bits_shifted % 8));
					self.current_bit_cycles = 0;
					self.bits_shifted += 1;
					if self.bits_shifted >= 8 {
						// send data to connected device & get data back. (if anything is connected)
						if let Some((ref mut sender, ref mut receiver)) = self.channels {
							match sender.send(self.data_out) { //send byte out through channel
								Ok(_) => {
									match receiver.recv() { //block while waiting for response
										Ok(byte) => self.sb = byte,
										Err(_) => {
											self.channels = None; /* assume disconnected */
											self.sb = 0xFF;
										}
									};
								},
								Err(_) => { // assume disconnected
									self.sb = 0xFF;
									self.channels = None;
								}
							};
						}
						else {
							self.sb = 0xFF; //if no serial device is connected load 0xFF
						}

						interrupt_line.request_interrupt(Interrupt::Serial);
						self.sc &= 0x7F;
						self.current_bit_cycles = 0;
						self.bits_shifted = 0;
					}
				}
				else {
					self.current_bit_cycles += 1;
				}
			}
		}
	}
}
<commit_msg>Cleaned up some warnings.<commit_after>use std::sync::mpsc::{Sender, Receiver, channel};
use ::gameboy::cpu::interrupts::{InterruptLine, Interrupt};

//pub type SerialCallback = (FnMut(u8) -> u8) + Send;

pub struct Serial {
	// Callback that is called when a byte is shifted through the serial port using the internal clock.
	// If an external clock is used to drive the serial port, this callback function will not be called.
	// The parameter is the byte that was shifted out of the serial port.
	// The return value is the byte to be shifted in.
	// removed in favor of using channels to handle serial communication.
	//callback: Option<Box<SerialCallback>>,

	/// Serial Data register ($FF01).
	/// When a transfer is active, the value in this register will be shifted out bit by bit, and on every
	/// shift a new bit will also be shifted in from the other end. (for performance reasons, the new data will only be loaded after all 8bits have been shifted out)
	sb: u8,

	/// Serial Control register ($FF02).
	/// Bit 7 - Transfer Status
	///     0: No transfer in progress
	///     1: Start transfer
	/// Bit 1 - Clock Speed (CGB only)
	///     0: Normal
	///     1: Fast
	/// Bit 0 - Internal/External Clock
	///     0: External Clock
	///     1: Internal Clock
	sc: u8,

	/// Counts how many 4MHz cycles since the last bit has been shifted out
	current_bit_cycles: usize,

	/// Counts how many bits have been shifted during the current transfer (0...8)
	bits_shifted: u8,

	/// Stores bits shifted out during the current transfer so they can all be sent at once.
	data_out: u8,

	channels: Option<(Sender<u8>, Receiver<u8>)>
}

impl Serial {
	pub fn new() -> Serial {
		Serial {
			channels: None,
			sb: 0xFF,
			sc: 0,
			current_bit_cycles: 0,
			bits_shifted: 0,
			data_out: 0
		}
	}

	pub fn reset(&mut self) {
		self.sb = 0xFF;
		self.sc = 0;
		self.current_bit_cycles = 0;
		self.bits_shifted = 0;
		self.data_out = 0;
	}

	/// Read a byte from the serial data register ($FF01).
	pub fn read_sb(&self) -> u8 {
		self.sb
	}

	/// Read a byte from the serial control register ($FF02).
	/// Unused bits are probably all 1 (TODO: confirm this).
	pub fn read_sc(&self) -> u8 {
		self.sc | 0x7C
	}

	/// Write a byte to the serial data register ($FF01).
	/// TODO: what happens if you write to sb during a transfer?
	pub fn write_sb(&mut self, value: u8) {
		self.sb = value;
	}

	/// Write a byte to the serial control register ($FF02).
	/// TODO: what happens when you set bit 7 when there is already an active transfer? Does it restart?
	/// TODO: what happens when you change the value of bit 1 (clock speed) in the middle of a transfer that is using the internal clock.
	pub fn write_sc(&mut self, value: u8) {
		self.sc = value & 0x83;
		if value & 0x80 == 0x80 {
			self.current_bit_cycles = 0;
			self.bits_shifted = 0;
			self.data_out = 0;
		}
	}

	/// Create channels to handle async serial transfers.
	/// When the remote device wants to shift a byte over the serial port, send the byte using the sender, and then then a corresponding response will be sent to the reciever channel.
	/// When the local device wants to shift a byte out during a transfer driven by the internal clock, it will send the byte and block until a byte is recieved in response.
	/// If one of the channels returned by this function is dropped, then it is assumed that the external device has been disconnected.
	pub fn create_channels(&mut self) -> (Sender<u8>, Receiver<u8>) {
		let input: (Sender<u8>, Receiver<u8>) = channel();
		let output: (Sender<u8>, Receiver<u8>) = channel();
		let (input_send, input_recv) = input;
		let (output_send, output_recv) = output;
		self.channels = Some((output_send, input_recv));
		(input_send, output_recv)
	}

	/// Emulate the serial port behaviour for 1 cycle.
	/// TODO: different transfer speeds for CGB mode.
	pub fn emulate_hardware(&mut self, interrupt_line: &mut InterruptLine) {
		if let Some((ref mut sender, ref mut reciever)) = self.channels {
			// handle externaly driven transfers
			if let Ok(byte) = reciever.try_recv() {
				if self.sc & 1 == 0 {
					//externally driven transfer
					let out = self.sb;
					self.sb = byte;
					self.bits_shifted += 8;
					// if bits_shifted >= 8 and bit 7 of sc is set an interrupt needs to be requested and bit 7 needs to be cleared.
					if self.sc & 0x80 == 0x80 {
						interrupt_line.request_interrupt(Interrupt::Serial);
						self.sc &= 0x7F;
						self.bits_shifted = 0;
					}

					if let Err(_) = sender.send(out) {
						// the channel on the other end was closed
						self.channels = None;
					}
				}
				else {
					//internally driven transfer -> ignore
					let out = if self.sb & 0x80 == 0x80 {
						0xFF
					}
					else {
						0
					};

					if let Err(_) = sender.send(out) {
						// the channel on the other end was closed
						self.channels = None;
					}
				}
			}
		}
		if self.sc & 0x80 == 0x80 {
			// transfer active
			if self.sc & 1 == 1 {
				//internal clock
				if self.current_bit_cycles >= 64 {
					//shift bit out
					self.data_out |= self.sb & (0x80 >> (self.bits_shifted % 8));
					self.current_bit_cycles = 0;
					self.bits_shifted += 1;
					if self.bits_shifted >= 8 {
						// send data to connected device & get data back. (if anything is connected)
						if let Some((ref mut sender, ref mut receiver)) = self.channels {
							match sender.send(self.data_out) { //send byte out through channel
								Ok(_) => {
									match receiver.recv() { //block while waiting for response
										Ok(byte) => self.sb = byte,
										Err(_) => {
											self.channels = None; /* assume disconnected */
											self.sb = 0xFF;
										}
									};
								},
								Err(_) => { // assume disconnected
									self.sb = 0xFF;
									self.channels = None;
								}
							};
						}
						else {
							self.sb = 0xFF; //if no serial device is connected load 0xFF
						}

						interrupt_line.request_interrupt(Interrupt::Serial);
						self.sc &= 0x7F;
						self.current_bit_cycles = 0;
						self.bits_shifted = 0;
					}
				}
				else {
					self.current_bit_cycles += 1;
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>extern crate gl;
extern crate glfw;
extern crate imagefmt;
extern crate time;

mod math;

use gl::types::*;
use glfw::{Context, OpenGlProfileHint, WindowHint, WindowMode};
use std::mem;
use std::ptr;

macro_rules! gl_str {
    ($string_literal:expr) => (
        concat!($string_literal, '\0').as_bytes().as_ptr() as *const GLchar
    )
}

const VERTEX_SHADER_SOURCE: &'static str = "
    #version 150

    in vec2 position;
    in vec3 color;
    in vec2 texcoord;

    out vec3 Color;
    out vec2 Texcoord;

    uniform mat4 model;
    uniform mat4 view;
    uniform mat4 proj;

    void main() {
        Color = color;
        Texcoord = texcoord;
        gl_Position = proj * view * model * vec4(position, 0.0, 1.0);
    }
";

const FRAGMENT_SHADER_SOURCE: &'static str = "
    #version 150

    in vec3 Color;
    in vec2 Texcoord;

    out vec4 out_color;

    uniform sampler2D tex_kitten;
    uniform sampler2D tex_puppy;
    uniform float time;

    void main() {
        float mix_factor = (sin(time * 3.0) + 1.0) / 2.0;
        vec4 col_kitten = texture(tex_kitten, Texcoord);
        vec4 col_puppy = texture(tex_puppy, Texcoord);
        vec4 mixed_texture = mix(col_kitten, col_puppy, mix_factor);
        out_color = mix(vec4(Color, 1.0), mixed_texture, 0.25);
    }
";

#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(C, packed)]
struct Vertex {
    // Position.
    x: f32, y: f32,

    // Color.
    r: f32, g: f32, b: f32,

    // Texture.
    s: f32, t: f32,
}

static VERTICES: [Vertex; 4] = [
    Vertex { x: -0.5, y:  0.5, r: 1.0, g: 0.0, b: 0.0, s: 0.0, t: 0.0 }, // Top-left
    Vertex { x:  0.5, y:  0.5, r: 0.0, g: 1.0, b: 0.0, s: 1.0, t: 0.0 }, // Top-right
    Vertex { x:  0.5, y: -0.5, r: 0.0, g: 0.0, b: 1.0, s: 1.0, t: 1.0 }, // Bottom-right
    Vertex { x: -0.5, y: -0.5, r: 1.0, g: 1.0, b: 1.0, s: 0.0, t: 1.0 }, // Bottom-left
];

static ELEMENTS: [GLuint; 6] = [
    0, 1, 2, // Top-right triangle
    2, 3, 0, // Bottom-left triangle
];

unsafe fn compile_shader(shader_type: GLenum, source: &str) -> Result<GLuint, String> {
    let shader = gl::CreateShader(shader_type);
    let source_ptr = source.as_bytes().as_ptr() as *const GLchar;
    let source_len = source.len() as GLint;
    gl::ShaderSource(shader, 1, &source_ptr, &source_len);
    gl::CompileShader(shader);

    let mut status = gl::FALSE as GLint;
    gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

    if status == gl::TRUE as GLint {
        Ok(shader)
    } else {
        let mut log_len = 0;
        gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut log_len);
        if log_len == 0 { return Err(String::new()) }

        let mut buf = Vec::with_capacity(log_len as usize);
        buf.set_len(log_len as usize - 1); // Subtract 1 to ignore the trailing null.
        gl::GetShaderInfoLog(shader, log_len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);

        Err(String::from_utf8_lossy(&buf).into_owned())
    }
}

fn main() {
    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    glfw.window_hint(WindowHint::ContextVersion(3, 2));
    glfw.window_hint(WindowHint::OpenGlProfile(OpenGlProfileHint::Core));
    glfw.window_hint(WindowHint::OpenGlForwardCompat(true));
    glfw.window_hint(WindowHint::Resizable(false));

    let (mut window, events) = glfw.create_window(800, 600, "OpenGL", WindowMode::Windowed)
        .expect("Failed to create GLFW window.");

    // Listen for keyboard events on this window.
    window.set_key_polling(true);

    // Make this window's OpenGL context the current context. This must be done before calling
    // `gl::load_with`.
    window.make_current();

    // Load OpenGL function pointers.
    gl::load_with(|symbol| window.get_proc_address(symbol));

    let vertex_shader;
    let fragment_shader;
    let shader_program;
    let mut vao = 0;
    let mut vbo = 0;
    let mut ebo = 0;
    let mut textures = [0; 2];

    unsafe {
        // Create a vertex array object.
        gl::GenVertexArrays(1, &mut vao);
        gl::BindVertexArray(vao);

        // Create a vertex buffer object and copy the vertex data to it.
        gl::GenBuffers(1, &mut vbo);
        gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
        gl::BufferData(gl::ARRAY_BUFFER,
                       mem::size_of_val(&VERTICES) as GLsizeiptr,
                       VERTICES.as_ptr() as *const GLvoid,
                       gl::STATIC_DRAW);

        // Create an element buffer object and copy the element data to it.
        gl::GenBuffers(1, &mut ebo);
        gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ebo);
        gl::BufferData(gl::ELEMENT_ARRAY_BUFFER,
                       mem::size_of_val(&ELEMENTS) as GLsizeiptr,
                       ELEMENTS.as_ptr() as *const GLvoid,
                       gl::STATIC_DRAW);

        // Compile the vertex and fragment shaders.
        vertex_shader = compile_shader(gl::VERTEX_SHADER, VERTEX_SHADER_SOURCE).unwrap();
        fragment_shader = compile_shader(gl::FRAGMENT_SHADER, FRAGMENT_SHADER_SOURCE).unwrap();

        // Link the vertex and fragment shaders into a shader program.
        shader_program = gl::CreateProgram();
        gl::AttachShader(shader_program, vertex_shader);
        gl::AttachShader(shader_program, fragment_shader);
        gl::BindFragDataLocation(shader_program, 0, gl_str!("out_color"));
        gl::LinkProgram(shader_program);
        gl::UseProgram(shader_program);

        // Specify the layout of the vertex data.
        let position_attrib = gl::GetAttribLocation(shader_program, gl_str!("position"));
        gl::EnableVertexAttribArray(position_attrib as GLuint);
        gl::VertexAttribPointer(position_attrib as GLuint, 2, gl::FLOAT, gl::FALSE,
                                mem::size_of::<Vertex>() as GLint, ptr::null());

        let position_attrib = gl::GetAttribLocation(shader_program, gl_str!("color"));
        gl::EnableVertexAttribArray(position_attrib as GLuint);
        gl::VertexAttribPointer(position_attrib as GLuint, 3, gl::FLOAT, gl::FALSE,
                                mem::size_of::<Vertex>() as GLint,
                                (2 * mem::size_of::<f32>()) as *const GLvoid);

        let position_attrib = gl::GetAttribLocation(shader_program, gl_str!("texcoord"));
        gl::EnableVertexAttribArray(position_attrib as GLuint);
        gl::VertexAttribPointer(position_attrib as GLuint, 2, gl::FLOAT, gl::FALSE,
                                mem::size_of::<Vertex>() as GLint,
                                (5 * mem::size_of::<f32>()) as *const GLvoid);

        // Create and load textures.
        gl::GenTextures(2, textures.as_mut_ptr());

        gl::ActiveTexture(gl::TEXTURE0);
        gl::BindTexture(gl::TEXTURE_2D, textures[0]);
        let image = imagefmt::read("sample.png", imagefmt::ColFmt::RGB).unwrap();
        gl::TexImage2D(gl::TEXTURE_2D, 0, gl::RGB as GLint, image.w as GLint, image.h as GLint,
                       0, gl::RGB, gl::UNSIGNED_BYTE, image.buf.as_ptr() as *const GLvoid);
        gl::Uniform1i(gl::GetUniformLocation(shader_program, gl_str!("tex_kitten")), 0);

        gl::GenerateMipmap(gl::TEXTURE_2D);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT as GLint);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT as GLint);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER,
                          gl::LINEAR_MIPMAP_LINEAR as GLint);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER,
                          gl::LINEAR_MIPMAP_LINEAR as GLint);

        gl::ActiveTexture(gl::TEXTURE1);
        gl::BindTexture(gl::TEXTURE_2D, textures[1]);
        let image = imagefmt::read("sample2.png", imagefmt::ColFmt::RGB).unwrap();
        gl::TexImage2D(gl::TEXTURE_2D, 0, gl::RGB as GLint, image.w as GLint, image.h as GLint,
                       0, gl::RGB, gl::UNSIGNED_BYTE, image.buf.as_ptr() as *const GLvoid);
        gl::Uniform1i(gl::GetUniformLocation(shader_program, gl_str!("tex_puppy")), 1);

        gl::GenerateMipmap(gl::TEXTURE_2D);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT as GLint);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT as GLint);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER,
                          gl::LINEAR_MIPMAP_LINEAR as GLint);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER,
                          gl::LINEAR_MIPMAP_LINEAR as GLint);
    }

    let view = math::Mat4::look_at(
        math::Vec3([1.2, 1.2, 1.2]),
        math::Vec3([0.0, 0.0, 0.0]),
        math::Vec3([0.0, 0.0, 1.0]));
    let proj = math::Mat4::perspective(math::TAU / 8.0, 800.0 / 600.0, 1.0, 10.0);

    let model_uniform = unsafe { gl::GetUniformLocation(shader_program, gl_str!("model")) };
    let view_uniform = unsafe { gl::GetUniformLocation(shader_program, gl_str!("view")) };
    let proj_uniform = unsafe { gl::GetUniformLocation(shader_program, gl_str!("proj")) };

    unsafe {
        gl::UniformMatrix4fv(view_uniform, 1, gl::FALSE, &view[0][0]);
        gl::UniformMatrix4fv(proj_uniform, 1, gl::FALSE, &proj[0][0]);
    }

    let time_uniform = unsafe { gl::GetUniformLocation(shader_program, gl_str!("time")) };
    let time_start = time::precise_time_ns();

    while !window.should_close() {
        glfw.poll_events();
        for (_, event) in glfw::flush_messages(&events) {
            handle_window_event(&mut window, event);
        }

        unsafe {
            // Update the `time` uniform.
            let time_now = time::precise_time_ns();
            let elapsed_seconds = (time_now - time_start) as f32 / 1e9;
            gl::Uniform1f(time_uniform, elapsed_seconds);

            // Vary the model matrix over time.
            let scale = (elapsed_seconds * 5.0).sin() * 0.25 + 0.75;
            let model =
                math::Mat4::rotate_z(math::TAU / 2.0 * elapsed_seconds) *
                math::Mat4::scale(scale, scale, scale);
            gl::UniformMatrix4fv(model_uniform, 1, gl::FALSE, &model[0][0]);

            // Clear the screen to black.
            gl::ClearColor(0.0, 0.0, 0.0, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT);

            // Draw the triangles described by the elements array.
            gl::DrawElements(gl::TRIANGLES, ELEMENTS.len() as GLint, gl::UNSIGNED_INT,
                             ptr::null());
        }

        window.swap_buffers();
    }

    unsafe {
        gl::DeleteTextures(2, textures.as_ptr());
        gl::DeleteProgram(shader_program);
        gl::DeleteShader(fragment_shader);
        gl::DeleteShader(vertex_shader);
        gl::DeleteBuffers(1, &ebo);
        gl::DeleteBuffers(1, &vbo);
        gl::DeleteVertexArrays(1, &vao);
    }
}

fn handle_window_event(window: &mut glfw::Window, event: glfw::WindowEvent) {
    use glfw::{Action, Key, WindowEvent};

    match event {
        WindowEvent::Key(Key::Escape, _, Action::Press, _) => {
            window.set_should_close(true);
        },
        _ => {},
    }
}
<commit_msg>Send combined trans matrix to the shader program.<commit_after>extern crate gl;
extern crate glfw;
extern crate imagefmt;
extern crate time;

mod math;

use gl::types::*;
use glfw::{Context, OpenGlProfileHint, WindowHint, WindowMode};
use std::mem;
use std::ptr;

macro_rules! gl_str {
    ($string_literal:expr) => (
        concat!($string_literal, '\0').as_bytes().as_ptr() as *const GLchar
    )
}

const VERTEX_SHADER_SOURCE: &'static str = "
    #version 150

    in vec2 position;
    in vec3 color;
    in vec2 texcoord;

    out vec3 Color;
    out vec2 Texcoord;

    uniform mat4 trans;

    void main() {
        Color = color;
        Texcoord = texcoord;
        gl_Position = trans * vec4(position, 0.0, 1.0);
    }
";

const FRAGMENT_SHADER_SOURCE: &'static str = "
    #version 150

    in vec3 Color;
    in vec2 Texcoord;

    out vec4 out_color;

    uniform sampler2D tex_kitten;
    uniform sampler2D tex_puppy;
    uniform float time;

    void main() {
        float mix_factor = (sin(time * 3.0) + 1.0) / 2.0;
        vec4 col_kitten = texture(tex_kitten, Texcoord);
        vec4 col_puppy = texture(tex_puppy, Texcoord);
        vec4 mixed_texture = mix(col_kitten, col_puppy, mix_factor);
        out_color = mix(vec4(Color, 1.0), mixed_texture, 0.25);
    }
";

#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(C, packed)]
struct Vertex {
    // Position.
    x: f32, y: f32,

    // Color.
    r: f32, g: f32, b: f32,

    // Texture.
    s: f32, t: f32,
}

static VERTICES: [Vertex; 4] = [
    Vertex { x: -0.5, y:  0.5, r: 1.0, g: 0.0, b: 0.0, s: 0.0, t: 0.0 }, // Top-left
    Vertex { x:  0.5, y:  0.5, r: 0.0, g: 1.0, b: 0.0, s: 1.0, t: 0.0 }, // Top-right
    Vertex { x:  0.5, y: -0.5, r: 0.0, g: 0.0, b: 1.0, s: 1.0, t: 1.0 }, // Bottom-right
    Vertex { x: -0.5, y: -0.5, r: 1.0, g: 1.0, b: 1.0, s: 0.0, t: 1.0 }, // Bottom-left
];

static ELEMENTS: [GLuint; 6] = [
    0, 1, 2, // Top-right triangle
    2, 3, 0, // Bottom-left triangle
];

unsafe fn compile_shader(shader_type: GLenum, source: &str) -> Result<GLuint, String> {
    let shader = gl::CreateShader(shader_type);
    let source_ptr = source.as_bytes().as_ptr() as *const GLchar;
    let source_len = source.len() as GLint;
    gl::ShaderSource(shader, 1, &source_ptr, &source_len);
    gl::CompileShader(shader);

    let mut status = gl::FALSE as GLint;
    gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

    if status == gl::TRUE as GLint {
        Ok(shader)
    } else {
        let mut log_len = 0;
        gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut log_len);
        if log_len == 0 { return Err(String::new()) }

        let mut buf = Vec::with_capacity(log_len as usize);
        buf.set_len(log_len as usize - 1); // Subtract 1 to ignore the trailing null.
        gl::GetShaderInfoLog(shader, log_len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);

        Err(String::from_utf8_lossy(&buf).into_owned())
    }
}

fn main() {
    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    glfw.window_hint(WindowHint::ContextVersion(3, 2));
    glfw.window_hint(WindowHint::OpenGlProfile(OpenGlProfileHint::Core));
    glfw.window_hint(WindowHint::OpenGlForwardCompat(true));
    glfw.window_hint(WindowHint::Resizable(false));

    let (mut window, events) = glfw.create_window(800, 600, "OpenGL", WindowMode::Windowed)
        .expect("Failed to create GLFW window.");

    // Listen for keyboard events on this window.
    window.set_key_polling(true);

    // Make this window's OpenGL context the current context. This must be done before calling
    // `gl::load_with`.
    window.make_current();

    // Load OpenGL function pointers.
    gl::load_with(|symbol| window.get_proc_address(symbol));

    let vertex_shader;
    let fragment_shader;
    let shader_program;
    let mut vao = 0;
    let mut vbo = 0;
    let mut ebo = 0;
    let mut textures = [0; 2];

    unsafe {
        // Create a vertex array object.
        gl::GenVertexArrays(1, &mut vao);
        gl::BindVertexArray(vao);

        // Create a vertex buffer object and copy the vertex data to it.
        gl::GenBuffers(1, &mut vbo);
        gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
        gl::BufferData(gl::ARRAY_BUFFER,
                       mem::size_of_val(&VERTICES) as GLsizeiptr,
                       VERTICES.as_ptr() as *const GLvoid,
                       gl::STATIC_DRAW);

        // Create an element buffer object and copy the element data to it.
        gl::GenBuffers(1, &mut ebo);
        gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ebo);
        gl::BufferData(gl::ELEMENT_ARRAY_BUFFER,
                       mem::size_of_val(&ELEMENTS) as GLsizeiptr,
                       ELEMENTS.as_ptr() as *const GLvoid,
                       gl::STATIC_DRAW);

        // Compile the vertex and fragment shaders.
        vertex_shader = compile_shader(gl::VERTEX_SHADER, VERTEX_SHADER_SOURCE).unwrap();
        fragment_shader = compile_shader(gl::FRAGMENT_SHADER, FRAGMENT_SHADER_SOURCE).unwrap();

        // Link the vertex and fragment shaders into a shader program.
        shader_program = gl::CreateProgram();
        gl::AttachShader(shader_program, vertex_shader);
        gl::AttachShader(shader_program, fragment_shader);
        gl::BindFragDataLocation(shader_program, 0, gl_str!("out_color"));
        gl::LinkProgram(shader_program);
        gl::UseProgram(shader_program);

        // Specify the layout of the vertex data.
        let position_attrib = gl::GetAttribLocation(shader_program, gl_str!("position"));
        gl::EnableVertexAttribArray(position_attrib as GLuint);
        gl::VertexAttribPointer(position_attrib as GLuint, 2, gl::FLOAT, gl::FALSE,
                                mem::size_of::<Vertex>() as GLint, ptr::null());

        let position_attrib = gl::GetAttribLocation(shader_program, gl_str!("color"));
        gl::EnableVertexAttribArray(position_attrib as GLuint);
        gl::VertexAttribPointer(position_attrib as GLuint, 3, gl::FLOAT, gl::FALSE,
                                mem::size_of::<Vertex>() as GLint,
                                (2 * mem::size_of::<f32>()) as *const GLvoid);

        let position_attrib = gl::GetAttribLocation(shader_program, gl_str!("texcoord"));
        gl::EnableVertexAttribArray(position_attrib as GLuint);
        gl::VertexAttribPointer(position_attrib as GLuint, 2, gl::FLOAT, gl::FALSE,
                                mem::size_of::<Vertex>() as GLint,
                                (5 * mem::size_of::<f32>()) as *const GLvoid);

        // Create and load textures.
        gl::GenTextures(2, textures.as_mut_ptr());

        gl::ActiveTexture(gl::TEXTURE0);
        gl::BindTexture(gl::TEXTURE_2D, textures[0]);
        let image = imagefmt::read("sample.png", imagefmt::ColFmt::RGB).unwrap();
        gl::TexImage2D(gl::TEXTURE_2D, 0, gl::RGB as GLint, image.w as GLint, image.h as GLint,
                       0, gl::RGB, gl::UNSIGNED_BYTE, image.buf.as_ptr() as *const GLvoid);
        gl::Uniform1i(gl::GetUniformLocation(shader_program, gl_str!("tex_kitten")), 0);

        gl::GenerateMipmap(gl::TEXTURE_2D);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT as GLint);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT as GLint);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER,
                          gl::LINEAR_MIPMAP_LINEAR as GLint);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER,
                          gl::LINEAR_MIPMAP_LINEAR as GLint);

        gl::ActiveTexture(gl::TEXTURE1);
        gl::BindTexture(gl::TEXTURE_2D, textures[1]);
        let image = imagefmt::read("sample2.png", imagefmt::ColFmt::RGB).unwrap();
        gl::TexImage2D(gl::TEXTURE_2D, 0, gl::RGB as GLint, image.w as GLint, image.h as GLint,
                       0, gl::RGB, gl::UNSIGNED_BYTE, image.buf.as_ptr() as *const GLvoid);
        gl::Uniform1i(gl::GetUniformLocation(shader_program, gl_str!("tex_puppy")), 1);

        gl::GenerateMipmap(gl::TEXTURE_2D);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT as GLint);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT as GLint);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER,
                          gl::LINEAR_MIPMAP_LINEAR as GLint);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER,
                          gl::LINEAR_MIPMAP_LINEAR as GLint);
    }

    let view = math::Mat4::look_at(
        math::Vec3([1.2, 1.2, 1.2]),
        math::Vec3([0.0, 0.0, 0.0]),
        math::Vec3([0.0, 0.0, 1.0]));
    let proj = math::Mat4::perspective(math::TAU / 8.0, 800.0 / 600.0, 1.0, 10.0);

    let trans_uniform = unsafe { gl::GetUniformLocation(shader_program, gl_str!("trans")) };
    let time_uniform = unsafe { gl::GetUniformLocation(shader_program, gl_str!("time")) };
    let time_start = time::precise_time_ns();

    while !window.should_close() {
        glfw.poll_events();
        for (_, event) in glfw::flush_messages(&events) {
            handle_window_event(&mut window, event);
        }

        unsafe {
            // Update the `time` uniform.
            let time_now = time::precise_time_ns();
            let elapsed_seconds = (time_now - time_start) as f32 / 1e9;
            gl::Uniform1f(time_uniform, elapsed_seconds);

            // Vary the model matrix over time.
            let scale = (elapsed_seconds * 5.0).sin() * 0.25 + 0.75;
            let model =
                math::Mat4::rotate_z(math::TAU / 2.0 * elapsed_seconds) *
                math::Mat4::scale(scale, scale, scale);
            let trans = proj * view * model;
            gl::UniformMatrix4fv(trans_uniform, 1, gl::FALSE, &trans[0][0]);

            // Clear the screen to black.
            gl::ClearColor(0.0, 0.0, 0.0, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT);

            // Draw the triangles described by the elements array.
            gl::DrawElements(gl::TRIANGLES, ELEMENTS.len() as GLint, gl::UNSIGNED_INT,
                             ptr::null());
        }

        window.swap_buffers();
    }

    unsafe {
        gl::DeleteTextures(2, textures.as_ptr());
        gl::DeleteProgram(shader_program);
        gl::DeleteShader(fragment_shader);
        gl::DeleteShader(vertex_shader);
        gl::DeleteBuffers(1, &ebo);
        gl::DeleteBuffers(1, &vbo);
        gl::DeleteVertexArrays(1, &vao);
    }
}

fn handle_window_event(window: &mut glfw::Window, event: glfw::WindowEvent) {
    use glfw::{Action, Key, WindowEvent};

    match event {
        WindowEvent::Key(Key::Escape, _, Action::Press, _) => {
            window.set_should_close(true);
        },
        _ => {},
    }
}
<|endoftext|>


<commit_before>#![feature(rustc_private)]

extern crate rustc_codegen_ssa;
extern crate rustc_errors;
extern crate rustc_middle;
extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_hir;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_symbol_mangling;
extern crate rustc_target;

use rustc_codegen_ssa::back::linker::LinkerInfo;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_codegen_ssa::{CodegenResults, CrateInfo};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::MetadataRef;
use rustc_errors::ErrorReported;
use rustc_middle::dep_graph::DepGraph;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader, MetadataLoaderDyn};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::OutputFilenames;
use rustc_session::Session;
use rustc_target::spec::Target;
use std::any::Any;
use std::path::Path;

pub struct NoLlvmMetadataLoader;

impl MetadataLoader for NoLlvmMetadataLoader {
    fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<MetadataRef, String> {
        unreachable!("some_crate.rs shouldn't depend on any external crates");
    }

    fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String> {
        unreachable!("some_crate.rs shouldn't depend on any external crates");
    }
}

struct TheBackend;

impl CodegenBackend for TheBackend {
    fn metadata_loader(&self) -> Box<MetadataLoaderDyn> {
        Box::new(NoLlvmMetadataLoader)
    }

    fn provide(&self, providers: &mut Providers) {}
    fn provide_extern(&self, providers: &mut Providers) {}

    fn codegen_crate<'a, 'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: EncodedMetadata,
        _need_metadata_module: bool,
    ) -> Box<dyn Any> {
        use rustc_hir::def_id::LOCAL_CRATE;

        Box::new(CodegenResults {
            crate_name: tcx.crate_name(LOCAL_CRATE),
            modules: vec![],
            allocator_module: None,
            metadata_module: None,
            metadata,
            windows_subsystem: None,
            linker_info: LinkerInfo::new(tcx),
            crate_info: CrateInfo::new(tcx),
        })
    }

    fn join_codegen(
        &self,
        ongoing_codegen: Box<dyn Any>,
        _sess: &Session,
    ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
        let codegen_results = ongoing_codegen
            .downcast::<CodegenResults>()
            .expect("in join_codegen: ongoing_codegen is not a CodegenResults");
        Ok((*codegen_results, FxHashMap::default()))
    }

    fn link(
        &self,
        sess: &Session,
        codegen_results: CodegenResults,
        outputs: &OutputFilenames,
    ) -> Result<(), ErrorReported> {
        use rustc_session::{config::CrateType, output::out_filename};
        use std::io::Write;
        let crate_name = codegen_results.crate_name;
        for &crate_type in sess.opts.crate_types.iter() {
            if crate_type != CrateType::Rlib {
                sess.fatal(&format!("Crate type is {:?}", crate_type));
            }
            let output_name = out_filename(sess, crate_type, &outputs, &*crate_name.as_str());
            let mut out_file = ::std::fs::File::create(output_name).unwrap();
            write!(out_file, "This has been \"compiled\" successfully.").unwrap();
        }
        Ok(())
    }
}

/// This is the entrypoint for a hot plugged rustc_codegen_llvm
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
    Box::new(TheBackend)
}
<commit_msg>Use DefaultMetadataLoader in the hotplug_codegen_backend test<commit_after>#![feature(rustc_private)]

extern crate rustc_codegen_ssa;
extern crate rustc_errors;
extern crate rustc_middle;
extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_hir;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_symbol_mangling;
extern crate rustc_target;

use rustc_codegen_ssa::back::linker::LinkerInfo;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_codegen_ssa::{CodegenResults, CrateInfo};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::MetadataRef;
use rustc_errors::ErrorReported;
use rustc_middle::dep_graph::DepGraph;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader, MetadataLoaderDyn};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::OutputFilenames;
use rustc_session::Session;
use rustc_target::spec::Target;
use std::any::Any;
use std::path::Path;

struct TheBackend;

impl CodegenBackend for TheBackend {
    fn metadata_loader(&self) -> Box<MetadataLoaderDyn> {
        Box::new(rustc_codegen_ssa::back::metadata::DefaultMetadataLoader)
    }

    fn provide(&self, providers: &mut Providers) {}
    fn provide_extern(&self, providers: &mut Providers) {}

    fn codegen_crate<'a, 'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: EncodedMetadata,
        _need_metadata_module: bool,
    ) -> Box<dyn Any> {
        use rustc_hir::def_id::LOCAL_CRATE;

        Box::new(CodegenResults {
            crate_name: tcx.crate_name(LOCAL_CRATE),
            modules: vec![],
            allocator_module: None,
            metadata_module: None,
            metadata,
            windows_subsystem: None,
            linker_info: LinkerInfo::new(tcx),
            crate_info: CrateInfo::new(tcx),
        })
    }

    fn join_codegen(
        &self,
        ongoing_codegen: Box<dyn Any>,
        _sess: &Session,
    ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
        let codegen_results = ongoing_codegen
            .downcast::<CodegenResults>()
            .expect("in join_codegen: ongoing_codegen is not a CodegenResults");
        Ok((*codegen_results, FxHashMap::default()))
    }

    fn link(
        &self,
        sess: &Session,
        codegen_results: CodegenResults,
        outputs: &OutputFilenames,
    ) -> Result<(), ErrorReported> {
        use rustc_session::{config::CrateType, output::out_filename};
        use std::io::Write;
        let crate_name = codegen_results.crate_name;
        for &crate_type in sess.opts.crate_types.iter() {
            if crate_type != CrateType::Rlib {
                sess.fatal(&format!("Crate type is {:?}", crate_type));
            }
            let output_name = out_filename(sess, crate_type, &outputs, &*crate_name.as_str());
            let mut out_file = ::std::fs::File::create(output_name).unwrap();
            write!(out_file, "This has been \"compiled\" successfully.").unwrap();
        }
        Ok(())
    }
}

/// This is the entrypoint for a hot plugged rustc_codegen_llvm
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
    Box::new(TheBackend)
}
<|endoftext|>


<commit_before>use crate::spec::{PanicStrategy, RelocModel, Target, TargetOptions};

pub fn target() -> Target {
    Target {
        llvm_target: "msp430-none-elf".to_string(),
        pointer_width: 16,
        data_layout: "e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16".to_string(),
        arch: "msp430".to_string(),

        options: TargetOptions {
            c_int_width: "16".to_string(),
            executables: true,

            // The LLVM backend currently can't generate object files. To
            // workaround this LLVM generates assembly files which then we feed
            // to gcc to get object files. For this reason we have a hard
            // dependency on this specific gcc.
            asm_args: vec!["-mcpu=msp430".to_string()],
            linker: Some("msp430-elf-gcc".to_string()),

            // There are no atomic CAS instructions available in the MSP430
            // instruction set, and the LLVM backend doesn't currently support
            // compiler fences so the Atomic* API is missing on this target.
            // When the LLVM backend gains support for compile fences uncomment
            // the `singlethread: true` line and set `max_atomic_width` to
            // `Some(16)`.
            max_atomic_width: Some(0),
            atomic_cas: false,
            // singlethread: true,

            // Because these devices have very little resources having an
            // unwinder is too onerous so we default to "abort" because the
            // "unwind" strategy is very rare.
            panic_strategy: PanicStrategy::Abort,

            // Similarly, one almost always never wants to use relocatable
            // code because of the extra costs it involves.
            relocation_model: RelocModel::Static,

            // Right now we invoke an external assembler and this isn't
            // compatible with multiple codegen units, and plus we probably
            // don't want to invoke that many gcc instances.
            default_codegen_units: Some(1),

            // Since MSP430 doesn't meaningfully support faulting on illegal
            // instructions, LLVM generates a call to abort() function instead
            // of a trap instruction. Such calls are 4 bytes long, and that is
            // too much overhead for such small target.
            trap_unreachable: false,

            // See the thumb_base.rs file for an explanation of this value
            emit_debug_gdb_scripts: false,

            eh_frame_header: false,

            ..Default::default()
        },
    }
}
<commit_msg>Rollup merge of #86014 - cr1901:msp430-link, r=jonas-schievink<commit_after>use crate::spec::{PanicStrategy, RelocModel, Target, TargetOptions};

pub fn target() -> Target {
    Target {
        llvm_target: "msp430-none-elf".to_string(),
        pointer_width: 16,
        data_layout: "e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16".to_string(),
        arch: "msp430".to_string(),

        options: TargetOptions {
            c_int_width: "16".to_string(),
            executables: true,

            // The LLVM backend currently can't generate object files. To
            // workaround this LLVM generates assembly files which then we feed
            // to gcc to get object files. For this reason we have a hard
            // dependency on this specific gcc.
            asm_args: vec!["-mcpu=msp430".to_string()],
            linker: Some("msp430-elf-gcc".to_string()),
            linker_is_gnu: false,

            // There are no atomic CAS instructions available in the MSP430
            // instruction set, and the LLVM backend doesn't currently support
            // compiler fences so the Atomic* API is missing on this target.
            // When the LLVM backend gains support for compile fences uncomment
            // the `singlethread: true` line and set `max_atomic_width` to
            // `Some(16)`.
            max_atomic_width: Some(0),
            atomic_cas: false,
            // singlethread: true,

            // Because these devices have very little resources having an
            // unwinder is too onerous so we default to "abort" because the
            // "unwind" strategy is very rare.
            panic_strategy: PanicStrategy::Abort,

            // Similarly, one almost always never wants to use relocatable
            // code because of the extra costs it involves.
            relocation_model: RelocModel::Static,

            // Right now we invoke an external assembler and this isn't
            // compatible with multiple codegen units, and plus we probably
            // don't want to invoke that many gcc instances.
            default_codegen_units: Some(1),

            // Since MSP430 doesn't meaningfully support faulting on illegal
            // instructions, LLVM generates a call to abort() function instead
            // of a trap instruction. Such calls are 4 bytes long, and that is
            // too much overhead for such small target.
            trap_unreachable: false,

            // See the thumb_base.rs file for an explanation of this value
            emit_debug_gdb_scripts: false,

            eh_frame_header: false,

            ..Default::default()
        },
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::audionode::AudioNode;
use dom::baseaudiocontext::BaseAudioContext;
use dom::bindings::codegen::Bindings::AudioScheduledSourceNodeBinding::AudioScheduledSourceNodeMethods;
use dom::bindings::codegen::Bindings::AudioNodeBinding::AudioNodeOptions;
use dom::bindings::num::Finite;
use dom_struct::dom_struct;
use servo_media::audio::node::AudioNodeType;

#[dom_struct]
pub struct AudioScheduledSourceNode {
    node: AudioNode,
}

impl AudioScheduledSourceNode {
    pub fn new_inherited(node_type: AudioNodeType,
                         context: &BaseAudioContext,
                         options: &AudioNodeOptions,
                         number_of_inputs: u32,
                         number_of_outputs: u32) -> AudioScheduledSourceNode {
        AudioScheduledSourceNode {
            node: AudioNode::new_inherited(node_type, context, options, number_of_inputs, number_of_outputs),
        }
    }
}

impl AudioScheduledSourceNodeMethods for AudioScheduledSourceNode {
    // https://webaudio.github.io/web-audio-api/#dom-audioscheduledsourcenode-onended
    event_handler!(ended, GetOnended, SetOnended);

    // https://webaudio.github.io/web-audio-api/#dom-audioscheduledsourcenode-start
    fn Start(&self, _when: Finite<f64>) {
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioscheduledsourcenode-stop
    fn Stop(&self, _when: Finite<f64>) {
    }
}
<commit_msg>AudioScheduledSourceNode start and stop<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::audionode::AudioNode;
use dom::baseaudiocontext::BaseAudioContext;
use dom::bindings::codegen::Bindings::AudioScheduledSourceNodeBinding::AudioScheduledSourceNodeMethods;
use dom::bindings::codegen::Bindings::AudioNodeBinding::AudioNodeOptions;
use dom::bindings::num::Finite;
use dom_struct::dom_struct;
use servo_media::audio::node::{AudioNodeMessage, AudioNodeType, AudioScheduledSourceNodeMessage};

#[dom_struct]
pub struct AudioScheduledSourceNode {
    node: AudioNode,
}

impl AudioScheduledSourceNode {
    pub fn new_inherited(node_type: AudioNodeType,
                         context: &BaseAudioContext,
                         options: &AudioNodeOptions,
                         number_of_inputs: u32,
                         number_of_outputs: u32) -> AudioScheduledSourceNode {
        AudioScheduledSourceNode {
            node: AudioNode::new_inherited(node_type, context, options, number_of_inputs, number_of_outputs),
        }
    }
}

impl AudioScheduledSourceNodeMethods for AudioScheduledSourceNode {
    // https://webaudio.github.io/web-audio-api/#dom-audioscheduledsourcenode-onended
    event_handler!(ended, GetOnended, SetOnended);

    // https://webaudio.github.io/web-audio-api/#dom-audioscheduledsourcenode-start
    fn Start(&self, when: Finite<f64>) {
        self.node.message(
            AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(*when))
            );
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioscheduledsourcenode-stop
    fn Stop(&self, when: Finite<f64>) {
        self.node.message(
            AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Stop(*when))
            );
    }
}
<|endoftext|>


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

// Finds items that are externally reachable, to determine which items
// need to have their metadata (and possibly their AST) serialized.
// All items that can be referred to through an exported name are
// reachable, and when a reachable thing is inline or generic, it
// makes all other generics or inline functions that it references
// reachable as well.

use middle::resolve;
use middle::ty;
use middle::typeck;

use core::prelude::*;
use core::hashmap::HashSet;
use syntax::ast;
use syntax::ast::*;
use syntax::ast_util::def_id_of_def;
use syntax::attr;
use syntax::codemap;
use syntax::print::pprust::expr_to_str;
use syntax::{visit, ast_map};

pub type map = @HashSet<node_id>;

struct ctx<'self> {
    exp_map2: resolve::ExportMap2,
    tcx: ty::ctxt,
    method_map: typeck::method_map,
    rmap: &'self mut HashSet<node_id>,
}

pub fn find_reachable(crate_mod: &_mod, exp_map2: resolve::ExportMap2,
                      tcx: ty::ctxt, method_map: typeck::method_map) -> map {
    let mut rmap = HashSet::new();
    {
        let cx = ctx {
            exp_map2: exp_map2,
            tcx: tcx,
            method_map: method_map,
            rmap: &mut rmap
        };
        traverse_public_mod(&cx, ast::crate_node_id, crate_mod);
        traverse_all_resources_and_impls(&cx, crate_mod);
    }
    return @rmap;
}

fn traverse_exports(cx: &ctx, mod_id: node_id) -> bool {
    let mut found_export = false;
    match cx.exp_map2.find(&mod_id) {
      Some(ref exp2s) => {
        for (*exp2s).each |e2| {
            found_export = true;
            traverse_def_id(cx, e2.def_id)
        };
      }
      None => ()
    }
    return found_export;
}

fn traverse_def_id(cx: &ctx, did: def_id) {
    if did.crate != local_crate { return; }
    match cx.tcx.items.find(&did.node) {
        None => (), // This can happen for self, for example
        Some(&ast_map::node_item(item, _)) => traverse_public_item(cx, item),
        Some(&ast_map::node_method(_, impl_id, _)) => traverse_def_id(cx, impl_id),
        Some(&ast_map::node_foreign_item(item, _, _, _)) => {
            cx.rmap.insert(item.id);
        }
        Some(&ast_map::node_variant(ref v, _, _)) => {
            cx.rmap.insert(v.node.id);
        }
        _ => ()
    }
}

fn traverse_public_mod(cx: &ctx, mod_id: node_id, m: &_mod) {
    if !traverse_exports(cx, mod_id) {
        // No exports, so every local item is exported
        for m.items.each |item| {
            traverse_public_item(cx, *item);
        }
    }
}

fn traverse_public_item(cx: &ctx, item: @item) {
    // XXX: it shouldn't be necessary to do this
    let rmap: &mut HashSet<node_id> = cx.rmap;
    if rmap.contains(&item.id) { return; }
    rmap.insert(item.id);
    match item.node {
      item_mod(ref m) => traverse_public_mod(cx, item.id, m),
      item_foreign_mod(ref nm) => {
          if !traverse_exports(cx, item.id) {
              for nm.items.each |item| {
                  cx.rmap.insert(item.id);
              }
          }
      }
      item_fn(_, _, _, ref generics, ref blk) => {
        if generics.ty_params.len() > 0u ||
           attr::find_inline_attr(item.attrs) != attr::ia_none {
            traverse_inline_body(cx, blk);
        }
      }
      item_impl(ref generics, _, _, ref ms) => {
        for ms.each |m| {
            if generics.ty_params.len() > 0u ||
                m.generics.ty_params.len() > 0u ||
                attr::find_inline_attr(m.attrs) != attr::ia_none
            {
                cx.rmap.insert(m.id);
                traverse_inline_body(cx, &m.body);
            }
        }
      }
      item_struct(ref struct_def, ref generics) => {
        for struct_def.ctor_id.each |&ctor_id| {
            cx.rmap.insert(ctor_id);
        }
        for struct_def.dtor.each |dtor| {
            cx.rmap.insert(dtor.node.id);
            if generics.ty_params.len() > 0u ||
                attr::find_inline_attr(dtor.node.attrs) != attr::ia_none
            {
                traverse_inline_body(cx, &dtor.node.body);
            }
        }
      }
      item_ty(t, _) => {
        traverse_ty(t, cx,
                    visit::mk_vt(@visit::Visitor {visit_ty: traverse_ty,
                                                  ..*visit::default_visitor()}))
      }
      item_const(*) |
      item_enum(*) | item_trait(*) => (),
      item_mac(*) => fail!(~"item macros unimplemented")
    }
}

fn traverse_ty<'a, 'b>(ty: @Ty, cx: &'b ctx<'a>, v: visit::vt<&'b ctx<'a>>) {
    // XXX: it shouldn't be necessary to do this
    let rmap: &mut HashSet<node_id> = cx.rmap;
    if rmap.contains(&ty.id) { return; }
    rmap.insert(ty.id);

    match ty.node {
      ty_path(p, p_id) => {
        match cx.tcx.def_map.find(&p_id) {
          // Kind of a hack to check this here, but I'm not sure what else
          // to do
          Some(&def_prim_ty(_)) => { /* do nothing */ }
          Some(&d) => traverse_def_id(cx, def_id_of_def(d)),
          None    => { /* do nothing -- but should we fail here? */ }
        }
        for p.types.each |t| {
            (v.visit_ty)(*t, cx, v);
        }
      }
      _ => visit::visit_ty(ty, cx, v)
    }
}

fn traverse_inline_body(cx: &ctx, body: &blk) {
    fn traverse_expr<'a, 'b>(e: @expr, cx: &'b ctx<'a>,
                             v: visit::vt<&'b ctx<'a>>) {
        match e.node {
          expr_path(_) => {
            match cx.tcx.def_map.find(&e.id) {
                Some(&d) => {
                  traverse_def_id(cx, def_id_of_def(d));
                }
                None      => cx.tcx.sess.span_bug(e.span, fmt!("Unbound node \
                  id %? while traversing %s", e.id,
                  expr_to_str(e, cx.tcx.sess.intr())))
            }
          }
          expr_field(_, _, _) => {
            match cx.method_map.find(&e.id) {
              Some(&typeck::method_map_entry {
                  origin: typeck::method_static(did),
                  _
                }) => {
                traverse_def_id(cx, did);
              }
              _ => ()
            }
          }
          expr_method_call(*) => {
            match cx.method_map.find(&e.id) {
              Some(&typeck::method_map_entry {
                  origin: typeck::method_static(did),
                  _
                }) => {
                traverse_def_id(cx, did);
              }
              Some(_) => {}
              None => {
                cx.tcx.sess.span_bug(e.span, ~"expr_method_call not in \
                                               method map");
              }
            }
          }
          _ => ()
        }
        visit::visit_expr(e, cx, v);
    }
    // Don't ignore nested items: for example if a generic fn contains a
    // generic impl (as in deque::create), we need to monomorphize the
    // impl as well
    fn traverse_item(i: @item, cx: &ctx, _v: visit::vt<&ctx>) {
      traverse_public_item(cx, i);
    }
    visit::visit_block(body, cx, visit::mk_vt(@visit::Visitor {
        visit_expr: traverse_expr,
        visit_item: traverse_item,
         ..*visit::default_visitor()
    }));
}

fn traverse_all_resources_and_impls(cx: &ctx, crate_mod: &_mod) {
    visit::visit_mod(
        crate_mod,
        codemap::dummy_sp(),
        0,
        cx,
        visit::mk_vt(@visit::Visitor {
            visit_expr: |_e, _cx, _v| { },
            visit_item: |i, cx, v| {
                visit::visit_item(i, cx, v);
                match i.node {
                    item_struct(sdef, _) if sdef.dtor.is_some() => {
                        traverse_public_item(cx, i);
                    }
                    item_impl(*) => {
                        traverse_public_item(cx, i);
                    }
                    _ => ()
                }
            },
            ..*visit::default_visitor()
        }));
}

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

// Finds items that are externally reachable, to determine which items
// need to have their metadata (and possibly their AST) serialized.
// All items that can be referred to through an exported name are
// reachable, and when a reachable thing is inline or generic, it
// makes all other generics or inline functions that it references
// reachable as well.

use middle::resolve;
use middle::ty;
use middle::typeck;

use core::prelude::*;
use core::hashmap::HashSet;
use syntax::ast;
use syntax::ast::*;
use syntax::ast_util::def_id_of_def;
use syntax::attr;
use syntax::codemap;
use syntax::print::pprust::expr_to_str;
use syntax::{visit, ast_map};

pub type map = @HashSet<node_id>;

struct ctx<'self> {
    exp_map2: resolve::ExportMap2,
    tcx: ty::ctxt,
    method_map: typeck::method_map,
    rmap: &'self mut HashSet<node_id>,
}

pub fn find_reachable(crate_mod: &_mod, exp_map2: resolve::ExportMap2,
                      tcx: ty::ctxt, method_map: typeck::method_map) -> map {
    let mut rmap = HashSet::new();
    {
        let cx = ctx {
            exp_map2: exp_map2,
            tcx: tcx,
            method_map: method_map,
            rmap: &mut rmap
        };
        traverse_public_mod(&cx, ast::crate_node_id, crate_mod);
        traverse_all_resources_and_impls(&cx, crate_mod);
    }
    return @rmap;
}

fn traverse_exports(cx: &ctx, mod_id: node_id) -> bool {
    let mut found_export = false;
    match cx.exp_map2.find(&mod_id) {
      Some(ref exp2s) => {
        for (*exp2s).each |e2| {
            found_export = true;
            traverse_def_id(cx, e2.def_id)
        };
      }
      None => ()
    }
    return found_export;
}

fn traverse_def_id(cx: &ctx, did: def_id) {
    if did.crate != local_crate { return; }
    match cx.tcx.items.find(&did.node) {
        None => (), // This can happen for self, for example
        Some(&ast_map::node_item(item, _)) => traverse_public_item(cx, item),
        Some(&ast_map::node_method(_, impl_id, _)) => traverse_def_id(cx, impl_id),
        Some(&ast_map::node_foreign_item(item, _, _, _)) => {
            cx.rmap.insert(item.id);
        }
        Some(&ast_map::node_variant(ref v, _, _)) => {
            cx.rmap.insert(v.node.id);
        }
        _ => ()
    }
}

fn traverse_public_mod(cx: &ctx, mod_id: node_id, m: &_mod) {
    if !traverse_exports(cx, mod_id) {
        // No exports, so every local item is exported
        for m.items.each |item| {
            traverse_public_item(cx, *item);
        }
    }
}

fn traverse_public_item(cx: &ctx, item: @item) {
    // FIXME #6021: naming rmap shouldn't be necessary
    let rmap: &mut HashSet<node_id> = cx.rmap;
    if rmap.contains(&item.id) { return; }
    rmap.insert(item.id);
    match item.node {
      item_mod(ref m) => traverse_public_mod(cx, item.id, m),
      item_foreign_mod(ref nm) => {
          if !traverse_exports(cx, item.id) {
              for nm.items.each |item| {
                  cx.rmap.insert(item.id);
              }
          }
      }
      item_fn(_, _, _, ref generics, ref blk) => {
        if generics.ty_params.len() > 0u ||
           attr::find_inline_attr(item.attrs) != attr::ia_none {
            traverse_inline_body(cx, blk);
        }
      }
      item_impl(ref generics, _, _, ref ms) => {
        for ms.each |m| {
            if generics.ty_params.len() > 0u ||
                m.generics.ty_params.len() > 0u ||
                attr::find_inline_attr(m.attrs) != attr::ia_none
            {
                cx.rmap.insert(m.id);
                traverse_inline_body(cx, &m.body);
            }
        }
      }
      item_struct(ref struct_def, ref generics) => {
        for struct_def.ctor_id.each |&ctor_id| {
            cx.rmap.insert(ctor_id);
        }
        for struct_def.dtor.each |dtor| {
            cx.rmap.insert(dtor.node.id);
            if generics.ty_params.len() > 0u ||
                attr::find_inline_attr(dtor.node.attrs) != attr::ia_none
            {
                traverse_inline_body(cx, &dtor.node.body);
            }
        }
      }
      item_ty(t, _) => {
        traverse_ty(t, cx,
                    visit::mk_vt(@visit::Visitor {visit_ty: traverse_ty,
                                                  ..*visit::default_visitor()}))
      }
      item_const(*) |
      item_enum(*) | item_trait(*) => (),
      item_mac(*) => fail!(~"item macros unimplemented")
    }
}

fn traverse_ty<'a, 'b>(ty: @Ty, cx: &'b ctx<'a>, v: visit::vt<&'b ctx<'a>>) {
    // FIXME #6021: naming rmap shouldn't be necessary
    let rmap: &mut HashSet<node_id> = cx.rmap;
    if rmap.contains(&ty.id) { return; }
    rmap.insert(ty.id);

    match ty.node {
      ty_path(p, p_id) => {
        match cx.tcx.def_map.find(&p_id) {
          // Kind of a hack to check this here, but I'm not sure what else
          // to do
          Some(&def_prim_ty(_)) => { /* do nothing */ }
          Some(&d) => traverse_def_id(cx, def_id_of_def(d)),
          None    => { /* do nothing -- but should we fail here? */ }
        }
        for p.types.each |t| {
            (v.visit_ty)(*t, cx, v);
        }
      }
      _ => visit::visit_ty(ty, cx, v)
    }
}

fn traverse_inline_body(cx: &ctx, body: &blk) {
    fn traverse_expr<'a, 'b>(e: @expr, cx: &'b ctx<'a>,
                             v: visit::vt<&'b ctx<'a>>) {
        match e.node {
          expr_path(_) => {
            match cx.tcx.def_map.find(&e.id) {
                Some(&d) => {
                  traverse_def_id(cx, def_id_of_def(d));
                }
                None      => cx.tcx.sess.span_bug(e.span, fmt!("Unbound node \
                  id %? while traversing %s", e.id,
                  expr_to_str(e, cx.tcx.sess.intr())))
            }
          }
          expr_field(_, _, _) => {
            match cx.method_map.find(&e.id) {
              Some(&typeck::method_map_entry {
                  origin: typeck::method_static(did),
                  _
                }) => {
                traverse_def_id(cx, did);
              }
              _ => ()
            }
          }
          expr_method_call(*) => {
            match cx.method_map.find(&e.id) {
              Some(&typeck::method_map_entry {
                  origin: typeck::method_static(did),
                  _
                }) => {
                traverse_def_id(cx, did);
              }
              Some(_) => {}
              None => {
                cx.tcx.sess.span_bug(e.span, ~"expr_method_call not in \
                                               method map");
              }
            }
          }
          _ => ()
        }
        visit::visit_expr(e, cx, v);
    }
    // Don't ignore nested items: for example if a generic fn contains a
    // generic impl (as in deque::create), we need to monomorphize the
    // impl as well
    fn traverse_item(i: @item, cx: &ctx, _v: visit::vt<&ctx>) {
      traverse_public_item(cx, i);
    }
    visit::visit_block(body, cx, visit::mk_vt(@visit::Visitor {
        visit_expr: traverse_expr,
        visit_item: traverse_item,
         ..*visit::default_visitor()
    }));
}

fn traverse_all_resources_and_impls(cx: &ctx, crate_mod: &_mod) {
    visit::visit_mod(
        crate_mod,
        codemap::dummy_sp(),
        0,
        cx,
        visit::mk_vt(@visit::Visitor {
            visit_expr: |_e, _cx, _v| { },
            visit_item: |i, cx, v| {
                visit::visit_item(i, cx, v);
                match i.node {
                    item_struct(sdef, _) if sdef.dtor.is_some() => {
                        traverse_public_item(cx, i);
                    }
                    item_impl(*) => {
                        traverse_public_item(cx, i);
                    }
                    _ => ()
                }
            },
            ..*visit::default_visitor()
        }));
}

<|endoftext|>


<commit_before>#![crate_name = "platform"]
#![crate_type = "rlib"]
#![no_std]
#![feature(const_fn)]

extern crate common;
extern crate drivers;
extern crate hil;
extern crate sam4l;

use hil::Controller;
use drivers::timer::AlarmToTimer;
use drivers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};

// Uncomment each module to test with respective commented out code block in
// `init`
//
//mod gpio_dummy;
//mod spi_dummy;

pub struct Firestorm {
    chip: sam4l::chip::Sam4l,
    console: &'static drivers::console::Console<'static, sam4l::usart::USART>,
    gpio: drivers::gpio::GPIO<[&'static hil::gpio::GPIOPin; 14]>,
    tmp006: &'static drivers::tmp006::TMP006<'static, sam4l::i2c::I2CDevice>,
}

impl Firestorm {
    pub unsafe fn service_pending_interrupts(&mut self) {
        self.chip.service_pending_interrupts()
    }

    pub unsafe fn has_pending_interrupts(&mut self) -> bool {
        self.chip.has_pending_interrupts()
    }

    #[inline(never)]
    pub fn with_driver<F, R>(&mut self, driver_num: usize, f: F) -> R where
            F: FnOnce(Option<&hil::Driver>) -> R {

        match driver_num {
            0 => f(Some(self.console)),
            1 => f(Some(&self.gpio)),
            2 => f(Some(self.tmp006)),
            _ => f(None)
        }
    }
}

pub unsafe fn init<'a>() -> &'a mut Firestorm {
    use core::mem;

    static mut FIRESTORM_BUF : [u8; 1024] = [0; 1024];
    static mut CONSOLE_BUF : [u8; 1024] = [0; 1024];
    static mut TIMER_BUF : [u8; 1024] = [0; 1024];
    static mut MUX_ALARM_BUF : [u8; 256] = [0; 256];
    static mut VIRT_ALARM_BUF : [u8; 256] = [0; 256];
    static mut TMP006_BUF : [u8; 1028] = [0; 1028];

    /* TODO(alevy): replace above line with this. Currently, over allocating to make development
     * easier, but should be obviated when `size_of` at compile time hits.
    static mut FIRESTORM_BUF : [u8; 192] = [0; 192];
    // Just test that FIRESTORM_BUF is correct size
    // (will throw compiler error if too large or small)
    let _ : Firestorm = mem::transmute(FIRESTORM_BUF);
    let _ : Firestorm = mem::transmute(CONSOLE_BUF);
    */

    let ast = &sam4l::ast::AST;
    ast.select_clock(sam4l::ast::Clock::ClockRCSys);
    ast.set_prescalar(0);
    ast.clear_alarm();

    let console : &mut drivers::console::Console<sam4l::usart::USART> = mem::transmute(&mut CONSOLE_BUF);
    *console = drivers::console::Console::new(&sam4l::usart::USART3);

    let mut mux_alarm : &mut MuxAlarm<'static, sam4l::ast::Ast> = mem::transmute(&mut MUX_ALARM_BUF);
    *mux_alarm = MuxAlarm::new(ast);
    ast.configure(mux_alarm);

    let mut virtual_alarm : &mut VirtualMuxAlarm<'static, sam4l::ast::Ast> = mem::transmute(&mut VIRT_ALARM_BUF);
    *virtual_alarm = VirtualMuxAlarm::new(mux_alarm);

    let mut timer : &mut AlarmToTimer<'static, VirtualMuxAlarm<'static, sam4l::ast::Ast>> = mem::transmute(&mut TIMER_BUF);
    *timer = AlarmToTimer::new(virtual_alarm);
    virtual_alarm.set_client(timer);

    let tmp006 : &mut drivers::tmp006::TMP006<'static, sam4l::i2c::I2CDevice> = mem::transmute(&mut TMP006_BUF);
    *tmp006 = drivers::tmp006::TMP006::new(&sam4l::i2c::I2C2, timer);

    timer.set_client(tmp006);

    sam4l::usart::USART3.set_client(&*console);

    let firestorm : &'static mut Firestorm = mem::transmute(&mut FIRESTORM_BUF);
    *firestorm = Firestorm {
        chip: sam4l::chip::Sam4l::new(),
        console: &*console,
        gpio: drivers::gpio::GPIO::new(
            [ &sam4l::gpio::PC[10], &sam4l::gpio::PC[19]
            , &sam4l::gpio::PC[13], &sam4l::gpio::PA[9]
            , &sam4l::gpio::PA[17], &sam4l::gpio::PC[20]
            , &sam4l::gpio::PA[19], &sam4l::gpio::PA[14]
            , &sam4l::gpio::PA[16], &sam4l::gpio::PA[13]
            , &sam4l::gpio::PA[11], &sam4l::gpio::PA[10]
            , &sam4l::gpio::PA[12], &sam4l::gpio::PC[09]]),
        tmp006: &*tmp006
    };

    sam4l::usart::USART3.configure(sam4l::usart::USARTParams {
        //client: &console,
        baud_rate: 115200,
        data_bits: 8,
        parity: hil::uart::Parity::None
    });

    sam4l::gpio::PB[09].configure(Some(sam4l::gpio::PeripheralFunction::A));
    sam4l::gpio::PB[10].configure(Some(sam4l::gpio::PeripheralFunction::A));

    sam4l::gpio::PA[21].configure(Some(sam4l::gpio::PeripheralFunction::E));
    sam4l::gpio::PA[22].configure(Some(sam4l::gpio::PeripheralFunction::E));

    // Configure SPI pins: CLK, MISO, MOSI, CS3
    sam4l::gpio::PC[ 6].configure(Some(sam4l::gpio::PeripheralFunction::A));
    sam4l::gpio::PC[ 4].configure(Some(sam4l::gpio::PeripheralFunction::A));
    sam4l::gpio::PC[ 5].configure(Some(sam4l::gpio::PeripheralFunction::A));
    sam4l::gpio::PC[ 1].configure(Some(sam4l::gpio::PeripheralFunction::A));

    // Uncommenting the following line will cause the device to write
    // [8, 7, 6, 5, 4, 3, 2, 1] once over the SPI then echo the 8 bytes read
    // from the slave continuously.
    //spi_dummy::spi_dummy_test();

    // Uncommenting the following line will toggle the LED whenever the value of
    // Firestorm's pin 8 changes value (e.g., connect a push button to pin 8 and
    // press toggle it).
    //gpio_dummy::gpio_dummy_test();

    firestorm.console.initialize();

    firestorm
}

<commit_msg>Macro-ize static initialization code for Firestorm<commit_after>#![crate_name = "platform"]
#![crate_type = "rlib"]
#![no_std]
#![feature(const_fn)]

extern crate common;
extern crate drivers;
extern crate hil;
extern crate sam4l;

use hil::Controller;
use drivers::timer::AlarmToTimer;
use drivers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};

// Uncomment each module to test with respective commented out code block in
// `init`
//
//mod gpio_dummy;
//mod spi_dummy;

pub struct Firestorm {
    chip: sam4l::chip::Sam4l,
    console: &'static drivers::console::Console<'static, sam4l::usart::USART>,
    gpio: drivers::gpio::GPIO<[&'static hil::gpio::GPIOPin; 14]>,
    tmp006: &'static drivers::tmp006::TMP006<'static, sam4l::i2c::I2CDevice>,
}

impl Firestorm {
    pub unsafe fn service_pending_interrupts(&mut self) {
        self.chip.service_pending_interrupts()
    }

    pub unsafe fn has_pending_interrupts(&mut self) -> bool {
        self.chip.has_pending_interrupts()
    }

    #[inline(never)]
    pub fn with_driver<F, R>(&mut self, driver_num: usize, f: F) -> R where
            F: FnOnce(Option<&hil::Driver>) -> R {

        match driver_num {
            0 => f(Some(self.console)),
            1 => f(Some(&self.gpio)),
            2 => f(Some(self.tmp006)),
            _ => f(None)
        }
    }
}

macro_rules! static_init {
   ($V:ident : $T:ty = $e:expr) => {
        let $V : &mut $T = {
            // Waiting out for size_of to be available at compile-time to avoid
            // hardcoding an abitrary large size...
            static mut BUF : [u8; 1024] = [0; 1024];
            let mut tmp : &mut $T = mem::transmute(&mut BUF);
            *tmp = $e;
            tmp
        };
   }
}

pub unsafe fn init<'a>() -> &'a mut Firestorm {
    use core::mem;

    static_init!(console : drivers::console::Console<sam4l::usart::USART> =
                    drivers::console::Console::new(&sam4l::usart::USART3));

    let ast = &sam4l::ast::AST;
    ast.select_clock(sam4l::ast::Clock::ClockRCSys);
    ast.set_prescalar(0);
    ast.clear_alarm();
    static_init!(mux_alarm : MuxAlarm<'static, sam4l::ast::Ast> =
                    MuxAlarm::new(&sam4l::ast::AST));
    ast.configure(mux_alarm);

    static_init!(virtual_alarm : VirtualMuxAlarm<'static, sam4l::ast::Ast> =
                    VirtualMuxAlarm::new(mux_alarm));

    static_init!(timer : AlarmToTimer<'static,
                                VirtualMuxAlarm<'static, sam4l::ast::Ast>> =
                            AlarmToTimer::new(virtual_alarm));
    virtual_alarm.set_client(timer);

    static_init!(tmp006 : drivers::tmp006::TMP006<'static,
                                sam4l::i2c::I2CDevice> =
                    drivers::tmp006::TMP006::new(&sam4l::i2c::I2C2, timer));
    timer.set_client(tmp006);

    sam4l::usart::USART3.set_client(console);

    static_init!(firestorm : Firestorm = Firestorm {
        chip: sam4l::chip::Sam4l::new(),
        console: &*console,
        gpio: drivers::gpio::GPIO::new(
            [ &sam4l::gpio::PC[10], &sam4l::gpio::PC[19]
            , &sam4l::gpio::PC[13], &sam4l::gpio::PA[9]
            , &sam4l::gpio::PA[17], &sam4l::gpio::PC[20]
            , &sam4l::gpio::PA[19], &sam4l::gpio::PA[14]
            , &sam4l::gpio::PA[16], &sam4l::gpio::PA[13]
            , &sam4l::gpio::PA[11], &sam4l::gpio::PA[10]
            , &sam4l::gpio::PA[12], &sam4l::gpio::PC[09]]),
        tmp006: &*tmp006
    });

    sam4l::usart::USART3.configure(sam4l::usart::USARTParams {
        //client: &console,
        baud_rate: 115200,
        data_bits: 8,
        parity: hil::uart::Parity::None
    });

    sam4l::gpio::PB[09].configure(Some(sam4l::gpio::PeripheralFunction::A));
    sam4l::gpio::PB[10].configure(Some(sam4l::gpio::PeripheralFunction::A));

    sam4l::gpio::PA[21].configure(Some(sam4l::gpio::PeripheralFunction::E));
    sam4l::gpio::PA[22].configure(Some(sam4l::gpio::PeripheralFunction::E));

    // Configure SPI pins: CLK, MISO, MOSI, CS3
    sam4l::gpio::PC[ 6].configure(Some(sam4l::gpio::PeripheralFunction::A));
    sam4l::gpio::PC[ 4].configure(Some(sam4l::gpio::PeripheralFunction::A));
    sam4l::gpio::PC[ 5].configure(Some(sam4l::gpio::PeripheralFunction::A));
    sam4l::gpio::PC[ 1].configure(Some(sam4l::gpio::PeripheralFunction::A));

    // Uncommenting the following line will cause the device to write
    // [8, 7, 6, 5, 4, 3, 2, 1] once over the SPI then echo the 8 bytes read
    // from the slave continuously.
    //spi_dummy::spi_dummy_test();

    // Uncommenting the following line will toggle the LED whenever the value of
    // Firestorm's pin 8 changes value (e.g., connect a push button to pin 8 and
    // press toggle it).
    //gpio_dummy::gpio_dummy_test();

    firestorm.console.initialize();

    firestorm
}

<|endoftext|>


<commit_before>use std::vec::IntoIter;

use clap::ArgMatches;
use regex::Regex;

use module::{CommandEnv, CommandResult, Module, ModuleError};
use module::bm::header::{build_header, get_tags_from_header};
use runtime::Runtime;
use storage::backend::StorageBackendError;
use storage::file::File;
use storage::json::parser::JsonHeaderParser;
use storage::parser::Parser;
use ui::file::{FilePrinter, TablePrinter};

pub fn add_command(module: &Module, env: CommandEnv) -> CommandResult {
    use url::Url;

    let url = env.matches.value_of("url").unwrap();

    if let Err(e) = Url::parse(url) {
        info!("Not an URL: '{}'", url);
        info!("  this will turn into an hard error before 0.1.0");
        debug!("URL parsing error: {:?}", e);
    }

    let tags = get_tags(env.rt, env.matches);
    info!("Adding url '{}' with tags '{:?}'", url, tags);

    let header  = build_header(&String::from(url), &tags);
    let file    = File::new_with_header(module, header);
    let parser  = Parser::new(JsonHeaderParser::new(None));
    let putres  = env.bk.put_file(file, &parser);

    putres.map_err(|sberr| {
        let mut err = ModuleError::new("Storage Backend Error");
        err.caused_by = Some(Box::new(sberr));
        err
    })
}

pub fn list_command(module: &Module, env: CommandEnv) -> CommandResult {
    let printer = TablePrinter::new(env.rt.is_verbose(), env.rt.is_debugging());
    let files   = get_filtered_files_from_backend(module, &env);

    debug!("Printing files now");
    files.map(|f| printer.print_files(f));

    Ok(())
}

pub fn remove_command(module: &Module, env: CommandEnv) -> CommandResult {
    let checked : bool = run_removal_checking(&env);
    debug!("Checked mode: {}", checked);
    if let Some(id) = get_id(env.rt, env.matches) {
        debug!("Remove by id: {}", id);

        let parser = Parser::new(JsonHeaderParser::new(None));
        let file = env.bk
            .get_file_by_id(module, &id.into(), &parser)
            .unwrap_or({
                info!("No files found");
                return Ok(())
            });

        debug!("Remove file: {:?}", file);

        if let Err(e) = env.bk.remove_file(module, file, checked) {
            debug!("Remove failed");
            let mut err = ModuleError::new("Removing file failed");
            err.caused_by = Some(Box::new(e));
            Err(err)
        } else {
            info!("Remove worked");
            Ok(())
        }
    } else {
        debug!("Remove more than one file");

        get_filtered_files_from_backend(module, &env).and_then(|files| {
            let nfiles = files.len();
            info!("Removing {} Files", nfiles);

            let errs = files.map(|file| {
                    debug!("Remove file: {:?}", file);
                    env.bk.remove_file(module, file, checked)
                })
                .filter(|e| e.is_err())
                .map(|e| {
                    let err = e.err().unwrap();
                    warn!("Error occured in Filesystem operation: {}", err);
                    err
                })
                .collect::<Vec<StorageBackendError>>();

            let nerrs = errs.len();

            if nerrs != 0 {
                warn!("{} Errors occured while removing {} files", nerrs, nfiles);
                let moderr = ModuleError::new("File removal failed");

                // TODO : Collect StorageBackendErrors

                Err(moderr)
            } else {
                Ok(())
            }
        })
    }
}

/*
 *
 * Private helpers
 *
 */

fn get_filtered_files_from_backend<'a>(module: &'a Module,
                                       env: &CommandEnv)
    -> Result<IntoIter<File<'a>>, ModuleError>
{
    let parser = Parser::new(JsonHeaderParser::new(None));
    let tags = get_tags(env.rt, env.matches);
    debug!("Tags: {:?}", tags);
    env.bk.iter_files(module, &parser)
        .map(|files| {
            let f = files.filter(|file| {
                debug!("Backend returns file: {:?}", file);
                if tags.len() != 0 {
                    debug!("Checking tags of: {:?}", file.id());
                    get_tags_from_header(&file.header()).iter()
                        .any(|t| tags.contains(t))
                } else {
                    true
                }
            }).filter(|file| {
                debug!("Checking matches of: {:?}", file.id());
                get_matcher(env.rt, env.matches)
                    .and_then(|r| Some(file.matches_with(&r)))
                    .unwrap_or(true)
            }).collect::<Vec<File>>();
            f.into_iter()
        }).map_err(|e| {
            debug!("Error from Backend: {:?}", e);
            let mut merr = ModuleError::new("Could not filter files");
            merr.caused_by = Some(Box::new(e));
            merr
        })
}

fn get_tags<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Vec<String> {

    fn reject_if_with_spaces(e: &String) -> bool {
        if e.contains(" ") {
            warn!("Tag contains spaces: '{}'", e);
            false
        } else {
            true
        }
    }

    debug!("Fetching tags from commandline");
    sub.value_of("tags").and_then(|tags| {
        Some(tags.split(",")
                 .into_iter()
                 .map(|s| s.to_string())
                 .filter(|e| reject_if_with_spaces(e))
                 .collect()
          )
    }).or(Some(vec![])).unwrap()
}

fn get_matcher<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Option<Regex> {
    debug!("Fetching matcher from commandline");
    if let Some(s) = sub.value_of("match") {
        if let Ok(r) = Regex::new(s) {
            return Some(r)
        } else {
            error!("Regex error, continuing without regex");
        }
    }
    None

}

fn get_id<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Option<String> {
    debug!("Fetching id from commandline");
    sub.value_of("id").and_then(|s| Some(String::from(s)))
}

/*
 * Checks whether the commandline call was set to run the removal "checked",
 * so if another entry from the store refers to this ID, do not remove the file.
 */
fn run_removal_checking(env: &CommandEnv) -> bool {
    env.matches.is_present("check")
}
<commit_msg>bm: remove_command: Refactor into sub-functions<commit_after>use std::vec::IntoIter;

use clap::ArgMatches;
use regex::Regex;

use module::{CommandEnv, CommandResult, Module, ModuleError};
use module::bm::header::{build_header, get_tags_from_header};
use runtime::Runtime;
use storage::backend::StorageBackendError;
use storage::file::File;
use storage::json::parser::JsonHeaderParser;
use storage::parser::Parser;
use ui::file::{FilePrinter, TablePrinter};

pub fn add_command(module: &Module, env: CommandEnv) -> CommandResult {
    use url::Url;

    let url = env.matches.value_of("url").unwrap();

    if let Err(e) = Url::parse(url) {
        info!("Not an URL: '{}'", url);
        info!("  this will turn into an hard error before 0.1.0");
        debug!("URL parsing error: {:?}", e);
    }

    let tags = get_tags(env.rt, env.matches);
    info!("Adding url '{}' with tags '{:?}'", url, tags);

    let header  = build_header(&String::from(url), &tags);
    let file    = File::new_with_header(module, header);
    let parser  = Parser::new(JsonHeaderParser::new(None));
    let putres  = env.bk.put_file(file, &parser);

    putres.map_err(|sberr| {
        let mut err = ModuleError::new("Storage Backend Error");
        err.caused_by = Some(Box::new(sberr));
        err
    })
}

pub fn list_command(module: &Module, env: CommandEnv) -> CommandResult {
    let printer = TablePrinter::new(env.rt.is_verbose(), env.rt.is_debugging());
    let files   = get_filtered_files_from_backend(module, &env);

    debug!("Printing files now");
    files.map(|f| printer.print_files(f));

    Ok(())
}

pub fn remove_command(module: &Module, env: CommandEnv) -> CommandResult {
    fn remove_by_id(module: &Module, env: CommandEnv, id: String, checked: bool) -> CommandResult {
        let parser = Parser::new(JsonHeaderParser::new(None));
        let file = env.bk
            .get_file_by_id(module, &id.into(), &parser)
            .unwrap_or({
                info!("No files found");
                return Ok(())
            });

        debug!("Remove file: {:?}", file);

        if let Err(e) = env.bk.remove_file(module, file, checked) {
            debug!("Remove failed");
            let mut err = ModuleError::new("Removing file failed");
            err.caused_by = Some(Box::new(e));
            Err(err)
        } else {
            info!("Remove worked");
            Ok(())
        }
    }

    fn remove_by_filtering(module: &Module, env: CommandEnv, checked: bool) -> CommandResult {
        get_filtered_files_from_backend(module, &env).and_then(|files| {
            let nfiles = files.len();
            info!("Removing {} Files", nfiles);

            let errs = files.map(|file| {
                    debug!("Remove file: {:?}", file);
                    env.bk.remove_file(module, file, checked)
                })
                .filter(|e| e.is_err())
                .map(|e| {
                    let err = e.err().unwrap();
                    warn!("Error occured in Filesystem operation: {}", err);
                    err
                })
                .collect::<Vec<StorageBackendError>>();

            let nerrs = errs.len();

            if nerrs != 0 {
                warn!("{} Errors occured while removing {} files", nerrs, nfiles);
                let moderr = ModuleError::new("File removal failed");

                // TODO : Collect StorageBackendErrors

                Err(moderr)
            } else {
                Ok(())
            }
        })
    }

    let checked : bool = run_removal_checking(&env);
    debug!("Checked mode: {}", checked);

    if let Some(id) = get_id(env.rt, env.matches) {
        debug!("Remove by id: {}", id);
        remove_by_id(module, env, id, checked)
    } else {
        debug!("Remove more than one file");
        remove_by_filtering(module, env, checked)
    }
}

/*
 *
 * Private helpers
 *
 */

fn get_filtered_files_from_backend<'a>(module: &'a Module,
                                       env: &CommandEnv)
    -> Result<IntoIter<File<'a>>, ModuleError>
{
    let parser = Parser::new(JsonHeaderParser::new(None));
    let tags = get_tags(env.rt, env.matches);
    debug!("Tags: {:?}", tags);
    env.bk.iter_files(module, &parser)
        .map(|files| {
            let f = files.filter(|file| {
                debug!("Backend returns file: {:?}", file);
                if tags.len() != 0 {
                    debug!("Checking tags of: {:?}", file.id());
                    get_tags_from_header(&file.header()).iter()
                        .any(|t| tags.contains(t))
                } else {
                    true
                }
            }).filter(|file| {
                debug!("Checking matches of: {:?}", file.id());
                get_matcher(env.rt, env.matches)
                    .and_then(|r| Some(file.matches_with(&r)))
                    .unwrap_or(true)
            }).collect::<Vec<File>>();
            f.into_iter()
        }).map_err(|e| {
            debug!("Error from Backend: {:?}", e);
            let mut merr = ModuleError::new("Could not filter files");
            merr.caused_by = Some(Box::new(e));
            merr
        })
}

fn get_tags<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Vec<String> {

    fn reject_if_with_spaces(e: &String) -> bool {
        if e.contains(" ") {
            warn!("Tag contains spaces: '{}'", e);
            false
        } else {
            true
        }
    }

    debug!("Fetching tags from commandline");
    sub.value_of("tags").and_then(|tags| {
        Some(tags.split(",")
                 .into_iter()
                 .map(|s| s.to_string())
                 .filter(|e| reject_if_with_spaces(e))
                 .collect()
          )
    }).or(Some(vec![])).unwrap()
}

fn get_matcher<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Option<Regex> {
    debug!("Fetching matcher from commandline");
    if let Some(s) = sub.value_of("match") {
        if let Ok(r) = Regex::new(s) {
            return Some(r)
        } else {
            error!("Regex error, continuing without regex");
        }
    }
    None

}

fn get_id<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Option<String> {
    debug!("Fetching id from commandline");
    sub.value_of("id").and_then(|s| Some(String::from(s)))
}

/*
 * Checks whether the commandline call was set to run the removal "checked",
 * so if another entry from the store refers to this ID, do not remove the file.
 */
fn run_removal_checking(env: &CommandEnv) -> bool {
    env.matches.is_present("check")
}
<|endoftext|>