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

use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::WebSocketBinding;
use dom::bindings::codegen::Bindings::WebSocketBinding::WebSocketMethods;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::InheritTypes::EventTargetCast;
use dom::bindings::codegen::InheritTypes::EventCast;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::error::Error::{InvalidAccess, Syntax};
use dom::bindings::global::{GlobalField, GlobalRef};
use dom::bindings::js::Root;
use dom::bindings::refcounted::Trusted;
use dom::bindings::str::USVString;
use dom::bindings::trace::JSTraceable;
use dom::bindings::utils::reflect_dom_object;
use dom::closeevent::CloseEvent;
use dom::event::{Event, EventBubbles, EventCancelable, EventHelpers};
use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId};
use script_task::Runnable;
use script_task::ScriptMsg;
use std::cell::{Cell, RefCell};
use std::borrow::ToOwned;
use util::str::DOMString;

use websocket::Message;
use websocket::ws::sender::Sender as Sender_Object;
use websocket::client::sender::Sender;
use websocket::client::receiver::Receiver;
use websocket::stream::WebSocketStream;
use websocket::client::request::Url;
use websocket::Client;

#[derive(JSTraceable, PartialEq, Copy, Clone)]
enum WebSocketRequestState {
    Connecting = 0,
    Open = 1,
    Closing = 2,
    Closed = 3,
}

no_jsmanaged_fields!(Sender<WebSocketStream>);
no_jsmanaged_fields!(Receiver<WebSocketStream>);

#[dom_struct]
pub struct WebSocket {
    eventtarget: EventTarget,
    url: Url,
    global: GlobalField,
    ready_state: Cell<WebSocketRequestState>,
    sender: RefCell<Option<Sender<WebSocketStream>>>,
    receiver: RefCell<Option<Receiver<WebSocketStream>>>,
    failed: Cell<bool>, //Flag to tell if websocket was closed due to failure
    full: Cell<bool>, //Flag to tell if websocket queue is full
    clean_close: Cell<bool>, //Flag to tell if the websocket closed cleanly (not due to full or fail)
    code: Cell<u16>, //Closing code
    reason: DOMRefCell<DOMString>, //Closing reason
    data: DOMRefCell<DOMString>, //Data from send - TODO: Remove after buffer is added.
    sendCloseFrame: Cell<bool>
}

fn parse_web_socket_url(url_str: &str) -> Fallible<(Url, String, u16, String, bool)> {
    // https://html.spec.whatwg.org/multipage/#parse-a-websocket-url's-components
    // Steps 1 and 2
    let parsed_url = Url::parse(url_str);
    let parsed_url = match parsed_url {
        Ok(parsed_url) => parsed_url,
        Err(_) => return Err(Error::Syntax),
    };

    // Step 4
    if parsed_url.fragment != None {
        return Err(Error::Syntax);
    }

    // Steps 3 and 5
    let secure = match parsed_url.scheme.as_ref() {
        "ws" => false,
        "wss" => true,
        _ => return Err(Error::Syntax), // step 3
    };

    let host = parsed_url.host().unwrap().serialize(); // Step 6
    let port = parsed_url.port_or_default().unwrap(); // Steps 7 and 8
    let mut resource = parsed_url.path().unwrap().connect("/"); // Step 9
    if resource.is_empty() {
        resource = "/".to_owned(); // Step 10
    }

    // Step 11
    if let Some(ref query) = parsed_url.query {
        resource.push('?');
        resource.push_str(query);
    }

    // Step 12
    // FIXME remove parsed_url once it's no longer used in WebSocket::new
    Ok((parsed_url, host, port, resource, secure))
}

impl WebSocket {
    pub fn new_inherited(global: GlobalRef, url: Url) -> WebSocket {
        WebSocket {
            eventtarget: EventTarget::new_inherited(EventTargetTypeId::WebSocket),
            url: url,
            global: GlobalField::from_rooted(&global),
            ready_state: Cell::new(WebSocketRequestState::Connecting),
            failed: Cell::new(false),
            sender: RefCell::new(None),
            receiver: RefCell::new(None),
            full: Cell::new(false),
            clean_close: Cell::new(true),
            code: Cell::new(0),
            reason: DOMRefCell::new("".to_owned()),
            data: DOMRefCell::new("".to_owned()),
            sendCloseFrame: Cell::new(false)
        }

    }

    pub fn new(global: GlobalRef, url: DOMString) -> Fallible<Root<WebSocket>> {
        // Step 1.
        // FIXME extract the right variables once Client::connect
        // implementation is fixed to follow the RFC 6455 properly.
        let (url, _, _, _, _) = try!(parse_web_socket_url(&url));

        /*TODO: This constructor is only a prototype, it does not accomplish the specs
          defined here:
          http://html.spec.whatwg.org
          The remaining 8 items must be satisfied.
          TODO: This constructor should be responsible for spawning a thread for the
          receive loop after ws.r().Open() - See comment
        */
        let ws = reflect_dom_object(box WebSocket::new_inherited(global, url.clone()),
                                    global,
                                    WebSocketBinding::Wrap);

        // TODO Client::connect does not conform to RFC 6455
        // see https://github.com/cyderize/rust-websocket/issues/38
        let request = match Client::connect(url) {
            Ok(request) => request,
            Err(_) => {
                let global_root = ws.r().global.root();
                let address = Trusted::new(global_root.r().get_cx(), ws.r(), global_root.r().script_chan().clone());
                let task = box WebSocketTaskHandler::new(address, WebSocketTask::Close);
                global_root.r().script_chan().send(ScriptMsg::RunnableMsg(task)).unwrap();
                return Ok(ws);
            }
        };
        let response = request.send().unwrap();
        response.validate().unwrap();
        ws.r().ready_state.set(WebSocketRequestState::Open);
        //Check to see if ready_state is Closing or Closed and failed = true - means we failed the websocket
        //if so return without setting any states
        let ready_state = ws.r().ready_state.get();
        let failed = ws.r().failed.get();
        if failed && (ready_state == WebSocketRequestState::Closed || ready_state == WebSocketRequestState::Closing) {
            //Do nothing else. Let the close finish.
            return Ok(ws);
        }

        let (temp_sender, temp_receiver) = response.begin().split();
        *ws.r().sender.borrow_mut() = Some(temp_sender);
        *ws.r().receiver.borrow_mut() = Some(temp_receiver);

        //Create everything necessary for starting the open asynchronous task, then begin the task.
        let global_root = ws.r().global.root();
        let addr: Trusted<WebSocket> =
            Trusted::new(global_root.r().get_cx(), ws.r(), global_root.r().script_chan().clone());
        let open_task = box WebSocketTaskHandler::new(addr.clone(), WebSocketTask::Open);
        global_root.r().script_chan().send(ScriptMsg::RunnableMsg(open_task)).unwrap();
        //TODO: Spawn thread here for receive loop
        /*TODO: Add receive loop here and make new thread run this
          Receive is an infinite loop "similiar" the one shown here:
          https://github.com/cyderize/rust-websocket/blob/master/examples/client.rs#L64
          TODO: The receive loop however does need to follow the spec. These are outlined here
          under "WebSocket message has been received" items 1-5:
          https://github.com/cyderize/rust-websocket/blob/master/examples/client.rs#L64
          TODO: The receive loop also needs to dispatch an asynchronous event as stated here:
          https://github.com/cyderize/rust-websocket/blob/master/examples/client.rs#L64
          TODO: When the receive loop receives a close message from the server,
          it confirms the websocket is now closed. This requires the close event
          to be fired (dispatch_close fires the close event - see implementation below)
        */
        Ok(ws)
    }

    pub fn Constructor(global: GlobalRef, url: DOMString) -> Fallible<Root<WebSocket>> {
        WebSocket::new(global, url)
    }
}

