<commit_before>use uuid::Uuid;
use std::io;

pub struct Packet {
    id: i32,
    data: Vec<Field>,
    buf: Vec<u8>
}

#[derive(Debug, Clone)]
enum Field {
    Boolean(bool),
    Byte(i8),
    UByte(u8),
    Short(i16),
    UShort(u16),
    Int(i32),
    Long(i64),
    Float(f32),
    Double(f64),
    String(String),
    Chat(String),
    VarInt(i32),
    VarLong(i64),
    //TODO: Chunk Section, Entity Metadata, Slot, NBT Tag, Byte Array, Optional X, Array of X, X Enum
    Position {
        x: i32,
        y: i16,
        z: i32
    },
    Angle(i8),
    UUID(Uuid)
}

pub enum PacketType {
    HandshakingOut(HandshakingOut),
    PlayIn(PlayIn),
    PlayOut(PlayOut),
    StatusIn(StatusIn),
    StatusOut(StatusOut),
    LoginIn(LoginIn),
    LoginOut(LoginOut)
}

/// Client -> Server (Play)
pub enum HandshakingOut {
    Handshake = 0x00,
    LegacyServerListPing = 0xFE
}

/// Server -> Client (Play)
pub enum PlayIn {
    SpawnObject = 0x00,
    SpawnExpOrb = 0x01,
    SpawnGlobalEntity = 0x02,
    SpawnMob = 0x03,
    SpawnPainting = 0x04,
    SpawnPlayer = 0x05,
    Animation = 0x06,
    Statistics = 0x07,
    BlockBreakAnimation = 0x08,
    UpdateBlockEntity = 0x09,
    BlockAction = 0x0A,
    BlockChange = 0x0B,
    BossBar = 0x0C,
    ServerDifficulty = 0x0D,
    TabComplete = 0x0E,
    ChatMessage = 0x0F,
    MultiBlockChange = 0x10,
    ConfirmTransaction = 0x11,
    CloseWindow = 0x12,
    OpenWindow = 0x13,
    WindowItems = 0x14,
    WindowProperty = 0x15,
    SetSlot = 0x16,
    SetCooldown = 0x17,
    PluginMessage = 0x18,
    NamedSoundEffect = 0x19,
    Disconnect = 0x1A,
    EntityStatus = 0x1B,
    Explosion = 0x1C,
    UnloadChunk = 0x1D,
    ChangeGameState = 0x1E,
    KeepAlive = 0x1F,
    ChunkData = 0x20,
    Effect = 0x21,
    Particle = 0x22,
    JoinGame = 0x23,
    Map = 0x24,
    EntityRelativeMove = 0x25,
    EntityLookRelativeMove = 0x26,
    EntityLook = 0x27,
    Entity = 0x28,
    VehicleMove = 0x29,
    OpenSignEditor = 0x2A,
    PlayerAbilities = 0x2B,
    CombatEvent = 0x2C,
    PlayerListItem = 0x2D,
    PlayerPositionLook = 0x2E,
    UseBed = 0x2F,
    DestroyEntities = 0x30,
    RemoveEntityEffect = 0x31,
    ResourcePackSend = 0x32,
    Respawn = 0x33,
    EntityHeadLook = 0x34,
    WorldBorder = 0x35,
    Camera = 0x36,
    HeldItemChange = 0x37,
    DisplayScoreboard = 0x38,
    EntityMetadata = 0x39,
    AttachEntity = 0x3A,
    EntityVelocity = 0x3B,
    EntityEquipment = 0x3C,
    SetExp = 0x3D,
    UpdateHealth = 0x3E,
    ScoreboardObjective = 0x3F,
    SetPassengers = 0x40,
    Teams = 0x41,
    UpdateScore = 0x42,
    SpawnPosition = 0x43,
    TimeUpdate = 0x44,
    Title = 0x45,
    SoundEffect = 0x46,
    PlayerListHeaderFooter = 0x47,
    CollectItem = 0x48,
    EntityTeleport = 0x49,
    EntityProperties = 0x4A,
    EntityEffect = 0x4B
}

/// Client -> Server (Play)
pub enum PlayOut {
    TeleportConfirm = 0x00,
    TabComplete = 0x01,
    ChatMessage = 0x02,
    ClientStatus = 0x03,
    ClientSettings = 0x04,
    ConfirmTransaction = 0x05,
    EnchantItem = 0x06,
    ClickWindow = 0x07,
    CloseWindow = 0x08,
    PluginMessage = 0x09,
    UseEntity = 0x0A,
    KeepAlive = 0x0B,
    PlayerPosition = 0x0C,
    PlayerPositionLook = 0x0D,
    PlayerLook = 0x0E,
    Player = 0x0F,
    VehicleMove = 0x10,
    SteerBoat = 0x11,
    PlayerAbilities = 0x12,
    PlayerDigging = 0x13,
    EntityAction = 0x14,
    SteerVehicle = 0x15,
    ResourcePackStatus = 0x16,
    HeldItemChange = 0x17,
    CreativeInventoryAction = 0x18,
    UpdateSign = 0x19,
    Animation = 0x1A,
    Spectate = 0x1B,
    PlayerBlockPlacement = 0x1C,
    UseItem = 0x1D
}

/// Server -> Client (Status)
pub enum StatusIn {
    Response = 0x00,
    Pong = 0x01
}

/// Client -> Server (Status)
pub enum StatusOut {
    Request = 0x00,
    Ping = 0x01
}

/// Server -> Client (Login)
pub enum LoginIn {
    Disconnect = 0x00,
    EncryptionRequest = 0x01,
    LoginSuccess = 0x02,
    SetCompression = 0x03
}

/// Client -> Server (Login)
pub enum LoginOut {
    LoginStart = 0x00,
    EncryptionResponse = 0x01
}

impl Packet {
    /// Create a new empty packet
    pub fn new(id: i32, buffer: Vec<u8>) -> Packet {
        Packet {
            id: id,
            data: vec![],
            buf: buffer
        }
    }

    // Decode a byte array into a packet
    //pub fn decode(data: &[u8]) -> Option<Packet> {}

    // Encode the packet into a byte array
    //pub fn encode(&self) -> &[u8] {}

    /// Get data field
    pub fn get_data(&self) -> &[Field] {
        &self.data
    }

    /// Get mutable data field
    pub fn get_data_mut(&mut self) -> &mut [Field] {
        &mut self.data
    }

    /// Read a VarInt, return the value and add it to the packet fields
    pub fn read_varint(&mut self) -> Result<i32, &'static str> {
        const PART: u8 = 0x7F;
        let mut size = 0;
        let mut val = 0u32;
        for b in &self.buf {
            val |= ((b & PART) << (size * 7)) as u32;
            size += 1;
            if size > 5 {
                return Result::Err("VarInt too big");
            }
            if (b & 0x80) == 0 {
                break
            }
        }

        Result::Ok(val as i32)
    }
}
<commit_msg>Added Write VarInt<commit_after>use uuid::Uuid;
use std::io;

pub struct Packet {
    id: i32,
    data: Vec<Field>,
    buf: Vec<u8>
}

#[derive(Debug, Clone)]
enum Field {
    Boolean(bool),
    Byte(i8),
    UByte(u8),
    Short(i16),
    UShort(u16),
    Int(i32),
    Long(i64),
    Float(f32),
    Double(f64),
    String(String),
    Chat(String),
    VarInt(i32),
    VarLong(i64),
    //TODO: Chunk Section, Entity Metadata, Slot, NBT Tag, Byte Array, Optional X, Array of X, X Enum
    Position {
        x: i32,
        y: i16,
        z: i32
    },
    Angle(i8),
    UUID(Uuid)
}

pub enum PacketType {
    HandshakingOut(HandshakingOut),
    PlayIn(PlayIn),
    PlayOut(PlayOut),
    StatusIn(StatusIn),
    StatusOut(StatusOut),
    LoginIn(LoginIn),
    LoginOut(LoginOut)
}

/// Client -> Server (Play)
pub enum HandshakingOut {
    Handshake = 0x00,
    LegacyServerListPing = 0xFE
}

/// Server -> Client (Play)
pub enum PlayIn {
    SpawnObject = 0x00,
    SpawnExpOrb = 0x01,
    SpawnGlobalEntity = 0x02,
    SpawnMob = 0x03,
    SpawnPainting = 0x04,
    SpawnPlayer = 0x05,
    Animation = 0x06,
    Statistics = 0x07,
    BlockBreakAnimation = 0x08,
    UpdateBlockEntity = 0x09,
    BlockAction = 0x0A,
    BlockChange = 0x0B,
    BossBar = 0x0C,
    ServerDifficulty = 0x0D,
    TabComplete = 0x0E,
    ChatMessage = 0x0F,
    MultiBlockChange = 0x10,
    ConfirmTransaction = 0x11,
    CloseWindow = 0x12,
    OpenWindow = 0x13,
    WindowItems = 0x14,
    WindowProperty = 0x15,
    SetSlot = 0x16,
    SetCooldown = 0x17,
    PluginMessage = 0x18,
    NamedSoundEffect = 0x19,
    Disconnect = 0x1A,
    EntityStatus = 0x1B,
    Explosion = 0x1C,
    UnloadChunk = 0x1D,
    ChangeGameState = 0x1E,
    KeepAlive = 0x1F,
    ChunkData = 0x20,
    Effect = 0x21,
    Particle = 0x22,
    JoinGame = 0x23,
    Map = 0x24,
    EntityRelativeMove = 0x25,
    EntityLookRelativeMove = 0x26,
    EntityLook = 0x27,
    Entity = 0x28,
    VehicleMove = 0x29,
    OpenSignEditor = 0x2A,
    PlayerAbilities = 0x2B,
    CombatEvent = 0x2C,
    PlayerListItem = 0x2D,
    PlayerPositionLook = 0x2E,
    UseBed = 0x2F,
    DestroyEntities = 0x30,
    RemoveEntityEffect = 0x31,
    ResourcePackSend = 0x32,
    Respawn = 0x33,
    EntityHeadLook = 0x34,
    WorldBorder = 0x35,
    Camera = 0x36,
    HeldItemChange = 0x37,
    DisplayScoreboard = 0x38,
    EntityMetadata = 0x39,
    AttachEntity = 0x3A,
    EntityVelocity = 0x3B,
    EntityEquipment = 0x3C,
    SetExp = 0x3D,
    UpdateHealth = 0x3E,
    ScoreboardObjective = 0x3F,
    SetPassengers = 0x40,
    Teams = 0x41,
    UpdateScore = 0x42,
    SpawnPosition = 0x43,
    TimeUpdate = 0x44,
    Title = 0x45,
    SoundEffect = 0x46,
    PlayerListHeaderFooter = 0x47,
    CollectItem = 0x48,
    EntityTeleport = 0x49,
    EntityProperties = 0x4A,
    EntityEffect = 0x4B
}

/// Client -> Server (Play)
pub enum PlayOut {
    TeleportConfirm = 0x00,
    TabComplete = 0x01,
    ChatMessage = 0x02,
    ClientStatus = 0x03,
    ClientSettings = 0x04,
    ConfirmTransaction = 0x05,
    EnchantItem = 0x06,
    ClickWindow = 0x07,
    CloseWindow = 0x08,
    PluginMessage = 0x09,
    UseEntity = 0x0A,
    KeepAlive = 0x0B,
    PlayerPosition = 0x0C,
    PlayerPositionLook = 0x0D,
    PlayerLook = 0x0E,
    Player = 0x0F,
    VehicleMove = 0x10,
    SteerBoat = 0x11,
    PlayerAbilities = 0x12,
    PlayerDigging = 0x13,
    EntityAction = 0x14,
    SteerVehicle = 0x15,
    ResourcePackStatus = 0x16,
    HeldItemChange = 0x17,
    CreativeInventoryAction = 0x18,
    UpdateSign = 0x19,
    Animation = 0x1A,
    Spectate = 0x1B,
    PlayerBlockPlacement = 0x1C,
    UseItem = 0x1D
}

