<commit_before>#![no_std]

extern crate alloc;
extern crate lang_items;
extern crate libtock_drivers;

use core::fmt::Write;
use libtock_drivers::console::Console;

#[cfg(not(feature = "with_nfc"))]
mod example {
    use super::Console;
    use super::Write;

    pub fn nfc(console: &mut Console) {
        writeln!(console, "NFC feature flag is missing!").unwrap();
    }
}

#[cfg(feature = "with_nfc")]
mod example {

    use super::Console;
    use super::Write;
    use libtock_core::result::CommandError;
    use libtock_drivers::nfc::NfcTag;
    use libtock_drivers::nfc::RecvOp;
    use libtock_drivers::result::FlexUnwrap;
    use libtock_drivers::result::TockError;
    use libtock_drivers::timer;
    use libtock_drivers::timer::Timer;
    use libtock_drivers::timer::Timestamp;

    /// Helper function to write on console the received packet.
    fn print_rx_buffer(buf: &mut [u8]) {
        let mut console = Console::new();
        write!(console, "RX:").unwrap();
        if let Some((last, bytes)) = buf.split_last() {
            for byte in bytes {
                write!(console, " {:02x?}", byte).unwrap();
            }
            writeln!(console, " {:02x?}", last).unwrap();
        }
        console.flush();
    }

    /// Function to identify the time elapsed for a transmission request.
    fn bench_transmit(console: &mut Console, timer: &Timer, title: &str, mut buf: &mut [u8]) {
        let amount = buf.len();
        let start = Timestamp::<f64>::from_clock_value(timer.get_current_clock().flex_unwrap());
        match NfcTag::transmit(&mut buf, amount) {
            Ok(_) => (),
            Err(_) => writeln!(Console::new(), " -- tx error!").unwrap(),
        }
        let end = Timestamp::<f64>::from_clock_value(timer.get_current_clock().flex_unwrap());
        let elapsed = (end - start).ms();
        writeln!(
            console,
            "{}\n{:.2} ms elapsed for {} bytes ({:.2} kbit/s)",
            title,
            elapsed,
            amount,
            (amount as f64) / elapsed * 8.
        )
        .unwrap();
        console.flush();
    }

    fn receive_packet(console: &mut Console, mut buf: &mut [u8; 256]) {
        match NfcTag::receive(&mut buf) {
            Ok(RecvOp {
                recv_amount: amount,
                ..
            }) => {
                if amount > 0 && amount <= buf.len() {
                    print_rx_buffer(&mut buf[..amount]);
                }
            }
            Err(TockError::Command(CommandError {
                return_code: -4, /* EOFF: Not Ready */
                ..
            })) => (),
            Err(TockError::Command(CommandError {
                return_code: value, ..
            })) => writeln!(console, " -- Err({})!", value).unwrap(),
            Err(_) => writeln!(console, " -- RX Err").unwrap(),
        }
    }

    fn transmit_reply(mut console: &mut Console, timer: &Timer, buf: &[u8]) -> bool {
        match buf[0] {
            0xe0 /* RATS */=> {
                let mut answer_to_select = [0x05, 0x78, 0x80, 0xB1, 0x00];
                bench_transmit(&mut console, &timer, "TX: ATS", &mut answer_to_select);
            }
            0xc2 /* DESELECT */ => {
                // Ignore the request
                let mut command_error = [0x6A, 0x81];
                bench_transmit(&mut console, &timer, "TX: DESELECT", &mut command_error);
            }
            0x02 | 0x03 /* APDU Prefix */ => match buf[2] {
                // If the received packet is applet selection command (FIDO 2)
                0xa4 /* SELECT */ => if buf[3] == 0x04 && buf[5] == 0x08 && buf[6] == 0xa0 {
                        // Vesion: "FIDO_2_0"
                        let mut reply = [buf[0], 0x46, 0x49, 0x44, 0x4f, 0x5f, 0x32, 0x5f, 0x30, 0x90, 0x00,];
                        bench_transmit(&mut console, &timer, "TX: Version Str", &mut reply);
                    } else {
                        let mut reply = [buf[0], 0x90, 0x00];
                        bench_transmit(&mut console, &timer, "TX: 0x9000", &mut reply);
                    }
                0xb0 /* READ */ =>  match buf[5] {
                        0x02 => {
                        let mut reply = [buf[0], 0x12, 0x90, 0x00,];
                        bench_transmit(&mut console, &timer, "TX: File Size", &mut reply);
                    }
                    0x12 => {
                        let mut reply = [buf[0], 0xd1, 0x01, 0x0e, 0x55, 0x77, 0x77, 0x77, 0x2e, 0x6f, 0x70, 0x65,
                        0x6e, 0x73, 0x6b, 0x2e, 0x64, 0x65, 0x76, 0x90, 0x00,];
                        bench_transmit(&mut console, &timer, "TX: NDEF", &mut reply);
                    }
                    0x0f => {
                        let mut reply = [buf[0], 0x00, 0x0f, 0x20, 0x00, 0x7f, 0x00, 0x7f, 0x04, 0x06, 0xe1, 0x04,
                        0x00, 0x7f, 0x00, 0x00, 0x90, 0x00,];
                        bench_transmit(&mut console, &timer, "TX: CC", &mut reply);
                    }
                    _ => {
                        let mut reply = [buf[0], 0x90, 0x00];
                        bench_transmit(&mut console, &timer, "TX: 0x9000", &mut reply);
                    }
                }
                _ => {
                    let mut reply = [buf[0], 0x90, 0x00];
                    bench_transmit(&mut console, &timer, "TX: 0x9000", &mut reply);
                }
            }
            0x26 | 0x52 | 0x50 /* REQA | WUPA | Halt */ => {
                if NfcTag::disable_emulation() {
                    writeln!(console, " -- TAG DISABLED").unwrap();
                }
                return false;
            }
            _ => (),
        }
        true
    }

    pub fn nfc(mut console: &mut Console) {
        // Setup the timer with a dummy callback (we only care about reading the current time, but the
        // API forces us to set an alarm callback too).
        let mut with_callback = timer::with_callback(|_, _| {});
        let timer = with_callback.init().flex_unwrap();

        writeln!(
            console,
            "Clock frequency: {} Hz",
            timer.clock_frequency().hz()
        )
        .unwrap();

        let mut is_enabled = false;
        let mut state_change_counter = 0;
        loop {
            match is_enabled {
                true => {
                    let mut rx_buf = [0; 256];
                    loop {
                        receive_packet(&mut console, &mut rx_buf);
                        // If the reader restarts the communication and we can't
                        // reply to the received packet, then disable the tag.
                        if !transmit_reply(&mut console, &timer, &rx_buf) {
                            is_enabled = false;
                            break;
                        }
                    }
                }
                false => {
                    NfcTag::enable_emulation();
                    // Configure Type 4 tag
                    if NfcTag::configure(4) {
                        is_enabled = true;
                    }
                }
            }
            state_change_counter += 1;
            if state_change_counter > 100 && is_enabled == false {
                break;
            }
        }
    }
}

fn main() {
    let mut console = Console::new();
    writeln!(console, "****************************************").unwrap();
    writeln!(console, "nfct_test application is installed").unwrap();
    example::nfc(&mut console);
    writeln!(console, "****************************************").unwrap();
}
<commit_msg>Refactor a `match` expression<commit_after>#![no_std]

extern crate alloc;
extern crate lang_items;
extern crate libtock_drivers;

use core::fmt::Write;
use libtock_drivers::console::Console;

#[cfg(not(feature = "with_nfc"))]
mod example {
    use super::Console;
    use super::Write;

    pub fn nfc(console: &mut Console) {
        writeln!(console, "NFC feature flag is missing!").unwrap();
    }
}

#[cfg(feature = "with_nfc")]
mod example {
    use super::Console;
    use super::Write;
    use libtock_core::result::CommandError;
    use libtock_drivers::nfc::NfcTag;
    use libtock_drivers::nfc::RecvOp;
    use libtock_drivers::result::FlexUnwrap;
    use libtock_drivers::result::TockError;
    use libtock_drivers::timer;
    use libtock_drivers::timer::Timer;
    use libtock_drivers::timer::Timestamp;

    /// Helper function to write on console the received packet.
    fn print_rx_buffer(buf: &mut [u8]) {
        let mut console = Console::new();
        write!(console, "RX:").unwrap();
        if let Some((last, bytes)) = buf.split_last() {
            for byte in bytes {
                write!(console, " {:02x?}", byte).unwrap();
            }
            writeln!(console, " {:02x?}", last).unwrap();
        }
        console.flush();
    }

    /// Function to identify the time elapsed for a transmission request.
    fn bench_transmit(console: &mut Console, timer: &Timer, title: &str, mut buf: &mut [u8]) {
        let amount = buf.len();
        let start = Timestamp::<f64>::from_clock_value(timer.get_current_clock().flex_unwrap());
        match NfcTag::transmit(&mut buf, amount) {
            Ok(_) => (),
            Err(_) => writeln!(Console::new(), " -- tx error!").unwrap(),
        }
        let end = Timestamp::<f64>::from_clock_value(timer.get_current_clock().flex_unwrap());
        let elapsed = (end - start).ms();
        writeln!(
            console,
            "{}\n{:.2} ms elapsed for {} bytes ({:.2} kbit/s)",
            title,
            elapsed,
            amount,
            (amount as f64) / elapsed * 8.
        )
        .unwrap();
        console.flush();
    }

