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

use std::collections::{HashMap, HashSet};
use std::thread;
use std::net::{SocketAddr, TcpStream};
use std::sync::{Arc, Mutex, RwLock, mpsc};
use std::sync::atomic::{Ordering, AtomicUsize};
use std::time::Duration;

use rocksdb::DB;

use super::cluster::{Simulator, Cluster};
use tikv::server::{Server, ServerTransport, SendCh, create_event_loop, Msg, bind};
use tikv::server::{Node, Config, create_raft_storage, PdStoreAddrResolver};
use tikv::raftstore::Result;
use tikv::util::codec::rpc;
use tikv::util::make_std_tcp_conn;
use kvproto::raft_serverpb;
use kvproto::msgpb::{Message, MessageType};
use kvproto::raft_cmdpb::*;
use super::pd::TestPdClient;
use super::pd_ask::run_ask_loop;
use super::transport_simulate::{Strategy, SimulateTransport};

pub struct ServerCluster {
    cluster_id: u64,
    senders: HashMap<u64, SendCh>,
    handles: HashMap<u64, thread::JoinHandle<()>>,
    addrs: HashMap<u64, SocketAddr>,
    conns: Mutex<HashMap<SocketAddr, Vec<TcpStream>>>,

    msg_id: AtomicUsize,
    pd_client: Arc<RwLock<TestPdClient>>,
}

impl ServerCluster {
    pub fn new(cluster_id: u64, pd_client: Arc<RwLock<TestPdClient>>) -> ServerCluster {
        ServerCluster {
            cluster_id: cluster_id,
            senders: HashMap::new(),
            handles: HashMap::new(),
            addrs: HashMap::new(),
            conns: Mutex::new(HashMap::new()),
            msg_id: AtomicUsize::new(1),
            pd_client: pd_client,
        }
    }

    fn alloc_msg_id(&self) -> u64 {
        self.msg_id.fetch_add(1, Ordering::Relaxed) as u64
    }

    fn pool_get(&self, addr: &SocketAddr) -> Result<TcpStream> {
        {
            let mut conns = self.conns
                                .lock()
                                .unwrap();
            let conn = conns.get_mut(addr);
            if let Some(mut pool) = conn {
                if !pool.is_empty() {
                    return Ok(pool.pop().unwrap());
                }
            }
        }

        let conn = make_std_tcp_conn(addr).unwrap();
        Ok(conn)
    }

    fn pool_put(&self, addr: &SocketAddr, conn: TcpStream) {
        let mut conns = self.conns
                            .lock()
                            .unwrap();
        let p = conns.entry(*addr).or_insert_with(Vec::new);
        p.push(conn);
    }
}

impl Simulator for ServerCluster {
    #[allow(useless_format)]
    fn run_node(&mut self,
                node_id: u64,
                cfg: Config,
                engine: Arc<DB>,
                strategy: Vec<Strategy>)
                -> u64 {
        assert!(node_id == 0 || !self.handles.contains_key(&node_id));
        assert!(node_id == 0 || !self.senders.contains_key(&node_id));

        // TODO: simplify creating raft server later.
        let mut event_loop = create_event_loop().unwrap();
        let sendch = SendCh::new(event_loop.channel());
        let resolver = PdStoreAddrResolver::new(self.cluster_id, self.pd_client.clone()).unwrap();
        let trans = Arc::new(RwLock::new(ServerTransport::new(sendch)));

        let mut cfg = cfg;

        let listener = bind(&cfg.addr).unwrap();
        let addr = listener.local_addr().unwrap();
        cfg.addr = format!("{}", addr);

        let simulate_trans = SimulateTransport::new(strategy, trans.clone());
        let mut node = Node::new(&cfg,
                                 self.pd_client.clone(),
                                 Arc::new(RwLock::new(simulate_trans)));

        node.start(engine.clone()).unwrap();
        let router = node.raft_store_router();

        assert!(node_id == 0 || node_id == node.id());
        let node_id = node.id();

        let store = create_raft_storage(node, engine).unwrap();

        let mut server = Server::new(&mut event_loop, listener, store, router, resolver).unwrap();

        let ch = server.get_sendch();

        let t = thread::spawn(move || {
            server.run(&mut event_loop).unwrap();
        });

        self.handles.insert(node_id, t);
        self.senders.insert(node_id, ch);
        self.addrs.insert(node_id, addr);

        node_id
    }

    fn stop_node(&mut self, node_id: u64) {
        let h = self.handles.remove(&node_id).unwrap();
        let ch = self.senders.remove(&node_id).unwrap();
        self.addrs.remove(&node_id).unwrap();

        ch.send(Msg::Quit).unwrap();
        h.join().unwrap();
    }

    fn get_node_ids(&self) -> HashSet<u64> {
        self.senders.keys().cloned().collect()
    }

    fn call_command(&self, request: RaftCmdRequest, timeout: Duration) -> Result<RaftCmdResponse> {
        let store_id = request.get_header().get_peer().get_store_id();
        let addr = self.addrs.get(&store_id).unwrap();
        let mut conn = self.pool_get(addr).unwrap();

        let mut msg = Message::new();
        msg.set_msg_type(MessageType::Cmd);
        msg.set_cmd_req(request);

        let msg_id = self.alloc_msg_id();
        conn.set_write_timeout(Some(timeout)).unwrap();
        try!(rpc::encode_msg(&mut conn, msg_id, &msg));

        conn.set_read_timeout(Some(timeout)).unwrap();
        let mut resp_msg = Message::new();
        let get_msg_id = try!(rpc::decode_msg(&mut conn, &mut resp_msg));

        self.pool_put(addr, conn);

        assert_eq!(resp_msg.get_msg_type(), MessageType::CmdResp);
        assert_eq!(msg_id, get_msg_id);

        Ok(resp_msg.take_cmd_resp())
    }

    fn send_raft_msg(&self, raft_msg: raft_serverpb::RaftMessage) -> Result<()> {
        let store_id = raft_msg.get_to_peer().get_store_id();
        let addr = self.addrs.get(&store_id).unwrap();

        let mut msg = Message::new();
        msg.set_msg_type(MessageType::Raft);
        msg.set_raft(raft_msg);
        let msg_id = self.alloc_msg_id();

        let mut conn = self.pool_get(addr).unwrap();
        conn.set_write_timeout(Some(Duration::from_secs(3))).unwrap();
        try!(rpc::encode_msg(&mut conn, msg_id, &msg));

        self.pool_put(addr, conn);

        Ok(())
    }
}

pub fn new_server_cluster(id: u64, count: usize) -> Cluster<ServerCluster> {
    let (tx, rx) = mpsc::channel();
    let pd_client = Arc::new(RwLock::new(TestPdClient::new(tx)));
    let sim = Arc::new(RwLock::new(ServerCluster::new(id, pd_client.clone())));
    run_ask_loop(pd_client.clone(), sim.clone(), rx);
    Cluster::new(id, count, sim, pd_client)
}
<commit_msg>raftstore: convert socket timeout error. (#487)<commit_after>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::{HashMap, HashSet};
use std::thread;
use std::net::{SocketAddr, TcpStream};
use std::sync::{Arc, Mutex, RwLock, mpsc};
use std::sync::atomic::{Ordering, AtomicUsize};
use std::time::Duration;
use std::io::ErrorKind;

use rocksdb::DB;

use super::cluster::{Simulator, Cluster};
use tikv::server::{Server, ServerTransport, SendCh, create_event_loop, Msg, bind};
use tikv::server::{Node, Config, create_raft_storage, PdStoreAddrResolver};
use tikv::raftstore::{Error, Result};
use tikv::util::codec::{Error as CodecError, rpc};
use tikv::util::make_std_tcp_conn;
use kvproto::raft_serverpb;
use kvproto::msgpb::{Message, MessageType};
use kvproto::raft_cmdpb::*;
use super::pd::TestPdClient;
use super::pd_ask::run_ask_loop;
use super::transport_simulate::{Strategy, SimulateTransport};

pub struct ServerCluster {
    cluster_id: u64,
    senders: HashMap<u64, SendCh>,
    handles: HashMap<u64, thread::JoinHandle<()>>,
    addrs: HashMap<u64, SocketAddr>,
    conns: Mutex<HashMap<SocketAddr, Vec<TcpStream>>>,

    msg_id: AtomicUsize,
    pd_client: Arc<RwLock<TestPdClient>>,
}

impl ServerCluster {
    pub fn new(cluster_id: u64, pd_client: Arc<RwLock<TestPdClient>>) -> ServerCluster {
        ServerCluster {
            cluster_id: cluster_id,
            senders: HashMap::new(),
            handles: HashMap::new(),
            addrs: HashMap::new(),
            conns: Mutex::new(HashMap::new()),
            msg_id: AtomicUsize::new(1),
            pd_client: pd_client,
        }
    }

    fn alloc_msg_id(&self) -> u64 {
        self.msg_id.fetch_add(1, Ordering::Relaxed) as u64
    }

    fn pool_get(&self, addr: &SocketAddr) -> Result<TcpStream> {
        {
            let mut conns = self.conns
                                .lock()
                                .unwrap();
            let conn = conns.get_mut(addr);
            if let Some(mut pool) = conn {
                if !pool.is_empty() {
                    return Ok(pool.pop().unwrap());
                }
            }
        }

        let conn = make_std_tcp_conn(addr).unwrap();
        Ok(conn)
    }

    fn pool_put(&self, addr: &SocketAddr, conn: TcpStream) {
        let mut conns = self.conns
                            .lock()
                            .unwrap();
        let p = conns.entry(*addr).or_insert_with(Vec::new);
        p.push(conn);
    }
}

impl Simulator for ServerCluster {
    #[allow(useless_format)]
    fn run_node(&mut self,
                node_id: u64,
                cfg: Config,
                engine: Arc<DB>,
                strategy: Vec<Strategy>)
                -> u64 {
        assert!(node_id == 0 || !self.handles.contains_key(&node_id));
        assert!(node_id == 0 || !self.senders.contains_key(&node_id));

        // TODO: simplify creating raft server later.
        let mut event_loop = create_event_loop().unwrap();
        let sendch = SendCh::new(event_loop.channel());
        let resolver = PdStoreAddrResolver::new(self.cluster_id, self.pd_client.clone()).unwrap();
        let trans = Arc::new(RwLock::new(ServerTransport::new(sendch)));

        let mut cfg = cfg;

        let listener = bind(&cfg.addr).unwrap();
        let addr = listener.local_addr().unwrap();
        cfg.addr = format!("{}", addr);

        let simulate_trans = SimulateTransport::new(strategy, trans.clone());
        let mut node = Node::new(&cfg,
                                 self.pd_client.clone(),
                                 Arc::new(RwLock::new(simulate_trans)));

        node.start(engine.clone()).unwrap();
        let router = node.raft_store_router();

        assert!(node_id == 0 || node_id == node.id());
        let node_id = node.id();

        let store = create_raft_storage(node, engine).unwrap();

        let mut server = Server::new(&mut event_loop, listener, store, router, resolver).unwrap();

        let ch = server.get_sendch();

        let t = thread::spawn(move || {
            server.run(&mut event_loop).unwrap();
        });

        self.handles.insert(node_id, t);
        self.senders.insert(node_id, ch);
        self.addrs.insert(node_id, addr);

        node_id
    }

    fn stop_node(&mut self, node_id: u64) {
        let h = self.handles.remove(&node_id).unwrap();
        let ch = self.senders.remove(&node_id).unwrap();
        self.addrs.remove(&node_id).unwrap();

        ch.send(Msg::Quit).unwrap();
        h.join().unwrap();
    }

    fn get_node_ids(&self) -> HashSet<u64> {
        self.senders.keys().cloned().collect()
    }

    fn call_command(&self, request: RaftCmdRequest, timeout: Duration) -> Result<RaftCmdResponse> {
        let store_id = request.get_header().get_peer().get_store_id();
        let addr = self.addrs.get(&store_id).unwrap();
        let mut conn = self.pool_get(addr).unwrap();

        let mut msg = Message::new();
        msg.set_msg_type(MessageType::Cmd);
        msg.set_cmd_req(request);

        let msg_id = self.alloc_msg_id();
        conn.set_write_timeout(Some(timeout)).unwrap();
        try!(rpc::encode_msg(&mut conn, msg_id, &msg));

        conn.set_read_timeout(Some(timeout)).unwrap();
        let mut resp_msg = Message::new();
        let get_msg_id = try!(rpc::decode_msg(&mut conn, &mut resp_msg).map_err(|e| {
            if let CodecError::Io(ref err) = e {
                // For unix, read timeout returns WouldBlock but windows returns TimedOut.
                if err.kind() == ErrorKind::WouldBlock || err.kind() == ErrorKind::TimedOut {
                    return Error::Timeout(format!("{:?}", err));
                }
            }

            Error::Codec(e)
        }));

        self.pool_put(addr, conn);

        assert_eq!(resp_msg.get_msg_type(), MessageType::CmdResp);
        assert_eq!(msg_id, get_msg_id);

        Ok(resp_msg.take_cmd_resp())
    }

    fn send_raft_msg(&self, raft_msg: raft_serverpb::RaftMessage) -> Result<()> {
        let store_id = raft_msg.get_to_peer().get_store_id();
        let addr = self.addrs.get(&store_id).unwrap();

        let mut msg = Message::new();
        msg.set_msg_type(MessageType::Raft);
        msg.set_raft(raft_msg);
        let msg_id = self.alloc_msg_id();

        let mut conn = self.pool_get(addr).unwrap();
        conn.set_write_timeout(Some(Duration::from_secs(3))).unwrap();
        try!(rpc::encode_msg(&mut conn, msg_id, &msg));

        self.pool_put(addr, conn);

        Ok(())
    }
}

pub fn new_server_cluster(id: u64, count: usize) -> Cluster<ServerCluster> {
    let (tx, rx) = mpsc::channel();
    let pd_client = Arc::new(RwLock::new(TestPdClient::new(tx)));
    let sim = Arc::new(RwLock::new(ServerCluster::new(id, pd_client.clone())));
    run_ask_loop(pd_client.clone(), sim.clone(), rx);
    Cluster::new(id, count, sim, pd_client)
}
<|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/. */

use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::{self, CSSStyleDeclarationMethods};
use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::global::GlobalRef;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, Root};
use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::element::{Element, StylePriority};
use dom::node::{Node, NodeDamage, window_from_node};
use dom::window::Window;
use std::ascii::AsciiExt;
use std::borrow::ToOwned;
use std::cell::Ref;
use string_cache::Atom;
use style::parser::ParserContextExtraData;
use style::properties::{PropertyDeclaration, Shorthand};
use style::properties::{is_supported_property, parse_one_declaration};
use style::selector_impl::PseudoElement;
use util::str::str_join;

