<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 https://mozilla.org/MPL/2.0/. */

use crate::connector::create_ssl_connector_builder;
use crate::cookie::Cookie;
use crate::fetch::methods::should_be_blocked_due_to_bad_port;
use crate::hosts::replace_host;
use crate::http_loader::HttpState;
use embedder_traits::resources::{self, Resource};
use headers::Host;
use http::header::{self, HeaderMap, HeaderName, HeaderValue};
use http::uri::Authority;
use ipc_channel::ipc::{IpcReceiver, IpcSender};
use net_traits::request::{RequestBuilder, RequestMode};
use net_traits::{CookieSource, MessageData};
use net_traits::{WebSocketDomAction, WebSocketNetworkEvent};
use openssl::ssl::SslStream;
use servo_url::ServoUrl;
use std::fs;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
use url::Url;
use ws::util::TcpStream;
use ws::{
    CloseCode, Factory, Handler, Handshake, Message, Request, Response as WsResponse, Sender,
    WebSocket,
};
use ws::{Error as WebSocketError, ErrorKind as WebSocketErrorKind, Result as WebSocketResult};

/// A client for connecting to a websocket server
#[derive(Clone)]
struct Client<'a> {
    origin: &'a str,
    host: &'a Host,
    protocols: &'a [String],
    http_state: &'a Arc<HttpState>,
    resource_url: &'a ServoUrl,
    event_sender: &'a IpcSender<WebSocketNetworkEvent>,
    protocol_in_use: Option<String>,
    certificate_path: Option<String>,
}

impl<'a> Factory for Client<'a> {
    type Handler = Self;

    fn connection_made(&mut self, _: Sender) -> Self::Handler {
        self.clone()
    }

    fn connection_lost(&mut self, _: Self::Handler) {
        let _ = self.event_sender.send(WebSocketNetworkEvent::Fail);
    }
}

impl<'a> Handler for Client<'a> {
    fn build_request(&mut self, url: &Url) -> WebSocketResult<Request> {
        let mut req = Request::from_url(url)?;
        req.headers_mut()
            .push(("Origin".to_string(), self.origin.as_bytes().to_owned()));
        req.headers_mut().push((
            "Host".to_string(),
            format!("{}", self.host).as_bytes().to_owned(),
        ));

        for protocol in self.protocols {
            req.add_protocol(protocol);
        }

        let mut cookie_jar = self.http_state.cookie_jar.write().unwrap();
        if let Some(cookie_list) = cookie_jar.cookies_for_url(self.resource_url, CookieSource::HTTP)
        {
            req.headers_mut()
                .push(("Cookie".into(), cookie_list.as_bytes().to_owned()))
        }

        Ok(req)
    }

    fn on_open(&mut self, shake: Handshake) -> WebSocketResult<()> {
        let mut headers = HeaderMap::new();
        for &(ref name, ref value) in shake.response.headers().iter() {
            let name = HeaderName::from_bytes(name.as_bytes()).unwrap();
            let value = HeaderValue::from_bytes(&value).unwrap();

            headers.insert(name, value);
        }

        let mut jar = self.http_state.cookie_jar.write().unwrap();
        // TODO(eijebong): Replace thise once typed headers settled on a cookie impl
        for cookie in headers.get_all(header::SET_COOKIE) {
            if let Ok(s) = cookie.to_str() {
                if let Some(cookie) =
                    Cookie::from_cookie_string(s.into(), self.resource_url, CookieSource::HTTP)
                {
                    jar.push(cookie, self.resource_url, CookieSource::HTTP);
                }
            }
        }

        let _ = self
            .event_sender
            .send(WebSocketNetworkEvent::ConnectionEstablished {
                protocol_in_use: self.protocol_in_use.clone(),
            });
        Ok(())
    }

    fn on_message(&mut self, message: Message) -> WebSocketResult<()> {
        let message = match message {
            Message::Text(message) => MessageData::Text(message),
            Message::Binary(message) => MessageData::Binary(message),
        };
        let _ = self
            .event_sender
            .send(WebSocketNetworkEvent::MessageReceived(message));

        Ok(())
    }

    fn on_error(&mut self, err: WebSocketError) {
        debug!("Error in WebSocket communication: {:?}", err);
        let _ = self.event_sender.send(WebSocketNetworkEvent::Fail);
    }

    fn on_response(&mut self, res: &WsResponse) -> WebSocketResult<()> {
        let protocol_in_use = res.protocol()?;

        if let Some(protocol_name) = protocol_in_use {
            if !self.protocols.is_empty() && !self.protocols.iter().any(|p| protocol_name == (*p)) {
                let error = WebSocketError::new(
                    WebSocketErrorKind::Protocol,
                    "Protocol in Use not in client-supplied protocol list",
                );
                return Err(error);
            }
            self.protocol_in_use = Some(protocol_name.into());
        }
        Ok(())
    }

    fn on_close(&mut self, code: CloseCode, reason: &str) {
        debug!("Connection closing due to ({:?}) {}", code, reason);
        let _ = self.event_sender.send(WebSocketNetworkEvent::Close(
            Some(code.into()),
            reason.to_owned(),
        ));
    }

    fn upgrade_ssl_client(
        &mut self,
        stream: TcpStream,
        url: &Url,
    ) -> WebSocketResult<SslStream<TcpStream>> {
        let certs = match self.certificate_path {
            Some(ref path) => fs::read_to_string(path).expect("Couldn't not find certificate file"),
            None => resources::read_string(Resource::SSLCertificates),
        };

        let domain = self
            .resource_url
            .as_url()
            .domain()
            .ok_or(WebSocketError::new(
                WebSocketErrorKind::Protocol,
                format!("Unable to parse domain from {}. Needed for SSL.", url),
            ))?;
        let connector = create_ssl_connector_builder(&certs).build();
        connector
            .connect(domain, stream)
            .map_err(WebSocketError::from)
    }
}

pub fn init(
    req_builder: RequestBuilder,
    resource_event_sender: IpcSender<WebSocketNetworkEvent>,
    dom_action_receiver: IpcReceiver<WebSocketDomAction>,
    http_state: Arc<HttpState>,
    certificate_path: Option<String>,
) {
    thread::Builder::new()
        .name(format!("WebSocket connection to {}", req_builder.url))
        .spawn(move || {
            let protocols = match req_builder.mode {
                RequestMode::WebSocket { protocols } => protocols,
                _ => panic!(
                    "Received a RequestBuilder with a non-websocket mode in websocket_loader"
                ),
            };

            let scheme = req_builder.url.scheme();
            let mut req_url = req_builder.url.clone();
            if scheme == "ws" {
                req_url.as_mut_url().set_scheme("http").unwrap();
            } else if scheme == "wss" {
                req_url.as_mut_url().set_scheme("https").unwrap();
            }

            if should_be_blocked_due_to_bad_port(&req_url) {
                debug!("Failed to establish a WebSocket connection: port blocked");
                let _ = resource_event_sender.send(WebSocketNetworkEvent::Fail);
                return;
            }

            let host = replace_host(req_builder.url.host_str().unwrap());
            let mut net_url = req_builder.url.clone().into_url();
            net_url.set_host(Some(&host)).unwrap();

            let host = Host::from(
                format!(
                    "{}{}",
                    req_builder.url.host_str().unwrap(),
                    req_builder
                        .url
                        .port_or_known_default()
                        .map(|v| format!(":{}", v))
                        .unwrap_or("".into())
                )
                .parse::<Authority>()
                .unwrap(),
            );

            let client = Client {
                origin: &req_builder.origin.ascii_serialization(),
                host: &host,
                protocols: &protocols,
                http_state: &http_state,
                resource_url: &req_builder.url,
                event_sender: &resource_event_sender,
                protocol_in_use: None,
                certificate_path,
            };
            let mut ws = WebSocket::new(client).unwrap();

            if let Err(e) = ws.connect(net_url) {
                debug!("Failed to establish a WebSocket connection: {:?}", e);
                return;
            };

            let ws_sender = ws.broadcaster();
            let initiated_close = Arc::new(AtomicBool::new(false));

            thread::spawn(move || {
                while let Ok(dom_action) = dom_action_receiver.recv() {
                    match dom_action {
                        WebSocketDomAction::SendMessage(MessageData::Text(data)) => {
                            ws_sender.send(Message::text(data)).unwrap();
                        },
                        WebSocketDomAction::SendMessage(MessageData::Binary(data)) => {
                            ws_sender.send(Message::binary(data)).unwrap();
                        },
                        WebSocketDomAction::Close(code, reason) => {
                            if !initiated_close.fetch_or(true, Ordering::SeqCst) {
                                match code {
                                    Some(code) => ws_sender
                                        .close_with_reason(
                                            code.into(),
                                            reason.unwrap_or("".to_owned()),
                                        )
                                        .unwrap(),
                                    None => ws_sender.close(CloseCode::Status).unwrap(),
                                };
                            }
                        },
                    }
                }
            });

            if let Err(e) = ws.run() {
                debug!("Failed to run WebSocket: {:?}", e);
                let _ = resource_event_sender.send(WebSocketNetworkEvent::Fail);
            };
        })
        .expect("Thread spawning failed");
}
<commit_msg>Auto merge of #24402 - gterzian:remove_thread_spawning_in_ws, r=jdm<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 https://mozilla.org/MPL/2.0/. */

use crate::connector::create_ssl_connector_builder;
use crate::cookie::Cookie;
use crate::fetch::methods::should_be_blocked_due_to_bad_port;
use crate::hosts::replace_host;
use crate::http_loader::HttpState;
use embedder_traits::resources::{self, Resource};
use headers::Host;
use http::header::{self, HeaderMap, HeaderName, HeaderValue};
use http::uri::Authority;
use ipc_channel::ipc::{IpcReceiver, IpcSender};
use ipc_channel::router::ROUTER;
use net_traits::request::{RequestBuilder, RequestMode};
use net_traits::{CookieSource, MessageData};
use net_traits::{WebSocketDomAction, WebSocketNetworkEvent};
use openssl::ssl::SslStream;
use servo_url::ServoUrl;
use std::fs;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
use url::Url;
use ws::util::TcpStream;
use ws::{
    CloseCode, Factory, Handler, Handshake, Message, Request, Response as WsResponse, Sender,
    WebSocket,
};
use ws::{Error as WebSocketError, ErrorKind as WebSocketErrorKind, Result as WebSocketResult};

