<commit_before>//! Bindings for Darknet

#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
#![deny(missing_copy_implementations)]
#![deny(trivial_casts)]
#![deny(trivial_numeric_casts)]
#![deny(unused_import_braces)]
#![deny(unused_qualifications)]

#[macro_use]
extern crate failure;

/// FFI bindings.
pub mod ffi {
    #![allow(missing_docs)]
    #![allow(missing_debug_implementations)]
    #![allow(missing_copy_implementations)]
    #![allow(trivial_casts)]
    #![allow(trivial_numeric_casts)]
    #![allow(unused_import_braces)]
    #![allow(unused_qualifications)]
    #![allow(dead_code)]
    #![allow(non_upper_case_globals)]
    #![allow(non_camel_case_types)]
    #![allow(non_snake_case)]

    #[cfg(feature = "gen")]
    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

    #[cfg(not(feature = "gen"))]
    include!("ffi.rs");
}

use std::ffi::{CStr, CString};
use std::path::Path;
pub use failure::Error;

mod errors {
    use std::path::PathBuf;

    #[derive(Debug, Fail)]
    /// Custom errors.
    pub enum DarknetError {
        #[fail(display = "invalid path: {:?}", _0)]
        /// Indicates that path was invalid
        InvalidPath(PathBuf),
    }
}

/// Network
#[derive(Debug)]
pub struct Network {
    net: *mut ffi::network,
}

fn path_to_cstring<P: AsRef<Path>>(path: P) -> Result<CString, Error> {
    let path = path.as_ref();
    let x = path.to_str()
        .ok_or(errors::DarknetError::InvalidPath(path.into()))?;
    let result = CString::new(x)?;
    Ok(result)
}

/// Perform simple detection with default threshold.
#[inline]
pub fn simple_detect(network: &Network, meta: &Meta, image: &Image) -> Vec<Detection> {
    let thres = 0.5;
    let hier_thresh = 0.5;
    let nms = 0.45;
    detect(network, meta, image, thres, hier_thresh, nms)
}

/// Perform detection.
pub fn detect(
    network: &Network,
    meta: &Meta,
    image: &Image,
    thresh: f32,
    hier_thresh: f32,
    nms: f32,
) -> Vec<Detection> {
    network.predict_image(image);
    let dets = network.get_network_boxes(image.0.w, image.0.h, thresh, hier_thresh);
    let detections = dets.postprocess(nms, meta);
    detections
}

impl Network {
    /// Create a new network.
    pub fn new<P: AsRef<Path>>(config: P, weight: P) -> Result<Self, Error> {
        let config = path_to_cstring(config)?.into_raw();
        let weight = path_to_cstring(weight)?.into_raw();
        let net = unsafe { ffi::load_network(config, weight, 0) };
        Ok(Network { net: net })
    }

    /// Return the width of the network.
    pub fn width(&self) -> usize {
        unsafe { ffi::network_width(self.net) as usize }
    }

    /// Return the height of the network.
    pub fn height(&self) -> usize {
        unsafe { ffi::network_height(self.net) as usize }
    }

    /// Perform prediction.
    pub fn predict(&self, data: *mut f32) -> *mut f32 {
        unsafe { ffi::network_predict(self.net, data) }
    }

    /// Perform prediction.
    pub fn predict_image(&self, image: &Image) -> *mut f32 {
        unsafe { ffi::network_predict_image(self.net, image.0) }
    }

    /// Get the network boxes.
    fn get_network_boxes(&self, w: i32, h: i32, thresh: f32, hier: f32) -> Detections_ {
        let mut num = 0;
        let det = unsafe {
            ffi::get_network_boxes(
                self.net,
                w,
                h,
                thresh,
                hier,
                std::ptr::null_mut(),
                0,
                &mut num,
            )
        };
        Detections_ {
            inner: det,
            num: num,
        }
    }
}

impl Drop for Network {
    fn drop(&mut self) {
        unsafe {
            ffi::free_network(self.net);
        }
    }
}

/// A rectangle type.
pub type Rect = ffi::box_;

/// Detection. Note that the bounding box is centered at (x, y) and have width
/// `w` and height `h`.
#[derive(Debug, Clone)]
pub struct Detection {
    /// The class.
    pub class: i32,
    /// x coordinate.
    pub x: f32,
    /// y coordinate.
    pub y: f32,
    /// width.
    pub w: f32,
    /// height.
    pub h: f32,
    /// probability.
    pub prob: f32,
    /// name.
    pub name: String,
}

/// Internal Detection.
#[derive(Debug)]
struct Detections_ {
    inner: *mut ffi::detection,
    num: i32,
}

impl Drop for Detections_ {
    fn drop(&mut self) {
        unsafe {
            ffi::free_detections(self.inner, self.num);
        }
    }
}

impl Detections_ {
    /// Non-maximum suppression.
    fn nms(&self, total: i32, classes: i32, thresh: f32) {
        unsafe {
            ffi::do_nms_obj(self.inner, total, classes, thresh);
        }
    }

    /// Filter detection.
    pub fn postprocess(&self, nms: f32, meta: &Meta) -> Vec<Detection> {
        if nms > 0.0 {
            self.nms(self.num, meta.num_classes(), nms);
        }

        let mut res = Vec::new();
        for j in 0..(self.num as isize) {
            let d = unsafe { *self.inner.offset(j) };
            let bbox = d.bbox;
            let probs = d.prob;
            for i in 0..(meta.num_classes() as isize) {
                let p = unsafe { *probs.offset(i) };
                if p > 0.0 {
                    let ffi::box_ { x, y, w, h } = bbox;
                    res.push(Detection {
                        class: i as i32,
                        x: x,
                        y: y,
                        w: w,
                        h: h,
                        prob: p,
                        name: meta.class_name(i as usize).to_string(),
                    });
                }
            }
        }

        res.sort_by(|a, b| b.prob.partial_cmp(&a.prob).unwrap());
        res
    }
}

/// Metadata.
#[derive(Debug)]
pub struct Meta {
    names: Vec<String>,
}

impl From<ffi::metadata> for Meta {
    fn from(meta: ffi::metadata) -> Self {
        let names = (0..(meta.classes as isize))
            .map(|i| unsafe {
                CStr::from_ptr(*(meta.names.offset(i)))
                    .to_string_lossy()
                    .into_owned()
            })
            .collect();
        Meta { names: names }
    }
}

impl Meta {
    /// Load a new metadata.
    pub fn new<P: AsRef<Path>>(filename: P) -> Result<Self, Error> {
        let filename = path_to_cstring(filename)?.into_raw();
        let meta = unsafe { ffi::get_metadata(filename) };
        Ok(meta.into())
    }

    /// Return the number of classes.
    pub fn num_classes(&self) -> i32 {
        self.names.len() as i32
    }

    /// Return the class name identified by the classification index.
    pub fn class_name(&self, i: usize) -> &str {
        &self.names[i]
    }
}

/// Image
#[derive(Debug, Clone)]
pub struct Image(pub ffi::image);

impl Image {
    /// Create a new image.
    pub fn new(w: i32, h: i32, c: i32) -> Self {
        Image(unsafe { ffi::make_image(w, h, c) })
    }

    /// Load a new image.
    pub fn load<P: AsRef<Path>>(filename: P) -> Result<Self, Error> {
        let filename = path_to_cstring(filename)?.into_raw();
        let img = unsafe { ffi::load_image(filename, 0, 0, 0) };
        Ok(Image(img))
    }

    /// Load a new image with color.
    pub fn load_color<P: AsRef<Path>>(filename: P) -> Result<Self, Error> {
        let filename = path_to_cstring(filename)?.into_raw();
        let img = unsafe { ffi::load_image_color(filename, 0, 0) };
        Ok(Image(img))
    }

    /// Decode a new image (always color, 3 channels).
    pub fn decode_jpg(buf: &[u8]) -> Self {
        let image = unsafe { ffi::decode_image_jpg(buf.as_ptr(), buf.len() as i32, 3) };
        Image(image)
    }

    /// Draw a box based on the detection.
    pub fn draw_box(&mut self, d: &Detection, w: i32, r: f32, g: f32, b: f32) {
        let x1 = d.x - d.w / 2.;
        let x2 = d.x + d.w / 2.;
        let y1 = d.y - d.h / 2.;
        let y2 = d.y + d.h / 2.;

        unsafe {
            ffi::draw_box_width(
                self.0,
                x1 as i32,
                y1 as i32,
                x2 as i32,
                y2 as i32,
                w,
                r,
                g,
                b,
            )
        }
    }

    /// Save the image.
    pub fn save<P: AsRef<Path>>(&self, filename: P) -> Result<(), Error> {
        let filename = path_to_cstring(filename)?.into_raw();
        unsafe { ffi::save_image(self.0, filename) };
        Ok(())
    }

    /// Save the image as jpg.
    pub fn save_jpg<P: AsRef<Path>>(&self, filename: P) -> Result<(), Error> {
        let filename = path_to_cstring(filename)?.into_raw();
        unsafe { ffi::save_image_jpg(self.0, filename) };
        Ok(())
    }

    /// Save the image as jpg.
    pub fn encode_jpg(&self) -> Vec<u8> {
        let cap = (self.0.w * self.0.h * self.0.c) as usize;
        let mut data: Vec<u8> = Vec::with_capacity(cap);
        let size = unsafe { ffi::encode_image_jpg(self.0, data.as_ptr()) };
        unsafe {
            data.set_len(size as usize);
        }

        data
    }

    /// Resize and return a new image.
    pub fn resize(&self, w: i32, h: i32) -> Image {
        Image(unsafe { ffi::resize_image(self.0, w, h) })
    }
}

impl Drop for Image {
    fn drop(&mut self) {
        unsafe {
            ffi::free_image(self.0);
        }
    }
}

/// Groundtruth.
#[derive(Debug)]
pub struct Groundtruth {
    boxes: Vec<ffi::box_label>,
}

impl Groundtruth {
    /// Load a new label.
    pub fn load<P: AsRef<Path>>(filename: P) -> Result<Self, Error> {
        let filename = path_to_cstring(filename)?.into_raw();
        let mut num = 0;
        let truth = unsafe { ffi::read_boxes(filename, &mut num) };

        let truth = (0..num)
            .map(|i| unsafe { *(truth.offset(i as isize)) })
            .collect();
        Ok(Groundtruth { boxes: truth })
    }

    /// Return the rectangle box at a particular index.
    pub fn box_at(&self, i: usize) -> Rect {
        Rect {
            x: self.boxes[i].x,
            y: self.boxes[i].y,
            w: self.boxes[i].w,
            h: self.boxes[i].h,
        }
    }
}
<commit_msg>image is send safe across thread<commit_after>//! Bindings for Darknet

