<commit_before>//! VMware provider on x86_64.
//!
//! This uses the guest->host backdoor protocol for introspection.

use super::VmwareProvider;
use crate::errors::*;
use error_chain::bail;

/// Guestinfo key for network kargs.
static INITRD_NET_KARGS: &str = "guestinfo.afterburn.initrd.network-kargs";

impl VmwareProvider {
    /// Build the VMware provider, fetching and caching guestinfo entries.
    pub fn try_new() -> Result<Self> {
        if !vmw_backdoor::is_vmware_cpu() {
            bail!("not running on VMWare CPU");
        }

        let mut backdoor = vmw_backdoor::probe_backdoor()?;
        let mut erpc = backdoor.open_enhanced_chan()?;
        let guestinfo_net_kargs = Self::fetch_guestinfo(&mut erpc, INITRD_NET_KARGS)?;

        let provider = Self {
            guestinfo_net_kargs,
        };

        slog_scope::trace!("cached vmware provider: {:?}", provider);
        Ok(provider)
    }

    /// Retrieve the value of a guestinfo string property, by key.
    fn fetch_guestinfo(erpc: &mut vmw_backdoor::EnhancedChan, key: &str) -> Result<Option<String>> {
        let guestinfo = erpc
            .get_guestinfo(key.as_bytes())
            .chain_err(|| "failed to retrieve network kargs")?
            .map(|bytes| String::from_utf8_lossy(&bytes).into_owned());
        Ok(guestinfo)
    }
}
<commit_msg>providers/vmware: allow avoiding iopl permission errors<commit_after>//! VMware provider on x86_64.
//!
//! This uses the guest->host backdoor protocol for introspection.

use super::VmwareProvider;
use crate::errors::*;
use error_chain::bail;

/// Guestinfo key for network kargs.
static INITRD_NET_KARGS: &str = "guestinfo.afterburn.initrd.network-kargs";

impl VmwareProvider {
    /// Build the VMware provider, fetching and caching guestinfo entries.
    pub fn try_new() -> Result<Self> {
        if !vmw_backdoor::is_vmware_cpu() {
            bail!("not running on VMWare CPU");
        }

        // NOTE(lucab): privileged mode is in theory more reliable but
        //  `kernel_lockdown(7)` may block it due to `iopl()` usage.
        //  Thus, we try that first and fall back if kernel blocks it.
        let mut backdoor = vmw_backdoor::probe_backdoor_privileged().or_else(|e| {
            slog_scope::warn!("failed to probe backdoor in privileged mode: {}", e);
            slog_scope::warn!("falling back to unprivileged backdoor access");
            vmw_backdoor::probe_backdoor()
        })?;

        let mut erpc = backdoor.open_enhanced_chan()?;
        let guestinfo_net_kargs = Self::fetch_guestinfo(&mut erpc, INITRD_NET_KARGS)?;

        let provider = Self {
            guestinfo_net_kargs,
        };

        slog_scope::trace!("cached vmware provider: {:?}", provider);
        Ok(provider)
    }

    /// Retrieve the value of a guestinfo string property, by key.
    fn fetch_guestinfo(erpc: &mut vmw_backdoor::EnhancedChan, key: &str) -> Result<Option<String>> {
        let guestinfo = erpc
            .get_guestinfo(key.as_bytes())
            .chain_err(|| "failed to retrieve network kargs")?
            .map(|bytes| String::from_utf8_lossy(&bytes).into_owned());
        Ok(guestinfo)
    }
}
<|endoftext|>


<commit_before>//
// Copyright (c) Pirmin Kalberer. All rights reserved.
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
//

use core::Config;
use core::enum_serializer::EnumString;
use toml;
use serde;
use serde::de::{Deserialize, Deserializer};
use std::fmt;

#[derive(PartialEq, Deserialize, Debug)]
pub struct Extent {
    pub minx: f64,
    pub miny: f64,
    pub maxx: f64,
    pub maxy: f64,
}

/// Min and max grid cell numbers
#[derive(PartialEq,Debug)]
pub struct ExtentInt {
    pub minx: u32,
    pub miny: u32,
    pub maxx: u32,
    pub maxy: u32,
}

#[derive(PartialEq, Debug)]
pub enum Origin {
    TopLeft,
    BottomLeft, //TopRight, BottomRight
}

impl EnumString<Origin> for Origin {
    fn from_str(val: &str) -> Result<Origin, String> {
        match val {
            "TopLeft" => Ok(Origin::TopLeft),
            "BottomLeft" => Ok(Origin::BottomLeft),
            _ => Err(format!("Unexpected enum value '{}'", val)),
        }
    }
    fn as_str(&self) -> &'static str {
        match *self {
            Origin::TopLeft => "TopLeft",
            Origin::BottomLeft => "BottomLeft",
        }
    }
}

enum_string_serialization!(Origin OriginVisitor);

#[derive(PartialEq, Debug)]
pub enum Unit {
    M,
    DD,
    Ft,
}

impl EnumString<Unit> for Unit {
    fn from_str(val: &str) -> Result<Unit, String> {
        match val {
            "M" => Ok(Unit::M),
            "DD" => Ok(Unit::DD),
            "Ft" => Ok(Unit::Ft),
            _ => Err(format!("Unexpected enum value '{}'", val)),
        }
    }
    fn as_str(&self) -> &'static str {
        match *self {
            Unit::M => "M",
            Unit::DD => "DD",
            Unit::Ft => "Ft",
        }
    }
}

enum_string_serialization!(Unit UnitVisitor);

// Credits: MapCache by Thomas Bonfort (http://mapserver.org/mapcache/)
#[derive(Deserialize, Debug)]
pub struct Grid {
    /// The width and height of an individual tile, in pixels.
    width: u16,
    height: u16,
    /// The geographical extent covered by the grid, in ground units (e.g. meters, degrees, feet, etc.).
    /// Must be specified as 4 floating point numbers ordered as minx, miny, maxx, maxy.
    /// The (minx,miny) point defines the origin of the grid, i.e. the pixel at the bottom left of the
    /// bottom-left most tile is always placed on the (minx,miny) geographical point.
    /// The (maxx,maxy) point is used to determine how many tiles there are for each zoom level.
    pub extent: Extent,
    /// Spatial reference system (PostGIS SRID).
    pub srid: i32,
    /// Grid units
    pub units: Unit,
    /// This is a list of resolutions for each of the zoom levels defined by the grid.
    /// This must be supplied as a list of positive floating point values, ordered from largest to smallest.
    /// The largest value will correspond to the grid’s zoom level 0. Resolutions
    /// are expressed in “units-per-pixel”,
    /// depending on the unit used by the grid (e.g. resolutions are in meters per
    /// pixel for most grids used in webmapping).
    resolutions: Vec<f64>,
    /// Grid origin
    pub origin: Origin,
}

impl Grid {
    /// WGS84 grid
    pub fn wgs84() -> Grid {
        Grid {
            width: 256,
            height: 256,
            extent: Extent {
                minx: -180.0,
                miny: -90.0,
                maxx: 180.0,
                maxy: 90.0,
            },
            srid: 4236,
            units: Unit::DD,
            resolutions: vec![0.703125000000000,
                              0.351562500000000,
                              0.175781250000000,
                              8.78906250000000e-2,
                              4.39453125000000e-2,
                              2.19726562500000e-2,
                              1.09863281250000e-2,
                              5.49316406250000e-3,
                              2.74658203125000e-3,
                              1.37329101562500e-3,
                              6.86645507812500e-4,
                              3.43322753906250e-4,
                              1.71661376953125e-4,
                              8.58306884765625e-5,
                              4.29153442382812e-5,
                              2.14576721191406e-5,
                              1.07288360595703e-5,
                              5.36441802978516e-6],
            origin: Origin::BottomLeft,
        }
    }

    /// Web Mercator grid (Google maps compatible)
    pub fn web_mercator() -> Grid {
        Grid {
            width: 256,
            height: 256,
            extent: Extent {
                minx: -20037508.3427892480,
                miny: -20037508.3427892480,
                maxx: 20037508.3427892480,
                maxy: 20037508.3427892480,
            },
            srid: 3857,
            units: Unit::M,
            resolutions: vec![156543.0339280410,
                              78271.51696402048,
                              39135.75848201023,
                              19567.87924100512,
                              9783.939620502561,
                              4891.969810251280,
                              2445.984905125640,
                              1222.992452562820,
                              611.4962262814100,
                              305.7481131407048,
                              152.8740565703525,
                              76.43702828517624,
                              38.21851414258813,
                              19.10925707129406,
                              9.554628535647032,
                              4.777314267823516,
                              2.388657133911758,
                              1.194328566955879,
                              0.5971642834779395],
            origin: Origin::BottomLeft,
        }
    }

