<commit_before>#![allow(missing_docs)]

use std::any::Any;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::panic;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, AtomicBool, ATOMIC_USIZE_INIT, Ordering};
use std::thread;

use Future;
use token::Tokens;
use slot::Slot;

pub struct Task {
    id: usize,
    ready: usize,
    list: Box<Any + Send>,
    handle: TaskHandle,
    tokens: Tokens,
}

pub struct ScopedTask<'a> {
    task: &'a mut Task,
    reset: bool,
}

#[derive(Clone)]
pub struct TaskHandle {
    inner: Arc<Inner>,
}

struct Inner {
    slot: Slot<(Task, Box<Future<Item=(), Error=()>>)>,
    tokens: Tokens,
    registered: AtomicBool,
}

pub struct TaskData {
    id: usize,
    ptr: *mut A,
}

impl Task {
    pub fn new() -> Task {
        static NEXT: AtomicUsize = ATOMIC_USIZE_INIT;

        Task {
            // TODO: what to do if this overflows?
            id: NEXT.fetch_add(1, Ordering::SeqCst),
            list: Box::new(()),
            tokens: Tokens::all(),
            ready: 0,
            handle: TaskHandle {
                inner: Arc::new(Inner {
                    slot: Slot::new(None),
                    registered: AtomicBool::new(false),
                    tokens: Tokens::all(),
                }),
            },
        }
    }

    pub fn may_contain(&self, token: usize) -> bool {
        self.ready > 0 || self.tokens.may_contain(token)
    }

    pub fn insert(&mut self, a: A) -> TaskData
        where A: Any + Send + 'static,
    {
        struct Node<T: ?Sized> {
            _next: Box<Any + Send>,
            data: T,
        }

        let prev = mem::replace(&mut self.list, Box::new(()));
        let mut next = Box::new(Node { _next: prev, data: a });
        let ret = TaskData { id: self.id, ptr: &mut next.data };
        self.list = next;
        return ret
    }

    pub fn get(&self, data: &TaskData) -> &A
        where A: Send + 'static,
    {
        assert_eq!(data.id, self.id);
        unsafe { &*data.ptr }
    }

    pub fn get_mut(&mut self, data: &TaskData) -> &mut A
        where A: Send + 'static,
    {
        assert_eq!(data.id, self.id);
        unsafe { &mut *data.ptr }
    }

    pub fn handle(&self) -> &TaskHandle {
        &self.handle
    }

    // TODO: terrible name
    pub fn scoped(&mut self) -> ScopedTask {
        ScopedTask { task: self, reset: false }
    }

    pub fn run(self, mut future: Box<Future<Item=(), Error=()>>) {
        let mut me = self;
        loop {
            // Note that we need to poll at least once as the wake callback may
            // have received an empty set of tokens, but that's still a valid
            // reason to poll a future.
            me.tokens = me.handle.inner.tokens.take();
            let result = catch_unwind(move || {
                (future.poll(&mut me), future, me)
            });
            match result {
                Ok((ref r, _, _)) if r.is_ready() => return,
                Ok((_, f, t)) => {
                    future = f;
                    me = t;
                }
                // TODO: do something smarter
                Err(e) => panic::resume_unwind(e),
            }
            future = match future.tailcall() {
                Some(f) => f,
                None => future,
            };
            if !me.handle.inner.tokens.any() {
                break
            }
        }

        // Ok, we've seen that there are no tokens which show interest in the
        // future. Schedule interest on the future for when something is ready
        // and then relinquish the future and the forget back to the slot, which
        // will then pick it up once a wake callback has fired.
        future.schedule(&mut me);

        // TODO: don't clone if we've been scheduled immediately
        let inner = me.handle.inner.clone();
        inner.slot.try_produce((me, future)).ok().unwrap();
    }

    pub fn notify(&mut self) {
        // TODO: optimize this
        self.handle().notify()
    }
}

fn catch_unwind<F, U>(f: F) -> thread::Result
    where F: FnOnce() -> U + Send + 'static,
{
    panic::catch_unwind(panic::AssertUnwindSafe(f))
}

impl TaskHandle {
    pub fn token_ready(&self, token: usize) {
        self.inner.tokens.insert(token);
    }

    pub fn equivalent(&self, other: &TaskHandle) -> bool {
        &*self.inner as *const _ == &*other.inner as *const _
    }

    pub fn notify(&self) {
        // Next, see if we can actually register an `on_full` callback. The
        // `Slot` requires that only one registration happens, and this flag
        // guards that.
        if self.inner.registered.swap(true, Ordering::SeqCst) {
            return
        }

        // If we won the race to register a callback, do so now. Once the slot
        // is resolve we allow another registration **before we poll again**.
        // This allows any future which may be somewhat badly behaved to be
        // compatible with this.
        //
        // TODO: this store of `false` should *probably* be before the
        //       `schedule` call in forget above, need to think it through.
        self.inner.slot.on_full(|slot| {
            let (task, future) = slot.try_consume().ok().unwrap();
            task.handle.inner.registered.store(false, Ordering::SeqCst);
            task.run(future)
        });
    }
}

impl<'a> ScopedTask<'a> {
    pub fn ready(&mut self) -> &mut ScopedTask<'a>{
        if !self.reset {
            self.reset = true;
            self.task.ready += 1;
        }
        self
    }
}

impl<'a> Deref for ScopedTask<'a> {
    type Target = Task;
    fn deref(&self) -> &Task {
        &*self.task
    }
}

impl<'a> DerefMut for ScopedTask<'a> {
    fn deref_mut(&mut self) -> &mut Task {
        &mut *self.task
    }
}

impl<'a> Drop for ScopedTask<'a> {
    fn drop(&mut self) {
        if self.reset {
            self.task.ready -= 1;
        }
    }
}

impl Clone for TaskData {
    fn clone(&self) -> TaskData {
        TaskData {
            id: self.id,
            ptr: self.ptr,
        }
    }
}

impl Copy for TaskData {}
<commit_msg>Document the task module<commit_after>use std::any::Any;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::panic;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, AtomicBool, ATOMIC_USIZE_INIT, Ordering};
use std::thread;

use Future;
use token::Tokens;
use slot::Slot;

/// A structure representing one "task", or thread of execution throughout the
/// lifetime of a set of futures.
///
/// It's intended that futures are composed together to form a large "task" of
/// futures which is driven as a whole throughout its lifetime. This task is
/// persistent for the entire lifetime of the future until its completion,
/// carrying any local data and such.
///
/// Currently tasks serve two primary purposes:
///
/// * They're used to drive futures to completion, e.g. executors (more to be
///   changed here soon).
/// * They store task local data. That is, any task can contain any number of
///   pieces of arbitrary data which can be accessed at a later date. The data
///   is owned and carried in the task itself, and `TaskData` handles are used
///   to access the internals.
///
/// This structure is likely to expand more customizable functionality over
/// time! That is, it's not quite done yet...
pub struct Task {
    id: usize,
    ready: usize,
    list: Box<Any + Send>,
    handle: TaskHandle,
    tokens: Tokens,
}

/// A scoped version of a task, returned by the `Task::scoped` method.
pub struct ScopedTask<'a> {
    task: &'a mut Task,
    reset: bool,
}

/// A handle to a task that can be sent to other threads.
///
/// Created by the `Task::handle` method.
#[derive(Clone)]
pub struct TaskHandle {
    inner: Arc<Inner>,
}

struct Inner {
    slot: Slot<(Task, Box<Future<Item=(), Error=()>>)>,
    tokens: Tokens,
    registered: AtomicBool,
}

/// A reference to a piece of data that's stored inside of a `Task`.
///
/// This can be used with the `Task::get` and `Task::get_mut` methods to access
/// data inside of tasks.
pub struct TaskData {
    id: usize,
    ptr: *mut A,
}

impl Task {
    /// Creates a new task ready to drive a future.
    ///
    /// The returned task has no internal data stored in it and considers all
    /// tokens "ready for polling" until informed otherwise.
    pub fn new() -> Task {
        static NEXT: AtomicUsize = ATOMIC_USIZE_INIT;

        // TODO: what to do if this overflows?
        let id = NEXT.fetch_add(1, Ordering::SeqCst);
        assert!(id != usize::max_value());

        Task {
            id: id,
            list: Box::new(()),
            tokens: Tokens::all(),
            ready: 0,
            handle: TaskHandle {
                inner: Arc::new(Inner {
                    slot: Slot::new(None),
                    registered: AtomicBool::new(false),
                    tokens: Tokens::all(),
                }),
            },
        }
    }

    /// Tests whether a token may be ready for polling.
    ///
    /// As events come in interest in particular tokens can be signaled through
    /// the `TaskHandle::token_ready` method. This method can then be used to
    /// see whether a token has arrive yet or not.
    ///
    /// Note that this will never return a false negative, but it can return
    /// false positives. That is, if a token has been passed to `token_ready`,
    /// that exact token will always return `true`. If a token has not been
    /// passed to `token_ready`, though, it may still return `true`. (e.g. this
    /// is a bloom filter).
    // TODO: probably want an opaque type around usize
    // TODO: needs a better name
    pub fn may_contain(&self, token: usize) -> bool {
        self.ready > 0 || self.tokens.may_contain(token)
    }

    /// Inserts a new piece of task-local data into this task, returning a
    /// reference to it.
    ///
    /// Ownership of the data will be transferred to the task, and the data will
    /// be destroyed when the task itself is destroyed. The returned value can
    /// be passed to the `Task::{get, get_mut}` methods to get a reference back
    /// to the original data.
    ///
    /// Note that the returned handle is cloneable and copyable and can be sent
    /// to other futures which will be associated with the same task. All
    /// futures will then have access to this data when passed the reference
    /// back.
    pub fn insert(&mut self, a: A) -> TaskData
        where A: Any + Send + 'static,
    {
        // Right now our list of task-local data is just stored as a linked
        // list, so allocate a new node and insert it into the list.
        struct Node<T: ?Sized> {
            _next: Box<Any + Send>,
            data: T,
        }
        let prev = mem::replace(&mut self.list, Box::new(()));
        let mut next = Box::new(Node { _next: prev, data: a });
        let ret = TaskData { id: self.id, ptr: &mut next.data };
        self.list = next;
        return ret
    }

