<commit_before>use std::borrow::Cow;
use std::collections::{HashMap, HashSet};
use std::collections::hash_map;
use std::rc::Rc;

use render::Renderer;
use routing::{DagHandle, Edge, Effect, GraphWatcher, NodeData, NodeHandle};

#[derive(Default)]
pub struct RefRenderer {
    nodes: HashMap<NodeHandle, Node>,
}

struct Node {
    data: MyNodeData,
    inbound: HashSet<Edge>
}

enum MyNodeData {
    /// This node is a non-primitive effect.
    UserNode(Rc<Effect>),
    /// This node is an instance of another DAG.
    Graph(DagHandle),
    /// Primitive Delay(samples) effect
    Delay(u64),
    /// Primitive Constant(value) effect.
    /// Also serves as a unit step;
    /// Returns the f32 value for t >= 0, else 0.
    Constant(f32),
    /// Primitive effect to multiply TWO input streams sample-wise.
    Multiply,
    /// This node is a DAG definition. i.e. it holds the output edges of a DAG.
    DagIO,
}

impl Renderer for RefRenderer {
    fn get_sample(&mut self, time: u64, ch: u8) -> f32 {
        // Try to find the edge that goes to -> (Null, slot=0, ch=ch)
        let root_handle = NodeHandle::toplevel();
        match self.nodes.get(&root_handle) {
            // for an empty graph, yield silence.
            None => 0f32,
            Some(node) => {
                // find all edges to ([Null], slot=0, ch=ch)
                self.sum_input_to_slot(node, time, 0, ch, &Vec::new())
            }
        }
    }
}
impl RefRenderer {
    /// Get the value on an edge at a particular time
    /// When backtracking from the output, we push each Node onto the context if we enter inside of
    ///   it (i.e. if it's a nested DAG) & pop when exiting.
    fn get_value(&self, edge: &Edge, time: u64, context: &Vec<NodeHandle>) -> f32 {
        let from = edge.from_full();
        if *from.node_handle() == None {
            // Reading from one of the inputs to the top of `context`
            let mut new_context = context.clone();
            let head = new_context.pop().unwrap();
            // Sum the inputs to the matching slot/ch
            let in_edges = self.nodes[&head].inbound.iter().filter(|in_edge| {
                in_edge.to_slot() == edge.from_slot() && in_edge.to_ch() == edge.from_ch()
            });
            let in_values = in_edges.map(|in_edge| {
                self.get_value(in_edge, time, &new_context)
            });
            in_values.sum()
        } else {
            // Reading from another node within the DAG
            let node = &self.nodes[&from];
            match node.data {
                MyNodeData::UserNode(ref _effect) => unimplemented!(),
                // Output = sum of all edges to Null of the same slot & ch, within the given DAG.
                MyNodeData::Graph(ref dag_handle) => {
                    let mut new_context = context.clone();
                    new_context.push(from);
                    let subdag = &self.nodes[&NodeHandle::new_dag(dag_handle.clone())];
                    let out_edges = subdag.inbound.iter().filter(|out_edge| {
                        out_edge.to_slot() == edge.from_slot() && out_edge.to_ch() == edge.from_ch()
                    });
                    let out_values = out_edges.map(|out_edge| {
                        self.get_value(out_edge, time, &new_context)
                    });
                    out_values.sum()
                }
                // Output = sum of all inputs to slot 0 of the same ch.
                MyNodeData::Delay(ref frames) => {
                    // The only nonzero output is slot=1.
                    if edge.from_slot() != 1 {
                        println!("Warning: attempt to read from Delay slot != 1");
                        0f32
                    } else {
                        match time.checked_sub(*frames) {
                            // t < 0 => no audio
                            None => 0f32,
                            Some(origin_time) => self.sum_input_to_slot(node, origin_time, 0, edge.from_ch(), context)
                        }
                    }
                },
                MyNodeData::Constant(ref value) => {
                    // The only nonzero output is slot=1.
                    if edge.from_slot() != 1 {
                        println!("Warning: attempt to read from Constant slot != 1");
                        0f32
                    } else {
                        *value
                    }
                },
                MyNodeData::Multiply => {
                    // The only nonzero output is slot=1.
                    if edge.from_slot() != 1 {
                        println!("Warning: attempt to read from Multiply slot != 1");
                        0f32
                    } else {
                        // Sum all inputs from slot=0 and slot=2 into two separate
                        // variables, then multiply them.
                        let val_a = self.sum_input_to_slot(node, time, 0, edge.from_ch(), context);
                        let val_b = self.sum_input_to_slot(node, time, 2, edge.from_ch(), context);
                        val_a * val_b
                    }
                },
                _ => panic!("Internal RefRenderer error: illegal node type"),
            }
        }
    }
    /// Return the sum of all inputs into a specific slot/channel of the given
    /// node at the given time.
    fn sum_input_to_slot(&self, node: &Node, time: u64, slot: u32, ch: u8, context: &Vec<NodeHandle>) -> f32 {
        let edges_in = node.inbound.iter().filter(|in_edge| {
            in_edge.to_slot() == slot && in_edge.to_ch() == ch
        });
        edges_in.map(|edge| self.get_value(edge, time, context)).sum()
    }
}

impl GraphWatcher for RefRenderer {
    fn on_add_node(&mut self, handle: &NodeHandle, data: &NodeData) {
        let my_node_data = match *data {
            NodeData::Graph(ref handle) => MyNodeData::Graph(handle.clone()),
            NodeData::Effect(ref effect) => {
                match effect.meta().get_primitive_url() {
                    Some(ref url) => {
                        let mut params: HashMap<_, _> = url.query_pairs().collect();
                        match url.path() {
                            "/Delay" => {
                                let frames: u64 = match params.entry(Cow::from("frames")) {
                                    hash_map::Entry::Occupied(e) => e.remove().parse().unwrap(),
                                    hash_map::Entry::Vacant(_) => 0u64,
                                };
                                // Make sure we consumed all arguments.
                                assert!(params.is_empty());
                                MyNodeData::Delay(frames)
                            },
                            "/Constant" => {
                                let value: f32 = match params.entry(Cow::from("value")) {
                                    hash_map::Entry::Occupied(e) => e.remove().parse().unwrap(),
                                    hash_map::Entry::Vacant(_) => 0f32,
                                };
                                // Make sure we consumed all arguments.
                                assert!(params.is_empty());
                                MyNodeData::Constant(value)
                            },
                            "/Multiply" => MyNodeData::Multiply,
                            _ => panic!("Unrecognized primitive effect: {} (full url: {})", url.path(), url),
                        }
                    }
                    None => MyNodeData::UserNode(effect.clone())
                }
            }
        };
        self.nodes.insert(handle.clone(), Node::new(my_node_data));
        // If the node is part of a new DAG, allocate data so that future edges
        // to null within the DAG can be held.
        self.nodes.entry(NodeHandle::new_dag(handle.dag_handle().clone())).or_insert_with(|| {
            Node::new(MyNodeData::DagIO)
        });
    }
    fn on_del_node(&mut self, handle: &NodeHandle) {
        self.nodes.remove(handle);
    }
    fn on_add_edge(&mut self, edge: &Edge) {
        self.nodes.get_mut(&edge.to_full()).unwrap().inbound.insert(edge.clone());
    }
    fn on_del_edge(&mut self, edge: &Edge) {
        self.nodes.get_mut(&edge.to_full()).unwrap().inbound.remove(edge);
    }
}

impl Node {
    fn new(data: MyNodeData) -> Self {
        Node {
            data: data,
            inbound: HashSet::new(),
        }
    }
}
<commit_msg>Prefer sum_input_to_slot when applicable<commit_after>use std::borrow::Cow;
use std::collections::{HashMap, HashSet};
use std::collections::hash_map;
use std::rc::Rc;

use render::Renderer;
use routing::{DagHandle, Edge, Effect, GraphWatcher, NodeData, NodeHandle};

#[derive(Default)]
pub struct RefRenderer {
    nodes: HashMap<NodeHandle, Node>,
}

struct Node {
    data: MyNodeData,
    inbound: HashSet<Edge>
}

enum MyNodeData {
    /// This node is a non-primitive effect.
    UserNode(Rc<Effect>),
    /// This node is an instance of another DAG.
    Graph(DagHandle),
    /// Primitive Delay(samples) effect
    Delay(u64),
    /// Primitive Constant(value) effect.
    /// Also serves as a unit step;
    /// Returns the f32 value for t >= 0, else 0.
    Constant(f32),
    /// Primitive effect to multiply TWO input streams sample-wise.
    Multiply,
    /// This node is a DAG definition. i.e. it holds the output edges of a DAG.
    DagIO,
}

impl Renderer for RefRenderer {
    fn get_sample(&mut self, time: u64, ch: u8) -> f32 {
        // Try to find the edge that goes to -> (Null, slot=0, ch=ch)
        let root_handle = NodeHandle::toplevel();
        match self.nodes.get(&root_handle) {
            // for an empty graph, yield silence.
            None => 0f32,
            Some(node) => {
                // find all edges to ([Null], slot=0, ch=ch)
                self.sum_input_to_slot(node, time, 0, ch, &Vec::new())
            }
        }
    }
}
impl RefRenderer {
    /// Get the value on an edge at a particular time
    /// When backtracking from the output, we push each Node onto the context if we enter inside of
    ///   it (i.e. if it's a nested DAG) & pop when exiting.
    fn get_value(&self, edge: &Edge, time: u64, context: &Vec<NodeHandle>) -> f32 {
        let from = edge.from_full();
        if *from.node_handle() == None {
            // Reading from one of the inputs to the top of `context`
            let mut new_context = context.clone();
            let head = new_context.pop().unwrap();
            // Sum the inputs to the matching slot/ch
            self.sum_input_to_slot(&self.nodes[&head], time, edge.from_slot(), edge.from_ch(), &new_context)
        } else {
            // Reading from another node within the DAG
            let node = &self.nodes[&from];
            match node.data {
                MyNodeData::UserNode(ref _effect) => unimplemented!(),
                // Output = sum of all edges to Null of the same slot & ch, within the given DAG.
                MyNodeData::Graph(ref dag_handle) => {
                    let mut new_context = context.clone();
                    new_context.push(from);
                    let subdag = &self.nodes[&NodeHandle::new_dag(dag_handle.clone())];
                    self.sum_input_to_slot(&subdag, time, edge.from_slot(), edge.from_ch(), &new_context)
                }
                // Output = sum of all inputs to slot 0 of the same ch.
                MyNodeData::Delay(ref frames) => {
                    // The only nonzero output is slot=1.
                    if edge.from_slot() != 1 {
                        println!("Warning: attempt to read from Delay slot != 1");
                        0f32
                    } else {
                        match time.checked_sub(*frames) {
                            // t < 0 => no audio
                            None => 0f32,
                            Some(origin_time) => self.sum_input_to_slot(node, origin_time, 0, edge.from_ch(), context)
                        }
                    }
                },
                MyNodeData::Constant(ref value) => {
                    // The only nonzero output is slot=1.
                    if edge.from_slot() != 1 {
                        println!("Warning: attempt to read from Constant slot != 1");
                        0f32
                    } else {
                        *value
                    }
                },
                MyNodeData::Multiply => {
                    // The only nonzero output is slot=1.
                    if edge.from_slot() != 1 {
                        println!("Warning: attempt to read from Multiply slot != 1");
                        0f32
                    } else {
                        // Sum all inputs from slot=0 and slot=2 into two separate
                        // variables, then multiply them.
                        let val_a = self.sum_input_to_slot(node, time, 0, edge.from_ch(), context);
                        let val_b = self.sum_input_to_slot(node, time, 2, edge.from_ch(), context);
                        val_a * val_b
                    }
                },
                _ => panic!("Internal RefRenderer error: illegal node type"),
            }
        }
    }
    /// Return the sum of all inputs into a specific slot/channel of the given
    /// node at the given time.
    fn sum_input_to_slot(&self, node: &Node, time: u64, slot: u32, ch: u8, context: &Vec<NodeHandle>) -> f32 {
        let edges_in = node.inbound.iter().filter(|in_edge| {
            in_edge.to_slot() == slot && in_edge.to_ch() == ch
        });
        edges_in.map(|edge| self.get_value(edge, time, context)).sum()
    }
}

