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

//!
//! # DFA compiler
//!
//! The DFA compiler converts NDFAs into DFAs, using a DFA builder.
//!

use std::marker::PhantomData;
use std::collections::HashSet;
use std::collections::HashMap;
use std::iter::*;
use std::cmp::Ordering;

use super::dfa_builder::*;
use super::state_machine::*;

///
/// Builds a deterministic finite automaton from a NDFA
///
pub struct DfaCompiler<InputSymbol: PartialOrd+Clone, OutputSymbol, DfaType, Ndfa: StateMachine<InputSymbol, OutputSymbol>, Builder: DfaBuilder<InputSymbol, OutputSymbol, DfaType>> {
    /// State machine that is to be compiled
    ndfa: Ndfa,

    /// Builder where the state machine should be generated
    builder: Builder,

    // Phantom data to poke Rust's type system (it's too dumb to see that InputSymbol is used in both Ndfa and Builder there via the type constraint)
    #[allow(dead_code)]
    phantom: (PhantomData<InputSymbol>, PhantomData<OutputSymbol>, PhantomData<DfaType>)
}

/// Represents a state in the DFA (one or more states from the source)
#[derive(Eq, PartialEq, Hash, Clone)]
struct DfaState {
    /// List of the states from the NDFA that make up this DFA state (will be ordered if `dedupe` is called)
    source_states: Vec<StateId>
}

impl DfaState {
    /// Creates a DFA state from a set of source states
    fn create(source_states: Vec<StateId>) -> DfaState {
        let mut set = HashSet::new();
        for state in source_states {
            set.insert(state);
        }

        DfaState { source_states: Vec::from_iter(set.into_iter()) }
    }

    /// Removes any duplicate states from source_states
    fn dedupe(&mut self) {
        self.source_states.sort();
        self.source_states.dedup();
    }
}

/// Represents the transitions for a source state
struct DfaTransitions<InputSymbol, OutputSymbol: Ord> {
    /// ID of this state in the resulting DFA
    state_id: StateId,

    /// Transitions for this state (will be unique if `merge_states` is called)
    transitions: Vec<(InputSymbol, DfaState)>,

    /// The output symbols for this state (empty if this is not an accepting state)
    output: Vec<OutputSymbol>
}

impl<InputSymbol: PartialOrd+Clone, OutputSymbol: Ord> DfaTransitions<InputSymbol, OutputSymbol> {
    /// Goes through the transitions in the object and merges the states of any with the same symbol
    fn merge_states(&mut self) {
        if self.transitions.len() > 0 {
            // Order the transitions so that if two transitions have the same input symbol, they are neighbours
            self.transitions.sort_by(|a, b| {
                let &(ref symbol_a, _) = a;
                let &(ref symbol_b, _) = b;

                if let Some(result) = symbol_a.partial_cmp(symbol_b) {
                    result
                } else {
                    // Unordered input symbols won't work well
                    Ordering::Equal
                }
            });

            // For any transition that has a duplicate state, combine it with the previous state
            let mut new_transitions = vec![];
            new_transitions.push(self.transitions[0].clone());

            for transit_idx in 1..self.transitions.len() {
                let len          = new_transitions.len();
                let this_transit = &mut self.transitions[transit_idx];

                if new_transitions[len-1].0 == this_transit.0 {
                    // Same symbol: expand this state
                    new_transitions[len-1].1.source_states.append(&mut this_transit.1.source_states);
                } else {
                    // Different symbol: add new state
                    new_transitions.push(this_transit.clone());
                }
            }

            // Ensure all of the states are sorted and de-duplicated
            for transit in &mut new_transitions {
                transit.1.dedupe();
            }

            // Update the transitions
            self.transitions = new_transitions;
        }
    }

    ///
    /// Finds the output symbol that corresponds to this state
    ///
    /// Rule is that if there is more than one output symbol then the symbol whose value is ordered lowest is the output for this state
    ///
    fn output_symbol(&mut self) -> Option<&OutputSymbol> {
        if self.output.len() > 0 {
            self.output.sort();
            Some(&self.output[0])
        } else {
            None
        }
    }
}