/// Server -> Client (Status)
pub enum StatusIn {
    Response = 0x00,
    Pong = 0x01
}

/// Client -> Server (Status)
pub enum StatusOut {
    Request = 0x00,
    Ping = 0x01
}

/// Server -> Client (Login)
pub enum LoginIn {
    Disconnect = 0x00,
    EncryptionRequest = 0x01,
    LoginSuccess = 0x02,
    SetCompression = 0x03
}

/// Client -> Server (Login)
pub enum LoginOut {
    LoginStart = 0x00,
    EncryptionResponse = 0x01
}

impl Packet {
    /// Create a new empty packet
    pub fn new(id: i32, buffer: Vec<u8>) -> Packet {
        Packet {
            id: id,
            data: vec![],
            buf: buffer
        }
    }

    // Decode a byte array into a packet
    //pub fn decode(data: &[u8]) -> Option<Packet> {}

    // Encode the packet into a byte array
    //pub fn encode(&self) -> &[u8] {}

    /// Get data field
    pub fn get_data(&self) -> &[Field] {
        &self.data
    }

    /// Get mutable data field
    pub fn get_data_mut(&mut self) -> &mut [Field] {
        &mut self.data
    }

    /// Read a VarInt, return the value and add it to the packet fields
    pub fn read_varint(&mut self) -> Result<i32, &'static str> {
        const PART: u8 = 0x7F;
        let mut size = 0;
        let mut val = 0u32;
        for b in &self.buf {
            val |= ((b & PART) << (size * 7)) as u32;
            size += 1;
            if size > 5 {
                return Result::Err("VarInt too big");
            }
            if (b & 0x80) == 0 {
                break
            }
        }

        Result::Ok(val as i32)
    }

    /// Write a VarInt, return an error if there is one
    pub fn write_varint(&mut self) -> Result<(), Error> {
        const PART: u32 = 0x7F;
        let mut val = self.0 as u32;
        loop {
            if (val & !PART) == 0 {
                self.buf.write_u8(val as u8)?;
                return Result::Ok(());
            }
            self.buf.write_u8(((val & PART) | 0x80) as u8)?;
            val >>= 7;
        }
    }
}
<|endoftext|>


<commit_before>//! Contains traits with platform-specific methods in them.
//!
//! Contains the following modules:
//!
//!  - `android`
//!  - `ios`
//!  - `macos`
//!  - `unix`
//!  - `windows`
//!

/// Platform-specific methods for android.
pub mod android;
/// Platform-specific methods for iOS.
pub mod ios;
/// Platform-specific methods for macOS.
pub mod macos;
/// Platform-specific methods for unix operating systems.
pub mod unix;
/// Platform-specific methods for Windows.
pub mod windows;

use std::os::raw;

/// Platform-specific extensions for OpenGL [`Context`]s.
///
/// [`Context`]: ../struct.Context.html
pub trait ContextTraitExt {
    /// Raw context handle.
    type Handle;

    /// Returns the raw context handle.
    unsafe fn raw_handle(&self) -> Self::Handle;

    /// Returns a pointer to the `EGLDisplay` object of EGL that is used by this
    /// context.
    ///
    /// Return `None` if the context doesn't use EGL.
    // The pointer will become invalid when the context is destroyed.
    unsafe fn get_egl_display(&self) -> Option<*const raw::c_void>;
}
<commit_msg>Fix winit desktop reexports (#1159)<commit_after>//! Contains traits with platform-specific methods in them.
//!
//! Contains the following modules:
//!
//!  - `android`
//!  - `ios`
//!  - `macos`
//!  - `unix`
//!  - `windows`
//!

/// Platform-specific methods for android.
pub mod android;
/// Platform-specific methods for iOS.
pub mod ios;
/// Platform-specific methods for macOS.
pub mod macos;
/// Platform-specific methods for unix operating systems.
pub mod unix;
/// Platform-specific methods for Windows.
pub mod windows;
/// Platform-specific methods for desktop operating systems.
pub mod desktop {
    pub use winit::platform::desktop::*;
}

use std::os::raw;

/// Platform-specific extensions for OpenGL [`Context`]s.
///
/// [`Context`]: ../struct.Context.html
pub trait ContextTraitExt {
    /// Raw context handle.
    type Handle;

    /// Returns the raw context handle.
    unsafe fn raw_handle(&self) -> Self::Handle;

    /// Returns a pointer to the `EGLDisplay` object of EGL that is used by this
    /// context.
    ///
    /// Return `None` if the context doesn't use EGL.
    // The pointer will become invalid when the context is destroyed.
    unsafe fn get_egl_display(&self) -> Option<*const raw::c_void>;
}
<|endoftext|>


<commit_before>
use std::error::Error;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::Path;

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};

fn get_input_lines(filename : &str) -> Vec<String> {
	let path = Path::new(filename);
    let display = path.display();

    // Open the path in read-only mode, returns `io::Result<File>`
    let file = match File::open(&path) {
        // The `description` method of `io::Error` returns a string that describes the error
        Err(why) => panic!("couldn't open {}: {}", display, Error::description(&why)),
        Ok(file) => file,
    };

	let reader = BufReader::new(file);
	let lines = reader.lines();

	lines.map(|x| x.unwrap()).collect()
}

// Try to parse the input as a constant. On falure, use as a wire ID.
fn get_input_value<'a>(wires: &mut HashMap<&'a str, u16>, input_str: &'a str) -> Option<u16> {
	let opt_val_in = input_str.parse::<u16>();
	match opt_val_in {
		Ok(input_value) => Some(input_value), // Parsed input as a constant integer
		Err(_) => {							  // Couldn't parse, so it must be a wire ID
			match wires.entry(input_str) {
				Occupied(entry) => Some(*entry.get()),
				Vacant(_) => None,
			}
		},
	}
}

// Check if the wire is unset
fn wire_is_unset<'a>(wires: &mut HashMap<&'a str, u16>, input_str: &'a str) -> bool {
	match wires.entry(input_str) {
		Occupied(_) => false,
		Vacant(_) => true,
	}
}

// AND, OR, LSHIFT, RSHIFT
fn calc_gate(gate_type: &str, input_1: u16, input_2: u16) -> u16 {
	match gate_type {
		"AND" => input_1 & input_2,
		"OR" => input_1 | input_2,
		"LSHIFT" => input_1 << input_2,
		"RSHIFT" => input_1 >> input_2,
		_ => { println!("Unknown pattern"); 0},
	}
}

// Main
fn main() {
	let gates = get_input_lines("day7.txt");

	let mut wires: HashMap<&str, u16> = HashMap::new();

	let mut repeated_gates = gates.iter().cycle();
	let mut num_processed_gates = 0;

	println!("Processing {} gates", gates.len());

	// Parse gates until none remain.
	while num_processed_gates < gates.len() {
		let l = repeated_gates.next().unwrap();
		let tokens: Vec<&str> = l.split_whitespace().collect();

		let gate_length = tokens.len();
		// match gate_length {
			// 3 => println!("WIRE: {}", l),
			// 4 => println!("1-arg GATE: {}", l),
			// 5 => println!("2-arg GATE: {}", l),
			// _ => println!("unknown: {}", l),
		// }

		if gate_length == 3 {
			// WIRE type: 123 -> x
			let in_arg = tokens[0];
			let wire_id_out = tokens[2];

			let opt_value_out = get_input_value(&mut wires, in_arg);

			if wire_is_unset(&mut wires, wire_id_out) {
				if let Some(value_out) = opt_value_out {
					wires.insert(wire_id_out, value_out);
					num_processed_gates += 1;
					println!("{}\tSet wire {} to {}", l, wire_id_out, value_out);
				}
			}
		} else if gate_length == 4 {
			// 1-arg NOT gate: NOT di -> dj
			let wire_id_in = tokens[1];
			let wire_id_out = tokens[3];

			// Try to find the input wire value
			let wire_opt_in = get_input_value(&mut wires, wire_id_in);

			// If the wire input exists, invert and write to output.
			if wire_is_unset(&mut wires, wire_id_out) {
				if let Some(wire_val_in) = wire_opt_in {
					let wire_val_out = !wire_val_in;
					wires.insert(wire_id_out, wire_val_out);
					num_processed_gates += 1;
					println!("{}\tSet wire {} to {}", l, wire_id_out, wire_val_out);
				}
			}
		} else if gate_length == 5 {
			// 2-arg gate: et AND fe -> fg
			let gate_type = tokens[1];
			let wire_in_1 = tokens[0];
			let wire_in_2 = tokens[2];
			let wire_id_out = tokens[4];

			let wire_opt_1 = get_input_value(&mut wires, wire_in_1);
			let wire_opt_2 = get_input_value(&mut wires, wire_in_2);

			// If both inputs are valid, calculate the gate output
			if wire_is_unset(&mut wires, wire_id_out) {
				if let (Some(val_1), Some(val_2)) = (wire_opt_1, wire_opt_2) {
					let value_out = calc_gate(gate_type, val_1, val_2);
					wires.insert(wire_id_out, value_out);
					num_processed_gates += 1;
					println!("{}\tSet wire {} to {}", l, wire_id_out, value_out);
				}
			}
		} else
		{
			println!("UNKNOWN GATE TYPE: {}", l);
		}
	}

	// // print wire values
	// for (wire_id, val) in &wires {
		// println!("{}: {}", wire_id, val);
	// }

	// Print output for part 1
	let wire_opt_a = get_input_value(&mut wires, "a");
	println!("Part 1: wire 'a' has value {:?}", wire_opt_a)
}
<commit_msg>Added day 7, part 2<commit_after>

use std::error::Error;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::Path;

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};

use std::collections::VecDeque;

fn get_input_lines(filename: &str) -> Vec<String> {
    let path = Path::new(filename);
    let display = path.display();

    // Open the path in read-only mode, returns `io::Result<File>`
    let file = match File::open(&path) {
        // The `description` method of `io::Error` returns a string that describes the error
        Err(why) => panic!("couldn't open {}: {}", display, Error::description(&why)),
        Ok(file) => file,
    };

    let reader = BufReader::new(file);
    let lines = reader.lines();

    lines.map(|x| x.unwrap()).collect()
}

// Try to parse the input as a constant. On falure, use as a wire ID.
// The explicit <'a> lifetime specifier denotes that the HashMap &str and input &str have equivelent lifetimes
fn get_input_value<'a>(wires: &mut HashMap<&'a str, u16>, input_str: &'a str) -> Option<u16> {
    let opt_val_in = input_str.parse::<u16>();
    match opt_val_in {
        Ok(input_value) => Some(input_value), // Parsed input as a constant integer
        Err(_) => {
            // Couldn't parse, so it must be a wire ID
            if input_str == "b" {
                Some(16076)
            } else {
                match wires.entry(input_str) {
                    Occupied(entry) => Some(*entry.get()),
                    Vacant(_) => None,
                }
            }
        }
    }
}

// Process gates of size 3. Returns true on success
fn process_gate_3<'a>(tokens: &Vec<&'a str>,
                      wires: &mut HashMap<&'a str, u16>,
                      verbose: bool)
                      -> bool {
    // WIRE type: 123 -> x
    let in_arg = tokens[0];
    let wire_id_out = tokens[2];

    let opt_value_out = get_input_value(wires, in_arg);

    if let Some(value_in_out) = opt_value_out {
        wires.insert(wire_id_out, value_in_out);
        if verbose {
            println!("{} ({}) => {} ({})",
                     in_arg,
                     value_in_out,
                     wire_id_out,
                     value_in_out);
        }
        true
    } else {
        false
    }
}