/// A client for connecting to a websocket server
#[derive(Clone)]
struct Client<'a> {
    origin: &'a str,
    host: &'a Host,
    protocols: &'a [String],
    http_state: &'a Arc<HttpState>,
    resource_url: &'a ServoUrl,
    event_sender: &'a IpcSender<WebSocketNetworkEvent>,
    protocol_in_use: Option<String>,
    certificate_path: Option<String>,
}

impl<'a> Factory for Client<'a> {
    type Handler = Self;

    fn connection_made(&mut self, _: Sender) -> Self::Handler {
        self.clone()
    }

    fn connection_lost(&mut self, _: Self::Handler) {
        let _ = self.event_sender.send(WebSocketNetworkEvent::Fail);
    }
}

impl<'a> Handler for Client<'a> {
    fn build_request(&mut self, url: &Url) -> WebSocketResult<Request> {
        let mut req = Request::from_url(url)?;
        req.headers_mut()
            .push(("Origin".to_string(), self.origin.as_bytes().to_owned()));
        req.headers_mut().push((
            "Host".to_string(),
            format!("{}", self.host).as_bytes().to_owned(),
        ));

        for protocol in self.protocols {
            req.add_protocol(protocol);
        }

        let mut cookie_jar = self.http_state.cookie_jar.write().unwrap();
        if let Some(cookie_list) = cookie_jar.cookies_for_url(self.resource_url, CookieSource::HTTP)
        {
            req.headers_mut()
                .push(("Cookie".into(), cookie_list.as_bytes().to_owned()))
        }

        Ok(req)
    }

    fn on_open(&mut self, shake: Handshake) -> WebSocketResult<()> {
        let mut headers = HeaderMap::new();
        for &(ref name, ref value) in shake.response.headers().iter() {
            let name = HeaderName::from_bytes(name.as_bytes()).unwrap();
            let value = HeaderValue::from_bytes(&value).unwrap();

            headers.insert(name, value);
        }

        let mut jar = self.http_state.cookie_jar.write().unwrap();
        // TODO(eijebong): Replace thise once typed headers settled on a cookie impl
        for cookie in headers.get_all(header::SET_COOKIE) {
            if let Ok(s) = cookie.to_str() {
                if let Some(cookie) =
                    Cookie::from_cookie_string(s.into(), self.resource_url, CookieSource::HTTP)
                {
                    jar.push(cookie, self.resource_url, CookieSource::HTTP);
                }
            }
        }

        let _ = self
            .event_sender
            .send(WebSocketNetworkEvent::ConnectionEstablished {
                protocol_in_use: self.protocol_in_use.clone(),
            });
        Ok(())
    }

    fn on_message(&mut self, message: Message) -> WebSocketResult<()> {
        let message = match message {
            Message::Text(message) => MessageData::Text(message),
            Message::Binary(message) => MessageData::Binary(message),
        };
        let _ = self
            .event_sender
            .send(WebSocketNetworkEvent::MessageReceived(message));

        Ok(())
    }

    fn on_error(&mut self, err: WebSocketError) {
        debug!("Error in WebSocket communication: {:?}", err);
        let _ = self.event_sender.send(WebSocketNetworkEvent::Fail);
    }

    fn on_response(&mut self, res: &WsResponse) -> WebSocketResult<()> {
        let protocol_in_use = res.protocol()?;

        if let Some(protocol_name) = protocol_in_use {
            if !self.protocols.is_empty() && !self.protocols.iter().any(|p| protocol_name == (*p)) {
                let error = WebSocketError::new(
                    WebSocketErrorKind::Protocol,
                    "Protocol in Use not in client-supplied protocol list",
                );
                return Err(error);
            }
            self.protocol_in_use = Some(protocol_name.into());
        }
        Ok(())
    }

    fn on_close(&mut self, code: CloseCode, reason: &str) {
        debug!("Connection closing due to ({:?}) {}", code, reason);
        let _ = self.event_sender.send(WebSocketNetworkEvent::Close(
            Some(code.into()),
            reason.to_owned(),
        ));
    }

    fn upgrade_ssl_client(
        &mut self,
        stream: TcpStream,
        url: &Url,
    ) -> WebSocketResult<SslStream<TcpStream>> {
        let certs = match self.certificate_path {
            Some(ref path) => fs::read_to_string(path).expect("Couldn't not find certificate file"),
            None => resources::read_string(Resource::SSLCertificates),
        };

        let domain = self
            .resource_url
            .as_url()
            .domain()
            .ok_or(WebSocketError::new(
                WebSocketErrorKind::Protocol,
                format!("Unable to parse domain from {}. Needed for SSL.", url),
            ))?;
        let connector = create_ssl_connector_builder(&certs).build();
        connector
            .connect(domain, stream)
            .map_err(WebSocketError::from)
    }
}

pub fn init(
    req_builder: RequestBuilder,
    resource_event_sender: IpcSender<WebSocketNetworkEvent>,
    dom_action_receiver: IpcReceiver<WebSocketDomAction>,
    http_state: Arc<HttpState>,
    certificate_path: Option<String>,
) {
    thread::Builder::new()
        .name(format!("WebSocket connection to {}", req_builder.url))
        .spawn(move || {
            let protocols = match req_builder.mode {
                RequestMode::WebSocket { protocols } => protocols,
                _ => panic!(
                    "Received a RequestBuilder with a non-websocket mode in websocket_loader"
                ),
            };

            let scheme = req_builder.url.scheme();
            let mut req_url = req_builder.url.clone();
            if scheme == "ws" {
                req_url.as_mut_url().set_scheme("http").unwrap();
            } else if scheme == "wss" {
                req_url.as_mut_url().set_scheme("https").unwrap();
            }

            if should_be_blocked_due_to_bad_port(&req_url) {
                debug!("Failed to establish a WebSocket connection: port blocked");
                let _ = resource_event_sender.send(WebSocketNetworkEvent::Fail);
                return;
            }

            let host = replace_host(req_builder.url.host_str().unwrap());
            let mut net_url = req_builder.url.clone().into_url();
            net_url.set_host(Some(&host)).unwrap();

            let host = Host::from(
                format!(
                    "{}{}",
                    req_builder.url.host_str().unwrap(),
                    req_builder
                        .url
                        .port_or_known_default()
                        .map(|v| format!(":{}", v))
                        .unwrap_or("".into())
                )
                .parse::<Authority>()
                .unwrap(),
            );

            let client = Client {
                origin: &req_builder.origin.ascii_serialization(),
                host: &host,
                protocols: &protocols,
                http_state: &http_state,
                resource_url: &req_builder.url,
                event_sender: &resource_event_sender,
                protocol_in_use: None,
                certificate_path,
            };
            let mut ws = WebSocket::new(client).unwrap();

            if let Err(e) = ws.connect(net_url) {
                debug!("Failed to establish a WebSocket connection: {:?}", e);
                return;
            };

            let ws_sender = ws.broadcaster();
            let initiated_close = Arc::new(AtomicBool::new(false));

            ROUTER.add_route(
                dom_action_receiver.to_opaque(),
                Box::new(move |message| {
                    let dom_action = message.to().expect("Ws dom_action message to deserialize");
                    match dom_action {
                        WebSocketDomAction::SendMessage(MessageData::Text(data)) => {
                            ws_sender.send(Message::text(data)).unwrap();
                        },
                        WebSocketDomAction::SendMessage(MessageData::Binary(data)) => {
                            ws_sender.send(Message::binary(data)).unwrap();
                        },
                        WebSocketDomAction::Close(code, reason) => {
                            if !initiated_close.fetch_or(true, Ordering::SeqCst) {
                                match code {
                                    Some(code) => ws_sender
                                        .close_with_reason(
                                            code.into(),
                                            reason.unwrap_or("".to_owned()),
                                        )
                                        .unwrap(),
                                    None => ws_sender.close(CloseCode::Status).unwrap(),
                                };
                            }
                        },
                    }
                }),
            );

            if let Err(e) = ws.run() {
                debug!("Failed to run WebSocket: {:?}", e);
                let _ = resource_event_sender.send(WebSocketNetworkEvent::Fail);
            };
        })
        .expect("Thread spawning failed");
}
<|endoftext|>


<commit_before>use alloc::arc::{Arc, Weak};
use alloc::boxed::Box;

use collections::VecDeque;

use core::cmp;

use fs::{KScheme, Resource, Url};

use sync::WaitQueue;

use system::error::{Error, ENOENT, Result};

pub struct Pty {
    id: usize,
    input: WaitQueue<u8>,
    output: WaitQueue<u8>
}

impl Pty {
    fn new(id: usize) -> Self {
        Pty {
            id: id,
            input: WaitQueue::new(),
            output: WaitQueue::new()
        }
    }
}

/// Psuedoterminal scheme
pub struct PtyScheme {
    next_id: usize,
    ptys: VecDeque<Weak<Pty>>
}

impl PtyScheme {
    pub fn new() -> Box<Self> {
        Box::new(PtyScheme {
            next_id: 1,
            ptys: VecDeque::new()
        })
    }
}

impl KScheme for PtyScheme {
    fn scheme(&self) -> &str {
        "pty"
    }

    fn open(&mut self, url: Url, _: usize) -> Result<Box<Resource>> {
        let req_id = url.reference().parse::<usize>().unwrap_or(0);

        self.ptys.retain(|pty| {
            pty.upgrade().is_some()
        });

        if req_id == 0 {
            let master = PtyMaster::new(self.next_id);

            self.ptys.push_back(Arc::downgrade(&master.inner));

            self.next_id += 1;
            //TODO: collision and rollover check

            Ok(Box::new(master))
        } else {
            for pty in self.ptys.iter() {
                if let Some(pty_strong) = pty.upgrade() {
                    if pty_strong.id == req_id {
                        return Ok(Box::new(PtySlave::new(&pty_strong)))
                    }
                }
            }

            Err(Error::new(ENOENT))
        }
    }
}

/// Psuedoterminal master
pub struct PtyMaster {
    inner: Arc<Pty>
}

impl PtyMaster {
    pub fn new(id: usize) -> Self {
        PtyMaster {
            inner: Arc::new(Pty::new(id))
        }
    }
}

impl Resource for PtyMaster {
    fn dup(&self) -> Result<Box<Resource>> {
        Ok(box PtyMaster {
            inner: self.inner.clone()
        })
    }

