<commit_before>//! Connection helper.
use tokio::{
    io::{AsyncRead, AsyncWrite},
    net::TcpStream,
};

use tungstenite::{
    client::uri_mode,
    error::{Error, UrlError},
    handshake::client::{Request, Response},
    protocol::WebSocketConfig,
};

use super::{client_async_with_config, IntoClientRequest, WebSocketStream};

#[cfg(feature = "native-tls")]
pub(crate) mod encryption {
    use native_tls_crate::TlsConnector as NativeTlsConnector;
    use tokio_native_tls::{TlsConnector as TokioTlsConnector, TlsStream};

    use tokio::io::{AsyncRead, AsyncWrite};

    use tungstenite::{error::TlsError, stream::Mode, Error};

    use crate::stream::Stream as StreamSwitcher;

    /// A stream that might be protected with TLS.
    pub type MaybeTlsStream<S> = StreamSwitcher<S, TlsStream<S>>;

    pub type AutoStream<S> = MaybeTlsStream<S>;

    /// A TLS connector that can be used when establishing TLS connections.
    pub type TlsConnector = NativeTlsConnector;

    pub async fn wrap_stream<S>(
        socket: S,
        domain: String,
        mode: Mode,
        tls_connector: Option<TlsConnector>,
    ) -> Result<AutoStream<S>, Error>
    where
        S: 'static + AsyncRead + AsyncWrite + Send + Unpin,
    {
        match mode {
            Mode::Plain => Ok(StreamSwitcher::Plain(socket)),
            Mode::Tls => {
                let try_connector = tls_connector.map_or_else(TlsConnector::new, Ok);
                let connector = try_connector.map_err(TlsError::Native)?;
                let stream = TokioTlsConnector::from(connector);
                let connected = stream.connect(&domain, socket).await;
                match connected {
                    Err(e) => Err(Error::Tls(e.into())),
                    Ok(s) => Ok(StreamSwitcher::Tls(s)),
                }
            }
        }
    }
}

#[cfg(all(feature = "rustls-tls", not(feature = "native-tls")))]
pub(crate) mod encryption {
    pub use rustls::ClientConfig;
    use tokio_rustls::{webpki::DNSNameRef, TlsConnector as TokioTlsConnector, TlsStream};

    use std::sync::Arc;
    use tokio::io::{AsyncRead, AsyncWrite};

    use tungstenite::{error::TlsError, stream::Mode, Error};

    use crate::stream::Stream as StreamSwitcher;

    /// A stream that might be protected with TLS.
    pub type MaybeTlsStream<S> = StreamSwitcher<S, TlsStream<S>>;

    pub type AutoStream<S> = MaybeTlsStream<S>;

    /// A TLS connector that can be used when establishing TLS connections.
    pub type TlsConnector = Arc<ClientConfig>;

    pub async fn wrap_stream<S>(
        socket: S,
        domain: String,
        mode: Mode,
        tls_connector: Option<TlsConnector>,
    ) -> Result<AutoStream<S>, Error>
    where
        S: 'static + AsyncRead + AsyncWrite + Send + Unpin,
    {
        match mode {
            Mode::Plain => Ok(StreamSwitcher::Plain(socket)),
            Mode::Tls => {
                let config = tls_connector.unwrap_or_else(|| {
                    let mut config = ClientConfig::new();
                    config.root_store.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);

                    Arc::new(config)
                });
                let domain = DNSNameRef::try_from_ascii_str(&domain).map_err(TlsError::Dns)?;
                let stream = TokioTlsConnector::from(config);
                let connected = stream.connect(domain, socket).await;

                match connected {
                    Err(e) => Err(Error::Io(e)),
                    Ok(s) => Ok(StreamSwitcher::Tls(TlsStream::Client(s))),
                }
            }
        }
    }
}

#[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
pub use self::encryption::MaybeTlsStream;
pub use self::encryption::TlsConnector;

#[cfg(not(any(feature = "native-tls", feature = "rustls-tls")))]
pub(crate) mod encryption {
    use tokio::io::{AsyncRead, AsyncWrite};

    use tungstenite::{
        error::{Error, UrlError},
        stream::Mode,
    };

    pub type AutoStream<S> = S;

    /// A TLS connector that can be used when establishing TLS connections.
    pub type TlsConnector = ();

    pub async fn wrap_stream<S>(
        socket: S,
        _domain: String,
        mode: Mode,
        _tls_connector: Option<TlsConnector>,
    ) -> Result<AutoStream<S>, Error>
    where
        S: 'static + AsyncRead + AsyncWrite + Send + Unpin,
    {
        match mode {
            Mode::Plain => Ok(socket),
            Mode::Tls => Err(Error::Url(UrlError::TlsFeatureNotEnabled)),
        }
    }
}

use self::encryption::{wrap_stream, AutoStream};

/// Get a domain from an URL.
#[inline]
fn domain(request: &Request) -> Result<String, Error> {
    match request.uri().host() {
        Some(d) => Ok(d.to_string()),
        None => Err(Error::Url(UrlError::NoHostName)),
    }
}

/// Creates a WebSocket handshake from a request and a stream,
/// upgrading the stream to TLS if required.
pub async fn client_async_tls<R, S>(
    request: R,
    stream: S,
) -> Result<(WebSocketStream<AutoStream<S>>, Response), Error>
where
    R: IntoClientRequest + Unpin,
    S: 'static + AsyncRead + AsyncWrite + Send + Unpin,
    AutoStream<S>: Unpin,
{
    client_async_tls_with_config(request, stream, None, None).await
}

/// The same as `client_async_tls()` but the one can specify a websocket configuration,
/// and an optional TLS connector. If no connector is specified, the default one will
/// be created.
///
/// Please refer to `client_async_tls()` for more details.
pub async fn client_async_tls_with_config<R, S>(
    request: R,
    stream: S,
    config: Option<WebSocketConfig>,
    tls_connector: Option<TlsConnector>,
) -> Result<(WebSocketStream<AutoStream<S>>, Response), Error>
where
    R: IntoClientRequest + Unpin,
    S: 'static + AsyncRead + AsyncWrite + Send + Unpin,
    AutoStream<S>: Unpin,
{
    let request = request.into_client_request()?;

    let domain = domain(&request)?;

    // Make sure we check domain and mode first. URL must be valid.
    let mode = uri_mode(&request.uri())?;

    let stream = wrap_stream(stream, domain, mode, tls_connector).await?;
    client_async_with_config(request, stream, config).await
}

/// Connect to a given URL.
pub async fn connect_async<R>(
    request: R,
) -> Result<(WebSocketStream<AutoStream<TcpStream>>, Response), Error>
where
    R: IntoClientRequest + Unpin,
{
    connect_async_with_config(request, None).await
}

/// The same as `connect_async()` but the one can specify a websocket configuration.
/// Please refer to `connect_async()` for more details.
pub async fn connect_async_with_config<R>(
    request: R,
    config: Option<WebSocketConfig>,
) -> Result<(WebSocketStream<AutoStream<TcpStream>>, Response), Error>
where
    R: IntoClientRequest + Unpin,
{
    let request = request.into_client_request()?;

    let domain = domain(&request)?;
    let port = request
        .uri()
        .port_u16()
        .or_else(|| match request.uri().scheme_str() {
            Some("wss") => Some(443),
            Some("ws") => Some(80),
            _ => None,
        })
        .ok_or(Error::Url(UrlError::UnsupportedUrlScheme))?;

    let addr = format!("{}:{}", domain, port);
    let try_socket = TcpStream::connect(addr).await;
    let socket = try_socket.map_err(Error::Io)?;
    client_async_tls_with_config(request, socket, config, None).await
}
<commit_msg>Use the rustls client TlsStream exclusively<commit_after>//! Connection helper.
use tokio::{
    io::{AsyncRead, AsyncWrite},
    net::TcpStream,
};

use tungstenite::{
    client::uri_mode,
    error::{Error, UrlError},
    handshake::client::{Request, Response},
    protocol::WebSocketConfig,
};

use super::{client_async_with_config, IntoClientRequest, WebSocketStream};

#[cfg(feature = "native-tls")]
pub(crate) mod encryption {
    use native_tls_crate::TlsConnector as NativeTlsConnector;
    use tokio_native_tls::{TlsConnector as TokioTlsConnector, TlsStream};

    use tokio::io::{AsyncRead, AsyncWrite};

    use tungstenite::{error::TlsError, stream::Mode, Error};

    use crate::stream::Stream as StreamSwitcher;

    /// A stream that might be protected with TLS.
    pub type MaybeTlsStream<S> = StreamSwitcher<S, TlsStream<S>>;

    pub type AutoStream<S> = MaybeTlsStream<S>;

    /// A TLS connector that can be used when establishing TLS connections.
    pub type TlsConnector = NativeTlsConnector;

    pub async fn wrap_stream<S>(
        socket: S,
        domain: String,
        mode: Mode,
        tls_connector: Option<TlsConnector>,
    ) -> Result<AutoStream<S>, Error>
    where
        S: 'static + AsyncRead + AsyncWrite + Send + Unpin,
    {
        match mode {
            Mode::Plain => Ok(StreamSwitcher::Plain(socket)),
            Mode::Tls => {
                let try_connector = tls_connector.map_or_else(TlsConnector::new, Ok);
                let connector = try_connector.map_err(TlsError::Native)?;
                let stream = TokioTlsConnector::from(connector);
                let connected = stream.connect(&domain, socket).await;
                match connected {
                    Err(e) => Err(Error::Tls(e.into())),
                    Ok(s) => Ok(StreamSwitcher::Tls(s)),
                }
            }
        }
    }
}

#[cfg(all(feature = "rustls-tls", not(feature = "native-tls")))]
pub(crate) mod encryption {
    pub use rustls::ClientConfig;
    use tokio_rustls::{webpki::DNSNameRef, TlsConnector as TokioTlsConnector, client::TlsStream};

    use std::sync::Arc;
    use tokio::io::{AsyncRead, AsyncWrite};

    use tungstenite::{error::TlsError, stream::Mode, Error};

    use crate::stream::Stream as StreamSwitcher;

    /// A stream that might be protected with TLS.
    pub type MaybeTlsStream<S> = StreamSwitcher<S, TlsStream<S>>;

    pub type AutoStream<S> = MaybeTlsStream<S>;

    /// A TLS connector that can be used when establishing TLS connections.
    pub type TlsConnector = Arc<ClientConfig>;

    pub async fn wrap_stream<S>(
        socket: S,
        domain: String,
        mode: Mode,
        tls_connector: Option<TlsConnector>,
    ) -> Result<AutoStream<S>, Error>
    where
        S: 'static + AsyncRead + AsyncWrite + Send + Unpin,
    {
        match mode {
            Mode::Plain => Ok(StreamSwitcher::Plain(socket)),
            Mode::Tls => {
                let config = tls_connector.unwrap_or_else(|| {
                    let mut config = ClientConfig::new();
                    config.root_store.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);

                    Arc::new(config)
                });
                let domain = DNSNameRef::try_from_ascii_str(&domain).map_err(TlsError::Dns)?;
                let stream = TokioTlsConnector::from(config);
                let connected = stream.connect(domain, socket).await;

                match connected {
                    Err(e) => Err(Error::Io(e)),
                    Ok(s) => Ok(StreamSwitcher::Tls(s)),
                }
            }
        }
    }
}

#[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
pub use self::encryption::MaybeTlsStream;
pub use self::encryption::TlsConnector;

#[cfg(not(any(feature = "native-tls", feature = "rustls-tls")))]
pub(crate) mod encryption {
    use tokio::io::{AsyncRead, AsyncWrite};

