<commit_before>//! FBX binary parser.

use std::fmt;
use std::io;
use std::io::Read;

pub use self::error::{Result, Error, Warning};
pub use self::event::{Event, FbxHeader, FbxFooter, StartNode};
pub use self::event::{Attributes, Attribute};
pub use self::event::{PrimitiveAttribute, ArrayAttribute, SpecialAttribute};
use self::event::{EventBuilder, NodeHeader, StartNodeBuilder};
use self::event::read_fbx_header;
use self::reader::CountReader;

mod error;
mod event;
mod reader;

/// Parser state without error.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum State {
    /// Reading file header.
    Header,
    /// A node started.
    ///
    /// This status means:
    ///
    /// - there might be some attributes remain unread, or
    /// - the most recent opened node might close without no null node header.
    NodeStarted,
    /// A node ended.
    ///
    /// This status means:
    ///
    /// - if the next event is `NodeEnd`, there must be a null node header, and
    /// - if the parser got an extra null header, it indicates end of implicit root node.
    NodeEnded,
}

/// Information about opened (but not yet closed) node.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct OpenNode {
    /// Start offset of the node attribute.
    ///
    /// Note that this doesn't mean start offset of node header.
    begin: u64,
    /// End offset of the node.
    end: u64,
    /// End offset of attributes of the node.
    attributes_end: u64,
}

/// Pull parser for FBX binary format.
// I want to use `#[derive(Debug)]` but it causes compile error for rustc-1.12(stable), 1.13(beta),
// 1.14(nightly).
// See also: #[derive] is too conservative with field trait bounds · Issue #26925 · rust-lang/rust
//           ( https://github.com/rust-lang/rust/issues/26925 ).
pub struct BinaryParser<R> {
    /// Source reader.
    source: CountReader<R>,
    /// Parser state.
    ///
    /// `Ok(State)` if the parser is working without critical error,
    /// `Err(Error)` if the parsing failed and cannot be continued.
    state: Result<State>,
    /// Warnings.
    warnings: Vec<Warning>,
    /// FBX version.
    fbx_version: Option<u32>,
    /// Open nodes stack.
    open_nodes: Vec<OpenNode>,
}

impl<R: Read> BinaryParser<R> {
    /// Creates a new binary parser.
    pub fn new(source: R) -> Self {
        BinaryParser {
            source: CountReader::new(source),
            state: Ok(State::Header),
            warnings: Vec::new(),
            fbx_version: None,
            open_nodes: Vec::new(),
        }
    }

    /// Returns FBX version of the reading input.
    ///
    /// Returns `None` if unknown yet.
    pub fn fbx_version(&self) -> Option<u32> {
        self.fbx_version
    }

    /// Returns the parser error if available.
    pub fn error(&self) -> Option<&Error> {
        self.state.as_ref().err()
    }

    /// Returns reference to the warnings.
    pub fn warnings(&self) -> &Vec<Warning> {
        &self.warnings
    }

    /// Parses FBX from the given stream and returns the next event.
    pub fn next_event(&mut self) -> Result<Event<R>> {
        let builder = match try!(self.state.clone()) {
            State::Header => self.read_fbx_header(),
            State::NodeStarted => self.read_after_node_start(),
            State::NodeEnded => self.read_after_node_end(),
        };
        if let Err(ref err) = builder {
            self.set_error(err);
        }
        Ok(try!(builder).build(self))
    }

    /// Set the parser state as finished parsing.
    fn set_finish(&mut self) {
        self.state = Err(Error::Finished);
    }

    /// Set the parser state as error.
    fn set_error(&mut self, err: &Error) {
        error!("FBX binary parser error: {}", err);
        debug!("Parser: {:#?}", self);
        self.state = Err(err.clone());
    }

    /// Add warning.
    fn warn(&mut self, warning: Warning) {
        warn!("FBX binary parser warning: {}", warning);
        debug!("Parser: {:#?}", self);
        self.warnings.push(warning);
    }

    /// Reads FBX header.
    fn read_fbx_header(&mut self) -> Result<EventBuilder> {
        let header = try!(read_fbx_header(self));
        self.fbx_version = Some(header.version);
        self.state = Ok(State::NodeEnded);
        Ok(header.into())
    }

    /// Gets event after node start.
    fn read_after_node_start(&mut self) -> Result<EventBuilder> {
        // Attributes of recent opened node might remain partially unread.
        // They should be skipped before getting a next node event.
        try!(self.skip_attributes());

        // Most recent opened node might ends here without a null node header.
        if let Some(end) = self.open_nodes.last().map(|v| v.end) {
            if self.source.count() == end {
                // Most recent opened node ends here (without a null node header).
                self.state = Ok(State::NodeEnded);
                self.open_nodes.pop();
                return Ok(EventBuilder::EndNode);
            }
        }

        let builder = try!(self.read_node_event());
        Ok(builder)
    }

    /// Gets event after node end.
    fn read_after_node_end(&mut self) -> Result<EventBuilder> {
        self.read_node_event()
    }

    /// Reads a next node-related event from the source.
    ///
    /// This always returns `Ok(EventBuilder::StartNode)`, `Ok(EventBuilder::EndNode)`,
    /// `Ok(EventBuilder::EndFbx)` or `Err(_)`.
    fn read_node_event(&mut self) -> Result<EventBuilder> {
        let header = try!(NodeHeader::read_from_parser(self));
        if header.is_node_end() {
            if let Some(last_node) = self.open_nodes.pop() {
                // There is open nodes, so this is not end of the FBX.
                let current_pos = self.source.count();
                if current_pos != last_node.end {
                    // Invalid node header.
                    return Err(Error::WrongNodeEndOffset {
                        begin: last_node.begin,
                        expected_end: last_node.end,
                        real_end: current_pos,
                    });
                }
            } else {
                assert_eq!(self.state.as_ref().ok(),
                           Some(&State::NodeEnded),
                           "End of implicit root node is read with unexpected parser state {:?}",
                           self.state);
                // No open nodes, so this `EndNode` event indicates the end of
                // the implicit root node.
                // FBX file has no more nodes.
                let footer = try!(self.read_fbx_footer());
                return Ok(footer.into());
            }

            self.state = Ok(State::NodeEnded);
            Ok(EventBuilder::EndNode)
        } else {
            let mut name_vec = vec![0u8; header.len_name as usize];
            try!(self.source.read_exact(&mut name_vec));
            let name = try!(String::from_utf8(name_vec).map_err(Error::node_name_invalid_utf8));
            let current_pos = self.source.count();
            self.open_nodes.push(OpenNode {
                begin: current_pos,
                end: header.end_offset,
                attributes_end: current_pos + header.len_attributes,
            });

            // Zero or more attributes come after node start.
            self.state = Ok(State::NodeStarted);
            Ok(StartNodeBuilder {
                name: name,
                header: header,
            }
            .into())
        }
    }

    /// Reads an FBX footer.
    fn read_fbx_footer(&mut self) -> Result<FbxFooter> {
        let footer = try!(FbxFooter::read_from_parser(self));
        self.set_finish();
        Ok(footer)
    }

    /// Skip attributes of the most recent opened node.
    fn skip_attributes(&mut self) -> io::Result<()> {
        let attributes_end = self.open_nodes
            .last()
            .expect("`BinaryParser::skip_attributes()` is called but no nodes are open")
            .attributes_end;
        self.source.skip_to(attributes_end)
    }
}

impl<R> fmt::Debug for BinaryParser<R> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("BinaryParser")
            .field("source", &self.source)
            .field("state", &self.state)
            .field("warnings", &self.warnings)
            .field("fbx_version", &self.fbx_version)
            .field("open_nodes", &self.open_nodes)
            .finish()
    }
}
<commit_msg>Make `CountReader` public<commit_after>//! FBX binary parser.

use std::fmt;
use std::io;
use std::io::Read;

pub use self::error::{Result, Error, Warning};
pub use self::event::{Event, FbxHeader, FbxFooter, StartNode};
pub use self::event::{Attributes, Attribute};
pub use self::event::{PrimitiveAttribute, ArrayAttribute, SpecialAttribute};
use self::event::{EventBuilder, NodeHeader, StartNodeBuilder};
use self::event::read_fbx_header;
pub use self::reader::CountReader;

mod error;
mod event;
mod reader;

/// Parser state without error.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum State {
    /// Reading file header.
    Header,
    /// A node started.
    ///
    /// This status means:
    ///
    /// - there might be some attributes remain unread, or
    /// - the most recent opened node might close without no null node header.
    NodeStarted,
    /// A node ended.
    ///
    /// This status means:
    ///
    /// - if the next event is `NodeEnd`, there must be a null node header, and
    /// - if the parser got an extra null header, it indicates end of implicit root node.
    NodeEnded,
}

/// Information about opened (but not yet closed) node.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct OpenNode {
    /// Start offset of the node attribute.
    ///
    /// Note that this doesn't mean start offset of node header.
    begin: u64,
    /// End offset of the node.
    end: u64,
    /// End offset of attributes of the node.
    attributes_end: u64,
}

/// Pull parser for FBX binary format.
// I want to use `#[derive(Debug)]` but it causes compile error for rustc-1.12(stable), 1.13(beta),
// 1.14(nightly).
// See also: #[derive] is too conservative with field trait bounds · Issue #26925 · rust-lang/rust
//           ( https://github.com/rust-lang/rust/issues/26925 ).
pub struct BinaryParser<R> {
    /// Source reader.
    source: CountReader<R>,
    /// Parser state.
    ///
    /// `Ok(State)` if the parser is working without critical error,
    /// `Err(Error)` if the parsing failed and cannot be continued.
    state: Result<State>,
    /// Warnings.
    warnings: Vec<Warning>,
    /// FBX version.
    fbx_version: Option<u32>,
    /// Open nodes stack.
    open_nodes: Vec<OpenNode>,
}

impl<R: Read> BinaryParser<R> {
    /// Creates a new binary parser.
    pub fn new(source: R) -> Self {
        BinaryParser {
            source: CountReader::new(source),
            state: Ok(State::Header),
            warnings: Vec::new(),
            fbx_version: None,
            open_nodes: Vec::new(),
        }
    }