    pub fn nlevels(&self) -> u8 {
        self.resolutions.len() as u8
    }
    pub fn maxzoom(&self) -> u8 {
        self.nlevels() - 1
    }
    pub fn pixel_width(&self, zoom: u8) -> f64 {
        self.resolutions[zoom as usize] //TODO: assumes grid unit 'm'
    }
    pub fn scale_denominator(&self, zoom: u8) -> f64 {
        let pixel_screen_width = 0.0254 / 96.0; //FIXME: assumes 96dpi - check with mapnik
        self.pixel_width(zoom) / pixel_screen_width
    }
    /// Extent of a given tile in the grid given its x, y, and z in TMS adressing scheme
    pub fn tile_extent(&self, xtile: u32, ytile: u32, zoom: u8) -> Extent {
        // based on mapcache_grid_get_tile_extent
        let res = self.resolutions[zoom as usize];
        let tile_sx = self.width as f64;
        let tile_sy = self.height as f64;
        match self.origin {
            Origin::BottomLeft => {
                Extent {
                    minx: self.extent.minx + (res * xtile as f64 * tile_sx),
                    miny: self.extent.miny + (res * ytile as f64 * tile_sy),
                    maxx: self.extent.minx + (res * (xtile + 1) as f64 * tile_sx),
                    maxy: self.extent.miny + (res * (ytile + 1) as f64 * tile_sy),
                }
            }
            Origin::TopLeft => {
                Extent {
                    minx: self.extent.minx + (res * xtile as f64 * tile_sx),
                    miny: self.extent.maxy - (res * (ytile + 1) as f64 * tile_sy),
                    maxx: self.extent.minx + (res * (xtile + 1) as f64 * tile_sx),
                    maxy: self.extent.maxy - (res * ytile as f64 * tile_sy),
                }
            }
        }
    }
    /// reverse y tile for XYZ adressing scheme
    pub fn ytile_from_xyz(&self, ytile: u32, zoom: u8) -> u32 {
        let res = self.resolutions[zoom as usize];
        let unitheight = self.height as f64 * res;
        // TODO: cache maxy for each resolution
        let maxy = ((self.extent.maxy - self.extent.minx - 0.01 * unitheight) / unitheight)
            .ceil() as u32;
        let y = maxy.saturating_sub(ytile).saturating_sub(1); // y = maxy-ytile-1
        y
    }
    /// Extent of a given tile in XYZ adressing scheme
    pub fn tile_extent_xyz(&self, xtile: u32, ytile: u32, zoom: u8) -> Extent {
        let y = self.ytile_from_xyz(ytile, zoom);
        self.tile_extent(xtile, y, zoom)
    }
    /// (maxx, maxy) of grid level
    pub fn level_limit(&self, zoom: u8) -> (u32, u32) {
        let res = self.resolutions[zoom as usize];
        let unitheight = self.height as f64 * res;
        let unitwidth = self.width as f64 * res;

        let maxy = ((self.extent.maxy - self.extent.miny - 0.01 * unitheight) / unitheight)
            .ceil() as u32;
        let maxx = ((self.extent.maxx - self.extent.miny - 0.01 * unitwidth) / unitwidth)
            .ceil() as u32;
        (maxx, maxy)
    }
    /// Tile index limits covering extent
    pub fn tile_limits(&self, extent: Extent, tolerance: i32) -> Vec<ExtentInt> {
        // Based on mapcache_grid_compute_limits
        const EPSILON: f64 = 0.0000001;
        let nlevels = self.resolutions.len() as u8;
        (0..nlevels)
            .map(|i| {
                let res = self.resolutions[i as usize];
                let unitheight = self.height as f64 * res;
                let unitwidth = self.width as f64 * res;
                let (level_maxx, level_maxy) = self.level_limit(i);

                let (mut minx, mut maxx, mut miny, mut maxy) = match self.origin {
                    Origin::BottomLeft => {
                        ((((extent.minx - self.extent.minx) / unitwidth + EPSILON).floor() as
                          i32) - tolerance,
                         (((extent.maxx - self.extent.minx) / unitwidth - EPSILON).ceil() as
                          i32) + tolerance,
                         (((extent.miny - self.extent.miny) / unitheight + EPSILON).floor() as
                          i32) - tolerance,
                         (((extent.maxy - self.extent.miny) / unitheight - EPSILON).ceil() as
                          i32) + tolerance)
                    }
                    Origin::TopLeft => {
                        ((((extent.minx - self.extent.minx) / unitwidth + EPSILON).floor() as
                          i32) - tolerance,
                         (((extent.maxx - self.extent.minx) / unitwidth - EPSILON).ceil() as
                          i32) + tolerance,
                         (((self.extent.maxy - extent.maxy) / unitheight + EPSILON).floor() as
                          i32) - tolerance,
                         (((self.extent.maxy - extent.miny) / unitheight - EPSILON).ceil() as
                          i32) + tolerance)
                    }
                };

                // to avoid requesting out-of-range tiles
                if minx < 0 {
                    minx = 0;
                }
                if maxx > level_maxx as i32 {
                    maxx = level_maxx as i32
                };
                if miny < 0 {
                    miny = 0
                };
                if maxy > level_maxy as i32 {
                    maxy = level_maxy as i32
                };

                ExtentInt {
                    minx: minx as u32,
                    maxx: maxx as u32,
                    miny: miny as u32,
                    maxy: maxy as u32,
                }
            })
            .collect()
    }
}

impl Config<Grid> for Grid {
    fn from_config(config: &toml::Value) -> Result<Self, String> {
        if config.get("grid").is_none() {
            return Err("Missing configuration entry [grid]".to_string());
        }
        if let Some(predef) = config.get("grid").and_then(|g| g.get("predefined")) {
            predef
                .as_str()
                .ok_or("grid.predefined entry is not a string".to_string())
                .and_then(|gridname| match gridname {
                              "wgs84" => Ok(Grid::wgs84()),
                              "web_mercator" => Ok(Grid::web_mercator()),
                              _ => Err(format!("Unkown grid '{}'", gridname)),
                          })
        } else {
            let ref gridcfg = config["grid"];
            let grid = gridcfg.clone().try_into::<Grid>();
            grid.map_err(|e| format!("Error reading configuration - {}", e))
        }
    }
    fn gen_config() -> String {
        let toml = r#"
[grid]
# Predefined grids: web_mercator, wgs84
predefined = "web_mercator"
"#;
        toml.to_string()
    }
}
<commit_msg>Extent Web Mercator grid to level 22<commit_after>//
// Copyright (c) Pirmin Kalberer. All rights reserved.
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
//

use core::Config;
use core::enum_serializer::EnumString;
use toml;
use serde;
use serde::de::{Deserialize, Deserializer};
use std::fmt;

#[derive(PartialEq, Deserialize, Debug)]
pub struct Extent {
    pub minx: f64,
    pub miny: f64,
    pub maxx: f64,
    pub maxy: f64,
}

/// Min and max grid cell numbers
#[derive(PartialEq,Debug)]
pub struct ExtentInt {
    pub minx: u32,
    pub miny: u32,
    pub maxx: u32,
    pub maxy: u32,
}

#[derive(PartialEq, Debug)]
pub enum Origin {
    TopLeft,
    BottomLeft, //TopRight, BottomRight
}

impl EnumString<Origin> for Origin {
    fn from_str(val: &str) -> Result<Origin, String> {
        match val {
            "TopLeft" => Ok(Origin::TopLeft),
            "BottomLeft" => Ok(Origin::BottomLeft),
            _ => Err(format!("Unexpected enum value '{}'", val)),
        }
    }
    fn as_str(&self) -> &'static str {
        match *self {
            Origin::TopLeft => "TopLeft",
            Origin::BottomLeft => "BottomLeft",
        }
    }
}

enum_string_serialization!(Origin OriginVisitor);

#[derive(PartialEq, Debug)]
pub enum Unit {
    M,
    DD,
    Ft,
}

impl EnumString<Unit> for Unit {
    fn from_str(val: &str) -> Result<Unit, String> {
        match val {
            "M" => Ok(Unit::M),
            "DD" => Ok(Unit::DD),
            "Ft" => Ok(Unit::Ft),
            _ => Err(format!("Unexpected enum value '{}'", val)),
        }
    }
    fn as_str(&self) -> &'static str {
        match *self {
            Unit::M => "M",
            Unit::DD => "DD",
            Unit::Ft => "Ft",
        }
    }
}

enum_string_serialization!(Unit UnitVisitor);

// Credits: MapCache by Thomas Bonfort (http://mapserver.org/mapcache/)
#[derive(Deserialize, Debug)]
pub struct Grid {
    /// The width and height of an individual tile, in pixels.
    width: u16,
    height: u16,
    /// The geographical extent covered by the grid, in ground units (e.g. meters, degrees, feet, etc.).
    /// Must be specified as 4 floating point numbers ordered as minx, miny, maxx, maxy.
    /// The (minx,miny) point defines the origin of the grid, i.e. the pixel at the bottom left of the
    /// bottom-left most tile is always placed on the (minx,miny) geographical point.
    /// The (maxx,maxy) point is used to determine how many tiles there are for each zoom level.
    pub extent: Extent,
    /// Spatial reference system (PostGIS SRID).
    pub srid: i32,
    /// Grid units
    pub units: Unit,
    /// This is a list of resolutions for each of the zoom levels defined by the grid.
    /// This must be supplied as a list of positive floating point values, ordered from largest to smallest.
    /// The largest value will correspond to the grid’s zoom level 0. Resolutions
    /// are expressed in “units-per-pixel”,
    /// depending on the unit used by the grid (e.g. resolutions are in meters per
    /// pixel for most grids used in webmapping).
    resolutions: Vec<f64>,
    /// Grid origin
    pub origin: Origin,
}

impl Grid {
    /// WGS84 grid
    pub fn wgs84() -> Grid {
        Grid {
            width: 256,
            height: 256,
            extent: Extent {
                minx: -180.0,
                miny: -90.0,
                maxx: 180.0,
                maxy: 90.0,
            },
            srid: 4236,
            units: Unit::DD,
            resolutions: vec![0.703125000000000,
                              0.351562500000000,
                              0.175781250000000,
                              8.78906250000000e-2,
                              4.39453125000000e-2,
                              2.19726562500000e-2,
                              1.09863281250000e-2,
                              5.49316406250000e-3,
                              2.74658203125000e-3,
                              1.37329101562500e-3,
                              6.86645507812500e-4,
                              3.43322753906250e-4,
                              1.71661376953125e-4,
                              8.58306884765625e-5,
                              4.29153442382812e-5,
                              2.14576721191406e-5,
                              1.07288360595703e-5,
                              5.36441802978516e-6],
            origin: Origin::BottomLeft,
        }
    }

    /// Web Mercator grid (Google maps compatible)
    pub fn web_mercator() -> Grid {
        Grid {
            width: 256,
            height: 256,
            extent: Extent {
                minx: -20037508.3427892480,
                miny: -20037508.3427892480,
                maxx: 20037508.3427892480,
                maxy: 20037508.3427892480,
            },
            srid: 3857,
            units: Unit::M,
            resolutions: vec![156543.0339280410,
                              78271.51696402048,
                              39135.75848201023,
                              19567.87924100512,
                              9783.939620502561,
                              4891.969810251280,
                              2445.984905125640,
                              1222.992452562820,
                              611.4962262814100,
                              305.7481131407048,
                              152.8740565703525,
                              76.43702828517624,
                              38.21851414258813,
                              19.10925707129406,
                              9.554628535647032,
                              4.777314267823516,
                              2.388657133911758,
                              1.194328566955879,
                              0.5971642834779395,
                              0.2985821417389700,
                              0.1492910708694850,
                              0.0746455354347424,
                              0.0373227677173712],
            origin: Origin::BottomLeft,
        }
    }