    fn path(&self, buf: &mut [u8]) -> Result<usize> {
        let path = format!("pty:{}", self.inner.id);

        for (b, p) in buf.iter_mut().zip(path.bytes()) {
            *b = p;
        }

        Ok(cmp::min(buf.len(), path.len()))
    }

    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        if ! buf.is_empty() {
            buf[0] = self.inner.output.receive("PtyMaster::read");
        }

        let mut i = 1;

        while i < buf.len() {
            match unsafe { self.inner.output.inner() }.pop_front() {
                Some(b) => {
                    buf[i] = b;
                    i += 1;
                },
                None => break
            }
        }

        Ok(i)
    }

    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        for &b in buf.iter() {
            self.inner.input.send(b, "PtyMaster::write");
        }

        Ok(buf.len())
    }
}

/// Psuedoterminal slave
pub struct PtySlave {
    inner: Weak<Pty>
}

impl PtySlave {
    pub fn new(pty: &Arc<Pty>) -> Self {
        PtySlave {
            inner: Arc::downgrade(&pty)
        }
    }
}

impl Resource for PtySlave {
    fn dup(&self) -> Result<Box<Resource>> {
        Ok(box PtySlave {
            inner: self.inner.clone()
        })
    }

    fn path(&self, buf: &mut [u8]) -> Result<usize> {
        match self.inner.upgrade() {
            Some(inner) => {
                let path = format!("pty:{}", inner.id);

                for (b, p) in buf.iter_mut().zip(path.bytes()) {
                    *b = p;
                }

                Ok(cmp::min(buf.len(), path.len()))
            },
            None => Ok(0)
        }
    }

    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        match self.inner.upgrade() {
            Some(inner) => {
                if ! buf.is_empty() {
                    buf[0] = inner.input.receive("PtySlave::read");
                }

                let mut i = 1;

                while i < buf.len() {
                    match unsafe { inner.input.inner() }.pop_front() {
                        Some(b) => {
                            buf[i] = b;
                            i += 1;
                        },
                        None => break
                    }
                }

                Ok(i)
            },
            None => Ok(0)
        }
    }

    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        match self.inner.upgrade() {
            Some(inner) => {
                for &b in buf.iter() {
                    inner.output.send(b, "PtySlave::write");
                }

                Ok(buf.len())
            },
            None => Ok(0)
        }
    }

    fn sync(&mut self) -> Result<()> {
        //TODO: Wait until empty
        Ok(())
    }
}
<commit_msg>PTY packet system<commit_after>use alloc::arc::{Arc, Weak};
use alloc::boxed::Box;

use collections::{Vec, VecDeque};

use core::cmp;

use fs::{KScheme, Resource, Url};

use sync::WaitQueue;

use system::error::{Error, ENOENT, Result};

pub struct Pty {
    id: usize,
    input: WaitQueue<u8>,
    output: WaitQueue<Vec<u8>>
}

impl Pty {
    fn new(id: usize) -> Self {
        Pty {
            id: id,
            input: WaitQueue::new(),
            output: WaitQueue::new()
        }
    }
}

/// Psuedoterminal scheme
pub struct PtyScheme {
    next_id: usize,
    ptys: VecDeque<Weak<Pty>>
}

impl PtyScheme {
    pub fn new() -> Box<Self> {
        Box::new(PtyScheme {
            next_id: 1,
            ptys: VecDeque::new()
        })
    }
}

impl KScheme for PtyScheme {
    fn scheme(&self) -> &str {
        "pty"
    }

    fn open(&mut self, url: Url, _: usize) -> Result<Box<Resource>> {
        let req_id = url.reference().parse::<usize>().unwrap_or(0);

        self.ptys.retain(|pty| {
            pty.upgrade().is_some()
        });

        if req_id == 0 {
            let master = PtyMaster::new(self.next_id);

            self.ptys.push_back(Arc::downgrade(&master.inner));

            self.next_id += 1;
            //TODO: collision and rollover check

            Ok(Box::new(master))
        } else {
            for pty in self.ptys.iter() {
                if let Some(pty_strong) = pty.upgrade() {
                    if pty_strong.id == req_id {
                        return Ok(Box::new(PtySlave::new(&pty_strong)))
                    }
                }
            }

            Err(Error::new(ENOENT))
        }
    }
}

/// Psuedoterminal master
pub struct PtyMaster {
    inner: Arc<Pty>
}

impl PtyMaster {
    pub fn new(id: usize) -> Self {
        PtyMaster {
            inner: Arc::new(Pty::new(id))
        }
    }
}

impl Resource for PtyMaster {
    fn dup(&self) -> Result<Box<Resource>> {
        Ok(box PtyMaster {
            inner: self.inner.clone()
        })
    }

    fn path(&self, buf: &mut [u8]) -> Result<usize> {
        let path = format!("pty:{}", self.inner.id);

        for (b, p) in buf.iter_mut().zip(path.bytes()) {
            *b = p;
        }

        Ok(cmp::min(buf.len(), path.len()))
    }

    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        let packet = self.inner.output.receive("PtyMaster::read");

        let mut i = 0;

        while i < buf.len() && i < packet.len() {
            buf[i] = packet[i];
            i += 1;
        }

        Ok(i)
    }

    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        for &b in buf.iter() {
            self.inner.input.send(b, "PtyMaster::write");
        }

        Ok(buf.len())
    }
}

/// Psuedoterminal slave
pub struct PtySlave {
    inner: Weak<Pty>
}

impl PtySlave {
    pub fn new(pty: &Arc<Pty>) -> Self {
        PtySlave {
            inner: Arc::downgrade(&pty)
        }
    }
}

impl Resource for PtySlave {
    fn dup(&self) -> Result<Box<Resource>> {
        Ok(box PtySlave {
            inner: self.inner.clone()
        })
    }

    fn path(&self, buf: &mut [u8]) -> Result<usize> {
        match self.inner.upgrade() {
            Some(inner) => {
                let path = format!("pty:{}", inner.id);

                for (b, p) in buf.iter_mut().zip(path.bytes()) {
                    *b = p;
                }

                Ok(cmp::min(buf.len(), path.len()))
            },
            None => Ok(0)
        }
    }

    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        match self.inner.upgrade() {
            Some(inner) => {
                if ! buf.is_empty() {
                    buf[0] = inner.input.receive("PtySlave::read");
                }

                let mut i = 1;

                while i < buf.len() {
                    match unsafe { inner.input.inner() }.pop_front() {
                        Some(b) => {
                            buf[i] = b;
                            i += 1;
                        },
                        None => break
                    }
                }

                Ok(i)
            },
            None => Ok(0)
        }
    }

    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        match self.inner.upgrade() {
            Some(inner) => {
                for chunk in buf.chunks(4095) {
                    let mut vec = vec![0];
                    vec.extend_from_slice(chunk);
                    inner.output.send(vec, "PtySlave::write");
                }

                Ok(buf.len())
            },
            None => Ok(0)
        }
    }

    fn sync(&mut self) -> Result<()> {
        if let Some(inner) = self.inner.upgrade() {
            inner.output.send(vec![1], "PtySlave::sync");
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Lints in the Rust compiler.
//!
//! This currently only contains the definitions and implementations
//! of most of the lints that `rustc` supports directly, it does not
//! contain the infrastructure for defining/registering lints. That is
//! available in `rustc::lint` and `rustc_plugin` respectively.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![crate_name = "rustc_lint"]
#![unstable(feature = "rustc_private", issue = "27812")]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
      html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
      html_root_url = "https://doc.rust-lang.org/nightly/")]
#![cfg_attr(not(stage0), deny(warnings))]

#![cfg_attr(test, feature(test))]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(slice_patterns)]
#![feature(staged_api)]

#[macro_use]
extern crate syntax;
#[macro_use]
extern crate rustc;
#[macro_use]
extern crate log;
extern crate rustc_back;
extern crate rustc_const_eval;

pub use rustc::lint as lint;
pub use rustc::middle as middle;
pub use rustc::session as session;
pub use rustc::util as util;

use session::Session;
use lint::LintId;
use lint::FutureIncompatibleInfo;

mod bad_style;
mod builtin;
mod types;
mod unused;

use bad_style::*;
use builtin::*;
use types::*;
use unused::*;