    use tungstenite::{
        error::{Error, UrlError},
        stream::Mode,
    };

    pub type AutoStream<S> = S;

    /// A TLS connector that can be used when establishing TLS connections.
    pub type TlsConnector = ();

    pub async fn wrap_stream<S>(
        socket: S,
        _domain: String,
        mode: Mode,
        _tls_connector: Option<TlsConnector>,
    ) -> Result<AutoStream<S>, Error>
    where
        S: 'static + AsyncRead + AsyncWrite + Send + Unpin,
    {
        match mode {
            Mode::Plain => Ok(socket),
            Mode::Tls => Err(Error::Url(UrlError::TlsFeatureNotEnabled)),
        }
    }
}

use self::encryption::{wrap_stream, AutoStream};

/// Get a domain from an URL.
#[inline]
fn domain(request: &Request) -> Result<String, Error> {
    match request.uri().host() {
        Some(d) => Ok(d.to_string()),
        None => Err(Error::Url(UrlError::NoHostName)),
    }
}

/// Creates a WebSocket handshake from a request and a stream,
/// upgrading the stream to TLS if required.
pub async fn client_async_tls<R, S>(
    request: R,
    stream: S,
) -> Result<(WebSocketStream<AutoStream<S>>, Response), Error>
where
    R: IntoClientRequest + Unpin,
    S: 'static + AsyncRead + AsyncWrite + Send + Unpin,
    AutoStream<S>: Unpin,
{
    client_async_tls_with_config(request, stream, None, None).await
}

/// The same as `client_async_tls()` but the one can specify a websocket configuration,
/// and an optional TLS connector. If no connector is specified, the default one will
/// be created.
///
/// Please refer to `client_async_tls()` for more details.
pub async fn client_async_tls_with_config<R, S>(
    request: R,
    stream: S,
    config: Option<WebSocketConfig>,
    tls_connector: Option<TlsConnector>,
) -> Result<(WebSocketStream<AutoStream<S>>, Response), Error>
where
    R: IntoClientRequest + Unpin,
    S: 'static + AsyncRead + AsyncWrite + Send + Unpin,
    AutoStream<S>: Unpin,
{
    let request = request.into_client_request()?;

    let domain = domain(&request)?;

    // Make sure we check domain and mode first. URL must be valid.
    let mode = uri_mode(&request.uri())?;

    let stream = wrap_stream(stream, domain, mode, tls_connector).await?;
    client_async_with_config(request, stream, config).await
}

/// Connect to a given URL.
pub async fn connect_async<R>(
    request: R,
) -> Result<(WebSocketStream<AutoStream<TcpStream>>, Response), Error>
where
    R: IntoClientRequest + Unpin,
{
    connect_async_with_config(request, None).await
}

/// The same as `connect_async()` but the one can specify a websocket configuration.
/// Please refer to `connect_async()` for more details.
pub async fn connect_async_with_config<R>(
    request: R,
    config: Option<WebSocketConfig>,
) -> Result<(WebSocketStream<AutoStream<TcpStream>>, Response), Error>
where
    R: IntoClientRequest + Unpin,
{
    let request = request.into_client_request()?;

    let domain = domain(&request)?;
    let port = request
        .uri()
        .port_u16()
        .or_else(|| match request.uri().scheme_str() {
            Some("wss") => Some(443),
            Some("ws") => Some(80),
            _ => None,
        })
        .ok_or(Error::Url(UrlError::UnsupportedUrlScheme))?;

    let addr = format!("{}:{}", domain, port);
    let try_socket = TcpStream::connect(addr).await;
    let socket = try_socket.map_err(Error::Io)?;
    client_async_tls_with_config(request, socket, config, None).await
}
<|endoftext|>


<commit_before>use crate::callback::Identity0Consumer;
use crate::executor;
use crate::futures;
use crate::result::TockResult;
use crate::syscalls;
use core::cell::Cell;
use core::fmt;
use core::mem;

// Global console
static mut CONSOLE: Option<Console> = None;

const DRIVER_NUMBER: usize = 1;

mod command_nr {
    pub const WRITE: usize = 1;
}

mod subscribe_nr {
    pub const SET_ALARM: usize = 1;
}

mod allow_nr {
    pub const SHARE_BUFFER: usize = 1;
}

#[non_exhaustive]
pub struct ConsoleDriver;

impl ConsoleDriver {
    pub fn create_console(self) {
        let console = Console {
            allow_buffer: [0; 64],
        };

        console.set_global_console();
    }
}

pub struct Console {
    allow_buffer: [u8; 64],
}

pub fn get_global_console() -> Option<Console> {
    unsafe {
        if let Some(con) = CONSOLE.take() {
            Some(con)
        } else {
            None
        }
    }
}

impl Console {
    pub fn write<S: AsRef<[u8]>>(&mut self, text: S) -> TockResult<()> {
        let mut not_written_yet = text.as_ref();
        while !not_written_yet.is_empty() {
            let num_bytes_to_print = self.allow_buffer.len().min(not_written_yet.len());
            self.allow_buffer[..num_bytes_to_print]
                .copy_from_slice(&not_written_yet[..num_bytes_to_print]);
            self.flush(num_bytes_to_print)?;
            not_written_yet = &not_written_yet[num_bytes_to_print..];
        }
        Ok(())
    }

    fn flush(&mut self, num_bytes_to_print: usize) -> TockResult<()> {
        let shared_memory = syscalls::allow(
            DRIVER_NUMBER,
            allow_nr::SHARE_BUFFER,
            &mut self.allow_buffer[..num_bytes_to_print],
        )?;

        let is_written = Cell::new(false);
        let mut is_written_alarm = || is_written.set(true);
        let subscription = syscalls::subscribe::<Identity0Consumer, _>(
            DRIVER_NUMBER,
            subscribe_nr::SET_ALARM,
            &mut is_written_alarm,
        )?;

        syscalls::command(DRIVER_NUMBER, command_nr::WRITE, num_bytes_to_print, 0)?;

        unsafe { executor::block_on(futures::wait_until(|| is_written.get())) };

        mem::drop(subscription);
        mem::drop(shared_memory);

        Ok(())
    }

    pub fn set_global_console(self) {
        unsafe {
            CONSOLE = Some(self);
        }
    }
}

impl fmt::Write for Console {
    fn write_str(&mut self, string: &str) -> Result<(), fmt::Error> {
        self.write(string).map_err(|_| fmt::Error)
    }
}

#[macro_export]
macro_rules! println {
    () => ({
        // Allow an empty println!() to print the location when hit
        println!("")
    });
    ($msg:expr) => ({
        if let Some(mut console) = $crate::console::get_global_console() {
            use core::fmt::Write;
            let _ = writeln!(console, $msg);
            console.set_global_console();
        }
    });
    ($fmt:expr, $($arg:tt)+) => ({
        if let Some(mut console) = $crate::console::get_global_console() {
            use core::fmt::Write;
            let _ = writeln!(console, "{}", format_args!($fmt, $($arg)+));
            console.set_global_console();
        }
    });
}

#[macro_export]
macro_rules! print {
    () => ({
        // Allow an empty print!() to print the location when hit
        print!("")
    });
    ($msg:expr) => ({
        if let Some(mut console) = $crate::console::get_global_console() {
            use core::fmt::Write;
            let _ =  write!(console, $msg);
            console.set_global_console();
        }
    });
    ($fmt:expr, $($arg:tt)+) => ({
        if let Some(mut console) = $crate::console::get_global_console() {
            use core::fmt::Write;
            let _ = write!(console, "{}", format_args!($fmt, $($arg)+));
            console.set_global_console();
        }
    });
}
<commit_msg>console: Print a warning if a print is lost<commit_after>use crate::callback::Identity0Consumer;
use crate::executor;
use crate::futures;
use crate::result::TockResult;
use crate::syscalls;
use core::cell::Cell;
use core::fmt;
use core::fmt::Write;
use core::mem;

// Global console
static mut CONSOLE: Option<Console> = None;

const DRIVER_NUMBER: usize = 1;

mod command_nr {
    pub const WRITE: usize = 1;
}

mod subscribe_nr {
    pub const SET_ALARM: usize = 1;
}

mod allow_nr {
    pub const SHARE_BUFFER: usize = 1;
}

#[non_exhaustive]
pub struct ConsoleDriver;

impl ConsoleDriver {
    pub fn create_console(self) {
        let console = Console {
            allow_buffer: [0; 64],
        };

        console.set_global_console();
    }
}

pub struct Console {
    allow_buffer: [u8; 64],
}

pub static mut MISSED_PRINT: bool = false;

pub fn get_global_console() -> Option<Console> {
    unsafe {
        if let Some(con) = CONSOLE.take() {
            Some(con)
        } else {
            // If we get here then either the console was never initalised
            // or someone else took it. Set MISSED_PRINT to true so that we
            // can warn the user.
            MISSED_PRINT = true;
            None
        }
    }
}

impl Console {
    pub fn write<S: AsRef<[u8]>>(&mut self, text: S) -> TockResult<()> {
        let mut not_written_yet = text.as_ref();
        while !not_written_yet.is_empty() {
            let num_bytes_to_print = self.allow_buffer.len().min(not_written_yet.len());
            self.allow_buffer[..num_bytes_to_print]
                .copy_from_slice(&not_written_yet[..num_bytes_to_print]);
            self.flush(num_bytes_to_print)?;
            not_written_yet = &not_written_yet[num_bytes_to_print..];
        }
        Ok(())
    }

    fn flush(&mut self, num_bytes_to_print: usize) -> TockResult<()> {
        let shared_memory = syscalls::allow(
            DRIVER_NUMBER,
            allow_nr::SHARE_BUFFER,
            &mut self.allow_buffer[..num_bytes_to_print],
        )?;

        let is_written = Cell::new(false);
        let mut is_written_alarm = || is_written.set(true);
        let subscription = syscalls::subscribe::<Identity0Consumer, _>(
            DRIVER_NUMBER,
            subscribe_nr::SET_ALARM,
            &mut is_written_alarm,
        )?;

        syscalls::command(DRIVER_NUMBER, command_nr::WRITE, num_bytes_to_print, 0)?;

        unsafe { executor::block_on(futures::wait_until(|| is_written.get())) };

        mem::drop(subscription);
        mem::drop(shared_memory);

        Ok(())
    }

    pub fn set_global_console(mut self) {
        unsafe {
            if MISSED_PRINT {
                // Someone tried to print while we were or someone tried
                // to print before initalisation, print a warning here.
                let _ = write!(self, "A print was dropped while the console was locked");
                MISSED_PRINT = false;
            }

            CONSOLE = Some(self);
        }
    }
}

impl fmt::Write for Console {
    fn write_str(&mut self, string: &str) -> Result<(), fmt::Error> {
        self.write(string).map_err(|_| fmt::Error)
    }
}

#[macro_export]
macro_rules! println {
    () => ({
        // Allow an empty println!() to print the location when hit
        println!("")
    });
    ($msg:expr) => ({
        if let Some(mut console) = $crate::console::get_global_console() {
            use core::fmt::Write;
            let _ = writeln!(console, $msg);
            console.set_global_console();
        }
    });
    ($fmt:expr, $($arg:tt)+) => ({
        if let Some(mut console) = $crate::console::get_global_console() {
            use core::fmt::Write;
            let _ = writeln!(console, "{}", format_args!($fmt, $($arg)+));
            console.set_global_console();
        }
    });
}