    /// Returns FBX version of the reading input.
    ///
    /// Returns `None` if unknown yet.
    pub fn fbx_version(&self) -> Option<u32> {
        self.fbx_version
    }

    /// Returns the parser error if available.
    pub fn error(&self) -> Option<&Error> {
        self.state.as_ref().err()
    }

    /// Returns reference to the warnings.
    pub fn warnings(&self) -> &Vec<Warning> {
        &self.warnings
    }

    /// Parses FBX from the given stream and returns the next event.
    pub fn next_event(&mut self) -> Result<Event<R>> {
        let builder = match try!(self.state.clone()) {
            State::Header => self.read_fbx_header(),
            State::NodeStarted => self.read_after_node_start(),
            State::NodeEnded => self.read_after_node_end(),
        };
        if let Err(ref err) = builder {
            self.set_error(err);
        }
        Ok(try!(builder).build(self))
    }

    /// Set the parser state as finished parsing.
    fn set_finish(&mut self) {
        self.state = Err(Error::Finished);
    }

    /// Set the parser state as error.
    fn set_error(&mut self, err: &Error) {
        error!("FBX binary parser error: {}", err);
        debug!("Parser: {:#?}", self);
        self.state = Err(err.clone());
    }

    /// Add warning.
    fn warn(&mut self, warning: Warning) {
        warn!("FBX binary parser warning: {}", warning);
        debug!("Parser: {:#?}", self);
        self.warnings.push(warning);
    }

    /// Reads FBX header.
    fn read_fbx_header(&mut self) -> Result<EventBuilder> {
        let header = try!(read_fbx_header(self));
        self.fbx_version = Some(header.version);
        self.state = Ok(State::NodeEnded);
        Ok(header.into())
    }

    /// Gets event after node start.
    fn read_after_node_start(&mut self) -> Result<EventBuilder> {
        // Attributes of recent opened node might remain partially unread.
        // They should be skipped before getting a next node event.
        try!(self.skip_attributes());

        // Most recent opened node might ends here without a null node header.
        if let Some(end) = self.open_nodes.last().map(|v| v.end) {
            if self.source.count() == end {
                // Most recent opened node ends here (without a null node header).
                self.state = Ok(State::NodeEnded);
                self.open_nodes.pop();
                return Ok(EventBuilder::EndNode);
            }
        }

        let builder = try!(self.read_node_event());
        Ok(builder)
    }

    /// Gets event after node end.
    fn read_after_node_end(&mut self) -> Result<EventBuilder> {
        self.read_node_event()
    }

    /// Reads a next node-related event from the source.
    ///
    /// This always returns `Ok(EventBuilder::StartNode)`, `Ok(EventBuilder::EndNode)`,
    /// `Ok(EventBuilder::EndFbx)` or `Err(_)`.
    fn read_node_event(&mut self) -> Result<EventBuilder> {
        let header = try!(NodeHeader::read_from_parser(self));
        if header.is_node_end() {
            if let Some(last_node) = self.open_nodes.pop() {
                // There is open nodes, so this is not end of the FBX.
                let current_pos = self.source.count();
                if current_pos != last_node.end {
                    // Invalid node header.
                    return Err(Error::WrongNodeEndOffset {
                        begin: last_node.begin,
                        expected_end: last_node.end,
                        real_end: current_pos,
                    });
                }
            } else {
                assert_eq!(self.state.as_ref().ok(),
                           Some(&State::NodeEnded),
                           "End of implicit root node is read with unexpected parser state {:?}",
                           self.state);
                // No open nodes, so this `EndNode` event indicates the end of
                // the implicit root node.
                // FBX file has no more nodes.
                let footer = try!(self.read_fbx_footer());
                return Ok(footer.into());
            }

            self.state = Ok(State::NodeEnded);
            Ok(EventBuilder::EndNode)
        } else {
            let mut name_vec = vec![0u8; header.len_name as usize];
            try!(self.source.read_exact(&mut name_vec));
            let name = try!(String::from_utf8(name_vec).map_err(Error::node_name_invalid_utf8));
            let current_pos = self.source.count();
            self.open_nodes.push(OpenNode {
                begin: current_pos,
                end: header.end_offset,
                attributes_end: current_pos + header.len_attributes,
            });

            // Zero or more attributes come after node start.
            self.state = Ok(State::NodeStarted);
            Ok(StartNodeBuilder {
                name: name,
                header: header,
            }
            .into())
        }
    }

    /// Reads an FBX footer.
    fn read_fbx_footer(&mut self) -> Result<FbxFooter> {
        let footer = try!(FbxFooter::read_from_parser(self));
        self.set_finish();
        Ok(footer)
    }

    /// Skip attributes of the most recent opened node.
    fn skip_attributes(&mut self) -> io::Result<()> {
        let attributes_end = self.open_nodes
            .last()
            .expect("`BinaryParser::skip_attributes()` is called but no nodes are open")
            .attributes_end;
        self.source.skip_to(attributes_end)
    }
}

impl<R> fmt::Debug for BinaryParser<R> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("BinaryParser")
            .field("source", &self.source)
            .field("state", &self.state)
            .field("warnings", &self.warnings)
            .field("fbx_version", &self.fbx_version)
            .field("open_nodes", &self.open_nodes)
            .finish()
    }
}
<|endoftext|>


<commit_before>// Such imports are used to allow for the expr_literal macro to work
use parser::number::numeric_literal;
use parser::identifier::identifier_literal;
use ast::Expression;

// Temp do bad stuff
named!(pub expr_literal<Expression>,
    alt!(numeric_literal | identifier_literal)
);<commit_msg>Add expression parser<commit_after>// Such imports are used to allow for the expr_literal macro to work
use parser::number::numeric_literal;
use parser::identifier::identifier_literal;
use ast::Expression;

// Temp do bad stuff
named!(pub expression_literal<Expression>,
    alt!(numeric_literal | identifier_literal)
);<|endoftext|>


<commit_before>//! Generic WebSocket protocol implementation

mod frame;
mod message;

pub use self::message::Message;

use std::collections::VecDeque;
use std::io::{Read, Write};
use std::mem::replace;

use error::{Error, Result};
use self::message::{IncompleteMessage, IncompleteMessageType};
use self::frame::{Frame, FrameSocket};
use self::frame::coding::{OpCode, Data as OpData, Control as OpCtl, CloseCode};
use util::NonBlockingResult;

/// Indicates a Client or Server role of the websocket
#[derive(Debug, Clone, Copy)]
pub enum Role {
    /// This socket is a server
    Server,
    /// This socket is a client
    Client,
}

/// WebSocket input-output stream
pub struct WebSocket<Stream> {
    /// Server or client?
    role: Role,
    /// The underlying socket.
    socket: FrameSocket<Stream>,
    /// The state of processing, either "active" or "closing".
    state: WebSocketState,
    /// Receive: an incomplete message being processed.
    incomplete: Option<IncompleteMessage>,
    /// Send: a data send queue.
    send_queue: VecDeque<Frame>,
    /// Send: an OOB pong message.
    pong: Option<Frame>,
}