impl<InputSymbol: PartialOrd+Clone, OutputSymbol: Ord+Clone, DfaType, Ndfa: StateMachine<InputSymbol, OutputSymbol>, Builder: DfaBuilder<InputSymbol, OutputSymbol, DfaType>>
    DfaCompiler<InputSymbol, OutputSymbol, DfaType, Ndfa, Builder> {
    ///
    /// Builds a DFA using an NDFA and a builder
    ///
    pub fn build(ndfa: Ndfa, builder: Builder) -> DfaType {
        let compiler = DfaCompiler::new(ndfa, builder);
        compiler.compile()
    }

    ///
    /// Creates a new DFA compiler using a particular builder and NDFA
    ///
    pub fn new(ndfa: Ndfa, builder: Builder) -> Self {
        DfaCompiler { ndfa: ndfa, builder: builder, phantom: (PhantomData, PhantomData, PhantomData) }
    }

    ///
    /// Compiles the NDFA into a DFA
    ///
    pub fn compile(self) -> DfaType {
        // We assume that input symbols are non-overlapping, which is not automatically the case for symbol ranges

        // Work out the state mapping for each input symbol
        let mut states       = vec![];
        let mut known_states = HashMap::new();
        let mut to_process   = vec![];

        // All state machines have state 0 as their starting state
        let state_zero = DfaState::create(vec![0]);

        known_states.insert(state_zero.clone(), 0);
        to_process.push(state_zero);

        while let Some(state) = to_process.pop() {
            // Create a new transitions object for this state
            let mut transitions = vec![];
            let mut output      = vec![];

            for source_state in &state.source_states {
                let source_transitions = self.ndfa.get_transitions_for_state(*source_state);

                for (symbol, state) in source_transitions {
                    transitions.push((symbol, DfaState::create(vec![state])));
                }

                if let Some(source_output) = self.ndfa.output_symbol_for_state(*source_state) {
                    output.push(source_output.clone());
                }
            }

            // Merge it so that we only have one transition per symbol
            let mut dfa_transitions = DfaTransitions { state_id: states.len() as StateId, transitions: transitions, output: output };
            dfa_transitions.merge_states();

            // Process any generated states that are not already in the DFA
            for &(_, ref maybe_new_state) in &dfa_transitions.transitions {
                if !known_states.contains_key(maybe_new_state) {
                    to_process.push(maybe_new_state.clone());
                }
            }

            // Store the new state
            known_states.insert(state.clone(), dfa_transitions.state_id);
            states.push(dfa_transitions);
        }

        // Build the DFA
        let mut builder = self.builder;

        for mut dfa_state in states {
            builder.start_state();

            if let Some(output_symbol) = dfa_state.output_symbol() {
                builder.accept(output_symbol.clone());
            }

            for (symbol, target_state) in dfa_state.transitions {
                builder.transition(symbol, known_states[&target_state]);
            }
        }

        // Generate the final DFA
        builder.build()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use super::super::regular_pattern::*;
    use super::super::state_machine::*;
    use super::super::symbol_range_dfa::*;
    use super::super::pattern_matcher::*;
    use super::super::symbol_reader::*;

    #[test]
    fn can_create_compiler() {
        let ndfa     = "abc".into_pattern().to_ndfa("success");
        let builder  = SymbolRangeDfaBuilder::new();

        DfaCompiler::new(ndfa, builder);
    }

    #[test]
    fn can_build_dfa() {
        // Generate a state machine from the "abc" pattern
        let ndfa     = "abc".into_pattern().to_ndfa("Success");
        let builder  = SymbolRangeDfaBuilder::new();

        let state_machine = DfaCompiler::build(ndfa, builder);

        // Read back 'abc' manually
        let mut state = More(state_machine.start());
        let mut input = "abc".read_symbols();

        while let More(this_state) = state {
            let next_state =
                if let Some(next_char) = input.next_symbol() {
                    this_state.next(next_char)
                } else {
                    this_state.finish()
                };

            state = next_state;
        }

        // Check for acceptance
        if let Accept(count, output) = state {
            assert!(count == 3);
            assert!(output == &"Success");
        } else {
            assert!(false);
        }
    }

    #[test]
    fn can_build_dfa_with_overlapping_range() {
        // Generate a state machine from the "abc" pattern
        let ndfa     = (MatchRange('b', 'b').append("a")).or(MatchRange('b', 'b').append("b")).to_ndfa("Success");
        let builder  = SymbolRangeDfaBuilder::new();

        let state_machine = DfaCompiler::build(ndfa, builder);

        println!("{:?}", state_machine);

        // Read back 'ba' manually
        let mut state = More(state_machine.start());
        let mut input = "ba".read_symbols();

        while let More(this_state) = state {
            let next_state =
                if let Some(next_char) = input.next_symbol() {
                    this_state.next(next_char)
                } else {
                    this_state.finish()
                };

            state = next_state;
        }

        // Check for acceptance
        if let Accept(count, output) = state {
            assert!(count == 2);
            assert!(output == &"Success");
        } else {
            assert!(false);
        }

        // Read back 'bb' manually
        state = More(state_machine.start());
        input = "bb".read_symbols();

        while let More(this_state) = state {
            let next_state =
                if let Some(next_char) = input.next_symbol() {
                    this_state.next(next_char)
                } else {
                    this_state.finish()
                };

            state = next_state;
        }

        // Check for acceptance
        if let Accept(count, output) = state {
            assert!(count == 2);
            assert!(output == &"Success");
        } else {
            assert!(false);
        }
    }
}
<commit_msg>Change test to fail (we need to deal with overlapping ranges properly)<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # DFA compiler
//!
//! The DFA compiler converts NDFAs into DFAs, using a DFA builder.
//!

use std::marker::PhantomData;
use std::collections::HashSet;
use std::collections::HashMap;
use std::iter::*;
use std::cmp::Ordering;

use super::dfa_builder::*;
use super::state_machine::*;

///
/// Builds a deterministic finite automaton from a NDFA
///
pub struct DfaCompiler<InputSymbol: PartialOrd+Clone, OutputSymbol, DfaType, Ndfa: StateMachine<InputSymbol, OutputSymbol>, Builder: DfaBuilder<InputSymbol, OutputSymbol, DfaType>> {
    /// State machine that is to be compiled
    ndfa: Ndfa,

    /// Builder where the state machine should be generated
    builder: Builder,

    // Phantom data to poke Rust's type system (it's too dumb to see that InputSymbol is used in both Ndfa and Builder there via the type constraint)
    #[allow(dead_code)]
    phantom: (PhantomData<InputSymbol>, PhantomData<OutputSymbol>, PhantomData<DfaType>)
}

/// Represents a state in the DFA (one or more states from the source)
#[derive(Eq, PartialEq, Hash, Clone)]
struct DfaState {
    /// List of the states from the NDFA that make up this DFA state (will be ordered if `dedupe` is called)
    source_states: Vec<StateId>
}

impl DfaState {
    /// Creates a DFA state from a set of source states
    fn create(source_states: Vec<StateId>) -> DfaState {
        let mut set = HashSet::new();
        for state in source_states {
            set.insert(state);
        }

        DfaState { source_states: Vec::from_iter(set.into_iter()) }
    }

    /// Removes any duplicate states from source_states
    fn dedupe(&mut self) {
        self.source_states.sort();
        self.source_states.dedup();
    }
}

/// Represents the transitions for a source state
struct DfaTransitions<InputSymbol, OutputSymbol: Ord> {
    /// ID of this state in the resulting DFA
    state_id: StateId,

    /// Transitions for this state (will be unique if `merge_states` is called)
    transitions: Vec<(InputSymbol, DfaState)>,

    /// The output symbols for this state (empty if this is not an accepting state)
    output: Vec<OutputSymbol>
}

impl<InputSymbol: PartialOrd+Clone, OutputSymbol: Ord> DfaTransitions<InputSymbol, OutputSymbol> {
    /// Goes through the transitions in the object and merges the states of any with the same symbol
    fn merge_states(&mut self) {
        if self.transitions.len() > 0 {
            // Order the transitions so that if two transitions have the same input symbol, they are neighbours
            self.transitions.sort_by(|a, b| {
                let &(ref symbol_a, _) = a;
                let &(ref symbol_b, _) = b;

                if let Some(result) = symbol_a.partial_cmp(symbol_b) {
                    result
                } else {
                    // Unordered input symbols won't work well
                    Ordering::Equal
                }
            });

            // For any transition that has a duplicate state, combine it with the previous state
            let mut new_transitions = vec![];
            new_transitions.push(self.transitions[0].clone());

            for transit_idx in 1..self.transitions.len() {
                let len          = new_transitions.len();
                let this_transit = &mut self.transitions[transit_idx];

                if new_transitions[len-1].0 == this_transit.0 {
                    // Same symbol: expand this state
                    new_transitions[len-1].1.source_states.append(&mut this_transit.1.source_states);
                } else {
                    // Different symbol: add new state
                    new_transitions.push(this_transit.clone());
                }
            }

            // Ensure all of the states are sorted and de-duplicated
            for transit in &mut new_transitions {
                transit.1.dedupe();
            }

            // Update the transitions
            self.transitions = new_transitions;
        }
    }

    ///
    /// Finds the output symbol that corresponds to this state
    ///
    /// Rule is that if there is more than one output symbol then the symbol whose value is ordered lowest is the output for this state
    ///
    fn output_symbol(&mut self) -> Option<&OutputSymbol> {
        if self.output.len() > 0 {
            self.output.sort();
            Some(&self.output[0])
        } else {
            None
        }
    }
}

impl<InputSymbol: PartialOrd+Clone, OutputSymbol: Ord+Clone, DfaType, Ndfa: StateMachine<InputSymbol, OutputSymbol>, Builder: DfaBuilder<InputSymbol, OutputSymbol, DfaType>>
    DfaCompiler<InputSymbol, OutputSymbol, DfaType, Ndfa, Builder> {
    ///
    /// Builds a DFA using an NDFA and a builder
    ///
    pub fn build(ndfa: Ndfa, builder: Builder) -> DfaType {
        let compiler = DfaCompiler::new(ndfa, builder);
        compiler.compile()
    }

    ///
    /// Creates a new DFA compiler using a particular builder and NDFA
    ///
    pub fn new(ndfa: Ndfa, builder: Builder) -> Self {
        DfaCompiler { ndfa: ndfa, builder: builder, phantom: (PhantomData, PhantomData, PhantomData) }
    }

    ///
    /// Compiles the NDFA into a DFA
    ///
    pub fn compile(self) -> DfaType {
        // We assume that input symbols are non-overlapping, which is not automatically the case for symbol ranges

        // Work out the state mapping for each input symbol
        let mut states       = vec![];
        let mut known_states = HashMap::new();
        let mut to_process   = vec![];

        // All state machines have state 0 as their starting state
        let state_zero = DfaState::create(vec![0]);

        known_states.insert(state_zero.clone(), 0);
        to_process.push(state_zero);

        while let Some(state) = to_process.pop() {
            // Create a new transitions object for this state
            let mut transitions = vec![];
            let mut output      = vec![];

            for source_state in &state.source_states {
                let source_transitions = self.ndfa.get_transitions_for_state(*source_state);

                for (symbol, state) in source_transitions {
                    transitions.push((symbol, DfaState::create(vec![state])));
                }

                if let Some(source_output) = self.ndfa.output_symbol_for_state(*source_state) {
                    output.push(source_output.clone());
                }
            }

            // Merge it so that we only have one transition per symbol
            let mut dfa_transitions = DfaTransitions { state_id: states.len() as StateId, transitions: transitions, output: output };
            dfa_transitions.merge_states();

            // Process any generated states that are not already in the DFA
            for &(_, ref maybe_new_state) in &dfa_transitions.transitions {
                if !known_states.contains_key(maybe_new_state) {
                    to_process.push(maybe_new_state.clone());
                }
            }

            // Store the new state
            known_states.insert(state.clone(), dfa_transitions.state_id);
            states.push(dfa_transitions);
        }

        // Build the DFA
        let mut builder = self.builder;

        for mut dfa_state in states {
            builder.start_state();

            if let Some(output_symbol) = dfa_state.output_symbol() {
                builder.accept(output_symbol.clone());
            }

            for (symbol, target_state) in dfa_state.transitions {
                builder.transition(symbol, known_states[&target_state]);
            }
        }

        // Generate the final DFA
        builder.build()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use super::super::regular_pattern::*;
    use super::super::state_machine::*;
    use super::super::symbol_range_dfa::*;
    use super::super::pattern_matcher::*;
    use super::super::symbol_reader::*;

    #[test]
    fn can_create_compiler() {
        let ndfa     = "abc".into_pattern().to_ndfa("success");
        let builder  = SymbolRangeDfaBuilder::new();

        DfaCompiler::new(ndfa, builder);
    }

    #[test]
    fn can_build_dfa() {
        // Generate a state machine from the "abc" pattern
        let ndfa     = "abc".into_pattern().to_ndfa("Success");
        let builder  = SymbolRangeDfaBuilder::new();

        let state_machine = DfaCompiler::build(ndfa, builder);

        // Read back 'abc' manually
        let mut state = More(state_machine.start());
        let mut input = "abc".read_symbols();

        while let More(this_state) = state {
            let next_state =
                if let Some(next_char) = input.next_symbol() {
                    this_state.next(next_char)
                } else {
                    this_state.finish()
                };

            state = next_state;
        }

        // Check for acceptance
        if let Accept(count, output) = state {
            assert!(count == 3);
            assert!(output == &"Success");
        } else {
            assert!(false);
        }
    }

    #[test]
    fn can_build_dfa_with_overlapping_range() {
        // Generate a state machine from the "abc" pattern
        let ndfa     = (MatchRange('a', 'c').append("a")).or(MatchRange('b', 'd').append("b")).to_ndfa("Success");
        let builder  = SymbolRangeDfaBuilder::new();

        let state_machine = DfaCompiler::build(ndfa, builder);

        println!("{:?}", state_machine);

        // Read back 'ba' manually
        let mut state = More(state_machine.start());
        let mut input = "ba".read_symbols();

        while let More(this_state) = state {
            let next_state =
                if let Some(next_char) = input.next_symbol() {
                    this_state.next(next_char)
                } else {
                    this_state.finish()
                };

            state = next_state;
        }

        // Check for acceptance
        if let Accept(count, output) = state {
            assert!(count == 2);
            assert!(output == &"Success");
        } else {
            assert!(false);
        }

        // Read back 'bb' manually
        state = More(state_machine.start());
        input = "bb".read_symbols();

        while let More(this_state) = state {
            let next_state =
                if let Some(next_char) = input.next_symbol() {
                    this_state.next(next_char)
                } else {
                    this_state.finish()
                };

            state = next_state;
        }

        // Check for acceptance
        if let Accept(count, output) = state {
            assert!(count == 2);
            assert!(output == &"Success");
        } else {
            assert!(false);
        }
    }
}
<|endoftext|>


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

extern crate app_units;
extern crate euclid;
extern crate gleam;
extern crate glutin;
extern crate webrender;
extern crate winit;

use app_units::Au;
use gleam::gl;
use glutin::GlContext;
use std::fs::File;
use std::io::Read;
use webrender::api::*;
use winit::dpi::LogicalSize;

struct Notifier {
    events_proxy: winit::EventsLoopProxy,
}

impl Notifier {
    fn new(events_proxy: winit::EventsLoopProxy) -> Notifier {
        Notifier { events_proxy }
    }
}

impl RenderNotifier for Notifier {
    fn clone(&self) -> Box<RenderNotifier> {
        Box::new(Notifier {
            events_proxy: self.events_proxy.clone(),
        })
    }

    fn wake_up(&self) {
        #[cfg(not(target_os = "android"))]
        let _ = self.events_proxy.wakeup();
    }

    fn new_frame_ready(&self,
                       _: DocumentId,
                       _scrolled: bool,
                       _composite_needed: bool,
                       _render_time: Option<u64>) {
        self.wake_up();
    }
}

struct Window {
    events_loop: winit::EventsLoop, //TODO: share events loop?
    window: glutin::GlWindow,
    renderer: webrender::Renderer,
    name: &'static str,
    pipeline_id: PipelineId,
    document_id: DocumentId,
    epoch: Epoch,
    api: RenderApi,
    font_instance_key: FontInstanceKey,
}

impl Window {
    fn new(name: &'static str, clear_color: ColorF) -> Self {
        let events_loop = winit::EventsLoop::new();
        let context_builder = glutin::ContextBuilder::new()
            .with_gl(glutin::GlRequest::GlThenGles {
                opengl_version: (3, 2),
                opengles_version: (3, 0),
            });
        let window_builder = winit::WindowBuilder::new()
            .with_title(name)
            .with_multitouch()
            .with_dimensions(LogicalSize::new(800., 600.));
        let window = glutin::GlWindow::new(window_builder, context_builder, &events_loop)
            .unwrap();

        unsafe {
            window.make_current().ok();
        }

        let gl = match window.get_api() {
            glutin::Api::OpenGl => unsafe {
                gl::GlFns::load_with(|symbol| window.get_proc_address(symbol) as *const _)
            },
            glutin::Api::OpenGlEs => unsafe {
                gl::GlesFns::load_with(|symbol| window.get_proc_address(symbol) as *const _)
            },
            glutin::Api::WebGl => unimplemented!(),
        };

        let device_pixel_ratio = window.get_hidpi_factor() as f32;

        let opts = webrender::RendererOptions {
            device_pixel_ratio,
            clear_color: Some(clear_color),
            ..webrender::RendererOptions::default()
        };

        let framebuffer_size = {
            let LogicalSize { width, height } = window.get_inner_size().unwrap();
            DeviceUintSize::new(width as u32, height as u32)
        };
        let notifier = Box::new(Notifier::new(events_loop.create_proxy()));
        let (renderer, sender) = webrender::Renderer::new(gl.clone(), notifier, opts).unwrap();
        let api = sender.create_api();
        let document_id = api.add_document(framebuffer_size, 0);

        let epoch = Epoch(0);
        let pipeline_id = PipelineId(0, 0);
        let mut txn = Transaction::new();

        let font_key = api.generate_font_key();
        let font_bytes = load_file("../wrench/reftests/text/FreeSans.ttf");
        txn.add_raw_font(font_key, font_bytes, 0);

        let font_instance_key = api.generate_font_instance_key();
        txn.add_font_instance(font_instance_key, font_key, Au::from_px(32), None, None, Vec::new());

        api.send_transaction(document_id, txn);

        Window {
            events_loop,
            window,
            renderer,
            name,
            epoch,
            pipeline_id,
            document_id,
            api,
            font_instance_key,
        }
    }

    fn tick(&mut self) -> bool {
        unsafe {
            self.window.make_current().ok();
        }
        let mut do_exit = false;
        let my_name = &self.name;
        let renderer = &mut self.renderer;

        self.events_loop.poll_events(|global_event| match global_event {
            winit::Event::WindowEvent { event, .. } => match event {
                winit::WindowEvent::CloseRequested |
                winit::WindowEvent::KeyboardInput {
                    input: winit::KeyboardInput {
                        virtual_keycode: Some(winit::VirtualKeyCode::Escape),
                        ..
                    },
                    ..
                } => {
                    do_exit = true
                }
                winit::WindowEvent::KeyboardInput {
                    input: winit::KeyboardInput {
                        state: winit::ElementState::Pressed,
                        virtual_keycode: Some(winit::VirtualKeyCode::P),
                        ..
                    },
                    ..
                } => {
                    println!("toggle flags {}", my_name);
                    renderer.toggle_debug_flags(webrender::DebugFlags::PROFILER_DBG);
                }
                _ => {}
            }
            _ => {}
        });
        if do_exit {
            return true
        }

        let framebuffer_size = {
            let LogicalSize { width, height } = self.window.get_inner_size().unwrap();
            DeviceUintSize::new(width as u32, height as u32)
        };
        let device_pixel_ratio = self.window.get_hidpi_factor() as f32;
        let layout_size = framebuffer_size.to_f32() / euclid::TypedScale::new(device_pixel_ratio);
        let mut txn = Transaction::new();
        let mut builder = DisplayListBuilder::new(self.pipeline_id, layout_size);

        let bounds = LayoutRect::new(LayoutPoint::zero(), builder.content_size());
        let info = LayoutPrimitiveInfo::new(bounds);
        builder.push_stacking_context(
            &info,
            None,
            TransformStyle::Flat,
            MixBlendMode::Normal,
            Vec::new(),
            GlyphRasterSpace::Screen,
        );

        let info = LayoutPrimitiveInfo::new(LayoutRect::new(
            LayoutPoint::new(100.0, 100.0),
            LayoutSize::new(100.0, 200.0)
        ));
        builder.push_rect(&info, ColorF::new(0.0, 1.0, 0.0, 1.0));

        let text_bounds = LayoutRect::new(
            LayoutPoint::new(100.0, 50.0),
            LayoutSize::new(700.0, 200.0)
        );
        let glyphs = vec![
            GlyphInstance {
                index: 48,
                point: LayoutPoint::new(100.0, 100.0),
            },
            GlyphInstance {
                index: 68,
                point: LayoutPoint::new(150.0, 100.0),
            },
            GlyphInstance {
                index: 80,
                point: LayoutPoint::new(200.0, 100.0),
            },
            GlyphInstance {
                index: 82,
                point: LayoutPoint::new(250.0, 100.0),
            },
            GlyphInstance {
                index: 81,
                point: LayoutPoint::new(300.0, 100.0),
            },
            GlyphInstance {
                index: 3,
                point: LayoutPoint::new(350.0, 100.0),
            },
            GlyphInstance {
                index: 86,
                point: LayoutPoint::new(400.0, 100.0),
            },
            GlyphInstance {
                index: 79,
                point: LayoutPoint::new(450.0, 100.0),
            },
            GlyphInstance {
                index: 72,
                point: LayoutPoint::new(500.0, 100.0),
            },
            GlyphInstance {
                index: 83,
                point: LayoutPoint::new(550.0, 100.0),
            },
            GlyphInstance {
                index: 87,
                point: LayoutPoint::new(600.0, 100.0),
            },
            GlyphInstance {
                index: 17,
                point: LayoutPoint::new(650.0, 100.0),
            },
        ];

        let info = LayoutPrimitiveInfo::new(text_bounds);
        builder.push_text(
            &info,
            &glyphs,
            self.font_instance_key,
            ColorF::new(1.0, 1.0, 0.0, 1.0),
            None,
        );

        builder.pop_stacking_context();

        txn.set_display_list(
            self.epoch,
            None,
            layout_size,
            builder.finalize(),
            true,
        );
        txn.set_root_pipeline(self.pipeline_id);
        txn.generate_frame();
        self.api.send_transaction(self.document_id, txn);

        renderer.update();
        renderer.render(framebuffer_size).unwrap();
        self.window.swap_buffers().ok();

        false
    }

    fn deinit(self) {
        self.renderer.deinit();
    }
}

fn main() {
    let mut win1 = Window::new("window1", ColorF::new(0.3, 0.0, 0.0, 1.0));
    let mut win2 = Window::new("window2", ColorF::new(0.0, 0.3, 0.0, 1.0));

    loop {
        if win1.tick() {
            break;
        }
        if win2.tick() {
            break;
        }
    }

    win1.deinit();
    win2.deinit();
}

fn load_file(name: &str) -> Vec<u8> {
    let mut file = File::open(name).unwrap();
    let mut buffer = vec![];
    file.read_to_end(&mut buffer).unwrap();
    buffer
}
<commit_msg>Fix framebuffer size in multiwindow example<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate app_units;
extern crate euclid;
extern crate gleam;
extern crate glutin;
extern crate webrender;
extern crate winit;

use app_units::Au;
use gleam::gl;
use glutin::GlContext;
use std::fs::File;
use std::io::Read;
use webrender::api::*;
use winit::dpi::LogicalSize;

struct Notifier {
    events_proxy: winit::EventsLoopProxy,
}

impl Notifier {
    fn new(events_proxy: winit::EventsLoopProxy) -> Notifier {
        Notifier { events_proxy }
    }
}

impl RenderNotifier for Notifier {
    fn clone(&self) -> Box<RenderNotifier> {
        Box::new(Notifier {
            events_proxy: self.events_proxy.clone(),
        })
    }

    fn wake_up(&self) {
        #[cfg(not(target_os = "android"))]
        let _ = self.events_proxy.wakeup();
    }

    fn new_frame_ready(&self,
                       _: DocumentId,
                       _scrolled: bool,
                       _composite_needed: bool,
                       _render_time: Option<u64>) {
        self.wake_up();
    }
}

struct Window {
    events_loop: winit::EventsLoop, //TODO: share events loop?
    window: glutin::GlWindow,
    renderer: webrender::Renderer,
    name: &'static str,
    pipeline_id: PipelineId,
    document_id: DocumentId,
    epoch: Epoch,
    api: RenderApi,
    font_instance_key: FontInstanceKey,
}

impl Window {
    fn new(name: &'static str, clear_color: ColorF) -> Self {
        let events_loop = winit::EventsLoop::new();
        let context_builder = glutin::ContextBuilder::new()
            .with_gl(glutin::GlRequest::GlThenGles {
                opengl_version: (3, 2),
                opengles_version: (3, 0),
            });
        let window_builder = winit::WindowBuilder::new()
            .with_title(name)
            .with_multitouch()
            .with_dimensions(LogicalSize::new(800., 600.));
        let window = glutin::GlWindow::new(window_builder, context_builder, &events_loop)
            .unwrap();

        unsafe {
            window.make_current().ok();
        }

        let gl = match window.get_api() {
            glutin::Api::OpenGl => unsafe {
                gl::GlFns::load_with(|symbol| window.get_proc_address(symbol) as *const _)
            },
            glutin::Api::OpenGlEs => unsafe {
                gl::GlesFns::load_with(|symbol| window.get_proc_address(symbol) as *const _)
            },
            glutin::Api::WebGl => unimplemented!(),
        };

        let device_pixel_ratio = window.get_hidpi_factor() as f32;

        let opts = webrender::RendererOptions {
            device_pixel_ratio,
            clear_color: Some(clear_color),
            ..webrender::RendererOptions::default()
        };

        let framebuffer_size = {
            let size = window
                .get_inner_size()
                .unwrap()
                .to_physical(device_pixel_ratio as f64);
            DeviceUintSize::new(size.width as u32, size.height as u32)
        };
        let notifier = Box::new(Notifier::new(events_loop.create_proxy()));
        let (renderer, sender) = webrender::Renderer::new(gl.clone(), notifier, opts).unwrap();
        let api = sender.create_api();
        let document_id = api.add_document(framebuffer_size, 0);

        let epoch = Epoch(0);
        let pipeline_id = PipelineId(0, 0);
        let mut txn = Transaction::new();

        let font_key = api.generate_font_key();
        let font_bytes = load_file("../wrench/reftests/text/FreeSans.ttf");
        txn.add_raw_font(font_key, font_bytes, 0);

        let font_instance_key = api.generate_font_instance_key();
        txn.add_font_instance(font_instance_key, font_key, Au::from_px(32), None, None, Vec::new());

        api.send_transaction(document_id, txn);

        Window {
            events_loop,
            window,
            renderer,
            name,
            epoch,
            pipeline_id,
            document_id,
            api,
            font_instance_key,
        }
    }

    fn tick(&mut self) -> bool {
        unsafe {
            self.window.make_current().ok();
        }
        let mut do_exit = false;
        let my_name = &self.name;
        let renderer = &mut self.renderer;

        self.events_loop.poll_events(|global_event| match global_event {
            winit::Event::WindowEvent { event, .. } => match event {
                winit::WindowEvent::CloseRequested |
                winit::WindowEvent::KeyboardInput {
                    input: winit::KeyboardInput {
                        virtual_keycode: Some(winit::VirtualKeyCode::Escape),
                        ..
                    },
                    ..
                } => {
                    do_exit = true
                }
                winit::WindowEvent::KeyboardInput {
                    input: winit::KeyboardInput {
                        state: winit::ElementState::Pressed,
                        virtual_keycode: Some(winit::VirtualKeyCode::P),
                        ..
                    },
                    ..
                } => {
                    println!("toggle flags {}", my_name);
                    renderer.toggle_debug_flags(webrender::DebugFlags::PROFILER_DBG);
                }
                _ => {}
            }
            _ => {}
        });
        if do_exit {
            return true
        }

        let device_pixel_ratio = self.window.get_hidpi_factor() as f32;
        let framebuffer_size = {
            let size = self.window
                .get_inner_size()
                .unwrap()
                .to_physical(device_pixel_ratio as f64);
            DeviceUintSize::new(size.width as u32, size.height as u32)
        };
        let layout_size = framebuffer_size.to_f32() / euclid::TypedScale::new(device_pixel_ratio);
        let mut txn = Transaction::new();
        let mut builder = DisplayListBuilder::new(self.pipeline_id, layout_size);

        let bounds = LayoutRect::new(LayoutPoint::zero(), builder.content_size());
        let info = LayoutPrimitiveInfo::new(bounds);
        builder.push_stacking_context(
            &info,
            None,
            TransformStyle::Flat,
            MixBlendMode::Normal,
            Vec::new(),
            GlyphRasterSpace::Screen,
        );

        let info = LayoutPrimitiveInfo::new(LayoutRect::new(
            LayoutPoint::new(100.0, 100.0),
            LayoutSize::new(100.0, 200.0)
        ));
        builder.push_rect(&info, ColorF::new(0.0, 1.0, 0.0, 1.0));

        let text_bounds = LayoutRect::new(
            LayoutPoint::new(100.0, 50.0),
            LayoutSize::new(700.0, 200.0)
        );
        let glyphs = vec![
            GlyphInstance {
                index: 48,
                point: LayoutPoint::new(100.0, 100.0),
            },
            GlyphInstance {
                index: 68,
                point: LayoutPoint::new(150.0, 100.0),
            },
            GlyphInstance {
                index: 80,
                point: LayoutPoint::new(200.0, 100.0),
            },
            GlyphInstance {
                index: 82,
                point: LayoutPoint::new(250.0, 100.0),
            },
            GlyphInstance {
                index: 81,
                point: LayoutPoint::new(300.0, 100.0),
            },
            GlyphInstance {
                index: 3,
                point: LayoutPoint::new(350.0, 100.0),
            },
            GlyphInstance {
                index: 86,
                point: LayoutPoint::new(400.0, 100.0),
            },
            GlyphInstance {
                index: 79,
                point: LayoutPoint::new(450.0, 100.0),
            },
            GlyphInstance {
                index: 72,
                point: LayoutPoint::new(500.0, 100.0),
            },
            GlyphInstance {
                index: 83,
                point: LayoutPoint::new(550.0, 100.0),
            },
            GlyphInstance {
                index: 87,
                point: LayoutPoint::new(600.0, 100.0),
            },
            GlyphInstance {
                index: 17,
                point: LayoutPoint::new(650.0, 100.0),
            },
        ];

        let info = LayoutPrimitiveInfo::new(text_bounds);
        builder.push_text(
            &info,
            &glyphs,
            self.font_instance_key,
            ColorF::new(1.0, 1.0, 0.0, 1.0),
            None,
        );

        builder.pop_stacking_context();

        txn.set_display_list(
            self.epoch,
            None,
            layout_size,
            builder.finalize(),
            true,
        );
        txn.set_root_pipeline(self.pipeline_id);
        txn.generate_frame();
        self.api.send_transaction(self.document_id, txn);

        renderer.update();
        renderer.render(framebuffer_size).unwrap();
        self.window.swap_buffers().ok();

        false
    }

    fn deinit(self) {
        self.renderer.deinit();
    }
}

fn main() {
    let mut win1 = Window::new("window1", ColorF::new(0.3, 0.0, 0.0, 1.0));
    let mut win2 = Window::new("window2", ColorF::new(0.0, 0.3, 0.0, 1.0));

    loop {
        if win1.tick() {
            break;
        }
        if win2.tick() {
            break;
        }
    }

    win1.deinit();
    win2.deinit();
}

fn load_file(name: &str) -> Vec<u8> {
    let mut file = File::open(name).unwrap();
    let mut buffer = vec![];
    file.read_to_end(&mut buffer).unwrap();
    buffer
}
<|endoftext|>


<commit_before>// Utility wrappers around an engine instance, so that it simplify an
// existing codebase and makes it more readable

#[macro_export]
macro_rules! handle_error {
    (&$connections:expr, &$addr:expr, $engine_instance:expr, $error:expr) => {
        let transmitter = &$connections.borrow_mut()[&$addr];
        let formatted_error = format!("{}", $error);
        let error_message = $engine_instance.borrow().wrap_an_error(formatted_error.as_str());
        transmitter.unbounded_send(error_message).unwrap();
    };
}
<commit_msg>Added documentation for engine_macro module<commit_after>//! Macros for a work with `engine::Engine`
//!
//! Utility wrappers around an instance of the `engine::Engine` type, so that
//! it simplify an existing codebase and makes it more readable.
//!

/// Sends an error message in JSON format to a client via `UnboundedSender`,
/// being a part of `mpsc::UnboundedSender<Message>` object.
///
/// # Remarks
///
/// This macro extracting a transmitter of the `UnboundedSender` type from the
/// passed `connections` argument. After the passed `error` transforms into
/// `std::string::String` so that it can be sent in JSON format later.
///
/// # Arguments
/// * `connections` - A reference to a variable of the `std::collections::HashMap<SocketAddr, mpsc::UnboundedSender<Message>` type.
/// * `addr` - A reference to an instance of the `std::net::SocketAddr` type.
/// * `engine_instance` - An instance of the `engine::{Engine}` type.
/// * `error` - An instance of `error::Error`, that will be processed and sent to a client.
///
#[macro_export]
macro_rules! handle_error {
    (&$connections:expr, &$addr:expr, $engine_instance:expr, $error:expr) => {
        let transmitter = &$connections.borrow_mut()[&$addr];
        let formatted_error = format!("{}", $error);
        let error_message = $engine_instance.borrow().wrap_an_error(formatted_error.as_str());
        transmitter.unbounded_send(error_message).unwrap();
    };
}
<|endoftext|>


<commit_before>//! A [Todo-Backend](http://todobackend.com/) implementation with rotor-http.
//!
//! Todo-Backed is a showcase to compare different languages and frameworks
//! for building web services. One has to implement a simple todo list
//! that is checked by automatic tests available on the website.
//!
//! NOTE: This example only works with Nightly Rust for now because
//! of serde macros.
//!
//! To run use `cargo run --example todobackend --features nightly`.

#![cfg_attr(feature="nightly", feature(custom_derive, plugin))]
#![cfg_attr(feature="nightly", plugin(serde_macros))]
#![allow(warnings)]

extern crate rotor;
extern crate rotor_http;
#[cfg(features="nightly")] extern crate serde;
#[cfg(features="nightly")] extern crate serde_json;

use std::borrow::Cow;
use std::collections::HashMap;
use std::str;
use std::time::Duration;

use rotor::{Scope, Time};
use rotor_http::ServerFsm;
use rotor_http::server;
use rotor_http::server::{RecvMode, Server, Head, Response};
use rotor::mio::tcp::TcpListener;

/// Represents a single Todo entry.
///
/// The entry is serialized and deserialized by serde without
/// any handwritten code.
#[cfg(feature="nightly")]
#[derive(Serialize, Deserialize, Debug)]
struct Todo {
    url: Option<String>,
    title: String,
    #[serde(default)]
    completed: bool,
    #[serde(default)]
    order: u64,
}

#[cfg(feature="nightly")]
impl Todo {
    fn set_url(&mut self, id: u64) {
        self.url = Some(format!("http://localhost:3000/todo/{}", id));
    }

    fn patch(&mut self, patch: TodoPatch) {
        if let Some(title) = patch.title {
            self.title = title;
        }
        if let Some(completed) = patch.completed {
            self.completed = completed;
        }
        if let Some(order) = patch.order {
            self.order = order
        }
    }
}

/// One can patch the title and the status of todos. It is also
/// possible to change the ordering.
#[cfg(feature="nightly")]
#[derive(Deserialize, Debug)]
struct TodoPatch {
    title: Option<String>,
    completed: Option<bool>,
    order: Option<u64>,
}

#[cfg(feature="nightly")]
/// Context is used for global storage.
struct Context {
    /// The last id assigned to a todo entry.
    ///
    /// New ids are incremented by one.
    last_id: u64,
    /// The in memory "database" used for the todo-list.
    database: HashMap<u64, Todo>,
}

#[cfg(feature="nightly")]
impl server::Context for Context {}

#[cfg(feature="nightly")]
trait Database {
    /// Get a unique new id.
    fn id(&mut self) -> u64;
    /// List all existing Todos.
    fn list(&self) -> Vec<&Todo>;
    /// Create a new Todo.
    fn create(&mut self, u64, Todo);
    /// Clear the database.
    fn clear(&mut self);
    /// Get one todo by id.
    fn get(&mut self, u64) -> Option<&Todo>;
    /// Get a mutable reference of a todo.
    ///
    /// This is useful for updating or patching an entry.
    fn get_mut(&mut self, u64) -> Option<&mut Todo>;
    /// Delete an entry.
    fn delete(&mut self, id: u64);
}

#[cfg(feature="nightly")]
impl Database for Context {
    fn id(&mut self) -> u64 {
        self.last_id += 1;
        self.last_id
    }

    fn list(&self) -> Vec<&Todo> {
        self.database.values().collect()
    }

    fn create(&mut self, id: u64, todo: Todo) {
        assert!(self.database.insert(id, todo).is_none());
    }

    fn clear(&mut self) {
        self.database.clear();
    }

    fn get(&mut self, id: u64) -> Option<&Todo> {
        self.database.get(&id)
    }

    fn get_mut(&mut self, id: u64) -> Option<&mut Todo> {
        self.database.get_mut(&id)
    }

    fn delete(&mut self, id: u64) {
        self.database.remove(&id);
    }
}

/// The main server state machine. After parsing the header
/// the type of request determined. Each variant of the
/// enum represents a single action. Some are directly related
/// to todo entries others are for error handling or and CORS.
#[derive(Debug, Clone)]
enum TodoBackend {
    List,
    Create,
    Clear,
    Get(u64),
    Patch(u64),
    Delete(u64),
    Preflight,
    MethodNotAllowed(&'static [u8]),
    NotFound,
}

#[cfg(feature="nightly")]
impl Server for TodoBackend {
    type Context = Context;
    fn headers_received(head: Head, _response: &mut Response,
        scope: &mut Scope<Context>)
        -> Option<(Self, RecvMode, Time)>
    {
        use TodoBackend::*;
        Some((if head.method == "OPTIONS" {
                Preflight
            } else if head.path == "/" {
                match head.method {
                    "GET" => List,
                    "POST" => Create,
                    "DELETE" => Clear,
                    _ => MethodNotAllowed(b"GET, POST, DELETE"),
                }
            } else if head.path.starts_with("/todo/") {
                let id = head.path[6..].parse().unwrap();
                match head.method {
                    "GET" => Get(id),
                    "PATCH" => Patch(id),
                    "DELETE" => Delete(id),
                    _ => MethodNotAllowed(b"GET, PATCH, DELETE"),
                }
            } else {
                NotFound
            }, RecvMode::Buffered(1024), scope.now() + Duration::new(10, 0)))

    }

    fn request_received(self, data: &[u8], response: &mut Response,
        scope: &mut Scope<Context>)
        -> Option<Self>
    {
        use self::TodoBackend::*;
        let text_data = str::from_utf8(data).unwrap();
        let (status, reason, body) = match self {
            List => (200, "OK", Cow::Owned(serde_json::to_string(&scope.list()).unwrap().into_bytes())),
            Create => {
                let mut todo: Todo = serde_json::from_str(text_data).unwrap();
                let id = scope.id();
                todo.set_url(id);
                let body = serde_json::to_string(&todo).unwrap().into_bytes();
                scope.create(id, todo);
                (201, "Created", Cow::Owned(body))
            }
            Clear => {
                scope.clear();
                (200, "OK", Cow::Borrowed(&b"[]"[..]))
            }
            Get(id) => (200, "OK",
                Cow::Owned(serde_json::to_string(&scope.get(id)).unwrap().into_bytes())),
            Patch(id) => {
                let patch: TodoPatch = serde_json::from_str(text_data).unwrap();
                if let Some(todo) = scope.get_mut(id) {
                    todo.patch(patch);
                    let body = serde_json::to_string(&todo).unwrap().into_bytes();
                    (200, "OK", Cow::Owned(body))
                } else {
                    (404, "Not found", Cow::Borrowed(&b"{}"[..]))
                }
            }
            Delete(id) => {
                scope.delete(id);
                (200, "OK", Cow::Borrowed(&b"{}"[..]))
            }
            Preflight => {
                response.status(200, "OK");
                response.add_length(0).unwrap();
                response.add_header("Access-Control-Allow-Origin", b"*").unwrap();
                response.add_header("Access-Control-Allow-Methods",
                                    b"GET, POST, DELETE, PATCH").unwrap();
                response.add_header("Access-Control-Allow-Headers",
                                    b"Content-Type").unwrap();
                response.add_header("Access-Control-Max-Age", b"60").unwrap();
                response.done_headers().unwrap();
                response.done();
                return None;
            }
            MethodNotAllowed(methods) => {
                response.status(405, "Method Not Allowed");
                response.add_length(b"Method Not Allowed".len() as u64).unwrap();
                response.add_header("Access-Control-Allow-Origin", b"*").unwrap();
                response.add_header("Allow", methods).unwrap();
                response.done_headers().unwrap();
                response.write_body(b"Method Not Allowed");
                response.done();
                return None;
            }
            NotFound => (404, "Not Found", Cow::Borrowed(&b"Not found"[..])),
        };
        response.status(status, reason);
        response.add_length(body.len() as u64).unwrap();
        response.add_header("Access-Control-Allow-Origin", b"*").unwrap();
        response.done_headers().unwrap();
        response.write_body(&body[..]);
        response.done();
        None
    }
    // It is save to leave out `request_chunk` and `request_end` since we
    // only use buffered requests in this example.
    fn request_chunk(self, _chunk: &[u8], _response: &mut Response,
        _scope: &mut Scope<Context>)
        -> Option<Self> { unreachable!(); }
    fn request_end(self, _response: &mut Response, _scope: &mut Scope<Context>)
        -> Option<Self> { unreachable!(); }

    fn timeout(self, _response: &mut Response, _scope: &mut Scope<Context>)
        -> Option<(Self, Time)>
    {
        unimplemented!();
    }
    fn wakeup(self, _response: &mut Response, _scope: &mut Scope<Context>)
        -> Option<Self>
    {
        unimplemented!();
    }
}

#[cfg(feature="nightly")]
fn main() {
    let event_loop = rotor::Loop::new(&rotor::Config::new()).unwrap();
    let mut loop_inst = event_loop.instantiate(Context {
        last_id: 0,
        database: HashMap::new(),
    });
    let lst = TcpListener::bind(&"127.0.0.1:3000".parse().unwrap()).unwrap();
    loop_inst.add_machine_with(|scope| {
        ServerFsm::<TodoBackend, _>::new(lst, scope)
    }).unwrap();
    loop_inst.run().unwrap();
}

#[cfg(not(feature="nightly"))]
fn main() { panic!("See NOTE in source. You must use --features nightly.")}
<commit_msg>Add more documentation to Todo example.<commit_after>//! A [Todo-Backend](http://todobackend.com/) implementation with rotor-http.
//!
//! Todo-Backed is a showcase to compare different languages and frameworks
//! for building web services. One has to implement a simple todo list
//! that is checked by automatic tests available on the website.
//!
//! NOTE: This example only works with Nightly Rust for now because
//! of serde macros.
//!
//! To run use `cargo run --example todobackend --features nightly`.
//!
//! Now you can edit your own todo list via
//! http://todobackend.com/client/index.html?http://localhost:3000
//! (The web page is just for the frontend, the backend is this Rust
//! program.)

#![cfg_attr(feature="nightly", feature(custom_derive, plugin))]
#![cfg_attr(feature="nightly", plugin(serde_macros))]
#![allow(warnings)]

extern crate rotor;
extern crate rotor_http;
#[cfg(feature="nightly")] extern crate serde;
#[cfg(feature="nightly")] extern crate serde_json;

use std::borrow::Cow;
use std::collections::HashMap;
use std::str;
use std::time::Duration;

use rotor::{Scope, Time};
use rotor_http::ServerFsm;
use rotor_http::server;
use rotor_http::server::{RecvMode, Server, Head, Response};
use rotor::mio::tcp::TcpListener;

/// Represents a single Todo entry.
///
/// The entry is serialized and deserialized by serde without
/// any handwritten code.
#[cfg(feature="nightly")]
#[derive(Serialize, Deserialize, Debug)]
struct Todo {
    url: Option<String>,
    title: String,
    #[serde(default)]
    completed: bool,
    #[serde(default)]
    order: u64,
}

#[cfg(feature="nightly")]
impl Todo {
    fn set_url(&mut self, id: u64) {
        self.url = Some(format!("http://localhost:3000/todo/{}", id));
    }

    fn patch(&mut self, patch: TodoPatch) {
        if let Some(title) = patch.title {
            self.title = title;
        }
        if let Some(completed) = patch.completed {
            self.completed = completed;
        }
        if let Some(order) = patch.order {
            self.order = order
        }
    }
}

/// One can patch the title and the status of todos. It is also
/// possible to change the ordering.
#[cfg(feature="nightly")]
#[derive(Deserialize, Debug)]
struct TodoPatch {
    title: Option<String>,
    completed: Option<bool>,
    order: Option<u64>,
}

#[cfg(feature="nightly")]
/// Context is used for global storage.
struct Context {
    /// The last id assigned to a todo entry.
    ///
    /// New ids are incremented by one.
    last_id: u64,
    /// The in memory "database" used for the todo-list.
    database: HashMap<u64, Todo>,
}

#[cfg(feature="nightly")]
impl server::Context for Context {}

#[cfg(feature="nightly")]
trait Database {
    /// Get a unique new id.
    fn id(&mut self) -> u64;
    /// List all existing Todos.
    fn list(&self) -> Vec<&Todo>;
    /// Create a new Todo.
    fn create(&mut self, u64, Todo);
    /// Clear the database.
    fn clear(&mut self);
    /// Get one todo by id.
    fn get(&mut self, u64) -> Option<&Todo>;
    /// Get a mutable reference of a todo.
    ///
    /// This is useful for updating or patching an entry.
    fn get_mut(&mut self, u64) -> Option<&mut Todo>;
    /// Delete an entry.
    fn delete(&mut self, id: u64);
}

#[cfg(feature="nightly")]
impl Database for Context {
    fn id(&mut self) -> u64 {
        self.last_id += 1;
        self.last_id
    }

    fn list(&self) -> Vec<&Todo> {
        self.database.values().collect()
    }

    fn create(&mut self, id: u64, todo: Todo) {
        assert!(self.database.insert(id, todo).is_none());
    }

    fn clear(&mut self) {
        self.database.clear();
    }

    fn get(&mut self, id: u64) -> Option<&Todo> {
        self.database.get(&id)
    }

    fn get_mut(&mut self, id: u64) -> Option<&mut Todo> {
        self.database.get_mut(&id)
    }

    fn delete(&mut self, id: u64) {
        self.database.remove(&id);
    }
}

/// The main server state machine. After parsing the header
/// the type of request determined. Each variant of the
/// enum represents a single action. Some are directly related
/// to todo entries others are for error handling or and CORS.
#[derive(Debug, Clone)]
enum TodoBackend {
    List,
    Create,
    Clear,
    Get(u64),
    Patch(u64),
    Delete(u64),
    Preflight,
    MethodNotAllowed(&'static [u8]),
    NotFound,
}

#[cfg(feature="nightly")]
impl Server for TodoBackend {
    type Context = Context;
    fn headers_received(head: Head, _response: &mut Response,
        scope: &mut Scope<Context>)
        -> Option<(Self, RecvMode, Time)>
    {
        use TodoBackend::*;
        Some((if head.method == "OPTIONS" {
                Preflight
            } else if head.path == "/" {
                match head.method {
                    "GET" => List,
                    "POST" => Create,
                    "DELETE" => Clear,
                    _ => MethodNotAllowed(b"GET, POST, DELETE"),
                }
            } else if head.path.starts_with("/todo/") {
                let id = head.path[6..].parse().unwrap();
                match head.method {
                    "GET" => Get(id),
                    "PATCH" => Patch(id),
                    "DELETE" => Delete(id),
                    _ => MethodNotAllowed(b"GET, PATCH, DELETE"),
                }
            } else {
                NotFound
            }, RecvMode::Buffered(1024), scope.now() + Duration::new(10, 0)))

    }

    fn request_received(self, data: &[u8], response: &mut Response,
        scope: &mut Scope<Context>)
        -> Option<Self>
    {
        use self::TodoBackend::*;
        let text_data = str::from_utf8(data).unwrap();
        let (status, reason, body) = match self {
            List => (200, "OK", Cow::Owned(serde_json::to_string(&scope.list()).unwrap().into_bytes())),
            Create => {
                let mut todo: Todo = serde_json::from_str(text_data).unwrap();
                let id = scope.id();
                todo.set_url(id);
                let body = serde_json::to_string(&todo).unwrap().into_bytes();
                scope.create(id, todo);
                (201, "Created", Cow::Owned(body))
            }
            Clear => {
                scope.clear();
                (200, "OK", Cow::Borrowed(&b"[]"[..]))
            }
            Get(id) => (200, "OK",
                Cow::Owned(serde_json::to_string(&scope.get(id)).unwrap().into_bytes())),
            Patch(id) => {
                let patch: TodoPatch = serde_json::from_str(text_data).unwrap();
                if let Some(todo) = scope.get_mut(id) {
                    todo.patch(patch);
                    let body = serde_json::to_string(&todo).unwrap().into_bytes();
                    (200, "OK", Cow::Owned(body))
                } else {
                    (404, "Not found", Cow::Borrowed(&b"{}"[..]))
                }
            }
            Delete(id) => {
                scope.delete(id);
                (200, "OK", Cow::Borrowed(&b"{}"[..]))
            }
            Preflight => {
                response.status(200, "OK");
                response.add_length(0).unwrap();
                response.add_header("Access-Control-Allow-Origin", b"*").unwrap();
                response.add_header("Access-Control-Allow-Methods",
                                    b"GET, POST, DELETE, PATCH").unwrap();
                response.add_header("Access-Control-Allow-Headers",
                                    b"Content-Type").unwrap();
                response.add_header("Access-Control-Max-Age", b"60").unwrap();
                response.done_headers().unwrap();
                response.done();
                return None;
            }
            MethodNotAllowed(methods) => {
                let reason = "Method Not Allowed";
                response.status(405, reason);
                response.add_length(reason.len() as u64).unwrap();
                response.add_header("Access-Control-Allow-Origin", b"*").unwrap();
                response.add_header("Content-Type", b"text/plain").unwrap();
                response.add_header("Allow", methods).unwrap();
                response.done_headers().unwrap();
                response.write_body(reason.as_bytes());
                response.done();
                return None;
            }
            NotFound => {
                let reason = "Not Found";
                response.status(404, reason);
                response.add_length(reason.len() as u64).unwrap();
                response.add_header("Access-Control-Allow-Origin", b"*").unwrap();
                response.add_header("Content-Type", b"text/plain").unwrap();
                response.done_headers().unwrap();
                response.write_body(reason.as_bytes());
                response.done();
                return None;
            },
        };
        response.status(status, reason);
        response.add_length(body.len() as u64).unwrap();
        response.add_header("Access-Control-Allow-Origin", b"*").unwrap();
        response.add_header("Content-Type", b"application/json").unwrap();
        response.done_headers().unwrap();
        response.write_body(&body[..]);
        response.done();
        None
    }
    // It is save to leave out `request_chunk` and `request_end` since we
    // only use buffered requests in this example.
    fn request_chunk(self, _chunk: &[u8], _response: &mut Response,
        _scope: &mut Scope<Context>)
        -> Option<Self> { unreachable!(); }
    fn request_end(self, _response: &mut Response, _scope: &mut Scope<Context>)
        -> Option<Self> { unreachable!(); }

    fn timeout(self, _response: &mut Response, _scope: &mut Scope<Context>)
        -> Option<(Self, Time)>
    {
        unimplemented!();
    }
    fn wakeup(self, _response: &mut Response, _scope: &mut Scope<Context>)
        -> Option<Self>
    {
        unimplemented!();
    }
}

#[cfg(feature="nightly")]
fn main() {
    let event_loop = rotor::Loop::new(&rotor::Config::new()).unwrap();
    let mut loop_inst = event_loop.instantiate(Context {
        last_id: 0,
        database: HashMap::new(),
    });
    let lst = TcpListener::bind(&"127.0.0.1:3000".parse().unwrap()).unwrap();
    loop_inst.add_machine_with(|scope| {
        ServerFsm::<TodoBackend, _>::new(lst, scope)
    }).unwrap();
    loop_inst.run().unwrap();
}

#[cfg(not(feature="nightly"))]
fn main() { panic!("See NOTE in source. You must use --features nightly.")}
<|endoftext|>


<commit_before>use rustc_target::spec::{HasTargetSpec, Target};

use cranelift::codegen::ir::{Opcode, InstructionData, ValueDef};
use cranelift_module::Module;

use crate::prelude::*;

pub fn mir_var(loc: Local) -> Variable {
    Variable::with_u32(loc.index() as u32)
}

pub fn pointer_ty(tcx: TyCtxt) -> types::Type {
    match tcx.data_layout.pointer_size.bits() {
        16 => types::I16,
        32 => types::I32,
        64 => types::I64,
        bits => bug!("ptr_sized_integer: unknown pointer bit size {}", bits),
    }
}

pub fn clif_type_from_ty<'tcx>(
    tcx: TyCtxt<'tcx>,
    ty: Ty<'tcx>,
) -> Option<types::Type> {
    Some(match ty.sty {
        ty::Bool => types::I8,
        ty::Uint(size) => match size {
            UintTy::U8 => types::I8,
            UintTy::U16 => types::I16,
            UintTy::U32 => types::I32,
            UintTy::U64 => types::I64,
            UintTy::U128 => types::I128,
            UintTy::Usize => pointer_ty(tcx),
        },
        ty::Int(size) => match size {
            IntTy::I8 => types::I8,
            IntTy::I16 => types::I16,
            IntTy::I32 => types::I32,
            IntTy::I64 => types::I64,
            IntTy::I128 => types::I128,
            IntTy::Isize => pointer_ty(tcx),
        },
        ty::Char => types::I32,
        ty::Float(size) => match size {
            FloatTy::F32 => types::F32,
            FloatTy::F64 => types::F64,
        },
        ty::FnPtr(_) => pointer_ty(tcx),
        ty::RawPtr(TypeAndMut { ty, mutbl: _ }) | ty::Ref(_, ty, _) => {
            if ty.is_sized(tcx.at(DUMMY_SP), ParamEnv::reveal_all()) {
                pointer_ty(tcx)
            } else {
                return None;
            }
        }
        ty::Param(_) => bug!("ty param {:?}", ty),
        _ => return None,
    })
}

pub fn codegen_select(bcx: &mut FunctionBuilder, cond: Value, lhs: Value, rhs: Value) -> Value {
    let lhs_ty = bcx.func.dfg.value_type(lhs);
    let rhs_ty = bcx.func.dfg.value_type(rhs);
    assert_eq!(lhs_ty, rhs_ty);
    if lhs_ty == types::I8 || lhs_ty == types::I16 {
        // FIXME workaround for missing encoding for select.i8
        let lhs = bcx.ins().uextend(types::I32, lhs);
        let rhs = bcx.ins().uextend(types::I32, rhs);
        let res = bcx.ins().select(cond, lhs, rhs);
        bcx.ins().ireduce(lhs_ty, res)
    } else {
        bcx.ins().select(cond, lhs, rhs)
    }
}

fn resolve_normal_value_imm(func: &Function, val: Value) -> Option<i64> {
    if let ValueDef::Result(inst, 0 /*param*/) = func.dfg.value_def(val) {
        if let InstructionData::UnaryImm {
            opcode: Opcode::Iconst,
            imm,
        } = func.dfg[inst] {
            Some(imm.into())
        } else {
            None
        }
    } else {
        None
    }
}

fn resolve_128bit_value_imm(func: &Function, val: Value) -> Option<u128> {
    let (lsb, msb) = if let ValueDef::Result(inst, 0 /*param*/) = func.dfg.value_def(val) {
        if let InstructionData::Binary {
            opcode: Opcode::Iconcat,
            args: [lsb, msb],
        } = func.dfg[inst] {
            (lsb, msb)
        } else {
            return None;
        }
    } else {
        return None;
    };

    let lsb = resolve_normal_value_imm(func, lsb)? as u64 as u128;
    let msb = resolve_normal_value_imm(func, msb)? as u64 as u128;

    Some(msb << 64 | lsb)
}

pub fn resolve_value_imm(func: &Function, val: Value) -> Option<u128> {
    if func.dfg.value_type(val) == types::I128 {
        resolve_128bit_value_imm(func, val)
    } else {
        resolve_normal_value_imm(func, val).map(|imm| imm as u64 as u128)
    }
}

pub fn type_min_max_value(ty: Type, signed: bool) -> (i64, i64) {
    assert!(ty.is_int());
    let min = match (ty, signed) {
        (types::I8 , false)
        | (types::I16, false)
        | (types::I32, false)
        | (types::I64, false) => 0i64,
        (types::I8, true) => i8::min_value() as i64,
        (types::I16, true) => i16::min_value() as i64,
        (types::I32, true) => i32::min_value() as i64,
        (types::I64, true) => i64::min_value(),
        (types::I128, _) => unimplemented!(),
        _ => unreachable!(),
    };

    let max = match (ty, signed) {
        (types::I8, false) => u8::max_value() as i64,
        (types::I16, false) => u16::max_value() as i64,
        (types::I32, false) => u32::max_value() as i64,
        (types::I64, false) => u64::max_value() as i64,
        (types::I8, true) => i8::max_value() as i64,
        (types::I16, true) => i16::max_value() as i64,
        (types::I32, true) => i32::max_value() as i64,
        (types::I64, true) => i64::max_value(),
        (types::I128, _) => unimplemented!(),
        _ => unreachable!(),
    };

    (min, max)
}

pub fn type_sign(ty: Ty<'_>) -> bool {
    match ty.sty {
        ty::Ref(..) | ty::RawPtr(..) | ty::FnPtr(..) | ty::Char | ty::Uint(..) | ty::Bool => false,
        ty::Int(..) => true,
        ty::Float(..) => false, // `signed` is unused for floats
        _ => panic!("{}", ty),
    }
}

pub struct FunctionCx<'a, 'tcx: 'a, B: Backend> {
    // FIXME use a reference to `CodegenCx` instead of `tcx`, `module` and `constants` and `caches`
    pub tcx: TyCtxt<'tcx>,
    pub module: &'a mut Module<B>,
    pub pointer_type: Type, // Cached from module

    pub instance: Instance<'tcx>,
    pub mir: &'tcx Body<'tcx>,

    pub bcx: FunctionBuilder<'a>,
    pub ebb_map: HashMap<BasicBlock, Ebb>,
    pub local_map: HashMap<Local, CPlace<'tcx>>,

    pub clif_comments: crate::pretty_clif::CommentWriter,
    pub constants: &'a mut crate::constant::ConstantCx,
    pub caches: &'a mut Caches<'tcx>,
    pub source_info_set: indexmap::IndexSet<SourceInfo>,
}

impl<'a, 'tcx: 'a, B: Backend> LayoutOf for FunctionCx<'a, 'tcx, B> {
    type Ty = Ty<'tcx>;
    type TyLayout = TyLayout<'tcx>;

    fn layout_of(&self, ty: Ty<'tcx>) -> TyLayout<'tcx> {
        let ty = self.monomorphize(&ty);
        self.tcx.layout_of(ParamEnv::reveal_all().and(&ty)).unwrap()
    }
}

impl<'a, 'tcx, B: Backend + 'a> layout::HasTyCtxt<'tcx> for FunctionCx<'a, 'tcx, B> {
    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
        self.tcx
    }
}

impl<'a, 'tcx, B: Backend + 'a> layout::HasDataLayout for FunctionCx<'a, 'tcx, B> {
    fn data_layout(&self) -> &layout::TargetDataLayout {
        &self.tcx.data_layout
    }
}

