<commit_before>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use std::result::Result;

use RequestError;

/// Wrapper over an HTTP Header type.
#[derive(Debug, Eq, Hash, PartialEq)]
pub enum Header {
    /// Header `Content-Length`.
    ContentLength,
    /// Header `Content-Type`.
    ContentType,
    /// Header `Expect`.
    Expect,
    /// Header `Transfer-Encoding`.
    TransferEncoding,
    /// Header `Server`.
    Server,
}

impl Header {
    pub fn raw(&self) -> &'static [u8] {
        match self {
            Header::ContentLength => b"Content-Length",
            Header::ContentType => b"Content-Type",
            Header::Expect => b"Expect",
            Header::TransferEncoding => b"Transfer-Encoding",
            Header::Server => b"Server",
        }
    }

    fn try_from(string: &[u8]) -> Result<Self, RequestError> {
        if let Ok(utf8_string) = String::from_utf8(string.to_vec()) {
            match utf8_string.trim() {
                "Content-Length" => Ok(Header::ContentLength),
                "Content-Type" => Ok(Header::ContentType),
                "Expect" => Ok(Header::Expect),
                "Transfer-Encoding" => Ok(Header::TransferEncoding),
                "Server" => Ok(Header::Server),
                _ => Err(RequestError::InvalidHeader),
            }
        } else {
            Err(RequestError::InvalidRequest)
        }
    }
}

/// Wrapper over the list of headers associated with a Request that we need
/// in order to parse the request correctly and be able to respond to it.
///
/// The only `Content-Type`s supported are `text/plain` and `application/json`, which are both
/// in plain text actually and don't influence our parsing process.
///
/// All the other possible header fields are not necessary in order to serve this connection
/// and, thus, are not of interest to us. However, we still look for header fields that might
/// invalidate our request as we don't support the full set of HTTP/1.1 specification.
/// Such header entries are "Transfer-Encoding: identity; q=0", which means a compression
/// algorithm is applied to the body of the request, or "Expect: 103-checkpoint".
#[derive(Debug)]
pub struct Headers {
    /// The `Content-Length` header field tells us how many bytes we need to receive
    /// from the source after the headers.
    content_length: i32,
    /// The `Expect` header field is set when the headers contain the entry "Expect: 100-continue".
    /// This means that, per HTTP/1.1 specifications, we must send a response with the status code
    /// 100 after we have received the headers in order to receive the body of the request. This
    /// field should be known immediately after parsing the headers.
    expect: bool,
    /// `Chunked` is a possible value of the `Transfer-Encoding` header field and every HTTP/1.1
    /// server must support it. It is useful only when receiving the body of the request and should
    /// be known immediately after parsing the headers.
    chunked: bool,
}

impl Headers {
    /// By default Requests are created with no headers.
    pub fn default() -> Headers {
        Headers {
            content_length: 0,
            expect: false,
            chunked: false,
        }
    }

    /// Expects one header line and parses it, updating the header structure or returning an
    /// error if the header is invalid.
    ///
    /// # Errors
    /// `UnsupportedHeader` is returned when the parsed header line is not of interest
    /// to us or when it is unrecognizable.
    /// `InvalidHeader` is returned when the parsed header is formatted incorrectly or suggests
    /// that the client is using HTTP features that we do not support in this implementation,
    /// which invalidates the request.
    pub fn parse_header_line(&mut self, header_line: &[u8]) -> Result<(), RequestError> {
        // Headers must be ASCII, so also UTF-8 valid.
        match std::str::from_utf8(header_line) {
            Ok(headers_str) => {
                let entry = headers_str.split(": ").collect::<Vec<&str>>();
                if entry.len() != 2 {
                    return Err(RequestError::InvalidHeader);
                }
                if let Ok(head) = Header::try_from(entry[0].as_bytes()) {
                    match head {
                        Header::ContentLength => {
                            let try_numeric: Result<i32, std::num::ParseIntError> =
                                std::str::FromStr::from_str(entry[1].trim());
                            if let Ok(content_length) = try_numeric {
                                self.content_length = content_length;
                                Ok(())
                            } else {
                                Err(RequestError::InvalidHeader)
                            }
                        }
                        Header::ContentType => {
                            match MediaType::try_from(entry[1].trim().as_bytes()) {
                                Ok(_) => Ok(()),
                                Err(_) => Err(RequestError::UnsupportedHeader),
                            }
                        }
                        Header::TransferEncoding => match entry[1].trim() {
                            "chunked" => {
                                self.chunked = true;
                                Ok(())
                            }
                            "identity; q=0" => Err(RequestError::InvalidHeader),
                            _ => Err(RequestError::UnsupportedHeader),
                        },
                        Header::Expect => match entry[1].trim() {
                            "100-continue" => {
                                self.expect = true;
                                Ok(())
                            }
                            _ => Err(RequestError::InvalidHeader),
                        },
                        Header::Server => Ok(()),
                    }
                } else {
                    Err(RequestError::UnsupportedHeader)
                }
            }
            _ => Err(RequestError::InvalidHeader),
        }
    }

    /// Returns the content length of the body.
    pub fn content_length(&self) -> i32 {
        self.content_length
    }

    /// Returns `true` if the transfer encoding is chunked.
    #[allow(unused)]
    pub fn chunked(&self) -> bool {
        self.chunked
    }

    /// Returns `true` if the client is expecting the code 100.
    #[allow(unused)]
    pub fn expect(&self) -> bool {
        self.expect
    }

    #[cfg(test)]
    pub fn new(content_length: i32, expect: bool, chunked: bool) -> Self {
        Headers {
            content_length,
            expect,
            chunked,
        }
    }

    /// Parses a byte slice into a Headers structure for a HTTP request.
    ///
    /// The byte slice is expected to have the following format: </br>
    ///     * Request Header Lines "<header_line> CRLF"- Optional </br>
    /// There can be any number of request headers, including none, followed by
    /// an extra sequence of Carriage Return and Line Feed.
    /// All header fields are parsed. However, only the ones present in the
    /// [`Headers`](struct.Headers.html) struct are relevant to us and stored
    /// for future use.
    ///
    /// # Errors
    /// The function returns `InvalidHeader` when parsing the byte stream fails.
    ///
    /// # Examples
    ///
    /// ```
    /// extern crate micro_http;
    /// use micro_http::Headers;
    ///
    /// let request_headers = Headers::try_from(b"Content-Length: 55\r\n\r\n");
    /// ```
    pub fn try_from(bytes: &[u8]) -> Result<Headers, RequestError> {
        // Headers must be ASCII, so also UTF-8 valid.
        if let Ok(text) = std::str::from_utf8(bytes) {
            let mut headers = Headers::default();

            let header_lines = text.split("\r\n");
            for header_line in header_lines {
                if header_line.is_empty() {
                    break;
                }
                match headers.parse_header_line(header_line.as_bytes()) {
                    Ok(_) | Err(RequestError::UnsupportedHeader) => continue,
                    Err(e) => return Err(e),
                };
            }
            return Ok(headers);
        }
        Err(RequestError::InvalidRequest)
    }
}

/// Wrapper over supported Media Types.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum MediaType {
    /// Media Type: "text/plain".
    PlainText,
    /// Media Type: "application/json".
    ApplicationJson,
}

impl Default for MediaType {
    fn default() -> Self {
        MediaType::ApplicationJson
    }
}

impl MediaType {
    fn try_from(bytes: &[u8]) -> Result<Self, RequestError> {
        if bytes.is_empty() {
            return Err(RequestError::InvalidRequest);
        }
        let utf8_slice =
            String::from_utf8(bytes.to_vec()).map_err(|_| RequestError::InvalidRequest)?;
        match utf8_slice.as_str().trim() {
            "text/plain" => Ok(MediaType::PlainText),
            "application/json" => Ok(MediaType::ApplicationJson),
            _ => Err(RequestError::InvalidRequest),
        }
    }

    /// Returns a static string representation of the object.
    pub fn as_str(self) -> &'static str {
        match self {
            MediaType::PlainText => "text/plain",
            MediaType::ApplicationJson => "application/json",
        }
    }
}

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

    #[test]
    fn test_default() {
        let headers = Headers::default();
        assert_eq!(headers.content_length(), 0);
        assert_eq!(headers.chunked(), false);
        assert_eq!(headers.expect(), false);
    }

    #[test]
    fn test_try_from_media() {
        assert_eq!(
            MediaType::try_from(b"application/json").unwrap(),
            MediaType::ApplicationJson
        );

        assert_eq!(
            MediaType::try_from(b"text/plain").unwrap(),
            MediaType::PlainText
        );

        assert_eq!(
            MediaType::try_from(b"").unwrap_err(),
            RequestError::InvalidRequest
        );

        assert_eq!(
            MediaType::try_from(b"application/json-patch").unwrap_err(),
            RequestError::InvalidRequest
        );
    }

    #[test]
    fn test_media_as_str() {
        let media_type = MediaType::ApplicationJson;
        assert_eq!(media_type.as_str(), "application/json");

        let media_type = MediaType::PlainText;
        assert_eq!(media_type.as_str(), "text/plain");
    }

    #[test]
    fn test_try_from_headers() {
        // Valid headers.
        assert_eq!(
            Headers::try_from(
                b"Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT\r\nContent-Length: 55\r\n\r\n"
            )
            .unwrap()
            .content_length,
            55
        );

        let bytes: [u8; 10] = [130, 140, 150, 130, 140, 150, 130, 140, 150, 160];
        // Invalid headers.
        assert!(Headers::try_from(&bytes[..]).is_err());
    }

    #[test]
    fn test_parse_header_line() {
        let mut header = Headers::default();

        // Invalid header syntax.
        assert_eq!(
            header.parse_header_line(b"Expect"),
            Err(RequestError::InvalidHeader)
        );

        // Invalid content length.
        assert_eq!(
            header.parse_header_line(b"Content-Length: five"),
            Err(RequestError::InvalidHeader)
        );

        // Invalid transfer encoding.
        assert_eq!(
            header.parse_header_line(b"Transfer-Encoding: gzip"),
            Err(RequestError::UnsupportedHeader)
        );

        // Invalid expect.
        assert_eq!(
            header
                .parse_header_line(b"Expect: 102-processing")
                .unwrap_err(),
            RequestError::InvalidHeader
        );

        // Unsupported media type.
        assert_eq!(
            header
                .parse_header_line(b"Content-Type: application/json-patch")
                .unwrap_err(),
            RequestError::UnsupportedHeader
        );

        // Invalid input format.
        let input: [u8; 10] = [130, 140, 150, 130, 140, 150, 130, 140, 150, 160];
        assert_eq!(
            header.parse_header_line(&input[..]).unwrap_err(),
            RequestError::InvalidHeader
        );

        // Test valid transfer encoding.
        assert!(header
            .parse_header_line(b"Transfer-Encoding: chunked")
            .is_ok());
        assert!(header.chunked());

        // Test valid expect.
        assert!(header.parse_header_line(b"Expect: 100-continue").is_ok());
        assert!(header.expect());

        // Test valid media type.
        assert!(header
            .parse_header_line(b"Content-Type: application/json")
            .is_ok());
    }

    #[test]
    fn test_header_try_from() {
        // Bad header.
        assert_eq!(
            Header::try_from(b"Encoding").unwrap_err(),
            RequestError::InvalidHeader
        );

        // Invalid encoding.
        let input: [u8; 10] = [130, 140, 150, 130, 140, 150, 130, 140, 150, 160];
        assert_eq!(
            Header::try_from(&input[..]).unwrap_err(),
            RequestError::InvalidRequest
        );

        // Test valid headers.
        let header = Header::try_from(b"Expect").unwrap();
        assert_eq!(header.raw(), b"Expect");

        let header = Header::try_from(b"Transfer-Encoding").unwrap();
        assert_eq!(header.raw(), b"Transfer-Encoding");
    }
}
<commit_msg>micro_http: adjust match on header fields<commit_after>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use std::result::Result;

