<commit_before>extern crate bytes;
extern crate futures;
extern crate futures_cpupool;
extern crate itertools;
extern crate serde_json;
extern crate tokio_core;
extern crate tokio_io;
extern crate tokio_proto;
extern crate tokio_service;

use std;
use std::collections::HashMap;
use std::error::Error as StdError;
use std::os::unix::fs::DirBuilderExt;
use std::sync::{Arc, Mutex};

use self::futures::{Future, Stream, Sink};
use self::futures::sync::mpsc;
use self::itertools::Itertools;
use self::tokio_io::AsyncRead;
use self::tokio_service::Service as TokioService;

use super::*;
use self::agent::{AgentStorage, DurableAgentStorage};
use self::api::{Authenticated, Request, Response};
use self::token::{DurableTokenStorage, TOKEN_NAME_LEN, TokenStorage};

pub struct ServiceCodec;

impl tokio_io::codec::Decoder for ServiceCodec {
    type Item = Request;
    type Error = std::io::Error;

    fn decode(&mut self, buf: &mut bytes::BytesMut) -> std::io::Result<Option<Self::Item>> {
        if let Some(i) = buf.iter().position(|&b| b == b'\n') {
            // remove the serialized frame from the buffer.
            let line = buf.split_to(i);

            // Also remove the '\n'
            buf.split_to(1);

            // Deserialize JSON and return it in a Frame.
            let maybe_req: Result<Self::Item, serde_json::error::Error> =
                serde_json::from_slice(&line[..]);
            match maybe_req {
                Ok(req) => {
                    trace!("service decode {:?}", req);
                    buf.take();
                    Ok(Some(req))
                }
                Err(e) => {
                    error!("service decode failed: {}", e);
                    Err(std::io::Error::new(std::io::ErrorKind::Other, e.description()))
                }
            }
        } else {
            Ok(None)
        }
    }
}

impl tokio_io::codec::Encoder for ServiceCodec {
    type Item = Response;
    type Error = std::io::Error;

    fn encode(&mut self, msg: Self::Item, buf: &mut bytes::BytesMut) -> std::io::Result<()> {
        match serde_json::to_vec(&msg) {
            Ok(json) => {
                trace!("service encode {:?}", msg);
                buf.extend(&json[..]);
                Ok(())
            }
            Err(e) => {
                error!("service encode {:?} failed: {}", msg, e);
                Err(std::io::Error::new(std::io::ErrorKind::Other, e.description()))
            }
        }?;
        buf.extend(&b"\n"[..]);
        Ok(())
    }
}

/// Associate local agent name with a sender that sends messages to that agent.
type AgentSenderMap = HashMap<String, mpsc::Sender<Message>>;

struct ServiceState<S: AgentStorage + Send + 'static> {
    storage: S,
    local_senders: AgentSenderMap,
}

impl<S: AgentStorage + Send> ServiceState<S> {
    pub fn new(storage: S) -> ServiceState<S> {
        ServiceState {
            storage: storage,
            local_senders: AgentSenderMap::new(),
        }
    }

    fn has_agent(&self, name: &str) -> bool {
        self.local_senders.contains_key(name)
    }

    fn remove(&mut self, name: &str) -> Result<(), Error> {
        self.storage.remove_agent(name)?;
        self.local_senders.remove(name);
        Ok(())
    }

    fn add_all_agents(&mut self, svc: &Service<S>) -> Result<(), Error> {
        let agents = self.storage.agents()?;
        for (name, glop) in agents {
            svc.spawn_agent(&name, &glop, self)?;
        }
        Ok(())
    }
}

#[derive(Clone)]
pub struct Service<S: AgentStorage + Send + 'static> {
    state: Arc<Mutex<ServiceState<S>>>,
    handle: tokio_core::reactor::Handle,
    pool: futures_cpupool::CpuPool,
}

impl<S: AgentStorage + Send> Service<S> {
    pub fn new(storage: S, h: &tokio_core::reactor::Handle) -> Result<Service<S>, Error> {
        let svc = Service {
            state: Arc::new(Mutex::new(ServiceState::new(storage))),
            handle: h.clone(),
            pool: futures_cpupool::CpuPool::new_num_cpus(),
        };
        {
            let mut state = &mut svc.state.lock().unwrap();
            state.add_all_agents(&svc)?;
        }
        Ok(svc)
    }

    fn add_agent_contents(&self,
                          name: &str,
                          contents: &str,
                          state: &mut ServiceState<S>)
                          -> Result<(), Error> {
        let glop = grammar::glop(contents).map_err(Error::Parse)?;
        self.add_agent(name, glop, state)
    }

    fn add_agent(&self,
                 name: &str,
                 glop: ast::Glop,
                 state: &mut ServiceState<S>)
                 -> Result<(), Error> {
        self.spawn_agent(name, &glop, state)?;
        state.storage.add_agent(name.to_string(), glop)
    }

    fn spawn_agent(&self,
                   name: &str,
                   glop: &ast::Glop,
                   state: &mut ServiceState<S>)
                   -> Result<(), Error> {
        let runtime_st = state
            .storage
            .new_state(name,
                       Box::new(SenderOutbox {
                                    src_agent: name.to_string(),
                                    remote: self.handle.remote().clone(),
                                    state: self.state.clone(),
                                }) as Box<runtime::Outbox + Send>)?;
        let (sender, receiver) = mpsc::channel(10);
        let agent = Agent::new(glop, runtime_st, receiver)?;
        state.local_senders.insert(name.to_string(), sender);
        self.handle
            .spawn(self.pool
                       .spawn(agent
                                  .for_each(|_| Ok(()))
                                  .or_else(|e| {
                                               error!("{}", e);
                                               Err(e)
                                           })
                                  .then(|_| Ok(()))));
        Ok(())
    }

    fn do_call(&self, req: Authenticated<Request>) -> Result<Response, Error> {
        debug!("request {:?}", &req);
        let res = match req.item {
            Request::Add {
                contents: ref add_contents,
                name: ref add_name,
            } => {
                let mut state = self.state.lock().unwrap();
                if state.has_agent(add_name) {
                    return Ok(Response::Error(format!("agent {} already added", add_name)));
                }
                self.add_agent_contents(add_name, add_contents, &mut state)?;
                Response::Add
            }
            Request::Remove { ref name } => {
                let mut state = self.state.lock().unwrap();
                state.remove(name)?;
                Response::Remove
            }
            Request::List => {
                let state = self.state.lock().unwrap();
                Response::List { names: state.local_senders.keys().cloned().collect() }
            }
            Request::SendTo(msg) => self.send_to(msg.src_remote(&req.auth_id)),
            Request::Introduce(agent_roles) => {
                let mut result = vec![];
                for ref p in agent_roles.iter().combinations(2) {
                    result.push(self.send_to(Message::new("intro", Obj::new())
                                                 .src_agent(&p[0].name)
                                                 .src_role(Some(p[0].role.to_string()))
                                                 .dst_agent(&p[1].name)));
                    result.push(self.send_to(Message::new("intro", Obj::new())
                                                 .src_agent(&p[1].name)
                                                 .src_role(Some(p[1].role.to_string()))
                                                 .dst_agent(&p[0].name)));
                }
                Response::Introduce(result)
            }
            Request::FetchReply { ref in_reply_to } => {
                let mut state = self.state.lock().unwrap();
                let maybe_msg = state
                    .storage
                    .fetch_remote_reply(&req.auth_id, in_reply_to)?;
                Response::FetchReply(maybe_msg)
            }
            Request::FetchMsgs => {
                let mut state = self.state.lock().unwrap();
                let msgs = state.storage.fetch_remote_msgs(&req.auth_id)?;
                Response::FetchMsgs(msgs)
            }
        };
        debug!("response {:?}", res);
        Ok(res)
    }

    fn send_to(&self, msg: Message) -> Response {
        if let Some(sender) = self.state
               .lock()
               .unwrap()
               .local_senders
               .get(&msg.dst_agent) {
            let resp = Response::SendTo {
                id: msg.id.to_string(),
                src_agent: msg.src_agent.to_string(),
                dst_agent: msg.dst_agent.to_string(),
            };
            let sender = sender.clone();
            self.handle.spawn(sender.send(msg).then(|_| Ok(())));
            resp
        } else {
            Response::Error(format!("agent {} not found", &msg.dst_agent))
        }
    }
}

#[derive(Clone)]
struct SenderOutbox<S: AgentStorage + Send + 'static> {
    src_agent: String,
    remote: tokio_core::reactor::Remote,
    state: Arc<Mutex<ServiceState<S>>>,
}

impl<S: AgentStorage + Send> runtime::Outbox for SenderOutbox<S> {
    fn send_msg(&self, msg: Message) -> Result<(), Error> {
        let mut state = self.state.lock().unwrap();
        match msg.dst_remote.clone() {
            Some(_) => state.storage.push_remote_msg(msg),
            None => {
                let sender = match state.local_senders.get(&msg.dst_agent) {
                    Some(s) => s.clone(),
                    None => return Err(Error::InvalidArgument(msg.dst_agent.to_string())),
                };
                self.remote.spawn(|_| sender.send(msg).then(|_| Ok(())));
                Ok(())
            }
        }
    }
}

impl<S: AgentStorage + Send> TokioService for Service<S> {
    type Request = Authenticated<Request>;
    type Response = Response;

    type Error = std::io::Error;

    type Future = futures::BoxFuture<Self::Response, Self::Error>;

    fn call(&self, req: Self::Request) -> Self::Future {
        match self.do_call(req) {
            Ok(res) => futures::future::ok(res).boxed(),
            Err(e) => {
                futures::future::ok(Response::Error(format!("agent service error: {}", e))).boxed()
            }
        }
    }
}

pub struct SecureServiceCodec {
    tokens: Box<TokenStorage>,
    codec: Option<crypto::SecretBoxCodec<ServiceCodec>>,
    auth_id: Option<String>,
}

impl SecureServiceCodec {
    #[allow(dead_code)]
    pub fn new(tokens: Box<TokenStorage>) -> SecureServiceCodec {
        SecureServiceCodec {
            tokens: tokens,
            codec: None,
            auth_id: None,
        }
    }