    pub fn nlevels(&self) -> u8 {
        self.resolutions.len() as u8
    }
    pub fn maxzoom(&self) -> u8 {
        self.nlevels() - 1
    }
    pub fn pixel_width(&self, zoom: u8) -> f64 {
        self.resolutions[zoom as usize] //TODO: assumes grid unit 'm'
    }
    pub fn scale_denominator(&self, zoom: u8) -> f64 {
        let pixel_screen_width = 0.0254 / 96.0; //FIXME: assumes 96dpi - check with mapnik
        self.pixel_width(zoom) / pixel_screen_width
    }
    /// Extent of a given tile in the grid given its x, y, and z in TMS adressing scheme
    pub fn tile_extent(&self, xtile: u32, ytile: u32, zoom: u8) -> Extent {
        // based on mapcache_grid_get_tile_extent
        let res = self.resolutions[zoom as usize];
        let tile_sx = self.width as f64;
        let tile_sy = self.height as f64;
        match self.origin {
            Origin::BottomLeft => {
                Extent {
                    minx: self.extent.minx + (res * xtile as f64 * tile_sx),
                    miny: self.extent.miny + (res * ytile as f64 * tile_sy),
                    maxx: self.extent.minx + (res * (xtile + 1) as f64 * tile_sx),
                    maxy: self.extent.miny + (res * (ytile + 1) as f64 * tile_sy),
                }
            }
            Origin::TopLeft => {
                Extent {
                    minx: self.extent.minx + (res * xtile as f64 * tile_sx),
                    miny: self.extent.maxy - (res * (ytile + 1) as f64 * tile_sy),
                    maxx: self.extent.minx + (res * (xtile + 1) as f64 * tile_sx),
                    maxy: self.extent.maxy - (res * ytile as f64 * tile_sy),
                }
            }
        }
    }
    /// reverse y tile for XYZ adressing scheme
    pub fn ytile_from_xyz(&self, ytile: u32, zoom: u8) -> u32 {
        let res = self.resolutions[zoom as usize];
        let unitheight = self.height as f64 * res;
        // TODO: cache maxy for each resolution
        let maxy = ((self.extent.maxy - self.extent.minx - 0.01 * unitheight) / unitheight)
            .ceil() as u32;
        let y = maxy.saturating_sub(ytile).saturating_sub(1); // y = maxy-ytile-1
        y
    }
    /// Extent of a given tile in XYZ adressing scheme
    pub fn tile_extent_xyz(&self, xtile: u32, ytile: u32, zoom: u8) -> Extent {
        let y = self.ytile_from_xyz(ytile, zoom);
        self.tile_extent(xtile, y, zoom)
    }
    /// (maxx, maxy) of grid level
    pub fn level_limit(&self, zoom: u8) -> (u32, u32) {
        let res = self.resolutions[zoom as usize];
        let unitheight = self.height as f64 * res;
        let unitwidth = self.width as f64 * res;

        let maxy = ((self.extent.maxy - self.extent.miny - 0.01 * unitheight) / unitheight)
            .ceil() as u32;
        let maxx = ((self.extent.maxx - self.extent.miny - 0.01 * unitwidth) / unitwidth)
            .ceil() as u32;
        (maxx, maxy)
    }
    /// Tile index limits covering extent
    pub fn tile_limits(&self, extent: Extent, tolerance: i32) -> Vec<ExtentInt> {
        // Based on mapcache_grid_compute_limits
        const EPSILON: f64 = 0.0000001;
        let nlevels = self.resolutions.len() as u8;
        (0..nlevels)
            .map(|i| {
                let res = self.resolutions[i as usize];
                let unitheight = self.height as f64 * res;
                let unitwidth = self.width as f64 * res;
                let (level_maxx, level_maxy) = self.level_limit(i);

                let (mut minx, mut maxx, mut miny, mut maxy) = match self.origin {
                    Origin::BottomLeft => {
                        ((((extent.minx - self.extent.minx) / unitwidth + EPSILON).floor() as
                          i32) - tolerance,
                         (((extent.maxx - self.extent.minx) / unitwidth - EPSILON).ceil() as
                          i32) + tolerance,
                         (((extent.miny - self.extent.miny) / unitheight + EPSILON).floor() as
                          i32) - tolerance,
                         (((extent.maxy - self.extent.miny) / unitheight - EPSILON).ceil() as
                          i32) + tolerance)
                    }
                    Origin::TopLeft => {
                        ((((extent.minx - self.extent.minx) / unitwidth + EPSILON).floor() as
                          i32) - tolerance,
                         (((extent.maxx - self.extent.minx) / unitwidth - EPSILON).ceil() as
                          i32) + tolerance,
                         (((self.extent.maxy - extent.maxy) / unitheight + EPSILON).floor() as
                          i32) - tolerance,
                         (((self.extent.maxy - extent.miny) / unitheight - EPSILON).ceil() as
                          i32) + tolerance)
                    }
                };

                // to avoid requesting out-of-range tiles
                if minx < 0 {
                    minx = 0;
                }
                if maxx > level_maxx as i32 {
                    maxx = level_maxx as i32
                };
                if miny < 0 {
                    miny = 0
                };
                if maxy > level_maxy as i32 {
                    maxy = level_maxy as i32
                };

                ExtentInt {
                    minx: minx as u32,
                    maxx: maxx as u32,
                    miny: miny as u32,
                    maxy: maxy as u32,
                }
            })
            .collect()
    }
}

impl Config<Grid> for Grid {
    fn from_config(config: &toml::Value) -> Result<Self, String> {
        if config.get("grid").is_none() {
            return Err("Missing configuration entry [grid]".to_string());
        }
        if let Some(predef) = config.get("grid").and_then(|g| g.get("predefined")) {
            predef
                .as_str()
                .ok_or("grid.predefined entry is not a string".to_string())
                .and_then(|gridname| match gridname {
                              "wgs84" => Ok(Grid::wgs84()),
                              "web_mercator" => Ok(Grid::web_mercator()),
                              _ => Err(format!("Unkown grid '{}'", gridname)),
                          })
        } else {
            let ref gridcfg = config["grid"];
            let grid = gridcfg.clone().try_into::<Grid>();
            grid.map_err(|e| format!("Error reading configuration - {}", e))
        }
    }
    fn gen_config() -> String {
        let toml = r#"
[grid]
# Predefined grids: web_mercator, wgs84
predefined = "web_mercator"
"#;
        toml.to_string()
    }
}
<|endoftext|>


<commit_before>fn main() {
    let mystr1: &'static str = "This is a readonly string";

    for c in mystr1.chars().rev() {
        print!("{}", c);
    }

    println!("");

    let mut mystr2 = String::new();
    for c in mystr1.chars() {
        mystr2.push(c);
    }

    println!("{}", mystr2);

    mystr2 = "Hello World".to_string();

    println!("{}", mystr2);

    let num: u32 = 12;

    mystr2 = num.to_string();

    println!("{}", mystr2);
}<commit_msg>added sort example<commit_after>pub fn sort(word: &'static str) -> String {
    let mut chars: Vec<char> = word.chars().collect();
    chars.sort();
    return chars.into_iter().collect();
}

fn main() {
    let mystr1: &'static str = "This is a readonly string";

    for c in mystr1.chars().rev() {
        print!("{}", c);
    }

    println!("");

    let mut mystr2 = String::new();
    for c in mystr1.chars() {
        mystr2.push(c);
    }

    println!("{}", mystr2);

    mystr2 = "Hello World".to_string();

    println!("{}", mystr2);

    let num: u32 = 12;

    mystr2 = num.to_string();

    println!("{}", mystr2);

    let str = sort("abzerfdsgyiof");
    print!("{}", str);
}<|endoftext|>


<commit_before>extern crate gfx;

use std::collections::HashMap;
use std::time;

use euclid::{TypedPoint2D, TypedRect, TypedSize2D, TypedTransform2D};
use gfx::handle::Buffer;
use gfx::pso::PipelineState;
use gfx::traits::FactoryExt;
use gfx::IndexBuffer;

use camera::CameraState;
use defs::*;
use delta::Delta;
use gamestate::GameState;
use math;
use math::*;
use mesh_gen::*;
use polyomino::*;
use shape::*;

// TODO: this works under the assumption that the shapes being drawn
// on each level are all distinct. (which is true currently)
#[derive(Clone, Debug)]
struct LevelTracker {
    level: i32,
    visual_level: f32,
    transforms: HashMap<ShapeId, Delta>,
}

impl LevelTracker {
    pub fn from_gamestate(gs: &GameState) -> LevelTracker {
        let chunk = &gs.camera_state.current_chunk;

        let mut result = hashmap![];

        for (shape_id, uvec) in &chunk.top_shape_ids {
            result.insert(*shape_id, Delta::from(*uvec));
        }

        LevelTracker {
            level: 0,
            visual_level: gs.camera_state.current_visual_level(),
            transforms: result,
        }
    }

    pub fn go_up(&self, gamestate: &GameState) -> LevelTracker {
        let mut result: HashMap<ShapeId, Delta> = hashmap![];
        let universe = &gamestate.logical_state.universe;

        for (shape_id, delta) in &self.transforms {
            let shape = &universe.shapes[shape_id];

            for parent in universe.parents_of(shape) {
                if result.contains_key(&parent.id) {
                    continue;
                }

                result.insert(
                    parent.id,
                    delta.revert(&gamestate.visual_delta_to_child(parent, shape)),
                );
            }
        }

        LevelTracker {
            level: self.level + 1,
            visual_level: self.visual_level + 1.0,
            transforms: result,
        }
    }