use RequestError;

/// Wrapper over an HTTP Header type.
#[derive(Debug, Eq, Hash, PartialEq)]
pub enum Header {
    /// Header `Content-Length`.
    ContentLength,
    /// Header `Content-Type`.
    ContentType,
    /// Header `Expect`.
    Expect,
    /// Header `Transfer-Encoding`.
    TransferEncoding,
    /// Header `Server`.
    Server,
}

impl Header {
    pub fn raw(&self) -> &'static [u8] {
        match self {
            Header::ContentLength => b"Content-Length",
            Header::ContentType => b"Content-Type",
            Header::Expect => b"Expect",
            Header::TransferEncoding => b"Transfer-Encoding",
            Header::Server => b"Server",
        }
    }

    fn try_from(string: &[u8]) -> Result<Self, RequestError> {
        if let Ok(mut utf8_string) = String::from_utf8(string.to_vec()) {
            utf8_string.make_ascii_lowercase();
            match utf8_string.trim() {
                "content-length" => Ok(Header::ContentLength),
                "content-type" => Ok(Header::ContentType),
                "expect" => Ok(Header::Expect),
                "transfer-encoding" => Ok(Header::TransferEncoding),
                "server" => Ok(Header::Server),
                _ => Err(RequestError::InvalidHeader),
            }
        } else {
            Err(RequestError::InvalidRequest)
        }
    }
}

/// Wrapper over the list of headers associated with a Request that we need
/// in order to parse the request correctly and be able to respond to it.
///
/// The only `Content-Type`s supported are `text/plain` and `application/json`, which are both
/// in plain text actually and don't influence our parsing process.
///
/// All the other possible header fields are not necessary in order to serve this connection
/// and, thus, are not of interest to us. However, we still look for header fields that might
/// invalidate our request as we don't support the full set of HTTP/1.1 specification.
/// Such header entries are "Transfer-Encoding: identity; q=0", which means a compression
/// algorithm is applied to the body of the request, or "Expect: 103-checkpoint".
#[derive(Debug)]
pub struct Headers {
    /// The `Content-Length` header field tells us how many bytes we need to receive
    /// from the source after the headers.
    content_length: i32,
    /// The `Expect` header field is set when the headers contain the entry "Expect: 100-continue".
    /// This means that, per HTTP/1.1 specifications, we must send a response with the status code
    /// 100 after we have received the headers in order to receive the body of the request. This
    /// field should be known immediately after parsing the headers.
    expect: bool,
    /// `Chunked` is a possible value of the `Transfer-Encoding` header field and every HTTP/1.1
    /// server must support it. It is useful only when receiving the body of the request and should
    /// be known immediately after parsing the headers.
    chunked: bool,
}

impl Headers {
    /// By default Requests are created with no headers.
    pub fn default() -> Headers {
        Headers {
            content_length: 0,
            expect: false,
            chunked: false,
        }
    }

    /// Expects one header line and parses it, updating the header structure or returning an
    /// error if the header is invalid.
    ///
    /// # Errors
    /// `UnsupportedHeader` is returned when the parsed header line is not of interest
    /// to us or when it is unrecognizable.
    /// `InvalidHeader` is returned when the parsed header is formatted incorrectly or suggests
    /// that the client is using HTTP features that we do not support in this implementation,
    /// which invalidates the request.
    pub fn parse_header_line(&mut self, header_line: &[u8]) -> Result<(), RequestError> {
        // Headers must be ASCII, so also UTF-8 valid.
        match std::str::from_utf8(header_line) {
            Ok(headers_str) => {
                let entry = headers_str.split(": ").collect::<Vec<&str>>();
                if entry.len() != 2 {
                    return Err(RequestError::InvalidHeader);
                }
                if let Ok(head) = Header::try_from(entry[0].as_bytes()) {
                    match head {
                        Header::ContentLength => {
                            let try_numeric: Result<i32, std::num::ParseIntError> =
                                std::str::FromStr::from_str(entry[1].trim());
                            if let Ok(content_length) = try_numeric {
                                self.content_length = content_length;
                                Ok(())
                            } else {
                                Err(RequestError::InvalidHeader)
                            }
                        }
                        Header::ContentType => {
                            match MediaType::try_from(entry[1].trim().as_bytes()) {
                                Ok(_) => Ok(()),
                                Err(_) => Err(RequestError::UnsupportedHeader),
                            }
                        }
                        Header::TransferEncoding => match entry[1].trim() {
                            "chunked" => {
                                self.chunked = true;
                                Ok(())
                            }
                            "identity; q=0" => Err(RequestError::InvalidHeader),
                            _ => Err(RequestError::UnsupportedHeader),
                        },
                        Header::Expect => match entry[1].trim() {
                            "100-continue" => {
                                self.expect = true;
                                Ok(())
                            }
                            _ => Err(RequestError::InvalidHeader),
                        },
                        Header::Server => Ok(()),
                    }
                } else {
                    Err(RequestError::UnsupportedHeader)
                }
            }
            _ => Err(RequestError::InvalidHeader),
        }
    }

    /// Returns the content length of the body.
    pub fn content_length(&self) -> i32 {
        self.content_length
    }

    /// Returns `true` if the transfer encoding is chunked.
    #[allow(unused)]
    pub fn chunked(&self) -> bool {
        self.chunked
    }

    /// Returns `true` if the client is expecting the code 100.
    #[allow(unused)]
    pub fn expect(&self) -> bool {
        self.expect
    }

    #[cfg(test)]
    pub fn new(content_length: i32, expect: bool, chunked: bool) -> Self {
        Headers {
            content_length,
            expect,
            chunked,
        }
    }

    /// Parses a byte slice into a Headers structure for a HTTP request.
    ///
    /// The byte slice is expected to have the following format: </br>
    ///     * Request Header Lines "<header_line> CRLF"- Optional </br>
    /// There can be any number of request headers, including none, followed by
    /// an extra sequence of Carriage Return and Line Feed.
    /// All header fields are parsed. However, only the ones present in the
    /// [`Headers`](struct.Headers.html) struct are relevant to us and stored
    /// for future use.
    ///
    /// # Errors
    /// The function returns `InvalidHeader` when parsing the byte stream fails.
    ///
    /// # Examples
    ///
    /// ```
    /// extern crate micro_http;
    /// use micro_http::Headers;
    ///
    /// let request_headers = Headers::try_from(b"Content-Length: 55\r\n\r\n");
    /// ```
    pub fn try_from(bytes: &[u8]) -> Result<Headers, RequestError> {
        // Headers must be ASCII, so also UTF-8 valid.
        if let Ok(text) = std::str::from_utf8(bytes) {
            let mut headers = Headers::default();

            let header_lines = text.split("\r\n");
            for header_line in header_lines {
                if header_line.is_empty() {
                    break;
                }
                match headers.parse_header_line(header_line.as_bytes()) {
                    Ok(_) | Err(RequestError::UnsupportedHeader) => continue,
                    Err(e) => return Err(e),
                };
            }
            return Ok(headers);
        }
        Err(RequestError::InvalidRequest)
    }
}

/// Wrapper over supported Media Types.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum MediaType {
    /// Media Type: "text/plain".
    PlainText,
    /// Media Type: "application/json".
    ApplicationJson,
}

impl Default for MediaType {
    fn default() -> Self {
        MediaType::ApplicationJson
    }
}

impl MediaType {
    fn try_from(bytes: &[u8]) -> Result<Self, RequestError> {
        if bytes.is_empty() {
            return Err(RequestError::InvalidRequest);
        }
        let utf8_slice =
            String::from_utf8(bytes.to_vec()).map_err(|_| RequestError::InvalidRequest)?;
        match utf8_slice.as_str().trim() {
            "text/plain" => Ok(MediaType::PlainText),
            "application/json" => Ok(MediaType::ApplicationJson),
            _ => Err(RequestError::InvalidRequest),
        }
    }

    /// Returns a static string representation of the object.
    pub fn as_str(self) -> &'static str {
        match self {
            MediaType::PlainText => "text/plain",
            MediaType::ApplicationJson => "application/json",
        }
    }
}

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

    #[test]
    fn test_default() {
        let headers = Headers::default();
        assert_eq!(headers.content_length(), 0);
        assert_eq!(headers.chunked(), false);
        assert_eq!(headers.expect(), false);
    }

    #[test]
    fn test_try_from_media() {
        assert_eq!(
            MediaType::try_from(b"application/json").unwrap(),
            MediaType::ApplicationJson
        );

        assert_eq!(
            MediaType::try_from(b"text/plain").unwrap(),
            MediaType::PlainText
        );

        assert_eq!(
            MediaType::try_from(b"").unwrap_err(),
            RequestError::InvalidRequest
        );

        assert_eq!(
            MediaType::try_from(b"application/json-patch").unwrap_err(),
            RequestError::InvalidRequest
        );
    }

    #[test]
    fn test_media_as_str() {
        let media_type = MediaType::ApplicationJson;
        assert_eq!(media_type.as_str(), "application/json");

        let media_type = MediaType::PlainText;
        assert_eq!(media_type.as_str(), "text/plain");
    }

    #[test]
    fn test_try_from_headers() {
        // Valid headers.
        assert_eq!(
            Headers::try_from(
                b"Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT\r\nContent-Length: 55\r\n\r\n"
            )
            .unwrap()
            .content_length,
            55
        );

        let bytes: [u8; 10] = [130, 140, 150, 130, 140, 150, 130, 140, 150, 160];
        // Invalid headers.
        assert!(Headers::try_from(&bytes[..]).is_err());
    }

    #[test]
    fn test_parse_header_line() {
        let mut header = Headers::default();

        // Invalid header syntax.
        assert_eq!(
            header.parse_header_line(b"Expect"),
            Err(RequestError::InvalidHeader)
        );

        // Invalid content length.
        assert_eq!(
            header.parse_header_line(b"Content-Length: five"),
            Err(RequestError::InvalidHeader)
        );

        // Invalid transfer encoding.
        assert_eq!(
            header.parse_header_line(b"Transfer-Encoding: gzip"),
            Err(RequestError::UnsupportedHeader)
        );

        // Invalid expect.
        assert_eq!(
            header
                .parse_header_line(b"Expect: 102-processing")
                .unwrap_err(),
            RequestError::InvalidHeader
        );

        // Unsupported media type.
        assert_eq!(
            header
                .parse_header_line(b"Content-Type: application/json-patch")
                .unwrap_err(),
            RequestError::UnsupportedHeader
        );

        // Invalid input format.
        let input: [u8; 10] = [130, 140, 150, 130, 140, 150, 130, 140, 150, 160];
        assert_eq!(
            header.parse_header_line(&input[..]).unwrap_err(),
            RequestError::InvalidHeader
        );

        // Test valid transfer encoding.
        assert!(header
            .parse_header_line(b"Transfer-Encoding: chunked")
            .is_ok());
        assert!(header.chunked());

        // Test valid expect.
        assert!(header.parse_header_line(b"Expect: 100-continue").is_ok());
        assert!(header.expect());

        // Test valid media type.
        assert!(header
            .parse_header_line(b"Content-Type: application/json")
            .is_ok());
    }

    #[test]
    fn test_header_try_from() {
        // Bad header.
        assert_eq!(
            Header::try_from(b"Encoding").unwrap_err(),
            RequestError::InvalidHeader
        );

        // Invalid encoding.
        let input: [u8; 10] = [130, 140, 150, 130, 140, 150, 130, 140, 150, 160];
        assert_eq!(
            Header::try_from(&input[..]).unwrap_err(),
            RequestError::InvalidRequest
        );

        // Test valid headers.
        let header = Header::try_from(b"Expect").unwrap();
        assert_eq!(header.raw(), b"Expect");

        let header = Header::try_from(b"Transfer-Encoding").unwrap();
        assert_eq!(header.raw(), b"Transfer-Encoding");

        let header = Header::try_from(b"content-length").unwrap();
        assert_eq!(header.raw(), b"Content-Length");
    }
}
<|endoftext|>