    /// Get a reference to the task-local data inside this task.
    ///
    /// This method should be passed a handle previously returned by
    /// `Task::insert`. That handle, when passed back into this method, will
    /// retrieve a reference to the original data.
    ///
    /// # Panics
    ///
    /// This method will panic if `data` does not belong to this task. That is,
    /// if another task generated the `data` handle passed in, this method will
    /// panic.
    pub fn get(&self, data: &TaskData) -> &A
        where A: Send + 'static,
    {
        assert_eq!(data.id, self.id);
        unsafe { &*data.ptr }
    }

    /// Get a mutable reference to the task-local data inside this task.
    ///
    /// This method should be passed a handle previously returned by
    /// `Task::insert`. That handle, when passed back into this method, will
    /// retrieve a reference to the original data.
    ///
    /// # Panics
    ///
    /// This method will panic if `data` does not belong to this task. That is,
    /// if another task generated the `data` handle passed in, this method will
    /// panic.
    pub fn get_mut(&mut self, data: &TaskData) -> &mut A
        where A: Send + 'static,
    {
        assert_eq!(data.id, self.id);
        unsafe { &mut *data.ptr }
    }

    /// During the `Future::schedule` method, notify to the task that a value is
    /// immediately ready.
    ///
    /// This method, more optimized than `TaskHandle::notify`, will inform the
    /// task that the future which is being scheduled is immediately ready to be
    /// `poll`ed again.
    pub fn notify(&mut self) {
        // TODO: optimize this
        self.handle().notify()
    }

    /// Gets a handle to this task which can be cloned to a piece of
    /// `Send+'static` data.
    ///
    /// This handle returned can be used to notify the task that a future is
    /// ready to get polled again. The returned handle implements the `Clone`
    /// trait and all clones will refer to this same task.
    ///
    /// Note that if data is immediately ready then the `Task::notify` method
    /// should be preferred.
    pub fn handle(&self) -> &TaskHandle {
        &self.handle
    }

    /// Creates a new temporary "scoped task" for setting the ready tokens.
    ///
    /// A scoped task is simply a borrowed version of this task with an
    /// associated destructor that restores the ready set when it goes out of
    /// scope. This returned object can use the `ScopedTask::ready` method to
    /// indicate that all further calls to `Task::may_contain` will return true.
    ///
    /// This can be useful when one call to `poll` may poll multiple futures or
    /// streams, but after one has been resolved the others may all immediately
    /// be ready so they shouldn't use the same readiness token sets as the
    /// previous one.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use futures::Task;
    ///
    /// fn poll(task: &mut Task) {
    ///     task.may_contain(1); // may return true or false
    ///
    ///     {
    ///         let mut task = task.scoped();
    ///
    ///         task.may_contain(1); // returns the same as before
    ///
    ///         task.ready();
    ///         assert!(task.may_contain(1)); // always returns true
    ///     }
    ///
    ///     task.may_contain(1); // returns the same as the first call
    /// }
    /// ```
    // TODO: terrible name
    pub fn scoped(&mut self) -> ScopedTask {
        ScopedTask { task: self, reset: false }
    }

    /// Consumes this task to run a future to completion.
    ///
    /// This function will consume the task provided and the task will be used
    /// to execute the `future` provided until it has been completed. The future
    /// wil be `poll`'d until it is resolved, at which point the `Result<(),
    /// ()>` will be discarded.
    ///
    /// The future will be `poll`ed on the threads that events arrive on. That
    /// is, this method does not attempt to control which thread a future is
    /// polled on.
    ///
    /// # Panics
    ///
    /// Currently, if `poll` panics, then this method will propagate the panic
    /// to the thread that `poll` was called on. This is bad and it will change.
    pub fn run(self, mut future: Box<Future<Item=(), Error=()>>) {
        let mut me = self;
        loop {
            // Note that we need to poll at least once as the wake callback may
            // have received an empty set of tokens, but that's still a valid
            // reason to poll a future.
            assert_eq!(me.ready, 0);
            me.tokens = me.handle.inner.tokens.take();
            let result = catch_unwind(move || {
                (future.poll(&mut me), future, me)
            });
            match result {
                Ok((ref r, _, _)) if r.is_ready() => return,
                Ok((_, f, t)) => {
                    future = f;
                    me = t;
                }
                // TODO: do something smarter
                Err(e) => panic::resume_unwind(e),
            }
            future = match future.tailcall() {
                Some(f) => f,
                None => future,
            };
            if !me.handle.inner.tokens.any() {
                break
            }
        }

        // Ok, we've seen that there are no tokens which show interest in the
        // future. Schedule interest on the future for when something is ready
        // and then relinquish the future and the forget back to the slot, which
        // will then pick it up once a wake callback has fired.
        future.schedule(&mut me);

        // TODO: don't clone if we've been scheduled immediately
        let inner = me.handle.inner.clone();
        inner.slot.try_produce((me, future)).ok().unwrap();
    }
}

fn catch_unwind<F, U>(f: F) -> thread::Result
    where F: FnOnce() -> U + Send + 'static,
{
    panic::catch_unwind(panic::AssertUnwindSafe(f))
}

impl TaskHandle {
    /// Returns whether this task handle and another point to the same task.
    ///
    /// In other words, this method returns whether `notify` would end up
    /// notifying the same task. If two task handles need to be notified but
    /// they are equivalent, then only one needs to be actually notified.
    pub fn equivalent(&self, other: &TaskHandle) -> bool {
        &*self.inner as *const _ == &*other.inner as *const _
    }

    /// Inform this handle's associated task that a particular token is ready.
    ///
    /// This information will be communicated to the task in question and
    /// affects the return value of future calls to `Task::may_contain`. This
    /// can be used to optimize calls to `poll` by avoiding a polling operation
    /// if `may_contain` returns false.
    pub fn token_ready(&self, token: usize) {
        self.inner.tokens.insert(token);
    }

    /// Notify the associated task that a future is ready to get polled.
    ///
    /// Futures should use this method to ensure that when a future can make
    /// progress as `Task` is notified that it should continue to `poll` the
    /// future at a later date.
    // TODO: more here
    pub fn notify(&self) {
        // First, see if we can actually register an `on_full` callback. The
        // `Slot` requires that only one registration happens, and this flag
        // guards that.
        if self.inner.registered.swap(true, Ordering::SeqCst) {
            return
        }

        // If we won the race to register a callback, do so now. Once the slot
        // is resolve we allow another registration **before we poll again**.
        // This allows any future which may be somewhat badly behaved to be
        // compatible with this.
        //
        // TODO: this store of `false` should *probably* be before the
        //       `schedule` call in forget above, need to think it through.
        self.inner.slot.on_full(|slot| {
            let (task, future) = slot.try_consume().ok().unwrap();
            task.handle.inner.registered.store(false, Ordering::SeqCst);
            task.run(future)
        });
    }
}

impl<'a> ScopedTask<'a> {
    /// Flag this scoped task as "all events are ready".
    ///
    /// In other words, once this method is called, all future calls to
    /// `may_contain` on the associated `Task` will return `true`.
    pub fn ready(&mut self) -> &mut ScopedTask<'a>{
        if !self.reset {
            self.reset = true;
            self.task.ready += 1;
        }
        self
    }
}

impl<'a> Deref for ScopedTask<'a> {
    type Target = Task;
    fn deref(&self) -> &Task {
        &*self.task
    }
}

impl<'a> DerefMut for ScopedTask<'a> {
    fn deref_mut(&mut self) -> &mut Task {
        &mut *self.task
    }
}

impl<'a> Drop for ScopedTask<'a> {
    fn drop(&mut self) {
        if self.reset {
            self.task.ready -= 1;
        }
    }
}

impl Clone for TaskData {
    fn clone(&self) -> TaskData {
        TaskData {
            id: self.id,
            ptr: self.ptr,
        }
    }
}

impl Copy for TaskData {}
<|endoftext|>


<commit_before>use std::io::{Read, Write};
use std::net::{TcpStream, TcpListener};
use std::thread;
use imp::TlsConnectorBuilderExt;

use super::*;

macro_rules! p {
    ($e:expr) => {
        match $e {
            Ok(r) => r,
            Err(e) => panic!("{:?}", e),
        }
    }
}

mod tests {
    use super::*;

    #[test]
    fn connect_google() {
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        let s = p!(TcpStream::connect("google.com:443"));
        let mut socket = p!(builder.connect("google.com", s));

        p!(socket.write_all(b"GET / HTTP/1.0\r\n\r\n"));
        let mut result = vec![];
        p!(socket.read_to_end(&mut result));

        println!("{}", String::from_utf8_lossy(&result));
        assert!(result.starts_with(b"HTTP/1.0"));
        assert!(result.ends_with(b"\r\n") || result.ends_with(b""));
    }

    #[test]
    fn connect_bad_hostname() {
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        let s = p!(TcpStream::connect("google.com:443"));
        builder.connect("goggle.com", s).unwrap_err();
    }

    #[test]
    fn connect_bad_hostname_ignored() {
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        let s = p!(TcpStream::connect("google.com:443"));
        builder.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(s).unwrap();
    }

    #[test]
    fn server() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            let mut socket = p!(builder.accept(socket));

            let mut buf = [0; 5];
            p!(socket.read_exact(&mut buf));
            assert_eq!(&buf, b"hello");