#[macro_export]
macro_rules! print {
    () => ({
        // Allow an empty print!() to print the location when hit
        print!("")
    });
    ($msg:expr) => ({
        if let Some(mut console) = $crate::console::get_global_console() {
            use core::fmt::Write;
            let _ =  write!(console, $msg);
            console.set_global_console();
        }
    });
    ($fmt:expr, $($arg:tt)+) => ({
        if let Some(mut console) = $crate::console::get_global_console() {
            use core::fmt::Write;
            let _ = write!(console, "{}", format_args!($fmt, $($arg)+));
            console.set_global_console();
        }
    });
}
<|endoftext|>


<commit_before>use std::fmt;
/// We re-export winit so it's easy for people to use the same version as we are
/// without having to mess around figuring it out.
pub use winit;

use crate::audio;
use crate::conf;
use crate::error::GameResult;
use crate::event::winit_event;
use crate::filesystem::Filesystem;
use crate::graphics::{self, Point2};
use crate::input::{gamepad, keyboard, mouse};
use crate::timer;

/// A `Context` is an object that holds on to global resources.
/// It basically tracks hardware state such as the screen, audio
/// system, timers, and so on.  Generally this type is **not** thread-
/// safe and only one `Context` can exist at a time.  Trying to create
/// another one will fail.
///
/// Most functions that interact with the hardware, for instance
/// drawing things, playing sounds, or loading resources (which then
/// need to be transformed into a format the hardware likes) will need
/// to access the `Context`.
pub struct Context {
    /// Filesystem state
    pub filesystem: Filesystem,
    /// Graphics state
    pub(crate) gfx_context: crate::graphics::context::GraphicsContext,
    /// Timer state
    pub timer_context: timer::TimeContext,
    /// Audio context
    pub audio_context: Box<dyn audio::AudioContext>,
    /// Keyboard context
    pub keyboard_context: keyboard::KeyboardContext,
    /// Mouse context
    pub mouse_context: mouse::MouseContext,
    /// Gamepad context
    pub gamepad_context: Box<dyn gamepad::GamepadContext>,

    /// The Conf object the Context was created with
    pub conf: conf::Conf,
    /// Controls whether or not the event loop should be running.
    pub continuing: bool,

    /// Context-specific unique ID.
    /// Compiles to nothing in release mode, and so
    /// vanishes; meanwhile we get dead-code warnings.
    #[allow(dead_code)]
    debug_id: DebugId,
}

impl fmt::Debug for Context {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<Context: {:p}>", self)
    }
}

impl Context {
    /// Tries to create a new Context using settings from the given [`Conf`](../conf/struct.Conf.html) object.
    /// Usually called by [`ContextBuilder::build()`](struct.ContextBuilder.html#method.build).
    fn from_conf(conf: conf::Conf, mut fs: Filesystem) -> GameResult<(Context, winit::EventsLoop)> {
        let debug_id = DebugId::new();
        let audio_context: Box<dyn audio::AudioContext> = if conf.modules.audio {
            Box::new(audio::RodioAudioContext::new()?)
        } else {
            Box::new(audio::NullAudioContext::default())
        };
        let events_loop = winit::EventsLoop::new();
        let timer_context = timer::TimeContext::new();
        let backend_spec = graphics::GlBackendSpec::from(conf.backend);
        let graphics_context = graphics::context::GraphicsContext::new(
            &mut fs,
            &events_loop,
            &conf.window_setup,
            conf.window_mode,
            backend_spec,
            debug_id,
        )?;
        let mouse_context = mouse::MouseContext::new();
        let keyboard_context = keyboard::KeyboardContext::new();
        let gamepad_context: Box<dyn gamepad::GamepadContext> = if conf.modules.gamepad {
            Box::new(gamepad::GilrsGamepadContext::new()?)
        } else {
            Box::new(gamepad::NullGamepadContext::default())
        };

        let ctx = Context {
            conf,
            filesystem: fs,
            gfx_context: graphics_context,
            continuing: true,
            timer_context,
            audio_context,
            keyboard_context,
            gamepad_context,
            mouse_context,

            debug_id,
        };

        Ok((ctx, events_loop))
    }

    /// Feeds an `Event` into the `Context` so it can update any internal
    /// state it needs to, such as detecting window resizes.  If you are
    /// rolling your own event loop, you should call this on the events
    /// you receive before processing them yourself.
    ///
    /// TODO: Resolve hidpi mongling in #391.
    /// This also returns a new version of the `Event` that has been modified
    /// for ggez's optional overriding of hidpi.  For full discussion see
    /// <https://github.com/tomaka/winit/issues/591#issuecomment-403096230>.
    pub fn process_event(&mut self, event: &winit::Event) -> winit::Event {
        let event = self.gfx_context.hack_event_hidpi(event);
        match event.clone() {
            winit_event::Event::WindowEvent { event, .. } => match event {
                winit_event::WindowEvent::Resized(_) => {
                    self.gfx_context.resize_viewport();
                }
                winit_event::WindowEvent::CursorMoved {
                    position: logical_position,
                    ..
                } => {
                    let actual_position =
                        logical_position.to_physical(self.gfx_context.hidpi_factor as f64);
                    self.mouse_context.set_last_position(Point2::new(
                        actual_position.x as f32,
                        actual_position.y as f32,
                    ));
                }
                winit_event::WindowEvent::MouseInput { button, state, .. } => {
                    let pressed = match state {
                        winit_event::ElementState::Pressed => true,
                        winit_event::ElementState::Released => false,
                    };
                    self.mouse_context.set_button(button, pressed);
                }
                winit_event::WindowEvent::KeyboardInput {
                    input:
                        winit::KeyboardInput {
                            state,
                            virtual_keycode: Some(keycode),
                            modifiers,
                            ..
                        },
                    ..
                } => {
                    let pressed = match state {
                        winit_event::ElementState::Pressed => true,
                        winit_event::ElementState::Released => false,
                    };
                    self.keyboard_context
                        .set_modifiers(keyboard::KeyMods::from(modifiers));
                    self.keyboard_context.set_key(keycode, pressed);
                }
                winit_event::WindowEvent::HiDpiFactorChanged(new_hidpi_factor) => {
                    // TODO: Test how this actually works... does winit's hidpi factor change and
                    // we have to account for it here, or does winit just tell us when something
                    // changes?
                    // Well this is actually really hard to test without the right hardware, soooo,
                    // I guess I'll just leave it as this for now.
                    self.gfx_context.hidpi_factor = new_hidpi_factor as f32;
                }
                _ => (),
            },
            winit_event::Event::DeviceEvent { event, .. } => match event {
                winit_event::DeviceEvent::MouseMotion { delta: (x, y) } => {
                    self.mouse_context.set_last_delta(Point2::new(
                        x as f32 * self.gfx_context.hidpi_factor,
                        y as f32 * self.gfx_context.hidpi_factor,
                    ));
                }
                _ => (),
            },

            _ => (),
        };
        event
    }
}

use std::path;

/// A builder object for creating a [`Context`](struct.Context.html).
#[derive(Debug, Clone, PartialEq)]
pub struct ContextBuilder {
    pub(crate) game_id: &'static str,
    pub(crate) author: &'static str,
    pub(crate) conf: conf::Conf,
    pub(crate) paths: Vec<path::PathBuf>,
    pub(crate) load_conf_file: bool,
}

impl ContextBuilder {
    /// Create a new `ContextBuilder` with default settings.
    pub fn new(game_id: &'static str, author: &'static str) -> Self {
        Self {
            game_id,
            author,
            conf: conf::Conf::default(),
            paths: vec![],
            load_conf_file: true,
        }
    }

    /// Sets the window setup settings.
    pub fn window_setup(mut self, setup: conf::WindowSetup) -> Self {
        self.conf.window_setup = setup;
        self
    }

    /// Sets the window mode settings.
    pub fn window_mode(mut self, mode: conf::WindowMode) -> Self {
        self.conf.window_mode = mode;
        self
    }

    /// Sets the graphics backend.
    pub fn backend(mut self, backend: conf::Backend) -> Self {
        self.conf.backend = backend;
        self
    }

    /// Sets the modules configuration.
    pub fn modules(mut self, modules: conf::ModuleConf) -> Self {
        self.conf.modules = modules;
        self
    }

    /// Sets all the config options, overriding any previous
    /// ones from [`window_setup()`](#method.window_setup),
    /// [`window_mode()`](#method.window_mode), and
    /// [`backend()`](#method.backend).
    pub fn conf(mut self, conf: conf::Conf) -> Self {
        self.conf = conf;
        self
    }

    /// Add a new read-only filesystem path to the places to search
    /// for resources.
    pub fn add_resource_path<T>(mut self, path: T) -> Self
    where
        T: Into<path::PathBuf>,
    {
        self.paths.push(path.into());
        self
    }

    /// Specifies whether or not to load the `conf.toml` file if it
    /// exists and use its settings to override the provided values.
    /// Defaults to `true` which is usually what you want, but being
    /// able to fiddle with it is sometimes useful for debugging.
    pub fn with_conf_file(mut self, load_conf_file: bool) -> Self {
        self.load_conf_file = load_conf_file;
        self
    }

    /// Build the `Context`.
    pub fn build(self) -> GameResult<(Context, winit::EventsLoop)> {
        let mut fs = Filesystem::new(self.game_id, self.author)?;

        for path in &self.paths {
            fs.mount(path, true);
        }

        let config = if self.load_conf_file {
            fs.read_config().unwrap_or(self.conf)
        } else {
            self.conf
        };

        Context::from_conf(config, fs)
    }
}

/// Terminates the [`ggez::run()`](fn.run.html) loop by setting
/// [`Context.continuing`](struct.Context.html#structfield.continuing)
/// to `false`.
pub fn quit(ctx: &mut Context) {
    ctx.continuing = false;
}

#[cfg(debug_assertions)]
use std::sync::atomic::{AtomicUsize, Ordering};
#[cfg(debug_assertions)]
static DEBUG_ID_COUNTER: AtomicUsize = AtomicUsize::new(0);

/// This is a type that contains a unique ID for each `Context` and
/// is contained in each thing created from the `Context` which
/// becomes invalid when the `Context` goes away (for example, `Image` because
/// it contains texture handles).  When compiling without assertions
/// (in release mode) it is replaced with a zero-size type, compiles
/// down to nothing, disappears entirely with a puff of optimization logic.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg(debug_assertions)]
pub(crate) struct DebugId(u32);
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg(not(debug_assertions))]
pub(crate) struct DebugId;

#[cfg(debug_assertions)]
impl DebugId {
    pub fn new() -> Self {
        let id = DEBUG_ID_COUNTER.fetch_add(1, Ordering::SeqCst) as u32;
        // fetch_add() wraps on overflow so we check for overflow explicitly.
        // JUST IN CASE YOU TRY TO CREATE 2^32 CONTEXTS IN ONE PROGRAM!  muahahahahaaa
        assert!(DEBUG_ID_COUNTER.load(Ordering::SeqCst) as u32 > id);
        DebugId(id)
    }

    pub fn get(ctx: &Context) -> Self {
        DebugId(ctx.debug_id.0)
    }

    pub fn assert(&self, ctx: &Context) {
        if *self != ctx.debug_id {
            panic!("Tried to use a resource with a Context that did not create it; this should never happen!");
        }
    }
}

#[cfg(not(debug_assertions))]
impl DebugId {
    pub fn new() -> Self {
        DebugId
    }

    pub fn get(_ctx: &Context) -> Self {
        DebugId
    }