impl GraphWatcher for RefRenderer {
    fn on_add_node(&mut self, handle: &NodeHandle, data: &NodeData) {
        let my_node_data = match *data {
            NodeData::Graph(ref handle) => MyNodeData::Graph(handle.clone()),
            NodeData::Effect(ref effect) => {
                match effect.meta().get_primitive_url() {
                    Some(ref url) => {
                        let mut params: HashMap<_, _> = url.query_pairs().collect();
                        match url.path() {
                            "/Delay" => {
                                let frames: u64 = match params.entry(Cow::from("frames")) {
                                    hash_map::Entry::Occupied(e) => e.remove().parse().unwrap(),
                                    hash_map::Entry::Vacant(_) => 0u64,
                                };
                                // Make sure we consumed all arguments.
                                assert!(params.is_empty());
                                MyNodeData::Delay(frames)
                            },
                            "/Constant" => {
                                let value: f32 = match params.entry(Cow::from("value")) {
                                    hash_map::Entry::Occupied(e) => e.remove().parse().unwrap(),
                                    hash_map::Entry::Vacant(_) => 0f32,
                                };
                                // Make sure we consumed all arguments.
                                assert!(params.is_empty());
                                MyNodeData::Constant(value)
                            },
                            "/Multiply" => MyNodeData::Multiply,
                            _ => panic!("Unrecognized primitive effect: {} (full url: {})", url.path(), url),
                        }
                    }
                    None => MyNodeData::UserNode(effect.clone())
                }
            }
        };
        self.nodes.insert(handle.clone(), Node::new(my_node_data));
        // If the node is part of a new DAG, allocate data so that future edges
        // to null within the DAG can be held.
        self.nodes.entry(NodeHandle::new_dag(handle.dag_handle().clone())).or_insert_with(|| {
            Node::new(MyNodeData::DagIO)
        });
    }
    fn on_del_node(&mut self, handle: &NodeHandle) {
        self.nodes.remove(handle);
    }
    fn on_add_edge(&mut self, edge: &Edge) {
        self.nodes.get_mut(&edge.to_full()).unwrap().inbound.insert(edge.clone());
    }
    fn on_del_edge(&mut self, edge: &Edge) {
        self.nodes.get_mut(&edge.to_full()).unwrap().inbound.remove(edge);
    }
}

impl Node {
    fn new(data: MyNodeData) -> Self {
        Node {
            data: data,
            inbound: HashSet::new(),
        }
    }
}
<|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/. */

//! The service worker manager persists the descriptor of any registered service workers.
//! It also stores an active workers map, which holds descriptors of running service workers.
//! If an active service worker timeouts, then it removes the descriptor entry from its
//! active_workers map

use devtools_traits::{DevtoolsPageInfo, ScriptToDevtoolsControlMsg};
use dom::serviceworkerglobalscope::{ServiceWorkerGlobalScope, ServiceWorkerScriptMsg};
use dom::serviceworkerregistration::longest_prefix_match;
use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER;
use net_traits::{CustomResponseMediator, CoreResourceMsg};
use script_traits::{ServiceWorkerMsg, ScopeThings, SWManagerMsg, SWManagerSenders};
use std::collections::HashMap;
use std::sync::mpsc::{channel, Sender, Receiver, RecvError};
use url::Url;
use util::prefs::PREFS;
use util::thread::spawn_named;

enum Message {
    FromResource(CustomResponseMediator),
    FromConstellation(ServiceWorkerMsg)
}

pub struct ServiceWorkerManager {
    // map of registered service worker descriptors
    registered_workers: HashMap<Url, ScopeThings>,
    // map of active service worker descriptors
    active_workers: HashMap<Url, ScopeThings>,
    // own sender to send messages here
    own_sender: IpcSender<ServiceWorkerMsg>,
    // receiver to receive messages from constellation
    own_port: Receiver<ServiceWorkerMsg>,
    // to receive resource messages
    resource_receiver: Receiver<CustomResponseMediator>
}

impl ServiceWorkerManager {
    fn new(own_sender: IpcSender<ServiceWorkerMsg>,
           from_constellation_receiver: Receiver<ServiceWorkerMsg>,
           resource_port: Receiver<CustomResponseMediator>) -> ServiceWorkerManager {
        ServiceWorkerManager {
            registered_workers: HashMap::new(),
            active_workers: HashMap::new(),
            own_sender: own_sender,
            own_port: from_constellation_receiver,
            resource_receiver: resource_port
        }
    }

    pub fn spawn_manager(sw_senders: SWManagerSenders) {
        let (own_sender, from_constellation_receiver) = ipc::channel().unwrap();
        let (resource_chan, resource_port) = ipc::channel().unwrap();
        let from_constellation = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(from_constellation_receiver);
        let resource_port = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(resource_port);
        let _ = sw_senders.resource_sender.send(CoreResourceMsg::NetworkMediator(resource_chan));
        let _ = sw_senders.swmanager_sender.send(SWManagerMsg::OwnSender(own_sender.clone()));
        spawn_named("ServiceWorkerManager".to_owned(), move || {
            ServiceWorkerManager::new(own_sender, from_constellation, resource_port).handle_message();
        });
    }

    pub fn prepare_activation(&mut self, load_url: &Url) -> Option<Sender<ServiceWorkerScriptMsg>> {
        let mut scope_url = None;
        for scope in self.registered_workers.keys() {
            if longest_prefix_match(&scope, load_url) {
                scope_url = Some(scope.clone());
                break;
            }
        }

        if let Some(ref scope_url) = scope_url {
            if self.active_workers.contains_key(&scope_url) {
                // do not run the same worker if already active.
                warn!("Service worker for {:?} already active", scope_url);
                return None;
            }
            let scope_things = self.registered_workers.get(&scope_url);
            if let Some(scope_things) = scope_things {
                let (sender, receiver) = channel();
                let (devtools_sender, devtools_receiver) = ipc::channel().unwrap();
                if let Some(ref chan) = scope_things.devtools_chan {
                    let title = format!("ServiceWorker for {}", scope_things.script_url);
                    let page_info = DevtoolsPageInfo {
                        title: title,
                        url: scope_things.script_url.clone(),
                    };
                    let _ = chan.send(ScriptToDevtoolsControlMsg::NewGlobal((scope_things.pipeline_id,
                                                                             Some(scope_things.worker_id)),
                                                                             devtools_sender.clone(),
                                                                             page_info));
                };
                ServiceWorkerGlobalScope::run_serviceworker_scope(scope_things.clone(),
                                                                              sender.clone(),
                                                                              receiver,
                                                                              devtools_receiver,
                                                                              self.own_sender.clone(),
                                                                              scope_url.clone());
                // We store the activated worker
                self.active_workers.insert(scope_url.clone(), scope_things.clone());
                return Some(sender);
            } else {
                warn!("Unable to activate service worker");
            }
        }
        None
    }

    fn handle_message(&mut self) {
        while let Ok(message) = self.receive_message() {
            let should_continue = match message {
                Message::FromConstellation(msg) => {
                    self.handle_message_from_constellation(msg)
                },
                Message::FromResource(msg) => {
                    self.handle_message_from_resource(msg)
                }
            };
            if !should_continue {
                break;
            }
        }
    }

    fn handle_message_from_constellation(&mut self, msg: ServiceWorkerMsg) -> bool {
        match msg {
            ServiceWorkerMsg::RegisterServiceWorker(scope_things, scope) => {
                if self.registered_workers.contains_key(&scope) {
                    warn!("ScopeThings for {:?} already stored in SW-Manager", scope);
                } else {
                    self.registered_workers.insert(scope, scope_things);
                }
                true
            }
            ServiceWorkerMsg::Timeout(scope) => {
                if self.active_workers.contains_key(&scope) {
                    let _ = self.active_workers.remove(&scope);
                } else {
                    warn!("ScopeThings for {:?} is not active", scope);
                }
                true
            }
            ServiceWorkerMsg::Exit => false
        }
    }

    #[inline]
    fn handle_message_from_resource(&mut self, mediator: CustomResponseMediator) -> bool {
        if serviceworker_enabled() {
            let worker_sender = self.prepare_activation(&mediator.load_url);
            if let Some(ref sender) = worker_sender {
                let _ = sender.send(ServiceWorkerScriptMsg::Response(mediator));
            }
        } else {
            let _ = mediator.response_chan.send(None);
        }
        true
    }

    #[allow(unsafe_code)]
    fn receive_message(&mut self) -> Result<Message, RecvError> {
        let msg_from_constellation = &self.own_port;
        let msg_from_resource = &self.resource_receiver;
        select! {
            msg = msg_from_constellation.recv() => msg.map(Message::FromConstellation),
            msg = msg_from_resource.recv() => msg.map(Message::FromResource)
        }
    }
}

pub fn serviceworker_enabled() -> bool {
    PREFS.get("dom.serviceworker.enabled").as_boolean().unwrap_or(false)
}
<commit_msg>Remove unnecessary clone from ServiceWorkerManager::prepare_activation<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/. */

//! The service worker manager persists the descriptor of any registered service workers.
//! It also stores an active workers map, which holds descriptors of running service workers.
//! If an active service worker timeouts, then it removes the descriptor entry from its
//! active_workers map

use devtools_traits::{DevtoolsPageInfo, ScriptToDevtoolsControlMsg};
use dom::serviceworkerglobalscope::{ServiceWorkerGlobalScope, ServiceWorkerScriptMsg};
use dom::serviceworkerregistration::longest_prefix_match;
use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER;
use net_traits::{CustomResponseMediator, CoreResourceMsg};
use script_traits::{ServiceWorkerMsg, ScopeThings, SWManagerMsg, SWManagerSenders};
use std::collections::HashMap;
use std::sync::mpsc::{channel, Sender, Receiver, RecvError};
use url::Url;
use util::prefs::PREFS;
use util::thread::spawn_named;

enum Message {
    FromResource(CustomResponseMediator),
    FromConstellation(ServiceWorkerMsg)
}

pub struct ServiceWorkerManager {
    // map of registered service worker descriptors
    registered_workers: HashMap<Url, ScopeThings>,
    // map of active service worker descriptors
    active_workers: HashMap<Url, ScopeThings>,
    // own sender to send messages here
    own_sender: IpcSender<ServiceWorkerMsg>,
    // receiver to receive messages from constellation
    own_port: Receiver<ServiceWorkerMsg>,
    // to receive resource messages
    resource_receiver: Receiver<CustomResponseMediator>
}

