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

#![stable(feature = "rust1", since = "1.0.0")]

use fs;
use os::windows::raw;
use net;
use sys_common::{self, AsInner, FromInner, IntoInner};
use sys;
use io;
use sys::c;

/// Raw HANDLEs.
#[stable(feature = "rust1", since = "1.0.0")]
pub type RawHandle = raw::HANDLE;

/// Raw SOCKETs.
#[stable(feature = "rust1", since = "1.0.0")]
pub type RawSocket = raw::SOCKET;

/// Extract raw handles.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRawHandle {
    /// Extracts the raw handle, without taking any ownership.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn as_raw_handle(&self) -> RawHandle;
}

/// Construct I/O objects from raw handles.
#[stable(feature = "from_raw_os", since = "1.1.0")]
pub trait FromRawHandle {
    /// Constructs a new I/O object from the specified raw handle.
    ///
    /// This function will **consume ownership** of the handle given,
    /// passing responsibility for closing the handle to the returned
    /// object.
    ///
    /// This function is also unsafe as the primitives currently returned
    /// have the contract that they are the sole owner of the file
    /// descriptor they are wrapping. Usage of this function could
    /// accidentally allow violating this contract which can cause memory
    /// unsafety in code that relies on it being true.
    #[stable(feature = "from_raw_os", since = "1.1.0")]
    unsafe fn from_raw_handle(handle: RawHandle) -> Self;
}

/// A trait to express the ability to consume an object and acquire ownership of
/// its raw `HANDLE`.
#[stable(feature = "into_raw_os", since = "1.4.0")]
pub trait IntoRawHandle {
    /// Consumes this object, returning the raw underlying handle.
    ///
    /// This function **transfers ownership** of the underlying handle to the
    /// caller. Callers are then the unique owners of the handle and must close
    /// it once it's no longer needed.
    #[stable(feature = "into_raw_os", since = "1.4.0")]
    fn into_raw_handle(self) -> RawHandle;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawHandle for fs::File {
    fn as_raw_handle(&self) -> RawHandle {
        self.as_inner().handle().raw() as RawHandle
    }
}

#[stable(feature = "asraw_stdio", since = "1.21.0")]
impl AsRawHandle for io::Stdin {
    fn as_raw_handle(&self) -> RawHandle {
        unsafe { c::GetStdHandle(c::STD_INPUT_HANDLE) } as RawHandle
    }
}

#[stable(feature = "asraw_stdio", since = "1.21.0")]
impl AsRawHandle for io::Stdout {
    fn as_raw_handle(&self) -> RawHandle {
        unsafe { c::GetStdHandle(c::STD_OUTPUT_HANDLE) } as RawHandle
    }
}

#[stable(feature = "asraw_stdio", since = "1.21.0")]
impl AsRawHandle for io::Stderr {
    fn as_raw_handle(&self) -> RawHandle {
        unsafe { c::GetStdHandle(c::STD_ERROR_HANDLE) } as RawHandle
    }
}

#[stable(feature = "from_raw_os", since = "1.1.0")]
impl FromRawHandle for fs::File {
    unsafe fn from_raw_handle(handle: RawHandle) -> fs::File {
        let handle = handle as c::HANDLE;
        fs::File::from_inner(sys::fs::File::from_inner(handle))
    }
}

#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawHandle for fs::File {
    fn into_raw_handle(self) -> RawHandle {
        self.into_inner().into_handle().into_raw() as *mut _
    }
}

/// Extract raw sockets.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRawSocket {
    /// Extracts the underlying raw socket from this object.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn as_raw_socket(&self) -> RawSocket;
}

/// Create I/O objects from raw sockets.
#[stable(feature = "from_raw_os", since = "1.1.0")]
pub trait FromRawSocket {
    /// Creates a new I/O object from the given raw socket.
    ///
    /// This function will **consume ownership** of the socket provided and
    /// it will be closed when the returned object goes out of scope.
    ///
    /// This function is also unsafe as the primitives currently returned
    /// have the contract that they are the sole owner of the file
    /// descriptor they are wrapping. Usage of this function could
    /// accidentally allow violating this contract which can cause memory
    /// unsafety in code that relies on it being true.
    #[stable(feature = "from_raw_os", since = "1.1.0")]
    unsafe fn from_raw_socket(sock: RawSocket) -> Self;
}

/// A trait to express the ability to consume an object and acquire ownership of
/// its raw `SOCKET`.
#[stable(feature = "into_raw_os", since = "1.4.0")]
pub trait IntoRawSocket {
    /// Consumes this object, returning the raw underlying socket.
    ///
    /// This function **transfers ownership** of the underlying socket to the
    /// caller. Callers are then the unique owners of the socket and must close
    /// it once it's no longer needed.
    #[stable(feature = "into_raw_os", since = "1.4.0")]
    fn into_raw_socket(self) -> RawSocket;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawSocket for net::TcpStream {
    fn as_raw_socket(&self) -> RawSocket {
        *self.as_inner().socket().as_inner()
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawSocket for net::TcpListener {
    fn as_raw_socket(&self) -> RawSocket {
        *self.as_inner().socket().as_inner()
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawSocket for net::UdpSocket {
    fn as_raw_socket(&self) -> RawSocket {
        *self.as_inner().socket().as_inner()
    }
}

#[stable(feature = "from_raw_os", since = "1.1.0")]
impl FromRawSocket for net::TcpStream {
    unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream {
        let sock = sys::net::Socket::from_inner(sock);
        net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(sock))
    }
}
#[stable(feature = "from_raw_os", since = "1.1.0")]
impl FromRawSocket for net::TcpListener {
    unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener {
        let sock = sys::net::Socket::from_inner(sock);
        net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(sock))
    }
}
#[stable(feature = "from_raw_os", since = "1.1.0")]
impl FromRawSocket for net::UdpSocket {
    unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket {
        let sock = sys::net::Socket::from_inner(sock);
        net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(sock))
    }
}

#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawSocket for net::TcpStream {
    fn into_raw_socket(self) -> RawSocket {
        self.into_inner().into_socket().into_inner()
    }
}

#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawSocket for net::TcpListener {
    fn into_raw_socket(self) -> RawSocket {
        self.into_inner().into_socket().into_inner()
    }
}

#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawSocket for net::UdpSocket {
    fn into_raw_socket(self) -> RawSocket {
        self.into_inner().into_socket().into_inner()
    }
}
<commit_msg>Fix AsRawHandle<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![stable(feature = "rust1", since = "1.0.0")]

use fs;
use os::windows::raw;
use net;
use sys_common::{self, AsInner, FromInner, IntoInner};
use sys;
use io;
use sys::c;

/// Raw HANDLEs.
#[stable(feature = "rust1", since = "1.0.0")]
pub type RawHandle = raw::HANDLE;

/// Raw SOCKETs.
#[stable(feature = "rust1", since = "1.0.0")]
pub type RawSocket = raw::SOCKET;

/// Extract raw handles.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRawHandle {
    /// Extracts the raw handle, without taking any ownership.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn as_raw_handle(&self) -> RawHandle;
}

/// Construct I/O objects from raw handles.
#[stable(feature = "from_raw_os", since = "1.1.0")]
pub trait FromRawHandle {
    /// Constructs a new I/O object from the specified raw handle.
    ///
    /// This function will **consume ownership** of the handle given,
    /// passing responsibility for closing the handle to the returned
    /// object.
    ///
    /// This function is also unsafe as the primitives currently returned
    /// have the contract that they are the sole owner of the file
    /// descriptor they are wrapping. Usage of this function could
    /// accidentally allow violating this contract which can cause memory
    /// unsafety in code that relies on it being true.
    #[stable(feature = "from_raw_os", since = "1.1.0")]
    unsafe fn from_raw_handle(handle: RawHandle) -> Self;
}

/// A trait to express the ability to consume an object and acquire ownership of
/// its raw `HANDLE`.
#[stable(feature = "into_raw_os", since = "1.4.0")]
pub trait IntoRawHandle {
    /// Consumes this object, returning the raw underlying handle.
    ///
    /// This function **transfers ownership** of the underlying handle to the
    /// caller. Callers are then the unique owners of the handle and must close
    /// it once it's no longer needed.
    #[stable(feature = "into_raw_os", since = "1.4.0")]
    fn into_raw_handle(self) -> RawHandle;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawHandle for fs::File {
    fn as_raw_handle(&self) -> RawHandle {
        self.as_inner().handle().raw() as RawHandle
    }
}

#[stable(feature = "asraw_stdio", since = "1.21.0")]
impl AsRawHandle for io::Stdin {
    fn as_raw_handle(&self) -> RawHandle {
        unsafe { c::GetStdHandle(c::STD_INPUT_HANDLE) as RawHandle }
    }
}

#[stable(feature = "asraw_stdio", since = "1.21.0")]
impl AsRawHandle for io::Stdout {
    fn as_raw_handle(&self) -> RawHandle {
        unsafe { c::GetStdHandle(c::STD_OUTPUT_HANDLE) as RawHandle }
    }
}

#[stable(feature = "asraw_stdio", since = "1.21.0")]
impl AsRawHandle for io::Stderr {
    fn as_raw_handle(&self) -> RawHandle {
        unsafe { c::GetStdHandle(c::STD_ERROR_HANDLE) as RawHandle }
    }
}

#[stable(feature = "from_raw_os", since = "1.1.0")]
impl FromRawHandle for fs::File {
    unsafe fn from_raw_handle(handle: RawHandle) -> fs::File {
        let handle = handle as c::HANDLE;
        fs::File::from_inner(sys::fs::File::from_inner(handle))
    }
}

#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawHandle for fs::File {
    fn into_raw_handle(self) -> RawHandle {
        self.into_inner().into_handle().into_raw() as *mut _
    }
}

/// Extract raw sockets.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRawSocket {
    /// Extracts the underlying raw socket from this object.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn as_raw_socket(&self) -> RawSocket;
}

/// Create I/O objects from raw sockets.
#[stable(feature = "from_raw_os", since = "1.1.0")]
pub trait FromRawSocket {
    /// Creates a new I/O object from the given raw socket.
    ///
    /// This function will **consume ownership** of the socket provided and
    /// it will be closed when the returned object goes out of scope.
    ///
    /// This function is also unsafe as the primitives currently returned
    /// have the contract that they are the sole owner of the file
    /// descriptor they are wrapping. Usage of this function could
    /// accidentally allow violating this contract which can cause memory
    /// unsafety in code that relies on it being true.
    #[stable(feature = "from_raw_os", since = "1.1.0")]
    unsafe fn from_raw_socket(sock: RawSocket) -> Self;
}