    fn decode_prelude
        (&mut self,
         buf: &mut bytes::BytesMut)
         -> std::io::Result<Option<(String, crypto::SecretBoxCodec<ServiceCodec>)>> {
        if let Some(i) = buf.iter().position(|&b| b == b'\0') {
            // remove the serialized frame from the buffer.
            let line = buf.split_to(i);

            // Also remove the '\0'
            buf.split_to(1);

            trace!("from {:?}", line);
            let id = std::str::from_utf8(&line[..]).map_err(to_ioerror)?;
            trace!("matched prelude, connection from {}", id);
            match self.tokens.token(id) {
                Ok(Some(ref token)) => {
                    Ok(Some((id.to_string(),
                             crypto::SecretBoxCodec::new(ServiceCodec, token.key().clone()))))
                }
                Ok(None) => {
                    Err(std::io::Error::new(std::io::ErrorKind::Other,
                                            format!("missing or invalid token name: {}", id)))
                }
                Err(e) => Err(to_ioerror(e)),
            }
        } else if buf.len() > TOKEN_NAME_LEN + 1 {
            Err(std::io::Error::new(std::io::ErrorKind::Other, "missing or invalid prelude"))
        } else {
            Ok(None)
        }
    }
}

impl tokio_io::codec::Decoder for SecureServiceCodec {
    type Item = Authenticated<<ServiceCodec as tokio_io::codec::Decoder>::Item>;
    type Error = std::io::Error;

    fn decode(&mut self, buf: &mut bytes::BytesMut) -> std::io::Result<Option<Self::Item>> {
        match self.decode_prelude(buf) {
            Ok(Some((id, codec))) => {
                self.auth_id = Some(id);
                self.codec = Some(codec);
            }
            Ok(None) => {}
            Err(e) => return Err(e),
        }
        if let (&Some(ref id), &mut Some(ref mut codec)) = (&self.auth_id, &mut self.codec) {
            trace!("decoding encrypted contents");
            match codec.decode(buf) {
                Ok(Some(req)) => {
                    buf.take();
                    Ok(Some(Authenticated {
                                auth_id: id.to_string(),
                                item: req,
                            }))
                }
                Ok(None) => Ok(None),
                Err(e) => Err(e),
            }
        } else {
            Ok(None)
        }
    }
}

impl tokio_io::codec::Encoder for SecureServiceCodec {
    type Item = <ServiceCodec as tokio_io::codec::Encoder>::Item;
    type Error = std::io::Error;

    fn encode(&mut self, msg: Self::Item, buf: &mut bytes::BytesMut) -> std::io::Result<()> {
        match self.codec {
            None => {
                Err(std::io::Error::new(std::io::ErrorKind::Other, "missing or invalid prelude"))
            }
            Some(ref mut codec) => codec.encode(msg, buf),
        }
    }
}

pub struct Server {
    pub addr: std::net::SocketAddr,
    pub tokens_path: String,
    pub agents_path: String,
}

impl Server {
    pub fn new(addr_str: &str, path: &str) -> Result<Server, Error> {
        let addr = addr_str.parse()?;
        Server::new_addr(addr, path)
    }

    pub fn new_addr(addr: std::net::SocketAddr, path: &str) -> Result<Server, Error> {
        std::fs::DirBuilder::new()
            .recursive(true)
            .mode(0o700)
            .create(path)
            .map_err(Error::IO)?;
        Ok(Server {
               addr: addr,
               agents_path: std::path::PathBuf::from(path)
                   .join("agents")
                   .to_str()
                   .unwrap()
                   .to_string(),
               tokens_path: std::path::PathBuf::from(path)
                   .join("tokens.json")
                   .to_str()
                   .unwrap()
                   .to_string(),
           })
    }

    pub fn run(&self) -> Result<(), Error> {
        let mut core = tokio_core::reactor::Core::new().map_err(Error::IO)?;
        let handle = core.handle();
        let listener = tokio_core::net::TcpListener::bind(&self.addr, &handle)
            .map_err(Error::IO)?;
        info!("server listening on {}", self.addr);
        let connections = listener.incoming();
        let agent_storage = DurableAgentStorage::new(&self.agents_path);
        let service = Service::new(agent_storage, &handle)?;
        let server = connections.for_each(move |(socket, _peer_addr)| {
            let token_storage = DurableTokenStorage::new(&self.tokens_path);
            let (wr, rd) = socket
                .framed(SecureServiceCodec::new(Box::new(token_storage)))
                .split();
            let service = service.clone();
            let responses = rd.and_then(move |req| service.call(req));
            let responder = wr.send_all(responses)
                .or_else(|e| {
                             error!("{}", e);
                             Err(e)
                         })
                .then(|_| Ok(()));
            handle.spawn(responder);
            Ok(())
        });
        core.run(server).map_err(Error::IO)
    }
}
<commit_msg>rustfmt<commit_after>extern crate bytes;
extern crate futures;
extern crate futures_cpupool;
extern crate itertools;
extern crate serde_json;
extern crate tokio_core;
extern crate tokio_io;
extern crate tokio_proto;
extern crate tokio_service;

use std;
use std::collections::HashMap;
use std::error::Error as StdError;
use std::os::unix::fs::DirBuilderExt;
use std::sync::{Arc, Mutex};

use self::futures::{Future, Stream, Sink};
use self::futures::sync::mpsc;
use self::itertools::Itertools;
use self::tokio_io::AsyncRead;
use self::tokio_service::Service as TokioService;

use super::*;
use self::agent::{AgentStorage, DurableAgentStorage};
use self::api::{Authenticated, Request, Response};
use self::token::{DurableTokenStorage, TOKEN_NAME_LEN, TokenStorage};

pub struct ServiceCodec;

impl tokio_io::codec::Decoder for ServiceCodec {
    type Item = Request;
    type Error = std::io::Error;

    fn decode(&mut self, buf: &mut bytes::BytesMut) -> std::io::Result<Option<Self::Item>> {
        if let Some(i) = buf.iter().position(|&b| b == b'\n') {
            // remove the serialized frame from the buffer.
            let line = buf.split_to(i);

            // Also remove the '\n'
            buf.split_to(1);

            // Deserialize JSON and return it in a Frame.
            let maybe_req: Result<Self::Item, serde_json::error::Error> =
                serde_json::from_slice(&line[..]);
            match maybe_req {
                Ok(req) => {
                    trace!("service decode {:?}", req);
                    buf.take();
                    Ok(Some(req))
                }
                Err(e) => {
                    error!("service decode failed: {}", e);
                    Err(std::io::Error::new(std::io::ErrorKind::Other, e.description()))
                }
            }
        } else {
            Ok(None)
        }
    }
}

impl tokio_io::codec::Encoder for ServiceCodec {
    type Item = Response;
    type Error = std::io::Error;

    fn encode(&mut self, msg: Self::Item, buf: &mut bytes::BytesMut) -> std::io::Result<()> {
        match serde_json::to_vec(&msg) {
            Ok(json) => {
                trace!("service encode {:?}", msg);
                buf.extend(&json[..]);
                Ok(())
            }
            Err(e) => {
                error!("service encode {:?} failed: {}", msg, e);
                Err(std::io::Error::new(std::io::ErrorKind::Other, e.description()))
            }
        }?;
        buf.extend(&b"\n"[..]);
        Ok(())
    }
}

/// Associate local agent name with a sender that sends messages to that agent.
type AgentSenderMap = HashMap<String, mpsc::Sender<Message>>;

struct ServiceState<S: AgentStorage + Send + 'static> {
    storage: S,
    local_senders: AgentSenderMap,
}

impl<S: AgentStorage + Send> ServiceState<S> {
    pub fn new(storage: S) -> ServiceState<S> {
        ServiceState {
            storage: storage,
            local_senders: AgentSenderMap::new(),
        }
    }

    fn has_agent(&self, name: &str) -> bool {
        self.local_senders.contains_key(name)
    }

    fn remove(&mut self, name: &str) -> Result<(), Error> {
        self.storage.remove_agent(name)?;
        self.local_senders.remove(name);
        Ok(())
    }

    fn add_all_agents(&mut self, svc: &Service<S>) -> Result<(), Error> {
        let agents = self.storage.agents()?;
        for (name, glop) in agents {
            svc.spawn_agent(&name, &glop, self)?;
        }
        Ok(())
    }
}

#[derive(Clone)]
pub struct Service<S: AgentStorage + Send + 'static> {
    state: Arc<Mutex<ServiceState<S>>>,
    handle: tokio_core::reactor::Handle,
    pool: futures_cpupool::CpuPool,
}

impl<S: AgentStorage + Send> Service<S> {
    pub fn new(storage: S, h: &tokio_core::reactor::Handle) -> Result<Service<S>, Error> {
        let svc = Service {
            state: Arc::new(Mutex::new(ServiceState::new(storage))),
            handle: h.clone(),
            pool: futures_cpupool::CpuPool::new_num_cpus(),
        };
        {
            let mut state = &mut svc.state.lock().unwrap();
            state.add_all_agents(&svc)?;
        }
        Ok(svc)
    }

    fn add_agent_contents(&self,
                          name: &str,
                          contents: &str,
                          state: &mut ServiceState<S>)
                          -> Result<(), Error> {
        let glop = grammar::glop(contents).map_err(Error::Parse)?;
        self.add_agent(name, glop, state)
    }

    fn add_agent(&self,
                 name: &str,
                 glop: ast::Glop,
                 state: &mut ServiceState<S>)
                 -> Result<(), Error> {
        self.spawn_agent(name, &glop, state)?;
        state.storage.add_agent(name.to_string(), glop)
    }

    fn spawn_agent(&self,
                   name: &str,
                   glop: &ast::Glop,
                   state: &mut ServiceState<S>)
                   -> Result<(), Error> {
        let runtime_st = state.storage
            .new_state(name,
                       Box::new(SenderOutbox {
                           src_agent: name.to_string(),
                           remote: self.handle.remote().clone(),
                           state: self.state.clone(),
                       }) as Box<runtime::Outbox + Send>)?;
        let (sender, receiver) = mpsc::channel(10);
        let agent = Agent::new(glop, runtime_st, receiver)?;
        state.local_senders.insert(name.to_string(), sender);
        self.handle
            .spawn(self.pool
                .spawn(agent.for_each(|_| Ok(()))
                    .or_else(|e| {
                        error!("{}", e);
                        Err(e)
                    })
                    .then(|_| Ok(()))));
        Ok(())
    }