impl<'a> WebSocketMethods for &'a WebSocket {
    event_handler!(open, GetOnopen, SetOnopen);
    event_handler!(close, GetOnclose, SetOnclose);
    event_handler!(error, GetOnerror, SetOnerror);

    fn Url(self) -> DOMString {
        self.url.serialize()
    }

    fn ReadyState(self) -> u16 {
        self.ready_state.get() as u16
    }

    fn Send(self, data: Option<USVString>)-> Fallible<()>{
        /*TODO: This is not up to spec see http://html.spec.whatwg.org/multipage/comms.html search for
                "If argument is a string"
          TODO: Need to buffer data
          TODO: bufferedAmount attribute returns the size of the buffer in bytes -
                this is a required attribute defined in the websocket.webidl file
          TODO: The send function needs to flag when full by using the following
          self.full.set(true). This needs to be done when the buffer is full
        */
        let mut other_sender = self.sender.borrow_mut();
        let my_sender = other_sender.as_mut().unwrap();
        if self.sendCloseFrame.get() { //TODO: Also check if the buffer is full
            self.sendCloseFrame.set(false);
            let _ = my_sender.send_message(Message::Close(None));
            return Ok(());
        }
        let _ = my_sender.send_message(Message::Text(data.unwrap().0));
        return Ok(())
    }

    fn Close(self, code: Option<u16>, reason: Option<USVString>) -> Fallible<()>{
        if let Some(code) = code {
            //Check code is NOT 1000 NOR in the range of 3000-4999 (inclusive)
            if  code != 1000 && (code < 3000 || code > 4999) {
                return Err(Error::InvalidAccess);
            }
        }
        if let Some(ref reason) = reason {
            if reason.0.as_bytes().len() > 123 { //reason cannot be larger than 123 bytes
                return Err(Error::Syntax);
            }
        }

        match self.ready_state.get() {
            WebSocketRequestState::Closing | WebSocketRequestState::Closed  => {} //Do nothing
            WebSocketRequestState::Connecting => { //Connection is not yet established
                /*By setting the state to closing, the open function
                  will abort connecting the websocket*/
                self.ready_state.set(WebSocketRequestState::Closing);
                self.failed.set(true);
                self.sendCloseFrame.set(true);
                //Dispatch send task to send close frame
                //TODO: Sending here is just empty string, though no string is really needed. Another send, empty
                //      send, could be used.
                let _ = self.Send(None);
                //Note: After sending the close message, the receive loop confirms a close message from the server and
                //      must fire a close event
            }
            WebSocketRequestState::Open => {
                //Closing handshake not started - still in open
                //Start the closing by setting the code and reason if they exist
                if let Some(code) = code {
                    self.code.set(code);
                }
                if let Some(reason) = reason {
                    *self.reason.borrow_mut() = reason.0;
                }
                self.ready_state.set(WebSocketRequestState::Closing);
                self.sendCloseFrame.set(true);
                //Dispatch send task to send close frame
                let _ = self.Send(None);
                //Note: After sending the close message, the receive loop confirms a close message from the server and
                //      must fire a close event
            }
        }
        Ok(()) //Return Ok
    }
}

pub enum WebSocketTask {
    Open,
    Close,
}

pub struct WebSocketTaskHandler {
    addr: Trusted<WebSocket>,
    task: WebSocketTask,
}

impl WebSocketTaskHandler {
    pub fn new(addr: Trusted<WebSocket>, task: WebSocketTask) -> WebSocketTaskHandler {
        WebSocketTaskHandler {
            addr: addr,
            task: task,
        }
    }

    fn dispatch_open(&self) {
        /*TODO: Items 1, 3, 4, & 5 under "WebSocket connection is established" as specified here:
          https://html.spec.whatwg.org/multipage/#feedback-from-the-protocol
        */
        let ws = self.addr.root(); //Get root
        let ws = ws.r(); //Get websocket reference
        let global = ws.global.root();
        let event = Event::new(global.r(),
            "open".to_owned(),
            EventBubbles::DoesNotBubble,
            EventCancelable::NotCancelable);
        let target = EventTargetCast::from_ref(ws);
        event.r().fire(target);
    }

    fn dispatch_close(&self) {
        let ws = self.addr.root();
        let ws = ws.r();
        let global = ws.global.root();
        ws.ready_state.set(WebSocketRequestState::Closed);
        //If failed or full, fire error event
        if ws.failed.get() || ws.full.get() {
            ws.failed.set(false);
            ws.full.set(false);
            //A Bad close
            ws.clean_close.set(false);
            let event = Event::new(global.r(),
                                   "error".to_owned(),
                                   EventBubbles::DoesNotBubble,
                                   EventCancelable::Cancelable);
            let target = EventTargetCast::from_ref(ws);
            event.r().fire(target);
        }
        let rsn = ws.reason.borrow();
        let rsn_clone = rsn.clone();
        /*In addition, we also have to fire a close even if error event fired
         https://html.spec.whatwg.org/multipage/#closeWebSocket
        */
        let close_event = CloseEvent::new(global.r(),
                                          "close".to_owned(),
                                          EventBubbles::DoesNotBubble,
                                          EventCancelable::NotCancelable,
                                          ws.clean_close.get(),
                                          ws.code.get(),
                                          rsn_clone);
        let target = EventTargetCast::from_ref(ws);
        let event = EventCast::from_ref(close_event.r());
        event.fire(target);
    }
}

impl Runnable for WebSocketTaskHandler {
    fn handler(self: Box<WebSocketTaskHandler>) {
        match self.task {
            WebSocketTask::Open => {
                self.dispatch_open();
            }
            WebSocketTask::Close => {
                self.dispatch_close();
            }
        }
    }
}

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

use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::WebSocketBinding;
use dom::bindings::codegen::Bindings::WebSocketBinding::WebSocketMethods;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::InheritTypes::EventTargetCast;
use dom::bindings::codegen::InheritTypes::EventCast;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::error::Error::{InvalidAccess, Syntax};
use dom::bindings::global::{GlobalField, GlobalRef};
use dom::bindings::js::Root;
use dom::bindings::refcounted::Trusted;
use dom::bindings::str::USVString;
use dom::bindings::trace::JSTraceable;
use dom::bindings::utils::reflect_dom_object;
use dom::closeevent::CloseEvent;
use dom::event::{Event, EventBubbles, EventCancelable, EventHelpers};
use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId};
use script_task::Runnable;
use script_task::ScriptMsg;
use std::cell::{Cell, RefCell};
use std::borrow::ToOwned;
use util::str::DOMString;

use websocket::Message;
use websocket::ws::sender::Sender as Sender_Object;
use websocket::client::sender::Sender;
use websocket::client::receiver::Receiver;
use websocket::stream::WebSocketStream;
use websocket::client::request::Url;
use websocket::Client;

#[derive(JSTraceable, PartialEq, Copy, Clone)]
enum WebSocketRequestState {
    Connecting = 0,
    Open = 1,
    Closing = 2,
    Closed = 3,
}

no_jsmanaged_fields!(Sender<WebSocketStream>);
no_jsmanaged_fields!(Receiver<WebSocketStream>);

#[dom_struct]
pub struct WebSocket {
    eventtarget: EventTarget,
    url: Url,
    global: GlobalField,
    ready_state: Cell<WebSocketRequestState>,
    sender: RefCell<Option<Sender<WebSocketStream>>>,
    receiver: RefCell<Option<Receiver<WebSocketStream>>>,
    failed: Cell<bool>, //Flag to tell if websocket was closed due to failure
    full: Cell<bool>, //Flag to tell if websocket queue is full
    clean_close: Cell<bool>, //Flag to tell if the websocket closed cleanly (not due to full or fail)
    code: Cell<u16>, //Closing code
    reason: DOMRefCell<DOMString>, //Closing reason
    data: DOMRefCell<DOMString>, //Data from send - TODO: Remove after buffer is added.
    sendCloseFrame: Cell<bool>
}