    fn receive_packet(console: &mut Console, mut buf: &mut [u8; 256]) {
        match NfcTag::receive(&mut buf) {
            Ok(RecvOp {
                recv_amount: amount,
                ..
            }) => {
                if amount > 0 && amount <= buf.len() {
                    print_rx_buffer(&mut buf[..amount]);
                }
            }
            Err(TockError::Command(CommandError {
                return_code: -4, /* EOFF: Not Ready */
                ..
            })) => (),
            Err(TockError::Command(CommandError {
                return_code: value, ..
            })) => writeln!(console, " -- Err({})!", value).unwrap(),
            Err(_) => writeln!(console, " -- RX Err").unwrap(),
        }
    }

    fn transmit_reply(mut console: &mut Console, timer: &Timer, buf: &[u8]) -> bool {
        match buf[0] {
            0xe0 /* RATS */=> {
                let mut answer_to_select = [0x05, 0x78, 0x80, 0xB1, 0x00];
                bench_transmit(&mut console, &timer, "TX: ATS", &mut answer_to_select);
            }
            0xc2 /* DESELECT */ => {
                // Ignore the request
                let mut command_error = [0x6A, 0x81];
                bench_transmit(&mut console, &timer, "TX: DESELECT", &mut command_error);
            }
            0x02 | 0x03 /* APDU Prefix */ => match buf[2] {
                // If the received packet is applet selection command (FIDO 2)
                0xa4 /* SELECT */ => if buf[3] == 0x04 && buf[5] == 0x08 && buf[6] == 0xa0 {
                        // Vesion: "FIDO_2_0"
                        let mut reply = [buf[0], 0x46, 0x49, 0x44, 0x4f, 0x5f, 0x32, 0x5f, 0x30, 0x90, 0x00,];
                        bench_transmit(&mut console, &timer, "TX: Version Str", &mut reply);
                    } else {
                        let mut reply = [buf[0], 0x90, 0x00];
                        bench_transmit(&mut console, &timer, "TX: 0x9000", &mut reply);
                    }
                0xb0 /* READ */ =>  match buf[5] {
                        0x02 => {
                        let mut reply = [buf[0], 0x12, 0x90, 0x00,];
                        bench_transmit(&mut console, &timer, "TX: File Size", &mut reply);
                    }
                    0x12 => {
                        let mut reply = [buf[0], 0xd1, 0x01, 0x0e, 0x55, 0x77, 0x77, 0x77, 0x2e, 0x6f, 0x70, 0x65,
                        0x6e, 0x73, 0x6b, 0x2e, 0x64, 0x65, 0x76, 0x90, 0x00,];
                        bench_transmit(&mut console, &timer, "TX: NDEF", &mut reply);
                    }
                    0x0f => {
                        let mut reply = [buf[0], 0x00, 0x0f, 0x20, 0x00, 0x7f, 0x00, 0x7f, 0x04, 0x06, 0xe1, 0x04,
                        0x00, 0x7f, 0x00, 0x00, 0x90, 0x00,];
                        bench_transmit(&mut console, &timer, "TX: CC", &mut reply);
                    }
                    _ => {
                        let mut reply = [buf[0], 0x90, 0x00];
                        bench_transmit(&mut console, &timer, "TX: 0x9000", &mut reply);
                    }
                }
                _ => {
                    let mut reply = [buf[0], 0x90, 0x00];
                    bench_transmit(&mut console, &timer, "TX: 0x9000", &mut reply);
                }
            }
            0x26 | 0x52 | 0x50 /* REQA | WUPA | Halt */ => {
                if NfcTag::disable_emulation() {
                    writeln!(console, " -- TAG DISABLED").unwrap();
                }
                return false;
            }
            _ => (),
        }
        true
    }

    pub fn nfc(mut console: &mut Console) {
        // Setup the timer with a dummy callback (we only care about reading the current time, but the
        // API forces us to set an alarm callback too).
        let mut with_callback = timer::with_callback(|_, _| {});
        let timer = with_callback.init().flex_unwrap();

        writeln!(
            console,
            "Clock frequency: {} Hz",
            timer.clock_frequency().hz()
        )
        .unwrap();

        let mut is_enabled = false;
        let mut state_change_counter = 0;
        loop {
            if is_enabled {
                let mut rx_buf = [0; 256];
                loop {
                    receive_packet(&mut console, &mut rx_buf);
                    // If the reader restarts the communication and we can't
                    // reply to the received packet, then disable the tag.
                    if !transmit_reply(&mut console, &timer, &rx_buf) {
                        is_enabled = false;
                        break;
                    }
                }
            } else {
                NfcTag::enable_emulation();
                // Configure Type 4 tag
                if NfcTag::configure(4) {
                    is_enabled = true;
                }
            }
            state_change_counter += 1;
            if !is_enabled && state_change_counter > 100 {
                break;
            }
        }
    }
}

fn main() {
    let mut console = Console::new();
    writeln!(console, "****************************************").unwrap();
    writeln!(console, "nfct_test application is installed").unwrap();
    example::nfc(&mut console);
    writeln!(console, "****************************************").unwrap();
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use std::io::{Read, Write};
use std::collections::HashMap;
use bincode::{self, serde};
use euclid::Point2D;
use calx_resource::ResourceStore;
use calx_ecs::Entity;
use calx_grid::Dir6;
use field::Field;
use spatial::{Place, Spatial};
use flags::Flags;
use location::{Location, Portal};
use components;
use stats;
use terrain;
use query::Query;
use command::{Command, CommandResult};
use mutate::Mutate;
use terraform::{Terraform, TerrainQuery};

pub const GAME_VERSION: &'static str = "0.1.0";

Ecs! {
    desc: components::Desc,
    map_memory: components::MapMemory,
    health: components::Health,
    brain: components::Brain,
    item: components::Item,
    composite_stats: components::CompositeStats,
    stats: stats::Stats,
}

/// Toplevel game state object.
#[derive(RustcEncodable, RustcDecodable)]
pub struct World {
    /// Game version. Not mutable in the slightest, but the simplest way to
    /// get versioned save files is to just drop it here.
    version: String,
    /// Entity component system.
    ecs: Ecs,
    /// Terrain data.
    terrain: Field<u8>,
    /// Optional portals between map zones.
    portals: HashMap<Location, Portal>,
    /// Spatial index for game entities.
    spatial: Spatial,
    /// Global gamestate flags.
    flags: Flags,
}

impl<'a> World {
    pub fn new(seed: u32) -> World {
        let mut ret = World {
            version: GAME_VERSION.to_string(),
            ecs: Ecs::new(),
            terrain: Field::new(0),
            portals: HashMap::new(),
            spatial: Spatial::new(),
            flags: Flags::new(seed),
        };

        ret.init_level(1);

        ret
    }

    /* TODO: Reactivate for rustc-serialize

    pub fn load<R: Read>(reader: &mut R) -> serde::DeserializeResult<World> {
        let ret: serde::DeserializeResult<World> =
            serde::deserialize_from(reader, bincode::SizeLimit::Infinite);
        if let &Ok(ref x) = &ret {
            if &x.version != GAME_VERSION {
                panic!("Save game version {} does not match current version \
                        {}",
                       x.version,
                       GAME_VERSION);
            }
        }
        ret
    }

    pub fn save<W: Write>(&self, writer: &mut W) -> serde::SerializeResult<()> {
        serde::serialize_into(writer, self, bincode::SizeLimit::Infinite)
    }
    */

    fn default_terrain_id(&self, loc: Location) -> u8 {
        terrain::Id::Rock as u8
    }
}

impl TerrainQuery for World {
    fn is_valid_location(&self, loc: Location) -> bool {
        ::on_screen(Point2D::new(loc.x as i32, loc.y as i32))
    }

    fn terrain_id(&self, loc: Location) -> u8 {
        let idx = self.terrain.get(loc);

        if idx == 0 {
            self.default_terrain_id(loc)
        } else {
            idx
        }
    }

    fn portal(&self, loc: Location) -> Option<Location> { self.portals.get(&loc).map(|&p| loc + p) }

    fn is_untouched(&self, loc: Location) -> bool {
        !self.terrain.overrides(loc)
    }
}

impl Query for World {
    fn location(&self, e: Entity) -> Option<Location> {
        match self.spatial.get(e) {
            Some(Place::At(loc)) => Some(loc),
            Some(Place::In(container, _)) => self.location(container),
            _ => None,
        }
    }

    fn player(&self) -> Option<Entity> {
        if let Some(p) = self.flags.player {
            if self.is_alive(p) {
                return Some(p);
            }
        }

        None
    }

    fn tick(&self) -> u64 { self.flags.tick }

    fn rng_seed(&self) -> u32 { self.flags.seed }

    fn entities_at(&self, loc: Location) -> Vec<Entity> { self.spatial.entities_at(loc) }

    fn ecs<'a>(&'a self) -> &'a Ecs { &self.ecs }
}

impl Mutate for World {
    fn next_tick(&mut self) -> CommandResult {
        // TODO: Run AI
        // TODO: Clean dead
        self.flags.tick += 1;
        Ok(())
    }

    fn set_entity_location(&mut self, e: Entity, loc: Location) { self.spatial.insert_at(e, loc); }

    fn set_player(&mut self, player: Entity) { self.flags.player = Some(player); }