    fn do_call(&self, req: Authenticated<Request>) -> Result<Response, Error> {
        debug!("request {:?}", &req);
        let res = match req.item {
            Request::Add { contents: ref add_contents, name: ref add_name } => {
                let mut state = self.state.lock().unwrap();
                if state.has_agent(add_name) {
                    return Ok(Response::Error(format!("agent {} already added", add_name)));
                }
                self.add_agent_contents(add_name, add_contents, &mut state)?;
                Response::Add
            }
            Request::Remove { ref name } => {
                let mut state = self.state.lock().unwrap();
                state.remove(name)?;
                Response::Remove
            }
            Request::List => {
                let state = self.state.lock().unwrap();
                Response::List { names: state.local_senders.keys().cloned().collect() }
            }
            Request::SendTo(msg) => self.send_to(msg.src_remote(&req.auth_id)),
            Request::Introduce(agent_roles) => {
                let mut result = vec![];
                for ref p in agent_roles.iter().combinations(2) {
                    result.push(self.send_to(Message::new("intro", Obj::new())
                        .src_agent(&p[0].name)
                        .src_role(Some(p[0].role.to_string()))
                        .dst_agent(&p[1].name)));
                    result.push(self.send_to(Message::new("intro", Obj::new())
                        .src_agent(&p[1].name)
                        .src_role(Some(p[1].role.to_string()))
                        .dst_agent(&p[0].name)));
                }
                Response::Introduce(result)
            }
            Request::FetchReply { ref in_reply_to } => {
                let mut state = self.state.lock().unwrap();
                let maybe_msg = state.storage
                    .fetch_remote_reply(&req.auth_id, in_reply_to)?;
                Response::FetchReply(maybe_msg)
            }
            Request::FetchMsgs => {
                let mut state = self.state.lock().unwrap();
                let msgs = state.storage.fetch_remote_msgs(&req.auth_id)?;
                Response::FetchMsgs(msgs)
            }
        };
        debug!("response {:?}", res);
        Ok(res)
    }

    fn send_to(&self, msg: Message) -> Response {
        if let Some(sender) = self.state
            .lock()
            .unwrap()
            .local_senders
            .get(&msg.dst_agent) {
            let resp = Response::SendTo {
                id: msg.id.to_string(),
                src_agent: msg.src_agent.to_string(),
                dst_agent: msg.dst_agent.to_string(),
            };
            let sender = sender.clone();
            self.handle.spawn(sender.send(msg).then(|_| Ok(())));
            resp
        } else {
            Response::Error(format!("agent {} not found", &msg.dst_agent))
        }
    }
}

#[derive(Clone)]
struct SenderOutbox<S: AgentStorage + Send + 'static> {
    src_agent: String,
    remote: tokio_core::reactor::Remote,
    state: Arc<Mutex<ServiceState<S>>>,
}

impl<S: AgentStorage + Send> runtime::Outbox for SenderOutbox<S> {
    fn send_msg(&self, msg: Message) -> Result<(), Error> {
        let mut state = self.state.lock().unwrap();
        match msg.dst_remote.clone() {
            Some(_) => state.storage.push_remote_msg(msg),
            None => {
                let sender = match state.local_senders.get(&msg.dst_agent) {
                    Some(s) => s.clone(),
                    None => return Err(Error::InvalidArgument(msg.dst_agent.to_string())),
                };
                self.remote.spawn(|_| sender.send(msg).then(|_| Ok(())));
                Ok(())
            }
        }
    }
}

impl<S: AgentStorage + Send> TokioService for Service<S> {
    type Request = Authenticated<Request>;
    type Response = Response;

    type Error = std::io::Error;

    type Future = futures::BoxFuture<Self::Response, Self::Error>;

    fn call(&self, req: Self::Request) -> Self::Future {
        match self.do_call(req) {
            Ok(res) => futures::future::ok(res).boxed(),
            Err(e) => {
                futures::future::ok(Response::Error(format!("agent service error: {}", e))).boxed()
            }
        }
    }
}

pub struct SecureServiceCodec {
    tokens: Box<TokenStorage>,
    codec: Option<crypto::SecretBoxCodec<ServiceCodec>>,
    auth_id: Option<String>,
}

impl SecureServiceCodec {
    #[allow(dead_code)]
    pub fn new(tokens: Box<TokenStorage>) -> SecureServiceCodec {
        SecureServiceCodec {
            tokens: tokens,
            codec: None,
            auth_id: None,
        }
    }

    fn decode_prelude
        (&mut self,
         buf: &mut bytes::BytesMut)
         -> std::io::Result<Option<(String, crypto::SecretBoxCodec<ServiceCodec>)>> {
        if let Some(i) = buf.iter().position(|&b| b == b'\0') {
            // remove the serialized frame from the buffer.
            let line = buf.split_to(i);

            // Also remove the '\0'
            buf.split_to(1);

            trace!("from {:?}", line);
            let id = std::str::from_utf8(&line[..]).map_err(to_ioerror)?;
            trace!("matched prelude, connection from {}", id);
            match self.tokens.token(id) {
                Ok(Some(ref token)) => {
                    Ok(Some((id.to_string(),
                             crypto::SecretBoxCodec::new(ServiceCodec, token.key().clone()))))
                }
                Ok(None) => {
                    Err(std::io::Error::new(std::io::ErrorKind::Other,
                                            format!("missing or invalid token name: {}", id)))
                }
                Err(e) => Err(to_ioerror(e)),
            }
        } else if buf.len() > TOKEN_NAME_LEN + 1 {
            Err(std::io::Error::new(std::io::ErrorKind::Other, "missing or invalid prelude"))
        } else {
            Ok(None)
        }
    }
}

impl tokio_io::codec::Decoder for SecureServiceCodec {
    type Item = Authenticated<<ServiceCodec as tokio_io::codec::Decoder>::Item>;
    type Error = std::io::Error;

    fn decode(&mut self, buf: &mut bytes::BytesMut) -> std::io::Result<Option<Self::Item>> {
        match self.decode_prelude(buf) {
            Ok(Some((id, codec))) => {
                self.auth_id = Some(id);
                self.codec = Some(codec);
            }
            Ok(None) => {}
            Err(e) => return Err(e),
        }
        if let (&Some(ref id), &mut Some(ref mut codec)) = (&self.auth_id, &mut self.codec) {
            trace!("decoding encrypted contents");
            match codec.decode(buf) {
                Ok(Some(req)) => {
                    buf.take();
                    Ok(Some(Authenticated {
                        auth_id: id.to_string(),
                        item: req,
                    }))
                }
                Ok(None) => Ok(None),
                Err(e) => Err(e),
            }
        } else {
            Ok(None)
        }
    }
}

impl tokio_io::codec::Encoder for SecureServiceCodec {
    type Item = <ServiceCodec as tokio_io::codec::Encoder>::Item;
    type Error = std::io::Error;

    fn encode(&mut self, msg: Self::Item, buf: &mut bytes::BytesMut) -> std::io::Result<()> {
        match self.codec {
            None => {
                Err(std::io::Error::new(std::io::ErrorKind::Other, "missing or invalid prelude"))
            }
            Some(ref mut codec) => codec.encode(msg, buf),
        }
    }
}

pub struct Server {
    pub addr: std::net::SocketAddr,
    pub tokens_path: String,
    pub agents_path: String,
}

impl Server {
    pub fn new(addr_str: &str, path: &str) -> Result<Server, Error> {
        let addr = addr_str.parse()?;
        Server::new_addr(addr, path)
    }

    pub fn new_addr(addr: std::net::SocketAddr, path: &str) -> Result<Server, Error> {
        std::fs::DirBuilder::new().recursive(true)
            .mode(0o700)
            .create(path)
            .map_err(Error::IO)?;
        Ok(Server {
            addr: addr,
            agents_path: std::path::PathBuf::from(path)
                .join("agents")
                .to_str()
                .unwrap()
                .to_string(),
            tokens_path: std::path::PathBuf::from(path)
                .join("tokens.json")
                .to_str()
                .unwrap()
                .to_string(),
        })
    }

    pub fn run(&self) -> Result<(), Error> {
        let mut core = tokio_core::reactor::Core::new().map_err(Error::IO)?;
        let handle = core.handle();
        let listener = tokio_core::net::TcpListener::bind(&self.addr, &handle).map_err(Error::IO)?;
        let local_addr = listener.local_addr().map_err(Error::IO)?;
        info!("server listening on {}", local_addr);
        let connections = listener.incoming();
        let agent_storage = DurableAgentStorage::new(&self.agents_path);
        let service = Service::new(agent_storage, &handle)?;
        let server = connections.for_each(move |(socket, _peer_addr)| {
            let token_storage = DurableTokenStorage::new(&self.tokens_path);
            let (wr, rd) = socket.framed(SecureServiceCodec::new(Box::new(token_storage)))
                .split();
            let service = service.clone();
            let responses = rd.and_then(move |req| service.call(req));
            let responder = wr.send_all(responses)
                .or_else(|e| {
                    error!("{}", e);
                    Err(e)
                })
                .then(|_| Ok(()));
            handle.spawn(responder);
            Ok(())
        });
        core.run(server).map_err(Error::IO)
    }
}
<|endoftext|>


<commit_before>use rand;
use rand::Rng;
use std::collections::VecDeque;
use common::{ParamType, MoveDestination};
use piston_window::*;

pub enum Content {
    Number(u8),
    Mine(bool), // bool is true when this is the mine that caused you to loose the game.
    None,
}

struct Cell {
    content: Content,
    revealed: bool,
    marked: bool,
}

impl Cell {
    pub fn clear(&mut self) {
        self.content = Content::None;
        self.revealed = false;
        self.marked = false;
    }

    fn reveal(&mut self) -> &Content {
        self.revealed = true;
        &self.content
    }

    fn toggle_mark(&mut self) {
        self.marked = !self.marked;
    }
}

pub struct Field {
    cells: Vec<Cell>,
    width: u32,
    height: u32,
    mines: u32,
    size: u32,
    selected_x: u32,
    selected_y: u32,
    nubmers_total: u32,
    nubmers_opened: u32
}

impl Field {
    pub fn new(width: u32, height: u32, mines: u32) -> Field {
        let mut field = Field {
            width: width,
            height: height,
            cells: vec![],
            mines: mines,
            size: width*height,
            selected_x: width/2,
            selected_y: height/2,
            nubmers_total: 0,
            nubmers_opened: 0
        };
        field.reinit_vec();
        field.fill();
        field
    }