/// Tell the `LintStore` about all the built-in lints (the ones
/// defined in this crate and the ones defined in
/// `rustc::lint::builtin`).
pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
    macro_rules! add_builtin {
        ($sess:ident, $($name:ident),*,) => (
            {$(
                store.register_late_pass($sess, false, box $name);
                )*}
            )
    }

    macro_rules! add_early_builtin {
        ($sess:ident, $($name:ident),*,) => (
            {$(
                store.register_early_pass($sess, false, box $name);
                )*}
            )
    }

    macro_rules! add_builtin_with_new {
        ($sess:ident, $($name:ident),*,) => (
            {$(
                store.register_late_pass($sess, false, box $name::new());
                )*}
            )
    }

    macro_rules! add_lint_group {
        ($sess:ident, $name:expr, $($lint:ident),*) => (
            store.register_group($sess, false, $name, vec![$(LintId::of($lint)),*]);
            )
    }

    add_early_builtin!(sess,
                       UnusedParens,
                       );

    add_builtin!(sess,
                 HardwiredLints,
                 WhileTrue,
                 ImproperCTypes,
                 BoxPointers,
                 UnusedAttributes,
                 PathStatements,
                 UnusedResults,
                 NonCamelCaseTypes,
                 NonSnakeCase,
                 NonUpperCaseGlobals,
                 UnusedImportBraces,
                 NonShorthandFieldPatterns,
                 UnusedUnsafe,
                 UnsafeCode,
                 UnusedMut,
                 UnusedAllocation,
                 MissingCopyImplementations,
                 UnstableFeatures,
                 Deprecated,
                 UnconditionalRecursion,
                 InvalidNoMangleItems,
                 PluginAsLibrary,
                 DropWithReprExtern,
                 MutableTransmutes,
                 );

    add_builtin_with_new!(sess,
                          TypeLimits,
                          MissingDoc,
                          MissingDebugImplementations,
                          );

    add_lint_group!(sess, "bad_style",
                    NON_CAMEL_CASE_TYPES, NON_SNAKE_CASE, NON_UPPER_CASE_GLOBALS);

    add_lint_group!(sess, "unused",
                    UNUSED_IMPORTS, UNUSED_VARIABLES, UNUSED_ASSIGNMENTS, DEAD_CODE,
                    UNUSED_MUT, UNREACHABLE_CODE, UNUSED_MUST_USE,
                    UNUSED_UNSAFE, PATH_STATEMENTS, UNUSED_ATTRIBUTES);

    // Guidelines for creating a future incompatibility lint:
    //
    // - Create a lint defaulting to warn as normal, with ideally the same error
    //   message you would normally give
    // - Add a suitable reference, typically an RFC or tracking issue. Go ahead
    //   and include the full URL.
    // - Later, change lint to error
    // - Eventually, remove lint
    store.register_future_incompatible(sess, vec![
        FutureIncompatibleInfo {
            id: LintId::of(PRIVATE_IN_PUBLIC),
            reference: "the explanation for E0446 (`--explain E0446`)",
        },
        FutureIncompatibleInfo {
            id: LintId::of(INACCESSIBLE_EXTERN_CRATE),
            reference: "PR 31362 <https://github.com/rust-lang/rust/pull/31362>",
        },
        FutureIncompatibleInfo {
            id: LintId::of(INVALID_TYPE_PARAM_DEFAULT),
            reference: "PR 30742 <https://github.com/rust-lang/rust/pull/30724>",
        },
        FutureIncompatibleInfo {
            id: LintId::of(SUPER_OR_SELF_IN_GLOBAL_PATH),
            reference: "PR #32403 <https://github.com/rust-lang/rust/pull/32403>",
        },
        FutureIncompatibleInfo {
            id: LintId::of(MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT),
            reference: "RFC 218 <https://github.com/rust-lang/rfcs/blob/\
                        master/text/0218-empty-struct-with-braces.md>",
        },
        FutureIncompatibleInfo {
            id: LintId::of(TRANSMUTE_FROM_FN_ITEM_TYPES),
            reference: "issue #19925 <https://github.com/rust-lang/rust/issues/19925>",
        },
        FutureIncompatibleInfo {
            id: LintId::of(OVERLAPPING_INHERENT_IMPLS),
            reference: "issue #22889 <https://github.com/rust-lang/rust/issues/22889>",
        },
        FutureIncompatibleInfo {
            id: LintId::of(ILLEGAL_FLOATING_POINT_CONSTANT_PATTERN),
            reference: "RFC 1445 <https://github.com/rust-lang/rfcs/pull/1445>",
        },
        FutureIncompatibleInfo {
            id: LintId::of(ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN),
            reference: "RFC 1445 <https://github.com/rust-lang/rfcs/pull/1445>",
        },
        FutureIncompatibleInfo {
            id: LintId::of(UNSIZED_IN_TUPLE),
            reference: "issue #33242 <https://github.com/rust-lang/rust/issues/33242>",
        },
        FutureIncompatibleInfo {
            id: LintId::of(OBJECT_UNSAFE_FRAGMENT),
            reference: "issue #33243 <https://github.com/rust-lang/rust/issues/33243>",
        },
        FutureIncompatibleInfo {
            id: LintId::of(HR_LIFETIME_IN_ASSOC_TYPE),
            reference: "issue #33685 <https://github.com/rust-lang/rust/issues/33685>",
        },
        FutureIncompatibleInfo {
            id: LintId::of(LIFETIME_UNDERSCORE),
            reference: "RFC 1177 <https://github.com/rust-lang/rfcs/pull/1177>",
        },
        ]);

    // We have one lint pass defined specially
    store.register_late_pass(sess, false, box lint::GatherNodeLevels);

    // Register renamed and removed lints
    store.register_renamed("unknown_features", "unused_features");
    store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate");
    store.register_removed("negate_unsigned", "cast a signed value instead");
    store.register_removed("raw_pointer_derive", "using derive with raw pointers is ok");
    // This was renamed to raw_pointer_derive, which was then removed,
    // so it is also considered removed
    store.register_removed("raw_pointer_deriving", "using derive with raw pointers is ok");
}
<commit_msg>Rollup merge of #34435 - sanxiyn:typo, r=apasel422<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Lints in the Rust compiler.
//!
//! This currently only contains the definitions and implementations
//! of most of the lints that `rustc` supports directly, it does not
//! contain the infrastructure for defining/registering lints. That is
//! available in `rustc::lint` and `rustc_plugin` respectively.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![crate_name = "rustc_lint"]
#![unstable(feature = "rustc_private", issue = "27812")]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
      html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
      html_root_url = "https://doc.rust-lang.org/nightly/")]
#![cfg_attr(not(stage0), deny(warnings))]

#![cfg_attr(test, feature(test))]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(slice_patterns)]
#![feature(staged_api)]

#[macro_use]
extern crate syntax;
#[macro_use]
extern crate rustc;
#[macro_use]
extern crate log;
extern crate rustc_back;
extern crate rustc_const_eval;

pub use rustc::lint as lint;
pub use rustc::middle as middle;
pub use rustc::session as session;
pub use rustc::util as util;

use session::Session;
use lint::LintId;
use lint::FutureIncompatibleInfo;

mod bad_style;
mod builtin;
mod types;
mod unused;

use bad_style::*;
use builtin::*;
use types::*;
use unused::*;

/// Tell the `LintStore` about all the built-in lints (the ones
/// defined in this crate and the ones defined in
/// `rustc::lint::builtin`).
pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
    macro_rules! add_builtin {
        ($sess:ident, $($name:ident),*,) => (
            {$(
                store.register_late_pass($sess, false, box $name);
                )*}
            )
    }

    macro_rules! add_early_builtin {
        ($sess:ident, $($name:ident),*,) => (
            {$(
                store.register_early_pass($sess, false, box $name);
                )*}
            )
    }

    macro_rules! add_builtin_with_new {
        ($sess:ident, $($name:ident),*,) => (
            {$(
                store.register_late_pass($sess, false, box $name::new());
                )*}
            )
    }

    macro_rules! add_lint_group {
        ($sess:ident, $name:expr, $($lint:ident),*) => (
            store.register_group($sess, false, $name, vec![$(LintId::of($lint)),*]);
            )
    }

    add_early_builtin!(sess,
                       UnusedParens,
                       );

    add_builtin!(sess,
                 HardwiredLints,
                 WhileTrue,
                 ImproperCTypes,
                 BoxPointers,
                 UnusedAttributes,
                 PathStatements,
                 UnusedResults,
                 NonCamelCaseTypes,
                 NonSnakeCase,
                 NonUpperCaseGlobals,
                 UnusedImportBraces,
                 NonShorthandFieldPatterns,
                 UnusedUnsafe,
                 UnsafeCode,
                 UnusedMut,
                 UnusedAllocation,
                 MissingCopyImplementations,
                 UnstableFeatures,
                 Deprecated,
                 UnconditionalRecursion,
                 InvalidNoMangleItems,
                 PluginAsLibrary,
                 DropWithReprExtern,
                 MutableTransmutes,
                 );

    add_builtin_with_new!(sess,
                          TypeLimits,
                          MissingDoc,
                          MissingDebugImplementations,
                          );

    add_lint_group!(sess, "bad_style",
                    NON_CAMEL_CASE_TYPES, NON_SNAKE_CASE, NON_UPPER_CASE_GLOBALS);

    add_lint_group!(sess, "unused",
                    UNUSED_IMPORTS, UNUSED_VARIABLES, UNUSED_ASSIGNMENTS, DEAD_CODE,
                    UNUSED_MUT, UNREACHABLE_CODE, UNUSED_MUST_USE,
                    UNUSED_UNSAFE, PATH_STATEMENTS, UNUSED_ATTRIBUTES);

    // Guidelines for creating a future incompatibility lint:
    //
    // - Create a lint defaulting to warn as normal, with ideally the same error
    //   message you would normally give
    // - Add a suitable reference, typically an RFC or tracking issue. Go ahead
    //   and include the full URL.
    // - Later, change lint to error
    // - Eventually, remove lint
    store.register_future_incompatible(sess, vec![
        FutureIncompatibleInfo {
            id: LintId::of(PRIVATE_IN_PUBLIC),
            reference: "the explanation for E0446 (`--explain E0446`)",
        },
        FutureIncompatibleInfo {
            id: LintId::of(INACCESSIBLE_EXTERN_CRATE),
            reference: "PR 31362 <https://github.com/rust-lang/rust/pull/31362>",
        },
        FutureIncompatibleInfo {
            id: LintId::of(INVALID_TYPE_PARAM_DEFAULT),
            reference: "PR 30724 <https://github.com/rust-lang/rust/pull/30724>",
        },
        FutureIncompatibleInfo {
            id: LintId::of(SUPER_OR_SELF_IN_GLOBAL_PATH),
            reference: "PR #32403 <https://github.com/rust-lang/rust/pull/32403>",
        },
        FutureIncompatibleInfo {
            id: LintId::of(MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT),
            reference: "RFC 218 <https://github.com/rust-lang/rfcs/blob/\
                        master/text/0218-empty-struct-with-braces.md>",
        },
        FutureIncompatibleInfo {
            id: LintId::of(TRANSMUTE_FROM_FN_ITEM_TYPES),
            reference: "issue #19925 <https://github.com/rust-lang/rust/issues/19925>",
        },
        FutureIncompatibleInfo {
            id: LintId::of(OVERLAPPING_INHERENT_IMPLS),
            reference: "issue #22889 <https://github.com/rust-lang/rust/issues/22889>",
        },
        FutureIncompatibleInfo {
            id: LintId::of(ILLEGAL_FLOATING_POINT_CONSTANT_PATTERN),
            reference: "RFC 1445 <https://github.com/rust-lang/rfcs/pull/1445>",
        },
        FutureIncompatibleInfo {
            id: LintId::of(ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN),
            reference: "RFC 1445 <https://github.com/rust-lang/rfcs/pull/1445>",
        },
        FutureIncompatibleInfo {
            id: LintId::of(UNSIZED_IN_TUPLE),
            reference: "issue #33242 <https://github.com/rust-lang/rust/issues/33242>",
        },
        FutureIncompatibleInfo {
            id: LintId::of(OBJECT_UNSAFE_FRAGMENT),
            reference: "issue #33243 <https://github.com/rust-lang/rust/issues/33243>",
        },
        FutureIncompatibleInfo {
            id: LintId::of(HR_LIFETIME_IN_ASSOC_TYPE),
            reference: "issue #33685 <https://github.com/rust-lang/rust/issues/33685>",
        },
        FutureIncompatibleInfo {
            id: LintId::of(LIFETIME_UNDERSCORE),
            reference: "RFC 1177 <https://github.com/rust-lang/rfcs/pull/1177>",
        },
        ]);

    // We have one lint pass defined specially
    store.register_late_pass(sess, false, box lint::GatherNodeLevels);

    // Register renamed and removed lints
    store.register_renamed("unknown_features", "unused_features");
    store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate");
    store.register_removed("negate_unsigned", "cast a signed value instead");
    store.register_removed("raw_pointer_derive", "using derive with raw pointers is ok");
    // This was renamed to raw_pointer_derive, which was then removed,
    // so it is also considered removed
    store.register_removed("raw_pointer_deriving", "using derive with raw pointers is ok");
}
<|endoftext|>