impl ServiceWorkerManager {
    fn new(own_sender: IpcSender<ServiceWorkerMsg>,
           from_constellation_receiver: Receiver<ServiceWorkerMsg>,
           resource_port: Receiver<CustomResponseMediator>) -> ServiceWorkerManager {
        ServiceWorkerManager {
            registered_workers: HashMap::new(),
            active_workers: HashMap::new(),
            own_sender: own_sender,
            own_port: from_constellation_receiver,
            resource_receiver: resource_port
        }
    }

    pub fn spawn_manager(sw_senders: SWManagerSenders) {
        let (own_sender, from_constellation_receiver) = ipc::channel().unwrap();
        let (resource_chan, resource_port) = ipc::channel().unwrap();
        let from_constellation = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(from_constellation_receiver);
        let resource_port = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(resource_port);
        let _ = sw_senders.resource_sender.send(CoreResourceMsg::NetworkMediator(resource_chan));
        let _ = sw_senders.swmanager_sender.send(SWManagerMsg::OwnSender(own_sender.clone()));
        spawn_named("ServiceWorkerManager".to_owned(), move || {
            ServiceWorkerManager::new(own_sender, from_constellation, resource_port).handle_message();
        });
    }

    pub fn prepare_activation(&mut self, load_url: &Url) -> Option<Sender<ServiceWorkerScriptMsg>> {
        let mut scope_url = None;
        for scope in self.registered_workers.keys() {
            if longest_prefix_match(&scope, load_url) {
                scope_url = Some(scope.clone());
                break;
            }
        }

        if let Some(scope_url) = scope_url {
            if self.active_workers.contains_key(&scope_url) {
                // do not run the same worker if already active.
                warn!("Service worker for {:?} already active", scope_url);
                return None;
            }
            let scope_things = self.registered_workers.get(&scope_url);
            if let Some(scope_things) = scope_things {
                let (sender, receiver) = channel();
                let (devtools_sender, devtools_receiver) = ipc::channel().unwrap();
                if let Some(ref chan) = scope_things.devtools_chan {
                    let title = format!("ServiceWorker for {}", scope_things.script_url);
                    let page_info = DevtoolsPageInfo {
                        title: title,
                        url: scope_things.script_url.clone(),
                    };
                    let _ = chan.send(ScriptToDevtoolsControlMsg::NewGlobal((scope_things.pipeline_id,
                                                                             Some(scope_things.worker_id)),
                                                                             devtools_sender.clone(),
                                                                             page_info));
                };
                ServiceWorkerGlobalScope::run_serviceworker_scope(scope_things.clone(),
                                                                              sender.clone(),
                                                                              receiver,
                                                                              devtools_receiver,
                                                                              self.own_sender.clone(),
                                                                              scope_url.clone());
                // We store the activated worker
                self.active_workers.insert(scope_url, scope_things.clone());
                return Some(sender);
            } else {
                warn!("Unable to activate service worker");
            }
        }
        None
    }

    fn handle_message(&mut self) {
        while let Ok(message) = self.receive_message() {
            let should_continue = match message {
                Message::FromConstellation(msg) => {
                    self.handle_message_from_constellation(msg)
                },
                Message::FromResource(msg) => {
                    self.handle_message_from_resource(msg)
                }
            };
            if !should_continue {
                break;
            }
        }
    }

    fn handle_message_from_constellation(&mut self, msg: ServiceWorkerMsg) -> bool {
        match msg {
            ServiceWorkerMsg::RegisterServiceWorker(scope_things, scope) => {
                if self.registered_workers.contains_key(&scope) {
                    warn!("ScopeThings for {:?} already stored in SW-Manager", scope);
                } else {
                    self.registered_workers.insert(scope, scope_things);
                }
                true
            }
            ServiceWorkerMsg::Timeout(scope) => {
                if self.active_workers.contains_key(&scope) {
                    let _ = self.active_workers.remove(&scope);
                } else {
                    warn!("ScopeThings for {:?} is not active", scope);
                }
                true
            }
            ServiceWorkerMsg::Exit => false
        }
    }

    #[inline]
    fn handle_message_from_resource(&mut self, mediator: CustomResponseMediator) -> bool {
        if serviceworker_enabled() {
            let worker_sender = self.prepare_activation(&mediator.load_url);
            if let Some(ref sender) = worker_sender {
                let _ = sender.send(ServiceWorkerScriptMsg::Response(mediator));
            }
        } else {
            let _ = mediator.response_chan.send(None);
        }
        true
    }

    #[allow(unsafe_code)]
    fn receive_message(&mut self) -> Result<Message, RecvError> {
        let msg_from_constellation = &self.own_port;
        let msg_from_resource = &self.resource_receiver;
        select! {
            msg = msg_from_constellation.recv() => msg.map(Message::FromConstellation),
            msg = msg_from_resource.recv() => msg.map(Message::FromResource)
        }
    }
}

pub fn serviceworker_enabled() -> bool {
    PREFS.get("dom.serviceworker.enabled").as_boolean().unwrap_or(false)
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;

use backend::Backend;
use platform::platform::Platform;
use provider::Provider;
use provider::file::FileProvider;
use provider::file::inline::posix::Posix;
use provider::file::shell::linux::Linux;

#[derive(Clone)]
pub struct Ubuntu {
    name: String,
    release: String,
}

fn detect_by_lsb_releae(content: &str) -> Option<Box<Platform>> {
    let mut lines = content.lines();
    let line = lines.next().unwrap();
    if line.starts_with("DISTRIB_ID") {
        let id = line.split("=").nth(1).unwrap().trim();
        if id == "Ubuntu" {
            let line = lines.next().unwrap();
            let release = line.split("=").nth(1).unwrap();
            let u = Ubuntu {
                name: id.to_string(),
                release: release.to_string(),
            };

            return Some(Box::new(u));
        }
    }
    None
}

impl Platform for Ubuntu {
    fn new() -> Ubuntu {
        Ubuntu {
            name: "".to_string(),
            release: "".to_string(),
        }
    }

    fn inline_detector(&self) -> Option<Box<Platform>> {
        let mut file = File::open("/etc/lsb-release").unwrap();
        let mut content = String::new();
        let _ = file.read_to_string(&mut content);
        detect_by_lsb_releae(&content)
    }

    fn shell_detector(&self, b: &Backend) -> Option<Box<Platform>> {
        let content = b.run_command("cat /etc/lsb-release").unwrap();
        detect_by_lsb_releae(&content)
    }

    fn get_provider(&self) -> Box<Provider> {
        let fp = FileProvider {
            inline: Box::new(Posix),
            shell: Box::new(Linux),
        };

        let p = Provider { file: Box::new(fp) };

        Box::new(p)
    }
}
<commit_msg>Return none when fail to open /etc/lsdb-release<commit_after>use std::fs::File;
use std::io::prelude::*;

use backend::Backend;
use platform::platform::Platform;
use provider::Provider;
use provider::file::FileProvider;
use provider::file::inline::posix::Posix;
use provider::file::shell::linux::Linux;

#[derive(Clone, Debug)]
pub struct Ubuntu {
    name: String,
    release: String,
}

fn detect_by_lsb_releae(content: &str) -> Option<Box<Platform>> {
    let mut lines = content.lines();
    let line = lines.next().unwrap();
    if line.starts_with("DISTRIB_ID") {
        let id = line.split("=").nth(1).unwrap().trim();
        if id == "Ubuntu" {
            let line = lines.next().unwrap();
            let release = line.split("=").nth(1).unwrap();
            let u = Ubuntu {
                name: id.to_string(),
                release: release.to_string(),
            };

            return Some(Box::new(u));
        }
    }
    None
}

impl Platform for Ubuntu {
    fn new() -> Ubuntu {
        Ubuntu {
            name: "".to_string(),
            release: "".to_string(),
        }
    }

    fn inline_detector(&self) -> Option<Box<Platform>> {
        let mut file = match File::open("/etc/lsb-release") {
            Err(_) => return None,
            Ok(f) => f,
        };

        let mut content = String::new();
        let _ = file.read_to_string(&mut content);
        detect_by_lsb_releae(&content)
    }

    fn shell_detector(&self, b: &Backend) -> Option<Box<Platform>> {
        let content = match b.run_command("cat /etc/lsb-release") {
            Err(_) => return None,
            Ok(f) => f,
        };

        detect_by_lsb_releae(&content)
    }

    fn get_provider(&self) -> Box<Provider> {
        let fp = FileProvider {
            inline: Box::new(Posix),
            shell: Box::new(Linux),
        };

        let p = Provider { file: Box::new(fp) };

        Box::new(p)
    }
}
<|endoftext|>


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

//! A unique pointer type.

#![stable]

use core::any::Any;
use core::clone::Clone;
use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering};
use core::default::Default;
use core::fmt;
use core::hash::{self, Hash};
use core::marker::Sized;
use core::mem;
use core::option::Option;
use core::ptr::Unique;
use core::raw::TraitObject;
use core::result::Result;
use core::result::Result::{Ok, Err};
use core::ops::{Deref, DerefMut};

/// A value that represents the global exchange heap. This is the default
/// place that the `box` keyword allocates into when no place is supplied.
///
/// The following two examples are equivalent:
///
/// ```rust
/// use std::boxed::HEAP;
///
/// # struct Bar;
/// # impl Bar { fn new(_a: int) { } }
/// let foo = box(HEAP) Bar::new(2);
/// let foo = box Bar::new(2);
/// ```
#[lang = "exchange_heap"]
#[experimental = "may be renamed; uncertain about custom allocator design"]
pub static HEAP: () = ();

/// A type that represents a uniquely-owned value.
#[lang = "owned_box"]
#[stable]
pub struct Box<T>(Unique<T>);

#[unstable]
impl<T> Box<T> {
    /// Moves `x` into a freshly allocated box on the global exchange heap.
    #[unstable]
    pub fn new(x: T) -> Box<T> {
        box x
    }
}

#[stable]
impl<T: Default> Default for Box<T> {
    #[stable]
    fn default() -> Box<T> { box Default::default() }
}

#[stable]
impl<T> Default for Box<[T]> {
    #[stable]
    fn default() -> Box<[T]> { box [] }
}

#[stable]
impl<T: Clone> Clone for Box<T> {
    /// Returns a copy of the owned box.
    #[inline]
    fn clone(&self) -> Box<T> { box {(**self).clone()} }

    /// Performs copy-assignment from `source` by reusing the existing allocation.
    #[inline]
    fn clone_from(&mut self, source: &Box<T>) {
        (**self).clone_from(&(**source));
    }
}