#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
#![deny(missing_copy_implementations)]
#![deny(trivial_casts)]
#![deny(trivial_numeric_casts)]
#![deny(unused_import_braces)]
#![deny(unused_qualifications)]

#[macro_use]
extern crate failure;

/// FFI bindings.
pub mod ffi {
    #![allow(missing_docs)]
    #![allow(missing_debug_implementations)]
    #![allow(missing_copy_implementations)]
    #![allow(trivial_casts)]
    #![allow(trivial_numeric_casts)]
    #![allow(unused_import_braces)]
    #![allow(unused_qualifications)]
    #![allow(dead_code)]
    #![allow(non_upper_case_globals)]
    #![allow(non_camel_case_types)]
    #![allow(non_snake_case)]

    #[cfg(feature = "gen")]
    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

    #[cfg(not(feature = "gen"))]
    include!("ffi.rs");
}

use std::ffi::{CStr, CString};
use std::path::Path;
pub use failure::Error;

mod errors {
    use std::path::PathBuf;

    #[derive(Debug, Fail)]
    /// Custom errors.
    pub enum DarknetError {
        #[fail(display = "invalid path: {:?}", _0)]
        /// Indicates that path was invalid
        InvalidPath(PathBuf),
    }
}

/// Network
#[derive(Debug)]
pub struct Network {
    net: *mut ffi::network,
}

fn path_to_cstring<P: AsRef<Path>>(path: P) -> Result<CString, Error> {
    let path = path.as_ref();
    let x = path.to_str()
        .ok_or(errors::DarknetError::InvalidPath(path.into()))?;
    let result = CString::new(x)?;
    Ok(result)
}

/// Perform simple detection with default threshold.
#[inline]
pub fn simple_detect(network: &Network, meta: &Meta, image: &Image) -> Vec<Detection> {
    let thres = 0.5;
    let hier_thresh = 0.5;
    let nms = 0.45;
    detect(network, meta, image, thres, hier_thresh, nms)
}

/// Perform detection.
pub fn detect(
    network: &Network,
    meta: &Meta,
    image: &Image,
    thresh: f32,
    hier_thresh: f32,
    nms: f32,
) -> Vec<Detection> {
    network.predict_image(image);
    let dets = network.get_network_boxes(image.0.w, image.0.h, thresh, hier_thresh);
    let detections = dets.postprocess(nms, meta);
    detections
}

impl Network {
    /// Create a new network.
    pub fn new<P: AsRef<Path>>(config: P, weight: P) -> Result<Self, Error> {
        let config = path_to_cstring(config)?.into_raw();
        let weight = path_to_cstring(weight)?.into_raw();
        let net = unsafe { ffi::load_network(config, weight, 0) };
        Ok(Network { net: net })
    }

    /// Return the width of the network.
    pub fn width(&self) -> usize {
        unsafe { ffi::network_width(self.net) as usize }
    }

    /// Return the height of the network.
    pub fn height(&self) -> usize {
        unsafe { ffi::network_height(self.net) as usize }
    }

    /// Perform prediction.
    pub fn predict(&self, data: *mut f32) -> *mut f32 {
        unsafe { ffi::network_predict(self.net, data) }
    }

    /// Perform prediction.
    pub fn predict_image(&self, image: &Image) -> *mut f32 {
        unsafe { ffi::network_predict_image(self.net, image.0) }
    }

    /// Get the network boxes.
    fn get_network_boxes(&self, w: i32, h: i32, thresh: f32, hier: f32) -> Detections_ {
        let mut num = 0;
        let det = unsafe {
            ffi::get_network_boxes(
                self.net,
                w,
                h,
                thresh,
                hier,
                std::ptr::null_mut(),
                0,
                &mut num,
            )
        };
        Detections_ {
            inner: det,
            num: num,
        }
    }
}

impl Drop for Network {
    fn drop(&mut self) {
        unsafe {
            ffi::free_network(self.net);
        }
    }
}

/// A rectangle type.
pub type Rect = ffi::box_;

/// Detection. Note that the bounding box is centered at (x, y) and have width
/// `w` and height `h`.
#[derive(Debug, Clone)]
pub struct Detection {
    /// The class.
    pub class: i32,
    /// x coordinate.
    pub x: f32,
    /// y coordinate.
    pub y: f32,
    /// width.
    pub w: f32,
    /// height.
    pub h: f32,
    /// probability.
    pub prob: f32,
    /// name.
    pub name: String,
}

/// Internal Detection.
#[derive(Debug)]
struct Detections_ {
    inner: *mut ffi::detection,
    num: i32,
}

impl Drop for Detections_ {
    fn drop(&mut self) {
        unsafe {
            ffi::free_detections(self.inner, self.num);
        }
    }
}

impl Detections_ {
    /// Non-maximum suppression.
    fn nms(&self, total: i32, classes: i32, thresh: f32) {
        unsafe {
            ffi::do_nms_obj(self.inner, total, classes, thresh);
        }
    }

    /// Filter detection.
    pub fn postprocess(&self, nms: f32, meta: &Meta) -> Vec<Detection> {
        if nms > 0.0 {
            self.nms(self.num, meta.num_classes(), nms);
        }

        let mut res = Vec::new();
        for j in 0..(self.num as isize) {
            let d = unsafe { *self.inner.offset(j) };
            let bbox = d.bbox;
            let probs = d.prob;
            for i in 0..(meta.num_classes() as isize) {
                let p = unsafe { *probs.offset(i) };
                if p > 0.0 {
                    let ffi::box_ { x, y, w, h } = bbox;
                    res.push(Detection {
                        class: i as i32,
                        x: x,
                        y: y,
                        w: w,
                        h: h,
                        prob: p,
                        name: meta.class_name(i as usize).to_string(),
                    });
                }
            }
        }

        res.sort_by(|a, b| b.prob.partial_cmp(&a.prob).unwrap());
        res
    }
}

/// Metadata.
#[derive(Debug)]
pub struct Meta {
    names: Vec<String>,
}

impl From<ffi::metadata> for Meta {
    fn from(meta: ffi::metadata) -> Self {
        let names = (0..(meta.classes as isize))
            .map(|i| unsafe {
                CStr::from_ptr(*(meta.names.offset(i)))
                    .to_string_lossy()
                    .into_owned()
            })
            .collect();
        Meta { names: names }
    }
}

impl Meta {
    /// Load a new metadata.
    pub fn new<P: AsRef<Path>>(filename: P) -> Result<Self, Error> {
        let filename = path_to_cstring(filename)?.into_raw();
        let meta = unsafe { ffi::get_metadata(filename) };
        Ok(meta.into())
    }

    /// Return the number of classes.
    pub fn num_classes(&self) -> i32 {
        self.names.len() as i32
    }

    /// Return the class name identified by the classification index.
    pub fn class_name(&self, i: usize) -> &str {
        &self.names[i]
    }
}

/// Image
#[derive(Debug, Clone)]
pub struct Image(pub ffi::image);

unsafe impl Send for Image {}

impl Image {
    /// Create a new image.
    pub fn new(w: i32, h: i32, c: i32) -> Self {
        Image(unsafe { ffi::make_image(w, h, c) })
    }

    /// Load a new image.
    pub fn load<P: AsRef<Path>>(filename: P) -> Result<Self, Error> {
        let filename = path_to_cstring(filename)?.into_raw();
        let img = unsafe { ffi::load_image(filename, 0, 0, 0) };
        Ok(Image(img))
    }

    /// Load a new image with color.
    pub fn load_color<P: AsRef<Path>>(filename: P) -> Result<Self, Error> {
        let filename = path_to_cstring(filename)?.into_raw();
        let img = unsafe { ffi::load_image_color(filename, 0, 0) };
        Ok(Image(img))
    }

    /// Decode a new image (always color, 3 channels).
    pub fn decode_jpg(buf: &[u8]) -> Self {
        let image = unsafe { ffi::decode_image_jpg(buf.as_ptr(), buf.len() as i32, 3) };
        Image(image)
    }

    /// Draw a box based on the detection.
    pub fn draw_box(&mut self, d: &Detection, w: i32, r: f32, g: f32, b: f32) {
        let x1 = d.x - d.w / 2.;
        let x2 = d.x + d.w / 2.;
        let y1 = d.y - d.h / 2.;
        let y2 = d.y + d.h / 2.;

        unsafe {
            ffi::draw_box_width(
                self.0,
                x1 as i32,
                y1 as i32,
                x2 as i32,
                y2 as i32,
                w,
                r,
                g,
                b,
            )
        }
    }

    /// Save the image.
    pub fn save<P: AsRef<Path>>(&self, filename: P) -> Result<(), Error> {
        let filename = path_to_cstring(filename)?.into_raw();
        unsafe { ffi::save_image(self.0, filename) };
        Ok(())
    }

    /// Save the image as jpg.
    pub fn save_jpg<P: AsRef<Path>>(&self, filename: P) -> Result<(), Error> {
        let filename = path_to_cstring(filename)?.into_raw();
        unsafe { ffi::save_image_jpg(self.0, filename) };
        Ok(())
    }

    /// Save the image as jpg.
    pub fn encode_jpg(&self) -> Vec<u8> {
        let cap = (self.0.w * self.0.h * self.0.c) as usize;
        let mut data: Vec<u8> = Vec::with_capacity(cap);
        let size = unsafe { ffi::encode_image_jpg(self.0, data.as_ptr()) };
        unsafe {
            data.set_len(size as usize);
        }

        data
    }

    /// Resize and return a new image.
    pub fn resize(&self, w: i32, h: i32) -> Image {
        Image(unsafe { ffi::resize_image(self.0, w, h) })
    }
}

impl Drop for Image {
    fn drop(&mut self) {
        unsafe {
            ffi::free_image(self.0);
        }
    }
}

/// Groundtruth.
#[derive(Debug)]
pub struct Groundtruth {
    boxes: Vec<ffi::box_label>,
}

impl Groundtruth {
    /// Load a new label.
    pub fn load<P: AsRef<Path>>(filename: P) -> Result<Self, Error> {
        let filename = path_to_cstring(filename)?.into_raw();
        let mut num = 0;
        let truth = unsafe { ffi::read_boxes(filename, &mut num) };

        let truth = (0..num)
            .map(|i| unsafe { *(truth.offset(i as isize)) })
            .collect();
        Ok(Groundtruth { boxes: truth })
    }

    /// Return the rectangle box at a particular index.
    pub fn box_at(&self, i: usize) -> Rect {
        Rect {
            x: self.boxes[i].x,
            y: self.boxes[i].y,
            w: self.boxes[i].w,
            h: self.boxes[i].h,
        }
    }
}
<|endoftext|>