<commit_before><commit_msg>add comment<commit_after><|endoftext|>


<commit_before><commit_msg>Hack a fix so packets work through net.<commit_after><|endoftext|>


<commit_before><commit_msg>debuginfo: Bring back some GDB pretty printing autotests that are not actually broken.<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-windows failing on win32 bot
// ignore-freebsd: output doesn't match
// ignore-tidy-linelength
// ignore-lldb
// ignore-android: FIXME(#10381)
// compile-flags:-g

// This test uses some GDB Python API features (e.g. accessing anonymous fields)
// which are only available in newer GDB version. The following directive will
// case the test runner to ignore this test if an older GDB version is used:
// min-gdb-version 7.7

// gdb-command: run

// gdb-command: print regular_struct
// gdb-check:$1 = RegularStruct = {the_first_field = 101, the_second_field = 102.5, the_third_field = false, the_fourth_field = "I'm so pretty, oh so pretty..."}

// gdb-command: print tuple
// gdb-check:$2 = {true, 103, "blub"}

// gdb-command: print tuple_struct
// gdb-check:$3 = TupleStruct = {-104.5, 105}

// gdb-command: print empty_struct
// gdb-check:$4 = EmptyStruct

// gdb-command: print c_style_enum1
// gdb-check:$5 = CStyleEnumVar1

// gdb-command: print c_style_enum2
// gdb-check:$6 = CStyleEnumVar2

// gdb-command: print c_style_enum3
// gdb-check:$7 = CStyleEnumVar3

// gdb-command: print mixed_enum_c_style_var
// gdb-check:$8 = MixedEnumCStyleVar

// gdb-command: print mixed_enum_tuple_var
// gdb-check:$9 = MixedEnumTupleVar = {106, 107, false}

// gdb-command: print mixed_enum_struct_var
// gdb-check:$10 = MixedEnumStructVar = {field1 = 108.5, field2 = 109}

// gdb-command: print some
// gdb-check:$11 = Some = {110}

// gdb-command: print none
// gdb-check:$12 = None

// gdb-command: print some_fat
// gdb-check:$13 = Some = {"abc"}

// gdb-command: print none_fat
// gdb-check:$14 = None

// gdb-command: print nested_variant1
// gdb-check:$15 = NestedVariant1 = {NestedStruct = {regular_struct = RegularStruct = {the_first_field = 111, the_second_field = 112.5, the_third_field = true, the_fourth_field = "NestedStructString1"}, tuple_struct = TupleStruct = {113.5, 114}, empty_struct = EmptyStruct, c_style_enum = CStyleEnumVar2, mixed_enum = MixedEnumTupleVar = {115, 116, false}}}

// gdb-command: print nested_variant2
// gdb-check:$16 = NestedVariant2 = {abc = NestedStruct = {regular_struct = RegularStruct = {the_first_field = 117, the_second_field = 118.5, the_third_field = false, the_fourth_field = "NestedStructString10"}, tuple_struct = TupleStruct = {119.5, 120}, empty_struct = EmptyStruct, c_style_enum = CStyleEnumVar3, mixed_enum = MixedEnumStructVar = {field1 = 121.5, field2 = -122}}}

// gdb-command: print none_check1
// gdb-check:$17 = None

// gdb-command: print none_check2
// gdb-check:$18 = None

#![allow(dead_code, unused_variables)]

use self::CStyleEnum::{CStyleEnumVar1, CStyleEnumVar2, CStyleEnumVar3};
use self::MixedEnum::{MixedEnumCStyleVar, MixedEnumTupleVar, MixedEnumStructVar};
use self::NestedEnum::{NestedVariant1, NestedVariant2};

struct RegularStruct {
    the_first_field: isize,
    the_second_field: f64,
    the_third_field: bool,
    the_fourth_field: &'static str,
}

struct TupleStruct(f64, i16);

struct EmptyStruct;

enum CStyleEnum {
    CStyleEnumVar1,
    CStyleEnumVar2,
    CStyleEnumVar3,
}

enum MixedEnum {
    MixedEnumCStyleVar,
    MixedEnumTupleVar(u32, u16, bool),
    MixedEnumStructVar { field1: f64, field2: i32 }
}

struct NestedStruct {
    regular_struct: RegularStruct,
    tuple_struct: TupleStruct,
    empty_struct: EmptyStruct,
    c_style_enum: CStyleEnum,
    mixed_enum: MixedEnum,
}

enum NestedEnum {
    NestedVariant1(NestedStruct),
    NestedVariant2 { abc: NestedStruct }
}

fn main() {

    let regular_struct = RegularStruct {
        the_first_field: 101,
        the_second_field: 102.5,
        the_third_field: false,
        the_fourth_field: "I'm so pretty, oh so pretty..."
    };

    let tuple = ( true, 103u32, "blub" );

    let tuple_struct = TupleStruct(-104.5, 105);

    let empty_struct = EmptyStruct;

    let c_style_enum1 = CStyleEnumVar1;
    let c_style_enum2 = CStyleEnumVar2;
    let c_style_enum3 = CStyleEnumVar3;

    let mixed_enum_c_style_var = MixedEnumCStyleVar;
    let mixed_enum_tuple_var = MixedEnumTupleVar(106, 107, false);
    let mixed_enum_struct_var = MixedEnumStructVar { field1: 108.5, field2: 109 };

    let some = Some(110_usize);
    let none: Option<isize> = None;
    let some_fat = Some("abc");
    let none_fat: Option<&'static str> = None;

    let nested_variant1 = NestedVariant1(
        NestedStruct {
            regular_struct: RegularStruct {
                the_first_field: 111,
                the_second_field: 112.5,
                the_third_field: true,
                the_fourth_field: "NestedStructString1",
            },
            tuple_struct: TupleStruct(113.5, 114),
            empty_struct: EmptyStruct,
            c_style_enum: CStyleEnumVar2,
            mixed_enum: MixedEnumTupleVar(115, 116, false)
        }
    );

    let nested_variant2 = NestedVariant2 {
        abc: NestedStruct {
            regular_struct: RegularStruct {
                the_first_field: 117,
                the_second_field: 118.5,
                the_third_field: false,
                the_fourth_field: "NestedStructString10",
            },
            tuple_struct: TupleStruct(119.5, 120),
            empty_struct: EmptyStruct,
            c_style_enum: CStyleEnumVar3,
            mixed_enum: MixedEnumStructVar {
                field1: 121.5,
                field2: -122
            }
        }
    };

    let none_check1: Option<(usize, Vec<usize>)> = None;
    let none_check2: Option<String> = None;

    zzz(); // #break
}

fn zzz() { () }
<|endoftext|>


<commit_before>//! Crate `ruma-api-macros` provides a procedural macro for easily generating
//! [ruma-api](https://github.com/ruma/ruma-api)-compatible endpoints.
//!
//! See the documentation for the `ruma_api!` macro for usage details.

#![deny(
    missing_copy_implementations,
    missing_debug_implementations,
    // missing_docs, # Uncomment when https://github.com/rust-lang/rust/pull/60562 is released.
    warnings
)]
#![warn(
    clippy::empty_line_after_outer_attr,
    clippy::expl_impl_clone_on_copy,
    clippy::if_not_else,
    clippy::items_after_statements,
    clippy::match_same_arms,
    clippy::mem_forget,
    clippy::missing_docs_in_private_items,
    clippy::multiple_inherent_impl,
    clippy::mut_mut,
    clippy::needless_borrow,
    clippy::needless_continue,
    clippy::single_match_else,
    clippy::unicode_not_nfc,
    clippy::use_self,
    clippy::used_underscore_binding,
    clippy::wrong_pub_self_convention,
    clippy::wrong_self_convention
)]
#![recursion_limit = "256"]

extern crate proc_macro;

use proc_macro::TokenStream;
use quote::ToTokens;

use crate::api::{Api, RawApi};

mod api;