impl<'a, 'tcx, B: Backend + 'a> layout::HasParamEnv<'tcx> for FunctionCx<'a, 'tcx, B> {
    fn param_env(&self) -> ParamEnv<'tcx> {
        ParamEnv::reveal_all()
    }
}

impl<'a, 'tcx, B: Backend + 'a> HasTargetSpec for FunctionCx<'a, 'tcx, B> {
    fn target_spec(&self) -> &Target {
        &self.tcx.sess.target.target
    }
}

impl<'a, 'tcx, B: Backend> BackendTypes for FunctionCx<'a, 'tcx, B> {
    type Value = Value;
    type BasicBlock = Ebb;
    type Type = Type;
    type Funclet = !;
    type DIScope = !;
}

impl<'a, 'tcx: 'a, B: Backend + 'a> FunctionCx<'a, 'tcx, B> {
    pub fn monomorphize<T>(&self, value: &T) -> T
    where
        T: TypeFoldable<'tcx>,
    {
        self.tcx.subst_and_normalize_erasing_regions(
            self.instance.substs,
            ty::ParamEnv::reveal_all(),
            value,
        )
    }

    pub fn clif_type(&self, ty: Ty<'tcx>) -> Option<Type> {
        clif_type_from_ty(self.tcx, self.monomorphize(&ty))
    }