<commit_before>#![feature(
    rustc_private,
    decl_macro,
    type_alias_impl_trait,
    associated_type_bounds,
    never_type,
    try_blocks,
    hash_drain_filter
)]
#![warn(rust_2018_idioms)]
#![warn(unused_lifetimes)]
#![warn(unreachable_pub)]

#[cfg(feature = "jit")]
extern crate libc;
extern crate snap;
#[macro_use]
extern crate rustc_middle;
extern crate rustc_ast;
extern crate rustc_codegen_ssa;
extern crate rustc_data_structures;
extern crate rustc_errors;
extern crate rustc_fs_util;
extern crate rustc_hir;
extern crate rustc_incremental;
extern crate rustc_index;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_symbol_mangling;
extern crate rustc_target;

// This prevents duplicating functions and statics that are already part of the host rustc process.
#[allow(unused_extern_crates)]
extern crate rustc_driver;

use std::any::Any;

use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_codegen_ssa::CodegenResults;
use rustc_errors::ErrorReported;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader};
use rustc_middle::ty::query::Providers;
use rustc_session::config::OutputFilenames;
use rustc_session::Session;

use cranelift_codegen::settings::{self, Configurable};

use crate::constant::ConstantCx;
use crate::prelude::*;

mod abi;
mod allocator;
mod analyze;
mod archive;
mod atomic_shim;
mod backend;
mod base;
mod cast;
mod codegen_i128;
mod common;
mod constant;
mod debuginfo;
mod discriminant;
mod driver;
mod inline_asm;
mod intrinsics;
mod linkage;
mod main_shim;
mod metadata;
mod num;
mod optimize;
mod pointer;
mod pretty_clif;
mod toolchain;
mod trap;
mod unsize;
mod value_and_place;
mod vtable;

mod prelude {
    pub(crate) use std::convert::{TryFrom, TryInto};

    pub(crate) use rustc_ast::ast::{FloatTy, IntTy, UintTy};
    pub(crate) use rustc_span::Span;

    pub(crate) use rustc_hir::def_id::{DefId, LOCAL_CRATE};
    pub(crate) use rustc_middle::bug;
    pub(crate) use rustc_middle::mir::{self, *};
    pub(crate) use rustc_middle::ty::layout::{self, TyAndLayout};
    pub(crate) use rustc_middle::ty::{
        self, FnSig, Instance, InstanceDef, ParamEnv, Ty, TyCtxt, TypeAndMut, TypeFoldable,
    };
    pub(crate) use rustc_target::abi::{Abi, LayoutOf, Scalar, Size, VariantIdx};

    pub(crate) use rustc_data_structures::fx::FxHashMap;

    pub(crate) use rustc_index::vec::Idx;

    pub(crate) use cranelift_codegen::entity::EntitySet;
    pub(crate) use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
    pub(crate) use cranelift_codegen::ir::function::Function;
    pub(crate) use cranelift_codegen::ir::types;
    pub(crate) use cranelift_codegen::ir::{
        AbiParam, Block, ExternalName, FuncRef, Inst, InstBuilder, MemFlags, Signature, SourceLoc,
        StackSlot, StackSlotData, StackSlotKind, TrapCode, Type, Value,
    };
    pub(crate) use cranelift_codegen::isa::{self, CallConv};
    pub(crate) use cranelift_codegen::Context;
    pub(crate) use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
    pub(crate) use cranelift_module::{self, DataContext, DataId, FuncId, Linkage, Module};

    pub(crate) use crate::abi::*;
    pub(crate) use crate::base::{codegen_operand, codegen_place};
    pub(crate) use crate::cast::*;
    pub(crate) use crate::common::*;
    pub(crate) use crate::debuginfo::{DebugContext, UnwindContext};
    pub(crate) use crate::pointer::Pointer;
    pub(crate) use crate::trap::*;
    pub(crate) use crate::value_and_place::{CPlace, CPlaceInner, CValue};
}

struct PrintOnPanic<F: Fn() -> String>(F);
impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
    fn drop(&mut self) {
        if ::std::thread::panicking() {
            println!("{}", (self.0)());
        }
    }
}

struct CodegenCx<'tcx, M: Module> {
    tcx: TyCtxt<'tcx>,
    module: M,
    global_asm: String,
    constants_cx: ConstantCx,
    cached_context: Context,
    vtables: FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>,
    debug_context: Option<DebugContext<'tcx>>,
    unwind_context: UnwindContext<'tcx>,
}

impl<'tcx, M: Module> CodegenCx<'tcx, M> {
    fn new(tcx: TyCtxt<'tcx>, module: M, debug_info: bool) -> Self {
        let unwind_context = UnwindContext::new(tcx, module.isa());
        let debug_context = if debug_info {
            Some(DebugContext::new(tcx, module.isa()))
        } else {
            None
        };
        CodegenCx {
            tcx,
            module,
            global_asm: String::new(),
            constants_cx: ConstantCx::default(),
            cached_context: Context::new(),
            vtables: FxHashMap::default(),
            debug_context,
            unwind_context,
        }
    }

    fn finalize(mut self) -> (M, String, Option<DebugContext<'tcx>>, UnwindContext<'tcx>) {
        self.constants_cx.finalize(self.tcx, &mut self.module);
        (
            self.module,
            self.global_asm,
            self.debug_context,
            self.unwind_context,
        )
    }
}

#[derive(Copy, Clone, Debug)]
pub struct BackendConfig {
    pub use_jit: bool,
}

pub struct CraneliftCodegenBackend {
    pub config: BackendConfig,
}

impl CodegenBackend for CraneliftCodegenBackend {
    fn init(&self, sess: &Session) {
        if sess.lto() != rustc_session::config::Lto::No && sess.opts.cg.embed_bitcode {
            sess.warn("LTO is not supported. You may get a linker error.");
        }
    }

    fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync> {
        Box::new(crate::metadata::CraneliftMetadataLoader)
    }

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

    fn target_features(&self, _sess: &Session) -> Vec<rustc_span::Symbol> {
        vec![]
    }

    fn codegen_crate<'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: EncodedMetadata,
        need_metadata_module: bool,
    ) -> Box<dyn Any> {
        let res = driver::codegen_crate(tcx, metadata, need_metadata_module, self.config);

        rustc_symbol_mangling::test::report_symbol_names(tcx);

        res
    }

    fn join_codegen(
        &self,
        ongoing_codegen: Box<dyn Any>,
        _sess: &Session,
    ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
        Ok(*ongoing_codegen
            .downcast::<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>)>()
            .unwrap())
    }

    fn link(
        &self,
        sess: &Session,
        codegen_results: CodegenResults,
        outputs: &OutputFilenames,
    ) -> Result<(), ErrorReported> {
        use rustc_codegen_ssa::back::link::link_binary;

        let _timer = sess.prof.generic_activity("link_crate");

        sess.time("linking", || {
            let target_cpu = crate::target_triple(sess).to_string();
            link_binary::<crate::archive::ArArchiveBuilder<'_>>(
                sess,
                &codegen_results,
                outputs,
                &codegen_results.crate_name.as_str(),
                &target_cpu,
            );
        });

        Ok(())
    }
}

fn target_triple(sess: &Session) -> target_lexicon::Triple {
    sess.target.llvm_target.parse().unwrap()
}

fn build_isa(sess: &Session, enable_pic: bool) -> Box<dyn isa::TargetIsa + 'static> {
    use target_lexicon::BinaryFormat;

    let target_triple = crate::target_triple(sess);

    let mut flags_builder = settings::builder();
    if enable_pic {
        flags_builder.enable("is_pic").unwrap();
    } else {
        flags_builder.set("is_pic", "false").unwrap();
    }
    flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided
    flags_builder
        .set(
            "enable_verifier",
            if cfg!(debug_assertions) {
                "true"
            } else {
                "false"
            },
        )
        .unwrap();

    let tls_model = match target_triple.binary_format {
        BinaryFormat::Elf => "elf_gd",
        BinaryFormat::Macho => "macho",
        BinaryFormat::Coff => "coff",
        _ => "none",
    };
    flags_builder.set("tls_model", tls_model).unwrap();

    flags_builder.set("enable_simd", "true").unwrap();

    // FIXME(CraneStation/cranelift#732) fix LICM in presence of jump tables
    /*
    use rustc_session::config::OptLevel;
    match sess.opts.optimize {
        OptLevel::No => {
            flags_builder.set("opt_level", "none").unwrap();
        }
        OptLevel::Less | OptLevel::Default => {}
        OptLevel::Aggressive => {
            flags_builder.set("opt_level", "speed_and_size").unwrap();
        }
        OptLevel::Size | OptLevel::SizeMin => {
            sess.warn("Optimizing for size is not supported. Just ignoring the request");
        }
    }*/

    let flags = settings::Flags::new(flags_builder);

    let mut isa_builder = cranelift_codegen::isa::lookup(target_triple).unwrap();
    // Don't use "haswell", as it implies `has_lzcnt`.macOS CI is still at Ivy Bridge EP, so `lzcnt`
    // is interpreted as `bsr`.
    isa_builder.enable("nehalem").unwrap();
    isa_builder.finish(flags)
}

/// This is the entrypoint for a hot plugged rustc_codegen_cranelift
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
    Box::new(CraneliftCodegenBackend {
        config: BackendConfig { use_jit: false },
    })
}
<commit_msg>Enable Cranelift optimizations when optimizing<commit_after>#![feature(
    rustc_private,
    decl_macro,
    type_alias_impl_trait,
    associated_type_bounds,
    never_type,
    try_blocks,
    hash_drain_filter
)]
#![warn(rust_2018_idioms)]
#![warn(unused_lifetimes)]
#![warn(unreachable_pub)]

#[cfg(feature = "jit")]
extern crate libc;
extern crate snap;
#[macro_use]
extern crate rustc_middle;
extern crate rustc_ast;
extern crate rustc_codegen_ssa;
extern crate rustc_data_structures;
extern crate rustc_errors;
extern crate rustc_fs_util;
extern crate rustc_hir;
extern crate rustc_incremental;
extern crate rustc_index;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_symbol_mangling;
extern crate rustc_target;

// This prevents duplicating functions and statics that are already part of the host rustc process.
#[allow(unused_extern_crates)]
extern crate rustc_driver;

use std::any::Any;

use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_codegen_ssa::CodegenResults;
use rustc_errors::ErrorReported;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader};
use rustc_middle::ty::query::Providers;
use rustc_session::config::OutputFilenames;
use rustc_session::Session;

use cranelift_codegen::settings::{self, Configurable};

use crate::constant::ConstantCx;
use crate::prelude::*;

