<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;
use websocket::header::Origin;
use websocket::result::WebSocketResult;

#[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))
}

/// *Establish a WebSocket Connection* as defined in RFC 6455.
fn establish_a_websocket_connection(url: Url, origin: String)
    -> WebSocketResult<(Sender<WebSocketStream>, Receiver<WebSocketStream>)> {
    let mut request = try!(Client::connect(url));
    request.headers.set(Origin(origin));

    let response = try!(request.send());
    try!(response.validate());

    Ok(response.begin().split())
}

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);

        let channel = establish_a_websocket_connection(url, global.get_url().serialize());
        let (temp_sender, temp_receiver) = match channel {
            Ok(channel) => channel,
            Err(e) => {
                debug!("Failed to establish a WebSocket connection: {:?}", e);
                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);
            }
        };

        *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, WebSocketTask::ConnectionEstablished);
        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<()> {
        if self.ready_state.get() == WebSocketRequestState::Connecting {
            return Err(Error::InvalidState);
        }

        /*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 {
    /// Task queued when *the WebSocket connection is established*.
    ConnectionEstablished,
    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 connection_established(&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();

        // Step 1: Protocols.

        // Step 2.
        ws.ready_state.set(WebSocketRequestState::Open);

        // Step 3: Extensions.
        // Step 4: Protocols.
        // Step 5: Cookies.

        // Step 6.
        let global = ws.global.root();
        let event = Event::new(global.r(), "open".to_owned(),
                               EventBubbles::DoesNotBubble,
                               EventCancelable::NotCancelable);
        event.fire(EventTargetCast::from_ref(ws.r()));
    }

    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::ConnectionEstablished => {
                self.connection_established();
            }
            WebSocketTask::Close => {
                self.dispatch_close();
            }
        }
    }
}

<commit_msg>Remove parse_web_socket_url in favour of functions in rust-websocket.<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 hyper::header::Host;
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;
use websocket::header::Origin;
use websocket::result::WebSocketResult;
use websocket::ws::util::url::parse_url;

#[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>
}

/// *Establish a WebSocket Connection* as defined in RFC 6455.
fn establish_a_websocket_connection(url: (Host, String, bool), origin: String)
    -> WebSocketResult<(Sender<WebSocketStream>, Receiver<WebSocketStream>)> {
    let mut request = try!(Client::connect(url));
    request.headers.set(Origin(origin));

    let response = try!(request.send());
    try!(response.validate());

    Ok(response.begin().split())
}

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.
        let parsed_url = try!(Url::parse(&url).map_err(|_| Error::Syntax));
        let url = try!(parse_url(&parsed_url).map_err(|_| Error::Syntax));

        /*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, parsed_url),
                                    global,
                                    WebSocketBinding::Wrap);

        let channel = establish_a_websocket_connection(url, global.get_url().serialize());
        let (temp_sender, temp_receiver) = match channel {
            Ok(channel) => channel,
            Err(e) => {
                debug!("Failed to establish a WebSocket connection: {:?}", e);
                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);
            }
        };

        *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, WebSocketTask::ConnectionEstablished);
        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<()> {
        if self.ready_state.get() == WebSocketRequestState::Connecting {
            return Err(Error::InvalidState);
        }

        /*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 {
    /// Task queued when *the WebSocket connection is established*.
    ConnectionEstablished,
    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 connection_established(&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();

        // Step 1: Protocols.

        // Step 2.
        ws.ready_state.set(WebSocketRequestState::Open);

        // Step 3: Extensions.
        // Step 4: Protocols.
        // Step 5: Cookies.

        // Step 6.
        let global = ws.global.root();
        let event = Event::new(global.r(), "open".to_owned(),
                               EventBubbles::DoesNotBubble,
                               EventCancelable::NotCancelable);
        event.fire(EventTargetCast::from_ref(ws.r()));
    }

    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::ConnectionEstablished => {
                self.connection_established();
            }
            WebSocketTask::Close => {
                self.dispatch_close();
            }
        }
    }
}

<|endoftext|>


<commit_before>//! Handles the IPC (Inter-process Communication) protocol used by the renderer client and server.
//!
//! This is the common "language" between client/server. It defines both the protocol for
//! connection and for send messages back and forth.

mod async_ipc_receiver;
mod messages;
mod protocol;

pub use messages::*;
pub use protocol::*;

use std::io;

use thiserror::Error;
use serde::{Serialize, Deserialize};
use tokio::sync::Mutex;
use ipc_channel::ipc::{self, IpcOneShotServer, IpcSender, IpcError};

use crate::renderer_server_process::RendererServerProcess;
use crate::renderer_client::ClientId;

use async_ipc_receiver::AsyncIpcReceiver;

#[derive(Debug, Error)]
#[error(transparent)]
pub enum ConnectionError {
    IpcChannelError(#[from] ipc_channel::Error),
    IOError(#[from] io::Error),
    JoinError(#[from] tokio::task::JoinError),
}

/// Represents either a sender from the connection handshake or a response
#[derive(Debug, Serialize, Deserialize)]
enum HandshakeResponse {
    /// Represents that the handshake has been completed successfully.
    ///
    /// Provides the sender that the client should use to send further requests to the server. This
    /// message is only ever sent **once** for each client at the beginning when the connection is
    /// first established.
    HandshakeFinish(IpcSender<(ClientId, ClientRequest)>),

    /// A response from the server sent in response to a request
    Response(ClientId, ServerResponse),
}

/// Represents the client side of the IPC connection
#[derive(Debug)]
pub struct ClientConnection {
    sender: Mutex<IpcSender<(ClientId, ClientRequest)>>,
    receiver: AsyncIpcReceiver<HandshakeResponse>,
}

impl ClientConnection {
    pub async fn new(process: &mut RendererServerProcess) -> Result<Self, ConnectionError> {
        // Send the oneshot token to the server which will then respond with its own oneshot token
        let (server, server_name) = IpcOneShotServer::new()?;
        process.writeln(server_name).await?;

        let (receiver, response): (_, HandshakeResponse) = tokio::task::spawn_blocking(|| {
            server.accept()
        }).await??;

        let sender = match response {
            HandshakeResponse::HandshakeFinish(sender) => sender,
            _ => unreachable!("bug: server did not send back Sender at the end of handshake"),
        };

        let sender = Mutex::new(sender);
        let receiver = AsyncIpcReceiver::new(receiver);

        Ok(Self {sender, receiver})
    }

    /// Sends a request to the server via IPC
    pub async fn send(&self, id: ClientId, req: ClientRequest) -> Result<(), ipc_channel::Error> {
        self.sender.lock().await.send((id, req))
    }

    /// Waits for a response from the server via IPC
    pub async fn recv(&self) -> Result<(ClientId, ServerResponse), IpcError> {
        let response = self.receiver.recv().await?;
        match response {
            HandshakeResponse::Response(id, response) => Ok((id, response)),
            _ => unreachable!("bug: server did not send response after request"),
        }
    }
}

/// Represents the server side of the IPC connection
#[derive(Debug)]
pub struct ServerConnection {
    sender: Mutex<IpcSender<HandshakeResponse>>,
    receiver: AsyncIpcReceiver<(ClientId, ClientRequest)>,
}

impl ServerConnection {
    /// Establishes a connection to the client by reading from stdin
    #[cfg(not(any(feature = "test", test)))]
    pub async fn connect_stdin() -> Result<Self, ConnectionError> {
        use tokio::io::{self, AsyncBufReadExt};

        let stdin = io::stdin();
        let mut reader = io::BufReader::new(stdin);

        let mut oneshot_name = String::new();
        reader.read_line(&mut oneshot_name).await?;
        if oneshot_name.is_empty() {
            panic!("bug: unexpected EOF when reading oneshot server name");
        }

        // Remove the trailing newline
        assert_eq!(oneshot_name.pop(), Some('\n'));
        let conn = ServerConnection::connect(oneshot_name)?;

        Ok(conn)
    }

    /// Establishes a connection with the IPC channel oneshot server with the given name
    pub fn connect(oneshot_name: String) -> Result<Self, ConnectionError> {
        let (server_sender, receiver) = ipc::channel()?;
        let sender = IpcSender::connect(oneshot_name)?;

        // Finish handshake by giving client a sender it can use to send messages to the server
        sender.send(HandshakeResponse::HandshakeFinish(server_sender))?;

        let sender = Mutex::new(sender);
        let receiver = AsyncIpcReceiver::new(receiver);

        Ok(Self {sender, receiver})
    }

    /// Returns the next request, waiting until one is available
    pub async fn recv(&self) -> Result<(ClientId, ClientRequest), IpcError> {
        self.receiver.recv().await
    }

    /// Sends a response to the client
    ///
    /// This should only ever be done in response to a request
    pub async fn send(&self, id: ClientId, res: ServerResponse) -> Result<(), ipc_channel::Error> {
        self.sender.lock().await
            .send(HandshakeResponse::Response(id, res))
    }
}
<commit_msg>Thread-safe wrapper around IpcOneShotServer::new() which did not end up solving the problem<commit_after>//! Handles the IPC (Inter-process Communication) protocol used by the renderer client and server.
//!
//! This is the common "language" between client/server. It defines both the protocol for
//! connection and for send messages back and forth.

mod async_ipc_receiver;
mod messages;
mod protocol;

pub use messages::*;
pub use protocol::*;

use std::io;

use thiserror::Error;
use serde::{Serialize, Deserialize};
use tokio::sync::Mutex;
use ipc_channel::ipc::{self, IpcOneShotServer, IpcSender, IpcError};

use crate::renderer_server_process::RendererServerProcess;
use crate::renderer_client::ClientId;

use async_ipc_receiver::AsyncIpcReceiver;

/// The IpcOneShotServer::new() function is not thread-safe. That means that initializing multiple
/// IPC connections at the same time (as we do in tests) can result in data races. This function
/// solves that.
async fn thread_safe_ipc_one_shot_server<T>() -> io::Result<(IpcOneShotServer<T>, String)>
    where T: for<'de> Deserialize<'de> + Serialize
{
    use once_cell::sync::OnceCell;

    // A mutex that protects no value, but is used to synchronize calls to IpcOneShotServer::new()
    static ONE_SHOT_NEW: OnceCell<Mutex<()>> = OnceCell::new();
    let _g = ONE_SHOT_NEW.get_or_init(|| Mutex::new(())).lock().await;

    IpcOneShotServer::new()
}

#[derive(Debug, Error)]
#[error(transparent)]
pub enum ConnectionError {
    IpcChannelError(#[from] ipc_channel::Error),
    IOError(#[from] io::Error),
    JoinError(#[from] tokio::task::JoinError),
}

/// Represents either a sender from the connection handshake or a response
#[derive(Debug, Serialize, Deserialize)]
enum HandshakeResponse {
    /// Represents that the handshake has been completed successfully.
    ///
    /// Provides the sender that the client should use to send further requests to the server. This
    /// message is only ever sent **once** for each client at the beginning when the connection is
    /// first established.
    HandshakeFinish(IpcSender<(ClientId, ClientRequest)>),

    /// A response from the server sent in response to a request
    Response(ClientId, ServerResponse),
}

/// Represents the client side of the IPC connection
#[derive(Debug)]
pub struct ClientConnection {
    sender: Mutex<IpcSender<(ClientId, ClientRequest)>>,
    receiver: AsyncIpcReceiver<HandshakeResponse>,
}

impl ClientConnection {
    pub async fn new(process: &mut RendererServerProcess) -> Result<Self, ConnectionError> {
        // Send the oneshot token to the server which will then respond with its own oneshot token
        let (server, server_name) = thread_safe_ipc_one_shot_server().await?;
        process.writeln(server_name).await?;

        let (receiver, response): (_, HandshakeResponse) = tokio::task::spawn_blocking(|| {
            server.accept()
        }).await??;

        let sender = match response {
            HandshakeResponse::HandshakeFinish(sender) => sender,
            _ => unreachable!("bug: server did not send back Sender at the end of handshake"),
        };

        let sender = Mutex::new(sender);
        let receiver = AsyncIpcReceiver::new(receiver);

        Ok(Self {sender, receiver})
    }

    /// Sends a request to the server via IPC
    pub async fn send(&self, id: ClientId, req: ClientRequest) -> Result<(), ipc_channel::Error> {
        self.sender.lock().await.send((id, req))
    }

    /// Waits for a response from the server via IPC
    pub async fn recv(&self) -> Result<(ClientId, ServerResponse), IpcError> {
        let response = self.receiver.recv().await?;
        match response {
            HandshakeResponse::Response(id, response) => Ok((id, response)),
            _ => unreachable!("bug: server did not send response after request"),
        }
    }
}

/// Represents the server side of the IPC connection
#[derive(Debug)]
pub struct ServerConnection {
    sender: Mutex<IpcSender<HandshakeResponse>>,
    receiver: AsyncIpcReceiver<(ClientId, ClientRequest)>,
}

impl ServerConnection {
    /// Establishes a connection to the client by reading from stdin
    #[cfg(not(any(feature = "test", test)))]
    pub async fn connect_stdin() -> Result<Self, ConnectionError> {
        use tokio::io::{self, AsyncBufReadExt};

        let stdin = io::stdin();
        let mut reader = io::BufReader::new(stdin);

        let mut oneshot_name = String::new();
        reader.read_line(&mut oneshot_name).await?;
        if oneshot_name.is_empty() {
            panic!("bug: unexpected EOF when reading oneshot server name");
        }

        // Remove the trailing newline
        assert_eq!(oneshot_name.pop(), Some('\n'));
        let conn = ServerConnection::connect(oneshot_name)?;

        Ok(conn)
    }

    /// Establishes a connection with the IPC channel oneshot server with the given name
    pub fn connect(oneshot_name: String) -> Result<Self, ConnectionError> {
        let (server_sender, receiver) = ipc::channel()?;
        let sender = IpcSender::connect(oneshot_name)?;

        // Finish handshake by giving client a sender it can use to send messages to the server
        sender.send(HandshakeResponse::HandshakeFinish(server_sender))?;

        let sender = Mutex::new(sender);
        let receiver = AsyncIpcReceiver::new(receiver);

        Ok(Self {sender, receiver})
    }

    /// Returns the next request, waiting until one is available
    pub async fn recv(&self) -> Result<(ClientId, ClientRequest), IpcError> {
        self.receiver.recv().await
    }

    /// Sends a response to the client
    ///
    /// This should only ever be done in response to a request
    pub async fn send(&self, id: ClientId, res: ServerResponse) -> Result<(), ipc_channel::Error> {
        self.sender.lock().await
            .send(HandshakeResponse::Response(id, res))
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_xml_rs;

#[derive(Debug, Deserialize, Default)]
pub struct Mass {
    pub value: f64,
}

#[derive(Debug, Deserialize, Default)]
pub struct Inertia {
    pub ixx: f64,
    pub ixy: f64,
    pub ixz: f64,
    pub iyy: f64,
    pub iyz: f64,
    pub izz: f64,
}

#[derive(Debug, Deserialize, Default)]
pub struct Inertial {
    #[serde(default)]
    pub origin: Pose,
    pub mass: Mass,
    pub inertia: Inertia,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Geometry {
    Box {
        #[serde(with = "urdf_vec3")]
        size: [f64; 3]
        //size: String
    },
    Cylinder { radius: f64, length: f64 },
    Sphere { radius: f64 },
    Mesh { filename: String, scale: f64 },
}

impl Default for Geometry {
    fn default() -> Geometry {
        Geometry::Box { size: [0.0f64, 0.0, 0.0] }
    }
}

#[derive(Debug, Deserialize, Default)]
pub struct Color {
    #[serde(with = "urdf_vec4")]
    #[serde(default="default_rgba")]
    pub rgba: [f64; 4],
}

#[derive(Debug, Deserialize)]
pub struct Texture {
    pub filename: String,
}

impl Default for Texture {
    fn default() -> Texture {
        Texture { filename: "".to_string() }
    }
}

#[derive(Debug, Deserialize, Default)]
pub struct Material {
    #[serde(default)]
    pub name: String,
    #[serde(default)]
    pub color: Color,
    #[serde(default)]
    pub texture: Texture,
}

#[derive(Debug, Deserialize, Default)]
pub struct Visual {
    #[serde(default)]
    pub name: String,
    #[serde(default)]
    pub origin: Pose,
    pub geometry: Geometry,
    #[serde(default)]
    pub material: Material,
}

#[derive(Debug, Deserialize, Default)]
pub struct Collision {
    #[serde(default)]
    pub name: String,
    pub origin: Pose,
    pub geometry: Geometry,
}

#[derive(Debug, Deserialize)]
pub struct Link {
    pub name: String,
    #[serde(default)]
    pub inertial: Inertial,
    #[serde(default)]
    pub visual: Visual,
    #[serde(default)]
    pub collision: Collision,
}

#[derive(Deserialize, Debug)]
pub struct Vec3 {
    #[serde(with = "urdf_vec3")]
    pub data: [f64; 3]
}

mod urdf_vec3 {
    use serde::{self, Deserialize, Deserializer};
    pub fn deserialize<D>(deserializer: D) -> Result<[f64; 3], D::Error>
    where D: Deserializer
{
        let s = String::deserialize(deserializer)?;
        let vec = s.split(" ").filter_map(|x| x.parse::<f64>().ok()).collect::<Vec<_>>();
        if vec.len() != 3 {
            return Err(serde::de::Error::custom(
                format!("failed to parse float array in {}", s)));
        }
        let mut arr = [0.0f64; 3];
        for i in 0..3 {
            arr[i] = vec[i];
        }
        Ok(arr)
    }
}

mod urdf_vec4 {
    use serde::{self, Deserialize, Deserializer};
    pub fn deserialize<D>(deserializer: D) -> Result<[f64; 4], D::Error>
    where D: Deserializer
{
        let s = String::deserialize(deserializer)?;
        let vec = s.split(" ").filter_map(|x| x.parse::<f64>().ok()).collect::<Vec<_>>();
        if vec.len() != 4 {
            return Err(serde::de::Error::custom(
                format!("failed to parse float array in {}", s)));
        }
        let mut arr = [0.0f64; 4];
        for i in 0..4 {
            arr[i] = vec[i];
        }
        Ok(arr)
    }
}

#[derive(Debug, Deserialize)]
pub struct Axis {
    #[serde(with = "urdf_vec3")]
    pub xyz: [f64; 3]
}

pub fn array_from(string: &str) -> Result<[f64; 3], UrdfError> {
    let vec = string.split(" ").filter_map(|x| x.parse::<f64>().ok()).collect::<Vec<_>>();
    if vec.len() != 3 {
        return Err(UrdfError::Parse(string.to_string()));
    }
    let mut arr = [0.0f64; 3];
    for i in 0..3 {
        arr[i] = vec[i];
    }
    Ok(arr)
}

impl Default for Axis {
    fn default() -> Axis {
        Axis { xyz: [1.0f64, 0.0, 0.0,] }
    }
}

#[derive(Debug, Deserialize)]
pub struct Pose {
    #[serde(with = "urdf_vec3")]
    #[serde(default="default_zero3")]
    pub xyz: [f64; 3],
    #[serde(with = "urdf_vec3")]
    #[serde(default="default_zero3")]
    pub rpy: [f64; 3],
}

pub fn default_zero3() -> [f64; 3] {
    [0.0f64, 0.0, 0.0]
}

pub fn default_rgba() -> [f64; 4] {
    [1.0f64, 1.0, 1.0, 1.0]
}

/*
impl Pose {
    pub fn xyz_as_array(&self) -> Result<[f64; 3], UrdfError> {
        array_from(&self.xyz)
    }
    pub fn rpy_as_array(&self) -> Result<[f64; 3], UrdfError> {
        array_from(&self.rpy)
    }
}
 */

impl Default for Pose {
    fn default() -> Pose {
        Pose {
            xyz: default_zero3(),
            rpy: default_zero3(),
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct LinkName {
    pub link: String,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum JointType {
    Revolute,
    Continuous,
    Prismatic,
    Fixed,
    Floating,
    Planar,
}

#[derive(Debug, Deserialize)]
pub struct JointLimit {
    #[serde(default)]
    pub lower: f64,
    #[serde(default)]
    pub upper: f64,
    pub effort: f64,
    pub velocity: f64,
}

#[derive(Debug, Deserialize, Default)]
pub struct Mimic {
    joint: String,
    multiplier: f64,
    offset: f64,
}

#[derive(Debug, Deserialize, Default)]
pub struct SafetyController {
    soft_lower_limit: f64,
    soft_upper_limit: f64,
    k_position: f64,
    k_velocity: f64,
}

#[derive(Debug, Deserialize)]
pub struct Joint {
    pub name: String,
    #[serde(rename = "type")]
    pub joint_type: JointType,
    #[serde(default)]
    pub origin: Pose,
    pub parent: LinkName,
    pub child: LinkName,
    #[serde(default)]
    pub axis: Axis,
    pub limit: JointLimit,
    #[serde(default)]
    pub dynamics: Dynamics,
    #[serde(default)]
    pub mimic: Mimic,
    #[serde(default)]
    pub safety_controller: SafetyController,
}

#[derive(Debug, Deserialize, Default)]
pub struct Dynamics {
    damping: f64,
    friction: f64,
}

#[derive(Debug, Deserialize)]
pub struct Robot {
    pub name: String,

    #[serde(rename = "link", default)]
    pub links: Vec<Link>,

    #[serde(rename = "joint", default)]
    pub joints: Vec<Joint>,
}

use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
use std::error::Error;
use std::fmt;

#[derive(Debug)]
pub enum UrdfError {
    File(std::io::Error),
    Xml(serde_xml_rs::Error),
    Parse(String),
}

impl fmt::Display for UrdfError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            UrdfError::File(ref err) => err.fmt(f),
            UrdfError::Xml(ref err) => err.fmt(f),
            UrdfError::Parse(ref msg) => write!(f, "parse error {}", msg),
        }
    }
}

impl Error for UrdfError {
    fn description(&self) -> &str {
        match *self {
            UrdfError::File(ref err) => err.description(),
            UrdfError::Xml(ref err) => err.description(),
            UrdfError::Parse(_) => "parse error",
        }
    }
}

impl From<std::io::Error> for UrdfError {
    fn from(err: std::io::Error) -> UrdfError {
        UrdfError::File(err)
    }
}

impl From<serde_xml_rs::Error> for UrdfError {
    fn from(err: serde_xml_rs::Error) -> UrdfError {
        UrdfError::Xml(err)
    }
}

pub fn read_file<P: AsRef<Path>>(path: P) -> Result<Robot, UrdfError> {
    let mut file = File::open(path)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    read_from_string(&contents)
}

pub fn read_from_string(string: &str) -> Result<Robot, UrdfError> {
    serde_xml_rs::deserialize(string.as_bytes())
        .map_err(From::from)
}

#[test]
fn it_works() {
    let s = r##"
        <robot name="robo">
            <link name="shoulder1">
                <inertial>
                    <origin xyz="0 0 0.5" rpy="0 0 0"/>
                    <mass value="1"/>
                    <inertia ixx="100"  ixy="0"  ixz="0" iyy="100" iyz="0" izz="100" />
                </inertial>
                <visual>
                    <origin xyz="0.1 0.2 0.3" rpy="-0.1 -0.2  -0.3" />
                    <geometry>
                        <box size="1.0 2.0 3.0" />
                    </geometry>
                    <material name="Cyan">
                        <color rgba="0 1.0 1.0 1.0"/>
                    </material>
                </visual>
                <collision>
                    <origin xyz="0 0 0" rpy="0 0 0"/>
                    <geometry>
                        <cylinder radius="1" length="0.5"/>
                    </geometry>
                </collision>
            </link>
            <link name="elbow1" />
            <link name="wrist1" />
            <joint name="shoulder_pitch" type="revolute">
                <origin xyz="0.0 0.0 0.1" />
                <parent link="shoulder1" />
                <child link="elbow1" />
                <axis xyz="0 1 -1" />
                <limit lower="-1" upper="1.0" effort="0" velocity="1.0"/>
            </joint>
            <joint name="shoulder_pitch" type="revolute">
                <origin xyz="0.0 0.0 0.0" />
                <parent link="elbow1" />
                <child link="wrist1" />
                <axis xyz="0 1 0" />
                <limit lower="-2" upper="1.0" effort="0" velocity="1.0"/>
            </joint>
        </robot>
    "##;
    let robo = read_from_string(s).unwrap();

    assert_eq!(robo.name, "robo");
    assert_eq!(robo.links.len(), 3);
    assert_eq!(robo.joints.len(), 2);
    let xyz = robo.links[0].visual.origin.xyz;
    assert_eq!(xyz[0], 0.1);
    assert_eq!(xyz[1], 0.2);
    assert_eq!(xyz[2], 0.3);
    let rpy = robo.links[0].visual.origin.rpy;
    assert_eq!(rpy[0], -0.1);
    assert_eq!(rpy[1], -0.2);
    assert_eq!(rpy[2], -0.3);

    match robo.links[0].visual.geometry {
        Geometry::Box{size} => {
            assert_eq!(size[0], 1.0f64);
            assert_eq!(size[1], 2.0f64);
            assert_eq!(size[2], 3.0f64);
        },
        _ => { panic!("geometry error") },
    }

    assert_eq!(robo.joints[0].name, "shoulder_pitch");
    let xyz = robo.joints[0].axis.xyz;
    assert_eq!(xyz[0], 0.0f64);
    assert_eq!(xyz[1], 1.0f64);
    assert_eq!(xyz[2], -1.0f64);
    let xyz = robo.joints[0].axis.xyz;
    //"0 1 -1"
    assert_eq!(xyz[0], 0.0);
    assert_eq!(xyz[1], 1.0);
    assert_eq!(xyz[2], -1.0);

}
<commit_msg>Add documents for urdf_rs<commit_after>#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_xml_rs;

#[derive(Debug, Deserialize, Default)]
pub struct Mass {
    pub value: f64,
}

#[derive(Debug, Deserialize, Default)]
pub struct Inertia {
    pub ixx: f64,
    pub ixy: f64,
    pub ixz: f64,
    pub iyy: f64,
    pub iyz: f64,
    pub izz: f64,
}

#[derive(Debug, Deserialize, Default)]
pub struct Inertial {
    #[serde(default)]
    pub origin: Pose,
    pub mass: Mass,
    pub inertia: Inertia,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Geometry {
    Box {
        #[serde(with = "urdf_vec3")]
        size: [f64; 3]
        //size: String
    },
    Cylinder { radius: f64, length: f64 },
    Sphere { radius: f64 },
    Mesh { filename: String, scale: f64 },
}

impl Default for Geometry {
    fn default() -> Geometry {
        Geometry::Box { size: [0.0f64, 0.0, 0.0] }
    }
}

#[derive(Debug, Deserialize, Default)]
pub struct Color {
    #[serde(with = "urdf_vec4")]
    #[serde(default="default_rgba")]
    pub rgba: [f64; 4],
}

#[derive(Debug, Deserialize)]
pub struct Texture {
    pub filename: String,
}

impl Default for Texture {
    fn default() -> Texture {
        Texture { filename: "".to_string() }
    }
}

#[derive(Debug, Deserialize, Default)]
pub struct Material {
    #[serde(default)]
    pub name: String,
    #[serde(default)]
    pub color: Color,
    #[serde(default)]
    pub texture: Texture,
}

#[derive(Debug, Deserialize, Default)]
pub struct Visual {
    #[serde(default)]
    pub name: String,
    #[serde(default)]
    pub origin: Pose,
    pub geometry: Geometry,
    #[serde(default)]
    pub material: Material,
}

#[derive(Debug, Deserialize, Default)]
pub struct Collision {
    #[serde(default)]
    pub name: String,
    pub origin: Pose,
    pub geometry: Geometry,
}

/// Urdf Link element
/// See http://wiki.ros.org/urdf/XML/link for more detail.
#[derive(Debug, Deserialize)]
pub struct Link {
    pub name: String,
    #[serde(default)]
    pub inertial: Inertial,
    #[serde(default)]
    pub visual: Visual,
    #[serde(default)]
    pub collision: Collision,
}

#[derive(Deserialize, Debug)]
pub struct Vec3 {
    #[serde(with = "urdf_vec3")]
    pub data: [f64; 3]
}

mod urdf_vec3 {
    use serde::{self, Deserialize, Deserializer};
    pub fn deserialize<D>(deserializer: D) -> Result<[f64; 3], D::Error>
    where D: Deserializer
{
        let s = String::deserialize(deserializer)?;
        let vec = s.split(" ").filter_map(|x| x.parse::<f64>().ok()).collect::<Vec<_>>();
        if vec.len() != 3 {
            return Err(serde::de::Error::custom(
                format!("failed to parse float array in {}", s)));
        }
        let mut arr = [0.0f64; 3];
        for i in 0..3 {
            arr[i] = vec[i];
        }
        Ok(arr)
    }
}

mod urdf_vec4 {
    use serde::{self, Deserialize, Deserializer};
    pub fn deserialize<D>(deserializer: D) -> Result<[f64; 4], D::Error>
    where D: Deserializer
{
        let s = String::deserialize(deserializer)?;
        let vec = s.split(" ").filter_map(|x| x.parse::<f64>().ok()).collect::<Vec<_>>();
        if vec.len() != 4 {
            return Err(serde::de::Error::custom(
                format!("failed to parse float array in {}", s)));
        }
        let mut arr = [0.0f64; 4];
        for i in 0..4 {
            arr[i] = vec[i];
        }
        Ok(arr)
    }
}

#[derive(Debug, Deserialize)]
pub struct Axis {
    #[serde(with = "urdf_vec3")]
    pub xyz: [f64; 3]
}

impl Default for Axis {
    fn default() -> Axis {
        Axis { xyz: [1.0f64, 0.0, 0.0,] }
    }
}

#[derive(Debug, Deserialize)]
pub struct Pose {
    #[serde(with = "urdf_vec3")]
    #[serde(default="default_zero3")]
    pub xyz: [f64; 3],
    #[serde(with = "urdf_vec3")]
    #[serde(default="default_zero3")]
    pub rpy: [f64; 3],
}

fn default_zero3() -> [f64; 3] {
    [0.0f64, 0.0, 0.0]
}

fn default_rgba() -> [f64; 4] {
    [1.0f64, 1.0, 1.0, 1.0]
}

impl Default for Pose {
    fn default() -> Pose {
        Pose {
            xyz: default_zero3(),
            rpy: default_zero3(),
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct LinkName {
    pub link: String,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum JointType {
    Revolute,
    Continuous,
    Prismatic,
    Fixed,
    Floating,
    Planar,
}

#[derive(Debug, Deserialize)]
pub struct JointLimit {
    #[serde(default)]
    pub lower: f64,
    #[serde(default)]
    pub upper: f64,
    pub effort: f64,
    pub velocity: f64,
}

#[derive(Debug, Deserialize, Default)]
pub struct Mimic {
    joint: String,
    multiplier: f64,
    offset: f64,
}

#[derive(Debug, Deserialize, Default)]
pub struct SafetyController {
    soft_lower_limit: f64,
    soft_upper_limit: f64,
    k_position: f64,
    k_velocity: f64,
}

/// Urdf Joint element
/// See http://wiki.ros.org/urdf/XML/joint for more detail.
#[derive(Debug, Deserialize)]
pub struct Joint {
    pub name: String,
    #[serde(rename = "type")]
    pub joint_type: JointType,
    #[serde(default)]
    pub origin: Pose,
    pub parent: LinkName,
    pub child: LinkName,
    #[serde(default)]
    pub axis: Axis,
    pub limit: JointLimit,
    #[serde(default)]
    pub dynamics: Dynamics,
    #[serde(default)]
    pub mimic: Mimic,
    #[serde(default)]
    pub safety_controller: SafetyController,
}

#[derive(Debug, Deserialize, Default)]
pub struct Dynamics {
    damping: f64,
    friction: f64,
}

/// Top level struct to access urdf.
#[derive(Debug, Deserialize)]
pub struct Robot {
    pub name: String,

    #[serde(rename = "link", default)]
    pub links: Vec<Link>,

    #[serde(rename = "joint", default)]
    pub joints: Vec<Joint>,
}

use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
use std::error::Error;
use std::fmt;

#[derive(Debug)]
pub enum UrdfError {
    File(std::io::Error),
    Xml(serde_xml_rs::Error),
    Parse(String),
}

impl fmt::Display for UrdfError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            UrdfError::File(ref err) => err.fmt(f),
            UrdfError::Xml(ref err) => err.fmt(f),
            UrdfError::Parse(ref msg) => write!(f, "parse error {}", msg),
        }
    }
}

impl Error for UrdfError {
    fn description(&self) -> &str {
        match *self {
            UrdfError::File(ref err) => err.description(),
            UrdfError::Xml(ref err) => err.description(),
            UrdfError::Parse(_) => "parse error",
        }
    }
}

impl From<std::io::Error> for UrdfError {
    fn from(err: std::io::Error) -> UrdfError {
        UrdfError::File(err)
    }
}

impl From<serde_xml_rs::Error> for UrdfError {
    fn from(err: serde_xml_rs::Error) -> UrdfError {
        UrdfError::Xml(err)
    }
}

/// Read urdf file and create Robot instance
///
/// # Examples
///
/// ```
/// extern crate urdf_rs;
/// let urdf_robo = urdf_rs::read_file("sample.urdf").unwrap();
/// let links = urdf_robo.links;
/// ```
pub fn read_file<P: AsRef<Path>>(path: P) -> Result<Robot, UrdfError> {
    let mut file = File::open(path)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    read_from_string(&contents)
}

/// Read from string instead of file.
///
///
/// # Examples
///
/// ```
/// let s = r##"
///     <robot name="robo">
///         <link name="shoulder1">
///             <inertial>
///                 <origin xyz="0 0 0.5" rpy="0 0 0"/>
///                 <mass value="1"/>
///                 <inertia ixx="100"  ixy="0"  ixz="0" iyy="100" iyz="0" izz="100" />
///             </inertial>
///             <visual>
///                 <origin xyz="0.1 0.2 0.3" rpy="-0.1 -0.2  -0.3" />
///                 <geometry>
///                     <box size="1.0 2.0 3.0" />
///                 </geometry>
///                 <material name="Cyan">
///                     <color rgba="0 1.0 1.0 1.0"/>
///                 </material>
///             </visual>
///             <collision>
///                 <origin xyz="0 0 0" rpy="0 0 0"/>
///                 <geometry>
///                     <cylinder radius="1" length="0.5"/>
///                 </geometry>
///             </collision>
///         </link>
///         <link name="elbow1" />
///         <link name="wrist1" />
///         <joint name="shoulder_pitch" type="revolute">
///             <origin xyz="0.0 0.0 0.1" />
///             <parent link="shoulder1" />
///             <child link="elbow1" />
///             <axis xyz="0 1 -1" />
///             <limit lower="-1" upper="1.0" effort="0" velocity="1.0"/>
///         </joint>
///         <joint name="shoulder_pitch" type="revolute">
///             <origin xyz="0.0 0.0 0.0" />
///             <parent link="elbow1" />
///             <child link="wrist1" />
///             <axis xyz="0 1 0" />
///             <limit lower="-2" upper="1.0" effort="0" velocity="1.0"/>
///         </joint>
///     </robot>
///    "##;
/// let robo = urdf_rs::read_from_string(s).unwrap();
/// ```

pub fn read_from_string(string: &str) -> Result<Robot, UrdfError> {
    serde_xml_rs::deserialize(string.as_bytes())
        .map_err(From::from)
}

#[test]
fn it_works() {
    let s = r##"
        <robot name="robo">
            <link name="shoulder1">
                <inertial>
                    <origin xyz="0 0 0.5" rpy="0 0 0"/>
                    <mass value="1"/>
                    <inertia ixx="100"  ixy="0"  ixz="0" iyy="100" iyz="0" izz="100" />
                </inertial>
                <visual>
                    <origin xyz="0.1 0.2 0.3" rpy="-0.1 -0.2  -0.3" />
                    <geometry>
                        <box size="1.0 2.0 3.0" />
                    </geometry>
                    <material name="Cyan">
                        <color rgba="0 1.0 1.0 1.0"/>
                    </material>
                </visual>
                <collision>
                    <origin xyz="0 0 0" rpy="0 0 0"/>
                    <geometry>
                        <cylinder radius="1" length="0.5"/>
                    </geometry>
                </collision>
            </link>
            <link name="elbow1" />
            <link name="wrist1" />
            <joint name="shoulder_pitch" type="revolute">
                <origin xyz="0.0 0.0 0.1" />
                <parent link="shoulder1" />
                <child link="elbow1" />
                <axis xyz="0 1 -1" />
                <limit lower="-1" upper="1.0" effort="0" velocity="1.0"/>
            </joint>
            <joint name="shoulder_pitch" type="revolute">
                <origin xyz="0.0 0.0 0.0" />
                <parent link="elbow1" />
                <child link="wrist1" />
                <axis xyz="0 1 0" />
                <limit lower="-2" upper="1.0" effort="0" velocity="1.0"/>
            </joint>
        </robot>
    "##;
    let robo = read_from_string(s).unwrap();

    assert_eq!(robo.name, "robo");
    assert_eq!(robo.links.len(), 3);
    assert_eq!(robo.joints.len(), 2);
    let xyz = robo.links[0].visual.origin.xyz;
    assert_eq!(xyz[0], 0.1);
    assert_eq!(xyz[1], 0.2);
    assert_eq!(xyz[2], 0.3);
    let rpy = robo.links[0].visual.origin.rpy;
    assert_eq!(rpy[0], -0.1);
    assert_eq!(rpy[1], -0.2);
    assert_eq!(rpy[2], -0.3);

    match robo.links[0].visual.geometry {
        Geometry::Box{size} => {
            assert_eq!(size[0], 1.0f64);
            assert_eq!(size[1], 2.0f64);
            assert_eq!(size[2], 3.0f64);
        },
        _ => { panic!("geometry error") },
    }

    assert_eq!(robo.joints[0].name, "shoulder_pitch");
    let xyz = robo.joints[0].axis.xyz;
    assert_eq!(xyz[0], 0.0f64);
    assert_eq!(xyz[1], 1.0f64);
    assert_eq!(xyz[2], -1.0f64);
    let xyz = robo.joints[0].axis.xyz;
    //"0 1 -1"
    assert_eq!(xyz[0], 0.0);
    assert_eq!(xyz[1], 1.0);
    assert_eq!(xyz[2], -1.0);

}
<|endoftext|>


<commit_before>use std::io::Write;
use std::option::Option;
use std::os::unix::process::CommandExt;
use std::process::Command;

const SYSTEMD_RUN: &'static str = "/usr/bin/systemd-run";
const FIREJAIL: &'static str = "/usr/bin/firejail";

const FIREFOX: &'static str = "/usr/bin/firefox";
const FIREFOX_PROFILE: &'static str = "/etc/firejail/firefox.profile";
const FIREFOX_MOZILLA_SFW_PROFILE: &'static str = "default-1473025815439";

const FIREFOX_MEMORY_HIGH: i32 = 4420;
const FIREFOX_MEMORY_MAX: i32 = 5200;

const KEIRA: &'static str = "/home/kalvin/Downloads/.firefox-nightly/firefox";
const KEIRA_PROFILE: &'static str = "/etc/firejail/firefox-nightly.profile";

const MPV: &'static str = "/usr/bin/mpv";
const MPV_PROFILE: &'static str = "/etc/firejail/mpv.profile";

const TERM: &'static str = "/usr/bin/alacritty";
const TERM_PROFILE: &'static str = "/etc/firejail/x-terminal-emulator.profile";

const THUNDERBIRD: &'static str = "/home/kalvin/Downloads/.thunderbird-beta/thunderbird";
const THUNDERBIRD_PROFILE: &'static str = "/etc/firejail/thunderbird-beta.profile";

const QUODLIBET_FIFO: &'static str = "/home/kalvin/.config/quodlibet/control";

// Partial ordering on enums are ordered by their declaration order:
// https://users.rust-lang.org/t/how-to-sort-enum-variants/52291/2
#[derive(PartialOrd, Ord, PartialEq, Eq)]
enum BuilderWatermark {
    Unset,
    MemoryHigh,
    MemoryMax,
    FirejailProfile,
    BinPath,
    ImplicitExtraArgs,
    RemainingArgs,
}

struct CgroupedFirejailedCommand {
    pub command: std::process::Command,
    watermark: BuilderWatermark,
}

impl CgroupedFirejailedCommand {
    pub fn new() -> Self {
        let mut result = Self {
            command: std::process::Command::new(SYSTEMD_RUN),
            watermark: BuilderWatermark::Unset,
        };
        result
            .command
            .args(&["--user", "--scope", "-p", "MemorySwapMax=0"]);
        result
    }

    pub fn memory_high(mut self, param: i32) -> Self {
        assert!(self.watermark < BuilderWatermark::MemoryHigh);
        self.watermark = BuilderWatermark::MemoryHigh;
        self.command.arg("-p");
        self.command.arg(format!("MemoryHigh={}M", param));
        self
    }

    pub fn memory_max(mut self, param: i32) -> Self {
        assert!(self.watermark < BuilderWatermark::MemoryMax);
        self.watermark = BuilderWatermark::MemoryMax;
        self.command.arg("-p");
        self.command.arg(format!("MemoryMax={}M", param));
        self
    }

    pub fn firejail_profile(mut self, path: &str) -> Self {
        assert!(self.watermark < BuilderWatermark::FirejailProfile);
        self.watermark = BuilderWatermark::FirejailProfile;
        self.command.args(&[FIREJAIL, "--ignore=seccomp"]);
        self.command.arg(format!("--profile={}", path));
        self
    }

    pub fn bin_path(mut self, path: &str) -> Self {
        assert!(self.watermark < BuilderWatermark::BinPath);
        self.watermark = BuilderWatermark::BinPath;
        self.command.arg(path);
        self
    }

    pub fn implicit_extra_args(mut self, args: &[&str]) -> Self {
        assert!(self.watermark < BuilderWatermark::ImplicitExtraArgs);
        self.watermark = BuilderWatermark::ImplicitExtraArgs;
        self.command.args(args);
        self
    }

    pub fn remaining_args(mut self, args: Vec<String>) -> Self {
        assert!(self.watermark < BuilderWatermark::RemainingArgs);
        self.watermark = BuilderWatermark::RemainingArgs;
        self.command.args(args);
        self
    }
}

fn simple_firejail_command(target: &str, args: Vec<String>) -> Command {
    let mut command = Command::new(FIREJAIL);

    command.arg(format!("--profile=/etc/firejail/{}.profile", target));
    command.arg(format!("/usr/bin/{}", target));
    command.args(args);

    command
}

fn quodlibet_command(args: Vec<String>) {
    let mut file = std::fs::OpenOptions::new()
        .append(true)
        .open(QUODLIBET_FIFO)
        .unwrap();
    file.write_all(match args[0].as_str() {
        "pp" => "play-pause".as_bytes(),
        "sa" => "stop-after 1".as_bytes(),
        _ => panic!(
            "bad argument for quodlibet command: ``{}''",
            args[0].as_str()
        ),
    })
    .unwrap();
}

fn init_command() -> Option<Command> {
    let mut args_less_the_first = std::env::args();
    // Pops the name of this executable.
    args_less_the_first.next();

    // Pops the name of the unner target.
    let target = args_less_the_first.next().unwrap();

    // Copies and collects the remaining argv.
    let args: Vec<String> = args_less_the_first.collect();

    match target.as_str() {
        "ef" => {
            // edgy Firefox; Firejail disabled
            return Some(
                CgroupedFirejailedCommand::new()
                    .memory_high(FIREFOX_MEMORY_HIGH)
                    .memory_max(FIREFOX_MEMORY_MAX)
                    .bin_path(FIREFOX)
                    .implicit_extra_args(&["-P", FIREFOX_MOZILLA_SFW_PROFILE])
                    .remaining_args(args)
                    .command,
            );
        }
        "ff" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .memory_high(FIREFOX_MEMORY_HIGH)
                    .memory_max(FIREFOX_MEMORY_MAX)
                    .firejail_profile(FIREFOX_PROFILE)
                    .bin_path(FIREFOX)
                    .implicit_extra_args(&["-P", FIREFOX_MOZILLA_SFW_PROFILE])
                    .remaining_args(args)
                    .command,
            );
        }
        "keira" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .memory_high(FIREFOX_MEMORY_HIGH)
                    .memory_max(FIREFOX_MEMORY_MAX)
                    .firejail_profile(KEIRA_PROFILE)
                    .bin_path(KEIRA)
                    .implicit_extra_args(&["-P", "nightly"])
                    .remaining_args(args)
                    .command,
            );
        }
        "npv" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .firejail_profile(MPV_PROFILE)
                    .bin_path(MPV)
                    .implicit_extra_args(&["--pulse-buffer=13"])
                    .remaining_args(args)
                    .command,
            );
        }
        "q" => {
            quodlibet_command(args);
            return None;
        }
        "read" => {
            let formatted_args: Vec<String> = vec![format!("about:reader?url={}", args[0])];
            return Some(
                CgroupedFirejailedCommand::new()
                    .memory_high(FIREFOX_MEMORY_HIGH)
                    .memory_max(FIREFOX_MEMORY_MAX)
                    .firejail_profile(FIREFOX_PROFILE)
                    .bin_path(FIREFOX)
                    .implicit_extra_args(&["-P", FIREFOX_MOZILLA_SFW_PROFILE])
                    .remaining_args(formatted_args)
                    .command,
            );
        }
        "t" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .firejail_profile(TERM_PROFILE)
                    .bin_path(TERM)
                    .remaining_args(args)
                    .command,
            );
        }
        "tbb" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .firejail_profile(THUNDERBIRD_PROFILE)
                    .bin_path(THUNDERBIRD)
                    .remaining_args(args)
                    .command,
            );
        }
        "vlk" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .firejail_profile("/etc/firejail/vlc.profile")
                    .bin_path("/usr/bin/vlc")
                    .implicit_extra_args(&["--play-and-exit"])
                    .remaining_args(args)
                    .command,
            );
        }
        "e" => return Some(simple_firejail_command("evince", args)),
        _ => panic!("no handler for ``{}''", target),
    }
}