    fn reinit_vec(&mut self) {
        self.cells.clear();
        self.size = self.width*self.height;
        for _i in 0..self.size {
            self.cells.push(Cell{content: Content::None,
                                 revealed: false,
                                 marked: false});
        }
        self.selected_x = self.width/2;
        self.selected_y = self.height/2;
    }

    fn fill(&mut self) {
        self.clear();
        for _i in 0..self.mines {
            let ind = rand::thread_rng().gen_range(0, self.size);
            self.get_cell_mut(ind).content = Content::Mine(false);
        }
        let mut i: i32 = -1;
        let w = self.width as i32;
        while i < (self.size - 1) as i32 {
            i += 1;
            match self.get_content_safe(i) {
                Some(&Content::None) => {
                    let ct_mine = |b| {
                        match b {
                            true => 1,
                            false => 0
                        }
                    };
                     // don`t care about row
                    let mut ct = ct_mine(self.is_mine_safe(i-w)) +
                                 ct_mine(self.is_mine_safe(i+w));
                    if i % w > 0 { // check left side position
                        ct += ct_mine(self.is_mine_safe(i-w-1)) +
                              ct_mine(self.is_mine_safe(i-1)) +
                              ct_mine(self.is_mine_safe(i+w-1));
                    }
                    if i % w < w - 1 { // check right side position
                        ct += ct_mine(self.is_mine_safe(i-w+1)) +
                              ct_mine(self.is_mine_safe(i+1)) +
                              ct_mine(self.is_mine_safe(i+w+1));
                    }
                    if ct > 0 {
                        self.get_cell_mut(i as u32).content = Content::Number(ct);
                        self.nubmers_total += 1;
                    }
                },
                _ => {}
            }
        }
    }

    fn clear(&mut self) {
        for i in 0..self.size {
            self.get_cell_mut(i).clear();
        }
        self.nubmers_opened = 0;
        self.nubmers_total = 0;
    }

    pub fn reveal(&mut self, i: u32) -> &Content {
        if !self.revealed(i) {
            if let &Content::Number(_i) = self.get_cell_mut(i).reveal() {
                self.nubmers_opened += 1;
            }
        }
        &self.get_content(i)
    }

    pub fn revealed(&self, i: u32) -> bool {
        self.get_cell(i).revealed
    }

    pub fn marked(&self, i: u32) -> bool {
        self.get_cell(i).marked
    }

    pub fn set_killer(&mut self, i: u32) {
        self.get_cell_mut(i).content = Content::Mine(true);
    }

    fn get_cell_mut(&mut self, i:u32) -> &mut Cell {
        self.cells.get_mut(i as usize)
            .unwrap_or_else(|| panic!("Range check error at Field::get_cell_mut ({})", i))
    }

    fn get_cell(& self, i:u32) -> &Cell {
        self.cells.get(i as usize)
            .unwrap_or_else(|| panic!("Range check error at Field::get_cell ({})", i))
    }

    fn get_content_safe(&self, i:i32) -> Option<&Content> {
        if (i < 0) || ((i as u32) >= self.size) {
            None
        } else {
            Some(self.get_content(i as u32))
        }
    }

    pub fn get_content(& self, i: u32) -> &Content {
        &self.get_cell(i).content
    }

    fn is_mine_safe(&self, i: i32) -> bool {
        match self.get_content_safe(i) {
            Some(&Content::Mine(_)) => true,
            _ => false
        }
    }

    pub fn get_width(&self) -> u32 {
        self.width
    }

    pub fn get_height(&self) -> u32 {
        self.height
    }

    pub fn get_size(&self) -> u32 {
        self.size
    }

    pub fn restart(&mut self) {
        self.fill();
    }

    pub fn reveal_all(&mut self) {
        for i in 0..self.size {
            self.get_cell_mut(i).revealed = true;
        }
    }

    pub fn chain_reveal(&mut self, u: u32) {
        if self.marked(u) {
            return;
        }
        let w = self.width as i32;
        // clojure to check for blank cells
        let mut check = |x, d: &mut VecDeque<i32>| {
            match self.get_content_safe(x) {
                Some(&Content::None) => {
                    if !self.revealed(x as u32) {
                        d.push_back(x);
                        self.get_cell_mut(x as u32).marked = false;
                        self.reveal(x as u32);
                    }
                },
                Some(&Content::Number(_n)) => {
                    if !(self.revealed(x as u32)) {
                        self.get_cell_mut(x as u32).marked = false;
                        self.reveal(x as u32);
                    }
                },
                _ => {}
            }
        };
        // BFS initialize
        let deq = &mut VecDeque::new();
        deq.push_back(u as i32);
        // BFS
        while !deq.is_empty() {
            let i = deq.pop_front().unwrap();
            // don`t care about row
            check(i-w, deq);
            check(i+w, deq);
            if i % w > 0 { // check left side position
                check(i-w-1, deq);
                check(i-1, deq);
                check(i+w-1, deq);
            }
            if i % w < w - 1 { // check right side position
                check(i-w+1, deq);
                check(i+1, deq);
                check(i+w+1, deq);
            }
        }
    }

    pub fn draw(&mut self,
            context: Context,
            graphics: &mut G2d,
            field_rect: [u32; 4],
            glyps: &mut Glyphs)
    {
        let cell_w = field_rect[2] / self.get_width();
        let cell_h = field_rect[3] / self.get_height();
        for i in 0..self.get_width() {
            for j in 0..self.get_height() {
                let ind = i + j*self.get_width();
                let transform = context.transform.trans((field_rect[0] + i*cell_w) as f64 + 5.0,
                                                        (field_rect[1] + (j+1)*cell_h) as f64 - 5.0);
                if self.revealed(ind) {
                    match *self.get_content(i + j*self.get_width()) {
                        Content::Mine(killer) => {
                            rectangle([1.0, 0.0, 0.0, 1.0],
                                      [
                                        (field_rect[0] + i*cell_w) as f64,
                                        (field_rect[1] + j*cell_h) as f64,
                                        cell_w as f64,
                                        cell_h as f64
                                      ],
                                      context.transform,
                                      graphics);
                            if killer {
                                text::Text::colored([1.0, 1.0, 1.0, 1.0], cell_h).draw(
                                    "*",
                                    glyps,
                                    &context.draw_state,
                                    transform,
                                    graphics
                                );
                            }
                        },
                        Content::Number(n) => {
                            rectangle(color::hex("c0c0c0"),
                                      [
                                        (field_rect[0] + i*cell_w) as f64,
                                        (field_rect[1] + j*cell_h) as f64,
                                        cell_w as f64,
                                        cell_h as f64
                                      ],
                                      context.transform,
                                      graphics);

                            let text_color = match n {
                                1 => color::hex("0000ff"),
                                2 => color::hex("008000"),
                                3 => color::hex("ff0000"),
                                4 => color::hex("000080"),
                                5 => color::hex("800000"),
                                6 => color::hex("008080"),
                                7 => color::hex("000000"),
                                8 => color::hex("808080"),
                                _ => [0.0, 0.0, 0.0, 1.0]
                            };

                            text::Text::colored(text_color, cell_h).draw(
                                &*n.to_string(),
                                glyps,
                                &context.draw_state,
                                transform,
                                graphics
                            );
                        },
                        Content::None => {
                            rectangle(color::hex("c0c0c0"),
                                      [
                                        (field_rect[0] + i*cell_w) as f64,
                                        (field_rect[1] + j*cell_h) as f64,
                                        cell_w as f64,
                                        cell_h as f64
                                      ],
                                      context.transform,
                                      graphics);
                        }
                    }
                } else {
                    // non revealed
                    rectangle(color::hex("303030"),
                              [
                                (field_rect[0] + i*cell_w) as f64,
                                (field_rect[1] + j*cell_h) as f64,
                                cell_w as f64,
                                cell_h as f64
                              ],
                              context.transform,
                              graphics);
                }
                if self.marked(ind) {
                    rectangle([0.0, 1.0, 0.0, 0.75],
                              [
                                (field_rect[0] + i*cell_w) as f64,
                                (field_rect[1] + j*cell_h) as f64,
                                cell_w as f64,
                                cell_h as f64
                              ],
                              context.transform,
                              graphics);
                }
            }
        }
        rectangle([0.5, 0.5, 0.5, 0.75],
                  [
                    (field_rect[0] + self.selected_x*cell_w) as f64,
                    (field_rect[1] + self.selected_y*cell_h) as f64,
                    cell_w as f64,
                    cell_h as f64
                  ],
                  context.transform,
                  graphics);
        for i in 0..self.get_width() + 1 {
            line::Line::new([0.5, 0.5, 0.5, 1.0], 1.0)
                .draw([
                        (field_rect[0] + i*cell_w) as f64,
                        field_rect[1] as f64,
                        (field_rect[0] + i*cell_w) as f64,
                        (field_rect[1] + field_rect[3]) as f64
                      ],
                      &context.draw_state,
                      context.transform,
                      graphics);
        }
        for i in 0..self.get_height() + 1 {
            line::Line::new([0.5, 0.5, 0.5, 1.0], 1.0)
                .draw([
                        field_rect[0] as f64,
                        (field_rect[1] + i*cell_h) as f64,
                        (field_rect[0] + field_rect[2]) as f64,
                        (field_rect[1] + i*cell_h) as f64
                      ],
                      &context.draw_state,
                      context.transform,
                      graphics);
        }
    }

    pub fn move_selection(&mut self, dest: MoveDestination) {
        match dest {
            MoveDestination::Up => {
                if self.selected_y > 0 {
                    self.selected_y -= 1;
                }
            },
            MoveDestination::Down => {
                if self.selected_y < self.height - 1 {
                    self.selected_y += 1;
                }
            },
            MoveDestination::Left => {
                if self.selected_x > 0 {
                    self.selected_x -= 1;
                }
            },
            MoveDestination::Right => {
                if self.selected_x < self.width - 1 {
                    self.selected_x += 1;
                }
            }
        }
    }

    pub fn get_selected_ind(&self) -> u32 {
        self.selected_x + self.selected_y*self.width
    }

    pub fn is_victory(&self) -> bool {
        self.nubmers_total == self.nubmers_opened
    }