impl<Stream> WebSocket<Stream>
    where Stream: Read + Write
{

    /// Convert a raw socket into a WebSocket without performing a handshake.
    pub fn from_raw_socket(stream: Stream, role: Role) -> Self {
        WebSocket::from_frame_socket(FrameSocket::new(stream), role)
    }

    /// Convert a raw socket into a WebSocket without performing a handshake.
    pub fn from_partially_read(stream: Stream, part: Vec<u8>, role: Role) -> Self {
        WebSocket::from_frame_socket(FrameSocket::from_partially_read(stream, part), role)
    }

    /// Read a message from stream, if possible.
    ///
    /// This function sends pong and close responses automatically.
    /// However, it never blocks on write.
    pub fn read_message(&mut self) -> Result<Message> {
        loop {
            // Since we may get ping or close, we need to reply to the messages even during read.
            // Thus we call write_pending() but ignore its blocking.
            self.write_pending().no_block()?;
            // If we get here, either write blocks or we have nothing to write.
            // Thus if read blocks, just let it return WouldBlock.
            if let Some(message) = self.read_message_frame()? {
                debug!("Received message {}", message);
                return Ok(message)
            }
        }
    }

    /// Send a message to stream, if possible.
    ///
    /// This function guarantees that the frame is queued regardless of any errors.
    /// There is no need to resend the frame. In order to handle WouldBlock or Incomplete,
    /// call write_pending() afterwards.
    pub fn write_message(&mut self, message: Message) -> Result<()> {
        let frame = {
            let opcode = match message {
                Message::Text(_) => OpData::Text,
                Message::Binary(_) => OpData::Binary,
            };
            Frame::message(message.into_data(), OpCode::Data(opcode), true)
        };
        self.send_queue.push_back(frame);
        self.write_pending()
    }

    /// Close the connection.
    ///
    /// This function guarantees that the close frame will be queued.
    /// There is no need to call it again, just like write_message().
    pub fn close(&mut self) -> Result<()> {
        match self.state {
            WebSocketState::Active => {
                self.state = WebSocketState::ClosedByUs;
                let frame = Frame::close(None);
                self.send_queue.push_back(frame);
            }
            _ => {
                // already closed, nothing to do
            }
        }
        self.write_pending()
    }

    /// Flush the pending send queue.
    pub fn write_pending(&mut self) -> Result<()> {
        // First, make sure we have no pending frame sending.
        self.socket.write_pending()?;

        // Upon receipt of a Ping frame, an endpoint MUST send a Pong frame in
        // response, unless it already received a Close frame. It SHOULD
        // respond with Pong frame as soon as is practical. (RFC 6455)
        if let Some(pong) = replace(&mut self.pong, None) {
            self.send_one_frame(pong)?;
        }
        // If we have any unsent frames, send them.
        while let Some(data) = self.send_queue.pop_front() {
            self.send_one_frame(data)?;
        }

        // If we're closing and there is nothing to send anymore, we should close the connection.
        match self.state {
            WebSocketState::ClosedByPeer if self.send_queue.is_empty() => {
                // The underlying TCP connection, in most normal cases, SHOULD be closed
                // first by the server, so that it holds the TIME_WAIT state and not the
                // client (as this would prevent it from re-opening the connection for 2
                // maximum segment lifetimes (2MSL), while there is no corresponding
                // server impact as a TIME_WAIT connection is immediately reopened upon
                // a new SYN with a higher seq number). (RFC 6455)
                match self.role {
                    Role::Client => Ok(()),
                    Role::Server => Err(Error::ConnectionClosed),
                }
            }
            _ => Ok(()),
        }
    }

    /// Convert a frame socket into a WebSocket.
    fn from_frame_socket(socket: FrameSocket<Stream>, role: Role) -> Self {
        WebSocket {
            role: role,
            socket: socket,
            state: WebSocketState::Active,
            incomplete: None,
            send_queue: VecDeque::new(),
            pong: None,
        }
    }

    /// Try to decode one message frame. May return None.
    fn read_message_frame(&mut self) -> Result<Option<Message>> {
        if let Some(mut frame) = self.socket.read_frame()? {

            // MUST be 0 unless an extension is negotiated that defines meanings
            // for non-zero values.  If a nonzero value is received and none of
            // the negotiated extensions defines the meaning of such a nonzero
            // value, the receiving endpoint MUST _Fail the WebSocket
            // Connection_.
            if frame.has_rsv1() || frame.has_rsv2() || frame.has_rsv3() {
                return Err(Error::Protocol("Reserved bits are non-zero".into()))
            }

            match self.role {
                Role::Server => {
                    if frame.is_masked() {
                        // A server MUST remove masking for data frames received from a client
                        // as described in Section 5.3. (RFC 6455)
                        frame.remove_mask()
                    } else {
                        // The server MUST close the connection upon receiving a
                        // frame that is not masked. (RFC 6455)
                        return Err(Error::Protocol("Received an unmasked frame from client".into()))
                    }
                }
                Role::Client => {
                    if frame.is_masked() {
                        // A client MUST close a connection if it detects a masked frame. (RFC 6455)
                        return Err(Error::Protocol("Received a masked frame from server".into()))
                    }
                }
            }

            match frame.opcode() {

                OpCode::Control(ctl) => {
                    (match ctl {
                        // All control frames MUST have a payload length of 125 bytes or less
                        // and MUST NOT be fragmented. (RFC 6455)
                        _ if !frame.is_final() => {
                            Err(Error::Protocol("Fragmented control frame".into()))
                        }
                        _ if frame.payload().len() > 125 => {
                            Err(Error::Protocol("Control frame too big".into()))
                        }
                        OpCtl::Close => {
                            self.do_close(frame.into_close()?)
                        }
                        OpCtl::Reserved(i) => {
                            Err(Error::Protocol(format!("Unknown control frame type {}", i).into()))
                        }
                        OpCtl::Ping | OpCtl::Pong if !self.state.is_active() => {
                            // No ping processing while closing.
                            Ok(())
                        }
                        OpCtl::Ping => {
                            self.do_ping(frame.into_data())
                        }
                        OpCtl::Pong => {
                            self.do_pong(frame.into_data())
                        }
                    }).map(|_| None)
                }

                OpCode::Data(_) if !self.state.is_active() => {
                    // No data processing while closing.
                    Ok(None)
                }

                OpCode::Data(data) => {
                    let fin = frame.is_final();
                    match data {
                        OpData::Continue => {
                            if let Some(ref mut msg) = self.incomplete {
                                // TODO if msg too big
                                msg.extend(frame.into_data())?;
                            } else {
                                return Err(Error::Protocol("Continue frame but nothing to continue".into()))
                            }
                            if fin {
                                Ok(Some(replace(&mut self.incomplete, None).unwrap().complete()?))
                            } else {
                                Ok(None)
                            }
                        }
                        c if self.incomplete.is_some() => {
                            Err(Error::Protocol(
                                format!("Received {} while waiting for more fragments", c).into()
                            ))
                        }
                        OpData::Text | OpData::Binary => {
                            let msg = {
                                let message_type = match data {
                                    OpData::Text => IncompleteMessageType::Text,
                                    OpData::Binary => IncompleteMessageType::Binary,
                                    _ => panic!("Bug: message is not text nor binary"),
                                };
                                let mut m = IncompleteMessage::new(message_type);
                                m.extend(frame.into_data())?;
                                m
                            };
                            if fin {
                                Ok(Some(msg.complete()?))
                            } else {
                                self.incomplete = Some(msg);
                                Ok(None)
                            }
                        }
                        OpData::Reserved(i) => {
                            Err(Error::Protocol(format!("Unknown data frame type {}", i).into()))
                        }
                    }
                }

            } // match opcode

        } else {
            Err(Error::Protocol("Connection reset without closing handshake".into()))
        }
    }

    /// Received a close frame.
    fn do_close(&mut self, close: Option<(CloseCode, String)>) -> Result<()> {
        match self.state {
            WebSocketState::Active => {
                self.state = WebSocketState::ClosedByPeer;
                let reply = if let Some((code, _)) = close {
                    if code.is_allowed() {
                        Frame::close(Some((CloseCode::Normal, "")))
                    } else {
                        Frame::close(Some((CloseCode::Protocol, "Protocol violation")))
                    }
                } else {
                    Frame::close(None)
                };
                self.send_queue.push_back(reply);
                Ok(())
            }
            WebSocketState::ClosedByPeer => {
                // It is already closed, just ignore.
                Ok(())
            }
            WebSocketState::ClosedByUs => {
                // We received a reply.
                match self.role {
                    Role::Client => {
                        // Client waits for the server to close the connection.
                        Ok(())
                    }
                    Role::Server => {
                        // Server closes the connection.
                        Err(Error::ConnectionClosed)
                    }
                }
            }
        }
    }

    /// Received a ping frame.
    fn do_ping(&mut self, ping: Vec<u8>) -> Result<()> {
        // If an endpoint receives a Ping frame and has not yet sent Pong
        // frame(s) in response to previous Ping frame(s), the endpoint MAY
        // elect to send a Pong frame for only the most recently processed Ping
        // frame. (RFC 6455)
        // We do exactly that, keeping a "queue" from one and only Pong frame.
        self.pong = Some(Frame::pong(ping));
        Ok(())
    }

    /// Received a pong frame.
    fn do_pong(&mut self, _: Vec<u8>) -> Result<()> {
        // A Pong frame MAY be sent unsolicited.  This serves as a
        // unidirectional heartbeat.  A response to an unsolicited Pong frame is
        // not expected. (RFC 6455)
        // Due to this, we just don't check pongs right now.
        // TODO: check if there was a reply to our ping at all...
        Ok(())
    }

    /// Send a single pending frame.
    fn send_one_frame(&mut self, mut frame: Frame) -> Result<()> {
        match self.role {
            Role::Server => {
            }
            Role::Client => {
                // 5.  If the data is being sent by the client, the frame(s) MUST be
                // masked as defined in Section 5.3. (RFC 6455)
                frame.set_mask();
            }
        }
        self.socket.write_frame(frame)
    }

}

/// The current connection state.
enum WebSocketState {
    Active,
    ClosedByUs,
    ClosedByPeer,
}

impl WebSocketState {
    /// Tell if we're allowed to process normal messages.
    fn is_active(&self) -> bool {
        match *self {
            WebSocketState::Active => true,
            _ => false,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{WebSocket, Role, Message};

    use std::io;
    use std::io::Cursor;

    struct WriteMoc<Stream>(Stream);

    impl<Stream> io::Write for WriteMoc<Stream> {
        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
            Ok(buf.len())
        }
        fn flush(&mut self) -> io::Result<()> {
            Ok(())
        }
    }

    impl<Stream: io::Read> io::Read for WriteMoc<Stream> {
        fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
            self.0.read(buf)
        }
    }

    #[test]
    fn receive_messages() {
        let incoming = Cursor::new(vec![
            0x01, 0x07,
            0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20,
            0x80, 0x06,
            0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21,
            0x82, 0x03,
            0x01, 0x02, 0x03,
        ]);
        let mut socket = WebSocket::from_raw_socket(WriteMoc(incoming), Role::Client);
        assert_eq!(socket.read_message().unwrap(), Message::Text("Hello, World!".into()));
        assert_eq!(socket.read_message().unwrap(), Message::Binary(vec![0x01, 0x02, 0x03]));
    }

}
<commit_msg>protocol: less strict trait requirements<commit_after>//! Generic WebSocket protocol implementation

mod frame;
mod message;

pub use self::message::Message;

use std::collections::VecDeque;
use std::io::{Read, Write};
use std::mem::replace;

use error::{Error, Result};
use self::message::{IncompleteMessage, IncompleteMessageType};
use self::frame::{Frame, FrameSocket};
use self::frame::coding::{OpCode, Data as OpData, Control as OpCtl, CloseCode};
use util::NonBlockingResult;

/// Indicates a Client or Server role of the websocket
#[derive(Debug, Clone, Copy)]
pub enum Role {
    /// This socket is a server
    Server,
    /// This socket is a client
    Client,
}

/// WebSocket input-output stream
pub struct WebSocket<Stream> {
    /// Server or client?
    role: Role,
    /// The underlying socket.
    socket: FrameSocket<Stream>,
    /// The state of processing, either "active" or "closing".
    state: WebSocketState,
    /// Receive: an incomplete message being processed.
    incomplete: Option<IncompleteMessage>,
    /// Send: a data send queue.
    send_queue: VecDeque<Frame>,
    /// Send: an OOB pong message.
    pong: Option<Frame>,
}

impl<Stream> WebSocket<Stream> {
    /// Convert a raw socket into a WebSocket without performing a handshake.
    pub fn from_raw_socket(stream: Stream, role: Role) -> Self {
        WebSocket::from_frame_socket(FrameSocket::new(stream), role)
    }