<commit_before>//! Compositor: wm state including the layout, helm, and interactions
//! state machines.

use std::sync::RwLock;

use rustwlc;
use rustwlc::*;

lazy_static! {
    static ref COMPOSITOR: RwLock<Compositor> = RwLock::new(Compositor::new());
}

const ERR_LOCK: &'static str = "Unable to lock compositor!";
const ERR_GEO: &'static str = "Unable to access view geometry!";

#[derive(Debug, PartialEq)]
pub struct Compositor {
    pub view: Option<WlcView>,
    pub grab: Point,
    pub edges: ResizeEdge,
    //pub actions: ClientState
}

impl Compositor {
    fn new() -> Compositor {
        Compositor {
            view: None,
            grab: Point {x: 0, y: 0},
            edges: ResizeEdge::empty()
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub struct ClientState {
    view_action: ViewAction,
    next_action: ClickAction
}

impl Default for ClientState {
    fn default() -> ClientState {
        ClientState {
            view_action: ViewAction::None,
            next_action: ClickAction::None
        }
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[allow(dead_code)]
pub enum ViewAction {
    None,
    Resize,
    Move
}

impl ViewAction {
    /// Is this ViewAction set
    #[allow(dead_code)]
    pub fn is_some(&self) -> bool {
        *self != ViewAction::None
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
/// Actions that the user may set before clicking on a window
#[allow(dead_code)]
enum ClickAction {
    None,
    CloseWindow,
    BeginMoving,
    BeginResizing,
    SelectWindow,

}

/// Maximizes the view to the size of the output it sits in
pub fn set_focused_window_maximized(wlc_view: &WlcView) {
    let maybe_geometry = wlc_view.get_geometry();
    if maybe_geometry.is_none() {
        return;
    }
    let geometry = maybe_geometry.expect(ERR_GEO);
    start_interactive_action(wlc_view, &geometry.origin);
    {
        let mut comp = COMPOSITOR.write().expect(ERR_LOCK);
        if let Some(ref mut view) = comp.view {
            let output = view.get_output();
            trace!("Output size of the view: {:?}", output.get_resolution());
            let output_size = output.get_resolution();
            let geometry = Geometry { origin: Point { x: 0, y: 0},
                                        size: output_size.clone() };
            view.set_geometry(EDGE_NONE, &geometry);
        }
    }
    stop_interactive_action();
}

pub fn stop_interactive_action() {
    if let Ok(mut comp) = COMPOSITOR.write() {
        match comp.view {
            None => return,
            Some(ref view) => view.set_state(VIEW_RESIZING, false)
        }

        comp.view = None;
        comp.edges = ResizeEdge::empty();
    }
}

pub fn start_interactive_resize(view: &WlcView, edges: ResizeEdge, origin: &Point) {
    let geometry = match view.get_geometry() {
        None => { return; }
        Some(g) => g,
    };

    if !start_interactive_action(view, origin) {
        return;
    }
    let halfw = geometry.origin.x + geometry.size.w as i32 / 2;
    let halfh = geometry.origin.y + geometry.size.h as i32 / 2;

    if let Ok(mut comp) = COMPOSITOR.write() {
        comp.edges = edges.clone();
        if comp.edges.bits() == 0 {
            let flag_x = if origin.x < halfw {
                RESIZE_LEFT
            } else if origin.x > halfw {
                RESIZE_RIGHT
            } else {
                ResizeEdge::empty()
            };

            let flag_y = if origin.y < halfh {
                RESIZE_TOP
            } else if origin.y > halfh {
                RESIZE_BOTTOM
            } else {
                ResizeEdge::empty()
            };

            comp.edges = flag_x | flag_y;
        }
    }
    view.set_state(VIEW_RESIZING, true);
}

pub fn start_interactive_move(view: &WlcView, origin: &Point) -> bool {
    if let Ok(mut comp) = COMPOSITOR.write() {
        if comp.view != None {
            return false;
        }
        comp.grab = origin.clone();
        comp.view = Some(view.clone());
        true
    } else {
        false
    }

}

pub fn on_pointer_button(view: WlcView, _time: u32, mods: &KeyboardModifiers, button: u32,
                         state: ButtonState, point: &Point) -> bool {
    if state == ButtonState::Pressed {
        if !view.is_root() {
            view.focus();
            view.bring_to_front();
            if mods.mods.contains(MOD_CTRL) {
                // Button left, we need to include linux/input.h somehow
                if button == 0x110 {
                    start_interactive_move(&view, point);
                }
                if button == 0x111 {
                    start_interactive_resize(&view, ResizeEdge::empty(), point);
                }
                if mods.mods.contains(MOD_SHIFT) {
                    set_focused_window_maximized(&view);
                }
            }
        }
    }
    else {
        stop_interactive_action();
    }

    {
        let comp = COMPOSITOR.read().expect(ERR_LOCK);
        return comp.view.is_some();
    }
}

pub fn on_pointer_motion(_view: WlcView, _time: u32, point: &Point) -> bool {
    rustwlc::input::pointer::set_position(point);
    if let Ok(comp) = COMPOSITOR.read() {
        if let Some(ref view) = comp.view {
            let dx = point.x - comp.grab.x;
            let dy = point.y - comp.grab.y;
            let mut geo = view.get_geometry().expect(ERR_GEO).clone();
            if comp.edges.bits() != 0 {
                let min = Size { w: 80u32, h: 40u32};
                let mut new_geo = geo.clone();

                if comp.edges.contains(RESIZE_LEFT) {
                    if dx < 0 {
                        new_geo.size.w += dx.abs() as u32;
                    } else {
                        new_geo.size.w -= dx.abs() as u32;
                    }
                    new_geo.origin.x += dx;
                }
                else if comp.edges.contains(RESIZE_RIGHT) {
                    if dx < 0 {
                        new_geo.size.w -= dx.abs() as u32;
                    } else {
                        new_geo.size.w += dx.abs() as u32;
                    }
                }

                if comp.edges.contains(RESIZE_TOP) {
                    if dy < 0 {
                        new_geo.size.h += dy.abs() as u32;
                    } else {
                        new_geo.size.h -= dy.abs() as u32;
                    }
                    new_geo.origin.y += dy;
                }
                else if comp.edges.contains(RESIZE_BOTTOM) {
                    if dy < 0 {
                        new_geo.size.h -= dy.abs() as u32;
                    } else {
                        new_geo.size.h += dy.abs() as u32;
                    }
                }

                if new_geo.size.w >= min.w {
                    geo.origin.x = new_geo.origin.x;
                    geo.size.w = new_geo.size.w;
                }

                if new_geo.size.h >= min.h {
                    geo.origin.y = new_geo.origin.y;
                    geo.size.h = new_geo.size.h;
                }

                view.set_geometry(comp.edges, &geo);
            }
            else {
                geo.origin.x += dx;
                geo.origin.y += dy;
                view.set_geometry(ResizeEdge::empty(), &geo);
            }
        }
    }
    if let Ok(mut comp) = COMPOSITOR.write() {
        comp.grab = point.clone();
        comp.view.is_some()
    } else {
        false
    }
}

fn start_interactive_action(view: &WlcView, origin: &Point) -> bool {
    if let Ok(mut comp) = COMPOSITOR.write() {
        if comp.view != None {
            return false;
        }
        comp.grab = origin.clone();
        comp.view = Some(view.clone());
    }

    view.bring_to_front();
    return true;
}

<commit_msg>Added docs to compositor, start_interactive_action now returns a result, which found a bug where we do not check the output<commit_after>//! Compositor: wm state including the layout, helm, and interactions
//! state machines.

use std::sync::RwLock;

use rustwlc;
use rustwlc::*;

lazy_static! {
    static ref COMPOSITOR: RwLock<Compositor> = RwLock::new(Compositor::new());
}

const ERR_LOCK: &'static str = "Unable to lock compositor!";
const ERR_GEO: &'static str = "Unable to access view geometry!";

#[derive(Debug, PartialEq)]
pub struct Compositor {
    pub view: Option<WlcView>,
    pub grab: Point,
    pub edges: ResizeEdge,
    //pub actions: ClientState
}

impl Compositor {
    fn new() -> Compositor {
        Compositor {
            view: None,
            grab: Point {x: 0, y: 0},
            edges: ResizeEdge::empty()
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub struct ClientState {
    view_action: ViewAction,
    next_action: ClickAction
}

impl Default for ClientState {
    fn default() -> ClientState {
        ClientState {
            view_action: ViewAction::None,
            next_action: ClickAction::None
        }
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[allow(dead_code)]
pub enum ViewAction {
    None,
    Resize,
    Move
}

impl ViewAction {
    /// Is this ViewAction set
    #[allow(dead_code)]
    pub fn is_some(&self) -> bool {
        *self != ViewAction::None
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
/// Actions that the user may set before clicking on a window
#[allow(dead_code)]
enum ClickAction {
    None,
    CloseWindow,
    BeginMoving,
    BeginResizing,
    SelectWindow,

}

/// Maximizes the view to the size of the output it sits in
pub fn set_focused_window_maximized(wlc_view: &WlcView) {
    let maybe_geometry = wlc_view.get_geometry();
    if maybe_geometry.is_none() {
        return;
    }
    let geometry = maybe_geometry.expect(ERR_GEO);
    if start_interactive_action(wlc_view, &geometry.origin).is_err() {
        return;
    };
    {
        let mut comp = COMPOSITOR.write().expect(ERR_LOCK);
        if let Some(ref mut view) = comp.view {
            let output = view.get_output();
            trace!("Output size of the view: {:?}", output.get_resolution());
            let output_size = output.get_resolution();
            let geometry = Geometry { origin: Point { x: 0, y: 0},
                                        size: output_size.clone() };
            view.set_geometry(EDGE_NONE, &geometry);
        }
    }
    stop_interactive_action();
}

/// Makes the compositor no longer track the node to be used in some interaction
pub fn stop_interactive_action() {
    if let Ok(mut comp) = COMPOSITOR.write() {
        match comp.view {
            None => return,
            Some(ref view) => view.set_state(VIEW_RESIZING, false)
        }

        comp.view = None;
        comp.edges = ResizeEdge::empty();
    }
}

/// Automatically adds the view as the object of interest if there is no other
/// action currently being performed on some view
pub fn start_interactive_resize(view: &WlcView, edges: ResizeEdge, origin: &Point) {
    let geometry = match view.get_geometry() {
        None => { return; }
        Some(g) => g,
    };

    if start_interactive_action(view, origin).is_err() {
        return;
    }
    let halfw = geometry.origin.x + geometry.size.w as i32 / 2;
    let halfh = geometry.origin.y + geometry.size.h as i32 / 2;

    if let Ok(mut comp) = COMPOSITOR.write() {
        comp.edges = edges.clone();
        if comp.edges.bits() == 0 {
            let flag_x = if origin.x < halfw {
                RESIZE_LEFT
            } else if origin.x > halfw {
                RESIZE_RIGHT
            } else {
                ResizeEdge::empty()
            };

            let flag_y = if origin.y < halfh {
                RESIZE_TOP
            } else if origin.y > halfh {
                RESIZE_BOTTOM
            } else {
                ResizeEdge::empty()
            };

            comp.edges = flag_x | flag_y;
        }
    }
    view.set_state(VIEW_RESIZING, true);
}

/// Begin using the given view as the object of interest in an interactive
/// move. If another action is currently being performed,
/// this function returns false
pub fn start_interactive_move(view: &WlcView, origin: &Point) -> bool {
    if let Ok(mut comp) = COMPOSITOR.write() {
        if comp.view != None {
            return false;
        }
        comp.grab = origin.clone();
        comp.view = Some(view.clone());
        true
    } else {
        false
    }

}

/// Performs an operation on a pointer button, to be used in the callback
pub fn on_pointer_button(view: WlcView, _time: u32, mods: &KeyboardModifiers, button: u32,
                         state: ButtonState, point: &Point) -> bool {
    if state == ButtonState::Pressed {
        if !view.is_root() {
            view.focus();
            view.bring_to_front();
            if mods.mods.contains(MOD_CTRL) {
                // Button left, we need to include linux/input.h somehow
                if button == 0x110 {
                    start_interactive_move(&view, point);
                }
                if button == 0x111 {
                    start_interactive_resize(&view, ResizeEdge::empty(), point);
                }
                if mods.mods.contains(MOD_SHIFT) {
                    set_focused_window_maximized(&view);
                }
            }
        }
    }
    else {
        stop_interactive_action();
    }

    {
        let comp = COMPOSITOR.read().expect(ERR_LOCK);
        return comp.view.is_some();
    }
}

/// Performs an operation on a pointer motion, to be used in the callback
pub fn on_pointer_motion(_view: WlcView, _time: u32, point: &Point) -> bool {
    rustwlc::input::pointer::set_position(point);
    if let Ok(comp) = COMPOSITOR.read() {
        if let Some(ref view) = comp.view {
            let dx = point.x - comp.grab.x;
            let dy = point.y - comp.grab.y;
            let mut geo = view.get_geometry().expect(ERR_GEO).clone();
            if comp.edges.bits() != 0 {
                let min = Size { w: 80u32, h: 40u32};
                let mut new_geo = geo.clone();

                if comp.edges.contains(RESIZE_LEFT) {
                    if dx < 0 {
                        new_geo.size.w += dx.abs() as u32;
                    } else {
                        new_geo.size.w -= dx.abs() as u32;
                    }
                    new_geo.origin.x += dx;
                }
                else if comp.edges.contains(RESIZE_RIGHT) {
                    if dx < 0 {
                        new_geo.size.w -= dx.abs() as u32;
                    } else {
                        new_geo.size.w += dx.abs() as u32;
                    }
                }

                if comp.edges.contains(RESIZE_TOP) {
                    if dy < 0 {
                        new_geo.size.h += dy.abs() as u32;
                    } else {
                        new_geo.size.h -= dy.abs() as u32;
                    }
                    new_geo.origin.y += dy;
                }
                else if comp.edges.contains(RESIZE_BOTTOM) {
                    if dy < 0 {
                        new_geo.size.h -= dy.abs() as u32;
                    } else {
                        new_geo.size.h += dy.abs() as u32;
                    }
                }

                if new_geo.size.w >= min.w {
                    geo.origin.x = new_geo.origin.x;
                    geo.size.w = new_geo.size.w;
                }

                if new_geo.size.h >= min.h {
                    geo.origin.y = new_geo.origin.y;
                    geo.size.h = new_geo.size.h;
                }

                view.set_geometry(comp.edges, &geo);
            }
            else {
                geo.origin.x += dx;
                geo.origin.y += dy;
                view.set_geometry(ResizeEdge::empty(), &geo);
            }
        }
    }
    if let Ok(mut comp) = COMPOSITOR.write() {
        comp.grab = point.clone();
        comp.view.is_some()
    } else {
        false
    }
}

/// Sets the given view to be the object of interest in some interactive action.
/// If another view is currently being used as the object of interest, an Err
/// is returned.
fn start_interactive_action(view: &WlcView, origin: &Point) -> Result<(), &'static str> {
    if let Ok(mut comp) = COMPOSITOR.write() {
        if comp.view != None {
            return Err("Compositor already interacting with another view");
        }
        comp.grab = origin.clone();
        comp.view = Some(view.clone());
    }

    view.bring_to_front();
    Ok(())
}

<|endoftext|>


<commit_before>use crate::timer::clock::now;
use crate::timer::timer::Inner;
use crate::timer::{Delay, Error, Timeout};

use std::cell::RefCell;
use std::fmt;
use std::marker::PhantomData;
use std::sync::{Arc, Weak};
use std::time::{Duration, Instant};

/// Handle to timer instance.
///
/// The `Handle` allows creating `Delay` instances that are driven by the
/// associated timer.
///
/// A `Handle` is obtained by calling [`Timer::handle`], [`Handle::current`], or
/// [`Handle::default`].
///
/// * [`Timer::handle`]: returns a handle associated with the specific timer.
///   The handle will always reference the same timer.
///
/// * [`Handle::current`]: returns a handle to the timer for the execution
///   context **at the time the function is called**. This function must be
///   called from a runtime that has an associated timer or it will panic.
///   The handle will always reference the same timer.
///
/// * [`Handle::default`]: returns a handle to the timer for the execution
///   context **at the time the handle is used**. This function is safe to call
///   at any time. The handle may reference different specific timer instances.
///   Calling `Handle::default().delay(...)` is always equivalent to
///   `Delay::new(...)`.
///
/// [`Timer::handle`]: struct.Timer.html#method.handle
/// [`Handle::current`]: #method.current
/// [`Handle::default`]: #method.default
#[derive(Debug, Clone)]
pub struct Handle {
    inner: Option<HandlePriv>,
}

/// Like `Handle` but never `None`.
#[derive(Clone)]
pub(crate) struct HandlePriv {
    inner: Weak<Inner>,
}

thread_local! {
    /// Tracks the timer for the current execution context.
    static CURRENT_TIMER: RefCell<Option<HandlePriv>> = RefCell::new(None)
}

#[derive(Debug)]
///Unsets default timer handler on drop.
pub struct DefaultGuard<'a> {
    _lifetime: PhantomData<&'a u8>,
}

impl Drop for DefaultGuard<'_> {
    fn drop(&mut self) {
        CURRENT_TIMER.with(|current| {
            let mut current = current.borrow_mut();
            *current = None;
        })
    }
}

///Sets handle to default timer, returning guard that unsets it on drop.
///
/// # Panics
///
/// This function panics if there already is a default timer set.
pub fn set_default(handle: &Handle) -> DefaultGuard<'_> {
    CURRENT_TIMER.with(|current| {
        let mut current = current.borrow_mut();

        assert!(
            current.is_none(),
            "default Tokio timer already set \
             for execution context"
        );

        let handle = handle
            .as_priv()
            .unwrap_or_else(|| panic!("`handle` does not reference a timer"));

        *current = Some(handle.clone());
    });

    DefaultGuard {
        _lifetime: PhantomData,
    }
}

impl Handle {
    pub(crate) fn new(inner: Weak<Inner>) -> Handle {
        let inner = HandlePriv { inner };
        Handle { inner: Some(inner) }
    }

    /// Returns a handle to the current timer.
    ///
    /// The current timer is the timer that is currently set as default using
    /// [`with_default`].
    ///
    /// This function should only be called from within the context of
    /// [`with_default`]. Calling this function from outside of this context
    /// will return a `Handle` that does not reference a timer. `Delay`
    /// instances created with this handle will error.
    ///
    /// See [type] level documentation for more ways to obtain a `Handle` value.
    ///
    /// [`with_default`]: fn.with_default
    /// [type]: #
    pub fn current() -> Handle {
        let private =
            HandlePriv::try_current().unwrap_or_else(|_| HandlePriv { inner: Weak::new() });

        Handle {
            inner: Some(private),
        }
    }

    /// Create a `Delay` driven by this handle's associated `Timer`.
    pub fn delay(&self, deadline: Instant) -> Delay {
        self.delay_timeout(deadline, Duration::from_secs(0))
    }

    fn delay_timeout(&self, deadline: Instant, duration: Duration) -> Delay {
        match self.inner {
            Some(ref handle_priv) => {
                Delay::new_with_handle(deadline, Duration::from_secs(0), handle_priv.clone())
            }
            None => Delay::new_timeout(deadline, duration),
        }
    }

    /// Create a `Timeout` driven by this handle's associated `Timer`.
    pub fn timeout<T>(&self, value: T, timeout: Duration) -> Timeout<T> {
        Timeout::new_with_delay(value, self.delay_timeout(now() + timeout, timeout))
    }

    /*
    /// Create a new `Interval` that starts at `at` and yields every `duration`
    /// interval after that.
    pub fn interval(&self, at: Instant, duration: Duration) -> Interval {
        Interval::new_with_delay(self.delay(at), duration)
    }
    */

    fn as_priv(&self) -> Option<&HandlePriv> {
        self.inner.as_ref()
    }
}

impl Default for Handle {
    fn default() -> Handle {
        Handle { inner: None }
    }
}

impl HandlePriv {
    /// Try to get a handle to the current timer.
    ///
    /// Returns `Err` if no handle is found.
    pub(crate) fn try_current() -> Result<HandlePriv, Error> {
        CURRENT_TIMER.with(|current| match *current.borrow() {
            Some(ref handle) => Ok(handle.clone()),
            None => Err(Error::shutdown()),
        })
    }

    /// Try to return a strong ref to the inner
    pub(crate) fn inner(&self) -> Option<Arc<Inner>> {
        self.inner.upgrade()
    }

    /// Consume the handle, returning the weak Inner ref.
    pub(crate) fn into_inner(self) -> Weak<Inner> {
        self.inner
    }
}

impl fmt::Debug for HandlePriv {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "HandlePriv")
    }
}
<commit_msg>Fix delay construction from non-lazy Handles (#1720)<commit_after>use crate::timer::clock::now;
use crate::timer::timer::Inner;
use crate::timer::{Delay, Error, Timeout};

use std::cell::RefCell;
use std::fmt;
use std::marker::PhantomData;
use std::sync::{Arc, Weak};
use std::time::{Duration, Instant};

/// Handle to timer instance.
///
/// The `Handle` allows creating `Delay` instances that are driven by the
/// associated timer.
///
/// A `Handle` is obtained by calling [`Timer::handle`], [`Handle::current`], or
/// [`Handle::default`].
///
/// * [`Timer::handle`]: returns a handle associated with the specific timer.
///   The handle will always reference the same timer.
///
/// * [`Handle::current`]: returns a handle to the timer for the execution
///   context **at the time the function is called**. This function must be
///   called from a runtime that has an associated timer or it will panic.
///   The handle will always reference the same timer.
///
/// * [`Handle::default`]: returns a handle to the timer for the execution
///   context **at the time the handle is used**. This function is safe to call
///   at any time. The handle may reference different specific timer instances.
///   Calling `Handle::default().delay(...)` is always equivalent to
///   `Delay::new(...)`.
///
/// [`Timer::handle`]: struct.Timer.html#method.handle
/// [`Handle::current`]: #method.current
/// [`Handle::default`]: #method.default
#[derive(Debug, Clone)]
pub struct Handle {
    inner: Option<HandlePriv>,
}

/// Like `Handle` but never `None`.
#[derive(Clone)]
pub(crate) struct HandlePriv {
    inner: Weak<Inner>,
}

thread_local! {
    /// Tracks the timer for the current execution context.
    static CURRENT_TIMER: RefCell<Option<HandlePriv>> = RefCell::new(None)
}

#[derive(Debug)]
///Unsets default timer handler on drop.
pub struct DefaultGuard<'a> {
    _lifetime: PhantomData<&'a u8>,
}

impl Drop for DefaultGuard<'_> {
    fn drop(&mut self) {
        CURRENT_TIMER.with(|current| {
            let mut current = current.borrow_mut();
            *current = None;
        })
    }
}

///Sets handle to default timer, returning guard that unsets it on drop.
///
/// # Panics
///
/// This function panics if there already is a default timer set.
pub fn set_default(handle: &Handle) -> DefaultGuard<'_> {
    CURRENT_TIMER.with(|current| {
        let mut current = current.borrow_mut();

        assert!(
            current.is_none(),
            "default Tokio timer already set \
             for execution context"
        );

        let handle = handle
            .as_priv()
            .unwrap_or_else(|| panic!("`handle` does not reference a timer"));

        *current = Some(handle.clone());
    });

    DefaultGuard {
        _lifetime: PhantomData,
    }
}

impl Handle {
    pub(crate) fn new(inner: Weak<Inner>) -> Handle {
        let inner = HandlePriv { inner };
        Handle { inner: Some(inner) }
    }

    /// Returns a handle to the current timer.
    ///
    /// The current timer is the timer that is currently set as default using
    /// [`with_default`].
    ///
    /// This function should only be called from within the context of
    /// [`with_default`]. Calling this function from outside of this context
    /// will return a `Handle` that does not reference a timer. `Delay`
    /// instances created with this handle will error.
    ///
    /// See [type] level documentation for more ways to obtain a `Handle` value.
    ///
    /// [`with_default`]: fn.with_default
    /// [type]: #
    pub fn current() -> Handle {
        let private =
            HandlePriv::try_current().unwrap_or_else(|_| HandlePriv { inner: Weak::new() });

        Handle {
            inner: Some(private),
        }
    }

    /// Create a `Delay` driven by this handle's associated `Timer`.
    pub fn delay(&self, deadline: Instant) -> Delay {
        self.delay_timeout(deadline, Duration::from_secs(0))
    }

    fn delay_timeout(&self, deadline: Instant, duration: Duration) -> Delay {
        match self.inner {
            Some(ref handle_priv) => {
                Delay::new_with_handle(deadline, duration, handle_priv.clone())
            }
            None => Delay::new_timeout(deadline, duration),
        }
    }

    /// Create a `Timeout` driven by this handle's associated `Timer`.
    pub fn timeout<T>(&self, value: T, timeout: Duration) -> Timeout<T> {
        Timeout::new_with_delay(value, self.delay_timeout(now() + timeout, timeout))
    }

    /*
    /// Create a new `Interval` that starts at `at` and yields every `duration`
    /// interval after that.
    pub fn interval(&self, at: Instant, duration: Duration) -> Interval {
        Interval::new_with_delay(self.delay(at), duration)
    }
    */

    fn as_priv(&self) -> Option<&HandlePriv> {
        self.inner.as_ref()
    }
}

impl Default for Handle {
    fn default() -> Handle {
        Handle { inner: None }
    }
}

impl HandlePriv {
    /// Try to get a handle to the current timer.
    ///
    /// Returns `Err` if no handle is found.
    pub(crate) fn try_current() -> Result<HandlePriv, Error> {
        CURRENT_TIMER.with(|current| match *current.borrow() {
            Some(ref handle) => Ok(handle.clone()),
            None => Err(Error::shutdown()),
        })
    }

    /// Try to return a strong ref to the inner
    pub(crate) fn inner(&self) -> Option<Arc<Inner>> {
        self.inner.upgrade()
    }

    /// Consume the handle, returning the weak Inner ref.
    pub(crate) fn into_inner(self) -> Weak<Inner> {
        self.inner
    }
}

impl fmt::Debug for HandlePriv {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "HandlePriv")
    }
}
<|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/. */

//! A media query condition:
//!
//! https://drafts.csswg.org/mediaqueries-4/#typedef-media-condition

use cssparser::{Parser, Token};
use parser::ParserContext;
use style_traits::ParseError;

use super::MediaFeatureExpression;

/// A binary `and` or `or` operator.
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, Parse, ToCss)]
#[allow(missing_docs)]
pub enum Operator {
    And,
    Or,
}

/// Represents a media condition.
pub enum MediaCondition {
    /// A simple media feature expression, implicitly parenthesized.
    Feature(MediaFeatureExpression),
    /// A negation of a condition.
    Not(Box<MediaCondition>),
    /// A set of joint operations.
    Operation(Box<[MediaCondition]>, Operator),
    /// A condition wrapped in parenthesis.
    InParens(Box<MediaCondition>),
}

impl MediaCondition {
    /// Parse a single media condition.
    pub fn parse<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        let location = input.current_source_location();

        // FIXME(emilio): This can be cleaner with nll.
        let is_negation = match *input.next()? {
            Token::ParenthesisBlock => false,
            Token::Ident(ref ident) if ident.eq_ignore_ascii_case("not") => true,
            ref t => {
                return Err(location.new_unexpected_token_error(t.clone()))
            }
        };

        if is_negation {
            let inner_condition = Self::parse_in_parens(context, input)?;
            return Ok(MediaCondition::Not(Box::new(inner_condition)))
        }

        // ParenthesisBlock.
        let first_condition = Self::parse_paren_block(context, input)?;
        let operator = match input.try(Operator::parse) {
            Ok(op) => op,
            Err(..) => return Ok(first_condition),
        };

        let mut conditions = vec![];
        conditions.push(first_condition);
        conditions.push(Self::parse_in_parens(context, input)?);

        let delim = match operator {
            Operator::And => "and",
            Operator::Or => "or",
        };

        loop {
            if input.try(|i| i.expect_ident_matching(delim)).is_err() {
                return Ok(MediaCondition::Operation(
                    conditions.into_boxed_slice(),
                    operator,
                ));
            }

            conditions.push(Self::parse_in_parens(context, input)?);
        }
    }

    /// Parse a media condition in parentheses.
    pub fn parse_in_parens<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        input.expect_parenthesis_block()?;
        Self::parse_paren_block(context, input)
    }