/// Generates a `ruma_api::Endpoint` from a concise definition.
///
/// The macro expects the following structure as input:
///
/// ```text
/// ruma_api! {
///     metadata {
///         description: &'static str
///         method: http::Method,
///         name: &'static str,
///         path: &'static str,
///         rate_limited: bool,
///         requires_authentication: bool,
///     }
///
///     request {
///         // Struct fields for each piece of data required
///         // to make a request to this API endpoint.
///     }
///
///     response {
///         // Struct fields for each piece of data expected
///         // in the response from this API endpoint.
///     }
/// }
/// # }
/// ```
///
/// This will generate a `ruma_api::Metadata` value to be used for the `ruma_api::Endpoint`'s
/// associated constant, single `Request` and `Response` structs, and the necessary trait
/// implementations to convert the request into a `http::Request` and to create a response from a
/// `http::Response` and vice versa.
///
/// The details of each of the three sections of the macros are documented below.
///
/// ## Metadata
///
/// *   `description`: A short description of what the endpoint does.
/// *   `method`: The HTTP method used for requests to the endpoint.
///     It's not necessary to import `http::Method`'s associated constants. Just write
///     the value as if it was imported, e.g. `GET`.
/// *   `name`: A unique name for the endpoint.
///     Generally this will be the same as the containing module.
/// *   `path`: The path component of the URL for the endpoint, e.g. "/foo/bar".
///     Components of the path that are parameterized can indicate a varible by using a Rust
///     identifier prefixed with a colon, e.g. `/foo/:some_parameter`.
///     A corresponding query string parameter will be expected in the request struct (see below
///     for details).
/// *   `rate_limited`: Whether or not the endpoint enforces rate limiting on requests.
/// *   `requires_authentication`: Whether or not the endpoint requires a valid access token.
///
/// ## Request
///
/// The request block contains normal struct field definitions.
/// Doc comments and attributes are allowed as normal.
/// There are also a few special attributes available to control how the struct is converted into a
/// `http::Request`:
///
/// *   `#[ruma_api(header = "HEADER_NAME")]`: Fields with this attribute will be treated as HTTP
///     headers on the request.
///     The value must implement `AsRef<str>`.
///     Generally this is a `String`.
///     The attribute value shown above as `HEADER_NAME` must be a header name constant from
///     `http::header`, e.g. `CONTENT_TYPE`.
/// *   `#[ruma_api(path)]`: Fields with this attribute will be inserted into the matching path
///     component of the request URL.
/// *   `#[ruma_api(query)]`: Fields with this attribute will be inserting into the URL's query
///     string.
///
/// Any field that does not include one of these attributes will be part of the request's JSON
/// body.
///
/// ## Response
///
/// Like the request block, the response block consists of normal struct field definitions.
/// Doc comments and attributes are allowed as normal.
/// There is also a special attribute available to control how the struct is created from a
/// `http::Request`:
///
/// *   `#[ruma_api(header = "HEADER_NAME")]`: Fields with this attribute will be treated as HTTP
///     headers on the response.
///     The value must implement `AsRef<str>`.
///     Generally this is a `String`.
///     The attribute value shown above as `HEADER_NAME` must be a header name constant from
///     `http::header`, e.g. `CONTENT_TYPE`.
///
/// Any field that does not include the above attribute will be expected in the response's JSON
/// body.
///
/// ## Newtype bodies
///
/// Both the request and response block also support "newtype bodies" by using the
/// `#[ruma_api(body)]` attribute on a field. If present on a field, the entire request or response
/// body will be treated as the value of the field. This allows you to treat the entire request or
/// response body as a specific type, rather than a JSON object with named fields. Only one field in
/// each struct can be marked with this attribute. It is an error to have a newtype body field and
/// normal body fields within the same struct.
///
/// # Examples
///
/// ```rust,ignore
/// # fn main() {
/// pub mod some_endpoint {
///     use ruma_api_macros::ruma_api;
///
///     ruma_api! {
///         metadata {
///             description: "Does something.",
///             method: GET,
///             name: "some_endpoint",
///             path: "/_matrix/some/endpoint/:baz",
///             rate_limited: false,
///             requires_authentication: false,
///         }
///
///         request {
///             pub foo: String,
///
///             #[ruma_api(header = CONTENT_TYPE)]
///             pub content_type: String,
///
///             #[ruma_api(query)]
///             pub bar: String,
///
///             #[ruma_api(path)]
///             pub baz: String,
///         }
///
///         response {
///             #[ruma_api(header = CONTENT_TYPE)]
///             pub content_type: String,
///
///             pub value: String,
///         }
///     }
/// }
///
/// pub mod newtype_body_endpoint {
///     use ruma_api_macros::ruma_api;
///
///     #[derive(Clone, Debug, Deserialize, Serialize)]
///     pub struct MyCustomType {
///         pub foo: String,
///     }
///
///     ruma_api! {
///         metadata {
///             description: "Does something.",
///             method: GET,
///             name: "newtype_body_endpoint",
///             path: "/_matrix/some/newtype/body/endpoint",
///             rate_limited: false,
///             requires_authentication: false,
///         }
///
///         request {
///             #[ruma_api(body)]
///             pub file: Vec<u8>,
///         }
///
///         response {
///             #[ruma_api(body)]
///             pub my_custom_type: MyCustomType,
///         }
///     }
/// }
/// # }
/// ```
#[proc_macro]
pub fn ruma_api(input: TokenStream) -> TokenStream {
    let raw_api = syn::parse_macro_input!(input as RawApi);

    let api = Api::from(raw_api);

    api.into_token_stream().into()
}
<commit_msg>Disable clippy lint cognitive_complexity for ruma-api-macros<commit_after>//! Crate `ruma-api-macros` provides a procedural macro for easily generating
//! [ruma-api](https://github.com/ruma/ruma-api)-compatible endpoints.
//!
//! See the documentation for the `ruma_api!` macro for usage details.

#![deny(
    missing_copy_implementations,
    missing_debug_implementations,
    // missing_docs, # Uncomment when https://github.com/rust-lang/rust/pull/60562 is released.
    warnings
)]
#![warn(
    clippy::empty_line_after_outer_attr,
    clippy::expl_impl_clone_on_copy,
    clippy::if_not_else,
    clippy::items_after_statements,
    clippy::match_same_arms,
    clippy::mem_forget,
    clippy::missing_docs_in_private_items,
    clippy::multiple_inherent_impl,
    clippy::mut_mut,
    clippy::needless_borrow,
    clippy::needless_continue,
    clippy::single_match_else,
    clippy::unicode_not_nfc,
    clippy::use_self,
    clippy::used_underscore_binding,
    clippy::wrong_pub_self_convention,
    clippy::wrong_self_convention
)]
#![allow(clippy::cognitive_complexity)]
#![recursion_limit = "256"]

extern crate proc_macro;

use proc_macro::TokenStream;
use quote::ToTokens;

use crate::api::{Api, RawApi};

mod api;

/// Generates a `ruma_api::Endpoint` from a concise definition.
///
/// The macro expects the following structure as input:
///
/// ```text
/// ruma_api! {
///     metadata {
///         description: &'static str
///         method: http::Method,
///         name: &'static str,
///         path: &'static str,
///         rate_limited: bool,
///         requires_authentication: bool,
///     }
///
///     request {
///         // Struct fields for each piece of data required
///         // to make a request to this API endpoint.
///     }
///
///     response {
///         // Struct fields for each piece of data expected
///         // in the response from this API endpoint.
///     }
/// }
/// # }
/// ```
///
/// This will generate a `ruma_api::Metadata` value to be used for the `ruma_api::Endpoint`'s
/// associated constant, single `Request` and `Response` structs, and the necessary trait
/// implementations to convert the request into a `http::Request` and to create a response from a
/// `http::Response` and vice versa.
///
/// The details of each of the three sections of the macros are documented below.
///
/// ## Metadata
///
/// *   `description`: A short description of what the endpoint does.
/// *   `method`: The HTTP method used for requests to the endpoint.
///     It's not necessary to import `http::Method`'s associated constants. Just write
///     the value as if it was imported, e.g. `GET`.
/// *   `name`: A unique name for the endpoint.
///     Generally this will be the same as the containing module.
/// *   `path`: The path component of the URL for the endpoint, e.g. "/foo/bar".
///     Components of the path that are parameterized can indicate a varible by using a Rust
///     identifier prefixed with a colon, e.g. `/foo/:some_parameter`.
///     A corresponding query string parameter will be expected in the request struct (see below
///     for details).
/// *   `rate_limited`: Whether or not the endpoint enforces rate limiting on requests.
/// *   `requires_authentication`: Whether or not the endpoint requires a valid access token.
///
/// ## Request
///
/// The request block contains normal struct field definitions.
/// Doc comments and attributes are allowed as normal.
/// There are also a few special attributes available to control how the struct is converted into a
/// `http::Request`:
///
/// *   `#[ruma_api(header = "HEADER_NAME")]`: Fields with this attribute will be treated as HTTP
///     headers on the request.
///     The value must implement `AsRef<str>`.
///     Generally this is a `String`.
///     The attribute value shown above as `HEADER_NAME` must be a header name constant from
///     `http::header`, e.g. `CONTENT_TYPE`.
/// *   `#[ruma_api(path)]`: Fields with this attribute will be inserted into the matching path
///     component of the request URL.
/// *   `#[ruma_api(query)]`: Fields with this attribute will be inserting into the URL's query
///     string.
///
/// Any field that does not include one of these attributes will be part of the request's JSON
/// body.
///
/// ## Response
///
/// Like the request block, the response block consists of normal struct field definitions.
/// Doc comments and attributes are allowed as normal.
/// There is also a special attribute available to control how the struct is created from a
/// `http::Request`:
///
/// *   `#[ruma_api(header = "HEADER_NAME")]`: Fields with this attribute will be treated as HTTP
///     headers on the response.
///     The value must implement `AsRef<str>`.
///     Generally this is a `String`.
///     The attribute value shown above as `HEADER_NAME` must be a header name constant from
///     `http::header`, e.g. `CONTENT_TYPE`.
///
/// Any field that does not include the above attribute will be expected in the response's JSON
/// body.
///
/// ## Newtype bodies
///
/// Both the request and response block also support "newtype bodies" by using the
/// `#[ruma_api(body)]` attribute on a field. If present on a field, the entire request or response
/// body will be treated as the value of the field. This allows you to treat the entire request or
/// response body as a specific type, rather than a JSON object with named fields. Only one field in
/// each struct can be marked with this attribute. It is an error to have a newtype body field and
/// normal body fields within the same struct.
///
/// # Examples
///
/// ```rust,ignore
/// # fn main() {
/// pub mod some_endpoint {
///     use ruma_api_macros::ruma_api;
///
///     ruma_api! {
///         metadata {
///             description: "Does something.",
///             method: GET,
///             name: "some_endpoint",
///             path: "/_matrix/some/endpoint/:baz",
///             rate_limited: false,
///             requires_authentication: false,
///         }
///
///         request {
///             pub foo: String,
///
///             #[ruma_api(header = CONTENT_TYPE)]
///             pub content_type: String,
///
///             #[ruma_api(query)]
///             pub bar: String,
///
///             #[ruma_api(path)]
///             pub baz: String,
///         }
///
///         response {
///             #[ruma_api(header = CONTENT_TYPE)]
///             pub content_type: String,
///
///             pub value: String,
///         }
///     }
/// }
///
/// pub mod newtype_body_endpoint {
///     use ruma_api_macros::ruma_api;
///
///     #[derive(Clone, Debug, Deserialize, Serialize)]
///     pub struct MyCustomType {
///         pub foo: String,
///     }
///
///     ruma_api! {
///         metadata {
///             description: "Does something.",
///             method: GET,
///             name: "newtype_body_endpoint",
///             path: "/_matrix/some/newtype/body/endpoint",
///             rate_limited: false,
///             requires_authentication: false,
///         }
///
///         request {
///             #[ruma_api(body)]
///             pub file: Vec<u8>,
///         }
///
///         response {
///             #[ruma_api(body)]
///             pub my_custom_type: MyCustomType,
///         }
///     }
/// }
/// # }
/// ```
#[proc_macro]
pub fn ruma_api(input: TokenStream) -> TokenStream {
    let raw_api = syn::parse_macro_input!(input as RawApi);

    let api = Api::from(raw_api);

    api.into_token_stream().into()
}
<|endoftext|>


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

use dom::bindings::codegen::Bindings::PerformanceBinding;
use dom::bindings::js::{JS, JSRef, Temporary};
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::performancetiming::{PerformanceTiming, PerformanceTimingMethods};
use dom::window::Window;
use time;