    fn spawn(&mut self, loadout: &Loadout) -> Entity { loadout.make(&mut self.ecs) }
}

impl Command for World {
    fn step(&mut self, dir: Dir6) -> CommandResult {
        let player = try!(self.player().ok_or(()));
        try!(self.entity_step(player, dir));
        self.next_tick()
    }

    fn melee(&mut self, dir: Dir6) -> CommandResult {
        let player = try!(self.player().ok_or(()));
        try!(self.entity_melee(player, dir));
        self.next_tick()
    }

    fn pass(&mut self) -> CommandResult { self.next_tick() }
}

impl Terraform for World {
    fn set_terrain(&mut self, loc: Location, terrain: u8) {
        self.terrain.set(loc, terrain);
    }

    fn set_portal(&mut self, loc: Location, mut portal: Portal) {
        let target_loc = loc + portal;
        // Don't create portal chains, if the target cell has another portal, just direct to its
        // destination.
        if let Some(&p) = self.portals.get(&target_loc) {
            portal = portal + p;
        }

        if portal.dx == 0 && portal.dy == 0 && portal.z == loc.z {
            self.portals.remove(&loc);
        } else {
            self.portals.insert(loc, portal);
        }
    }

    fn remove_portal(&mut self, loc: Location) { self.portals.remove(&loc); }
}
<commit_msg>Default terrain is Empty<commit_after>use std::sync::Arc;
use std::io::{Read, Write};
use std::collections::HashMap;
use bincode::{self, serde};
use euclid::Point2D;
use calx_resource::ResourceStore;
use calx_ecs::Entity;
use calx_grid::Dir6;
use field::Field;
use spatial::{Place, Spatial};
use flags::Flags;
use location::{Location, Portal};
use components;
use stats;
use terrain;
use query::Query;
use command::{Command, CommandResult};
use mutate::Mutate;
use terraform::{Terraform, TerrainQuery};

pub const GAME_VERSION: &'static str = "0.1.0";

Ecs! {
    desc: components::Desc,
    map_memory: components::MapMemory,
    health: components::Health,
    brain: components::Brain,
    item: components::Item,
    composite_stats: components::CompositeStats,
    stats: stats::Stats,
}

/// Toplevel game state object.
#[derive(RustcEncodable, RustcDecodable)]
pub struct World {
    /// Game version. Not mutable in the slightest, but the simplest way to
    /// get versioned save files is to just drop it here.
    version: String,
    /// Entity component system.
    ecs: Ecs,
    /// Terrain data.
    terrain: Field<u8>,
    /// Optional portals between map zones.
    portals: HashMap<Location, Portal>,
    /// Spatial index for game entities.
    spatial: Spatial,
    /// Global gamestate flags.
    flags: Flags,
}

impl<'a> World {
    pub fn new(seed: u32) -> World {
        let mut ret = World {
            version: GAME_VERSION.to_string(),
            ecs: Ecs::new(),
            terrain: Field::new(0),
            portals: HashMap::new(),
            spatial: Spatial::new(),
            flags: Flags::new(seed),
        };

        ret.init_level(1);

        ret
    }

    /* TODO: Reactivate for rustc-serialize

    pub fn load<R: Read>(reader: &mut R) -> serde::DeserializeResult<World> {
        let ret: serde::DeserializeResult<World> =
            serde::deserialize_from(reader, bincode::SizeLimit::Infinite);
        if let &Ok(ref x) = &ret {
            if &x.version != GAME_VERSION {
                panic!("Save game version {} does not match current version \
                        {}",
                       x.version,
                       GAME_VERSION);
            }
        }
        ret
    }

    pub fn save<W: Write>(&self, writer: &mut W) -> serde::SerializeResult<()> {
        serde::serialize_into(writer, self, bincode::SizeLimit::Infinite)
    }
    */

    fn default_terrain_id(&self, loc: Location) -> u8 {
        terrain::Id::Empty as u8
    }
}

impl TerrainQuery for World {
    fn is_valid_location(&self, loc: Location) -> bool {
        ::on_screen(Point2D::new(loc.x as i32, loc.y as i32))
    }

    fn terrain_id(&self, loc: Location) -> u8 {
        let idx = self.terrain.get(loc);

        if idx == 0 {
            self.default_terrain_id(loc)
        } else {
            idx
        }
    }

    fn portal(&self, loc: Location) -> Option<Location> { self.portals.get(&loc).map(|&p| loc + p) }

    fn is_untouched(&self, loc: Location) -> bool {
        !self.terrain.overrides(loc)
    }
}

impl Query for World {
    fn location(&self, e: Entity) -> Option<Location> {
        match self.spatial.get(e) {
            Some(Place::At(loc)) => Some(loc),
            Some(Place::In(container, _)) => self.location(container),
            _ => None,
        }
    }

    fn player(&self) -> Option<Entity> {
        if let Some(p) = self.flags.player {
            if self.is_alive(p) {
                return Some(p);
            }
        }

        None
    }

    fn tick(&self) -> u64 { self.flags.tick }

    fn rng_seed(&self) -> u32 { self.flags.seed }

    fn entities_at(&self, loc: Location) -> Vec<Entity> { self.spatial.entities_at(loc) }

    fn ecs<'a>(&'a self) -> &'a Ecs { &self.ecs }
}

impl Mutate for World {
    fn next_tick(&mut self) -> CommandResult {
        // TODO: Run AI
        // TODO: Clean dead
        self.flags.tick += 1;
        Ok(())
    }

    fn set_entity_location(&mut self, e: Entity, loc: Location) { self.spatial.insert_at(e, loc); }

    fn set_player(&mut self, player: Entity) { self.flags.player = Some(player); }

    fn spawn(&mut self, loadout: &Loadout) -> Entity { loadout.make(&mut self.ecs) }
}

impl Command for World {
    fn step(&mut self, dir: Dir6) -> CommandResult {
        let player = try!(self.player().ok_or(()));
        try!(self.entity_step(player, dir));
        self.next_tick()
    }

    fn melee(&mut self, dir: Dir6) -> CommandResult {
        let player = try!(self.player().ok_or(()));
        try!(self.entity_melee(player, dir));
        self.next_tick()
    }

    fn pass(&mut self) -> CommandResult { self.next_tick() }
}

impl Terraform for World {
    fn set_terrain(&mut self, loc: Location, terrain: u8) {
        self.terrain.set(loc, terrain);
    }

    fn set_portal(&mut self, loc: Location, mut portal: Portal) {
        let target_loc = loc + portal;
        // Don't create portal chains, if the target cell has another portal, just direct to its
        // destination.
        if let Some(&p) = self.portals.get(&target_loc) {
            portal = portal + p;
        }

        if portal.dx == 0 && portal.dy == 0 && portal.z == loc.z {
            self.portals.remove(&loc);
        } else {
            self.portals.insert(loc, portal);
        }
    }

    fn remove_portal(&mut self, loc: Location) { self.portals.remove(&loc); }
}
<|endoftext|>


<commit_before>//!
//! The API for communicating with devices.
//!
//! This API is provided as Traits to be implemented:
//!
//! - by the low-level layers of the FoxBox, including the adapters;
//! - by test suites and tools that need to simulate connected devices.
//!
//! In turn, this API is used to implement:
//!
//! - the public-facing REST and WebSocket API;
//! - the rules API (ThinkerBell).
//!
//!

use services::*;
use selector::*;
use values::{Value, Range, TypeError};
use util::{Exactly, Id};

use std::sync::mpsc::Sender;

/// An error that took place while communicating with either an adapter or the mechanism that
/// handles registeration of adapters.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum AdapterError {
    DuplicateGetter(Id<Getter>),
    NoSuchGetter(Id<Getter>),
    GetterDoesNotSupportPolling(Id<Getter>),
    GetterDoesNotSupportWatching(Id<Getter>),
    GetterRequiresThresholdForWatching(Id<Getter>),

    DuplicateSetter(Id<Setter>),
    NoSuchSetter(Id<Setter>),

    DuplicateService(Id<ServiceId>),
    NoSuchService(Id<ServiceId>),
    TypeError(TypeError),

    DuplicateAdapter(Id<AdapterId>),
    ConflictingAdapter(Id<AdapterId>, Id<AdapterId>),
    NoSuchAdapter(Id<AdapterId>),
    InvalidValue
}

/// An error produced by one of the APIs in this module.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Error {
    /// There is no such service connected to the Foxbox, even indirectly.
    NoSuchService(Id<ServiceId>),

    /// There is no such getter channel connected to the Foxbox, even indirectly.
    NoSuchGetter(Id<Getter>),

    /// There is no such setter channel connected to the Foxbox, even indirectly.
    NoSuchSetter(Id<Setter>),

    /// Attempting to set a value with the wrong type.{}
    TypeError,

    /// An error arose when talking to the adapter.
    AdapterError(AdapterError),
}

/// An event during watching.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum WatchEvent {
    /// A new value is available.
    Value {
        /// The channel that sent the value.
        from: Id<Getter>,

        /// The actual value.
        value: Value
    },

    /// The set of devices being watched has changed, typically either
    /// because a tag was edited or because a device was
    /// removed. Payload is the id of the device that was removed.
    GetterRemoved(Id<Getter>),

    /// The set of devices being watched has changed, typically either
    /// because a tag was edited or because a device was
    /// added. Payload is the id of the device that was added.
    GetterAdded(Id<Getter>),

    /// One of the channels encountered an error during initialization.
    /// This channel will not be watched, but other channels will remain
    /// watched.
    InitializationError {
        channel: Id<Getter>,
        error: AdapterError
    },
}