#[stable]
impl<T: ?Sized + PartialEq> PartialEq for Box<T> {
    #[inline]
    fn eq(&self, other: &Box<T>) -> bool { PartialEq::eq(&**self, &**other) }
    #[inline]
    fn ne(&self, other: &Box<T>) -> bool { PartialEq::ne(&**self, &**other) }
}
#[stable]
impl<T: ?Sized + PartialOrd> PartialOrd for Box<T> {
    #[inline]
    fn partial_cmp(&self, other: &Box<T>) -> Option<Ordering> {
        PartialOrd::partial_cmp(&**self, &**other)
    }
    #[inline]
    fn lt(&self, other: &Box<T>) -> bool { PartialOrd::lt(&**self, &**other) }
    #[inline]
    fn le(&self, other: &Box<T>) -> bool { PartialOrd::le(&**self, &**other) }
    #[inline]
    fn ge(&self, other: &Box<T>) -> bool { PartialOrd::ge(&**self, &**other) }
    #[inline]
    fn gt(&self, other: &Box<T>) -> bool { PartialOrd::gt(&**self, &**other) }
}
#[stable]
impl<T: ?Sized + Ord> Ord for Box<T> {
    #[inline]
    fn cmp(&self, other: &Box<T>) -> Ordering {
        Ord::cmp(&**self, &**other)
    }

#[stable]}
impl<T: ?Sized + Eq> Eq for Box<T> {}

impl<S: hash::Writer, T: ?Sized + Hash<S>> Hash<S> for Box<T> {
    #[inline]
    fn hash(&self, state: &mut S) {
        (**self).hash(state);
    }
}

/// Extension methods for an owning `Any` trait object.
#[unstable = "post-DST and coherence changes, this will not be a trait but \
              rather a direct `impl` on `Box<Any>`"]
pub trait BoxAny {
    /// Returns the boxed value if it is of type `T`, or
    /// `Err(Self)` if it isn't.
    #[stable]
    fn downcast<T: 'static>(self) -> Result<Box<T>, Self>;
}

impl BoxAny for Box<Any> {
    #[inline]
    #[unstable = "method may be renamed with respect to other downcasting \
                  methods"]
    fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
        if self.is::<T>() {
            unsafe {
                // Get the raw representation of the trait object
                let to: TraitObject =
                    mem::transmute::<Box<Any>, TraitObject>(self);

                // Extract the data pointer
                Ok(mem::transmute(to.data))
            }
        } else {
            Err(self)
        }
    }
}

impl<T: ?Sized + fmt::Show> fmt::Show for Box<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Box({:?})", &**self)
    }
}

impl<T: ?Sized + fmt::String> fmt::String for Box<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::String::fmt(&**self, f)
    }
}

impl fmt::Show for Box<Any> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("Box<Any>")
    }
}

#[stable]
impl<T: ?Sized> Deref for Box<T> {
    type Target = T;

    fn deref(&self) -> &T { &**self }
}

#[stable]
impl<T: ?Sized> DerefMut for Box<T> {
    fn deref_mut(&mut self) -> &mut T { &mut **self }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_owned_clone() {
        let a = box 5i;
        let b: Box<int> = a.clone();
        assert!(a == b);
    }

    #[test]
    fn any_move() {
        let a = box 8u as Box<Any>;
        let b = box Test as Box<Any>;

        match a.downcast::<uint>() {
            Ok(a) => { assert!(a == box 8u); }
            Err(..) => panic!()
        }
        match b.downcast::<Test>() {
            Ok(a) => { assert!(a == box Test); }
            Err(..) => panic!()
        }

        let a = box 8u as Box<Any>;
        let b = box Test as Box<Any>;

        assert!(a.downcast::<Box<Test>>().is_err());
        assert!(b.downcast::<Box<uint>>().is_err());
    }

    #[test]
    fn test_show() {
        let a = box 8u as Box<Any>;
        let b = box Test as Box<Any>;
        let a_str = a.to_str();
        let b_str = b.to_str();
        assert_eq!(a_str, "Box<Any>");
        assert_eq!(b_str, "Box<Any>");

        let a = &8u as &Any;
        let b = &Test as &Any;
        let s = format!("{}", a);
        assert_eq!(s, "&Any");
        let s = format!("{}", b);
        assert_eq!(s, "&Any");
    }

    #[test]
    fn deref() {
        fn homura<T: Deref<Target=i32>>(_: T) { }
        homura(box 765i32);
    }
}
<commit_msg>Switch to using `Box::new` in the tests in  `alloc::boxed`.<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A unique pointer type.

#![stable]

use core::any::Any;
use core::clone::Clone;
use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering};
use core::default::Default;
use core::fmt;
use core::hash::{self, Hash};
use core::marker::Sized;
use core::mem;
use core::option::Option;
use core::ptr::Unique;
use core::raw::TraitObject;
use core::result::Result;
use core::result::Result::{Ok, Err};
use core::ops::{Deref, DerefMut};

/// A value that represents the global exchange heap. This is the default
/// place that the `box` keyword allocates into when no place is supplied.
///
/// The following two examples are equivalent:
///
/// ```rust
/// use std::boxed::HEAP;
///
/// # struct Bar;
/// # impl Bar { fn new(_a: int) { } }
/// let foo = box(HEAP) Bar::new(2);
/// let foo = box Bar::new(2);
/// ```
#[lang = "exchange_heap"]
#[experimental = "may be renamed; uncertain about custom allocator design"]
pub static HEAP: () = ();

/// A type that represents a uniquely-owned value.
#[lang = "owned_box"]
#[stable]
pub struct Box<T>(Unique<T>);

#[unstable]
impl<T> Box<T> {
    /// Moves `x` into a freshly allocated box on the global exchange heap.
    #[unstable]
    pub fn new(x: T) -> Box<T> {
        box x
    }
}

#[stable]
impl<T: Default> Default for Box<T> {
    #[stable]
    fn default() -> Box<T> { box Default::default() }
}

#[stable]
impl<T> Default for Box<[T]> {
    #[stable]
    fn default() -> Box<[T]> { box [] }
}

#[stable]
impl<T: Clone> Clone for Box<T> {
    /// Returns a copy of the owned box.
    #[inline]
    fn clone(&self) -> Box<T> { box {(**self).clone()} }

    /// Performs copy-assignment from `source` by reusing the existing allocation.
    #[inline]
    fn clone_from(&mut self, source: &Box<T>) {
        (**self).clone_from(&(**source));
    }
}

#[stable]
impl<T: ?Sized + PartialEq> PartialEq for Box<T> {
    #[inline]
    fn eq(&self, other: &Box<T>) -> bool { PartialEq::eq(&**self, &**other) }
    #[inline]
    fn ne(&self, other: &Box<T>) -> bool { PartialEq::ne(&**self, &**other) }
}
#[stable]
impl<T: ?Sized + PartialOrd> PartialOrd for Box<T> {
    #[inline]
    fn partial_cmp(&self, other: &Box<T>) -> Option<Ordering> {
        PartialOrd::partial_cmp(&**self, &**other)
    }
    #[inline]
    fn lt(&self, other: &Box<T>) -> bool { PartialOrd::lt(&**self, &**other) }
    #[inline]
    fn le(&self, other: &Box<T>) -> bool { PartialOrd::le(&**self, &**other) }
    #[inline]
    fn ge(&self, other: &Box<T>) -> bool { PartialOrd::ge(&**self, &**other) }
    #[inline]
    fn gt(&self, other: &Box<T>) -> bool { PartialOrd::gt(&**self, &**other) }
}
#[stable]
impl<T: ?Sized + Ord> Ord for Box<T> {
    #[inline]
    fn cmp(&self, other: &Box<T>) -> Ordering {
        Ord::cmp(&**self, &**other)
    }

#[stable]}
impl<T: ?Sized + Eq> Eq for Box<T> {}

impl<S: hash::Writer, T: ?Sized + Hash<S>> Hash<S> for Box<T> {
    #[inline]
    fn hash(&self, state: &mut S) {
        (**self).hash(state);
    }
}

/// Extension methods for an owning `Any` trait object.
#[unstable = "post-DST and coherence changes, this will not be a trait but \
              rather a direct `impl` on `Box<Any>`"]
pub trait BoxAny {
    /// Returns the boxed value if it is of type `T`, or
    /// `Err(Self)` if it isn't.
    #[stable]
    fn downcast<T: 'static>(self) -> Result<Box<T>, Self>;
}

impl BoxAny for Box<Any> {
    #[inline]
    #[unstable = "method may be renamed with respect to other downcasting \
                  methods"]
    fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
        if self.is::<T>() {
            unsafe {
                // Get the raw representation of the trait object
                let to: TraitObject =
                    mem::transmute::<Box<Any>, TraitObject>(self);

                // Extract the data pointer
                Ok(mem::transmute(to.data))
            }
        } else {
            Err(self)
        }
    }
}

impl<T: ?Sized + fmt::Show> fmt::Show for Box<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Box({:?})", &**self)
    }
}

impl<T: ?Sized + fmt::String> fmt::String for Box<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::String::fmt(&**self, f)
    }
}

impl fmt::Show for Box<Any> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("Box<Any>")
    }
}

#[stable]
impl<T: ?Sized> Deref for Box<T> {
    type Target = T;

    fn deref(&self) -> &T { &**self }
}

#[stable]
impl<T: ?Sized> DerefMut for Box<T> {
    fn deref_mut(&mut self) -> &mut T { &mut **self }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_owned_clone() {
        let a = Box::new(5i);
        let b: Box<int> = a.clone();
        assert!(a == b);
    }

    #[test]
    fn any_move() {
        let a = Box::new(8u) as Box<Any>;
        let b = Box::new(Test) as Box<Any>;

        match a.downcast::<uint>() {
            Ok(a) => { assert!(a == Box::new(8u)); }
            Err(..) => panic!()
        }
        match b.downcast::<Test>() {
            Ok(a) => { assert!(a == Box::new(Test)); }
            Err(..) => panic!()
        }

        let a = Box::new(8u) as Box<Any>;
        let b = Box::new(Test) as Box<Any>;

        assert!(a.downcast::<Box<Test>>().is_err());
        assert!(b.downcast::<Box<uint>>().is_err());
    }

    #[test]
    fn test_show() {
        let a = Box::new(8u) as Box<Any>;
        let b = Box::new(Test) as Box<Any>;
        let a_str = a.to_str();
        let b_str = b.to_str();
        assert_eq!(a_str, "Box<Any>");
        assert_eq!(b_str, "Box<Any>");

        let a = &8u as &Any;
        let b = &Test as &Any;
        let s = format!("{}", a);
        assert_eq!(s, "&Any");
        let s = format!("{}", b);
        assert_eq!(s, "&Any");
    }

    #[test]
    fn deref() {
        fn homura<T: Deref<Target=i32>>(_: T) { }
        homura(Box::new(765i32));
    }
}
<|endoftext|>


<commit_before>use std::io::{Error, ErrorKind};
use byteorder::{ReadBytesExt, LittleEndian};
use std::io::Read;
use std::mem;

#[derive(Debug)]
pub struct MamHeader{
    pub signature: u32,
    pub uncompressed_size: u32
}

#[derive(Debug)]
pub struct PrefetchHeader{
    pub version: u32,
    pub signature: u32,
    pub unknown1: u32,
    pub filesize: u32,
    pub filename: [u16; 30],
    pub hash: u32,
    pub unknon2: u32
}

pub fn read_mam_head<R: Read>(mut buffer: R)->Result<MamHeader,Error>{
    let mut header: MamHeader = unsafe {
        mem::zeroed()
    };

    header.signature = buffer.read_u32::<LittleEndian>()?;
    header.uncompressed_size = buffer.read_u32::<LittleEndian>()?;

    Ok(header)
}
<commit_msg>method to get prefetch signature type<commit_after>use librp::errors;
use librp::utils;
use std::io::{Error, ErrorKind};
use byteorder::{ReadBytesExt, LittleEndian};
use std::fs::File;
use std::io::Read;
use std::mem;