// http://dev.w3.org/csswg/cssom/#the-cssstyledeclaration-interface
#[dom_struct]
pub struct CSSStyleDeclaration {
    reflector_: Reflector,
    owner: JS<Element>,
    readonly: bool,
    pseudo: Option<PseudoElement>,
}

#[derive(PartialEq, HeapSizeOf)]
pub enum CSSModificationAccess {
    ReadWrite,
    Readonly,
}

macro_rules! css_properties(
    ( $([$getter:ident, $setter:ident, $cssprop:expr]),* ) => (
        $(
            fn $getter(&self) -> DOMString {
                self.GetPropertyValue(DOMString::from($cssprop))
            }
            fn $setter(&self, value: DOMString) -> ErrorResult {
                self.SetPropertyValue(DOMString::from($cssprop), value)
            }
        )*
    );
);

fn serialize_shorthand(shorthand: Shorthand, declarations: &[Ref<PropertyDeclaration>]) -> String {
    // https://drafts.csswg.org/css-variables/#variables-in-shorthands
    if let Some(css) = declarations[0].with_variables_from_shorthand(shorthand) {
        if declarations[1..]
               .iter()
               .all(|d| d.with_variables_from_shorthand(shorthand) == Some(css)) {
            css.to_owned()
        } else {
            String::new()
        }
    } else {
        if declarations.iter().any(|d| d.with_variables()) {
            String::new()
        } else {
            let str_iter = declarations.iter().map(|d| d.value());
            // FIXME: this needs property-specific code, which probably should be in style/
            // "as appropriate according to the grammar of shorthand "
            // https://drafts.csswg.org/cssom/#serialize-a-css-value
            str_join(str_iter, " ")
        }
    }
}

impl CSSStyleDeclaration {
    pub fn new_inherited(owner: &Element,
                         pseudo: Option<PseudoElement>,
                         modification_access: CSSModificationAccess)
                         -> CSSStyleDeclaration {
        CSSStyleDeclaration {
            reflector_: Reflector::new(),
            owner: JS::from_ref(owner),
            readonly: modification_access == CSSModificationAccess::Readonly,
            pseudo: pseudo,
        }
    }

    pub fn new(global: &Window,
               owner: &Element,
               pseudo: Option<PseudoElement>,
               modification_access: CSSModificationAccess)
               -> Root<CSSStyleDeclaration> {
        reflect_dom_object(box CSSStyleDeclaration::new_inherited(owner,
                                                                  pseudo,
                                                                  modification_access),
                           GlobalRef::Window(global),
                           CSSStyleDeclarationBinding::Wrap)
    }

    fn get_computed_style(&self, property: &Atom) -> Option<DOMString> {
        let node = self.owner.upcast::<Node>();
        if !node.is_in_doc() {
            // TODO: Node should be matched against the style rules of this window.
            // Firefox is currently the only browser to implement this.
            return None;
        }
        let addr = node.to_trusted_node_address();
        window_from_node(&*self.owner).resolved_style_query(addr, self.pseudo.clone(), property)
    }
}

impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
    // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-length
    fn Length(&self) -> u32 {
        let elem = self.owner.upcast::<Element>();
        let len = match *elem.style_attribute().borrow() {
            Some(ref declarations) => declarations.normal.len() + declarations.important.len(),
            None => 0,
        };
        len as u32
    }

    // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-item
    fn Item(&self, index: u32) -> DOMString {
        let index = index as usize;
        let elem = self.owner.upcast::<Element>();
        let style_attribute = elem.style_attribute().borrow();
        let result = style_attribute.as_ref().and_then(|declarations| {
            if index > declarations.normal.len() {
                declarations.important
                            .get(index - declarations.normal.len())
                            .map(|decl| format!("{:?} !important", decl))
            } else {
                declarations.normal
                            .get(index)
                            .map(|decl| format!("{:?}", decl))
            }
        });

        result.map_or(DOMString::new(), DOMString::from)
    }

    // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertyvalue
    fn GetPropertyValue(&self, mut property: DOMString) -> DOMString {
        let owner = &self.owner;

        // Step 1
        property.make_ascii_lowercase();
        let property = Atom::from(property);

        if self.readonly {
            // Readonly style declarations are used for getComputedStyle.
            return self.get_computed_style(&property).unwrap_or(DOMString::new());
        }

        // Step 2
        if let Some(shorthand) = Shorthand::from_name(&property) {
            // Step 2.1
            let mut list = vec![];

            // Step 2.2
            for longhand in shorthand.longhands() {
                // Step 2.2.1
                let declaration = owner.get_inline_style_declaration(&Atom::from(*longhand));

                // Step 2.2.2 & 2.2.3
                match declaration {
                    Some(declaration) => list.push(declaration),
                    None => return DOMString::new(),
                }
            }

            // Step 2.3
            return DOMString::from(serialize_shorthand(shorthand, &list));
        }

        // Step 3 & 4
        match owner.get_inline_style_declaration(&property) {
            Some(declaration) => DOMString::from(declaration.value()),
            None => DOMString::new(),
        }
    }

    // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertypriority
    fn GetPropertyPriority(&self, mut property: DOMString) -> DOMString {
        // Step 1
        property.make_ascii_lowercase();
        let property = Atom::from(property);

        // Step 2
        if let Some(shorthand) = Shorthand::from_name(&property) {
            // Step 2.1 & 2.2 & 2.3
            if shorthand.longhands().iter()
                                    .map(|&longhand| self.GetPropertyPriority(DOMString::from(longhand)))
                                    .all(|priority| priority == "important") {

                return DOMString::from("important");
            }
        // Step 3
        } else {
            if self.owner.get_important_inline_style_declaration(&property).is_some() {
                return DOMString::from("important");
            }
        }

        // Step 4
        DOMString::new()
    }

    // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-setproperty
    fn SetProperty(&self,
                   mut property: DOMString,
                   value: DOMString,
                   priority: DOMString)
                   -> ErrorResult {
        // Step 1
        if self.readonly {
            return Err(Error::NoModificationAllowed);
        }

        // Step 2
        property.make_ascii_lowercase();

        // Step 3
        if !is_supported_property(&property) {
            return Ok(());
        }

        // Step 4
        if value.is_empty() {
            return self.RemoveProperty(property).map(|_| ());
        }

        // Step 5
        let priority = match &*priority {
            "" => StylePriority::Normal,
            p if p.eq_ignore_ascii_case("important") => StylePriority::Important,
            _ => return Ok(()),
        };

        // Step 6
        let window = window_from_node(&*self.owner);
        let declarations =
            parse_one_declaration(&property, &value, &window.get_url(), window.css_error_reporter(),
                                  ParserContextExtraData::default());

        // Step 7
        let declarations = if let Ok(declarations) = declarations {
            declarations
        } else {
            return Ok(());
        };

        let element = self.owner.upcast::<Element>();

        // Step 8
        for decl in declarations {
            // Step 9
            element.update_inline_style(decl, priority);
        }

        let node = element.upcast::<Node>();
        node.dirty(NodeDamage::NodeStyleDamaged);
        Ok(())
    }

    // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-setpropertypriority
    fn SetPropertyPriority(&self, property: DOMString, priority: DOMString) -> ErrorResult {
        // Step 1
        if self.readonly {
            return Err(Error::NoModificationAllowed);
        }

        // Step 2 & 3
        if !is_supported_property(&property) {
            return Ok(());
        }

        // Step 4
        let priority = match &*priority {
            "" => StylePriority::Normal,
            p if p.eq_ignore_ascii_case("important") => StylePriority::Important,
            _ => return Ok(()),
        };

        let element = self.owner.upcast::<Element>();

        // Step 5 & 6
        match Shorthand::from_name(&property) {
            Some(shorthand) => {
                element.set_inline_style_property_priority(shorthand.longhands(), priority)
            }
            None => element.set_inline_style_property_priority(&[&*property], priority),
        }

        let node = element.upcast::<Node>();
        node.dirty(NodeDamage::NodeStyleDamaged);
        Ok(())
    }

    // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-setpropertyvalue
    fn SetPropertyValue(&self, property: DOMString, value: DOMString) -> ErrorResult {
        self.SetProperty(property, value, DOMString::new())
    }

    // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-removeproperty
    fn RemoveProperty(&self, mut property: DOMString) -> Fallible<DOMString> {
        // Step 1
        if self.readonly {
            return Err(Error::NoModificationAllowed);
        }

        // Step 2
        property.make_ascii_lowercase();

        // Step 3
        let value = self.GetPropertyValue(property.clone());

        let elem = self.owner.upcast::<Element>();

        match Shorthand::from_name(&property) {
            // Step 4
            Some(shorthand) => {
                for longhand in shorthand.longhands() {
                    elem.remove_inline_style_property(longhand)
                }
            }
            // Step 5
            None => elem.remove_inline_style_property(&property),
        }

        let node = elem.upcast::<Node>();
        node.dirty(NodeDamage::NodeStyleDamaged);

        // Step 6
        Ok(value)
    }

    // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-cssfloat
    fn CssFloat(&self) -> DOMString {
        self.GetPropertyValue(DOMString::from("float"))
    }

    // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-cssfloat
    fn SetCssFloat(&self, value: DOMString) -> ErrorResult {
        self.SetPropertyValue(DOMString::from("float"), value)
    }

    // https://dev.w3.org/csswg/cssom/#the-cssstyledeclaration-interface
    fn IndexedGetter(&self, index: u32, found: &mut bool) -> DOMString {
        let rval = self.Item(index);
        *found = index < self.Length();
        rval
    }

    // https://drafts.csswg.org/cssom/#cssstyledeclaration
    css_properties_accessors!(css_properties);
}
<commit_msg>Removed previously copied serialize_shorthand method as well as unnecessary calls to document.content_changed<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/. */