fn process_gate_4<'a>(tokens: &Vec<&'a str>,
                      wires: &mut HashMap<&'a str, u16>,
                      verbose: bool)
                      -> bool {
    // 1-arg NOT gate: NOT di -> dj
    let wire_id_in = tokens[1];
    let wire_id_out = tokens[3];

    // Try to find the input wire value
    let wire_opt_in = get_input_value(wires, wire_id_in);

    // If the wire input exists, invert and write to output.
    if let Some(wire_val_in) = wire_opt_in {
        let value_out = !wire_val_in;
        wires.insert(wire_id_out, value_out);
        if verbose {
            println!("NOT {} ({}) \t=> {} ({})",
                     wire_id_in,
                     wire_val_in,
                     wire_id_out,
                     value_out);
        }
        true
    } else {
        false
    }
}

fn process_gate_5<'a>(tokens: &Vec<&'a str>,
                      wires: &mut HashMap<&'a str, u16>,
                      verbose: bool)
                      -> bool {
    // 2-arg gate: et AND fe -> fg
    let gate_type = tokens[1];
    let wire_in_1 = tokens[0];
    let wire_in_2 = tokens[2];
    let wire_id_out = tokens[4];

    let wire_opt_1 = get_input_value(wires, wire_in_1);
    let wire_opt_2 = get_input_value(wires, wire_in_2);

    // If both inputs are valid, calculate the gate output
    if let (Some(input_1), Some(input_2)) = (wire_opt_1, wire_opt_2) {
        let value_out = match gate_type {
            "AND" => input_1 & input_2,
            "OR" => input_1 | input_2,
            "LSHIFT" => input_1 << input_2,
            "RSHIFT" => input_1 >> input_2,
            _ => {
                println!("Unknown pattern");
                0
            }
        };
        wires.insert(wire_id_out, value_out);
        if verbose {
            println!("{} ({}) {} {} ({}) \t=> {} ({})",
                     wire_in_1,
                     input_1,
                     gate_type,
                     wire_in_2,
                     input_2,
                     wire_id_out,
                     value_out);
        }
        true
    } else {
        false
    }
}

fn process_gate_queue<'a>(gates: &'a Vec<String>,
                          wires: &mut HashMap<&'a str, u16>,
                          verbose: bool) {

    // Create a local deque of references as a queue of gates
    let mut remaining_gates: VecDeque<&str> = gates.into_iter().map(AsRef::as_ref).collect();

    while remaining_gates.len() > 0 {

        let opt_gate = remaining_gates.pop_front().to_owned();
        let mut retry_gate = false;

        match opt_gate {
            Some(gate) => {

                let tokens: Vec<&str> = gate.split_whitespace().collect();
                let gate_length = tokens.len();

                if gate_length == 3 {
                    retry_gate = !process_gate_3(&tokens, wires, verbose);
                } else if gate_length == 4 {
                    retry_gate = !process_gate_4(&tokens, wires, verbose);
                } else if gate_length == 5 {
                    retry_gate = !process_gate_5(&tokens, wires, verbose);
                } else {
                    println!("UNKNOWN GATE TYPE: {}", gate);
                }

                if retry_gate {
                    if tokens[0] == "b" {
                        println!("{}", gate);
                    }
                    remaining_gates.push_back(gate); // Return the unprocessed gate to the queue
                }
            }
            None => (),
        } // match
    } // loop
}

// Main
fn main() {

    let gates = get_input_lines("day7.txt");
    let mut wires: HashMap<&str, u16> = HashMap::new();

    process_gate_queue(&gates, &mut wires, false);

    // Print output for part 1
    let wire_opt_a = get_input_value(&mut wires, "a");
    println!("Part 1: wire 'a' has value {:?}", wire_opt_a);

    println!("================================================");

    // Part 2:
    // Clear wires, set 'b' to 'a', and reprocess.
    let opt_old_a_value = get_input_value(&mut wires, "a");
    if let Some(old_a_value) = opt_old_a_value {
        wires.clear();
        wires.insert("b", old_a_value);

        println!("Part 2 in: {:?}", wires);

        process_gate_queue(&gates, &mut wires, false);

        let wire_opt_a_after = get_input_value(&mut wires, "a");
        println!("Part 2: wire 'a' has value {:?}", wire_opt_a_after)
    }
}
<|endoftext|>


<commit_before>// content-type: application/octet-stream
// status: 204 No Content
// ratelimit-limit: 1200
// ratelimit-remaining: 771
// ratelimit-reset: 1415984218

use std::borrow::Cow;
use std::fmt;

use hyper::client::response::Response;
use hyper::header;

use response::NamedResponse;
use response;

#[derive(Deserialize)]
pub struct HeaderOnly {
    #[serde(rename="content-type")]
    pub content_type: String,
    pub status: String,
    #[serde(rename="ratelimit-limit")]
    pub ratelimit_limit: f64,
    #[serde(rename="ratelimit-remaining")]
    pub ratelimit_remaining: f64,
    #[serde(rename="ratelimit-reset")]
    pub ratelimit_reset: f64,
}

impl response::NotArray for HeaderOnly {}

impl HeaderOnly {
    pub fn from_response(r: Response) -> Result<HeaderOnly, String> {
        let c_type = match r.headers.get::<header::ContentType>() {
            Some(c) => c,
            None => return Err("No content-type provided".to_owned()),
        };
        let raw_status = r.status_raw();
        let status = format!("{} {}", raw_status.0, raw_status.1);
        let rl_limit_raw = match r.headers.get_raw("ratelimit-limit") {
            Some(c) => c,
            None => return Err("No ratelimit-limit provided".to_owned()),
        };
        let rl_remain_raw = match r.headers.get_raw("ratelimit-remaining") {
            Some(c) => c,
            None => return Err("No ratelimit-remaining provided".to_owned()),
        };
        let rl_reset_raw = match r.headers.get_raw("ratelimit-reset") {
            Some(c) => c,
            None => return Err("No ratelimit-reset provided".to_owned()),
        };
        let rl_limit_str = String::from_utf8_lossy(&rl_limit_raw[0][..]);
        let rl_remain_str = String::from_utf8_lossy(&rl_remain_raw[0][..]);
        let rl_reset_str = String::from_utf8_lossy(&rl_reset_raw[0][..]);
        let rl_limit = match rl_limit_str.as_ref().parse::<f64>() {
            Ok(n) => n,
            Err(e) => return Err(e.to_string()),
        };
        let rl_remain = match rl_remain_str.as_ref().parse::<f64>() {
            Ok(n) => n,
            Err(e) => return Err(e.to_string()),
        };
        let rl_reset = match rl_reset_str.as_ref().parse::<f64>() {
            Ok(n) => n,
            Err(e) => return Err(e.to_string()),
        };
        Ok(HeaderOnly {
            content_type: c_type.to_string(),
            status: status,
            ratelimit_limit: rl_limit,
            ratelimit_remaining: rl_remain,
            ratelimit_reset: rl_reset,
        })
    }
}

impl NamedResponse for HeaderOnly {
    fn name<'a>() -> Cow<'a, str> {
        "header".into()
    }
}

impl fmt::Display for HeaderOnly {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "Status: {}\n\
                   Request Limit: {:.0}\n\
                   Requests Remaining: {:.0}\n\
                   Time to Reset: {:.0}\n",
               self.status,
               self.ratelimit_limit,
               self.ratelimit_remaining,
               self.ratelimit_reset)
    }
}

impl fmt::Debug for HeaderOnly {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "content-type: {:?}\n\
                   status: {:?}\n\
                   ratelimit-limit: {:.0}\n\
                   ratelimit-remaining: {:.0}\n\
                   ratelimit_reset: {:.0}\n",
               self.content_type,
               self.status,
               self.ratelimit_limit,
               self.ratelimit_remaining,
               self.ratelimit_reset)
    }
}
<commit_msg>Auto merge of #22 - aidanhs:aphs-no-content-type, r=kbknapp<commit_after>// content-type: application/octet-stream
// status: 204 No Content
// ratelimit-limit: 1200
// ratelimit-remaining: 771
// ratelimit-reset: 1415984218

use std::borrow::Cow;
use std::fmt;

use hyper::client::response::Response;
use hyper::header;

use response::NamedResponse;
use response;

#[derive(Deserialize)]
pub struct HeaderOnly {
    #[serde(rename="content-type")]
    pub content_type: String,
    pub status: String,
    #[serde(rename="ratelimit-limit")]
    pub ratelimit_limit: f64,
    #[serde(rename="ratelimit-remaining")]
    pub ratelimit_remaining: f64,
    #[serde(rename="ratelimit-reset")]
    pub ratelimit_reset: f64,
}

impl response::NotArray for HeaderOnly {}

impl HeaderOnly {
    pub fn from_response(r: Response) -> Result<HeaderOnly, String> {
        let c_type = match r.headers.get::<header::ContentType>() {
            Some(c) => c.to_string(),
            None => String::new(),
        };
        let raw_status = r.status_raw();
        let status = format!("{} {}", raw_status.0, raw_status.1);
        let rl_limit_raw = match r.headers.get_raw("ratelimit-limit") {
            Some(c) => c,
            None => return Err("No ratelimit-limit provided".to_owned()),
        };
        let rl_remain_raw = match r.headers.get_raw("ratelimit-remaining") {
            Some(c) => c,
            None => return Err("No ratelimit-remaining provided".to_owned()),
        };
        let rl_reset_raw = match r.headers.get_raw("ratelimit-reset") {
            Some(c) => c,
            None => return Err("No ratelimit-reset provided".to_owned()),
        };
        let rl_limit_str = String::from_utf8_lossy(&rl_limit_raw[0][..]);
        let rl_remain_str = String::from_utf8_lossy(&rl_remain_raw[0][..]);
        let rl_reset_str = String::from_utf8_lossy(&rl_reset_raw[0][..]);
        let rl_limit = match rl_limit_str.as_ref().parse::<f64>() {
            Ok(n) => n,
            Err(e) => return Err(e.to_string()),
        };
        let rl_remain = match rl_remain_str.as_ref().parse::<f64>() {
            Ok(n) => n,
            Err(e) => return Err(e.to_string()),
        };
        let rl_reset = match rl_reset_str.as_ref().parse::<f64>() {
            Ok(n) => n,
            Err(e) => return Err(e.to_string()),
        };
        Ok(HeaderOnly {
            content_type: c_type,
            status: status,
            ratelimit_limit: rl_limit,
            ratelimit_remaining: rl_remain,
            ratelimit_reset: rl_reset,
        })
    }
}

impl NamedResponse for HeaderOnly {
    fn name<'a>() -> Cow<'a, str> {
        "header".into()
    }
}

impl fmt::Display for HeaderOnly {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "Status: {}\n\
                   Request Limit: {:.0}\n\
                   Requests Remaining: {:.0}\n\
                   Time to Reset: {:.0}\n",
               self.status,
               self.ratelimit_limit,
               self.ratelimit_remaining,
               self.ratelimit_reset)
    }
}

impl fmt::Debug for HeaderOnly {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "content-type: {:?}\n\
                   status: {:?}\n\
                   ratelimit-limit: {:.0}\n\
                   ratelimit-remaining: {:.0}\n\
                   ratelimit_reset: {:.0}\n",
               self.content_type,
               self.status,
               self.ratelimit_limit,
               self.ratelimit_remaining,
               self.ratelimit_reset)
    }
}
<|endoftext|>


<commit_before>//! Compiler plugin defining macros that create PHF data structures.
//!
//! # Example
//!
//! ```rust
//! #![feature(plugin, core)]
//! #![plugin(phf_macros)]
//!
//! extern crate phf;
//!
//! #[derive(Clone)]
//! pub enum Keyword {
//!     Loop,
//!     Continue,
//!     Break,
//!     Fn,
//!     Extern,
//! }
//!
//! static KEYWORDS: phf::Map<&'static str, Keyword> = phf_map! {
//!     "loop" => Keyword::Loop,
//!     "continue" => Keyword::Continue,
//!     "break" => Keyword::Break,
//!     "fn" => Keyword::Fn,
//!     "extern" => Keyword::Extern,
//! };
//!
//! pub fn parse_keyword(keyword: &str) -> Option<Keyword> {
//!     KEYWORDS.get(keyword).cloned()
//! }
//! # fn main() {}
//! ```
#![doc(html_root_url="http://sfackler.github.io/rust-phf/doc/v0.7.17")]
#![feature(plugin_registrar, quote, rustc_private)]