fn parse_web_socket_url(url_str: &str) -> Fallible<(Url, String, u16, String, bool)> {
    // https://html.spec.whatwg.org/multipage/#parse-a-websocket-url's-components
    // Steps 1 and 2
    let parsed_url = Url::parse(url_str);
    let parsed_url = match parsed_url {
        Ok(parsed_url) => parsed_url,
        Err(_) => return Err(Error::Syntax),
    };

    // Step 4
    if parsed_url.fragment != None {
        return Err(Error::Syntax);
    }

    // Steps 3 and 5
    let secure = match parsed_url.scheme.as_ref() {
        "ws" => false,
        "wss" => true,
        _ => return Err(Error::Syntax), // step 3
    };

    let host = parsed_url.host().unwrap().serialize(); // Step 6
    let port = parsed_url.port_or_default().unwrap(); // Steps 7 and 8
    let mut resource = parsed_url.path().unwrap().connect("/"); // Step 9
    if resource.is_empty() {
        resource = "/".to_owned(); // Step 10
    }

    // Step 11
    if let Some(ref query) = parsed_url.query {
        resource.push('?');
        resource.push_str(query);
    }

    // Step 12
    // FIXME remove parsed_url once it's no longer used in WebSocket::new
    Ok((parsed_url, host, port, resource, secure))
}

impl WebSocket {
    pub fn new_inherited(global: GlobalRef, url: Url) -> WebSocket {
        WebSocket {
            eventtarget: EventTarget::new_inherited(EventTargetTypeId::WebSocket),
            url: url,
            global: GlobalField::from_rooted(&global),
            ready_state: Cell::new(WebSocketRequestState::Connecting),
            failed: Cell::new(false),
            sender: RefCell::new(None),
            receiver: RefCell::new(None),
            full: Cell::new(false),
            clean_close: Cell::new(true),
            code: Cell::new(0),
            reason: DOMRefCell::new("".to_owned()),
            data: DOMRefCell::new("".to_owned()),
            sendCloseFrame: Cell::new(false)
        }

    }

    pub fn new(global: GlobalRef, url: DOMString) -> Fallible<Root<WebSocket>> {
        // Step 1.
        // FIXME extract the right variables once Client::connect
        // implementation is fixed to follow the RFC 6455 properly.
        let (url, _, _, _, _) = try!(parse_web_socket_url(&url));

        /*TODO: This constructor is only a prototype, it does not accomplish the specs
          defined here:
          http://html.spec.whatwg.org
          The remaining 8 items must be satisfied.
          TODO: This constructor should be responsible for spawning a thread for the
          receive loop after ws.r().Open() - See comment
        */
        let ws = reflect_dom_object(box WebSocket::new_inherited(global, url.clone()),
                                    global,
                                    WebSocketBinding::Wrap);

        // TODO Client::connect does not conform to RFC 6455
        // see https://github.com/cyderize/rust-websocket/issues/38
        let request = match Client::connect(url) {
            Ok(request) => request,
            Err(_) => {
                let global_root = ws.r().global.root();
                let address = Trusted::new(global_root.r().get_cx(), ws.r(), global_root.r().script_chan().clone());
                let task = box WebSocketTaskHandler::new(address, WebSocketTask::Close);
                global_root.r().script_chan().send(ScriptMsg::RunnableMsg(task)).unwrap();
                return Ok(ws);
            }
        };
        let response = request.send().unwrap();
        response.validate().unwrap();
        ws.r().ready_state.set(WebSocketRequestState::Open);

        let (temp_sender, temp_receiver) = response.begin().split();
        *ws.r().sender.borrow_mut() = Some(temp_sender);
        *ws.r().receiver.borrow_mut() = Some(temp_receiver);

        //Create everything necessary for starting the open asynchronous task, then begin the task.
        let global_root = ws.r().global.root();
        let addr: Trusted<WebSocket> =
            Trusted::new(global_root.r().get_cx(), ws.r(), global_root.r().script_chan().clone());
        let open_task = box WebSocketTaskHandler::new(addr.clone(), WebSocketTask::Open);
        global_root.r().script_chan().send(ScriptMsg::RunnableMsg(open_task)).unwrap();
        //TODO: Spawn thread here for receive loop
        /*TODO: Add receive loop here and make new thread run this
          Receive is an infinite loop "similiar" the one shown here:
          https://github.com/cyderize/rust-websocket/blob/master/examples/client.rs#L64
          TODO: The receive loop however does need to follow the spec. These are outlined here
          under "WebSocket message has been received" items 1-5:
          https://github.com/cyderize/rust-websocket/blob/master/examples/client.rs#L64
          TODO: The receive loop also needs to dispatch an asynchronous event as stated here:
          https://github.com/cyderize/rust-websocket/blob/master/examples/client.rs#L64
          TODO: When the receive loop receives a close message from the server,
          it confirms the websocket is now closed. This requires the close event
          to be fired (dispatch_close fires the close event - see implementation below)
        */
        Ok(ws)
    }

    pub fn Constructor(global: GlobalRef, url: DOMString) -> Fallible<Root<WebSocket>> {
        WebSocket::new(global, url)
    }
}

impl<'a> WebSocketMethods for &'a WebSocket {
    event_handler!(open, GetOnopen, SetOnopen);
    event_handler!(close, GetOnclose, SetOnclose);
    event_handler!(error, GetOnerror, SetOnerror);

    fn Url(self) -> DOMString {
        self.url.serialize()
    }

    fn ReadyState(self) -> u16 {
        self.ready_state.get() as u16
    }

    fn Send(self, data: Option<USVString>)-> Fallible<()>{
        /*TODO: This is not up to spec see http://html.spec.whatwg.org/multipage/comms.html search for
                "If argument is a string"
          TODO: Need to buffer data
          TODO: bufferedAmount attribute returns the size of the buffer in bytes -
                this is a required attribute defined in the websocket.webidl file
          TODO: The send function needs to flag when full by using the following
          self.full.set(true). This needs to be done when the buffer is full
        */
        let mut other_sender = self.sender.borrow_mut();
        let my_sender = other_sender.as_mut().unwrap();
        if self.sendCloseFrame.get() { //TODO: Also check if the buffer is full
            self.sendCloseFrame.set(false);
            let _ = my_sender.send_message(Message::Close(None));
            return Ok(());
        }
        let _ = my_sender.send_message(Message::Text(data.unwrap().0));
        return Ok(())
    }

    fn Close(self, code: Option<u16>, reason: Option<USVString>) -> Fallible<()>{
        if let Some(code) = code {
            //Check code is NOT 1000 NOR in the range of 3000-4999 (inclusive)
            if  code != 1000 && (code < 3000 || code > 4999) {
                return Err(Error::InvalidAccess);
            }
        }
        if let Some(ref reason) = reason {
            if reason.0.as_bytes().len() > 123 { //reason cannot be larger than 123 bytes
                return Err(Error::Syntax);
            }
        }

        match self.ready_state.get() {
            WebSocketRequestState::Closing | WebSocketRequestState::Closed  => {} //Do nothing
            WebSocketRequestState::Connecting => { //Connection is not yet established
                /*By setting the state to closing, the open function
                  will abort connecting the websocket*/
                self.ready_state.set(WebSocketRequestState::Closing);
                self.failed.set(true);
                self.sendCloseFrame.set(true);
                //Dispatch send task to send close frame
                //TODO: Sending here is just empty string, though no string is really needed. Another send, empty
                //      send, could be used.
                let _ = self.Send(None);
                //Note: After sending the close message, the receive loop confirms a close message from the server and
                //      must fire a close event
            }
            WebSocketRequestState::Open => {
                //Closing handshake not started - still in open
                //Start the closing by setting the code and reason if they exist
                if let Some(code) = code {
                    self.code.set(code);
                }
                if let Some(reason) = reason {
                    *self.reason.borrow_mut() = reason.0;
                }
                self.ready_state.set(WebSocketRequestState::Closing);
                self.sendCloseFrame.set(true);
                //Dispatch send task to send close frame
                let _ = self.Send(None);
                //Note: After sending the close message, the receive loop confirms a close message from the server and
                //      must fire a close event
            }
        }
        Ok(()) //Return Ok
    }
}