    pub fn assert(&self, _ctx: &Context) {
        // Do nothing.
    }
}
<commit_msg>Improve context docs some.<commit_after>use std::fmt;
/// We re-export winit so it's easy for people to use the same version as we are
/// without having to mess around figuring it out.
pub use winit;

use crate::audio;
use crate::conf;
use crate::error::GameResult;
use crate::event::winit_event;
use crate::filesystem::Filesystem;
use crate::graphics::{self, Point2};
use crate::input::{gamepad, keyboard, mouse};
use crate::timer;

/// A `Context` is an object that holds on to global resources.
/// It basically tracks hardware state such as the screen, audio
/// system, timers, and so on.  Generally this type is **not** thread-
/// safe and only one `Context` can exist at a time.  Trying to create
/// another one will fail.
///
/// Most functions that interact with the hardware, for instance
/// drawing things, playing sounds, or loading resources (which then
/// need to be transformed into a format the hardware likes) will need
/// to access the `Context`.
///
/// All fields in this struct are basically undocumented features, only
/// here to make it easier to debug,
/// or to let advanced users hook into the guts of ggez and make it
/// do things it normally can't.
/// Most users shouldn't touch these things directly, since
/// implementation details may change without warning.  The
/// public and stable API is `ggez`'s module-level functions and types.
pub struct Context {
    /// Filesystem state
    pub filesystem: Filesystem,
    /// Graphics state
    pub(crate) gfx_context: crate::graphics::context::GraphicsContext,
    /// Timer state
    pub timer_context: timer::TimeContext,
    /// Audio context
    pub audio_context: Box<dyn audio::AudioContext>,
    /// Keyboard context
    pub keyboard_context: keyboard::KeyboardContext,
    /// Mouse context
    pub mouse_context: mouse::MouseContext,
    /// Gamepad context
    pub gamepad_context: Box<dyn gamepad::GamepadContext>,

    /// The Conf object the Context was created with.
    /// It's here just so that we can see the original settings,
    /// updating it will have no effect.
    pub conf: conf::Conf,
    /// Controls whether or not the event loop should be running.
    /// Set this with `ggez::quit()`.
    pub continuing: bool,

    /// Context-specific unique ID.
    /// Compiles to nothing in release mode, and so
    /// vanishes; meanwhile we get dead-code warnings.
    #[allow(dead_code)]
    debug_id: DebugId,
}

impl fmt::Debug for Context {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<Context: {:p}>", self)
    }
}

impl Context {
    /// Tries to create a new Context using settings from the given [`Conf`](../conf/struct.Conf.html) object.
    /// Usually called by [`ContextBuilder::build()`](struct.ContextBuilder.html#method.build).
    fn from_conf(conf: conf::Conf, mut fs: Filesystem) -> GameResult<(Context, winit::EventsLoop)> {
        let debug_id = DebugId::new();
        let audio_context: Box<dyn audio::AudioContext> = if conf.modules.audio {
            Box::new(audio::RodioAudioContext::new()?)
        } else {
            Box::new(audio::NullAudioContext::default())
        };
        let events_loop = winit::EventsLoop::new();
        let timer_context = timer::TimeContext::new();
        let backend_spec = graphics::GlBackendSpec::from(conf.backend);
        let graphics_context = graphics::context::GraphicsContext::new(
            &mut fs,
            &events_loop,
            &conf.window_setup,
            conf.window_mode,
            backend_spec,
            debug_id,
        )?;
        let mouse_context = mouse::MouseContext::new();
        let keyboard_context = keyboard::KeyboardContext::new();
        let gamepad_context: Box<dyn gamepad::GamepadContext> = if conf.modules.gamepad {
            Box::new(gamepad::GilrsGamepadContext::new()?)
        } else {
            Box::new(gamepad::NullGamepadContext::default())
        };

        let ctx = Context {
            conf,
            filesystem: fs,
            gfx_context: graphics_context,
            continuing: true,
            timer_context,
            audio_context,
            keyboard_context,
            gamepad_context,
            mouse_context,

            debug_id,
        };

        Ok((ctx, events_loop))
    }

    /// Feeds an `Event` into the `Context` so it can update any internal
    /// state it needs to, such as detecting window resizes.  If you are
    /// rolling your own event loop, you should call this on the events
    /// you receive before processing them yourself.
    ///
    /// TODO: Resolve hidpi mongling in #391.
    /// This also returns a new version of the `Event` that has been modified
    /// for ggez's optional overriding of hidpi.  For full discussion see
    /// <https://github.com/tomaka/winit/issues/591#issuecomment-403096230>.
    pub fn process_event(&mut self, event: &winit::Event) -> winit::Event {
        let event = self.gfx_context.hack_event_hidpi(event);
        match event.clone() {
            winit_event::Event::WindowEvent { event, .. } => match event {
                winit_event::WindowEvent::Resized(_) => {
                    self.gfx_context.resize_viewport();
                }
                winit_event::WindowEvent::CursorMoved {
                    position: logical_position,
                    ..
                } => {
                    let actual_position =
                        logical_position.to_physical(self.gfx_context.hidpi_factor as f64);
                    self.mouse_context.set_last_position(Point2::new(
                        actual_position.x as f32,
                        actual_position.y as f32,
                    ));
                }
                winit_event::WindowEvent::MouseInput { button, state, .. } => {
                    let pressed = match state {
                        winit_event::ElementState::Pressed => true,
                        winit_event::ElementState::Released => false,
                    };
                    self.mouse_context.set_button(button, pressed);
                }
                winit_event::WindowEvent::KeyboardInput {
                    input:
                        winit::KeyboardInput {
                            state,
                            virtual_keycode: Some(keycode),
                            modifiers,
                            ..
                        },
                    ..
                } => {
                    let pressed = match state {
                        winit_event::ElementState::Pressed => true,
                        winit_event::ElementState::Released => false,
                    };
                    self.keyboard_context
                        .set_modifiers(keyboard::KeyMods::from(modifiers));
                    self.keyboard_context.set_key(keycode, pressed);
                }
                winit_event::WindowEvent::HiDpiFactorChanged(new_hidpi_factor) => {
                    // TODO: Test how this actually works... does winit's hidpi factor change and
                    // we have to account for it here, or does winit just tell us when something
                    // changes?
                    // Well this is actually really hard to test without the right hardware, soooo,
                    // I guess I'll just leave it as this for now.
                    self.gfx_context.hidpi_factor = new_hidpi_factor as f32;
                }
                _ => (),
            },
            winit_event::Event::DeviceEvent { event, .. } => match event {
                winit_event::DeviceEvent::MouseMotion { delta: (x, y) } => {
                    self.mouse_context.set_last_delta(Point2::new(
                        x as f32 * self.gfx_context.hidpi_factor,
                        y as f32 * self.gfx_context.hidpi_factor,
                    ));
                }
                _ => (),
            },

            _ => (),
        };
        event
    }
}

use std::path;

/// A builder object for creating a [`Context`](struct.Context.html).
#[derive(Debug, Clone, PartialEq)]
pub struct ContextBuilder {
    pub(crate) game_id: &'static str,
    pub(crate) author: &'static str,
    pub(crate) conf: conf::Conf,
    pub(crate) paths: Vec<path::PathBuf>,
    pub(crate) load_conf_file: bool,
}

impl ContextBuilder {
    /// Create a new `ContextBuilder` with default settings.
    pub fn new(game_id: &'static str, author: &'static str) -> Self {
        Self {
            game_id,
            author,
            conf: conf::Conf::default(),
            paths: vec![],
            load_conf_file: true,
        }
    }

    /// Sets the window setup settings.
    pub fn window_setup(mut self, setup: conf::WindowSetup) -> Self {
        self.conf.window_setup = setup;
        self
    }

    /// Sets the window mode settings.
    pub fn window_mode(mut self, mode: conf::WindowMode) -> Self {
        self.conf.window_mode = mode;
        self
    }

    /// Sets the graphics backend.
    pub fn backend(mut self, backend: conf::Backend) -> Self {
        self.conf.backend = backend;
        self
    }

    /// Sets the modules configuration.
    pub fn modules(mut self, modules: conf::ModuleConf) -> Self {
        self.conf.modules = modules;
        self
    }

    /// Sets all the config options, overriding any previous
    /// ones from [`window_setup()`](#method.window_setup),
    /// [`window_mode()`](#method.window_mode), and
    /// [`backend()`](#method.backend).
    pub fn conf(mut self, conf: conf::Conf) -> Self {
        self.conf = conf;
        self
    }

    /// Add a new read-only filesystem path to the places to search
    /// for resources.
    pub fn add_resource_path<T>(mut self, path: T) -> Self
    where
        T: Into<path::PathBuf>,
    {
        self.paths.push(path.into());
        self
    }

    /// Specifies whether or not to load the `conf.toml` file if it
    /// exists and use its settings to override the provided values.
    /// Defaults to `true` which is usually what you want, but being
    /// able to fiddle with it is sometimes useful for debugging.
    pub fn with_conf_file(mut self, load_conf_file: bool) -> Self {
        self.load_conf_file = load_conf_file;
        self
    }

    /// Build the `Context`.
    pub fn build(self) -> GameResult<(Context, winit::EventsLoop)> {
        let mut fs = Filesystem::new(self.game_id, self.author)?;

        for path in &self.paths {
            fs.mount(path, true);
        }

        let config = if self.load_conf_file {
            fs.read_config().unwrap_or(self.conf)
        } else {
            self.conf
        };

        Context::from_conf(config, fs)
    }
}

/// Terminates the [`ggez::run()`](fn.run.html) loop by setting
/// [`Context.continuing`](struct.Context.html#structfield.continuing)
/// to `false`.
pub fn quit(ctx: &mut Context) {
    ctx.continuing = false;
}

#[cfg(debug_assertions)]
use std::sync::atomic::{AtomicUsize, Ordering};
#[cfg(debug_assertions)]
static DEBUG_ID_COUNTER: AtomicUsize = AtomicUsize::new(0);

/// This is a type that contains a unique ID for each `Context` and
/// is contained in each thing created from the `Context` which
/// becomes invalid when the `Context` goes away (for example, `Image` because
/// it contains texture handles).  When compiling without assertions
/// (in release mode) it is replaced with a zero-size type, compiles
/// down to nothing, disappears entirely with a puff of optimization logic.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg(debug_assertions)]
pub(crate) struct DebugId(u32);
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg(not(debug_assertions))]
pub(crate) struct DebugId;

#[cfg(debug_assertions)]
impl DebugId {
    pub fn new() -> Self {
        let id = DEBUG_ID_COUNTER.fetch_add(1, Ordering::SeqCst) as u32;
        // fetch_add() wraps on overflow so we check for overflow explicitly.
        // JUST IN CASE YOU TRY TO CREATE 2^32 CONTEXTS IN ONE PROGRAM!  muahahahahaaa
        assert!(DEBUG_ID_COUNTER.load(Ordering::SeqCst) as u32 > id);
        DebugId(id)
    }

    pub fn get(ctx: &Context) -> Self {
        DebugId(ctx.debug_id.0)
    }

    pub fn assert(&self, ctx: &Context) {
        if *self != ctx.debug_id {
            panic!("Tried to use a resource with a Context that did not create it; this should never happen!");
        }
    }
}

#[cfg(not(debug_assertions))]
impl DebugId {
    pub fn new() -> Self {
        DebugId
    }

    pub fn get(_ctx: &Context) -> Self {
        DebugId
    }

    pub fn assert(&self, _ctx: &Context) {
        // Do nothing.
    }
}
<|endoftext|>