use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::{self, CSSStyleDeclarationMethods};
use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::global::GlobalRef;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, Root};
use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::element::{Element, StylePriority};
use dom::node::{Node, NodeDamage, window_from_node};
use dom::window::Window;
use std::ascii::AsciiExt;
use string_cache::Atom;
use style::parser::ParserContextExtraData;
use style::properties::{PropertyDeclaration, Shorthand};
use style::properties::{is_supported_property, parse_one_declaration};
use style::selector_impl::PseudoElement;

// http://dev.w3.org/csswg/cssom/#the-cssstyledeclaration-interface
#[dom_struct]
pub struct CSSStyleDeclaration {
    reflector_: Reflector,
    owner: JS<Element>,
    readonly: bool,
    pseudo: Option<PseudoElement>,
}

#[derive(PartialEq, HeapSizeOf)]
pub enum CSSModificationAccess {
    ReadWrite,
    Readonly,
}

macro_rules! css_properties(
    ( $([$getter:ident, $setter:ident, $cssprop:expr]),* ) => (
        $(
            fn $getter(&self) -> DOMString {
                self.GetPropertyValue(DOMString::from($cssprop))
            }
            fn $setter(&self, value: DOMString) -> ErrorResult {
                self.SetPropertyValue(DOMString::from($cssprop), value)
            }
        )*
    );
);

impl CSSStyleDeclaration {
    pub fn new_inherited(owner: &Element,
                         pseudo: Option<PseudoElement>,
                         modification_access: CSSModificationAccess)
                         -> CSSStyleDeclaration {
        CSSStyleDeclaration {
            reflector_: Reflector::new(),
            owner: JS::from_ref(owner),
            readonly: modification_access == CSSModificationAccess::Readonly,
            pseudo: pseudo,
        }
    }

    pub fn new(global: &Window,
               owner: &Element,
               pseudo: Option<PseudoElement>,
               modification_access: CSSModificationAccess)
               -> Root<CSSStyleDeclaration> {
        reflect_dom_object(box CSSStyleDeclaration::new_inherited(owner,
                                                                  pseudo,
                                                                  modification_access),
                           GlobalRef::Window(global),
                           CSSStyleDeclarationBinding::Wrap)
    }

    fn get_computed_style(&self, property: &Atom) -> Option<DOMString> {
        let node = self.owner.upcast::<Node>();
        if !node.is_in_doc() {
            // TODO: Node should be matched against the style rules of this window.
            // Firefox is currently the only browser to implement this.
            return None;
        }
        let addr = node.to_trusted_node_address();
        window_from_node(&*self.owner).resolved_style_query(addr, self.pseudo.clone(), property)
    }
}

impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
    // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-length
    fn Length(&self) -> u32 {
        let elem = self.owner.upcast::<Element>();
        let len = match *elem.style_attribute().borrow() {
            Some(ref declarations) => declarations.normal.len() + declarations.important.len(),
            None => 0,
        };
        len as u32
    }

    // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-item
    fn Item(&self, index: u32) -> DOMString {
        let index = index as usize;
        let elem = self.owner.upcast::<Element>();
        let style_attribute = elem.style_attribute().borrow();
        let result = style_attribute.as_ref().and_then(|declarations| {
            if index > declarations.normal.len() {
                declarations.important
                            .get(index - declarations.normal.len())
                            .map(|decl| format!("{:?} !important", decl))
            } else {
                declarations.normal
                            .get(index)
                            .map(|decl| format!("{:?}", decl))
            }
        });

        result.map_or(DOMString::new(), DOMString::from)
    }

    // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertyvalue
    fn GetPropertyValue(&self, mut property: DOMString) -> DOMString {
        let owner = &self.owner;

        // Step 1
        property.make_ascii_lowercase();
        let property = Atom::from(property);

        if self.readonly {
            // Readonly style declarations are used for getComputedStyle.
            return self.get_computed_style(&property).unwrap_or(DOMString::new());
        }

        // Step 2
        if let Some(shorthand) = Shorthand::from_name(&property) {
            // Step 2.1
            let mut list = vec![];

            // Step 2.2
            for longhand in shorthand.longhands() {
                // Step 2.2.1
                let declaration = owner.get_inline_style_declaration(&Atom::from(*longhand));

                // Step 2.2.2 & 2.2.3
                match declaration {
                    Some(declaration) => list.push(declaration.clone()),
                    None => return DOMString::new(),
                }
            }

            // Step 2.3
            let list = list.iter().map(|x| &*x).collect::<Vec<_>>();
            return DOMString::from(shorthand.serialize_shorthand(&list));
        }

        // Step 3 & 4
        match owner.get_inline_style_declaration(&property) {
            Some(declaration) => DOMString::from(declaration.value()),
            None => DOMString::new(),
        }
    }

    // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertypriority
    fn GetPropertyPriority(&self, mut property: DOMString) -> DOMString {
        // Step 1
        property.make_ascii_lowercase();
        let property = Atom::from(property);

        // Step 2
        if let Some(shorthand) = Shorthand::from_name(&property) {
            // Step 2.1 & 2.2 & 2.3
            if shorthand.longhands().iter()
                                    .map(|&longhand| self.GetPropertyPriority(DOMString::from(longhand)))
                                    .all(|priority| priority == "important") {

                return DOMString::from("important");
            }
        // Step 3
        } else {
            if self.owner.get_important_inline_style_declaration(&property).is_some() {
                return DOMString::from("important");
            }
        }

        // Step 4
        DOMString::new()
    }

    // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-setproperty
    fn SetProperty(&self,
                   mut property: DOMString,
                   value: DOMString,
                   priority: DOMString)
                   -> ErrorResult {
        // Step 1
        if self.readonly {
            return Err(Error::NoModificationAllowed);
        }

        // Step 2
        property.make_ascii_lowercase();

        // Step 3
        if !is_supported_property(&property) {
            return Ok(());
        }

        // Step 4
        if value.is_empty() {
            return self.RemoveProperty(property).map(|_| ());
        }

        // Step 5
        let priority = match &*priority {
            "" => StylePriority::Normal,
            p if p.eq_ignore_ascii_case("important") => StylePriority::Important,
            _ => return Ok(()),
        };

        // Step 6
        let window = window_from_node(&*self.owner);
        let declarations =
            parse_one_declaration(&property, &value, &window.get_url(), window.css_error_reporter(),
                                  ParserContextExtraData::default());

        // Step 7
        let declarations = if let Ok(declarations) = declarations {
            declarations
        } else {
            return Ok(());
        };

        let element = self.owner.upcast::<Element>();

        // Step 8
        for decl in declarations {
            // Step 9
            element.update_inline_style(decl, priority);
        }

        Ok(())
    }

    // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-setpropertypriority
    fn SetPropertyPriority(&self, property: DOMString, priority: DOMString) -> ErrorResult {
        // Step 1
        if self.readonly {
            return Err(Error::NoModificationAllowed);
        }

        // Step 2 & 3
        if !is_supported_property(&property) {
            return Ok(());
        }

        // Step 4
        let priority = match &*priority {
            "" => StylePriority::Normal,
            p if p.eq_ignore_ascii_case("important") => StylePriority::Important,
            _ => return Ok(()),
        };

        let element = self.owner.upcast::<Element>();

        // Step 5 & 6
        match Shorthand::from_name(&property) {
            Some(shorthand) => {
                element.set_inline_style_property_priority(shorthand.longhands(), priority)
            }
            None => element.set_inline_style_property_priority(&[&*property], priority),
        }

        Ok(())
    }

    // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-setpropertyvalue
    fn SetPropertyValue(&self, property: DOMString, value: DOMString) -> ErrorResult {
        self.SetProperty(property, value, DOMString::new())
    }

    // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-removeproperty
    fn RemoveProperty(&self, mut property: DOMString) -> Fallible<DOMString> {
        // Step 1
        if self.readonly {
            return Err(Error::NoModificationAllowed);
        }

        // Step 2
        property.make_ascii_lowercase();

        // Step 3
        let value = self.GetPropertyValue(property.clone());

        let elem = self.owner.upcast::<Element>();

        match Shorthand::from_name(&property) {
            // Step 4
            Some(shorthand) => {
                for longhand in shorthand.longhands() {
                    elem.remove_inline_style_property(longhand)
                }
            }
            // Step 5
            None => elem.remove_inline_style_property(&property),
        }

        // Step 6
        Ok(value)
    }

    // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-cssfloat
    fn CssFloat(&self) -> DOMString {
        self.GetPropertyValue(DOMString::from("float"))
    }

    // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-cssfloat
    fn SetCssFloat(&self, value: DOMString) -> ErrorResult {
        self.SetPropertyValue(DOMString::from("float"), value)
    }

    // https://dev.w3.org/csswg/cssom/#the-cssstyledeclaration-interface
    fn IndexedGetter(&self, index: u32, found: &mut bool) -> DOMString {
        let rval = self.Item(index);
        *found = index < self.Length();
        rval
    }

    // https://drafts.csswg.org/cssom/#cssstyledeclaration
    css_properties_accessors!(css_properties);
}
<|endoftext|>


<commit_before>#![allow(unreachable_pub)]
use crate::{
    runtime::{context, Handle},
    task::{JoinHandle, LocalSet},
};
use std::{future::Future, io};