    /// Convert a raw socket into a WebSocket without performing a handshake.
    pub fn from_partially_read(stream: Stream, part: Vec<u8>, role: Role) -> Self {
        WebSocket::from_frame_socket(FrameSocket::from_partially_read(stream, part), role)
    }

    /// Convert a frame socket into a WebSocket.
    fn from_frame_socket(socket: FrameSocket<Stream>, role: Role) -> Self {
        WebSocket {
            role: role,
            socket: socket,
            state: WebSocketState::Active,
            incomplete: None,
            send_queue: VecDeque::new(),
            pong: None,
        }
    }
}

impl<Stream: Read + Write> WebSocket<Stream> {
    /// Read a message from stream, if possible.
    ///
    /// This function sends pong and close responses automatically.
    /// However, it never blocks on write.
    pub fn read_message(&mut self) -> Result<Message> {
        loop {
            // Since we may get ping or close, we need to reply to the messages even during read.
            // Thus we call write_pending() but ignore its blocking.
            self.write_pending().no_block()?;
            // If we get here, either write blocks or we have nothing to write.
            // Thus if read blocks, just let it return WouldBlock.
            if let Some(message) = self.read_message_frame()? {
                debug!("Received message {}", message);
                return Ok(message)
            }
        }
    }

    /// Send a message to stream, if possible.
    ///
    /// This function guarantees that the frame is queued regardless of any errors.
    /// There is no need to resend the frame. In order to handle WouldBlock or Incomplete,
    /// call write_pending() afterwards.
    pub fn write_message(&mut self, message: Message) -> Result<()> {
        let frame = {
            let opcode = match message {
                Message::Text(_) => OpData::Text,
                Message::Binary(_) => OpData::Binary,
            };
            Frame::message(message.into_data(), OpCode::Data(opcode), true)
        };
        self.send_queue.push_back(frame);
        self.write_pending()
    }

    /// Close the connection.
    ///
    /// This function guarantees that the close frame will be queued.
    /// There is no need to call it again, just like write_message().
    pub fn close(&mut self) -> Result<()> {
        match self.state {
            WebSocketState::Active => {
                self.state = WebSocketState::ClosedByUs;
                let frame = Frame::close(None);
                self.send_queue.push_back(frame);
            }
            _ => {
                // already closed, nothing to do
            }
        }
        self.write_pending()
    }

    /// Flush the pending send queue.
    pub fn write_pending(&mut self) -> Result<()> {
        // First, make sure we have no pending frame sending.
        self.socket.write_pending()?;

        // Upon receipt of a Ping frame, an endpoint MUST send a Pong frame in
        // response, unless it already received a Close frame. It SHOULD
        // respond with Pong frame as soon as is practical. (RFC 6455)
        if let Some(pong) = replace(&mut self.pong, None) {
            self.send_one_frame(pong)?;
        }
        // If we have any unsent frames, send them.
        while let Some(data) = self.send_queue.pop_front() {
            self.send_one_frame(data)?;
        }

        // If we're closing and there is nothing to send anymore, we should close the connection.
        match self.state {
            WebSocketState::ClosedByPeer if self.send_queue.is_empty() => {
                // The underlying TCP connection, in most normal cases, SHOULD be closed
                // first by the server, so that it holds the TIME_WAIT state and not the
                // client (as this would prevent it from re-opening the connection for 2
                // maximum segment lifetimes (2MSL), while there is no corresponding
                // server impact as a TIME_WAIT connection is immediately reopened upon
                // a new SYN with a higher seq number). (RFC 6455)
                match self.role {
                    Role::Client => Ok(()),
                    Role::Server => Err(Error::ConnectionClosed),
                }
            }
            _ => Ok(()),
        }
    }

    /// Try to decode one message frame. May return None.
    fn read_message_frame(&mut self) -> Result<Option<Message>> {
        if let Some(mut frame) = self.socket.read_frame()? {

            // MUST be 0 unless an extension is negotiated that defines meanings
            // for non-zero values.  If a nonzero value is received and none of
            // the negotiated extensions defines the meaning of such a nonzero
            // value, the receiving endpoint MUST _Fail the WebSocket
            // Connection_.
            if frame.has_rsv1() || frame.has_rsv2() || frame.has_rsv3() {
                return Err(Error::Protocol("Reserved bits are non-zero".into()))
            }

            match self.role {
                Role::Server => {
                    if frame.is_masked() {
                        // A server MUST remove masking for data frames received from a client
                        // as described in Section 5.3. (RFC 6455)
                        frame.remove_mask()
                    } else {
                        // The server MUST close the connection upon receiving a
                        // frame that is not masked. (RFC 6455)
                        return Err(Error::Protocol("Received an unmasked frame from client".into()))
                    }
                }
                Role::Client => {
                    if frame.is_masked() {
                        // A client MUST close a connection if it detects a masked frame. (RFC 6455)
                        return Err(Error::Protocol("Received a masked frame from server".into()))
                    }
                }
            }

            match frame.opcode() {

                OpCode::Control(ctl) => {
                    (match ctl {
                        // All control frames MUST have a payload length of 125 bytes or less
                        // and MUST NOT be fragmented. (RFC 6455)
                        _ if !frame.is_final() => {
                            Err(Error::Protocol("Fragmented control frame".into()))
                        }
                        _ if frame.payload().len() > 125 => {
                            Err(Error::Protocol("Control frame too big".into()))
                        }
                        OpCtl::Close => {
                            self.do_close(frame.into_close()?)
                        }
                        OpCtl::Reserved(i) => {
                            Err(Error::Protocol(format!("Unknown control frame type {}", i).into()))
                        }
                        OpCtl::Ping | OpCtl::Pong if !self.state.is_active() => {
                            // No ping processing while closing.
                            Ok(())
                        }
                        OpCtl::Ping => {
                            self.do_ping(frame.into_data())
                        }
                        OpCtl::Pong => {
                            self.do_pong(frame.into_data())
                        }
                    }).map(|_| None)
                }

                OpCode::Data(_) if !self.state.is_active() => {
                    // No data processing while closing.
                    Ok(None)
                }

                OpCode::Data(data) => {
                    let fin = frame.is_final();
                    match data {
                        OpData::Continue => {
                            if let Some(ref mut msg) = self.incomplete {
                                // TODO if msg too big
                                msg.extend(frame.into_data())?;
                            } else {
                                return Err(Error::Protocol("Continue frame but nothing to continue".into()))
                            }
                            if fin {
                                Ok(Some(replace(&mut self.incomplete, None).unwrap().complete()?))
                            } else {
                                Ok(None)
                            }
                        }
                        c if self.incomplete.is_some() => {
                            Err(Error::Protocol(
                                format!("Received {} while waiting for more fragments", c).into()
                            ))
                        }
                        OpData::Text | OpData::Binary => {
                            let msg = {
                                let message_type = match data {
                                    OpData::Text => IncompleteMessageType::Text,
                                    OpData::Binary => IncompleteMessageType::Binary,
                                    _ => panic!("Bug: message is not text nor binary"),
                                };
                                let mut m = IncompleteMessage::new(message_type);
                                m.extend(frame.into_data())?;
                                m
                            };
                            if fin {
                                Ok(Some(msg.complete()?))
                            } else {
                                self.incomplete = Some(msg);
                                Ok(None)
                            }
                        }
                        OpData::Reserved(i) => {
                            Err(Error::Protocol(format!("Unknown data frame type {}", i).into()))
                        }
                    }
                }

            } // match opcode

        } else {
            Err(Error::Protocol("Connection reset without closing handshake".into()))
        }
    }

    /// Received a close frame.
    fn do_close(&mut self, close: Option<(CloseCode, String)>) -> Result<()> {
        match self.state {
            WebSocketState::Active => {
                self.state = WebSocketState::ClosedByPeer;
                let reply = if let Some((code, _)) = close {
                    if code.is_allowed() {
                        Frame::close(Some((CloseCode::Normal, "")))
                    } else {
                        Frame::close(Some((CloseCode::Protocol, "Protocol violation")))
                    }
                } else {
                    Frame::close(None)
                };
                self.send_queue.push_back(reply);
                Ok(())
            }
            WebSocketState::ClosedByPeer => {
                // It is already closed, just ignore.
                Ok(())
            }
            WebSocketState::ClosedByUs => {
                // We received a reply.
                match self.role {
                    Role::Client => {
                        // Client waits for the server to close the connection.
                        Ok(())
                    }
                    Role::Server => {
                        // Server closes the connection.
                        Err(Error::ConnectionClosed)
                    }
                }
            }
        }
    }

    /// Received a ping frame.
    fn do_ping(&mut self, ping: Vec<u8>) -> Result<()> {
        // If an endpoint receives a Ping frame and has not yet sent Pong
        // frame(s) in response to previous Ping frame(s), the endpoint MAY
        // elect to send a Pong frame for only the most recently processed Ping
        // frame. (RFC 6455)
        // We do exactly that, keeping a "queue" from one and only Pong frame.
        self.pong = Some(Frame::pong(ping));
        Ok(())
    }

    /// Received a pong frame.
    fn do_pong(&mut self, _: Vec<u8>) -> Result<()> {
        // A Pong frame MAY be sent unsolicited.  This serves as a
        // unidirectional heartbeat.  A response to an unsolicited Pong frame is
        // not expected. (RFC 6455)
        // Due to this, we just don't check pongs right now.
        // TODO: check if there was a reply to our ping at all...
        Ok(())
    }

    /// Send a single pending frame.
    fn send_one_frame(&mut self, mut frame: Frame) -> Result<()> {
        match self.role {
            Role::Server => {
            }
            Role::Client => {
                // 5.  If the data is being sent by the client, the frame(s) MUST be
                // masked as defined in Section 5.3. (RFC 6455)
                frame.set_mask();
            }
        }
        self.socket.write_frame(frame)
    }

}

/// The current connection state.
enum WebSocketState {
    Active,
    ClosedByUs,
    ClosedByPeer,
}