pub enum WebSocketTask {
    Open,
    Close,
}

pub struct WebSocketTaskHandler {
    addr: Trusted<WebSocket>,
    task: WebSocketTask,
}

impl WebSocketTaskHandler {
    pub fn new(addr: Trusted<WebSocket>, task: WebSocketTask) -> WebSocketTaskHandler {
        WebSocketTaskHandler {
            addr: addr,
            task: task,
        }
    }

    fn dispatch_open(&self) {
        /*TODO: Items 1, 3, 4, & 5 under "WebSocket connection is established" as specified here:
          https://html.spec.whatwg.org/multipage/#feedback-from-the-protocol
        */
        let ws = self.addr.root(); //Get root
        let ws = ws.r(); //Get websocket reference
        let global = ws.global.root();
        let event = Event::new(global.r(),
            "open".to_owned(),
            EventBubbles::DoesNotBubble,
            EventCancelable::NotCancelable);
        let target = EventTargetCast::from_ref(ws);
        event.r().fire(target);
    }

    fn dispatch_close(&self) {
        let ws = self.addr.root();
        let ws = ws.r();
        let global = ws.global.root();
        ws.ready_state.set(WebSocketRequestState::Closed);
        //If failed or full, fire error event
        if ws.failed.get() || ws.full.get() {
            ws.failed.set(false);
            ws.full.set(false);
            //A Bad close
            ws.clean_close.set(false);
            let event = Event::new(global.r(),
                                   "error".to_owned(),
                                   EventBubbles::DoesNotBubble,
                                   EventCancelable::Cancelable);
            let target = EventTargetCast::from_ref(ws);
            event.r().fire(target);
        }
        let rsn = ws.reason.borrow();
        let rsn_clone = rsn.clone();
        /*In addition, we also have to fire a close even if error event fired
         https://html.spec.whatwg.org/multipage/#closeWebSocket
        */
        let close_event = CloseEvent::new(global.r(),
                                          "close".to_owned(),
                                          EventBubbles::DoesNotBubble,
                                          EventCancelable::NotCancelable,
                                          ws.clean_close.get(),
                                          ws.code.get(),
                                          rsn_clone);
        let target = EventTargetCast::from_ref(ws);
        let event = EventCast::from_ref(close_event.r());
        event.fire(target);
    }
}

impl Runnable for WebSocketTaskHandler {
    fn handler(self: Box<WebSocketTaskHandler>) {
        match self.task {
            WebSocketTask::Open => {
                self.dispatch_open();
            }
            WebSocketTask::Close => {
                self.dispatch_close();
            }
        }
    }
}

<|endoftext|>


<commit_before>use rosrust_diagnostics::{CompositeTask, FunctionExt, Level, Status, Task};

#[test]
fn oks_get_ignored_when_issues_arise() {
    let task_noop = (|_: &mut Status| {}).into_task("task_noop");

    let task1 = (|status: &mut Status| {
        status.set_summary(Level::Warn, "foo");
        status.add("one", 1);
    })
    .into_task("my_task1");

    let task2 = (|status: &mut Status| {
        status.set_summary(Level::Error, "bar");
        status.add("two", 2);
    })
    .into_task("my_task2");

    let task3 = (|status: &mut Status| {
        status.set_summary(Level::Ok, "baz");
        status.add("three", 3);
    })
    .into_task("my_task3");

    let mut target = Status::default();
    target.set_summary(Level::Ok, "start");

    let mut task = CompositeTask::new("composite_task");
    task.add_task(task_noop.clone());
    task.add_task(task1);
    task.add_task(task2);
    task.add_task(task3);
    task.add_task(task_noop);

    task.run(&mut target);

    assert_eq!(&target.message, "foo; bar");
    assert_eq!(target.level, Level::Error);
    assert_eq!(target.values.len(), 3);
    assert_eq!(target.values[0].key, "one");
    assert_eq!(target.values[0].value, "1");
    assert_eq!(target.values[1].key, "two");
    assert_eq!(target.values[1].value, "2");
    assert_eq!(target.values[2].key, "three");
    assert_eq!(target.values[2].value, "3");
}

#[test]
fn oks_get_perserved_when_there_are_no_issues() {
    let task_noop = (|_: &mut Status| {}).into_task("task_noop");

    let task1 = (|status: &mut Status| {
        status.set_summary(Level::Ok, "foo");
        status.add("one", 1);
    })
    .into_task("my_task1");

    let task2 = (|status: &mut Status| {
        status.set_summary(Level::Ok, "bar");
        status.add("two", 2);
    })
    .into_task("my_task2");

    let task3 = (|status: &mut Status| {
        status.set_summary(Level::Ok, "baz");
        status.add("three", 3);
    })
    .into_task("my_task3");

    let mut target = Status::default();
    target.set_summary(Level::Ok, "start");

    let mut task = CompositeTask::new("composite_task");
    task.add_task(task_noop.clone());
    task.add_task(task1);
    task.add_task(task2);
    task.add_task(task3);
    task.add_task(task_noop);

    task.run(&mut target);

    assert_eq!(&target.message, "start; foo; bar; baz; start");
    assert_eq!(target.level, Level::Ok);
    assert_eq!(target.values.len(), 3);
    assert_eq!(target.values[0].key, "one");
    assert_eq!(target.values[0].value, "1");
    assert_eq!(target.values[1].key, "two");
    assert_eq!(target.values[1].value, "2");
    assert_eq!(target.values[2].key, "three");
    assert_eq!(target.values[2].value, "3");
}
<commit_msg>Fix diagnostics tests<commit_after>use rosrust_diagnostics::{CompositeTask, FunctionExt, Level, Status, Task};

#[test]
fn oks_get_ignored_when_issues_arise() {
    let task_noop = (|_: &mut Status| {}).into_task("task_noop");

    let task1 = (|status: &mut Status| {
        status.set_summary(Level::Warn, "foo");
        status.add("one", 1);
    })
    .into_task("my_task1");

    let task2 = (|status: &mut Status| {
        status.set_summary(Level::Error, "bar");
        status.add("two", 2);
    })
    .into_task("my_task2");

    let task3 = (|status: &mut Status| {
        status.set_summary(Level::Ok, "baz");
        status.add("three", 3);
    })
    .into_task("my_task3");

    let mut target = Status::default();
    target.set_summary(Level::Ok, "start");

    let mut task = CompositeTask::new("composite_task");
    task.add_task(&task_noop);
    task.add_task(&task1);
    task.add_task(&task2);
    task.add_task(&task3);
    task.add_task(&task_noop);

    task.run(&mut target);

    assert_eq!(&target.message, "foo; bar");
    assert_eq!(target.level, Level::Error);
    assert_eq!(target.values.len(), 3);
    assert_eq!(target.values[0].key, "one");
    assert_eq!(target.values[0].value, "1");
    assert_eq!(target.values[1].key, "two");
    assert_eq!(target.values[1].value, "2");
    assert_eq!(target.values[2].key, "three");
    assert_eq!(target.values[2].value, "3");
}