/// Factory which is used to configure the properties of a new task.
///
/// **Note**: This is an [unstable API][unstable]. The public API of this type
/// may break in 1.x releases. See [the documentation on unstable
/// features][unstable] for details.
///
/// Methods can be chained in order to configure it.
///
/// Currently, there is only one configuration option:
///
/// - [`name`], which specifies an associated name for
///   the task
///
/// There are three types of task that can be spawned from a Builder:
/// - [`spawn_local`] for executing futures on the current thread
/// - [`spawn`] for executing [`Send`] futures on the runtime
/// - [`spawn_blocking`] for executing blocking code in the
///   blocking thread pool.
///
/// ## Example
///
/// ```no_run
/// use tokio::net::{TcpListener, TcpStream};
///
/// use std::io;
///
/// async fn process(socket: TcpStream) {
///     // ...
/// # drop(socket);
/// }
///
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
///     let listener = TcpListener::bind("127.0.0.1:8080").await?;
///
///     loop {
///         let (socket, _) = listener.accept().await?;
///
///         tokio::task::Builder::new()
///             .name("tcp connection handler")
///             .spawn(async move {
///                 // Process each socket concurrently.
///                 process(socket).await
///             })?;
///     }
/// }
/// ```
/// [unstable]: crate#unstable-features
/// [`name`]: Builder::name
/// [`spawn_local`]: Builder::spawn_local
/// [`spawn`]: Builder::spawn
/// [`spawn_blocking`]: Builder::spawn_blocking
#[derive(Default, Debug)]
#[cfg_attr(docsrs, doc(cfg(all(tokio_unstable, feature = "tracing"))))]
pub struct Builder<'a> {
    name: Option<&'a str>,
}

impl<'a> Builder<'a> {
    /// Creates a new task builder.
    pub fn new() -> Self {
        Self::default()
    }

    /// Assigns a name to the task which will be spawned.
    pub fn name(&self, name: &'a str) -> Self {
        Self { name: Some(name) }
    }

    /// Spawns a task with this builder's settings on the current runtime.
    ///
    /// # Panics
    ///
    /// This method panics if called outside of a Tokio runtime.
    ///
    /// See [`task::spawn`](crate::task::spawn) for
    /// more details.
    #[track_caller]
    pub fn spawn<Fut>(self, future: Fut) -> io::Result<JoinHandle<Fut::Output>>
    where
        Fut: Future + Send + 'static,
        Fut::Output: Send + 'static,
    {
        Ok(super::spawn::spawn_inner(future, self.name))
    }

    /// Spawn a task with this builder's settings on the provided [runtime
    /// handle].
    ///
    /// See [`Handle::spawn`] for more details.
    ///
    /// [runtime handle]: crate::runtime::Handle
    /// [`Handle::spawn`]: crate::runtime::Handle::spawn
    #[track_caller]
    pub fn spawn_on<Fut>(
        &mut self,
        future: Fut,
        handle: &Handle,
    ) -> io::Result<JoinHandle<Fut::Output>>
    where
        Fut: Future + Send + 'static,
        Fut::Output: Send + 'static,
    {
        Ok(handle.spawn_named(future, self.name))
    }

    /// Spawns `!Send` a task on the current [`LocalSet`] with this builder's
    /// settings.
    ///
    /// The spawned future will be run on the same thread that called `spawn_local`.
    /// This may only be called from the context of a [local task set][`LocalSet`].
    ///
    /// # Panics
    ///
    /// This function panics if called outside of a [local task set][`LocalSet`].
    ///
    /// See [`task::spawn_local`] for more details.
    ///
    /// [`task::spawn_local`]: crate::task::spawn_local
    /// [`LocalSet`]: crate::task::LocalSet
    #[track_caller]
    pub fn spawn_local<Fut>(self, future: Fut) -> io::Result<JoinHandle<Fut::Output>>
    where
        Fut: Future + 'static,
        Fut::Output: 'static,
    {
        Ok(super::local::spawn_local_inner(future, self.name))
    }

    /// Spawns `!Send` a task on the provided [`LocalSet`] with this builder's
    /// settings.
    ///
    /// See [`LocalSet::spawn_local`] for more details.
    ///
    /// [`LocalSet::spawn_local`]: crate::task::LocalSet::spawn_local
    /// [`LocalSet`]: crate::task::LocalSet
    #[track_caller]
    pub fn spawn_local_on<Fut>(
        self,
        future: Fut,
        local_set: &LocalSet,
    ) -> io::Result<JoinHandle<Fut::Output>>
    where
        Fut: Future + 'static,
        Fut::Output: 'static,
    {
        Ok(local_set.spawn_named(future, self.name))
    }

    /// Spawns blocking code on the blocking threadpool.
    ///
    /// # Panics
    ///
    /// This method panics if called outside of a Tokio runtime.
    ///
    /// See [`task::spawn_blocking`](crate::task::spawn_blocking)
    /// for more details.
    #[track_caller]
    pub fn spawn_blocking<Function, Output>(
        self,
        function: Function,
    ) -> io::Result<JoinHandle<Output>>
    where
        Function: FnOnce() -> Output + Send + 'static,
        Output: Send + 'static,
    {
        self.spawn_blocking_on(function, &context::current())
    }

    /// Spawns blocking code on the provided [runtime handle]'s blocking threadpool.
    ///
    /// See [`Handle::spawn_blocking`] for more details.
    ///
    /// [runtime handle]: crate::runtime::Handle
    /// [`Handle::spawn_blocking`]: crate::runtime::Handle::spawn_blocking
    #[track_caller]
    pub fn spawn_blocking_on<Function, Output>(
        self,
        function: Function,
        handle: &Handle,
    ) -> io::Result<JoinHandle<Output>>
    where
        Function: FnOnce() -> Output + Send + 'static,
        Output: Send + 'static,
    {
        use crate::runtime::Mandatory;
        let (join_handle, spawn_result) = handle.as_inner().spawn_blocking_inner(
            function,
            Mandatory::NonMandatory,
            self.name,
            handle,
        );

        spawn_result?;
        Ok(join_handle)
    }
}
<commit_msg>task: fix incorrect signature in `Builder::spawn_on` (#4953)<commit_after>#![allow(unreachable_pub)]
use crate::{
    runtime::{context, Handle},
    task::{JoinHandle, LocalSet},
};
use std::{future::Future, io};

/// Factory which is used to configure the properties of a new task.
///
/// **Note**: This is an [unstable API][unstable]. The public API of this type
/// may break in 1.x releases. See [the documentation on unstable
/// features][unstable] for details.
///
/// Methods can be chained in order to configure it.
///
/// Currently, there is only one configuration option:
///
/// - [`name`], which specifies an associated name for
///   the task
///
/// There are three types of task that can be spawned from a Builder:
/// - [`spawn_local`] for executing futures on the current thread
/// - [`spawn`] for executing [`Send`] futures on the runtime
/// - [`spawn_blocking`] for executing blocking code in the
///   blocking thread pool.
///
/// ## Example
///
/// ```no_run
/// use tokio::net::{TcpListener, TcpStream};
///
/// use std::io;
///
/// async fn process(socket: TcpStream) {
///     // ...
/// # drop(socket);
/// }
///
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
///     let listener = TcpListener::bind("127.0.0.1:8080").await?;
///
///     loop {
///         let (socket, _) = listener.accept().await?;
///
///         tokio::task::Builder::new()
///             .name("tcp connection handler")
///             .spawn(async move {
///                 // Process each socket concurrently.
///                 process(socket).await
///             })?;
///     }
/// }
/// ```
/// [unstable]: crate#unstable-features
/// [`name`]: Builder::name
/// [`spawn_local`]: Builder::spawn_local
/// [`spawn`]: Builder::spawn
/// [`spawn_blocking`]: Builder::spawn_blocking
#[derive(Default, Debug)]
#[cfg_attr(docsrs, doc(cfg(all(tokio_unstable, feature = "tracing"))))]
pub struct Builder<'a> {
    name: Option<&'a str>,
}

impl<'a> Builder<'a> {
    /// Creates a new task builder.
    pub fn new() -> Self {
        Self::default()
    }

    /// Assigns a name to the task which will be spawned.
    pub fn name(&self, name: &'a str) -> Self {
        Self { name: Some(name) }
    }

    /// Spawns a task with this builder's settings on the current runtime.
    ///
    /// # Panics
    ///
    /// This method panics if called outside of a Tokio runtime.
    ///
    /// See [`task::spawn`](crate::task::spawn) for
    /// more details.
    #[track_caller]
    pub fn spawn<Fut>(self, future: Fut) -> io::Result<JoinHandle<Fut::Output>>
    where
        Fut: Future + Send + 'static,
        Fut::Output: Send + 'static,
    {
        Ok(super::spawn::spawn_inner(future, self.name))
    }

    /// Spawn a task with this builder's settings on the provided [runtime
    /// handle].
    ///
    /// See [`Handle::spawn`] for more details.
    ///
    /// [runtime handle]: crate::runtime::Handle
    /// [`Handle::spawn`]: crate::runtime::Handle::spawn
    #[track_caller]
    pub fn spawn_on<Fut>(self, future: Fut, handle: &Handle) -> io::Result<JoinHandle<Fut::Output>>
    where
        Fut: Future + Send + 'static,
        Fut::Output: Send + 'static,
    {
        Ok(handle.spawn_named(future, self.name))
    }

    /// Spawns `!Send` a task on the current [`LocalSet`] with this builder's
    /// settings.
    ///
    /// The spawned future will be run on the same thread that called `spawn_local`.
    /// This may only be called from the context of a [local task set][`LocalSet`].
    ///
    /// # Panics
    ///
    /// This function panics if called outside of a [local task set][`LocalSet`].
    ///
    /// See [`task::spawn_local`] for more details.
    ///
    /// [`task::spawn_local`]: crate::task::spawn_local
    /// [`LocalSet`]: crate::task::LocalSet
    #[track_caller]
    pub fn spawn_local<Fut>(self, future: Fut) -> io::Result<JoinHandle<Fut::Output>>
    where
        Fut: Future + 'static,
        Fut::Output: 'static,
    {
        Ok(super::local::spawn_local_inner(future, self.name))
    }

    /// Spawns `!Send` a task on the provided [`LocalSet`] with this builder's
    /// settings.
    ///
    /// See [`LocalSet::spawn_local`] for more details.
    ///
    /// [`LocalSet::spawn_local`]: crate::task::LocalSet::spawn_local
    /// [`LocalSet`]: crate::task::LocalSet
    #[track_caller]
    pub fn spawn_local_on<Fut>(
        self,
        future: Fut,
        local_set: &LocalSet,
    ) -> io::Result<JoinHandle<Fut::Output>>
    where
        Fut: Future + 'static,
        Fut::Output: 'static,
    {
        Ok(local_set.spawn_named(future, self.name))
    }

    /// Spawns blocking code on the blocking threadpool.
    ///
    /// # Panics
    ///
    /// This method panics if called outside of a Tokio runtime.
    ///
    /// See [`task::spawn_blocking`](crate::task::spawn_blocking)
    /// for more details.
    #[track_caller]
    pub fn spawn_blocking<Function, Output>(
        self,
        function: Function,
    ) -> io::Result<JoinHandle<Output>>
    where
        Function: FnOnce() -> Output + Send + 'static,
        Output: Send + 'static,
    {
        self.spawn_blocking_on(function, &context::current())
    }

    /// Spawns blocking code on the provided [runtime handle]'s blocking threadpool.
    ///
    /// See [`Handle::spawn_blocking`] for more details.
    ///
    /// [runtime handle]: crate::runtime::Handle
    /// [`Handle::spawn_blocking`]: crate::runtime::Handle::spawn_blocking
    #[track_caller]
    pub fn spawn_blocking_on<Function, Output>(
        self,
        function: Function,
        handle: &Handle,
    ) -> io::Result<JoinHandle<Output>>
    where
        Function: FnOnce() -> Output + Send + 'static,
        Output: Send + 'static,
    {
        use crate::runtime::Mandatory;
        let (join_handle, spawn_result) = handle.as_inner().spawn_blocking_inner(
            function,
            Mandatory::NonMandatory,
            self.name,
            handle,
        );

        spawn_result?;
        Ok(join_handle)
    }
}
<|endoftext|>