mod abi;
mod allocator;
mod analyze;
mod archive;
mod atomic_shim;
mod backend;
mod base;
mod cast;
mod codegen_i128;
mod common;
mod constant;
mod debuginfo;
mod discriminant;
mod driver;
mod inline_asm;
mod intrinsics;
mod linkage;
mod main_shim;
mod metadata;
mod num;
mod optimize;
mod pointer;
mod pretty_clif;
mod toolchain;
mod trap;
mod unsize;
mod value_and_place;
mod vtable;

mod prelude {
    pub(crate) use std::convert::{TryFrom, TryInto};

    pub(crate) use rustc_ast::ast::{FloatTy, IntTy, UintTy};
    pub(crate) use rustc_span::Span;

    pub(crate) use rustc_hir::def_id::{DefId, LOCAL_CRATE};
    pub(crate) use rustc_middle::bug;
    pub(crate) use rustc_middle::mir::{self, *};
    pub(crate) use rustc_middle::ty::layout::{self, TyAndLayout};
    pub(crate) use rustc_middle::ty::{
        self, FnSig, Instance, InstanceDef, ParamEnv, Ty, TyCtxt, TypeAndMut, TypeFoldable,
    };
    pub(crate) use rustc_target::abi::{Abi, LayoutOf, Scalar, Size, VariantIdx};

    pub(crate) use rustc_data_structures::fx::FxHashMap;

    pub(crate) use rustc_index::vec::Idx;

    pub(crate) use cranelift_codegen::entity::EntitySet;
    pub(crate) use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
    pub(crate) use cranelift_codegen::ir::function::Function;
    pub(crate) use cranelift_codegen::ir::types;
    pub(crate) use cranelift_codegen::ir::{
        AbiParam, Block, ExternalName, FuncRef, Inst, InstBuilder, MemFlags, Signature, SourceLoc,
        StackSlot, StackSlotData, StackSlotKind, TrapCode, Type, Value,
    };
    pub(crate) use cranelift_codegen::isa::{self, CallConv};
    pub(crate) use cranelift_codegen::Context;
    pub(crate) use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
    pub(crate) use cranelift_module::{self, DataContext, DataId, FuncId, Linkage, Module};

    pub(crate) use crate::abi::*;
    pub(crate) use crate::base::{codegen_operand, codegen_place};
    pub(crate) use crate::cast::*;
    pub(crate) use crate::common::*;
    pub(crate) use crate::debuginfo::{DebugContext, UnwindContext};
    pub(crate) use crate::pointer::Pointer;
    pub(crate) use crate::trap::*;
    pub(crate) use crate::value_and_place::{CPlace, CPlaceInner, CValue};
}

struct PrintOnPanic<F: Fn() -> String>(F);
impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
    fn drop(&mut self) {
        if ::std::thread::panicking() {
            println!("{}", (self.0)());
        }
    }
}

struct CodegenCx<'tcx, M: Module> {
    tcx: TyCtxt<'tcx>,
    module: M,
    global_asm: String,
    constants_cx: ConstantCx,
    cached_context: Context,
    vtables: FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>,
    debug_context: Option<DebugContext<'tcx>>,
    unwind_context: UnwindContext<'tcx>,
}

impl<'tcx, M: Module> CodegenCx<'tcx, M> {
    fn new(tcx: TyCtxt<'tcx>, module: M, debug_info: bool) -> Self {
        let unwind_context = UnwindContext::new(tcx, module.isa());
        let debug_context = if debug_info {
            Some(DebugContext::new(tcx, module.isa()))
        } else {
            None
        };
        CodegenCx {
            tcx,
            module,
            global_asm: String::new(),
            constants_cx: ConstantCx::default(),
            cached_context: Context::new(),
            vtables: FxHashMap::default(),
            debug_context,
            unwind_context,
        }
    }

    fn finalize(mut self) -> (M, String, Option<DebugContext<'tcx>>, UnwindContext<'tcx>) {
        self.constants_cx.finalize(self.tcx, &mut self.module);
        (
            self.module,
            self.global_asm,
            self.debug_context,
            self.unwind_context,
        )
    }
}

#[derive(Copy, Clone, Debug)]
pub struct BackendConfig {
    pub use_jit: bool,
}

pub struct CraneliftCodegenBackend {
    pub config: BackendConfig,
}

impl CodegenBackend for CraneliftCodegenBackend {
    fn init(&self, sess: &Session) {
        if sess.lto() != rustc_session::config::Lto::No && sess.opts.cg.embed_bitcode {
            sess.warn("LTO is not supported. You may get a linker error.");
        }
    }

    fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync> {
        Box::new(crate::metadata::CraneliftMetadataLoader)
    }

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

    fn target_features(&self, _sess: &Session) -> Vec<rustc_span::Symbol> {
        vec![]
    }

    fn codegen_crate<'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: EncodedMetadata,
        need_metadata_module: bool,
    ) -> Box<dyn Any> {
        let res = driver::codegen_crate(tcx, metadata, need_metadata_module, self.config);

        rustc_symbol_mangling::test::report_symbol_names(tcx);

        res
    }

    fn join_codegen(
        &self,
        ongoing_codegen: Box<dyn Any>,
        _sess: &Session,
    ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
        Ok(*ongoing_codegen
            .downcast::<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>)>()
            .unwrap())
    }

    fn link(
        &self,
        sess: &Session,
        codegen_results: CodegenResults,
        outputs: &OutputFilenames,
    ) -> Result<(), ErrorReported> {
        use rustc_codegen_ssa::back::link::link_binary;

        let _timer = sess.prof.generic_activity("link_crate");

        sess.time("linking", || {
            let target_cpu = crate::target_triple(sess).to_string();
            link_binary::<crate::archive::ArArchiveBuilder<'_>>(
                sess,
                &codegen_results,
                outputs,
                &codegen_results.crate_name.as_str(),
                &target_cpu,
            );
        });

        Ok(())
    }
}

fn target_triple(sess: &Session) -> target_lexicon::Triple {
    sess.target.llvm_target.parse().unwrap()
}

fn build_isa(sess: &Session, enable_pic: bool) -> Box<dyn isa::TargetIsa + 'static> {
    use target_lexicon::BinaryFormat;

    let target_triple = crate::target_triple(sess);

    let mut flags_builder = settings::builder();
    if enable_pic {
        flags_builder.enable("is_pic").unwrap();
    } else {
        flags_builder.set("is_pic", "false").unwrap();
    }
    flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided
    flags_builder
        .set(
            "enable_verifier",
            if cfg!(debug_assertions) {
                "true"
            } else {
                "false"
            },
        )
        .unwrap();

    let tls_model = match target_triple.binary_format {
        BinaryFormat::Elf => "elf_gd",
        BinaryFormat::Macho => "macho",
        BinaryFormat::Coff => "coff",
        _ => "none",
    };
    flags_builder.set("tls_model", tls_model).unwrap();

    flags_builder.set("enable_simd", "true").unwrap();

    use rustc_session::config::OptLevel;
    match sess.opts.optimize {
        OptLevel::No => {
            flags_builder.set("opt_level", "none").unwrap();
        }
        OptLevel::Less | OptLevel::Default => {}
        OptLevel::Aggressive => {
            flags_builder.set("opt_level", "speed_and_size").unwrap();
        }
        OptLevel::Size | OptLevel::SizeMin => {
            sess.warn("Optimizing for size is not supported. Just ignoring the request");
        }
    }

    let flags = settings::Flags::new(flags_builder);

    let mut isa_builder = cranelift_codegen::isa::lookup(target_triple).unwrap();
    // Don't use "haswell", as it implies `has_lzcnt`.macOS CI is still at Ivy Bridge EP, so `lzcnt`
    // is interpreted as `bsr`.
    isa_builder.enable("nehalem").unwrap();
    isa_builder.finish(flags)
}

/// This is the entrypoint for a hot plugged rustc_codegen_cranelift
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
    Box::new(CraneliftCodegenBackend {
        config: BackendConfig { use_jit: false },
    })
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::fmt;
use std::iter::FromIterator;

#[derive(Clone, PartialEq, Eq)]
pub enum Token {
    Output,
    Input,
    Loop(Vec<Token>),
    Move(i32),
    Add(i32, i32),
    Set(i32, i32),
    MulCopy(i32, i32, i32),
    Scan(i32),
    LoadOut(i32, i32),
    LoadOutSet(i32),
    If(i32, Vec<Token>),
}
use Token::*;

impl fmt::Debug for Token {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Output => write!(f, "Output"),
            Input => write!(f, "Input"),
            Move(offset) => write!(f, "Move(offset={})", offset),
            Add(offset, value) => write!(f, "Add(offset={}, value={})", offset, value),
            Set(offset, value) => write!(f, "Set(offset={}, value={})", offset, value),
            MulCopy(src, dest, mul) => {
                write!(f, "MulCopy(src={}, dest={}, mul={})", src, dest, mul)
            }
            Scan(offset) => write!(f, "Scan(offset={})", offset),
            LoadOut(offset, add) => write!(f, "LoadOut(offset={}, add={})", offset, add),
            LoadOutSet(value) => write!(f, "LoadOutSet(value={})", value),
            Loop(ref content) => write!(f, "Loop(content={:?})", content),
            If(offset, ref content) => write!(f, "If(offset={}, content={:?})", offset, content),
        }
    }
}

pub fn parse(code: &str) -> Vec<Token> {
    _parse(&mut code.chars())
}

fn _parse(chars: &mut std::str::Chars) -> Vec<Token> {
    let mut tokens = Vec::new();
    while let Some(i) = chars.next() {
        match i {
            '+' => tokens.push(Add(0, 1)),
            '-' => tokens.push(Add(0, -1)),
            '>' => tokens.push(Move(1)),
            '<' => tokens.push(Move(-1)),
            '[' => tokens.push(Loop(_parse(chars))),
            ']' => {
                break;
            }
            ',' => tokens.push(Input),
            '.' => {
                tokens.push(LoadOut(0, 0));
                tokens.push(Output);
            }
            _ => (),
        };
    }

    tokens
}