    fn parse_paren_block<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        input.parse_nested_block(|input| {
            // Base case.
            if let Ok(expr) = input.try(|i| MediaFeatureExpression::parse_in_parenthesis_block(context, i)) {
                return Ok(MediaCondition::Feature(expr));
            }

            let inner = Self::parse(context, input)?;
            Ok(MediaCondition::InParens(Box::new(inner)))
        })
    }
}
<commit_msg>style: Add serialization code for MediaCondition.<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/. */

//! A media query condition:
//!
//! https://drafts.csswg.org/mediaqueries-4/#typedef-media-condition

use cssparser::{Parser, Token};
use parser::ParserContext;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, ToCss};

use super::MediaFeatureExpression;

/// A binary `and` or `or` operator.
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, Parse, ToCss)]
#[allow(missing_docs)]
pub enum Operator {
    And,
    Or,
}

/// Represents a media condition.
pub enum MediaCondition {
    /// A simple media feature expression, implicitly parenthesized.
    Feature(MediaFeatureExpression),
    /// A negation of a condition.
    Not(Box<MediaCondition>),
    /// A set of joint operations.
    Operation(Box<[MediaCondition]>, Operator),
    /// A condition wrapped in parenthesis.
    InParens(Box<MediaCondition>),
}

impl ToCss for MediaCondition {
    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
    where
        W: fmt::Write,
    {
        match *self {
            // NOTE(emilio): MediaFeatureExpression already includes the
            // parenthesis.
            MediaCondition::Feature(ref f) => f.to_css(dest),
            MediaCondition::Not(ref c) => {
                dest.write_str("not ")?;
                c.to_css(dest)
            }
            MediaCondition::InParens(ref c) => {
                dest.write_char('(')?;
                c.to_css(dest)?;
                dest.write_char(')')
            }
            MediaCondition::Operation(ref list, op) => {
                let mut iter = list.iter();
                iter.next().unwrap().to_css(dest)?;
                for item in iter {
                    dest.write_char(' ')?;
                    op.to_css(dest)?;
                    dest.write_char(' ')?;
                    item.to_css(dest)?;
                }
                Ok(())
            }
        }
    }
}