pub type ResultMap<K, T, E> = Vec<(K, Result<T, E>)>;

/// A handle to the public API.
pub trait API {
    /// Get the metadata on services matching some conditions.
    ///
    /// A call to `API::get_services(vec![req1, req2, ...])` will return
    /// the metadata on all services matching _either_ `req1` or `req2`
    /// or ...
    ///
    /// # REST API
    ///
    /// `GET /api/v1/services`
    ///
    /// ## Requests
    ///
    /// Any JSON that can be deserialized to a `Vec<ServiceSelector>`. See
    /// the implementation of `ServiceSelector` for details.
    ///
    /// ### Example
    ///
    /// Selector all doors in the entrance (tags `door`, `entrance`)
    /// that support setter channel `OpenClose`
    ///
    /// ```json
    /// [{
    ///   "tags": ["entrance", "door"],
    ///   "getters": [
    ///     {
    ///       "kind": {
    ///         "Exactly": {
    ///           "OpenClose": []
    ///         }
    ///       }
    ///     }
    ///   ]
    /// }]
    /// ```
    ///
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing an array of `Service`. See the implementation
    /// of `Service` for details.
    ///
    /// ### Example
    ///
    /// ```json
    /// [{
    ///   "tags": ["entrance", "door", "somevendor"],
    ///   "id: "some-service-id",
    ///   "getters": [],
    ///   "setters": [
    ///     "tags": [...],
    ///     "id": "some-channel-id",
    ///     "service": "some-service-id",
    ///     "last_seen": "some-date",
    ///     "mechanism": {
    ///       "Setter":  {
    ///         "kind": {
    ///           "OnOff": []
    ///         },
    ///         "push": [5000],
    ///         "updated": "some-date",
    ///       }
    ///     }
    ///   ]
    /// }]
    /// ```
    fn get_services(&self, &[ServiceSelector]) -> Vec<Service>;

    /// Label a set of services with a set of tags.
    ///
    /// A call to `API::put_service_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the services matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of services
    /// matching any of the selectors.
    ///
    /// Some of the services may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `POST /api/v1/services/tag`
    ///
    /// ## Getters
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<ServiceSelector>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON string representing a number.
    fn add_service_tags(&self, selectors: &[ServiceSelector], tags: &[String]) -> usize;

    /// Remove a set of tags from a set of services.
    ///
    /// A call to `API::delete_service_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the services matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of services
    /// matching any of the selectors.
    ///
    /// Some of the services may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `DELETE /api/v1/services/tag`
    ///
    /// ## Getters
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<ServiceSelector>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn remove_service_tags(&self, selectors: &[ServiceSelector], tags: &[String]) -> usize;

    /// Get a list of getters matching some conditions
    ///
    /// # REST API
    ///
    /// `GET /api/v1/channels`
    fn get_getter_channels(&self, selectors: &[GetterSelector]) -> Vec<Channel<Getter>>;
    fn get_setter_channels(&self, selectors: &[SetterSelector]) -> Vec<Channel<Setter>>;

    /// Label a set of channels with a set of tags.
    ///
    /// A call to `API::put_{getter, setter}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the channels matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of channels
    /// matching any of the selectors.
    ///
    /// Some of the channels may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if channels
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `POST /api/v1/channels/tag`
    ///
    /// ## Requests
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<GetterSelector>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    /// or
    /// ```ignore
    /// {
    ///   set: Vec<SetterSelector>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn add_getter_tags(&self, selectors: &[GetterSelector], tags: &[String]) -> usize;
    fn add_setter_tags(&self, selectors: &[SetterSelector], tags: &[String]) -> usize;

    /// Remove a set of tags from a set of channels.
    ///
    /// A call to `API::delete_{getter, setter}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the channels matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of channels
    /// matching any of the selectors.
    ///
    /// Some of the channels may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if channels
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `DELETE /api/v1/channels/tag`
    ///
    /// ## Requests
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<GetterSelector>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    /// or
    /// ```ignore
    /// {
    ///   set: Vec<SetterSelector>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn remove_getter_tags(&self, selectors: &[GetterSelector], tags: &[String]) -> usize;
    fn remove_setter_tags(&self, selectors: &[SetterSelector], tags: &[String]) -> usize;

    /// Read the latest value from a set of channels
    ///
    /// # REST API
    ///
    /// `GET /api/v1/channels/value`
    fn fetch_values(&self, &[GetterSelector]) -> ResultMap<Id<Getter>, Option<Value>, Error>;

    /// Send a bunch of values to a set of channels
    ///
    /// # REST API
    ///
    /// `POST /api/v1/channels/value`
    fn send_values(&self, Vec<(Vec<SetterSelector>, Value)>) -> ResultMap<Id<Setter>, (), Error>;

    /// Watch for any change
    ///
    /// # WebSocket API
    ///
    /// `/api/v1/channels/watch`
    fn register_channel_watch(&self, selectors: Vec<GetterSelector>, range: Exactly<Range>, on_event: Sender<WatchEvent>) -> Self::WatchGuard;

    /// A value that causes a disconnection once it is dropped.
    type WatchGuard;
}

<commit_msg>[fxbox/taxonomy] Rolling back register_channel_watch to take a function instead of a sender<commit_after>//!
//! The API for communicating with devices.
//!
//! This API is provided as Traits to be implemented:
//!
//! - by the low-level layers of the FoxBox, including the adapters;
//! - by test suites and tools that need to simulate connected devices.
//!
//! In turn, this API is used to implement:
//!
//! - the public-facing REST and WebSocket API;
//! - the rules API (ThinkerBell).
//!
//!

use services::*;
use selector::*;
use values::{Value, Range, TypeError};
use util::{Exactly, Id};

/// An error that took place while communicating with either an adapter or the mechanism that
/// handles registeration of adapters.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum AdapterError {
    DuplicateGetter(Id<Getter>),
    NoSuchGetter(Id<Getter>),
    GetterDoesNotSupportPolling(Id<Getter>),
    GetterDoesNotSupportWatching(Id<Getter>),
    GetterRequiresThresholdForWatching(Id<Getter>),

    DuplicateSetter(Id<Setter>),
    NoSuchSetter(Id<Setter>),

    DuplicateService(Id<ServiceId>),
    NoSuchService(Id<ServiceId>),
    TypeError(TypeError),

    DuplicateAdapter(Id<AdapterId>),
    ConflictingAdapter(Id<AdapterId>, Id<AdapterId>),
    NoSuchAdapter(Id<AdapterId>),
    InvalidValue
}

/// An error produced by one of the APIs in this module.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Error {
    /// There is no such service connected to the Foxbox, even indirectly.
    NoSuchService(Id<ServiceId>),

    /// There is no such getter channel connected to the Foxbox, even indirectly.
    NoSuchGetter(Id<Getter>),

    /// There is no such setter channel connected to the Foxbox, even indirectly.
    NoSuchSetter(Id<Setter>),

    /// Attempting to set a value with the wrong type.{}
    TypeError,

    /// An error arose when talking to the adapter.
    AdapterError(AdapterError),
}

/// An event during watching.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum WatchEvent {
    /// A new value is available.
    Value {
        /// The channel that sent the value.
        from: Id<Getter>,

        /// The actual value.
        value: Value
    },

    /// The set of devices being watched has changed, typically either
    /// because a tag was edited or because a device was
    /// removed. Payload is the id of the device that was removed.
    GetterRemoved(Id<Getter>),

    /// The set of devices being watched has changed, typically either
    /// because a tag was edited or because a device was
    /// added. Payload is the id of the device that was added.
    GetterAdded(Id<Getter>),

    /// One of the channels encountered an error during initialization.
    /// This channel will not be watched, but other channels will remain
    /// watched.
    InitializationError {
        channel: Id<Getter>,
        error: AdapterError
    },
}

pub type ResultMap<K, T, E> = Vec<(K, Result<T, E>)>;

/// A handle to the public API.
pub trait API {
    /// Get the metadata on services matching some conditions.
    ///
    /// A call to `API::get_services(vec![req1, req2, ...])` will return
    /// the metadata on all services matching _either_ `req1` or `req2`
    /// or ...
    ///
    /// # REST API
    ///
    /// `GET /api/v1/services`
    ///
    /// ## Requests
    ///
    /// Any JSON that can be deserialized to a `Vec<ServiceSelector>`. See
    /// the implementation of `ServiceSelector` for details.
    ///
    /// ### Example
    ///
    /// Selector all doors in the entrance (tags `door`, `entrance`)
    /// that support setter channel `OpenClose`
    ///
    /// ```json
    /// [{
    ///   "tags": ["entrance", "door"],
    ///   "getters": [
    ///     {
    ///       "kind": {
    ///         "Exactly": {
    ///           "OpenClose": []
    ///         }
    ///       }
    ///     }
    ///   ]
    /// }]
    /// ```
    ///
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing an array of `Service`. See the implementation
    /// of `Service` for details.
    ///
    /// ### Example
    ///
    /// ```json
    /// [{
    ///   "tags": ["entrance", "door", "somevendor"],
    ///   "id: "some-service-id",
    ///   "getters": [],
    ///   "setters": [
    ///     "tags": [...],
    ///     "id": "some-channel-id",
    ///     "service": "some-service-id",
    ///     "last_seen": "some-date",
    ///     "mechanism": {
    ///       "Setter":  {
    ///         "kind": {
    ///           "OnOff": []
    ///         },
    ///         "push": [5000],
    ///         "updated": "some-date",
    ///       }
    ///     }
    ///   ]
    /// }]
    /// ```
    fn get_services(&self, &[ServiceSelector]) -> Vec<Service>;