/// A trait to express the ability to consume an object and acquire ownership of
/// its raw `SOCKET`.
#[stable(feature = "into_raw_os", since = "1.4.0")]
pub trait IntoRawSocket {
    /// Consumes this object, returning the raw underlying socket.
    ///
    /// This function **transfers ownership** of the underlying socket to the
    /// caller. Callers are then the unique owners of the socket and must close
    /// it once it's no longer needed.
    #[stable(feature = "into_raw_os", since = "1.4.0")]
    fn into_raw_socket(self) -> RawSocket;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawSocket for net::TcpStream {
    fn as_raw_socket(&self) -> RawSocket {
        *self.as_inner().socket().as_inner()
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawSocket for net::TcpListener {
    fn as_raw_socket(&self) -> RawSocket {
        *self.as_inner().socket().as_inner()
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawSocket for net::UdpSocket {
    fn as_raw_socket(&self) -> RawSocket {
        *self.as_inner().socket().as_inner()
    }
}

#[stable(feature = "from_raw_os", since = "1.1.0")]
impl FromRawSocket for net::TcpStream {
    unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream {
        let sock = sys::net::Socket::from_inner(sock);
        net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(sock))
    }
}
#[stable(feature = "from_raw_os", since = "1.1.0")]
impl FromRawSocket for net::TcpListener {
    unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener {
        let sock = sys::net::Socket::from_inner(sock);
        net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(sock))
    }
}
#[stable(feature = "from_raw_os", since = "1.1.0")]
impl FromRawSocket for net::UdpSocket {
    unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket {
        let sock = sys::net::Socket::from_inner(sock);
        net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(sock))
    }
}

#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawSocket for net::TcpStream {
    fn into_raw_socket(self) -> RawSocket {
        self.into_inner().into_socket().into_inner()
    }
}

#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawSocket for net::TcpListener {
    fn into_raw_socket(self) -> RawSocket {
        self.into_inner().into_socket().into_inner()
    }
}

#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawSocket for net::UdpSocket {
    fn into_raw_socket(self) -> RawSocket {
        self.into_inner().into_socket().into_inner()
    }
}
<|endoftext|>


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

#![allow(dead_code)]
#![unstable(feature = "process_internals", issue = "0")]

use ffi::{OsStr, OsString};
use env;
use collections::BTreeMap;
use alloc::borrow::Borrow;

pub trait EnvKey:
    From<OsString> + Into<OsString> +
    Borrow<OsStr> + Borrow<Self> + AsRef<OsStr> +
    Ord + Clone {}

// Implement a case-sensitive environment variable key
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct DefaultEnvKey(OsString);

impl From<OsString> for DefaultEnvKey {
    fn from(k: OsString) -> Self { DefaultEnvKey(k) }
}

impl From<DefaultEnvKey> for OsString {
    fn from(k: DefaultEnvKey) -> Self { k.0 }
}

impl Borrow<OsStr> for DefaultEnvKey {
    fn borrow(&self) -> &OsStr { &self.0 }
}

impl AsRef<OsStr> for DefaultEnvKey {
    fn as_ref(&self) -> &OsStr { &self.0 }
}

impl EnvKey for DefaultEnvKey {}

// Stores a set of changes to an environment
#[derive(Clone, Debug)]
pub struct CommandEnv<K> {
    clear: bool,
    saw_path: bool,
    vars: BTreeMap<K, Option<OsString>>
}

impl<K: EnvKey> Default for CommandEnv<K> {
    fn default() -> Self {
        CommandEnv {
            clear: false,
            saw_path: false,
            vars: Default::default()
        }
    }
}

impl<K: EnvKey> CommandEnv<K> {
    // Capture the current environment with these changes applied
    pub fn capture(&self) -> BTreeMap<K, OsString> {
        let mut result = BTreeMap::<K, OsString>::new();
        if !self.clear {
            for (k, v) in env::vars_os() {
                result.insert(k.into(), v);
            }
        }
        for (k, maybe_v) in &self.vars {
            if let &Some(ref v) = maybe_v {
                result.insert(k.clone(), v.clone());
            } else {
                result.remove(k);
            }
        }
        result
    }

    // Apply these changes directly to the current environment
    pub fn apply(&self) {
        if self.clear {
            for (k, _) in env::vars_os() {
                env::remove_var(k);
            }
        }
        for (key, maybe_val) in self.vars.iter() {
            if let &Some(ref val) = maybe_val {
                env::set_var(key, val);
            } else {
                env::remove_var(key);
            }
        }
    }

    pub fn is_unchanged(&self) -> bool {
        !self.clear && self.vars.is_empty()
    }

    pub fn capture_if_changed(&self) -> Option<BTreeMap<K, OsString>> {
        if self.is_unchanged() {
            None
        } else {
            Some(self.capture())
        }
    }

    // The following functions build up changes
    pub fn set(&mut self, key: &OsStr, value: &OsStr) {
        self.maybe_saw_path(&key);
        self.vars.insert(key.to_owned().into(), Some(value.to_owned()));
    }
    pub fn remove(&mut self, key: &OsStr) {
        self.maybe_saw_path(&key);
        if self.clear {
            self.vars.remove(key);
        } else {
            self.vars.insert(key.to_owned().into(), None);
        }
    }
    pub fn clear(&mut self) {
        self.clear = true;
        self.vars.clear();
    }
    pub fn have_changed_path(&self) -> bool {
        self.saw_path || self.clear
    }
    fn maybe_saw_path(&mut self, key: &OsStr) {
        if !self.saw_path && key.to_os_string() == OsString::from("PATH") {
            self.saw_path = true;
        }
    }
}
<commit_msg>Simplify PATH key comparison<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(dead_code)]
#![unstable(feature = "process_internals", issue = "0")]

use ffi::{OsStr, OsString};
use env;
use collections::BTreeMap;
use alloc::borrow::Borrow;

pub trait EnvKey:
    From<OsString> + Into<OsString> +
    Borrow<OsStr> + Borrow<Self> + AsRef<OsStr> +
    Ord + Clone {}

// Implement a case-sensitive environment variable key
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct DefaultEnvKey(OsString);

impl From<OsString> for DefaultEnvKey {
    fn from(k: OsString) -> Self { DefaultEnvKey(k) }
}

impl From<DefaultEnvKey> for OsString {
    fn from(k: DefaultEnvKey) -> Self { k.0 }
}

impl Borrow<OsStr> for DefaultEnvKey {
    fn borrow(&self) -> &OsStr { &self.0 }
}

impl AsRef<OsStr> for DefaultEnvKey {
    fn as_ref(&self) -> &OsStr { &self.0 }
}

impl EnvKey for DefaultEnvKey {}

// Stores a set of changes to an environment
#[derive(Clone, Debug)]
pub struct CommandEnv<K> {
    clear: bool,
    saw_path: bool,
    vars: BTreeMap<K, Option<OsString>>
}

impl<K: EnvKey> Default for CommandEnv<K> {
    fn default() -> Self {
        CommandEnv {
            clear: false,
            saw_path: false,
            vars: Default::default()
        }
    }
}

impl<K: EnvKey> CommandEnv<K> {
    // Capture the current environment with these changes applied
    pub fn capture(&self) -> BTreeMap<K, OsString> {
        let mut result = BTreeMap::<K, OsString>::new();
        if !self.clear {
            for (k, v) in env::vars_os() {
                result.insert(k.into(), v);
            }
        }
        for (k, maybe_v) in &self.vars {
            if let &Some(ref v) = maybe_v {
                result.insert(k.clone(), v.clone());
            } else {
                result.remove(k);
            }
        }
        result
    }

    // Apply these changes directly to the current environment
    pub fn apply(&self) {
        if self.clear {
            for (k, _) in env::vars_os() {
                env::remove_var(k);
            }
        }
        for (key, maybe_val) in self.vars.iter() {
            if let &Some(ref val) = maybe_val {
                env::set_var(key, val);
            } else {
                env::remove_var(key);
            }
        }
    }

    pub fn is_unchanged(&self) -> bool {
        !self.clear && self.vars.is_empty()
    }

    pub fn capture_if_changed(&self) -> Option<BTreeMap<K, OsString>> {
        if self.is_unchanged() {
            None
        } else {
            Some(self.capture())
        }
    }

    // The following functions build up changes
    pub fn set(&mut self, key: &OsStr, value: &OsStr) {
        self.maybe_saw_path(&key);
        self.vars.insert(key.to_owned().into(), Some(value.to_owned()));
    }
    pub fn remove(&mut self, key: &OsStr) {
        self.maybe_saw_path(&key);
        if self.clear {
            self.vars.remove(key);
        } else {
            self.vars.insert(key.to_owned().into(), None);
        }
    }
    pub fn clear(&mut self) {
        self.clear = true;
        self.vars.clear();
    }
    pub fn have_changed_path(&self) -> bool {
        self.saw_path || self.clear
    }
    fn maybe_saw_path(&mut self, key: &OsStr) {
        if !self.saw_path && key == "PATH" {
            self.saw_path = true;
        }
    }
}
<|endoftext|>


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

#![allow(non_snake_case)]

// Error messages for EXXXX errors.
// Each message should start and end with a new line, and be wrapped to 80 characters.
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
register_long_diagnostics! {

E0533: r##"
The export_name attribute was badly formatted.

Erroneous code example:

```compile_fail,E0533
#[export_name] // error: export_name attribute has invalid format
pub fn something() {}

fn main() {}
```

The export_name attribute expects a string in order to determine the name of
the exported symbol. Example:

```
#[export_name = "some function"] // ok!
pub fn something() {}

fn main() {}
```
"##,

E0534: r##"
The inline attribute was badly used.

Erroneous code example:

```compile_fail,E0534
#[inline()] // error: expected one argument
pub fn something() {}

fn main() {}
```

The inline attribute can be used without arguments:

```
#[inline] // ok!
pub fn something() {}

fn main() {}
```

Or with arguments (and parens have to be used for this case!):

```
#[inline(always)] // ok!
pub fn something() {}

fn main() {}
```

For more information about the inline attribute, take a look here:
https://doc.rust-lang.org/reference.html#inline-attributes
"##,

E0535: r##"
An unknown argument was given to inline attribute.

Erroneous code example:

```compile_fail,E0535
#[inline(unknown)] // error: invalid argument
pub fn something() {}

fn main() {}
```

The inline attribute only knows two arguments:

 * always
 * never

All other arguments given to the inline attribute will return this error.
Example:

```
#[inline(never)] // ok!
pub fn something() {}

fn main() {}
```

For more information about the inline attribute, take a look here:
https://doc.rust-lang.org/reference.html#inline-attributes
"##,

E0536: r##"
No cfg-pattern was found for `not` statement.

Erroneous code example:

```compile_fail,E0536
#[cfg(not())] // error: expected 1 cfg-pattern
pub fn something() {}

pub fn main() {}
```

The `not` statement expects at least one cfg-pattern. Example:

```
#[cfg(not(target_os = "linux"))] // ok!
pub fn something() {}

pub fn main() {}
```

For more information about the cfg attribute, take a look here:
https://doc.rust-lang.org/reference.html#conditional-compilation
"##,

}