fn _optimize(tokens: &Vec<Token>) -> (Vec<Token>, BTreeMap<i32, i32>, BTreeMap<i32, i32>, i32) {
    let mut newtokens: Vec<Token> = Vec::with_capacity(tokens.len());
    let mut shift = 0;
    let mut do_output = false;
    // With HashMap, the order sometimes switches
    // in recursion, and the optimizer never exits.
    let mut adds: BTreeMap<i32, i32> = BTreeMap::new();
    let mut sets: BTreeMap<i32, i32> = BTreeMap::new();

    for token in tokens.iter() {
        match *token {
            Set(..) | Add(..) | Move(_) | LoadOut(..) | LoadOutSet(_) | Output => {}
            _ => {
                if do_output {
                    newtokens.push(Output);
                    do_output = false;
                }

                for (offset, value) in sets.iter() {
                    newtokens.push(Set(*offset, *value));
                }
                for (offset, value) in adds.iter() {
                    newtokens.push(Add(*offset, *value));
                }
                sets.clear();
                adds.clear();
            }
        }

        if shift != 0 {
            match *token {
                Loop(_) | Input | Scan(_) => {
                    newtokens.push(Move(shift));
                    shift = 0;
                }
                _ => {}
            }
        }

        match *token {
            Set(mut offset, val) => {
                offset += shift;
                // Add before Set does nothing; remove it
                adds.remove(&offset);
                sets.insert(offset, val);
            }
            Add(mut offset, mut val) => {
                offset += shift;
                if sets.contains_key(&offset) {
                    val = sets.get(&offset).unwrap() + val;
                    sets.insert(offset, val);
                } else {
                    val = adds.get(&offset).unwrap_or(&0) + val;
                    adds.insert(offset, val);
                }
            }
            MulCopy(src, dest, mul) => newtokens.push(MulCopy(src + shift, dest + shift, mul)),
            If(offset, ref contents) => {
                let mut newcontents = Vec::new();
                for i in contents.iter() {
                    newcontents.push(match *i {
                        Set(offset, value) => Set(offset + shift, value),
                        MulCopy(src, dest, mul) => MulCopy(src + shift, dest + shift, mul),
                        _ => unreachable!(),
                    });
                }
                newtokens.push(If(offset + shift, newcontents));
            }
            Move(offset) => shift += offset,
            Output => do_output = true,
            LoadOut(mut offset, add) => {
                offset += shift;
                if sets.contains_key(&offset) {
                    newtokens.push(LoadOutSet(sets.get(&offset).unwrap() + add));
                } else {
                    newtokens.push(LoadOut(offset, adds.get(&offset).unwrap_or(&0) + add));
                }
            }
            Loop(ref contents) => {
                _optimize_loop(contents, &mut newtokens, &mut sets, &mut adds, &mut shift)
            }
            LoadOutSet(value) => newtokens.push(LoadOutSet(value)),
            Input => newtokens.push(Input),
            Scan(offset) => newtokens.push(Scan(offset + shift)),
        }
    }

    if do_output {
        newtokens.push(Output);
    }

    (newtokens, sets, adds, shift)
}

fn _optimize_loop(tokens: &Vec<Token>,
                  outer_tokens: &mut Vec<Token>,
                  outer_sets: &mut BTreeMap<i32, i32>,
                  outer_adds: &mut BTreeMap<i32, i32>,
                  outer_shift: &mut i32) {
    let (mut newtokens, sets, adds, shift) = _optimize(tokens);

    if shift != 0 && sets.is_empty() && adds.is_empty() && newtokens.is_empty() {
        outer_tokens.push(Scan(shift));
    } else if shift == 0 && newtokens.is_empty() && adds.contains_key(&0) && adds.len() == 1 {
        if !sets.is_empty() {
            let mut iftokens = Vec::new();
            for (offset, value) in sets.iter() {
                iftokens.push(Set(*offset, *value));
            }
            iftokens.push(Set(0, 0));
            outer_tokens.push(If(0, iftokens));
        } else {
            outer_sets.insert(0, 0);
        }
    } else if shift == 0 && newtokens.is_empty() && adds.get(&0) == Some(&-1) {
        let contents = adds.iter().filter_map(|(offset, value)| {
            if *offset != 0 {
                let src = 0;
                let dest = *offset;
                let mul = *value;
                Some(MulCopy(src, dest, mul))
            } else {
                None
            }
        });

        if !sets.is_empty() {
            let iftokens = Vec::from_iter(sets.iter()
                .map(|(offset, value)| Set(*offset, *value))
                .chain(contents));
            outer_tokens.push(If(0, iftokens));
        } else {
            outer_tokens.extend(contents);
        }

        outer_sets.insert(0, 0);
    } else {
        for (offset, value) in sets.iter() {
            newtokens.push(Set(*offset, *value));
        }
        for (offset, value) in adds.iter() {
            newtokens.push(Add(*offset, *value));
        }
        if shift != 0 {
            newtokens.push(Move(shift));
        }

        outer_tokens.push(Loop(newtokens));
    }
}

pub fn optimize(tokens: Vec<Token>) -> Vec<Token> {
    let mut oldtokens = tokens;
    // Ignore sets/adds/shifts at end of file
    let mut newtokens = _optimize(&oldtokens).0;
    while newtokens != oldtokens {
        oldtokens = newtokens;
        newtokens = _optimize(&oldtokens).0;
    }
    newtokens
}
<commit_msg>Create OptimizeState struct to store tokens, adds, sets, shift<commit_after>use std::collections::BTreeMap;
use std::fmt;
use std::iter::FromIterator;

#[derive(Clone, PartialEq, Eq)]
pub enum Token {
    Output,
    Input,
    Loop(Vec<Token>),
    Move(i32),
    Add(i32, i32),
    Set(i32, i32),
    MulCopy(i32, i32, i32),
    Scan(i32),
    LoadOut(i32, i32),
    LoadOutSet(i32),
    If(i32, Vec<Token>),
}
use Token::*;

impl fmt::Debug for Token {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Output => write!(f, "Output"),
            Input => write!(f, "Input"),
            Move(offset) => write!(f, "Move(offset={})", offset),
            Add(offset, value) => write!(f, "Add(offset={}, value={})", offset, value),
            Set(offset, value) => write!(f, "Set(offset={}, value={})", offset, value),
            MulCopy(src, dest, mul) => {
                write!(f, "MulCopy(src={}, dest={}, mul={})", src, dest, mul)
            }
            Scan(offset) => write!(f, "Scan(offset={})", offset),
            LoadOut(offset, add) => write!(f, "LoadOut(offset={}, add={})", offset, add),
            LoadOutSet(value) => write!(f, "LoadOutSet(value={})", value),
            Loop(ref content) => write!(f, "Loop(content={:?})", content),
            If(offset, ref content) => write!(f, "If(offset={}, content={:?})", offset, content),
        }
    }
}

struct OptimizeState {
    tokens: Vec<Token>,
    // With HashMap, the order sometimes switches
    // in recursion, and the optimizer never exits.
    adds: BTreeMap<i32, i32>,
    sets: BTreeMap<i32, i32>,
    shift: i32,
}

pub fn parse(code: &str) -> Vec<Token> {
    _parse(&mut code.chars())
}

fn _parse(chars: &mut std::str::Chars) -> Vec<Token> {
    let mut tokens = Vec::new();
    while let Some(i) = chars.next() {
        match i {
            '+' => tokens.push(Add(0, 1)),
            '-' => tokens.push(Add(0, -1)),
            '>' => tokens.push(Move(1)),
            '<' => tokens.push(Move(-1)),
            '[' => tokens.push(Loop(_parse(chars))),
            ']' => {
                break;
            }
            ',' => tokens.push(Input),
            '.' => {
                tokens.push(LoadOut(0, 0));
                tokens.push(Output);
            }
            _ => (),
        };
    }

    tokens
}

fn _optimize(tokens: &Vec<Token>) -> OptimizeState {
    let mut do_output = false;

    let mut state = OptimizeState {
        tokens: Vec::with_capacity(tokens.len()),
        adds: BTreeMap::new(),
        sets: BTreeMap::new(),
        shift: 0,
    };

    for token in tokens.iter() {
        match *token {
            Set(..) | Add(..) | Move(_) | LoadOut(..) | LoadOutSet(_) | Output => {}
            _ => {
                if do_output {
                    state.tokens.push(Output);
                    do_output = false;
                }

                for (offset, value) in state.sets.iter() {
                    state.tokens.push(Set(*offset, *value));
                }
                for (offset, value) in state.adds.iter() {
                    state.tokens.push(Add(*offset, *value));
                }
                state.sets.clear();
                state.adds.clear();
            }
        }

        if state.shift != 0 {
            match *token {
                Loop(_) | Input | Scan(_) => {
                    state.tokens.push(Move(state.shift));
                    state.shift = 0;
                }
                _ => {}
            }
        }

        match *token {
            Set(mut offset, val) => {
                offset += state.shift;
                // Add before Set does nothing; remove it
                state.adds.remove(&offset);
                state.sets.insert(offset, val);
            }
            Add(mut offset, mut val) => {
                offset += state.shift;
                if state.sets.contains_key(&offset) {
                    val = state.sets.get(&offset).unwrap() + val;
                    state.sets.insert(offset, val);
                } else {
                    val = state.adds.get(&offset).unwrap_or(&0) + val;
                    state.adds.insert(offset, val);
                }
            }
            MulCopy(src, dest, mul) => {
                state.tokens.push(MulCopy(src + state.shift, dest + state.shift, mul))
            }
            If(offset, ref contents) => {
                let mut newcontents = Vec::new();
                for i in contents.iter() {
                    newcontents.push(match *i {
                        Set(offset, value) => Set(offset + state.shift, value),
                        MulCopy(src, dest, mul) => {
                            MulCopy(src + state.shift, dest + state.shift, mul)
                        }
                        _ => unreachable!(),
                    });
                }
                state.tokens.push(If(offset + state.shift, newcontents));
            }
            Move(offset) => state.shift += offset,
            Output => do_output = true,
            LoadOut(mut offset, add) => {
                offset += state.shift;
                if state.sets.contains_key(&offset) {
                    state.tokens.push(LoadOutSet(state.sets.get(&offset).unwrap() + add));
                } else {
                    state.tokens.push(LoadOut(offset, state.adds.get(&offset).unwrap_or(&0) + add));
                }
            }
            Loop(ref contents) => _optimize_loop(contents, &mut state),
            LoadOutSet(value) => state.tokens.push(LoadOutSet(value)),
            Input => state.tokens.push(Input),
            Scan(offset) => state.tokens.push(Scan(offset + state.shift)),
        }
    }

    if do_output {
        state.tokens.push(Output);
    }

    state
}