    /// Label a set of services with a set of tags.
    ///
    /// A call to `API::put_service_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the services matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of services
    /// matching any of the selectors.
    ///
    /// Some of the services may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `POST /api/v1/services/tag`
    ///
    /// ## Getters
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<ServiceSelector>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON string representing a number.
    fn add_service_tags(&self, selectors: &[ServiceSelector], tags: &[String]) -> usize;

    /// Remove a set of tags from a set of services.
    ///
    /// A call to `API::delete_service_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the services matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of services
    /// matching any of the selectors.
    ///
    /// Some of the services may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `DELETE /api/v1/services/tag`
    ///
    /// ## Getters
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<ServiceSelector>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn remove_service_tags(&self, selectors: &[ServiceSelector], tags: &[String]) -> usize;

    /// Get a list of getters matching some conditions
    ///
    /// # REST API
    ///
    /// `GET /api/v1/channels`
    fn get_getter_channels(&self, selectors: &[GetterSelector]) -> Vec<Channel<Getter>>;
    fn get_setter_channels(&self, selectors: &[SetterSelector]) -> Vec<Channel<Setter>>;

    /// Label a set of channels with a set of tags.
    ///
    /// A call to `API::put_{getter, setter}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the channels matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of channels
    /// matching any of the selectors.
    ///
    /// Some of the channels may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if channels
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `POST /api/v1/channels/tag`
    ///
    /// ## Requests
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<GetterSelector>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    /// or
    /// ```ignore
    /// {
    ///   set: Vec<SetterSelector>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn add_getter_tags(&self, selectors: &[GetterSelector], tags: &[String]) -> usize;
    fn add_setter_tags(&self, selectors: &[SetterSelector], tags: &[String]) -> usize;

    /// Remove a set of tags from a set of channels.
    ///
    /// A call to `API::delete_{getter, setter}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the channels matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of channels
    /// matching any of the selectors.
    ///
    /// Some of the channels may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if channels
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `DELETE /api/v1/channels/tag`
    ///
    /// ## Requests
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<GetterSelector>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    /// or
    /// ```ignore
    /// {
    ///   set: Vec<SetterSelector>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn remove_getter_tags(&self, selectors: &[GetterSelector], tags: &[String]) -> usize;
    fn remove_setter_tags(&self, selectors: &[SetterSelector], tags: &[String]) -> usize;

    /// Read the latest value from a set of channels
    ///
    /// # REST API
    ///
    /// `GET /api/v1/channels/value`
    fn fetch_values(&self, &[GetterSelector]) -> ResultMap<Id<Getter>, Option<Value>, Error>;

    /// Send a bunch of values to a set of channels
    ///
    /// # REST API
    ///
    /// `POST /api/v1/channels/value`
    fn send_values(&self, Vec<(Vec<SetterSelector>, Value)>) -> ResultMap<Id<Setter>, (), Error>;

    /// Watch for any change
    ///
    /// # WebSocket API
    ///
    /// `/api/v1/channels/watch`
    fn register_channel_watch(&self, selectors: Vec<GetterSelector>, range: Exactly<Range>, on_event: Box<Fn(WatchEvent)>) -> Self::WatchGuard;

    /// A value that causes a disconnection once it is dropped.
    type WatchGuard;
}

<|endoftext|>


<commit_before>mod extractor;
mod nodes_types;

use clap;
use std::fs;
use std::io::BufRead;
use std::path::{Path, PathBuf};
use tree_sitter::Language;

fn main() -> std::io::Result<()> {
    extern "C" {
        fn tree_sitter_ruby() -> Language;
    }

    let matches = clap::App::new("Ruby extractor")
        .version("1.0")
        .author("GitHub")
        .about("CodeQL Ruby extractor")
        .args_from_usage(
            "--source-archive-dir=<DIR> 'Sets a custom source archive folder'
                    --output-dir=<DIR>         'Sets a custom trap folder'
                    --file-list=<FILE_LIST>    'A text files containing the paths of the files to extract'",
        )
        .get_matches();
    let src_archive_dir = matches
        .value_of("source-archive-dir")
        .expect("missing --source-archive-dir");
    let src_archive_dir = PathBuf::from(src_archive_dir);

    let trap_dir = matches
        .value_of("output-dir")
        .expect("missing --output-dir");
    let trap_dir = PathBuf::from(trap_dir);

    let file_list = matches.value_of("file-list").expect("missing --file-list");
    let file_list = fs::File::open(file_list)?;

    let node_types_path = PathBuf::from("tree-sitter-ruby/src/node-types.json");
    let language = unsafe { tree_sitter_ruby() };
    let schema = nodes_types::read_node_types(&node_types_path)?;
    let mut extractor = extractor::create(language, schema);
    for line in std::io::BufReader::new(file_list).lines() {
        let path = PathBuf::from(line?);
        let trap_file = path_for(&trap_dir, &path, ".trap");
        let src_archive_file = path_for(&src_archive_dir, &path, "");
        let trap = extractor.extract(&path)?;
        std::fs::create_dir_all(&src_archive_file.parent().unwrap())?;
        std::fs::copy(&path, &src_archive_file)?;
        std::fs::create_dir_all(&trap_file.parent().unwrap())?;
        let mut trap_file = std::fs::File::create(&trap_file)?;
        let trap_file: &mut dyn std::io::Write = &mut trap_file;
        write!(trap_file, "{}", trap)?;
    }
    return Ok(());
}
fn path_for(dir: &Path, path: &Path, ext: &str) -> PathBuf {
    let mut result = PathBuf::from(dir);
    for component in path.components() {
        match component {
            std::path::Component::Prefix(_) => {
                // skip for now
                // TODO: handle this properly for Windows
            }
            std::path::Component::RootDir => {
                // skip
            }
            std::path::Component::Normal(_) => {
                result.push(component);
            }
            std::path::Component::CurDir => {
                // skip
            }
            std::path::Component::ParentDir => {
                result.pop();
            }
        }
    }
    if let Some(x) = result.extension() {
        let mut new_ext = x.to_os_string();
        new_ext.push(ext);
        result.set_extension(new_ext);
    } else {
        result.set_extension(ext);
    }
    result
}
<commit_msg>Handle Windows path prefixes<commit_after>mod extractor;
mod nodes_types;

use clap;
use std::fs;
use std::io::BufRead;
use std::path::{Path, PathBuf};
use tree_sitter::Language;

fn main() -> std::io::Result<()> {
    extern "C" {
        fn tree_sitter_ruby() -> Language;
    }

    let matches = clap::App::new("Ruby extractor")
        .version("1.0")
        .author("GitHub")
        .about("CodeQL Ruby extractor")
        .args_from_usage(
            "--source-archive-dir=<DIR> 'Sets a custom source archive folder'
                    --output-dir=<DIR>         'Sets a custom trap folder'
                    --file-list=<FILE_LIST>    'A text files containing the paths of the files to extract'",
        )
        .get_matches();
    let src_archive_dir = matches
        .value_of("source-archive-dir")
        .expect("missing --source-archive-dir");
    let src_archive_dir = PathBuf::from(src_archive_dir);

    let trap_dir = matches
        .value_of("output-dir")
        .expect("missing --output-dir");
    let trap_dir = PathBuf::from(trap_dir);

    let file_list = matches.value_of("file-list").expect("missing --file-list");
    let file_list = fs::File::open(file_list)?;

    let node_types_path = PathBuf::from("tree-sitter-ruby/src/node-types.json");
    let language = unsafe { tree_sitter_ruby() };
    let schema = nodes_types::read_node_types(&node_types_path)?;
    let mut extractor = extractor::create(language, schema);
    for line in std::io::BufReader::new(file_list).lines() {
        let path = PathBuf::from(line?);
        let trap_file = path_for(&trap_dir, &path, ".trap");
        let src_archive_file = path_for(&src_archive_dir, &path, "");
        let trap = extractor.extract(&path)?;
        std::fs::create_dir_all(&src_archive_file.parent().unwrap())?;
        std::fs::copy(&path, &src_archive_file)?;
        std::fs::create_dir_all(&trap_file.parent().unwrap())?;
        let mut trap_file = std::fs::File::create(&trap_file)?;
        let trap_file: &mut dyn std::io::Write = &mut trap_file;
        write!(trap_file, "{}", trap)?;
    }
    return Ok(());
}
fn path_for(dir: &Path, path: &Path, ext: &str) -> PathBuf {
    let mut result = PathBuf::from(dir);
    for component in path.components() {
        match component {
            std::path::Component::Prefix(prefix) => match prefix.kind() {
                std::path::Prefix::Disk(letter) | std::path::Prefix::VerbatimDisk(letter) => {
                    result.push(format!("{}_", letter as char))
                }
                std::path::Prefix::Verbatim(x) | std::path::Prefix::DeviceNS(x) => {
                    result.push(x);
                }
                std::path::Prefix::UNC(server, share)
                | std::path::Prefix::VerbatimUNC(server, share) => {
                    result.push("unc");
                    result.push(server);
                    result.push(share);
                }
            },
            std::path::Component::RootDir => {
                // skip
            }
            std::path::Component::Normal(_) => {
                result.push(component);
            }
            std::path::Component::CurDir => {
                // skip
            }
            std::path::Component::ParentDir => {
                result.pop();
            }
        }
    }
    if let Some(x) = result.extension() {
        let mut new_ext = x.to_os_string();
        new_ext.push(ext);
        result.set_extension(new_ext);
    } else {
        result.set_extension(ext);
    }
    result
}
<|endoftext|>