fn main() {
    if let Some(mut command) = init_command() {
        println!("{:#?}", command);
        command.exec();
    }
}
<commit_msg>unner: Remove `--pulse-buffer` flag<commit_after>use std::io::Write;
use std::option::Option;
use std::os::unix::process::CommandExt;
use std::process::Command;

const SYSTEMD_RUN: &'static str = "/usr/bin/systemd-run";
const FIREJAIL: &'static str = "/usr/bin/firejail";

const FIREFOX: &'static str = "/usr/bin/firefox";
const FIREFOX_PROFILE: &'static str = "/etc/firejail/firefox.profile";
const FIREFOX_MOZILLA_SFW_PROFILE: &'static str = "default-1473025815439";

const FIREFOX_MEMORY_HIGH: i32 = 4420;
const FIREFOX_MEMORY_MAX: i32 = 5200;

const KEIRA: &'static str = "/home/kalvin/Downloads/.firefox-nightly/firefox";
const KEIRA_PROFILE: &'static str = "/etc/firejail/firefox-nightly.profile";

const MPV: &'static str = "/usr/bin/mpv";
const MPV_PROFILE: &'static str = "/etc/firejail/mpv.profile";

const TERM: &'static str = "/usr/bin/alacritty";
const TERM_PROFILE: &'static str = "/etc/firejail/x-terminal-emulator.profile";