fn _optimize_loop(tokens: &Vec<Token>, outer: &mut OptimizeState) {
    let mut inner = _optimize(tokens);

    if inner.shift != 0 && inner.sets.is_empty() && inner.adds.is_empty() &&
       inner.tokens.is_empty() {
        outer.tokens.push(Scan(inner.shift));
    } else if inner.shift == 0 && inner.tokens.is_empty() && inner.adds.contains_key(&0) &&
              inner.adds.len() == 1 {
        if !inner.sets.is_empty() {
            let mut iftokens = Vec::new();
            for (offset, value) in inner.sets.iter() {
                iftokens.push(Set(*offset, *value));
            }
            iftokens.push(Set(0, 0));
            outer.tokens.push(If(0, iftokens));
        } else {
            outer.sets.insert(0, 0);
        }
    } else if inner.shift == 0 && inner.tokens.is_empty() && inner.adds.get(&0) == Some(&-1) {
        let contents = inner.adds.iter().filter_map(|(offset, value)| {
            if *offset != 0 {
                let src = 0;
                let dest = *offset;
                let mul = *value;
                Some(MulCopy(src, dest, mul))
            } else {
                None
            }
        });

        if !inner.sets.is_empty() {
            let iftokens = Vec::from_iter(inner.sets
                .iter()
                .map(|(offset, value)| Set(*offset, *value))
                .chain(contents));
            outer.tokens.push(If(0, iftokens));
        } else {
            outer.tokens.extend(contents);
        }

        outer.sets.insert(0, 0);
    } else {
        for (offset, value) in inner.sets.iter() {
            inner.tokens.push(Set(*offset, *value));
        }
        for (offset, value) in inner.adds.iter() {
            inner.tokens.push(Add(*offset, *value));
        }
        if inner.shift != 0 {
            inner.tokens.push(Move(inner.shift));
        }

        outer.tokens.push(Loop(inner.tokens));
    }
}

pub fn optimize(tokens: Vec<Token>) -> Vec<Token> {
    let mut oldtokens = tokens;
    // Ignore sets/adds/shifts at end of file
    let mut newtokens = _optimize(&oldtokens).tokens;
    while newtokens != oldtokens {
        oldtokens = newtokens;
        newtokens = _optimize(&oldtokens).tokens;
    }
    newtokens
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#![crate_name = "js"]
#![crate_type = "rlib"]

#![feature(core_intrinsics)]
#![feature(link_args)]
#![feature(str_utf16)]
#![feature(unsafe_no_drop_flag)]

#![allow(non_upper_case_globals, non_camel_case_types, non_snake_case, improper_ctypes, raw_pointer_derive)]

extern crate libc;
#[macro_use]
extern crate log;
#[macro_use]
extern crate heapsize;
extern crate rustc_serialize as serialize;

pub mod jsapi;
pub mod linkhack;
pub mod rust;
pub mod glue;
pub mod jsval;

use jsapi::{JSContext, JSProtoKey, Heap};
use jsval::JSVal;
use rust::GCMethods;

use libc::c_uint;

use heapsize::HeapSizeOf;

pub const default_heapsize: u32 = 32_u32 * 1024_u32 * 1024_u32;
pub const default_stacksize: usize = 8192;

pub const JSID_TYPE_STRING: i64 = 0;
pub const JSID_TYPE_INT: i64 = 1;
pub const JSID_TYPE_VOID: i64 = 2;
pub const JSID_TYPE_OBJECT: i64 = 4;
pub const JSID_TYPE_DEFAULT_XML_NAMESPACE: i64 = 6;
pub const JSID_TYPE_MASK: i64 = 7;

pub const JSFUN_CONSTRUCTOR: u32 = 0x400; /* native that can be called as a ctor */

pub const JSPROP_ENUMERATE: c_uint = 0x01;
pub const JSPROP_READONLY: c_uint  = 0x02;
pub const JSPROP_PERMANENT: c_uint = 0x04;
pub const JSPROP_GETTER: c_uint = 0x10;
pub const JSPROP_SETTER: c_uint = 0x20;
pub const JSPROP_SHARED: c_uint =    0x40;
pub const JSPROP_NATIVE_ACCESSORS: c_uint = 0x08;

pub const JSCLASS_RESERVED_SLOTS_SHIFT: c_uint = 8;
pub const JSCLASS_RESERVED_SLOTS_WIDTH: c_uint = 8;
pub const JSCLASS_RESERVED_SLOTS_MASK: c_uint = ((1 << JSCLASS_RESERVED_SLOTS_WIDTH) - 1) as c_uint;

pub const JSCLASS_HIGH_FLAGS_SHIFT: c_uint =
    JSCLASS_RESERVED_SLOTS_SHIFT + JSCLASS_RESERVED_SLOTS_WIDTH;
pub const JSCLASS_IS_GLOBAL: c_uint = 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 1);
pub const JSCLASS_GLOBAL_APPLICATION_SLOTS: c_uint = 4;
pub const JSCLASS_GLOBAL_SLOT_COUNT: c_uint = JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProtoKey::JSProto_LIMIT as u32 * 3 + 31;

pub const JSCLASS_IS_DOMJSCLASS: u32 = 1 << 4;
pub const JSCLASS_IMPLEMENTS_BARRIERS: u32 = 1 << 5;
pub const JSCLASS_USERBIT1: u32 = 1 << 7;

pub const JSCLASS_IS_PROXY: u32 = 1 << (JSCLASS_HIGH_FLAGS_SHIFT+4);

pub const JSSLOT_PROXY_PRIVATE: u32 = 1;

pub const JS_DEFAULT_ZEAL_FREQ: u32 = 100;

pub const JSTrue: u8 = 1;
pub const JSFalse: u8 = 0;

#[link(name = "jsglue")]
extern { }

#[cfg(target_os = "android")]
#[link(name = "stdc++")]
extern { }

#[cfg(target_os = "android")]
#[link(name = "gcc")]
extern { }

#[inline(always)]
pub unsafe fn JS_ARGV(_cx: *mut JSContext, vp: *mut JSVal) -> *mut JSVal {
    vp.offset(2)
}

#[inline(always)]
pub unsafe fn JS_CALLEE(_cx: *mut JSContext, vp: *mut JSVal) -> JSVal {
    *vp
}

// This is measured properly by the heap measurement implemented in SpiderMonkey.
impl<T: Copy + GCMethods<T>> HeapSizeOf for Heap<T> {
    fn heap_size_of_children(&self) -> usize {
        0
    }
}
known_heap_size!(0, JSVal);

<commit_msg>Auto merge of #191 - frewsxcv:jsiter, r=mwu<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#![crate_name = "js"]
#![crate_type = "rlib"]

#![feature(core_intrinsics)]
#![feature(link_args)]
#![feature(str_utf16)]
#![feature(unsafe_no_drop_flag)]

#![allow(non_upper_case_globals, non_camel_case_types, non_snake_case, improper_ctypes, raw_pointer_derive)]

extern crate libc;
#[macro_use]
extern crate log;
#[macro_use]
extern crate heapsize;
extern crate rustc_serialize as serialize;

pub mod jsapi;
pub mod linkhack;
pub mod rust;
pub mod glue;
pub mod jsval;

use jsapi::{JSContext, JSProtoKey, Heap};
use jsval::JSVal;
use rust::GCMethods;

use libc::c_uint;

use heapsize::HeapSizeOf;

pub const default_heapsize: u32 = 32_u32 * 1024_u32 * 1024_u32;
pub const default_stacksize: usize = 8192;

pub const JSID_TYPE_STRING: i64 = 0;
pub const JSID_TYPE_INT: i64 = 1;
pub const JSID_TYPE_VOID: i64 = 2;
pub const JSID_TYPE_OBJECT: i64 = 4;
pub const JSID_TYPE_DEFAULT_XML_NAMESPACE: i64 = 6;
pub const JSID_TYPE_MASK: i64 = 7;

pub const JSFUN_CONSTRUCTOR: u32 = 0x400; /* native that can be called as a ctor */

pub const JSPROP_ENUMERATE: c_uint = 0x01;
pub const JSPROP_READONLY: c_uint  = 0x02;
pub const JSPROP_PERMANENT: c_uint = 0x04;
pub const JSPROP_GETTER: c_uint = 0x10;
pub const JSPROP_SETTER: c_uint = 0x20;
pub const JSPROP_SHARED: c_uint =    0x40;
pub const JSPROP_NATIVE_ACCESSORS: c_uint = 0x08;

pub const JSCLASS_RESERVED_SLOTS_SHIFT: c_uint = 8;
pub const JSCLASS_RESERVED_SLOTS_WIDTH: c_uint = 8;
pub const JSCLASS_RESERVED_SLOTS_MASK: c_uint = ((1 << JSCLASS_RESERVED_SLOTS_WIDTH) - 1) as c_uint;

pub const JSCLASS_HIGH_FLAGS_SHIFT: c_uint =
    JSCLASS_RESERVED_SLOTS_SHIFT + JSCLASS_RESERVED_SLOTS_WIDTH;
pub const JSCLASS_IS_GLOBAL: c_uint = 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 1);
pub const JSCLASS_GLOBAL_APPLICATION_SLOTS: c_uint = 4;
pub const JSCLASS_GLOBAL_SLOT_COUNT: c_uint = JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProtoKey::JSProto_LIMIT as u32 * 3 + 31;

pub const JSCLASS_IS_DOMJSCLASS: u32 = 1 << 4;
pub const JSCLASS_IMPLEMENTS_BARRIERS: u32 = 1 << 5;
pub const JSCLASS_USERBIT1: u32 = 1 << 7;

pub const JSCLASS_IS_PROXY: u32 = 1 << (JSCLASS_HIGH_FLAGS_SHIFT+4);

pub const JSSLOT_PROXY_PRIVATE: u32 = 1;

pub const JS_DEFAULT_ZEAL_FREQ: u32 = 100;

pub const JSTrue: u8 = 1;
pub const JSFalse: u8 = 0;

pub const JSITER_ENUMERATE: c_uint   = 0x1;
pub const JSITER_FOREACH: c_uint     = 0x2;
pub const JSITER_KEYVALUE: c_uint    = 0x4;
pub const JSITER_OWNONLY: c_uint     = 0x8;
pub const JSITER_HIDDEN: c_uint      = 0x10;
pub const JSITER_SYMBOLS: c_uint     = 0x20;
pub const JSITER_SYMBOLSONLY: c_uint = 0x40;

#[link(name = "jsglue")]
extern { }

#[cfg(target_os = "android")]
#[link(name = "stdc++")]
extern { }

#[cfg(target_os = "android")]
#[link(name = "gcc")]
extern { }

#[inline(always)]
pub unsafe fn JS_ARGV(_cx: *mut JSContext, vp: *mut JSVal) -> *mut JSVal {
    vp.offset(2)
}

#[inline(always)]
pub unsafe fn JS_CALLEE(_cx: *mut JSContext, vp: *mut JSVal) -> JSVal {
    *vp
}

// This is measured properly by the heap measurement implemented in SpiderMonkey.
impl<T: Copy + GCMethods<T>> HeapSizeOf for Heap<T> {
    fn heap_size_of_children(&self) -> usize {
        0
    }
}
known_heap_size!(0, JSVal);

<|endoftext|>