    pub fn reinit_field(&mut self, num: u32, param: ParamType) {
        let mut restart_neded = false;
        match param {
            ParamType::Height => {
                if self.height != num {
                    self.height = num;
                    self.reinit_vec();
                    restart_neded = true;
                }
            }
            ParamType::Width => {
                if self.width != num {
                    self.width = num;
                    self.reinit_vec();
                    restart_neded = true;
                }
            }
            ParamType::Mines => {
                if self.mines != num {
                    self.mines = num;
                    restart_neded = true;
                }
            }
        }
        if restart_neded {
            self.restart();
        }
    }

    pub fn toggle_mark(&mut self, i: u32) {
        self.get_cell_mut(i).toggle_mark();
    }
}
<commit_msg>fix: true number of mines on board, not the case before<commit_after>use rand;
use rand::Rng;
use std::collections::VecDeque;
use common::{ParamType, MoveDestination};
use piston_window::*;

pub enum Content {
    Number(u8),
    Mine(bool), // bool is true when this is the mine that caused you to loose the game.
    None,
}

struct Cell {
    content: Content,
    revealed: bool,
    marked: bool,
}

impl Cell {
    pub fn clear(&mut self) {
        self.content = Content::None;
        self.revealed = false;
        self.marked = false;
    }

    fn reveal(&mut self) -> &Content {
        self.revealed = true;
        &self.content
    }

    fn toggle_mark(&mut self) {
        self.marked = !self.marked;
    }
}

pub struct Field {
    cells: Vec<Cell>,
    width: u32,
    height: u32,
    mines: u32,
    size: u32,
    selected_x: u32,
    selected_y: u32,
    nubmers_total: u32,
    nubmers_opened: u32
}

impl Field {
    pub fn new(width: u32, height: u32, mines: u32) -> Field {
        let mut field = Field {
            width: width,
            height: height,
            cells: vec![],
            mines: mines,
            size: width*height,
            selected_x: width/2,
            selected_y: height/2,
            nubmers_total: 0,
            nubmers_opened: 0
        };
        field.reinit_vec();
        field.fill();
        field
    }

    fn reinit_vec(&mut self) {
        self.cells.clear();
        self.size = self.width*self.height;
        for _i in 0..self.size {
            self.cells.push(Cell{content: Content::None,
                                 revealed: false,
                                 marked: false});
        }
        self.selected_x = self.width/2;
        self.selected_y = self.height/2;
    }

    fn fill(&mut self) {
        self.clear();
        //todo: maybe a better algorithm. for now, this

        if self.mines > self.size {
            panic!("too many mines");// avoid an infinite loop.. could retern a result
        }
        let mut nmines = 0u32;
        while nmines < self.mines {
            let ind = rand::thread_rng().gen_range(0, self.size);
            let cell = self.get_cell_mut(ind);
            match cell.content {
                Content::Mine(_) => {
                    continue;
                },
                _ => {
                    cell.content = Content::Mine(false);
                    nmines += 1;
                },
            }
        }

        let mut i: i32 = -1;
        let w = self.width as i32;
        while i < (self.size - 1) as i32 {
            i += 1;
            match self.get_content_safe(i) {
                Some(&Content::None) => {
                    let ct_mine = |b| {
                        match b {
                            true => 1,
                            false => 0
                        }
                    };
                     // don`t care about row
                    let mut ct = ct_mine(self.is_mine_safe(i-w)) +
                                 ct_mine(self.is_mine_safe(i+w));
                    if i % w > 0 { // check left side position
                        ct += ct_mine(self.is_mine_safe(i-w-1)) +
                              ct_mine(self.is_mine_safe(i-1)) +
                              ct_mine(self.is_mine_safe(i+w-1));
                    }
                    if i % w < w - 1 { // check right side position
                        ct += ct_mine(self.is_mine_safe(i-w+1)) +
                              ct_mine(self.is_mine_safe(i+1)) +
                              ct_mine(self.is_mine_safe(i+w+1));
                    }
                    if ct > 0 {
                        self.get_cell_mut(i as u32).content = Content::Number(ct);
                        self.nubmers_total += 1;
                    }
                },
                _ => {}
            }
        }
    }

    fn clear(&mut self) {
        for i in 0..self.size {
            self.get_cell_mut(i).clear();
        }
        self.nubmers_opened = 0;
        self.nubmers_total = 0;
    }

    pub fn reveal(&mut self, i: u32) -> &Content {
        if !self.revealed(i) {
            if let &Content::Number(_i) = self.get_cell_mut(i).reveal() {
                self.nubmers_opened += 1;
            }
        }
        &self.get_content(i)
    }

    pub fn revealed(&self, i: u32) -> bool {
        self.get_cell(i).revealed
    }

    pub fn marked(&self, i: u32) -> bool {
        self.get_cell(i).marked
    }

    pub fn set_killer(&mut self, i: u32) {
        self.get_cell_mut(i).content = Content::Mine(true);
    }

    fn get_cell_mut(&mut self, i:u32) -> &mut Cell {
        self.cells.get_mut(i as usize)
            .unwrap_or_else(|| panic!("Range check error at Field::get_cell_mut ({})", i))
    }

    fn get_cell(& self, i:u32) -> &Cell {
        self.cells.get(i as usize)
            .unwrap_or_else(|| panic!("Range check error at Field::get_cell ({})", i))
    }

    fn get_content_safe(&self, i:i32) -> Option<&Content> {
        if (i < 0) || ((i as u32) >= self.size) {
            None
        } else {
            Some(self.get_content(i as u32))
        }
    }

    pub fn get_content(& self, i: u32) -> &Content {
        &self.get_cell(i).content
    }

    fn is_mine_safe(&self, i: i32) -> bool {
        match self.get_content_safe(i) {
            Some(&Content::Mine(_)) => true,
            _ => false
        }
    }

    pub fn get_width(&self) -> u32 {
        self.width
    }

    pub fn get_height(&self) -> u32 {
        self.height
    }

    pub fn get_size(&self) -> u32 {
        self.size
    }

    pub fn restart(&mut self) {
        self.fill();
    }

    pub fn reveal_all(&mut self) {
        for i in 0..self.size {
            self.get_cell_mut(i).revealed = true;
        }
    }

    pub fn chain_reveal(&mut self, u: u32) {
        if self.marked(u) {
            return;
        }
        let w = self.width as i32;
        // clojure to check for blank cells
        let mut check = |x, d: &mut VecDeque<i32>| {
            match self.get_content_safe(x) {
                Some(&Content::None) => {
                    if !self.revealed(x as u32) {
                        d.push_back(x);
                        self.get_cell_mut(x as u32).marked = false;
                        self.reveal(x as u32);
                    }
                },
                Some(&Content::Number(_n)) => {
                    if !(self.revealed(x as u32)) {
                        self.get_cell_mut(x as u32).marked = false;
                        self.reveal(x as u32);
                    }
                },
                _ => {}
            }
        };
        // BFS initialize
        let deq = &mut VecDeque::new();
        deq.push_back(u as i32);
        // BFS
        while !deq.is_empty() {
            let i = deq.pop_front().unwrap();
            // don`t care about row
            check(i-w, deq);
            check(i+w, deq);
            if i % w > 0 { // check left side position
                check(i-w-1, deq);
                check(i-1, deq);
                check(i+w-1, deq);
            }
            if i % w < w - 1 { // check right side position
                check(i-w+1, deq);
                check(i+1, deq);
                check(i+w+1, deq);
            }
        }
    }

    pub fn draw(&mut self,
            context: Context,
            graphics: &mut G2d,
            field_rect: [u32; 4],
            glyps: &mut Glyphs)
    {
        let cell_w = field_rect[2] / self.get_width();
        let cell_h = field_rect[3] / self.get_height();
        for i in 0..self.get_width() {
            for j in 0..self.get_height() {
                let ind = i + j*self.get_width();
                let transform = context.transform.trans((field_rect[0] + i*cell_w) as f64 + 5.0,
                                                        (field_rect[1] + (j+1)*cell_h) as f64 - 5.0);
                if self.revealed(ind) {
                    match *self.get_content(i + j*self.get_width()) {
                        Content::Mine(killer) => {
                            rectangle([1.0, 0.0, 0.0, 1.0],
                                      [
                                        (field_rect[0] + i*cell_w) as f64,
                                        (field_rect[1] + j*cell_h) as f64,
                                        cell_w as f64,
                                        cell_h as f64
                                      ],
                                      context.transform,
                                      graphics);
                            if killer {
                                text::Text::colored([1.0, 1.0, 1.0, 1.0], cell_h).draw(
                                    "*",
                                    glyps,
                                    &context.draw_state,
                                    transform,
                                    graphics
                                );
                            }
                        },
                        Content::Number(n) => {
                            rectangle(color::hex("c0c0c0"),
                                      [
                                        (field_rect[0] + i*cell_w) as f64,
                                        (field_rect[1] + j*cell_h) as f64,
                                        cell_w as f64,
                                        cell_h as f64
                                      ],
                                      context.transform,
                                      graphics);

                            let text_color = match n {
                                1 => color::hex("0000ff"),
                                2 => color::hex("008000"),
                                3 => color::hex("ff0000"),
                                4 => color::hex("000080"),
                                5 => color::hex("800000"),
                                6 => color::hex("008080"),
                                7 => color::hex("000000"),
                                8 => color::hex("808080"),
                                _ => [0.0, 0.0, 0.0, 1.0]
                            };

                            text::Text::colored(text_color, cell_h).draw(
                                &*n.to_string(),
                                glyps,
                                &context.draw_state,
                                transform,
                                graphics
                            );
                        },
                        Content::None => {
                            rectangle(color::hex("c0c0c0"),
                                      [
                                        (field_rect[0] + i*cell_w) as f64,
                                        (field_rect[1] + j*cell_h) as f64,
                                        cell_w as f64,
                                        cell_h as f64
                                      ],
                                      context.transform,
                                      graphics);
                        }
                    }
                } else {
                    // non revealed
                    rectangle(color::hex("303030"),
                              [
                                (field_rect[0] + i*cell_w) as f64,
                                (field_rect[1] + j*cell_h) as f64,
                                cell_w as f64,
                                cell_h as f64
                              ],
                              context.transform,
                              graphics);
                }
                if self.marked(ind) {
                    rectangle([0.0, 1.0, 0.0, 0.75],
                              [
                                (field_rect[0] + i*cell_w) as f64,
                                (field_rect[1] + j*cell_h) as f64,
                                cell_w as f64,
                                cell_h as f64
                              ],
                              context.transform,
                              graphics);
                }
            }
        }
        rectangle([0.5, 0.5, 0.5, 0.75],
                  [
                    (field_rect[0] + self.selected_x*cell_w) as f64,
                    (field_rect[1] + self.selected_y*cell_h) as f64,
                    cell_w as f64,
                    cell_h as f64
                  ],
                  context.transform,
                  graphics);
        for i in 0..self.get_width() + 1 {
            line::Line::new([0.5, 0.5, 0.5, 1.0], 1.0)
                .draw([
                        (field_rect[0] + i*cell_w) as f64,
                        field_rect[1] as f64,
                        (field_rect[0] + i*cell_w) as f64,
                        (field_rect[1] + field_rect[3]) as f64
                      ],
                      &context.draw_state,
                      context.transform,
                      graphics);
        }
        for i in 0..self.get_height() + 1 {
            line::Line::new([0.5, 0.5, 0.5, 1.0], 1.0)
                .draw([
                        field_rect[0] as f64,
                        (field_rect[1] + i*cell_h) as f64,
                        (field_rect[0] + field_rect[2]) as f64,
                        (field_rect[1] + i*cell_h) as f64
                      ],
                      &context.draw_state,
                      context.transform,
                      graphics);
        }
    }