#[derive(Debug)]
pub struct MamHeader{
    pub signature: u32,
    pub uncompressed_size: u32
}

#[derive(Debug)]
pub struct PrefetchHeader{
    pub version: u32,
    pub signature: u32,
    pub unknown1: u32,
    pub filesize: u32,
    pub filename: [u16; 30],
    pub hash: u32,
    pub unknon2: u32
}

pub fn read_mam_head<R: Read>(mut buffer: R)->Result<MamHeader,Error>{
    let mut header: MamHeader = unsafe {
        mem::zeroed()
    };

    header.signature = buffer.read_u32::<LittleEndian>()?;
    header.uncompressed_size = buffer.read_u32::<LittleEndian>()?;

    Ok(header)
}

pub fn prefetch_signature(filename: &str)->Result<u32,errors::PrefetchError>{
    // Open a filehandle to the file
    let mut fh = try!(File::open(filename));

    // Get File Size to ensure we have enough data to read
    let metadata = try!(fh.metadata());
    let file_size = metadata.len();

    if file_size > 8 {
        // We are only ever going to check the first 8 bytes of the file for a signature
        // check for MAM signature
        let prt1 = try!(fh.read_u32::<LittleEndian>());
        if prt1 == 72171853 {
            Ok(prt1)
        }else{
            // check for SCCA signature
            let prt2 = try!(fh.read_u32::<LittleEndian>());
            if prt2 == 1094927187 {
                Ok(prt2)
            } else {
                // Unknown File signature
                Err(errors::PrefetchError::invalid_file_signature(format!(
                        "Unkown File Signature"
                )))
            }
        }
    } else {
        Err(errors::PrefetchError::invalid_file_signature(format!("File size invalid")))
    }
}
<|endoftext|>


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

#[link(name = "rustc",
       vers = "0.8-pre",
       uuid = "0ce89b41-2f92-459e-bbc1-8f5fe32f16cf",
       url = "https://github.com/mozilla/rust/tree/master/src/rustc")];

#[comment = "The Rust compiler"];
#[license = "MIT/ASL2"];
#[crate_type = "lib"];

extern mod extra;
extern mod syntax;

use driver::driver::{host_triple, optgroups, early_error};
use driver::driver::{str_input, file_input, build_session_options};
use driver::driver::{build_session, build_configuration, parse_pretty};
use driver::driver::{pp_mode, pretty_print_input, list_metadata};
use driver::driver::{compile_input};
use driver::session;
use middle::lint;

use std::io;
use std::num;
use std::os;
use std::result;
use std::str;
use std::task;
use std::vec;
use extra::getopts::{groups, opt_present};
use extra::getopts;
use syntax::codemap;
use syntax::diagnostic;

pub mod middle {
    pub mod trans;
    pub mod ty;
    pub mod subst;
    pub mod resolve;
    pub mod typeck;
    pub mod check_loop;
    pub mod check_match;
    pub mod check_const;
    pub mod lint;
    pub mod borrowck;
    pub mod dataflow;
    pub mod mem_categorization;
    pub mod liveness;
    pub mod kind;
    pub mod freevars;
    pub mod pat_util;
    pub mod region;
    pub mod const_eval;
    pub mod astencode;
    pub mod lang_items;
    pub mod privacy;
    pub mod moves;
    pub mod entry;
    pub mod effect;
    pub mod reachable;
    pub mod graph;
    pub mod cfg;
}

pub mod front {
    pub mod config;
    pub mod test;
    pub mod std_inject;
}

pub mod back {
    pub mod link;
    pub mod abi;
    pub mod upcall;
    pub mod arm;
    pub mod mips;
    pub mod x86;
    pub mod x86_64;
    pub mod rpath;
    pub mod target_strs;
    pub mod passes;
}

pub mod metadata;

pub mod driver;

pub mod util {
    pub mod common;
    pub mod ppaux;
}

pub mod lib {
    pub mod llvm;
}

// A curious inner module that allows ::std::foo to be available in here for
// macros.
/*
mod std {
    pub use std::clone;
    pub use std::cmp;
    pub use std::os;
    pub use std::str;
    pub use std::sys;
    pub use std::to_bytes;
    pub use std::unstable;
    pub use extra::serialize;
}
*/

pub fn version(argv0: &str) {
    let vers = match option_env!("CFG_VERSION") {
        Some(vers) => vers,
        None => "unknown version"
    };
    printfln!("%s %s", argv0, vers);
    printfln!("host: %s", host_triple());
}

pub fn usage(argv0: &str) {
    let message = fmt!("Usage: %s [OPTIONS] INPUT", argv0);
    printfln!("%s\
Additional help:
    -W help             Print 'lint' options and default settings
    -Z help             Print internal options for debugging rustc\n",
              groups::usage(message, optgroups()));
}