impl WebSocketState {
    /// Tell if we're allowed to process normal messages.
    fn is_active(&self) -> bool {
        match *self {
            WebSocketState::Active => true,
            _ => false,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{WebSocket, Role, Message};

    use std::io;
    use std::io::Cursor;

    struct WriteMoc<Stream>(Stream);

    impl<Stream> io::Write for WriteMoc<Stream> {
        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
            Ok(buf.len())
        }
        fn flush(&mut self) -> io::Result<()> {
            Ok(())
        }
    }

    impl<Stream: io::Read> io::Read for WriteMoc<Stream> {
        fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
            self.0.read(buf)
        }
    }

    #[test]
    fn receive_messages() {
        let incoming = Cursor::new(vec![
            0x01, 0x07,
            0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20,
            0x80, 0x06,
            0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21,
            0x82, 0x03,
            0x01, 0x02, 0x03,
        ]);
        let mut socket = WebSocket::from_raw_socket(WriteMoc(incoming), Role::Client);
        assert_eq!(socket.read_message().unwrap(), Message::Text("Hello, World!".into()));
        assert_eq!(socket.read_message().unwrap(), Message::Binary(vec![0x01, 0x02, 0x03]));
    }

}
<|endoftext|>


<commit_before>use super::{Component, Draw};
use crate::err::Result;
use crate::series::LastWatched;
use crate::tui::UIState;
use crate::CmdOptions;
use termion::event::Key;
use tui::backend::Backend;
use tui::layout::Rect;
use tui::style::{Color, Modifier, Style};
use tui::terminal::Frame;
use tui::widgets::{Block, Borders, List, ListState, Text};

pub struct SeriesList {
    list_state: ListState,
}

impl SeriesList {
    pub fn init(args: &CmdOptions, state: &mut UIState, last_watched: &LastWatched) -> Self {
        let selected = {
            let desired_series = args.series.as_ref().or_else(|| last_watched.get());

            match desired_series {
                Some(desired) => state
                    .series
                    .iter()
                    .position(|series| series.nickname() == desired)
                    .unwrap_or(0),
                None => 0,
            }
        };

        state.series.set_selected(selected);
        state.init_selected_series().ok();

        Self {
            list_state: ListState::default(),
        }
    }
}

impl Component for SeriesList {
    type State = UIState;
    type KeyResult = Result<()>;

    fn process_key(&mut self, key: Key, state: &mut Self::State) -> Self::KeyResult {
        match key {
            Key::Up | Key::Down => {
                match key {
                    Key::Up => state.series.dec_selected(),
                    Key::Down => state.series.inc_selected(),
                    _ => unreachable!(),
                }

                state.init_selected_series()
            }
            _ => Ok(()),
        }
    }
}

impl<B> Draw<B> for SeriesList
where
    B: Backend,
{
    type State = UIState;

    fn draw(&mut self, state: &Self::State, rect: Rect, frame: &mut Frame<B>) {
        let series_names = state
            .series
            .iter()
            .map(|series| Text::raw(series.nickname()));

        let series_list = List::new(series_names)
            .block(Block::default().title("Series").borders(Borders::ALL))
            .style(Style::default().fg(Color::White))
            .highlight_style(Style::default().fg(Color::Green).modifier(Modifier::ITALIC))
            .highlight_symbol(">");

        self.list_state.select(Some(state.series.index()));

        frame.render_stateful_widget(series_list, rect, &mut self.list_state);
    }
}
<commit_msg>anup: Gray out the selected series when it cannot be changed<commit_after>use super::{Component, Draw};
use crate::err::Result;
use crate::series::LastWatched;
use crate::tui::{CurrentAction, UIState};
use crate::CmdOptions;
use termion::event::Key;
use tui::backend::Backend;
use tui::layout::Rect;
use tui::style::{Color, Modifier, Style};
use tui::terminal::Frame;
use tui::widgets::{Block, Borders, List, ListState, Text};

pub struct SeriesList {
    list_state: ListState,
}

impl SeriesList {
    pub fn init(args: &CmdOptions, state: &mut UIState, last_watched: &LastWatched) -> Self {
        let selected = {
            let desired_series = args.series.as_ref().or_else(|| last_watched.get());

            match desired_series {
                Some(desired) => state
                    .series
                    .iter()
                    .position(|series| series.nickname() == desired)
                    .unwrap_or(0),
                None => 0,
            }
        };

        state.series.set_selected(selected);
        state.init_selected_series().ok();

        Self {
            list_state: ListState::default(),
        }
    }
}

impl Component for SeriesList {
    type State = UIState;
    type KeyResult = Result<()>;

    fn process_key(&mut self, key: Key, state: &mut Self::State) -> Self::KeyResult {
        match key {
            Key::Up | Key::Down => {
                match key {
                    Key::Up => state.series.dec_selected(),
                    Key::Down => state.series.inc_selected(),
                    _ => unreachable!(),
                }

                state.init_selected_series()
            }
            _ => Ok(()),
        }
    }
}

impl<B> Draw<B> for SeriesList
where
    B: Backend,
{
    type State = UIState;

    fn draw(&mut self, state: &Self::State, rect: Rect, frame: &mut Frame<B>) {
        let series_names = state
            .series
            .iter()
            .map(|series| Text::raw(series.nickname()));

        let highlight_style = match &state.current_action {
            CurrentAction::Idle => Style::default().fg(Color::Green).modifier(Modifier::ITALIC),
            _ => Style::default()
                .fg(Color::DarkGray)
                .modifier(Modifier::ITALIC),
        };

        let series_list = List::new(series_names)
            .block(Block::default().title("Series").borders(Borders::ALL))
            .style(Style::default().fg(Color::White))
            .highlight_style(highlight_style)
            .highlight_symbol(">");

        self.list_state.select(Some(state.series.index()));

        frame.render_stateful_widget(series_list, rect, &mut self.list_state);
    }
}
<|endoftext|>


<commit_before>use std::sync::mpsc::{SyncSender, Receiver, Sender, channel};
use std::thread::Thread;

use uci::Response;
use game::{Move, Position, receive_legal, make_move};
use types::NumPlies;
use eval::Score;

use super::types::{State, Cmd};
use super::negamax::{negamax, Data};

pub fn start(mut state: State, rx: Receiver<Cmd>, tx:SyncSender<Response>) {
    let mut is_debug = false;
    if state.param.ponder {
        if is_debug { debug!("pondering, waiting for next command") }
        // Actually should ponder, but now just waits for our move.
        for cmd in rx.iter() {
            match cmd {
                Cmd::SetDebug(val) => {
                    is_debug = val;
                    debug!("debug is now {:?}", val);
                },
                Cmd::PonderHit => {
                    if is_debug { debug!("ponder hit when pondering") }
                    state.param.ponder = false;
                    break;
                },
                Cmd::Stop => {
                    if is_debug { debug!("stop from pondering") }
                    // TODO report stuff.about pondering and terminate.
                    unimplemented!();
                },
            }
        }
        if state.param.ponder {
            panic!("Sender hung up while pondering");
        }
        if is_debug { debug!("pondering finished") }
    }

    let legal_moves_chan = receive_legal(state.pos.clone());
    let legal_moves = legal_moves_chan.iter();
    let search_moves: Vec<Move> = match state.param.search_moves {
        None => legal_moves.collect(),
        Some(ref val) => legal_moves.filter(|x| val.contains(x)).collect(),
    };
    if search_moves.is_empty() {
        panic!("No legal moves searched in searched position");
    }

    let search_pos: Vec<Position> = {
        search_moves.iter().map(|x: &Move| {
            let mut new_pos = state.pos.clone();
            make_move(&mut new_pos, x);
            new_pos
        }).collect()
    };

    let mut best_move = search_moves[0].clone();

    let (search_tx, mut search_rx) = channel::<(Score, Move, Data)>();
    let (mut kill_tx, kill_rx) = channel::<()>();
    Thread::spawn(move || depth_limited_search(&*search_pos, NumPlies(1), search_tx, kill_rx));

    loop {
        select! {
            val = rx.recv() => {
                let cmd = val.ok().expect("Sender hung up while calculating");
                match cmd {
                    Cmd::SetDebug(val) => {
                        is_debug = val;
                        debug!("debug is now {:?}", val);
                    },
                    Cmd::PonderHit => {
                        if is_debug { debug!("ponder hit when not pondering (ignored)") }
                        // Ignore this cmd
                    },
                    Cmd::Stop => {
                        let _ = kill_tx.send(());
                        if is_debug { debug!("stop search") }
                        // TODO send info again
                        tx.send(Response::BestMove(best_move, None))
                          .ok().expect("output channel closed");
                        return;
                    }
                }
            },
            search_res = search_rx.recv() => {
                // TODO use search_res
                // TODO send info
                // TODO do next iteration of depth limited search
                unimplemented!()
            }
        }
    }
}

fn depth_limited_search(search_pos: &[Position],
                        depth: NumPlies,
                        tx: Sender<(Score, Move, Data)>,
                        kill_rx: Receiver<()>) {
    // TODO call negamax() for each Position
    unimplemented!()
}
<commit_msg>Partially implement iterated deepening<commit_after>use std::sync::mpsc::{SyncSender, Receiver, Sender, channel};
use std::sync::Arc;
use std::thread::Thread;

use uci::Response;
use game::{Move, Position, receive_legal, make_move};
use types::NumPlies;
use eval::Score;

use super::types::{State, Cmd};
use super::negamax::{negamax, Data};