register_diagnostics! {
    E0537, // invalid predicate
    E0538, // multiple [same] items
    E0539, // incorrect meta item
    E0540, // multiple rustc_deprecated attributes
    E0541, // unknown meta item
    E0542, // missing 'since'
    E0543, // missing 'reason'
    E0544, // multiple stability levels
    E0545, // incorrect 'issue'
    E0546, // missing 'feature'
    E0547, // missing 'issue'
    E0548, // incorrect stability attribute type
    E0549, // rustc_deprecated attribute must be paired with either stable or unstable attribute
    E0550, // multiple deprecated attributes
    E0551, // incorrect meta item
    E0552, // unrecognized representation hint
    E0553, // unrecognized enum representation hint
    E0554, // #[feature] may not be used on the [] release channel
    E0555, // malformed feature attribute, expected #![feature(...)]
    E0556, // malformed feature, expected just one word
    E0557, // feature has been removed
}
<commit_msg>Add E0537 error explanation<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_snake_case)]

// Error messages for EXXXX errors.
// Each message should start and end with a new line, and be wrapped to 80 characters.
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
register_long_diagnostics! {

E0533: r##"
The export_name attribute was badly formatted.

Erroneous code example:

```compile_fail,E0533
#[export_name] // error: export_name attribute has invalid format
pub fn something() {}

fn main() {}
```

The export_name attribute expects a string in order to determine the name of
the exported symbol. Example:

```
#[export_name = "some function"] // ok!
pub fn something() {}

fn main() {}
```
"##,

E0534: r##"
The inline attribute was badly used.

Erroneous code example:

```compile_fail,E0534
#[inline()] // error: expected one argument
pub fn something() {}

fn main() {}
```

The inline attribute can be used without arguments:

```
#[inline] // ok!
pub fn something() {}

fn main() {}
```

Or with arguments (and parens have to be used for this case!):

```
#[inline(always)] // ok!
pub fn something() {}

fn main() {}
```

For more information about the inline attribute, take a look here:
https://doc.rust-lang.org/reference.html#inline-attributes
"##,

E0535: r##"
An unknown argument was given to inline attribute.

Erroneous code example:

```compile_fail,E0535
#[inline(unknown)] // error: invalid argument
pub fn something() {}

fn main() {}
```

The inline attribute only knows two arguments:

 * always
 * never

All other arguments given to the inline attribute will return this error.
Example:

```
#[inline(never)] // ok!
pub fn something() {}

fn main() {}
```

For more information about the inline attribute, take a look here:
https://doc.rust-lang.org/reference.html#inline-attributes
"##,

E0536: r##"
No cfg-pattern was found for `not` statement.

Erroneous code example:

```compile_fail,E0536
#[cfg(not())] // error: expected 1 cfg-pattern
pub fn something() {}

pub fn main() {}
```

The `not` statement expects at least one cfg-pattern. Example:

```
#[cfg(not(target_os = "linux"))] // ok!
pub fn something() {}

pub fn main() {}
```

For more information about the cfg attribute, take a look here:
https://doc.rust-lang.org/reference.html#conditional-compilation
"##,

E0537: r##"
A unknown predicate was used inside the cfg attribute.

Erroneous code example:

```compile_fail,E0537
#[cfg(unknown())] // error: invalid predicate `unknown`
pub fn something() {}

pub fn main() {}
```

There are only three predicates for the cfg attribute:

 * any
 * all
 * not

Example:

```
#[cfg(not(target_os = "linux"))] // ok!
pub fn something() {}

pub fn main() {}
```

For more information about the cfg attribute, take a look here:
https://doc.rust-lang.org/reference.html#conditional-compilation
"##,

}

register_diagnostics! {
    E0538, // multiple [same] items
    E0539, // incorrect meta item
    E0540, // multiple rustc_deprecated attributes
    E0541, // unknown meta item
    E0542, // missing 'since'
    E0543, // missing 'reason'
    E0544, // multiple stability levels
    E0545, // incorrect 'issue'
    E0546, // missing 'feature'
    E0547, // missing 'issue'
    E0548, // incorrect stability attribute type
    E0549, // rustc_deprecated attribute must be paired with either stable or unstable attribute
    E0550, // multiple deprecated attributes
    E0551, // incorrect meta item
    E0552, // unrecognized representation hint
    E0553, // unrecognized enum representation hint
    E0554, // #[feature] may not be used on the [] release channel
    E0555, // malformed feature attribute, expected #![feature(...)]
    E0556, // malformed feature, expected just one word
    E0557, // feature has been removed
}
<|endoftext|>


<commit_before>//! [GET /_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey}](https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-rooms-roomid-state-eventtype-statekey)

use ruma_api::ruma_api;
use ruma_events::{AnyStateEventContent, EventType};
use ruma_identifiers::RoomId;
use ruma_serde::{Outgoing, Raw};

ruma_api! {
    metadata: {
        description: "Get state events associated with a given key.",
        method: GET,
        name: "get_state_events_for_key",
        path: "/_matrix/client/r0/rooms/:room_id/state/:event_type/:state_key",
        rate_limited: false,
        authentication: AccessToken,
    }

    response: {
        /// The content of the state event.
        ///
        /// Since the inner type of the `Raw` does not implement `Deserialize`, you need to use
        /// `ruma_events::RawExt` to deserialize it.
        #[ruma_api(body)]
        pub content: Raw<AnyStateEventContent>,
    }

    error: crate::Error
}

/// Data for a request to the `get_state_events_for_key` API endpoint.
///
/// Get state events associated with a given key.
#[derive(Clone, Debug, Outgoing)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[incoming_derive(!Deserialize)]
pub struct Request<'a> {
    /// The room to look up the state for.
    pub room_id: &'a RoomId,

    /// The type of state to look up.
    pub event_type: EventType,

    /// The key of the state to look up.
    pub state_key: &'a str,
}

impl<'a> Request<'a> {
    /// Creates a new `Request` with the given room ID, event type and state key.
    pub fn new(room_id: &'a RoomId, event_type: EventType, state_key: &'a str) -> Self {
        Self { room_id, event_type, state_key }
    }
}

impl Response {
    /// Creates a new `Response` with the given content.
    pub fn new(content: Raw<AnyStateEventContent>) -> Self {
        Self { content }
    }
}

#[cfg(feature = "client")]
impl<'a> ruma_api::OutgoingRequest for Request<'a> {
    type EndpointError = crate::Error;
    type IncomingResponse = <Response as ruma_serde::Outgoing>::Incoming;

    const METADATA: ruma_api::Metadata = METADATA;

    fn try_into_http_request<T: Default + bytes::BufMut>(
        self,
        base_url: &str,
        access_token: ruma_api::SendAccessToken<'_>,
    ) -> Result<http::Request<T>, ruma_api::error::IntoHttpError> {
        use std::borrow::Cow;

        use http::header;
        use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};

        let mut url = format!(
            "{}/_matrix/client/r0/rooms/{}/state/{}",
            base_url.strip_suffix('/').unwrap_or(base_url),
            utf8_percent_encode(&self.room_id.to_string(), NON_ALPHANUMERIC),
            utf8_percent_encode(&self.event_type.to_string(), NON_ALPHANUMERIC)
        );

        if !self.state_key.is_empty() {
            url.push('/');
            url.push_str(&Cow::from(utf8_percent_encode(self.state_key, NON_ALPHANUMERIC)));
        }

        http::Request::builder()
            .method(http::Method::GET)
            .uri(url)
            .header(header::CONTENT_TYPE, "application/json")
            .header(
                header::AUTHORIZATION,
                format!(
                    "Bearer {}",
                    access_token
                        .get_required_for_endpoint()
                        .ok_or(ruma_api::error::IntoHttpError::NeedsAuthentication)?,
                ),
            )
            .body(T::default())
            .map_err(Into::into)
    }
}

#[cfg(feature = "server")]
impl ruma_api::IncomingRequest for IncomingRequest {
    type EndpointError = crate::Error;
    type OutgoingResponse = Response;

    const METADATA: ruma_api::Metadata = METADATA;

    fn try_from_http_request<T: AsRef<[u8]>>(
        request: http::Request<T>,
    ) -> Result<Self, ruma_api::error::FromHttpRequestError> {
        use std::convert::TryFrom;

        let path_segments: Vec<&str> = request.uri().path()[1..].split('/').collect();

        let room_id = {
            let decoded =
                percent_encoding::percent_decode(path_segments[4].as_bytes()).decode_utf8()?;

            Box::<RoomId>::try_from(&*decoded)?
        };

        let event_type = {
            let decoded =
                percent_encoding::percent_decode(path_segments[6].as_bytes()).decode_utf8()?;

            EventType::try_from(&*decoded)?
        };

        let state_key = match path_segments.get(7) {
            Some(segment) => {
                let decoded = percent_encoding::percent_decode(segment.as_bytes()).decode_utf8()?;

                String::try_from(&*decoded)?
            }
            None => "".into(),
        };

        Ok(Self { room_id, event_type, state_key })
    }
}
<commit_msg>client-api: Fix unnecessary allocation in URL construction<commit_after>//! [GET /_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey}](https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-rooms-roomid-state-eventtype-statekey)

use ruma_api::ruma_api;
use ruma_events::{AnyStateEventContent, EventType};
use ruma_identifiers::RoomId;
use ruma_serde::{Outgoing, Raw};

ruma_api! {
    metadata: {
        description: "Get state events associated with a given key.",
        method: GET,
        name: "get_state_events_for_key",
        path: "/_matrix/client/r0/rooms/:room_id/state/:event_type/:state_key",
        rate_limited: false,
        authentication: AccessToken,
    }

    response: {
        /// The content of the state event.
        ///
        /// Since the inner type of the `Raw` does not implement `Deserialize`, you need to use
        /// `ruma_events::RawExt` to deserialize it.
        #[ruma_api(body)]
        pub content: Raw<AnyStateEventContent>,
    }

    error: crate::Error
}