pub fn describe_warnings() {
    use extra::sort::Sort;
    println("
Available lint options:
    -W <foo>           Warn about <foo>
    -A <foo>           Allow <foo>
    -D <foo>           Deny <foo>
    -F <foo>           Forbid <foo> (deny, and deny all overrides)
");

    let lint_dict = lint::get_lint_dict();
    let mut lint_dict = lint_dict.move_iter()
                                 .map(|(k, v)| (v, k))
                                 .collect::<~[(lint::LintSpec, &'static str)]>();
    lint_dict.qsort();

    let mut max_key = 0;
    for &(_, name) in lint_dict.iter() {
        max_key = num::max(name.len(), max_key);
    }
    fn padded(max: uint, s: &str) -> ~str {
        str::from_bytes(vec::from_elem(max - s.len(), ' ' as u8)) + s
    }
    println("\nAvailable lint checks:\n");
    printfln!("    %s  %7.7s  %s",
              padded(max_key, "name"), "default", "meaning");
    printfln!("    %s  %7.7s  %s\n",
              padded(max_key, "----"), "-------", "-------");
    for (spec, name) in lint_dict.move_iter() {
        let name = name.replace("_", "-");
        printfln!("    %s  %7.7s  %s",
                  padded(max_key, name),
                  lint::level_to_str(spec.default),
                  spec.desc);
    }
    io::println("");
}

pub fn describe_debug_flags() {
    println("\nAvailable debug options:\n");
    let r = session::debugging_opts_map();
    for tuple in r.iter() {
        match *tuple {
            (ref name, ref desc, _) => {
                printfln!("    -Z %-20s -- %s", *name, *desc);
            }
        }
    }
}

pub fn run_compiler(args: &~[~str], demitter: diagnostic::Emitter) {
    // Don't display log spew by default. Can override with RUST_LOG.
    ::std::logging::console_off();

    let mut args = (*args).clone();
    let binary = args.shift().to_managed();

    if args.is_empty() { usage(binary); return; }

    let matches =
        &match getopts::groups::getopts(args, optgroups()) {
          Ok(m) => m,
          Err(f) => {
            early_error(demitter, getopts::fail_str(f));
          }
        };

    if opt_present(matches, "h") || opt_present(matches, "help") {
        usage(binary);
        return;
    }

    // Display the available lint options if "-W help" or only "-W" is given.
    let lint_flags = vec::append(getopts::opt_strs(matches, "W"),
                                 getopts::opt_strs(matches, "warn"));

    let show_lint_options = lint_flags.iter().any(|x| x == &~"help") ||
        (opt_present(matches, "W") && lint_flags.is_empty());

    if show_lint_options {
        describe_warnings();
        return;
    }

    let r = getopts::opt_strs(matches, "Z");
    if r.iter().any(|x| x == &~"help") {
        describe_debug_flags();
        return;
    }

    if getopts::opt_maybe_str(matches, "passes") == Some(~"list") {
        back::passes::list_passes();
        return;
    }

    if opt_present(matches, "v") || opt_present(matches, "version") {
        version(binary);
        return;
    }
    let input = match matches.free.len() {
      0u => early_error(demitter, ~"no input filename given"),
      1u => {
        let ifile = matches.free[0].as_slice();
        if "-" == ifile {
            let src = str::from_bytes(io::stdin().read_whole_stream());
            str_input(src.to_managed())
        } else {
            file_input(Path(ifile))
        }
      }
      _ => early_error(demitter, ~"multiple input filenames provided")
    };

    let sopts = build_session_options(binary, matches, demitter);
    let sess = build_session(sopts, demitter);
    let odir = getopts::opt_maybe_str(matches, "out-dir").map_move(|o| Path(o));
    let ofile = getopts::opt_maybe_str(matches, "o").map_move(|o| Path(o));
    let cfg = build_configuration(sess);
    let pretty = do getopts::opt_default(matches, "pretty", "normal").map_move |a| {
        parse_pretty(sess, a)
    };
    match pretty {
      Some::<pp_mode>(ppm) => {
        pretty_print_input(sess, cfg, &input, ppm);
        return;
      }
      None::<pp_mode> => {/* continue */ }
    }
    let ls = opt_present(matches, "ls");
    if ls {
        match input {
          file_input(ref ifile) => {
            list_metadata(sess, &(*ifile), io::stdout());
          }
          str_input(_) => {
            early_error(demitter, ~"can not list metadata for stdin");
          }
        }
        return;
    }

    compile_input(sess, cfg, &input, &odir, &ofile);
}

#[deriving(Eq)]
pub enum monitor_msg {
    fatal,
    done,
}

/*
This is a sanity check that any failure of the compiler is performed
through the diagnostic module and reported properly - we shouldn't be calling
plain-old-fail on any execution path that might be taken. Since we have
console logging off by default, hitting a plain fail statement would make the
compiler silently exit, which would be terrible.

This method wraps the compiler in a subtask and injects a function into the
diagnostic emitter which records when we hit a fatal error. If the task
fails without recording a fatal error then we've encountered a compiler
bug and need to present an error.
*/
pub fn monitor(f: ~fn(diagnostic::Emitter)) {
    use std::comm::*;

    // XXX: This is a hack for newsched since it doesn't support split stacks.
    // rustc needs a lot of stack!
    static STACK_SIZE: uint = 6000000;

    let (p, ch) = stream();
    let ch = SharedChan::new(ch);
    let ch_capture = ch.clone();
    let mut task_builder = task::task();
    task_builder.supervised();

    // XXX: Hacks on hacks. If the env is trying to override the stack size
    // then *don't* set it explicitly.
    if os::getenv("RUST_MIN_STACK").is_none() {
        task_builder.opts.stack_size = Some(STACK_SIZE);
    }

    match do task_builder.try {
        let ch = ch_capture.clone();
        let ch_capture = ch.clone();
        // The 'diagnostics emitter'. Every error, warning, etc. should
        // go through this function.
        let demitter: @fn(Option<(@codemap::CodeMap, codemap::span)>,
                          &str,
                          diagnostic::level) =
                          |cmsp, msg, lvl| {
            if lvl == diagnostic::fatal {
                ch_capture.send(fatal);
            }
            diagnostic::emit(cmsp, msg, lvl);
        };

        struct finally {
            ch: SharedChan<monitor_msg>,
        }

        impl Drop for finally {
            fn drop(&self) { self.ch.send(done); }
        }

        let _finally = finally { ch: ch };

        f(demitter);

        // Due reasons explain in #7732, if there was a jit execution context it
        // must be consumed and passed along to our parent task.
        back::link::jit::consume_engine()
    } {
        result::Ok(_) => { /* fallthrough */ }
        result::Err(_) => {
            // Task failed without emitting a fatal diagnostic
            if p.recv() == done {
                diagnostic::emit(
                    None,
                    diagnostic::ice_msg("unexpected failure"),
                    diagnostic::error);

                let xs = [
                    ~"the compiler hit an unexpected failure path. \
                     this is a bug",
                    ~"try running with RUST_LOG=rustc=1,::rt::backtrace \
                     to get further details and report the results \
                     to github.com/mozilla/rust/issues"
                ];
                for note in xs.iter() {
                    diagnostic::emit(None, *note, diagnostic::note)
                }
            }
            // Fail so the process returns a failure code
            fail!();
        }
    }
}

pub fn main() {
    let args = os::args();
    do monitor |demitter| {
        run_compiler(&args, demitter);
    }
}
<commit_msg>auto merge of #8530 : brson/rust/rt-backtrace, r=alexcrichton<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[link(name = "rustc",
       vers = "0.8-pre",
       uuid = "0ce89b41-2f92-459e-bbc1-8f5fe32f16cf",
       url = "https://github.com/mozilla/rust/tree/master/src/rustc")];

#[comment = "The Rust compiler"];
#[license = "MIT/ASL2"];
#[crate_type = "lib"];

extern mod extra;
extern mod syntax;

use driver::driver::{host_triple, optgroups, early_error};
use driver::driver::{str_input, file_input, build_session_options};
use driver::driver::{build_session, build_configuration, parse_pretty};
use driver::driver::{pp_mode, pretty_print_input, list_metadata};
use driver::driver::{compile_input};
use driver::session;
use middle::lint;

use std::io;
use std::num;
use std::os;
use std::result;
use std::str;
use std::task;
use std::vec;
use extra::getopts::{groups, opt_present};
use extra::getopts;
use syntax::codemap;
use syntax::diagnostic;

pub mod middle {
    pub mod trans;
    pub mod ty;
    pub mod subst;
    pub mod resolve;
    pub mod typeck;
    pub mod check_loop;
    pub mod check_match;
    pub mod check_const;
    pub mod lint;
    pub mod borrowck;
    pub mod dataflow;
    pub mod mem_categorization;
    pub mod liveness;
    pub mod kind;
    pub mod freevars;
    pub mod pat_util;
    pub mod region;
    pub mod const_eval;
    pub mod astencode;
    pub mod lang_items;
    pub mod privacy;
    pub mod moves;
    pub mod entry;
    pub mod effect;
    pub mod reachable;
    pub mod graph;
    pub mod cfg;
}

pub mod front {
    pub mod config;
    pub mod test;
    pub mod std_inject;
}

pub mod back {
    pub mod link;
    pub mod abi;
    pub mod upcall;
    pub mod arm;
    pub mod mips;
    pub mod x86;
    pub mod x86_64;
    pub mod rpath;
    pub mod target_strs;
    pub mod passes;
}

pub mod metadata;

pub mod driver;

pub mod util {
    pub mod common;
    pub mod ppaux;
}

pub mod lib {
    pub mod llvm;
}

// A curious inner module that allows ::std::foo to be available in here for
// macros.
/*
mod std {
    pub use std::clone;
    pub use std::cmp;
    pub use std::os;
    pub use std::str;
    pub use std::sys;
    pub use std::to_bytes;
    pub use std::unstable;
    pub use extra::serialize;
}
*/

pub fn version(argv0: &str) {
    let vers = match option_env!("CFG_VERSION") {
        Some(vers) => vers,
        None => "unknown version"
    };
    printfln!("%s %s", argv0, vers);
    printfln!("host: %s", host_triple());
}

pub fn usage(argv0: &str) {
    let message = fmt!("Usage: %s [OPTIONS] INPUT", argv0);
    printfln!("%s\
Additional help:
    -W help             Print 'lint' options and default settings
    -Z help             Print internal options for debugging rustc\n",
              groups::usage(message, optgroups()));
}

pub fn describe_warnings() {
    use extra::sort::Sort;
    println("
Available lint options:
    -W <foo>           Warn about <foo>
    -A <foo>           Allow <foo>
    -D <foo>           Deny <foo>
    -F <foo>           Forbid <foo> (deny, and deny all overrides)
");

    let lint_dict = lint::get_lint_dict();
    let mut lint_dict = lint_dict.move_iter()
                                 .map(|(k, v)| (v, k))
                                 .collect::<~[(lint::LintSpec, &'static str)]>();
    lint_dict.qsort();

    let mut max_key = 0;
    for &(_, name) in lint_dict.iter() {
        max_key = num::max(name.len(), max_key);
    }
    fn padded(max: uint, s: &str) -> ~str {
        str::from_bytes(vec::from_elem(max - s.len(), ' ' as u8)) + s
    }
    println("\nAvailable lint checks:\n");
    printfln!("    %s  %7.7s  %s",
              padded(max_key, "name"), "default", "meaning");
    printfln!("    %s  %7.7s  %s\n",
              padded(max_key, "----"), "-------", "-------");
    for (spec, name) in lint_dict.move_iter() {
        let name = name.replace("_", "-");
        printfln!("    %s  %7.7s  %s",
                  padded(max_key, name),
                  lint::level_to_str(spec.default),
                  spec.desc);
    }
    io::println("");
}

pub fn describe_debug_flags() {
    println("\nAvailable debug options:\n");
    let r = session::debugging_opts_map();
    for tuple in r.iter() {
        match *tuple {
            (ref name, ref desc, _) => {
                printfln!("    -Z %-20s -- %s", *name, *desc);
            }
        }
    }
}

pub fn run_compiler(args: &~[~str], demitter: diagnostic::Emitter) {
    // Don't display log spew by default. Can override with RUST_LOG.
    ::std::logging::console_off();

    let mut args = (*args).clone();
    let binary = args.shift().to_managed();

    if args.is_empty() { usage(binary); return; }

    let matches =
        &match getopts::groups::getopts(args, optgroups()) {
          Ok(m) => m,
          Err(f) => {
            early_error(demitter, getopts::fail_str(f));
          }
        };

    if opt_present(matches, "h") || opt_present(matches, "help") {
        usage(binary);
        return;
    }

    // Display the available lint options if "-W help" or only "-W" is given.
    let lint_flags = vec::append(getopts::opt_strs(matches, "W"),
                                 getopts::opt_strs(matches, "warn"));

    let show_lint_options = lint_flags.iter().any(|x| x == &~"help") ||
        (opt_present(matches, "W") && lint_flags.is_empty());

    if show_lint_options {
        describe_warnings();
        return;
    }

    let r = getopts::opt_strs(matches, "Z");
    if r.iter().any(|x| x == &~"help") {
        describe_debug_flags();
        return;
    }

    if getopts::opt_maybe_str(matches, "passes") == Some(~"list") {
        back::passes::list_passes();
        return;
    }

    if opt_present(matches, "v") || opt_present(matches, "version") {
        version(binary);
        return;
    }
    let input = match matches.free.len() {
      0u => early_error(demitter, ~"no input filename given"),
      1u => {
        let ifile = matches.free[0].as_slice();
        if "-" == ifile {
            let src = str::from_bytes(io::stdin().read_whole_stream());
            str_input(src.to_managed())
        } else {
            file_input(Path(ifile))
        }
      }
      _ => early_error(demitter, ~"multiple input filenames provided")
    };

    let sopts = build_session_options(binary, matches, demitter);
    let sess = build_session(sopts, demitter);
    let odir = getopts::opt_maybe_str(matches, "out-dir").map_move(|o| Path(o));
    let ofile = getopts::opt_maybe_str(matches, "o").map_move(|o| Path(o));
    let cfg = build_configuration(sess);
    let pretty = do getopts::opt_default(matches, "pretty", "normal").map_move |a| {
        parse_pretty(sess, a)
    };
    match pretty {
      Some::<pp_mode>(ppm) => {
        pretty_print_input(sess, cfg, &input, ppm);
        return;
      }
      None::<pp_mode> => {/* continue */ }
    }
    let ls = opt_present(matches, "ls");
    if ls {
        match input {
          file_input(ref ifile) => {
            list_metadata(sess, &(*ifile), io::stdout());
          }
          str_input(_) => {
            early_error(demitter, ~"can not list metadata for stdin");
          }
        }
        return;
    }

    compile_input(sess, cfg, &input, &odir, &ofile);
}

#[deriving(Eq)]
pub enum monitor_msg {
    fatal,
    done,
}

/*
This is a sanity check that any failure of the compiler is performed
through the diagnostic module and reported properly - we shouldn't be calling
plain-old-fail on any execution path that might be taken. Since we have
console logging off by default, hitting a plain fail statement would make the
compiler silently exit, which would be terrible.

This method wraps the compiler in a subtask and injects a function into the
diagnostic emitter which records when we hit a fatal error. If the task
fails without recording a fatal error then we've encountered a compiler
bug and need to present an error.
*/
pub fn monitor(f: ~fn(diagnostic::Emitter)) {
    use std::comm::*;

    // XXX: This is a hack for newsched since it doesn't support split stacks.
    // rustc needs a lot of stack!
    static STACK_SIZE: uint = 6000000;

    let (p, ch) = stream();
    let ch = SharedChan::new(ch);
    let ch_capture = ch.clone();
    let mut task_builder = task::task();
    task_builder.supervised();

    // XXX: Hacks on hacks. If the env is trying to override the stack size
    // then *don't* set it explicitly.
    if os::getenv("RUST_MIN_STACK").is_none() {
        task_builder.opts.stack_size = Some(STACK_SIZE);
    }

    match do task_builder.try {
        let ch = ch_capture.clone();
        let ch_capture = ch.clone();
        // The 'diagnostics emitter'. Every error, warning, etc. should
        // go through this function.
        let demitter: @fn(Option<(@codemap::CodeMap, codemap::span)>,
                          &str,
                          diagnostic::level) =
                          |cmsp, msg, lvl| {
            if lvl == diagnostic::fatal {
                ch_capture.send(fatal);
            }
            diagnostic::emit(cmsp, msg, lvl);
        };

        struct finally {
            ch: SharedChan<monitor_msg>,
        }

        impl Drop for finally {
            fn drop(&self) { self.ch.send(done); }
        }

        let _finally = finally { ch: ch };

        f(demitter);

        // Due reasons explain in #7732, if there was a jit execution context it
        // must be consumed and passed along to our parent task.
        back::link::jit::consume_engine()
    } {
        result::Ok(_) => { /* fallthrough */ }
        result::Err(_) => {
            // Task failed without emitting a fatal diagnostic
            if p.recv() == done {
                diagnostic::emit(
                    None,
                    diagnostic::ice_msg("unexpected failure"),
                    diagnostic::error);

                let xs = [
                    ~"the compiler hit an unexpected failure path. \
                     this is a bug",
                    ~"try running with RUST_LOG=rustc=1 \
                     to get further details and report the results \
                     to github.com/mozilla/rust/issues"
                ];
                for note in xs.iter() {
                    diagnostic::emit(None, *note, diagnostic::note)
                }
            }
            // Fail so the process returns a failure code
            fail!();
        }
    }
}

pub fn main() {
    let args = os::args();
    do monitor |demitter| {
        run_compiler(&args, demitter);
    }
}
<|endoftext|>


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

/*!

Many programming languages have a 'prelude': a particular subset of the
libraries that come with the language. Every program imports the prelude by
default.

For example, it would be annoying to add `use std::io::println;` to every single
program, and the vast majority of Rust programs will wish to print to standard
output. Therefore, it makes sense to import it into every program.

Rust's prelude has three main parts:

1. io::print and io::println.
2. Core operators, such as `Add`, `Mul`, and `Not`.
3. Various types and traits, such as `Clone`, `Eq`, and `comm::Chan`.

*/

// Reexported core operators
pub use either::{Either, Left, Right};
pub use kinds::{Const, Copy, Owned, Sized};
pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not};
pub use ops::{BitAnd, BitOr, BitXor};
pub use ops::{Drop};
pub use ops::{Shl, Shr, Index};
pub use option::{Option, Some, None};
pub use result::{Result, Ok, Err};

// Reexported functions
pub use io::{print, println};

// Reexported types and traits
pub use clone::{Clone, DeepClone};
pub use cmp::{Eq, ApproxEq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv};
pub use char::Char;
pub use container::{Container, Mutable, Map, Set};
pub use hash::Hash;
pub use old_iter::{BaseIter, ReverseIter, MutableIter, ExtendedIter, EqIter};
pub use old_iter::{CopyableIter, CopyableOrderedIter, CopyableNonstrictIter};
pub use old_iter::{ExtendedMutableIter};
pub use iter::{Times, FromIter};
// FIXME: #5898 pub use iterator::{Iterator, IteratorUtil};
pub use num::{Num, NumCast};
pub use num::{Orderable, Signed, Unsigned, Round};
pub use num::{Algebraic, Trigonometric, Exponential, Hyperbolic};
pub use num::{Integer, Fractional, Real, RealExt};
pub use num::{Bitwise, BitCount, Bounded};
pub use num::{Primitive, Int, Float};
pub use path::GenericPath;
pub use path::Path;
pub use path::PosixPath;
pub use path::WindowsPath;
pub use ptr::RawPtr;
pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr};
pub use str::{StrVector, StrSlice, OwnedStr, StrUtil};
pub use from_str::{FromStr};
pub use to_bytes::IterBytes;
pub use to_str::{ToStr, ToStrConsume};
pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps};
pub use tuple::{CloneableTuple2, CloneableTuple3, CloneableTuple4, CloneableTuple5};
pub use tuple::{CloneableTuple6, CloneableTuple7, CloneableTuple8, CloneableTuple9};
pub use tuple::{CloneableTuple10, CloneableTuple11, CloneableTuple12};
pub use tuple::{ImmutableTuple2, ImmutableTuple3, ImmutableTuple4, ImmutableTuple5};
pub use tuple::{ImmutableTuple6, ImmutableTuple7, ImmutableTuple8, ImmutableTuple9};
pub use tuple::{ImmutableTuple10, ImmutableTuple11, ImmutableTuple12};
pub use vec::{VectorVector, CopyableVector, ImmutableVector};
pub use vec::{ImmutableEqVector, ImmutableCopyableVector};
pub use vec::{OwnedVector, OwnedCopyableVector, MutableVector};
pub use io::{Reader, ReaderUtil, Writer, WriterUtil};

// Reexported runtime types
pub use comm::{stream, Port, Chan, GenericChan, GenericSmartChan, GenericPort, Peekable};
pub use task::spawn;
<commit_msg>auto merge of #7008 : thestinger/rust/iterator, r=catamorphism<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

Many programming languages have a 'prelude': a particular subset of the
libraries that come with the language. Every program imports the prelude by
default.

For example, it would be annoying to add `use std::io::println;` to every single
program, and the vast majority of Rust programs will wish to print to standard
output. Therefore, it makes sense to import it into every program.

Rust's prelude has three main parts:

1. io::print and io::println.
2. Core operators, such as `Add`, `Mul`, and `Not`.
3. Various types and traits, such as `Clone`, `Eq`, and `comm::Chan`.

*/

// Reexported core operators
pub use either::{Either, Left, Right};
pub use kinds::{Const, Copy, Owned, Sized};
pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not};
pub use ops::{BitAnd, BitOr, BitXor};
pub use ops::{Drop};
pub use ops::{Shl, Shr, Index};
pub use option::{Option, Some, None};
pub use result::{Result, Ok, Err};