#[test]
fn oks_get_perserved_when_there_are_no_issues() {
    let task_noop = (|_: &mut Status| {}).into_task("task_noop");

    let task1 = (|status: &mut Status| {
        status.set_summary(Level::Ok, "foo");
        status.add("one", 1);
    })
    .into_task("my_task1");

    let task2 = (|status: &mut Status| {
        status.set_summary(Level::Ok, "bar");
        status.add("two", 2);
    })
    .into_task("my_task2");

    let task3 = (|status: &mut Status| {
        status.set_summary(Level::Ok, "baz");
        status.add("three", 3);
    })
    .into_task("my_task3");

    let mut target = Status::default();
    target.set_summary(Level::Ok, "start");

    let mut task = CompositeTask::new("composite_task");
    task.add_task(&task_noop);
    task.add_task(&task1);
    task.add_task(&task2);
    task.add_task(&task3);
    task.add_task(&task_noop);

    task.run(&mut target);

    assert_eq!(&target.message, "start; foo; bar; baz; start");
    assert_eq!(target.level, Level::Ok);
    assert_eq!(target.values.len(), 3);
    assert_eq!(target.values[0].key, "one");
    assert_eq!(target.values[0].value, "1");
    assert_eq!(target.values[1].key, "two");
    assert_eq!(target.values[1].value, "2");
    assert_eq!(target.values[2].key, "three");
    assert_eq!(target.values[2].value, "3");
}
<|endoftext|>


<commit_before>//! Shader programs.
//!
//! A shader program is a piece of code that runs on GPU, consuming vertices, primitives, geometry
//! patches and fragments and output into a framebuffer colors and depth information.
//!
//! Shaders are abstracted by *shader modules* – see the `render::shader::module` module for further
//! details. You are not supposed to write *shader programs* directly, but instead, you write one or
//! several *shader modules* and are automatically handed a *shader program* based on the analysis
//! of the *shader modules* you wrote and how you combined them.
use luminance::shader::program::Program as LProgram;
pub use luminance::shader::program::{ProgramError, Uniform, Uniformable, UniformBuilder,
                                     UniformInterface, UniformWarning};
use luminance::vertex::Vertex;
use std::error::Error;
use std::fmt;
use std::io;
use std::ops::Deref;

use render::shader::cheddar::syntax::GLSLConversionError;
use render::shader::module::Module;
use sys::resource::{DebugRes, Key, Load, Loaded, LogicalKey, Storage, StoreErrorOr, load_with};

/// Errors that can be risen by a shader.
#[derive(Debug)]
pub enum ShaderError {
  ModuleError(StoreErrorOr<Module>),
  GLSLConversionError(GLSLConversionError),
  ProgramError(ProgramError),
  KeyError(io::Error)
}

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

impl Error for ShaderError {
  fn description(&self) -> &str {
    match *self {
      ShaderError::ModuleError(_) => "module error",
      ShaderError::GLSLConversionError(_) => "GLSL conversion error",
      ShaderError::ProgramError(_) => "program error",
      ShaderError::KeyError(_) => "key error"
    }
  }

  fn cause(&self) -> Option<&Error> {
    match *self {
      ShaderError::ModuleError(ref err) => Some(err),
      ShaderError::GLSLConversionError(ref err) => Some(err),
      ShaderError::ProgramError(ref err) => Some(err),
      ShaderError::KeyError(ref err) => Some(err)
    }
  }
}

/// Shader program.
///
/// This program must be used in a pipeline to take effect.
pub struct Program<In, Out, Uni>(LProgram<In, Out, Uni>);

impl<In, Out, Uni> Deref for Program<In, Out, Uni> {
  type Target = LProgram<In, Out, Uni>;

  fn deref(&self) -> &Self::Target {
    &self.0
  }
}

impl<In, Out, Uni> DebugRes for Program<In, Out, Uni> {
  const TY_DESC: &'static str = "program";
}

impl<In, Out, Uni> Load for Program<In, Out, Uni>
    where In: 'static + Vertex,
          Out: 'static,
          Uni: 'static + UniformInterface {
  type Key = LogicalKey;

  type Error = ShaderError;

  fn load(key: Self::Key, store: &mut Storage) -> Result<Loaded<Self>, Self::Error> {
    let path = key.as_str().as_ref();

    load_with::<Self, _, _>(path, move || {
      let module_key = Key::<Module>::path(path.to_owned()).map_err(|e| ShaderError::KeyError(e))?;
      let module = store.get(&module_key).map_err(ShaderError::ModuleError)?;

      let module_ = module.borrow();

      match module_.to_glsl_setup() {
        Err(err) => {
          Err(ShaderError::GLSLConversionError(err))
        }
        Ok(fold) => {
          deb!("vertex shader");
          annotate_shader(&fold.vs);

          if let Some(ref gs) = fold.gs {
            deb!("geometry shader");
            annotate_shader(gs);
          }

          deb!("fragment shader");
          annotate_shader(&fold.fs);

          match LProgram::from_strings(None, &fold.vs, fold.gs.as_ref().map(String::as_str), &fold.fs) {
            Err(err) => {
              Err(ShaderError::ProgramError(err))
            }
            Ok((program, warnings)) => {
              // print warnings in case there’s any
              for warning in &warnings {
                warn!("{:?}", warning);
              }

              let res = Program(program);
              Ok(Loaded::with_deps(res, vec![module_key.into()]))
            }
          }
        }
      }
    })
  }

  impl_reload_passthrough!();
}

fn annotate_shader(s: &str) {
  for (i, line) in s.lines().enumerate() {
    info!("{:3}: {}", i + 1, line);
  }
}

pub trait UnwrapOrUnbound<T> {
  fn unwrap_or_unbound(self, builder: &UniformBuilder, warnings: &mut Vec<UniformWarning>) -> Uniform<T> where T: Uniformable;
}

impl<T> UnwrapOrUnbound<T> for Result<Uniform<T>, UniformWarning> {
  fn unwrap_or_unbound(self, builder: &UniformBuilder, warnings: &mut Vec<UniformWarning>) -> Uniform<T> where T: Uniformable {
    self.unwrap_or_else(|w| {
      warnings.push(w);
      builder.unbound()
    })
  }
}
<commit_msg>Remove the UnwrapOrUnbound trait.<commit_after>//! Shader programs.
//!
//! A shader program is a piece of code that runs on GPU, consuming vertices, primitives, geometry
//! patches and fragments and output into a framebuffer colors and depth information.
//!
//! Shaders are abstracted by *shader modules* – see the `render::shader::module` module for further
//! details. You are not supposed to write *shader programs* directly, but instead, you write one or
//! several *shader modules* and are automatically handed a *shader program* based on the analysis
//! of the *shader modules* you wrote and how you combined them.
use luminance::shader::program::Program as LProgram;
pub use luminance::shader::program::{ProgramError, Uniform, Uniformable, UniformBuilder,
                                     UniformInterface, UniformWarning};
use luminance::vertex::Vertex;
use std::error::Error;
use std::fmt;
use std::io;
use std::ops::Deref;

use render::shader::cheddar::syntax::GLSLConversionError;
use render::shader::module::Module;
use sys::resource::{DebugRes, Key, Load, Loaded, LogicalKey, Storage, StoreErrorOr, load_with};

/// Errors that can be risen by a shader.
#[derive(Debug)]
pub enum ShaderError {
  ModuleError(StoreErrorOr<Module>),
  GLSLConversionError(GLSLConversionError),
  ProgramError(ProgramError),
  KeyError(io::Error)
}

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

impl Error for ShaderError {
  fn description(&self) -> &str {
    match *self {
      ShaderError::ModuleError(_) => "module error",
      ShaderError::GLSLConversionError(_) => "GLSL conversion error",
      ShaderError::ProgramError(_) => "program error",
      ShaderError::KeyError(_) => "key error"
    }
  }