/// Data for a request to the `get_state_events_for_key` API endpoint.
///
/// Get state events associated with a given key.
#[derive(Clone, Debug, Outgoing)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[incoming_derive(!Deserialize)]
pub struct Request<'a> {
    /// The room to look up the state for.
    pub room_id: &'a RoomId,

    /// The type of state to look up.
    pub event_type: EventType,

    /// The key of the state to look up.
    pub state_key: &'a str,
}

impl<'a> Request<'a> {
    /// Creates a new `Request` with the given room ID, event type and state key.
    pub fn new(room_id: &'a RoomId, event_type: EventType, state_key: &'a str) -> Self {
        Self { room_id, event_type, state_key }
    }
}

impl Response {
    /// Creates a new `Response` with the given content.
    pub fn new(content: Raw<AnyStateEventContent>) -> Self {
        Self { content }
    }
}

#[cfg(feature = "client")]
impl<'a> ruma_api::OutgoingRequest for Request<'a> {
    type EndpointError = crate::Error;
    type IncomingResponse = <Response as ruma_serde::Outgoing>::Incoming;

    const METADATA: ruma_api::Metadata = METADATA;

    fn try_into_http_request<T: Default + bytes::BufMut>(
        self,
        base_url: &str,
        access_token: ruma_api::SendAccessToken<'_>,
    ) -> Result<http::Request<T>, ruma_api::error::IntoHttpError> {
        use std::borrow::Cow;

        use http::header;
        use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};

        let mut url = format!(
            "{}/_matrix/client/r0/rooms/{}/state/{}",
            base_url.strip_suffix('/').unwrap_or(base_url),
            utf8_percent_encode(self.room_id.as_str(), NON_ALPHANUMERIC),
            utf8_percent_encode(self.event_type.as_str(), NON_ALPHANUMERIC)
        );

        if !self.state_key.is_empty() {
            url.push('/');
            url.push_str(&Cow::from(utf8_percent_encode(self.state_key, NON_ALPHANUMERIC)));
        }

        http::Request::builder()
            .method(http::Method::GET)
            .uri(url)
            .header(header::CONTENT_TYPE, "application/json")
            .header(
                header::AUTHORIZATION,
                format!(
                    "Bearer {}",
                    access_token
                        .get_required_for_endpoint()
                        .ok_or(ruma_api::error::IntoHttpError::NeedsAuthentication)?,
                ),
            )
            .body(T::default())
            .map_err(Into::into)
    }
}

#[cfg(feature = "server")]
impl ruma_api::IncomingRequest for IncomingRequest {
    type EndpointError = crate::Error;
    type OutgoingResponse = Response;

    const METADATA: ruma_api::Metadata = METADATA;

    fn try_from_http_request<T: AsRef<[u8]>>(
        request: http::Request<T>,
    ) -> Result<Self, ruma_api::error::FromHttpRequestError> {
        use std::convert::TryFrom;

        let path_segments: Vec<&str> = request.uri().path()[1..].split('/').collect();

        let room_id = {
            let decoded =
                percent_encoding::percent_decode(path_segments[4].as_bytes()).decode_utf8()?;

            Box::<RoomId>::try_from(&*decoded)?
        };

        let event_type = {
            let decoded =
                percent_encoding::percent_decode(path_segments[6].as_bytes()).decode_utf8()?;

            EventType::try_from(&*decoded)?
        };

        let state_key = match path_segments.get(7) {
            Some(segment) => {
                let decoded = percent_encoding::percent_decode(segment.as_bytes()).decode_utf8()?;

                String::try_from(&*decoded)?
            }
            None => "".into(),
        };

        Ok(Self { room_id, event_type, state_key })
    }
}
<|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/. */

/*

    An example of how to implement the Compositor trait that
    allows picture caching surfaces to be composited by the operating
    system.

    The current example supports DirectComposite on Windows only.

 */

use euclid::Angle;
use gleam::gl;
use std::ffi::CString;
use std::sync::mpsc;
use webrender::api::*;
use webrender::api::units::*;
#[cfg(target_os = "windows")]
use compositor_windows as compositor;
use std::{env, f32, process};

// A very hacky integration with DirectComposite. It proxies calls from the compositor
// interface to a simple C99 library which does the DirectComposition / D3D11 / ANGLE
// interfacing. This is a very unsafe impl due to the way the window pointer is passed
// around!
struct DirectCompositeInterface {
    window: *mut compositor::Window,
}

impl DirectCompositeInterface {
    fn new(window: *mut compositor::Window) -> Self {
        DirectCompositeInterface {
            window,
        }
    }
}

impl webrender::Compositor for DirectCompositeInterface {
    fn create_surface(
        &mut self,
        id: webrender::NativeSurfaceId,
        tile_size: DeviceIntSize,
        is_opaque: bool,
    ) {
        compositor::create_surface(
            self.window,
            id.0,
            tile_size.width,
            tile_size.height,
            is_opaque,
        );
    }

    fn destroy_surface(
        &mut self,
        id: webrender::NativeSurfaceId,
    ) {
        compositor::destroy_surface(self.window, id.0);
    }

    fn create_tile(
        &mut self,
        id: webrender::NativeTileId,
    ) {
        compositor::create_tile(
            self.window,
            id.surface_id.0,
            id.x,
            id.y,
        );
    }

    fn destroy_tile(
        &mut self,
        id: webrender::NativeTileId,
    ) {
        compositor::destroy_tile(
            self.window,
            id.surface_id.0,
            id.x,
            id.y,
        );
    }

    fn bind(
        &mut self,
        id: webrender::NativeTileId,
        dirty_rect: DeviceIntRect,
    ) -> webrender::NativeSurfaceInfo {
        let (fbo_id, x, y) = compositor::bind_surface(
            self.window,
            id.surface_id.0,
            id.x,
            id.y,
            dirty_rect.origin.x,
            dirty_rect.origin.y,
            dirty_rect.size.width,
            dirty_rect.size.height,
        );

        webrender::NativeSurfaceInfo {
            origin: DeviceIntPoint::new(x, y),
            fbo_id,
        }
    }

    fn unbind(&mut self) {
        compositor::unbind_surface(self.window);
    }

    fn begin_frame(&mut self) {
        compositor::begin_transaction(self.window);
    }

    fn add_surface(
        &mut self,
        id: webrender::NativeSurfaceId,
        position: DeviceIntPoint,
        clip_rect: DeviceIntRect,
    ) {
        compositor::add_surface(
            self.window,
            id.0,
            position.x,
            position.y,
            clip_rect.origin.x,
            clip_rect.origin.y,
            clip_rect.size.width,
            clip_rect.size.height,
        );
    }

    fn end_frame(&mut self) {
        compositor::end_transaction(self.window);
    }
}

// Simplisitic implementation of the WR notifier interface to know when a frame
// has been prepared and can be rendered.
struct Notifier {
    tx: mpsc::Sender<()>,
}

impl Notifier {
    fn new(tx: mpsc::Sender<()>) -> Self {
        Notifier {
            tx,
        }
    }
}

impl RenderNotifier for Notifier {
    fn clone(&self) -> Box<dyn RenderNotifier> {
        Box::new(Notifier {
            tx: self.tx.clone()
        })
    }

    fn wake_up(&self, _composite_needed: bool) {
    }

    fn new_frame_ready(&self,
                       _: DocumentId,
                       _scrolled: bool,
                       _composite_needed: bool,
                       _render_time: Option<u64>) {
        self.tx.send(()).ok();
    }
}

fn push_rotated_rect(
    builder: &mut DisplayListBuilder,
    rect: LayoutRect,
    color: ColorF,
    spatial_id: SpatialId,
    root_pipeline_id: PipelineId,
    angle: f32,
    time: f32,
) {
    let color = color.scale_rgb(time);
    let rotation = LayoutTransform::create_rotation(
        0.0,
        0.0,
        1.0,
        Angle::radians(2.0 * std::f32::consts::PI * angle),
    );
    let transform_origin = LayoutVector3D::new(
        rect.origin.x + rect.size.width * 0.5,
        rect.origin.y + rect.size.height * 0.5,
        0.0,
    );
    let transform = rotation
        .pre_translate(-transform_origin)
        .post_translate(transform_origin);
    let spatial_id = builder.push_reference_frame(
        LayoutPoint::zero(),
        spatial_id,
        TransformStyle::Flat,
        PropertyBinding::Value(transform),
        ReferenceFrameKind::Transform,
    );
    builder.push_rect(
        &CommonItemProperties::new(
            rect,
            SpaceAndClipInfo {
                spatial_id,
                clip_id: ClipId::root(root_pipeline_id),
            },
        ),
        rect,
        color,
    );
}

fn build_display_list(
    builder: &mut DisplayListBuilder,
    scroll_id: ExternalScrollId,
    root_pipeline_id: PipelineId,
    layout_size: LayoutSize,
    time: f32,
    invalidations: Invalidations,
) {
    let size_factor = match invalidations {
        Invalidations::Small => 0.1,
        Invalidations::Large | Invalidations::Scrolling => 1.0,
    };

    let fixed_space_info = SpaceAndClipInfo {
        spatial_id: SpatialId::root_scroll_node(root_pipeline_id),
        clip_id: ClipId::root(root_pipeline_id),
    };

    let scroll_space_info = builder.define_scroll_frame(
        &fixed_space_info,
        scroll_id,
        LayoutRect::new(LayoutPoint::zero(), layout_size),
        LayoutRect::new(LayoutPoint::zero(), layout_size),
        ScrollSensitivity::Script,
        LayoutVector2D::zero(),
    );

    builder.push_rect(
        &CommonItemProperties::new(
            LayoutRect::new(LayoutPoint::zero(), layout_size).inflate(-10.0, -10.0),
            fixed_space_info,
        ),
        LayoutRect::new(LayoutPoint::zero(), layout_size).inflate(-10.0, -10.0),
        ColorF::new(0.8, 0.8, 0.8, 1.0),
    );

    push_rotated_rect(
        builder,
        LayoutRect::new(
            LayoutPoint::new(100.0, 100.0),
            LayoutSize::new(size_factor * 400.0, size_factor * 400.0),
        ),
        ColorF::new(1.0, 0.0, 0.0, 1.0),
        scroll_space_info.spatial_id,
        root_pipeline_id,
        time,
        time,
    );

    push_rotated_rect(
        builder,
        LayoutRect::new(
            LayoutPoint::new(800.0, 100.0),
            LayoutSize::new(size_factor * 100.0, size_factor * 600.0),
        ),
        ColorF::new(0.0, 1.0, 0.0, 1.0),
        fixed_space_info.spatial_id,
        root_pipeline_id,
        0.2,
        time,
    );

    push_rotated_rect(
        builder,
        LayoutRect::new(
            LayoutPoint::new(700.0, 200.0),
            LayoutSize::new(size_factor * 300.0, size_factor * 300.0),
        ),
        ColorF::new(0.0, 0.0, 1.0, 1.0),
        scroll_space_info.spatial_id,
        root_pipeline_id,
        0.1,
        time,
    );
}