// Reexported functions
pub use io::{print, println};

// Reexported types and traits
pub use clone::{Clone, DeepClone};
pub use cmp::{Eq, ApproxEq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv};
pub use char::Char;
pub use container::{Container, Mutable, Map, Set};
pub use hash::Hash;
pub use old_iter::{BaseIter, ReverseIter, MutableIter, ExtendedIter, EqIter};
pub use old_iter::{CopyableIter, CopyableOrderedIter, CopyableNonstrictIter};
pub use old_iter::{ExtendedMutableIter};
pub use iter::{Times, FromIter};
// FIXME: #5898 pub use iterator::{Iterator, IteratorUtil};
pub use iterator::Iterator;
pub use num::{Num, NumCast};
pub use num::{Orderable, Signed, Unsigned, Round};
pub use num::{Algebraic, Trigonometric, Exponential, Hyperbolic};
pub use num::{Integer, Fractional, Real, RealExt};
pub use num::{Bitwise, BitCount, Bounded};
pub use num::{Primitive, Int, Float};
pub use path::GenericPath;
pub use path::Path;
pub use path::PosixPath;
pub use path::WindowsPath;
pub use ptr::RawPtr;
pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr};
pub use str::{StrVector, StrSlice, OwnedStr, StrUtil};
pub use from_str::{FromStr};
pub use to_bytes::IterBytes;
pub use to_str::{ToStr, ToStrConsume};
pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps};
pub use tuple::{CloneableTuple2, CloneableTuple3, CloneableTuple4, CloneableTuple5};
pub use tuple::{CloneableTuple6, CloneableTuple7, CloneableTuple8, CloneableTuple9};
pub use tuple::{CloneableTuple10, CloneableTuple11, CloneableTuple12};
pub use tuple::{ImmutableTuple2, ImmutableTuple3, ImmutableTuple4, ImmutableTuple5};
pub use tuple::{ImmutableTuple6, ImmutableTuple7, ImmutableTuple8, ImmutableTuple9};
pub use tuple::{ImmutableTuple10, ImmutableTuple11, ImmutableTuple12};
pub use vec::{VectorVector, CopyableVector, ImmutableVector};
pub use vec::{ImmutableEqVector, ImmutableCopyableVector};
pub use vec::{OwnedVector, OwnedCopyableVector, MutableVector};
pub use io::{Reader, ReaderUtil, Writer, WriterUtil};

// Reexported runtime types
pub use comm::{stream, Port, Chan, GenericChan, GenericSmartChan, GenericPort, Peekable};
pub use task::spawn;
<|endoftext|>


<commit_before>use super::*;
use std::collections::HashMap;
use rand;
use core::geometry;
use backend::obj;
use backend::obj::Transformable;
use backend::obj::Identified;
use backend::world;
use backend::world::gen;
use backend::world::agent;
use backend::world::segment;
use backend::world::WorldState;
use backend::world::alert;
use backend::world::AlertReceiver;
use serialize::base64::{self, ToBase64};

type StateMap = HashMap<obj::Id, agent::State>;
type GeneMap = HashMap<obj::Id, gen::Dna>;

pub struct AlifeSystem {
	dt: Seconds,
	source: Box<[world::Emitter]>,
	eaten: StateMap,
	touched: GeneMap,
}

impl Updateable for AlifeSystem {
	fn update(&mut self, _: &WorldState, dt: Seconds) {
		self.dt = dt;
	}
}

impl System for AlifeSystem {
	fn get_from_world(&mut self, world: &world::World) {
		self.source = world.emitters().to_vec().into_boxed_slice();
		self.eaten = Self::find_eaten_resources(
			&world.agents(agent::AgentType::Minion),
			&world.agents(agent::AgentType::Resource),
		);
		self.touched = Self::find_touched_spores(
			&world.agents(agent::AgentType::Minion),
			&world.agents(agent::AgentType::Spore),
		);
	}

	fn put_to_world(&self, world: &mut world::World) {
		Self::update_resources(
			self.dt,
			&mut world.agents_mut(agent::AgentType::Resource),
			&self.eaten,
		);

		let (spores, corpses) = Self::update_minions(
			self.dt,
			&world.extent.clone(),
			&mut world.agents_mut(agent::AgentType::Minion),
			&self.eaten,
		);
		let (hatch, fertilised) = Self::update_spores(
			self.dt,
			&mut world.agents_mut(agent::AgentType::Spore),
			&self.touched,
		);

		for &(ref transform, ref dna) in spores.into_iter() {
			world.alert(alert::Alert::NewSpore);
			world.new_spore(transform, dna);
		}
		for &(ref transform, ref dna) in hatch.into_iter() {
			world.alert(alert::Alert::NewMinion);
			world.hatch_spore(transform, dna);
		}
		for &(ref transform, ref dna) in corpses.into_iter() {
			world.alert(alert::Alert::DieMinion);
			world.decay_to_resource(transform, dna);
		}
		for _ in 0..fertilised {
			world.alert(alert::Alert::Fertilised);
		}
	}
}

impl Default for AlifeSystem {
	fn default() -> Self {
		AlifeSystem {
			dt: Seconds::new(1. / 60.),
			source: Box::new([]),
			eaten: StateMap::new(),
			touched: GeneMap::new(),
		}
	}
}

impl AlifeSystem {
	fn find_eaten_resources(minions: &agent::AgentMap, resources: &agent::AgentMap) -> StateMap {
		let mut eaten = HashMap::new();
		for (_, agent) in minions.iter().filter(|&(_, a)| a.state.is_active()) {
			for segment in agent.segments.iter().filter(|&s| {
				s.flags.contains(segment::Flags::MOUTH)
			})
				{
					if let Some(key) = segment.state.last_touched {
						if let Some(&agent::Agent { ref state, .. }) = resources.get(&key.id()) {
							eaten.insert(key.id(), (*state).clone());
						}
					}
				}
		}
		eaten
	}

	fn find_touched_spores(minions: &agent::AgentMap, spores: &agent::AgentMap) -> GeneMap {
		let mut touched = HashMap::new();
		for (_, spore) in spores.iter().filter(|&(_, a)| {
			a.state.is_active() && !a.state.is_fertilised()
		})
			{
				for segment in spore.segments.iter() {
					if let Some(key) = segment.state.last_touched {
						if let Some(ref agent) = minions.get(&key.id()) {
							if agent.gender() != spore.gender() {
								touched.insert(key.id(), agent.dna().clone());
							}
						}
					}
				}
			}
		touched
	}