const THUNDERBIRD: &'static str = "/home/kalvin/Downloads/.thunderbird-beta/thunderbird";
const THUNDERBIRD_PROFILE: &'static str = "/etc/firejail/thunderbird-beta.profile";

const QUODLIBET_FIFO: &'static str = "/home/kalvin/.config/quodlibet/control";

// Partial ordering on enums are ordered by their declaration order:
// https://users.rust-lang.org/t/how-to-sort-enum-variants/52291/2
#[derive(PartialOrd, Ord, PartialEq, Eq)]
enum BuilderWatermark {
    Unset,
    MemoryHigh,
    MemoryMax,
    FirejailProfile,
    BinPath,
    ImplicitExtraArgs,
    RemainingArgs,
}

struct CgroupedFirejailedCommand {
    pub command: std::process::Command,
    watermark: BuilderWatermark,
}

impl CgroupedFirejailedCommand {
    pub fn new() -> Self {
        let mut result = Self {
            command: std::process::Command::new(SYSTEMD_RUN),
            watermark: BuilderWatermark::Unset,
        };
        result
            .command
            .args(&["--user", "--scope", "-p", "MemorySwapMax=0"]);
        result
    }

    pub fn memory_high(mut self, param: i32) -> Self {
        assert!(self.watermark < BuilderWatermark::MemoryHigh);
        self.watermark = BuilderWatermark::MemoryHigh;
        self.command.arg("-p");
        self.command.arg(format!("MemoryHigh={}M", param));
        self
    }