pub type DOMHighResTimeStamp = f64;

#[deriving(Encodable)]
pub struct Performance {
    reflector_: Reflector,
    timing: JS<PerformanceTiming>,
}

impl Performance {
    fn new_inherited(window: &JSRef<Window>) -> Performance {
        let timing = JS::from_rooted(&PerformanceTiming::new(window).root().root_ref());
        Performance {
            reflector_: Reflector::new(),
            timing: timing,
        }
    }

    pub fn new(window: &JSRef<Window>) -> Temporary<Performance> {
        let performance = Performance::new_inherited(window);
        reflect_dom_object(box performance, window, PerformanceBinding::Wrap)
    }
}

pub trait PerformanceMethods {
    fn Timing(&self) -> Temporary<PerformanceTiming>;
    fn Now(&self) -> DOMHighResTimeStamp;
}

impl<'a> PerformanceMethods for JSRef<'a, Performance> {
    fn Timing(&self) -> Temporary<PerformanceTiming> {
        Temporary::new(self.timing.clone())
    }

    fn Now(&self) -> DOMHighResTimeStamp {
        let navStart = self.timing.root().NavigationStartPrecise() as f64;
        (time::precise_time_s() - navStart) as DOMHighResTimeStamp
    }
}

impl Reflectable for Performance {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        &self.reflector_
    }
}
<commit_msg>Simplify the initialization of Performance.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::PerformanceBinding;
use dom::bindings::js::{JS, JSRef, Temporary};
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::performancetiming::{PerformanceTiming, PerformanceTimingMethods};
use dom::window::Window;
use time;

pub type DOMHighResTimeStamp = f64;

#[deriving(Encodable)]
pub struct Performance {
    reflector_: Reflector,
    timing: JS<PerformanceTiming>,
}

impl Performance {
    fn new_inherited(window: &JSRef<Window>) -> Performance {
        Performance {
            reflector_: Reflector::new(),
            timing: JS::from_rooted(&PerformanceTiming::new(window)),
        }
    }

    pub fn new(window: &JSRef<Window>) -> Temporary<Performance> {
        let performance = Performance::new_inherited(window);
        reflect_dom_object(box performance, window, PerformanceBinding::Wrap)
    }
}

pub trait PerformanceMethods {
    fn Timing(&self) -> Temporary<PerformanceTiming>;
    fn Now(&self) -> DOMHighResTimeStamp;
}

impl<'a> PerformanceMethods for JSRef<'a, Performance> {
    fn Timing(&self) -> Temporary<PerformanceTiming> {
        Temporary::new(self.timing.clone())
    }

    fn Now(&self) -> DOMHighResTimeStamp {
        let navStart = self.timing.root().NavigationStartPrecise() as f64;
        (time::precise_time_s() - navStart) as DOMHighResTimeStamp
    }
}

impl Reflectable for Performance {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        &self.reflector_
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![unstable(feature = "futures_api",
            reason = "futures in libcore are unstable",
            issue = "50547")]

use {fmt, mem};
use marker::Unpin;
use ptr::NonNull;

/// A `Waker` is a handle for waking up a task by notifying its executor that it
/// is ready to be run.
///
/// This handle contains a trait object pointing to an instance of the `UnsafeWake`
/// trait, allowing notifications to get routed through it.
#[repr(transparent)]
pub struct Waker {
    inner: NonNull<dyn UnsafeWake>,
}

impl Unpin for Waker {}
unsafe impl Send for Waker {}
unsafe impl Sync for Waker {}

impl Waker {
    /// Constructs a new `Waker` directly.
    ///
    /// Note that most code will not need to call this. Implementers of the
    /// `UnsafeWake` trait will typically provide a wrapper that calls this
    /// but you otherwise shouldn't call it directly.
    ///
    /// If you're working with the standard library then it's recommended to
    /// use the `Waker::from` function instead which works with the safe
    /// `Arc` type and the safe `Wake` trait.
    #[inline]
    pub unsafe fn new(inner: NonNull<dyn UnsafeWake>) -> Self {
        Waker { inner }
    }

    /// Wake up the task associated with this `Waker`.
    #[inline]
    pub fn wake(&self) {
        unsafe { self.inner.as_ref().wake() }
    }

    /// Returns whether or not this `Waker` and `other` awaken the same task.
    ///
    /// This function works on a best-effort basis, and may return false even
    /// when the `Waker`s would awaken the same task. However, if this function
    /// returns true, it is guaranteed that the `Waker`s will awaken the same
    /// task.
    ///
    /// This function is primarily used for optimization purposes.
    #[inline]
    pub fn will_wake(&self, other: &Waker) -> bool {
        self.inner == other.inner
    }
}

impl Clone for Waker {
    #[inline]
    fn clone(&self) -> Self {
        unsafe {
            self.inner.as_ref().clone_raw()
        }
    }
}

impl fmt::Debug for Waker {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Waker")
            .finish()
    }
}

impl Drop for Waker {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            self.inner.as_ref().drop_raw()
        }
    }
}

/// A `LocalWaker` is a handle for waking up a task by notifying its executor that it
/// is ready to be run.
///
/// This is similar to the `Waker` type, but cannot be sent across threads.
/// Task executors can use this type to implement more optimized singlethreaded wakeup
/// behavior.
#[repr(transparent)]
pub struct LocalWaker {
    inner: NonNull<dyn UnsafeWake>,
}

impl Unpin for LocalWaker {}
impl !Send for LocalWaker {}
impl !Sync for LocalWaker {}

impl LocalWaker {
    /// Constructs a new `LocalWaker` directly.
    ///
    /// Note that most code will not need to call this. Implementers of the
    /// `UnsafeWake` trait will typically provide a wrapper that calls this
    /// but you otherwise shouldn't call it directly.
    ///
    /// If you're working with the standard library then it's recommended to
    /// use the `local_waker_from_nonlocal` or `local_waker` to convert a `Waker`
    /// into a `LocalWaker`.
    ///
    /// For this function to be used safely, it must be sound to call `inner.wake_local()`
    /// on the current thread.
    #[inline]
    pub unsafe fn new(inner: NonNull<dyn UnsafeWake>) -> Self {
        LocalWaker { inner }
    }

    /// Converts this `LocalWaker` into a `Waker`.
    ///
    /// `Waker` is nearly identical to `LocalWaker`, but is threadsafe
    /// (implements `Send` and `Sync`).
    #[inline]
    pub fn into_waker(self) -> Waker {
        self.into()
    }

    /// Wake up the task associated with this `LocalWaker`.
    #[inline]
    pub fn wake(&self) {
        unsafe { self.inner.as_ref().wake_local() }
    }

    /// Returns whether or not this `LocalWaker` and `other` `LocalWaker` awaken the same task.
    ///
    /// This function works on a best-effort basis, and may return false even
    /// when the `LocalWaker`s would awaken the same task. However, if this function
    /// returns true, it is guaranteed that the `LocalWaker`s will awaken the same
    /// task.
    ///
    /// This function is primarily used for optimization purposes.
    #[inline]
    pub fn will_wake(&self, other: &LocalWaker) -> bool {
        self.inner == other.inner
    }

    /// Returns whether or not this `LocalWaker` and `other` `Waker` awaken the same task.
    ///
    /// This function works on a best-effort basis, and may return false even
    /// when the `Waker`s would awaken the same task. However, if this function
    /// returns true, it is guaranteed that the `LocalWaker`s will awaken the same
    /// task.
    ///
    /// This function is primarily used for optimization purposes.
    #[inline]
    pub fn will_wake_nonlocal(&self, other: &Waker) -> bool {
        self.inner == other.inner
    }
}

impl From<LocalWaker> for Waker {
    #[inline]
    fn from(local_waker: LocalWaker) -> Self {
        let inner = local_waker.inner;
        mem::forget(local_waker);
        Waker { inner }
    }
}

impl Clone for LocalWaker {
    #[inline]
    fn clone(&self) -> Self {
        let waker = unsafe { self.inner.as_ref().clone_raw() };
        let inner = waker.inner;
        mem::forget(waker);
        LocalWaker { inner }
    }
}

impl fmt::Debug for LocalWaker {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Waker")
            .finish()
    }
}

impl Drop for LocalWaker {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            self.inner.as_ref().drop_raw()
        }
    }
}

/// An unsafe trait for implementing custom memory management for a `Waker` or `LocalWaker`.
///
/// A `Waker` conceptually is a cloneable trait object for `Wake`, and is
/// most often essentially just `Arc<dyn Wake>`. However, in some contexts
/// (particularly `no_std`), it's desirable to avoid `Arc` in favor of some
/// custom memory management strategy. This trait is designed to allow for such
/// customization.
///
/// When using `std`, a default implementation of the `UnsafeWake` trait is provided for
/// `Arc<T>` where `T: Wake`.
pub unsafe trait UnsafeWake: Send + Sync {
    /// Creates a clone of this `UnsafeWake` and stores it behind a `Waker`.
    ///
    /// This function will create a new uniquely owned handle that under the
    /// hood references the same notification instance. In other words calls
    /// to `wake` on the returned handle should be equivalent to calls to
    /// `wake` on this handle.
    ///
    /// # Unsafety
    ///
    /// This function is unsafe to call because it's asserting the `UnsafeWake`
    /// value is in a consistent state, i.e. hasn't been dropped.
    unsafe fn clone_raw(&self) -> Waker;

    /// Drops this instance of `UnsafeWake`, deallocating resources
    /// associated with it.
    ///
    /// FIXME(cramertj)
    /// This method is intended to have a signature such as:
    ///
    /// ```ignore (not-a-doctest)
    /// fn drop_raw(self: *mut Self);
    /// ```
    ///
    /// Unfortunately in Rust today that signature is not object safe.
    /// Nevertheless it's recommended to implement this function *as if* that
    /// were its signature. As such it is not safe to call on an invalid
    /// pointer, nor is the validity of the pointer guaranteed after this
    /// function returns.
    ///
    /// # Unsafety
    ///
    /// This function is unsafe to call because it's asserting the `UnsafeWake`
    /// value is in a consistent state, i.e. hasn't been dropped.
    unsafe fn drop_raw(&self);