extern crate syntax;
#[cfg(feature = "stats")]
extern crate time;
extern crate rustc_plugin;
extern crate phf_shared;
extern crate phf_generator;
#[cfg(feature = "unicase_support")]
extern crate unicase;

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use syntax::ast::{self, Expr, ExprKind, Mutability, TyKind};
use syntax::tokenstream::TokenTree;
use syntax::codemap::Span;
use syntax::ext::base::{DummyResult, ExtCtxt, MacResult};
use syntax::ext::build::AstBuilder;
use syntax::fold::Folder;
use syntax::parse;
use syntax::parse::token::{InternedString, Comma, Eof, FatArrow};
use syntax::print::pprust;
use syntax::ptr::P;
use rustc_plugin::Registry;
use phf_generator::HashState;
use std::env;
#[cfg(feature = "unicase_support")]
use unicase::UniCase;

use util::{Entry, Key};
use util::{create_map, create_set, create_ordered_map, create_ordered_set};

pub mod util;
mod macros;

#[plugin_registrar]
#[doc(hidden)]
pub fn macro_registrar(reg: &mut Registry) {
    reg.register_macro("phf_map", expand_phf_map);
    reg.register_macro("phf_set", expand_phf_set);
    reg.register_macro("phf_ordered_map", expand_phf_ordered_map);
    reg.register_macro("phf_ordered_set", expand_phf_ordered_set);
}

fn generate_hash(cx: &mut ExtCtxt, sp: Span, entries: &[Entry]) -> HashState {
    #[cfg(feature = "stats")]
    use time::precise_time_s;
    #[cfg(not(feature = "stats"))]
    fn precise_time_s() -> f64 {
        0.
    }

    let start = precise_time_s();
    let state = phf_generator::generate_hash(entries);
    let time = precise_time_s() - start;

    if cfg!(feature = "stats") && env::var_os("PHF_STATS").is_some() {
        cx.parse_sess
          .span_diagnostic
          .span_note_without_error(sp, &format!("PHF generation took {} seconds", time));
    }

    state
}

fn expand_phf_map(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
    let entries = match parse_map(cx, tts) {
        Some(entries) => entries,
        None => return DummyResult::expr(sp),
    };

    if has_duplicates(cx, sp, &*entries) {
        return DummyResult::expr(sp);
    }

    let state = generate_hash(cx, sp, &*entries);

    create_map(cx, sp, entries, state)
}

fn expand_phf_set(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
    let entries = match parse_set(cx, tts) {
        Some(entries) => entries,
        None => return DummyResult::expr(sp),
    };

    if has_duplicates(cx, sp, &*entries) {
        return DummyResult::expr(sp);
    }

    let state = generate_hash(cx, sp, &*entries);

    create_set(cx, sp, entries, state)
}

fn expand_phf_ordered_map(cx: &mut ExtCtxt,
                          sp: Span,
                          tts: &[TokenTree])
                          -> Box<MacResult + 'static> {
    let entries = match parse_map(cx, tts) {
        Some(entries) => entries,
        None => return DummyResult::expr(sp),
    };

    if has_duplicates(cx, sp, &*entries) {
        return DummyResult::expr(sp);
    }

    let state = generate_hash(cx, sp, &*entries);

    create_ordered_map(cx, sp, entries, state)
}

fn expand_phf_ordered_set(cx: &mut ExtCtxt,
                          sp: Span,
                          tts: &[TokenTree])
                          -> Box<MacResult + 'static> {
    let entries = match parse_set(cx, tts) {
        Some(entries) => entries,
        None => return DummyResult::expr(sp),
    };

    if has_duplicates(cx, sp, &*entries) {
        return DummyResult::expr(sp);
    }

    let state = generate_hash(cx, sp, &*entries);

    create_ordered_set(cx, sp, entries, state)
}

fn parse_map(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option<Vec<Entry>> {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), tts.to_vec());
    let mut entries = Vec::new();

    let mut bad = false;
    while parser.token != Eof {
        let key = cx.expander().fold_expr(parser.parse_expr().unwrap());
        let key_contents = parse_key(cx, &*key).unwrap_or_else(|| {
            bad = true;
            Key::Str(InternedString::new(""))
        });
        let key = adjust_key(cx, key);

        if !parser.eat(&FatArrow) {
            cx.span_err(parser.span, "expected `=>`");
            return None;
        }

        let value = parser.parse_expr().unwrap();

        entries.push(Entry {
            key_contents: key_contents,
            key: key,
            value: value,
        });

        if !parser.eat(&Comma) && parser.token != Eof {
            cx.span_err(parser.span, "expected `,`");
            return None;
        }
    }

    if bad {
        return None;
    }

    Some(entries)
}

fn parse_set(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option<Vec<Entry>> {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), tts.to_vec());
    let mut entries = Vec::new();
    let value = quote_expr!(&*cx, ());

    let mut bad = false;
    while parser.token != Eof {
        let key = cx.expander().fold_expr(parser.parse_expr().unwrap());
        let key_contents = parse_key(cx, &*key).unwrap_or_else(|| {
            bad = true;
            Key::Str(InternedString::new(""))
        });
        let key = adjust_key(cx, key);

        entries.push(Entry {
            key_contents: key_contents,
            key: key,
            value: value.clone(),
        });

        if !parser.eat(&Comma) && parser.token != Eof {
            cx.span_err(parser.span, "expected `,`");
            return None;
        }
    }

    if bad {
        return None;
    }

    Some(entries)
}

fn parse_key(cx: &mut ExtCtxt, e: &Expr) -> Option<Key> {
    match e.node {
        ExprKind::Lit(ref lit) => {
            match lit.node {
                ast::LitKind::Str(ref s, _) => Some(Key::Str(s.clone())),
                ast::LitKind::ByteStr(ref b) => Some(Key::Binary(b.clone())),
                ast::LitKind::Byte(b) => Some(Key::U8(b)),
                ast::LitKind::Char(c) => Some(Key::Char(c)),
                ast::LitKind::Int(i, ast::LitIntType::Signed(ast::IntTy::I8)) =>
                    Some(Key::I8(i as i8)),
                ast::LitKind::Int(i, ast::LitIntType::Signed(ast::IntTy::I16)) =>
                    Some(Key::I16(i as i16)),
                ast::LitKind::Int(i, ast::LitIntType::Signed(ast::IntTy::I32)) =>
                    Some(Key::I32(i as i32)),
                ast::LitKind::Int(i, ast::LitIntType::Signed(ast::IntTy::I64)) =>
                    Some(Key::I64(i as i64)),
                ast::LitKind::Int(i, ast::LitIntType::Unsigned(ast::UintTy::U8)) =>
                    Some(Key::U8(i as u8)),
                ast::LitKind::Int(i, ast::LitIntType::Unsigned(ast::UintTy::U16)) =>
                    Some(Key::U16(i as u16)),
                ast::LitKind::Int(i, ast::LitIntType::Unsigned(ast::UintTy::U32)) =>
                    Some(Key::U32(i as u32)),
                ast::LitKind::Int(i, ast::LitIntType::Unsigned(ast::UintTy::U64)) =>
                    Some(Key::U64(i as u64)),
                ast::LitKind::Bool(b) => Some(Key::Bool(b)),
                _ => {
                    cx.span_err(e.span, "unsupported literal type");
                    None
                }
            }
        }
        ExprKind::Vec(ref v) => {
            let bytes: Vec<Option<u8>> = v.iter().map(|expr|
                if let ExprKind::Lit(ref p) = expr.node {
                    match p.node {
                        ast::LitKind::Int(val, ast::LitIntType::Unsigned(ast::UintTy::U8)) if val < 256 =>
                            Some(val as u8),
                        ast::LitKind::Int(val, ast::LitIntType::Unsuffixed) if val < 256 =>
                            Some(val as u8),
                        _ => None,
                    }
                } else {
                    None
            }).collect();
            if bytes.iter().all(|x| x.is_some()) {
                Some(Key::Binary(std::rc::Rc::new(bytes.iter().map(|x| x.unwrap()).collect())))
            } else {
                cx.span_err(e.span,
                            "not all elements of an expected u8 array literal were u8 literals");
                None
            }
        }
        #[cfg(feature = "unicase_support")]
        ExprKind::Call(ref f, ref args) => {
            if let ExprKind::Path(_, ref path) = f.node {
                if path.segments.last().unwrap().identifier.name.as_str() == "UniCase" {
                    if args.len() == 1 {
                        if let ExprKind::Lit(ref lit) = args.first().unwrap().node {
                            if let ast::LitKind::Str(ref s, _) = lit.node {
                                return Some(Key::UniCase(UniCase(s.to_string())));
                            } else {
                                cx.span_err(e.span, "only a str literal is allowed in UniCase");
                                return None;
                            }
                        }
                    } else {
                        cx.span_err(e.span, "only one str literal is allowed in UniCase");
                        return None;
                    }
                }
            }
            cx.span_err(e.span, "only UniCase is allowed besides literals");
            None
        },
        _ => {
            cx.span_err(e.span, "expected a literal (or a UniCase if the unicase_support feature is enabled)");
            None
        }
    }
}

fn adjust_key(cx: &mut ExtCtxt, e: P<Expr>) -> P<Expr> {
    let coerce_as_slice = match e.node {
        ExprKind::Lit(ref lit) => {
            match lit.node {
                ast::LitKind::ByteStr(_) => true,
                _ => false,
            }
        },
        _ => false,
    };
    if coerce_as_slice {
        let u8_type = cx.ty_path(cx.path_ident(e.span, cx.ident_of("u8")));
        let array_type = cx.ty(e.span, TyKind::Slice(u8_type));
        let slice_type = cx.ty_rptr(e.span, array_type, None, Mutability::Immutable);
        cx.expr_cast(e.span, e, slice_type)
    } else {
        e
    }
}

fn has_duplicates(cx: &mut ExtCtxt, sp: Span, entries: &[Entry]) -> bool {
    let mut dups = false;
    let mut strings = HashMap::new();
    for entry in entries.iter() {
        let &mut (ref mut spans, _) = match strings.entry(&entry.key_contents) {
            Occupied(e) => e.into_mut(),
            Vacant(e) => e.insert((vec![], &entry.key)),
        };
        spans.push(entry.key.span);
    }

    for &(ref spans, key) in strings.values() {
        if spans.len() == 1 {
            continue;
        }

        dups = true;
        let mut err = cx.struct_span_err(sp, &*format!("duplicate key {}",
                                                       pprust::expr_to_string(&**key)));
        for span in spans.iter() {
            err.span_note(*span, "one occurrence here");
        }
        err.emit();
    }

    dups
}
<commit_msg>Fix for latest nightly<commit_after>//! Compiler plugin defining macros that create PHF data structures.
//!
//! # Example
//!
//! ```rust
//! #![feature(plugin, core)]
//! #![plugin(phf_macros)]
//!
//! extern crate phf;
//!
//! #[derive(Clone)]
//! pub enum Keyword {
//!     Loop,
//!     Continue,
//!     Break,
//!     Fn,
//!     Extern,
//! }
//!
//! static KEYWORDS: phf::Map<&'static str, Keyword> = phf_map! {
//!     "loop" => Keyword::Loop,
//!     "continue" => Keyword::Continue,
//!     "break" => Keyword::Break,
//!     "fn" => Keyword::Fn,
//!     "extern" => Keyword::Extern,
//! };
//!
//! pub fn parse_keyword(keyword: &str) -> Option<Keyword> {
//!     KEYWORDS.get(keyword).cloned()
//! }
//! # fn main() {}
//! ```
#![doc(html_root_url="http://sfackler.github.io/rust-phf/doc/v0.7.17")]
#![feature(plugin_registrar, quote, rustc_private)]