<commit_before>#![allow(clippy::non_ascii_literal)]

#[macro_use]
extern crate seed;

use seed::prelude::*;
use web_sys;

pub mod pages;
pub mod utils;

#[derive(Copy, Clone)]
pub enum Page {
    ContactUs,
    Downloads,
    Faq,
    Home,
    Status,
    FermatArchive,
    FibonacciArchive,
    MersenneArchive,
    PerfectArchive,
    PrimalityChecker,
    PrimeNumbersArchive,
    NumberCruncher,
}

// Model
pub struct Model {
    download: pages::archive::perfect::perfects_utils::PerfectDownload,
    page: Page,
    slug: std::string::String,
}

// Setup a default here, for initialization later.
impl Default for Model {
    fn default() -> Self {
        Self {
            download: pages::archive::perfect::perfects_utils::PerfectDownload {n: 0, p: 0},
            page: Page::Home,
            slug: "".to_owned(),
        }
    }
}

// Update
#[derive(Clone)]
pub enum Msg {
    ChangePage(Page, std::string::String),
    GenerateMersenneDownload(web_sys::MouseEvent, pages::archive::mersenne::mersenne_utils::MersenneDownload),
    GeneratePerfectDownload(web_sys::MouseEvent, pages::archive::perfect::perfects_utils::PerfectDownload),
}

/// The sole source of updating the model
fn update(msg: Msg, model: &mut Model, _: &mut impl Orders<Msg>) {
    match msg {
        Msg::ChangePage(page, slug) => {
            //reset download so subsequent visits to perfect page don't hang the browser with a download
            model.download = pages::archive::perfect::perfects_utils::PerfectDownload {n: 0, p: 0};
            model.page = page;
            model.slug = slug
        },
        Msg::GenerateMersenneDownload(_event, perfect_download) => {
            //event.prevent_default();
            model.download.n = perfect_download.n;
            model.download.p = perfect_download.p
        },
        Msg::GeneratePerfectDownload(_event, perfect_download) => {
            //event.prevent_default();
            model.download.n = perfect_download.n;
            model.download.p = perfect_download.p
        }
    }
}

/// The top-level component we pass to the virtual dom. Must accept the model as its
/// only argument, and output has to implement trait `ElContainer`.
fn view(model: &Model) -> impl View<Msg> {
    match model.page {
        Page::ContactUs => pages::contact::render(),
        Page::Downloads => pages::downloads::render(),
        Page::Faq => pages::faq::render(),
        Page::FermatArchive => pages::archive::fermat::render(),
        Page::FibonacciArchive => pages::archive::fibonacci::render(model.slug.to_owned()),
        Page::Home => pages::home::render(),
        Page::MersenneArchive => pages::archive::mersenne::render(&model),
        Page::NumberCruncher => pages::cruncher::render(model.slug.to_owned()),
        Page::PerfectArchive => pages::archive::perfect::render(&model),
        Page::PrimalityChecker => pages::primalitytest::render(),
        Page::PrimeNumbersArchive => pages::archive::prime::render(model.slug.to_owned()),
        Page::Status => pages::status::render(),
    }
}

impl ToString for Page {
    fn to_string(&self) -> String {
        // Eg for url routing
        match self {
            Page::ContactUs => "contactus".into(),
            Page::Downloads => "downloads".into(),
            Page::Faq => "faq".into(),
            Page::FermatArchive => "fermat".into(),
            Page::FibonacciArchive => "fibonacci".into(),//TODO: check this is right, might need the archive/ prefix!
            Page::Home => "home".into(),
            Page::Status => "status".into(),
            Page::MersenneArchive => "mersenne".into(),
            Page::NumberCruncher => "cruncher".into(),
            Page::PerfectArchive => "perfect".into(),
            Page::PrimalityChecker => "primalitytest".into(),
            Page::PrimeNumbersArchive => "primes".into(),//TODO: check this is right, might need the archive/ prefix!
        }
    }
}

fn routes(url: seed::Url) -> Option<Msg> {

    let empty_string = "".to_owned();

    if url.path.is_empty() {
        return Some(Msg::ChangePage(Page::Home, empty_string))
    }

    Some(match url.path[0].as_ref() {
        "archive" => {
            // Determine if we are at the archive page, or a subpage
            match url.path[1].as_ref() {
                "fermat" => Msg::ChangePage(Page::FermatArchive, empty_string),
                "fibonacci" => {
                    match url.path.get(2).as_ref() {
                        Some(_slug) => Msg::ChangePage(Page::FibonacciArchive, url.path[2].to_owned()),
                        None => Msg::ChangePage(Page::FibonacciArchive, "1".to_owned()),
                    }
                },
                "mersenne" => Msg::ChangePage(Page::MersenneArchive, empty_string),
                "perfect" => Msg::ChangePage(Page::PerfectArchive, empty_string),
                "prime" => {
                    match url.path.get(2).as_ref() {
                        Some(_slug) => Msg::ChangePage(Page::PrimeNumbersArchive, url.path[2].to_owned()),
                        None => Msg::ChangePage(Page::PrimeNumbersArchive, "1".to_owned()),
                    }
                },
                _ => Msg::ChangePage(Page::Home, empty_string)//TODO: add archive page
            }
        },
        "contactus" => Msg::ChangePage(Page::ContactUs, empty_string),
        "cruncher" => {
            match url.path.get(1).as_ref() {
                Some(_slug) => Msg::ChangePage(Page::NumberCruncher, url.path[1].to_owned()),
                None => Msg::ChangePage(Page::NumberCruncher, empty_string),
            }
        },
        "downloads" => Msg::ChangePage(Page::Downloads, empty_string),
        "faq" => Msg::ChangePage(Page::Faq, empty_string),
        "primalitytest" => Msg::ChangePage(Page::PrimalityChecker, empty_string),
        "status" => Msg::ChangePage(Page::Status, empty_string),
        _ => Msg::ChangePage(Page::Home, empty_string)
    })
}

#[wasm_bindgen(start)]
pub fn render() {
    seed::App::build(|_, _| Init::new(Model::default()), update, view)
    .routes(routes)
    .build_and_start();
}<commit_msg>Added log function for web browser debug<commit_after>#![allow(clippy::non_ascii_literal)]

#[macro_use]
extern crate seed;

use seed::prelude::*;
use web_sys;

pub mod pages;
pub mod utils;

#[derive(Copy, Clone)]
pub enum Page {
    ContactUs,
    Downloads,
    Faq,
    Home,
    Status,
    FermatArchive,
    FibonacciArchive,
    MersenneArchive,
    PerfectArchive,
    PrimalityChecker,
    PrimeNumbersArchive,
    NumberCruncher,
}

// Model
pub struct Model {
    download: pages::archive::perfect::perfects_utils::PerfectDownload,
    page: Page,
    slug: std::string::String,
}

// Setup a default here, for initialization later.
impl Default for Model {
    fn default() -> Self {
        Self {
            download: pages::archive::perfect::perfects_utils::PerfectDownload {n: 0, p: 0},
            page: Page::Home,
            slug: "".to_owned(),
        }
    }
}

// Update
#[derive(Clone)]
pub enum Msg {
    ChangePage(Page, std::string::String),
    GenerateMersenneDownload(web_sys::MouseEvent, pages::archive::mersenne::mersenne_utils::MersenneDownload),
    GeneratePerfectDownload(web_sys::MouseEvent, pages::archive::perfect::perfects_utils::PerfectDownload),
}

/// The sole source of updating the model
fn update(msg: Msg, model: &mut Model, _: &mut impl Orders<Msg>) {
    match msg {
        Msg::ChangePage(page, slug) => {
            //reset download so subsequent visits to perfect page don't hang the browser with a download
            model.download = pages::archive::perfect::perfects_utils::PerfectDownload {n: 0, p: 0};
            model.page = page;
            model.slug = slug
        },
        Msg::GenerateMersenneDownload(_event, perfect_download) => {
            //event.prevent_default();
            model.download.n = perfect_download.n;
            model.download.p = perfect_download.p
        },
        Msg::GeneratePerfectDownload(_event, perfect_download) => {
            //event.prevent_default();
            model.download.n = perfect_download.n;
            model.download.p = perfect_download.p
        }
    }
}

/// The top-level component we pass to the virtual dom. Must accept the model as its
/// only argument, and output has to implement trait `ElContainer`.
fn view(model: &Model) -> impl View<Msg> {
    match model.page {
        Page::ContactUs => pages::contact::render(),
        Page::Downloads => pages::downloads::render(),
        Page::Faq => pages::faq::render(),
        Page::FermatArchive => pages::archive::fermat::render(),
        Page::FibonacciArchive => pages::archive::fibonacci::render(model.slug.to_owned()),
        Page::Home => pages::home::render(),
        Page::MersenneArchive => pages::archive::mersenne::render(&model),
        Page::NumberCruncher => pages::cruncher::render(model.slug.to_owned()),
        Page::PerfectArchive => pages::archive::perfect::render(&model),
        Page::PrimalityChecker => pages::primalitytest::render(),
        Page::PrimeNumbersArchive => pages::archive::prime::render(model.slug.to_owned()),
        Page::Status => pages::status::render(),
    }
}

impl ToString for Page {
    fn to_string(&self) -> String {
        // Eg for url routing
        match self {
            Page::ContactUs => "contactus".into(),
            Page::Downloads => "downloads".into(),
            Page::Faq => "faq".into(),
            Page::FermatArchive => "fermat".into(),
            Page::FibonacciArchive => "fibonacci".into(),//TODO: check this is right, might need the archive/ prefix!
            Page::Home => "home".into(),
            Page::Status => "status".into(),
            Page::MersenneArchive => "mersenne".into(),
            Page::NumberCruncher => "cruncher".into(),
            Page::PerfectArchive => "perfect".into(),
            Page::PrimalityChecker => "primalitytest".into(),
            Page::PrimeNumbersArchive => "primes".into(),//TODO: check this is right, might need the archive/ prefix!
        }
    }
}