impl MediaCondition {
    /// Parse a single media condition.
    pub fn parse<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        let location = input.current_source_location();

        // FIXME(emilio): This can be cleaner with nll.
        let is_negation = match *input.next()? {
            Token::ParenthesisBlock => false,
            Token::Ident(ref ident) if ident.eq_ignore_ascii_case("not") => true,
            ref t => {
                return Err(location.new_unexpected_token_error(t.clone()))
            }
        };

        if is_negation {
            let inner_condition = Self::parse_in_parens(context, input)?;
            return Ok(MediaCondition::Not(Box::new(inner_condition)))
        }

        // ParenthesisBlock.
        let first_condition = Self::parse_paren_block(context, input)?;
        let operator = match input.try(Operator::parse) {
            Ok(op) => op,
            Err(..) => return Ok(first_condition),
        };

        let mut conditions = vec![];
        conditions.push(first_condition);
        conditions.push(Self::parse_in_parens(context, input)?);

        let delim = match operator {
            Operator::And => "and",
            Operator::Or => "or",
        };

        loop {
            if input.try(|i| i.expect_ident_matching(delim)).is_err() {
                return Ok(MediaCondition::Operation(
                    conditions.into_boxed_slice(),
                    operator,
                ));
            }

            conditions.push(Self::parse_in_parens(context, input)?);
        }
    }

    /// Parse a media condition in parentheses.
    pub fn parse_in_parens<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        input.expect_parenthesis_block()?;
        Self::parse_paren_block(context, input)
    }

    fn parse_paren_block<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        input.parse_nested_block(|input| {
            // Base case.
            if let Ok(expr) = input.try(|i| MediaFeatureExpression::parse_in_parenthesis_block(context, i)) {
                return Ok(MediaCondition::Feature(expr));
            }

            let inner = Self::parse(context, input)?;
            Ok(MediaCondition::InParens(Box::new(inner)))
        })
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::collections::VecDeque;
use std::net::SocketAddr;
use std::rc::Rc;