extern crate syntax;
#[cfg(feature = "stats")]
extern crate time;
extern crate rustc_plugin;
extern crate phf_shared;
extern crate phf_generator;
#[cfg(feature = "unicase_support")]
extern crate unicase;

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use syntax::ast::{self, Expr, ExprKind, Mutability, TyKind};
use syntax::tokenstream::TokenTree;
use syntax::codemap::Span;
use syntax::ext::base::{DummyResult, ExtCtxt, MacResult};
use syntax::ext::build::AstBuilder;
use syntax::fold::Folder;
use syntax::parse;
use syntax::parse::token::{InternedString, Comma, Eof, FatArrow};
use syntax::print::pprust;
use syntax::ptr::P;
use rustc_plugin::Registry;
use phf_generator::HashState;
use std::env;
#[cfg(feature = "unicase_support")]
use unicase::UniCase;

use util::{Entry, Key};
use util::{create_map, create_set, create_ordered_map, create_ordered_set};

pub mod util;
mod macros;

#[plugin_registrar]
#[doc(hidden)]
pub fn macro_registrar(reg: &mut Registry) {
    reg.register_macro("phf_map", expand_phf_map);
    reg.register_macro("phf_set", expand_phf_set);
    reg.register_macro("phf_ordered_map", expand_phf_ordered_map);
    reg.register_macro("phf_ordered_set", expand_phf_ordered_set);
}

fn generate_hash(cx: &mut ExtCtxt, sp: Span, entries: &[Entry]) -> HashState {
    #[cfg(feature = "stats")]
    use time::precise_time_s;
    #[cfg(not(feature = "stats"))]
    fn precise_time_s() -> f64 {
        0.
    }

    let start = precise_time_s();
    let state = phf_generator::generate_hash(entries);
    let time = precise_time_s() - start;

    if cfg!(feature = "stats") && env::var_os("PHF_STATS").is_some() {
        cx.parse_sess
          .span_diagnostic
          .span_note_without_error(sp, &format!("PHF generation took {} seconds", time));
    }

    state
}

fn expand_phf_map(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
    let entries = match parse_map(cx, tts) {
        Some(entries) => entries,
        None => return DummyResult::expr(sp),
    };

    if has_duplicates(cx, sp, &*entries) {
        return DummyResult::expr(sp);
    }

    let state = generate_hash(cx, sp, &*entries);

    create_map(cx, sp, entries, state)
}

fn expand_phf_set(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
    let entries = match parse_set(cx, tts) {
        Some(entries) => entries,
        None => return DummyResult::expr(sp),
    };

    if has_duplicates(cx, sp, &*entries) {
        return DummyResult::expr(sp);
    }

    let state = generate_hash(cx, sp, &*entries);

    create_set(cx, sp, entries, state)
}

fn expand_phf_ordered_map(cx: &mut ExtCtxt,
                          sp: Span,
                          tts: &[TokenTree])
                          -> Box<MacResult + 'static> {
    let entries = match parse_map(cx, tts) {
        Some(entries) => entries,
        None => return DummyResult::expr(sp),
    };

    if has_duplicates(cx, sp, &*entries) {
        return DummyResult::expr(sp);
    }

    let state = generate_hash(cx, sp, &*entries);

    create_ordered_map(cx, sp, entries, state)
}

fn expand_phf_ordered_set(cx: &mut ExtCtxt,
                          sp: Span,
                          tts: &[TokenTree])
                          -> Box<MacResult + 'static> {
    let entries = match parse_set(cx, tts) {
        Some(entries) => entries,
        None => return DummyResult::expr(sp),
    };

    if has_duplicates(cx, sp, &*entries) {
        return DummyResult::expr(sp);
    }

    let state = generate_hash(cx, sp, &*entries);

    create_ordered_set(cx, sp, entries, state)
}

fn parse_map(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option<Vec<Entry>> {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg().clone(), tts.to_vec());
    let mut entries = Vec::new();

    let mut bad = false;
    while parser.token != Eof {
        let key = cx.expander().fold_expr(parser.parse_expr().unwrap());
        let key_contents = parse_key(cx, &*key).unwrap_or_else(|| {
            bad = true;
            Key::Str(InternedString::new(""))
        });
        let key = adjust_key(cx, key);

        if !parser.eat(&FatArrow) {
            cx.span_err(parser.span, "expected `=>`");
            return None;
        }

        let value = parser.parse_expr().unwrap();

        entries.push(Entry {
            key_contents: key_contents,
            key: key,
            value: value,
        });

        if !parser.eat(&Comma) && parser.token != Eof {
            cx.span_err(parser.span, "expected `,`");
            return None;
        }
    }

    if bad {
        return None;
    }

    Some(entries)
}

fn parse_set(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option<Vec<Entry>> {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg().clone(), tts.to_vec());
    let mut entries = Vec::new();
    let value = quote_expr!(&*cx, ());

    let mut bad = false;
    while parser.token != Eof {
        let key = cx.expander().fold_expr(parser.parse_expr().unwrap());
        let key_contents = parse_key(cx, &*key).unwrap_or_else(|| {
            bad = true;
            Key::Str(InternedString::new(""))
        });
        let key = adjust_key(cx, key);

        entries.push(Entry {
            key_contents: key_contents,
            key: key,
            value: value.clone(),
        });

        if !parser.eat(&Comma) && parser.token != Eof {
            cx.span_err(parser.span, "expected `,`");
            return None;
        }
    }

    if bad {
        return None;
    }

    Some(entries)
}

fn parse_key(cx: &mut ExtCtxt, e: &Expr) -> Option<Key> {
    match e.node {
        ExprKind::Lit(ref lit) => {
            match lit.node {
                ast::LitKind::Str(ref s, _) => Some(Key::Str(s.clone())),
                ast::LitKind::ByteStr(ref b) => Some(Key::Binary(b.clone())),
                ast::LitKind::Byte(b) => Some(Key::U8(b)),
                ast::LitKind::Char(c) => Some(Key::Char(c)),
                ast::LitKind::Int(i, ast::LitIntType::Signed(ast::IntTy::I8)) =>
                    Some(Key::I8(i as i8)),
                ast::LitKind::Int(i, ast::LitIntType::Signed(ast::IntTy::I16)) =>
                    Some(Key::I16(i as i16)),
                ast::LitKind::Int(i, ast::LitIntType::Signed(ast::IntTy::I32)) =>
                    Some(Key::I32(i as i32)),
                ast::LitKind::Int(i, ast::LitIntType::Signed(ast::IntTy::I64)) =>
                    Some(Key::I64(i as i64)),
                ast::LitKind::Int(i, ast::LitIntType::Unsigned(ast::UintTy::U8)) =>
                    Some(Key::U8(i as u8)),
                ast::LitKind::Int(i, ast::LitIntType::Unsigned(ast::UintTy::U16)) =>
                    Some(Key::U16(i as u16)),
                ast::LitKind::Int(i, ast::LitIntType::Unsigned(ast::UintTy::U32)) =>
                    Some(Key::U32(i as u32)),
                ast::LitKind::Int(i, ast::LitIntType::Unsigned(ast::UintTy::U64)) =>
                    Some(Key::U64(i as u64)),
                ast::LitKind::Bool(b) => Some(Key::Bool(b)),
                _ => {
                    cx.span_err(e.span, "unsupported literal type");
                    None
                }
            }
        }
        ExprKind::Vec(ref v) => {
            let bytes: Vec<Option<u8>> = v.iter().map(|expr|
                if let ExprKind::Lit(ref p) = expr.node {
                    match p.node {
                        ast::LitKind::Int(val, ast::LitIntType::Unsigned(ast::UintTy::U8)) if val < 256 =>
                            Some(val as u8),
                        ast::LitKind::Int(val, ast::LitIntType::Unsuffixed) if val < 256 =>
                            Some(val as u8),
                        _ => None,
                    }
                } else {
                    None
            }).collect();
            if bytes.iter().all(|x| x.is_some()) {
                Some(Key::Binary(std::rc::Rc::new(bytes.iter().map(|x| x.unwrap()).collect())))
            } else {
                cx.span_err(e.span,
                            "not all elements of an expected u8 array literal were u8 literals");
                None
            }
        }
        #[cfg(feature = "unicase_support")]
        ExprKind::Call(ref f, ref args) => {
            if let ExprKind::Path(_, ref path) = f.node {
                if path.segments.last().unwrap().identifier.name.as_str() == "UniCase" {
                    if args.len() == 1 {
                        if let ExprKind::Lit(ref lit) = args.first().unwrap().node {
                            if let ast::LitKind::Str(ref s, _) = lit.node {
                                return Some(Key::UniCase(UniCase(s.to_string())));
                            } else {
                                cx.span_err(e.span, "only a str literal is allowed in UniCase");
                                return None;
                            }
                        }
                    } else {
                        cx.span_err(e.span, "only one str literal is allowed in UniCase");
                        return None;
                    }
                }
            }
            cx.span_err(e.span, "only UniCase is allowed besides literals");
            None
        },
        _ => {
            cx.span_err(e.span, "expected a literal (or a UniCase if the unicase_support feature is enabled)");
            None
        }
    }
}

fn adjust_key(cx: &mut ExtCtxt, e: P<Expr>) -> P<Expr> {
    let coerce_as_slice = match e.node {
        ExprKind::Lit(ref lit) => {
            match lit.node {
                ast::LitKind::ByteStr(_) => true,
                _ => false,
            }
        },
        _ => false,
    };
    if coerce_as_slice {
        let u8_type = cx.ty_path(cx.path_ident(e.span, cx.ident_of("u8")));
        let array_type = cx.ty(e.span, TyKind::Slice(u8_type));
        let slice_type = cx.ty_rptr(e.span, array_type, None, Mutability::Immutable);
        cx.expr_cast(e.span, e, slice_type)
    } else {
        e
    }
}

fn has_duplicates(cx: &mut ExtCtxt, sp: Span, entries: &[Entry]) -> bool {
    let mut dups = false;
    let mut strings = HashMap::new();
    for entry in entries.iter() {
        let &mut (ref mut spans, _) = match strings.entry(&entry.key_contents) {
            Occupied(e) => e.into_mut(),
            Vacant(e) => e.insert((vec![], &entry.key)),
        };
        spans.push(entry.key.span);
    }

    for &(ref spans, key) in strings.values() {
        if spans.len() == 1 {
            continue;
        }

        dups = true;
        let mut err = cx.struct_span_err(sp, &*format!("duplicate key {}",
                                                       pprust::expr_to_string(&**key)));
        for span in spans.iter() {
            err.span_note(*span, "one occurrence here");
        }
        err.emit();
    }

    dups
}
<|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::MAX_CHANNEL_COUNT;
use dom::bindings::cell::DomRefCell;
use dom::bindings::codegen::Bindings::AudioBufferBinding::{self, AudioBufferMethods, AudioBufferOptions};
use dom::bindings::error::{Error, Fallible};
use dom::bindings::num::Finite;
use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::bindings::root::DomRoot;
use dom::window::Window;
use dom_struct::dom_struct;
use js::jsapi::{Heap, JSAutoCompartment, JSContext, JSObject};
use js::jsapi::JS_GetArrayBufferViewBuffer;
use js::rust::CustomAutoRooterGuard;
use js::rust::wrappers::JS_DetachArrayBuffer;
use js::typedarray::{CreateWith, Float32Array};
use servo_media::audio::buffer_source_node::AudioBuffer as ServoMediaAudioBuffer;
use std::cmp::min;
use std::ptr::{self, NonNull};