    pub fn move_selection(&mut self, dest: MoveDestination) {
        match dest {
            MoveDestination::Up => {
                if self.selected_y > 0 {
                    self.selected_y -= 1;
                }
            },
            MoveDestination::Down => {
                if self.selected_y < self.height - 1 {
                    self.selected_y += 1;
                }
            },
            MoveDestination::Left => {
                if self.selected_x > 0 {
                    self.selected_x -= 1;
                }
            },
            MoveDestination::Right => {
                if self.selected_x < self.width - 1 {
                    self.selected_x += 1;
                }
            }
        }
    }

    pub fn get_selected_ind(&self) -> u32 {
        self.selected_x + self.selected_y*self.width
    }

    pub fn is_victory(&self) -> bool {
        self.nubmers_total == self.nubmers_opened
    }

    pub fn reinit_field(&mut self, num: u32, param: ParamType) {
        let mut restart_neded = false;
        match param {
            ParamType::Height => {
                if self.height != num {
                    self.height = num;
                    self.reinit_vec();
                    restart_neded = true;
                }
            }
            ParamType::Width => {
                if self.width != num {
                    self.width = num;
                    self.reinit_vec();
                    restart_neded = true;
                }
            }
            ParamType::Mines => {
                if self.mines != num {
                    self.mines = num;
                    restart_neded = true;
                }
            }
        }
        if restart_neded {
            self.restart();
        }
    }

    pub fn toggle_mark(&mut self, i: u32) {
        self.get_cell_mut(i).toggle_mark();
    }
}
<|endoftext|>


<commit_before>use proc_macro2::{Delimiter, Span};

use error::Result;
use parse::ParseBuffer;
use token;

pub struct Parens<'a> {
    pub token: token::Paren,
    pub content: ParseBuffer<'a>,
}

pub struct Braces<'a> {
    pub token: token::Brace,
    pub content: ParseBuffer<'a>,
}

pub struct Brackets<'a> {
    pub token: token::Bracket,
    pub content: ParseBuffer<'a>,
}

impl<'a> ParseBuffer<'a> {
    fn parse_group(&self, delimiter: Delimiter) -> Result<(Span, ParseBuffer<'a>)> {
        self.step_cursor(|cursor| {
            if let Some((content, span, rest)) = cursor.group(delimiter) {
                let content =
                    ParseBuffer::new(span, cursor.advance(content), self.get_unexpected());
                Ok(((span, content), rest))
            } else {
                let message = match delimiter {
                    Delimiter::Parenthesis => "expected parentheses",
                    Delimiter::Brace => "expected curly braces",
                    Delimiter::Bracket => "expected square brackets",
                    Delimiter::None => unreachable!(),
                };
                Err(cursor.error(message))
            }
        })
    }

    // Not public API.
    #[doc(hidden)]
    pub fn parse_parens(&self) -> Result<Parens<'a>> {
        self.parse_group(Delimiter::Parenthesis)
            .map(|(span, content)| Parens {
                token: token::Paren(span),
                content: content,
            })
    }

    // Not public API.
    #[doc(hidden)]
    pub fn parse_braces(&self) -> Result<Braces<'a>> {
        self.parse_group(Delimiter::Brace)
            .map(|(span, content)| Braces {
                token: token::Brace(span),
                content: content,
            })
    }

    // Not public API.
    #[doc(hidden)]
    pub fn parse_brackets(&self) -> Result<Brackets<'a>> {
        self.parse_group(Delimiter::Bracket)
            .map(|(span, content)| Brackets {
                token: token::Bracket(span),
                content: content,
            })
    }
}

/// Parse a set of parentheses and expose their content to subsequent parsers.
#[macro_export]
macro_rules! parenthesized {
    ($content:ident in $cursor:expr) => {
        match $crate::parse::ParseBuffer::parse_parens(&$cursor) {
            $crate::export::Ok(parens) => {
                $content = parens.content;
                parens.token
            }
            $crate::export::Err(error) => {
                return $crate::export::Err(error);
            }
        }
    };
}

/// Parse a set of curly braces and expose their content to subsequent parsers.
///
/// ```rust
/// # extern crate syn;
/// #
/// use syn::{braced, token, Ident, Token};
/// use syn::parse::{Parse, ParseStream, Result};
/// #
/// # mod example {
/// #     use super::{syn, braced, token, Ident, Parse, ParseStream, Result};
/// #
/// #     macro_rules! Token {
/// #         (struct) => {
/// #             syn::token::Struct
/// #         };
/// #     }
/// #
/// #     type Field = Ident;
///
/// // Parse a simplified struct syntax like:
/// //
/// //     struct S {
/// //         a: A,
/// //         b: B,
/// //     }
/// struct Struct {
///     pub struct_token: Token![struct],
///     pub ident: Ident,
///     pub brace_token: token::Brace,
///     pub fields: Vec<Field>,
/// }
///
/// impl Parse for Struct {
///     fn parse(input: ParseStream) -> Result<Self> {
///         let content;
///         Ok(Struct {
///             struct_token: input.parse()?,
///             ident: input.parse()?,
///             brace_token: braced!(content in input),
///             fields: content.parse()?,
///         })
///     }
/// }
/// # }
/// #
/// # fn main() {}
/// ```
#[macro_export]
macro_rules! braced {
    ($content:ident in $cursor:expr) => {
        match $crate::parse::ParseBuffer::parse_braces(&$cursor) {
            $crate::export::Ok(braces) => {
                $content = braces.content;
                braces.token
            }
            $crate::export::Err(error) => {
                return $crate::export::Err(error);
            }
        }
    };
}

/// Parse a set of square brackets and expose their content to subsequent
/// parsers.
#[macro_export]
macro_rules! bracketed {
    ($content:ident in $cursor:expr) => {
        match $crate::parse::ParseBuffer::parse_brackets(&$cursor) {
            $crate::export::Ok(brackets) => {
                $content = brackets.content;
                brackets.token
            }
            $crate::export::Err(error) => {
                return $crate::export::Err(error);
            }
        }
    };
}
<commit_msg>Update doc test on braced parser<commit_after>use proc_macro2::{Delimiter, Span};

use error::Result;
use parse::ParseBuffer;
use token;

pub struct Parens<'a> {
    pub token: token::Paren,
    pub content: ParseBuffer<'a>,
}

pub struct Braces<'a> {
    pub token: token::Brace,
    pub content: ParseBuffer<'a>,
}

pub struct Brackets<'a> {
    pub token: token::Bracket,
    pub content: ParseBuffer<'a>,
}

impl<'a> ParseBuffer<'a> {
    fn parse_group(&self, delimiter: Delimiter) -> Result<(Span, ParseBuffer<'a>)> {
        self.step_cursor(|cursor| {
            if let Some((content, span, rest)) = cursor.group(delimiter) {
                let content =
                    ParseBuffer::new(span, cursor.advance(content), self.get_unexpected());
                Ok(((span, content), rest))
            } else {
                let message = match delimiter {
                    Delimiter::Parenthesis => "expected parentheses",
                    Delimiter::Brace => "expected curly braces",
                    Delimiter::Bracket => "expected square brackets",
                    Delimiter::None => unreachable!(),
                };
                Err(cursor.error(message))
            }
        })
    }

    // Not public API.
    #[doc(hidden)]
    pub fn parse_parens(&self) -> Result<Parens<'a>> {
        self.parse_group(Delimiter::Parenthesis)
            .map(|(span, content)| Parens {
                token: token::Paren(span),
                content: content,
            })
    }

    // Not public API.
    #[doc(hidden)]
    pub fn parse_braces(&self) -> Result<Braces<'a>> {
        self.parse_group(Delimiter::Brace)
            .map(|(span, content)| Braces {
                token: token::Brace(span),
                content: content,
            })
    }

    // Not public API.
    #[doc(hidden)]
    pub fn parse_brackets(&self) -> Result<Brackets<'a>> {
        self.parse_group(Delimiter::Bracket)
            .map(|(span, content)| Brackets {
                token: token::Bracket(span),
                content: content,
            })
    }
}

/// Parse a set of parentheses and expose their content to subsequent parsers.
#[macro_export]
macro_rules! parenthesized {
    ($content:ident in $cursor:expr) => {
        match $crate::parse::ParseBuffer::parse_parens(&$cursor) {
            $crate::export::Ok(parens) => {
                $content = parens.content;
                parens.token
            }
            $crate::export::Err(error) => {
                return $crate::export::Err(error);
            }
        }
    };
}