use mio::tcp::TcpStream;
use mio::Timeout as TimeoutHandle;
use mio::{
    EventLoop,
    EventSet,
    PollOpt,
    Token,
};
use capnp::{
    MallocMessageBuilder,
    OwnedSpaceMessageReader,
    ReaderOptions,
};
use capnp::serialize::{
    read_message_async,
    write_message_async,
    AsyncValue,
    ReadContinuation,
    WriteContinuation,
};

use ClientId;
use Result;
use ServerId;
use backoff::Backoff;
use messages;
use server::{Server, ServerTimeout};
use state_machine::StateMachine;
use store::Store;

fn poll_opt() -> PollOpt {
    PollOpt::edge() | PollOpt::oneshot()
}

/// The type of a connection.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub enum ConnectionKind {
    /// A peer in the cluster.
    Peer(ServerId),
    /// A client which is asking the Raft cluster to do things.
    Client(ClientId),
    /// Something else.
    Unknown,
}

impl ConnectionKind {
    /// Returns if the `Connection` is a peer type.
    fn is_peer(&self) -> bool {
        match *self {
            ConnectionKind::Peer(..) => true,
            _ => false,
        }
    }
    /// Returns if the `Connection` is a client type.
    fn is_Client(&self) -> bool {
        match *self {
            ConnectionKind::Client(..) => true,
            _ => false,
        }
    }
}

pub struct Connection {
    kind: ConnectionKind,
    addr: SocketAddr,
    stream: TcpStream,
    backoff: Backoff,
    events: EventSet,
    read_continuation: Option<ReadContinuation>,
    write_continuation: Option<WriteContinuation>,
    write_queue: VecDeque<Rc<MallocMessageBuilder>>,
    is_connected: bool,
}

impl Connection {

    /// Creates a new `Connection` wrapping the provided socket stream.
    ///
    /// The socket must already be connected.
    ///
    /// Note: the caller must manually set the token field after inserting the
    /// connection into a slab.
    pub fn unknown(socket: TcpStream) -> Result<Connection> {
        let addr = try!(socket.peer_addr());
        Ok(Connection {
            kind: ConnectionKind::Unknown,
            addr: addr,
            stream: socket,
            backoff: Backoff::with_duration_range(8, 10000),
            events: EventSet::hup() | EventSet::readable(),
            read_continuation: None,
            write_continuation: None,
            write_queue: VecDeque::new(),
            is_connected: true,
        })
    }

    /// Creates a new peer connection.
    pub fn peer(id: ServerId, addr: SocketAddr) -> Result<Connection> {
        let stream = try!(TcpStream::connect(&addr));
        Ok(Connection {
            kind: ConnectionKind::Peer(id),
            addr: addr,
            stream: stream,
            backoff: Backoff::with_duration_range(1, 10000),
            events: EventSet::hup() | EventSet::readable(),
            read_continuation: None,
            write_continuation: None,
            write_queue: VecDeque::new(),
            is_connected: true,
        })
    }

    pub fn kind(&self) -> &ConnectionKind {
        &self.kind
    }

    pub fn set_kind(&mut self, kind: ConnectionKind) {
        self.kind = kind;
    }

    /// Writes queued messages to the socket.
    pub fn writable(&mut self) -> Result<()> {
        trace!("{:?}: writable; queued message count: {}", self, self.write_queue.len());
        assert!(self.is_connected, "raft::{:?}: writable event while not connected", self);

        while let Some(message) = self.write_queue.pop_front() {
            let continuation = self.write_continuation.take();
            match write_message_async(&mut self.stream, &*message, continuation) {
                Ok(AsyncValue::Complete(())) => (),
                Ok(AsyncValue::Continue(continuation)) =>  {
                    // The write only partially completed. Save the continuation and add the
                    // message back to the front of the queue.
                    self.write_continuation = Some(continuation);
                    self.write_queue.push_front(message);
                    break;
                }
                Err(error) => {
                    // The write failed; reinsert the message back to the write queue.
                    self.write_queue.push_front(message);
                    return Err(From::from(error));
                }
            }
        }

        if self.write_queue.is_empty() {
            self.events.remove(EventSet::writable());
        }

        self.backoff.reset();
        Ok(())
    }

    /// Reads a message from the connection's stream, or if a full message is
    /// not available, returns `None`.
    ///
    /// Connections are edge-triggered, so the handler must continue calling
    /// until no more messages are returned.
    pub fn readable(&mut self) -> Result<Option<OwnedSpaceMessageReader>> {
        trace!("{:?}: readable", self);
        assert!(self.is_connected, "raft::{:?}: readable event while not connected", self);

        let read = try!(read_message_async(&mut self.stream,
                                           ReaderOptions::new(),
                                           self.read_continuation.take()));
        self.backoff.reset();
        match read {
            AsyncValue::Complete(message) => {
                Ok(Some(message))
            },
            AsyncValue::Continue(continuation) => {
                // the read only partially completed. Save the continuation and return.
                self.read_continuation = Some(continuation);
                Ok(None)
            },
        }
    }

    /// Queues a message to be sent to this connection.
    pub fn send_message(&mut self, message: Rc<MallocMessageBuilder>) {
        trace!("{:?}: send_message", self);
        if self.is_connected {
            if self.write_queue.is_empty() {
                self.events.insert(EventSet::writable());
            }
            self.write_queue.push_back(message);
        }
    }

    /// Registers the connection with the event loop.
    pub fn register<S, M>(&mut self, event_loop: &mut EventLoop<Server<S, M>>, token: Token) -> Result<()>
    where S: Store, M: StateMachine {
        event_loop.register_opt(&self.stream, token, self.events, poll_opt())
                  .map_err(From::from)
    }

    /// Reregisters the connection with the event loop.
    pub fn reregister<S, M>(&mut self, event_loop: &mut EventLoop<Server<S, M>>, token: Token) -> Result<()>
    where S: Store, M: StateMachine {
        event_loop.reregister(&self.stream, token, self.events, poll_opt())
                  .map_err(From::from)
    }

    pub fn reconnect_peer(&mut self, id: ServerId) -> Result<()> {
        self.stream = try!(TcpStream::connect(&self.addr));
        self.is_connected = true;
        self.read_continuation = None;
        self.write_continuation = None;
        self.write_queue.clear();
        self.send_message(messages::server_connection_preamble(id));
        Ok(())
    }

    /// Resets a peer connection.
    pub fn reset_peer<S, M>(&mut self,
                            event_loop: &mut EventLoop<Server<S, M>>,
                            token: Token)
                            -> Result<(ServerTimeout, TimeoutHandle)>
    where S: Store, M: StateMachine {
        assert!(self.kind.is_peer());
        let duration = self.backoff.next_backoff_ms();
        self.read_continuation = None;
        self.write_continuation = None;
        self.write_queue.clear();
        self.is_connected = false;
        let timeout = ServerTimeout::Reconnect(token);
        let handle = event_loop.timeout_ms(timeout, duration).unwrap();

        info!("{:?}: {:?} reset, will attempt to reconnect in {}ms", self,
              self, duration);
        Ok((timeout, handle))
    }
}

impl fmt::Debug for Connection {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self.kind {
            ConnectionKind::Peer(id) => {
                write!(fmt, "PeerConnection({})", id)
            },
            ConnectionKind::Client(id) => {
                write!(fmt, "ClientConnection({})", id)
            },
            ConnectionKind::Unknown => {
                write!(fmt, "UnknownConnection({})", &self.addr)
            },
        }
    }
}
<commit_msg>Fix speeling<commit_after>use std::fmt;
use std::collections::VecDeque;
use std::net::SocketAddr;
use std::rc::Rc;

use mio::tcp::TcpStream;
use mio::Timeout as TimeoutHandle;
use mio::{
    EventLoop,
    EventSet,
    PollOpt,
    Token,
};
use capnp::{
    MallocMessageBuilder,
    OwnedSpaceMessageReader,
    ReaderOptions,
};
use capnp::serialize::{
    read_message_async,
    write_message_async,
    AsyncValue,
    ReadContinuation,
    WriteContinuation,
};

use ClientId;
use Result;
use ServerId;
use backoff::Backoff;
use messages;
use server::{Server, ServerTimeout};
use state_machine::StateMachine;
use store::Store;

fn poll_opt() -> PollOpt {
    PollOpt::edge() | PollOpt::oneshot()
}

/// The type of a connection.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub enum ConnectionKind {
    /// A peer in the cluster.
    Peer(ServerId),
    /// A client which is asking the Raft cluster to do things.
    Client(ClientId),
    /// Something else.
    Unknown,
}

impl ConnectionKind {
    /// Returns if the `Connection` is a peer type.
    fn is_peer(&self) -> bool {
        match *self {
            ConnectionKind::Peer(..) => true,
            _ => false,
        }
    }
    /// Returns if the `Connection` is a client type.
    fn is_client(&self) -> bool {
        match *self {
            ConnectionKind::Client(..) => true,
            _ => false,
        }
    }
}

pub struct Connection {
    kind: ConnectionKind,
    addr: SocketAddr,
    stream: TcpStream,
    backoff: Backoff,
    events: EventSet,
    read_continuation: Option<ReadContinuation>,
    write_continuation: Option<WriteContinuation>,
    write_queue: VecDeque<Rc<MallocMessageBuilder>>,
    is_connected: bool,
}

impl Connection {

    /// Creates a new `Connection` wrapping the provided socket stream.
    ///
    /// The socket must already be connected.
    ///
    /// Note: the caller must manually set the token field after inserting the
    /// connection into a slab.
    pub fn unknown(socket: TcpStream) -> Result<Connection> {
        let addr = try!(socket.peer_addr());
        Ok(Connection {
            kind: ConnectionKind::Unknown,
            addr: addr,
            stream: socket,
            backoff: Backoff::with_duration_range(8, 10000),
            events: EventSet::hup() | EventSet::readable(),
            read_continuation: None,
            write_continuation: None,
            write_queue: VecDeque::new(),
            is_connected: true,
        })
    }