    pub fn memory_max(mut self, param: i32) -> Self {
        assert!(self.watermark < BuilderWatermark::MemoryMax);
        self.watermark = BuilderWatermark::MemoryMax;
        self.command.arg("-p");
        self.command.arg(format!("MemoryMax={}M", param));
        self
    }

    pub fn firejail_profile(mut self, path: &str) -> Self {
        assert!(self.watermark < BuilderWatermark::FirejailProfile);
        self.watermark = BuilderWatermark::FirejailProfile;
        self.command.args(&[FIREJAIL, "--ignore=seccomp"]);
        self.command.arg(format!("--profile={}", path));
        self
    }

    pub fn bin_path(mut self, path: &str) -> Self {
        assert!(self.watermark < BuilderWatermark::BinPath);
        self.watermark = BuilderWatermark::BinPath;
        self.command.arg(path);
        self
    }

    pub fn implicit_extra_args(mut self, args: &[&str]) -> Self {
        assert!(self.watermark < BuilderWatermark::ImplicitExtraArgs);
        self.watermark = BuilderWatermark::ImplicitExtraArgs;
        self.command.args(args);
        self
    }

    pub fn remaining_args(mut self, args: Vec<String>) -> Self {
        assert!(self.watermark < BuilderWatermark::RemainingArgs);
        self.watermark = BuilderWatermark::RemainingArgs;
        self.command.args(args);
        self
    }
}