/// Parse a set of curly braces and expose their content to subsequent parsers.
///
/// ```rust
/// # extern crate syn;
/// #
/// use syn::{braced, token, Ident, Token};
/// use syn::parse::{Parse, ParseStream, Result};
/// use syn::punctuated::Punctuated;
/// #
/// # type Field = Ident;
///
/// // Parse a simplified struct syntax like:
/// //
/// //     struct S {
/// //         a: A,
/// //         b: B,
/// //     }
/// struct Struct {
///     pub struct_token: Token![struct],
///     pub ident: Ident,
///     pub brace_token: token::Brace,
///     pub fields: Punctuated<Field, Token![,]>,
/// }
///
/// impl Parse for Struct {
///     fn parse(input: ParseStream) -> Result<Self> {
///         let content;
///         Ok(Struct {
///             struct_token: input.parse()?,
///             ident: input.parse()?,
///             brace_token: braced!(content in input),
///             fields: content.parse_terminated(Field::parse)?,
///         })
///     }
/// }
/// ```
#[macro_export]
macro_rules! braced {
    ($content:ident in $cursor:expr) => {
        match $crate::parse::ParseBuffer::parse_braces(&$cursor) {
            $crate::export::Ok(braces) => {
                $content = braces.content;
                braces.token
            }
            $crate::export::Err(error) => {
                return $crate::export::Err(error);
            }
        }
    };
}

/// Parse a set of square brackets and expose their content to subsequent
/// parsers.
#[macro_export]
macro_rules! bracketed {
    ($content:ident in $cursor:expr) => {
        match $crate::parse::ParseBuffer::parse_brackets(&$cursor) {
            $crate::export::Ok(brackets) => {
                $content = brackets.content;
                brackets.token
            }
            $crate::export::Err(error) => {
                return $crate::export::Err(error);
            }
        }
    };
}
<|endoftext|>


<commit_before>//! # Command Parser
//!
//! The `commands::parser` module provides:
//!
//! * Functionality for building a tree of commands based on their names.
//! * Parsing tokenized input to select a command. Input tokenization can
//!   be performed by the `commands::tokenizer` module.
//! * Validating parameters.
//! * Performing completion on commands and parameters.
//!
//! The parser is still a work in progress but is rapidly advancing.

pub mod nodes;
pub mod completion;

use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::rc::Rc;
use parser::nodes::*;
use tokenizer::{Token, TokenType};
use parser::completion::{Complete, Completion};

/// Command parser
///
/// The lifetime parameter `'p` refers to the lifetime of the
/// parser itself, the root node of the command tree that was
/// used to create this parser, as well as the tokens passed
/// into the parser.
pub struct Parser<'p> {
    current_node: Rc<Node>,
    /// The nodes which have been accepted during `parse` or `advance`.
    pub nodes: Vec<Rc<Node>>,
    /// The tokens which have been accepted during `parse` or `advance`.
    pub tokens: Vec<Token<'p>>,
    commands: Vec<Rc<CommandNode>>,
    parameters: HashMap<String, String>,
}

impl<'p> Parser<'p> {
    /// Construct a parser with a root node.
    pub fn new(initial_node: Rc<Node>) -> Parser<'p> {
        Parser {
            current_node: initial_node,
            nodes: vec![],
            tokens: vec![],
            commands: vec![],
            parameters: HashMap::new(),
        }
    }

    /// Given an optional token, get the possible valid completions
    /// for the current parser state.
    pub fn complete(&self, token: Option<Token<'p>>) -> Vec<Completion> {
        self.current_node
            .successors()
            .into_iter()
            .filter(|n| {
                // To be a possible completion, the node should not be
                // hidden, it should be acceptable, and if there's a token,
                // it should be a valid match for the node.
                !n.hidden() && n.acceptable(self) &&
                if let Some(t) = token {
                    n.matches(self, t)
                } else {
                    true
                }
            })
            .map(|n| n.complete(token))
            .collect::<Vec<_>>()
    }

    /// Parse a vector of tokens, advancing through the
    /// node hierarchy.
    pub fn parse(&mut self, tokens: Vec<Token<'p>>) -> Result<(), ParserError<'p>> {
        for token in tokens {
            match token.token_type {
                TokenType::Invalid => unreachable!(),
                TokenType::Whitespace => {}
                TokenType::Word => try!(self.advance(token)),
            }
        }
        Ok(())
    }

    /// Parse a single token, advancing through the node hierarchy.
    pub fn advance(&mut self, token: Token<'p>) -> Result<(), ParserError<'p>> {
        // We clone the current node so that it doesn't stay borrowed
        // and break things when we try to modify it below.
        let cn = self.current_node.clone();
        let matches = cn.successors()
                        .into_iter()
                        .filter(|n| n.acceptable(self) && n.matches(self, token))
                        .collect::<Vec<_>>();
        match matches.len() {
            1 => {
                let matching_node = matches[0];
                matching_node.accept(self, token);
                self.current_node = matching_node.clone();
                self.nodes.push(matching_node.clone());
                self.tokens.push(token);
                Ok(())
            }
            0 => Err(ParserError::NoMatches(token)),
            _ => Err(ParserError::AmbiguousMatch(token)),
        }
    }

    /// Execute the command that has been accepted by the parser.
    ///
    /// * XXX: This should be returning a Result probably.
    pub fn execute(&self) {
        if !self.commands.is_empty() {
            unimplemented!();
            // self.commands[0].execute(self)
        }
    }

    /// Verify that the parser is in a valid state with
    /// respect to having accepted a command and all
    /// required parameters.
    ///
    /// * XXX: This should be returning Option or Result
    ///        with an enum for the various error conditions.
    pub fn verify(&self) -> bool {
        if self.commands.is_empty() {
            // XXX: We'll want an enum error here with a Result.
            return false;
        } else {
            for expected in self.commands[0].parameters() {
                if expected.required() && !self.parameters.contains_key(expected.name()) {
                    return false;
                }
            }
        }
        true
    }
}

/// Errors that the `Parser` can raise.
#[derive(Clone,Debug)]
pub enum ParserError<'t> {
    /// The parser is in an invalid state.
    InvalidState,
    /// There were no matches for the token.
    NoMatches(Token<'t>),
    /// There was more than 1 possible match for the token.
    AmbiguousMatch(Token<'t>), // XXX: One day, add: Vec<&'p Rc<Node>>),
}

impl<'t> Error for ParserError<'t> {
    fn description(&self) -> &str {
        match *self {
            ParserError::InvalidState => "Invalid state.",
            ParserError::NoMatches(_) => "No match.",
            ParserError::AmbiguousMatch(_) => "Ambiguous match.",
        }
    }
}

impl<'t> fmt::Display for ParserError<'t> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.description().fmt(f)
    }
}

trait Acceptable {
    fn acceptable(&self, parser: &Parser) -> bool;
}

impl Acceptable for Rc<Node> {
    fn acceptable(&self, parser: &Parser) -> bool {
        !parser.nodes.contains(self)
    }
}

impl Acceptable for RepeatableNode {
    fn acceptable(&self, _parser: &Parser) -> bool {
        if self.repeatable() {
            return true;
        }
        unimplemented!()
        // This should check nodes.contains, but then go on to check
        // for a repeat marker and whether or not that's been seen.
    }
}

trait Matches {
    fn matches(&self, parser: &Parser, token: Token) -> bool;
}

impl Matches for Node {
    fn matches(&self, _parser: &Parser, token: Token) -> bool {
        self.name().starts_with(token.text)
    }
}

trait Accept {
    fn accept<'p>(&self, parser: &mut Parser<'p>, token: Token);
}

impl Accept for Node {
    fn accept<'p>(&self, _parser: &mut Parser<'p>, _token: Token) {}
}

impl Accept for Rc<CommandNode> {
    fn accept<'p>(&self, parser: &mut Parser<'p>, _token: Token) {
        if let Some(_) = self.handler() {
            parser.commands.push(self.clone())
        }
    }
}

impl Accept for Rc<ParameterNode> {
    fn accept<'p>(&self, parser: &mut Parser<'p>, token: Token) {
        if self.repeatable() {
            unimplemented!();
        } else {
            parser.parameters.insert(self.name().clone(), token.text.to_string());
        }
    }
}
<commit_msg>Add better Parser::complete comment.<commit_after>//! # Command Parser
//!
//! The `commands::parser` module provides:
//!
//! * Functionality for building a tree of commands based on their names.
//! * Parsing tokenized input to select a command. Input tokenization can
//!   be performed by the `commands::tokenizer` module.
//! * Validating parameters.
//! * Performing completion on commands and parameters.
//!
//! The parser is still a work in progress but is rapidly advancing.

pub mod nodes;
pub mod completion;

use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::rc::Rc;
use parser::nodes::*;
use tokenizer::{Token, TokenType};
use parser::completion::{Complete, Completion};

/// Command parser
///
/// The lifetime parameter `'p` refers to the lifetime of the
/// parser itself, the root node of the command tree that was
/// used to create this parser, as well as the tokens passed
/// into the parser.
pub struct Parser<'p> {
    current_node: Rc<Node>,
    /// The nodes which have been accepted during `parse` or `advance`.
    pub nodes: Vec<Rc<Node>>,
    /// The tokens which have been accepted during `parse` or `advance`.
    pub tokens: Vec<Token<'p>>,
    commands: Vec<Rc<CommandNode>>,
    parameters: HashMap<String, String>,
}