    /// Creates a new peer connection.
    pub fn peer(id: ServerId, addr: SocketAddr) -> Result<Connection> {
        let stream = try!(TcpStream::connect(&addr));
        Ok(Connection {
            kind: ConnectionKind::Peer(id),
            addr: addr,
            stream: stream,
            backoff: Backoff::with_duration_range(1, 10000),
            events: EventSet::hup() | EventSet::readable(),
            read_continuation: None,
            write_continuation: None,
            write_queue: VecDeque::new(),
            is_connected: true,
        })
    }

    pub fn kind(&self) -> &ConnectionKind {
        &self.kind
    }

    pub fn set_kind(&mut self, kind: ConnectionKind) {
        self.kind = kind;
    }

    /// Writes queued messages to the socket.
    pub fn writable(&mut self) -> Result<()> {
        trace!("{:?}: writable; queued message count: {}", self, self.write_queue.len());
        assert!(self.is_connected, "raft::{:?}: writable event while not connected", self);

        while let Some(message) = self.write_queue.pop_front() {
            let continuation = self.write_continuation.take();
            match write_message_async(&mut self.stream, &*message, continuation) {
                Ok(AsyncValue::Complete(())) => (),
                Ok(AsyncValue::Continue(continuation)) =>  {
                    // The write only partially completed. Save the continuation and add the
                    // message back to the front of the queue.
                    self.write_continuation = Some(continuation);
                    self.write_queue.push_front(message);
                    break;
                }
                Err(error) => {
                    // The write failed; reinsert the message back to the write queue.
                    self.write_queue.push_front(message);
                    return Err(From::from(error));
                }
            }
        }

        if self.write_queue.is_empty() {
            self.events.remove(EventSet::writable());
        }

        self.backoff.reset();
        Ok(())
    }

    /// Reads a message from the connection's stream, or if a full message is
    /// not available, returns `None`.
    ///
    /// Connections are edge-triggered, so the handler must continue calling
    /// until no more messages are returned.
    pub fn readable(&mut self) -> Result<Option<OwnedSpaceMessageReader>> {
        trace!("{:?}: readable", self);
        assert!(self.is_connected, "raft::{:?}: readable event while not connected", self);

        let read = try!(read_message_async(&mut self.stream,
                                           ReaderOptions::new(),
                                           self.read_continuation.take()));
        self.backoff.reset();
        match read {
            AsyncValue::Complete(message) => {
                Ok(Some(message))
            },
            AsyncValue::Continue(continuation) => {
                // the read only partially completed. Save the continuation and return.
                self.read_continuation = Some(continuation);
                Ok(None)
            },
        }
    }

    /// Queues a message to be sent to this connection.
    pub fn send_message(&mut self, message: Rc<MallocMessageBuilder>) {
        trace!("{:?}: send_message", self);
        if self.is_connected {
            if self.write_queue.is_empty() {
                self.events.insert(EventSet::writable());
            }
            self.write_queue.push_back(message);
        }
    }

    /// Registers the connection with the event loop.
    pub fn register<S, M>(&mut self, event_loop: &mut EventLoop<Server<S, M>>, token: Token) -> Result<()>
    where S: Store, M: StateMachine {
        event_loop.register_opt(&self.stream, token, self.events, poll_opt())
                  .map_err(From::from)
    }

    /// Reregisters the connection with the event loop.
    pub fn reregister<S, M>(&mut self, event_loop: &mut EventLoop<Server<S, M>>, token: Token) -> Result<()>
    where S: Store, M: StateMachine {
        event_loop.reregister(&self.stream, token, self.events, poll_opt())
                  .map_err(From::from)
    }

    pub fn reconnect_peer(&mut self, id: ServerId) -> Result<()> {
        self.stream = try!(TcpStream::connect(&self.addr));
        self.is_connected = true;
        self.read_continuation = None;
        self.write_continuation = None;
        self.write_queue.clear();
        self.send_message(messages::server_connection_preamble(id));
        Ok(())
    }

    /// Resets a peer connection.
    pub fn reset_peer<S, M>(&mut self,
                            event_loop: &mut EventLoop<Server<S, M>>,
                            token: Token)
                            -> Result<(ServerTimeout, TimeoutHandle)>
    where S: Store, M: StateMachine {
        assert!(self.kind.is_peer());
        let duration = self.backoff.next_backoff_ms();
        self.read_continuation = None;
        self.write_continuation = None;
        self.write_queue.clear();
        self.is_connected = false;
        let timeout = ServerTimeout::Reconnect(token);
        let handle = event_loop.timeout_ms(timeout, duration).unwrap();

        info!("{:?}: {:?} reset, will attempt to reconnect in {}ms", self,
              self, duration);
        Ok((timeout, handle))
    }
}

impl fmt::Debug for Connection {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self.kind {
            ConnectionKind::Peer(id) => {
                write!(fmt, "PeerConnection({})", id)
            },
            ConnectionKind::Client(id) => {
                write!(fmt, "ClientConnection({})", id)
            },
            ConnectionKind::Unknown => {
                write!(fmt, "UnknownConnection({})", &self.addr)
            },
        }
    }
}
<|endoftext|>


<commit_before>//! Code for building the standard library.

use crate::core::compiler::{BuildContext, CompileMode, Kind, Unit};
use crate::core::profiles::UnitFor;
use crate::core::resolver::ResolveOpts;
use crate::core::{Dependency, PackageId, PackageSet, Resolve, SourceId, Workspace};
use crate::ops::{self, Packages};
use crate::util::errors::CargoResult;
use std::collections::{HashMap, HashSet};
use std::path::PathBuf;

/// Parse the `-Zbuild-std` flag.
pub fn parse_unstable_flag(value: Option<&str>) -> Vec<String> {
    // This is a temporary hack until there is a more principled way to
    // declare dependencies in Cargo.toml.
    let value = value.unwrap_or("std");
    let mut crates: HashSet<&str> = value.split(',').collect();
    if crates.contains("std") {
        crates.insert("core");
        crates.insert("alloc");
        crates.insert("proc_macro");
        crates.insert("panic_unwind");
        crates.insert("compiler_builtins");
    } else if crates.contains("core") {
        crates.insert("compiler_builtins");
    }
    crates.into_iter().map(|s| s.to_string()).collect()
}

/// Resolve the standard library dependencies.
pub fn resolve_std<'cfg>(
    ws: &Workspace<'cfg>,
    crates: &[String],
) -> CargoResult<(PackageSet<'cfg>, Resolve)> {
    let src_path = detect_sysroot_src_path(ws)?;
    let to_patch = [
        "rustc-std-workspace-core",
        "rustc-std-workspace-alloc",
        "rustc-std-workspace-std",
    ];
    let patches = to_patch
        .iter()
        .map(|&name| {
            let source_path = SourceId::for_path(&src_path.join("src").join("tools").join(name))?;
            let dep = Dependency::parse_no_deprecated(name, None, source_path)?;
            Ok(dep)
        })
        .collect::<CargoResult<Vec<_>>>()?;
    let crates_io_url = crate::sources::CRATES_IO_INDEX.parse().unwrap();
    let mut patch = HashMap::new();
    patch.insert(crates_io_url, patches);
    let members = vec![
        String::from("src/libstd"),
        String::from("src/libcore"),
        String::from("src/liballoc"),
        String::from("src/libtest"),
    ];
    let ws_config = crate::core::WorkspaceConfig::Root(crate::core::WorkspaceRootConfig::new(
        &src_path,
        &Some(members),
        /*default_members*/ &None,
        /*exclude*/ &None,
    ));
    let virtual_manifest = crate::core::VirtualManifest::new(
        /*replace*/ Vec::new(),
        patch,
        ws_config,
        // Profiles are not used here, but we need something to pass in.
        ws.profiles().clone(),
        crate::core::Features::default(),
    );

    let config = ws.config();
    // This is a delicate hack. In order for features to resolve correctly,
    // the resolver needs to run a specific "current" member of the workspace.
    // Thus, in order to set the features for `std`, we need to set `libtest`
    // to be the "current" member. `libtest` is the root, and all other
    // standard library crates are dependencies from there. Since none of the
    // other crates need to alter their features, this should be fine, for
    // now. Perhaps in the future features will be decoupled from the resolver
    // and it will be easier to control feature selection.
    let current_manifest = src_path.join("src/libtest/Cargo.toml");
    // TODO: Consider setting require_option_deps false?
    // TODO: Consider doing something to enforce --locked? Or to prevent the
    // lock file from being written, such as setting ephemeral.
    let std_ws = Workspace::new_virtual(src_path, current_manifest, virtual_manifest, config)?;
    // `test` is not in the default set because it is optional, but it needs
    // to be part of the resolve in case we do need it.
    let mut spec_pkgs = Vec::from(crates);
    spec_pkgs.push("test".to_string());
    let spec = Packages::Packages(spec_pkgs);
    let specs = spec.to_package_id_specs(&std_ws)?;
    let features = vec!["panic-unwind".to_string(), "backtrace".to_string()];
    // dev_deps setting shouldn't really matter here.
    let opts = ResolveOpts::new(
        /*dev_deps*/ false, &features, /*all_features*/ false,
        /*uses_default_features*/ true,
    );
    let resolve = ops::resolve_ws_with_opts(&std_ws, opts, &specs)?;
    Ok(resolve)
}

/// Generate a list of root `Unit`s for the standard library.
///
/// The given slice of crate names is the root set.
pub fn generate_std_roots<'a>(
    bcx: &BuildContext<'a, '_>,
    crates: &[String],
    std_resolve: &'a Resolve,
) -> CargoResult<Vec<Unit<'a>>> {
    // Generate the root Units for the standard library.
    let std_ids = crates
        .iter()
        .map(|crate_name| std_resolve.query(crate_name))
        .collect::<CargoResult<Vec<PackageId>>>()?;
    // Convert PackageId to Package.
    let std_pkgs = bcx.packages.get_many(std_ids)?;
    // Generate a list of Units.
    std_pkgs
        .into_iter()
        .map(|pkg| {
            let lib = pkg
                .targets()
                .iter()
                .find(|t| t.is_lib())
                .expect("std has a lib");
            let unit_for = UnitFor::new_normal();
            // I don't think we need to bother with Check here, the difference
            // in time is minimal, and the difference in caching is
            // significant.
            let mode = CompileMode::Build;
            let profile = bcx.profiles.get_profile(
                pkg.package_id(),
                /*is_member*/ false,
                unit_for,
                mode,
                bcx.build_config.release,
            );
            let features = std_resolve.features_sorted(pkg.package_id());
            Ok(bcx
                .units
                .intern(pkg, lib, profile, Kind::Target, mode, features))
        })
        .collect::<CargoResult<Vec<_>>>()
}