pub fn start(mut state: State, rx: Receiver<Cmd>, tx:SyncSender<Response>) {
    let mut is_debug = false;
    if state.param.ponder {
        if is_debug { debug!("pondering, waiting for next command") }
        // Actually should ponder, but now just waits for our move.
        for cmd in rx.iter() {
            match cmd {
                Cmd::SetDebug(val) => {
                    is_debug = val;
                    debug!("debug is now {:?}", val);
                },
                Cmd::PonderHit => {
                    if is_debug { debug!("ponder hit when pondering") }
                    state.param.ponder = false;
                    break;
                },
                Cmd::Stop => {
                    if is_debug { debug!("stop from pondering") }
                    // TODO report stuff.about pondering and terminate.
                    unimplemented!();
                },
            }
        }
        if state.param.ponder {
            panic!("Sender hung up while pondering");
        }
        if is_debug { debug!("pondering finished") }
    }

    let legal_moves_chan = receive_legal(state.pos.clone());
    let legal_moves = legal_moves_chan.iter();
    let search_moves: Vec<Move> = match state.param.search_moves {
        None => legal_moves.collect(),
        Some(ref val) => legal_moves.filter(|x| val.contains(x)).collect(),
    };
    if search_moves.is_empty() {
        panic!("No legal moves searched in searched position");
    }

    // This is a hack required because Send currently requires 'static
    // TODO remove the Arc when Send does not require 'static
    let search_pos_arc: Arc<Vec<Position>> = Arc::new({
        search_moves.iter().map(|x: &Move| {
            let mut new_pos = state.pos.clone();
            make_move(&mut new_pos, x);
            new_pos
        }).collect()
    });

    let mut best_score = None::<Score>;
    let mut best_move = search_moves[0].clone();
    let mut total_search_data = Data;

    let mut curr_plies = NumPlies(1);

    let (search_tx, mut search_rx) = channel::<(Score, Move, Data)>();
    let (mut kill_tx, kill_rx) = channel::<()>();

    let temp_search_pos_arc = search_pos_arc.clone();
    let mut search_guard = Thread::scoped(move ||
        depth_limited_search(temp_search_pos_arc, curr_plies, search_tx, kill_rx));

    loop {
        // This is a hack to get around a problem in select! {}
        // TODO remove this hack after the problem is solved
        let mut search_rx_opt: Option<Receiver<(Score, Move, Data)>> = None;
        select! {
            val = rx.recv() => {
                let cmd = val.ok().expect("Sender hung up while calculating");
                match cmd {
                    Cmd::SetDebug(val) => {
                        is_debug = val;
                        debug!("debug is now {:?}", val);
                    },
                    Cmd::PonderHit => {
                        if is_debug { debug!("ponder hit when not pondering (ignored)") }
                        // Ignore this cmd
                    },
                    Cmd::Stop => {
                        let _ = kill_tx.send(());
                        search_guard.join().ok().expect("depth_limited_search panicked");
                        if is_debug { debug!("stop search") }
                        // TODO send info again
                        tx.send(Response::BestMove(best_move, None))
                          .ok().expect("output channel closed");
                        return;
                    }
                }
            },
            search_res = search_rx.recv() => {
                search_guard.join().ok().expect("depth_limited_search panicked");

                let (temp_best_score, temp_best_move, curr_search_data) = search_res.ok()
                    .expect("depth_limited_search unexpectedly dropped Sender");

                best_score = Some(temp_best_score);
                best_move = temp_best_move;

                total_search_data = total_search_data.combine(curr_search_data);

                // TODO use search data
                // TODO send info

                curr_plies.0 += 1;

                let (new_search_tx, new_search_rx) = channel::<(Score, Move, Data)>();
                search_rx_opt = Some(new_search_rx);
                let (new_kill_tx, new_kill_rx) = channel::<()>();
                kill_tx = new_kill_tx;

                let temp_search_pos_arc = search_pos_arc.clone();
                search_guard = Thread::scoped(move ||
                    depth_limited_search(temp_search_pos_arc, curr_plies,
                                         new_search_tx, new_kill_rx));
            }
        }
        if let Some(val) = search_rx_opt { search_rx = val; }
    }
}

fn depth_limited_search(search_pos_arc: Arc<Vec<Position>>,
                        depth: NumPlies,
                        tx: Sender<(Score, Move, Data)>,
                        kill_rx: Receiver<()>) {
    debug_assert!(!search_pos_arc.is_empty());

    // TODO call negamax() for each Position
    unimplemented!()
}
<|endoftext|>


<commit_before>use jsrs_parser::ast::BinOp::*;
use jsrs_parser::ast::Exp::*;
use std::f64::NAN;

macro_rules! format_exp {
    ($e1:expr, $o:expr, $e2:expr) => { &format!("{}", exp!($e1, $o, $e2)) }
}

#[test]
fn constants() {
    // Floating point values specifically chosen so fractional part can be perfectly represented
    // by floating-point numbers.
    assert_eq!("12.25", format!("{}", Float(12.25)));
    assert_eq!("-3.5", format!("{}", Float(-3.5)));
    assert_eq!("NaN", format!("{}", Float(NAN)));
    assert_eq!("undefined", format!("{}", Undefined));
}

#[test]
fn single_binop_exprs() {
    assert_eq!("-14 * 7", format_exp!(Float(-14.0), Star, Float(7.0)));
    assert_eq!("8 - -10", format_exp!(Float(8.0), Minus, Float(-10.0)));
    assert_eq!("12.25 + 72", format_exp!(Float(12.25), Plus, Float(72.0)));
    assert_eq!("-3 * 42.5", format_exp!(Float(-3.0), Star, Float(42.5)));
    assert_eq!("22 / x", format_exp!(Float(22.0), Slash, var!("x")))
}

#[test]
fn multi_binop_exprs_no_grouping() {
    assert_eq!("x + 18.5 - 17",
        format_exp!(exp!(var!("x"), Plus, Float(18.5)), Minus, Float(17.0)));
    assert_eq!("-10 / num - 17",
        format_exp!(exp!(Float(-10.0), Slash, var!("num")), Minus, Float(17.0)));
    assert_eq!("-10 * 18.5 + some_num",
        format_exp!(exp!(Float(-10.0), Star, Float(18.5)), Plus, var!("some_num")));
    assert_eq!("anotherNumber - _x / 17",
        format_exp!(var!("anotherNumber"), Minus, exp!(var!("_x"), Slash, Float(17.0))));
    assert_eq!("_ - 18.5 + x2 * -3.25",
        format_exp!(exp!(var!("_"), Minus, Float(18.5)), Plus, exp!(var!("x2"), Star, Float(-3.25))));
    assert_eq!("NUMBER * 18.5 / 17 + N_4",
        format_exp!(exp!(exp!(var!("NUMBER"), Star, Float(18.5)), Slash, Float(17.0)), Plus, var!("N_4")));
}

#[test]
fn multi_binop_exprs_with_grouping() {
    assert_eq!("_7 * (e_4_4 + OkDk)",
        format_exp!(var!("_7"), Star, exp!(var!("e_4_4"), Plus, var!("OkDk"))));
    assert_eq!("(-10 - 18.5) / 17",
        format_exp!(exp!(Float(-10.0), Minus, Float(18.5)), Slash, Float(17.0)));
    assert_eq!("-10 - (O_k + 17)",
        format_exp!(Float(-10.0), Minus, exp!(var!("O_k"), Plus, Float(17.0))));
    assert_eq!("-10 / (O_k * 17)",
        format_exp!(Float(-10.0), Slash, exp!(var!("O_k"), Star, Float(17.0))));
    assert_eq!("(_Ok - h2o) * 17 / -3.25",
        format_exp!(exp!(var!("_Ok"), Minus, var!("h2o")), Star, exp!(Float(17.0), Slash, Float(-3.25))));
    assert_eq!("(-10 + 18.5 - 17) * -3.25",
        format_exp!(exp!(exp!(Float(-10.0), Plus, Float(18.5)), Minus, Float(17.0)), Star, Float(-3.25)));
    assert_eq!("(-10 - (18.5 - 17)) / -3.25",
        format_exp!(exp!(Float(-10.0), Minus, exp!(Float(18.5), Minus, Float(17.0))), Slash, Float(-3.25)));
}
<commit_msg>add format tests for statements<commit_after>use jsrs_parser::ast::BinOp::*;
use jsrs_parser::ast::Exp::*;
use jsrs_parser::ast::Stmt::*;
use std::f64::NAN;

macro_rules! format_exp {
    ($e1:expr, $o:expr, $e2:expr) => { &format!("{}", exp!($e1, $o, $e2)) }
}

macro_rules! format_assign {
    ($s:expr, $e:expr) => { &format!("{}", Assign(String::from($s), $e)) }
}

macro_rules! format_bare_exp {
    ($e:expr) => { &format!("{}", BareExp($e)) }
}

macro_rules! format_decl {
    ($s:expr, $e:expr) => { &format!("{}", Decl(String::from($s), $e)) }
}

#[test]
fn constants() {
    // Floating point values specifically chosen so fractional part can be perfectly represented
    // by floating-point numbers.
    assert_eq!("12.25", format!("{}", Float(12.25)));
    assert_eq!("-3.5", format!("{}", Float(-3.5)));
    assert_eq!("NaN", format!("{}", Float(NAN)));
    assert_eq!("undefined", format!("{}", Undefined));
}

#[test]
fn single_binop_exprs() {
    assert_eq!("-14 * 7", format_exp!(Float(-14.0), Star, Float(7.0)));
    assert_eq!("8 - -10", format_exp!(Float(8.0), Minus, Float(-10.0)));
    assert_eq!("12.25 + 72", format_exp!(Float(12.25), Plus, Float(72.0)));
    assert_eq!("-3 * 42.5", format_exp!(Float(-3.0), Star, Float(42.5)));
    assert_eq!("22 / x", format_exp!(Float(22.0), Slash, var!("x")))
}

#[test]
fn multi_binop_exprs_no_grouping() {
    assert_eq!("x + 18.5 - 17",
        format_exp!(exp!(var!("x"), Plus, Float(18.5)), Minus, Float(17.0)));
    assert_eq!("-10 / num - 17",
        format_exp!(exp!(Float(-10.0), Slash, var!("num")), Minus, Float(17.0)));
    assert_eq!("-10 * 18.5 + some_num",
        format_exp!(exp!(Float(-10.0), Star, Float(18.5)), Plus, var!("some_num")));
    assert_eq!("anotherNumber - _x / 17",
        format_exp!(var!("anotherNumber"), Minus, exp!(var!("_x"), Slash, Float(17.0))));
    assert_eq!("_ - 18.5 + x2 * -3.25",
        format_exp!(exp!(var!("_"), Minus, Float(18.5)), Plus, exp!(var!("x2"), Star, Float(-3.25))));
    assert_eq!("NUMBER * 18.5 / 17 + N_4",
        format_exp!(exp!(exp!(var!("NUMBER"), Star, Float(18.5)), Slash, Float(17.0)), Plus, var!("N_4")));
}