  fn cause(&self) -> Option<&Error> {
    match *self {
      ShaderError::ModuleError(ref err) => Some(err),
      ShaderError::GLSLConversionError(ref err) => Some(err),
      ShaderError::ProgramError(ref err) => Some(err),
      ShaderError::KeyError(ref err) => Some(err)
    }
  }
}

/// Shader program.
///
/// This program must be used in a pipeline to take effect.
pub struct Program<In, Out, Uni>(LProgram<In, Out, Uni>);

impl<In, Out, Uni> Deref for Program<In, Out, Uni> {
  type Target = LProgram<In, Out, Uni>;

  fn deref(&self) -> &Self::Target {
    &self.0
  }
}

impl<In, Out, Uni> DebugRes for Program<In, Out, Uni> {
  const TY_DESC: &'static str = "program";
}

impl<In, Out, Uni> Load for Program<In, Out, Uni>
    where In: 'static + Vertex,
          Out: 'static,
          Uni: 'static + UniformInterface {
  type Key = LogicalKey;

  type Error = ShaderError;

  fn load(key: Self::Key, store: &mut Storage) -> Result<Loaded<Self>, Self::Error> {
    let path = key.as_str().as_ref();

    load_with::<Self, _, _>(path, move || {
      let module_key = Key::<Module>::path(path.to_owned()).map_err(|e| ShaderError::KeyError(e))?;
      let module = store.get(&module_key).map_err(ShaderError::ModuleError)?;

      let module_ = module.borrow();

      match module_.to_glsl_setup() {
        Err(err) => {
          Err(ShaderError::GLSLConversionError(err))
        }
        Ok(fold) => {
          deb!("vertex shader");
          annotate_shader(&fold.vs);

          if let Some(ref gs) = fold.gs {
            deb!("geometry shader");
            annotate_shader(gs);
          }

          deb!("fragment shader");
          annotate_shader(&fold.fs);

          match LProgram::from_strings(None, &fold.vs, fold.gs.as_ref().map(String::as_str), &fold.fs) {
            Err(err) => {
              Err(ShaderError::ProgramError(err))
            }
            Ok((program, warnings)) => {
              // print warnings in case there’s any
              for warning in &warnings {
                warn!("{:?}", warning);
              }

              let res = Program(program);
              Ok(Loaded::with_deps(res, vec![module_key.into()]))
            }
          }
        }
      }
    })
  }

  impl_reload_passthrough!();
}

fn annotate_shader(s: &str) {
  for (i, line) in s.lines().enumerate() {
    info!("{:3}: {}", i + 1, line);
  }
}
<|endoftext|>


<commit_before>#![deny(rust_2018_idioms)]
#![deny(proc_macro_derive_resolution_fallback)]

mod channel;
mod guild;

use std::sync::{mpsc, Arc};
use std::thread;

use rendezvous_common::{
    data::*,
    ipc,
    parking_lot::RwLock,
    tracing::{self, debug, info, info_span, warn},
    Fallible,
};
use serenity::{
    model::{
        self,
        channel::{ChannelType, GuildChannel, Message, MessageType},
        guild::{Guild, Member},
        id::GuildId,
    },
    prelude::*,
};

use crate::{channel::{Channel, ChannelList}, guild::{GuildMap, GuildData, UserData, author_name}};

fn main() -> Fallible<()> {
    tracing::init()?;

    let token = std::env::var("RENDEZVOUS_DISCORD_BOT_TOKEN")?;

    let (msg_tx, msg_rx) = mpsc::channel();
    let (event_tx, event_rx) = mpsc::sync_channel(8);

    let handler = Handler::new(event_tx);
    let channels = Arc::clone(&handler.channels);
    let mut client = Client::new(&token, handler)?;
    ipc::spawn_socket(msg_tx, event_rx)?;

    let http = Arc::clone(&client.cache_and_http.http);
    thread::spawn(move || {
        for m in msg_rx {
            match m {
                Event::MessageCreated {
                    nickname,
                    channel,
                    content,
                    ..
                } => {
                    if !channel.starts_with("#") {
                        continue;
                    }
                    let channels = channels.read();
                    debug!(
                        "channels: {:?}",
                        channels.iter().map(|ch| ch.name()).collect::<Vec<_>>()
                    );
                    if let Some(ch) = channels.get_by_name(&channel[1..]) {
                        debug!("{:?}", ch);
                        ch.id()
                            .send_message(&*http, |m| {
                                m.content(format!("<{}> {}", nickname, content))
                            })
                            .unwrap();
                    } else {
                        warn!("unknown channel: {:?}", channel);
                    }
                }
                _ => {}
            }
        }
    });

    client.start_autosharded()?;

    Ok(())
}

struct Handler {
    guilds: RwLock<GuildMap>,
    channels: Arc<RwLock<ChannelList>>,
    current_user: RwLock<Option<model::user::CurrentUser>>,
    event_tx: mpsc::SyncSender<Event>,
}

impl Handler {
    fn new(event_tx: mpsc::SyncSender<Event>) -> Self {
        Handler {
            guilds: Default::default(),
            channels: Default::default(),
            current_user: Default::default(),
            event_tx,
        }
    }

    fn insert_guild(&self, guild: Guild) -> Option<GuildData> {
        let mut lock = self.guilds.write();
        lock.insert(guild.id, guild.into())
    }

    fn register_guild_channel<'a>(&'a self, channel: &GuildChannel) -> bool {
        if channel.kind != ChannelType::Text {
            return false;
        }
        self.channels
            .write()
            .get_or_insert_with(channel.id, || Channel::Guild(channel.clone()));
        true
    }
}

impl EventHandler for Handler {
    fn ready(
        &self,
        _ctx: Context,
        model::gateway::Ready {
            user,
            guilds,
            private_channels,
            ..
        }: model::gateway::Ready,
    ) {
        use model::guild::GuildStatus::*;
        *self.current_user.write() = Some(user);
        self.guilds
            .write()
            .extend(guilds.into_iter().filter_map(|g| match g {
                OnlineGuild(g) => Some((g.id, g.into())),
                _ => None,
            }));
        self.channels.write().extend(
            private_channels
                .into_iter()
                .filter_map(|(_, ch)| Channel::from_discord(ch)),
        );
    }

    fn guild_create(&self, _ctx: Context, guild: Guild) {
        let mut new_channels = vec![];
        for channel in guild.channels.values() {
            let chan = channel.read();
            if self.register_guild_channel(&chan) {
                new_channels.push(chan.name.clone());
            }
        }
        self.insert_guild(guild);
    }

    fn guild_member_addition(&self, _ctx: Context, guild_id: GuildId, new_member: Member) {
        if let Some(g) = self.guilds.write().get_mut(&guild_id) {
            let id = new_member.user.read().id;
            g.members.insert(id, new_member.into());
        }
    }

    fn guild_member_removal(&self, _ctx: Context, guild_id: GuildId, user: model::user::User) {
        if let Some(g) = self.guilds.write().get_mut(&guild_id) {
            g.members.remove(&user.id);
        }
    }

    fn guild_member_update(&self, _ctx: Context, new: model::event::GuildMemberUpdateEvent) {
        let guild_id = new.guild_id;
        let new = UserData::from(new);
        if let Some(m) = self
            .guilds
            .write()
            .get_mut(&guild_id)
            .and_then(|g| g.members.get_mut(&new.id))
        {
            if m.name != new.name {
                let _ = self.event_tx.send(Event::UserRenamed {
                    old: m.name.clone(),
                    new: new.name.clone(),
                });
            }
            *m = new;
        }
    }