impl<'p> Parser<'p> {
    /// Construct a parser with a root node.
    pub fn new(initial_node: Rc<Node>) -> Parser<'p> {
        Parser {
            current_node: initial_node,
            nodes: vec![],
            tokens: vec![],
            commands: vec![],
            parameters: HashMap::new(),
        }
    }

    /// Given an optional token, get the possible valid completions
    /// for the current parser state.
    ///
    /// Possible completions are successors of the current node which
    /// are not `hidden`, are `acceptable`, and which match the token,
    /// if one has been provided.
    ///
    /// Nodes may customize the `Complete` trait to customize the
    /// `Completion` and `CompletionOption`s which are generated
    /// for that node.
    ///
    /// Each valid successor node will have one `Completion` in the
    /// result vector. Each `Completion` will have one or more
    /// `CompletionOption` for each valid way that the value may be
    /// entered.
    pub fn complete(&self, token: Option<Token<'p>>) -> Vec<Completion> {
        self.current_node
            .successors()
            .into_iter()
            .filter(|n| {
                // To be a possible completion, the node should not be
                // hidden, it should be acceptable, and if there's a token,
                // it should be a valid match for the node.
                !n.hidden() && n.acceptable(self) &&
                if let Some(t) = token {
                    n.matches(self, t)
                } else {
                    true
                }
            })
            .map(|n| n.complete(token))
            .collect::<Vec<_>>()
    }

    /// Parse a vector of tokens, advancing through the
    /// node hierarchy.
    pub fn parse(&mut self, tokens: Vec<Token<'p>>) -> Result<(), ParserError<'p>> {
        for token in tokens {
            match token.token_type {
                TokenType::Invalid => unreachable!(),
                TokenType::Whitespace => {}
                TokenType::Word => try!(self.advance(token)),
            }
        }
        Ok(())
    }

    /// Parse a single token, advancing through the node hierarchy.
    pub fn advance(&mut self, token: Token<'p>) -> Result<(), ParserError<'p>> {
        // We clone the current node so that it doesn't stay borrowed
        // and break things when we try to modify it below.
        let cn = self.current_node.clone();
        let matches = cn.successors()
                        .into_iter()
                        .filter(|n| n.acceptable(self) && n.matches(self, token))
                        .collect::<Vec<_>>();
        match matches.len() {
            1 => {
                let matching_node = matches[0];
                matching_node.accept(self, token);
                self.current_node = matching_node.clone();
                self.nodes.push(matching_node.clone());
                self.tokens.push(token);
                Ok(())
            }
            0 => Err(ParserError::NoMatches(token)),
            _ => Err(ParserError::AmbiguousMatch(token)),
        }
    }

    /// Execute the command that has been accepted by the parser.
    ///
    /// * XXX: This should be returning a Result probably.
    pub fn execute(&self) {
        if !self.commands.is_empty() {
            unimplemented!();
            // self.commands[0].execute(self)
        }
    }

    /// Verify that the parser is in a valid state with
    /// respect to having accepted a command and all
    /// required parameters.
    ///
    /// * XXX: This should be returning Option or Result
    ///        with an enum for the various error conditions.
    pub fn verify(&self) -> bool {
        if self.commands.is_empty() {
            // XXX: We'll want an enum error here with a Result.
            return false;
        } else {
            for expected in self.commands[0].parameters() {
                if expected.required() && !self.parameters.contains_key(expected.name()) {
                    return false;
                }
            }
        }
        true
    }
}

/// Errors that the `Parser` can raise.
#[derive(Clone,Debug)]
pub enum ParserError<'t> {
    /// The parser is in an invalid state.
    InvalidState,
    /// There were no matches for the token.
    NoMatches(Token<'t>),
    /// There was more than 1 possible match for the token.
    AmbiguousMatch(Token<'t>), // XXX: One day, add: Vec<&'p Rc<Node>>),
}

impl<'t> Error for ParserError<'t> {
    fn description(&self) -> &str {
        match *self {
            ParserError::InvalidState => "Invalid state.",
            ParserError::NoMatches(_) => "No match.",
            ParserError::AmbiguousMatch(_) => "Ambiguous match.",
        }
    }
}

impl<'t> fmt::Display for ParserError<'t> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.description().fmt(f)
    }
}

trait Acceptable {
    fn acceptable(&self, parser: &Parser) -> bool;
}

impl Acceptable for Rc<Node> {
    fn acceptable(&self, parser: &Parser) -> bool {
        !parser.nodes.contains(self)
    }
}

impl Acceptable for RepeatableNode {
    fn acceptable(&self, _parser: &Parser) -> bool {
        if self.repeatable() {
            return true;
        }
        unimplemented!()
        // This should check nodes.contains, but then go on to check
        // for a repeat marker and whether or not that's been seen.
    }
}

trait Matches {
    fn matches(&self, parser: &Parser, token: Token) -> bool;
}

impl Matches for Node {
    fn matches(&self, _parser: &Parser, token: Token) -> bool {
        self.name().starts_with(token.text)
    }
}

trait Accept {
    fn accept<'p>(&self, parser: &mut Parser<'p>, token: Token);
}

impl Accept for Node {
    fn accept<'p>(&self, _parser: &mut Parser<'p>, _token: Token) {}
}

impl Accept for Rc<CommandNode> {
    fn accept<'p>(&self, parser: &mut Parser<'p>, _token: Token) {
        if let Some(_) = self.handler() {
            parser.commands.push(self.clone())
        }
    }
}

impl Accept for Rc<ParameterNode> {
    fn accept<'p>(&self, parser: &mut Parser<'p>, token: Token) {
        if self.repeatable() {
            unimplemented!();
        } else {
            parser.parameters.insert(self.name().clone(), token.text.to_string());
        }
    }
}
<|endoftext|>


<commit_before>

// https://github.com/rust-lang/getopts
extern crate getopts;

// https://doc.rust-lang.org/stable/book/ffi.html
extern crate libc;

// Rust/C bindings for:
// krb5_init_context
// krb5_cc_default
// krb5_cc_get_principal
// com_err
#[allow(non_camel_case_types)]
mod krb5;
mod com_err;

use getopts::Options;
use std::env;
use std::ffi::{CStr,CString};
use std::io::{self,Write};
use std::process;
use std::ptr;

// This is a silly amount of work, but I wanted to learn how to
// get the progname into a global variable.
//
// https://github.com/Kimundi/lazy-static.rs
#[macro_use]
extern crate lazy_static;
lazy_static! {
    static ref PROGNAME: String = env::current_exe().unwrap() // PathBuf
        .file_name().unwrap()                                 // &OsStr
        .to_string_lossy().into_owned();                      // Cow<str> -> String
}

fn error(err: getopts::Fail) -> ! {
    let mut stderr = io::stderr();
    writeln!(&mut stderr, "Error: {}", err).unwrap();
    writeln!(&mut stderr, "Try '{} --help' for more information.", *PROGNAME).unwrap();
    process::exit(1);
}

fn usage(opts: &Options) -> ! {
    let brief = opts.short_usage(&*PROGNAME);
    println!("{}", opts.usage(&brief));
    process::exit(0);
}

fn main() {

    let progname = CString::new((*PROGNAME).clone())
        .unwrap()
        .into_raw();

    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { error(f) }
    };

    if matches.opt_present("h") {
        usage(&opts);
    }

    let mut ctx: krb5::krb5_context = ptr::null_mut();
    let mut code: krb5::krb5_error_code = unsafe { krb5::krb5_init_context(&mut ctx) };
    if code != 0 {
        unsafe {
            com_err::com_err(progname,
                             code as i64,
                             CString::new("while initializing krb5").unwrap().into_raw());
        }
        std::process::exit(1);
    }

    let mut cache: krb5::krb5_ccache = ptr::null_mut();
    code = unsafe {krb5::krb5_cc_default(ctx, &mut cache)};
    if code != 0 {
        unsafe {
            com_err::com_err(progname,
                             code as i64,
                             CString::new("while getting default ccache").unwrap().into_raw());
        }
        std::process::exit(1);
    }

    let mut princ: krb5::krb5_principal = ptr::null_mut();
    code = unsafe { krb5::krb5_cc_get_principal(ctx, cache, &mut princ) };
    if code != 0 {
        unsafe {
            com_err::com_err(progname,
                             code as i64,
                             CString::new("while retrieving principal name").unwrap().into_raw());
        }
        std::process::exit(1);
    }

    let len = unsafe{(*princ).length};

    let d = unsafe { CStr::from_ptr((*(*princ).data).data).to_string_lossy() };
    print!("{}", d);

    for i in 1..len {
        let d2 = unsafe { CStr::from_ptr((*(*princ).data.offset(i as isize)).data).to_string_lossy() };
        print!("/{}", d2);
    }
    println!("");

}
<commit_msg>Explore what steps are `unsafe`.<commit_after>

// https://github.com/rust-lang/getopts
extern crate getopts;

// https://doc.rust-lang.org/stable/book/ffi.html
extern crate libc;

// Rust/C bindings for:
// krb5_init_context
// krb5_cc_default
// krb5_cc_get_principal
// com_err
#[allow(non_camel_case_types)]
mod krb5;
mod com_err;

use getopts::Options;
use std::env;
use std::ffi::{CStr,CString};
use std::io::{self,Write};
use std::process;
use std::ptr;

// This is a silly amount of work, but I wanted to learn how to
// get the progname into a global variable.
//
// https://github.com/Kimundi/lazy-static.rs
#[macro_use]
extern crate lazy_static;
lazy_static! {
    static ref PROGNAME: String = env::current_exe().unwrap() // PathBuf
        .file_name().unwrap()                                 // &OsStr
        .to_string_lossy().into_owned();                      // Cow<str> -> String
}

fn error(err: getopts::Fail) -> ! {
    let mut stderr = io::stderr();
    writeln!(&mut stderr, "Error: {}", err).unwrap();
    writeln!(&mut stderr, "Try '{} --help' for more information.", *PROGNAME).unwrap();
    process::exit(1);
}

fn usage(opts: &Options) -> ! {
    let brief = opts.short_usage(&*PROGNAME);
    println!("{}", opts.usage(&brief));
    process::exit(0);
}

fn main() {

    let progname = CString::new((*PROGNAME).clone())
        .unwrap()
        .into_raw();

    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { error(f) }
    };

    if matches.opt_present("h") {
        usage(&opts);
    }

    let mut ctx: krb5::krb5_context = ptr::null_mut();
    let mut code: krb5::krb5_error_code = unsafe { krb5::krb5_init_context(&mut ctx) };
    if code != 0 {
        unsafe {
            com_err::com_err(progname,
                             code as i64,
                             CString::new("while initializing krb5").unwrap().into_raw());
        }
        std::process::exit(1);
    }

    let mut cache: krb5::krb5_ccache = ptr::null_mut();
    code = unsafe {krb5::krb5_cc_default(ctx, &mut cache)};
    if code != 0 {
        unsafe {
            com_err::com_err(progname,
                             code as i64,
                             CString::new("while getting default ccache").unwrap().into_raw());
        }
        std::process::exit(1);
    }

    let mut princ: krb5::krb5_principal = ptr::null_mut();
    code = unsafe { krb5::krb5_cc_get_principal(ctx, cache, &mut princ) };
    if code != 0 {
        unsafe {
            com_err::com_err(progname,
                             code as i64,
                             CString::new("while retrieving principal name").unwrap().into_raw());
        }
        std::process::exit(1);
    }

    let kpd = unsafe{(*princ)};
    let len = kpd.length;

    let d = unsafe { (*kpd.data).data };
    let s = unsafe { CStr::from_ptr(d).to_string_lossy() };
    print!("{}", s);

    for i in 1..len {
        let d = unsafe { (*kpd.data.offset(i as isize)).data };
        let s = unsafe { CStr::from_ptr(d).to_string_lossy() };
        print!("/{}", s);
    }
    println!("");

}
<|endoftext|>