#[test]
fn multi_binop_exprs_with_grouping() {
    assert_eq!("_7 * (e_4_4 + OkDk)",
        format_exp!(var!("_7"), Star, exp!(var!("e_4_4"), Plus, var!("OkDk"))));
    assert_eq!("(-10 - 18.5) / 17",
        format_exp!(exp!(Float(-10.0), Minus, Float(18.5)), Slash, Float(17.0)));
    assert_eq!("-10 - (O_k + 17)",
        format_exp!(Float(-10.0), Minus, exp!(var!("O_k"), Plus, Float(17.0))));
    assert_eq!("-10 / (O_k * 17)",
        format_exp!(Float(-10.0), Slash, exp!(var!("O_k"), Star, Float(17.0))));
    assert_eq!("(_Ok - h2o) * 17 / -3.25",
        format_exp!(exp!(var!("_Ok"), Minus, var!("h2o")), Star, exp!(Float(17.0), Slash, Float(-3.25))));
    assert_eq!("(-10 + 18.5 - 17) * -3.25",
        format_exp!(exp!(exp!(Float(-10.0), Plus, Float(18.5)), Minus, Float(17.0)), Star, Float(-3.25)));
    assert_eq!("(-10 - (18.5 - 17)) / -3.25",
        format_exp!(exp!(Float(-10.0), Minus, exp!(Float(18.5), Minus, Float(17.0))), Slash, Float(-3.25)));
}

#[test]
fn assign_stmts() {
    assert_eq!("x = NaN;\n", format_assign!("x", Float(NAN)));
    assert_eq!("someThing = 8.25 - OTHER;\n",
        format_assign!("someThing", exp!(Float(8.25), Minus, var!("OTHER"))));
    assert_eq!("thing2 = r * -51 + 3.5;\n",
        format_assign!("thing2", exp!(exp!(var!("r"), Star, Float(-51.0)), Plus, Float(3.5))));
    assert_eq!("_2 = (-42.5 + undefined) / 7.125;\n",
        format_assign!("_2", exp!(exp!(Float(-42.5), Plus, Undefined), Slash, Float(7.125))));
}

#[test]
fn bare_exp_stmts() {
    assert_eq!("-3.5;\n", format_bare_exp!(Float(-3.5)));
    assert_eq!("NaN;\n", format_bare_exp!(Float(NAN)));
    assert_eq!("x - -10;\n", format_bare_exp!(exp!(var!("x"), Minus, Float(-10.0))));
    assert_eq!("-3 * 42.5;\n", format_bare_exp!(exp!(Float(-3.0), Star, Float(42.5))));
    assert_eq!("-10 / num - 17;\n",
        format_bare_exp!(exp!(exp!(Float(-10.0), Slash, var!("num")), Minus, Float(17.0))));
    assert_eq!("NUMBER * 18.5 / 17 + N_4;\n",
        format_bare_exp!(exp!(exp!(exp!(var!("NUMBER"), Star, Float(18.5)), Slash, Float(17.0)), Plus, var!("N_4"))));
    assert_eq!("-10 / (O_k * 17);\n",
        format_bare_exp!(exp!(Float(-10.0), Slash, exp!(var!("O_k"), Star, Float(17.0)))));
    assert_eq!("(-10 - (18.5 - 17)) / -3.25;\n",
        format_bare_exp!(exp!(exp!(Float(-10.0), Minus, exp!(Float(18.5), Minus, Float(17.0))), Slash, Float(-3.25))));
}

#[test]
fn decl_stmts() {
    assert_eq!("var _Nu4 = 2.25;\n", format_decl!("_Nu4", Float(2.25)));
    assert_eq!("var nU_M = x * -72;\n", format_decl!("nU_M", exp!(var!("x"), Star, Float(-72.0))));
    assert_eq!("var NUM = -34.5 / _l4 + 8;\n",
        format_decl!("NUM", exp!(exp!(Float(-34.5), Slash, var!("_l4")), Plus, Float(8.0))));
    assert_eq!("var eleven = (Y + 3) * -11;\n",
        format_decl!("eleven", exp!(exp!(var!("Y"), Plus, Float(3.0)), Star, Float(-11.0))));
}
<|endoftext|>


<commit_before>#[cfg(target_os = "linux")]
mod platform {
    fn runmain(f: fn()) {
        f()
    }
}

#[cfg(target_os = "macos")]
mod platform {
    use cocoa;
    import cocoa::base::*;

    mod NSApplication {
        fn sharedApplication() -> id {
            let klass = str::as_c_str("NSApplication") { |s|
                objc::objc_getClass(s)
            };

            let sel = str::as_c_str("sharedApplication") { |s|
                objc::sel_registerName(s)
            };

            let nsapp = objc::objc_msgSend(klass, sel);
            #debug("nsapp: %d", (nsapp as int));

	    ret nsapp;
        }
    }

    mod NSAutoreleasePool {
        fn alloc() -> id {
            let klass = str::as_c_str("NSAutoreleasePool") { |s|
                objc::objc_getClass(s)
            };
            let sel = str::as_c_str("alloc") { |s|
                objc::sel_registerName(s)
            };
            let pool = objc::objc_msgSend(klass, sel);
            #debug("autorelease pool: %?", pool);
            ret pool;
        }
        fn init(pool: id) {
            let sel = str::as_c_str("init") { |s|
                objc::sel_registerName(s)
            };
            objc::objc_msgSend(pool, sel);
        }
        fn release(pool: id) {
            let sel = str::as_c_str("release") { |s|
                objc::sel_registerName(s)
            };
            objc::objc_msgSend(pool, sel);
        }
    }

    mod NSApp {
         fn setDelegate(nsapp: id, main: id) {
	     #debug("NSApp::setDelegate");
	     let sel = str::as_c_str("setDelegate:") { |s|
	         objc::sel_registerName(s)
	     };
	     cocoa::msgSend1Id(nsapp, sel, main);
         }

         fn run(nsapp: id) {
	    #debug("NSApp::run");
            let sel = str::as_c_str("run") { |s|
                objc::sel_registerName(s)
            };
            objc::objc_msgSend(nsapp, sel);
         }
    }

    mod MainObj {
         crust fn applicationDidFinishLaunching(this: id, _sel: SEL) {
	     #debug("applicationDidFinishLaunching");

	     let fptr: *fn() = ptr::null();
	     str::as_c_str("fptr") { |name|
	         let outValue = unsafe { unsafe::reinterpret_cast(ptr::addr_of(fptr)) };
                 #debug("*fptr %?", outValue);
                 objc::object_getInstanceVariable(this, name, outValue)
             };

	     #debug("getting osmain fptr: %?", fptr);

	     unsafe {
	         // FIXME: We probably don't want to run the main routine in a crust function
                 (*fptr)();
             }
	 }

    	 fn create(f: fn()) -> id {
             let NSObject = str::as_c_str("NSObject") { |s|
	         objc::objc_getClass(s)
             };
	     let MainObj = str::as_c_str("MainObj") { |s|
	         objc::objc_allocateClassPair(NSObject, s, 0 as libc::size_t)
	     };

             // Add a field to our class to contain a pointer to a rust closure
	     let res = str::as_c_str("fptr") { |name|
                 str::as_c_str("^i") { |types|
                     objc::class_addIvar(MainObj, name,
                                         sys::size_of::<libc::uintptr_t>() as libc::size_t,
                                         16u8, types)
                 }
             };
 	     assert res == true;

	     let launchfn = str::as_c_str("applicationDidFinishLaunching:") { |s|
	         objc::sel_registerName(s)
	     };
	     let _ = str::as_c_str("@@:") { |types|
	         objc::class_addMethod(MainObj, launchfn, applicationDidFinishLaunching, types)
	     };

	     objc::objc_registerClassPair(MainObj);

             let sel = str::as_c_str("alloc") { |s|
                 objc::sel_registerName(s)
             };
             let mainobj = objc::objc_msgSend(MainObj, sel);

             let sel = str::as_c_str("init") { |s|
                 objc::sel_registerName(s)
             };
             objc::objc_msgSend(mainobj, sel);

	     let fptr = ptr::addr_of(f);
	     str::as_c_str("fptr") { |name|
	         #debug("setting osmain fptr: %?", fptr);
		 let value = unsafe { unsafe::reinterpret_cast(fptr) };
                 #debug("*fptr: %?", value);
                 objc::object_setInstanceVariable(mainobj, name, value)
             };

	     ret mainobj;
	 }
	 fn release(mainobj: id) {
             let sel = str::as_c_str("release") { |s|
                 objc::sel_registerName(s)
             };
             objc::objc_msgSend(mainobj, sel);
	 }
    }

    fn runmain(f: fn()) {
	let pool = NSAutoreleasePool::alloc();
	NSAutoreleasePool::init(pool);
        let NSApp = NSApplication::sharedApplication();

        let mainobj = MainObj::create(f);
	NSApp::setDelegate(NSApp, mainobj);
	NSApp::run(NSApp);

	MainObj::release(mainobj);
	NSAutoreleasePool::release(pool);
    }
}

enum msg {
    get_draw_target(comm::chan<AzDrawTargetRef>),
    add_key_handler(comm::chan<()>),
    draw(comm::chan<()>),
    exit
}

fn osmain() -> comm::chan<msg> {
    on_osmain::<msg> {|po|
        platform::runmain {||
            #debug("preparing to enter main loop");
	    mainloop(po);
        }
    }
}

// A function for spawning into the platform's main thread
fn on_osmain<T: send>(f: fn~(comm::port<T>)) -> comm::chan<T> {
    let builder = task::builder();
    let opts = {
        sched: some({
            mode: task::osmain,
            native_stack_size: none
        })
        with task::get_opts(builder)
    };
    task::set_opts(builder, opts);
    ret task::run_listener(builder, f);
}