<commit_before>use std::backtrace::Backtrace;
use std::error::Error as StdError;
use std::fmt::{self, Debug, Display};

use crate::Error;

/// Provides the `context` method for `Result`.
pub trait Context<T, E> {
    /// Wrap the error value with additional context.
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static;

    /// Wrap the error value with additional context lazily.
    fn with_context<C, F>(self, f: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C;
}

impl<T, E> Context<T, E> for Result<T, E>
where
    E: StdError + Send + Sync + 'static,
{
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
    {
        self.map_err(|error| Error::from(ContextError { error, context }))
    }

    fn with_context<C, F>(self, f: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C,
    {
        self.map_err(|error| {
            Error::from(ContextError {
                context: f(),
                error,
            })
        })
    }
}

impl<T> Context<T, Error> for Result<T, Error> {
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
    {
        self.map_err(|error| Error::from(ContextError { error, context }))
    }

    fn with_context<C, F>(self, f: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C,
    {
        self.map_err(|error| {
            Error::from(ContextError {
                context: f(),
                error,
            })
        })
    }
}

struct ContextError<E, C> {
    error: E,
    context: C,
}

impl<E, C> Debug for ContextError<E, C>
where
    E: Debug,
    C: Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}\n\n{}", self.error, self.context)
    }
}

impl<E, C> Display for ContextError<E, C>
where
    C: Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&self.context, f)
    }
}

impl<E, C> StdError for ContextError<E, C>
where
    E: StdError + 'static,
    C: Display,
{
    fn backtrace(&self) -> Option<&Backtrace> {
        self.error.backtrace()
    }

    fn cause(&self) -> Option<&dyn StdError> {
        Some(&self.error)
    }

    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        Some(&self.error)
    }
}

impl<C> StdError for ContextError<Error, C>
where
    C: Display,
{
    fn backtrace(&self) -> Option<&Backtrace> {
        Some(self.error.backtrace())
    }

    fn cause(&self) -> Option<&dyn StdError> {
        Some(&*self.error)
    }

    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        Some(&*self.error)
    }
}
<commit_msg>Construct ContextError with error and context in consistent order<commit_after>use std::backtrace::Backtrace;
use std::error::Error as StdError;
use std::fmt::{self, Debug, Display};

use crate::Error;

/// Provides the `context` method for `Result`.
pub trait Context<T, E> {
    /// Wrap the error value with additional context.
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static;

    /// Wrap the error value with additional context lazily.
    fn with_context<C, F>(self, f: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C;
}

impl<T, E> Context<T, E> for Result<T, E>
where
    E: StdError + Send + Sync + 'static,
{
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
    {
        self.map_err(|error| Error::from(ContextError { error, context }))
    }

    fn with_context<C, F>(self, f: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C,
    {
        self.map_err(|error| {
            Error::from(ContextError {
                error,
                context: f(),
            })
        })
    }
}

impl<T> Context<T, Error> for Result<T, Error> {
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
    {
        self.map_err(|error| Error::from(ContextError { error, context }))
    }

    fn with_context<C, F>(self, f: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C,
    {
        self.map_err(|error| {
            Error::from(ContextError {
                error,
                context: f(),
            })
        })
    }
}

struct ContextError<E, C> {
    error: E,
    context: C,
}

impl<E, C> Debug for ContextError<E, C>
where
    E: Debug,
    C: Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}\n\n{}", self.error, self.context)
    }
}

impl<E, C> Display for ContextError<E, C>
where
    C: Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&self.context, f)
    }
}

impl<E, C> StdError for ContextError<E, C>
where
    E: StdError + 'static,
    C: Display,
{
    fn backtrace(&self) -> Option<&Backtrace> {
        self.error.backtrace()
    }

    fn cause(&self) -> Option<&dyn StdError> {
        Some(&self.error)
    }

    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        Some(&self.error)
    }
}

impl<C> StdError for ContextError<Error, C>
where
    C: Display,
{
    fn backtrace(&self) -> Option<&Backtrace> {
        Some(self.error.backtrace())
    }

    fn cause(&self) -> Option<&dyn StdError> {
        Some(&*self.error)
    }

    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        Some(&*self.error)
    }
}
<|endoftext|>


<commit_before>//! HTTP/1 implementation
use actix_net::codec::Framed;
use bytes::Bytes;

mod client;
mod codec;
mod decoder;
mod dispatcher;
mod encoder;
mod service;

pub use self::client::{ClientCodec, ClientPayloadCodec};
pub use self::codec::Codec;
pub use self::dispatcher::Dispatcher;
pub use self::service::{H1Service, H1ServiceHandler, OneRequest};

use request::Request;

/// H1 service response type
pub enum H1ServiceResult<T> {
    Disconnected,
    Shutdown(T),
    Unhandled(Request, Framed<T, Codec>),
}

#[derive(Debug)]
/// Codec message
pub enum Message<T> {
    /// Http message
    Item(T),
    /// Payload chunk
    Chunk(Option<Bytes>),
}

impl<T> From<T> for Message<T> {
    fn from(item: T) -> Self {
        Message::Item(item)
    }
}

/// Incoming request type
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MessageType {
    None,
    Payload,
    Stream,
}

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

    impl Message<Request> {
        pub fn message(self) -> Request {
            match self {
                Message::Item(req) => req,
                _ => panic!("error"),
            }
        }

        pub fn chunk(self) -> Bytes {
            match self {
                Message::Chunk(Some(data)) => data,
                _ => panic!("error"),
            }
        }

        pub fn eof(self) -> bool {
            match self {
                Message::Chunk(None) => true,
                Message::Chunk(Some(_)) => false,
                _ => panic!("error"),
            }
        }
    }
}
<commit_msg>add debug impl for H1ServiceResult<commit_after>//! HTTP/1 implementation
use std::fmt;

use actix_net::codec::Framed;
use bytes::Bytes;

mod client;
mod codec;
mod decoder;
mod dispatcher;
mod encoder;
mod service;

pub use self::client::{ClientCodec, ClientPayloadCodec};
pub use self::codec::Codec;
pub use self::dispatcher::Dispatcher;
pub use self::service::{H1Service, H1ServiceHandler, OneRequest};

use request::Request;

/// H1 service response type
pub enum H1ServiceResult<T> {
    Disconnected,
    Shutdown(T),
    Unhandled(Request, Framed<T, Codec>),
}

impl<T: fmt::Debug> fmt::Debug for H1ServiceResult<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            H1ServiceResult::Disconnected => write!(f, "H1ServiceResult::Disconnected"),
            H1ServiceResult::Shutdown(ref v) => {
                write!(f, "H1ServiceResult::Shutdown({:?})", v)
            }
            H1ServiceResult::Unhandled(ref req, _) => {
                write!(f, "H1ServiceResult::Unhandled({:?})", req)
            }
        }
    }
}

#[derive(Debug)]
/// Codec message
pub enum Message<T> {
    /// Http message
    Item(T),
    /// Payload chunk
    Chunk(Option<Bytes>),
}

impl<T> From<T> for Message<T> {
    fn from(item: T) -> Self {
        Message::Item(item)
    }
}

/// Incoming request type
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MessageType {
    None,
    Payload,
    Stream,
}

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

    impl Message<Request> {
        pub fn message(self) -> Request {
            match self {
                Message::Item(req) => req,
                _ => panic!("error"),
            }
        }

        pub fn chunk(self) -> Bytes {
            match self {
                Message::Chunk(Some(data)) => data,
                _ => panic!("error"),
            }
        }

        pub fn eof(self) -> bool {
            match self {
                Message::Chunk(None) => true,
                Message::Chunk(Some(_)) => false,
                _ => panic!("error"),
            }
        }
    }
}
<|endoftext|>


<commit_before>use crypto::Algorithm;

/// A basic JWT header, the alg defaults to HS256 and typ is automatically
/// set to `JWT`. All the other fields are optional.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Header {
    /// The type of JWS: it can only be "JWT" here
    ///
    /// Defined in [RFC7515#4.1.9](https://tools.ietf.org/html/rfc7515#section-4.1.9).
    typ: Option<String>,
    /// The algorithm used
    ///
    /// Defined in [RFC7515#4.1.1](https://tools.ietf.org/html/rfc7515#section-4.1.1).
    pub alg: Algorithm,
    /// Content type
    ///
    /// Defined in [RFC7519#5.2](https://tools.ietf.org/html/rfc7519#section-5.2).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub cty: Option<String>,
    /// JSON Key URL
    ///
    /// Defined in [RFC7515#4.1.2](https://tools.ietf.org/html/rfc7515#section-4.1.2).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub jku: Option<String>,
    /// Key ID
    ///
    /// Defined in [RFC7515#4.1.4](https://tools.ietf.org/html/rfc7515#section-4.1.4).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub kid: Option<String>,
    /// X.509 URL
    ///
    /// Defined in [RFC7515#4.1.5](https://tools.ietf.org/html/rfc7515#section-4.1.5).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub x5u: Option<String>,
    /// X.509 certificate thumbprint
    ///
    /// Defined in [RFC7515#4.1.7](https://tools.ietf.org/html/rfc7515#section-4.1.7).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub x5t: Option<String>,
}

impl Header {
    /// Returns a JWT header with the algorithm given
    pub fn new(algorithm: Algorithm) -> Header {
        Header {
            typ: Some("JWT".to_string()),
            alg: algorithm,
            cty: None,
            jku: None,
            kid: None,
            x5u: None,
            x5t: None,
        }
    }
}

impl Default for Header {
    /// Returns a JWT header using the default Algorithm, HS256
    fn default() -> Self {
        Header::new(Algorithm::default())
    }
}
<commit_msg>Don't serialize typ if None<commit_after>use crypto::Algorithm;

/// A basic JWT header, the alg defaults to HS256 and typ is automatically
/// set to `JWT`. All the other fields are optional.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Header {
    /// The type of JWS: it can only be "JWT" here
    ///
    /// Defined in [RFC7515#4.1.9](https://tools.ietf.org/html/rfc7515#section-4.1.9).
    #[serde(skip_serializing_if = "Option::is_none")]
    typ: Option<String>,
    /// The algorithm used
    ///
    /// Defined in [RFC7515#4.1.1](https://tools.ietf.org/html/rfc7515#section-4.1.1).
    pub alg: Algorithm,
    /// Content type
    ///
    /// Defined in [RFC7519#5.2](https://tools.ietf.org/html/rfc7519#section-5.2).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub cty: Option<String>,
    /// JSON Key URL
    ///
    /// Defined in [RFC7515#4.1.2](https://tools.ietf.org/html/rfc7515#section-4.1.2).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub jku: Option<String>,
    /// Key ID
    ///
    /// Defined in [RFC7515#4.1.4](https://tools.ietf.org/html/rfc7515#section-4.1.4).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub kid: Option<String>,
    /// X.509 URL
    ///
    /// Defined in [RFC7515#4.1.5](https://tools.ietf.org/html/rfc7515#section-4.1.5).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub x5u: Option<String>,
    /// X.509 certificate thumbprint
    ///
    /// Defined in [RFC7515#4.1.7](https://tools.ietf.org/html/rfc7515#section-4.1.7).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub x5t: Option<String>,
}

impl Header {
    /// Returns a JWT header with the algorithm given
    pub fn new(algorithm: Algorithm) -> Header {
        Header {
            typ: Some("JWT".to_string()),
            alg: algorithm,
            cty: None,
            jku: None,
            kid: None,
            x5u: None,
            x5t: None,
        }
    }
}

impl Default for Header {
    /// Returns a JWT header using the default Algorithm, HS256
    fn default() -> Self {
        Header::new(Algorithm::default())
    }
}
<|endoftext|>