            p!(socket.write_all(b"world"));
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        let builder = p!(builder.build());
        let mut socket = p!(builder.connect("foobar.com", socket));

        p!(socket.write_all(b"hello"));
        let mut buf = vec![];
        p!(socket.read_to_end(&mut buf));
        assert_eq!(buf, b"world");

        p!(j.join());
    }

    #[test]
    fn server_tls11_only() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let mut builder = p!(TlsAcceptor::builder(pkcs12));
        p!(builder.supported_protocols(&[Protocol::Tlsv11]));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            let mut socket = p!(builder.accept(socket));

            let mut buf = [0; 5];
            p!(socket.read_exact(&mut buf));
            assert_eq!(&buf, b"hello");

            p!(socket.write_all(b"world"));
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        p!(builder.supported_protocols(&[Protocol::Tlsv11]));
        let builder = p!(builder.build());
        let mut socket = p!(builder.connect("foobar.com", socket));

        p!(socket.write_all(b"hello"));
        let mut buf = vec![];
        p!(socket.read_to_end(&mut buf));
        assert_eq!(buf, b"world");

        p!(j.join());
    }

    #[test]
    fn server_no_shared_protocol() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let mut builder = p!(TlsAcceptor::builder(pkcs12));
        p!(builder.supported_protocols(&[Protocol::Tlsv12]));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            assert!(builder.accept(socket).is_err());
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        p!(builder.supported_protocols(&[Protocol::Sslv3, Protocol::Tlsv10, Protocol::Tlsv11]));
        let builder = p!(builder.build());
        assert!(builder.connect("foobar.com", socket).is_err());

        p!(j.join());
    }

    #[test]
    fn server_untrusted() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            // FIXME should assert error
            // https://github.com/steffengy/schannel-rs/issues/20
            let _ = builder.accept(socket);
        });

        let socket = p!(TcpStream::connect(("localhost", port)));
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        builder.connect("foobar.com", socket).unwrap_err();

        p!(j.join());
    }

    #[cfg(target_os = "windows")]
    #[test]
    fn schannel_verify_callback() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            // FIXME should assert error
            // https://github.com/steffengy/schannel-rs/issues/20
            let _ = builder.accept(socket);
        });

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        builder.verify_callback(|validation_result| {
            assert!(validation_result.result().is_err());
            Ok(())
        });
        let builder = p!(builder.build());
        builder.connect("foobar.com", socket).unwrap();

        p!(j.join());
    }

    #[test]
    fn shutdown() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            let mut socket = p!(builder.accept(socket));

            let mut buf = [0; 5];
            p!(socket.read_exact(&mut buf));
            assert_eq!(&buf, b"hello");

            assert_eq!(p!(socket.read(&mut buf)), 0);
            p!(socket.shutdown());
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        let builder = p!(builder.build());
        let mut socket = p!(builder.connect("foobar.com", socket));

        p!(socket.write_all(b"hello"));
        p!(socket.shutdown());

        p!(j.join());
    }
}<commit_msg>Fix ios build<commit_after>use std::io::{Read, Write};
use std::net::{TcpStream, TcpListener};
use std::thread;
use imp::TlsConnectorBuilderExt;

use super::*;

macro_rules! p {
    ($e:expr) => {
        match $e {
            Ok(r) => r,
            Err(e) => panic!("{:?}", e),
        }
    }
}

mod tests {
    use super::*;

    #[test]
    fn connect_google() {
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        let s = p!(TcpStream::connect("google.com:443"));
        let mut socket = p!(builder.connect("google.com", s));

        p!(socket.write_all(b"GET / HTTP/1.0\r\n\r\n"));
        let mut result = vec![];
        p!(socket.read_to_end(&mut result));

        println!("{}", String::from_utf8_lossy(&result));
        assert!(result.starts_with(b"HTTP/1.0"));
        assert!(result.ends_with(b"\r\n") || result.ends_with(b""));
    }

    #[test]
    fn connect_bad_hostname() {
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        let s = p!(TcpStream::connect("google.com:443"));
        builder.connect("goggle.com", s).unwrap_err();
    }

    #[test]
    fn connect_bad_hostname_ignored() {
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        let s = p!(TcpStream::connect("google.com:443"));
        builder.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(s).unwrap();
    }

    #[test]
    fn server() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            let mut socket = p!(builder.accept(socket));

            let mut buf = [0; 5];
            p!(socket.read_exact(&mut buf));
            assert_eq!(&buf, b"hello");

            p!(socket.write_all(b"world"));
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        let builder = p!(builder.build());
        let mut socket = p!(builder.connect("foobar.com", socket));

        p!(socket.write_all(b"hello"));
        let mut buf = vec![];
        p!(socket.read_to_end(&mut buf));
        assert_eq!(buf, b"world");

        p!(j.join());
    }

    #[test]
    fn server_tls11_only() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let mut builder = p!(TlsAcceptor::builder(pkcs12));
        p!(builder.supported_protocols(&[Protocol::Tlsv11]));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            let mut socket = p!(builder.accept(socket));

            let mut buf = [0; 5];
            p!(socket.read_exact(&mut buf));
            assert_eq!(&buf, b"hello");

            p!(socket.write_all(b"world"));
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        p!(builder.supported_protocols(&[Protocol::Tlsv11]));
        let builder = p!(builder.build());
        let mut socket = p!(builder.connect("foobar.com", socket));

        p!(socket.write_all(b"hello"));
        let mut buf = vec![];
        p!(socket.read_to_end(&mut buf));
        assert_eq!(buf, b"world");

        p!(j.join());
    }

    #[test]
    fn server_no_shared_protocol() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let mut builder = p!(TlsAcceptor::builder(pkcs12));
        p!(builder.supported_protocols(&[Protocol::Tlsv12]));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            assert!(builder.accept(socket).is_err());
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        p!(builder.supported_protocols(&[Protocol::Sslv3, Protocol::Tlsv10, Protocol::Tlsv11]));
        let builder = p!(builder.build());
        assert!(builder.connect("foobar.com", socket).is_err());

        p!(j.join());
    }

    #[test]
    fn server_untrusted() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            // FIXME should assert error
            // https://github.com/steffengy/schannel-rs/issues/20
            let _ = builder.accept(socket);
        });

        let socket = p!(TcpStream::connect(("localhost", port)));
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        builder.connect("foobar.com", socket).unwrap_err();

        p!(j.join());
    }

    #[test]
    #[cfg(target_os = "windows")]
    fn schannel_verify_callback() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            // FIXME should assert error
            // https://github.com/steffengy/schannel-rs/issues/20
            let _ = builder.accept(socket);
        });

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        builder.verify_callback(|validation_result| {
            assert!(validation_result.result().is_err());
            Ok(())
        });
        let builder = p!(builder.build());
        builder.connect("foobar.com", socket).unwrap();

        p!(j.join());
    }

    #[test]
    fn shutdown() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            let mut socket = p!(builder.accept(socket));

            let mut buf = [0; 5];
            p!(socket.read_exact(&mut buf));
            assert_eq!(&buf, b"hello");

            assert_eq!(p!(socket.read(&mut buf)), 0);
            p!(socket.shutdown());
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        let builder = p!(builder.build());
        let mut socket = p!(builder.connect("foobar.com", socket));

        p!(socket.write_all(b"hello"));
        p!(socket.shutdown());

        p!(j.join());
    }
}<|endoftext|>


<commit_before>mod skills {
    use skills;
    use path;

    #[test]
    fn test_skills() {
        match ::skills::SkillReader(&path::Path(~"files/skills.idx"), &path::Path(~"files/skills.mul")) {
            result::Err(msg) => {
                error!("%s", msg);
                fail;
            },
            result::Ok(skill_reader) => {
                match skill_reader.read_skill(0) {
                    option::Some(skill) => {
                        assert skill.name == ~"Alchemy";
                        assert skill.clickable == false;
                    },
                    option::None => {
                        error!("No skill at 0");
                        fail;
                    }
                };
                //There should be a skill at #10
                match skill_reader.read_skill(10) {
                    option::Some(_skill) => {
                        ()
                    },
                    option::None => {
                        error!("No skill at 10");
                        fail;
                    }
                };
                //There shouldn't be 100 skills
                match skill_reader.read_skill(100) {
                    option::Some(_skill) => {
                        error!("Skill at 100");
                        fail;
                    },
                    option::None => ()
                };
            }
        }
    }

    #[test]
    fn test_read_all() {
        match ::skills::load_skills(&path::Path(~"files/skills.idx"), &path::Path(~"files/skills.mul")) {
            result::Err(msg) => {
                error!("%s", msg);
                fail;
            },
            result::Ok(skill_list) => {
                assert skill_list.len() >= 49 //49 skills in the original UO
            }
        }
    }
}

mod art {
    use art;
    use path;

    #[test]
    fn test_read_tile() {
        match ::art::TileReader(&path::Path(~"files/artidx.mul"), &path::Path(~"files/art.mul")) {
            result::Err(msg) => {
                error!("%s", msg);
                fail;
            },
            result::Ok(tileReader) => {
                match tileReader.read_tile(400) {
                    option::Some(tile) => {
                        assert tile.raw_image.len() == 1012;
                        let bitmap = tile.with_transparency(0xF000);
                        assert bitmap.len() == (44*44);
                        assert bitmap[0] == 0xF000;
                        assert bitmap[21] != 0xF000;
                    },
                    option::None => {
                        error!("Couldn't read tile 0")
                    }
                };
                match tileReader.read_tile(100) {
                    option::Some(tile) => {
                        assert tile.raw_image.len() == 1012;
                        let bitmap = tile.with_transparency(0xF000);
                        assert bitmap.len() == (44*44);
                        assert bitmap[0] == 0xF000;
                        assert bitmap[21] != 0xF000;
                    },
                    option::None => {
                        error!("Couldn't read tile 100")
                        fail
                    }
                };
                match tileReader.read_tile(4000) {
                    option::Some(_tile) => {
                        error!("Read static 4000 as tile")
                        fail;
                    },
                    option::None => ()
                };
            }
        }
    }