fn routes(url: seed::Url) -> Option<Msg> {

    let empty_string = "".to_owned();

    if url.path.is_empty() {
        return Some(Msg::ChangePage(Page::Home, empty_string))
    }

    Some(match url.path[0].as_ref() {
        "archive" => {
            // Determine if we are at the archive page, or a subpage
            match url.path[1].as_ref() {
                "fermat" => Msg::ChangePage(Page::FermatArchive, empty_string),
                "fibonacci" => {
                    match url.path.get(2).as_ref() {
                        Some(_slug) => Msg::ChangePage(Page::FibonacciArchive, url.path[2].to_owned()),
                        None => Msg::ChangePage(Page::FibonacciArchive, "1".to_owned()),
                    }
                },
                "mersenne" => Msg::ChangePage(Page::MersenneArchive, empty_string),
                "perfect" => Msg::ChangePage(Page::PerfectArchive, empty_string),
                "prime" => {
                    match url.path.get(2).as_ref() {
                        Some(_slug) => Msg::ChangePage(Page::PrimeNumbersArchive, url.path[2].to_owned()),
                        None => Msg::ChangePage(Page::PrimeNumbersArchive, "1".to_owned()),
                    }
                },
                _ => Msg::ChangePage(Page::Home, empty_string)//TODO: add archive page
            }
        },
        "contactus" => Msg::ChangePage(Page::ContactUs, empty_string),
        "cruncher" => {
            match url.path.get(1).as_ref() {
                Some(_slug) => Msg::ChangePage(Page::NumberCruncher, url.path[1].to_owned()),
                None => Msg::ChangePage(Page::NumberCruncher, empty_string),
            }
        },
        "downloads" => Msg::ChangePage(Page::Downloads, empty_string),
        "faq" => Msg::ChangePage(Page::Faq, empty_string),
        "primalitytest" => Msg::ChangePage(Page::PrimalityChecker, empty_string),
        "status" => Msg::ChangePage(Page::Status, empty_string),
        _ => Msg::ChangePage(Page::Home, empty_string)
    })
}

#[wasm_bindgen(start)]
pub fn render() {
    seed::App::build(|_, _| Init::new(Model::default()), update, view)
    .routes(routes)
    .build_and_start();
}

pub fn log(s: &str){
    use web_sys::console;
    console::log_1(&s.into());
}
<|endoftext|>


<commit_before>//! A helper trait to initialize a data structure with custom code.
//!
//! This crate is meant to aid in initializing fixed arrays using something other than a `Default`
//! implementation. For example, if you wanted to create an array of Vecs, you could create one
//! with `Default` that made all the Vecs empty:
//!
//! ```rust
//! let my_array = <[Vec<u32>; 3]>::default();
//! assert_eq!(my_array, [[], [], []]);
//! ```
//!
//! But if you wanted to start the arrays with some state, you either need to start with the empty
//! arrays and fill from there, or drop into unsafe code to write in a partially-initialized array.
//!
//! ```rust
//! let mut my_array = <[Vec<usize>; 3]>::default();
//!
//! for (idx, arr) in my_array.iter_mut().enumerate() {
//!     for i in 0..(idx+1) {
//!         arr.push(i);
//!     }
//! }
//!
//! assert_eq!(my_array, [vec![0], vec![0, 1], vec![0, 1, 2]]);
//! ```
//!
//! With `InitWith`, the same array could be initialized like this:
//!
//! ```rust
//! use init_with::InitWith;
//!
//! let my_array = {
//!     let mut seed = Vec::new();
//!     let mut next_val = 0;
//!
//!     <[Vec<u32>; 3]>::init_with(|| {
//!         seed.push(next_val);
//!         next_val += 1;
//!         seed.clone()
//!     })
//! };
//!
//! assert_eq!(my_array, [vec![0], vec![0, 1], vec![0, 1, 2]]);
//! ```
//!
//! This crate is built with `#![no_std]` and only uses libcore for its code, so it can be used
//! from other `no_std` crates.

#![no_std]

/// A trait that allows you to create an instance of a type by using a given function to generate
/// each element.
pub trait InitWith<T> {
    /// Create a new instance of this type using the given function to fill elements.
    ///
    /// # Examples
    ///
    /// Prefilling an array with a Vec, with no unsafe code:
    ///
    /// ```rust
    /// use init_with::InitWith;
    ///
    /// let src = vec![1, 2, 3];
    /// let dest: [i32; 3] = {
    ///     let mut idx = 0;
    ///
    ///     <[i32; 3]>::init_with(|| {
    ///         let val = src[idx];
    ///         idx += 1;
    ///         val
    ///     })
    /// };
    ///
    /// assert_eq!(src, dest);
    /// ```
    fn init_with<F>(init: F) -> Self
        where F: FnMut() -> T,
              Self: Sized;
}

macro_rules! array_init {
    {$n:expr, $init:ident, $($stack:ident,)+} => {
        impl<T> InitWith<T> for [T; $n] {
            fn init_with<F>(mut $init: F) -> Self
                where F: FnMut() -> T
            {
                [$init(), $($stack()),+]
            }
        }
        array_init!{($n - 1), $($stack,)+}
    };
    {$n:expr, $init:ident,} => {
        impl<T> InitWith<T> for [T; $n] {
            fn init_with<F>(mut $init: F) -> Self
                where F: FnMut() -> T
            {
                [$init()]
            }
        }
        array_init!{($n - 1)}
    };
    {$n:expr} => {
        impl<T> InitWith<T> for [T; $n] {
            fn init_with<F>(_init: F) -> Self
                where F: FnMut() -> T
            {
                []
            }
        }
    };
}

array_init!{32, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init,}

#[cfg(test)]
mod tests {
    use super::InitWith;

    #[test]
    fn expected() {
        let val = <[i32; 3]>::init_with(|| 4);
        assert_eq!(val, [4, 4, 4]);
    }
}
<commit_msg>Added init_with_indices + docs + tests<commit_after>//! A helper trait to initialize a data structure with custom code.
//!
//! This crate is meant to aid in initializing fixed arrays using something other than a `Default`
//! implementation. For example, if you wanted to create an array of Vecs, you could create one
//! with `Default` that made all the Vecs empty:
//!
//! ```rust
//! let my_array = <[Vec<u32>; 3]>::default();
//! assert_eq!(my_array, [[], [], []]);
//! ```
//!
//! But if you wanted to start the arrays with some state, you either need to start with the empty
//! arrays and fill from there, or drop into unsafe code to write in a partially-initialized array.
//!
//! ```rust
//! let mut my_array = <[Vec<usize>; 3]>::default();
//!
//! for (idx, arr) in my_array.iter_mut().enumerate() {
//!     for i in 0..(idx+1) {
//!         arr.push(i);
//!     }
//! }
//!
//! assert_eq!(my_array, [vec![0], vec![0, 1], vec![0, 1, 2]]);
//! ```
//!
//! With `InitWith`, the same array could be initialized like this:
//!
//! ```rust
//! use init_with::InitWith;
//!
//! let my_array = {
//!     let mut seed = Vec::new();
//!     let mut next_val = 0;
//!
//!     <[Vec<u32>; 3]>::init_with(|| {
//!         seed.push(next_val);
//!         next_val += 1;
//!         seed.clone()
//!     })
//! };
//!
//! assert_eq!(my_array, [vec![0], vec![0, 1], vec![0, 1, 2]]);
//! ```
//!
//! Alternatively, `init_with_indices` can be used to more easily create array entries based on their index:
//!
//! ```rust
//! use init_with::InitWith;
//!
//! let squares = <[usize; 5]>::init_with_indices(|i| i*i);
//!
//! assert_eq!(squares, [0,1,4,9,16]);
//! ```
//!
//! This crate is built with `#![no_std]` and only uses libcore for its code, so it can be used
//! from other `no_std` crates.

#![no_std]

/// A trait that allows you to create an instance of a type by using a given function to generate
/// each element.
pub trait InitWith<T> {
    /// Create a new instance of this type using the given function to fill elements.
    ///
    /// # Examples
    ///
    /// Prefilling an array with a Vec, with no unsafe code:
    ///
    /// ```rust
    /// use init_with::InitWith;
    ///
    /// let src = vec![1, 2, 3];
    /// let dest: [i32; 3] = {
    ///     let mut idx = 0;
    ///
    ///     <[i32; 3]>::init_with(|| {
    ///         let val = src[idx];
    ///         idx += 1;
    ///         val
    ///     })
    /// };
    ///
    /// assert_eq!(src, dest);
    /// ```
    fn init_with<F>(init: F) -> Self
    where
        F: FnMut() -> T,
        Self: Sized;

    /// Create a new instance of this type to fill elements
    /// by mapping the given function over the new array's indices.
    ///
    /// # Examples
    ///
    /// Prefilling an array of eeven numbers, with no unsafe code
    ///
    /// ```rust
    /// use init_with::InitWith;
    ///
    /// let src = vec![0, 2, 4];
    /// let dest = <[i32; 3]>::init_with_indices(|x| 2*x as i32);
    ///
    ///
    /// assert_eq!(src, dest);
    /// ```
    fn init_with_indices<F>(init: F) -> Self
    where
        F: FnMut(usize) -> T,
        Self: Sized;
}

macro_rules! array_init {
    {$n:expr, $init:ident, $($stack:ident,)+} => {
        impl<T> InitWith<T> for [T; $n] {
            fn init_with<F>(mut $init: F) -> Self
                where F: FnMut() -> T,
                Self: Sized
            {
                [$init(), $($stack()),+]
            }
            fn init_with_indices<F>(mut $init: F) -> Self
                where F: FnMut(usize) -> T
            {
                build_incrementing_list!([], 0, $init, $($stack),+)
            }
        }
        array_init!{($n - 1), $($stack,)+}
    };
    {$n:expr, $init:ident,} => {
        impl<T> InitWith<T> for [T; $n] {
            fn init_with<F>(mut $init: F) -> Self
                where F: FnMut() -> T,
                Self: Sized
            {
                [$init()]
            }
            fn init_with_indices<F>(mut $init: F) -> Self
                where F: FnMut(usize) -> T,
                Self: Sized
            {
                [$init(0)]
            }
        }
        array_init!{($n - 1)}
    };
    {$n:expr} => {
        impl<T> InitWith<T> for [T; $n] {
            fn init_with<F>(_init: F) -> Self
                where F: FnMut() -> T,
                Self: Sized
            {
                []
            }
            fn init_with_indices<F>(_: F) -> Self
                where F: FnMut(usize) -> T,
                Self: Sized
            {
                []
            }
        }
    };
}

macro_rules! build_incrementing_list {
	{[$($result:tt)*], $n:expr, $head:ident} => {
		[$($result)* $head($n),]
	};
	{[$($result:tt)*], $n:expr, $head:ident, $($stack:ident),+} => {
		build_incrementing_list!([$($result)* $head($n),], $n+1, $($stack),+)
	};
}

array_init!{32, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init,}

#[cfg(test)]
mod tests {
    use super::InitWith;

    #[test]
    fn expected() {
        let val = <[i32; 3]>::init_with(|| 4);
        assert_eq!(val, [4, 4, 4]);
    }

    #[test]
    fn expected_build_incrementing_list() {
        let val = <[usize; 5]>::init_with_indices(|x| x);
        assert_eq!(val, [0, 1, 2, 3, 4]);
    }
}
<|endoftext|>