fn simple_firejail_command(target: &str, args: Vec<String>) -> Command {
    let mut command = Command::new(FIREJAIL);

    command.arg(format!("--profile=/etc/firejail/{}.profile", target));
    command.arg(format!("/usr/bin/{}", target));
    command.args(args);

    command
}

fn quodlibet_command(args: Vec<String>) {
    let mut file = std::fs::OpenOptions::new()
        .append(true)
        .open(QUODLIBET_FIFO)
        .unwrap();
    file.write_all(match args[0].as_str() {
        "pp" => "play-pause".as_bytes(),
        "sa" => "stop-after 1".as_bytes(),
        _ => panic!(
            "bad argument for quodlibet command: ``{}''",
            args[0].as_str()
        ),
    })
    .unwrap();
}

fn init_command() -> Option<Command> {
    let mut args_less_the_first = std::env::args();
    // Pops the name of this executable.
    args_less_the_first.next();

    // Pops the name of the unner target.
    let target = args_less_the_first.next().unwrap();

    // Copies and collects the remaining argv.
    let args: Vec<String> = args_less_the_first.collect();

    match target.as_str() {
        "ef" => {
            // edgy Firefox; Firejail disabled
            return Some(
                CgroupedFirejailedCommand::new()
                    .memory_high(FIREFOX_MEMORY_HIGH)
                    .memory_max(FIREFOX_MEMORY_MAX)
                    .bin_path(FIREFOX)
                    .implicit_extra_args(&["-P", FIREFOX_MOZILLA_SFW_PROFILE])
                    .remaining_args(args)
                    .command,
            );
        }
        "ff" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .memory_high(FIREFOX_MEMORY_HIGH)
                    .memory_max(FIREFOX_MEMORY_MAX)
                    .firejail_profile(FIREFOX_PROFILE)
                    .bin_path(FIREFOX)
                    .implicit_extra_args(&["-P", FIREFOX_MOZILLA_SFW_PROFILE])
                    .remaining_args(args)
                    .command,
            );
        }
        "keira" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .memory_high(FIREFOX_MEMORY_HIGH)
                    .memory_max(FIREFOX_MEMORY_MAX)
                    .firejail_profile(KEIRA_PROFILE)
                    .bin_path(KEIRA)
                    .implicit_extra_args(&["-P", "nightly"])
                    .remaining_args(args)
                    .command,
            );
        }
        "npv" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .firejail_profile(MPV_PROFILE)
                    .bin_path(MPV)
                    .remaining_args(args)
                    .command,
            );
        }
        "q" => {
            quodlibet_command(args);
            return None;
        }
        "read" => {
            let formatted_args: Vec<String> = vec![format!("about:reader?url={}", args[0])];
            return Some(
                CgroupedFirejailedCommand::new()
                    .memory_high(FIREFOX_MEMORY_HIGH)
                    .memory_max(FIREFOX_MEMORY_MAX)
                    .firejail_profile(FIREFOX_PROFILE)
                    .bin_path(FIREFOX)
                    .implicit_extra_args(&["-P", FIREFOX_MOZILLA_SFW_PROFILE])
                    .remaining_args(formatted_args)
                    .command,
            );
        }
        "t" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .firejail_profile(TERM_PROFILE)
                    .bin_path(TERM)
                    .remaining_args(args)
                    .command,
            );
        }
        "tbb" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .firejail_profile(THUNDERBIRD_PROFILE)
                    .bin_path(THUNDERBIRD)
                    .remaining_args(args)
                    .command,
            );
        }
        "vlk" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .firejail_profile("/etc/firejail/vlc.profile")
                    .bin_path("/usr/bin/vlc")
                    .implicit_extra_args(&["--play-and-exit"])
                    .remaining_args(args)
                    .command,
            );
        }
        "e" => return Some(simple_firejail_command("evince", args)),
        _ => panic!("no handler for ``{}''", target),
    }
}