    fn message(&self, _ctx: Context, new_message: Message) {
        let span = info_span!("message");
        let _enter = span.enter();
        info!("entered");
        if new_message.kind != MessageType::Regular
            || self
                .current_user
                .read()
                .as_ref()
                .map(|u| u.id == new_message.author.id)
                .unwrap_or(false)
        {
            return;
        }

        if let Some(ch) = self.channels.read().get_by_id(new_message.channel_id) {
            self.event_tx
                .send(Event::MessageCreated {
                    nickname: author_name(&self.guilds.read(), &new_message).to_owned(),
                    channel: format!("#{}", ch.name()),
                    content: new_message.content,
                    origin: None,
                })
                .unwrap();
        } else {
            info!("channel not found: {}", new_message.channel_id);
        }
    }
}
<commit_msg>Extract handle_ipc_event<commit_after>#![deny(rust_2018_idioms)]
#![deny(proc_macro_derive_resolution_fallback)]

mod channel;
mod guild;

use std::sync::{mpsc, Arc};
use std::thread;

use rendezvous_common::{
    data::*,
    ipc,
    parking_lot::RwLock,
    tracing::{self, debug, info, info_span, warn},
    Fallible,
};
use serenity::{
    http::Http,
    model::{
        self,
        channel::{ChannelType, GuildChannel, Message, MessageType},
        guild::{Guild, Member},
        id::GuildId,
    },
    prelude::*,
};

use crate::{
    channel::{Channel, ChannelList},
    guild::{author_name, GuildData, GuildMap, UserData},
};

fn main() -> Fallible<()> {
    tracing::init()?;

    let token = std::env::var("RENDEZVOUS_DISCORD_BOT_TOKEN")?;

    let (msg_tx, msg_rx) = mpsc::channel();
    let (event_tx, event_rx) = mpsc::sync_channel(8);

    let handler = Handler::new(event_tx);
    let channels = Arc::clone(&handler.channels);
    let mut client = Client::new(&token, handler)?;
    ipc::spawn_socket(msg_tx, event_rx)?;

    let http = Arc::clone(&client.cache_and_http.http);
    thread::spawn(move || {
        for m in msg_rx {
            handle_ipc_event(&http, &channels, m).unwrap();
        }
    });

    client.start_autosharded()?;

    Ok(())
}

fn handle_ipc_event(http: &Http, channels: &RwLock<ChannelList>, e: Event) -> Fallible<()> {
    match e {
        Event::MessageCreated {
            nickname,
            channel,
            content,
            ..
        } => {
            if !channel.starts_with("#") {
                return Ok(());
            }
            let channels = channels.read();
            debug!(
                "channels: {:?}",
                channels.iter().map(|ch| ch.name()).collect::<Vec<_>>()
            );
            if let Some(ch) = channels.get_by_name(&channel[1..]) {
                debug!("{:?}", ch);
                ch.id()
                    .send_message(http, |m| m.content(format!("<{}> {}", nickname, content)))?;
            } else {
                warn!("unknown channel: {:?}", channel);
            }
        }
        _ => {}
    }
    Ok(())
}

struct Handler {
    guilds: RwLock<GuildMap>,
    channels: Arc<RwLock<ChannelList>>,
    current_user: RwLock<Option<model::user::CurrentUser>>,
    event_tx: mpsc::SyncSender<Event>,
}

impl Handler {
    fn new(event_tx: mpsc::SyncSender<Event>) -> Self {
        Handler {
            guilds: Default::default(),
            channels: Default::default(),
            current_user: Default::default(),
            event_tx,
        }
    }

    fn insert_guild(&self, guild: Guild) -> Option<GuildData> {
        let mut lock = self.guilds.write();
        lock.insert(guild.id, guild.into())
    }

    fn register_guild_channel<'a>(&'a self, channel: &GuildChannel) -> bool {
        if channel.kind != ChannelType::Text {
            return false;
        }
        self.channels
            .write()
            .get_or_insert_with(channel.id, || Channel::Guild(channel.clone()));
        true
    }
}

impl EventHandler for Handler {
    fn ready(
        &self,
        _ctx: Context,
        model::gateway::Ready {
            user,
            guilds,
            private_channels,
            ..
        }: model::gateway::Ready,
    ) {
        use model::guild::GuildStatus::*;
        *self.current_user.write() = Some(user);
        self.guilds
            .write()
            .extend(guilds.into_iter().filter_map(|g| match g {
                OnlineGuild(g) => Some((g.id, g.into())),
                _ => None,
            }));
        self.channels.write().extend(
            private_channels
                .into_iter()
                .filter_map(|(_, ch)| Channel::from_discord(ch)),
        );
    }

    fn guild_create(&self, _ctx: Context, guild: Guild) {
        let mut new_channels = vec![];
        for channel in guild.channels.values() {
            let chan = channel.read();
            if self.register_guild_channel(&chan) {
                new_channels.push(chan.name.clone());
            }
        }
        self.insert_guild(guild);
    }

    fn guild_member_addition(&self, _ctx: Context, guild_id: GuildId, new_member: Member) {
        if let Some(g) = self.guilds.write().get_mut(&guild_id) {
            let id = new_member.user.read().id;
            g.members.insert(id, new_member.into());
        }
    }

    fn guild_member_removal(&self, _ctx: Context, guild_id: GuildId, user: model::user::User) {
        if let Some(g) = self.guilds.write().get_mut(&guild_id) {
            g.members.remove(&user.id);
        }
    }

    fn guild_member_update(&self, _ctx: Context, new: model::event::GuildMemberUpdateEvent) {
        let guild_id = new.guild_id;
        let new = UserData::from(new);
        if let Some(m) = self
            .guilds
            .write()
            .get_mut(&guild_id)
            .and_then(|g| g.members.get_mut(&new.id))
        {
            if m.name != new.name {
                let _ = self.event_tx.send(Event::UserRenamed {
                    old: m.name.clone(),
                    new: new.name.clone(),
                });
            }
            *m = new;
        }
    }

    fn message(&self, _ctx: Context, new_message: Message) {
        let span = info_span!("message");
        let _enter = span.enter();
        info!("entered");
        if new_message.kind != MessageType::Regular
            || self
                .current_user
                .read()
                .as_ref()
                .map(|u| u.id == new_message.author.id)
                .unwrap_or(false)
        {
            return;
        }

        if let Some(ch) = self.channels.read().get_by_id(new_message.channel_id) {
            self.event_tx
                .send(Event::MessageCreated {
                    nickname: author_name(&self.guilds.read(), &new_message).to_owned(),
                    channel: format!("#{}", ch.name()),
                    content: new_message.content,
                    origin: None,
                })
                .unwrap();
        } else {
            info!("channel not found: {}", new_message.channel_id);
        }
    }
}
<|endoftext|>


<commit_before>use hir::Semantics;
use ide_db::{
    defs::{Definition, NameClass, NameRefClass},
    RootDatabase,
};
use syntax::{ast, match_ast, AstNode, SyntaxKind::*, T};

use crate::{FilePosition, NavigationTarget, RangeInfo};

// Feature: Go to Declaration
//
// Navigates to the declaration of an identifier.
pub(crate) fn goto_declaration(
    db: &RootDatabase,
    position: FilePosition,
) -> Option<RangeInfo<Vec<NavigationTarget>>> {
    let sema = Semantics::new(db);
    let file = sema.parse(position.file_id).syntax().clone();
    let original_token = file
        .token_at_offset(position.offset)
        .find(|it| matches!(it.kind(), IDENT | T![self] | T![super] | T![crate]))?;
    let token = sema.descend_into_macros_single(original_token.clone());
    let parent = token.parent()?;
    let def = match_ast! {
        match parent {
            ast::NameRef(name_ref) => match NameRefClass::classify(&sema, &name_ref)? {
                NameRefClass::Definition(it) => Some(it),
                _ => None
            },
            ast::Name(name) => match NameClass::classify(&sema, &name)? {
                NameClass::Definition(it) => Some(it),
                _ => None
            },
            _ => None,
        }
    };
    match def? {
        Definition::ModuleDef(hir::ModuleDef::Module(module)) => Some(RangeInfo::new(
            original_token.text_range(),
            vec![NavigationTarget::from_module_to_decl(db, module)],
        )),
        _ => None,
    }
}