    pub fn go_down(&self, gamestate: &GameState) -> LevelTracker {
        let mut result: HashMap<ShapeId, Delta> = hashmap![];
        let universe = &gamestate.logical_state.universe;

        for (shape_id, delta) in &self.transforms {
            let shape = &universe.shapes[shape_id];

            for child in universe.children_of(shape) {
                if result.contains_key(&child.id) {
                    continue;
                }

                result.insert(child.id, delta.append(&gamestate.visual_delta_to_child(shape, child)));
            }
        }

        LevelTracker {
            level: self.level - 1,
            visual_level: self.visual_level - 1.0,
            transforms: result,
        }
    }

    pub fn filter_nonvisible(&mut self) -> () {
        // TODO: do this
    }
}

pub struct Director<R: gfx::Resources> {
    pub resolution: TypedSize2D<u32, ScreenSpace>,

    draw_space_to_gl: TypedTransform2D<f32, DrawSpace, GLSpace>,

    mesh_store: MeshStore,
    poly_mesh_buffer: Buffer<R, GpuShapeVertex>,
    poly_mesh_index_buffer: IndexBuffer<R>,
    shape_pso: PipelineState<R, shape_pipe::Meta>,

    pub game_state: GameState,
}

impl<R: gfx::Resources> Director<R> {
    pub fn new<F: gfx::traits::Factory<R>>(
        factory: &mut F,
        resolution: TypedSize2D<u32, ScreenSpace>,
    ) -> Director<R> {
        let game_state = GameState::new(resolution);

        // TODO: will one day have to make this choose the right
        // shaders for the platform.
        let shape_pso = factory
            .create_pipeline_simple(
                include_bytes!(concat!(
                    env!("CARGO_MANIFEST_DIR"),
                    "/src/shaders/shape_150.glslv"
                )),
                include_bytes!(concat!(
                    env!("CARGO_MANIFEST_DIR"),
                    "/src/shaders/shape_150.glslf"
                )),
                shape_pipe::new(),
            )
            .unwrap();

        let store = Director::build_mesh_cache(&game_state.logical_state, factory);
        let pmb = factory.create_vertex_buffer(&store.poly_meshes.vertices);
        let pmib = factory.create_index_buffer(&store.poly_meshes.all_indices[..]);

        let ndc_bounds = TypedRect::new(TypedPoint2D::new(-1.0, -1.0), TypedSize2D::new(2.0, 2.0));
        let draw_space_to_gl =
            transform::rect_to_rect(&game_state.camera_state.camera_bounds, &ndc_bounds);

        Director {
            shape_pso,
            resolution,
            draw_space_to_gl,

            mesh_store: store,
            poly_mesh_buffer: pmb,
            poly_mesh_index_buffer: pmib,

            game_state,
        }
    }

    fn build_mesh_cache<F: gfx::traits::Factory<R>>(
        gs: &LogicalState,
        _factory: &mut F,
    ) -> MeshStore {
        let mut result = MeshStore::new();

        for s in gs.universe.shapes.values() {
            if result.contains_poly(&s.polyomino) {
                continue;
            }

            result.gen_polyomino_mesh(&s.polyomino);
        }

        result
    }

    fn execute_poly_draw<C: gfx::CommandBuffer<R>>(
        &self,
        encoder: &mut gfx::Encoder<R, C>,
        target: &gfx::handle::RenderTargetView<R, ColorFormat>,
        poly: &Polyomino,
        raw_transform: &TypedTransform2D<f32, UniverseSpace, GLSpace>,
        fill_color: [f32; 3],
        outline_color: [f32; 3],
    ) -> () {
        let arr_transform = (*raw_transform).to_gl_mat3();

        let fill_slice = self.mesh_store.poly_meshes.gfx_slice_for(
            &self.poly_mesh_index_buffer,
            PolyMeshId {
                poly: poly.clone(),
                which: PolyMeshType::FillMesh,
            },
        );

        let fill_data = shape_pipe::Data {
            vbuf: self.poly_mesh_buffer.clone(),
            out: target.clone(),
            transform: arr_transform,
            color: fill_color,
        };

        encoder.draw(&fill_slice, &self.shape_pso, &fill_data);

        let outline_slice = self.mesh_store.poly_meshes.gfx_slice_for(
            &self.poly_mesh_index_buffer,
            PolyMeshId {
                poly: poly.clone(),
                which: PolyMeshType::GridMesh,
            },
        );

        let outline_data = shape_pipe::Data {
            vbuf: self.poly_mesh_buffer.clone(),
            out: target.clone(),
            transform: arr_transform,
            color: outline_color,
        };

        //        encoder.draw(&outline_slice, &self.shape_pso, &outline_data);
    }

    fn draw_level<C: gfx::CommandBuffer<R>>(
        &self,
        encoder: &mut gfx::Encoder<R, C>,
        target: &gfx::handle::RenderTargetView<R, ColorFormat>,
        level_tracker: &LevelTracker,
    ) -> () {
        let transform_to_gl = self
            .game_state
            .camera_state
            .current_transform
            .post_mul(&self.draw_space_to_gl);

        for (shape_id, offset) in &level_tracker.transforms {
            let shape = &self.game_state.logical_state.universe.shapes[shape_id];
            let offset_transform = offset.to_scale_transform();

            self.execute_poly_draw(
                encoder,
                target,
                &shape.polyomino,
                &offset_transform.post_mul(&transform_to_gl),
                shape.fill_color,
                shape.outline_color,
            );
        }
    }

    pub fn draw<C: gfx::CommandBuffer<R>>(
        &self,
        encoder: &mut gfx::Encoder<R, C>,
        target: &gfx::handle::RenderTargetView<R, ColorFormat>,
    ) -> () {
        let mut l = LevelTracker::from_gamestate(&self.game_state);

        for _ in 0..DRAW_DISTANCE_UP {
            l = l.go_up(&self.game_state);
            l.filter_nonvisible();
        }

        self.draw_level(encoder, target, &l);
        for _ in 0..(DRAW_DISTANCE_UP + DRAW_DISTANCE_DOWN) {
            l = l.go_down(&self.game_state);
            l.filter_nonvisible();
            self.draw_level(encoder, target, &l);
        }
    }
}
<commit_msg>Use the fade visually<commit_after>extern crate gfx;

use std::collections::HashMap;
use std::time;

use euclid::{TypedPoint2D, TypedRect, TypedSize2D, TypedTransform2D};
use gfx::handle::Buffer;
use gfx::pso::PipelineState;
use gfx::traits::FactoryExt;
use gfx::IndexBuffer;

use camera::CameraState;
use defs::*;
use delta::Delta;
use gamestate::GameState;
use math;
use math::*;
use mesh_gen::*;
use polyomino::*;
use shape::*;

// TODO: this works under the assumption that the shapes being drawn
// on each level are all distinct. (which is true currently)
#[derive(Clone, Debug)]
struct LevelTracker {
    level: i32,
    visual_level: f32,
    transforms: HashMap<ShapeId, Delta>,
}

impl LevelTracker {
    pub fn from_gamestate(gs: &GameState) -> LevelTracker {
        let chunk = &gs.camera_state.current_chunk;

        let mut result = hashmap![];

        for (shape_id, uvec) in &chunk.top_shape_ids {
            result.insert(*shape_id, Delta::from(*uvec));
        }

        LevelTracker {
            level: 0,
            visual_level: gs.camera_state.current_visual_level(),
            transforms: result,
        }
    }

    pub fn go_up(&self, gamestate: &GameState) -> LevelTracker {
        let mut result: HashMap<ShapeId, Delta> = hashmap![];
        let universe = &gamestate.logical_state.universe;

        for (shape_id, delta) in &self.transforms {
            let shape = &universe.shapes[shape_id];

            for parent in universe.parents_of(shape) {
                if result.contains_key(&parent.id) {
                    continue;
                }

                result.insert(
                    parent.id,
                    delta.revert(&gamestate.visual_delta_to_child(parent, shape)),
                );
            }
        }

        LevelTracker {
            level: self.level + 1,
            visual_level: self.visual_level + 1.0,
            transforms: result,
        }
    }

    pub fn go_down(&self, gamestate: &GameState) -> LevelTracker {
        let mut result: HashMap<ShapeId, Delta> = hashmap![];
        let universe = &gamestate.logical_state.universe;

        for (shape_id, delta) in &self.transforms {
            let shape = &universe.shapes[shape_id];

            for child in universe.children_of(shape) {
                if result.contains_key(&child.id) {
                    continue;
                }

                result.insert(child.id, delta.append(&gamestate.visual_delta_to_child(shape, child)));
            }
        }

        LevelTracker {
            level: self.level - 1,
            visual_level: self.visual_level - 1.0,
            transforms: result,
        }
    }

    pub fn filter_nonvisible(&mut self) -> () {
        // TODO: do this
    }
}

pub struct Director<R: gfx::Resources> {
    pub resolution: TypedSize2D<u32, ScreenSpace>,

    draw_space_to_gl: TypedTransform2D<f32, DrawSpace, GLSpace>,

    mesh_store: MeshStore,
    poly_mesh_buffer: Buffer<R, GpuShapeVertex>,
    poly_mesh_index_buffer: IndexBuffer<R>,
    shape_pso: PipelineState<R, shape_pipe::Meta>,

    pub game_state: GameState,
}

impl<R: gfx::Resources> Director<R> {
    pub fn new<F: gfx::traits::Factory<R>>(
        factory: &mut F,
        resolution: TypedSize2D<u32, ScreenSpace>,
    ) -> Director<R> {
        let game_state = GameState::new(resolution);

        // TODO: will one day have to make this choose the right
        // shaders for the platform.
        let shape_pso = factory
            .create_pipeline_simple(
                include_bytes!(concat!(
                    env!("CARGO_MANIFEST_DIR"),
                    "/src/shaders/shape_150.glslv"
                )),
                include_bytes!(concat!(
                    env!("CARGO_MANIFEST_DIR"),
                    "/src/shaders/shape_150.glslf"
                )),
                shape_pipe::new(),
            )
            .unwrap();

        let store = Director::build_mesh_cache(&game_state.logical_state, factory);
        let pmb = factory.create_vertex_buffer(&store.poly_meshes.vertices);
        let pmib = factory.create_index_buffer(&store.poly_meshes.all_indices[..]);

        let ndc_bounds = TypedRect::new(TypedPoint2D::new(-1.0, -1.0), TypedSize2D::new(2.0, 2.0));
        let draw_space_to_gl =
            transform::rect_to_rect(&game_state.camera_state.camera_bounds, &ndc_bounds);

        Director {
            shape_pso,
            resolution,
            draw_space_to_gl,

            mesh_store: store,
            poly_mesh_buffer: pmb,
            poly_mesh_index_buffer: pmib,

            game_state,
        }
    }