    pub fn get_ebb(&self, bb: BasicBlock) -> Ebb {
        *self.ebb_map.get(&bb).unwrap()
    }

    pub fn get_local_place(&mut self, local: Local) -> CPlace<'tcx> {
        *self.local_map.get(&local).unwrap()
    }

    pub fn set_debug_loc(&mut self, source_info: mir::SourceInfo) {
        let (index, _) = self.source_info_set.insert_full(source_info);
        self.bcx.set_srcloc(SourceLoc::new(index as u32));
    }
}
<commit_msg>Fix a panic on type size overflow<commit_after>use rustc_target::spec::{HasTargetSpec, Target};

use cranelift::codegen::ir::{Opcode, InstructionData, ValueDef};
use cranelift_module::Module;

use crate::prelude::*;

pub fn mir_var(loc: Local) -> Variable {
    Variable::with_u32(loc.index() as u32)
}

pub fn pointer_ty(tcx: TyCtxt) -> types::Type {
    match tcx.data_layout.pointer_size.bits() {
        16 => types::I16,
        32 => types::I32,
        64 => types::I64,
        bits => bug!("ptr_sized_integer: unknown pointer bit size {}", bits),
    }
}

pub fn clif_type_from_ty<'tcx>(
    tcx: TyCtxt<'tcx>,
    ty: Ty<'tcx>,
) -> Option<types::Type> {
    Some(match ty.sty {
        ty::Bool => types::I8,
        ty::Uint(size) => match size {
            UintTy::U8 => types::I8,
            UintTy::U16 => types::I16,
            UintTy::U32 => types::I32,
            UintTy::U64 => types::I64,
            UintTy::U128 => types::I128,
            UintTy::Usize => pointer_ty(tcx),
        },
        ty::Int(size) => match size {
            IntTy::I8 => types::I8,
            IntTy::I16 => types::I16,
            IntTy::I32 => types::I32,
            IntTy::I64 => types::I64,
            IntTy::I128 => types::I128,
            IntTy::Isize => pointer_ty(tcx),
        },
        ty::Char => types::I32,
        ty::Float(size) => match size {
            FloatTy::F32 => types::F32,
            FloatTy::F64 => types::F64,
        },
        ty::FnPtr(_) => pointer_ty(tcx),
        ty::RawPtr(TypeAndMut { ty, mutbl: _ }) | ty::Ref(_, ty, _) => {
            if ty.is_sized(tcx.at(DUMMY_SP), ParamEnv::reveal_all()) {
                pointer_ty(tcx)
            } else {
                return None;
            }
        }
        ty::Param(_) => bug!("ty param {:?}", ty),
        _ => return None,
    })
}