<commit_before>//! The initializer module parses arguments and verfies commands are valid
//! The creator module handles creating the muxed directory and project files.
#![allow(experimental)]

use std::io::File;
use std::path::posix::Path;
use editor;
use root;

#[cfg(test)] use std::finally::Finally;
#[cfg(test)] use test_helper::{random_name,cleanup_file};

static TEMPLATE: &'static str = include_str!("creator/template.toml");
static DEFAULT_MUXED_DIR: &'static str = "muxed";

pub fn new(name: &str) {
    let muxed_dir = match root::muxed_dir_exists(&DEFAULT_MUXED_DIR.to_string()) {
        true  => Path::new(format!("{}/.{}/", root::homedir_string(), &DEFAULT_MUXED_DIR.to_string())),
        false => root::create_muxed_dir(&DEFAULT_MUXED_DIR.to_string())
    };

    let path = &Path::new(format!("{}/{}.toml", muxed_dir.display(), name));
    if !path.exists() {
        create_project_file(path);

        match editor::default_editor_set() {
            true  => editor::open_project_file(path),
            false => println!("Default editor is not set. Please define $EDITOR in your ~/.bashrc or similar file.")
        }
    } else {
        println!("Project already exists.");
    }
}

/// Copy and create the new project file from a template. Attempt to open the
/// users default editor to make changes.
fn create_project_file(path: &Path) {
    match File::create(path).write(TEMPLATE.as_bytes()) {
        Ok(()) => (),
        Err(_e) => println!("Failed to create project {}", path.filename()),
    }
}

#[test]
fn creates_project_file() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), name));
    create_project_file(path);
    assert!(path.exists());

    cleanup_file(path);
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), name));
    new(name.as_slice());
    assert!(path.exists());
    match fs::unlink(path) {
        Ok(()) => (), // succeeded
        Err(e) => println!("Failed to unlink the path {} with error {}", path.display(), e),
    }

    cleanup_file(path);
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), name));
    new(name.as_slice());
    assert!(path.exists());

    cleanup_file(path);
}
<commit_msg>Fix comments and spacing.<commit_after>//! The initializer module parses arguments and verfies commands are valid
//! The creator module handles creating the muxed directory and project files.
#![allow(experimental)]

use std::io::File;
use std::path::posix::Path;
use editor;
use root;

#[cfg(test)] use std::finally::Finally;
#[cfg(test)] use test_helper::{random_name,cleanup_file};

static TEMPLATE: &'static str = include_str!("creator/template.toml");
static DEFAULT_MUXED_DIR: &'static str = "muxed";

pub fn new(name: &str) {
    let muxed_dir = match root::muxed_dir_exists(&DEFAULT_MUXED_DIR.to_string()) {
        true  => Path::new(format!("{}/.{}/", root::homedir_string(), &DEFAULT_MUXED_DIR.to_string())),
        false => root::create_muxed_dir(&DEFAULT_MUXED_DIR.to_string())
    };

    let path = &Path::new(format!("{}/{}.toml", muxed_dir.display(), name));
    if !path.exists() {
        create_project_file(path);

        match editor::default_editor_set() {
            true  => editor::open_project_file(path),
            false => println!("Default editor is not set. Please define $EDITOR in your ~/.bashrc or similar file.")
        }
    } else {
        println!("Project already exists.");
    }
}

/// Copy and create the new project file from a template.
fn create_project_file(path: &Path) {
    match File::create(path).write(TEMPLATE.as_bytes()) {
        Ok(())  => (),
        Err(_e) => println!("Failed to create project {}", path.filename()),
    }
}

#[test]
fn creates_project_file() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), name));
    create_project_file(path);
    assert!(path.exists());

    cleanup_file(path);
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), name));
    new(name.as_slice());
    assert!(path.exists());
    match fs::unlink(path) {
        Ok(()) => (), // succeeded
        Err(e) => println!("Failed to unlink the path {} with error {}", path.display(), e),
    }

    cleanup_file(path);
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), name));
    new(name.as_slice());
    assert!(path.exists());

    cleanup_file(path);
}
<|endoftext|>


<commit_before>use socket::Socket;

pub trait Pin: ::std::fmt::Display {
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Gpio {
    DIO0_N,
    DIO0_P,
    DIO1_N,
    DIO1_P,
    DIO2_N,
    DIO2_P,
    DIO3_N,
    DIO3_P,
    DIO4_N,
    DIO4_P,
    DIO5_N,
    DIO5_P,
    DIO6_N,
    DIO6_P,
    DIO7_N,
    DIO7_P,
}

impl Pin for Gpio {
}

impl ::std::fmt::Display for Gpio {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let display = match self {
            &Gpio::DIO0_N => "DIO0_N",
            &Gpio::DIO0_P => "DIO0_P",
            &Gpio::DIO1_N => "DIO1_N",
            &Gpio::DIO1_P => "DIO1_P",
            &Gpio::DIO2_N => "DIO2_N",
            &Gpio::DIO2_P => "DIO2_P",
            &Gpio::DIO3_N => "DIO3_N",
            &Gpio::DIO3_P => "DIO3_P",
            &Gpio::DIO4_N => "DIO4_N",
            &Gpio::DIO4_P => "DIO4_P",
            &Gpio::DIO5_N => "DIO5_N",
            &Gpio::DIO5_P => "DIO5_P",
            &Gpio::DIO6_N => "DIO6_N",
            &Gpio::DIO6_P => "DIO6_P",
            &Gpio::DIO7_N => "DIO7_N",
            &Gpio::DIO7_P => "DIO7_P",
        };

        write!(f, "{}", display)
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Led {
    LED0,
    LED1,
    LED2,
    LED3,
    LED4,
    LED5,
    LED6,
    LED7,
    LED8,
}

impl Pin for Led {
}

impl ::std::fmt::Display for Led {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let display = match self {
            &Led::LED0 => "LED0",
            &Led::LED1 => "LED1",
            &Led::LED2 => "LED2",
            &Led::LED3 => "LED3",
            &Led::LED4 => "LED4",
            &Led::LED5 => "LED5",
            &Led::LED6 => "LED6",
            &Led::LED7 => "LED7",
            &Led::LED8 => "LED8",
        };

        write!(f, "{}", display)
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum State {
    LOW,
    HIGH,
}

impl ::std::fmt::Display for State {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let display = match self {
            &State::LOW => "0",
            &State::HIGH => "1",
        };

        write!(f, "{}", display)
    }
}

impl ::std::str::FromStr for State {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "0" => Ok(State::LOW),
            "1" => Ok(State::HIGH),
            _ => Err(()),
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Direction {
    OUT,
    IN,
}

impl ::std::fmt::Display for Direction {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let display = match self {
            &Direction::OUT => "OUT",
            &Direction::IN => "IN",
        };

        write!(f, "{}", display)
    }
}

#[derive(Clone)]
pub struct Digital {
    socket: ::std::cell::RefCell<Socket>,
}

impl Digital {
    pub fn new(socket: Socket) -> Self {
        Digital {
            socket: ::std::cell::RefCell::new(socket),
        }
    }

    /**
     * Set direction of digital pins to output or input.
     */
    pub fn set_direction<P>(&self, pin: P, direction: Direction)
        where P: Pin
    {
        self.send(format!("DIG:PIN:DIR {},{}", direction, pin));
    }

    /**
     * Set state of digital outputs to 1 (HIGH) or 0 (LOW).
     */
    pub fn set_state<P>(&self, pin: P, state: State)
        where P: Pin
    {
        self.send(format!("DIG:PIN {},{}", pin, state));
    }

    /**
     * Get state of digital inputs and outputs.
     */
    pub fn get_state<P>(&self, pin: P) -> State
        where P: Pin
    {
        self.send(format!("DIG:PIN? {}", pin));

        self.receive()
            .parse()
            .unwrap()
    }

    fn send<D>(&self, message: D)
        where D: ::std::fmt::Display
    {
        let mut socket = self.socket.borrow_mut();

        socket.send(message);
    }