#[derive(Debug, Copy, Clone)]
enum Invalidations {
    Large,
    Small,
    Scrolling,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
enum Sync {
    None = 0,
    Swap = 1,
    Commit = 2,
    Flush = 3,
    Query = 4,
}

fn main() {
    let args: Vec<String> = env::args().collect();

    if args.len() != 6 {
        println!("USAGE: compositor [native|none] [small|large|scroll] [none|swap|commit|flush|query] width height");
        process::exit(0);
    }

    let enable_compositor = match args[1].parse::<String>().unwrap().as_str() {
        "native" => true,
        "none" => false,
        _ => panic!("invalid compositor [native, none]"),
    };

    let inv_mode = match args[2].parse::<String>().unwrap().as_str() {
        "small" => Invalidations::Small,
        "large" => Invalidations::Large,
        "scroll" => Invalidations::Scrolling,
        _ => panic!("invalid invalidations [small, large, scroll]"),
    };

    let sync_mode = match args[3].parse::<String>().unwrap().as_str() {
        "none" => Sync::None,
        "swap" => Sync::Swap,
        "commit" => Sync::Commit,
        "flush" => Sync::Flush,
        "query" => Sync::Query,
        _ => panic!("invalid sync mode [none, swap, commit, flush, query]"),
    };

    let width = args[4].parse().unwrap();
    let height = args[5].parse().unwrap();
    let device_size = DeviceIntSize::new(width, height);

    // Load GL, construct WR and the native compositor interface.
    let window = compositor::create_window(
        device_size.width,
        device_size.height,
        enable_compositor,
        sync_mode as i32,
    );
    let debug_flags = DebugFlags::empty();
    let compositor_config = if enable_compositor {
        webrender::CompositorConfig::Native {
            max_update_rects: 1,
            compositor: Box::new(DirectCompositeInterface::new(window)),
        }
    } else {
        webrender::CompositorConfig::Draw {
            max_partial_present_rects: 0,
        }
    };
    let opts = webrender::RendererOptions {
        clear_color: Some(ColorF::new(1.0, 1.0, 1.0, 1.0)),
        debug_flags,
        compositor_config,
        ..webrender::RendererOptions::default()
    };
    let (tx, rx) = mpsc::channel();
    let notifier = Box::new(Notifier::new(tx));
    let gl = unsafe {
        gl::GlesFns::load_with(
            |symbol| {
                let symbol = CString::new(symbol).unwrap();
                let ptr = compositor::get_proc_address(symbol.as_ptr());
                ptr
            }
        )
    };
    let (mut renderer, sender) = webrender::Renderer::new(
        gl.clone(),
        notifier,
        opts,
        None,
    ).unwrap();
    let api = sender.create_api();
    let document_id = api.add_document(device_size);
    let device_pixel_ratio = 1.0;
    let mut current_epoch = Epoch(0);
    let root_pipeline_id = PipelineId(0, 0);
    let layout_size = device_size.to_f32() / euclid::Scale::new(device_pixel_ratio);
    let mut time = 0.0;
    let scroll_id = ExternalScrollId(3, root_pipeline_id);

    // Kick off first transaction which will mean we get a notify below to build the DL and render.
    let mut txn = Transaction::new();
    txn.set_root_pipeline(root_pipeline_id);

    if let Invalidations::Scrolling = inv_mode {
        let mut root_builder = DisplayListBuilder::new(root_pipeline_id);

        build_display_list(
            &mut root_builder,
            scroll_id,
            root_pipeline_id,
            layout_size,
            1.0,
            inv_mode,
        );

        txn.set_display_list(
            current_epoch,
            None,
            layout_size,
            root_builder.finalize(),
            true,
        );
    }

    txn.generate_frame(0);
    api.send_transaction(document_id, txn);

    // Tick the compositor (in this sample, we don't block on UI events)
    while compositor::tick(window) {
        // If there is a new frame ready to draw
        if let Ok(..) = rx.try_recv() {
            // Update and render. This will invoke the native compositor interface implemented above
            // as required.
            renderer.update();
            renderer.render(device_size).unwrap();
            let _ = renderer.flush_pipeline_info();

            // Construct a simple display list that can be drawn and composited by DC.
            let mut txn = Transaction::new();

            match inv_mode {
                Invalidations::Small | Invalidations::Large => {
                    let mut root_builder = DisplayListBuilder::new(root_pipeline_id);

                    build_display_list(
                        &mut root_builder,
                        scroll_id,
                        root_pipeline_id,
                        layout_size,
                        time,
                        inv_mode,
                    );

                    txn.set_display_list(
                        current_epoch,
                        None,
                        layout_size,
                        root_builder.finalize(),
                        true,
                    );
                }
                Invalidations::Scrolling => {
                    let d = 0.5 - 0.5 * (2.0 * f32::consts::PI * 5.0 * time).cos();
                    txn.scroll_node_with_id(
                        LayoutPoint::new(0.0, (d * 100.0).round()),
                        scroll_id,
                        ScrollClamping::NoClamping,
                    );
                }
            }

            txn.generate_frame(0);
            api.send_transaction(document_id, txn);
            current_epoch.0 += 1;
            time += 0.001;
            if time > 1.0 {
                time = 0.0;
            }

            // This does nothing when native compositor is enabled
            compositor::swap_buffers(window);
        }
    }

    renderer.deinit();
    compositor::destroy_window(window);
}
<commit_msg>Bug 1690145 - Get the example compositor building again r=jrmuizel<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/. */

/*

    An example of how to implement the Compositor trait that
    allows picture caching surfaces to be composited by the operating
    system.

    The current example supports DirectComposite on Windows only.

 */

use euclid::Angle;
use gleam::gl;
use std::ffi::CString;
use std::sync::mpsc;
use webrender::{CompositorSurfaceTransform, Transaction, api::*, euclid::point2};
use webrender::api::units::*;
#[cfg(target_os = "windows")]
use compositor_windows as compositor;
use std::{env, f32, process};

// A very hacky integration with DirectComposite. It proxies calls from the compositor
// interface to a simple C99 library which does the DirectComposition / D3D11 / ANGLE
// interfacing. This is a very unsafe impl due to the way the window pointer is passed
// around!
struct DirectCompositeInterface {
    window: *mut compositor::Window,
}

impl DirectCompositeInterface {
    fn new(window: *mut compositor::Window) -> Self {
        DirectCompositeInterface {
            window,
        }
    }
}

impl webrender::Compositor for DirectCompositeInterface {
    fn create_surface(
        &mut self,
        id: webrender::NativeSurfaceId,
        _virtual_offset: DeviceIntPoint,
        tile_size: DeviceIntSize,
        is_opaque: bool,
    ) {
        compositor::create_surface(
            self.window,
            id.0,
            tile_size.width,
            tile_size.height,
            is_opaque,
        );
    }

    fn destroy_surface(
        &mut self,
        id: webrender::NativeSurfaceId,
    ) {
        compositor::destroy_surface(self.window, id.0);
    }

    fn create_tile(
        &mut self,
        id: webrender::NativeTileId,
    ) {
        compositor::create_tile(
            self.window,
            id.surface_id.0,
            id.x,
            id.y,
        );
    }

    fn destroy_tile(
        &mut self,
        id: webrender::NativeTileId,
    ) {
        compositor::destroy_tile(
            self.window,
            id.surface_id.0,
            id.x,
            id.y,
        );
    }

    fn bind(
        &mut self,
        id: webrender::NativeTileId,
        dirty_rect: DeviceIntRect,
        _valid_rect: DeviceIntRect,
    ) -> webrender::NativeSurfaceInfo {
        let (fbo_id, x, y) = compositor::bind_surface(
            self.window,
            id.surface_id.0,
            id.x,
            id.y,
            dirty_rect.origin.x,
            dirty_rect.origin.y,
            dirty_rect.size.width,
            dirty_rect.size.height,
        );

        webrender::NativeSurfaceInfo {
            origin: DeviceIntPoint::new(x, y),
            fbo_id,
        }
    }

    fn unbind(&mut self) {
        compositor::unbind_surface(self.window);
    }

    fn begin_frame(&mut self) {
        compositor::begin_transaction(self.window);
    }

    fn add_surface(
        &mut self,
        id: webrender::NativeSurfaceId,
        transform: CompositorSurfaceTransform,
        clip_rect: DeviceIntRect,
        _image_rendering: ImageRendering,
    ) {
        compositor::add_surface(
            self.window,
            id.0,
            transform.transform_point2d(point2(0., 0.)).unwrap().x as i32,
            transform.transform_point2d(point2(0., 0.)).unwrap().y as i32,
            clip_rect.origin.x,
            clip_rect.origin.y,
            clip_rect.size.width,
            clip_rect.size.height,
        );
    }

    fn end_frame(&mut self) {
        compositor::end_transaction(self.window);
    }
    fn create_external_surface(&mut self, _: webrender::NativeSurfaceId, _: bool) { todo!() }

    fn attach_external_image(
        &mut self,
        _id: webrender::NativeSurfaceId,
        _external_image: ExternalImageId
    ) {
        todo!()
    }

    fn enable_native_compositor(&mut self, _enable: bool) {
        todo!()
    }

    fn deinit(&mut self) {
        todo!()
    }

    fn get_capabilities(&self) -> webrender::CompositorCapabilities {
        webrender::CompositorCapabilities { virtual_surface_size: 1024 * 1024 }
    }

    fn invalidate_tile(
        &mut self,
        _id: webrender::NativeTileId,
        _valid_rect: DeviceIntRect,
    ) {}

    fn start_compositing(
        &mut self,
        _dirty_rects: &[DeviceIntRect],
        _opaque_rects: &[DeviceIntRect],
    ) {}
}

// Simplisitic implementation of the WR notifier interface to know when a frame
// has been prepared and can be rendered.
struct Notifier {
    tx: mpsc::Sender<()>,
}

impl Notifier {
    fn new(tx: mpsc::Sender<()>) -> Self {
        Notifier {
            tx,
        }
    }
}

impl RenderNotifier for Notifier {
    fn clone(&self) -> Box<dyn RenderNotifier> {
        Box::new(Notifier {
            tx: self.tx.clone()
        })
    }