    #[test]
    fn test_read_static() {
        match ::art::TileReader(&path::Path(~"files/artidx.mul"), &path::Path(~"files/art.mul")) {
            result::Err(msg) => {
                error!("%s", msg);
                fail;
            },
            result::Ok(tile_reader) => {
                match tile_reader.read_static(16384) {
                    option::Some(staticTile) => {
                        let bitmap = staticTile.with_transparency(0xF000);
                        error!("%u, %u, %u", bitmap.len(), staticTile.width as uint, staticTile.height as uint);
                        assert bitmap.len() == (staticTile.width + staticTile.height) as uint;
                    },
                    option::None => {
                        error!("Couldn't read tile 16384");
                        fail
                    }
                };
            }
        }
    }
}
<commit_msg>Minor tidyup<commit_after>mod skills {
    use skills;
    use path;

    #[test]
    fn test_skills() {
        match ::skills::SkillReader(&path::Path(~"files/skills.idx"), &path::Path(~"files/skills.mul")) {
            result::Err(msg) => {
                error!("%s", msg);
                fail;
            },
            result::Ok(skill_reader) => {
                match skill_reader.read_skill(0) {
                    option::Some(skill) => {
                        assert skill.name == ~"Alchemy";
                        assert skill.clickable == false;
                    },
                    option::None => {
                        error!("No skill at 0");
                        fail;
                    }
                };
                //There should be a skill at #10
                match skill_reader.read_skill(10) {
                    option::Some(_skill) => {
                        ()
                    },
                    option::None => {
                        error!("No skill at 10");
                        fail;
                    }
                };
                //There shouldn't be 100 skills
                match skill_reader.read_skill(100) {
                    option::Some(_skill) => {
                        error!("Skill at 100");
                        fail;
                    },
                    option::None => ()
                };
            }
        }
    }

    #[test]
    fn test_read_all() {
        match ::skills::load_skills(&path::Path(~"files/skills.idx"), &path::Path(~"files/skills.mul")) {
            result::Err(msg) => {
                error!("%s", msg);
                fail;
            },
            result::Ok(skill_list) => {
                assert skill_list.len() >= 49 //49 skills in the original UO
            }
        }
    }
}

mod art {
    use art;
    use path;

    #[test]
    fn test_read_tile() {
        match ::art::TileReader(&path::Path(~"files/artidx.mul"), &path::Path(~"files/art.mul")) {
            result::Err(msg) => {
                error!("%s", msg);
                fail;
            },
            result::Ok(tileReader) => {
                match tileReader.read_tile(400) {
                    option::Some(tile) => {
                        assert tile.raw_image.len() == 1012;
                        let bitmap = tile.with_transparency(0xF000);
                        assert bitmap.len() == (44*44);
                        assert bitmap[0] == 0xF000;
                        assert bitmap[21] != 0xF000;
                    },
                    option::None => {
                        error!("Couldn't read tile 0")
                    }
                };
                match tileReader.read_tile(100) {
                    option::Some(tile) => {
                        assert tile.raw_image.len() == 1012;
                        let bitmap = tile.with_transparency(0xF000);
                        assert bitmap.len() == (44*44);
                        assert bitmap[0] == 0xF000;
                        assert bitmap[21] != 0xF000;
                    },
                    option::None => {
                        error!("Couldn't read tile 100")
                        fail
                    }
                };
                match tileReader.read_tile(4000) {
                    option::Some(_tile) => {
                        error!("Read static 4000 as tile")
                        fail;
                    },
                    option::None => ()
                };
            }
        }
    }

    #[test]
    fn test_read_static() {
        match ::art::TileReader(&path::Path(~"files/artidx.mul"), &path::Path(~"files/art.mul")) {
            result::Err(msg) => {
                error!("%s", msg);
                fail;
            },
            result::Ok(tile_reader) => {
                match tile_reader.read_static(16384) {
                    option::Some(static_tile) => {
                        let bitmap = static_tile.with_transparency(0xF000);
                        error!("%u, %u, %u", bitmap.len(), static_tile.width as uint, static_tile.height as uint);
                        assert bitmap.len() == (static_tile.width + static_tile.height) as uint;
                    },
                    option::None => {
                        error!("Couldn't read tile 16384");
                        fail
                    }
                };
            }
        }
    }
}
<|endoftext|>


<commit_before>//!
//! # Tools
//!

use std::result::Result;
use std::rc::Rc;
use serde_json::*;

use environment::*;

///
/// Trait implemented by things that represent a tool
///
/// A tool is simply a routine that takes some input, does some processing
/// and returns a value or an error. The main difference between a tool and
/// a simple function is that a tool's input and output must be simple data,
/// which for Rust we define as 'can be serialized to JSON'.
///
/// Tools also have the requirement that they are encapsulated and can instantiate
/// themselves with no dependencies other than those they can discover from
/// their environment.
///
/// These two requirements mean that tools can be invoked simply by specifying
/// the input data (without necessarily having to know the exact Rust type involved!).
/// Test cases for tools can be specified as simple JSON data with no need for any
/// actual code. Tools can be turned into stand-alone command line programs or
/// web endpoints with no modification.
///
pub trait Tool {
    ///
    /// Invokes this tool with its input and output specified using JSON
    ///
    fn invoke_json(&self, input: Value, environment: &Environment) -> Result<Value, Value>;
}

impl<T: Tool> Tool for Rc<T> {
    #[inline]
    fn invoke_json(&self, input: Value, environment: &Environment) -> Result<Value, Value> {
        (**self).invoke_json(input, environment)
    }
}

impl<T: Tool> Tool for Box<T> {
    #[inline]
    fn invoke_json(&self, input: Value, environment: &Environment) -> Result<Value, Value> {
        (**self).invoke_json(input, environment)
    }
}
<commit_msg>Don’t need this<commit_after>//!
//! # Tools
//!

use std::result::Result;
use std::rc::Rc;
use serde_json::*;

use environment::*;

///
/// Trait implemented by things that represent a tool
///
/// A tool is simply a routine that takes some input, does some processing
/// and returns a value or an error. The main difference between a tool and
/// a simple function is that a tool's input and output must be simple data,
/// which for Rust we define as 'can be serialized to JSON'.
///
/// Tools also have the requirement that they are encapsulated and can instantiate
/// themselves with no dependencies other than those they can discover from
/// their environment.
///
/// These two requirements mean that tools can be invoked simply by specifying
/// the input data (without necessarily having to know the exact Rust type involved!).
/// Test cases for tools can be specified as simple JSON data with no need for any
/// actual code. Tools can be turned into stand-alone command line programs or
/// web endpoints with no modification.
///
pub trait Tool {
    ///
    /// Invokes this tool with its input and output specified using JSON
    ///
    fn invoke_json(&self, input: Value, environment: &Environment) -> Result<Value, Value>;
}

impl<T: Tool> Tool for Rc<T> {
    #[inline]
    fn invoke_json(&self, input: Value, environment: &Environment) -> Result<Value, Value> {
        (**self).invoke_json(input, environment)
    }
}
<|endoftext|>


<commit_before>//! Unix-specific types for signal handling.
//!
//! This module is only defined on Unix platforms and contains the primary
//! `Signal` type for receiving notifications of signals.

#![cfg(unix)]

pub extern crate libc;
extern crate mio;
extern crate mio_uds;

use std::cell::UnsafeCell;
use std::collections::HashSet;
use std::io::prelude::*;
use std::io;
use std::mem;
use std::os::unix::prelude::*;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Mutex, Once, ONCE_INIT};

use futures::future;
use futures::sync::mpsc::{Receiver, Sender, channel};
use futures::{Async, AsyncSink, Future};
use futures::{Sink, Stream, Poll};
use self::libc::c_int;
use self::mio::Poll as MioPoll;
use self::mio::unix::EventedFd;
use self::mio::{Evented, Token, Ready, PollOpt};
use self::mio_uds::UnixStream;
use tokio_io::IoFuture;
use tokio_core::reactor::{Handle, CoreId, PollEvented};

pub use self::libc::{SIGINT, SIGTERM, SIGUSR1, SIGUSR2};
pub use self::libc::{SIGHUP, SIGQUIT, SIGPIPE, SIGALRM, SIGTRAP};

// Number of different unix signals
const SIGNUM: usize = 32;

struct SignalInfo {
    pending: AtomicBool,
    // The ones interested in this signal
    recipients: Mutex<Vec<Box<Sender<c_int>>>>,

    init: Once,
    initialized: UnsafeCell<bool>,
    prev: UnsafeCell<libc::sigaction>,
}

struct Globals {
    sender: UnixStream,
    receiver: UnixStream,
    signals: [SignalInfo; SIGNUM],
    drivers: Mutex<HashSet<CoreId>>,
}

impl Default for SignalInfo {
    fn default() -> SignalInfo {
        SignalInfo {
            pending: AtomicBool::new(false),
            init: ONCE_INIT,
            initialized: UnsafeCell::new(false),
            recipients: Mutex::new(Vec::new()),
            prev: UnsafeCell::new(unsafe { mem::zeroed() }),
        }
    }
}

static mut GLOBALS: *mut Globals = 0 as *mut Globals;

fn globals() -> &'static Globals {
    static INIT: Once = ONCE_INIT;

    unsafe {
        INIT.call_once(|| {
            let (receiver, sender) = UnixStream::pair().unwrap();
            let globals = Globals {
                sender: sender,
                receiver: receiver,
                signals: Default::default(),
                drivers: Mutex::new(HashSet::new()),
            };
            GLOBALS = Box::into_raw(Box::new(globals));
        });
        &*GLOBALS
    }
}