    fn build_mesh_cache<F: gfx::traits::Factory<R>>(
        gs: &LogicalState,
        _factory: &mut F,
    ) -> MeshStore {
        let mut result = MeshStore::new();

        for s in gs.universe.shapes.values() {
            if result.contains_poly(&s.polyomino) {
                continue;
            }

            result.gen_polyomino_mesh(&s.polyomino);
        }

        result
    }

    fn execute_poly_draw<C: gfx::CommandBuffer<R>>(
        &self,
        encoder: &mut gfx::Encoder<R, C>,
        target: &gfx::handle::RenderTargetView<R, ColorFormat>,
        poly: &Polyomino,
        raw_transform: &TypedTransform2D<f32, UniverseSpace, GLSpace>,
        fill_color: [f32; 3],
        outline_color: [f32; 3],
    ) -> () {
        let arr_transform = (*raw_transform).to_gl_mat3();

        let fill_slice = self.mesh_store.poly_meshes.gfx_slice_for(
            &self.poly_mesh_index_buffer,
            PolyMeshId {
                poly: poly.clone(),
                which: PolyMeshType::FillMesh,
            },
        );

        let fill_data = shape_pipe::Data {
            vbuf: self.poly_mesh_buffer.clone(),
            out: target.clone(),
            transform: arr_transform,
            color: fill_color,
        };

        encoder.draw(&fill_slice, &self.shape_pso, &fill_data);

        let outline_slice = self.mesh_store.poly_meshes.gfx_slice_for(
            &self.poly_mesh_index_buffer,
            PolyMeshId {
                poly: poly.clone(),
                which: PolyMeshType::GridMesh,
            },
        );

        let outline_data = shape_pipe::Data {
            vbuf: self.poly_mesh_buffer.clone(),
            out: target.clone(),
            transform: arr_transform,
            color: outline_color,
        };

        //        encoder.draw(&outline_slice, &self.shape_pso, &outline_data);
    }

    fn fade_amount_for_level(level: f32) -> f32 {
        if level < 0.0 {
            1.0
        } else if 0.0 <= level && level <= 1.0 {
            1.0 - (0.7 * level)
        } else {
            0.3
        }
    }

    fn draw_level<C: gfx::CommandBuffer<R>>(
        &self,
        encoder: &mut gfx::Encoder<R, C>,
        target: &gfx::handle::RenderTargetView<R, ColorFormat>,
        level_tracker: &LevelTracker,
    ) -> () {
        let transform_to_gl = self
            .game_state
            .camera_state
            .current_transform
            .post_mul(&self.draw_space_to_gl);

        let fade = <Director<R>>::fade_amount_for_level(level_tracker.visual_level);

        for (shape_id, offset) in &level_tracker.transforms {
            let shape = &self.game_state.logical_state.universe.shapes[shape_id];
            let offset_transform = offset.to_scale_transform();

            let faded_fill = [shape.fill_color[0] * fade,
                              shape.fill_color[1] * fade,
                              shape.fill_color[2] * fade];

            self.execute_poly_draw(
                encoder,
                target,
                &shape.polyomino,
                &offset_transform.post_mul(&transform_to_gl),
                faded_fill,
                shape.outline_color,
            );
        }
    }

    pub fn draw<C: gfx::CommandBuffer<R>>(
        &self,
        encoder: &mut gfx::Encoder<R, C>,
        target: &gfx::handle::RenderTargetView<R, ColorFormat>,
    ) -> () {
        let mut l = LevelTracker::from_gamestate(&self.game_state);

        for _ in 0..DRAW_DISTANCE_UP {
            l = l.go_up(&self.game_state);
            l.filter_nonvisible();
        }

        self.draw_level(encoder, target, &l);
        for _ in 0..(DRAW_DISTANCE_UP + DRAW_DISTANCE_DOWN) {
            l = l.go_down(&self.game_state);
            l.filter_nonvisible();
            self.draw_level(encoder, target, &l);
        }
    }
}
<|endoftext|>


<commit_before>use {Byte, Chunk, SChunks};
use client::GetResponse;
use hyper::client::Client;
use hyper::error::Error;
use hyper::header::{ByteRangeSpec, Headers, Range};
use std::cmp::min;
use std::io::Read;
use std::thread;

/// Represents a range between two Byte types
#[derive(Debug, PartialEq)]
struct RangeBytes(Byte, Byte);

/// Function to get the current chunk length, based on the chunk index.
fn get_chunk_length(chunk_index: u64,
                    content_length: Byte,
                    global_chunk_length: Byte)
                    -> Option<RangeBytes> {

    if content_length == 0 || global_chunk_length == 0 {
        return None;
    }

    let b_range: Byte = chunk_index * global_chunk_length;

    if b_range >= (content_length - 1) {
        return None;
    }

    let e_range: Byte = min(content_length - 1,
                            ((chunk_index + 1) * global_chunk_length) - 1);

    Some(RangeBytes(b_range, e_range))

}

/// Function to get the HTTP header to send to the file server, for a chunk (specified by its index)
fn get_header_from_index(chunk_index: u64,
                         content_length: Byte,
                         global_chunk_length: Byte)
                         -> Option<(Headers, Byte)> {

    match get_chunk_length(chunk_index, content_length, global_chunk_length) {
        Some(range) => {
            let mut header = Headers::new();
            header.set(Range::Bytes(vec![ByteRangeSpec::FromTo(range.0, range.1)]));
            Some((header, range.1 - range.0))
        }
        None => None,
    }

}

/// Function to get from the server the content of a chunk.
/// This function returns a Result type - Byte if the content of the header is accessible, an Error type otherwise.
fn download_a_chunk(http_client: &Client,
                    http_header: Headers,
                    chunk_vector: &mut Chunk,
                    url: &str)
                    -> Result<Byte, Error> {

    match http_client.get_http_response_using_headers(url, http_header) {
        Ok(mut body) => {
            match body.read_to_end(chunk_vector) {
                Ok(nb_bytes) => Ok(nb_bytes as u64),
                Err(_) => Ok(0u64),
            }
        }
        Err(http_error) => Err(http_error),
    }

}

/// Function to download each chunk of a remote content (given by its URL).
/// This function takes as parameters:
/// * the remote content length,
/// * a mutable reference to share between threads, which contains each chunk,
/// * the number of chunks that contains the remote content,
/// * the URL of the remote content server.
pub fn download_chunks(content_length: u64,
                       downloaded_chunks: &SChunks,
                       nb_chunks: u64,
                       url: &str) {

    // let mut downloaded_chunks: Arc<Mutex<Chunks>> =
    //     Arc::new(Mutex::new(Chunks::with_capacity(nb_chunks as usize)));
    let global_chunk_length: u64 = (content_length / nb_chunks) + 1;
    let mut jobs = vec![];

    for chunk_index in 0..nb_chunks {

        let (http_header, chunk_length) =
            get_header_from_index(chunk_index, content_length, global_chunk_length).unwrap();
        let mut chunk_content = Chunk::with_capacity(chunk_length as usize);
        let hyper_client = Client::new();
        let url_clone = String::from(url);
        let clone_chunks = downloaded_chunks.clone();

        jobs.push(thread::spawn(move || {
            match download_a_chunk(&hyper_client, http_header, &mut chunk_content, &url_clone) {
                Ok(bytes_written) => {
                    if bytes_written > 0 {
                        let mut shared_clone_chunks = clone_chunks.lock().unwrap();
                        shared_clone_chunks.insert(chunk_index as usize, chunk_content);
                    } else {
                        panic!("The downloaded chunk {} is empty", chunk_index);
                    }
                }
                Err(error) => {
                    panic!("Canno't download the chunk {}, due to error {}",
                           chunk_index,
                           error);
                }
            }
        }));
    }

    for child in jobs {
        let _ = child.join();
    }

}

#[cfg(test)]
mod test_chunk_length {
    use super::get_chunk_length;
    use super::RangeBytes;