    fn wake_up(&self, _composite_needed: bool) {
    }

    fn new_frame_ready(&self,
                       _: DocumentId,
                       _scrolled: bool,
                       _composite_needed: bool,
                       _render_time: Option<u64>) {
        self.tx.send(()).ok();
    }
}

fn push_rotated_rect(
    builder: &mut DisplayListBuilder,
    rect: LayoutRect,
    color: ColorF,
    spatial_id: SpatialId,
    root_pipeline_id: PipelineId,
    angle: f32,
    time: f32,
) {
    let color = color.scale_rgb(time);
    let rotation = LayoutTransform::rotation(
        0.0,
        0.0,
        1.0,
        Angle::radians(2.0 * std::f32::consts::PI * angle),
    );
    let transform_origin = LayoutVector3D::new(
        rect.origin.x + rect.size.width * 0.5,
        rect.origin.y + rect.size.height * 0.5,
        0.0,
    );
    let transform = rotation
        .pre_translate(-transform_origin)
        .then_translate(transform_origin);
    let spatial_id = builder.push_reference_frame(
        LayoutPoint::zero(),
        spatial_id,
        TransformStyle::Flat,
        PropertyBinding::Value(transform),
        ReferenceFrameKind::Transform,
    );
    builder.push_rect(
        &CommonItemProperties::new(
            rect,
            SpaceAndClipInfo {
                spatial_id,
                clip_id: ClipId::root(root_pipeline_id),
            },
        ),
        rect,
        color,
    );
}

fn build_display_list(
    builder: &mut DisplayListBuilder,
    scroll_id: ExternalScrollId,
    root_pipeline_id: PipelineId,
    layout_size: LayoutSize,
    time: f32,
    invalidations: Invalidations,
) {
    let size_factor = match invalidations {
        Invalidations::Small => 0.1,
        Invalidations::Large | Invalidations::Scrolling => 1.0,
    };

    let fixed_space_info = SpaceAndClipInfo {
        spatial_id: SpatialId::root_scroll_node(root_pipeline_id),
        clip_id: ClipId::root(root_pipeline_id),
    };

    let scroll_space_info = builder.define_scroll_frame(
        &fixed_space_info,
        scroll_id,
        LayoutRect::new(LayoutPoint::zero(), layout_size),
        LayoutRect::new(LayoutPoint::zero(), layout_size),
        ScrollSensitivity::Script,
        LayoutVector2D::zero(),
    );

    builder.push_rect(
        &CommonItemProperties::new(
            LayoutRect::new(LayoutPoint::zero(), layout_size).inflate(-10.0, -10.0),
            fixed_space_info,
        ),
        LayoutRect::new(LayoutPoint::zero(), layout_size).inflate(-10.0, -10.0),
        ColorF::new(0.8, 0.8, 0.8, 1.0),
    );

    push_rotated_rect(
        builder,
        LayoutRect::new(
            LayoutPoint::new(100.0, 100.0),
            LayoutSize::new(size_factor * 400.0, size_factor * 400.0),
        ),
        ColorF::new(1.0, 0.0, 0.0, 1.0),
        scroll_space_info.spatial_id,
        root_pipeline_id,
        time,
        time,
    );

    push_rotated_rect(
        builder,
        LayoutRect::new(
            LayoutPoint::new(800.0, 100.0),
            LayoutSize::new(size_factor * 100.0, size_factor * 600.0),
        ),
        ColorF::new(0.0, 1.0, 0.0, 1.0),
        fixed_space_info.spatial_id,
        root_pipeline_id,
        0.2,
        time,
    );

    push_rotated_rect(
        builder,
        LayoutRect::new(
            LayoutPoint::new(700.0, 200.0),
            LayoutSize::new(size_factor * 300.0, size_factor * 300.0),
        ),
        ColorF::new(0.0, 0.0, 1.0, 1.0),
        scroll_space_info.spatial_id,
        root_pipeline_id,
        0.1,
        time,
    );

    push_rotated_rect(
        builder,
        LayoutRect::new(
            LayoutPoint::new(100.0, 600.0),
            LayoutSize::new(size_factor * 400.0, size_factor * 400.0),
        ),
        ColorF::new(1.0, 1.0, 0.0, 1.0),
        scroll_space_info.spatial_id,
        root_pipeline_id,
        time,
        time,
    );

    push_rotated_rect(
        builder,
        LayoutRect::new(
            LayoutPoint::new(700.0, 600.0),
            LayoutSize::new(size_factor * 400.0, size_factor * 400.0),
        ),
        ColorF::new(0.0, 1.0, 1.0, 1.0),
        scroll_space_info.spatial_id,
        root_pipeline_id,
        time,
        time,
    );
}

#[derive(Debug, Copy, Clone)]
enum Invalidations {
    Large,
    Small,
    Scrolling,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
enum Sync {
    None = 0,
    Swap = 1,
    Commit = 2,
    Flush = 3,
    Query = 4,
}

fn main() {
    let args: Vec<String> = env::args().collect();

    if args.len() != 6 {
        println!("USAGE: compositor [native|none] [small|large|scroll] [none|swap|commit|flush|query] width height");
        process::exit(0);
    }

    let enable_compositor = match args[1].parse::<String>().unwrap().as_str() {
        "native" => true,
        "none" => false,
        _ => panic!("invalid compositor [native, none]"),
    };

    let inv_mode = match args[2].parse::<String>().unwrap().as_str() {
        "small" => Invalidations::Small,
        "large" => Invalidations::Large,
        "scroll" => Invalidations::Scrolling,
        _ => panic!("invalid invalidations [small, large, scroll]"),
    };

    let sync_mode = match args[3].parse::<String>().unwrap().as_str() {
        "none" => Sync::None,
        "swap" => Sync::Swap,
        "commit" => Sync::Commit,
        "flush" => Sync::Flush,
        "query" => Sync::Query,
        _ => panic!("invalid sync mode [none, swap, commit, flush, query]"),
    };

    let width = args[4].parse().unwrap();
    let height = args[5].parse().unwrap();
    let device_size = DeviceIntSize::new(width, height);

    // Load GL, construct WR and the native compositor interface.
    let window = compositor::create_window(
        device_size.width,
        device_size.height,
        enable_compositor,
        sync_mode as i32,
    );
    let debug_flags = DebugFlags::empty();
    let compositor_config = if enable_compositor {
        webrender::CompositorConfig::Native {
            max_update_rects: 1,
            compositor: Box::new(DirectCompositeInterface::new(window)),
        }
    } else {
        webrender::CompositorConfig::Draw {
            max_partial_present_rects: 0,
            draw_previous_partial_present_regions: false,
            partial_present: None,
        }
    };
    let opts = webrender::RendererOptions {
        clear_color: Some(ColorF::new(1.0, 1.0, 1.0, 1.0)),
        debug_flags,
        compositor_config,
        ..webrender::RendererOptions::default()
    };
    let (tx, rx) = mpsc::channel();
    let notifier = Box::new(Notifier::new(tx));
    let gl = unsafe {
        gl::GlesFns::load_with(
            |symbol| {
                let symbol = CString::new(symbol).unwrap();
                let ptr = compositor::get_proc_address(symbol.as_ptr());
                ptr
            }
        )
    };
    let (mut renderer, sender) = webrender::Renderer::new(
        gl.clone(),
        notifier,
        opts,
        None,
    ).unwrap();
    let mut api = sender.create_api();
    let document_id = api.add_document(device_size);
    let device_pixel_ratio = 1.0;
    let mut current_epoch = Epoch(0);
    let root_pipeline_id = PipelineId(0, 0);
    let layout_size = device_size.to_f32() / euclid::Scale::new(device_pixel_ratio);
    let mut time = 0.0;
    let scroll_id = ExternalScrollId(3, root_pipeline_id);

    // Kick off first transaction which will mean we get a notify below to build the DL and render.
    let mut txn = Transaction::new();
    txn.set_root_pipeline(root_pipeline_id);

    if let Invalidations::Scrolling = inv_mode {
        let mut root_builder = DisplayListBuilder::new(root_pipeline_id);

        build_display_list(
            &mut root_builder,
            scroll_id,
            root_pipeline_id,
            layout_size,
            1.0,
            inv_mode,
        );

        txn.set_display_list(
            current_epoch,
            None,
            layout_size,
            root_builder.finalize(),
            true,
        );
    }

    txn.generate_frame(0);
    api.send_transaction(document_id, txn);

    // Tick the compositor (in this sample, we don't block on UI events)
    while compositor::tick(window) {
        // If there is a new frame ready to draw
        if let Ok(..) = rx.try_recv() {
            // Update and render. This will invoke the native compositor interface implemented above
            // as required.
            renderer.update();
            renderer.render(device_size, 0).unwrap();
            let _ = renderer.flush_pipeline_info();

            // Construct a simple display list that can be drawn and composited by DC.
            let mut txn = Transaction::new();

            match inv_mode {
                Invalidations::Small | Invalidations::Large => {
                    let mut root_builder = DisplayListBuilder::new(root_pipeline_id);

                    build_display_list(
                        &mut root_builder,
                        scroll_id,
                        root_pipeline_id,
                        layout_size,
                        time,
                        inv_mode,
                    );

                    txn.set_display_list(
                        current_epoch,
                        None,
                        layout_size,
                        root_builder.finalize(),
                        true,
                    );
                }
                Invalidations::Scrolling => {
                    let d = 0.5 - 0.5 * (2.0 * f32::consts::PI * 5.0 * time).cos();
                    txn.scroll_node_with_id(
                        LayoutPoint::new(0.0, (d * 100.0).round()),
                        scroll_id,
                        ScrollClamping::NoClamping,
                    );
                }
            }

            txn.generate_frame(0);
            api.send_transaction(document_id, txn);
            current_epoch.0 += 1;
            time += 0.001;
            if time > 1.0 {
                time = 0.0;
            }

            // This does nothing when native compositor is enabled
            compositor::swap_buffers(window);
        }
    }

    renderer.deinit();
    compositor::destroy_window(window);
}
<|endoftext|>


<commit_before>use crate::syntax::check::Check;
use crate::syntax::{error, Api, Pair};
use proc_macro2::Ident;

fn check(cx: &mut Check, ident: &Ident) {
    let s = ident.to_string();
    if s.starts_with("cxxbridge") {
        cx.error(ident, error::CXXBRIDGE_RESERVED.msg);
    }
    if s.contains("__") {
        cx.error(ident, error::DOUBLE_UNDERSCORE.msg);
    }
}

fn check_ident(cx: &mut Check, name: &Pair) {
    for segment in &name.namespace {
        check(cx, segment);
    }
    check(cx, &name.cxx);
}

pub(crate) fn check_all(cx: &mut Check, apis: &[Api]) {
    for api in apis {
        match api {
            Api::Include(_) | Api::Impl(_) => {}
            Api::Struct(strct) => {
                check_ident(cx, &strct.name);
                for field in &strct.fields {
                    check_ident(cx, &field.name);
                }
            }
            Api::Enum(enm) => {
                check_ident(cx, &enm.name);
                for variant in &enm.variants {
                    check(cx, &variant.name.rust);
                }
            }
            Api::CxxType(ety) | Api::RustType(ety) => {
                check_ident(cx, &ety.name);
            }
            Api::CxxFunction(efn) | Api::RustFunction(efn) => {
                check(cx, &efn.name.rust);
                for arg in &efn.args {
                    check_ident(cx, &arg.name);
                }
            }
            Api::TypeAlias(alias) => {
                check_ident(cx, &alias.name);
            }
        }
    }
}
<commit_msg>Check rust idents for cxxbridge prefix<commit_after>use crate::syntax::check::Check;
use crate::syntax::{error, Api, Pair};
use proc_macro2::Ident;

fn check(cx: &mut Check, name: &Pair) {
    for segment in &name.namespace {
        check_cxx_ident(cx, segment);
    }
    check_cxx_ident(cx, &name.cxx);
    check_rust_ident(cx, &name.rust);

    fn check_cxx_ident(cx: &mut Check, ident: &Ident) {
        let s = ident.to_string();
        if s.starts_with("cxxbridge") {
            cx.error(ident, error::CXXBRIDGE_RESERVED.msg);
        }
        if s.contains("__") {
            cx.error(ident, error::DOUBLE_UNDERSCORE.msg);
        }
    }

    fn check_rust_ident(cx: &mut Check, ident: &Ident) {
        let s = ident.to_string();
        if s.starts_with("cxxbridge") {
            cx.error(ident, error::CXXBRIDGE_RESERVED.msg);
        }
    }
}

pub(crate) fn check_all(cx: &mut Check, apis: &[Api]) {
    for api in apis {
        match api {
            Api::Include(_) | Api::Impl(_) => {}
            Api::Struct(strct) => {
                check(cx, &strct.name);
                for field in &strct.fields {
                    check(cx, &field.name);
                }
            }
            Api::Enum(enm) => {
                check(cx, &enm.name);
                for variant in &enm.variants {
                    check(cx, &variant.name);
                }
            }
            Api::CxxType(ety) | Api::RustType(ety) => {
                check(cx, &ety.name);
            }
            Api::CxxFunction(efn) | Api::RustFunction(efn) => {
                check(cx, &efn.name);
                for arg in &efn.args {
                    check(cx, &arg.name);
                }
            }
            Api::TypeAlias(alias) => {
                check(cx, &alias.name);
            }
        }
    }
}
<|endoftext|>


<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # RangeDfa
//!
//! A DFA that matches transitions against symbol ranges.
//!

use super::dfa_builder::*;
use super::pattern_matcher::*;
use super::symbol_range::*;
use super::state_machine::*;

///
/// DFA that decides on transitions based on non-overlapping, sorted lists of input symbols
///
#[derive(Debug)]
pub struct SymbolRangeDfa<InputSymbol: PartialOrd, OutputSymbol> {
    //
    // Indexes of where each state starts in the transition table (it ends at the start of the next state)
    //
    states: Vec<usize>,