/// Our global signal handler for all signals registered by this module.
///
/// The purpose of this signal handler is to primarily:
///
/// 1. Flag that our specific signal was received (e.g. store an atomic flag)
/// 2. Wake up driver tasks by writing a byte to a pipe
///
/// Those two operations shoudl both be async-signal safe. After that's done we
/// just try to call a previous signal handler, if any, to be "good denizens of
/// the internet"
extern fn handler(signum: c_int,
                  info: *mut libc::siginfo_t,
                  ptr: *mut libc::c_void) {
    type FnSigaction = extern fn(c_int, *mut libc::siginfo_t, *mut libc::c_void);
    type FnHandler = extern fn(c_int);
    unsafe {
        let slot = match (*GLOBALS).signals.get(signum as usize) {
            Some(slot) => slot,
            None => return,
        };
        slot.pending.store(true, Ordering::SeqCst);

        // Send a wakeup, ignore any errors (anything reasonably possible is
        // full pipe and then it will wake up anyway).
        drop((*GLOBALS).sender.write(&[1]));

        let fnptr = (*slot.prev.get()).sa_sigaction;
        if fnptr == 0 || fnptr == libc::SIG_DFL || fnptr == libc::SIG_IGN {
            return
        }
        if (*slot.prev.get()).sa_flags & libc::SA_SIGINFO == 0 {
            let action = mem::transmute::<usize, FnHandler>(fnptr);
            action(signum)
        } else {
            let action = mem::transmute::<usize, FnSigaction>(fnptr);
            action(signum, info, ptr)
        }
    }
}

/// Enable this module to receive signal notifications for the `signal`
/// provided.
///
/// This will register the signal handler if it hasn't already been registered,
/// returning any error along the way if that fails.
fn signal_enable(signal: c_int) -> io::Result<()> {
    let siginfo = match globals().signals.get(signal as usize) {
        Some(slot) => slot,
        None => {
            return Err(io::Error::new(io::ErrorKind::Other, "signal too large"))
        }
    };
    unsafe {
        #[cfg(target_os = "android")]
        fn flags() -> libc::c_ulong {
            (libc::SA_RESTART as libc::c_ulong) |
                libc::SA_SIGINFO |
                (libc::SA_NOCLDSTOP as libc::c_ulong)
        }
        #[cfg(not(target_os = "android"))]
        fn flags() -> c_int {
            libc::SA_RESTART |
                libc::SA_SIGINFO |
                libc::SA_NOCLDSTOP
        }
        let mut err = None;
        siginfo.init.call_once(|| {
            let mut new: libc::sigaction = mem::zeroed();
            new.sa_sigaction = handler as usize;
            new.sa_flags = flags();
            if libc::sigaction(signal, &new, &mut *siginfo.prev.get()) != 0 {
                err = Some(io::Error::last_os_error());
            } else {
                *siginfo.initialized.get() = true;
            }
        });
        if let Some(err) = err {
            return Err(err)
        }
        if *siginfo.initialized.get() {
            Ok(())
        } else {
            Err(io::Error::new(io::ErrorKind::Other,
                               "failed to register signal handler"))
        }
    }
}

/// A helper struct to register our global receiving end of the signal pipe on
/// multiple event loops.
///
/// This structure represents registering the receiving end on all event loops,
/// and uses `EventedFd` in mio to do so. It's stored in each driver task and is
/// used to read data and register interest in new signals coming in.
struct EventedReceiver;

impl Evented for EventedReceiver {
    fn register(&self, poll: &MioPoll, token: Token, events: Ready, opts: PollOpt) -> io::Result<()> {
        let fd = globals().receiver.as_raw_fd();
        EventedFd(&fd).register(poll, token, events, opts)
    }
    fn reregister(&self, poll: &MioPoll, token: Token, events: Ready, opts: PollOpt) -> io::Result<()> {
        let fd = globals().receiver.as_raw_fd();
        EventedFd(&fd).reregister(poll, token, events, opts)
    }
    fn deregister(&self, poll: &MioPoll) -> io::Result<()> {
        let fd = globals().receiver.as_raw_fd();
        EventedFd(&fd).deregister(poll)
    }
}

impl Read for EventedReceiver {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (&globals().receiver).read(buf)
    }
}

struct Driver {
    id: CoreId,
    wakeup: PollEvented<EventedReceiver>,
}

impl Future for Driver {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<(), ()> {
        // Drain the data from the pipe and maintain interest in getting more
        let any_wakeup = self.drain();
        if any_wakeup {
            self.broadcast();
        }
        // This task just lives until the end of the event loop
        Ok(Async::NotReady)
    }
}

impl Drop for Driver {
    fn drop(&mut self) {
        let mut drivers = globals().drivers.lock().unwrap();
        drivers.remove(&self.id);
    }
}

impl Driver {
    fn new(handle: &Handle) -> io::Result<Driver> {
        Ok(Driver {
            id: handle.id(),
            wakeup: try!(PollEvented::new(EventedReceiver, handle)),
        })
    }

    /// Drain all data in the global receiver, returning whether data was to be
    /// had.
    ///
    /// If this function returns `true` then some signal has been received since
    /// we last checked, otherwise `false` indicates that no signal has been
    /// received.
    fn drain(&mut self) -> bool {
        let mut received = false;
        loop {
            match self.wakeup.read(&mut [0; 128]) {
                Ok(0) => panic!("EOF on self-pipe"),
                Ok(_) => received = true,
                Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => break,
                Err(e) => panic!("Bad read on self-pipe: {}", e),
            }
        }
        received
    }

    /// Go through all the signals and broadcast everything.
    ///
    /// Driver tasks wake up for *any* signal and simply process all globally
    /// registered signal streams, so each task is sort of cooperatively working
    /// for all the rest as well.
    fn broadcast(&self) {
        for (sig, slot) in globals().signals.iter().enumerate() {
            // Any signal of this kind arrived since we checked last?
            if !slot.pending.swap(false, Ordering::SeqCst) {
                continue
            }

            let signum = sig as c_int;
            let mut recipients = slot.recipients.lock().unwrap();

            // Notify all waiters on this signal that the signal has been
            // received. If we can't push a message into the queue then we don't
            // worry about it as everything is coalesced anyway. If the channel
            // has gone away then we can remove that slot.
            for i in (0..recipients.len()).rev() {
                // TODO: This thing probably generates unnecessary wakups of
                //       this task when `NotReady` is received because we don't
                //       actually want to get woken up to continue sending a
                //       message. Let's optimise it later on though, as we know
                //       this works.
                match recipients[i].start_send(signum) {
                    Ok(AsyncSink::Ready) => {}
                    Ok(AsyncSink::NotReady(_)) => {}
                    Err(_) => { recipients.swap_remove(i); }
                }
            }
        }
    }
}

/// An implementation of `Stream` for receiving a particular type of signal.
///
/// This structure implements the `Stream` trait and represents notifications
/// of the current process receiving a particular signal. The signal being
/// listened for is passed to `Signal::new`, and the same signal number is then
/// yielded as each element for the stream.
///
/// In general signal handling on Unix is a pretty tricky topic, and this
/// structure is no exception! There are some important limitations to keep in
/// mind when using `Signal` streams:
///
/// * Signals handling in Unix already necessitates coalescing signals
///   together sometimes. This `Signal` stream is also no exception here in
///   that it will also coalesce signals. That is, even if the signal handler
///   for this process runs multiple times, the `Signal` stream may only return
///   one signal notification. Specifically, before `poll` is called, all
///   signal notifications are coalesced into one item returned from `poll`.
///   Once `poll` has been called, however, a further signal is guaranteed to
///   be yielded as an item.
///
///   Put another way, any element pulled off the returned stream corresponds to
///   *at least one* signal, but possibly more.
///
/// * Signal handling in general is relatively inefficient. Although some
///   improvements are possible in this crate, it's recommended to not plan on
///   having millions of signal channels open.
///
/// * Currently the "driver task" to process incoming signals never exits. This
///   driver task runs in the background of the event loop provided, and
///   in general you shouldn't need to worry about it.
///
/// If you've got any questions about this feel free to open an issue on the
/// repo, though, as I'd love to chat about this! In other words, I'd love to
/// alleviate some of these limitations if possible!
pub struct Signal {
    signal: c_int,
    // Used only as an identifier. We place the real sender into a Box, so it
    // stays on the same address forever. That gives us a unique pointer, so we
    // can use this to identify the sender in a Vec and delete it when we are
    // dropped.
    id: *const Sender<c_int>,
    rx: Receiver<c_int>,
}

// The raw pointer prevents the compiler from determining it as Send
// automatically. But the only thing we use the raw pointer for is to identify
// the correct Box to delete, not manipulate any data through that.
unsafe impl Send for Signal {}