pub fn codegen_select(bcx: &mut FunctionBuilder, cond: Value, lhs: Value, rhs: Value) -> Value {
    let lhs_ty = bcx.func.dfg.value_type(lhs);
    let rhs_ty = bcx.func.dfg.value_type(rhs);
    assert_eq!(lhs_ty, rhs_ty);
    if lhs_ty == types::I8 || lhs_ty == types::I16 {
        // FIXME workaround for missing encoding for select.i8
        let lhs = bcx.ins().uextend(types::I32, lhs);
        let rhs = bcx.ins().uextend(types::I32, rhs);
        let res = bcx.ins().select(cond, lhs, rhs);
        bcx.ins().ireduce(lhs_ty, res)
    } else {
        bcx.ins().select(cond, lhs, rhs)
    }
}

fn resolve_normal_value_imm(func: &Function, val: Value) -> Option<i64> {
    if let ValueDef::Result(inst, 0 /*param*/) = func.dfg.value_def(val) {
        if let InstructionData::UnaryImm {
            opcode: Opcode::Iconst,
            imm,
        } = func.dfg[inst] {
            Some(imm.into())
        } else {
            None
        }
    } else {
        None
    }
}

fn resolve_128bit_value_imm(func: &Function, val: Value) -> Option<u128> {
    let (lsb, msb) = if let ValueDef::Result(inst, 0 /*param*/) = func.dfg.value_def(val) {
        if let InstructionData::Binary {
            opcode: Opcode::Iconcat,
            args: [lsb, msb],
        } = func.dfg[inst] {
            (lsb, msb)
        } else {
            return None;
        }
    } else {
        return None;
    };

    let lsb = resolve_normal_value_imm(func, lsb)? as u64 as u128;
    let msb = resolve_normal_value_imm(func, msb)? as u64 as u128;

    Some(msb << 64 | lsb)
}