    //
    // The transitions making up this DFA
    //
    transitions: Vec<(SymbolRange<InputSymbol>, StateId)>,

    //
    // The accepting symbol for each state
    //
    accept: Vec<Option<OutputSymbol>>
}

///
/// DFA builder that creates RangeDfas
///
pub struct SymbolRangeDfaBuilder<InputSymbol: PartialOrd, OutputSymbol> {
    states: Vec<usize>,
    transitions: Vec<(SymbolRange<InputSymbol>, StateId)>,
    accept: Vec<Option<OutputSymbol>>
}

impl<InputSymbol: PartialOrd, OutputSymbol> SymbolRangeDfaBuilder<InputSymbol, OutputSymbol> {
    pub fn new() -> SymbolRangeDfaBuilder<InputSymbol, OutputSymbol> {
        SymbolRangeDfaBuilder { states: vec![], transitions: vec![], accept: vec![] }
    }
}

impl<InputSymbol: PartialOrd, OutputSymbol> DfaBuilder<SymbolRange<InputSymbol>, OutputSymbol, SymbolRangeDfa<InputSymbol, OutputSymbol>> for SymbolRangeDfaBuilder<InputSymbol, OutputSymbol> {
    fn start_state(&mut self) {
        // Begin the next state
        self.states.push(self.transitions.len());
        self.accept.push(None);
    }

    fn transition(&mut self, symbol: SymbolRange<InputSymbol>, target_state: StateId) {
        self.transitions.push((symbol, target_state));
    }

    fn accept(&mut self, symbol: OutputSymbol) {
        self.accept.pop();
        self.accept.push(Some(symbol));
    }

    fn build(self) -> SymbolRangeDfa<InputSymbol, OutputSymbol> {
        // Turn into a RangeDfa
        let mut result = SymbolRangeDfa { states: self.states, transitions: self.transitions, accept: self.accept };

        // 'Cap' the last state so we don't need to special-case it later
        // ie, we can always find the index of the last symbol by looking at the next state and don't need to handle the final state differently
        result.states.push(result.transitions.len());

        result
    }
}

impl<InputSymbol: PartialOrd+Clone, OutputSymbol> StateMachine<SymbolRange<InputSymbol>, OutputSymbol> for SymbolRangeDfa<InputSymbol, OutputSymbol> {
    ///
    /// Returns the number of states in this state machine
    ///
    /// Note that if state x exists then state x-1 is also expected to exist provided x > 0. This means that this returns the
    /// first unused state in this state machine.
    ///
    fn count_states(&self) -> StateId {
        (self.states.len()-1) as StateId
    }

    ///
    /// Returns the transitions for a particular symbol
    ///
    fn get_transitions_for_state(&self, state: StateId) -> Vec<(SymbolRange<InputSymbol>, StateId)> {
        let mut result = vec![];

        let start_index = self.states[state as usize];
        let end_index   = self.states[(state+1) as usize];

        for transit_index in start_index..end_index {
            let (ref range, target_state) = self.transitions[transit_index];

            result.push((range.clone(), target_state));
        }

        result
    }

    ///
    /// If a state is an accepting state, then this returns the output symbol that should be produced if this is the longest match
    ///
    fn output_symbol_for_state(&self, state: StateId) -> Option<&OutputSymbol> {
        self.accept[state as usize].as_ref()
    }
}

///
/// A state of a symbol range state machine
///
#[derive(Clone)]
pub struct SymbolRangeState<'a, InputSymbol: PartialOrd+'a, OutputSymbol: 'a> {
    // The current state of the state machine
    state: StateId,

    // The number of symbols that have been processed so far
    count: usize,

    // If something other than none, the most recent accepting state
    accept: Option<(usize, &'a OutputSymbol)>,

    // The state machine this is running
    state_machine: &'a SymbolRangeDfa<InputSymbol, OutputSymbol>
}

impl<'a, InputSymbol: PartialOrd+'a, OutputSymbol: 'a> PatternMatcher<'a, InputSymbol, OutputSymbol> for SymbolRangeDfa<InputSymbol, OutputSymbol> {
    type State = SymbolRangeState<'a, InputSymbol, OutputSymbol>;

    fn start(&'a self) -> Self::State {
        // TODO: if state 0 is accepting, then this will erroneously not move straight to the accepting state
        SymbolRangeState { state: 0, count: 0, accept: None, state_machine: self }
    }
}

impl<'a, InputSymbol: PartialOrd+'a, OutputSymbol: 'a> MatchingState<'a, InputSymbol, OutputSymbol> for SymbolRangeState<'a, InputSymbol, OutputSymbol> {
    fn next(self, symbol: InputSymbol) -> MatchAction<'a, OutputSymbol, Self> {
        // The transition range is defined by the current state
        let start_transition    = self.state_machine.states[self.state as usize];
        let end_transition      = self.state_machine.states[self.state as usize+1];

        // See if there is an input symbol matching this transition
        // TODO: consider binary searching for states with large numbers of transitions? (Do these occur regularly in patterns that people use?)
        // Linear searching in reverse is a quick way to apply the rule that if two adjacent ranges share their last/first symbol that
        // the later range is the one that matches. This works provided the ranges are sorted into order as required by the builder trait.
        for transit in (start_transition..end_transition).rev() {
            // Test this transition
            let (ref range, new_state) = self.state_machine.transitions[transit];

            if range.includes(&symbol) {
                // Found a transition to a new state: result will be `More(new state)`
                let new_count = self.count+1;

                // If the new state is an accepting state, then remember it in case we reach a rejecting state later
                let new_accept = if let Some(ref output) = self.state_machine.accept[new_state as usize] {
                    Some((new_count, output))
                } else {
                    self.accept
                };

                // Action is 'More'
                // TODO: might be an option to return Accept or Reject here if the new state has no transitions
                // (Possible performance advantage, but depends on the regex and input conditions)
                return More(SymbolRangeState { state: new_state, count: new_count, accept: new_accept, state_machine: self.state_machine });
            }
        }

        // No matches: finish the state machine
        self.finish()
    }

    fn finish(self) -> MatchAction<'a, OutputSymbol, Self> {
        if let Some(accept_state) = self.accept {
            // We found an accepting state earlier on, so return that
            let (length, symbol) = accept_state;
            Accept(length, symbol)
        } else {
            // No accepting state was found while this state machine was running
            Reject
        }
    }
}

#[cfg(test)]
mod test {
    use super::super::dfa_builder::*;
    use super::super::symbol_range::*;
    use super::super::pattern_matcher::*;
    use super::super::state_machine::*;
    use super::*;

    #[test]
    fn can_build_state_machine() {
        let mut builder = SymbolRangeDfaBuilder::new();

        // State 0: '0', move to state 1
        builder.start_state();
        builder.transition(SymbolRange::new(0, 0), 1);

        // State 1: accept, output symbol "Success"
        builder.start_state();
        builder.accept("Success");

        // Create the state machine
        let state_machine = builder.build();

        assert!(state_machine.count_states() == 2);
        assert!(state_machine.output_symbol_for_state(0) == None);
        assert!(state_machine.output_symbol_for_state(1) == Some(&"Success"));
        assert!(state_machine.get_transitions_for_state(0) == vec![(SymbolRange::new(0,0), 1)]);
    }