    /// Indicates that the associated task is ready to make progress and should
    /// be `poll`ed.
    ///
    /// Executors generally maintain a queue of "ready" tasks; `wake` should place
    /// the associated task onto this queue.
    ///
    /// # Panics
    ///
    /// Implementations should avoid panicking, but clients should also be prepared
    /// for panics.
    ///
    /// # Unsafety
    ///
    /// This function is unsafe to call because it's asserting the `UnsafeWake`
    /// value is in a consistent state, i.e. hasn't been dropped.
    unsafe fn wake(&self);

    /// Indicates that the associated task is ready to make progress and should
    /// be `poll`ed. This function is the same as `wake`, but can only be called
    /// from the thread that this `UnsafeWake` is "local" to. This allows for
    /// implementors to provide specialized wakeup behavior specific to the current
    /// thread. This function is called by `LocalWaker::wake`.
    ///
    /// Executors generally maintain a queue of "ready" tasks; `wake_local` should place
    /// the associated task onto this queue.
    ///
    /// # Panics
    ///
    /// Implementations should avoid panicking, but clients should also be prepared
    /// for panics.
    ///
    /// # Unsafety
    ///
    /// This function is unsafe to call because it's asserting the `UnsafeWake`
    /// value is in a consistent state, i.e. hasn't been dropped, and that the
    /// `UnsafeWake` hasn't moved from the thread on which it was created.
    unsafe fn wake_local(&self) {
        self.wake()
    }
}
<commit_msg>LocalWaker and Waker cleanups<commit_after>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![unstable(feature = "futures_api",
            reason = "futures in libcore are unstable",
            issue = "50547")]

use fmt;
use marker::Unpin;
use ptr::NonNull;

/// A `Waker` is a handle for waking up a task by notifying its executor that it
/// is ready to be run.
///
/// This handle contains a trait object pointing to an instance of the `UnsafeWake`
/// trait, allowing notifications to get routed through it.
#[repr(transparent)]
pub struct Waker {
    inner: NonNull<dyn UnsafeWake>,
}

impl Unpin for Waker {}
unsafe impl Send for Waker {}
unsafe impl Sync for Waker {}

impl Waker {
    /// Constructs a new `Waker` directly.
    ///
    /// Note that most code will not need to call this. Implementers of the
    /// `UnsafeWake` trait will typically provide a wrapper that calls this
    /// but you otherwise shouldn't call it directly.
    ///
    /// If you're working with the standard library then it's recommended to
    /// use the `Waker::from` function instead which works with the safe
    /// `Arc` type and the safe `Wake` trait.
    #[inline]
    pub unsafe fn new(inner: NonNull<dyn UnsafeWake>) -> Self {
        Waker { inner }
    }

    /// Wake up the task associated with this `Waker`.
    #[inline]
    pub fn wake(&self) {
        unsafe { self.inner.as_ref().wake() }
    }

    /// Returns whether or not this `Waker` and `other` awaken the same task.
    ///
    /// This function works on a best-effort basis, and may return false even
    /// when the `Waker`s would awaken the same task. However, if this function
    /// returns true, it is guaranteed that the `Waker`s will awaken the same
    /// task.
    ///
    /// This function is primarily used for optimization purposes.
    #[inline]
    pub fn will_wake(&self, other: &Waker) -> bool {
        self.inner == other.inner
    }

    /// Returns whether or not this `Waker` and `other` `LocalWaker` awaken
    /// the same task.
    ///
    /// This function works on a best-effort basis, and may return false even
    /// when the `Waker`s would awaken the same task. However, if this function
    /// returns true, it is guaranteed that the `Waker`s will awaken the same
    /// task.
    ///
    /// This function is primarily used for optimization purposes.
    #[inline]
    pub fn will_wake_local(&self, other: &LocalWaker) -> bool {
        self.will_wake(&other.0)
    }
}

impl Clone for Waker {
    #[inline]
    fn clone(&self) -> Self {
        unsafe {
            self.inner.as_ref().clone_raw()
        }
    }
}

impl fmt::Debug for Waker {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Waker")
            .finish()
    }
}

impl Drop for Waker {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            self.inner.as_ref().drop_raw()
        }
    }
}

/// A `LocalWaker` is a handle for waking up a task by notifying its executor that it
/// is ready to be run.
///
/// This is similar to the `Waker` type, but cannot be sent across threads.
/// Task executors can use this type to implement more optimized singlethreaded wakeup
/// behavior.
#[repr(transparent)]
#[derive(Clone)]
pub struct LocalWaker(Waker);

impl Unpin for LocalWaker {}
impl !Send for LocalWaker {}
impl !Sync for LocalWaker {}

impl LocalWaker {
    /// Constructs a new `LocalWaker` directly.
    ///
    /// Note that most code will not need to call this. Implementers of the
    /// `UnsafeWake` trait will typically provide a wrapper that calls this
    /// but you otherwise shouldn't call it directly.
    ///
    /// If you're working with the standard library then it's recommended to
    /// use the `local_waker_from_nonlocal` or `local_waker` to convert a `Waker`
    /// into a `LocalWaker`.
    ///
    /// For this function to be used safely, it must be sound to call `inner.wake_local()`
    /// on the current thread.
    #[inline]
    pub unsafe fn new(inner: NonNull<dyn UnsafeWake>) -> Self {
        LocalWaker(Waker::new(inner))
    }

    /// Borrows this `LocalWaker` as a `Waker`.
    ///
    /// `Waker` is nearly identical to `LocalWaker`, but is threadsafe
    /// (implements `Send` and `Sync`).
    #[inline]
    pub fn as_waker(&self) -> &Waker {
        &self.0
    }

    /// Converts this `LocalWaker` into a `Waker`.
    ///
    /// `Waker` is nearly identical to `LocalWaker`, but is threadsafe
    /// (implements `Send` and `Sync`).
    #[inline]
    pub fn into_waker(self) -> Waker {
        self.0
    }

    /// Wake up the task associated with this `LocalWaker`.
    #[inline]
    pub fn wake(&self) {
        unsafe { self.0.inner.as_ref().wake_local() }
    }

    /// Returns whether or not this `LocalWaker` and `other` `LocalWaker` awaken the same task.
    ///
    /// This function works on a best-effort basis, and may return false even
    /// when the `LocalWaker`s would awaken the same task. However, if this function
    /// returns true, it is guaranteed that the `LocalWaker`s will awaken the same
    /// task.
    ///
    /// This function is primarily used for optimization purposes.
    #[inline]
    pub fn will_wake(&self, other: &LocalWaker) -> bool {
        self.0.will_wake(&other.0)
    }

    /// Returns whether or not this `LocalWaker` and `other` `Waker` awaken the same task.
    ///
    /// This function works on a best-effort basis, and may return false even
    /// when the `Waker`s would awaken the same task. However, if this function
    /// returns true, it is guaranteed that the `LocalWaker`s will awaken the same
    /// task.
    ///
    /// This function is primarily used for optimization purposes.
    #[inline]
    pub fn will_wake_nonlocal(&self, other: &Waker) -> bool {
        self.0.will_wake(other)
    }
}

impl From<LocalWaker> for Waker {
    #[inline]
    fn from(local_waker: LocalWaker) -> Self {
        local_waker.0
    }
}

impl fmt::Debug for LocalWaker {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("LocalWaker")
            .finish()
    }
}

/// An unsafe trait for implementing custom memory management for a `Waker` or `LocalWaker`.
///
/// A `Waker` conceptually is a cloneable trait object for `Wake`, and is
/// most often essentially just `Arc<dyn Wake>`. However, in some contexts
/// (particularly `no_std`), it's desirable to avoid `Arc` in favor of some
/// custom memory management strategy. This trait is designed to allow for such
/// customization.
///
/// When using `std`, a default implementation of the `UnsafeWake` trait is provided for
/// `Arc<T>` where `T: Wake`.
pub unsafe trait UnsafeWake: Send + Sync {
    /// Creates a clone of this `UnsafeWake` and stores it behind a `Waker`.
    ///
    /// This function will create a new uniquely owned handle that under the
    /// hood references the same notification instance. In other words calls
    /// to `wake` on the returned handle should be equivalent to calls to
    /// `wake` on this handle.
    ///
    /// # Unsafety
    ///
    /// This function is unsafe to call because it's asserting the `UnsafeWake`
    /// value is in a consistent state, i.e. hasn't been dropped.
    unsafe fn clone_raw(&self) -> Waker;

    /// Drops this instance of `UnsafeWake`, deallocating resources
    /// associated with it.
    ///
    /// FIXME(cramertj)
    /// This method is intended to have a signature such as:
    ///
    /// ```ignore (not-a-doctest)
    /// fn drop_raw(self: *mut Self);
    /// ```
    ///
    /// Unfortunately in Rust today that signature is not object safe.
    /// Nevertheless it's recommended to implement this function *as if* that
    /// were its signature. As such it is not safe to call on an invalid
    /// pointer, nor is the validity of the pointer guaranteed after this
    /// function returns.
    ///
    /// # Unsafety
    ///
    /// This function is unsafe to call because it's asserting the `UnsafeWake`
    /// value is in a consistent state, i.e. hasn't been dropped.
    unsafe fn drop_raw(&self);

    /// Indicates that the associated task is ready to make progress and should
    /// be `poll`ed.
    ///
    /// Executors generally maintain a queue of "ready" tasks; `wake` should place
    /// the associated task onto this queue.
    ///
    /// # Panics
    ///
    /// Implementations should avoid panicking, but clients should also be prepared
    /// for panics.
    ///
    /// # Unsafety
    ///
    /// This function is unsafe to call because it's asserting the `UnsafeWake`
    /// value is in a consistent state, i.e. hasn't been dropped.
    unsafe fn wake(&self);

    /// Indicates that the associated task is ready to make progress and should
    /// be `poll`ed. This function is the same as `wake`, but can only be called
    /// from the thread that this `UnsafeWake` is "local" to. This allows for
    /// implementors to provide specialized wakeup behavior specific to the current
    /// thread. This function is called by `LocalWaker::wake`.
    ///
    /// Executors generally maintain a queue of "ready" tasks; `wake_local` should place
    /// the associated task onto this queue.
    ///
    /// # Panics
    ///
    /// Implementations should avoid panicking, but clients should also be prepared
    /// for panics.
    ///
    /// # Unsafety
    ///
    /// This function is unsafe to call because it's asserting the `UnsafeWake`
    /// value is in a consistent state, i.e. hasn't been dropped, and that the
    /// `UnsafeWake` hasn't moved from the thread on which it was created.
    unsafe fn wake_local(&self) {
        self.wake()
    }
}
<|endoftext|>