pub fn resolve_value_imm(func: &Function, val: Value) -> Option<u128> {
    if func.dfg.value_type(val) == types::I128 {
        resolve_128bit_value_imm(func, val)
    } else {
        resolve_normal_value_imm(func, val).map(|imm| imm as u64 as u128)
    }
}

pub fn type_min_max_value(ty: Type, signed: bool) -> (i64, i64) {
    assert!(ty.is_int());
    let min = match (ty, signed) {
        (types::I8 , false)
        | (types::I16, false)
        | (types::I32, false)
        | (types::I64, false) => 0i64,
        (types::I8, true) => i8::min_value() as i64,
        (types::I16, true) => i16::min_value() as i64,
        (types::I32, true) => i32::min_value() as i64,
        (types::I64, true) => i64::min_value(),
        (types::I128, _) => unimplemented!(),
        _ => unreachable!(),
    };

    let max = match (ty, signed) {
        (types::I8, false) => u8::max_value() as i64,
        (types::I16, false) => u16::max_value() as i64,
        (types::I32, false) => u32::max_value() as i64,
        (types::I64, false) => u64::max_value() as i64,
        (types::I8, true) => i8::max_value() as i64,
        (types::I16, true) => i16::max_value() as i64,
        (types::I32, true) => i32::max_value() as i64,
        (types::I64, true) => i64::max_value(),
        (types::I128, _) => unimplemented!(),
        _ => unreachable!(),
    };

    (min, max)
}