<commit_before>use crate::mem;
use crate::slice;

pub fn hashmap_random_keys() -> (u64, u64) {
    let mut v = (0, 0);
    unsafe {
        let view = slice::from_raw_parts_mut(&mut v as *mut _ as *mut u8, mem::size_of_val(&v));
        imp::fill_bytes(view);
    }
    v
}

#[cfg(all(
    unix,
    not(target_os = "ios"),
    not(target_os = "openbsd"),
    not(target_os = "freebsd"),
    not(target_os = "netbsd"),
    not(target_os = "fuchsia"),
    not(target_os = "redox")
))]
mod imp {
    use crate::fs::File;
    use crate::io::Read;

    #[cfg(any(target_os = "linux", target_os = "android"))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        unsafe {
            libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr(), buf.len(), libc::GRND_NONBLOCK)
        }
    }

    #[cfg(not(any(target_os = "linux", target_os = "android")))]
    fn getrandom_fill_bytes(_buf: &mut [u8]) -> bool {
        false
    }

    #[cfg(any(target_os = "linux", target_os = "android"))]
    fn getrandom_fill_bytes(v: &mut [u8]) -> bool {
        use crate::sync::atomic::{AtomicBool, Ordering};
        use crate::sys::os::errno;

        static GETRANDOM_UNAVAILABLE: AtomicBool = AtomicBool::new(false);
        if GETRANDOM_UNAVAILABLE.load(Ordering::Relaxed) {
            return false;
        }

        let mut read = 0;
        while read < v.len() {
            let result = getrandom(&mut v[read..]);
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else if err == libc::ENOSYS || err == libc::EPERM {
                    // Fall back to reading /dev/urandom if `getrandom` is not
                    // supported on the current kernel.
                    //
                    // Also fall back in case it is disabled by something like
                    // seccomp or inside of virtual machines.
                    GETRANDOM_UNAVAILABLE.store(true, Ordering::Relaxed);
                    return false;
                } else if err == libc::EAGAIN {
                    return false;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as usize;
            }
        }
        true
    }

    pub fn fill_bytes(v: &mut [u8]) {
        // getrandom_fill_bytes here can fail if getrandom() returns EAGAIN,
        // meaning it would have blocked because the non-blocking pool (urandom)
        // has not initialized in the kernel yet due to a lack of entropy. The
        // fallback we do here is to avoid blocking applications which could
        // depend on this call without ever knowing they do and don't have a
        // work around. The PRNG of /dev/urandom will still be used but over a
        // possibly predictable entropy pool.
        if getrandom_fill_bytes(v) {
            return;
        }

        // getrandom failed because it is permanently or temporarily (because
        // of missing entropy) unavailable. Open /dev/urandom, read from it,
        // and close it again.
        let mut file = File::open("/dev/urandom").expect("failed to open /dev/urandom");
        file.read_exact(v).expect("failed to read /dev/urandom")
    }
}

#[cfg(target_os = "openbsd")]
mod imp {
    use crate::sys::os::errno;

    pub fn fill_bytes(v: &mut [u8]) {
        // getentropy(2) permits a maximum buffer size of 256 bytes
        for s in v.chunks_mut(256) {
            let ret = unsafe { libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len()) };
            if ret == -1 {
                panic!("unexpected getentropy error: {}", errno());
            }
        }
    }
}

// On iOS and MacOS `SecRandomCopyBytes` calls `CCRandomCopyBytes` with
// `kCCRandomDefault`. `CCRandomCopyBytes` manages a CSPRNG which is seeded
// from `/dev/random` and which runs on its own thread accessed via GCD.
// This seems needlessly heavyweight for the purposes of generating two u64s
// once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is
// only used on iOS where direct access to `/dev/urandom` is blocked by the
// sandbox.
#[cfg(target_os = "ios")]
mod imp {
    use crate::io;
    use crate::ptr;
    use libc::{c_int, size_t};

    enum SecRandom {}

    #[allow(non_upper_case_globals)]
    const kSecRandomDefault: *const SecRandom = ptr::null();

    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom, count: size_t, bytes: *mut u8) -> c_int;
    }

    pub fn fill_bytes(v: &mut [u8]) {
        let ret = unsafe { SecRandomCopyBytes(kSecRandomDefault, v.len(), v.as_mut_ptr()) };
        if ret == -1 {
            panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
        }
    }
}

#[cfg(any(target_os = "freebsd", target_os = "netbsd"))]
mod imp {
    use crate::ptr;

    pub fn fill_bytes(v: &mut [u8]) {
        let mib = [libc::CTL_KERN, libc::KERN_ARND];
        // kern.arandom permits a maximum buffer size of 256 bytes
        for s in v.chunks_mut(256) {
            let mut s_len = s.len();
            let ret = unsafe {
                libc::sysctl(
                    mib.as_ptr(),
                    mib.len() as libc::c_uint,
                    s.as_mut_ptr() as *mut _,
                    &mut s_len,
                    ptr::null(),
                    0,
                )
            };
            if ret == -1 || s_len != s.len() {
                panic!(
                    "kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})",
                    ret,
                    s.len(),
                    s_len
                );
            }
        }
    }
}

#[cfg(target_os = "fuchsia")]
mod imp {
    #[link(name = "zircon")]
    extern "C" {
        fn zx_cprng_draw(buffer: *mut u8, len: usize);
    }

    pub fn fill_bytes(v: &mut [u8]) {
        unsafe { zx_cprng_draw(v.as_mut_ptr(), v.len()) }
    }
}

#[cfg(target_os = "redox")]
mod imp {
    use crate::fs::File;
    use crate::io::Read;

    pub fn fill_bytes(v: &mut [u8]) {
        // Open rand:, read from it, and close it again.
        let mut file = File::open("rand:").expect("failed to open rand:");
        file.read_exact(v).expect("failed to read rand:")
    }
}
<commit_msg>Rollup merge of #70207 - hatoo:macos-getentropy, r=dtolnay<commit_after>use crate::mem;
use crate::slice;

pub fn hashmap_random_keys() -> (u64, u64) {
    let mut v = (0, 0);
    unsafe {
        let view = slice::from_raw_parts_mut(&mut v as *mut _ as *mut u8, mem::size_of_val(&v));
        imp::fill_bytes(view);
    }
    v
}

#[cfg(all(
    unix,
    not(target_os = "macos"),
    not(target_os = "ios"),
    not(target_os = "openbsd"),
    not(target_os = "freebsd"),
    not(target_os = "netbsd"),
    not(target_os = "fuchsia"),
    not(target_os = "redox")
))]
mod imp {
    use crate::fs::File;
    use crate::io::Read;

    #[cfg(any(target_os = "linux", target_os = "android"))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        unsafe {
            libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr(), buf.len(), libc::GRND_NONBLOCK)
        }
    }

    #[cfg(not(any(target_os = "linux", target_os = "android")))]
    fn getrandom_fill_bytes(_buf: &mut [u8]) -> bool {
        false
    }

    #[cfg(any(target_os = "linux", target_os = "android"))]
    fn getrandom_fill_bytes(v: &mut [u8]) -> bool {
        use crate::sync::atomic::{AtomicBool, Ordering};
        use crate::sys::os::errno;

        static GETRANDOM_UNAVAILABLE: AtomicBool = AtomicBool::new(false);
        if GETRANDOM_UNAVAILABLE.load(Ordering::Relaxed) {
            return false;
        }

        let mut read = 0;
        while read < v.len() {
            let result = getrandom(&mut v[read..]);
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else if err == libc::ENOSYS || err == libc::EPERM {
                    // Fall back to reading /dev/urandom if `getrandom` is not
                    // supported on the current kernel.
                    //
                    // Also fall back in case it is disabled by something like
                    // seccomp or inside of virtual machines.
                    GETRANDOM_UNAVAILABLE.store(true, Ordering::Relaxed);
                    return false;
                } else if err == libc::EAGAIN {
                    return false;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as usize;
            }
        }
        true
    }

    pub fn fill_bytes(v: &mut [u8]) {
        // getrandom_fill_bytes here can fail if getrandom() returns EAGAIN,
        // meaning it would have blocked because the non-blocking pool (urandom)
        // has not initialized in the kernel yet due to a lack of entropy. The
        // fallback we do here is to avoid blocking applications which could
        // depend on this call without ever knowing they do and don't have a
        // work around. The PRNG of /dev/urandom will still be used but over a
        // possibly predictable entropy pool.
        if getrandom_fill_bytes(v) {
            return;
        }

        // getrandom failed because it is permanently or temporarily (because
        // of missing entropy) unavailable. Open /dev/urandom, read from it,
        // and close it again.
        let mut file = File::open("/dev/urandom").expect("failed to open /dev/urandom");
        file.read_exact(v).expect("failed to read /dev/urandom")
    }
}

