<commit_before>use app_units::Au;
use euclid::{Rect, Size2D};

#[cfg(target_os="macos")]
use core_graphics::font::CGFont;

// TODO: This is bogus - work out a clean way to generate scroll layer IDs that integrates well with servo...
const FIXED_SCROLL_LAYER_ID: usize = 0xffffffff;

#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct BorderRadius {
    pub top_left: Size2D<f32>,
    pub top_right: Size2D<f32>,
    pub bottom_left: Size2D<f32>,
    pub bottom_right: Size2D<f32>,
}

impl BorderRadius {
    pub fn zero() -> BorderRadius {
        BorderRadius {
            top_left: Size2D::new(0.0, 0.0),
            top_right: Size2D::new(0.0, 0.0),
            bottom_left: Size2D::new(0.0, 0.0),
            bottom_right: Size2D::new(0.0, 0.0),
        }
    }

    pub fn uniform(radius: f32) -> BorderRadius {
        BorderRadius {
            top_left: Size2D::new(radius, radius),
            top_right: Size2D::new(radius, radius),
            bottom_left: Size2D::new(radius, radius),
            bottom_right: Size2D::new(radius, radius),
        }
    }
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct BorderSide {
    pub width: f32,
    pub color: ColorF,
    pub style: BorderStyle,
}

#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum BorderStyle {
    None,
    Solid,
    Double,
    Dotted,
    Dashed,
    Hidden,
    Groove,
    Ridge,
    Inset,
    Outset,
}