#[cfg(test)]
mod tests {
    use ide_db::base_db::FileRange;
    use itertools::Itertools;

    use crate::fixture;

    fn check(ra_fixture: &str) {
        let (analysis, position, expected) = fixture::annotations(ra_fixture);
        let navs = analysis
            .goto_declaration(position)
            .unwrap()
            .expect("no declaration or definition found")
            .info;
        if navs.is_empty() {
            panic!("unresolved reference")
        }

        let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start());
        let navs = navs
            .into_iter()
            .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
            .sorted_by_key(cmp)
            .collect::<Vec<_>>();
        let expected = expected
            .into_iter()
            .map(|(FileRange { file_id, range }, _)| FileRange { file_id, range })
            .sorted_by_key(cmp)
            .collect::<Vec<_>>();
        assert_eq!(expected, navs);
    }

    #[test]
    fn goto_decl_module_outline() {
        check(
            r#"
//- /main.rs
mod foo;
 // ^^^
//- /foo.rs
use self$0;
"#,
        )
    }

    #[test]
    fn goto_decl_module_inline() {
        check(
            r#"
mod foo {
 // ^^^
    use self$0;
}
"#,
        )
    }
}
<commit_msg>fix: make `goto_declaration` multi-token mapping aware<commit_after>use hir::Semantics;
use ide_db::{
    defs::{Definition, NameClass, NameRefClass},
    RootDatabase,
};
use syntax::{ast, match_ast, AstNode, SyntaxKind::*, T};

use crate::{FilePosition, NavigationTarget, RangeInfo};

// Feature: Go to Declaration
//
// Navigates to the declaration of an identifier.
pub(crate) fn goto_declaration(
    db: &RootDatabase,
    position: FilePosition,
) -> Option<RangeInfo<Vec<NavigationTarget>>> {
    let sema = Semantics::new(db);
    let file = sema.parse(position.file_id).syntax().clone();
    let original_token = file
        .token_at_offset(position.offset)
        .find(|it| matches!(it.kind(), IDENT | T![self] | T![super] | T![crate]))?;
    let range = original_token.text_range();
    let info: Vec<NavigationTarget> = sema
        .descend_into_macros(original_token)
        .iter()
        .filter_map(|token| {
            let parent = token.parent()?;
            let def = match_ast! {
                match parent {
                    ast::NameRef(name_ref) => match NameRefClass::classify(&sema, &name_ref)? {
                        NameRefClass::Definition(it) => Some(it),
                        _ => None
                    },
                    ast::Name(name) => match NameClass::classify(&sema, &name)? {
                        NameClass::Definition(it) => Some(it),
                        _ => None
                    },
                    _ => None
                }
            };
            match def? {
                Definition::ModuleDef(hir::ModuleDef::Module(module)) => {
                    Some(NavigationTarget::from_module_to_decl(db, module))
                }
                _ => None,
            }
        })
        .collect();

    Some(RangeInfo::new(range, info))
}

#[cfg(test)]
mod tests {
    use ide_db::base_db::FileRange;
    use itertools::Itertools;

    use crate::fixture;

    fn check(ra_fixture: &str) {
        let (analysis, position, expected) = fixture::annotations(ra_fixture);
        let navs = analysis
            .goto_declaration(position)
            .unwrap()
            .expect("no declaration or definition found")
            .info;
        if navs.is_empty() {
            panic!("unresolved reference")
        }

        let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start());
        let navs = navs
            .into_iter()
            .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
            .sorted_by_key(cmp)
            .collect::<Vec<_>>();
        let expected = expected
            .into_iter()
            .map(|(FileRange { file_id, range }, _)| FileRange { file_id, range })
            .sorted_by_key(cmp)
            .collect::<Vec<_>>();
        assert_eq!(expected, navs);
    }

    #[test]
    fn goto_decl_module_outline() {
        check(
            r#"
//- /main.rs
mod foo;
 // ^^^
//- /foo.rs
use self$0;
"#,
        )
    }

    #[test]
    fn goto_decl_module_inline() {
        check(
            r#"
mod foo {
 // ^^^
    use self$0;
}
"#,
        )
    }
}
<|endoftext|>


<commit_before>//! FBX binary parser.

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, SpecialAttributeType};
pub use self::event::{PrimitiveAttribute, ArrayAttribute, SpecialAttribute};
pub use self::event::ArrayAttributeReader;
use self::event::{EventBuilder, NodeHeader, StartNodeBuilder};
use self::event::read_fbx_header;
pub use self::reader::{BasicSource, SeekableSource, LimitedSeekReader};
use self::reader::ParserSource;

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.
#[derive(Debug)]
pub struct BinaryParser<R> {
    /// Source reader.
    source: 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<BasicSource<R>> {
    /// Creates a new binary parser.
    pub fn new(source: R) -> Self {
        BinaryParser {
            source: BasicSource::new(source),
            state: Ok(State::Header),
            warnings: Vec::new(),
            fbx_version: None,
            open_nodes: Vec::new(),
        }
    }
}

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

impl<R: ParserSource> BinaryParser<R> {
    /// 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))
    }

    /// Returns the number of the opened (and not closed) node.
    pub fn num_open_nodes(&self) -> usize {
        self.open_nodes.len()
    }

    /// 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.position() == 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.position();
                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 = self.read_fbx_footer();
                return Ok(footer.into());
            }

            self.state = Ok(State::NodeEnded);
            Ok(EventBuilder::EndNode)
        } else {
            let mut name_vec = vec![0u8; header.bytelen_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.position();
            self.open_nodes.push(OpenNode {
                begin: current_pos,
                end: header.end_offset,
                attributes_end: current_pos + header.bytelen_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> {
        self.set_finish();
        FbxFooter::read_from_parser(self)
    }

    /// 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)
    }
}
<commit_msg>Make `ParserSoruce` trait public<commit_after>//! FBX binary parser.

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, SpecialAttributeType};
pub use self::event::{PrimitiveAttribute, ArrayAttribute, SpecialAttribute};
pub use self::event::ArrayAttributeReader;
use self::event::{EventBuilder, NodeHeader, StartNodeBuilder};
use self::event::read_fbx_header;
pub use self::reader::{ParserSource, BasicSource, SeekableSource, LimitedSeekReader};

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.
#[derive(Debug)]
pub struct BinaryParser<R> {
    /// Source reader.
    source: 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<BasicSource<R>> {
    /// Creates a new binary parser.
    pub fn new(source: R) -> Self {
        BinaryParser {
            source: BasicSource::new(source),
            state: Ok(State::Header),
            warnings: Vec::new(),
            fbx_version: None,
            open_nodes: Vec::new(),
        }
    }
}

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

impl<R: ParserSource> BinaryParser<R> {
    /// 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))
    }

    /// Returns the number of the opened (and not closed) node.
    pub fn num_open_nodes(&self) -> usize {
        self.open_nodes.len()
    }

    /// 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.position() == 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.position();
                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 = self.read_fbx_footer();
                return Ok(footer.into());
            }

            self.state = Ok(State::NodeEnded);
            Ok(EventBuilder::EndNode)
        } else {
            let mut name_vec = vec![0u8; header.bytelen_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.position();
            self.open_nodes.push(OpenNode {
                begin: current_pos,
                end: header.end_offset,
                attributes_end: current_pos + header.bytelen_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> {
        self.set_finish();
        FbxFooter::read_from_parser(self)
    }

    /// 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)
    }
}
<|endoftext|>