    #[test]
    fn state_machine_follows_adjacency_rules() {
        let mut builder = SymbolRangeDfaBuilder::new();

        // State 0: '0-1', move to state 1, '1-2', move to state 2
        // By the adjacency rules defined in symbol_range.rs, '1' should always move to state 2
        builder.start_state();
        builder.transition(SymbolRange::new(0, 1), 1);
        builder.transition(SymbolRange::new(1, 2), 2);

        // State 1: reject
        builder.start_state();

        // State 2: accept
        builder.start_state();
        builder.accept("Success");

        let state_machine = builder.build();

        // For the string '1' we should move to state 2 and accept
        let start_state = state_machine.start();
        let mut action  = start_state.next(1);

        if let More(next_state) = action {
            action = next_state.finish();
        }

        if let Accept(count, symbol) = action {
            assert!(count == 1);
            assert!(symbol == &"Success");
        } else {
            assert!(false);
        }
    }

    #[test]
    fn can_accept_single_symbol() {
        let mut builder = SymbolRangeDfaBuilder::new();

        // State 0: '0', move to state 1
        builder.start_state();
        builder.transition(SymbolRange::new(0, 0), 1);

        // State 1: accept, output symbol "Success"
        builder.start_state();
        builder.accept("Success");

        // Create the state machine
        let state_machine = builder.build();

        // Run the first state
        let start_state = state_machine.start();
        let mut action  = start_state.next(0);

        if let More(next_state) = action {
            action = next_state.next(0);

            // Should have reached an accepting state (read one character)
            if let Accept(count, symbol) = action {
                // One symbol accepted
                assert!(count == 1);

                // Output symbol correct
                assert!(symbol == &"Success");
            } else {
                // Should have accepted here (the second '0' is rejected)
                assert!(false);
            }
        } else {
            // State machine did not accept the character
            assert!(false);
        }
    }
}
<commit_msg>Don’t have the adjacency rules any more as we added countability and fixed the issue that way<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # RangeDfa
//!
//! A DFA that matches transitions against symbol ranges.
//!

use super::dfa_builder::*;
use super::pattern_matcher::*;
use super::symbol_range::*;
use super::state_machine::*;

///
/// DFA that decides on transitions based on non-overlapping, sorted lists of input symbols
///
#[derive(Debug)]
pub struct SymbolRangeDfa<InputSymbol: PartialOrd, OutputSymbol> {
    //
    // Indexes of where each state starts in the transition table (it ends at the start of the next state)
    //
    states: Vec<usize>,

    //
    // The transitions making up this DFA
    //
    transitions: Vec<(SymbolRange<InputSymbol>, StateId)>,

    //
    // The accepting symbol for each state
    //
    accept: Vec<Option<OutputSymbol>>
}

///
/// DFA builder that creates RangeDfas
///
pub struct SymbolRangeDfaBuilder<InputSymbol: PartialOrd, OutputSymbol> {
    states: Vec<usize>,
    transitions: Vec<(SymbolRange<InputSymbol>, StateId)>,
    accept: Vec<Option<OutputSymbol>>
}

impl<InputSymbol: PartialOrd, OutputSymbol> SymbolRangeDfaBuilder<InputSymbol, OutputSymbol> {
    pub fn new() -> SymbolRangeDfaBuilder<InputSymbol, OutputSymbol> {
        SymbolRangeDfaBuilder { states: vec![], transitions: vec![], accept: vec![] }
    }
}

impl<InputSymbol: PartialOrd, OutputSymbol> DfaBuilder<SymbolRange<InputSymbol>, OutputSymbol, SymbolRangeDfa<InputSymbol, OutputSymbol>> for SymbolRangeDfaBuilder<InputSymbol, OutputSymbol> {
    fn start_state(&mut self) {
        // Begin the next state
        self.states.push(self.transitions.len());
        self.accept.push(None);
    }

    fn transition(&mut self, symbol: SymbolRange<InputSymbol>, target_state: StateId) {
        self.transitions.push((symbol, target_state));
    }

    fn accept(&mut self, symbol: OutputSymbol) {
        self.accept.pop();
        self.accept.push(Some(symbol));
    }

    fn build(self) -> SymbolRangeDfa<InputSymbol, OutputSymbol> {
        // Turn into a RangeDfa
        let mut result = SymbolRangeDfa { states: self.states, transitions: self.transitions, accept: self.accept };

        // 'Cap' the last state so we don't need to special-case it later
        // ie, we can always find the index of the last symbol by looking at the next state and don't need to handle the final state differently
        result.states.push(result.transitions.len());

        result
    }
}

impl<InputSymbol: PartialOrd+Clone, OutputSymbol> StateMachine<SymbolRange<InputSymbol>, OutputSymbol> for SymbolRangeDfa<InputSymbol, OutputSymbol> {
    ///
    /// Returns the number of states in this state machine
    ///
    /// Note that if state x exists then state x-1 is also expected to exist provided x > 0. This means that this returns the
    /// first unused state in this state machine.
    ///
    fn count_states(&self) -> StateId {
        (self.states.len()-1) as StateId
    }

    ///
    /// Returns the transitions for a particular symbol
    ///
    fn get_transitions_for_state(&self, state: StateId) -> Vec<(SymbolRange<InputSymbol>, StateId)> {
        let mut result = vec![];

        let start_index = self.states[state as usize];
        let end_index   = self.states[(state+1) as usize];

        for transit_index in start_index..end_index {
            let (ref range, target_state) = self.transitions[transit_index];

            result.push((range.clone(), target_state));
        }

        result
    }

    ///
    /// If a state is an accepting state, then this returns the output symbol that should be produced if this is the longest match
    ///
    fn output_symbol_for_state(&self, state: StateId) -> Option<&OutputSymbol> {
        self.accept[state as usize].as_ref()
    }
}

///
/// A state of a symbol range state machine
///
#[derive(Clone)]
pub struct SymbolRangeState<'a, InputSymbol: PartialOrd+'a, OutputSymbol: 'a> {
    // The current state of the state machine
    state: StateId,

    // The number of symbols that have been processed so far
    count: usize,

    // If something other than none, the most recent accepting state
    accept: Option<(usize, &'a OutputSymbol)>,

    // The state machine this is running
    state_machine: &'a SymbolRangeDfa<InputSymbol, OutputSymbol>
}

impl<'a, InputSymbol: PartialOrd+'a, OutputSymbol: 'a> PatternMatcher<'a, InputSymbol, OutputSymbol> for SymbolRangeDfa<InputSymbol, OutputSymbol> {
    type State = SymbolRangeState<'a, InputSymbol, OutputSymbol>;

    fn start(&'a self) -> Self::State {
        // TODO: if state 0 is accepting, then this will erroneously not move straight to the accepting state
        SymbolRangeState { state: 0, count: 0, accept: None, state_machine: self }
    }
}

impl<'a, InputSymbol: PartialOrd+'a, OutputSymbol: 'a> MatchingState<'a, InputSymbol, OutputSymbol> for SymbolRangeState<'a, InputSymbol, OutputSymbol> {
    fn next(self, symbol: InputSymbol) -> MatchAction<'a, OutputSymbol, Self> {
        // The transition range is defined by the current state
        let start_transition    = self.state_machine.states[self.state as usize];
        let end_transition      = self.state_machine.states[self.state as usize+1];

        // See if there is an input symbol matching this transition
        // TODO: consider binary searching for states with large numbers of transitions? (Do these occur regularly in patterns that people use?)
        for transit in start_transition..end_transition {
            // Test this transition
            let (ref range, new_state) = self.state_machine.transitions[transit];

            if range.includes(&symbol) {
                // Found a transition to a new state: result will be `More(new state)`
                let new_count = self.count+1;

                // If the new state is an accepting state, then remember it in case we reach a rejecting state later
                let new_accept = if let Some(ref output) = self.state_machine.accept[new_state as usize] {
                    Some((new_count, output))
                } else {
                    self.accept
                };

                // Action is 'More'
                // TODO: might be an option to return Accept or Reject here if the new state has no transitions
                // (Possible performance advantage, but depends on the regex and input conditions)
                return More(SymbolRangeState { state: new_state, count: new_count, accept: new_accept, state_machine: self.state_machine });
            }
        }

        // No matches: finish the state machine
        self.finish()
    }

    fn finish(self) -> MatchAction<'a, OutputSymbol, Self> {
        if let Some(accept_state) = self.accept {
            // We found an accepting state earlier on, so return that
            let (length, symbol) = accept_state;
            Accept(length, symbol)
        } else {
            // No accepting state was found while this state machine was running
            Reject
        }
    }
}

#[cfg(test)]
mod test {
    use super::super::dfa_builder::*;
    use super::super::symbol_range::*;
    use super::super::pattern_matcher::*;
    use super::super::state_machine::*;
    use super::*;

    #[test]
    fn can_build_state_machine() {
        let mut builder = SymbolRangeDfaBuilder::new();

        // State 0: '0', move to state 1
        builder.start_state();
        builder.transition(SymbolRange::new(0, 0), 1);

        // State 1: accept, output symbol "Success"
        builder.start_state();
        builder.accept("Success");

        // Create the state machine
        let state_machine = builder.build();

        assert!(state_machine.count_states() == 2);
        assert!(state_machine.output_symbol_for_state(0) == None);
        assert!(state_machine.output_symbol_for_state(1) == Some(&"Success"));
        assert!(state_machine.get_transitions_for_state(0) == vec![(SymbolRange::new(0,0), 1)]);
    }

    #[test]
    fn can_accept_single_symbol() {
        let mut builder = SymbolRangeDfaBuilder::new();

        // State 0: '0', move to state 1
        builder.start_state();
        builder.transition(SymbolRange::new(0, 0), 1);

        // State 1: accept, output symbol "Success"
        builder.start_state();
        builder.accept("Success");

        // Create the state machine
        let state_machine = builder.build();

        // Run the first state
        let start_state = state_machine.start();
        let mut action  = start_state.next(0);

        if let More(next_state) = action {
            action = next_state.next(0);

            // Should have reached an accepting state (read one character)
            if let Accept(count, symbol) = action {
                // One symbol accepted
                assert!(count == 1);

                // Output symbol correct
                assert!(symbol == &"Success");
            } else {
                // Should have accepted here (the second '0' is rejected)
                assert!(false);
            }
        } else {
            // State machine did not accept the character
            assert!(false);
        }
    }
}
<|endoftext|>