pub fn type_sign(ty: Ty<'_>) -> bool {
    match ty.sty {
        ty::Ref(..) | ty::RawPtr(..) | ty::FnPtr(..) | ty::Char | ty::Uint(..) | ty::Bool => false,
        ty::Int(..) => true,
        ty::Float(..) => false, // `signed` is unused for floats
        _ => panic!("{}", ty),
    }
}

pub struct FunctionCx<'a, 'tcx: 'a, B: Backend> {
    // FIXME use a reference to `CodegenCx` instead of `tcx`, `module` and `constants` and `caches`
    pub tcx: TyCtxt<'tcx>,
    pub module: &'a mut Module<B>,
    pub pointer_type: Type, // Cached from module

    pub instance: Instance<'tcx>,
    pub mir: &'tcx Body<'tcx>,

    pub bcx: FunctionBuilder<'a>,
    pub ebb_map: HashMap<BasicBlock, Ebb>,
    pub local_map: HashMap<Local, CPlace<'tcx>>,

    pub clif_comments: crate::pretty_clif::CommentWriter,
    pub constants: &'a mut crate::constant::ConstantCx,
    pub caches: &'a mut Caches<'tcx>,
    pub source_info_set: indexmap::IndexSet<SourceInfo>,
}

impl<'a, 'tcx: 'a, B: Backend> LayoutOf for FunctionCx<'a, 'tcx, B> {
    type Ty = Ty<'tcx>;
    type TyLayout = TyLayout<'tcx>;

    fn layout_of(&self, ty: Ty<'tcx>) -> TyLayout<'tcx> {
        let ty = self.monomorphize(&ty);
        self.tcx.layout_of(ParamEnv::reveal_all().and(&ty))
            .unwrap_or_else(|e| if let layout::LayoutError::SizeOverflow(_) = e {
                self.tcx.sess.fatal(&e.to_string())
            } else {
                bug!("failed to get layout for `{}`: {}", ty, e)
            })
    }
}