	fn update_minions(dt: Seconds, extent: &geometry::Rect, minions: &mut agent::AgentMap, eaten: &StateMap)
					  -> (Box<[(geometry::Transform, gen::Dna)]>, Box<[(geometry::Transform, gen::Dna)]>) {
		let mut spawns = Vec::new();
		let mut corpses = Vec::new();
		for (_, agent) in minions.iter_mut() {
			if agent.state.is_active() {
				if agent.state.lifecycle().is_expired() && agent.state.consume_ratio(0.75) {
					spawns.push((
						agent.last_segment().transform().clone(),
						agent.dna().clone(),
					));
					agent.state.renew();
				}
				for segment in agent.segments.iter_mut() {
					let p = segment.transform().position;
					if p.x < extent.min.x || p.x > extent.max.x || p.y < extent.min.y || p.y > extent.max.y {
						agent.state.die();
					}
					if segment.flags.contains(segment::Flags::MOUTH) {
						if let Some(id) = segment.state.last_touched {
							if let Some(eaten_state) = eaten.get(&id.id()) {
								agent.state.absorb(eaten_state.energy());
							}
						}
					}
					agent.state.consume(
						dt.get() * segment.state.get_charge() * segment.mesh.shape.radius(),
					);
					segment.state.update(dt);
				}

				if agent.state.energy() < 1. {
					for segment in agent.segments.iter().filter(|s| {
						s.flags.contains(segment::Flags::STORAGE)
					})
						{
							corpses.push((segment.transform.clone(), agent.dna().clone()));
						}
					agent.state.die();
				}

				if let Some(segment) = agent.first_segment(segment::Flags::TRACKER) {
					agent.state.track_position(&segment.transform.position);
				}
			}
		}
		(spawns.into_boxed_slice(), corpses.into_boxed_slice())
	}

	fn update_resources(dt: Seconds, resources: &mut agent::AgentMap, eaten: &StateMap) {
		for (_, agent) in resources.iter_mut() {
			if eaten.get(&agent.id()).is_some() {
				agent.state.die();
			} else if agent.state.energy() <= 0. {
				agent.state.die();
			} else if agent.state.lifecycle().is_expired() {
				agent.state.die();
			} else if agent.state.is_active() {
				for segment in agent.segments.iter_mut() {
					segment.state.update(dt)
				}
			}
		}
	}

	fn crossover(dna: &gen::Dna, foreign_dna: &Option<gen::Dna>) -> gen::Dna {
		match foreign_dna {
			&Some(ref foreign) => {
				gen::Genome::new(&foreign)
					.crossover(&mut rand::thread_rng(), dna)
					.dna()
					.clone()
			}
			&None => dna.clone(),
		}
	}

	fn update_spores(dt: Seconds, spores: &mut agent::AgentMap, touched: &GeneMap)
					 -> (Box<[(geometry::Transform, gen::Dna)]>, usize) {
		let mut spawns = Vec::new();
		let mut fertilise_count = 0usize;
		for (spore_id, spore) in spores.iter_mut() {
			if spore.state.lifecycle().is_expired() {
				spore.state.die();
				spawns.push((
					spore.transform().clone(),
					Self::crossover(spore.dna(), spore.state.foreign_dna()),
				))
			} else if spore.state.is_active() {
				for segment in spore.segments.iter_mut() {
					if let Some(key) = segment.state.last_touched {
						if let Some(touched_dna) = touched.get(&key.id()) {
							info!(
								"fertilised: {} by {} as {}",
								spore_id,
								key.id(),
								touched_dna.to_base64(base64::STANDARD)
							);
							fertilise_count += 1;
							spore.state.fertilise(touched_dna);
						}
					}
				}
				for segment in spore.segments.iter_mut() {
					segment.state.update(dt)
				}
			}
		}
		(spawns.into_boxed_slice(), fertilise_count)
	}
}
<commit_msg>More material to scavenge after minion death<commit_after>use super::*;
use std::collections::HashMap;
use rand;
use core::geometry;
use backend::obj;
use backend::obj::Transformable;
use backend::obj::Identified;
use backend::world;
use backend::world::gen;
use backend::world::agent;
use backend::world::segment;
use backend::world::WorldState;
use backend::world::alert;
use backend::world::AlertReceiver;
use serialize::base64::{self, ToBase64};

type StateMap = HashMap<obj::Id, agent::State>;
type GeneMap = HashMap<obj::Id, gen::Dna>;

pub struct AlifeSystem {
	dt: Seconds,
	source: Box<[world::Emitter]>,
	eaten: StateMap,
	touched: GeneMap,
}

impl Updateable for AlifeSystem {
	fn update(&mut self, _: &WorldState, dt: Seconds) {
		self.dt = dt;
	}
}

impl System for AlifeSystem {
	fn get_from_world(&mut self, world: &world::World) {
		self.source = world.emitters().to_vec().into_boxed_slice();
		self.eaten = Self::find_eaten_resources(
			&world.agents(agent::AgentType::Minion),
			&world.agents(agent::AgentType::Resource),
		);
		self.touched = Self::find_touched_spores(
			&world.agents(agent::AgentType::Minion),
			&world.agents(agent::AgentType::Spore),
		);
	}

	fn put_to_world(&self, world: &mut world::World) {
		Self::update_resources(
			self.dt,
			&mut world.agents_mut(agent::AgentType::Resource),
			&self.eaten,
		);

		let (spores, corpses) = Self::update_minions(
			self.dt,
			&world.extent.clone(),
			&mut world.agents_mut(agent::AgentType::Minion),
			&self.eaten,
		);
		let (hatch, fertilised) = Self::update_spores(
			self.dt,
			&mut world.agents_mut(agent::AgentType::Spore),
			&self.touched,
		);

		for &(ref transform, ref dna) in spores.into_iter() {
			world.alert(alert::Alert::NewSpore);
			world.new_spore(transform, dna);
		}
		for &(ref transform, ref dna) in hatch.into_iter() {
			world.alert(alert::Alert::NewMinion);
			world.hatch_spore(transform, dna);
		}
		for &(ref transform, ref dna) in corpses.into_iter() {
			world.alert(alert::Alert::DieMinion);
			world.decay_to_resource(transform, dna);
		}
		for _ in 0..fertilised {
			world.alert(alert::Alert::Fertilised);
		}
	}
}

impl Default for AlifeSystem {
	fn default() -> Self {
		AlifeSystem {
			dt: Seconds::new(1. / 60.),
			source: Box::new([]),
			eaten: StateMap::new(),
			touched: GeneMap::new(),
		}
	}
}

impl AlifeSystem {
	fn find_eaten_resources(minions: &agent::AgentMap, resources: &agent::AgentMap) -> StateMap {
		let mut eaten = HashMap::new();
		for (_, agent) in minions.iter().filter(|&(_, a)| a.state.is_active()) {
			for segment in agent.segments.iter().filter(|&s| {
				s.flags.contains(segment::Flags::MOUTH)
			})
				{
					if let Some(key) = segment.state.last_touched {
						if let Some(&agent::Agent { ref state, .. }) = resources.get(&key.id()) {
							eaten.insert(key.id(), (*state).clone());
						}
					}
				}
		}
		eaten
	}

	fn find_touched_spores(minions: &agent::AgentMap, spores: &agent::AgentMap) -> GeneMap {
		let mut touched = HashMap::new();
		for (_, spore) in spores.iter().filter(|&(_, a)| {
			a.state.is_active() && !a.state.is_fertilised()
		})
			{
				for segment in spore.segments.iter() {
					if let Some(key) = segment.state.last_touched {
						if let Some(ref agent) = minions.get(&key.id()) {
							if agent.gender() != spore.gender() {
								touched.insert(key.id(), agent.dna().clone());
							}
						}
					}
				}
			}
		touched
	}

	fn update_minions(dt: Seconds, extent: &geometry::Rect, minions: &mut agent::AgentMap, eaten: &StateMap)
					  -> (Box<[(geometry::Transform, gen::Dna)]>, Box<[(geometry::Transform, gen::Dna)]>) {
		let mut spawns = Vec::new();
		let mut corpses = Vec::new();
		for (_, agent) in minions.iter_mut() {
			if agent.state.is_active() {
				if agent.state.lifecycle().is_expired() && agent.state.consume_ratio(0.75) {
					spawns.push((
						agent.last_segment().transform().clone(),
						agent.dna().clone(),
					));
					agent.state.renew();
				}
				for segment in agent.segments.iter_mut() {
					let p = segment.transform().position;
					if p.x < extent.min.x || p.x > extent.max.x || p.y < extent.min.y || p.y > extent.max.y {
						agent.state.die();
					}
					if segment.flags.contains(segment::Flags::MOUTH) {
						if let Some(id) = segment.state.last_touched {
							if let Some(eaten_state) = eaten.get(&id.id()) {
								agent.state.absorb(eaten_state.energy());
							}
						}
					}
					agent.state.consume(
						dt.get() * segment.state.get_charge() * segment.mesh.shape.radius(),
					);
					segment.state.update(dt);
				}

				if agent.state.energy() < 1. {
					for segment in agent.segments.iter().filter(|s| {
						true//s.flags.contains(segment::Flags::STORAGE)
					})
						{
							corpses.push((segment.transform.clone(), agent.dna().clone()));
						}
					agent.state.die();
				}

				if let Some(segment) = agent.first_segment(segment::Flags::TRACKER) {
					agent.state.track_position(&segment.transform.position);
				}
			}
		}
		(spawns.into_boxed_slice(), corpses.into_boxed_slice())
	}

	fn update_resources(dt: Seconds, resources: &mut agent::AgentMap, eaten: &StateMap) {
		for (_, agent) in resources.iter_mut() {
			if eaten.get(&agent.id()).is_some() {
				agent.state.die();
			} else if agent.state.energy() <= 0. {
				agent.state.die();
			} else if agent.state.lifecycle().is_expired() {
				agent.state.die();
			} else if agent.state.is_active() {
				for segment in agent.segments.iter_mut() {
					segment.state.update(dt)
				}
			}
		}
	}

	fn crossover(dna: &gen::Dna, foreign_dna: &Option<gen::Dna>) -> gen::Dna {
		match foreign_dna {
			&Some(ref foreign) => {
				gen::Genome::new(&foreign)
					.crossover(&mut rand::thread_rng(), dna)
					.dna()
					.clone()
			}
			&None => dna.clone(),
		}
	}

	fn update_spores(dt: Seconds, spores: &mut agent::AgentMap, touched: &GeneMap)
					 -> (Box<[(geometry::Transform, gen::Dna)]>, usize) {
		let mut spawns = Vec::new();
		let mut fertilise_count = 0usize;
		for (spore_id, spore) in spores.iter_mut() {
			if spore.state.lifecycle().is_expired() {
				spore.state.die();
				spawns.push((
					spore.transform().clone(),
					Self::crossover(spore.dna(), spore.state.foreign_dna()),
				))
			} else if spore.state.is_active() {
				for segment in spore.segments.iter_mut() {
					if let Some(key) = segment.state.last_touched {
						if let Some(touched_dna) = touched.get(&key.id()) {
							info!(
								"fertilised: {} by {} as {}",
								spore_id,
								key.id(),
								touched_dna.to_base64(base64::STANDARD)
							);
							fertilise_count += 1;
							spore.state.fertilise(touched_dna);
						}
					}
				}
				for segment in spore.segments.iter_mut() {
					segment.state.update(dt)
				}
			}
		}
		(spawns.into_boxed_slice(), fertilise_count)
	}
}
<|endoftext|>