    fn receive(&self) -> String {
        let mut socket = self.socket.borrow_mut();

        socket.receive()
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_set_direction_in() {
        let (rx, digital) = create_digital();

        digital.set_direction(::digital::Gpio::DIO0_N, ::digital::Direction::IN);
        assert_eq!("DIG:PIN:DIR IN,DIO0_N\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_set_direction_out() {
        let (rx, digital) = create_digital();

        digital.set_direction(::digital::Led::LED0, ::digital::Direction::OUT);
        assert_eq!("DIG:PIN:DIR OUT,LED0\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_set_state() {
        let (rx, digital) = create_digital();

        digital.set_state(::digital::Gpio::DIO0_N, ::digital::State::LOW);
        assert_eq!("DIG:PIN DIO0_N,0\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_get_state() {
        let (_, digital) = create_digital();

        assert_eq!(digital.get_state(::digital::Gpio::DIO0_N), ::digital::State::HIGH);
    }

    fn create_digital() -> (::std::sync::mpsc::Receiver<String>, ::digital::Digital) {
        let (addr, rx) = ::test::launch_server();
        let socket = ::socket::Socket::new(addr);

        (rx, ::digital::Digital::new(socket))
    }
}
<commit_msg>[digital] Add digital.reset()<commit_after>use socket::Socket;

pub trait Pin: ::std::fmt::Display {
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Gpio {
    DIO0_N,
    DIO0_P,
    DIO1_N,
    DIO1_P,
    DIO2_N,
    DIO2_P,
    DIO3_N,
    DIO3_P,
    DIO4_N,
    DIO4_P,
    DIO5_N,
    DIO5_P,
    DIO6_N,
    DIO6_P,
    DIO7_N,
    DIO7_P,
}

impl Pin for Gpio {
}

impl ::std::fmt::Display for Gpio {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let display = match self {
            &Gpio::DIO0_N => "DIO0_N",
            &Gpio::DIO0_P => "DIO0_P",
            &Gpio::DIO1_N => "DIO1_N",
            &Gpio::DIO1_P => "DIO1_P",
            &Gpio::DIO2_N => "DIO2_N",
            &Gpio::DIO2_P => "DIO2_P",
            &Gpio::DIO3_N => "DIO3_N",
            &Gpio::DIO3_P => "DIO3_P",
            &Gpio::DIO4_N => "DIO4_N",
            &Gpio::DIO4_P => "DIO4_P",
            &Gpio::DIO5_N => "DIO5_N",
            &Gpio::DIO5_P => "DIO5_P",
            &Gpio::DIO6_N => "DIO6_N",
            &Gpio::DIO6_P => "DIO6_P",
            &Gpio::DIO7_N => "DIO7_N",
            &Gpio::DIO7_P => "DIO7_P",
        };

        write!(f, "{}", display)
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Led {
    LED0,
    LED1,
    LED2,
    LED3,
    LED4,
    LED5,
    LED6,
    LED7,
    LED8,
}

impl Pin for Led {
}

impl ::std::fmt::Display for Led {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let display = match self {
            &Led::LED0 => "LED0",
            &Led::LED1 => "LED1",
            &Led::LED2 => "LED2",
            &Led::LED3 => "LED3",
            &Led::LED4 => "LED4",
            &Led::LED5 => "LED5",
            &Led::LED6 => "LED6",
            &Led::LED7 => "LED7",
            &Led::LED8 => "LED8",
        };

        write!(f, "{}", display)
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum State {
    LOW,
    HIGH,
}

impl ::std::fmt::Display for State {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let display = match self {
            &State::LOW => "0",
            &State::HIGH => "1",
        };

        write!(f, "{}", display)
    }
}

impl ::std::str::FromStr for State {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "0" => Ok(State::LOW),
            "1" => Ok(State::HIGH),
            _ => Err(()),
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Direction {
    OUT,
    IN,
}

impl ::std::fmt::Display for Direction {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let display = match self {
            &Direction::OUT => "OUT",
            &Direction::IN => "IN",
        };

        write!(f, "{}", display)
    }
}

#[derive(Clone)]
pub struct Digital {
    socket: ::std::cell::RefCell<Socket>,
}

impl Digital {
    pub fn new(socket: Socket) -> Self {
        Digital {
            socket: ::std::cell::RefCell::new(socket),
        }
    }

    /**
     * Sets digital pins to default values.
     *
     * Pins DIO1_P - DIO7_P, RP_DIO0_N - RP_DIO7_N are set al OUTPUT and to LOW.
     * LEDs are set to LOW/OFF
     */
    pub fn reset(&self) {
        self.send("DIG:RST");
    }

    /**
     * Set direction of digital pins to output or input.
     */
    pub fn set_direction<P>(&self, pin: P, direction: Direction)
        where P: Pin
    {
        self.send(format!("DIG:PIN:DIR {},{}", direction, pin));
    }

    /**
     * Set state of digital outputs to 1 (HIGH) or 0 (LOW).
     */
    pub fn set_state<P>(&self, pin: P, state: State)
        where P: Pin
    {
        self.send(format!("DIG:PIN {},{}", pin, state));
    }

    /**
     * Get state of digital inputs and outputs.
     */
    pub fn get_state<P>(&self, pin: P) -> State
        where P: Pin
    {
        self.send(format!("DIG:PIN? {}", pin));

        self.receive()
            .parse()
            .unwrap()
    }

    fn send<D>(&self, message: D)
        where D: ::std::fmt::Display
    {
        let mut socket = self.socket.borrow_mut();

        socket.send(message);
    }

    fn receive(&self) -> String {
        let mut socket = self.socket.borrow_mut();

        socket.receive()
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_reset() {
        let (rx, digital) = create_digital();

        digital.reset();
        assert_eq!("DIG:RST\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_set_direction_in() {
        let (rx, digital) = create_digital();

        digital.set_direction(::digital::Gpio::DIO0_N, ::digital::Direction::IN);
        assert_eq!("DIG:PIN:DIR IN,DIO0_N\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_set_direction_out() {
        let (rx, digital) = create_digital();

        digital.set_direction(::digital::Led::LED0, ::digital::Direction::OUT);
        assert_eq!("DIG:PIN:DIR OUT,LED0\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_set_state() {
        let (rx, digital) = create_digital();

        digital.set_state(::digital::Gpio::DIO0_N, ::digital::State::LOW);
        assert_eq!("DIG:PIN DIO0_N,0\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_get_state() {
        let (_, digital) = create_digital();

        assert_eq!(digital.get_state(::digital::Gpio::DIO0_N), ::digital::State::HIGH);
    }

    fn create_digital() -> (::std::sync::mpsc::Receiver<String>, ::digital::Digital) {
        let (addr, rx) = ::test::launch_server();
        let socket = ::socket::Socket::new(addr);

        (rx, ::digital::Digital::new(socket))
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! Display — Controls a set of GdkScreens and their associated input devices
//!
//! #Description
//!
//! Display objects purpose are two fold:
//! * To manage and provide information about input devices (pointers and keyboards)
//! * To manage and provide information about the available Screens
//!
//! Display objects are the GDK representation of an X Display, which can be described as
//! a workstation consisting of a keyboard, a pointing device (such as a mouse) and one or
//! more screens. It is used to open and keep track of various GdkScreen objects currently
//! instantiated by the application. It is also used to access the keyboard(s) and mouse
//! pointer(s) of the display.
//!
//! Most of the input device handling has been factored out into the separate DeviceManager
//! object. Every display has a device manager, which you can obtain using
//! Display::get_device_manager().

use ffi;
use glib::translate::*;
use glib::types::{StaticType, Type};
use atom::Atom;
use app_launch_context::AppLaunchContext;
use device::Device;
use device_manager::DeviceManager;
use object::Object;
use screen::Screen;
use window::Window;

pub type Display = Object<ffi::GdkDisplay>;

impl StaticType for Display {
    fn static_type() -> Type { unsafe { from_glib(ffi::gdk_display_get_type()) } }
}

impl Display {
    /// Opens a display.
    pub fn open(display_name: &str) -> Option<Display> {
        unsafe { from_glib_none(ffi::gdk_display_open(display_name.to_glib_none().0)) }
    }

    /// Gets the default Display. This is a convenience function for:
    /// DisplayManager::get_default_display(DisplayManager::get()).
    pub fn get_default() -> Option<Display> {
        unsafe { from_glib_none(ffi::gdk_display_get_default()) }
    }

    /// Gets the name of the display.
    pub fn get_name(&self) -> String {
        unsafe { from_glib_none(ffi::gdk_display_get_name(self.to_glib_none().0)) }
    }

    /// Returns a screen object for one of the screens of the display.
    pub fn get_screen(&self, screen_num: i32) -> Screen {
        unsafe { from_glib_none(ffi::gdk_display_get_screen(self.to_glib_none().0, screen_num)) }
    }

    /// Get the default Screen for `self`.
    pub fn get_default_screen(&self) -> Screen {
        unsafe {
            from_glib_none(ffi::gdk_display_get_default_screen(self.to_glib_none().0))
        }
    }

    /// Returns the DeviceManager associated to `self`.
    pub fn get_device_manager(&self) -> Option<DeviceManager> {
        unsafe { from_glib_none(ffi::gdk_display_get_device_manager(self.to_glib_none().0)) }
    }

    /// Returns true if there is an ongoing grab on `device` for `self`.
    pub fn device_is_grabbed(&self, device: &Device) -> bool {
        unsafe {
            from_glib(ffi::gdk_display_device_is_grabbed(self.to_glib_none().0,
                      device.to_glib_none().0))
        }
    }

    /// Emits a short beep on `self`.
    pub fn beep(&self) {
        unsafe { ffi::gdk_display_beep(self.to_glib_none().0) }
    }

    /// Flushes any requests queued for the windowing system and waits until all requests
    /// have been handled. This is often used for making sure that the display is synchronized
    /// with the current state of the program. Calling Display::sync() before
    /// gdk::error_trap_pop() makes sure that any errors generated from earlier requests are
    /// handled before the error trap is removed.
    ///
    /// This is most useful for X11. On windowing systems where requests are handled
    /// synchronously, this function will do nothing.
    pub fn sync(&self) {
        unsafe { ffi::gdk_display_sync(self.to_glib_none().0) }
    }

    /// Flushes any requests queued for the windowing system; this happens automatically when
    /// the main loop blocks waiting for new events, but if your application is drawing without
    /// returning control to the main loop, you may need to call this function explicitly. A
    /// common case where this function needs to be called is when an application is executing
    /// drawing commands from a thread other than the thread where the main loop is running.
    ///
    /// This is most useful for X11. On windowing systems where requests are handled synchronously,
    /// this function will do nothing.
    pub fn flush(&self) {
        unsafe { ffi::gdk_display_flush(self.to_glib_none().0) }
    }

    /// Closes the connection to the windowing system for the given display, and cleans up
    /// associated resources.
    pub fn close(&self) {
        unsafe { ffi::gdk_display_close(self.to_glib_none().0) }
    }

    /// Finds out if the display has been closed.
    pub fn is_closed(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_is_closed(self.to_glib_none().0)) }
    }

    /*pub fn get_event(&self) -> Option<::Event> {
        unsafe { ffi::gdk_display_get_event(self.to_glib_none().0) };

        if tmp.is_null() {
            None
        } else {
            unsafe { Some(::Event::wrap(tmp)) }
        }
    }

    pub fn peek_event(&self) -> Option<::Event> {
        unsafe { ffi::gdk_display_peek_event(self.to_glib_none().0) };

        if tmp.is_null() {
            None
        } else {
            unsafe { Some(::Event::wrap(tmp)) }
        }
    }

    pub fn put_event(&self, event: &::Event) {
        unsafe { ffi::gdk_display_put_event(self.to_glib_none().0, event.to_glib_none().0 as *const ffi::GdkEvent) }
    }*/

    /// Returns whether the display has events that are waiting to be processed.
    pub fn has_pending(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_has_pending(self.to_glib_none().0)) }
    }

    /// Sets the double click time (two clicks within this time interval count as a double click
    /// and result in a GDK_2BUTTON_PRESS event). Applications should not set this, it is a global
    /// user-configured setting.
    pub fn set_double_click_time(&self, msec: u32) {
        unsafe { ffi::gdk_display_set_double_click_time(self.to_glib_none().0, msec) }
    }

    /// Sets the double click distance (two clicks within this distance count as a double click and
    /// result in a GDK_2BUTTON_PRESS event). See also Display::set_double_click_time(). Applications
    /// should not set this, it is a global user-configured setting.
    pub fn set_double_click_distance(&self, msec: u32) {
        unsafe { ffi::gdk_display_set_double_click_distance(self.to_glib_none().0, msec) }
    }

    /// Returns true if multicolored cursors are supported on `self`. Otherwise, cursors have only a
    /// foerground and a background color.
    pub fn supports_cursor_color(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_cursor_color(self.to_glib_none().0)) }
    }

    /// Returns true if cursors can use an 8bit alpha channel on `self`. Otherwise, cursors are
    /// restricted to bilevel alpha (i.e. a mask).
    pub fn supports_cursor_alpha(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_cursor_alpha(self.to_glib_none().0)) }
    }

    /// Returns the default size to use for cursors on `self`.
    pub fn get_default_cursor_size(&self) -> u32 {
        unsafe { ffi::gdk_display_get_default_cursor_size(self.to_glib_none().0) }
    }

    /// Gets the maximal size to use for cursors on `self`.
    pub fn get_maximal_cursor_size(&self, width: &mut u32, height: &mut u32) {
        unsafe { ffi::gdk_display_get_maximal_cursor_size(self.to_glib_none().0, width, height) }
    }

    /// Returns the default group leader window for all toplevel windows on `self`. This
    /// window is implicitly created by GDK. See Window::set_group().
    pub fn get_default_group(&self) -> Window {
        unsafe { from_glib_none(ffi::gdk_display_get_default_group(self.to_glib_none().0)) }
    }

    /// Returns whether GdkEventOwnerChange events will be sent when the owner of a selection
    /// changes.
    pub fn supports_selection_notification(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_selection_notification(self.to_glib_none().0)) }
    }

    /// Request GdkEventOwnerChange events for ownership changes of the selection named by the
    /// given atom.
    pub fn request_selection_notification(&self, selection: &Atom) -> bool {
        unsafe {
            from_glib(
                ffi::gdk_display_request_selection_notification(self.to_glib_none().0,
                    selection.to_glib_none().0))
        }
    }

    /// Returns whether the speicifed display supports clipboard persistance; i.e. if it’s
    /// possible to store the clipboard data after an application has quit. On X11 this checks
    /// if a clipboard daemon is running.
    pub fn supports_clipboard_persistence(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_clipboard_persistence(self.to_glib_none().0)) }
    }

    /*pub fn store_clipboard(&self, clipboard_window: &::Window, time_: u32, targets: Vec<Atom>) {
        unsafe { ffi::gdk_display_store_clipboard(self.to_glib_none().0, clipboard_window.to_glib_none().0, time_, targets.as_mut_pointer(),
            targets.len() as c_int) }
    }*/

    /// Returns true if Window::shape_combine_mask() can be used to create shaped windows on
    /// `self`.
    pub fn supports_shapes(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_shapes(self.to_glib_none().0)) }
    }