#[cfg(target_os = "macos")]
mod imp {
    use crate::fs::File;
    use crate::io::Read;
    use crate::sys::os::errno;
    use libc::{c_int, c_void, size_t};

    fn getentropy_fill_bytes(v: &mut [u8]) -> bool {
        weak!(fn getentropy(*mut c_void, size_t) -> c_int);

        getentropy
            .get()
            .map(|f| {
                // getentropy(2) permits a maximum buffer size of 256 bytes
                for s in v.chunks_mut(256) {
                    let ret = unsafe { f(s.as_mut_ptr() as *mut c_void, s.len()) };
                    if ret == -1 {
                        panic!("unexpected getentropy error: {}", errno());
                    }
                }
                true
            })
            .unwrap_or(false)
    }

    pub fn fill_bytes(v: &mut [u8]) {
        if getentropy_fill_bytes(v) {
            return;
        }

        // for older macos which doesn't support getentropy
        let mut file = File::open("/dev/urandom").expect("failed to open /dev/urandom");
        file.read_exact(v).expect("failed to read /dev/urandom")
    }
}

#[cfg(target_os = "openbsd")]
mod imp {
    use crate::sys::os::errno;

    pub fn fill_bytes(v: &mut [u8]) {
        // getentropy(2) permits a maximum buffer size of 256 bytes
        for s in v.chunks_mut(256) {
            let ret = unsafe { libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len()) };
            if ret == -1 {
                panic!("unexpected getentropy error: {}", errno());
            }
        }
    }
}

// On iOS and MacOS `SecRandomCopyBytes` calls `CCRandomCopyBytes` with
// `kCCRandomDefault`. `CCRandomCopyBytes` manages a CSPRNG which is seeded
// from `/dev/random` and which runs on its own thread accessed via GCD.
// This seems needlessly heavyweight for the purposes of generating two u64s
// once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is
// only used on iOS where direct access to `/dev/urandom` is blocked by the
// sandbox.
#[cfg(target_os = "ios")]
mod imp {
    use crate::io;
    use crate::ptr;
    use libc::{c_int, size_t};

    enum SecRandom {}

    #[allow(non_upper_case_globals)]
    const kSecRandomDefault: *const SecRandom = ptr::null();

    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom, count: size_t, bytes: *mut u8) -> c_int;
    }

    pub fn fill_bytes(v: &mut [u8]) {
        let ret = unsafe { SecRandomCopyBytes(kSecRandomDefault, v.len(), v.as_mut_ptr()) };
        if ret == -1 {
            panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
        }
    }
}

#[cfg(any(target_os = "freebsd", target_os = "netbsd"))]
mod imp {
    use crate::ptr;

    pub fn fill_bytes(v: &mut [u8]) {
        let mib = [libc::CTL_KERN, libc::KERN_ARND];
        // kern.arandom permits a maximum buffer size of 256 bytes
        for s in v.chunks_mut(256) {
            let mut s_len = s.len();
            let ret = unsafe {
                libc::sysctl(
                    mib.as_ptr(),
                    mib.len() as libc::c_uint,
                    s.as_mut_ptr() as *mut _,
                    &mut s_len,
                    ptr::null(),
                    0,
                )
            };
            if ret == -1 || s_len != s.len() {
                panic!(
                    "kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})",
                    ret,
                    s.len(),
                    s_len
                );
            }
        }
    }
}

#[cfg(target_os = "fuchsia")]
mod imp {
    #[link(name = "zircon")]
    extern "C" {
        fn zx_cprng_draw(buffer: *mut u8, len: usize);
    }

    pub fn fill_bytes(v: &mut [u8]) {
        unsafe { zx_cprng_draw(v.as_mut_ptr(), v.len()) }
    }
}

#[cfg(target_os = "redox")]
mod imp {
    use crate::fs::File;
    use crate::io::Read;

    pub fn fill_bytes(v: &mut [u8]) {
        // Open rand:, read from it, and close it again.
        let mut file = File::open("rand:").expect("failed to open rand:");
        file.read_exact(v).expect("failed to read rand:")
    }
}
<|endoftext|>


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

use mem;
use slice;

pub fn hashmap_random_keys() -> (u64, u64) {
    let mut v = (0, 0);
    unsafe {
        let view = slice::from_raw_parts_mut(&mut v as *mut _ as *mut u8,
                                             mem::size_of_val(&v));
        imp::fill_bytes(view);
    }
    return v
}

#[cfg(all(unix,
          not(target_os = "ios"),
          not(target_os = "openbsd"),
          not(target_os = "freebsd"),
          not(target_os = "fuchsia")))]
mod imp {
    use fs::File;
    use io::Read;
    use libc;
    use sys::os::errno;

    #[cfg(any(target_os = "linux", target_os = "android"))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        unsafe {
            libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr(), buf.len(), libc::GRND_NONBLOCK)
        }
    }

    #[cfg(not(any(target_os = "linux", target_os = "android")))]
    fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }

    fn getrandom_fill_bytes(v: &mut [u8]) -> bool {
        let mut read = 0;
        while read < v.len() {
            let result = getrandom(&mut v[read..]);
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else if err == libc::EAGAIN {
                    return false
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as usize;
            }
        }

        return true
    }

    #[cfg(any(target_os = "linux", target_os = "android"))]
    fn is_getrandom_available() -> bool {
        use io;
        use sync::atomic::{AtomicBool, Ordering};
        use sync::Once;

        static CHECKER: Once = Once::new();
        static AVAILABLE: AtomicBool = AtomicBool::new(false);

        CHECKER.call_once(|| {
            let mut buf: [u8; 0] = [];
            let result = getrandom(&mut buf);
            let available = if result == -1 {
                let err = io::Error::last_os_error().raw_os_error();
                err != Some(libc::ENOSYS)
            } else {
                true
            };
            AVAILABLE.store(available, Ordering::Relaxed);
        });

        AVAILABLE.load(Ordering::Relaxed)
    }

    #[cfg(not(any(target_os = "linux", target_os = "android")))]
    fn is_getrandom_available() -> bool { false }

    pub fn fill_bytes(v: &mut [u8]) {
        // getrandom_fill_bytes here can fail if getrandom() returns EAGAIN,
        // meaning it would have blocked because the non-blocking pool (urandom)
        // has not initialized in the kernel yet due to a lack of entropy the
        // fallback we do here is to avoid blocking applications which could
        // depend on this call without ever knowing they do and don't have a
        // work around.  The PRNG of /dev/urandom will still be used but not
        // over a completely full entropy pool
        if is_getrandom_available() && getrandom_fill_bytes(v) {
            return
        }

        let mut file = File::open("/dev/urandom")
            .expect("failed to open /dev/urandom");
        file.read_exact(v).expect("failed to read /dev/urandom");
    }
}

#[cfg(target_os = "openbsd")]
mod imp {
    use libc;
    use sys::os::errno;

    pub fn fill_bytes(v: &mut [u8]) {
        // getentropy(2) permits a maximum buffer size of 256 bytes
        for s in v.chunks_mut(256) {
            let ret = unsafe {
                libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len())
            };
            if ret == -1 {
                panic!("unexpected getentropy error: {}", errno());
            }
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    use io;
    use libc::{c_int, size_t};
    use ptr;

    enum SecRandom {}

    #[allow(non_upper_case_globals)]
    const kSecRandomDefault: *const SecRandom = ptr::null();

    extern {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t,
                              bytes: *mut u8) -> c_int;
    }

    pub fn fill_bytes(v: &mut [u8]) {
        let ret = unsafe {
            SecRandomCopyBytes(kSecRandomDefault,
                               v.len(),
                               v.as_mut_ptr())
        };
        if ret == -1 {
            panic!("couldn't generate random bytes: {}",
                   io::Error::last_os_error());
        }
    }
}

#[cfg(target_os = "freebsd")]
mod imp {
    use libc;
    use ptr;

    pub fn fill_bytes(v: &mut [u8]) {
        let mib = [libc::CTL_KERN, libc::KERN_ARND];
        // kern.arandom permits a maximum buffer size of 256 bytes
        for s in v.chunks_mut(256) {
            let mut s_len = s.len();
            let ret = unsafe {
                libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint,
                             s.as_mut_ptr() as *mut _, &mut s_len,
                             ptr::null(), 0)
            };
            if ret == -1 || s_len != s.len() {
                panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})",
                       ret, s.len(), s_len);
            }
        }
    }
}

#[cfg(target_os = "fuchsia")]
mod imp {
    #[link(name = "zircon")]
    extern {
        fn zx_cprng_draw(buffer: *mut u8, len: usize, actual: *mut usize) -> i32;
    }

    fn getrandom(buf: &mut [u8]) -> Result<usize, i32> {
        unsafe {
            let mut actual = 0;
            let status = zx_cprng_draw(buf.as_mut_ptr(), buf.len(), &mut actual);
            if status == 0 {
                Ok(actual)
            } else {
                Err(status)
            }
        }
    }

    pub fn fill_bytes(v: &mut [u8]) {
        let mut buf = v;
        while !buf.is_empty() {
            let ret = getrandom(buf);
            match ret {
                Err(err) => {
                    panic!("kernel zx_cprng_draw call failed! (returned {}, buf.len() {})",
                        err, buf.len())
                }
                Ok(actual) => {
                    let move_buf = buf;
                    buf = &mut move_buf[(actual as usize)..];
                }
            }
        }
    }
}
<commit_msg>Update zx_cprng_draw_new on Fuchsia<commit_after>// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use mem;
use slice;