// This range is defined by the spec.
// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createbuffer
pub const MIN_SAMPLE_RATE: f32 = 8000.;
pub const MAX_SAMPLE_RATE: f32 = 96000.;

type JSAudioChannel = Heap<*mut JSObject>;

#[dom_struct]
pub struct AudioBuffer {
    reflector_: Reflector,
    js_channels: DomRefCell<Vec<JSAudioChannel>>,
    #[ignore_malloc_size_of = "servo_media"]
    shared_channels: DomRefCell<ServoMediaAudioBuffer>,
    sample_rate: f32,
    length: u32,
    duration: f64,
    number_of_channels: u32,
}

impl AudioBuffer {
    #[allow(unrooted_must_root)]
    #[allow(unsafe_code)]
    pub fn new_inherited(number_of_channels: u32, length: u32, sample_rate: f32) -> AudioBuffer {
        let vec = (0..number_of_channels).map(|_| Heap::default()).collect();
        AudioBuffer {
            reflector_: Reflector::new(),
            js_channels: DomRefCell::new(vec),
            shared_channels: DomRefCell::new(ServoMediaAudioBuffer::new(
                number_of_channels as u8,
                length as usize,
            )),
            sample_rate,
            length,
            duration: length as f64 / sample_rate as f64,
            number_of_channels,
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(
        global: &Window,
        number_of_channels: u32,
        length: u32,
        sample_rate: f32,
        initial_data: Option<&[Vec<f32>]>,
    ) -> DomRoot<AudioBuffer> {
        let buffer = AudioBuffer::new_inherited(number_of_channels, length, sample_rate);
        let buffer = reflect_dom_object(Box::new(buffer), global, AudioBufferBinding::Wrap);
        buffer.set_channels(initial_data);
        buffer
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-audiobuffer
    pub fn Constructor(
        window: &Window,
        options: &AudioBufferOptions,
    ) -> Fallible<DomRoot<AudioBuffer>> {
        if options.length <= 0 ||
            options.numberOfChannels <= 0 ||
            options.numberOfChannels > MAX_CHANNEL_COUNT ||
            *options.sampleRate < MIN_SAMPLE_RATE ||
            *options.sampleRate > MAX_SAMPLE_RATE
        {
            return Err(Error::NotSupported);
        }
        Ok(AudioBuffer::new(
            window,
            options.numberOfChannels,
            options.length,
            *options.sampleRate,
            None,
        ))
    }

    // Initialize the underlying channels data with initial data provided by
    // the user or silence otherwise.
    #[allow(unsafe_code)]
    pub fn set_channels(&self, initial_data: Option<&[Vec<f32>]>) {
        for channel in 0..self.number_of_channels {
            (*self.shared_channels.borrow_mut()).buffers[channel as usize] = match initial_data {
                Some(data) => data[channel as usize].clone(),
                None => vec![0.; self.length as usize],
            };
        }
    }

    pub fn get_channels(&self) -> ServoMediaAudioBuffer {
        self.shared_channels.borrow().clone()
    }

    #[allow(unsafe_code)]
    unsafe fn restore_js_channel_data(&self, cx: *mut JSContext) -> bool {
        let global = self.global();
        let _ac = JSAutoCompartment::new(cx, global.reflector().get_jsobject().get());
        for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
            if !channel.get().is_null() {
                // Already have data in JS array.
                continue;
            }

            // Copy the channel data from shared_channels to js_channels.
            rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
            let shared_channel = &(*self.shared_channels.borrow_mut()).buffers[i];
            if Float32Array::create(cx, CreateWith::Slice(shared_channel), array.handle_mut())
                .is_err()
            {
                return false;
            }
            channel.set(array.get());
        }

        true
    }

    // https://webaudio.github.io/web-audio-api/#acquire-the-content
    #[allow(unsafe_code)]
    pub fn acquire_contents(&self) -> Option<ServoMediaAudioBuffer> {
        let cx = self.global().get_cx();
        for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
            // Step 1.
            if channel.get().is_null() {
                return None;
            }

            // Step 2.
            let channel_data = unsafe {
                typedarray!(in(cx) let array: Float32Array = channel.get());
                if let Ok(array) = array {
                    let data = array.to_vec();
                    let mut is_shared = false;
                    rooted!(in (cx) let view_buffer =
                        JS_GetArrayBufferViewBuffer(cx, channel.handle(), &mut is_shared));
                    // This buffer is always created unshared
                    debug_assert!(!is_shared);
                    let _ = JS_DetachArrayBuffer(cx, view_buffer.handle());
                    data
                } else {
                    return None;
                }
            };

            channel.set(ptr::null_mut());

            // Step 3.
            (*self.shared_channels.borrow_mut()).buffers[i] = channel_data;

            // Step 4 will complete turning shared_channels
            // data into js_channels ArrayBuffers in restore_js_channel_data.
        }

        Some((*self.shared_channels.borrow()).clone())
    }
}

impl AudioBufferMethods for AudioBuffer {
    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-samplerate
    fn SampleRate(&self) -> Finite<f32> {
        Finite::wrap(self.sample_rate)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-length
    fn Length(&self) -> u32 {
        self.length
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-duration
    fn Duration(&self) -> Finite<f64> {
        Finite::wrap(self.duration)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-numberofchannels
    fn NumberOfChannels(&self) -> u32 {
        self.number_of_channels
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-getchanneldata
    #[allow(unsafe_code)]
    unsafe fn GetChannelData(
        &self,
        cx: *mut JSContext,
        channel: u32,
    ) -> Fallible<NonNull<JSObject>> {
        if channel >= self.number_of_channels {
            return Err(Error::IndexSize);
        }

        if !self.restore_js_channel_data(cx) {
            return Err(Error::JSFailed);
        }

        Ok(NonNull::new_unchecked(
            self.js_channels.borrow()[channel as usize].get(),
        ))
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copyfromchannel
    #[allow(unsafe_code)]
    fn CopyFromChannel(
        &self,
        mut destination: CustomAutoRooterGuard<Float32Array>,
        channel_number: u32,
        start_in_channel: u32,
    ) -> Fallible<()> {
        if destination.is_shared() {
            return Err(Error::Type("Cannot copy to shared buffer".to_owned()));
        }

        if channel_number >= self.number_of_channels || start_in_channel > self.length {
            return Err(Error::IndexSize);
        }

        let bytes_to_copy = min(self.length - start_in_channel, destination.len() as u32) as usize;
        let cx = self.global().get_cx();
        let channel_number = channel_number as usize;
        let offset = start_in_channel as usize;
        let mut dest = Vec::with_capacity(destination.len());

        // We either copy form js_channels or shared_channels.

        let js_channel = self.js_channels.borrow()[channel_number].get();
        if !js_channel.is_null() {
            typedarray!(in(cx) let array: Float32Array = js_channel);
            if let Ok(array) = array {
                let data = unsafe { array.as_slice() };
                dest.extend_from_slice(&data[offset..offset + bytes_to_copy]);
                return Ok(());
            }
        }

        if let Some(shared_channel) = self.shared_channels.borrow().buffers.get(channel_number) {
            dest.extend_from_slice(&shared_channel.as_slice()[offset..offset + bytes_to_copy]);
        }

        unsafe {
            destination.update(&dest);
        }

        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copytochannel
    #[allow(unsafe_code)]
    fn CopyToChannel(
        &self,
        source: CustomAutoRooterGuard<Float32Array>,
        channel_number: u32,
        start_in_channel: u32,
    ) -> Fallible<()> {
        if source.is_shared() {
            return Err(Error::Type("Cannot copy from shared buffer".to_owned()));
        }

        if channel_number >= self.number_of_channels || start_in_channel > (source.len() as u32) {
            return Err(Error::IndexSize);
        }

        let cx = self.global().get_cx();
        if unsafe { !self.restore_js_channel_data(cx) } {
            return Err(Error::JSFailed);
        }

        let js_channel = self.js_channels.borrow()[channel_number as usize].get();
        if js_channel.is_null() {
            // The array buffer was detached.
            return Err(Error::IndexSize);
        }

        typedarray!(in(cx) let array: Float32Array = js_channel);
        if let Ok(mut array) = array {
            let bytes_to_copy = min(self.length - start_in_channel, source.len() as u32) as usize;
            let offset = start_in_channel as usize;
            unsafe {
                let data = &source.as_slice()[offset..offset + bytes_to_copy];
                array.update(data);
                (*self.shared_channels.borrow_mut()).buffers[channel_number as usize] = data.to_vec();
            }
        } else {
            return Err(Error::IndexSize);
        }

        Ok(())
    }
}
<commit_msg>Apply start_in_channel to destination and not source during AudioBuffer.CopyToChannel<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::MAX_CHANNEL_COUNT;
use dom::bindings::cell::DomRefCell;
use dom::bindings::codegen::Bindings::AudioBufferBinding::{self, AudioBufferMethods, AudioBufferOptions};
use dom::bindings::error::{Error, Fallible};
use dom::bindings::num::Finite;
use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::bindings::root::DomRoot;
use dom::window::Window;
use dom_struct::dom_struct;
use js::jsapi::{Heap, JSAutoCompartment, JSContext, JSObject};
use js::jsapi::JS_GetArrayBufferViewBuffer;
use js::rust::CustomAutoRooterGuard;
use js::rust::wrappers::JS_DetachArrayBuffer;
use js::typedarray::{CreateWith, Float32Array};
use servo_media::audio::buffer_source_node::AudioBuffer as ServoMediaAudioBuffer;
use std::cmp::min;
use std::ptr::{self, NonNull};

// This range is defined by the spec.
// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createbuffer
pub const MIN_SAMPLE_RATE: f32 = 8000.;
pub const MAX_SAMPLE_RATE: f32 = 96000.;

type JSAudioChannel = Heap<*mut JSObject>;

#[dom_struct]
pub struct AudioBuffer {
    reflector_: Reflector,
    js_channels: DomRefCell<Vec<JSAudioChannel>>,
    #[ignore_malloc_size_of = "servo_media"]
    shared_channels: DomRefCell<ServoMediaAudioBuffer>,
    sample_rate: f32,
    length: u32,
    duration: f64,
    number_of_channels: u32,
}

impl AudioBuffer {
    #[allow(unrooted_must_root)]
    #[allow(unsafe_code)]
    pub fn new_inherited(number_of_channels: u32, length: u32, sample_rate: f32) -> AudioBuffer {
        let vec = (0..number_of_channels).map(|_| Heap::default()).collect();
        AudioBuffer {
            reflector_: Reflector::new(),
            js_channels: DomRefCell::new(vec),
            shared_channels: DomRefCell::new(ServoMediaAudioBuffer::new(
                number_of_channels as u8,
                length as usize,
            )),
            sample_rate,
            length,
            duration: length as f64 / sample_rate as f64,
            number_of_channels,
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(
        global: &Window,
        number_of_channels: u32,
        length: u32,
        sample_rate: f32,
        initial_data: Option<&[Vec<f32>]>,
    ) -> DomRoot<AudioBuffer> {
        let buffer = AudioBuffer::new_inherited(number_of_channels, length, sample_rate);
        let buffer = reflect_dom_object(Box::new(buffer), global, AudioBufferBinding::Wrap);
        buffer.set_channels(initial_data);
        buffer
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-audiobuffer
    pub fn Constructor(
        window: &Window,
        options: &AudioBufferOptions,
    ) -> Fallible<DomRoot<AudioBuffer>> {
        if options.length <= 0 ||
            options.numberOfChannels <= 0 ||
            options.numberOfChannels > MAX_CHANNEL_COUNT ||
            *options.sampleRate < MIN_SAMPLE_RATE ||
            *options.sampleRate > MAX_SAMPLE_RATE
        {
            return Err(Error::NotSupported);
        }
        Ok(AudioBuffer::new(
            window,
            options.numberOfChannels,
            options.length,
            *options.sampleRate,
            None,
        ))
    }

    // Initialize the underlying channels data with initial data provided by
    // the user or silence otherwise.
    #[allow(unsafe_code)]
    pub fn set_channels(&self, initial_data: Option<&[Vec<f32>]>) {
        for channel in 0..self.number_of_channels {
            (*self.shared_channels.borrow_mut()).buffers[channel as usize] = match initial_data {
                Some(data) => data[channel as usize].clone(),
                None => vec![0.; self.length as usize],
            };
        }
    }

    pub fn get_channels(&self) -> ServoMediaAudioBuffer {
        self.shared_channels.borrow().clone()
    }

    #[allow(unsafe_code)]
    unsafe fn restore_js_channel_data(&self, cx: *mut JSContext) -> bool {
        let global = self.global();
        let _ac = JSAutoCompartment::new(cx, global.reflector().get_jsobject().get());
        for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
            if !channel.get().is_null() {
                // Already have data in JS array.
                continue;
            }

            // Copy the channel data from shared_channels to js_channels.
            rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
            let shared_channel = &(*self.shared_channels.borrow_mut()).buffers[i];
            if Float32Array::create(cx, CreateWith::Slice(shared_channel), array.handle_mut())
                .is_err()
            {
                return false;
            }
            channel.set(array.get());
        }

        true
    }

    // https://webaudio.github.io/web-audio-api/#acquire-the-content
    #[allow(unsafe_code)]
    pub fn acquire_contents(&self) -> Option<ServoMediaAudioBuffer> {
        let cx = self.global().get_cx();
        for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
            // Step 1.
            if channel.get().is_null() {
                return None;
            }

            // Step 2.
            let channel_data = unsafe {
                typedarray!(in(cx) let array: Float32Array = channel.get());
                if let Ok(array) = array {
                    let data = array.to_vec();
                    let mut is_shared = false;
                    rooted!(in (cx) let view_buffer =
                        JS_GetArrayBufferViewBuffer(cx, channel.handle(), &mut is_shared));
                    // This buffer is always created unshared
                    debug_assert!(!is_shared);
                    let _ = JS_DetachArrayBuffer(cx, view_buffer.handle());
                    data
                } else {
                    return None;
                }
            };

            channel.set(ptr::null_mut());

            // Step 3.
            (*self.shared_channels.borrow_mut()).buffers[i] = channel_data;

            // Step 4 will complete turning shared_channels
            // data into js_channels ArrayBuffers in restore_js_channel_data.
        }

        Some((*self.shared_channels.borrow()).clone())
    }
}

impl AudioBufferMethods for AudioBuffer {
    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-samplerate
    fn SampleRate(&self) -> Finite<f32> {
        Finite::wrap(self.sample_rate)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-length
    fn Length(&self) -> u32 {
        self.length
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-duration
    fn Duration(&self) -> Finite<f64> {
        Finite::wrap(self.duration)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-numberofchannels
    fn NumberOfChannels(&self) -> u32 {
        self.number_of_channels
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-getchanneldata
    #[allow(unsafe_code)]
    unsafe fn GetChannelData(
        &self,
        cx: *mut JSContext,
        channel: u32,
    ) -> Fallible<NonNull<JSObject>> {
        if channel >= self.number_of_channels {
            return Err(Error::IndexSize);
        }

        if !self.restore_js_channel_data(cx) {
            return Err(Error::JSFailed);
        }

        Ok(NonNull::new_unchecked(
            self.js_channels.borrow()[channel as usize].get(),
        ))
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copyfromchannel
    #[allow(unsafe_code)]
    fn CopyFromChannel(
        &self,
        mut destination: CustomAutoRooterGuard<Float32Array>,
        channel_number: u32,
        start_in_channel: u32,
    ) -> Fallible<()> {
        if destination.is_shared() {
            return Err(Error::Type("Cannot copy to shared buffer".to_owned()));
        }

        if channel_number >= self.number_of_channels || start_in_channel > self.length {
            return Err(Error::IndexSize);
        }

        let bytes_to_copy = min(self.length - start_in_channel, destination.len() as u32) as usize;
        let cx = self.global().get_cx();
        let channel_number = channel_number as usize;
        let offset = start_in_channel as usize;
        let mut dest = Vec::with_capacity(destination.len());

        // We either copy form js_channels or shared_channels.

        let js_channel = self.js_channels.borrow()[channel_number].get();
        if !js_channel.is_null() {
            typedarray!(in(cx) let array: Float32Array = js_channel);
            if let Ok(array) = array {
                let data = unsafe { array.as_slice() };
                dest.extend_from_slice(&data[offset..offset + bytes_to_copy]);
                return Ok(());
            }
        }

        if let Some(shared_channel) = self.shared_channels.borrow().buffers.get(channel_number) {
            dest.extend_from_slice(&shared_channel.as_slice()[offset..offset + bytes_to_copy]);
        }

        unsafe {
            destination.update(&dest);
        }

        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copytochannel
    #[allow(unsafe_code)]
    fn CopyToChannel(
        &self,
        source: CustomAutoRooterGuard<Float32Array>,
        channel_number: u32,
        start_in_channel: u32,
    ) -> Fallible<()> {
        if source.is_shared() {
            return Err(Error::Type("Cannot copy from shared buffer".to_owned()));
        }

        if channel_number >= self.number_of_channels || start_in_channel > (source.len() as u32) {
            return Err(Error::IndexSize);
        }

        let cx = self.global().get_cx();
        if unsafe { !self.restore_js_channel_data(cx) } {
            return Err(Error::JSFailed);
        }

        let js_channel = self.js_channels.borrow()[channel_number as usize].get();
        if js_channel.is_null() {
            // The array buffer was detached.
            return Err(Error::IndexSize);
        }

        typedarray!(in(cx) let js_channel: Float32Array = js_channel);
        if let Ok(mut js_channel) = js_channel {
            let bytes_to_copy = min(self.length - start_in_channel, source.len() as u32) as usize;
            unsafe {
                let data = &source.as_slice()[0..bytes_to_copy];
                // Update shared channel.
                let mut shared_channels = self.shared_channels.borrow_mut();
                let shared_channel = shared_channels.data_chan_mut(channel_number as u8);
                let (_, mut shared_channel) = shared_channel.split_at_mut(start_in_channel as usize);
                shared_channel[0..bytes_to_copy].copy_from_slice(data);
                // Update js channel.
                js_channel.update(data);
            }
        } else {
            return Err(Error::IndexSize);
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Sample counter service.
use exonum::{
    api, blockchain::{ExecutionError, ExecutionResult, Service, Transaction, TransactionSet},
    crypto::{Hash, PublicKey}, encoding, messages::{Message, RawTransaction},
    node::TransactionSend, storage::{Entry, Fork, Snapshot},
};

pub const SERVICE_ID: u16 = 1;

// "correct horse battery staple" brainwallet pubkey in Ed25519 with SHA-256 digest
pub const ADMIN_KEY: &str = "506f27b1b4c2403f2602d663a059b0262afd6a5bcda95a08dd96a4614a89f1b0";

// // // // Schema // // // //

pub struct CounterSchema<T> {
    view: T,
}

impl<T: AsRef<Snapshot>> CounterSchema<T> {
    pub fn new(view: T) -> Self {
        CounterSchema { view }
    }

    fn entry(&self) -> Entry<&Snapshot, u64> {
        Entry::new("counter.count", self.view.as_ref())
    }

    pub fn count(&self) -> Option<u64> {
        self.entry().get()
    }
}

impl<'a> CounterSchema<&'a mut Fork> {
    fn entry_mut(&mut self) -> Entry<&mut Fork, u64> {
        Entry::new("counter.count", self.view)
    }

    fn inc_count(&mut self, inc: u64) -> u64 {
        let count = self.count().unwrap_or(0) + inc;
        self.entry_mut().set(count);
        count
    }

    fn set_count(&mut self, count: u64) {
        self.entry_mut().set(count);
    }
}

// // // // Transactions // // // //

transactions! {
    pub CounterTransactions {
        const SERVICE_ID = SERVICE_ID;

        struct TxIncrement {
            author: &PublicKey,
            by: u64,
        }

        struct TxReset {
            author: &PublicKey,
        }
    }
}

impl Transaction for TxIncrement {
    fn verify(&self) -> bool {
        self.verify_signature(self.author())
    }

    // This method purposely does not check counter overflow in order to test
    // behavior of panicking transactions.
    fn execute(&self, fork: &mut Fork) -> ExecutionResult {
        if self.by() == 0 {
            Err(ExecutionError::with_description(
                0,
                "Adding zero does nothing!".to_string(),
            ))?;
        }

        let mut schema = CounterSchema::new(fork);
        schema.inc_count(self.by());
        Ok(())
    }
}

impl TxReset {
    pub fn verify_author(&self) -> bool {
        use exonum::encoding::serialize::FromHex;
        *self.author() == PublicKey::from_hex(ADMIN_KEY).unwrap()
    }
}

impl Transaction for TxReset {
    fn verify(&self) -> bool {
        self.verify_author() && self.verify_signature(self.author())
    }

    fn execute(&self, fork: &mut Fork) -> ExecutionResult {
        let mut schema = CounterSchema::new(fork);
        schema.set_count(0);
        Ok(())
    }
}

// // // // API // // // //

#[derive(Debug, Serialize, Deserialize)]
pub struct TransactionResponse {
    pub tx_hash: Hash,
}

#[derive(Debug, Clone, Copy)]
struct CounterApi;

impl CounterApi {
    fn increment(
        state: &api::ServiceApiState,
        transaction: TxIncrement,
    ) -> api::Result<TransactionResponse> {
        trace!("received increment tx");

        let transaction: Box<Transaction> = Box::new(transaction);
        let tx_hash = transaction.hash();
        state.sender().send(transaction)?;
        Ok(TransactionResponse { tx_hash })
    }

    fn count(state: &api::ServiceApiState, _query: ()) -> api::Result<u64> {
        let snapshot = state.snapshot();
        let schema = CounterSchema::new(&snapshot);
        Ok(schema.count().unwrap_or_default())
    }

    fn reset(
        state: &api::ServiceApiState,
        transaction: TxReset,
    ) -> api::Result<TransactionResponse> {
        trace!("received reset tx");

        let transaction: Box<Transaction> = Box::new(transaction);
        let tx_hash = transaction.hash();
        state.sender().send(transaction)?;
        Ok(TransactionResponse { tx_hash })
    }

    fn wire(builder: &mut api::ServiceApiBuilder) {
        builder
            .private_scope()
            .endpoint("count", Self::count)
            .endpoint_mut("reset", Self::reset);
        builder
            .public_scope()
            .endpoint("count", Self::count)
            .endpoint_mut("count", Self::increment);
    }
}

// // // // Service // // // //

pub struct CounterService;

impl Service for CounterService {
    fn service_name(&self) -> &str {
        "counter"
    }

    fn state_hash(&self, _: &Snapshot) -> Vec<Hash> {
        Vec::new()
    }

    fn service_id(&self) -> u16 {
        SERVICE_ID
    }

    /// Implement a method to deserialize transactions coming to the node.
    fn tx_from_raw(&self, raw: RawTransaction) -> Result<Box<Transaction>, encoding::Error> {
        let tx = CounterTransactions::tx_from_raw(raw)?;
        Ok(tx.into())
    }

    fn wire_api(&self, builder: &mut api::ServiceApiBuilder) {
        CounterApi::wire(builder)
    }
}
<commit_msg>test_explorer_transaction_statuses: add explicit panic on overflow (#957)<commit_after>// Copyright 2018 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Sample counter service.
use exonum::{
    api, blockchain::{ExecutionError, ExecutionResult, Service, Transaction, TransactionSet},
    crypto::{Hash, PublicKey}, encoding, messages::{Message, RawTransaction},
    node::TransactionSend, storage::{Entry, Fork, Snapshot},
};

pub const SERVICE_ID: u16 = 1;

// "correct horse battery staple" brainwallet pubkey in Ed25519 with SHA-256 digest
pub const ADMIN_KEY: &str = "506f27b1b4c2403f2602d663a059b0262afd6a5bcda95a08dd96a4614a89f1b0";

// // // // Schema // // // //

pub struct CounterSchema<T> {
    view: T,
}

impl<T: AsRef<Snapshot>> CounterSchema<T> {
    pub fn new(view: T) -> Self {
        CounterSchema { view }
    }

    fn entry(&self) -> Entry<&Snapshot, u64> {
        Entry::new("counter.count", self.view.as_ref())
    }

    pub fn count(&self) -> Option<u64> {
        self.entry().get()
    }
}

impl<'a> CounterSchema<&'a mut Fork> {
    fn entry_mut(&mut self) -> Entry<&mut Fork, u64> {
        Entry::new("counter.count", self.view)
    }

    fn inc_count(&mut self, inc: u64) -> u64 {
        let count = self.count()
            .unwrap_or(0)
            .checked_add(inc)
            .expect("attempt to add with overflow");
        self.entry_mut().set(count);
        count
    }

    fn set_count(&mut self, count: u64) {
        self.entry_mut().set(count);
    }
}

// // // // Transactions // // // //

transactions! {
    pub CounterTransactions {
        const SERVICE_ID = SERVICE_ID;

        struct TxIncrement {
            author: &PublicKey,
            by: u64,
        }

        struct TxReset {
            author: &PublicKey,
        }
    }
}

impl Transaction for TxIncrement {
    fn verify(&self) -> bool {
        self.verify_signature(self.author())
    }

    // This method purposely does not check counter overflow in order to test
    // behavior of panicking transactions.
    fn execute(&self, fork: &mut Fork) -> ExecutionResult {
        if self.by() == 0 {
            Err(ExecutionError::with_description(
                0,
                "Adding zero does nothing!".to_string(),
            ))?;
        }

        let mut schema = CounterSchema::new(fork);
        schema.inc_count(self.by());
        Ok(())
    }
}

impl TxReset {
    pub fn verify_author(&self) -> bool {
        use exonum::encoding::serialize::FromHex;
        *self.author() == PublicKey::from_hex(ADMIN_KEY).unwrap()
    }
}

impl Transaction for TxReset {
    fn verify(&self) -> bool {
        self.verify_author() && self.verify_signature(self.author())
    }

    fn execute(&self, fork: &mut Fork) -> ExecutionResult {
        let mut schema = CounterSchema::new(fork);
        schema.set_count(0);
        Ok(())
    }
}

// // // // API // // // //

#[derive(Debug, Serialize, Deserialize)]
pub struct TransactionResponse {
    pub tx_hash: Hash,
}

#[derive(Debug, Clone, Copy)]
struct CounterApi;

impl CounterApi {
    fn increment(
        state: &api::ServiceApiState,
        transaction: TxIncrement,
    ) -> api::Result<TransactionResponse> {
        trace!("received increment tx");

        let transaction: Box<Transaction> = Box::new(transaction);
        let tx_hash = transaction.hash();
        state.sender().send(transaction)?;
        Ok(TransactionResponse { tx_hash })
    }

    fn count(state: &api::ServiceApiState, _query: ()) -> api::Result<u64> {
        let snapshot = state.snapshot();
        let schema = CounterSchema::new(&snapshot);
        Ok(schema.count().unwrap_or_default())
    }

    fn reset(
        state: &api::ServiceApiState,
        transaction: TxReset,
    ) -> api::Result<TransactionResponse> {
        trace!("received reset tx");

        let transaction: Box<Transaction> = Box::new(transaction);
        let tx_hash = transaction.hash();
        state.sender().send(transaction)?;
        Ok(TransactionResponse { tx_hash })
    }

    fn wire(builder: &mut api::ServiceApiBuilder) {
        builder
            .private_scope()
            .endpoint("count", Self::count)
            .endpoint_mut("reset", Self::reset);
        builder
            .public_scope()
            .endpoint("count", Self::count)
            .endpoint_mut("count", Self::increment);
    }
}

// // // // Service // // // //

pub struct CounterService;

impl Service for CounterService {
    fn service_name(&self) -> &str {
        "counter"
    }

    fn state_hash(&self, _: &Snapshot) -> Vec<Hash> {
        Vec::new()
    }

    fn service_id(&self) -> u16 {
        SERVICE_ID
    }

    /// Implement a method to deserialize transactions coming to the node.
    fn tx_from_raw(&self, raw: RawTransaction) -> Result<Box<Transaction>, encoding::Error> {
        let tx = CounterTransactions::tx_from_raw(raw)?;
        Ok(tx.into())
    }

    fn wire_api(&self, builder: &mut api::ServiceApiBuilder) {
        CounterApi::wire(builder)
    }
}
<|endoftext|>


<commit_before>use crate::schema::Term;
use crate::termdict::TermOrdinal;
use crate::termdict::TermStreamer;
use std::cmp::Ordering;
use std::collections::BinaryHeap;

pub struct HeapItem<'a> {
    pub streamer: TermStreamer<'a>,
    pub segment_ord: usize,
}

impl<'a> PartialEq for HeapItem<'a> {
    fn eq(&self, other: &Self) -> bool {
        self.segment_ord == other.segment_ord
    }
}

impl<'a> Eq for HeapItem<'a> {}

impl<'a> PartialOrd for HeapItem<'a> {
    fn partial_cmp(&self, other: &HeapItem<'a>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<'a> Ord for HeapItem<'a> {
    fn cmp(&self, other: &HeapItem<'a>) -> Ordering {
        (&other.streamer.key(), &other.segment_ord).cmp(&(&self.streamer.key(), &self.segment_ord))
    }
}

/// Given a list of sorted term streams,
/// returns an iterator over sorted unique terms.
///
/// The item yield is actually a pair with
/// - the term
/// - a slice with the ordinal of the segments containing
/// the terms.
pub struct TermMerger<'a> {
    heap: BinaryHeap<HeapItem<'a>>,
    current_streamers: Vec<HeapItem<'a>>,
}

impl<'a> TermMerger<'a> {
    /// Stream of merged term dictionary
    ///
    pub fn new(streams: Vec<TermStreamer<'a>>) -> TermMerger<'a> {
        TermMerger {
            heap: BinaryHeap::new(),
            current_streamers: streams
                .into_iter()
                .enumerate()
                .map(|(ord, streamer)| HeapItem {
                    streamer,
                    segment_ord: ord,
                })
                .collect(),
        }
    }

    pub(crate) fn matching_segments<'b: 'a>(
        &'b self,
    ) -> impl 'b + Iterator<Item = (usize, TermOrdinal)> {
        self.current_streamers
            .iter()
            .map(|heap_item| (heap_item.segment_ord, heap_item.streamer.term_ord()))
    }

    fn advance_segments(&mut self) {
        let streamers = &mut self.current_streamers;
        let heap = &mut self.heap;
        for mut heap_item in streamers.drain(..) {
            if heap_item.streamer.advance() {
                heap.push(heap_item);
            }
        }
    }

    /// Advance the term iterator to the next term.
    /// Returns true if there is indeed another term
    /// False if there is none.
    pub fn advance(&mut self) -> bool {
        self.advance_segments();
        if let Some(head) = self.heap.pop() {
            self.current_streamers.push(head);
            while let Some(next_streamer) = self.heap.peek() {
                if self.current_streamers[0].streamer.key() != next_streamer.streamer.key() {
                    break;
                }
                let next_heap_it = self.heap.pop().unwrap(); // safe : we peeked beforehand
                self.current_streamers.push(next_heap_it);
            }
            true
        } else {
            false
        }
    }

    /// Returns the current term.
    ///
    /// This method may be called
    /// iff advance() has been called before
    /// and "true" was returned.
    pub fn key(&self) -> &[u8] {
        self.current_streamers[0].streamer.key()
    }

    /// Returns the sorted list of segment ordinals
    /// that include the current term.
    ///
    /// This method may be called
    /// iff advance() has been called before
    /// and "true" was returned.
    pub fn current_kvs(&self) -> &[HeapItem<'a>] {
        &self.current_streamers[..]
    }

    /// Iterates through terms
    #[cfg_attr(feature = "cargo-clippy", allow(clippy::should_implement_trait))]
    pub fn next(&mut self) -> Option<Term<&[u8]>> {
        if self.advance() {
            Some(Term::wrap(self.current_streamers[0].streamer.key()))
        } else {
            None
        }
    }
}
<commit_msg>Removing `TermMerger::next()`.<commit_after>use crate::termdict::TermOrdinal;
use crate::termdict::TermStreamer;
use std::cmp::Ordering;
use std::collections::BinaryHeap;

pub struct HeapItem<'a> {
    pub streamer: TermStreamer<'a>,
    pub segment_ord: usize,
}

impl<'a> PartialEq for HeapItem<'a> {
    fn eq(&self, other: &Self) -> bool {
        self.segment_ord == other.segment_ord
    }
}

impl<'a> Eq for HeapItem<'a> {}

impl<'a> PartialOrd for HeapItem<'a> {
    fn partial_cmp(&self, other: &HeapItem<'a>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<'a> Ord for HeapItem<'a> {
    fn cmp(&self, other: &HeapItem<'a>) -> Ordering {
        (&other.streamer.key(), &other.segment_ord).cmp(&(&self.streamer.key(), &self.segment_ord))
    }
}

/// Given a list of sorted term streams,
/// returns an iterator over sorted unique terms.
///
/// The item yield is actually a pair with
/// - the term
/// - a slice with the ordinal of the segments containing
/// the terms.
pub struct TermMerger<'a> {
    heap: BinaryHeap<HeapItem<'a>>,
    current_streamers: Vec<HeapItem<'a>>,
}

impl<'a> TermMerger<'a> {
    /// Stream of merged term dictionary
    ///
    pub fn new(streams: Vec<TermStreamer<'a>>) -> TermMerger<'a> {
        TermMerger {
            heap: BinaryHeap::new(),
            current_streamers: streams
                .into_iter()
                .enumerate()
                .map(|(ord, streamer)| HeapItem {
                    streamer,
                    segment_ord: ord,
                })
                .collect(),
        }
    }

    pub(crate) fn matching_segments<'b: 'a>(
        &'b self,
    ) -> impl 'b + Iterator<Item = (usize, TermOrdinal)> {
        self.current_streamers
            .iter()
            .map(|heap_item| (heap_item.segment_ord, heap_item.streamer.term_ord()))
    }

    fn advance_segments(&mut self) {
        let streamers = &mut self.current_streamers;
        let heap = &mut self.heap;
        for mut heap_item in streamers.drain(..) {
            if heap_item.streamer.advance() {
                heap.push(heap_item);
            }
        }
    }

    /// Advance the term iterator to the next term.
    /// Returns true if there is indeed another term
    /// False if there is none.
    pub fn advance(&mut self) -> bool {
        self.advance_segments();
        if let Some(head) = self.heap.pop() {
            self.current_streamers.push(head);
            while let Some(next_streamer) = self.heap.peek() {
                if self.current_streamers[0].streamer.key() != next_streamer.streamer.key() {
                    break;
                }
                let next_heap_it = self.heap.pop().unwrap(); // safe : we peeked beforehand
                self.current_streamers.push(next_heap_it);
            }
            true
        } else {
            false
        }
    }

    /// Returns the current term.
    ///
    /// This method may be called
    /// iff advance() has been called before
    /// and "true" was returned.
    pub fn key(&self) -> &[u8] {
        self.current_streamers[0].streamer.key()
    }

    /// Returns the sorted list of segment ordinals
    /// that include the current term.
    ///
    /// This method may be called
    /// iff advance() has been called before
    /// and "true" was returned.
    pub fn current_kvs(&self) -> &[HeapItem<'a>] {
        &self.current_streamers[..]
    }
}
<|endoftext|>