impl Signal {
    /// Creates a new stream which will receive notifications when the current
    /// process receives the signal `signal`.
    ///
    /// This function will create a new stream which may be based on the
    /// event loop handle provided. This function returns a future which will
    /// then resolve to the signal stream, if successful.
    ///
    /// The `Signal` stream is an infinite stream which will receive
    /// notifications whenever a signal is received. More documentation can be
    /// found on `Signal` itself, but to reiterate:
    ///
    /// * Signals may be coalesced beyond what the kernel already does.
    /// * Once a signal handler is registered with the process the underlying
    ///   libc signal handler is never unregistered.
    ///
    /// A `Signal` stream can be created for a particular signal number
    /// multiple times. When a signal is received then all the associated
    /// channels will receive the signal notification.
    pub fn new(signal: c_int, handle: &Handle) -> IoFuture<Signal> {
        let result = (|| {
            // Turn the signal delivery on once we are ready for it
            try!(signal_enable(signal));

            // Ensure there's a driver for our associated event loop processing
            // signals.
            let id = handle.id();
            let mut drivers = globals().drivers.lock().unwrap();
            if !drivers.contains(&id) {
                handle.spawn(try!(Driver::new(handle)));
                drivers.insert(id);
            }
            drop(drivers);

            // One wakeup in a queue is enough, no need for us to buffer up any
            // more.
            let (tx, rx) = channel(1);
            let tx = Box::new(tx);
            let id: *const _ = &*tx;
            let idx = signal as usize;
            globals().signals[idx].recipients.lock().unwrap().push(tx);
            Ok(Signal {
                rx: rx,
                id: id,
                signal: signal,
            })
        })();

        Box::new(future::result(result))
    }
}

impl Stream for Signal {
    type Item = c_int;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<c_int>, io::Error> {
        // receivers don't generate errors
        self.rx.poll().map_err(|_| panic!())
    }
}

impl Drop for Signal {
    fn drop(&mut self) {
        let idx = self.signal as usize;
        let mut list = globals().signals[idx].recipients.lock().unwrap();
        list.retain(|sender| &**sender as *const _ != self.id);
    }
}
<commit_msg>signal: Fix a bug with most recent tokio-core release<commit_after>//! Unix-specific types for signal handling.
//!
//! This module is only defined on Unix platforms and contains the primary
//! `Signal` type for receiving notifications of signals.

#![cfg(unix)]

pub extern crate libc;
extern crate mio;
extern crate mio_uds;

use std::cell::UnsafeCell;
use std::collections::HashSet;
use std::io::prelude::*;
use std::io;
use std::mem;
use std::os::unix::prelude::*;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Mutex, Once, ONCE_INIT};

use futures::future;
use futures::sync::mpsc::{Receiver, Sender, channel};
use futures::{Async, AsyncSink, Future};
use futures::{Sink, Stream, Poll};
use self::libc::c_int;
use self::mio::Poll as MioPoll;
use self::mio::unix::EventedFd;
use self::mio::{Evented, Token, Ready, PollOpt};
use self::mio_uds::UnixStream;
use tokio_io::IoFuture;
use tokio_core::reactor::{Handle, CoreId, PollEvented};

pub use self::libc::{SIGINT, SIGTERM, SIGUSR1, SIGUSR2};
pub use self::libc::{SIGHUP, SIGQUIT, SIGPIPE, SIGALRM, SIGTRAP};

// Number of different unix signals
const SIGNUM: usize = 32;

struct SignalInfo {
    pending: AtomicBool,
    // The ones interested in this signal
    recipients: Mutex<Vec<Box<Sender<c_int>>>>,

    init: Once,
    initialized: UnsafeCell<bool>,
    prev: UnsafeCell<libc::sigaction>,
}

struct Globals {
    sender: UnixStream,
    receiver: UnixStream,
    signals: [SignalInfo; SIGNUM],
    drivers: Mutex<HashSet<CoreId>>,
}

impl Default for SignalInfo {
    fn default() -> SignalInfo {
        SignalInfo {
            pending: AtomicBool::new(false),
            init: ONCE_INIT,
            initialized: UnsafeCell::new(false),
            recipients: Mutex::new(Vec::new()),
            prev: UnsafeCell::new(unsafe { mem::zeroed() }),
        }
    }
}

static mut GLOBALS: *mut Globals = 0 as *mut Globals;

fn globals() -> &'static Globals {
    static INIT: Once = ONCE_INIT;

    unsafe {
        INIT.call_once(|| {
            let (receiver, sender) = UnixStream::pair().unwrap();
            let globals = Globals {
                sender: sender,
                receiver: receiver,
                signals: Default::default(),
                drivers: Mutex::new(HashSet::new()),
            };
            GLOBALS = Box::into_raw(Box::new(globals));
        });
        &*GLOBALS
    }
}

/// Our global signal handler for all signals registered by this module.
///
/// The purpose of this signal handler is to primarily:
///
/// 1. Flag that our specific signal was received (e.g. store an atomic flag)
/// 2. Wake up driver tasks by writing a byte to a pipe
///
/// Those two operations shoudl both be async-signal safe. After that's done we
/// just try to call a previous signal handler, if any, to be "good denizens of
/// the internet"
extern fn handler(signum: c_int,
                  info: *mut libc::siginfo_t,
                  ptr: *mut libc::c_void) {
    type FnSigaction = extern fn(c_int, *mut libc::siginfo_t, *mut libc::c_void);
    type FnHandler = extern fn(c_int);
    unsafe {
        let slot = match (*GLOBALS).signals.get(signum as usize) {
            Some(slot) => slot,
            None => return,
        };
        slot.pending.store(true, Ordering::SeqCst);

        // Send a wakeup, ignore any errors (anything reasonably possible is
        // full pipe and then it will wake up anyway).
        drop((*GLOBALS).sender.write(&[1]));

        let fnptr = (*slot.prev.get()).sa_sigaction;
        if fnptr == 0 || fnptr == libc::SIG_DFL || fnptr == libc::SIG_IGN {
            return
        }
        if (*slot.prev.get()).sa_flags & libc::SA_SIGINFO == 0 {
            let action = mem::transmute::<usize, FnHandler>(fnptr);
            action(signum)
        } else {
            let action = mem::transmute::<usize, FnSigaction>(fnptr);
            action(signum, info, ptr)
        }
    }
}

/// Enable this module to receive signal notifications for the `signal`
/// provided.
///
/// This will register the signal handler if it hasn't already been registered,
/// returning any error along the way if that fails.
fn signal_enable(signal: c_int) -> io::Result<()> {
    let siginfo = match globals().signals.get(signal as usize) {
        Some(slot) => slot,
        None => {
            return Err(io::Error::new(io::ErrorKind::Other, "signal too large"))
        }
    };
    unsafe {
        #[cfg(target_os = "android")]
        fn flags() -> libc::c_ulong {
            (libc::SA_RESTART as libc::c_ulong) |
                libc::SA_SIGINFO |
                (libc::SA_NOCLDSTOP as libc::c_ulong)
        }
        #[cfg(not(target_os = "android"))]
        fn flags() -> c_int {
            libc::SA_RESTART |
                libc::SA_SIGINFO |
                libc::SA_NOCLDSTOP
        }
        let mut err = None;
        siginfo.init.call_once(|| {
            let mut new: libc::sigaction = mem::zeroed();
            new.sa_sigaction = handler as usize;
            new.sa_flags = flags();
            if libc::sigaction(signal, &new, &mut *siginfo.prev.get()) != 0 {
                err = Some(io::Error::last_os_error());
            } else {
                *siginfo.initialized.get() = true;
            }
        });
        if let Some(err) = err {
            return Err(err)
        }
        if *siginfo.initialized.get() {
            Ok(())
        } else {
            Err(io::Error::new(io::ErrorKind::Other,
                               "failed to register signal handler"))
        }
    }
}

/// A helper struct to register our global receiving end of the signal pipe on
/// multiple event loops.
///
/// This structure represents registering the receiving end on all event loops,
/// and uses `EventedFd` in mio to do so. It's stored in each driver task and is
/// used to read data and register interest in new signals coming in.
struct EventedReceiver;

impl Evented for EventedReceiver {
    fn register(&self, poll: &MioPoll, token: Token, events: Ready, opts: PollOpt) -> io::Result<()> {
        let fd = globals().receiver.as_raw_fd();
        match EventedFd(&fd).register(poll, token, events, opts) {
            Ok(()) => Ok(()),
            // Due to tokio-rs/tokio-core#307
            Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => Ok(()),
            Err(e) => Err(e),
        }
    }
    fn reregister(&self, poll: &MioPoll, token: Token, events: Ready, opts: PollOpt) -> io::Result<()> {
        let fd = globals().receiver.as_raw_fd();
        EventedFd(&fd).reregister(poll, token, events, opts)
    }
    fn deregister(&self, poll: &MioPoll) -> io::Result<()> {
        let fd = globals().receiver.as_raw_fd();
        EventedFd(&fd).deregister(poll)
    }
}

impl Read for EventedReceiver {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (&globals().receiver).read(buf)
    }
}

struct Driver {
    id: CoreId,
    wakeup: PollEvented<EventedReceiver>,
}

impl Future for Driver {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<(), ()> {
        // Drain the data from the pipe and maintain interest in getting more
        let any_wakeup = self.drain();
        if any_wakeup {
            self.broadcast();
        }
        // This task just lives until the end of the event loop
        Ok(Async::NotReady)
    }
}

impl Drop for Driver {
    fn drop(&mut self) {
        let mut drivers = globals().drivers.lock().unwrap();
        drivers.remove(&self.id);
    }
}

impl Driver {
    fn new(handle: &Handle) -> io::Result<Driver> {
        Ok(Driver {
            id: handle.id(),
            wakeup: try!(PollEvented::new(EventedReceiver, handle)),
        })
    }

    /// Drain all data in the global receiver, returning whether data was to be
    /// had.
    ///
    /// If this function returns `true` then some signal has been received since
    /// we last checked, otherwise `false` indicates that no signal has been
    /// received.
    fn drain(&mut self) -> bool {
        let mut received = false;
        loop {
            match self.wakeup.read(&mut [0; 128]) {
                Ok(0) => panic!("EOF on self-pipe"),
                Ok(_) => received = true,
                Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => break,
                Err(e) => panic!("Bad read on self-pipe: {}", e),
            }
        }
        received
    }