pub fn hashmap_random_keys() -> (u64, u64) {
    let mut v = (0, 0);
    unsafe {
        let view = slice::from_raw_parts_mut(&mut v as *mut _ as *mut u8,
                                             mem::size_of_val(&v));
        imp::fill_bytes(view);
    }
    return v
}

#[cfg(all(unix,
          not(target_os = "ios"),
          not(target_os = "openbsd"),
          not(target_os = "freebsd"),
          not(target_os = "fuchsia")))]
mod imp {
    use fs::File;
    use io::Read;
    use libc;
    use sys::os::errno;

    #[cfg(any(target_os = "linux", target_os = "android"))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        unsafe {
            libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr(), buf.len(), libc::GRND_NONBLOCK)
        }
    }

    #[cfg(not(any(target_os = "linux", target_os = "android")))]
    fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }

    fn getrandom_fill_bytes(v: &mut [u8]) -> bool {
        let mut read = 0;
        while read < v.len() {
            let result = getrandom(&mut v[read..]);
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else if err == libc::EAGAIN {
                    return false
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as usize;
            }
        }

        return true
    }

    #[cfg(any(target_os = "linux", target_os = "android"))]
    fn is_getrandom_available() -> bool {
        use io;
        use sync::atomic::{AtomicBool, Ordering};
        use sync::Once;

        static CHECKER: Once = Once::new();
        static AVAILABLE: AtomicBool = AtomicBool::new(false);

        CHECKER.call_once(|| {
            let mut buf: [u8; 0] = [];
            let result = getrandom(&mut buf);
            let available = if result == -1 {
                let err = io::Error::last_os_error().raw_os_error();
                err != Some(libc::ENOSYS)
            } else {
                true
            };
            AVAILABLE.store(available, Ordering::Relaxed);
        });

        AVAILABLE.load(Ordering::Relaxed)
    }

    #[cfg(not(any(target_os = "linux", target_os = "android")))]
    fn is_getrandom_available() -> bool { false }

    pub fn fill_bytes(v: &mut [u8]) {
        // getrandom_fill_bytes here can fail if getrandom() returns EAGAIN,
        // meaning it would have blocked because the non-blocking pool (urandom)
        // has not initialized in the kernel yet due to a lack of entropy the
        // fallback we do here is to avoid blocking applications which could
        // depend on this call without ever knowing they do and don't have a
        // work around.  The PRNG of /dev/urandom will still be used but not
        // over a completely full entropy pool
        if is_getrandom_available() && getrandom_fill_bytes(v) {
            return
        }

        let mut file = File::open("/dev/urandom")
            .expect("failed to open /dev/urandom");
        file.read_exact(v).expect("failed to read /dev/urandom");
    }
}

#[cfg(target_os = "openbsd")]
mod imp {
    use libc;
    use sys::os::errno;

    pub fn fill_bytes(v: &mut [u8]) {
        // getentropy(2) permits a maximum buffer size of 256 bytes
        for s in v.chunks_mut(256) {
            let ret = unsafe {
                libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len())
            };
            if ret == -1 {
                panic!("unexpected getentropy error: {}", errno());
            }
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    use io;
    use libc::{c_int, size_t};
    use ptr;

    enum SecRandom {}

    #[allow(non_upper_case_globals)]
    const kSecRandomDefault: *const SecRandom = ptr::null();

    extern {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t,
                              bytes: *mut u8) -> c_int;
    }

    pub fn fill_bytes(v: &mut [u8]) {
        let ret = unsafe {
            SecRandomCopyBytes(kSecRandomDefault,
                               v.len(),
                               v.as_mut_ptr())
        };
        if ret == -1 {
            panic!("couldn't generate random bytes: {}",
                   io::Error::last_os_error());
        }
    }
}

#[cfg(target_os = "freebsd")]
mod imp {
    use libc;
    use ptr;

    pub fn fill_bytes(v: &mut [u8]) {
        let mib = [libc::CTL_KERN, libc::KERN_ARND];
        // kern.arandom permits a maximum buffer size of 256 bytes
        for s in v.chunks_mut(256) {
            let mut s_len = s.len();
            let ret = unsafe {
                libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint,
                             s.as_mut_ptr() as *mut _, &mut s_len,
                             ptr::null(), 0)
            };
            if ret == -1 || s_len != s.len() {
                panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})",
                       ret, s.len(), s_len);
            }
        }
    }
}

#[cfg(target_os = "fuchsia")]
mod imp {
    #[link(name = "zircon")]
    extern {
        fn zx_cprng_draw_new(buffer: *mut u8, len: usize) -> i32;
    }

    fn getrandom(buf: &mut [u8]) -> Result<usize, i32> {
        unsafe {
            let status = zx_cprng_draw_new(buf.as_mut_ptr(), buf.len());
            if status == 0 {
                Ok(buf.len())
            } else {
                Err(status)
            }
        }
    }

    pub fn fill_bytes(v: &mut [u8]) {
        let mut buf = v;
        while !buf.is_empty() {
            let ret = getrandom(buf);
            match ret {
                Err(err) => {
                    panic!("kernel zx_cprng_draw call failed! (returned {}, buf.len() {})",
                        err, buf.len())
                }
                Ok(actual) => {
                    let move_buf = buf;
                    buf = &mut move_buf[(actual as usize)..];
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate criterion;
use criterion::Criterion;

use rsvg_internals::rect::IRect;
use rsvg_internals::surface_utils::shared_surface::{
    AlphaOnly, Horizontal, NotAlphaOnly, SharedImageSurface, SurfaceType, Vertical,
};

const SURFACE_SIDE: i32 = 512;
const BOUNDS: IRect = IRect {
    x0: 64,
    y0: 64,
    x1: 64 + 64,
    y1: 64 + 64,
};

fn bench_box_blur(c: &mut Criterion) {
    c.bench_function_over_inputs(
        "box_blur 9",
        |b, &(vertical, alpha_only)| {
            let input_surface =
                cairo::ImageSurface::create(cairo::Format::ARgb32, SURFACE_SIDE, SURFACE_SIDE)
                    .unwrap();
            let surface_type = if alpha_only {
                SurfaceType::AlphaOnly
            } else {
                SurfaceType::SRgb
            };
            let input_surface = SharedImageSurface::wrap(input_surface, surface_type).unwrap();

            let mut output_surface =
                cairo::ImageSurface::create(cairo::Format::ARgb32, SURFACE_SIDE, SURFACE_SIDE)
                    .unwrap();
            const KERNEL_SIZE: usize = 9;

            let f = match (vertical, alpha_only) {
                (true, true) => SharedImageSurface::box_blur_loop::<Vertical, AlphaOnly>,
                (true, false) => SharedImageSurface::box_blur_loop::<Vertical, NotAlphaOnly>,
                (false, true) => SharedImageSurface::box_blur_loop::<Horizontal, AlphaOnly>,
                (false, false) => SharedImageSurface::box_blur_loop::<Horizontal, NotAlphaOnly>,
            };

            b.iter(|| {
                f(
                    &input_surface,
                    &mut output_surface,
                    BOUNDS,
                    KERNEL_SIZE,
                    KERNEL_SIZE / 2,
                )
            })
        },
        vec![(false, false), (false, true), (true, false), (true, true)],
    );
}

criterion_group!(benches, bench_box_blur);
criterion_main!(benches);
<commit_msg>benches: shorten code<commit_after>#[macro_use]
extern crate criterion;
use criterion::Criterion;

use rsvg_internals::rect::IRect;
use rsvg_internals::surface_utils::shared_surface::{
    AlphaOnly, Horizontal, NotAlphaOnly, SharedImageSurface, SurfaceType, Vertical,
};

const SURFACE_SIDE: i32 = 512;
const BOUNDS: IRect = IRect {
    x0: 64,
    y0: 64,
    x1: 64 + 64,
    y1: 64 + 64,
};

fn bench_box_blur(c: &mut Criterion) {
    c.bench_function_over_inputs(
        "box_blur 9",
        |b, &(vertical, alpha_only)| {
            let surface_type = if alpha_only {
                SurfaceType::AlphaOnly
            } else {
                SurfaceType::SRgb
            };
            let input_surface =
                SharedImageSurface::empty(SURFACE_SIDE, SURFACE_SIDE, surface_type).unwrap();

            let mut output_surface =
                cairo::ImageSurface::create(cairo::Format::ARgb32, SURFACE_SIDE, SURFACE_SIDE)
                    .unwrap();
            const KERNEL_SIZE: usize = 9;

            let f = match (vertical, alpha_only) {
                (true, true) => SharedImageSurface::box_blur_loop::<Vertical, AlphaOnly>,
                (true, false) => SharedImageSurface::box_blur_loop::<Vertical, NotAlphaOnly>,
                (false, true) => SharedImageSurface::box_blur_loop::<Horizontal, AlphaOnly>,
                (false, false) => SharedImageSurface::box_blur_loop::<Horizontal, NotAlphaOnly>,
            };

            b.iter(|| {
                f(
                    &input_surface,
                    &mut output_surface,
                    BOUNDS,
                    KERNEL_SIZE,
                    KERNEL_SIZE / 2,
                )
            })
        },
        vec![(false, false), (false, true), (true, false), (true, true)],
    );
}

criterion_group!(benches, bench_box_blur);
criterion_main!(benches);
<|endoftext|>