rust_asio 0.6.0

Asynchronous I/O library
Documentation
use ffi::TssPtr;
use core::{IoContext, ThreadIoContext};

use std::ptr;
use std::ops::{Deref, DerefMut};

pub struct ThreadCallStack {
    key: *const IoContext,
    next: *mut ThreadCallStack,
    value: ThreadIoContext,
}

impl ThreadCallStack {
    pub fn new(value: ThreadIoContext) -> ThreadCallStack {
        ThreadCallStack {
            key: ptr::null(),
            next: ptr::null_mut(),
            value: value,
        }
    }

    pub fn wind(&mut self, key: &IoContext) -> ThreadCallStackRef {
        self.key = key;
        self.next = TOP.get();
        TOP.set(self);
        ThreadCallStackRef(self)
    }

    pub fn contains<'a>(key: &'a IoContext) -> Option<&'a mut ThreadIoContext> {
        let mut ptr = TOP.get();
        unsafe {
            while !ptr.is_null() {
                if (*ptr).key == key as *const IoContext {
                    return Some(&mut (*ptr).value);
                }
                ptr = (*ptr).next;
            }
        }
        None
    }
}

pub struct ThreadCallStackRef<'a>(&'a mut ThreadCallStack);

impl<'a> Drop for ThreadCallStackRef<'a> {
    fn drop(&mut self) {
        TOP.set(self.0.next)
    }
}

impl<'a> Deref for ThreadCallStackRef<'a> {
    type Target = ThreadIoContext;

    fn deref(&self) -> &Self::Target {
        &self.0.value
    }
}

impl<'a> DerefMut for ThreadCallStackRef<'a> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0.value
    }
}

lazy_static! {
    static ref TOP: TssPtr<ThreadCallStack> = TssPtr::new().unwrap();
}

#[test]
fn test_call_stack_1() {
    let ctx = IoContext::new().unwrap();
    let mut cs = ThreadCallStack::new(Default::default());
    {
        let _ctx = cs.wind(&ctx);
        assert!(ThreadCallStack::contains(&ctx).is_some());
    }
    assert!(ThreadCallStack::contains(&ctx).is_none());
}

#[test]
fn test_call_stack_2() {
    use std::thread;

    let ctx = IoContext::new().unwrap();
    let mut cs = ThreadCallStack::new(Default::default());
    let _ctx = cs.wind(&ctx);
    assert!(ThreadCallStack::contains(&ctx).is_some());
    {
        let ctx = ctx.clone();
        thread::spawn(move || {
            assert!(ThreadCallStack::contains(&ctx).is_none());
        }).join().unwrap();
    }
}