#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
pub enum BoxShadowClipMode {
    None,
    Outset,
    Inset,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ClipRegion {
    pub main: Rect<f32>,
    pub complex: Vec<ComplexClipRegion>,
}

impl ClipRegion {
    pub fn new(rect: Rect<f32>, complex: Vec<ComplexClipRegion>) -> ClipRegion {
        ClipRegion {
            main: rect,
            complex: complex,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct ComplexClipRegion {
    /// The boundaries of the rectangle.
    pub rect: Rect<f32>,
    /// Border radii of this rectangle.
    pub radii: BorderRadius,
}

impl ComplexClipRegion {
    pub fn new(rect: Rect<f32>, radii: BorderRadius) -> ComplexClipRegion {
        ComplexClipRegion {
            rect: rect,
            radii: radii,
        }
    }

    pub fn from_rect(rect: &Rect<f32>) -> ComplexClipRegion {
        ComplexClipRegion {
            rect: *rect,
            radii: BorderRadius::zero(),
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct ColorF {
    pub r: f32,
    pub g: f32,
    pub b: f32,
    pub a: f32,
}

impl ColorF {
    pub fn new(r: f32, g: f32, b: f32, a: f32) -> ColorF {
        ColorF {
            r: r,
            g: g,
            b: b,
            a: a,
        }
    }

    pub fn scale_rgb(&self, scale: f32) -> ColorF {
        ColorF {
            r: self.r * scale,
            g: self.g * scale,
            b: self.b * scale,
            a: self.a,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct StackingContextId(pub u32, pub u32);

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct DisplayListId(pub u32, pub u32);

#[derive(Serialize, Deserialize)]
pub enum DisplayListMode {
    Default,
    PseudoFloat,
    PseudoPositionedContent,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize)]
pub struct Epoch(pub u32);

#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub enum FilterOp {
    Blur(Au),
    Brightness(f32),
    Contrast(f32),
    Grayscale(f32),
    HueRotate(f32),
    Invert(f32),
    Opacity(f32),
    Saturate(f32),
    Sepia(f32),
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct FontKey(u32, u32);

impl FontKey {
    pub fn new(key0: u32, key1: u32) -> FontKey {
        FontKey(key0, key1)
    }
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct GlyphInstance {
    pub index: u32,
    pub x: f32,
    pub y: f32,
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct GradientStop {
    pub offset: f32,
    pub color: ColorF,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ImageFormat {
    Invalid,
    A8,
    RGB8,
    RGBA8,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ImageRendering {
    Auto,
    CrispEdges,
    Pixelated,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct ImageKey(u32, u32);

impl ImageKey {
    pub fn new(key0: u32, key1: u32) -> ImageKey {
        ImageKey(key0, key1)
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub enum MixBlendMode {
    Normal,
    Multiply,
    Screen,
    Overlay,
    Darken,
    Lighten,
    ColorDodge,
    ColorBurn,
    HardLight,
    SoftLight,
    Difference,
    Exclusion,
    Hue,
    Saturation,
    Color,
    Luminosity,
}

#[cfg(target_os="macos")]
pub type NativeFontHandle = CGFont;

/// Native fonts are not used on Linux; all fonts are raw.
#[cfg(not(target_os="macos"))]
#[derive(Clone, Serialize, Deserialize)]
pub struct NativeFontHandle;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct PipelineId(pub u32, pub u32);

pub trait RenderNotifier : Send {
    fn new_frame_ready(&mut self);
    fn pipeline_size_changed(&mut self,
                             pipeline_id: PipelineId,
                             size: Option<Size2D<f32>>);
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ScrollLayerId(pub usize);

impl ScrollLayerId {
    pub fn new(value: usize) -> ScrollLayerId {
        debug_assert!(value != FIXED_SCROLL_LAYER_ID);
        ScrollLayerId(value)
    }

    pub fn fixed_layer() -> ScrollLayerId {
        ScrollLayerId(FIXED_SCROLL_LAYER_ID)
    }
}

#[derive(Clone, PartialEq, Eq, Copy, Deserialize, Serialize, Debug)]
pub enum ScrollPolicy {
    Scrollable,
    Fixed,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum StackingLevel {
    BackgroundAndBorders,
    BlockBackgroundAndBorders,
    Floats,
    Content,
    PositionedContent,
    Outlines,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct WebGLContextId(pub usize);

#[derive(Debug, Serialize, Deserialize)]
pub enum WebGLCommand {
    Clear(u32),
    ClearColor(f32, f32, f32, f32),
}
<commit_msg>Make `MixBlendMode` hashable.<commit_after>use app_units::Au;
use euclid::{Rect, Size2D};

#[cfg(target_os="macos")]
use core_graphics::font::CGFont;

// TODO: This is bogus - work out a clean way to generate scroll layer IDs that integrates well with servo...
const FIXED_SCROLL_LAYER_ID: usize = 0xffffffff;

#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct BorderRadius {
    pub top_left: Size2D<f32>,
    pub top_right: Size2D<f32>,
    pub bottom_left: Size2D<f32>,
    pub bottom_right: Size2D<f32>,
}

impl BorderRadius {
    pub fn zero() -> BorderRadius {
        BorderRadius {
            top_left: Size2D::new(0.0, 0.0),
            top_right: Size2D::new(0.0, 0.0),
            bottom_left: Size2D::new(0.0, 0.0),
            bottom_right: Size2D::new(0.0, 0.0),
        }
    }

    pub fn uniform(radius: f32) -> BorderRadius {
        BorderRadius {
            top_left: Size2D::new(radius, radius),
            top_right: Size2D::new(radius, radius),
            bottom_left: Size2D::new(radius, radius),
            bottom_right: Size2D::new(radius, radius),
        }
    }
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct BorderSide {
    pub width: f32,
    pub color: ColorF,
    pub style: BorderStyle,
}

#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum BorderStyle {
    None,
    Solid,
    Double,
    Dotted,
    Dashed,
    Hidden,
    Groove,
    Ridge,
    Inset,
    Outset,
}

#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
pub enum BoxShadowClipMode {
    None,
    Outset,
    Inset,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ClipRegion {
    pub main: Rect<f32>,
    pub complex: Vec<ComplexClipRegion>,
}

impl ClipRegion {
    pub fn new(rect: Rect<f32>, complex: Vec<ComplexClipRegion>) -> ClipRegion {
        ClipRegion {
            main: rect,
            complex: complex,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct ComplexClipRegion {
    /// The boundaries of the rectangle.
    pub rect: Rect<f32>,
    /// Border radii of this rectangle.
    pub radii: BorderRadius,
}

impl ComplexClipRegion {
    pub fn new(rect: Rect<f32>, radii: BorderRadius) -> ComplexClipRegion {
        ComplexClipRegion {
            rect: rect,
            radii: radii,
        }
    }

    pub fn from_rect(rect: &Rect<f32>) -> ComplexClipRegion {
        ComplexClipRegion {
            rect: *rect,
            radii: BorderRadius::zero(),
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct ColorF {
    pub r: f32,
    pub g: f32,
    pub b: f32,
    pub a: f32,
}

impl ColorF {
    pub fn new(r: f32, g: f32, b: f32, a: f32) -> ColorF {
        ColorF {
            r: r,
            g: g,
            b: b,
            a: a,
        }
    }

    pub fn scale_rgb(&self, scale: f32) -> ColorF {
        ColorF {
            r: self.r * scale,
            g: self.g * scale,
            b: self.b * scale,
            a: self.a,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct StackingContextId(pub u32, pub u32);

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct DisplayListId(pub u32, pub u32);

#[derive(Serialize, Deserialize)]
pub enum DisplayListMode {
    Default,
    PseudoFloat,
    PseudoPositionedContent,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize)]
pub struct Epoch(pub u32);

#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub enum FilterOp {
    Blur(Au),
    Brightness(f32),
    Contrast(f32),
    Grayscale(f32),
    HueRotate(f32),
    Invert(f32),
    Opacity(f32),
    Saturate(f32),
    Sepia(f32),
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct FontKey(u32, u32);

impl FontKey {
    pub fn new(key0: u32, key1: u32) -> FontKey {
        FontKey(key0, key1)
    }
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct GlyphInstance {
    pub index: u32,
    pub x: f32,
    pub y: f32,
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct GradientStop {
    pub offset: f32,
    pub color: ColorF,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ImageFormat {
    Invalid,
    A8,
    RGB8,
    RGBA8,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ImageRendering {
    Auto,
    CrispEdges,
    Pixelated,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct ImageKey(u32, u32);

impl ImageKey {
    pub fn new(key0: u32, key1: u32) -> ImageKey {
        ImageKey(key0, key1)
    }
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum MixBlendMode {
    Normal,
    Multiply,
    Screen,
    Overlay,
    Darken,
    Lighten,
    ColorDodge,
    ColorBurn,
    HardLight,
    SoftLight,
    Difference,
    Exclusion,
    Hue,
    Saturation,
    Color,
    Luminosity,
}

#[cfg(target_os="macos")]
pub type NativeFontHandle = CGFont;

/// Native fonts are not used on Linux; all fonts are raw.
#[cfg(not(target_os="macos"))]
#[derive(Clone, Serialize, Deserialize)]
pub struct NativeFontHandle;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct PipelineId(pub u32, pub u32);

pub trait RenderNotifier : Send {
    fn new_frame_ready(&mut self);
    fn pipeline_size_changed(&mut self,
                             pipeline_id: PipelineId,
                             size: Option<Size2D<f32>>);
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ScrollLayerId(pub usize);

impl ScrollLayerId {
    pub fn new(value: usize) -> ScrollLayerId {
        debug_assert!(value != FIXED_SCROLL_LAYER_ID);
        ScrollLayerId(value)
    }

    pub fn fixed_layer() -> ScrollLayerId {
        ScrollLayerId(FIXED_SCROLL_LAYER_ID)
    }
}

#[derive(Clone, PartialEq, Eq, Copy, Deserialize, Serialize, Debug)]
pub enum ScrollPolicy {
    Scrollable,
    Fixed,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum StackingLevel {
    BackgroundAndBorders,
    BlockBackgroundAndBorders,
    Floats,
    Content,
    PositionedContent,
    Outlines,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct WebGLContextId(pub usize);

#[derive(Debug, Serialize, Deserialize)]
pub enum WebGLCommand {
    Clear(u32),
    ClearColor(f32, f32, f32, f32),
}
<|endoftext|>


<commit_before>use std::collections::hash_map::HashMap;
use std::vec::Vec;
use js_types::js_type::{JsTrait, JsT};

pub struct JsObj {
    proto: JsProto,
    dict: HashMap<JsT, JsT>,
}

impl JsTrait for JsObj {}

impl JsObj {
    pub fn new(proto: JsProto, kv_pairs: Vec<(JsT, JsT)>) -> JsObj {
        let mut obj_map = HashMap::new();
        kv_pairs.into_iter().map(|(k,v)| obj_map.insert(k, v));
        JsObj {
            proto: None,
            dict: obj_map,
        }
    }
}

pub type JsProto = Option<Box<JsObj>>;

#[cfg(test)]
mod test {
    use js_types::js_obj::JsObj;
    use js_types::js_type::JsT;
    use js_types::js_primitive::{JsNum, JsStr};
    #[test]
    fn test_js_obj() {
        let mut vec: Vec<(JsT, JsT)> = Vec::new();
        for i in 0..10 {
            let k = JsT::new(Box::new(JsNum(i as f64)));
            let v = JsT::new(Box::new(JsStr::new(&format!("test{}", i))));
            vec.push((k,v));
        }
        let o = JsObj::new(None, vec);
        for (k, v) in o.dict {
            assert!(k >= 0); // Problem: is this type erased at runtime?
            assert!(k < 10);
            assert!(v.starts_with("test"));
        }
    }

}
<commit_msg>Rename JsObj -> JsObjStruct, make working tests<commit_after>use std::collections::hash_map::HashMap;
use std::vec::Vec;
use js_types::js_type::{JsType,JsT};

pub struct JsObjStruct {
    pub proto: JsProto,
    pub dict: HashMap<JsT, JsT>,
}

impl JsObjStruct {
    pub fn new(proto: JsProto, kv_pairs: Vec<(JsT, JsT)>) -> JsObjStruct {
        let mut obj_map = HashMap::new();
        kv_pairs.into_iter().map(|(k,v)| obj_map.insert(k, v));
        JsObjStruct {
            proto: None,
            dict: obj_map,
        }
    }
}

pub type JsProto = Option<Box<JsObjStruct>>;

#[cfg(test)]
mod test {
    use js_types::js_obj::JsObjStruct;
    use js_types::js_type::{JsType,JsT};
    use js_types::js_str::JsStrStruct;

    #[test]
    fn test_js_obj() {
        let mut vec: Vec<(JsT, JsT)> = Vec::new();
        for i in 0..10 {
            let k = JsT::new(JsType::JsNum(i as f64));
            let v = JsT::new(JsType::JsStr(JsStrStruct::new(
                                            &format!("test{}", i))));
            vec.push((k,v));
        }
        let o = JsObjStruct::new(None, vec);
        for (k, v) in o.dict {
            match k.t {
                JsType::JsNum(ki) => { assert!(ki >= 0.0f64);
                                       assert!(ki < 10.0f64) },
                _ => panic!("Expected a JsNum!"),
            };
            match v.t {
                JsType::JsStr(vs) => assert!(vs.text.starts_with("test")),
                _ => panic!("Expected a JsStr!"),
            };
        }
    }

}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::process::exit;
use std::rc::Rc;

use super::super::ir::layout as ir;
use super::super::target::bytecode::layout::Instruction;

use super::frame::{Frame, SharedFrame};
use super::loader::Loader;
use super::value::Value;

pub struct Vm {
    stack: Vec<SharedFrame>,
    loader: Loader,
}

enum Action {
    None,
    Push(SharedFrame),
    Pop(Value),
}

fn prelude_println(arguments: Vec<Value>) -> Value {
    if let Some(argument) = arguments.first() {
        match argument {
            Value::Integer(value) => println!("{}", value),
            _ => unreachable!(),
        }
    };
    Value::Null
}

impl Vm {
    pub fn run_main(ir_unit: ir::Unit) {
        let mut vm = Self {
            stack: vec![],
            loader: Loader::new(),
        };
        let loaded_unit = vm.loader.load(ir_unit);
        let frame = Frame::new(loaded_unit.main(), None, 0);
        vm.stack.push(Rc::new(RefCell::new(frame)));
        vm.run();
    }

    // fn build_prelude() -> SharedFrame {
    //     let prelude_unit = Unit {
    //         functions: vec![Function {
    //             id: 0,
    //             name: "prelude".to_string(),
    //             registers: 0,
    //             basic_blocks: vec![],
    //             locals: 1,
    //             locals_names: vec!["println".to_string()],
    //         }],
    //     };
    //     let prelude_main_function = prelude_unit.functions[0].clone();
    //     let mut prelude = Frame::new(
    //         Rc::new(prelude_unit),
    //         Rc::new(prelude_main_function),
    //         None,
    //         0,
    //     );
    //     prelude.set_local(
    //         0,
    //         Value::NativeFunction(NativeFunction::new(Rc::new(prelude_println))),
    //     );
    //     Rc::new(RefCell::new(prelude))
    // }

    fn run(&mut self) {
        loop {
            match self.dispatch() {
                Some(code) => exit(code),
                None => (),
            }
        }
    }

    fn dispatch(&mut self) -> Option<i32> {
        use self::Action::*;

        let top = self.stack.last().expect("Empty stack");
        let instruction = top.borrow().current();

        let action = {
            // Need the `&mut Frame` to force this to be a mutable borrow.
            let top: &mut Frame = &mut top.borrow_mut();
            match &instruction {
                Instruction::GetLocal(lval, index) => {
                    top.write_register(*lval, top.get_local(*index));
                    top.advance();
                    None
                }
                Instruction::GetLocalLexical(lval, name) => {
                    top.write_register(*lval, top.get_local_lexical(name));
                    top.advance();
                    None
                }
                Instruction::SetLocal(index, rval) => {
                    top.set_local(*index, top.read_register(*rval));
                    top.advance();
                    None
                }
                Instruction::MakeFunction(lval, id) => {
                    let function = top.unit().function(*id);
                    let value = Value::from_dynamic_function(function);
                    top.write_register(*lval, value);
                    top.advance();
                    None
                }
                Instruction::MakeInteger(lval, value) => {
                    top.write_register(*lval, Value::Integer(*value));
                    top.advance();
                    None
                }
                Instruction::Call(lval, target, arguments) => {
                    let return_register = *lval;
                    let target = top.read_register(*target);
                    let arguments = arguments
                        .iter()
                        .map(|argument| top.read_register(*argument))
                        .collect::<Vec<Value>>();
                    match target {
                        Value::DynamicFunction(dynamic_function) => {
                            // TODO: Make `CallTarget` able to do specialization.
                            let function = dynamic_function.call_target.function;
                            let frame = Rc::new(RefCell::new(Frame::new(
                                function,
                                Option::None,
                                return_register,
                            )));
                            Push(frame)
                        }
                        Value::NativeFunction(native_function) => {
                            let result = native_function.call(arguments);
                            top.write_register(return_register, result);
                            top.advance();
                            None
                        }
                        _ => panic!("Cannot call"),
                    }
                }
                Instruction::Return(rval) => Pop(top.read_register(*rval)),
                Instruction::ReturnNull => Pop(Value::Null),
                _ => panic!("Cannot dispatch: {:?}", instruction),
            }
        };
        match action {
            Push(frame) => self.stack.push(frame),
            Pop(return_value) => {
                let popped = self.stack.pop().expect("Empty stack");
                let return_register = popped.borrow().return_register;
                match self.stack.last() {
                    Option::Some(top) => {
                        let mut top = top.borrow_mut();
                        top.write_register(return_register, return_value);
                        top.advance();
                    }
                    // Returning from the top frame.
                    Option::None => return Some(0),
                }
            }
            None => (),
        };
        Option::None
    }
}
<commit_msg>Inject the prelude's `println` in an even hackier way<commit_after>use std::cell::RefCell;
use std::process::exit;
use std::rc::Rc;

use super::super::ir::layout as ir;
use super::super::target::bytecode::layout::Instruction;

use super::frame::{Frame, SharedFrame};
use super::loader::Loader;
use super::value::{NativeFunction, Value};

pub struct Vm {
    stack: Vec<SharedFrame>,
    loader: Loader,
}

enum Action {
    None,
    Push(SharedFrame),
    Pop(Value),
}

fn prelude_println(arguments: Vec<Value>) -> Value {
    if let Some(argument) = arguments.first() {
        match argument {
            Value::Integer(value) => println!("{}", value),
            _ => unreachable!(),
        }
    };
    Value::Null
}

impl Vm {
    pub fn run_main(ir_unit: ir::Unit) {
        let mut vm = Self {
            stack: vec![],
            loader: Loader::new(),
        };

        // Declare "println" in the local scope of the main function.
        let ir_main = ir_unit.main_function();
        let index = ir_main.borrow_mut().get_or_add_local("println".to_string());

        let loaded_unit = vm.loader.load(ir_unit);

        // Then inject the println at the index we previously declared.
        let mut frame = Frame::new(loaded_unit.main(), None, 0);
        frame.set_local(index, Value::NativeFunction(NativeFunction::new(Rc::new(prelude_println))));

        vm.stack.push(Rc::new(RefCell::new(frame)));
        vm.run();
    }

    fn run(&mut self) {
        loop {
            match self.dispatch() {
                Some(code) => exit(code),
                None => (),
            }
        }
    }

    fn dispatch(&mut self) -> Option<i32> {
        use self::Action::*;

        let top = self.stack.last().expect("Empty stack");
        let instruction = top.borrow().current();

        let action = {
            // Need the `&mut Frame` to force this to be a mutable borrow.
            let top: &mut Frame = &mut top.borrow_mut();
            match &instruction {
                Instruction::GetLocal(lval, index) => {
                    top.write_register(*lval, top.get_local(*index));
                    top.advance();
                    None
                }
                Instruction::GetLocalLexical(lval, name) => {
                    top.write_register(*lval, top.get_local_lexical(name));
                    top.advance();
                    None
                }
                Instruction::SetLocal(index, rval) => {
                    top.set_local(*index, top.read_register(*rval));
                    top.advance();
                    None
                }
                Instruction::MakeFunction(lval, id) => {
                    let function = top.unit().function(*id);
                    let value = Value::from_dynamic_function(function);
                    top.write_register(*lval, value);
                    top.advance();
                    None
                }
                Instruction::MakeInteger(lval, value) => {
                    top.write_register(*lval, Value::Integer(*value));
                    top.advance();
                    None
                }
                Instruction::Call(lval, target, arguments) => {
                    let return_register = *lval;
                    let target = top.read_register(*target);
                    let arguments = arguments
                        .iter()
                        .map(|argument| top.read_register(*argument))
                        .collect::<Vec<Value>>();
                    match target {
                        Value::DynamicFunction(dynamic_function) => {
                            // TODO: Make `CallTarget` able to do specialization.
                            let function = dynamic_function.call_target.function;
                            let frame = Rc::new(RefCell::new(Frame::new(
                                function,
                                Option::None,
                                return_register,
                            )));
                            Push(frame)
                        }
                        Value::NativeFunction(native_function) => {
                            let result = native_function.call(arguments);
                            top.write_register(return_register, result);
                            top.advance();
                            None
                        }
                        _ => panic!("Cannot call"),
                    }
                }
                Instruction::Return(rval) => Pop(top.read_register(*rval)),
                Instruction::ReturnNull => Pop(Value::Null),
                _ => panic!("Cannot dispatch: {:?}", instruction),
            }
        };
        match action {
            Push(frame) => self.stack.push(frame),
            Pop(return_value) => {
                let popped = self.stack.pop().expect("Empty stack");
                let return_register = popped.borrow().return_register;
                match self.stack.last() {
                    Option::Some(top) => {
                        let mut top = top.borrow_mut();
                        top.write_register(return_register, return_value);
                        top.advance();
                    }
                    // Returning from the top frame.
                    Option::None => return Some(0),
                }
            }
            None => (),
        };
        Option::None
    }
}
<|endoftext|>


<commit_before>use mio;
use mio::tcp::*;
use mio::{TryRead,TryWrite};
use serde_json as json;

use std::collections::VecDeque;
use std::net::SocketAddr;
use std::fmt;
use std::io::ErrorKind;

use super::{ChainRepl, ChainReplMsg,OpResp, Operation, PeerMsg};
use line_conn::{Encoder, Reader, SexpPeer};

#[derive(Debug)]
pub struct Downstream<T: fmt::Debug> {
    token: mio::Token,
    peer: Option<SocketAddr>,
    // Rather feels like we need to factor this into per-iteration state.
    // ... LAYERS!
    socket: Option<TcpStream>,
    sock_status: mio::EventSet,
    pending: VecDeque<PeerMsg>,
    write_buf: Vec<u8>,
    should_disconnect: bool,
    timeout_triggered: bool,
    codec: T,
}

impl Downstream<SexpPeer> {
    pub fn new(target: Option<SocketAddr>, token: mio::Token) -> Self {
       Self::with_codec(target, token, SexpPeer::fresh(token))
    }
}

impl<T: Reader<OpResp> + Encoder<PeerMsg> + fmt::Debug> Downstream<T> {
    pub fn with_codec(target: Option<SocketAddr>, token: mio::Token, codec: T) -> Self {
        debug!("Connecting to {:?}", target);
        let mut conn = Downstream {
            token: token,
            peer: target,
            socket: None,
            sock_status: mio::EventSet::none(),
            pending: VecDeque::new(),
            write_buf: Vec::new(),
            should_disconnect: false,
            timeout_triggered: false,
            codec: codec,
        };
        conn
    }

    pub fn reconnect_to(&mut self, target: SocketAddr) {
        if self.peer != Some(target) {
            info!("New downstream: {:?}", target);
            self.peer = Some(target);
            self.should_disconnect = true;
        } else {
            debug!("No change of downstream: {:?}", target);
        }
    }

    pub fn disconnect(&mut self) {
        info!("Disconnect");
        self.peer = None;
        self.should_disconnect = true;
    }

    pub fn send_to_downstream(&mut self, epoch: u64, seqno: u64, op: Operation) {
        let msg = (epoch, seqno, op);
        debug!("Queuing for downstream (qlen: {}): {:?}: {:?}", self.pending.len()+1, self.peer, msg);
        self.pending.push_back(msg);
    }

    pub fn initialize(&self, event_loop: &mut mio::EventLoop<ChainRepl>, token: mio::Token) {
        if let Some(ref sock) = self.socket {
            debug!("Initialize!{:?}", self);
            match event_loop.register_opt(
                    sock,
                    token,
                    mio::EventSet::readable(),
                    mio::PollOpt::edge() | mio::PollOpt::oneshot()) {
                Ok(()) => (),
                Err(e) => {
                    warn!("Registration failed:{}; kind:{:?}", e, e.kind());
                    // self.should_disconnect = true;
                }
            }
        } else {
            warn!("Registering disconnected downstream?!? {:?}", self);
        }
    }

    pub fn handle_event(&mut self, _event_loop: &mut mio::EventLoop<ChainRepl>, events: mio::EventSet) {
        self.sock_status.insert(events);
        trace!("Listener::handle_event: {:?}; this time: {:?}; now: {:?}",
                self.socket.as_ref().map(|s| s.local_addr()), events, self.sock_status);
    }

    pub fn handle_timeout(&mut self) {
        self.timeout_triggered = true
    }

    pub fn process_rules<F: FnMut(ChainReplMsg)>(&mut self, event_loop: &mut mio::EventLoop<ChainRepl>,
            to_parent: &mut F) -> bool {
        trace!("the downstream socket is {:?}", self.sock_status);

        if self.sock_status.is_readable() {
            self.read();
            self.sock_status.remove(mio::EventSet::readable());
        }

        let changed = self.process_buffer(to_parent);

        if self.sock_status.is_writable() {
            self.prep_write_buffer();
            self.write();
            self.sock_status.remove(mio::EventSet::writable());
        }

        if self.sock_status.is_hup() || self.sock_status.is_error() || self.should_disconnect {
            if let Some(sock) = self.socket.take() {
                debug!("Disconnecting socket! {:?}: {:?}", sock, self.sock_status);
                match event_loop.deregister(&sock) {
                    Ok(()) => (),
                    Err(e) => {
                        warn!("Deregister socket failed: {}", e);
                    }
                }
                event_loop.timeout_ms(self.token, 1000).expect("reconnect timeout");
                self.reset();
            }
        }

        if self.timeout_triggered {
            self.attempt_connect();
            self.initialize(event_loop, self.token);
            self.timeout_triggered = false;
        }

        if !self.is_closed() {
            self.reinitialize(event_loop)
        }
        changed
    }

    fn reset(&mut self) {
        let peer = self.peer.clone();
        let token = self.token.clone();
        let _ = ::std::mem::replace(self, Self::with_codec(peer, token, T::new(token)));
    }

    fn attempt_connect(&mut self) {
        assert!(self.socket.is_none());
        debug!("Connecting: {:?}", self);
        if let &mut Downstream { peer: Some(ref peer), ref mut socket, ref mut sock_status, .. } = self {
            let conn = TcpStream::connect(peer).expect("Connect downstream");
            debug!("New downstream for {:?}! {:?}; {:?}", self.token, self.peer, conn);
            *socket = Some(conn);
            sock_status.remove(mio::EventSet::all());
        } else {
            warn!("Attempting to connect Downstream with no target set");
        }
    }

    fn read(&mut self) {
        let mut abuf = Vec::new();
        if let &mut Downstream { socket: Some(ref mut sock), ref mut codec, token, .. } = self {
            match sock.try_read_buf(&mut abuf) {
                Ok(Some(0)) => {
                    trace!("{:?}: EOF!", token);
                    self.should_disconnect = true
                },
                Ok(Some(n)) => {
                    trace!("{:?}: Read {}bytes", token, n);
                    codec.feed(&abuf);
                },
                Ok(None) => {
                    trace!("{:?}: Noop!", token);
                },
                Err(e) => {
                    error!("got an error trying to read; err={:?}", e);
                    self.should_disconnect = true
                }
            }
        }
    }

    fn prep_write_buffer(&mut self) {
        if let Some((epoch, seqno, it)) = self.pending.pop_front() {
            debug!("Preparing to send downstream (qlen {}): {:?}/{:?}", self.pending.len(), seqno, it);
            let msg : PeerMsg = (epoch, seqno, it);
            let out = self.codec.encode(msg);
            self.write_buf.extend(&out);
        }
    }

    fn write(&mut self) {
        if let &mut Downstream { socket: Some(ref mut sock), ref mut write_buf, token, .. } = self {
            match sock.try_write(write_buf) {
                Ok(Some(n)) => {
                    trace!("Downstream: {:?}: Wrote {} of {} in buffer", token, n,
                            write_buf.len());
                    *write_buf = write_buf[n..].to_vec();
                    trace!("Downstream: {:?}: Now {:?}b", sock, write_buf.len());
                },
                Ok(None) => {
                    trace!("Write unready");
                },
                Err(e) => {
                    error!("got an error trying to write; err={:?}", e);
                    self.should_disconnect = true
                }
            }
        }
    }

    fn process_buffer<F: FnMut(ChainReplMsg)>(&mut self, to_parent: &mut F) -> bool {
        let mut changed = false;
       // trace!("{:?}: Read buffer: {:?}", self.socket.peer_addr(), self.read_buf);
        while let Some(cmd) = self.codec.take() {
            debug!("Read message {:?}", cmd);
            to_parent(ChainReplMsg::DownstreamResponse(cmd));

            changed = true;
        }

        changed
    }

    pub fn is_closed(&self) -> bool {
        self.peer.is_none()
    }

    fn reinitialize(&mut self, event_loop: &mut mio::EventLoop<ChainRepl>) {
        if let Some(ref sock) = self.socket {
            let mut flags = mio::EventSet::readable();
            if !(self.write_buf.is_empty() && self.pending.is_empty()) {
                flags.insert(mio::EventSet::writable());
            }
            trace!("Re-register {:?} with {:?}", self, flags);

            match event_loop.reregister(
                    sock,
                    self.token,
                    flags,
                    mio::PollOpt::oneshot()) {
                Ok(()) => (),
                Err(ref e) if e.kind() == ErrorKind::NotFound => {
                    warn!("Re-registration failed:{}; kind:{:?}", e, e.kind());
                    self.should_disconnect = true
                }
                Err(ref e) => {
                    warn!("Re-registration failed:{}; kind:{:?}", e, e.kind());
                    self.should_disconnect = true
                }
            }
        }
    }
}
<commit_msg>Actually initialize downstreams.<commit_after>use mio;
use mio::tcp::*;
use mio::{TryRead,TryWrite};
use serde_json as json;

use std::collections::VecDeque;
use std::net::SocketAddr;
use std::fmt;
use std::io::ErrorKind;

use super::{ChainRepl, ChainReplMsg,OpResp, Operation, PeerMsg};
use line_conn::{Encoder, Reader, SexpPeer};

#[derive(Debug)]
pub struct Downstream<T: fmt::Debug> {
    token: mio::Token,
    peer: Option<SocketAddr>,
    // Rather feels like we need to factor this into per-iteration state.
    // ... LAYERS!
    socket: Option<TcpStream>,
    sock_status: mio::EventSet,
    pending: VecDeque<PeerMsg>,
    write_buf: Vec<u8>,
    should_disconnect: bool,
    timeout_triggered: bool,
    codec: T,
}

impl Downstream<SexpPeer> {
    pub fn new(target: Option<SocketAddr>, token: mio::Token) -> Self {
       Self::with_codec(target, token, SexpPeer::fresh(token))
    }
}

impl<T: Reader<OpResp> + Encoder<PeerMsg> + fmt::Debug> Downstream<T> {
    pub fn with_codec(target: Option<SocketAddr>, token: mio::Token, codec: T) -> Self {
        debug!("Connecting to {:?}", target);
        let mut conn = Downstream {
            token: token,
            peer: target,
            socket: None,
            sock_status: mio::EventSet::none(),
            pending: VecDeque::new(),
            write_buf: Vec::new(),
            should_disconnect: false,
            timeout_triggered: true,
            codec: codec,
        };
        conn
    }

    pub fn reconnect_to(&mut self, target: SocketAddr) {
        if self.peer != Some(target) {
            info!("New downstream: {:?}", target);
            self.peer = Some(target);
            self.should_disconnect = true;
        } else {
            debug!("No change of downstream: {:?}", target);
        }
    }

    pub fn disconnect(&mut self) {
        info!("Disconnect");
        self.peer = None;
        self.should_disconnect = true;
    }

    pub fn send_to_downstream(&mut self, epoch: u64, seqno: u64, op: Operation) {
        let msg = (epoch, seqno, op);
        debug!("Queuing for downstream (qlen: {}): {:?}: {:?}", self.pending.len()+1, self.peer, msg);
        self.pending.push_back(msg);
    }

    pub fn initialize(&self, event_loop: &mut mio::EventLoop<ChainRepl>, token: mio::Token) {
        if let Some(ref sock) = self.socket {
            debug!("Initialize!{:?}", self);
            match event_loop.register_opt(
                    sock,
                    token,
                    mio::EventSet::readable(),
                    mio::PollOpt::edge() | mio::PollOpt::oneshot()) {
                Ok(()) => (),
                Err(e) => {
                    warn!("Registration failed:{}; kind:{:?}", e, e.kind());
                    // self.should_disconnect = true;
                }
            }
        } else {
            warn!("Registering disconnected downstream?!? {:?}", self);
        }
    }

    pub fn handle_event(&mut self, _event_loop: &mut mio::EventLoop<ChainRepl>, events: mio::EventSet) {
        self.sock_status.insert(events);
        trace!("Listener::handle_event: {:?}; this time: {:?}; now: {:?}",
                self.socket.as_ref().map(|s| s.local_addr()), events, self.sock_status);
    }

    pub fn handle_timeout(&mut self) {
        self.timeout_triggered = true
    }

    pub fn process_rules<F: FnMut(ChainReplMsg)>(&mut self, event_loop: &mut mio::EventLoop<ChainRepl>,
            to_parent: &mut F) -> bool {
        trace!("the downstream socket is {:?}", self.sock_status);

        if self.sock_status.is_readable() {
            self.read();
            self.sock_status.remove(mio::EventSet::readable());
        }

        let changed = self.process_buffer(to_parent);

        if self.sock_status.is_writable() {
            self.prep_write_buffer();
            self.write();
            self.sock_status.remove(mio::EventSet::writable());
        }

        if self.sock_status.is_hup() || self.sock_status.is_error() || self.should_disconnect {
            if let Some(sock) = self.socket.take() {
                debug!("Disconnecting socket! {:?}: {:?}", sock, self.sock_status);
                match event_loop.deregister(&sock) {
                    Ok(()) => (),
                    Err(e) => {
                        warn!("Deregister socket failed: {}", e);
                    }
                }
                event_loop.timeout_ms(self.token, 1000).expect("reconnect timeout");
                self.reset();
            }
        }

        if self.socket.is_none() && self.timeout_triggered {
            self.attempt_connect();
            self.initialize(event_loop, self.token);
            self.timeout_triggered = false;
        }

        if !self.is_closed() {
            self.reinitialize(event_loop)
        }
        changed
    }

    fn reset(&mut self) {
        let peer = self.peer.clone();
        let token = self.token.clone();
        let _ = ::std::mem::replace(self, Self::with_codec(peer, token, T::new(token)));
    }

    fn attempt_connect(&mut self) {
        assert!(self.socket.is_none());
        debug!("Connecting: {:?}", self);
        if let &mut Downstream { peer: Some(ref peer), ref mut socket, ref mut sock_status, .. } = self {
            let conn = TcpStream::connect(peer).expect("Connect downstream");
            debug!("New downstream for {:?}! {:?}; {:?}", self.token, self.peer, conn);
            *socket = Some(conn);
            sock_status.remove(mio::EventSet::all());
        } else {
            warn!("Attempting to connect Downstream with no target set");
        }
    }

    fn read(&mut self) {
        let mut abuf = Vec::new();
        if let &mut Downstream { socket: Some(ref mut sock), ref mut codec, token, .. } = self {
            match sock.try_read_buf(&mut abuf) {
                Ok(Some(0)) => {
                    trace!("{:?}: EOF!", token);
                    self.should_disconnect = true
                },
                Ok(Some(n)) => {
                    trace!("{:?}: Read {}bytes", token, n);
                    codec.feed(&abuf);
                },
                Ok(None) => {
                    trace!("{:?}: Noop!", token);
                },
                Err(e) => {
                    error!("got an error trying to read; err={:?}", e);
                    self.should_disconnect = true
                }
            }
        }
    }

    fn prep_write_buffer(&mut self) {
        if let Some((epoch, seqno, it)) = self.pending.pop_front() {
            debug!("Preparing to send downstream (qlen {}): {:?}/{:?}", self.pending.len(), seqno, it);
            let msg : PeerMsg = (epoch, seqno, it);
            let out = self.codec.encode(msg);
            self.write_buf.extend(&out);
        }
    }

    fn write(&mut self) {
        if let &mut Downstream { socket: Some(ref mut sock), ref mut write_buf, token, .. } = self {
            match sock.try_write(write_buf) {
                Ok(Some(n)) => {
                    trace!("Downstream: {:?}: Wrote {} of {} in buffer", token, n,
                            write_buf.len());
                    *write_buf = write_buf[n..].to_vec();
                    trace!("Downstream: {:?}: Now {:?}b", sock, write_buf.len());
                },
                Ok(None) => {
                    trace!("Write unready");
                },
                Err(e) => {
                    error!("got an error trying to write; err={:?}", e);
                    self.should_disconnect = true
                }
            }
        }
    }

    fn process_buffer<F: FnMut(ChainReplMsg)>(&mut self, to_parent: &mut F) -> bool {
        let mut changed = false;
       // trace!("{:?}: Read buffer: {:?}", self.socket.peer_addr(), self.read_buf);
        while let Some(cmd) = self.codec.take() {
            debug!("Read message {:?}", cmd);
            to_parent(ChainReplMsg::DownstreamResponse(cmd));

            changed = true;
        }

        changed
    }

    pub fn is_closed(&self) -> bool {
        self.peer.is_none()
    }

    fn reinitialize(&mut self, event_loop: &mut mio::EventLoop<ChainRepl>) {
        if let Some(ref sock) = self.socket {
            let mut flags = mio::EventSet::readable();
            if !(self.write_buf.is_empty() && self.pending.is_empty()) {
                flags.insert(mio::EventSet::writable());
            }
            trace!("Re-register {:?} with {:?}", self, flags);

            match event_loop.reregister(
                    sock,
                    self.token,
                    flags,
                    mio::PollOpt::oneshot()) {
                Ok(()) => (),
                Err(ref e) if e.kind() == ErrorKind::NotFound => {
                    warn!("Re-registration failed:{}; kind:{:?}", e, e.kind());
                    self.should_disconnect = true
                }
                Err(ref e) => {
                    warn!("Re-registration failed:{}; kind:{:?}", e, e.kind());
                    self.should_disconnect = true
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use super::{Function, Parameterised, Linear, VFunction, QFunction};

use utils::dot;
use ndarray::{arr1, Array1, Array2};
use geometry::{Span, Space, RegularSpace, Projection};
use geometry::dimensions::{Partitioned, Continuous};

/// Linearly partitioned function representation.
pub struct UniformGrid {
    weights: Array2<f64>,
    input_space: RegularSpace<Partitioned>,
}

impl UniformGrid {
    pub fn new(input_space: RegularSpace<Partitioned>,
               n_outputs: usize) -> Self
    {
        let n_features = input_space.span().into();

        UniformGrid {
            weights: Array2::<f64>::zeros((n_features, n_outputs)),
            input_space: input_space,
        }
    }

    fn hash(&self, input: &[f64]) -> usize {
        let mut in_it = input.iter().rev();
        let mut d_it = self.input_space.iter().rev();

        let acc = in_it.next().unwrap().project(d_it.next().unwrap());

        d_it.zip(in_it).fold(acc, |acc, (d, v)| {
            let i = v.project(d);

            i + d.density() * acc
        })
    }
}

impl Function<Vec<f64>, f64> for UniformGrid {
    fn evaluate(&self, input: &Vec<f64>) -> f64 {
        // Hash the input down to an index:
        self.weights[[self.hash(input), 0]]
    }
}

impl Function<Vec<f64>, Vec<f64>> for UniformGrid {
    fn evaluate(&self, input: &Vec<f64>) -> Vec<f64> {
        // Hash the input down to a row index:
        let ri = self.hash(input);

        // Get the row slice and convert to a Vec<f64>:
        self.weights.row(ri).to_vec()
    }
}

impl Parameterised<Vec<f64>, f64> for UniformGrid {
    fn update(&mut self, input: &Vec<f64>, error: f64) {
        let index = self.hash(input);

        unsafe {
            *self.weights.uget_mut((index, 0)) += error
        }
    }

    fn equivalent(&self, other: &Self) -> bool {
        self.weights.shape() == other.weights.shape()
    }
}

impl Parameterised<Vec<f64>, Vec<f64>> for UniformGrid {
    fn update(&mut self, input: &Vec<f64>, errors: Vec<f64>) {
        // Hash the input down to a row index:
        let ri = self.hash(input);

        // Get the row slice and perform update via memcpy:
        self.weights.row_mut(ri).scaled_add(1.0, &arr1(&errors));
    }

    fn equivalent(&self, other: &Self) -> bool {
        <Self as Parameterised<Vec<f64>, f64>>::equivalent(self, other)
    }
}

impl Linear<RegularSpace<Continuous>> for UniformGrid
{
    fn phi(&self, input: &Vec<f64>) -> Array1<f64> {
        let mut p = Array1::<f64>::zeros(self.weights.rows());
        p[self.hash(input)] = 1.0;

        p
    }
}

impl VFunction<RegularSpace<Continuous>> for UniformGrid
{
    fn evaluate_phi(&self, phi: &Array1<f64>) -> f64 {
        dot(self.weights.column(0).as_slice().unwrap(),
            phi.as_slice().unwrap())
    }

    fn update_phi(&mut self, phi: &Array1<f64>, error: f64) {
        self.weights.column_mut(0).scaled_add(error, phi);
    }
}

impl QFunction<RegularSpace<Continuous>> for UniformGrid
{
    fn evaluate_action(&self, input: &Vec<f64>, action: usize) -> f64 {
        // Hash the input down to a row index:
        let ri = self.hash(input);

        self.weights[[ri, action]]
    }

    fn update_action(&mut self, input: &Vec<f64>, action: usize, error: f64) {
        let index = self.hash(input);

        unsafe {
            *self.weights.uget_mut((index, action)) += error
        }
    }
}

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

    use fa::{Function, Parameterised};
    use geometry::RegularSpace;
    use geometry::dimensions::Partitioned;

    #[test]
    fn test_update_eval() {
        let mut ds = RegularSpace::new();
        ds = ds.push(Partitioned::new(0.0, 10.0, 10));

        let mut t = UniformGrid::new(ds, 1);

        t.update(&vec![1.5], 25.5);

        let out: f64 = t.evaluate(&vec![1.5]);
        assert_eq!(out, 25.5);

        t.update(&vec![1.5], -12.75);

        let out: f64 = t.evaluate(&vec![1.5]);
        assert_eq!(out, 12.75);
    }

    #[test]
    fn test_generalisation() {
        let mut ds = RegularSpace::new();
        ds = ds.push(Partitioned::new(0.0, 10.0, 10));

        let mut t = UniformGrid::new(ds, 1);

        t.update(&vec![0.5], vec![1.2]);

        for i in 1..10 {
            let out: f64 = t.evaluate(&vec![i as f64 / 10.0]);
            assert_eq!(out, 1.2);
        }
    }

    #[test]
    fn test_1d() {
        let mut ds = RegularSpace::new();
        ds = ds.push(Partitioned::new(0.0, 10.0, 10));

        let mut t = UniformGrid::new(ds, 1);

        for i in 0..10 {
            let input: Vec<f64> = vec![i as u32 as f64];

            let out: f64 = t.evaluate(&input);
            assert_eq!(out, 0.0);

            t.update(&input, vec![1.0]);

            let out: f64 = t.evaluate(&input);
            assert_eq!(out, 1.0);
        }
    }

    #[test]
    fn test_2d() {
        let mut ds = RegularSpace::new();
        ds = ds.push(Partitioned::new(0.0, 10.0, 10));
        ds = ds.push(Partitioned::new(0.0, 10.0, 10));

        let mut t = UniformGrid::new(ds, 1);

        for i in 0..10 {
            for j in 0..10 {
                let input: Vec<f64> = vec![i as u32 as f64, j as u32 as f64];

                let out: f64 = t.evaluate(&input);
                assert_eq!(out, 0.0);

                t.update(&input, vec![1.0]);

                let out: f64 = t.evaluate(&input);
                assert_eq!(out, 1.0);
            }
        }
    }

    #[test]
    fn test_3d() {
        let mut ds = RegularSpace::new();
        ds = ds.push(Partitioned::new(0.0, 10.0, 10));
        ds = ds.push(Partitioned::new(0.0, 10.0, 10));
        ds = ds.push(Partitioned::new(0.0, 10.0, 10));

        let mut t = UniformGrid::new(ds, 1);

        for i in 0..10 {
            for j in 0..10 {
                for k in 0..10 {
                    let input: Vec<f64> = vec![i as u32 as f64, j as u32 as f64, k as u32 as f64];

                    let out: f64 = t.evaluate(&input);
                    assert_eq!(out, 0.0);

                    t.update(&input, vec![1.0]);

                    let out: f64 = t.evaluate(&input);
                    assert_eq!(out, 1.0);
                }
            }
        }
    }
}
<commit_msg>Add test for multiple outputs for UniformGrid<commit_after>use super::{Function, Parameterised, Linear, VFunction, QFunction};

use utils::dot;
use ndarray::{arr1, Array1, Array2};
use geometry::{Span, Space, RegularSpace, Projection};
use geometry::dimensions::{Partitioned, Continuous};

/// Linearly partitioned function representation.
pub struct UniformGrid {
    weights: Array2<f64>,
    input_space: RegularSpace<Partitioned>,
}

impl UniformGrid {
    pub fn new(input_space: RegularSpace<Partitioned>,
               n_outputs: usize) -> Self
    {
        let n_features = input_space.span().into();

        UniformGrid {
            weights: Array2::<f64>::zeros((n_features, n_outputs)),
            input_space: input_space,
        }
    }

    fn hash(&self, input: &[f64]) -> usize {
        let mut in_it = input.iter().rev();
        let mut d_it = self.input_space.iter().rev();

        let acc = in_it.next().unwrap().project(d_it.next().unwrap());

        d_it.zip(in_it).fold(acc, |acc, (d, v)| {
            let i = v.project(d);

            i + d.density() * acc
        })
    }
}

impl Function<Vec<f64>, f64> for UniformGrid {
    fn evaluate(&self, input: &Vec<f64>) -> f64 {
        // Hash the input down to an index:
        self.weights[[self.hash(input), 0]]
    }
}

impl Function<Vec<f64>, Vec<f64>> for UniformGrid {
    fn evaluate(&self, input: &Vec<f64>) -> Vec<f64> {
        // Hash the input down to a row index:
        let ri = self.hash(input);

        // Get the row slice and convert to a Vec<f64>:
        self.weights.row(ri).to_vec()
    }
}

impl Parameterised<Vec<f64>, f64> for UniformGrid {
    fn update(&mut self, input: &Vec<f64>, error: f64) {
        let index = self.hash(input);

        unsafe {
            *self.weights.uget_mut((index, 0)) += error
        }
    }

    fn equivalent(&self, other: &Self) -> bool {
        self.weights.shape() == other.weights.shape()
    }
}

impl Parameterised<Vec<f64>, Vec<f64>> for UniformGrid {
    fn update(&mut self, input: &Vec<f64>, errors: Vec<f64>) {
        // Hash the input down to a row index:
        let ri = self.hash(input);

        // Get the row slice and perform update via memcpy:
        self.weights.row_mut(ri).scaled_add(1.0, &arr1(&errors));
    }

    fn equivalent(&self, other: &Self) -> bool {
        <Self as Parameterised<Vec<f64>, f64>>::equivalent(self, other)
    }
}

impl Linear<RegularSpace<Continuous>> for UniformGrid
{
    fn phi(&self, input: &Vec<f64>) -> Array1<f64> {
        let mut p = Array1::<f64>::zeros(self.weights.rows());
        p[self.hash(input)] = 1.0;

        p
    }
}

impl VFunction<RegularSpace<Continuous>> for UniformGrid
{
    fn evaluate_phi(&self, phi: &Array1<f64>) -> f64 {
        dot(self.weights.column(0).as_slice().unwrap(),
            phi.as_slice().unwrap())
    }

    fn update_phi(&mut self, phi: &Array1<f64>, error: f64) {
        self.weights.column_mut(0).scaled_add(error, phi);
    }
}

impl QFunction<RegularSpace<Continuous>> for UniformGrid
{
    fn evaluate_action(&self, input: &Vec<f64>, action: usize) -> f64 {
        // Hash the input down to a row index:
        let ri = self.hash(input);

        self.weights[[ri, action]]
    }

    fn update_action(&mut self, input: &Vec<f64>, action: usize, error: f64) {
        let index = self.hash(input);

        unsafe {
            *self.weights.uget_mut((index, action)) += error
        }
    }
}

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

    use fa::{Function, Parameterised, VFunction, QFunction};
    use geometry::RegularSpace;
    use geometry::dimensions::Partitioned;

    #[test]
    fn test_update_eval() {
        let mut ds = RegularSpace::new();
        ds = ds.push(Partitioned::new(0.0, 10.0, 10));

        let mut t = UniformGrid::new(ds, 1);

        t.update(&vec![1.5], 25.5);

        let out: f64 = t.evaluate(&vec![1.5]);
        assert_eq!(out, 25.5);

        t.update(&vec![1.5], -12.75);

        let out: f64 = t.evaluate(&vec![1.5]);
        assert_eq!(out, 12.75);
    }

    #[test]
    fn test_multiple_outputs() {
        let mut ds = RegularSpace::new();
        ds = ds.push(Partitioned::new(0.0, 10.0, 10));

        let mut t = UniformGrid::new(ds, 2);

        t.update(&vec![1.5], vec![-20.1, 25.5]);

        let out: Vec<f64> = t.evaluate(&vec![1.5]);
        assert_eq!(out, vec![-20.1, 25.5]);

        t.update_action(&vec![1.5], 0, 20.1);

        let out: f64 = t.evaluate_action(&vec![1.5], 0);
        assert_eq!(out, 0.0);
    }

    #[test]
    fn test_generalisation() {
        let mut ds = RegularSpace::new();
        ds = ds.push(Partitioned::new(0.0, 10.0, 10));

        let mut t = UniformGrid::new(ds, 1);

        t.update(&vec![0.5], vec![1.2]);

        for i in 1..10 {
            let out: f64 = t.evaluate(&vec![i as f64 / 10.0]);
            assert_eq!(out, 1.2);
        }
    }

    #[test]
    fn test_1d() {
        let mut ds = RegularSpace::new();
        ds = ds.push(Partitioned::new(0.0, 10.0, 10));

        let mut t = UniformGrid::new(ds, 1);

        for i in 0..10 {
            let input: Vec<f64> = vec![i as u32 as f64];

            let out: f64 = t.evaluate(&input);
            assert_eq!(out, 0.0);

            t.update(&input, vec![1.0]);

            let out: f64 = t.evaluate(&input);
            assert_eq!(out, 1.0);
        }
    }

    #[test]
    fn test_2d() {
        let mut ds = RegularSpace::new();
        ds = ds.push(Partitioned::new(0.0, 10.0, 10));
        ds = ds.push(Partitioned::new(0.0, 10.0, 10));

        let mut t = UniformGrid::new(ds, 1);

        for i in 0..10 {
            for j in 0..10 {
                let input: Vec<f64> = vec![i as u32 as f64, j as u32 as f64];

                let out: f64 = t.evaluate(&input);
                assert_eq!(out, 0.0);

                t.update(&input, vec![1.0]);

                let out: f64 = t.evaluate(&input);
                assert_eq!(out, 1.0);
            }
        }
    }

    #[test]
    fn test_3d() {
        let mut ds = RegularSpace::new();
        ds = ds.push(Partitioned::new(0.0, 10.0, 10));
        ds = ds.push(Partitioned::new(0.0, 10.0, 10));
        ds = ds.push(Partitioned::new(0.0, 10.0, 10));

        let mut t = UniformGrid::new(ds, 1);

        for i in 0..10 {
            for j in 0..10 {
                for k in 0..10 {
                    let input: Vec<f64> = vec![i as u32 as f64, j as u32 as f64, k as u32 as f64];

                    let out: f64 = t.evaluate(&input);
                    assert_eq!(out, 0.0);

                    t.update(&input, vec![1.0]);

                    let out: f64 = t.evaluate(&input);
                    assert_eq!(out, 1.0);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//!
//! This module defines the external interface for controlling one particular
//! instance of a mock server.
//!

use crate::hyper_server;
use crate::matching::MatchResult;

use pact_matching::models::{Pact, Interaction, PactSpecification};
use std::ffi::CString;
use std::path::PathBuf;
use std::io;
use std::sync::{Arc, Mutex};
use serde_json::json;
use futures::future::Future;
use lazy_static::*;

lazy_static! {
    static ref PACT_FILE_MUTEX: Mutex<()> = Mutex::new(());
}

/// Struct to represent the "foreground" part of mock server
#[derive(Debug)]
pub struct MockServer {
    /// Mock server unique ID
    pub id: String,
    /// Address the mock server is running on
    pub addr: std::net::SocketAddr,
    /// List of resources that need to be cleaned up when the mock server completes
    pub resources: Vec<CString>,
    /// Pact that this mock server is based on
    pub pact: Pact,
    /// Receiver of match results
    matches: Arc<Mutex<Vec<MatchResult>>>,
    /// Shutdown signal
    shutdown_tx: Option<futures::channel::oneshot::Sender<()>>
}

impl MockServer {
    /// Create a new mock server, consisting of its state (self) and its executable server future.
    pub async fn new(
        id: String,
        pact: Pact,
        addr: std::net::SocketAddr
    ) -> Result<(MockServer, impl Future<Output = ()>), String> {
        let (shutdown_tx, shutdown_rx) = futures::channel::oneshot::channel();
        let matches = Arc::new(Mutex::new(vec![]));

        let (future, socket_addr) = hyper_server::create_and_bind(
            pact.clone(),
            addr,
            async {
                shutdown_rx.await.ok();
            },
            matches.clone()
        )
            .await
            .map_err(|err| format!("Could not start server: {}", err))?;

        let mock_server = MockServer {
            id: id.clone(),
            addr: socket_addr,
            resources: vec![],
            pact: pact,
            matches: matches,
            shutdown_tx: Some(shutdown_tx)
        };

        Ok((mock_server, future))
    }

    /// Send the shutdown signal to the server
    pub fn shutdown(&mut self) -> Result<(), String> {
        match self.shutdown_tx.take() {
            Some(sender) => {
                match sender.send(()) {
                    Ok(()) => Ok(()),
                    Err(_) => Err("Problem sending shutdown signal to mock server".into())
                }
            },
            _ => Err("Mock server already shut down".into())
        }
    }

    /// Converts this mock server to a `Value` struct
    pub fn to_json(&self) -> serde_json::Value {
        json!({
            "id" : json!(self.id.clone()),
            "port" : json!(self.addr.port() as u64),
            "provider" : json!(self.pact.provider.name.clone()),
            "status" : json!(if self.mismatches().is_empty() { "ok" } else { "error" })
        })
    }

    /// Returns all collected matches
    pub fn matches(&self) -> Vec<MatchResult> {
        self.matches.lock().unwrap().clone()
    }

    /// Returns all the mismatches that have occurred with this mock server
    pub fn mismatches(&self) -> Vec<MatchResult> {
        let matches = self.matches();
        let mismatches = matches.iter()
            .filter(|m| !m.matched())
            .map(|m| m.clone());
        let interactions: Vec<&Interaction> = matches.iter().map(|m| {
            match *m {
                MatchResult::RequestMatch(ref interaction) => Some(interaction),
                MatchResult::RequestMismatch(ref interaction, _) => Some(interaction),
                MatchResult::RequestNotFound(_) => None,
                MatchResult::MissingRequest(_) => None
            }
        }).filter(|o| o.is_some()).map(|o| o.unwrap()).collect();
        let missing = self.pact.interactions.iter()
            .filter(|i| !interactions.contains(i))
            .map(|i| MatchResult::MissingRequest(i.clone()));
        mismatches.chain(missing).collect()
    }

    /// Mock server writes its pact out to the provided directory
    pub fn write_pact(&self, output_path: &Option<String>) -> io::Result<()> {
        let pact_file_name = self.pact.default_file_name();
        let filename = match *output_path {
            Some(ref path) => {
                let mut path = PathBuf::from(path);
                path.push(pact_file_name);
                path
            },
            None => PathBuf::from(pact_file_name)
        };

        log::info!("Writing pact out to '{}'", filename.display());

        // Lock so that no two threads can read/write pact file at the same time.
        // TODO: Could use a fs-based lock in case multiple processes are doing
        // this concurrently?
        let _file_lock = PACT_FILE_MUTEX.lock().unwrap();

        match self.pact.write_pact(filename.as_path(), PactSpecification::V3) {
            Ok(_) => Ok(()),
            Err(err) => {
                log::warn!("Failed to write pact to file - {}", err);
                Err(err)
            }
        }
    }

    /// Returns the URL of the mock server
    pub fn url(&self) -> String {
        format!("http://localhost:{}", self.addr.port())
    }
}

impl Clone for MockServer {
    /// Make a clone all of the MockServer fields.
    /// Note that the clone of the original server cannot be shut down directly.
    fn clone(&self) -> MockServer {
        MockServer {
            id: self.id.clone(),
            addr: self.addr,
            resources: vec![],
            pact: self.pact.clone(),
            matches: self.matches.clone(),
            shutdown_tx: None
        }
    }
}
<commit_msg>pact_mock_server: Use std future trait instead of futures-rs<commit_after>//!
//! This module defines the external interface for controlling one particular
//! instance of a mock server.
//!

use crate::hyper_server;
use crate::matching::MatchResult;

use pact_matching::models::{Pact, Interaction, PactSpecification};
use std::ffi::CString;
use std::path::PathBuf;
use std::io;
use std::sync::{Arc, Mutex};
use serde_json::json;
use lazy_static::*;

lazy_static! {
    static ref PACT_FILE_MUTEX: Mutex<()> = Mutex::new(());
}

/// Struct to represent the "foreground" part of mock server
#[derive(Debug)]
pub struct MockServer {
    /// Mock server unique ID
    pub id: String,
    /// Address the mock server is running on
    pub addr: std::net::SocketAddr,
    /// List of resources that need to be cleaned up when the mock server completes
    pub resources: Vec<CString>,
    /// Pact that this mock server is based on
    pub pact: Pact,
    /// Receiver of match results
    matches: Arc<Mutex<Vec<MatchResult>>>,
    /// Shutdown signal
    shutdown_tx: Option<futures::channel::oneshot::Sender<()>>
}

impl MockServer {
    /// Create a new mock server, consisting of its state (self) and its executable server future.
    pub async fn new(
        id: String,
        pact: Pact,
        addr: std::net::SocketAddr
    ) -> Result<(MockServer, impl std::future::Future<Output = ()>), String> {
        let (shutdown_tx, shutdown_rx) = futures::channel::oneshot::channel();
        let matches = Arc::new(Mutex::new(vec![]));

        let (future, socket_addr) = hyper_server::create_and_bind(
            pact.clone(),
            addr,
            async {
                shutdown_rx.await.ok();
            },
            matches.clone()
        )
            .await
            .map_err(|err| format!("Could not start server: {}", err))?;

        let mock_server = MockServer {
            id: id.clone(),
            addr: socket_addr,
            resources: vec![],
            pact: pact,
            matches: matches,
            shutdown_tx: Some(shutdown_tx)
        };

        Ok((mock_server, future))
    }

    /// Send the shutdown signal to the server
    pub fn shutdown(&mut self) -> Result<(), String> {
        match self.shutdown_tx.take() {
            Some(sender) => {
                match sender.send(()) {
                    Ok(()) => Ok(()),
                    Err(_) => Err("Problem sending shutdown signal to mock server".into())
                }
            },
            _ => Err("Mock server already shut down".into())
        }
    }

    /// Converts this mock server to a `Value` struct
    pub fn to_json(&self) -> serde_json::Value {
        json!({
            "id" : json!(self.id.clone()),
            "port" : json!(self.addr.port() as u64),
            "provider" : json!(self.pact.provider.name.clone()),
            "status" : json!(if self.mismatches().is_empty() { "ok" } else { "error" })
        })
    }

    /// Returns all collected matches
    pub fn matches(&self) -> Vec<MatchResult> {
        self.matches.lock().unwrap().clone()
    }

    /// Returns all the mismatches that have occurred with this mock server
    pub fn mismatches(&self) -> Vec<MatchResult> {
        let matches = self.matches();
        let mismatches = matches.iter()
            .filter(|m| !m.matched())
            .map(|m| m.clone());
        let interactions: Vec<&Interaction> = matches.iter().map(|m| {
            match *m {
                MatchResult::RequestMatch(ref interaction) => Some(interaction),
                MatchResult::RequestMismatch(ref interaction, _) => Some(interaction),
                MatchResult::RequestNotFound(_) => None,
                MatchResult::MissingRequest(_) => None
            }
        }).filter(|o| o.is_some()).map(|o| o.unwrap()).collect();
        let missing = self.pact.interactions.iter()
            .filter(|i| !interactions.contains(i))
            .map(|i| MatchResult::MissingRequest(i.clone()));
        mismatches.chain(missing).collect()
    }

    /// Mock server writes its pact out to the provided directory
    pub fn write_pact(&self, output_path: &Option<String>) -> io::Result<()> {
        let pact_file_name = self.pact.default_file_name();
        let filename = match *output_path {
            Some(ref path) => {
                let mut path = PathBuf::from(path);
                path.push(pact_file_name);
                path
            },
            None => PathBuf::from(pact_file_name)
        };

        log::info!("Writing pact out to '{}'", filename.display());

        // Lock so that no two threads can read/write pact file at the same time.
        // TODO: Could use a fs-based lock in case multiple processes are doing
        // this concurrently?
        let _file_lock = PACT_FILE_MUTEX.lock().unwrap();

        match self.pact.write_pact(filename.as_path(), PactSpecification::V3) {
            Ok(_) => Ok(()),
            Err(err) => {
                log::warn!("Failed to write pact to file - {}", err);
                Err(err)
            }
        }
    }

    /// Returns the URL of the mock server
    pub fn url(&self) -> String {
        format!("http://localhost:{}", self.addr.port())
    }
}

impl Clone for MockServer {
    /// Make a clone all of the MockServer fields.
    /// Note that the clone of the original server cannot be shut down directly.
    fn clone(&self) -> MockServer {
        MockServer {
            id: self.id.clone(),
            addr: self.addr,
            resources: vec![],
            pact: self.pact.clone(),
            matches: self.matches.clone(),
            shutdown_tx: None
        }
    }
}
<|endoftext|>


<commit_before>//! A control flow graph represented as mappings of extended basic blocks to their predecessors
//! and successors. Successors are represented as extended basic blocks while predecessors are
//! represented by basic blocks.
//! BasicBlocks are denoted by tuples of EBB and branch/jump instructions. Each predecessor
//! tuple corresponds to the end of a basic block.
//!
//! ```c
//!     Ebb0:
//!         ...          ; beginning of basic block
//!
//!         ...
//!
//!         brz vx, Ebb1 ; end of basic block
//!
//!         ...          ; beginning of basic block
//!
//!         ...
//!
//!         jmp Ebb2     ; end of basic block
//! ```
//!
//! Here Ebb1 and Ebb2 would each have a single predecessor denoted as (Ebb0, `brz vx, Ebb1`)
//! and (Ebb0, `jmp Ebb2`) respectively.

use ir::Function;
use ir::entities::{Inst, Ebb};
use ir::instructions::BranchInfo;
use entity_map::EntityMap;
use std::collections::HashSet;

/// A basic block denoted by its enclosing Ebb and last instruction.
pub type BasicBlock = (Ebb, Inst);

/// A container for the successors and predecessors of some Ebb.
#[derive(Debug, Clone, Default)]
pub struct CFGNode {
    pub successors: Vec<Ebb>,
    pub predecessors: Vec<BasicBlock>,
}

impl CFGNode {
    pub fn new() -> CFGNode {
        CFGNode {
            successors: Vec::new(),
            predecessors: Vec::new(),
        }
    }
}

/// The Control Flow Graph maintains a mapping of ebbs to their predecessors
/// and successors where predecessors are basic blocks and successors are
/// extended basic blocks.
#[derive(Debug)]
pub struct ControlFlowGraph {
    entry_block: Option<Ebb>,
    data: EntityMap<Ebb, CFGNode>,
}

impl ControlFlowGraph {
    /// During initialization mappings will be generated for any existing
    /// blocks within the CFG's associated function.
    pub fn new(func: &Function) -> ControlFlowGraph {

        let mut cfg = ControlFlowGraph {
            data: EntityMap::with_capacity(func.dfg.num_ebbs()),
            entry_block: func.layout.entry_block(),
        };

        for ebb in &func.layout {
            for inst in func.layout.ebb_insts(ebb) {
                match func.dfg[inst].analyze_branch() {
                    BranchInfo::SingleDest(dest, _) => {
                        cfg.add_edge((ebb, inst), dest);
                    }
                    BranchInfo::Table(jt) => {
                        for (_, dest) in func.jump_tables[jt].entries() {
                            cfg.add_edge((ebb, inst), dest);
                        }
                    }
                    BranchInfo::NotABranch => {}
                }
            }
        }
        cfg
    }

    fn add_edge(&mut self, from: BasicBlock, to: Ebb) {
        self.data[from.0].successors.push(to);
        self.data[to].predecessors.push(from);
    }

    pub fn get_predecessors(&self, ebb: Ebb) -> &Vec<BasicBlock> {
        &self.data[ebb].predecessors
    }

    pub fn get_successors(&self, ebb: Ebb) -> &Vec<Ebb> {
        &self.data[ebb].successors
    }

    /// Return ebbs in reverse postorder along with a mapping of
    /// the ebb to its [post]order of visitation.
    pub fn reverse_postorder_ebbs(&self) -> EntityMap<Ebb, usize> {
        let entry_block = match self.entry_block {
            None => {
                return EntityMap::new();
            }
            Some(eb) => eb,
        };

        let mut grey = HashSet::new();
        let mut black = HashSet::new();
        let mut stack = vec![entry_block.clone()];
        let mut postorder = Vec::new();

        while !stack.is_empty() {
            let node = stack.pop().unwrap();
            if !grey.contains(&node) {
                // This is a white node. Mark it as gray.
                grey.insert(node);
                stack.push(node);
                // Get any children we’ve never seen before.
                for child in self.get_successors(node) {
                    if !grey.contains(child) {
                        stack.push(child.clone());
                    }
                }
            } else if !black.contains(&node) {
                postorder.push(node.clone());
                black.insert(node.clone());
            }
        }
        postorder.reverse();

        let mut result = EntityMap::with_capacity(postorder.len());
        for (offset, ebb) in postorder.iter().enumerate() {
            let i = postorder.len() - offset;
            result[ebb.clone()] = i;
        }
        result
    }

    pub fn len(&self) -> usize {
        self.data.len()
    }

    pub fn predecessors_iter(&self) -> CFGPredecessorsIter {
        CFGPredecessorsIter {
            cur: 0,
            cfg: &self,
        }
    }
}

/// Iterate through every mapping of ebb to predecessors in the CFG
pub struct CFGPredecessorsIter<'a> {
    cfg: &'a ControlFlowGraph,
    cur: usize,
}

impl<'a> Iterator for CFGPredecessorsIter<'a> {
    type Item = (Ebb, &'a Vec<BasicBlock>);

    fn next(&mut self) -> Option<Self::Item> {
        if self.cur < self.cfg.len() {
            let ebb = Ebb::with_number(self.cur as u32).unwrap();
            let bbs = self.cfg.get_predecessors(ebb);
            self.cur += 1;
            Some((ebb, bbs))
        } else {
            None
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use ir::Function;

    use test_utils::make_inst;

    #[test]
    fn empty() {
        let func = Function::new();
        let cfg = ControlFlowGraph::new(&func);
        assert_eq!(None, cfg.predecessors_iter().next());
    }

    #[test]
    fn no_predecessors() {
        let mut func = Function::new();
        let ebb0 = func.dfg.make_ebb();
        let ebb1 = func.dfg.make_ebb();
        let ebb2 = func.dfg.make_ebb();
        func.layout.append_ebb(ebb0);
        func.layout.append_ebb(ebb1);
        func.layout.append_ebb(ebb2);

        let cfg = ControlFlowGraph::new(&func);
        let nodes = cfg.predecessors_iter().collect::<Vec<_>>();
        assert_eq!(nodes.len(), 3);

        let mut fun_ebbs = func.layout.ebbs();
        for (ebb, predecessors) in nodes {
            assert_eq!(ebb, fun_ebbs.next().unwrap());
            assert_eq!(predecessors.len(), 0);
            assert_eq!(predecessors.len(), 0);
            assert_eq!(cfg.get_successors(ebb).len(), 0);
        }
    }

    #[test]
    fn branches_and_jumps() {
        let mut func = Function::new();
        let ebb0 = func.dfg.make_ebb();
        let ebb1 = func.dfg.make_ebb();
        let ebb2 = func.dfg.make_ebb();
        func.layout.append_ebb(ebb0);
        func.layout.append_ebb(ebb1);
        func.layout.append_ebb(ebb2);

        let br_ebb0_ebb2 = make_inst::branch(&mut func, ebb2);
        func.layout.append_inst(br_ebb0_ebb2, ebb0);

        let jmp_ebb0_ebb1 = make_inst::jump(&mut func, ebb1);
        func.layout.append_inst(jmp_ebb0_ebb1, ebb0);

        let br_ebb1_ebb1 = make_inst::branch(&mut func, ebb1);
        func.layout.append_inst(br_ebb1_ebb1, ebb1);

        let jmp_ebb1_ebb2 = make_inst::jump(&mut func, ebb2);
        func.layout.append_inst(jmp_ebb1_ebb2, ebb1);

        let cfg = ControlFlowGraph::new(&func);

        let ebb0_predecessors = cfg.get_predecessors(ebb0);
        let ebb1_predecessors = cfg.get_predecessors(ebb1);
        let ebb2_predecessors = cfg.get_predecessors(ebb2);

        let ebb0_successors = cfg.get_successors(ebb0);
        let ebb1_successors = cfg.get_successors(ebb1);
        let ebb2_successors = cfg.get_successors(ebb2);

        assert_eq!(ebb0_predecessors.len(), 0);
        assert_eq!(ebb1_predecessors.len(), 2);
        assert_eq!(ebb2_predecessors.len(), 2);

        assert_eq!(ebb1_predecessors.contains(&(ebb0, jmp_ebb0_ebb1)), true);
        assert_eq!(ebb1_predecessors.contains(&(ebb1, br_ebb1_ebb1)), true);
        assert_eq!(ebb2_predecessors.contains(&(ebb0, br_ebb0_ebb2)), true);
        assert_eq!(ebb2_predecessors.contains(&(ebb1, jmp_ebb1_ebb2)), true);

        assert_eq!(ebb0_successors.len(), 2);
        assert_eq!(ebb1_successors.len(), 2);
        assert_eq!(ebb2_successors.len(), 0);

        assert_eq!(ebb0_successors.contains(&ebb1), true);
        assert_eq!(ebb0_successors.contains(&ebb2), true);
        assert_eq!(ebb1_successors.contains(&ebb1), true);
        assert_eq!(ebb1_successors.contains(&ebb2), true);
    }
}
<commit_msg>Remove the cfg::predecessors_iter() method and iterator.<commit_after>//! A control flow graph represented as mappings of extended basic blocks to their predecessors
//! and successors. Successors are represented as extended basic blocks while predecessors are
//! represented by basic blocks.
//! BasicBlocks are denoted by tuples of EBB and branch/jump instructions. Each predecessor
//! tuple corresponds to the end of a basic block.
//!
//! ```c
//!     Ebb0:
//!         ...          ; beginning of basic block
//!
//!         ...
//!
//!         brz vx, Ebb1 ; end of basic block
//!
//!         ...          ; beginning of basic block
//!
//!         ...
//!
//!         jmp Ebb2     ; end of basic block
//! ```
//!
//! Here Ebb1 and Ebb2 would each have a single predecessor denoted as (Ebb0, `brz vx, Ebb1`)
//! and (Ebb0, `jmp Ebb2`) respectively.

use ir::Function;
use ir::entities::{Inst, Ebb};
use ir::instructions::BranchInfo;
use entity_map::EntityMap;
use std::collections::HashSet;

/// A basic block denoted by its enclosing Ebb and last instruction.
pub type BasicBlock = (Ebb, Inst);

/// A container for the successors and predecessors of some Ebb.
#[derive(Debug, Clone, Default)]
pub struct CFGNode {
    pub successors: Vec<Ebb>,
    pub predecessors: Vec<BasicBlock>,
}

impl CFGNode {
    pub fn new() -> CFGNode {
        CFGNode {
            successors: Vec::new(),
            predecessors: Vec::new(),
        }
    }
}

/// The Control Flow Graph maintains a mapping of ebbs to their predecessors
/// and successors where predecessors are basic blocks and successors are
/// extended basic blocks.
#[derive(Debug)]
pub struct ControlFlowGraph {
    entry_block: Option<Ebb>,
    data: EntityMap<Ebb, CFGNode>,
}

impl ControlFlowGraph {
    /// During initialization mappings will be generated for any existing
    /// blocks within the CFG's associated function.
    pub fn new(func: &Function) -> ControlFlowGraph {

        let mut cfg = ControlFlowGraph {
            data: EntityMap::with_capacity(func.dfg.num_ebbs()),
            entry_block: func.layout.entry_block(),
        };

        for ebb in &func.layout {
            for inst in func.layout.ebb_insts(ebb) {
                match func.dfg[inst].analyze_branch() {
                    BranchInfo::SingleDest(dest, _) => {
                        cfg.add_edge((ebb, inst), dest);
                    }
                    BranchInfo::Table(jt) => {
                        for (_, dest) in func.jump_tables[jt].entries() {
                            cfg.add_edge((ebb, inst), dest);
                        }
                    }
                    BranchInfo::NotABranch => {}
                }
            }
        }
        cfg
    }

    fn add_edge(&mut self, from: BasicBlock, to: Ebb) {
        self.data[from.0].successors.push(to);
        self.data[to].predecessors.push(from);
    }

    pub fn get_predecessors(&self, ebb: Ebb) -> &Vec<BasicBlock> {
        &self.data[ebb].predecessors
    }

    pub fn get_successors(&self, ebb: Ebb) -> &Vec<Ebb> {
        &self.data[ebb].successors
    }

    /// Return ebbs in reverse postorder along with a mapping of
    /// the ebb to its [post]order of visitation.
    pub fn reverse_postorder_ebbs(&self) -> EntityMap<Ebb, usize> {
        let entry_block = match self.entry_block {
            None => {
                return EntityMap::new();
            }
            Some(eb) => eb,
        };

        let mut grey = HashSet::new();
        let mut black = HashSet::new();
        let mut stack = vec![entry_block.clone()];
        let mut postorder = Vec::new();

        while !stack.is_empty() {
            let node = stack.pop().unwrap();
            if !grey.contains(&node) {
                // This is a white node. Mark it as gray.
                grey.insert(node);
                stack.push(node);
                // Get any children we’ve never seen before.
                for child in self.get_successors(node) {
                    if !grey.contains(child) {
                        stack.push(child.clone());
                    }
                }
            } else if !black.contains(&node) {
                postorder.push(node.clone());
                black.insert(node.clone());
            }
        }
        postorder.reverse();

        let mut result = EntityMap::with_capacity(postorder.len());
        for (offset, ebb) in postorder.iter().enumerate() {
            let i = postorder.len() - offset;
            result[ebb.clone()] = i;
        }
        result
    }

    pub fn len(&self) -> usize {
        self.data.len()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use ir::Function;

    use test_utils::make_inst;

    #[test]
    fn empty() {
        let func = Function::new();
        let cfg = ControlFlowGraph::new(&func);
        assert_eq!(cfg.reverse_postorder_ebbs().keys().count(), 0);
    }

    #[test]
    fn no_predecessors() {
        let mut func = Function::new();
        let ebb0 = func.dfg.make_ebb();
        let ebb1 = func.dfg.make_ebb();
        let ebb2 = func.dfg.make_ebb();
        func.layout.append_ebb(ebb0);
        func.layout.append_ebb(ebb1);
        func.layout.append_ebb(ebb2);

        let cfg = ControlFlowGraph::new(&func);
        let nodes =
            [ebb0, ebb1, ebb2].iter().map(|&e| (e, cfg.get_predecessors(e))).collect::<Vec<_>>();
        assert_eq!(nodes.len(), 3);

        let mut fun_ebbs = func.layout.ebbs();
        for (ebb, predecessors) in nodes {
            assert_eq!(ebb, fun_ebbs.next().unwrap());
            assert_eq!(predecessors.len(), 0);
            assert_eq!(predecessors.len(), 0);
            assert_eq!(cfg.get_successors(ebb).len(), 0);
        }
    }

    #[test]
    fn branches_and_jumps() {
        let mut func = Function::new();
        let ebb0 = func.dfg.make_ebb();
        let ebb1 = func.dfg.make_ebb();
        let ebb2 = func.dfg.make_ebb();
        func.layout.append_ebb(ebb0);
        func.layout.append_ebb(ebb1);
        func.layout.append_ebb(ebb2);

        let br_ebb0_ebb2 = make_inst::branch(&mut func, ebb2);
        func.layout.append_inst(br_ebb0_ebb2, ebb0);

        let jmp_ebb0_ebb1 = make_inst::jump(&mut func, ebb1);
        func.layout.append_inst(jmp_ebb0_ebb1, ebb0);

        let br_ebb1_ebb1 = make_inst::branch(&mut func, ebb1);
        func.layout.append_inst(br_ebb1_ebb1, ebb1);

        let jmp_ebb1_ebb2 = make_inst::jump(&mut func, ebb2);
        func.layout.append_inst(jmp_ebb1_ebb2, ebb1);

        let cfg = ControlFlowGraph::new(&func);

        let ebb0_predecessors = cfg.get_predecessors(ebb0);
        let ebb1_predecessors = cfg.get_predecessors(ebb1);
        let ebb2_predecessors = cfg.get_predecessors(ebb2);

        let ebb0_successors = cfg.get_successors(ebb0);
        let ebb1_successors = cfg.get_successors(ebb1);
        let ebb2_successors = cfg.get_successors(ebb2);

        assert_eq!(ebb0_predecessors.len(), 0);
        assert_eq!(ebb1_predecessors.len(), 2);
        assert_eq!(ebb2_predecessors.len(), 2);

        assert_eq!(ebb1_predecessors.contains(&(ebb0, jmp_ebb0_ebb1)), true);
        assert_eq!(ebb1_predecessors.contains(&(ebb1, br_ebb1_ebb1)), true);
        assert_eq!(ebb2_predecessors.contains(&(ebb0, br_ebb0_ebb2)), true);
        assert_eq!(ebb2_predecessors.contains(&(ebb1, jmp_ebb1_ebb2)), true);

        assert_eq!(ebb0_successors.len(), 2);
        assert_eq!(ebb1_successors.len(), 2);
        assert_eq!(ebb2_successors.len(), 0);

        assert_eq!(ebb0_successors.contains(&ebb1), true);
        assert_eq!(ebb0_successors.contains(&ebb2), true);
        assert_eq!(ebb1_successors.contains(&ebb1), true);
        assert_eq!(ebb1_successors.contains(&ebb2), true);
    }
}
<|endoftext|>


<commit_before>use memory::Memory;
use std::fmt;

/// Data object for a single instruction.
///
/// An instruction consists of 4 words á 4 bytes. Each instruction can be
/// intepreted as 4 address `[op_a, op_b, target, jmp]`. the
/// execution of an instruction is equivalent to
///
/// ```text
///   *target := *op_a - *op_b
///   if (*target <= 0)
///     GOTO jmp;
/// ```
///
/// `jmp` must be a multiple of the word size. If it’s not, it will be rounded
/// to the next biggest multiple of the word size.
///
/// osci is a 32-bit little endian CPU and instructions must be serialized
/// accordingly.
///
/// # Examples
/// ```
/// use osciemu::memory::SliceMemory;
/// use osciemu::instruction::Instruction;
///
/// let mut ip = 0;
/// let mut m = SliceMemory::from_slice_u32(16, &[
///     0, 4, 8, 128,
/// ]);
/// Instruction::execute_at(&mut ip, &mut m);
/// assert_eq!(ip, 128);
/// ```
pub struct Instruction {
    /// Address of operand A
    pub op_a: u32,
    /// Address of operand B
    pub op_b: u32,
    /// Address to store result of `*A - *B`
    pub target: u32,
    /// Address to jump to when `*target <= 0`
    pub jmp: u32,
}

impl Instruction {
    /// Deserializes an instruction from memory at the given address.
    pub fn from_memory(addr: usize, mem: &Memory) -> Instruction {
        Instruction {
            op_a: mem.get(addr),
            op_b: mem.get(addr + 4),
            target: mem.get(addr + 8),
            jmp: mem.get(addr + 12),
        }
    }

    /// Serializes the instruction to memory at the given adress.
    pub fn serialize(&self, addr: usize, mem: &mut Memory) {
        mem.set(addr + 0, self.op_a);
        mem.set(addr + 4, self.op_b);
        mem.set(addr + 8, self.target);
        mem.set(addr + 12, self.jmp);
    }

    /// Executes the instruction using `mem` for reads and writes and
    /// adjusting `ip` appropriately.
    pub fn execute(&self, ip: &mut usize, mem: &mut Memory) {
        let a = mem.get(self.op_a as usize) as i32;
        let b = mem.get(self.op_b as usize) as i32;
        let r = a - b;
        mem.set(self.target as usize, r as u32);
        *ip = if r <= 0 { self.jmp as usize } else { *ip + 16 }
    }

    /// Executes the instruction in memory at the given address, adjusting the
    // `ip` appropriately.
    pub fn execute_at(ip: &mut usize, mem: &mut Memory) {
        let instr = Instruction::from_memory(*ip, mem);
        instr.execute(ip, mem);
    }
}

impl fmt::Debug for Instruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "Instruction {{ op_a: 0x{:08X}, op_b: 0x{:08X}, target: 0x{:08X}, jmp: 0x{:08X} }}",
               self.op_a,
               self.op_b,
               self.target,
               self.jmp)
    }
}

#[cfg(test)]
mod tests {
    use memory::{Memory, SliceMemory};

    #[test]
    fn execute() {
        let mut ip = 0;
        let mut m = SliceMemory::from_slice_u32(16, &[1, 2, 0, 0]);
        let i1 = super::Instruction {
            op_a: 0,
            op_b: 4,
            target: 8,
            jmp: 128,
        };
        i1.execute(&mut ip, &mut m);
        assert_eq!(m.get(8) as i32, -1);
        assert_eq!(ip, 128);

        ip = 0;
        let i2 = super::Instruction {
            op_a: 4,
            op_b: 0,
            target: 8,
            jmp: 128,
        };
        i2.execute(&mut ip, &mut m);
        assert_eq!(m.get(8), 1);
        assert_eq!(ip, 16);
    }

    #[test]
    fn execute_at() {
        let mut ip = 0;
        let mut m = SliceMemory::from_slice_u32(64,
                                                &[48, 52, 56, 60, 48, 48, 56, 60, 0, 0, 0, 0, 2,
                                                  1, 0, 0]);
        super::Instruction::execute_at(&mut ip, &mut m);
        assert_eq!(m.get(56), 1);
        assert_eq!(ip, 16);
        super::Instruction::execute_at(&mut ip, &mut m);
        assert_eq!(m.get(56), 0);
        assert_eq!(ip, 60);

    }
}
<commit_msg>docs(instruction): Merge new instruction design from attempt3<commit_after>use memory::Memory;
use std::fmt;

/// Data object for a single instruction.
///
/// An instruction consists of 4 words á 32 bit. Each instruction is a set of 4
/// addresses ``op_a``, ``op_b``, ``target`` and ``jmp``. All 4 words are
/// *signed* words. If a word is negative, it is considered indirect. The
/// execution of an instruction is described by the following pseudo-code:
///
/// ```text
/// if(op_a < 0) op_a = *(-op_a)
/// if(op_b < 0) op_b = *(-op_b)
/// if(target < 0) target = *(-target)
/// if(jmp < 0) jmp = *(-jmp)
///
/// *target := *op_a - *op_b
/// if (*target <= 0)
///   GOTO jmp;
/// ```
///
/// # Examples
/// ```
/// use osciemu::memory::SliceMemory;
/// use osciemu::instruction::Instruction;
///
/// let mut ip = 0;
/// let mut m = SliceMemory::from_slice_u32(16, &[
///     0, 4, 8, 128,
/// ]);
/// Instruction::execute_at(&mut ip, &mut m);
/// assert_eq!(ip, 128);
/// ```
pub struct Instruction {
    /// Address of operand A
    pub op_a: u32,
    /// Address of operand B
    pub op_b: u32,
    /// Address to store result of `*A - *B`
    pub target: u32,
    /// Address to jump to when `*target <= 0`
    pub jmp: u32,
}

impl Instruction {
    /// Deserializes an instruction from memory at the given address.
    pub fn from_memory(addr: usize, mem: &Memory) -> Instruction {
        Instruction {
            op_a: mem.get(addr),
            op_b: mem.get(addr + 4),
            target: mem.get(addr + 8),
            jmp: mem.get(addr + 12),
        }
    }

    /// Serializes the instruction to memory at the given adress.
    pub fn serialize(&self, addr: usize, mem: &mut Memory) {
        mem.set(addr + 0, self.op_a);
        mem.set(addr + 4, self.op_b);
        mem.set(addr + 8, self.target);
        mem.set(addr + 12, self.jmp);
    }

    /// Executes the instruction using `mem` for reads and writes and
    /// adjusting `ip` appropriately.
    pub fn execute(&self, ip: &mut usize, mem: &mut Memory) {
        let a = mem.get(self.op_a as usize) as i32;
        let b = mem.get(self.op_b as usize) as i32;
        let r = a - b;
        mem.set(self.target as usize, r as u32);
        *ip = if r <= 0 { self.jmp as usize } else { *ip + 16 }
    }

    /// Executes the instruction in memory at the given address, adjusting the
    // `ip` appropriately.
    pub fn execute_at(ip: &mut usize, mem: &mut Memory) {
        let instr = Instruction::from_memory(*ip, mem);
        instr.execute(ip, mem);
    }
}

impl fmt::Debug for Instruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "Instruction {{ op_a: 0x{:08X}, op_b: 0x{:08X}, target: 0x{:08X}, jmp: 0x{:08X} }}",
               self.op_a,
               self.op_b,
               self.target,
               self.jmp)
    }
}

#[cfg(test)]
mod tests {
    use memory::{Memory, SliceMemory};

    #[test]
    fn execute() {
        let mut ip = 0;
        let mut m = SliceMemory::from_slice_u32(16, &[1, 2, 0, 0]);
        let i1 = super::Instruction {
            op_a: 0,
            op_b: 4,
            target: 8,
            jmp: 128,
        };
        i1.execute(&mut ip, &mut m);
        assert_eq!(m.get(8) as i32, -1);
        assert_eq!(ip, 128);

        ip = 0;
        let i2 = super::Instruction {
            op_a: 4,
            op_b: 0,
            target: 8,
            jmp: 128,
        };
        i2.execute(&mut ip, &mut m);
        assert_eq!(m.get(8), 1);
        assert_eq!(ip, 16);
    }

    #[test]
    fn execute_at() {
        let mut ip = 0;
        let mut m = SliceMemory::from_slice_u32(64,
                                                &[48, 52, 56, 60, 48, 48, 56, 60, 0, 0, 0, 0, 2,
                                                  1, 0, 0]);
        super::Instruction::execute_at(&mut ip, &mut m);
        assert_eq!(m.get(56), 1);
        assert_eq!(ip, 16);
        super::Instruction::execute_at(&mut ip, &mut m);
        assert_eq!(m.get(56), 0);
        assert_eq!(ip, 60);

    }
}
<|endoftext|>


<commit_before>pub use std::collections::HashMap;
pub use autograd::{Variable, VarKind, VarId};
pub use nn::ModIntf;
pub use tensor::{Tensor, TensorKind, NewSelf, NumLimits};
use utils::unsafe_lib::MutMap;

pub struct Optimizer {
    pub defaults: HashMap<&'static str, OptimVal>,
    pub state: MutMap<VarId, ParamState>,
}

#[derive(Clone)]
pub enum OptimVal {
    Bool(bool),
    Int(i32),
    Float(f32),
    Tensor(TensorKind),
    Variable(VarKind),
    Required,
}
impl From<f32> for OptimVal {
    fn from(input: f32) -> Self {
        OptimVal::Float(input)
    }
}
impl From<i32> for OptimVal {
    fn from(input: i32) -> Self {
        OptimVal::Int(input)
    }
}
impl From<bool> for OptimVal {
    fn from(input: bool) -> Self {
        OptimVal::Bool(input)
    }
}
impl From<TensorKind> for OptimVal {
    fn from(input: TensorKind) -> Self {
        OptimVal::Tensor(input)
    }
}
impl<T: NumLimits<T>> From<Tensor<T>> for OptimVal {
    fn from(input: Tensor<T>) -> Self {
        OptimVal::Tensor(input.into())
    }
}
impl From<OptimVal> for bool {
    fn from(input: OptimVal) -> Self {
        match input {
            self::OptimVal::Bool(x) => x.clone(),
            _ => unimplemented!(),
        }
    }
}
impl From<OptimVal> for f32 {
    fn from(input: OptimVal) -> Self {
        match input {
            self::OptimVal::Float(x) => x.clone(),
            _ => unimplemented!(),
        }
    }
}

impl<T: NumLimits<T>> From<OptimVal> for Tensor<T> {
    fn from(input: OptimVal) -> Self {
        match input {
            self::OptimVal::Tensor(x) => x.clone().into(),
            _ => unimplemented!(),
        }
    }
}

pub type ParamState = HashMap<&'static str, OptimVal>;

impl Optimizer {
    pub fn new(defaults: HashMap<&'static str, OptimVal>) -> Self {
        Optimizer {
            defaults: defaults,
            state: MutMap::new(),
        }
    }
}

pub trait OptIntf<T: ::tensor::NumLimits<T> + From<OptimVal>> {
    fn optimizer(&mut self) -> &mut Optimizer;
    fn zero_grad(&mut self, model: &mut ModIntf<T>) {
        // XXX figure out point of parameter groups
        model.apply_parameters(&mut |p| {
            let mut opt_grad = p.grad();
            // XXX where is this first allocated?
            if let Some(ref mut grad) = opt_grad.clone() {
                if grad.is_volatile() {
                    grad.data().zero_();
                } else {
                    let data = grad.data();
                    *opt_grad = Some(Variable::new(data.new(()).zero_().clone()));
                }
            }
        });
    }
    /* ignore largely unused closure arg to start */
    fn step(&mut self, model: &mut ModIntf<T>);
}
<commit_msg>remove dead lines<commit_after>pub use std::collections::HashMap;
pub use autograd::{Variable, VarKind, VarId};
pub use nn::ModIntf;
pub use tensor::{Tensor, TensorKind, NewSelf, NumLimits};
use utils::unsafe_lib::MutMap;

pub struct Optimizer {
    pub defaults: HashMap<&'static str, OptimVal>,
    pub state: MutMap<VarId, ParamState>,
}

#[derive(Clone)]
pub enum OptimVal {
    Bool(bool),
    Int(i32),
    Float(f32),
    Tensor(TensorKind),
    Variable(VarKind),
    Required,
}
impl From<f32> for OptimVal {
    fn from(input: f32) -> Self {
        OptimVal::Float(input)
    }
}
impl From<i32> for OptimVal {
    fn from(input: i32) -> Self {
        OptimVal::Int(input)
    }
}
impl From<bool> for OptimVal {
    fn from(input: bool) -> Self {
        OptimVal::Bool(input)
    }
}
impl From<TensorKind> for OptimVal {
    fn from(input: TensorKind) -> Self {
        OptimVal::Tensor(input)
    }
}
impl<T: NumLimits<T>> From<Tensor<T>> for OptimVal {
    fn from(input: Tensor<T>) -> Self {
        OptimVal::Tensor(input.into())
    }
}
impl From<OptimVal> for bool {
    fn from(input: OptimVal) -> Self {
        match input {
            self::OptimVal::Bool(x) => x.clone(),
            _ => unimplemented!(),
        }
    }
}
impl From<OptimVal> for f32 {
    fn from(input: OptimVal) -> Self {
        match input {
            self::OptimVal::Float(x) => x.clone(),
            _ => unimplemented!(),
        }
    }
}

impl<T: NumLimits<T>> From<OptimVal> for Tensor<T> {
    fn from(input: OptimVal) -> Self {
        match input {
            self::OptimVal::Tensor(x) => x.clone().into(),
            _ => unimplemented!(),
        }
    }
}

pub type ParamState = HashMap<&'static str, OptimVal>;

impl Optimizer {
    pub fn new(defaults: HashMap<&'static str, OptimVal>) -> Self {
        Optimizer {
            defaults: defaults,
            state: MutMap::new(),
        }
    }
}

pub trait OptIntf<T: ::tensor::NumLimits<T> + From<OptimVal>> {
    fn optimizer(&mut self) -> &mut Optimizer;
    fn zero_grad(&mut self, model: &mut ModIntf<T>) {
        // XXX figure out point of parameter groups
        model.apply_parameters(&mut |p| {
            let mut opt_grad = p.grad();
            if let Some(ref mut grad) = opt_grad.clone() {
                if grad.is_volatile() {
                    grad.data().zero_();
                } else {
                    let data = grad.data();
                    *opt_grad = Some(Variable::new(data.new(()).zero_().clone()));
                }
            }
        });
    }
    /* ignore largely unused closure arg to start */
    fn step(&mut self, model: &mut ModIntf<T>);
}
<|endoftext|>