<commit_before>use ValidatorResult;
#[cfg(feature = "inclusive_range")]
use std::ops::RangeInclusive;

/// Enforce that a `String` is maximum `max` characters long.
pub fn max(max: usize) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        if s.len() <= max {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Must not contain more characters than %1.".to_string(),
                args: vec![max.to_string()],
                human_readable: format!("Must contain less than {} characters", max)
            })
        }
    })
}

// Enforce that a `String` is minimum `min` characters long.
pub fn min(min: usize) -> Box<Fn(&String) -> ValidatorResult> {
    Box::new(move |s: &String| {
        if s.len() >= min {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Must contain more than %1 characters".to_string(),
                args: vec![min.to_string()],
                human_readable: format!("Must contain more than {} characters", min)
            })
        }
    })
}

#[cfg(not(feature = "inclusive_range"))]
/// Enforce that a string is minimum `mi` and maximum `ma` characters long.
pub fn length(mi: usize, ma: usize) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        match (min(mi)(s), max(ma)(s)) {
            (Err(_), Err(_)) => {
                Err(::Invalid {
                    msg: "Must not be less characters than %1 and not more than %2.".to_string(),
                    args: vec![mi.to_string(), ma.to_string()],
                    human_readable: format!("Must contain between {} and {} characters", mi, ma - 1)
                })
            }
            (Err(e), _) => Err(e),
            (_, Err(e)) => Err(e),
            (_, _) => Ok(()),
        }
    })
}

#[cfg(not(feature = "inclusive_range"))]
/// Enforce that a string is minimum `mi` and maximum `ma` characters long if it is present. Always ok if not present.
pub fn length_if_present(mi: usize, ma: usize) -> Box<Fn(&Option<String>) -> ::ValidatorResult> {
    Box::new(move |s: &Option<String>| {
        if s.is_none() {
            return Ok(());
        }
        let s = s.as_ref().unwrap();
        match (min(mi)(s), max(ma)(s)) {
            (Err(_), Err(_)) => {
                Err(::Invalid {
                    msg: "Must not be less characters than %1 and not more than %2.".to_string(),
                    args: vec![mi.to_string(), ma.to_string()],
                    human_readable: format!("Must contain between {} and {} characters", mi, ma - 1)
                })
            }
            (Err(e), _) => Err(e),
            (_, Err(e)) => Err(e),
            (_, _) => Ok(()),
        }
    })
}

#[cfg(feature = "inclusive_range")]
/// Enforce that a string is minimum `mi` and maximum `ma` characters long.
pub fn length(range: RangeInclusive<usize>) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        match range {
            RangeInclusive::NonEmpty { ref start, ref end } => {
                match (min(*start)(s), max(*end)(s)) {
                    (Err(_), Err(_)) => {
                        Err(::Invalid {
                            msg: "Must not be less characters than %1 and not more than %2."
                                .to_string(),
                            args: vec![start.to_string(), end.to_string()],
                            human_readable: format!("Must contain between {} and {} characters", mi, ma)
                        })
                    }
                    (Err(e), _) => Err(e),
                    (_, Err(e)) => Err(e),
                    (_, _) => Ok(()),
                }
            }
            _ => panic!("range must be a RangeInclusive::NonEmpty"),
        }
    })
}

#[cfg(feature = "inclusive_range")]
/// Enforce that a string is minimum `mi` and maximum `ma` characters long if it is present. Always ok if not present.
pub fn length_if_present(range: RangeInclusive<usize>) -> Box<Fn(&Option<String>) -> ::ValidatorResult> {
    Box::new(move |s: &Option<String>| {
        if s.is_none() {
            return Ok(());
        }
        let s = s.as_ref().unwrap();
        match range {
            RangeInclusive::NonEmpty { ref start, ref end } => {
                match (min(*start)(s), max(*end)(s)) {
                    (Err(_), Err(_)) => {
                        Err(::Invalid {
                            msg: "Must not be less characters than %1 and not more than %2."
                                .to_string(),
                            args: vec![start.to_string(), end.to_string()],
                            human_readable: format!("Must contain between {} and {} characters", start, end)
                        })
                    }
                    (Err(e), _) => Err(e),
                    (_, Err(e)) => Err(e),
                    (_, _) => Ok(()),
                }
            }
            _ => panic!("range must be a RangeInclusive::NonEmpty"),
        }
    })
}
<commit_msg>Tests for max, min, length & length_is_present (#3 #1)<commit_after>use ValidatorResult;

#[cfg(feature = "inclusive_range")]
use std::ops::RangeInclusive;

/// Enforce that a `String` is maximum `max` characters long.
pub fn max(max: usize) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        if s.len() <= max {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Must not contain more characters than %1.".to_string(),
                args: vec![max.to_string()],
                human_readable: format!("Must contain less than {} characters", max)
            })
        }
    })
}

// Enforce that a `String` is minimum `min` characters long.
pub fn min(min: usize) -> Box<Fn(&String) -> ValidatorResult> {
    Box::new(move |s: &String| {
        if s.len() >= min {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Must contain more than %1 characters".to_string(),
                args: vec![min.to_string()],
                human_readable: format!("Must contain more than {} characters", min)
            })
        }
    })
}

#[cfg(not(feature = "inclusive_range"))]
/// Enforce that a string is minimum `mi` and maximum `ma` characters long.
pub fn length(mi: usize, ma: usize) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        match (min(mi)(s), max(ma)(s)) {
            (Err(_), Err(_)) => {
                Err(::Invalid {
                    msg: "Must not be less characters than %1 and not more than %2.".to_string(),
                    args: vec![mi.to_string(), ma.to_string()],
                    human_readable: format!("Must contain between {} and {} characters", mi, ma - 1)
                })
            }
            (Err(e), _) => Err(e),
            (_, Err(e)) => Err(e),
            (_, _) => Ok(()),
        }
    })
}

#[cfg(not(feature = "inclusive_range"))]
/// Enforce that a string is minimum `mi` and maximum `ma` characters long if it is present. Always ok if not present.
pub fn length_if_present(mi: usize, ma: usize) -> Box<Fn(&Option<String>) -> ::ValidatorResult> {
    Box::new(move |s: &Option<String>| {
        if s.is_none() {
            return Ok(());
        }
        let s = s.as_ref().unwrap();
        match (min(mi)(s), max(ma)(s)) {
            (Err(_), Err(_)) => {
                Err(::Invalid {
                    msg: "Must not be less characters than %1 and not more than %2.".to_string(),
                    args: vec![mi.to_string(), ma.to_string()],
                    human_readable: format!("Must contain between {} and {} characters", mi, ma - 1)
                })
            }
            (Err(e), _) => Err(e),
            (_, Err(e)) => Err(e),
            (_, _) => Ok(()),
        }
    })
}

#[cfg(feature = "inclusive_range")]
/// Enforce that a string is minimum `mi` and maximum `ma` characters long.
pub fn length(range: RangeInclusive<usize>) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        match range {
            RangeInclusive::NonEmpty { ref start, ref end } => {
                match (min(*start)(s), max(*end)(s)) {
                    (Err(_), Err(_)) => {
                        Err(::Invalid {
                            msg: "Must not be less characters than %1 and not more than %2."
                                .to_string(),
                            args: vec![start.to_string(), end.to_string()],
                            human_readable: format!("Must contain between {} and {} characters", mi, ma)
                        })
                    }
                    (Err(e), _) => Err(e),
                    (_, Err(e)) => Err(e),
                    (_, _) => Ok(()),
                }
            }
            _ => panic!("range must be a RangeInclusive::NonEmpty"),
        }
    })
}

#[cfg(feature = "inclusive_range")]
/// Enforce that a string is minimum `mi` and maximum `ma` characters long if it is present. Always ok if not present.
pub fn length_if_present(range: RangeInclusive<usize>) -> Box<Fn(&Option<String>) -> ::ValidatorResult> {
    Box::new(move |s: &Option<String>| {
        if s.is_none() {
            return Ok(());
        }
        let s = s.as_ref().unwrap();
        match range {
            RangeInclusive::NonEmpty { ref start, ref end } => {
                match (min(*start)(s), max(*end)(s)) {
                    (Err(_), Err(_)) => {
                        Err(::Invalid {
                            msg: "Must not be less characters than %1 and not more than %2."
                                .to_string(),
                            args: vec![start.to_string(), end.to_string()],
                            human_readable: format!("Must contain between {} and {} characters", start, end)
                        })
                    }
                    (Err(e), _) => Err(e),
                    (_, Err(e)) => Err(e),
                    (_, _) => Ok(()),
                }
            }
            _ => panic!("range must be a RangeInclusive::NonEmpty"),
        }
    })
}

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

    // max
    #[test]
    pub fn max_valid() {
        assert!(max(3)(&"123".to_owned()).is_ok());
        assert!(max(3)(&"12".to_owned()).is_ok());
        assert!(max(3)(&"1".to_owned()).is_ok());
    }

    #[test]
    pub fn max_invalid() {
        assert!(max(3)(&"1234".to_owned()).is_err());
        assert!(max(3)(&"12345".to_owned()).is_err());
        assert!(max(3)(&"123456".to_owned()).is_err());
    }

    // min
    #[test]
    pub fn min_valid() {
        assert!(min(3)(&"123".to_owned()).is_ok());
        assert!(min(3)(&"1234".to_owned()).is_ok());
        assert!(min(3)(&"12345".to_owned()).is_ok());
    }

    #[test]
    pub fn min_invalid() {
        assert!(min(3)(&"12".to_owned()).is_err());
        assert!(min(3)(&"1".to_owned()).is_err());
        assert!(min(3)(&"".to_owned()).is_err());
    }

    // length & length_if_present

    #[cfg(not(feature = "inclusive_range"))]
    mod length {
        use super::super::{length, length_if_present};

        // length
        #[test]
        pub fn length_valid() {
            assert!(length(1, 3)(&"123".to_owned()).is_ok());
            assert!(length(1, 3)(&"12".to_owned()).is_ok());
            assert!(length(1, 3)(&"1".to_owned()).is_ok());
        }

        #[test]
        pub fn length_invalid() {
            assert!(length(1, 3)(&"1234".to_owned()).is_err());
            assert!(length(1, 3)(&"".to_owned()).is_err());
        }

        // length_if_present
        #[test]
        pub fn length_if_present_valid() {
            assert!(length_if_present(1, 3)(&Some("123".to_owned())).is_ok());
            assert!(length_if_present(1, 3)(&Some("12".to_owned())).is_ok());
            assert!(length_if_present(1, 3)(&None).is_ok());
        }

        #[test]
        pub fn length_if_present_invalid() {
            assert!(length_if_present(1, 3)(&Some("1234".to_owned())).is_err());
            assert!(length_if_present(1, 3)(&Some("".to_owned())).is_err());
        }
    }

    #[cfg(feature = "inclusive_range")]
    mod length {
        use super::super::{length, length_if_present};

        // length
        #[test]
        pub fn length_valid() {
            assert!(length(1..=3)(&"123".to_owned()).is_ok());
            assert!(length(1..=3)(&"12".to_owned()).is_ok());
            assert!(length(1..=3)(&"1".to_owned()).is_ok());
        }

        #[test]
        pub fn length_invalid() {
            assert!(length(1..=3)(&"1234".to_owned()).is_err());
            assert!(length(1..=3)(&"".to_owned()).is_err());
        }

        // length_if_present
        #[test]
        pub fn length_if_present_valid() {
            assert!(length_if_present(1..=3)(&Some("123".to_owned())).is_ok());
            assert!(length_if_present(1..=3)(&Some("12".to_owned())).is_ok());
            assert!(length_if_present(1..=3)(&None).is_ok());
        }

        #[test]
        pub fn length_if_present_invalid() {
            assert!(length_if_present(1..=3)(&Some("1234".to_owned())).is_err());
            assert!(length_if_present(1..=3)(&Some("".to_owned())).is_err());
        }
    }
}<|endoftext|>