impl<'a, 'tcx, B: Backend + 'a> layout::HasTyCtxt<'tcx> for FunctionCx<'a, 'tcx, B> {
    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
        self.tcx
    }
}

impl<'a, 'tcx, B: Backend + 'a> layout::HasDataLayout for FunctionCx<'a, 'tcx, B> {
    fn data_layout(&self) -> &layout::TargetDataLayout {
        &self.tcx.data_layout
    }
}

impl<'a, 'tcx, B: Backend + 'a> layout::HasParamEnv<'tcx> for FunctionCx<'a, 'tcx, B> {
    fn param_env(&self) -> ParamEnv<'tcx> {
        ParamEnv::reveal_all()
    }
}

impl<'a, 'tcx, B: Backend + 'a> HasTargetSpec for FunctionCx<'a, 'tcx, B> {
    fn target_spec(&self) -> &Target {
        &self.tcx.sess.target.target
    }
}

impl<'a, 'tcx, B: Backend> BackendTypes for FunctionCx<'a, 'tcx, B> {
    type Value = Value;
    type BasicBlock = Ebb;
    type Type = Type;
    type Funclet = !;
    type DIScope = !;
}

impl<'a, 'tcx: 'a, B: Backend + 'a> FunctionCx<'a, 'tcx, B> {
    pub fn monomorphize<T>(&self, value: &T) -> T
    where
        T: TypeFoldable<'tcx>,
    {
        self.tcx.subst_and_normalize_erasing_regions(
            self.instance.substs,
            ty::ParamEnv::reveal_all(),
            value,
        )
    }

    pub fn clif_type(&self, ty: Ty<'tcx>) -> Option<Type> {
        clif_type_from_ty(self.tcx, self.monomorphize(&ty))
    }

    pub fn get_ebb(&self, bb: BasicBlock) -> Ebb {
        *self.ebb_map.get(&bb).unwrap()
    }

    pub fn get_local_place(&mut self, local: Local) -> CPlace<'tcx> {
        *self.local_map.get(&local).unwrap()
    }

    pub fn set_debug_loc(&mut self, source_info: mir::SourceInfo) {
        let (index, _) = self.source_info_set.insert_full(source_info);
        self.bcx.set_srcloc(SourceLoc::new(index as u32));
    }
}
<|endoftext|>


<commit_before>use js::value::{Value, VNumber, VInteger, VFunction, VObject, ResultValue};
use js::function::{NativeFunction, NativeFunc};
use js::object::ObjectData;
use collections::treemap::TreeMap;
use rand::random;
use std::io::stdio;
use std::f64;
use std::gc::Gc;
use std::cell::RefCell;

/// Get the absolute value of a number
pub fn abs(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().abs()
	} else {
		f64::NAN
	})))
}
/// Get the arccos of a number
pub fn acos(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().acos()
	} else {
		f64::NAN
	})))
}
/// Get the arcsine of a number
pub fn asin(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().asin()
	} else {
		f64::NAN
	})))
}
/// Get the arctangent of a number
pub fn atan(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().atan()
	} else {
		f64::NAN
	})))
}
/// Get the arctangent of a numbers
pub fn atan2(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().atan2(&args.get(1).borrow().to_num())
	} else {
		f64::NAN
	})))
}
/// Get the cubic root of a number
pub fn cbrt(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().cbrt()
	} else {
		f64::NAN
	})))
}
/// Get lowest integer above a number
pub fn ceil(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().ceil()
	} else {
		f64::NAN
	})))
}
/// Get the cosine of a number
pub fn cos(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().cos()
	} else {
		f64::NAN
	})))
}
/// Get the highest integer below a number
pub fn floor(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().floor()
	} else {
		f64::NAN
	})))
}
/// Generate a random floating-point number between 0 and 1
pub fn _random(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(random())))
}
/// Get the sine of a number
pub fn sin(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().sin()
	} else {
		f64::NAN
	})))
}
/// Get the tangent of a number
pub fn tan(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().tan()
	} else {
		f64::NAN
	})))
}
/// Create a new 'Math' object
pub fn _create() -> Value {
	let mut math = TreeMap::new();
	math.insert(~"E", Gc::new(VNumber(f64::consts::E)));
	math.insert(~"LN2", Gc::new(VNumber(f64::consts::LN_2)));
	math.insert(~"LN10", Gc::new(VNumber(f64::consts::LN_10)));
	math.insert(~"LOG2E", Gc::new(VNumber(f64::consts::LOG2_E)));
	math.insert(~"LOG10E", Gc::new(VNumber(f64::consts::LOG10_E)));
	math.insert(~"SQRT1_2", Gc::new(VNumber(0.5f64.sqrt())));
	math.insert(~"SQRT2", Gc::new(VNumber(f64::consts::SQRT2)));
	math.insert(~"PI", Gc::new(VNumber(f64::consts::PI)));
	math.insert(~"abs", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(abs, 1))))));
	math.insert(~"acos", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(acos, 1))))));
	math.insert(~"asin", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(asin, 1))))));
	math.insert(~"atan", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(atan, 1))))));
	math.insert(~"atan2", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(atan2, 2))))));
	math.insert(~"cbrt", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(cbrt, 1))))));
	math.insert(~"ceil", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(ceil, 1))))));
	math.insert(~"cos", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(cos, 1))))));
	math.insert(~"floor", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(floor, 1))))));
	math.insert(~"random", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(_random, 0))))));
	math.insert(~"sin", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(sin, 1))))));
	math.insert(~"tan", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(tan, 1))))));
	Gc::new(VObject(RefCell::new(math)))
}<commit_msg>Add Math.exp(x)<commit_after>use js::value::{Value, VNumber, VInteger, VFunction, VObject, ResultValue};
use js::function::{NativeFunction, NativeFunc};
use js::object::ObjectData;
use collections::treemap::TreeMap;
use rand::random;
use std::io::stdio;
use std::f64;
use std::gc::Gc;
use std::cell::RefCell;

/// Get the absolute value of a number
pub fn abs(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().abs()
	} else {
		f64::NAN
	})))
}
/// Get the arccos of a number
pub fn acos(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().acos()
	} else {
		f64::NAN
	})))
}
/// Get the arcsine of a number
pub fn asin(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().asin()
	} else {
		f64::NAN
	})))
}
/// Get the arctangent of a number
pub fn atan(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().atan()
	} else {
		f64::NAN
	})))
}
/// Get the arctangent of a numbers
pub fn atan2(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().atan2(&args.get(1).borrow().to_num())
	} else {
		f64::NAN
	})))
}
/// Get the cubic root of a number
pub fn cbrt(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().cbrt()
	} else {
		f64::NAN
	})))
}
/// Get lowest integer above a number
pub fn ceil(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().ceil()
	} else {
		f64::NAN
	})))
}
/// Get the cosine of a number
pub fn cos(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().cos()
	} else {
		f64::NAN
	})))
}
/// Get the power to raise the natural logarithm to get the number
pub fn exp(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().exp()
	} else {
		f64::NAN
	})))
}
/// Get the highest integer below a number
pub fn floor(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().floor()
	} else {
		f64::NAN
	})))
}
/// Generate a random floating-point number between 0 and 1
pub fn _random(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(random())))
}
/// Get the sine of a number
pub fn sin(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().sin()
	} else {
		f64::NAN
	})))
}
/// Get the tangent of a number
pub fn tan(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().tan()
	} else {
		f64::NAN
	})))
}
/// Create a new 'Math' object
pub fn _create() -> Value {
	let mut math = TreeMap::new();
	math.insert(~"E", Gc::new(VNumber(f64::consts::E)));
	math.insert(~"LN2", Gc::new(VNumber(f64::consts::LN_2)));
	math.insert(~"LN10", Gc::new(VNumber(f64::consts::LN_10)));
	math.insert(~"LOG2E", Gc::new(VNumber(f64::consts::LOG2_E)));
	math.insert(~"LOG10E", Gc::new(VNumber(f64::consts::LOG10_E)));
	math.insert(~"SQRT1_2", Gc::new(VNumber(0.5f64.sqrt())));
	math.insert(~"SQRT2", Gc::new(VNumber(f64::consts::SQRT2)));
	math.insert(~"PI", Gc::new(VNumber(f64::consts::PI)));
	math.insert(~"abs", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(abs, 1))))));
	math.insert(~"acos", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(acos, 1))))));
	math.insert(~"asin", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(asin, 1))))));
	math.insert(~"atan", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(atan, 1))))));
	math.insert(~"atan2", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(atan2, 2))))));
	math.insert(~"cbrt", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(cbrt, 1))))));
	math.insert(~"ceil", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(ceil, 1))))));
	math.insert(~"cos", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(cos, 1))))));
	math.insert(~"exp", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(exp, 1))))));
	math.insert(~"floor", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(floor, 1))))));
	math.insert(~"random", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(_random, 0))))));
	math.insert(~"sin", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(sin, 1))))));
	math.insert(~"tan", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(tan, 1))))));
	Gc::new(VObject(RefCell::new(math)))
}<|endoftext|>