    /// Go through all the signals and broadcast everything.
    ///
    /// Driver tasks wake up for *any* signal and simply process all globally
    /// registered signal streams, so each task is sort of cooperatively working
    /// for all the rest as well.
    fn broadcast(&self) {
        for (sig, slot) in globals().signals.iter().enumerate() {
            // Any signal of this kind arrived since we checked last?
            if !slot.pending.swap(false, Ordering::SeqCst) {
                continue
            }

            let signum = sig as c_int;
            let mut recipients = slot.recipients.lock().unwrap();

            // Notify all waiters on this signal that the signal has been
            // received. If we can't push a message into the queue then we don't
            // worry about it as everything is coalesced anyway. If the channel
            // has gone away then we can remove that slot.
            for i in (0..recipients.len()).rev() {
                // TODO: This thing probably generates unnecessary wakups of
                //       this task when `NotReady` is received because we don't
                //       actually want to get woken up to continue sending a
                //       message. Let's optimise it later on though, as we know
                //       this works.
                match recipients[i].start_send(signum) {
                    Ok(AsyncSink::Ready) => {}
                    Ok(AsyncSink::NotReady(_)) => {}
                    Err(_) => { recipients.swap_remove(i); }
                }
            }
        }
    }
}

/// An implementation of `Stream` for receiving a particular type of signal.
///
/// This structure implements the `Stream` trait and represents notifications
/// of the current process receiving a particular signal. The signal being
/// listened for is passed to `Signal::new`, and the same signal number is then
/// yielded as each element for the stream.
///
/// In general signal handling on Unix is a pretty tricky topic, and this
/// structure is no exception! There are some important limitations to keep in
/// mind when using `Signal` streams:
///
/// * Signals handling in Unix already necessitates coalescing signals
///   together sometimes. This `Signal` stream is also no exception here in
///   that it will also coalesce signals. That is, even if the signal handler
///   for this process runs multiple times, the `Signal` stream may only return
///   one signal notification. Specifically, before `poll` is called, all
///   signal notifications are coalesced into one item returned from `poll`.
///   Once `poll` has been called, however, a further signal is guaranteed to
///   be yielded as an item.
///
///   Put another way, any element pulled off the returned stream corresponds to
///   *at least one* signal, but possibly more.
///
/// * Signal handling in general is relatively inefficient. Although some
///   improvements are possible in this crate, it's recommended to not plan on
///   having millions of signal channels open.
///
/// * Currently the "driver task" to process incoming signals never exits. This
///   driver task runs in the background of the event loop provided, and
///   in general you shouldn't need to worry about it.
///
/// If you've got any questions about this feel free to open an issue on the
/// repo, though, as I'd love to chat about this! In other words, I'd love to
/// alleviate some of these limitations if possible!
pub struct Signal {
    signal: c_int,
    // Used only as an identifier. We place the real sender into a Box, so it
    // stays on the same address forever. That gives us a unique pointer, so we
    // can use this to identify the sender in a Vec and delete it when we are
    // dropped.
    id: *const Sender<c_int>,
    rx: Receiver<c_int>,
}

// The raw pointer prevents the compiler from determining it as Send
// automatically. But the only thing we use the raw pointer for is to identify
// the correct Box to delete, not manipulate any data through that.
unsafe impl Send for Signal {}

impl Signal {
    /// Creates a new stream which will receive notifications when the current
    /// process receives the signal `signal`.
    ///
    /// This function will create a new stream which may be based on the
    /// event loop handle provided. This function returns a future which will
    /// then resolve to the signal stream, if successful.
    ///
    /// The `Signal` stream is an infinite stream which will receive
    /// notifications whenever a signal is received. More documentation can be
    /// found on `Signal` itself, but to reiterate:
    ///
    /// * Signals may be coalesced beyond what the kernel already does.
    /// * Once a signal handler is registered with the process the underlying
    ///   libc signal handler is never unregistered.
    ///
    /// A `Signal` stream can be created for a particular signal number
    /// multiple times. When a signal is received then all the associated
    /// channels will receive the signal notification.
    pub fn new(signal: c_int, handle: &Handle) -> IoFuture<Signal> {
        let result = (|| {
            // Turn the signal delivery on once we are ready for it
            try!(signal_enable(signal));

            // Ensure there's a driver for our associated event loop processing
            // signals.
            let id = handle.id();
            let mut drivers = globals().drivers.lock().unwrap();
            if !drivers.contains(&id) {
                handle.spawn(try!(Driver::new(handle)));
                drivers.insert(id);
            }
            drop(drivers);

            // One wakeup in a queue is enough, no need for us to buffer up any
            // more.
            let (tx, rx) = channel(1);
            let tx = Box::new(tx);
            let id: *const _ = &*tx;
            let idx = signal as usize;
            globals().signals[idx].recipients.lock().unwrap().push(tx);
            Ok(Signal {
                rx: rx,
                id: id,
                signal: signal,
            })
        })();

        Box::new(future::result(result))
    }
}

impl Stream for Signal {
    type Item = c_int;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<c_int>, io::Error> {
        // receivers don't generate errors
        self.rx.poll().map_err(|_| panic!())
    }
}

impl Drop for Signal {
    fn drop(&mut self) {
        let idx = self.signal as usize;
        let mut list = globals().signals[idx].recipients.lock().unwrap();
        list.retain(|sender| &**sender as *const _ != self.id);
    }
}
<|endoftext|>


<commit_before>// ignore-freebsd: gdb package too new
// only-cdb // "Temporarily" ignored on GDB/LLDB due to debuginfo tests being disabled, see PR 47155
// ignore-android: FIXME(#10381)
// compile-flags:-g
// min-gdb-version: 7.7
// min-lldb-version: 310
// min-cdb-version: 10.0.18317.1001

// === GDB TESTS ===================================================================================

// gdb-command: run

// gdb-command: print slice
// gdb-check:$1 = &[i32](len: 4) = {0, 1, 2, 3}

// gdb-command: print vec
// gdb-check:$2 = Vec<u64, alloc::alloc::Global>(len: 4, cap: [...]) = {4, 5, 6, 7}

// gdb-command: print str_slice
// gdb-check:$3 = "IAMA string slice!"

// gdb-command: print string
// gdb-check:$4 = "IAMA string!"

// gdb-command: print some
// gdb-check:$5 = Some = {8}

// gdb-command: print none
// gdbg-check:$6 = None
// gdbr-check:$6 = core::option::Option::None

// gdb-command: print os_string
// gdb-check:$7 = "IAMA OS string 😃"

// gdb-command: print some_string
// gdb-check:$8 = Some = {"IAMA optional string!"}

// gdb-command: set print length 5
// gdb-command: print some_string
// gdb-check:$8 = Some = {"IAMA "...}

// === LLDB TESTS ==================================================================================

// lldb-command: run

// lldb-command: print slice
// lldb-check:[...]$0 = &[0, 1, 2, 3]

// lldb-command: print vec
// lldb-check:[...]$1 = vec![4, 5, 6, 7]

// lldb-command: print str_slice
// lldb-check:[...]$2 = "IAMA string slice!"

// lldb-command: print string
// lldb-check:[...]$3 = "IAMA string!"

// lldb-command: print some
// lldb-check:[...]$4 = Some(8)

// lldb-command: print none
// lldb-check:[...]$5 = None

// lldb-command: print os_string
// lldb-check:[...]$6 = "IAMA OS string 😃"[...]

// === CDB TESTS ==================================================================================

// cdb-command: g

// cdb-command: dx slice,d
// cdb-check:slice,d          : { len=4 } [Type: slice$<i32>]
// cdb-check:    [len]            : 4 [Type: [...]]
// cdb-check:    [0]              : 0 [Type: int]
// cdb-check:    [1]              : 1 [Type: int]
// cdb-check:    [2]              : 2 [Type: int]
// cdb-check:    [3]              : 3 [Type: int]

// cdb-command: dx vec,d
// cdb-check:vec,d [...] : { len=4 } [Type: [...]::Vec<u64,alloc::alloc::Global>]
// cdb-check:    [len]            : 4 [Type: [...]]
// cdb-check:    [capacity]       : [...] [Type: [...]]
// cdb-check:    [0]              : 4 [Type: unsigned __int64]
// cdb-check:    [1]              : 5 [Type: unsigned __int64]
// cdb-check:    [2]              : 6 [Type: unsigned __int64]
// cdb-check:    [3]              : 7 [Type: unsigned __int64]

// cdb-command: dx str_slice
// cdb-check:str_slice        : "IAMA string slice!" [Type: str]

// cdb-command: dx string
// cdb-check:string           : "IAMA string!" [Type: [...]::String]
// cdb-check:    [<Raw View>]     [Type: [...]::String]
// cdb-check:    [len]            : 0xc [Type: [...]]
// cdb-check:    [capacity]       : 0xc [Type: [...]]

// cdb-command: dx -r2 string
// cdb-check:    [0]              : 73 'I' [Type: char]
// cdb-check:    [1]              : 65 'A' [Type: char]
// cdb-check:    [2]              : 77 'M' [Type: char]
// cdb-check:    [3]              : 65 'A' [Type: char]
// cdb-check:    [4]              : 32 ' ' [Type: char]
// cdb-check:    [5]              : 115 's' [Type: char]
// cdb-check:    [6]              : 116 't' [Type: char]
// cdb-check:    [7]              : 114 'r' [Type: char]
// cdb-check:    [8]              : 105 'i' [Type: char]
// cdb-check:    [9]              : 110 'n' [Type: char]
// cdb-check:    [10]             : 103 'g' [Type: char]
// cdb-check:    [11]             : 33 '!' [Type: char]

// cdb-command: dx os_string
// cdb-check:os_string        : "IAMA OS string 😃" [Type: std::ffi::os_str::OsString]
// cdb-check:    [<Raw View>]     [Type: std::ffi::os_str::OsString]
// cdb-check:    [chars]          : "IAMA OS string 😃"