<commit_before>struct Stack {
    content: Vec<i32>,
}

impl Stack {
    fn push(&mut self, d: i32) {
        self.content.push(d);
    }

    fn multiply(&mut self) {
        println!("Multiply");
    }

    fn add(&mut self) {
        println!("Add");
    }

    fn subtract(&mut self) {
        println!("Subtract");
    }

    fn divide(&mut self) {
        println!("Divide");
    }
}

fn evaluate(program: Vec<char>) {
    let mut stack = Stack { content: vec![] };

    for c in program {
        match c {
            '*' => stack.multiply(),
            '+' => stack.add(),
            '-' => stack.subtract(),
            '/' => stack.divide(),
            '1' => stack.push(1),
            '2' => stack.push(2),
            '3' => stack.push(3),
            '4' => stack.push(4),
            '5' => stack.push(5),
            '6' => stack.push(6),
            '7' => stack.push(7),
            '8' => stack.push(8),
            '9' => stack.push(9),
            _   => println!("DIE..."),
        }
    }

    for c in stack.content {
        println!("{}", c);
    }
}

fn main() {
    let program: Vec<char> = "3 4 * 2 * 1 /".chars().filter(|&c| c != ' ').collect();

    evaluate(program);
}
<commit_msg>Evaluting. Poorly<commit_after>struct Stack {
    content: Vec<i32>,
}

impl Stack {
    fn push(&mut self, d: i32) {
        self.content.push(d);
    }

    fn multiply(&mut self) {
        let r = self.content.pop().expect("Stack empty!");
        let l = self.content.pop().expect("Stack empty!");

        self.content.push(l * r);
    }

    fn add(&mut self) {
        let r = self.content.pop().expect("Stack empty!");
        let l = self.content.pop().expect("Stack empty!");

        self.content.push(l + r);
    }

    fn subtract(&mut self) {
        let r = self.content.pop().expect("Stack empty!");
        let l = self.content.pop().expect("Stack empty!");

        self.content.push(l - r);
    }

    fn divide(&mut self) {
        let r = self.content.pop().expect("Stack empty!");
        let l = self.content.pop().expect("Stack empty!");

        self.content.push(l / r);
    }
}

fn evaluate(program: Vec<char>) {
    let mut stack = Stack { content: vec![] };

    for c in program {
        match c {
            '*' => stack.multiply(),
            '+' => stack.add(),
            '-' => stack.subtract(),
            '/' => stack.divide(),
            '1' => stack.push(1),
            '2' => stack.push(2),
            '3' => stack.push(3),
            '4' => stack.push(4),
            '5' => stack.push(5),
            '6' => stack.push(6),
            '7' => stack.push(7),
            '8' => stack.push(8),
            '9' => stack.push(9),
            _   => println!("DIE..."),
        }
    }

    for c in stack.content {
        println!("{}", c);
    }
}

fn main() {
    let program: Vec<char> = "3 4 * 2 * 1 /".chars().filter(|&c| c != ' ').collect();

    evaluate(program);
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use extra::json;
use std::hashmap::HashMap;
use serialize::Decodable;
use glfw;
use gl;
use gl::types::{
  GLfloat,
  GLint,
  GLuint,
};
use cgmath::vector::{
  Vec3,
  Vec2,
};
use glh = gl_helpers;
use camera::Camera;
use map::TileIterator;
use geom::Geom;
use tile_picker::TilePicker;
use obj;
use mesh::Mesh;
use misc::read_file;

fn build_hex_mesh(&geom: &Geom) -> ~[Vec3<GLfloat>] {
  let mut vertex_data = ~[];
  for tile_pos in TileIterator::new() {
    let pos3d = geom.map_pos_to_world_pos(tile_pos);
    for num in range(0, 6) {
      let vertex = geom.index_to_hex_vertex(num);
      let next_vertex = geom.index_to_hex_vertex(num + 1);
      vertex_data.push(pos3d + vertex);
      vertex_data.push(pos3d + next_vertex);
      vertex_data.push(pos3d + Vec3::zero());
    }
  }
  vertex_data
}

fn build_hex_tex_coord() -> ~[Vec2<GLfloat>] {
  let mut vertex_data = ~[];
  for _ in TileIterator::new() {
    for _ in range(0, 6) {
      vertex_data.push(Vec2{x: 0.0, y: 0.0});
      vertex_data.push(Vec2{x: 1.0, y: 0.0});
      vertex_data.push(Vec2{x: 0.5, y: 0.5});
    }
  }
  vertex_data
}

pub struct SceneNode {
  pos: Vec3<f32>,
}

#[deriving(Decodable)]
struct Size2<T> {
  x: T,
  y: T,
}

fn read_win_size(config_path: &str) -> Vec2<int> {
  let path = Path::new(config_path);
  let json = json::from_str(read_file(&path)).unwrap();
  let mut decoder = json::Decoder::new(json);
  let size: Size2<int> = Decodable::decode(&mut decoder);
  Vec2{x: size.x, y: size.y}
}

fn init_win(win_size: Vec2<int>) -> glfw::Window {
  glfw::set_error_callback(~glfw::LogErrorHandler);
  let init_status = glfw::init();
  if !init_status.is_ok() {
    fail!("Failed to initialize GLFW");
  }
  let win = glfw::Window::create(
    win_size.x as u32,
    win_size.y as u32,
    "Marauder",
    glfw::Windowed,
  ).unwrap();
  win.make_context_current();
  win.set_all_polling(true);
  win
}

pub struct Visualizer {
  program: GLuint,
  map_mesh: Mesh,
  unit_mesh: Mesh,
  mat_id: GLint,
  win: Option<glfw::Window>,
  mouse_pos: Vec2<f32>,
  camera: Camera,
  picker: TilePicker,
  selected_tile_pos: Option<Vec2<i32>>,
  geom: Geom,
  scene_nodes: HashMap<i32, SceneNode>,
}

impl Visualizer {
  pub fn new() -> ~Visualizer {
    let win_size = read_win_size("config.json");
    let win = init_win(win_size);
    let geom = Geom::new();
    let mut vis = ~Visualizer {
      program: 0,
      map_mesh: Mesh::new(),
      unit_mesh: Mesh::new(),
      mat_id: 0,
      win: Some(win),
      mouse_pos: Vec2::zero(),
      camera: Camera::new(),
      picker: TilePicker::new(),
      selected_tile_pos: None,
      geom: geom,
      scene_nodes: HashMap::new(),
    };
    vis.init_opengl();
    vis.picker.init(&geom);
    vis.init_models();
    vis.init_textures();
    vis.init_units();
    vis
  }

  fn init_textures(&mut self) {
  }

  fn win<'a>(&'a self) -> &'a glfw::Window {
    self.win.get_ref()
  }

  fn init_models(&mut self) {
    self.program = glh::compile_program(
      read_file(&Path::new("normal.vs.glsl")),
      read_file(&Path::new("normal.fs.glsl")),
    );
    gl::UseProgram(self.program);
    self.mat_id = glh::get_uniform(self.program, "mvp_mat");
    let position_attr = glh::get_attr(self.program, "in_vertex_coordinates");
    gl::EnableVertexAttribArray(position_attr);
    glh::vertex_attrib_pointer(position_attr, 3);
    let vt_attr = glh::get_attr(self.program, "in_texture_coordinates");
    gl::EnableVertexAttribArray(vt_attr);
    glh::vertex_attrib_pointer(vt_attr, 3);
    let map_vertex_data = build_hex_mesh(&self.geom);
    self.map_mesh.set_vertex_coords(map_vertex_data);
    self.map_mesh.set_texture_coords(build_hex_tex_coord());
    self.map_mesh.set_texture(glh::load_texture(~"data/floor.png"));
    let unit_obj = obj::Model::new("data/tank.obj");
    self.unit_mesh.set_vertex_coords(unit_obj.build());
    self.unit_mesh.set_texture_coords(unit_obj.build_tex_coord());
    self.unit_mesh.set_texture(glh::load_texture(~"data/tank.png"));
  }

  fn add_unit(&mut self, id: i32, pos: Vec2<i32>) {
    let world_pos = self.geom.map_pos_to_world_pos(pos);
    self.scene_nodes.insert(id, SceneNode{pos: world_pos});
  }

  fn init_units(&mut self) {
    self.add_unit(0, Vec2{x: 0, y: 0});
    self.add_unit(1, Vec2{x: 0, y: 1});
    self.add_unit(2, Vec2{x: 1, y: 0});
    self.add_unit(2, Vec2{x: 1, y: 1});
  }

  fn init_opengl(&mut self) {
    gl::load_with(glfw::get_proc_address);
    gl::Enable(gl::DEPTH_TEST);
  }

  fn cleanup_opengl(&self) {
    gl::DeleteProgram(self.program);
  }

  fn draw_units(&self) {
    gl::UseProgram(self.program);
    for (_, unit) in self.scene_nodes.iter() {
      let m = glh::tr(self.camera.mat(), unit.pos);
      glh::uniform_mat4f(self.mat_id, &m);
      self.unit_mesh.draw(self.program);
    }
  }

  fn draw_map(&self) {
    glh::uniform_mat4f(self.mat_id, &self.camera.mat());
    self.map_mesh.draw(self.program);
  }

  fn draw(&self) {
    gl::ClearColor(0.3, 0.3, 0.3, 1.0);
    gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
    gl::UseProgram(self.program);
    self.draw_units();
    self.draw_map();
    self.win().swap_buffers();
  }

  pub fn is_running(&self) -> bool {
    return !self.win().should_close()
  }

  fn handle_key_event(&mut self, key: glfw::Key) {
    match key {
      glfw::KeyEscape | glfw::KeyQ => {
        self.win().set_should_close(true);
      },
      glfw::KeySpace => println!("space"),
      glfw::KeyUp => self.camera.move(270.0),
      glfw::KeyDown => self.camera.move(90.0),
      glfw::KeyRight => self.camera.move(0.0),
      glfw::KeyLeft => self.camera.move(180.0),
      glfw::KeyMinus => self.camera.zoom += 1.0,
      glfw::KeyEqual => self.camera.zoom -= 1.0,
      _ => {},
    }
  }

  fn handle_cursor_pos_event(&mut self, pos: Vec2<f32>) {
    let button = self.win().get_mouse_button(glfw::MouseButtonRight);
    if button == glfw::Press {
      self.camera.z_angle += (self.mouse_pos.x - pos.x) / 2.0;
      self.camera.x_angle += (self.mouse_pos.y - pos.y) / 2.0;
    }
    self.mouse_pos = pos;
  }

  fn handle_mouse_button_event(&mut self) {
    if !self.selected_tile_pos.is_none() {
      let map_pos = self.selected_tile_pos.unwrap();
      let pos = self.geom.map_pos_to_world_pos(map_pos);
      let unit_id = 0;
      self.scene_nodes.get_mut(&unit_id).pos = pos;
    }
  }

  fn get_events(&mut self) -> ~[glfw::WindowEvent] {
    glfw::poll_events();
    let mut events = ~[];
    for (_, event) in self.win().flush_events() {
      events.push(event);
    }
    events
  }

  fn handle_event(&mut self, event: glfw::WindowEvent) {
    match event {
      glfw::KeyEvent(key, _, glfw::Press, _) => {
        self.handle_key_event(key);
      },
      glfw::CursorPosEvent(x, y) => {
        let p = Vec2{x: x as f32, y: y as f32};
        self.handle_cursor_pos_event(p);
      },
      glfw::MouseButtonEvent(glfw::MouseButtonLeft, glfw::Press, _) => {
        self.handle_mouse_button_event();
      },
      glfw::SizeEvent(w, h) => {
        gl::Viewport(0, 0, w, h);
      },
      _ => {},
    }
  }

  fn handle_events(&mut self) {
    for event in self.get_events().iter() {
      self.handle_event(*event);
    }
  }

  fn pick_tile(&mut self) {
    let mouse_pos = Vec2 {
      x: self.mouse_pos.x as i32,
      y: self.mouse_pos.y as i32,
    };
    let win_size = self.win().get_size();
    self.selected_tile_pos = self.picker.pick_tile(
      win_size, &self.camera, mouse_pos);
  }

  pub fn tick(&mut self) {
    self.handle_events();
    self.pick_tile();
    self.draw();
  }
}