fn mainloop(po: comm::port<msg>) {

    let mut key_handlers = [];

    sdl::init([
        sdl::init_video
    ]);
    let screen = sdl::video::set_video_mode(
        800, 600, 32,
        [sdl::video::swsurface],
        [sdl::video::doublebuf]);
    assert !screen.is_null();
    let sdl_surf = sdl::video::create_rgb_surface(
        [sdl::video::swsurface],
        800, 600, 32,
        0x00FF0000u32,
        0x0000FF00u32,
        0x000000FFu32,
        0x00000000u32
        );
    assert !sdl_surf.is_null();
    sdl::video::lock_surface(sdl_surf);
    let cairo_surf = unsafe {
        cairo_image_surface_create_for_data(
            unsafe::reinterpret_cast((*sdl_surf).pixels),
            cairo::CAIRO_FORMAT_RGB24,
            (*sdl_surf).w,
            (*sdl_surf).h,
            (*sdl_surf).pitch as libc::c_int
        )
    };
    assert !cairo_surf.is_null();
    let azure_target = AzCreateDrawTargetForCairoSurface(cairo_surf);
    assert !azure_target.is_null();

    loop {
        sdl::event::poll_event {|event|
            alt event {
              sdl::event::keydown_event(_) {
                key_handlers.iter {|key_ch|
                    comm::send(key_ch, ())
                }
              }
              _ { }
            }
        }

        // Handle messages
        if comm::peek(po) {
            alt check comm::recv(po) {
              add_key_handler(key_ch) {
                key_handlers += [key_ch];
              }
              get_draw_target(response_ch) {
                comm::send(response_ch, azure_target);
              }
              draw(response_ch) {
                sdl::video::unlock_surface(sdl_surf);
                sdl::video::blit_surface(sdl_surf, ptr::null(),
                                         screen, ptr::null());
                sdl::video::lock_surface(sdl_surf);
                sdl::video::flip(screen);
                comm::send(response_ch, ());
              }
              exit { break; }
            }
        }
    }
    AzReleaseDrawTarget(azure_target);
    cairo_surface_destroy(cairo_surf);
    sdl::video::unlock_surface(sdl_surf);
    sdl::quit();
}<commit_msg>Work around type inference problem<commit_after>#[cfg(target_os = "linux")]
mod platform {
    fn runmain(f: fn()) {
        f()
    }
}

#[cfg(target_os = "macos")]
mod platform {
    use cocoa;
    import cocoa::base::*;

    mod NSApplication {
        fn sharedApplication() -> id {
            let klass = str::as_c_str("NSApplication") { |s|
                objc::objc_getClass(s)
            };

            let sel = str::as_c_str("sharedApplication") { |s|
                objc::sel_registerName(s)
            };

            let nsapp = objc::objc_msgSend(klass, sel);
            #debug("nsapp: %d", (nsapp as int));

	    ret nsapp;
        }
    }

    mod NSAutoreleasePool {
        fn alloc() -> id {
            let klass = str::as_c_str("NSAutoreleasePool") { |s|
                objc::objc_getClass(s)
            };
            let sel = str::as_c_str("alloc") { |s|
                objc::sel_registerName(s)
            };
            let pool = objc::objc_msgSend(klass, sel);
            #debug("autorelease pool: %?", pool);
            ret pool;
        }
        fn init(pool: id) {
            let sel = str::as_c_str("init") { |s|
                objc::sel_registerName(s)
            };
            objc::objc_msgSend(pool, sel);
        }
        fn release(pool: id) {
            let sel = str::as_c_str("release") { |s|
                objc::sel_registerName(s)
            };
            objc::objc_msgSend(pool, sel);
        }
    }

    mod NSApp {
         fn setDelegate(nsapp: id, main: id) {
	     #debug("NSApp::setDelegate");
	     let sel = str::as_c_str("setDelegate:") { |s|
	         objc::sel_registerName(s)
	     };
	     cocoa::msgSend1Id(nsapp, sel, main);
         }

         fn run(nsapp: id) {
	    #debug("NSApp::run");
            let sel = str::as_c_str("run") { |s|
                objc::sel_registerName(s)
            };
            objc::objc_msgSend(nsapp, sel);
         }
    }

    mod MainObj {
         crust fn applicationDidFinishLaunching(this: id, _sel: SEL) {
	     #debug("applicationDidFinishLaunching");

	     let fptr: *fn() = ptr::null();
	     str::as_c_str("fptr") { |name|
	         let outValue = unsafe { unsafe::reinterpret_cast(ptr::addr_of(fptr)) };
                 #debug("*fptr %?", outValue);
                 objc::object_getInstanceVariable(this, name, outValue)
             };

	     #debug("getting osmain fptr: %?", fptr);

	     unsafe {
	         // FIXME: We probably don't want to run the main routine in a crust function
                 (*fptr)();
             }
	 }

    	 fn create(f: fn()) -> id {
             let NSObject = str::as_c_str("NSObject") { |s|
	         objc::objc_getClass(s)
             };
	     let MainObj = str::as_c_str("MainObj") { |s|
	         objc::objc_allocateClassPair(NSObject, s, 0 as libc::size_t)
	     };

             // Add a field to our class to contain a pointer to a rust closure
	     let res = str::as_c_str("fptr") { |name|
                 str::as_c_str("^i") { |types|
                     objc::class_addIvar(MainObj, name,
                                         sys::size_of::<libc::uintptr_t>() as libc::size_t,
                                         16u8, types)
                 }
             };
 	     assert res == true;

	     let launchfn = str::as_c_str("applicationDidFinishLaunching:") { |s|
	         objc::sel_registerName(s)
	     };
	     let _ = str::as_c_str("@@:") { |types|
	         objc::class_addMethod(MainObj, launchfn, applicationDidFinishLaunching, types)
	     };

	     objc::objc_registerClassPair(MainObj);

             let sel = str::as_c_str("alloc") { |s|
                 objc::sel_registerName(s)
             };
             let mainobj = objc::objc_msgSend(MainObj, sel);

             let sel = str::as_c_str("init") { |s|
                 objc::sel_registerName(s)
             };
             objc::objc_msgSend(mainobj, sel);

	     let fptr = ptr::addr_of(f);
	     str::as_c_str("fptr") { |name|
	         #debug("setting osmain fptr: %?", fptr);
		 let value = unsafe { unsafe::reinterpret_cast(fptr) };
                 #debug("*fptr: %?", value);
                 objc::object_setInstanceVariable(mainobj, name, value)
             };

	     ret mainobj;
	 }
	 fn release(mainobj: id) {
             let sel = str::as_c_str("release") { |s|
                 objc::sel_registerName(s)
             };
             objc::objc_msgSend(mainobj, sel);
	 }
    }

    fn runmain(f: fn()) {
	let pool = NSAutoreleasePool::alloc();
	NSAutoreleasePool::init(pool);
        let NSApp = NSApplication::sharedApplication();

        let mainobj = MainObj::create(f);
	NSApp::setDelegate(NSApp, mainobj);
	NSApp::run(NSApp);

	MainObj::release(mainobj);
	NSAutoreleasePool::release(pool);
    }
}

enum msg {
    get_draw_target(comm::chan<AzDrawTargetRef>),
    add_key_handler(comm::chan<()>),
    draw(comm::chan<()>),
    exit
}

fn osmain() -> comm::chan<msg> {
    on_osmain::<msg> {|po|
        platform::runmain {||
            #debug("preparing to enter main loop");
	    mainloop(po);
        }
    }
}

// A function for spawning into the platform's main thread
fn on_osmain<T: send>(f: fn~(comm::port<T>)) -> comm::chan<T> {
    let builder = task::builder();
    let opts = {
        sched: some({
            mode: task::osmain,
            native_stack_size: none
        })
        with task::get_opts(builder)
    };
    task::set_opts(builder, opts);
    ret task::run_listener(builder, f);
}

fn mainloop(po: comm::port<msg>) {

    let mut key_handlers = [];

    sdl::init([
        sdl::init_video
    ]);
    let screen = sdl::video::set_video_mode(
        800, 600, 32,
        [sdl::video::swsurface],
        [sdl::video::doublebuf]);
    assert !ptr::is_null(screen);
    let sdl_surf = sdl::video::create_rgb_surface(
        [sdl::video::swsurface],
        800, 600, 32,
        0x00FF0000u32,
        0x0000FF00u32,
        0x000000FFu32,
        0x00000000u32
        );
    assert !ptr::is_null(sdl_surf);
    sdl::video::lock_surface(sdl_surf);
    let cairo_surf = unsafe {
        cairo_image_surface_create_for_data(
            unsafe::reinterpret_cast((*sdl_surf).pixels),
            cairo::CAIRO_FORMAT_RGB24,
            (*sdl_surf).w,
            (*sdl_surf).h,
            (*sdl_surf).pitch as libc::c_int
        )
    };
    assert !ptr::is_null(cairo_surf);
    let azure_target = AzCreateDrawTargetForCairoSurface(cairo_surf);
    assert !ptr::is_null(azure_target);

    loop {
        sdl::event::poll_event {|event|
            alt event {
              sdl::event::keydown_event(_) {
                key_handlers.iter {|key_ch|
                    comm::send(key_ch, ())
                }
              }
              _ { }
            }
        }

        // Handle messages
        if comm::peek(po) {
            alt check comm::recv(po) {
              add_key_handler(key_ch) {
                key_handlers += [key_ch];
              }
              get_draw_target(response_ch) {
                comm::send(response_ch, azure_target);
              }
              draw(response_ch) {
                sdl::video::unlock_surface(sdl_surf);
                sdl::video::blit_surface(sdl_surf, ptr::null(),
                                         screen, ptr::null());
                sdl::video::lock_surface(sdl_surf);
                sdl::video::flip(screen);
                comm::send(response_ch, ());
              }
              exit { break; }
            }
        }
    }
    AzReleaseDrawTarget(azure_target);
    cairo_surface_destroy(cairo_surf);
    sdl::video::unlock_surface(sdl_surf);
    sdl::quit();
}<|endoftext|>