// cdb-command: dx some
// cdb-check:some             : Some [Type: enum$<core::option::Option<i16> >]
// cdb-check:    [<Raw View>]     [Type: enum$<core::option::Option<i16> >]
// cdb-check:    [variant]        : Some
// cdb-check:    [+0x002] __0              : 8 [Type: short]

// cdb-command: dx none
// cdb-check:none             : None [Type: enum$<core::option::Option<i64> >]
// cdb-check:    [<Raw View>]     [Type: enum$<core::option::Option<i64> >]
// cdb-check:    [variant]        : None

// cdb-command: dx some_string
// NOTE: cdb fails to interpret debug info of Option enums on i686.
// cdb-check:some_string      [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]

// cdb-command: dx linkedlist
// cdb-check:linkedlist       : { len=0x2 } [Type: alloc::collections::linked_list::LinkedList<i32>]
// cdb-check:    [<Raw View>]     [Type: alloc::collections::linked_list::LinkedList<i32>]
// cdb-check:    [0x0]            : 128 [Type: int]
// cdb-check:    [0x1]            : 42 [Type: int]

// cdb-command: dx vecdeque
// cdb-check:vecdeque         : { len=0x2 } [Type: alloc::collections::vec_deque::VecDeque<i32>]
// cdb-check:    [<Raw View>]     [Type: alloc::collections::vec_deque::VecDeque<i32>]
// cdb-check:    [len]            : 0x2
// cdb-check:    [capacity]       : 0x8 [Type: unsigned [...]]
// cdb-check:    [0x0]            : 90 [Type: int]
// cdb-check:    [0x1]            : 20 [Type: int]

#![allow(unused_variables)]
use std::collections::{LinkedList, VecDeque};
use std::ffi::OsString;

fn main() {

    // &[]
    let slice: &[i32] = &[0, 1, 2, 3];

    // Vec
    let vec = vec![4u64, 5, 6, 7];

    // &str
    let str_slice = "IAMA string slice!";

    // String
    let string = "IAMA string!".to_string();

    // OsString
    let os_string = OsString::from("IAMA OS string \u{1F603}");

    // Option
    let some = Some(8i16);
    let none: Option<i64> = None;

    let some_string = Some("IAMA optional string!".to_owned());

    // LinkedList
    let mut linkedlist = LinkedList::new();
    linkedlist.push_back(42);
    linkedlist.push_front(128);

    // VecDeque
    let mut vecdeque = VecDeque::new();
    vecdeque.push_back(20);
    vecdeque.push_front(90);

    zzz(); // #break
}

fn zzz() { () }
<commit_msg>Fix failing test<commit_after>// ignore-freebsd: gdb package too new
// only-cdb // "Temporarily" ignored on GDB/LLDB due to debuginfo tests being disabled, see PR 47155
// ignore-android: FIXME(#10381)
// compile-flags:-g
// min-gdb-version: 7.7
// min-lldb-version: 310
// min-cdb-version: 10.0.18317.1001

// === GDB TESTS ===================================================================================

// gdb-command: run

// gdb-command: print slice
// gdb-check:$1 = &[i32](len: 4) = {0, 1, 2, 3}

// gdb-command: print vec
// gdb-check:$2 = Vec<u64, alloc::alloc::Global>(len: 4, cap: [...]) = {4, 5, 6, 7}

// gdb-command: print str_slice
// gdb-check:$3 = "IAMA string slice!"

// gdb-command: print string
// gdb-check:$4 = "IAMA string!"

// gdb-command: print some
// gdb-check:$5 = Some = {8}

// gdb-command: print none
// gdbg-check:$6 = None
// gdbr-check:$6 = core::option::Option::None

// gdb-command: print os_string
// gdb-check:$7 = "IAMA OS string 😃"

// gdb-command: print some_string
// gdb-check:$8 = Some = {"IAMA optional string!"}

// gdb-command: set print length 5
// gdb-command: print some_string
// gdb-check:$8 = Some = {"IAMA "...}

// === LLDB TESTS ==================================================================================

// lldb-command: run

// lldb-command: print slice
// lldb-check:[...]$0 = &[0, 1, 2, 3]

// lldb-command: print vec
// lldb-check:[...]$1 = vec![4, 5, 6, 7]

// lldb-command: print str_slice
// lldb-check:[...]$2 = "IAMA string slice!"

// lldb-command: print string
// lldb-check:[...]$3 = "IAMA string!"

// lldb-command: print some
// lldb-check:[...]$4 = Some(8)

// lldb-command: print none
// lldb-check:[...]$5 = None

// lldb-command: print os_string
// lldb-check:[...]$6 = "IAMA OS string 😃"[...]

// === CDB TESTS ==================================================================================

// cdb-command: g

// cdb-command: dx slice,d
// cdb-check:slice,d          : { len=4 } [Type: slice$<i32>]
// cdb-check:    [len]            : 4 [Type: [...]]
// cdb-check:    [0]              : 0 [Type: int]
// cdb-check:    [1]              : 1 [Type: int]
// cdb-check:    [2]              : 2 [Type: int]
// cdb-check:    [3]              : 3 [Type: int]

// cdb-command: dx vec,d
// cdb-check:vec,d [...] : { len=4 } [Type: [...]::Vec<u64,alloc::alloc::Global>]
// cdb-check:    [len]            : 4 [Type: [...]]
// cdb-check:    [capacity]       : [...] [Type: [...]]
// cdb-check:    [0]              : 4 [Type: unsigned __int64]
// cdb-check:    [1]              : 5 [Type: unsigned __int64]
// cdb-check:    [2]              : 6 [Type: unsigned __int64]
// cdb-check:    [3]              : 7 [Type: unsigned __int64]

// cdb-command: dx str_slice
// cdb-check:str_slice        : "IAMA string slice!" [Type: str]

// cdb-command: dx string
// cdb-check:string           : "IAMA string!" [Type: [...]::String]
// cdb-check:    [<Raw View>]     [Type: [...]::String]
// cdb-check:    [len]            : 0xc [Type: [...]]
// cdb-check:    [capacity]       : 0xc [Type: [...]]

// cdb-command: dx -r2 string
// cdb-check:    [0]              : 73 'I' [Type: char]
// cdb-check:    [1]              : 65 'A' [Type: char]
// cdb-check:    [2]              : 77 'M' [Type: char]
// cdb-check:    [3]              : 65 'A' [Type: char]
// cdb-check:    [4]              : 32 ' ' [Type: char]
// cdb-check:    [5]              : 115 's' [Type: char]
// cdb-check:    [6]              : 116 't' [Type: char]
// cdb-check:    [7]              : 114 'r' [Type: char]
// cdb-check:    [8]              : 105 'i' [Type: char]
// cdb-check:    [9]              : 110 'n' [Type: char]
// cdb-check:    [10]             : 103 'g' [Type: char]
// cdb-check:    [11]             : 33 '!' [Type: char]

// cdb-command: dx os_string
// cdb-check:os_string        : "IAMA OS string 😃" [Type: std::ffi::os_str::OsString]
// cdb-check:    [<Raw View>]     [Type: std::ffi::os_str::OsString]
// cdb-check:    [chars]          : "IAMA OS string 😃"

// cdb-command: dx some
// cdb-check:some             : Some [Type: enum$<core::option::Option<i16> >]
// cdb-check:    [<Raw View>]     [Type: enum$<core::option::Option<i16> >]
// cdb-check:    [variant]        : Some
// cdb-check:    [+0x002] __0              : 8 [Type: short]

// cdb-command: dx none
// cdb-check:none             : None [Type: enum$<core::option::Option<i64> >]
// cdb-check:    [<Raw View>]     [Type: enum$<core::option::Option<i64> >]
// cdb-check:    [variant]        : None

// cdb-command: dx some_string
// NOTE: cdb fails to interpret debug info of Option enums on i686.
// cdb-check:some_string      [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]

// cdb-command: dx linkedlist
// cdb-check:linkedlist       : { len=0x2 } [Type: alloc::collections::linked_list::LinkedList<i32>]
// cdb-check:    [<Raw View>]     [Type: alloc::collections::linked_list::LinkedList<i32>]
// cdb-check:    [0x0]            : 128 [Type: int]
// cdb-check:    [0x1]            : 42 [Type: int]

// cdb-command: dx vecdeque
// cdb-check:vecdeque         : { len=0x2 } [Type: alloc::collections::vec_deque::VecDeque<i32,alloc::alloc::Global>]
// cdb-check:    [<Raw View>]     [Type: alloc::collections::vec_deque::VecDeque<i32,alloc::alloc::Global>]
// cdb-check:    [len]            : 0x2
// cdb-check:    [capacity]       : 0x8 [Type: unsigned [...]]
// cdb-check:    [0x0]            : 90 [Type: int]
// cdb-check:    [0x1]            : 20 [Type: int]

#![allow(unused_variables)]
use std::collections::{LinkedList, VecDeque};
use std::ffi::OsString;

fn main() {

    // &[]
    let slice: &[i32] = &[0, 1, 2, 3];

    // Vec
    let vec = vec![4u64, 5, 6, 7];

    // &str
    let str_slice = "IAMA string slice!";

    // String
    let string = "IAMA string!".to_string();

    // OsString
    let os_string = OsString::from("IAMA OS string \u{1F603}");

    // Option
    let some = Some(8i16);
    let none: Option<i64> = None;

    let some_string = Some("IAMA optional string!".to_owned());

    // LinkedList
    let mut linkedlist = LinkedList::new();
    linkedlist.push_back(42);
    linkedlist.push_front(128);

    // VecDeque
    let mut vecdeque = VecDeque::new();
    vecdeque.push_back(20);
    vecdeque.push_front(90);

    zzz(); // #break
}

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