impl Drop for Visualizer {
  fn drop(&mut self) {
    self.cleanup_opengl();
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<commit_msg>Visualizer: Removed useless init_textures(&mut self)<commit_after>// See LICENSE file for copyright and license details.

use extra::json;
use std::hashmap::HashMap;
use serialize::Decodable;
use glfw;
use gl;
use gl::types::{
  GLfloat,
  GLint,
  GLuint,
};
use cgmath::vector::{
  Vec3,
  Vec2,
};
use glh = gl_helpers;
use camera::Camera;
use map::TileIterator;
use geom::Geom;
use tile_picker::TilePicker;
use obj;
use mesh::Mesh;
use misc::read_file;

fn build_hex_mesh(&geom: &Geom) -> ~[Vec3<GLfloat>] {
  let mut vertex_data = ~[];
  for tile_pos in TileIterator::new() {
    let pos3d = geom.map_pos_to_world_pos(tile_pos);
    for num in range(0, 6) {
      let vertex = geom.index_to_hex_vertex(num);
      let next_vertex = geom.index_to_hex_vertex(num + 1);
      vertex_data.push(pos3d + vertex);
      vertex_data.push(pos3d + next_vertex);
      vertex_data.push(pos3d + Vec3::zero());
    }
  }
  vertex_data
}

fn build_hex_tex_coord() -> ~[Vec2<GLfloat>] {
  let mut vertex_data = ~[];
  for _ in TileIterator::new() {
    for _ in range(0, 6) {
      vertex_data.push(Vec2{x: 0.0, y: 0.0});
      vertex_data.push(Vec2{x: 1.0, y: 0.0});
      vertex_data.push(Vec2{x: 0.5, y: 0.5});
    }
  }
  vertex_data
}

pub struct SceneNode {
  pos: Vec3<f32>,
}

#[deriving(Decodable)]
struct Size2<T> {
  x: T,
  y: T,
}

fn read_win_size(config_path: &str) -> Vec2<int> {
  let path = Path::new(config_path);
  let json = json::from_str(read_file(&path)).unwrap();
  let mut decoder = json::Decoder::new(json);
  let size: Size2<int> = Decodable::decode(&mut decoder);
  Vec2{x: size.x, y: size.y}
}

fn init_win(win_size: Vec2<int>) -> glfw::Window {
  glfw::set_error_callback(~glfw::LogErrorHandler);
  let init_status = glfw::init();
  if !init_status.is_ok() {
    fail!("Failed to initialize GLFW");
  }
  let win = glfw::Window::create(
    win_size.x as u32,
    win_size.y as u32,
    "Marauder",
    glfw::Windowed,
  ).unwrap();
  win.make_context_current();
  win.set_all_polling(true);
  win
}

pub struct Visualizer {
  program: GLuint,
  map_mesh: Mesh,
  unit_mesh: Mesh,
  mat_id: GLint,
  win: Option<glfw::Window>,
  mouse_pos: Vec2<f32>,
  camera: Camera,
  picker: TilePicker,
  selected_tile_pos: Option<Vec2<i32>>,
  geom: Geom,
  scene_nodes: HashMap<i32, SceneNode>,
}

impl Visualizer {
  pub fn new() -> ~Visualizer {
    let win_size = read_win_size("config.json");
    let win = init_win(win_size);
    let geom = Geom::new();
    let mut vis = ~Visualizer {
      program: 0,
      map_mesh: Mesh::new(),
      unit_mesh: Mesh::new(),
      mat_id: 0,
      win: Some(win),
      mouse_pos: Vec2::zero(),
      camera: Camera::new(),
      picker: TilePicker::new(),
      selected_tile_pos: None,
      geom: geom,
      scene_nodes: HashMap::new(),
    };
    vis.init_opengl();
    vis.picker.init(&geom);
    vis.init_models();
    vis.init_units();
    vis
  }

  fn win<'a>(&'a self) -> &'a glfw::Window {
    self.win.get_ref()
  }

  fn init_models(&mut self) {
    self.program = glh::compile_program(
      read_file(&Path::new("normal.vs.glsl")),
      read_file(&Path::new("normal.fs.glsl")),
    );
    gl::UseProgram(self.program);
    self.mat_id = glh::get_uniform(self.program, "mvp_mat");
    let position_attr = glh::get_attr(self.program, "in_vertex_coordinates");
    gl::EnableVertexAttribArray(position_attr);
    glh::vertex_attrib_pointer(position_attr, 3);
    let vt_attr = glh::get_attr(self.program, "in_texture_coordinates");
    gl::EnableVertexAttribArray(vt_attr);
    glh::vertex_attrib_pointer(vt_attr, 3);
    let map_vertex_data = build_hex_mesh(&self.geom);
    self.map_mesh.set_vertex_coords(map_vertex_data);
    self.map_mesh.set_texture_coords(build_hex_tex_coord());
    self.map_mesh.set_texture(glh::load_texture(~"data/floor.png"));
    let unit_obj = obj::Model::new("data/tank.obj");
    self.unit_mesh.set_vertex_coords(unit_obj.build());
    self.unit_mesh.set_texture_coords(unit_obj.build_tex_coord());
    self.unit_mesh.set_texture(glh::load_texture(~"data/tank.png"));
  }

  fn add_unit(&mut self, id: i32, pos: Vec2<i32>) {
    let world_pos = self.geom.map_pos_to_world_pos(pos);
    self.scene_nodes.insert(id, SceneNode{pos: world_pos});
  }

  fn init_units(&mut self) {
    self.add_unit(0, Vec2{x: 0, y: 0});
    self.add_unit(1, Vec2{x: 0, y: 1});
    self.add_unit(2, Vec2{x: 1, y: 0});
    self.add_unit(2, Vec2{x: 1, y: 1});
  }

  fn init_opengl(&mut self) {
    gl::load_with(glfw::get_proc_address);
    gl::Enable(gl::DEPTH_TEST);
  }

  fn cleanup_opengl(&self) {
    gl::DeleteProgram(self.program);
  }

  fn draw_units(&self) {
    gl::UseProgram(self.program);
    for (_, unit) in self.scene_nodes.iter() {
      let m = glh::tr(self.camera.mat(), unit.pos);
      glh::uniform_mat4f(self.mat_id, &m);
      self.unit_mesh.draw(self.program);
    }
  }

  fn draw_map(&self) {
    glh::uniform_mat4f(self.mat_id, &self.camera.mat());
    self.map_mesh.draw(self.program);
  }

  fn draw(&self) {
    gl::ClearColor(0.3, 0.3, 0.3, 1.0);
    gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
    gl::UseProgram(self.program);
    self.draw_units();
    self.draw_map();
    self.win().swap_buffers();
  }

  pub fn is_running(&self) -> bool {
    return !self.win().should_close()
  }

  fn handle_key_event(&mut self, key: glfw::Key) {
    match key {
      glfw::KeyEscape | glfw::KeyQ => {
        self.win().set_should_close(true);
      },
      glfw::KeySpace => println!("space"),
      glfw::KeyUp => self.camera.move(270.0),
      glfw::KeyDown => self.camera.move(90.0),
      glfw::KeyRight => self.camera.move(0.0),
      glfw::KeyLeft => self.camera.move(180.0),
      glfw::KeyMinus => self.camera.zoom += 1.0,
      glfw::KeyEqual => self.camera.zoom -= 1.0,
      _ => {},
    }
  }

  fn handle_cursor_pos_event(&mut self, pos: Vec2<f32>) {
    let button = self.win().get_mouse_button(glfw::MouseButtonRight);
    if button == glfw::Press {
      self.camera.z_angle += (self.mouse_pos.x - pos.x) / 2.0;
      self.camera.x_angle += (self.mouse_pos.y - pos.y) / 2.0;
    }
    self.mouse_pos = pos;
  }

  fn handle_mouse_button_event(&mut self) {
    if !self.selected_tile_pos.is_none() {
      let map_pos = self.selected_tile_pos.unwrap();
      let pos = self.geom.map_pos_to_world_pos(map_pos);
      let unit_id = 0;
      self.scene_nodes.get_mut(&unit_id).pos = pos;
    }
  }

  fn get_events(&mut self) -> ~[glfw::WindowEvent] {
    glfw::poll_events();
    let mut events = ~[];
    for (_, event) in self.win().flush_events() {
      events.push(event);
    }
    events
  }

  fn handle_event(&mut self, event: glfw::WindowEvent) {
    match event {
      glfw::KeyEvent(key, _, glfw::Press, _) => {
        self.handle_key_event(key);
      },
      glfw::CursorPosEvent(x, y) => {
        let p = Vec2{x: x as f32, y: y as f32};
        self.handle_cursor_pos_event(p);
      },
      glfw::MouseButtonEvent(glfw::MouseButtonLeft, glfw::Press, _) => {
        self.handle_mouse_button_event();
      },
      glfw::SizeEvent(w, h) => {
        gl::Viewport(0, 0, w, h);
      },
      _ => {},
    }
  }

  fn handle_events(&mut self) {
    for event in self.get_events().iter() {
      self.handle_event(*event);
    }
  }

  fn pick_tile(&mut self) {
    let mouse_pos = Vec2 {
      x: self.mouse_pos.x as i32,
      y: self.mouse_pos.y as i32,
    };
    let win_size = self.win().get_size();
    self.selected_tile_pos = self.picker.pick_tile(
      win_size, &self.camera, mouse_pos);
  }

  pub fn tick(&mut self) {
    self.handle_events();
    self.pick_tile();
    self.draw();
  }
}