fn detect_sysroot_src_path(ws: &Workspace<'_>) -> CargoResult<PathBuf> {
    // NOTE: This is temporary until we figure out how to acquire the source.
    // If we decide to keep the sysroot probe, then BuildConfig will need to
    // be restructured so that the TargetInfo is created earlier and passed
    // in, so we don't have this extra call to rustc.
    let rustc = ws.config().load_global_rustc(Some(ws))?;
    let output = rustc.process().arg("--print=sysroot").exec_with_output()?;
    let s = String::from_utf8(output.stdout)
        .map_err(|e| failure::format_err!("rustc didn't return utf8 output: {:?}", e))?;
    let sysroot = PathBuf::from(s.trim());
    let src_path = sysroot.join("lib").join("rustlib").join("src").join("rust");
    let lock = src_path.join("Cargo.lock");
    if !lock.exists() {
        failure::bail!(
            "{:?} does not exist, unable to build with the standard \
             library, try:\n        rustup component add rust-src",
            lock
        );
    }
    Ok(src_path)
}
<commit_msg>Don't resolve std's optional dependencies<commit_after>//! Code for building the standard library.

use crate::core::compiler::{BuildContext, CompileMode, Kind, Unit};
use crate::core::profiles::UnitFor;
use crate::core::resolver::ResolveOpts;
use crate::core::{Dependency, PackageId, PackageSet, Resolve, SourceId, Workspace};
use crate::ops::{self, Packages};
use crate::util::errors::CargoResult;
use std::collections::{HashMap, HashSet};
use std::path::PathBuf;

/// Parse the `-Zbuild-std` flag.
pub fn parse_unstable_flag(value: Option<&str>) -> Vec<String> {
    // This is a temporary hack until there is a more principled way to
    // declare dependencies in Cargo.toml.
    let value = value.unwrap_or("std");
    let mut crates: HashSet<&str> = value.split(',').collect();
    if crates.contains("std") {
        crates.insert("core");
        crates.insert("alloc");
        crates.insert("proc_macro");
        crates.insert("panic_unwind");
        crates.insert("compiler_builtins");
    } else if crates.contains("core") {
        crates.insert("compiler_builtins");
    }
    crates.into_iter().map(|s| s.to_string()).collect()
}

/// Resolve the standard library dependencies.
pub fn resolve_std<'cfg>(
    ws: &Workspace<'cfg>,
    crates: &[String],
) -> CargoResult<(PackageSet<'cfg>, Resolve)> {
    let src_path = detect_sysroot_src_path(ws)?;
    let to_patch = [
        "rustc-std-workspace-core",
        "rustc-std-workspace-alloc",
        "rustc-std-workspace-std",
    ];
    let patches = to_patch
        .iter()
        .map(|&name| {
            let source_path = SourceId::for_path(&src_path.join("src").join("tools").join(name))?;
            let dep = Dependency::parse_no_deprecated(name, None, source_path)?;
            Ok(dep)
        })
        .collect::<CargoResult<Vec<_>>>()?;
    let crates_io_url = crate::sources::CRATES_IO_INDEX.parse().unwrap();
    let mut patch = HashMap::new();
    patch.insert(crates_io_url, patches);
    let members = vec![
        String::from("src/libstd"),
        String::from("src/libcore"),
        String::from("src/liballoc"),
        String::from("src/libtest"),
    ];
    let ws_config = crate::core::WorkspaceConfig::Root(crate::core::WorkspaceRootConfig::new(
        &src_path,
        &Some(members),
        /*default_members*/ &None,
        /*exclude*/ &None,
    ));
    let virtual_manifest = crate::core::VirtualManifest::new(
        /*replace*/ Vec::new(),
        patch,
        ws_config,
        // Profiles are not used here, but we need something to pass in.
        ws.profiles().clone(),
        crate::core::Features::default(),
    );

    let config = ws.config();
    // This is a delicate hack. In order for features to resolve correctly,
    // the resolver needs to run a specific "current" member of the workspace.
    // Thus, in order to set the features for `std`, we need to set `libtest`
    // to be the "current" member. `libtest` is the root, and all other
    // standard library crates are dependencies from there. Since none of the
    // other crates need to alter their features, this should be fine, for
    // now. Perhaps in the future features will be decoupled from the resolver
    // and it will be easier to control feature selection.
    let current_manifest = src_path.join("src/libtest/Cargo.toml");
    // TODO: Consider doing something to enforce --locked? Or to prevent the
    // lock file from being written, such as setting ephemeral.
    let mut std_ws = Workspace::new_virtual(src_path, current_manifest, virtual_manifest, config)?;
    // Don't require optional dependencies in this workspace, aka std's own
    // `[dev-dependencies]`. No need for us to generate a `Resolve` which has
    // those included because we'll never use them anyway.
    std_ws.set_require_optional_deps(false);
    // `test` is not in the default set because it is optional, but it needs
    // to be part of the resolve in case we do need it.
    let mut spec_pkgs = Vec::from(crates);
    spec_pkgs.push("test".to_string());
    let spec = Packages::Packages(spec_pkgs);
    let specs = spec.to_package_id_specs(&std_ws)?;
    let features = vec!["panic-unwind".to_string(), "backtrace".to_string()];
    // dev_deps setting shouldn't really matter here.
    let opts = ResolveOpts::new(
        /*dev_deps*/ false, &features, /*all_features*/ false,
        /*uses_default_features*/ true,
    );
    let resolve = ops::resolve_ws_with_opts(&std_ws, opts, &specs)?;
    Ok(resolve)
}

/// Generate a list of root `Unit`s for the standard library.
///
/// The given slice of crate names is the root set.
pub fn generate_std_roots<'a>(
    bcx: &BuildContext<'a, '_>,
    crates: &[String],
    std_resolve: &'a Resolve,
) -> CargoResult<Vec<Unit<'a>>> {
    // Generate the root Units for the standard library.
    let std_ids = crates
        .iter()
        .map(|crate_name| std_resolve.query(crate_name))
        .collect::<CargoResult<Vec<PackageId>>>()?;
    // Convert PackageId to Package.
    let std_pkgs = bcx.packages.get_many(std_ids)?;
    // Generate a list of Units.
    std_pkgs
        .into_iter()
        .map(|pkg| {
            let lib = pkg
                .targets()
                .iter()
                .find(|t| t.is_lib())
                .expect("std has a lib");
            let unit_for = UnitFor::new_normal();
            // I don't think we need to bother with Check here, the difference
            // in time is minimal, and the difference in caching is
            // significant.
            let mode = CompileMode::Build;
            let profile = bcx.profiles.get_profile(
                pkg.package_id(),
                /*is_member*/ false,
                unit_for,
                mode,
                bcx.build_config.release,
            );
            let features = std_resolve.features_sorted(pkg.package_id());
            Ok(bcx
                .units
                .intern(pkg, lib, profile, Kind::Target, mode, features))
        })
        .collect::<CargoResult<Vec<_>>>()
}

fn detect_sysroot_src_path(ws: &Workspace<'_>) -> CargoResult<PathBuf> {
    // NOTE: This is temporary until we figure out how to acquire the source.
    // If we decide to keep the sysroot probe, then BuildConfig will need to
    // be restructured so that the TargetInfo is created earlier and passed
    // in, so we don't have this extra call to rustc.
    let rustc = ws.config().load_global_rustc(Some(ws))?;
    let output = rustc.process().arg("--print=sysroot").exec_with_output()?;
    let s = String::from_utf8(output.stdout)
        .map_err(|e| failure::format_err!("rustc didn't return utf8 output: {:?}", e))?;
    let sysroot = PathBuf::from(s.trim());
    let src_path = sysroot.join("lib").join("rustlib").join("src").join("rust");
    let lock = src_path.join("Cargo.lock");
    if !lock.exists() {
        failure::bail!(
            "{:?} does not exist, unable to build with the standard \
             library, try:\n        rustup component add rust-src",
            lock
        );
    }
    Ok(src_path)
}
<|endoftext|>


<commit_before>use super::{DataMode, Dir, Expr, Item, ProtocolRef};

fn count_item_fields(i: &Item) -> usize {
    match *i {
        Item::Value(Expr::Const(_)) => 0,
        Item::Value(_) => 1,
        Item::Tuple(ref t) => t.iter().map(count_item_fields).sum(),
        _ => panic!("Item {:?} not allowed in shape", i),
    }
}

#[derive(Clone, Debug)]
pub struct ShapeMsg {
    pub name: String,
    pub params: Vec<ShapeMsgParam>,
    pub num_fields: usize,
}

#[derive(Clone, Debug)]
pub struct ShapeMsgParam {
    pub item: Item,
    pub direction: DataMode,
}

impl ShapeMsgParam {
    fn count_fields(&self) -> usize {
        if self.direction.down || self.direction.up {
            count_item_fields(&self.item)
        } else { 0 }
    }
}

impl ShapeMsg {
    pub fn new(name: String, params: Vec<ShapeMsgParam>) -> ShapeMsg {
        let num_fields = params.iter().map(|x| x.count_fields()).sum();
        ShapeMsg { name, params, num_fields }
    }
}

/// Representation of token alphabet between state machine layers of abstraction.
#[derive(Clone, Debug)]
pub struct Shape {
    pub def: ProtocolRef,
    pub dir: Dir,
    pub param: Item,
    pub messages: Vec<ShapeMsg>,
}

impl Shape {
    pub fn variant_named(&self, name: &str) -> Option<(usize, &ShapeMsg)> {
        self.messages.iter().enumerate().find(|&(_, m)| m.name == name)
    }

    pub fn direction(&self) -> DataMode {
        DataMode {
            up: self.messages.iter().flat_map(|m| m.params.iter()).any(|f| f.direction.up),
            down: self.messages.iter().flat_map(|m| m.params.iter()).any(|f| f.direction.down)
        }
    }
}

<commit_msg>Remove dead code<commit_after>use super::{DataMode, Dir, Expr, Item, ProtocolRef};

fn count_item_fields(i: &Item) -> usize {
    match *i {
        Item::Value(Expr::Const(_)) => 0,
        Item::Value(_) => 1,
        Item::Tuple(ref t) => t.iter().map(count_item_fields).sum(),
        _ => panic!("Item {:?} not allowed in shape", i),
    }
}

#[derive(Clone, Debug)]
pub struct ShapeMsg {
    pub name: String,
    pub params: Vec<ShapeMsgParam>,
}

#[derive(Clone, Debug)]
pub struct ShapeMsgParam {
    pub item: Item,
    pub direction: DataMode,
}

impl ShapeMsg {
    pub fn new(name: String, params: Vec<ShapeMsgParam>) -> ShapeMsg {
        ShapeMsg { name, params }
    }
}

/// Representation of token alphabet between state machine layers of abstraction.
#[derive(Clone, Debug)]
pub struct Shape {
    pub def: ProtocolRef,
    pub dir: Dir,
    pub param: Item,
    pub messages: Vec<ShapeMsg>,
}

impl Shape {
    pub fn variant_named(&self, name: &str) -> Option<(usize, &ShapeMsg)> {
        self.messages.iter().enumerate().find(|&(_, m)| m.name == name)
    }

    pub fn direction(&self) -> DataMode {
        DataMode {
            up: self.messages.iter().flat_map(|m| m.params.iter()).any(|f| f.direction.up),
            down: self.messages.iter().flat_map(|m| m.params.iter()).any(|f| f.direction.down)
        }
    }
}

<|endoftext|>