fn main() {
    if let Some(mut command) = init_command() {
        println!("{:#?}", command);
        command.exec();
    }
}
<|endoftext|>


<commit_before>use crate::attr::Display;
use proc_macro2::TokenStream;
use quote::quote_spanned;
use syn::{Ident, LitStr};

impl Display {
    // Transform `"error {var}"` to `"error {}", var`.
    pub fn expand_shorthand(&mut self) {
        if !self.args.is_empty() {
            return;
        }

        let span = self.fmt.span();
        let fmt = self.fmt.value();
        let mut read = fmt.as_str();
        let mut out = String::new();
        let mut args = TokenStream::new();

        while let Some(brace) = read.find('{') {
            out += &read[..brace + 1];
            read = &read[brace + 1..];
            if read.starts_with('{') {
                out.push('{');
                read = &read[1..];
                continue;
            }
            let next = match read.chars().next() {
                Some(next) => next,
                None => return,
            };
            let var = match next {
                '0'..='9' => take_int(&mut read),
                'a'..='z' | 'A'..='Z' | '_' => take_ident(&mut read),
                _ => return,
            };
            let ident = Ident::new(&var, span);
            args.extend(quote_spanned!(span=> , #ident));
        }

        out += read;
        self.fmt = LitStr::new(&out, self.fmt.span());
        self.args = args;
    }
}

fn take_int(read: &mut &str) -> String {
    let mut int = String::new();
    int.push('_');
    for (i, ch) in read.char_indices() {
        match ch {
            '0'..='9' => int.push(ch),
            _ => {
                *read = &read[i..];
                break;
            }
        }
    }
    int
}

fn take_ident(read: &mut &str) -> String {
    let mut ident = String::new();
    for (i, ch) in read.char_indices() {
        match ch {
            'a'..='z' | 'A'..='Z' | '_' => ident.push(ch),
            _ => {
                *read = &read[i..];
                break;
            }
        }
    }
    ident
}

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

    fn assert(input: &str, fmt: &str, args: &str) {
        let mut display = Display {
            fmt: LitStr::new(input, Span::call_site()),
            args: TokenStream::new(),
        };
        display.expand_shorthand();
        assert_eq!(fmt, display.fmt.value());
        assert_eq!(args, display.args.to_string());
    }

    #[test]
    fn test_expand() {
        assert("error {var}", "error {}", ", var");
        assert("fn main() {{ }}", "fn main() {{ }}", "");
        assert("{v} {v:?} {0} {0:?}", "{} {:?} {} {:?}", ", v , v , _0 , _0");
    }
}
<commit_msg>Resolve range_plus_one lint<commit_after>use crate::attr::Display;
use proc_macro2::TokenStream;
use quote::quote_spanned;
use syn::{Ident, LitStr};

impl Display {
    // Transform `"error {var}"` to `"error {}", var`.
    pub fn expand_shorthand(&mut self) {
        if !self.args.is_empty() {
            return;
        }

        let span = self.fmt.span();
        let fmt = self.fmt.value();
        let mut read = fmt.as_str();
        let mut out = String::new();
        let mut args = TokenStream::new();

        while let Some(brace) = read.find('{') {
            out += &read[..=brace];
            read = &read[brace + 1..];
            if read.starts_with('{') {
                out.push('{');
                read = &read[1..];
                continue;
            }
            let next = match read.chars().next() {
                Some(next) => next,
                None => return,
            };
            let var = match next {
                '0'..='9' => take_int(&mut read),
                'a'..='z' | 'A'..='Z' | '_' => take_ident(&mut read),
                _ => return,
            };
            let ident = Ident::new(&var, span);
            args.extend(quote_spanned!(span=> , #ident));
        }

        out += read;
        self.fmt = LitStr::new(&out, self.fmt.span());
        self.args = args;
    }
}

fn take_int(read: &mut &str) -> String {
    let mut int = String::new();
    int.push('_');
    for (i, ch) in read.char_indices() {
        match ch {
            '0'..='9' => int.push(ch),
            _ => {
                *read = &read[i..];
                break;
            }
        }
    }
    int
}

fn take_ident(read: &mut &str) -> String {
    let mut ident = String::new();
    for (i, ch) in read.char_indices() {
        match ch {
            'a'..='z' | 'A'..='Z' | '_' => ident.push(ch),
            _ => {
                *read = &read[i..];
                break;
            }
        }
    }
    ident
}

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

    fn assert(input: &str, fmt: &str, args: &str) {
        let mut display = Display {
            fmt: LitStr::new(input, Span::call_site()),
            args: TokenStream::new(),
        };
        display.expand_shorthand();
        assert_eq!(fmt, display.fmt.value());
        assert_eq!(args, display.args.to_string());
    }

    #[test]
    fn test_expand() {
        assert("error {var}", "error {}", ", var");
        assert("fn main() {{ }}", "fn main() {{ }}", "");
        assert("{v} {v:?} {0} {0:?}", "{} {:?} {} {:?}", ", v , v , _0 , _0");
    }
}
<|endoftext|>


<commit_before>//! Conversion lsp_types types to rust-analyzer specific ones.
use std::convert::TryFrom;

use ra_db::{FileId, FilePosition, FileRange};
use ra_ide::{AssistKind, LineCol, LineIndex};
use ra_syntax::{TextRange, TextSize};
use vfs::AbsPathBuf;

use crate::{global_state::GlobalStateSnapshot, Result};

pub(crate) fn abs_path(url: &lsp_types::Url) -> Result<AbsPathBuf> {
    let path = url.to_file_path().map_err(|()| "url is not a file")?;
    Ok(AbsPathBuf::try_from(path).unwrap())
}

pub(crate) fn vfs_path(url: &lsp_types::Url) -> Result<vfs::VfsPath> {
    abs_path(url).map(vfs::VfsPath::from)
}

pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> TextSize {
    let line_col = LineCol { line: position.line as u32, col_utf16: position.character as u32 };
    line_index.offset(line_col)
}

pub(crate) fn text_range(line_index: &LineIndex, range: lsp_types::Range) -> TextRange {
    let start = offset(line_index, range.start);
    let end = offset(line_index, range.end);
    TextRange::new(start, end)
}

pub(crate) fn file_id(world: &GlobalStateSnapshot, url: &lsp_types::Url) -> Result<FileId> {
    world.url_to_file_id(url)
}

pub(crate) fn file_position(
    world: &GlobalStateSnapshot,
    tdpp: lsp_types::TextDocumentPositionParams,
) -> Result<FilePosition> {
    let file_id = file_id(world, &tdpp.text_document.uri)?;
    let line_index = world.analysis.file_line_index(file_id)?;
    let offset = offset(&*line_index, tdpp.position);
    Ok(FilePosition { file_id, offset })
}

pub(crate) fn file_range(
    world: &GlobalStateSnapshot,
    text_document_identifier: lsp_types::TextDocumentIdentifier,
    range: lsp_types::Range,
) -> Result<FileRange> {
    let file_id = file_id(world, &text_document_identifier.uri)?;
    let line_index = world.analysis.file_line_index(file_id)?;
    let range = text_range(&line_index, range);
    Ok(FileRange { file_id, range })
}

pub(crate) fn assist_kind(kind: lsp_types::CodeActionKind) -> Option<AssistKind> {
    let assist_kind = match &kind {
        k if k == &lsp_types::CodeActionKind::EMPTY => AssistKind::None,
        k if k == &lsp_types::CodeActionKind::QUICKFIX => AssistKind::QuickFix,
        k if k == &lsp_types::CodeActionKind::REFACTOR => AssistKind::Refactor,
        k if k == &lsp_types::CodeActionKind::REFACTOR => AssistKind::RefactorExtract,
        k if k == &lsp_types::CodeActionKind::REFACTOR => AssistKind::RefactorInline,
        k if k == &lsp_types::CodeActionKind::REFACTOR => AssistKind::RefactorRewrite,
        _ => return None,
    };

    Some(assist_kind)
}
<commit_msg>Fix conversion<commit_after>//! Conversion lsp_types types to rust-analyzer specific ones.
use std::convert::TryFrom;

use ra_db::{FileId, FilePosition, FileRange};
use ra_ide::{AssistKind, LineCol, LineIndex};
use ra_syntax::{TextRange, TextSize};
use vfs::AbsPathBuf;

use crate::{global_state::GlobalStateSnapshot, Result};

pub(crate) fn abs_path(url: &lsp_types::Url) -> Result<AbsPathBuf> {
    let path = url.to_file_path().map_err(|()| "url is not a file")?;
    Ok(AbsPathBuf::try_from(path).unwrap())
}

pub(crate) fn vfs_path(url: &lsp_types::Url) -> Result<vfs::VfsPath> {
    abs_path(url).map(vfs::VfsPath::from)
}

pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> TextSize {
    let line_col = LineCol { line: position.line as u32, col_utf16: position.character as u32 };
    line_index.offset(line_col)
}

pub(crate) fn text_range(line_index: &LineIndex, range: lsp_types::Range) -> TextRange {
    let start = offset(line_index, range.start);
    let end = offset(line_index, range.end);
    TextRange::new(start, end)
}

pub(crate) fn file_id(world: &GlobalStateSnapshot, url: &lsp_types::Url) -> Result<FileId> {
    world.url_to_file_id(url)
}

pub(crate) fn file_position(
    world: &GlobalStateSnapshot,
    tdpp: lsp_types::TextDocumentPositionParams,
) -> Result<FilePosition> {
    let file_id = file_id(world, &tdpp.text_document.uri)?;
    let line_index = world.analysis.file_line_index(file_id)?;
    let offset = offset(&*line_index, tdpp.position);
    Ok(FilePosition { file_id, offset })
}

pub(crate) fn file_range(
    world: &GlobalStateSnapshot,
    text_document_identifier: lsp_types::TextDocumentIdentifier,
    range: lsp_types::Range,
) -> Result<FileRange> {
    let file_id = file_id(world, &text_document_identifier.uri)?;
    let line_index = world.analysis.file_line_index(file_id)?;
    let range = text_range(&line_index, range);
    Ok(FileRange { file_id, range })
}

pub(crate) fn assist_kind(kind: lsp_types::CodeActionKind) -> Option<AssistKind> {
    let assist_kind = match &kind {
        k if k == &lsp_types::CodeActionKind::EMPTY => AssistKind::None,
        k if k == &lsp_types::CodeActionKind::QUICKFIX => AssistKind::QuickFix,
        k if k == &lsp_types::CodeActionKind::REFACTOR => AssistKind::Refactor,
        k if k == &lsp_types::CodeActionKind::REFACTOR_EXTRACT => AssistKind::RefactorExtract,
        k if k == &lsp_types::CodeActionKind::REFACTOR_INLINE => AssistKind::RefactorInline,
        k if k == &lsp_types::CodeActionKind::REFACTOR_REWRITE => AssistKind::RefactorRewrite,
        _ => return None,
    };

    Some(assist_kind)
}
<|endoftext|>


<commit_before>use stm32f0x2::{TIM3, GPIOB, RCC};

use cortex_m;

// Init Timer Function without remap pin
pub fn init(period: u32) {
    cortex_m::interrupt::free(|cs| {
        let rcc = RCC.borrow(cs);
        let tim3 = TIM3.borrow(cs);
        let gpiob = GPIOB.borrow(cs);

        // GPIO Clock Activated
        rcc.ahbenr.modify(|_, w| w.iopben().enabled());
        // TIMER Clock Activated
        rcc.apb1enr.modify(|_, w| w.tim3en().enabled());

        gpiob.moder.modify(|_, w| w.moder4().alternate());
        gpiob.afrl.modify(|_, w| w.afrl4().af1());
        gpiob.otyper.modify(|_, w| w.ot4().push_pull());

        tim3.ccmr1_output.modify(|_, w| {
            w.oc1m().pwmmode1().oc1pe().enabled())
        });
        tim3.ccer.modify(|_, w| w.cc1p().clear_bit());
        set_period(period);

        tim3.ccer.modify(|_, w| w.cc1e().active());
        tim3.cr1.write(|w| {
            w.cms()
                .center_align_mode1()
                .dir()
                .up()
                .opm()
                .continuous()
                .cen()
                .enabled()
        });

        tim3.egr.write(|w| w.ug().set_bit());
    });
}

pub fn set_period(_period: u32) {
    cortex_m::interrupt::free(|cs| {
        let tim3 = TIM3.borrow(cs);

        // Set Prescaler Register - 16 bits
        tim3.psc.write(|w| w.psc().bits(7));

        // Set Auto-Reload register - 32 bits
        let arr = 10000;
        tim3.arr.write(|w| w.arr_h().bits((arr >> 16) as u16));
        tim3.arr.write(|w| w.arr_l().bits(arr as u16));
    });
}

pub fn enable() {
    cortex_m::interrupt::free(|cs| {
        let tim3 = TIM3.borrow(cs);
        tim3.ccer.modify(|_, w| w.cc1e().set_bit());
    });
}

pub fn set_duty(duty: u32) {
    cortex_m::interrupt::free(|cs| {
        let tim3 = TIM3.borrow(cs);
        tim3.ccr1.write(|w| {
            w.ccr1_l().bits((duty) as u16).ccr1_h().bits(
                (duty >> 16) as u16,
            )
        })
    });
}
<commit_msg>Missing ')'<commit_after>use stm32f0x2::{TIM3, GPIOB, RCC};

use cortex_m;

// Init Timer Function without remap pin
pub fn init(period: u32) {
    cortex_m::interrupt::free(|cs| {
        let rcc = RCC.borrow(cs);
        let tim3 = TIM3.borrow(cs);
        let gpiob = GPIOB.borrow(cs);

        // GPIO Clock Activated
        rcc.ahbenr.modify(|_, w| w.iopben().enabled());
        // TIMER Clock Activated
        rcc.apb1enr.modify(|_, w| w.tim3en().enabled());

        gpiob.moder.modify(|_, w| w.moder4().alternate());
        gpiob.afrl.modify(|_, w| w.afrl4().af1());
        gpiob.otyper.modify(|_, w| w.ot4().push_pull());

        tim3.ccmr1_output.modify(|_, w| {
            w.oc1m().pwmmode1().oc1pe().enabled()
        });
        tim3.ccer.modify(|_, w| w.cc1p().clear_bit());
        set_period(period);

        tim3.ccer.modify(|_, w| w.cc1e().active());
        tim3.cr1.write(|w| {
            w.cms()
                .center_align_mode1()
                .dir()
                .up()
                .opm()
                .continuous()
                .cen()
                .enabled()
        });

        tim3.egr.write(|w| w.ug().set_bit());
    });
}

pub fn set_period(_period: u32) {
    cortex_m::interrupt::free(|cs| {
        let tim3 = TIM3.borrow(cs);

        // Set Prescaler Register - 16 bits
        tim3.psc.write(|w| w.psc().bits(7));

        // Set Auto-Reload register - 32 bits
        let arr = 10000;
        tim3.arr.write(|w| w.arr_h().bits((arr >> 16) as u16));
        tim3.arr.write(|w| w.arr_l().bits(arr as u16));
    });
}

pub fn enable() {
    cortex_m::interrupt::free(|cs| {
        let tim3 = TIM3.borrow(cs);
        tim3.ccer.modify(|_, w| w.cc1e().set_bit());
    });
}

pub fn set_duty(duty: u32) {
    cortex_m::interrupt::free(|cs| {
        let tim3 = TIM3.borrow(cs);
        tim3.ccr1.write(|w| {
            w.ccr1_l().bits((duty) as u16).ccr1_h().bits(
                (duty >> 16) as u16,
            )
        })
    });
}
<|endoftext|>