impl Drop for Visualizer {
  fn drop(&mut self) {
    self.cleanup_opengl();
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<|endoftext|>


<commit_before>//! This is documentation for the `file` module.

use std::io::prelude::Read;
use std::io::prelude::Write;
use std::error::Error;
use std::fs::File;
use std::fs;
use std::path::Path;

/// Read Text File
///
/// # Examples
///
/// ```ignore
/// use zwreec::file;
///
/// let stringContent = file::open_source_file("../README.md");
/// ```
pub fn open_source_file(source_file_name: &str) -> String {

    let path = Path::new(source_file_name);
    let display = path.display();

    // Open the path in read-only mode, returns `io::Result<File>`
    let mut file = match File::open(&path) {
        // The `description` method of `io::Error` returns a string that
        // describes the error
        Err(why) => panic!("couldn't open {}: {}", display,
                                                   Error::description(&why)),
        Ok(file) => file,
    };

    let mut content = String::new();
    match file.read_to_string(&mut content) {
        Err(why) => panic!("couldn't read {}: {}", display,
                                                   Error::description(&why)),
        Ok(_) => debug!("{} contains:\n-------\n{}\n----", display, content),
    }

    content
}

/// saves bytes to an file
pub fn save_bytes_to_file(target_file_name: &str, bytes: &[u8]) {
    // saving
    info!("save to file: {}", target_file_name);

    let path = Path::new(target_file_name);
    let display = path.display();

    // Open a file in write-only mode, returns `io::Result<File>`
    let mut file = match File::create(&path) {
        Err(why) => panic!("couldn't create {}: {}",
                           display,
                           Error::description(&why)),
        Ok(file) => file,
    };

    match file.write_all(bytes) {
        Err(why) => {
            panic!("couldn't write to {}: {}", display,
                                               Error::description(&why))
        },
        Ok(_) => info!("successfully wrote to {}", display),
    }
}

pub fn save_target_file(target_file_name: &str) {
    // saving
    info!("save to file: {}", target_file_name)
}
<commit_msg>remove unused import<commit_after>//! This is documentation for the `file` module.

use std::io::prelude::Read;
use std::io::prelude::Write;
use std::error::Error;
use std::fs::File;
use std::path::Path;

/// Read Text File
///
/// # Examples
///
/// ```ignore
/// use zwreec::file;
///
/// let stringContent = file::open_source_file("../README.md");
/// ```
pub fn open_source_file(source_file_name: &str) -> String {

    let path = Path::new(source_file_name);
    let display = path.display();

    // Open the path in read-only mode, returns `io::Result<File>`
    let mut file = match File::open(&path) {
        // The `description` method of `io::Error` returns a string that
        // describes the error
        Err(why) => panic!("couldn't open {}: {}", display,
                                                   Error::description(&why)),
        Ok(file) => file,
    };

    let mut content = String::new();
    match file.read_to_string(&mut content) {
        Err(why) => panic!("couldn't read {}: {}", display,
                                                   Error::description(&why)),
        Ok(_) => debug!("{} contains:\n-------\n{}\n----", display, content),
    }

    content
}

/// saves bytes to an file
pub fn save_bytes_to_file(target_file_name: &str, bytes: &[u8]) {
    // saving
    info!("save to file: {}", target_file_name);

    let path = Path::new(target_file_name);
    let display = path.display();

    // Open a file in write-only mode, returns `io::Result<File>`
    let mut file = match File::create(&path) {
        Err(why) => panic!("couldn't create {}: {}",
                           display,
                           Error::description(&why)),
        Ok(file) => file,
    };

    match file.write_all(bytes) {
        Err(why) => {
            panic!("couldn't write to {}: {}", display,
                                               Error::description(&why))
        },
        Ok(_) => info!("successfully wrote to {}", display),
    }
}

pub fn save_target_file(target_file_name: &str) {
    // saving
    info!("save to file: {}", target_file_name)
}
<|endoftext|>


<commit_before>use super::errors::{AttesterSlashingInvalid as Invalid, AttesterSlashingValidationError as Error};
use super::verify_indexed_attestation::verify_indexed_attestation;
use std::collections::HashSet;
use types::*;

/// Indicates if an `AttesterSlashing` is valid to be included in a block in the current epoch of the given
/// state.
///
/// Returns `Ok(())` if the `AttesterSlashing` is valid, otherwise indicates the reason for invalidity.
///
/// Spec v0.6.1
pub fn verify_attester_slashing<T: EthSpec>(
    state: &BeaconState<T>,
    attester_slashing: &AttesterSlashing,
    should_verify_indexed_attestations: bool,
    spec: &ChainSpec,
) -> Result<(), Error> {
    let attestation_1 = &attester_slashing.attestation_1;
    let attestation_2 = &attester_slashing.attestation_2;

    // Spec: is_slashable_attestation_data
    verify!(
        attestation_1.is_double_vote(attestation_2)
            || attestation_1.is_surround_vote(attestation_2),
        Invalid::NotSlashable
    );

    if should_verify_indexed_attestations {
        verify_indexed_attestation(state, &attestation_1, spec)
            .map_err(|e| Error::Invalid(Invalid::IndexedAttestation1Invalid(e.into())))?;
        verify_indexed_attestation(state, &attestation_2, spec)
            .map_err(|e| Error::Invalid(Invalid::IndexedAttestation2Invalid(e.into())))?;
    }

    Ok(())
}

/// For a given attester slashing, return the indices able to be slashed.
///
/// Returns Ok(indices) if `indices.len() > 0`.
///
/// Spec v0.6.1
pub fn get_slashable_indices<T: EthSpec>(
    state: &BeaconState<T>,
    attester_slashing: &AttesterSlashing,
    spec: &ChainSpec,
) -> Result<Vec<u64>, Error> {
    get_slashable_indices_modular(
        state,
        attester_slashing,
        |_, validator| validator.is_slashable_at(state.current_epoch()),
        spec,
    )
}

/// Same as `gather_attester_slashing_indices` but allows the caller to specify the criteria
/// for determining whether a given validator should be considered slashable.
pub fn get_slashable_indices_modular<F, T: EthSpec>(
    state: &BeaconState<T>,
    attester_slashing: &AttesterSlashing,
    is_slashable: F,
    spec: &ChainSpec,
) -> Result<Vec<u64>, Error>
where
    F: Fn(u64, &Validator) -> bool,
{
    let attestation_1 = &attester_slashing.attestation_1;
    let attestation_2 = &attester_slashing.attestation_2;

    let mut attesting_indices_1 = HashSet::new();
    attesting_indices_1.extend(attestation_1.custody_bit_0_indices.clone());
    attesting_indices_1.extend(attestation_1.custody_bit_1_indices.clone());

    let mut attesting_indices_2 = HashSet::new();
    attesting_indices_2.extend(attestation_2.custody_bit_0_indices.clone());
    attesting_indices_2.extend(attestation_2.custody_bit_1_indices.clone());

    let mut slashable_indices = vec![];

    for index in &attesting_indices_1 & &attesting_indices_2 {
        let validator = state
            .validator_registry
            .get(index as usize)
            .ok_or_else(|| Error::Invalid(Invalid::UnknownValidator(index)))?;

        if is_slashable(index, validator) {
            slashable_indices.push(index);
        }
    }

    verify!(!slashable_indices.is_empty(), Invalid::NoSlashableIndices);

    Ok(slashable_indices)
}
<commit_msg>state_processing: sort attester slashing indices<commit_after>use super::errors::{AttesterSlashingInvalid as Invalid, AttesterSlashingValidationError as Error};
use super::verify_indexed_attestation::verify_indexed_attestation;
use std::collections::BTreeSet;
use types::*;

/// Indicates if an `AttesterSlashing` is valid to be included in a block in the current epoch of the given
/// state.
///
/// Returns `Ok(())` if the `AttesterSlashing` is valid, otherwise indicates the reason for invalidity.
///
/// Spec v0.6.1
pub fn verify_attester_slashing<T: EthSpec>(
    state: &BeaconState<T>,
    attester_slashing: &AttesterSlashing,
    should_verify_indexed_attestations: bool,
    spec: &ChainSpec,
) -> Result<(), Error> {
    let attestation_1 = &attester_slashing.attestation_1;
    let attestation_2 = &attester_slashing.attestation_2;

    // Spec: is_slashable_attestation_data
    verify!(
        attestation_1.is_double_vote(attestation_2)
            || attestation_1.is_surround_vote(attestation_2),
        Invalid::NotSlashable
    );

    if should_verify_indexed_attestations {
        verify_indexed_attestation(state, &attestation_1, spec)
            .map_err(|e| Error::Invalid(Invalid::IndexedAttestation1Invalid(e.into())))?;
        verify_indexed_attestation(state, &attestation_2, spec)
            .map_err(|e| Error::Invalid(Invalid::IndexedAttestation2Invalid(e.into())))?;
    }

    Ok(())
}

/// For a given attester slashing, return the indices able to be slashed.
///
/// Returns Ok(indices) if `indices.len() > 0`.
///
/// Spec v0.6.1
pub fn get_slashable_indices<T: EthSpec>(
    state: &BeaconState<T>,
    attester_slashing: &AttesterSlashing,
    spec: &ChainSpec,
) -> Result<Vec<u64>, Error> {
    get_slashable_indices_modular(
        state,
        attester_slashing,
        |_, validator| validator.is_slashable_at(state.current_epoch()),
        spec,
    )
}

/// Same as `gather_attester_slashing_indices` but allows the caller to specify the criteria
/// for determining whether a given validator should be considered slashable.
pub fn get_slashable_indices_modular<F, T: EthSpec>(
    state: &BeaconState<T>,
    attester_slashing: &AttesterSlashing,
    is_slashable: F,
    spec: &ChainSpec,
) -> Result<Vec<u64>, Error>
where
    F: Fn(u64, &Validator) -> bool,
{
    let attestation_1 = &attester_slashing.attestation_1;
    let attestation_2 = &attester_slashing.attestation_2;

    let attesting_indices_1 = attestation_1
        .custody_bit_0_indices
        .iter()
        .chain(&attestation_1.custody_bit_1_indices)
        .cloned()
        .collect::<BTreeSet<_>>();
    let attesting_indices_2 = attestation_2
        .custody_bit_0_indices
        .iter()
        .chain(&attestation_2.custody_bit_1_indices)
        .cloned()
        .collect::<BTreeSet<_>>();

    let mut slashable_indices = vec![];

    for index in &attesting_indices_1 & &attesting_indices_2 {
        let validator = state
            .validator_registry
            .get(index as usize)
            .ok_or_else(|| Error::Invalid(Invalid::UnknownValidator(index)))?;

        if is_slashable(index, validator) {
            slashable_indices.push(index);
        }
    }

    verify!(!slashable_indices.is_empty(), Invalid::NoSlashableIndices);

    Ok(slashable_indices)
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;

use clap::App;

fn main() {
    App::new("myapp")
        .about("does awesome things")
       // use crate_authors! to pull the author(s) names from the Cargo.toml
       .author(crate_authors!())
       .get_matches();

    // running the this app with the -h will display whatever author(s) are in your
    // Cargo.toml
}<commit_msg>Fix typos<commit_after>#[macro_use]
extern crate clap;

use clap::App;

fn main() {
    App::new("myapp")
        .about("does awesome things")
       // use crate_authors! to pull the author(s) names from the Cargo.toml
       .author(crate_authors!())
       .get_matches();

    // running this app with -h will display whatever author(s) are in your
    // Cargo.toml
}
<|endoftext|>