    /// Returns true if Window::input_shape_combine_mask() can be used to modify the input shape
    /// of windows on `self`.
    pub fn supports_input_shapes(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_input_shapes(self.to_glib_none().0)) }
    }

    /// Returns true if Window::set_composited() can be used to redirect drawing on the window
    /// using compositing.
    ///
    /// Currently this only works on X11 with XComposite and XDamage extensions available.
    ///
    /// Deprecated since GDK 3.16
    #[cfg(not(gdk_3_16))]
    pub fn supports_composite(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_composite(self.to_glib_none().0)) }
    }

    /// Returns an AppLaunchContext suitable for launching applications on the given display.
    pub fn get_app_launch_context(&self) -> AppLaunchContext {
        unsafe { from_glib_full(ffi::gdk_display_get_app_launch_context(self.to_glib_none().0)) }
    }

    /// Indicates to the GUI environment that the application has finished loading, using a
    /// given identifier.
    ///
    /// GTK+ will call this function automatically for GtkWindow with custom startup-notification
    /// identifier unless gtk::Window::set_auto_startup_notification() is called to disable that
    /// feature.
    pub fn notify_startup_complete(&self, startup_id: &str) {
        unsafe {
            ffi::gdk_display_notify_startup_complete(self.to_glib_none().0,
                                                     startup_id.to_glib_none().0)
        }
    }
}
<commit_msg>Remove cfg(not(gdk_3_16)) -- this is not how we handle deprecation<commit_after>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! Display — Controls a set of GdkScreens and their associated input devices
//!
//! #Description
//!
//! Display objects purpose are two fold:
//! * To manage and provide information about input devices (pointers and keyboards)
//! * To manage and provide information about the available Screens
//!
//! Display objects are the GDK representation of an X Display, which can be described as
//! a workstation consisting of a keyboard, a pointing device (such as a mouse) and one or
//! more screens. It is used to open and keep track of various GdkScreen objects currently
//! instantiated by the application. It is also used to access the keyboard(s) and mouse
//! pointer(s) of the display.
//!
//! Most of the input device handling has been factored out into the separate DeviceManager
//! object. Every display has a device manager, which you can obtain using
//! Display::get_device_manager().

use ffi;
use glib::translate::*;
use glib::types::{StaticType, Type};
use atom::Atom;
use app_launch_context::AppLaunchContext;
use device::Device;
use device_manager::DeviceManager;
use object::Object;
use screen::Screen;
use window::Window;

pub type Display = Object<ffi::GdkDisplay>;

impl StaticType for Display {
    fn static_type() -> Type { unsafe { from_glib(ffi::gdk_display_get_type()) } }
}

impl Display {
    /// Opens a display.
    pub fn open(display_name: &str) -> Option<Display> {
        unsafe { from_glib_none(ffi::gdk_display_open(display_name.to_glib_none().0)) }
    }

    /// Gets the default Display. This is a convenience function for:
    /// DisplayManager::get_default_display(DisplayManager::get()).
    pub fn get_default() -> Option<Display> {
        unsafe { from_glib_none(ffi::gdk_display_get_default()) }
    }

    /// Gets the name of the display.
    pub fn get_name(&self) -> String {
        unsafe { from_glib_none(ffi::gdk_display_get_name(self.to_glib_none().0)) }
    }

    /// Returns a screen object for one of the screens of the display.
    pub fn get_screen(&self, screen_num: i32) -> Screen {
        unsafe { from_glib_none(ffi::gdk_display_get_screen(self.to_glib_none().0, screen_num)) }
    }

    /// Get the default Screen for `self`.
    pub fn get_default_screen(&self) -> Screen {
        unsafe {
            from_glib_none(ffi::gdk_display_get_default_screen(self.to_glib_none().0))
        }
    }

    /// Returns the DeviceManager associated to `self`.
    pub fn get_device_manager(&self) -> Option<DeviceManager> {
        unsafe { from_glib_none(ffi::gdk_display_get_device_manager(self.to_glib_none().0)) }
    }

    /// Returns true if there is an ongoing grab on `device` for `self`.
    pub fn device_is_grabbed(&self, device: &Device) -> bool {
        unsafe {
            from_glib(ffi::gdk_display_device_is_grabbed(self.to_glib_none().0,
                      device.to_glib_none().0))
        }
    }

    /// Emits a short beep on `self`.
    pub fn beep(&self) {
        unsafe { ffi::gdk_display_beep(self.to_glib_none().0) }
    }

    /// Flushes any requests queued for the windowing system and waits until all requests
    /// have been handled. This is often used for making sure that the display is synchronized
    /// with the current state of the program. Calling Display::sync() before
    /// gdk::error_trap_pop() makes sure that any errors generated from earlier requests are
    /// handled before the error trap is removed.
    ///
    /// This is most useful for X11. On windowing systems where requests are handled
    /// synchronously, this function will do nothing.
    pub fn sync(&self) {
        unsafe { ffi::gdk_display_sync(self.to_glib_none().0) }
    }

    /// Flushes any requests queued for the windowing system; this happens automatically when
    /// the main loop blocks waiting for new events, but if your application is drawing without
    /// returning control to the main loop, you may need to call this function explicitly. A
    /// common case where this function needs to be called is when an application is executing
    /// drawing commands from a thread other than the thread where the main loop is running.
    ///
    /// This is most useful for X11. On windowing systems where requests are handled synchronously,
    /// this function will do nothing.
    pub fn flush(&self) {
        unsafe { ffi::gdk_display_flush(self.to_glib_none().0) }
    }

    /// Closes the connection to the windowing system for the given display, and cleans up
    /// associated resources.
    pub fn close(&self) {
        unsafe { ffi::gdk_display_close(self.to_glib_none().0) }
    }

    /// Finds out if the display has been closed.
    pub fn is_closed(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_is_closed(self.to_glib_none().0)) }
    }

    /*pub fn get_event(&self) -> Option<::Event> {
        unsafe { ffi::gdk_display_get_event(self.to_glib_none().0) };

        if tmp.is_null() {
            None
        } else {
            unsafe { Some(::Event::wrap(tmp)) }
        }
    }

    pub fn peek_event(&self) -> Option<::Event> {
        unsafe { ffi::gdk_display_peek_event(self.to_glib_none().0) };

        if tmp.is_null() {
            None
        } else {
            unsafe { Some(::Event::wrap(tmp)) }
        }
    }

    pub fn put_event(&self, event: &::Event) {
        unsafe { ffi::gdk_display_put_event(self.to_glib_none().0, event.to_glib_none().0 as *const ffi::GdkEvent) }
    }*/

    /// Returns whether the display has events that are waiting to be processed.
    pub fn has_pending(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_has_pending(self.to_glib_none().0)) }
    }

    /// Sets the double click time (two clicks within this time interval count as a double click
    /// and result in a GDK_2BUTTON_PRESS event). Applications should not set this, it is a global
    /// user-configured setting.
    pub fn set_double_click_time(&self, msec: u32) {
        unsafe { ffi::gdk_display_set_double_click_time(self.to_glib_none().0, msec) }
    }

    /// Sets the double click distance (two clicks within this distance count as a double click and
    /// result in a GDK_2BUTTON_PRESS event). See also Display::set_double_click_time(). Applications
    /// should not set this, it is a global user-configured setting.
    pub fn set_double_click_distance(&self, msec: u32) {
        unsafe { ffi::gdk_display_set_double_click_distance(self.to_glib_none().0, msec) }
    }

    /// Returns true if multicolored cursors are supported on `self`. Otherwise, cursors have only a
    /// foerground and a background color.
    pub fn supports_cursor_color(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_cursor_color(self.to_glib_none().0)) }
    }

    /// Returns true if cursors can use an 8bit alpha channel on `self`. Otherwise, cursors are
    /// restricted to bilevel alpha (i.e. a mask).
    pub fn supports_cursor_alpha(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_cursor_alpha(self.to_glib_none().0)) }
    }

    /// Returns the default size to use for cursors on `self`.
    pub fn get_default_cursor_size(&self) -> u32 {
        unsafe { ffi::gdk_display_get_default_cursor_size(self.to_glib_none().0) }
    }

    /// Gets the maximal size to use for cursors on `self`.
    pub fn get_maximal_cursor_size(&self, width: &mut u32, height: &mut u32) {
        unsafe { ffi::gdk_display_get_maximal_cursor_size(self.to_glib_none().0, width, height) }
    }

    /// Returns the default group leader window for all toplevel windows on `self`. This
    /// window is implicitly created by GDK. See Window::set_group().
    pub fn get_default_group(&self) -> Window {
        unsafe { from_glib_none(ffi::gdk_display_get_default_group(self.to_glib_none().0)) }
    }

    /// Returns whether GdkEventOwnerChange events will be sent when the owner of a selection
    /// changes.
    pub fn supports_selection_notification(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_selection_notification(self.to_glib_none().0)) }
    }

    /// Request GdkEventOwnerChange events for ownership changes of the selection named by the
    /// given atom.
    pub fn request_selection_notification(&self, selection: &Atom) -> bool {
        unsafe {
            from_glib(
                ffi::gdk_display_request_selection_notification(self.to_glib_none().0,
                    selection.to_glib_none().0))
        }
    }

    /// Returns whether the speicifed display supports clipboard persistance; i.e. if it’s
    /// possible to store the clipboard data after an application has quit. On X11 this checks
    /// if a clipboard daemon is running.
    pub fn supports_clipboard_persistence(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_clipboard_persistence(self.to_glib_none().0)) }
    }

    /*pub fn store_clipboard(&self, clipboard_window: &::Window, time_: u32, targets: Vec<Atom>) {
        unsafe { ffi::gdk_display_store_clipboard(self.to_glib_none().0, clipboard_window.to_glib_none().0, time_, targets.as_mut_pointer(),
            targets.len() as c_int) }
    }*/

    /// Returns true if Window::shape_combine_mask() can be used to create shaped windows on
    /// `self`.
    pub fn supports_shapes(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_shapes(self.to_glib_none().0)) }
    }

    /// Returns true if Window::input_shape_combine_mask() can be used to modify the input shape
    /// of windows on `self`.
    pub fn supports_input_shapes(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_input_shapes(self.to_glib_none().0)) }
    }

    /// Returns true if Window::set_composited() can be used to redirect drawing on the window
    /// using compositing.
    ///
    /// Currently this only works on X11 with XComposite and XDamage extensions available.
    ///
    /// Deprecated since GDK 3.16
    pub fn supports_composite(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_composite(self.to_glib_none().0)) }
    }

    /// Returns an AppLaunchContext suitable for launching applications on the given display.
    pub fn get_app_launch_context(&self) -> AppLaunchContext {
        unsafe { from_glib_full(ffi::gdk_display_get_app_launch_context(self.to_glib_none().0)) }
    }

    /// Indicates to the GUI environment that the application has finished loading, using a
    /// given identifier.
    ///
    /// GTK+ will call this function automatically for GtkWindow with custom startup-notification
    /// identifier unless gtk::Window::set_auto_startup_notification() is called to disable that
    /// feature.
    pub fn notify_startup_complete(&self, startup_id: &str) {
        unsafe {
            ffi::gdk_display_notify_startup_complete(self.to_glib_none().0,
                                                     startup_id.to_glib_none().0)
        }
    }
}
<|endoftext|>