    #[test]
    fn wrong_content_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 15, 0));
    }

    #[test]
    fn wrong_global_chunk_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 15));
    }

    #[test]
    fn wrong_length_parameters_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 0));
    }

    #[test]
    fn get_the_first_range_in_chunk() {
        assert_eq!(Some(RangeBytes(0, 249)), get_chunk_length(0, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_chunk() {
        assert_eq!(Some(RangeBytes(750, 999)), get_chunk_length(3, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_shorten_chunk() {
        assert_eq!(Some(RangeBytes(750, 997)), get_chunk_length(3, 998, 250));
    }

    #[test]
    fn wrong_index_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(4, 1000, 250));
    }

}<commit_msg>Change tests<commit_after>use {Byte, Chunk, SChunks};
use client::GetResponse;
use hyper::client::Client;
use hyper::error::Error;
use hyper::header::{ByteRangeSpec, Headers, Range};
use std::cmp::min;
use std::io::Read;
use std::thread;

/// Represents a range between two Byte types
#[derive(Debug, PartialEq)]
struct RangeBytes(Byte, Byte);

/// Function to get the current chunk length, based on the chunk index.
fn get_chunk_length(chunk_index: u64,
                    content_length: Byte,
                    global_chunk_length: Byte)
                    -> Option<RangeBytes> {

    if content_length == 0 || global_chunk_length == 0 {
        return None;
    }

    let b_range: Byte = chunk_index * global_chunk_length;

    if b_range >= (content_length - 1) {
        return None;
    }

    let e_range: Byte = min(content_length - 1,
                            ((chunk_index + 1) * global_chunk_length) - 1);

    Some(RangeBytes(b_range, e_range))

}

/// Function to get the HTTP header to send to the file server, for a chunk (specified by its index)
fn get_header_from_index(chunk_index: u64,
                         content_length: Byte,
                         global_chunk_length: Byte)
                         -> Option<(Headers, Byte)> {

    match get_chunk_length(chunk_index, content_length, global_chunk_length) {
        Some(range) => {
            let mut header = Headers::new();
            header.set(Range::Bytes(vec![ByteRangeSpec::FromTo(range.0, range.1)]));
            Some((header, range.1 - range.0))
        }
        None => None,
    }

}

/// Function to get from the server the content of a chunk.
/// This function returns a Result type - Byte if the content of the header is accessible, an Error type otherwise.
fn download_a_chunk(http_client: &Client,
                    http_header: Headers,
                    chunk_vector: &mut Chunk,
                    url: &str)
                    -> Result<Byte, Error> {

    match http_client.get_http_response_using_headers(url, http_header) {
        Ok(mut body) => {
            match body.read_to_end(chunk_vector) {
                Ok(nb_bytes) => Ok(nb_bytes as u64),
                Err(_) => Ok(0u64),
            }
        }
        Err(http_error) => Err(http_error),
    }

}

/// Function to download each chunk of a remote content (given by its URL).
/// This function takes as parameters:
/// * the remote content length,
/// * a mutable reference to share between threads, which contains each chunk,
/// * the number of chunks that contains the remote content,
/// * the URL of the remote content server.
pub fn download_chunks(content_length: u64,
                       downloaded_chunks: &SChunks,
                       nb_chunks: u64,
                       url: &str) {

    // let mut downloaded_chunks: Arc<Mutex<Chunks>> =
    //     Arc::new(Mutex::new(Chunks::with_capacity(nb_chunks as usize)));
    let global_chunk_length: u64 = (content_length / nb_chunks) + 1;
    let mut jobs = vec![];

    for chunk_index in 0..nb_chunks {

        let (http_header, chunk_length) =
            get_header_from_index(chunk_index, content_length, global_chunk_length).unwrap();
        let mut chunk_content = Chunk::with_capacity(chunk_length as usize);
        let hyper_client = Client::new();
        let url_clone = String::from(url);
        let clone_chunks = downloaded_chunks.clone();

        jobs.push(thread::spawn(move || {
            match download_a_chunk(&hyper_client, http_header, &mut chunk_content, &url_clone) {
                Ok(bytes_written) => {
                    if bytes_written > 0 {
                        let mut shared_clone_chunks = clone_chunks.lock().unwrap();
                        shared_clone_chunks.insert(chunk_index as usize, chunk_content);
                    } else {
                        panic!("The downloaded chunk {} is empty", chunk_index);
                    }
                }
                Err(error) => {
                    panic!("Canno't download the chunk {}, due to error {}",
                           chunk_index,
                           error);
                }
            }
        }));
    }

    for child in jobs {
        let _ = child.join();
    }

}

#[cfg(test)]
mod test_chunk_length {

    use super::get_chunk_length;
    use super::RangeBytes;

    #[test]
    fn wrong_content_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 15, 0));
    }

    #[test]
    fn wrong_global_chunk_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 15));
    }

    #[test]
    fn wrong_length_parameters_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 0));
    }

    #[test]
    fn get_the_first_range_in_chunk() {
        assert_eq!(Some(RangeBytes(0, 249)), get_chunk_length(0, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_chunk() {
        assert_eq!(Some(RangeBytes(750, 999)), get_chunk_length(3, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_shorten_chunk() {
        assert_eq!(Some(RangeBytes(750, 997)), get_chunk_length(3, 998, 250));
    }

    #[test]
    fn wrong_index_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(4, 1000, 250));
    }

}

#[cfg(test)]
mod test_header {

    use super::get_header_from_index;
    use hyper::header::{ByteRangeSpec, Headers, Range};

    #[test]
    fn wrong_chunk_length_should_return_none() {
        assert_eq!(None, get_header_from_index(0, 0, 0));
    }

    #[test]
    fn good_chunk_length_should_return_a_good_header() {
        let mut test_header = Headers::new();
        test_header.set(Range::Bytes(vec![ByteRangeSpec::FromTo(750, 997)]));
        assert_eq!(Some((test_header, 247)), get_header_from_index(3, 998, 250));
    }

}<|endoftext|>


<commit_before>use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;

#[cfg(unix)]
pub use unix::eventloop::EventLoop;

#[cfg(windows)]
pub use windows::eventloop::EventLoop;

pub struct EventLoopHandle {
    handle: Option<thread::JoinHandle<()>>,
    quit: Arc<AtomicBool>,
}

impl EventLoopHandle {
    pub fn new(handle: thread::JoinHandle<()>, quit: Arc<AtomicBool>) -> EventLoopHandle {
        EventLoopHandle {
            handle: Some(handle),
            quit,
        }
    }
}

impl Drop for EventLoopHandle {
    fn drop(&mut self) {
        if let Some(_handle) = self.handle.take() {
            self.quit.store(true, Ordering::Relaxed);
        }
    }
}
<commit_msg>Unnecessary Option<commit_after>use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;

#[cfg(unix)]
pub use unix::eventloop::EventLoop;

#[cfg(windows)]
pub use windows::eventloop::EventLoop;

// Dropping the EventLoopHandle causes the event loop to quit.
pub struct EventLoopHandle {
    _handle: thread::JoinHandle<()>,
    quit: Arc<AtomicBool>,
}

impl EventLoopHandle {
    pub fn new(handle: thread::JoinHandle<()>, quit: Arc<AtomicBool>) -> EventLoopHandle {
        EventLoopHandle {
            _handle: handle,
            quit,
        }
    }
}

impl Drop for EventLoopHandle {
    fn drop(&mut self) {
        self.quit.store(true, Ordering::Relaxed);
    }
}
<|endoftext|>


<commit_before>#[macro_use]
mod macros;

use coerce::{AsBool,AsNumber};

use french_press::ScopeManager;
use french_press::alloc::AllocBox;
use js_types::binding::Binding;
use js_types::js_fn::JsFnStruct;
use js_types::js_obj::JsObjStruct;
use js_types::js_str::JsStrStruct;
use js_types::js_var::{JsVar, JsType, JsPtrEnum, JsKey, JsPtrTag};
use js_types::js_var::JsType::*;

use jsrs_parser::lalr::parse_Stmt;
use jsrs_common::ast::*;
use jsrs_common::ast::Exp::*;
use jsrs_common::ast::BinOp::*;
use jsrs_common::ast::Stmt::*;

type VarWithPtr = (JsVar, Option<JsPtrEnum>);

// Helper to avoid repeating this everywhere
fn scalar(v: JsType) -> (JsVar, Option<JsPtrEnum>) {
    (JsVar::new(v), None)
}

/// Evaluate a string containing some JavaScript statements (or sequences of statements).
/// Returns a JsVar which is the return value of those statements.
pub fn eval_string(string: &str, state: &mut ScopeManager) -> JsVar {
    match parse_Stmt(string) {
        Ok(stmt) => {
            eval_stmt(&stmt, state).0
        }
        Err(e) => panic!("parse error: {:?}", e),
    }
}

/// Evaluate a single JS statement (which may be a block or sequence of statements).
/// Returns tuple of (evaluated final value, return value), where return value requires that
/// `return` be used to generate it.
pub fn eval_stmt(s: &Stmt, mut state: &mut ScopeManager) -> (JsVar, Option<JsVar>) {
    match *s {
        // var_string = exp;
        Assign(ref var_string, ref exp) => {
            let (mut js_var, js_ptr) = eval_exp(exp, state);
            js_var.binding = Binding::new(var_string.clone());

            // Clone the js_var to store into the ScopeManager
            let cloned = js_var.clone();
            match state.alloc(cloned, js_ptr) {
                Ok(_) => (),
                e @ Err(_) => println!("{:?}", e),
            }

            (js_var, None)
        },

        // exp;
        BareExp(ref exp) => (eval_exp(exp, &mut state).0, None),

        // var var_string = exp
        Decl(ref var_string, ref exp) => {
            let (mut js_var, js_ptr) = eval_exp(exp, state);
            js_var.binding = Binding::new(var_string.clone());
            match state.alloc(js_var.clone(), js_ptr) {
                Ok(_) => (js_var, None),
                e @ Err(_) => panic!("{:?}", e),
            }
        },

        // Empty statement (?)
        Empty => (JsVar::new(JsUndef), None),

        // if (condition) { if_block } else { else_block }
        If(ref condition, ref if_block, ref else_block) => {
            // evaluate expression
            if eval_exp(&condition, state).0.as_bool() {
                // condition = true, evaluate if-block.
                eval_stmt(&*if_block, state)
            } else {
                // condition = false
                // evaluate else-block if it exists, otherwise return undefined.
                if let Some(ref block) = *else_block {
                    eval_stmt(&*block, state)
                } else {
                    (JsVar::new(JsUndef), None)
                }
            }
        },

        // return exp
        Ret(ref exp) => {
            let js_var = eval_exp(&exp, &mut state).0;
            (js_var.clone(), Some(js_var))
        }

        // a sequence of any two expressions
        Seq(ref s1, ref s2) => {
            eval_stmt(&*s1, &mut state);
            eval_stmt(&*s2, &mut state)
        },

        // while (condition) { block }
        While(ref condition, ref block) => {
            let mut ret_val = None;
            loop {
                if eval_exp(&condition, state).0.as_bool() {
                    // TODO: check to see if a return stmt has been reached.
                    let (_, v) = eval_stmt(&*block, state);
                    ret_val = v;
                } else {
                    // condition is no longer true, return a return value
                    return (JsVar::new(JsUndef), ret_val);
                }
            }
        }
    }
}

/// Evaluate an expression into a JsVar.
pub fn eval_exp(e: &Exp, mut state: &mut ScopeManager) -> (JsVar, Option<JsPtrEnum>) {
    match e {
        // e1 [op] e2
        &BinExp(ref e1, ref op, ref e2) => {
            let val1 = eval_exp(e1, state).0;
            let val2 = eval_exp(e2, state).0;

            match *op {
                And => scalar(JsBool(val1.as_bool() && val2.as_bool())),
                Or  => scalar(JsBool(val1.as_bool() || val2.as_bool())),

                Ge  => scalar(JsBool(val1.as_bool() >= val2.as_bool())),
                Gt  => scalar(JsBool(val1.as_bool() >  val2.as_bool())),
                Le  => scalar(JsBool(val1.as_bool() <= val2.as_bool())),
                Lt  => scalar(JsBool(val1.as_bool() <  val2.as_bool())),
                Neq => scalar(JsBool(val1.as_bool() != val2.as_bool())),
                Eql => scalar(JsBool(val1.as_bool() == val2.as_bool())),

                Minus => scalar(JsNum(val1.as_number() - val2.as_number())),
                Plus  => scalar(JsNum(val1.as_number() + val2.as_number())),
                Slash => scalar(JsNum(val1.as_number() / val2.as_number())),
                Star  => scalar(JsNum(val1.as_number() * val2.as_number())),
            }
        }
        &Bool(b) => scalar(JsBool(b)),

        // fun_name([arg_exp1, arg_exps])
        &Call(ref fun_name, ref arg_exps) => {
            let fun_binding = eval_exp(fun_name, state).0;

            // Create vector of arguments, evaluated to JsVars.
            let mut args = Vec::new();
            for exp in arg_exps {
                args.push(eval_exp(exp, state));
            }

            match state.load(&fun_binding.binding) {
                Ok((_, Some(JsPtrEnum::JsFn(js_fn_struct)))) => {
                    state.push_scope(e);

                    for param in js_fn_struct.params {
                        let mut arg = if args.is_empty() {
                            scalar(JsUndef)
                        } else {
                            args.remove(0)
                        };

                        arg.0.binding = Binding::new(param.to_owned());
                        state.alloc(arg.0, arg.1)
                            .expect("Unable to store function argument in scope");
                    }

                    let (_, v) = eval_stmt(&js_fn_struct.stmt, state);

                    // Should we yield here? Not sure, so for now it doesn't
                    state.pop_scope(false).expect("Unable to clear scope for function");
                    // TODO handle obj
                    v.map(|x| (x, None)).unwrap_or(scalar(JsUndef))
                }
                Ok(_) => panic!("Invalid call object"),
                _ => panic!("ReferenceError: {:?} is not defined", fun_name)
            }
        },

        // function([param1, params]) { body }
        // function opt_binding([param1, params]) { body }
        &Defun(ref opt_binding, ref params, ref body) => {
            let js_fun = JsFnStruct::new(opt_binding, params, &**body);
            let mut var = JsVar::new(JsPtr(JsPtrTag::JsFn));

            if let &Some(ref s) = opt_binding {
                var.binding = Binding::new(s.to_owned());
            }

            if let Err(_) = state.alloc(var.clone(), Some(JsPtrEnum::JsFn(js_fun.clone()))) {
                panic!("error storing function into state");
            }

            (var, Some(JsPtrEnum::JsFn(js_fun)))
        },

        // var.binding
        &InstanceVar(ref instance_exp, ref var) => {
            // TODO: this needs better type-reasoning and errors
            let (instance_var, var_ptr) = eval_exp(instance_exp, state);
            if let JsPtr(_) = instance_var.t {
                match var_ptr {
                    Some(JsPtrEnum::JsObj(obj_struct)) => {
                        let try_inner = obj_struct.dict.get(&JsKey::JsStr(JsStrStruct::new(var)));
                        if let Some(inner_var) = try_inner {
                            return (inner_var.clone(), None);
                        } else {
                            return scalar(JsUndef);
                        }
                    },
                    // TODO: all JsPtrs can have instance vars/methods, not just JsObjs
                    _ => unimplemented!()
                }
            } else {
                // TODO: Things which are not ptrs can also have instance vars/methods
                unimplemented!()
            }
        },

        &Method(_, _, _) => {
            unimplemented!();
        },

        &Null => {
            scalar(JsNull)
        },

        &Float(f) => scalar(JsType::JsNum(f)),
        &Neg(ref exp) => scalar(JsNum(-eval_exp(exp, state).0.as_number())),
        &Pos(ref exp) => scalar(JsNum(eval_exp(exp, state).0.as_number())),

        &PostDec(ref exp) => (eval_float_post_op!(exp, f, f - 1.0, state), None),
        &PostInc(ref exp) => (eval_float_post_op!(exp, f, f + 1.0, state), None),
        &PreDec(ref exp)  => (eval_float_pre_op!(exp, f, f - 1.0, state),  None),
        &PreInc(ref exp)  => (eval_float_pre_op!(exp, f, f + 1.0, state),  None),

        &NewObject(_, _) => unimplemented!(),
        &Object(ref fields) => {
            let mut kv_tuples = Vec::new();
            for f in fields {
                let f_key = JsKey::JsStr(JsStrStruct::new(&f.0));
                // TODO: handle obj as key/value pair
                let f_exp = eval_exp(&*f.1, state).0;
                kv_tuples.push((f_key, f_exp, None));
            }
            let obj = JsObjStruct::new(None, "", kv_tuples, &mut AllocBox::new());
            (JsVar::new(JsPtr(JsPtrTag::JsObj)), Some(JsPtrEnum::JsObj(obj)))
        },

        &Undefined => scalar(JsUndef),
        &Var(ref var_binding) => {
            state.load(&Binding::new(var_binding.clone()))
                .expect("ReferenceError: {} is not defined")
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::collections::hash_set::HashSet;
    use french_press::init_gc;
    use js_types::js_var::JsType;
    use js_types::binding::Binding;

    #[test]
    fn test_eval_literals() {
        let mut state = init_gc();
        assert_eq!(JsType::JsNum(5.0f64), eval_string("5.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(0.0f64), eval_string("0.0;\n", &mut state).t);
        assert_eq!(JsType::JsUndef, eval_string("undefined;\n", &mut state).t);
    }

    //// TODO: handle `var` and no `var` separately
    //#[test]
    //fn test_store_state() {
    //    let mut state = HashMap::new();
    //    assert_eq!(JsUndefined, eval_string("var a = 1;\n", &mut state));
    //    assert_eq!(JsNumber(2.0f64), eval_string("a = 2;\n", &mut state));
    //    assert_eq!(JsUndefined, eval_string("var b = 3;\n", &mut state));
    //    assert_eq!(JsNumber(4.0f64), eval_string("c = 4;\n", &mut state));
    //}

    #[test]
    fn test_inc_dec() {
        let mut state = init_gc();
        //assert_eq!(JsType::JsNum(1.0f64), eval_string("var a = 1;\n", &mut state).t);
        //assert_eq!(&JsType::JsNum(1.0), state.load(&Binding::new("a")).unwrap());

        //assert_eq!(JsType::JsNum(1.0f64), eval_string("a++;\n", &mut state));
        //assert_eq!(&JsNumber(2.0f64), state.get("a").unwrap());

        //assert_eq!(JsNumber(3.0f64), eval_string("++a;\n", &mut state));
        //assert_eq!(&JsNumber(3.0f64), state.get("a").unwrap());

        //assert_eq!(JsNumber(3.0f64), eval_string("a--;\n", &mut state));
        //assert_eq!(&JsNumber(2.0f64), state.get("a").unwrap());

        //assert_eq!(JsNumber(1.0f64), eval_string("--a;\n", &mut state));
        //assert_eq!(&JsNumber(1.0f64), state.get("a").unwrap());
    }

    #[test]
    fn test_binexp() {
        let mut state = init_gc();
        assert_eq!(JsType::JsNum(6.0f64),  eval_string("2.0 + 4.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(0.5f64),  eval_string("2.0 / 4.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(-2.0f64), eval_string("2.0 - 4.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(8.0f64),  eval_string("2.0 * 4.0;\n", &mut state).t);
    }
}
<commit_msg>add string and `typeof` expressions<commit_after>#[macro_use]
mod macros;

use coerce::{AsBool,AsNumber};

use french_press::ScopeManager;
use french_press::alloc::AllocBox;
use js_types::binding::Binding;
use js_types::js_fn::JsFnStruct;
use js_types::js_obj::JsObjStruct;
use js_types::js_str::JsStrStruct;
use js_types::js_var::{JsVar, JsType, JsPtrEnum, JsKey, JsPtrTag};
use js_types::js_var::JsType::*;

use jsrs_parser::lalr::parse_Stmt;
use jsrs_common::ast::*;
use jsrs_common::ast::Exp::*;
use jsrs_common::ast::BinOp::*;
use jsrs_common::ast::Stmt::*;

type VarWithPtr = (JsVar, Option<JsPtrEnum>);

// Helper to avoid repeating this everywhere
fn scalar(v: JsType) -> (JsVar, Option<JsPtrEnum>) {
    (JsVar::new(v), None)
}

/// Evaluate a string containing some JavaScript statements (or sequences of statements).
/// Returns a JsVar which is the return value of those statements.
pub fn eval_string(string: &str, state: &mut ScopeManager) -> JsVar {
    match parse_Stmt(string) {
        Ok(stmt) => {
            eval_stmt(&stmt, state).0
        }
        Err(e) => panic!("parse error: {:?}", e),
    }
}

/// Evaluate a single JS statement (which may be a block or sequence of statements).
/// Returns tuple of (evaluated final value, return value), where return value requires that
/// `return` be used to generate it.
pub fn eval_stmt(s: &Stmt, mut state: &mut ScopeManager) -> (JsVar, Option<JsVar>) {
    match *s {
        // var_string = exp;
        Assign(ref var_string, ref exp) => {
            let (mut js_var, js_ptr) = eval_exp(exp, state);
            js_var.binding = Binding::new(var_string.clone());

            // Clone the js_var to store into the ScopeManager
            let cloned = js_var.clone();
            match state.alloc(cloned, js_ptr) {
                Ok(_) => (),
                e @ Err(_) => println!("{:?}", e),
            }

            (js_var, None)
        },

        // exp;
        BareExp(ref exp) => (eval_exp(exp, &mut state).0, None),

        // var var_string = exp
        Decl(ref var_string, ref exp) => {
            let (mut js_var, js_ptr) = eval_exp(exp, state);
            js_var.binding = Binding::new(var_string.clone());
            match state.alloc(js_var.clone(), js_ptr) {
                Ok(_) => (js_var, None),
                e @ Err(_) => panic!("{:?}", e),
            }
        },

        // if (condition) { if_block } else { else_block }
        If(ref condition, ref if_block, ref else_block) => {
            // evaluate expression
            if eval_exp(&condition, state).0.as_bool() {
                // condition = true, evaluate if-block.
                eval_stmt(&*if_block, state)
            } else {
                // condition = false
                // evaluate else-block if it exists, otherwise return undefined.
                if let Some(ref block) = *else_block {
                    eval_stmt(&*block, state)
                } else {
                    (JsVar::new(JsUndef), None)
                }
            }
        },

        // return exp
        Ret(ref exp) => {
            let js_var = eval_exp(&exp, &mut state).0;
            (js_var.clone(), Some(js_var))
        }

        // a sequence of any two expressions
        Seq(ref s1, ref s2) => {
            eval_stmt(&*s1, &mut state);
            eval_stmt(&*s2, &mut state)
        },

        // throw <expression>;
        Throw(..) => unimplemented!(),

        // while (condition) { block }
        While(ref condition, ref block) => {
            let mut ret_val = None;
            loop {
                if eval_exp(&condition, state).0.as_bool() {
                    // TODO: check to see if a return stmt has been reached.
                    let (_, v) = eval_stmt(&*block, state);
                    ret_val = v;
                } else {
                    // condition is no longer true, return a return value
                    return (JsVar::new(JsUndef), ret_val);
                }
            }
        }
    }
}

/// Evaluate an expression into a JsVar.
pub fn eval_exp(e: &Exp, mut state: &mut ScopeManager) -> (JsVar, Option<JsPtrEnum>) {
    match e {
        // e1 [op] e2
        &BinExp(ref e1, ref op, ref e2) => {
            let val1 = eval_exp(e1, state).0;
            let val2 = eval_exp(e2, state).0;

            match *op {
                And => scalar(JsBool(val1.as_bool() && val2.as_bool())),
                Or  => scalar(JsBool(val1.as_bool() || val2.as_bool())),

                Ge  => scalar(JsBool(val1.as_bool() >= val2.as_bool())),
                Gt  => scalar(JsBool(val1.as_bool() >  val2.as_bool())),
                Le  => scalar(JsBool(val1.as_bool() <= val2.as_bool())),
                Lt  => scalar(JsBool(val1.as_bool() <  val2.as_bool())),
                Neq => scalar(JsBool(val1.as_bool() != val2.as_bool())),
                Eql => scalar(JsBool(val1.as_bool() == val2.as_bool())),

                Minus => scalar(JsNum(val1.as_number() - val2.as_number())),
                Plus  => scalar(JsNum(val1.as_number() + val2.as_number())),
                Slash => scalar(JsNum(val1.as_number() / val2.as_number())),
                Star  => scalar(JsNum(val1.as_number() * val2.as_number())),
            }
        }
        &Bool(b) => scalar(JsBool(b)),

        // fun_name([arg_exp1, arg_exps])
        &Call(ref fun_name, ref arg_exps) => {
            let fun_binding = eval_exp(fun_name, state).0;

            // Create vector of arguments, evaluated to JsVars.
            let mut args = Vec::new();
            for exp in arg_exps {
                args.push(eval_exp(exp, state));
            }

            match state.load(&fun_binding.binding) {
                Ok((_, Some(JsPtrEnum::JsFn(js_fn_struct)))) => {
                    state.push_scope(e);

                    for param in js_fn_struct.params {
                        let mut arg = if args.is_empty() {
                            scalar(JsUndef)
                        } else {
                            args.remove(0)
                        };

                        arg.0.binding = Binding::new(param.to_owned());
                        state.alloc(arg.0, arg.1)
                            .expect("Unable to store function argument in scope");
                    }

                    let (_, v) = eval_stmt(&js_fn_struct.stmt, state);

                    // Should we yield here? Not sure, so for now it doesn't
                    state.pop_scope(false).expect("Unable to clear scope for function");
                    // TODO handle obj
                    v.map(|x| (x, None)).unwrap_or(scalar(JsUndef))
                }
                Ok(_) => panic!("Invalid call object"),
                _ => panic!("ReferenceError: {:?} is not defined", fun_name)
            }
        },

        // function([param1, params]) { body }
        // function opt_binding([param1, params]) { body }
        &Defun(ref opt_binding, ref params, ref body) => {
            let js_fun = JsFnStruct::new(opt_binding, params, &**body);
            let mut var = JsVar::new(JsPtr(JsPtrTag::JsFn));

            if let &Some(ref s) = opt_binding {
                var.binding = Binding::new(s.to_owned());
            }

            if let Err(_) = state.alloc(var.clone(), Some(JsPtrEnum::JsFn(js_fun.clone()))) {
                panic!("error storing function into state");
            }

            (var, Some(JsPtrEnum::JsFn(js_fun)))
        },

        // var.binding
        &InstanceVar(ref instance_exp, ref var) => {
            // TODO: this needs better type-reasoning and errors
            let (instance_var, var_ptr) = eval_exp(instance_exp, state);
            if let JsPtr(_) = instance_var.t {
                match var_ptr {
                    Some(JsPtrEnum::JsObj(obj_struct)) => {
                        let try_inner = obj_struct.dict.get(&JsKey::JsStr(JsStrStruct::new(var)));
                        if let Some(inner_var) = try_inner {
                            return (inner_var.clone(), None);
                        } else {
                            return scalar(JsUndef);
                        }
                    },
                    // TODO: all JsPtrs can have instance vars/methods, not just JsObjs
                    _ => unimplemented!()
                }
            } else {
                // TODO: Things which are not ptrs can also have instance vars/methods
                unimplemented!()
            }
        },

        &Null => {
            scalar(JsNull)
        },

        &Float(f) => scalar(JsType::JsNum(f)),
        &Neg(ref exp) => scalar(JsNum(-eval_exp(exp, state).0.as_number())),
        &Pos(ref exp) => scalar(JsNum(eval_exp(exp, state).0.as_number())),

        &PostDec(ref exp) => (eval_float_post_op!(exp, f, f - 1.0, state), None),
        &PostInc(ref exp) => (eval_float_post_op!(exp, f, f + 1.0, state), None),
        &PreDec(ref exp)  => (eval_float_pre_op!(exp, f, f - 1.0, state),  None),
        &PreInc(ref exp)  => (eval_float_pre_op!(exp, f, f + 1.0, state),  None),

        &NewObject(_, _) => unimplemented!(),
        &Object(ref fields) => {
            let mut kv_tuples = Vec::new();
            for f in fields {
                let f_key = JsKey::JsStr(JsStrStruct::new(&f.0));
                // TODO: handle obj as key/value pair
                let f_exp = eval_exp(&*f.1, state).0;
                kv_tuples.push((f_key, f_exp, None));
            }
            let obj = JsObjStruct::new(None, "", kv_tuples, &mut AllocBox::new());
            (JsVar::new(JsPtr(JsPtrTag::JsObj)), Some(JsPtrEnum::JsObj(obj)))
        },

        &Str(ref s) => (JsVar::new(JsPtr(JsPtrTag::JsStr)), Some(JsPtrEnum::JsStr(JsStrStruct::new(s)))),
        &TypeOf(ref e) => (JsVar::new(JsPtr(JsPtrTag::JsStr)), Some(JsPtrEnum::JsStr(JsStrStruct::new(&eval_exp(e, state).0.type_of())))),
        &Undefined => scalar(JsUndef),
        &Var(ref var_binding) => {
            state.load(&Binding::new(var_binding.clone()))
                .expect("ReferenceError: {} is not defined")
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::collections::hash_set::HashSet;
    use french_press::init_gc;
    use js_types::js_var::JsType;
    use js_types::binding::Binding;

    #[test]
    fn test_eval_literals() {
        let mut state = init_gc();
        assert_eq!(JsType::JsNum(5.0f64), eval_string("5.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(0.0f64), eval_string("0.0;\n", &mut state).t);
        assert_eq!(JsType::JsUndef, eval_string("undefined;\n", &mut state).t);
    }

    //// TODO: handle `var` and no `var` separately
    //#[test]
    //fn test_store_state() {
    //    let mut state = HashMap::new();
    //    assert_eq!(JsUndefined, eval_string("var a = 1;\n", &mut state));
    //    assert_eq!(JsNumber(2.0f64), eval_string("a = 2;\n", &mut state));
    //    assert_eq!(JsUndefined, eval_string("var b = 3;\n", &mut state));
    //    assert_eq!(JsNumber(4.0f64), eval_string("c = 4;\n", &mut state));
    //}

    #[test]
    fn test_inc_dec() {
        let mut state = init_gc();
        //assert_eq!(JsType::JsNum(1.0f64), eval_string("var a = 1;\n", &mut state).t);
        //assert_eq!(&JsType::JsNum(1.0), state.load(&Binding::new("a")).unwrap());

        //assert_eq!(JsType::JsNum(1.0f64), eval_string("a++;\n", &mut state));
        //assert_eq!(&JsNumber(2.0f64), state.get("a").unwrap());

        //assert_eq!(JsNumber(3.0f64), eval_string("++a;\n", &mut state));
        //assert_eq!(&JsNumber(3.0f64), state.get("a").unwrap());

        //assert_eq!(JsNumber(3.0f64), eval_string("a--;\n", &mut state));
        //assert_eq!(&JsNumber(2.0f64), state.get("a").unwrap());

        //assert_eq!(JsNumber(1.0f64), eval_string("--a;\n", &mut state));
        //assert_eq!(&JsNumber(1.0f64), state.get("a").unwrap());
    }

    #[test]
    fn test_binexp() {
        let mut state = init_gc();
        assert_eq!(JsType::JsNum(6.0f64),  eval_string("2.0 + 4.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(0.5f64),  eval_string("2.0 / 4.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(-2.0f64), eval_string("2.0 - 4.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(8.0f64),  eval_string("2.0 * 4.0;\n", &mut state).t);
    }
}
<|endoftext|>